Esempio n. 1
0
        void PopulateAssetList()
        {
            assetList.RemoveChildren();
            availableShps.Clear();

            // TODO: This is too slow to run in the main thread
            // var files = AssetSource != null ? AssetSource.AllFileNames() :
            // FileSystem.MountedFolders.SelectMany(f => f.AllFileNames());

            if (assetSource == null)
            {
                return;
            }

            var files = assetSource.AllFileNames();

            foreach (var file in files)
            {
                if (AllowedExtensions.Any(ext => file.EndsWith(ext, true, CultureInfo.InvariantCulture)))
                {
                    AddAsset(assetList, file, template);
                    availableShps.Add(file);
                }
            }
        }
Esempio n. 2
0
        void PopulateAssetList()
        {
            assetList.RemoveChildren();
            AvailableShps.Clear();

            // TODO: This is too slow to run in the main thread
            //var files = AssetSource != null ? AssetSource.AllFileNames() :
            //	FileSystem.MountedFolders.SelectMany(f => f.AllFileNames());

            if (AssetSource == null)
            {
                return;
            }

            var files = AssetSource.AllFileNames();

            foreach (var file in files)
            {
                if (file.EndsWith(".shp"))
                {
                    AddAsset(assetList, file, template);
                    AvailableShps.Add(file);
                }
            }
        }
Esempio n. 3
0
        public void Save(string toPath)
        {
            MapFormat = 6;

            var root   = new List <MiniYamlNode>();
            var fields = new[]
            {
                "Selectable",
                "MapFormat",
                "RequiresMod",
                "Title",
                "Description",
                "Author",
                "Tileset",
                "MapSize",
                "Bounds",
                "UseAsShellmap",
                "Type",
            };

            foreach (var field in fields)
            {
                var f = this.GetType().GetField(field);
                if (f.GetValue(this) == null)
                {
                    continue;
                }
                root.Add(new MiniYamlNode(field, FieldSaver.FormatValue(this, f)));
            }

            root.Add(new MiniYamlNode("Options", FieldSaver.SaveDifferences(Options, new MapOptions())));

            root.Add(new MiniYamlNode("Players", null,
                                      Players.Select(p => new MiniYamlNode("PlayerReference@{0}".F(p.Key), FieldSaver.SaveDifferences(p.Value, new PlayerReference()))).ToList())
                     );

            root.Add(new MiniYamlNode("Actors", null,
                                      Actors.Value.Select(x => new MiniYamlNode(x.Key, x.Value.Save())).ToList())
                     );

            root.Add(new MiniYamlNode("Smudges", MiniYaml.FromList <SmudgeReference>(Smudges.Value)));
            root.Add(new MiniYamlNode("Rules", null, RuleDefinitions));
            root.Add(new MiniYamlNode("Sequences", null, SequenceDefinitions));
            root.Add(new MiniYamlNode("VoxelSequences", null, VoxelSequenceDefinitions));
            root.Add(new MiniYamlNode("Weapons", null, WeaponDefinitions));
            root.Add(new MiniYamlNode("Voices", null, VoiceDefinitions));
            root.Add(new MiniYamlNode("Notifications", null, NotificationDefinitions));
            root.Add(new MiniYamlNode("Translations", null, TranslationDefinitions));

            var entries = new Dictionary <string, byte[]>();

            entries.Add("map.bin", SaveBinaryData());
            var s = root.WriteToString();

            entries.Add("map.yaml", Encoding.UTF8.GetBytes(s));

            // Add any custom assets
            if (Container != null)
            {
                foreach (var file in Container.AllFileNames())
                {
                    if (file == "map.bin" || file == "map.yaml")
                    {
                        continue;
                    }

                    entries.Add(file, Container.GetContent(file).ReadAllBytes());
                }
            }

            // Saving the map to a new location
            if (toPath != Path)
            {
                Path = toPath;

                // Create a new map package
                Container = GlobalFileSystem.CreatePackage(Path, int.MaxValue, entries);
            }

            // Update existing package
            Container.Write(entries);
        }
