Merge pull request #4151 from Mailaender/assetbrowser-renovation

Asset Browser Renovation
This commit is contained in:
Chris Forbes
2013-11-21 12:15:40 -08:00
5 changed files with 172 additions and 71 deletions

View File

@@ -13,6 +13,10 @@ NEW:
Improved the ingame chat interface and input, with it defaulting to Team Chat. Improved the ingame chat interface and input, with it defaulting to Team Chat.
Redesigned the settings panel. Redesigned the settings panel.
Re-added move flashes. Re-added move flashes.
Asset Browser:
Fixed crashes when trying to load invalid filenames or sprites with just 1 frame.
Added support for browsing the folders for R8 files.
Added palette chooser and colorpicker dropdown boxes.
Red Alert: Red Alert:
Added MAD Tank. Added MAD Tank.
Fixed a crash in Monster Tank Madness. Fixed a crash in Monster Tank Madness.

View File

@@ -44,5 +44,15 @@ namespace OpenRA.Mods.RA
if (info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant()) if (info.Tileset == null || info.Tileset.ToLowerInvariant() == world.Map.Tileset.ToLowerInvariant())
wr.AddPalette(info.Name, new Palette(FileSystem.Open(info.Filename), info.ShadowIndex), info.AllowModifiers); wr.AddPalette(info.Name, new Palette(FileSystem.Open(info.Filename), info.ShadowIndex), info.AllowModifiers);
} }
public string Filename
{
get { return info.Filename; }
}
public string Name
{
get { return info.Name; }
}
} }
} }

View File

