Index: binaries/data/config/default.cfg
===================================================================
--- binaries/data/config/default.cfg
+++ binaries/data/config/default.cfg
@@ -294,6 +294,9 @@
8 = 8
9 = 9
+[hotkey.gamesetup]
+mapbrowser.open = "M"
+
[hotkey.session]
kill = Delete ; Destroy selected units
stop = "H" ; Stop the current action
Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/GameSettingControlButton.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/GameSettingControlButton.js
@@ -0,0 +1,25 @@
+/**
+ * This class is implemented by gamesettings that are controlled by a button.
+ */
+class GameSettingControlButton extends GameSettingControl
+{
+ setControl(gameSettingControlManager)
+ {
+ let row = gameSettingControlManager.getNextRow("buttonSettingFrame");
+ this.frame = Engine.GetGUIObjectByName("buttonSettingFrame[" + row + "]");
+ this.button = Engine.GetGUIObjectByName("buttonSettingControl[" + row + "]");
+ this.button.onPress = this.onPress.bind(this);
+ if (this.Caption)
+ this.button.caption = this.Caption;
+ }
+
+ setControlTooltip(tooltip)
+ {
+ this.button.tooltip = tooltip;
+ }
+
+ setControlHidden(hidden)
+ {
+ this.button.hidden = hidden;
+ }
+}
Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/GameSettingControlButton.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/GameSettingControlButton.xml
@@ -0,0 +1,13 @@
+
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/GameSettingsLayout.js
===================================================================
--- binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/GameSettingsLayout.js
+++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/GameSettingsLayout.js
@@ -9,6 +9,7 @@
"MapType",
"MapFilter",
"MapSelection",
+ "MapBrowser",
"MapSize",
"TeamPlacement",
"Landscape",
Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/Single/Buttons/MapBrowser.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSettings/Single/Buttons/MapBrowser.js
@@ -0,0 +1,31 @@
+GameSettingControls.MapBrowser = class extends GameSettingControlButton
+{
+ constructor(...args)
+ {
+ super(...args);
+
+ this.button.tooltip = colorizeHotkey(this.HotkeyTooltip, this.HotkeyConfig);
+ Engine.SetGlobalHotkey(this.HotkeyConfig, this.onPress.bind(this));
+ }
+
+ setControlHidden()
+ {
+ // This button is always visible
+ this.button.hidden = false;
+ }
+
+ onPress()
+ {
+ // Defer access to the page until after the constructor
+ this.setupWindow.pages.MapBrowserPage.openPage();
+ }
+};
+
+GameSettingControls.MapBrowser.prototype.HotkeyConfig =
+ "gamesetup.mapbrowser.open";
+
+GameSettingControls.MapBrowser.prototype.Caption =
+ translate("Browse Maps");
+
+GameSettingControls.MapBrowser.prototype.HotkeyTooltip =
+ translate("Press %(hotkey)s to view the list of available maps.");
Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSetupPage.xml
===================================================================
--- binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSetupPage.xml
+++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/GameSetupPage.xml
@@ -6,6 +6,7 @@
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/Chat/ChatInputPanel.js
===================================================================
--- binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/Chat/ChatInputPanel.js
+++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/Chat/ChatInputPanel.js
@@ -8,7 +8,9 @@
this.chatInput.tooltip = colorizeAutocompleteHotkey(this.Tooltip);
this.chatInput.onPress = this.onPress.bind(this);
this.chatInput.onTab = this.onTab.bind(this);
- this.chatInput.focus();
+
+ if (g_IsNetworked)
+ this.chatInput.focus();
this.chatSubmitButton = Engine.GetGUIObjectByName("chatSubmitButton");
this.chatSubmitButton.onPress = this.onPress.bind(this);
Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/GameSettingsPanel.xml
===================================================================
--- binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/GameSettingsPanel.xml
+++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/GameSettingsPanel.xml
@@ -5,6 +5,12 @@
+
+
+
+
+
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/MapPreview.js
===================================================================
--- binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/MapPreview.js
+++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/MapPreview.js
@@ -2,16 +2,25 @@
{
constructor(setupWindow)
{
+ this.setupWindow = setupWindow;
this.gameSettingsControl = setupWindow.controls.gameSettingsControl;
this.mapCache = setupWindow.controls.mapCache;
this.mapInfoName = Engine.GetGUIObjectByName("mapInfoName");
this.mapPreview = Engine.GetGUIObjectByName("mapPreview");
+ this.mapPreview.onMouseLeftPress = this.onPress.bind(this); // TODO: Why does onPress not work? CGUI.cpp seems to support it
+ this.mapPreview.tooltip = this.Tooltip;
this.gameSettingsControl.registerMapChangeHandler(this.onMapChange.bind(this));
this.gameSettingsControl.registerGameAttributesBatchChangeHandler(this.onGameAttributesBatchChange.bind(this));
}
+ onPress()
+ {
+ // Defer access to the page until after the constructor
+ this.setupWindow.pages.MapBrowserPage.openPage();
+ }
+
onMapChange(mapData)
{
let preview = mapData && mapData.settings && mapData.settings.Preview;
@@ -34,3 +43,6 @@
this.mapCache.getMapPreview(g_GameAttributes.mapType, g_GameAttributes.map, g_GameAttributes);
}
}
+
+MapPreview.prototype.Tooltip =
+ translate("Click to view the list of available maps.");
Index: binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/MapPreview.xml
===================================================================
--- binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/MapPreview.xml
+++ binaries/data/mods/public/gui/gamesetup/Pages/GameSetupPage/Panels/MapPreview.xml
@@ -1,7 +1,7 @@
-
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/CloseButton.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/CloseButton.js
@@ -0,0 +1,17 @@
+MapBrowserPageControls.CloseButton = class
+{
+ constructor(mapBrowserPage)
+ {
+ this.mapBrowserPageClose = Engine.GetGUIObjectByName("mapBrowserPageClose");
+ this.mapBrowserPageClose.tooltip = colorizeHotkey(this.Tooltip, this.HotkeyConfig);
+ this.mapBrowserPageClose.onPress = mapBrowserPage.closePage.bind(mapBrowserPage, false);
+
+ if (!g_IsController)
+ this.mapBrowserPageClose.size = Engine.GetGUIObjectByName("mapBrowserPageSelect").size;
+ }
+};
+
+MapBrowserPageControls.CloseButton.prototype.HotkeyConfig = "cancel";
+
+MapBrowserPageControls.CloseButton.prototype.Tooltip =
+ translate("%(hotkey)s: Close map browser and discard the selection.");
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/CloseButton.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/CloseButton.xml
@@ -0,0 +1,4 @@
+
+
+ Cancel
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapBrowserFilter.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapBrowserFilter.js
@@ -0,0 +1,18 @@
+class MapBrowserFilter
+{
+ resizeLabel()
+ {
+ let labelWidth = Engine.GetTextWidth(this.label.font, this.label.caption) + 15;
+
+ {
+ let size = this.label.size
+ size.right = labelWidth;
+ this.label.size = size;
+ }
+ {
+ let size = this.control.size;
+ size.left = labelWidth;
+ this.control.size = size;
+ }
+ }
+}
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapDescription.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapDescription.js
@@ -0,0 +1,49 @@
+MapBrowserPageControls.MapDescription = class
+{
+ constructor(mapBrowserPage, gridBrowser, setupWindow)
+ {
+ this.mapBrowserPage = mapBrowserPage;
+ this.gridBrowser = gridBrowser;
+ this.mapCache = setupWindow.controls.mapCache;
+
+ this.mapBrowserSelectedName = Engine.GetGUIObjectByName("mapBrowserSelectedName");
+ this.mapBrowserSelectedPreview = Engine.GetGUIObjectByName("mapBrowserSelectedPreview");
+ this.mapBrowserSelectedDescription = Engine.GetGUIObjectByName("mapBrowserSelectedDescription");
+
+ let computedSize = this.mapBrowserSelectedPreview.getComputedSize();
+ let top = this.mapBrowserSelectedName.size.bottom;
+ let height = Math.floor((computedSize.right - computedSize.left) / this.ImageRatio);
+
+ {
+ let size = this.mapBrowserSelectedPreview.size;
+ size.top = top;
+ size.bottom = top + height;
+ this.mapBrowserSelectedPreview.size = size;
+ }
+
+ {
+ let size = this.mapBrowserSelectedDescription.size;
+ size.top = top + height + 10;
+ this.mapBrowserSelectedDescription.size = size;
+ }
+
+ gridBrowser.registerSelectionChangeHandler(this.onSelectionChange.bind(this));
+ }
+
+ onSelectionChange()
+ {
+ let map = this.gridBrowser.mapList[this.gridBrowser.selected] || undefined;
+
+ this.mapBrowserSelectedName.caption = map ? map.name : "";
+ this.mapBrowserSelectedDescription.caption = map ? map.description : "";
+
+ this.mapBrowserSelectedPreview.sprite =
+ map ?
+ this.mapCache.getMapPreview(
+ this.mapBrowserPage.controls.MapType.getSelected(),
+ map.file) :
+ this.mapCache.getMapPreview();
+ }
+};
+
+MapBrowserPageControls.MapDescription.prototype.ImageRatio = 4/3;
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapDescription.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapDescription.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapFilter.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapFilter.js
@@ -0,0 +1,54 @@
+MapBrowserPageControls.MapFilter = class extends MapBrowserFilter
+{
+ constructor(mapBrowserPage, gridBrowser, setupPage)
+ {
+ super();
+
+ this.mapBrowserPage = mapBrowserPage;
+ this.gridBrowser = gridBrowser;
+ this.mapFilters = mapBrowserPage.setupWindow.controls.mapFilters;
+
+ this.control = Engine.GetGUIObjectByName("mapBrowserMapFilterDropdown");
+ this.control.onSelectionChange = this.onSelectionChange.bind(this);
+
+ this.label = Engine.GetGUIObjectByName("mapBrowserMapFilterLabel");
+ this.resizeLabel();
+
+ mapBrowserPage.registerOpenPageHandler(this.onOpenPage.bind(this));
+ }
+
+ onOpenPage()
+ {
+ this.updateMapFilter(g_GameAttributes.mapFilter);
+ }
+
+ onMapTypeUpdate()
+ {
+ this.updateMapFilter(this.getSelected());
+ this.gridBrowser.updateMapList();
+ this.gridBrowser.goToPage(0);
+ }
+
+ onSelectionChange()
+ {
+ this.gridBrowser.updateMapList();
+ this.gridBrowser.goToPage(0);
+ }
+
+ updateMapFilter(selectedMapFilter)
+ {
+ let filters = this.mapFilters.getAvailableMapFilters(
+ this.mapBrowserPage.controls.MapType.getSelected());
+
+ this.control.list = filters.map(filter => filter.Title);
+ this.control.list_data = filters.map(filter => filter.Name);
+
+ this.control.selected =
+ this.control.list_data.indexOf(selectedMapFilter);
+ }
+
+ getSelected()
+ {
+ return this.control.list_data[this.control.selected] || g_GameAttributes.mapFilter;
+ }
+};
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapFilter.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapFilter.xml
@@ -0,0 +1,7 @@
+
+
+
+ Map Filter:
+
+
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapGridBrowser.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapGridBrowser.js
@@ -0,0 +1,93 @@
+MapBrowserPageControls.MapGridBrowser = class extends GridBrowser
+{
+ constructor(mapBrowserPage, setupWindow)
+ {
+ super(Engine.GetGUIObjectByName("mapBrowserContainer"));
+
+ this.setupWindow = setupWindow;
+ this.mapBrowserPage = mapBrowserPage;
+ this.mapCache = setupWindow.controls.mapCache;
+ this.mapFilters = setupWindow.controls.mapFilters;
+
+ this.mapList = [];
+
+ this.items = this.container.children.map((imageObject, itemIndex) =>
+ new MapGridBrowserItem(mapBrowserPage, this, imageObject, itemIndex));
+
+ this.container.tooltip =
+ colorizeHotkey(this.TooltipPrevious, this.HotkeyConfigPrevious) + "\n" +
+ colorizeHotkey(this.TooltipNext, this.HotkeyConfigNext);
+
+ this.mapBrowserPage.registerOpenPageHandler(this.onOpenPage.bind(this));
+ this.mapBrowserPage.registerClosePageHandler(this.onClosePage.bind(this));
+ }
+
+ onOpenPage()
+ {
+ this.updateMapList();
+ this.setSelectedIndex(this.mapList.findIndex(map => map.file == g_GameAttributes.map));
+ this.goToPageOfSelected();
+ this.container.onWindowResized = this.onWindowResized.bind(this);
+
+ Engine.SetGlobalHotkey(this.HotkeyConfigNext, this.nextPage.bind(this));
+ Engine.SetGlobalHotkey(this.HotkeyConfigPrevious, this.previousPage.bind(this));
+ }
+
+ onClosePage()
+ {
+ delete this.container.onWindowResized;
+ Engine.UnsetGlobalHotkey(this.HotkeyConfigNext);
+ Engine.UnsetGlobalHotkey(this.HotkeyConfigPrevious);
+ }
+
+ updateMapList()
+ {
+ let selectedMap =
+ this.mapList[this.selected] &&
+ this.mapList[this.selected].file || undefined;
+
+ let mapList = this.mapFilters.getFilteredMaps(
+ this.mapBrowserPage.controls.MapType.getSelected(),
+ this.mapBrowserPage.controls.MapFilter.getSelected());
+
+ let filterText = this.mapBrowserPage.controls.SearchBox.getFilterText();
+ if (filterText)
+ mapList = MatchSort.get(filterText, mapList, "name");
+
+ this.mapList = mapList;
+ this.itemCount = this.mapList.length;
+ this.resizeGrid();
+
+ this.setSelectedIndex(this.mapList.findIndex(map => map.file == selectedMap));
+ }
+
+ submitMapSelection()
+ {
+ let map = this.mapList[this.selected] || undefined;
+ if (!map)
+ return;
+
+ g_GameAttributes.mapType = this.mapBrowserPage.controls.MapType.getSelected();
+ g_GameAttributes.mapFilter = this.mapBrowserPage.controls.MapFilter.getSelected();
+ g_GameAttributes.map = map.file;
+ this.setupWindow.controls.gameSettingsControl.updateGameAttributes();
+ }
+};
+
+MapBrowserPageControls.MapGridBrowser.prototype.ItemRatio = 4/3;
+
+MapBrowserPageControls.MapGridBrowser.prototype.DefaultItemWidth = 250;
+
+MapBrowserPageControls.MapGridBrowser.prototype.MinItemWidth = 100;
+
+MapBrowserPageControls.MapGridBrowser.prototype.HotkeyConfigNext =
+ "tab.next";
+
+MapBrowserPageControls.MapGridBrowser.prototype.HotkeyConfigPrevious =
+ "tab.prev";
+
+MapBrowserPageControls.MapGridBrowser.prototype.TooltipNext =
+ translate("%(hotkey)s: Go to the next page.");
+
+MapBrowserPageControls.MapGridBrowser.prototype.TooltipPrevious =
+ translate("%(hotkey)s: Go to the previous page.");
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapGridBrowser.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapGridBrowser.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapGridBrowserItem.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapGridBrowserItem.js
@@ -0,0 +1,64 @@
+class MapGridBrowserItem extends GridBrowserItem
+{
+ constructor(mapBrowserPage, mapGridBrowser, imageObject, itemIndex)
+ {
+ super(mapGridBrowser, imageObject, itemIndex);
+
+ this.mapBrowserPage = mapBrowserPage;
+ this.mapCache = mapBrowserPage.setupWindow.controls.mapCache;
+
+ this.mapPreview = Engine.GetGUIObjectByName("mapPreview[" + itemIndex + "]");
+
+ mapGridBrowser.registerSelectionChangeHandler(this.onSelectionChange.bind(this));
+ mapGridBrowser.registerPageChangeHandler(this.onGridResize.bind(this));
+
+ if (g_IsController)
+ this.imageObject.onMouseLeftDoubleClick = this.onMouseLeftDoubleClick.bind(this);
+ }
+
+ onSelectionChange()
+ {
+ this.updateSprite();
+ }
+
+ onGridResize()
+ {
+ super.onGridResize();
+ this.updateMapAssignment();
+ this.updateSprite();
+ }
+
+ updateSprite()
+ {
+ this.imageObject.sprite =
+ this.gridBrowser.selected == this.itemIndex + this.gridBrowser.currentPage * this.gridBrowser.itemsPerPage ?
+ this.SelectedSprite :
+ "";
+ }
+
+ updateMapAssignment()
+ {
+ let map = this.gridBrowser.mapList[
+ this.itemIndex + this.gridBrowser.currentPage * this.gridBrowser.itemsPerPage] || undefined;
+
+ if (!map)
+ return;
+
+ this.mapPreview.caption = map.name;
+
+ this.imageObject.tooltip =
+ map.description + "\n" +
+ this.gridBrowser.container.tooltip;
+
+ this.mapPreview.sprite =
+ this.mapCache.getMapPreview(this.mapBrowserPage.controls.MapType.getSelected(), map.file);
+ }
+
+ onMouseLeftDoubleClick()
+ {
+ this.gridBrowser.submitMapSelection();
+ this.mapBrowserPage.closePage();
+ }
+}
+
+MapGridBrowserItem.prototype.SelectedSprite = "color: 120 0 0 255";
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapType.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapType.js
@@ -0,0 +1,35 @@
+MapBrowserPageControls.MapType = class extends MapBrowserFilter
+{
+ constructor(mapBrowserPage, gridBrowser)
+ {
+ super();
+
+ this.mapBrowserPage = mapBrowserPage;
+ this.gridBrowser = gridBrowser;
+
+ this.control = Engine.GetGUIObjectByName("mapBrowserMapTypeDropdown");
+ this.control.onSelectionChange = this.onSelectionChange.bind(this);
+ this.control.list = g_MapTypes.Title;
+ this.control.list_data = g_MapTypes.Name;
+
+ this.label = Engine.GetGUIObjectByName("mapBrowserMapTypeLabel");
+ this.resizeLabel();
+
+ mapBrowserPage.registerOpenPageHandler(this.onOpenPage.bind(this));
+ }
+
+ onOpenPage()
+ {
+ this.control.selected = this.control.list_data.indexOf(g_GameAttributes.mapType);
+ }
+
+ getSelected()
+ {
+ return this.control.list_data[this.control.selected] || g_GameAttributes.mapType;
+ }
+
+ onSelectionChange()
+ {
+ this.mapBrowserPage.controls.MapFilter.onMapTypeUpdate();
+ }
+};
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapType.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/MapType.xml
@@ -0,0 +1,7 @@
+
+
+
+ Map Type:
+
+
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/NextButton.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/NextButton.js
@@ -0,0 +1,18 @@
+MapBrowserPageControls.NextButton = class
+{
+ constructor(mapBrowserPage, gridBrowser)
+ {
+ this.gridBrowser = gridBrowser;
+
+ this.mapBrowserNextButton = Engine.GetGUIObjectByName("mapBrowserNextButton");
+ this.mapBrowserNextButton.onPress = this.gridBrowser.nextPage.bind(this.gridBrowser);
+
+ gridBrowser.registerPageChangeHandler(this.updateEnabled.bind(this));
+ gridBrowser.registerGridResizeHandler(this.updateEnabled.bind(this));
+ }
+
+ updateEnabled()
+ {
+ this.mapBrowserNextButton.enabled = this.gridBrowser.currentPage + 1 < this.gridBrowser.pageCount;
+ }
+};
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/NextButton.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/NextButton.xml
@@ -0,0 +1,4 @@
+
+
+ Next
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/PageCounter.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/PageCounter.js
@@ -0,0 +1,30 @@
+MapBrowserPageControls.PageCounter = class
+{
+ constructor(mapBrowserPage, gridBrowser)
+ {
+ this.mapBrowserPageCounter = Engine.GetGUIObjectByName("mapBrowserPageStatus");
+
+ this.gridBrowser = gridBrowser;
+ this.gridBrowser.registerPageChangeHandler(this.update.bind(this));
+ this.gridBrowser.registerGridResizeHandler(this.update.bind(this));
+ }
+
+ update()
+ {
+ this.mapBrowserPageCounter.caption =
+ sprintf(this.ItemCountCaption, {
+ "mapCount": this.gridBrowser.itemCount
+ }) +
+ " " +
+ sprintf(this.PageCaption, {
+ "currentPage": this.gridBrowser.currentPage + 1,
+ "maxPage": Math.max(1, this.gridBrowser.pageCount)
+ });
+ }
+};
+
+MapBrowserPageControls.PageCounter.prototype.ItemCountCaption =
+ translate("Maps: %(mapCount)s")
+
+MapBrowserPageControls.PageCounter.prototype.PageCaption =
+ translate("Page: %(currentPage)s/%(maxPage)s");
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/PageCounter.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/PageCounter.xml
@@ -0,0 +1,2 @@
+
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/PreviousButton.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/PreviousButton.js
@@ -0,0 +1,18 @@
+MapBrowserPageControls.PreviousButton = class
+{
+ constructor(mapBrowserPage, gridBrowser)
+ {
+ this.gridBrowser = gridBrowser;
+
+ this.mapBrowserPreviousButton = Engine.GetGUIObjectByName("mapBrowserPreviousButton");
+ this.mapBrowserPreviousButton.onPress = this.gridBrowser.previousPage.bind(this.gridBrowser);
+
+ gridBrowser.registerPageChangeHandler(this.updateEnabled.bind(this));
+ gridBrowser.registerGridResizeHandler(this.updateEnabled.bind(this));
+ }
+
+ updateEnabled()
+ {
+ this.mapBrowserPreviousButton.enabled = this.gridBrowser.currentPage > 0;
+ }
+};
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/PreviousButton.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/PreviousButton.xml
@@ -0,0 +1,4 @@
+
+
+ Previous
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/SearchBox.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/SearchBox.js
@@ -0,0 +1,44 @@
+MapBrowserPageControls.SearchBox = class extends MapBrowserFilter
+{
+ constructor(mapBrowserPage, gridBrowser, setupWindow)
+ {
+ super();
+
+ this.mapBrowserPage = mapBrowserPage;
+ this.gridBrowser = gridBrowser;
+ this.mapCache = setupWindow.controls.mapCache;
+
+ this.control = Engine.GetGUIObjectByName("mapsSearchBox");
+ this.control.onTab = this.gridBrowser.nextPage.bind(this.gridBrowser);
+ this.control.onPress = this.onPress.bind(this);
+ this.control.onTextEdit = this.onTextEdit.bind(this);
+
+ this.label = Engine.GetGUIObjectByName("mapsSearchBoxLabel");
+ this.resizeLabel();
+
+ mapBrowserPage.registerOpenPageHandler(this.onOpenPage.bind(this));
+ }
+
+ onOpenPage()
+ {
+ this.control.focus();
+ }
+
+ onTextEdit()
+ {
+ this.gridBrowser.updateMapList();
+ this.gridBrowser.goToPage(0);
+ }
+
+ onPress()
+ {
+ this.gridBrowser.setSelectedIndex(0);
+ this.gridBrowser.submitMapSelection();
+ this.mapBrowserPage.closePage();
+ }
+
+ getFilterText()
+ {
+ return this.control.caption.trim();
+ }
+};
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/SearchBox.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/SearchBox.xml
@@ -0,0 +1,7 @@
+
+
+
+ Search Map:
+
+
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/SelectButton.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/SelectButton.js
@@ -0,0 +1,25 @@
+MapBrowserPageControls.SelectButton = class
+{
+ constructor(mapBrowserPage, gridBrowser)
+ {
+ this.mapBrowserPage = mapBrowserPage;
+ this.gridBrowser = gridBrowser;
+
+ this.mapBrowserPageSelect = Engine.GetGUIObjectByName("mapBrowserPageSelect");
+ this.mapBrowserPageSelect.onPress = this.onPress.bind(this);
+ this.mapBrowserPageSelect.hidden = !g_IsController;
+
+ gridBrowser.registerSelectionChangeHandler(this.onSelectionChange.bind(this));
+ }
+
+ onSelectionChange()
+ {
+ this.mapBrowserPageSelect.enabled = this.gridBrowser.selected != -1;
+ }
+
+ onPress()
+ {
+ this.gridBrowser.submitMapSelection();
+ this.mapBrowserPage.closePage();
+ }
+};
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/SelectButton.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/SelectButton.xml
@@ -0,0 +1,4 @@
+
+
+ Select
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/ZoomInButton.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/ZoomInButton.js
@@ -0,0 +1,20 @@
+MapBrowserPageControls.ZoomInButton = class
+{
+ constructor(mapBrowserPage, gridBrowser)
+ {
+ this.gridBrowser = gridBrowser;
+
+ this.mapsZoonIn = Engine.GetGUIObjectByName("mapsZoomIn");
+ this.mapsZoonIn.tooltip = this.Tooltip;
+ this.mapsZoonIn.onPress = gridBrowser.increaseColumnCount.bind(gridBrowser, -1);
+ gridBrowser.registerGridResizeHandler(this.onGridResize.bind(this));
+ }
+
+ onGridResize()
+ {
+ this.mapsZoonIn.enabled = this.gridBrowser.minColumns < this.gridBrowser.columnCount;
+ }
+};
+
+MapBrowserPageControls.ZoomInButton.prototype.Tooltip =
+ translate("Increase map preview size.");
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/ZoomInButton.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/ZoomInButton.xml
@@ -0,0 +1,4 @@
+
+
+ +
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/ZoomOutButton.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/ZoomOutButton.js
@@ -0,0 +1,20 @@
+MapBrowserPageControls.ZoomOutButton = class
+{
+ constructor(mapBrowserPage, gridBrowser)
+ {
+ this.gridBrowser = gridBrowser;
+
+ this.mapsZoomOut = Engine.GetGUIObjectByName("mapsZoomOut");
+ this.mapsZoomOut.tooltip = this.Tooltip;
+ this.mapsZoomOut.onPress = gridBrowser.increaseColumnCount.bind(gridBrowser, 1);
+ gridBrowser.registerGridResizeHandler(this.onGridResize.bind(this));
+ }
+
+ onGridResize()
+ {
+ this.mapsZoomOut.enabled = this.gridBrowser.columnCount < this.gridBrowser.maxColumns;
+ }
+};
+
+MapBrowserPageControls.ZoomOutButton.prototype.Tooltip =
+ translate("Decrease map preview size.");
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/ZoomOutButton.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/Controls/ZoomOutButton.xml
@@ -0,0 +1,4 @@
+
+
+ −
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/GridBrowser.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/GridBrowser.js
@@ -0,0 +1,127 @@
+/**
+ * Class that arranges a grid of items using paging
+ *
+ * Needs an object as container with itemss and a object to display the page numbering (if not
+ * make hidden object and assign it to it).
+ */
+class GridBrowser
+{
+ constructor(container)
+ {
+ this.container = container;
+
+ // These properties may be read from publicly
+ this.pageCount = undefined;
+ this.currentPage = undefined;
+ this.columnCount = undefined;
+ this.minColumns = undefined;
+ this.maxColumns = undefined;
+ this.rowCount = undefined;
+ this.itemCount = undefined;
+ this.itemsPerPage = undefined;
+ this.selected = undefined;
+
+ this.gridResizeHandlers = new Set();
+ this.pageChangeHandlers = new Set();
+ this.selectionChangeHandlers = new Set();
+ }
+
+ registerGridResizeHandler(handler)
+ {
+ this.gridResizeHandlers.add(handler);
+ }
+
+ registerPageChangeHandler(handler)
+ {
+ this.pageChangeHandlers.add(handler);
+ }
+
+ registerSelectionChangeHandler(handler)
+ {
+ this.selectionChangeHandlers.add(handler);
+ }
+
+ // Inheriting classes must subscribe this event
+ onWindowResized()
+ {
+ this.resizeGrid();
+ this.goToPageOfSelected();
+ }
+
+ setSelectedIndex(index)
+ {
+ this.selected = index;
+
+ for (let handler of this.selectionChangeHandlers)
+ handler();
+ }
+
+ goToPage(pageNumber)
+ {
+ if (!Number.isInteger(pageNumber))
+ throw new Error("Given argument is not a number");
+
+ this.currentPage = pageNumber;
+
+ for (let handler of this.pageChangeHandlers)
+ handler();
+ }
+
+ nextPage()
+ {
+ this.goToPage(Math.min(this.currentPage + 1, this.pageCount - 1));
+ }
+
+ previousPage()
+ {
+ this.goToPage(Math.max(this.currentPage - 1, 0));
+ }
+
+ goToPageOfSelected()
+ {
+ this.goToPage(Math.floor(this.selected / this.itemsPerPage));
+ }
+
+ increaseColumnCount(diff)
+ {
+ let isSelectedInPage =
+ this.selected !== undefined &&
+ Math.floor(this.selected / this.itemsPerPage) == this.currentPage;
+
+ this.columnCount += diff;
+ this.resizeGrid();
+
+ if (isSelectedInPage)
+ this.goToPageOfSelected();
+ else
+ this.goToPage(Math.min(this.currentPage, this.pageCount - 1));
+ }
+
+ resizeGrid()
+ {
+ let size = this.container.getComputedSize();
+ let width = size.right - size.left;
+ let height = size.bottom - size.top;
+
+ if (this.columnCount === undefined)
+ this.columnCount = Math.floor(width / this.DefaultItemWidth);
+
+ this.minColumns = Math.ceil(width / (height * this.ItemRatio));
+ this.maxColumns = Math.floor(width / this.MinItemWidth);
+
+ if (this.maxColumns <= 0)
+ throw new Error("MapGridBrowser area too small");
+
+ this.columnCount = Math.min(this.maxColumns, Math.max(this.minColumns, this.columnCount));
+
+ this.itemWidth = Math.floor(width / this.columnCount);
+ this.itemHeight = Math.floor(this.itemWidth / this.ItemRatio);
+
+ this.rowCount = Math.floor((size.bottom - size.top) / this.itemHeight);
+ this.itemsPerPage = Math.min(this.columnCount * this.rowCount, this.items.length);
+ this.pageCount = Math.ceil(this.itemCount / this.itemsPerPage);
+
+ for (let handler of this.gridResizeHandlers)
+ handler();
+ }
+}
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/GridBrowserItem.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/GridBrowserItem.js
@@ -0,0 +1,44 @@
+class GridBrowserItem
+{
+ constructor(gridBrowser, imageObject, itemIndex)
+ {
+ this.gridBrowser = gridBrowser;
+ this.itemIndex = itemIndex;
+ this.imageObject = imageObject;
+
+ imageObject.onMouseLeftPress = this.select.bind(this);
+ imageObject.onMouseWheelUp = gridBrowser.nextPage.bind(gridBrowser);
+ imageObject.onMouseWheelDown = gridBrowser.previousPage.bind(gridBrowser)
+
+ gridBrowser.registerGridResizeHandler(this.onGridResize.bind(this));
+ gridBrowser.registerPageChangeHandler(this.updateVisibility.bind(this));
+ }
+
+ updateVisibility()
+ {
+ this.imageObject.hidden =
+ this.itemIndex >= Math.min(
+ this.gridBrowser.itemsPerPage,
+ this.gridBrowser.itemCount - this.gridBrowser.currentPage * this.gridBrowser.itemsPerPage);
+ }
+
+ onGridResize()
+ {
+ let gridBrowser = this.gridBrowser;
+ let x = this.itemIndex % gridBrowser.columnCount;
+ let y = Math.floor(this.itemIndex / gridBrowser.columnCount);
+ let size = this.imageObject.size;
+ size.left = gridBrowser.itemWidth * x;
+ size.right = gridBrowser.itemWidth * (x + 1);
+ size.top = gridBrowser.itemHeight * y;
+ size.bottom = gridBrowser.itemHeight * (y + 1);
+ this.imageObject.size = size;
+ this.updateVisibility();
+ }
+
+ select()
+ {
+ this.gridBrowser.setSelectedIndex(
+ this.itemIndex + this.gridBrowser.currentPage * this.gridBrowser.itemsPerPage);
+ }
+}
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/MapBrowserPage.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/MapBrowserPage.js
@@ -0,0 +1,57 @@
+/**
+ * This class stores the MapBrowserPage controls.
+ */
+class MapBrowserPageControls
+{
+}
+
+/**
+ * This class contains all controls modifying the map settings.
+ */
+SetupWindowPages.MapBrowserPage = class
+{
+ constructor(setupWindow)
+ {
+ this.setupWindow = setupWindow;
+
+ this.openPageHandlers = new Set();
+ this.closePageHandlers = new Set();
+
+ this.mapBrowserPage = Engine.GetGUIObjectByName("mapBrowserPage");
+
+ this.controls = {
+ "MapGridBrowser": new MapBrowserPageControls.MapGridBrowser(this, setupWindow)
+ };
+
+ for (let name in MapBrowserPageControls)
+ if (!this.controls[name])
+ this.controls[name] = new MapBrowserPageControls[name](
+ this, this.controls.MapGridBrowser, setupWindow);
+ }
+
+ registerOpenPageHandler(handler)
+ {
+ this.openPageHandlers.add(handler);
+ }
+
+ registerClosePageHandler(handler)
+ {
+ this.closePageHandlers.add(handler);
+ }
+
+ openPage()
+ {
+ for (let handler of this.openPageHandlers)
+ handler();
+
+ this.mapBrowserPage.hidden = false;
+ }
+
+ closePage()
+ {
+ for (let handler of this.closePageHandlers)
+ handler();
+
+ this.mapBrowserPage.hidden = true;
+ }
+};
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/MapBrowserPage.xml
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/MapBrowserPage.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+ Map Browser
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/MatchSort.js
===================================================================
--- /dev/null
+++ binaries/data/mods/public/gui/gamesetup/Pages/MapBrowserPage/MatchSort.js
@@ -0,0 +1,84 @@
+class MatchSort
+{
+}
+
+/**
+ * Returns a new list filtered and sorted by the similarity with the input text
+ * Order of sorting:
+ * 1. Exact match
+ * 2. Exact lowercase match
+ * 3. Starting letters match and sorted alphabetically
+ * 4. By similarity score (lookahead match)
+ * 5. Entry is discarded if one of the previous don't apply
+ *
+ * @param {string} input text to seach for
+ * @param {string[] | object[]} list
+ * @param {string} [key] text to use if the list is made up of objects
+ */
+MatchSort.get = function(input, list, key)
+{
+ input = input.toLowerCase();
+
+ let result = [];
+
+ for (let obj of list)
+ {
+ let text = key == null ? obj : obj[key];
+ let score = MatchSort.scoreText(input, text);
+ if (score !== undefined)
+ result.push([obj, score, text, text.startsWith(input)])
+ }
+
+ return result.sort(MatchSort.sort).map(v => v[0]);
+};
+
+MatchSort.sort = function([o1, s1, t1, a1], [o2, s2, t2, a2])
+{
+ if (a1 && a2)
+ return t1.localeCompare(t2);
+
+ if (a1)
+ return -1;
+
+ if (a2)
+ return 1;
+
+ return s1 - s2;
+};
+
+/**
+ * The lower the score the better the match.
+ */
+MatchSort.scoreText = function(input, text)
+{
+ // Exact match
+ if (input == text)
+ return MatchSort.Highscore;
+
+ text = text.toLowerCase();
+
+ // Exact match relaxed
+ if (input == text)
+ return MatchSort.Highscore / 2;
+
+ let score = 0;
+ let offset = -1;
+
+ for (let i = 0; i < input.length; ++i)
+ {
+ let offsetNext = text.indexOf(input[i], offset + 1);
+
+ // No match
+ if (offsetNext == -1)
+ return undefined;
+
+ // Lower score increase if consecutive index
+ let isConsecutive = offsetNext == offset + 1 ? 0 : 1;
+ score += offsetNext + isConsecutive * offsetNext;
+ offset = offsetNext;
+ }
+
+ return score;
+};
+
+MatchSort.Highscore = -10E7;
Index: binaries/data/mods/public/gui/gamesetup/gamesetup.xml
===================================================================
--- binaries/data/mods/public/gui/gamesetup/gamesetup.xml
+++ binaries/data/mods/public/gui/gamesetup/gamesetup.xml
@@ -15,6 +15,7 @@
+