Esempio n. 4
0
        public AssetBrowserLogic(Widget widget, Action onExit, World world, Dictionary <string, MiniYaml> logicArgs)
        {
            this.world = world;

            panel       = widget;
            assetSource = Game.ModData.ModFiles.MountedFolders.First();

            var ticker = panel.GetOrNull <LogicTickerWidget>("ANIMATION_TICKER");

            if (ticker != null)
            {
                ticker.OnTick = () =>
                {
                    if (animateFrames)
                    {
                        SelectNextFrame();
                    }
                };
            }

            var sourceDropdown = panel.GetOrNull <DropDownButtonWidget>("SOURCE_SELECTOR");

            if (sourceDropdown != null)
            {
                sourceDropdown.OnMouseDown = _ => ShowSourceDropdown(sourceDropdown);
                sourceDropdown.GetText     = () =>
                {
                    var name = assetSource != null?Platform.UnresolvePath(assetSource.Name) : "All Packages";

                    if (name.Length > 15)
                    {
                        name = "..." + name.Substring(name.Length - 15);
                    }

                    return(name);
                };
            }

            var spriteWidget = panel.GetOrNull <SpriteWidget>("SPRITE");

            if (spriteWidget != null)
            {
                spriteWidget.GetSprite  = () => currentSprites != null ? currentSprites[currentFrame] : null;
                currentPalette          = spriteWidget.Palette;
                spriteWidget.GetPalette = () => currentPalette;
                spriteWidget.IsVisible  = () => !isVideoLoaded;
            }

            var playerWidget = panel.GetOrNull <VqaPlayerWidget>("PLAYER");

            if (playerWidget != null)
            {
                playerWidget.IsVisible = () => isVideoLoaded;
            }

            var paletteDropDown = panel.GetOrNull <DropDownButtonWidget>("PALETTE_SELECTOR");

            if (paletteDropDown != null)
            {
                paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown, world);
                paletteDropDown.GetText     = () => currentPalette;
            }

            var colorPreview = panel.GetOrNull <ColorPreviewManagerWidget>("COLOR_MANAGER");

            if (colorPreview != null)
            {
                colorPreview.Color = Game.Settings.Player.Color;
            }

            var colorDropdown = panel.GetOrNull <DropDownButtonWidget>("COLOR");

            if (colorDropdown != null)
            {
                colorDropdown.IsDisabled  = () => currentPalette != colorPreview.PaletteName;
                colorDropdown.OnMouseDown = _ => ColorPickerLogic.ShowColorDropDown(colorDropdown, colorPreview, world);
                panel.Get <ColorBlockWidget>("COLORBLOCK").GetColor = () => Game.Settings.Player.Color.RGB;
            }

            filenameInput = panel.Get <TextFieldWidget>("FILENAME_INPUT");
            filenameInput.OnTextEdited = () => ApplyFilter(filenameInput.Text);
            filenameInput.OnEscKey     = filenameInput.YieldKeyboardFocus;

            var frameContainer = panel.GetOrNull("FRAME_SELECTOR");

            if (frameContainer != null)
            {
                frameContainer.IsVisible = () => (currentSprites != null && currentSprites.Length > 1) ||
                                           (isVideoLoaded && player != null && player.Video != null && player.Video.Frames > 1);
            }

            frameSlider = panel.Get <SliderWidget>("FRAME_SLIDER");
            if (frameSlider != null)
            {
                frameSlider.OnChange += x =>
                {
                    if (!isVideoLoaded)
                    {
                        currentFrame = (int)Math.Round(x);
                    }
                };

                frameSlider.GetValue   = () => isVideoLoaded ? player.Video.CurrentFrame : currentFrame;
                frameSlider.IsDisabled = () => isVideoLoaded;
            }

            var frameText = panel.GetOrNull <LabelWidget>("FRAME_COUNT");

            if (frameText != null)
            {
                frameText.GetText = () =>
                                    isVideoLoaded ?
                                    "{0} / {1}".F(player.Video.CurrentFrame + 1, player.Video.Frames) :
                                    "{0} / {1}".F(currentFrame, currentSprites.Length - 1);
            }

            var playButton = panel.GetOrNull <ButtonWidget>("BUTTON_PLAY");

            if (playButton != null)
            {
                playButton.Key     = new Hotkey(Keycode.SPACE, Modifiers.None);
                playButton.OnClick = () =>
                {
                    if (isVideoLoaded)
                    {
                        player.Play();
                    }
                    else
                    {
                        animateFrames = true;
                    }
                };

                playButton.IsVisible = () => isVideoLoaded ? player.Paused : !animateFrames;
            }

            var pauseButton = panel.GetOrNull <ButtonWidget>("BUTTON_PAUSE");

            if (pauseButton != null)
            {
                pauseButton.Key     = new Hotkey(Keycode.SPACE, Modifiers.None);
                pauseButton.OnClick = () =>
                {
                    if (isVideoLoaded)
                    {
                        player.Pause();
                    }
                    else
                    {
                        animateFrames = false;
                    }
                };

                pauseButton.IsVisible = () => isVideoLoaded ? !player.Paused : animateFrames;
            }

            var stopButton = panel.GetOrNull <ButtonWidget>("BUTTON_STOP");

            if (stopButton != null)
            {
                stopButton.Key     = new Hotkey(Keycode.RETURN, Modifiers.None);
                stopButton.OnClick = () =>
                {
                    if (isVideoLoaded)
                    {
                        player.Stop();
                    }
                    else
                    {
                        frameSlider.Value = 0;
                        currentFrame      = 0;
                        animateFrames     = false;
                    }
                };
            }

            var nextButton = panel.GetOrNull <ButtonWidget>("BUTTON_NEXT");

            if (nextButton != null)
            {
                nextButton.Key     = new Hotkey(Keycode.RIGHT, Modifiers.None);
                nextButton.OnClick = () =>
                {
                    if (!isVideoLoaded)
                    {
                        nextButton.OnClick = SelectNextFrame;
                    }
                };

                nextButton.IsVisible = () => !isVideoLoaded;
            }

            var prevButton = panel.GetOrNull <ButtonWidget>("BUTTON_PREV");

            if (prevButton != null)
            {
                prevButton.Key     = new Hotkey(Keycode.LEFT, Modifiers.None);
                prevButton.OnClick = () =>
                {
                    if (!isVideoLoaded)
                    {
                        SelectPreviousFrame();
                    }
                };

                prevButton.IsVisible = () => !isVideoLoaded;
            }

            if (logicArgs.ContainsKey("SupportedFormats"))
            {
                allowedExtensions = FieldLoader.GetValue <string[]>("SupportedFormats", logicArgs["SupportedFormats"].Value);
            }
            else
            {
                allowedExtensions = new string[0];
            }

            assetList = panel.Get <ScrollPanelWidget>("ASSET_LIST");
            template  = panel.Get <ScrollItemWidget>("ASSET_TEMPLATE");
            PopulateAssetList();

            var closeButton = panel.GetOrNull <ButtonWidget>("CLOSE_BUTTON");

            if (closeButton != null)
            {
                closeButton.OnClick = () =>
                {
                    if (isVideoLoaded)
                    {
                        player.Stop();
                    }
                    Ui.CloseWindow();
                    onExit();
                }
            }
            ;
        }

        void SelectNextFrame()
        {
            currentFrame++;
            if (currentFrame >= currentSprites.Length)
            {
                currentFrame = 0;
            }
        }

        void SelectPreviousFrame()
        {
            currentFrame--;
            if (currentFrame < 0)
            {
                currentFrame = currentSprites.Length - 1;
            }
        }

        Dictionary <string, bool> assetVisByName = new Dictionary <string, bool>();

        bool FilterAsset(string filename)
        {
            var filter = filenameInput.Text;

            if (string.IsNullOrWhiteSpace(filter))
            {
                return(true);
            }

            if (filename.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0)
            {
                return(true);
            }

            return(false);
        }

        void ApplyFilter(string filename)
        {
            assetVisByName.Clear();
            assetList.Layout.AdjustChildren();
            assetList.ScrollToTop();

            // Select the first visible
            var firstVisible = assetVisByName.FirstOrDefault(kvp => kvp.Value);

            if (firstVisible.Key != null)
            {
                LoadAsset(firstVisible.Key);
            }
        }

        void AddAsset(ScrollPanelWidget list, string filepath, ScrollItemWidget template)
        {
            var filename = Path.GetFileName(filepath);
            var item     = ScrollItemWidget.Setup(template,
                                                  () => currentFilename == filename,
                                                  () => { LoadAsset(filename); });

            item.Get <LabelWidget>("TITLE").GetText = () => filepath;
            item.IsVisible = () =>
            {
                bool visible;
                if (assetVisByName.TryGetValue(filepath, out visible))
                {
                    return(visible);
                }

                visible = FilterAsset(filepath);
                assetVisByName.Add(filepath, visible);
                return(visible);
            };

            list.AddChild(item);
        }

        bool LoadAsset(string filename)
        {
            if (isVideoLoaded)
            {
                player.Stop();
                player        = null;
                isVideoLoaded = false;
            }

            if (string.IsNullOrEmpty(filename))
            {
                return(false);
            }

            if (!Game.ModData.ModFiles.Exists(filename))
            {
                return(false);
            }

            if (Path.GetExtension(filename.ToLowerInvariant()) == ".vqa")
            {
                player          = panel.Get <VqaPlayerWidget>("PLAYER");
                currentFilename = filename;
                player.Load(filename);
                player.DrawOverlay       = false;
                isVideoLoaded            = true;
                frameSlider.MaximumValue = (float)player.Video.Frames - 1;
                frameSlider.Ticks        = 0;
                return(true);
            }
            else
            {
                currentFilename          = filename;
                currentSprites           = world.Map.SequenceProvider.SpriteCache[filename];
                currentFrame             = 0;
                frameSlider.MaximumValue = (float)currentSprites.Length - 1;
                frameSlider.Ticks        = currentSprites.Length;
            }

            return(true);
        }

        bool ShowSourceDropdown(DropDownButtonWidget dropdown)
        {
            Func <IFolder, ScrollItemWidget, ScrollItemWidget> setupItem = (source, itemTemplate) =>
            {
                var item = ScrollItemWidget.Setup(itemTemplate,
                                                  () => assetSource == source,
                                                  () => { assetSource = source; PopulateAssetList(); });
                item.Get <LabelWidget>("LABEL").GetText = () => source != null?Platform.UnresolvePath(source.Name) : "All Packages";

                return(item);
            };

            // TODO: Re-enable "All Packages" once list generation is done in a background thread
            // var sources = new[] { (IFolder)null }.Concat(GlobalFileSystem.MountedFolders);
            var sources = Game.ModData.ModFiles.MountedFolders;

            dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, sources, setupItem);
            return(true);
        }

        void PopulateAssetList()
        {
            assetList.RemoveChildren();
            availableShps.Clear();

            // TODO: This is too slow to run in the main thread
            // var files = AssetSource != null ? AssetSource.AllFileNames() :
            // GlobalFileSystem.MountedFolders.SelectMany(f => f.AllFileNames());
            if (assetSource == null)
            {
                return;
            }

            var files = assetSource.AllFileNames().OrderBy(s => s);

            foreach (var file in files)
            {
                if (allowedExtensions.Any(ext => file.EndsWith(ext, true, CultureInfo.InvariantCulture)))
                {
                    AddAsset(assetList, file, template);
                    availableShps.Add(file);
                }
            }
        }

        bool ShowPaletteDropdown(DropDownButtonWidget dropdown, World world)
        {
            Func <string, ScrollItemWidget, ScrollItemWidget> setupItem = (name, itemTemplate) =>
            {
                var item = ScrollItemWidget.Setup(itemTemplate,
                                                  () => currentPalette == name,
                                                  () => currentPalette = name);
                item.Get <LabelWidget>("LABEL").GetText = () => name;

                return(item);
            };

            var palettes = world.WorldActor.TraitsImplementing <IProvidesAssetBrowserPalettes>()
                           .SelectMany(p => p.PaletteNames);

            dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, palettes, setupItem);
            return(true);
        }
    }