@@ -10,9 +10,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Traits;
using OpenRA.Widgets; using OpenRA.Widgets;
namespace OpenRA.Mods.RA.Widgets.Logic namespace OpenRA.Mods.RA.Widgets.Logic
@@ -21,15 +23,17 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{ {
Widget panel; Widget panel;
ShpImageWidget spriteImage; ShpImageWidget spriteWidget;
TextFieldWidget filenameInput; TextFieldWidget filenameInput;
SliderWidget frameSlider; SliderWidget frameSlider;
ButtonWidget playButton, pauseButton; ButtonWidget playButton, pauseButton;
ScrollPanelWidget assetList; ScrollPanelWidget assetList;
ScrollItemWidget template; ScrollItemWidget template;
IFolder AssetSource = null; IFolder assetSource = null;
List<string> AvailableShps = new List<string>(); List<string> availableShps = new List<string>();
PaletteFromFile currentPalette;
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public AssetBrowserLogic(Widget widget, Action onExit, World world) public AssetBrowserLogic(Widget widget, Action onExit, World world)
@@ -40,55 +44,70 @@ namespace OpenRA.Mods.RA.Widgets.Logic
sourceDropdown.OnMouseDown = _ => ShowSourceDropdown(sourceDropdown); sourceDropdown.OnMouseDown = _ => ShowSourceDropdown(sourceDropdown);
sourceDropdown.GetText = () => sourceDropdown.GetText = () =>
{ {
var name = AssetSource != null ? AssetSource.Name : "All Packages"; var name = assetSource != null ? assetSource.Name.Replace(Platform.SupportDir, "^") : "All Packages";
if (name.Length > 15) if (name.Length > 15)
name = "..."+name.Substring(name.Length - 15); name = "..." + name.Substring(name.Length - 15);
return name; return name;
}; };
AssetSource = FileSystem.MountedFolders.First(); assetSource = FileSystem.MountedFolders.First();
spriteImage = panel.Get<ShpImageWidget>("SPRITE"); spriteWidget = panel.Get<ShpImageWidget>("SPRITE");
currentPalette = world.WorldActor.TraitsImplementing<PaletteFromFile>().First(p => p.Name == spriteWidget.Palette);
var paletteDropDown = panel.Get<DropDownButtonWidget>("PALETTE_SELECTOR");
paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown, world);
var colorPreview = panel.Get<ColorPreviewManagerWidget>("COLOR_MANAGER");
colorPreview.Color = Game.Settings.Player.Color;
var color = panel.Get<DropDownButtonWidget>("COLOR");
color.IsDisabled = () => currentPalette.Name != colorPreview.Palette;
color.OnMouseDown = _ => ShowColorDropDown(color, colorPreview, world);
var block = panel.Get<ColorBlockWidget>("COLORBLOCK");
block.GetColor = () => Game.Settings.Player.Color.RGB;
filenameInput = panel.Get<TextFieldWidget>("FILENAME_INPUT"); filenameInput = panel.Get<TextFieldWidget>("FILENAME_INPUT");
filenameInput.Text = spriteImage.Image+".shp";
filenameInput.OnEnterKey = () => LoadAsset(filenameInput.Text); filenameInput.OnEnterKey = () => LoadAsset(filenameInput.Text);
frameSlider = panel.Get<SliderWidget>("FRAME_SLIDER"); frameSlider = panel.Get<SliderWidget>("FRAME_SLIDER");
frameSlider.MaximumValue = (float)spriteImage.FrameCount; frameSlider.MaximumValue = (float)spriteWidget.FrameCount;
frameSlider.Ticks = spriteImage.FrameCount+1; frameSlider.Ticks = spriteWidget.FrameCount + 1;
frameSlider.OnChange += x => { spriteImage.Frame = (int)Math.Round(x); }; frameSlider.IsVisible = () => spriteWidget.FrameCount > 0;
frameSlider.GetValue = () => spriteImage.Frame; frameSlider.OnChange += x => { spriteWidget.Frame = (int)Math.Round(x); };
frameSlider.GetValue = () => spriteWidget.Frame;
panel.Get<LabelWidget>("FRAME_COUNT").GetText = () => "{0}/{1}".F(spriteImage.Frame, spriteImage.FrameCount); panel.Get<LabelWidget>("FRAME_COUNT").GetText = () => "{0}/{1}".F(spriteWidget.Frame, spriteWidget.FrameCount);
playButton = panel.Get<ButtonWidget>("BUTTON_PLAY"); playButton = panel.Get<ButtonWidget>("BUTTON_PLAY");
playButton.OnClick = () => playButton.OnClick = () =>
{ {
spriteImage.LoopAnimation = true; spriteWidget.LoopAnimation = true;
playButton.Visible = false; playButton.Visible = false;
pauseButton.Visible = true; pauseButton.Visible = true;
}; };
pauseButton = panel.Get<ButtonWidget>("BUTTON_PAUSE"); pauseButton = panel.Get<ButtonWidget>("BUTTON_PAUSE");
pauseButton.OnClick = () => pauseButton.OnClick = () =>
{ {
spriteImage.LoopAnimation = false; spriteWidget.LoopAnimation = false;
playButton.Visible = true; playButton.Visible = true;
pauseButton.Visible = false; pauseButton.Visible = false;
}; };
panel.Get<ButtonWidget>("BUTTON_STOP").OnClick = () => panel.Get<ButtonWidget>("BUTTON_STOP").OnClick = () =>
{ {
spriteImage.LoopAnimation = false; spriteWidget.LoopAnimation = false;
frameSlider.Value = 0; frameSlider.Value = 0;
spriteImage.Frame = 0; spriteWidget.Frame = 0;
playButton.Visible = true; playButton.Visible = true;
pauseButton.Visible = false; pauseButton.Visible = false;
}; };
panel.Get<ButtonWidget>("BUTTON_NEXT").OnClick = () => { spriteImage.RenderNextFrame(); }; panel.Get<ButtonWidget>("BUTTON_NEXT").OnClick = () => { spriteWidget.RenderNextFrame(); };
panel.Get<ButtonWidget>("BUTTON_PREV").OnClick = () => { spriteImage.RenderPreviousFrame(); }; panel.Get<ButtonWidget>("BUTTON_PREV").OnClick = () => { spriteWidget.RenderPreviousFrame(); };
panel.Get<ButtonWidget>("LOAD_BUTTON").OnClick = () => panel.Get<ButtonWidget>("LOAD_BUTTON").OnClick = () =>
{ {
@@ -99,21 +118,21 @@ namespace OpenRA.Mods.RA.Widgets.Logic
template = panel.Get<ScrollItemWidget>("ASSET_TEMPLATE"); template = panel.Get<ScrollItemWidget>("ASSET_TEMPLATE");
PopulateAssetList(); PopulateAssetList();
// TODO: Horrible hack
var modID = Game.modData.Manifest.Mod.Id; var modID = Game.modData.Manifest.Mod.Id;
var palette = (modID == "d2k") ? "d2k.pal" : "egopal.pal";
// TODO: This should not invoke the OpenRA.Utility.exe, but use it's functions directly.
// TODO: Does not work with SHP(TS) yet?!
panel.Get<ButtonWidget>("EXPORT_BUTTON").OnClick = () => panel.Get<ButtonWidget>("EXPORT_BUTTON").OnClick = () =>
{ {
var ExtractGameFiles = new string[][] var ExtractGameFiles = new string[][]
{ {
new string[] {"--extract", modID, palette, "--userdir"}, new string[] { "--extract", modID, currentPalette.Filename, "--userdir" },
new string[] {"--extract", modID, "{0}.shp".F(spriteImage.Image), "--userdir"}, new string[] { "--extract", modID, "{0}.shp".F(spriteWidget.Image), "--userdir" },
}; };
var ExportToPng = new string[][] var ExportToPng = new string[][]
{ {
new string[] {"--png", Platform.SupportDir+"{0}.shp".F(spriteImage.Image), Platform.SupportDir+palette}, new string[] { "--png", Platform.SupportDir + "{0}.shp".F(spriteWidget.Image), Platform.SupportDir + currentPalette.Filename },
}; };
var ImportFromPng = new string[][] { }; var ImportFromPng = new string[][] { };
@@ -122,9 +141,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{ {
{ "ExtractGameFiles", ExtractGameFiles }, { "ExtractGameFiles", ExtractGameFiles },
{ "ExportToPng", ExportToPng }, { "ExportToPng", ExportToPng },
{ "ImportFromPng", ImportFromPng} { "ImportFromPng", ImportFromPng }
}; };
Ui.OpenWindow("CONVERT_ASSETS_PANEL", args); Ui.OpenWindow("CONVERT_ASSETS_PANEL", args);
}; };
@@ -133,13 +152,13 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var ExtractGameFilesList = new List<string[]>(); var ExtractGameFilesList = new List<string[]>();
var ExportToPngList = new List<string[]>(); var ExportToPngList = new List<string[]>();
ExtractGameFilesList.Add(new string[] { "--extract", modID, palette, "--userdir"} ); ExtractGameFilesList.Add(new string[] { "--extract", modID, currentPalette.Filename, "--userdir" });
foreach (var shp in AvailableShps) foreach (var shp in availableShps)
{ {
ExtractGameFilesList.Add(new string[] { "--extract", modID, shp, "--userdir" } ); ExtractGameFilesList.Add(new string[] { "--extract", modID, shp, "--userdir" });
ExportToPngList.Add(new string[] { "--png", Platform.SupportDir+shp, Platform.SupportDir+palette } ); ExportToPngList.Add(new string[] { "--png", Platform.SupportDir + shp, Platform.SupportDir + currentPalette.Filename });
Console.WriteLine(Platform.SupportDir+shp); Console.WriteLine(Platform.SupportDir + shp);
} }
var ExtractGameFiles = ExtractGameFilesList.ToArray(); var ExtractGameFiles = ExtractGameFilesList.ToArray();
@@ -152,11 +171,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic
{ "ExportToPng", ExportToPng }, { "ExportToPng", ExportToPng },
{ "ImportFromPng", ImportFromPng } { "ImportFromPng", ImportFromPng }
}; };
Ui.OpenWindow("CONVERT_ASSETS_PANEL", args); Ui.OpenWindow("CONVERT_ASSETS_PANEL", args);
}; };
panel.Get<ButtonWidget>("IMPORT_BUTTON").OnClick = () => panel.Get<ButtonWidget>("IMPORT_BUTTON").OnClick = () =>
{ {
var imageSizeInput = panel.Get<TextFieldWidget>("IMAGE_SIZE_INPUT"); var imageSizeInput = panel.Get<TextFieldWidget>("IMAGE_SIZE_INPUT");
@@ -166,16 +184,16 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var ExportToPng = new string[][] { }; var ExportToPng = new string[][] { };
var ImportFromPng = new string[][] var ImportFromPng = new string[][]
{ {
new string[] {"--shp", Platform.SupportDir+imageFilename.Text, imageSizeInput.Text}, new string[] { "--shp", Platform.SupportDir + imageFilename.Text, imageSizeInput.Text },
}; };
var args = new WidgetArgs() var args = new WidgetArgs()
{ {
{ "ExtractGameFiles", ExtractGameFiles }, { "ExtractGameFiles", ExtractGameFiles },
{ "ExportToPng", ExportToPng }, { "ExportToPng", ExportToPng },
{ "ImportFromPng", ImportFromPng} { "ImportFromPng", ImportFromPng }
}; };
Ui.OpenWindow("CONVERT_ASSETS_PANEL", args); Ui.OpenWindow("CONVERT_ASSETS_PANEL", args);
}; };
@@ -184,24 +202,32 @@ namespace OpenRA.Mods.RA.Widgets.Logic
void AddAsset(ScrollPanelWidget list, string filepath, ScrollItemWidget template) void AddAsset(ScrollPanelWidget list, string filepath, ScrollItemWidget template)
{ {
var sprite = Path.GetFileNameWithoutExtension(filepath); var r8 = filepath.EndsWith(".r8", true, CultureInfo.InvariantCulture);
var filename = Path.GetFileName(filepath);
var sprite = r8 ? filename : Path.GetFileNameWithoutExtension(filepath);
var item = ScrollItemWidget.Setup(template, var item = ScrollItemWidget.Setup(template,
() => spriteImage.Image == sprite, () => spriteWidget.Image == sprite,
() => LoadAsset(sprite)); () => {filenameInput.Text = filename; LoadAsset(filename); });
item.Get<LabelWidget>("TITLE").GetText = () => filepath; item.Get<LabelWidget>("TITLE").GetText = () => filepath;
list.AddChild(item); list.AddChild(item);
} }
bool LoadAsset(string sprite) bool LoadAsset(string filename)
{ {
if (sprite == null) if (string.IsNullOrEmpty(filename))
return false; return false;
spriteImage.Frame = 0; if (!FileSystem.Exists(filename))
spriteImage.Image = sprite; return false;
frameSlider.MaximumValue = (float)spriteImage.FrameCount;
frameSlider.Ticks = spriteImage.FrameCount+1; var r8 = filename.EndsWith(".r8", true, CultureInfo.InvariantCulture);
var sprite = r8 ? filename : Path.GetFileNameWithoutExtension(filename);
spriteWidget.Frame = 0;
spriteWidget.Image = sprite;
frameSlider.MaximumValue = (float)spriteWidget.FrameCount;
frameSlider.Ticks = spriteWidget.FrameCount + 1;
return true; return true;
} }
@@ -210,41 +236,78 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Func<IFolder, ScrollItemWidget, ScrollItemWidget> setupItem = (source, itemTemplate) => Func<IFolder, ScrollItemWidget, ScrollItemWidget> setupItem = (source, itemTemplate) =>
{ {
var item = ScrollItemWidget.Setup(itemTemplate, var item = ScrollItemWidget.Setup(itemTemplate,
() => AssetSource == source, () => assetSource == source,
() => { AssetSource = source; PopulateAssetList(); }); () => { assetSource = source; PopulateAssetList(); });
item.Get<LabelWidget>("LABEL").GetText = () => source != null ? source.Name : "All Packages"; item.Get<LabelWidget>("LABEL").GetText = () => source != null ? source.Name.Replace(Platform.SupportDir, "^") : "All Packages";
return item; return item;
}; };
// TODO: Re-enable "All Packages" once list generation is done in a background thread // TODO: Re-enable "All Packages" once list generation is done in a background thread
//var sources = new[] { (IFolder)null }.Concat(FileSystem.MountedFolders); // var sources = new[] { (IFolder)null }.Concat(FileSystem.MountedFolders);
var sources = FileSystem.MountedFolders; var sources = FileSystem.MountedFolders;
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 250, sources, setupItem); dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, sources, setupItem);
return true; return true;
} }
void PopulateAssetList() void PopulateAssetList()
{ {
assetList.RemoveChildren(); assetList.RemoveChildren();
AvailableShps.Clear(); availableShps.Clear();
// TODO: This is too slow to run in the main thread // TODO: This is too slow to run in the main thread
//var files = AssetSource != null ? AssetSource.AllFileNames() : // var files = AssetSource != null ? AssetSource.AllFileNames() :
// FileSystem.MountedFolders.SelectMany(f => f.AllFileNames()); // FileSystem.MountedFolders.SelectMany(f => f.AllFileNames());
if (AssetSource == null) if (assetSource == null)
return; return;
var files = AssetSource.AllFileNames(); var files = assetSource.AllFileNames();
foreach (var file in files) foreach (var file in files)
{ {
if (file.EndsWith(".shp")) if (file.EndsWith(".shp", true, CultureInfo.InvariantCulture) || file.EndsWith(".r8", true, CultureInfo.InvariantCulture))
{ {
AddAsset(assetList, file, template); AddAsset(assetList, file, template);
AvailableShps.Add(file); availableShps.Add(file);
} }
} }
} }
bool ShowPaletteDropdown(DropDownButtonWidget dropdown, World world)
{
Func<PaletteFromFile, ScrollItemWidget, ScrollItemWidget> setupItem = (palette, itemTemplate) =>
{
var item = ScrollItemWidget.Setup(itemTemplate,
() => currentPalette.Name == palette.Name,
() => { currentPalette = palette; spriteWidget.Palette = currentPalette.Name; });
item.Get<LabelWidget>("LABEL").GetText = () => palette.Name;
return item;
};
var palettes = world.WorldActor.TraitsImplementing<PaletteFromFile>();
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, palettes, setupItem);
return true;
}
void ShowColorDropDown(DropDownButtonWidget color, ColorPreviewManagerWidget preview, World world)
{
Action onExit = () =>
{
Game.Settings.Player.Color = preview.Color;
Game.Settings.Save();
};
color.RemovePanel();
Action<HSLColor> onChange = c => preview.Color = c;
var colorChooser = Game.LoadWidget(world, "COLOR_CHOOSER", null, new WidgetArgs()
{
{ "onChange", onChange },
{ "initialColor", Game.Settings.Player.Color }
});
color.AttachPanel(colorChooser, onExit);
}
} }
} }