Esempio n. 5
0
        public void Save(string toPath)
        {
            MapFormat = 7;

            var root   = new List <MiniYamlNode>();
            var fields = new[]
            {
                "MapFormat",
                "RequiresMod",
                "Title",
                "Description",
                "Author",
                "Tileset",
                "MapSize",
                "Bounds",
                "Visibility",
                "Type",
            };

            foreach (var field in fields)
            {
                var f = this.GetType().GetField(field);
                if (f.GetValue(this) == null)
                {
                    continue;
                }
                root.Add(new MiniYamlNode(field, FieldSaver.FormatValue(this, f)));
            }

            root.Add(new MiniYamlNode("Videos", FieldSaver.SaveDifferences(Videos, new MapVideos())));

            root.Add(new MiniYamlNode("Options", FieldSaver.SaveDifferences(Options, new MapOptions())));

            root.Add(new MiniYamlNode("Players", null, PlayerDefinitions));

            root.Add(new MiniYamlNode("Actors", null, ActorDefinitions));
            root.Add(new MiniYamlNode("Smudges", null, SmudgeDefinitions));
            root.Add(new MiniYamlNode("Rules", null, RuleDefinitions));
            root.Add(new MiniYamlNode("Sequences", null, SequenceDefinitions));
            root.Add(new MiniYamlNode("VoxelSequences", null, VoxelSequenceDefinitions));
            root.Add(new MiniYamlNode("Weapons", null, WeaponDefinitions));
            root.Add(new MiniYamlNode("Voices", null, VoiceDefinitions));
            root.Add(new MiniYamlNode("Music", null, MusicDefinitions));
            root.Add(new MiniYamlNode("Notifications", null, NotificationDefinitions));
            root.Add(new MiniYamlNode("Translations", null, TranslationDefinitions));

            var entries = new Dictionary <string, byte[]>();

            entries.Add("map.bin", SaveBinaryData());
            var s = root.WriteToString();

            entries.Add("map.yaml", Encoding.UTF8.GetBytes(s));

            // Add any custom assets
            if (Container != null)
            {
                foreach (var file in Container.AllFileNames())
                {
                    if (file == "map.bin" || file == "map.yaml")
                    {
                        continue;
                    }

                    entries.Add(file, Container.GetContent(file).ReadAllBytes());
                }
            }

            // Saving the map to a new location
            if (toPath != Path || Container == null)
            {
                Path = toPath;

                // Create a new map package
                Container = GlobalFileSystem.CreatePackage(Path, int.MaxValue, entries);
            }

            // Update existing package
            Container.Write(entries);

            // Update UID to match the newly saved data
            Uid = ComputeHash();
        }
        public AssetBrowserLogic(Widget widget, Action onExit, World world)
        {
            this.world = world;

            panel       = widget;
            assetSource = GlobalFileSystem.MountedFolders.First();

            var ticker = panel.GetOrNull <LogicTickerWidget>("ANIMATION_TICKER");

            if (ticker != null)
            {
                ticker.OnTick = () =>
                {
                    if (animateFrames)
                    {
                        SelectNextFrame();
                    }
                };
            }

            var sourceDropdown = panel.GetOrNull <DropDownButtonWidget>("SOURCE_SELECTOR");

            if (sourceDropdown != null)
            {
                sourceDropdown.OnMouseDown = _ => ShowSourceDropdown(sourceDropdown);
                sourceDropdown.GetText     = () =>
                {
                    var name = assetSource != null?assetSource.Name.Replace(Platform.SupportDir, "^") : "All Packages";

                    if (name.Length > 15)
                    {
                        name = "..." + name.Substring(name.Length - 15);
                    }

                    return(name);
                };
            }

            var spriteWidget = panel.GetOrNull <SpriteWidget>("SPRITE");

            if (spriteWidget != null)
            {
                spriteWidget.GetSprite  = () => currentSprites != null ? currentSprites[currentFrame] : null;
                currentPalette          = spriteWidget.Palette;
                spriteWidget.GetPalette = () => currentPalette;
            }

            var paletteDropDown = panel.GetOrNull <DropDownButtonWidget>("PALETTE_SELECTOR");

            if (paletteDropDown != null)
            {
                paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown, world);
                paletteDropDown.GetText     = () => currentPalette;
            }

            var colorPreview = panel.GetOrNull <ColorPreviewManagerWidget>("COLOR_MANAGER");

            if (colorPreview != null)
            {
                colorPreview.Color = Game.Settings.Player.Color;
            }

            var colorDropdown = panel.GetOrNull <DropDownButtonWidget>("COLOR");

            if (colorDropdown != null)
            {
                colorDropdown.IsDisabled  = () => currentPalette != colorPreview.Palette;
                colorDropdown.OnMouseDown = _ => ShowColorDropDown(colorDropdown, colorPreview, world);
                panel.Get <ColorBlockWidget>("COLORBLOCK").GetColor = () => Game.Settings.Player.Color.RGB;
            }

            filenameInput            = panel.Get <TextFieldWidget>("FILENAME_INPUT");
            filenameInput.OnEnterKey = () => LoadAsset(filenameInput.Text);

            var frameContainer = panel.GetOrNull("FRAME_SELECTOR");

            if (frameContainer != null)
            {
                frameContainer.IsVisible = () => currentSprites != null && currentSprites.Length > 1;
            }

            frameSlider           = panel.Get <SliderWidget>("FRAME_SLIDER");
            frameSlider.OnChange += x => { currentFrame = (int)Math.Round(x); };
            frameSlider.GetValue  = () => currentFrame;

            var frameText = panel.GetOrNull <LabelWidget>("FRAME_COUNT");

            if (frameText != null)
            {
                frameText.GetText = () => "{0} / {1}".F(currentFrame + 1, currentSprites.Length);
            }

            var playButton = panel.GetOrNull <ButtonWidget>("BUTTON_PLAY");

            if (playButton != null)
            {
                playButton.OnClick   = () => animateFrames = true;
                playButton.IsVisible = () => !animateFrames;
            }

            var pauseButton = panel.GetOrNull <ButtonWidget>("BUTTON_PAUSE");

            if (pauseButton != null)
            {
                pauseButton.OnClick   = () => animateFrames = false;
                pauseButton.IsVisible = () => animateFrames;
            }

            var stopButton = panel.GetOrNull <ButtonWidget>("BUTTON_STOP");

            if (stopButton != null)
            {
                stopButton.OnClick = () =>
                {
                    frameSlider.Value = 0;
                    currentFrame      = 0;
                    animateFrames     = false;
                };
            }

            var nextButton = panel.GetOrNull <ButtonWidget>("BUTTON_NEXT");

            if (nextButton != null)
            {
                nextButton.OnClick = SelectNextFrame;
            }

            var prevButton = panel.GetOrNull <ButtonWidget>("BUTTON_PREV");

            if (prevButton != null)
            {
                prevButton.OnClick = SelectPreviousFrame;
            }

            var loadButton = panel.GetOrNull <ButtonWidget>("LOAD_BUTTON");

            if (loadButton != null)
            {
                loadButton.OnClick = () => LoadAsset(filenameInput.Text);
            }

            assetList = panel.Get <ScrollPanelWidget>("ASSET_LIST");
            template  = panel.Get <ScrollItemWidget>("ASSET_TEMPLATE");
            PopulateAssetList();

            var closeButton = panel.GetOrNull <ButtonWidget>("CLOSE_BUTTON");

            if (closeButton != null)
            {
                closeButton.OnClick = () => { Ui.CloseWindow(); onExit(); }
            }
            ;
        }

        void SelectNextFrame()
        {
            currentFrame++;
            if (currentFrame >= currentSprites.Length)
            {
                currentFrame = 0;
            }
        }

        void SelectPreviousFrame()
        {
            currentFrame--;
            if (currentFrame < 0)
            {
                currentFrame = currentSprites.Length - 1;
            }
        }

        void AddAsset(ScrollPanelWidget list, string filepath, ScrollItemWidget template)
        {
            var filename = Path.GetFileName(filepath);
            var item     = ScrollItemWidget.Setup(template,
                                                  () => currentFilename == filename,
                                                  () => { filenameInput.Text = filename; LoadAsset(filename); });

            item.Get <LabelWidget>("TITLE").GetText = () => filepath;

            list.AddChild(item);
        }

        bool LoadAsset(string filename)
        {
            if (string.IsNullOrEmpty(filename))
            {
                return(false);
            }

            if (!GlobalFileSystem.Exists(filename))
            {
                return(false);
            }

            currentFilename          = filename;
            currentSprites           = world.Map.SequenceProvider.SpriteLoader.LoadAllSprites(filename);
            currentFrame             = 0;
            frameSlider.MaximumValue = (float)currentSprites.Length - 1;
            frameSlider.Ticks        = currentSprites.Length;

            return(true);
        }

        bool ShowSourceDropdown(DropDownButtonWidget dropdown)
        {
            Func <IFolder, ScrollItemWidget, ScrollItemWidget> setupItem = (source, itemTemplate) =>
            {
                var item = ScrollItemWidget.Setup(itemTemplate,
                                                  () => assetSource == source,
                                                  () => { assetSource = source; PopulateAssetList(); });
                item.Get <LabelWidget>("LABEL").GetText = () => source != null?source.Name.Replace(Platform.SupportDir, "^") : "All Packages";

                return(item);
            };

            // TODO: Re-enable "All Packages" once list generation is done in a background thread
            // var sources = new[] { (IFolder)null }.Concat(GlobalFileSystem.MountedFolders);

            var sources = GlobalFileSystem.MountedFolders;

            dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, sources, setupItem);
            return(true);
        }

        void PopulateAssetList()
        {
            assetList.RemoveChildren();
            availableShps.Clear();

            // TODO: This is too slow to run in the main thread
            // var files = AssetSource != null ? AssetSource.AllFileNames() :
            // GlobalFileSystem.MountedFolders.SelectMany(f => f.AllFileNames());

            if (assetSource == null)
            {
                return;
            }

            var files = assetSource.AllFileNames().OrderBy(s => s);

            foreach (var file in files)
            {
                if (AllowedExtensions.Any(ext => file.EndsWith(ext, true, CultureInfo.InvariantCulture)))
                {
                    AddAsset(assetList, file, template);
                    availableShps.Add(file);
                }
            }
        }

        bool ShowPaletteDropdown(DropDownButtonWidget dropdown, World world)
        {
            Func <PaletteFromFile, ScrollItemWidget, ScrollItemWidget> setupItem = (palette, itemTemplate) =>
            {
                var name = palette.Name;
                var item = ScrollItemWidget.Setup(itemTemplate,
                                                  () => currentPalette == name,
                                                  () => currentPalette = name);
                item.Get <LabelWidget>("LABEL").GetText = () => name;

                return(item);
            };

            var palettes = world.WorldActor.TraitsImplementing <PaletteFromFile>();

            dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, palettes, setupItem);
            return(true);
        }