View File

@@ -5,9 +5,10 @@ Background@ASSETBROWSER_BG:
Width:700 Width:700
Height:410 Height:410
Children: Children:
ColorPreviewManager@COLOR_MANAGER:
Label@ASSETBROWSER_TITLE: Label@ASSETBROWSER_TITLE:
X:0 X:0
Y:20 Y:10
Width:PARENT_RIGHT Width:PARENT_RIGHT
Height:25 Height:25
Text:Game Asset Viewer & Converter Text:Game Asset Viewer & Converter
@@ -42,6 +43,7 @@ Background@ASSETBROWSER_BG:
Y:280 Y:280
Width:140 Width:140
Height:25 Height:25
Text:mouse.r8
Button@LOAD_BUTTON: Button@LOAD_BUTTON:
X:40 X:40
Y:310 Y:310
@@ -50,13 +52,24 @@ Background@ASSETBROWSER_BG:
Text:Load Text:Load
Font:Bold Font:Bold
Key:return Key:return
Label@PREVIEW_TITLE: DropDownButton@PALETTE_SELECTOR:
X:320 X:230
Y:45 Y:45
Width:PARENT_RIGHT Width:150
Height:25 Height:25
Text:Preview
Font:Bold Font:Bold
Text:Palette
DropDownButton@COLOR:
X:380
Y:45
Width:80
Height:25
Children:
ColorBlock@COLORBLOCK:
X:5
Y:6
Width:PARENT_RIGHT-35
Height:PARENT_BOTTOM-12
Background@SPRITE_BG: Background@SPRITE_BG:
X:220 X:220
Y:80 Y:80
@@ -69,8 +82,7 @@ Background@ASSETBROWSER_BG:
Y:4 Y:4
Width:246 Width:246
Height:246 Height:246
Image:DATA.R8 Image:mouse.r8
Palette:colorpicker
Label@ACTIONS_TITLE: Label@ACTIONS_TITLE:
X:PARENT_RIGHT - 150 X:PARENT_RIGHT - 150
Y:45 Y:45

View File

@@ -5,9 +5,10 @@ Background@ASSETBROWSER_BG:
Width:700 Width:700
Height:410 Height:410
Children: Children:
ColorPreviewManager@COLOR_MANAGER:
Label@ASSETBROWSER_TITLE: Label@ASSETBROWSER_TITLE:
X:0 X:0
Y:20 Y:10
Width:PARENT_RIGHT Width:PARENT_RIGHT
Height:25 Height:25
Text:Game Asset Viewer & Converter Text:Game Asset Viewer & Converter
@@ -42,6 +43,7 @@ Background@ASSETBROWSER_BG:
Y:280 Y:280
Width:140 Width:140
Height:25 Height:25
Text:mouse.shp
Button@LOAD_BUTTON: Button@LOAD_BUTTON:
X:40 X:40
Y:310 Y:310
@@ -50,13 +52,24 @@ Background@ASSETBROWSER_BG:
Text:Load Text:Load
Font:Bold Font:Bold
Key:return Key:return
Label@PREVIEW_TITLE: DropDownButton@PALETTE_SELECTOR:
X:320 X:230
Y:45 Y:45
Width:PARENT_RIGHT Width:150
Height:25 Height:25
Text:Preview
Font:Bold Font:Bold
Text:Palette
DropDownButton@COLOR:
X:380
Y:45
Width:80
Height:25
Children:
ColorBlock@COLORBLOCK:
X:5
Y:6
Width:PARENT_RIGHT-35
Height:PARENT_BOTTOM-12
Background@SPRITE_BG: Background@SPRITE_BG:
X:220 X:220
Y:80 Y:80
@@ -70,7 +83,6 @@ Background@ASSETBROWSER_BG:
Width:246 Width:246
Height:246 Height:246
Image:mouse Image:mouse
Palette:colorpicker
Label@ACTIONS_TITLE: Label@ACTIONS_TITLE:
X:PARENT_RIGHT - 150 X:PARENT_RIGHT - 150
Y:45 Y:45