Index: binaries/data/mods/public/gui/common/functions_utility_loadsave.js =================================================================== --- binaries/data/mods/public/gui/common/functions_utility_loadsave.js +++ binaries/data/mods/public/gui/common/functions_utility_loadsave.js @@ -40,30 +40,50 @@ function deleteGame() { let gameSelection = Engine.GetGUIObjectByName("gameSelection"); - let gameID = gameSelection.list_data[gameSelection.selected]; + let selected = gameSelection.selected; - if (!gameID) - return; + let toDelete = []; + let toDeleteNames = []; + + if (!gameSelection.multiSelected.length) + { + toDelete.push(gameSelection.list_data[selected]); + toDeleteNames.push(gameSelection.list[selected]); + } + else + { + for (let selected of gameSelection.multiSelected) + { + toDelete.push(gameSelection.list_data[selected]); + toDeleteNames.push(gameSelection.list[selected]); + } + } if (Engine.HotkeyIsPressed("session.savedgames.noconfirmation")) - reallyDeleteGame(gameID); + reallyDeleteGame(toDelete); else messageBox( 500, 200, sprintf(translate("\"%(label)s\""), { - "label": gameSelection.list[gameSelection.selected] - }) + "\n" + translate("Saved game will be permanently deleted, are you sure?"), + "label": toDeleteNames.join("\n") + }) + "\n" + translatePlural( + "Saved game will be permanently deleted, are you sure?", + "Saved games will be permanently deleted, are you sure?", + toDeleteNames.length + ), translate("DELETE"), [translate("No"), translate("Yes")], - [null, function(){ reallyDeleteGame(gameID); }] + [null, function(){ reallyDeleteGame(toDelete); }] ); } -function reallyDeleteGame(gameID) +function reallyDeleteGame(gameIDs) { - if (!Engine.DeleteSavedGame(gameID)) - error("Could not delete saved game: " + gameID); - + for (let gameID of gameIDs) + { + if (!Engine.DeleteSavedGame(gameID)) + error("Could not delete saved game: " + gameID); + } // Run init again to refresh saved game list init(); } Index: binaries/data/mods/public/gui/loadgame/load.js =================================================================== --- binaries/data/mods/public/gui/loadgame/load.js +++ binaries/data/mods/public/gui/loadgame/load.js @@ -89,9 +89,10 @@ gameSelection.selected = g_SavedGamesMetadata.length - 1; else if (gameSelection.selected == -1 && g_SavedGamesMetadata.length) gameSelection.selected = 0; - selectionChanged(); + gameSelection.multiSelected = []; Engine.GetGUIObjectByName("deleteGameButton").tooltip = deleteTooltip(); + selectionChanged(); } function selectionChanged() @@ -99,7 +100,7 @@ let metadata = g_SavedGamesMetadata[Engine.GetGUIObjectByName("gameSelection").selected]; Engine.GetGUIObjectByName("invalidGame").hidden = !!metadata; Engine.GetGUIObjectByName("validGame").hidden = !metadata; - Engine.GetGUIObjectByName("loadGameButton").enabled = !!metadata; + Engine.GetGUIObjectByName("loadGameButton").enabled = !!metadata && !Engine.GetGUIObjectByName("gameSelection").multiSelected.length; Engine.GetGUIObjectByName("deleteGameButton").enabled = !!metadata; if (!metadata) Index: binaries/data/mods/public/gui/loadgame/load.xml =================================================================== --- binaries/data/mods/public/gui/loadgame/load.xml +++ binaries/data/mods/public/gui/loadgame/load.xml @@ -23,6 +23,7 @@ size="24 4 100%-24 100%-70" type="olist" auto_scroll="true" + multiSelection_enabled="true" > selectionChanged(); init(); Index: binaries/data/mods/public/gui/replaymenu/replay_actions.js =================================================================== --- binaries/data/mods/public/gui/replaymenu/replay_actions.js +++ binaries/data/mods/public/gui/replaymenu/replay_actions.js @@ -155,19 +155,35 @@ function deleteReplay() { // Get selected replay - var selected = Engine.GetGUIObjectByName("replaySelection").selected; + let replaySelection = Engine.GetGUIObjectByName("replaySelection"); + let selected = replaySelection.selected; if (selected == -1) return; - - var replay = g_ReplaysFiltered[selected]; - + let directories = []; + let directoryNames = []; + if (!replaySelection.multiSelected.length) + { + directories.push(g_ReplaysFiltered[selected].directory); + directoryNames.push(Engine.GetReplayDirectoryName(g_ReplaysFiltered[selected].directory)); + } + else + { + for (selected of replaySelection.multiSelected) + { + directories.push(g_ReplaysFiltered[selected].directory); + directoryNames.push(Engine.GetReplayDirectoryName(g_ReplaysFiltered[selected].directory)); + } + } messageBox( 500, 200, - translate("Are you sure you want to delete this replay permanently?") + "\n" + - escapeText(Engine.GetReplayDirectoryName(replay.directory)), - translate("Delete replay"), + translatePlural("Are you sure you want to delete this replay permanently?", + "Are you sure you want to delete these replays permanently?", + directories.length + ) + "\n" + + escapeText(directoryNames.join("\n")), + translatePlural("Delete replay", "Delete replays", directories.length), [translate("No"), translate("Yes")], - [null, function() { reallyDeleteReplay(replay.directory); }] + [null, function() { reallyDeleteReplay(directories); }] ); } @@ -176,23 +192,36 @@ */ function deleteReplayWithoutConfirmation() { - var selected = Engine.GetGUIObjectByName("replaySelection").selected; - if (selected > -1) - reallyDeleteReplay(g_ReplaysFiltered[selected].directory); + let replaySelection = Engine.GetGUIObjectByName("replaySelection"); + let selected = replaySelection.selected; + if (selected == -1) + return; + let directories = []; + if (!replaySelection.multiSelected.length) + directories.push(g_ReplaysFiltered[selected].directory); + else + { + for (selected of replaySelection.multiSelected) + directories.push(g_ReplaysFiltered[selected].directory); + } + reallyDeleteReplay(directories); } /** * Attempts to delete the given replay directory from the disk. * - * @param replayDirectory {string} + * @param replayDirectories {string[]} */ -function reallyDeleteReplay(replayDirectory) +function reallyDeleteReplay(replayDirectories) { var replaySelection = Engine.GetGUIObjectByName("replaySelection"); var selectedIndex = replaySelection.selected; - if (!Engine.DeleteReplay(replayDirectory)) - error("Could not delete replay!"); + for (let replayDirectory of replayDirectories) + { + if (!Engine.DeleteReplay(replayDirectory)) + error("Could not delete replay!"); + } // Refresh replay list init(); Index: binaries/data/mods/public/gui/replaymenu/replay_menu.js =================================================================== --- binaries/data/mods/public/gui/replaymenu/replay_menu.js +++ binaries/data/mods/public/gui/replaymenu/replay_menu.js @@ -77,6 +77,10 @@ if (data && data.summarySelectedData) g_SummarySelectedData = data.summarySelectedData; + + let replaySelection = Engine.GetGUIObjectByName("replaySelection"); + if(replaySelection) + replaySelection.multiSelected = []; } /** @@ -251,16 +255,16 @@ function displayReplayDetails() { let selected = Engine.GetGUIObjectByName("replaySelection").selected; - let replaySelected = selected > -1; + let singleReplaySelected = selected > -1 && !Engine.GetGUIObjectByName("replaySelection").multiSelected.length; - Engine.GetGUIObjectByName("replayInfo").hidden = !replaySelected; - Engine.GetGUIObjectByName("replayInfoEmpty").hidden = replaySelected; - Engine.GetGUIObjectByName("startReplayButton").enabled = replaySelected; - Engine.GetGUIObjectByName("deleteReplayButton").enabled = replaySelected; - Engine.GetGUIObjectByName("replayFilename").hidden = !replaySelected; + Engine.GetGUIObjectByName("replayInfo").hidden = !singleReplaySelected; + Engine.GetGUIObjectByName("replayInfoEmpty").hidden = singleReplaySelected; + Engine.GetGUIObjectByName("startReplayButton").enabled = singleReplaySelected; + Engine.GetGUIObjectByName("deleteReplayButton").enabled = (selected > -1); + Engine.GetGUIObjectByName("replayFilename").hidden = !singleReplaySelected; Engine.GetGUIObjectByName("summaryButton").hidden = true; - if (!replaySelected) + if (!singleReplaySelected) return; let replay = g_ReplaysFiltered[selected]; Index: binaries/data/mods/public/gui/replaymenu/replay_menu.xml =================================================================== --- binaries/data/mods/public/gui/replaymenu/replay_menu.xml +++ binaries/data/mods/public/gui/replaymenu/replay_menu.xml @@ -58,6 +58,7 @@ selected_column_order="-1" font="sans-stroke-13" auto_scroll="true" + multiSelection_enabled="true" > displayReplayDetails(); Index: binaries/data/mods/public/gui/savegame/save.js =================================================================== --- binaries/data/mods/public/gui/savegame/save.js +++ binaries/data/mods/public/gui/savegame/save.js @@ -6,6 +6,7 @@ let gameSelection = Engine.GetGUIObjectByName("gameSelection"); let gameID = gameSelection.list_data[gameSelection.selected]; Engine.GetGUIObjectByName("deleteGameButton").enabled = !!gameID; + Engine.GetGUIObjectByName("saveGameButton").enabled = !gameSelection.multiSelected.length; if (!gameID) return; @@ -40,8 +41,9 @@ gameSelection.list = savedGames.map(game => generateSavegameLabel(game.metadata, engineInfo)); gameSelection.list_data = savedGames.map(game => game.id); gameSelection.selected = Math.min(gameSelection.selected, gameSelection.list.length - 1); - + gameSelection.multiSelected = []; Engine.GetGUIObjectByName("deleteGameButton").tooltip = deleteTooltip(); + selectDescription(); } function saveGame() Index: binaries/data/mods/public/gui/savegame/save.xml =================================================================== --- binaries/data/mods/public/gui/savegame/save.xml +++ binaries/data/mods/public/gui/savegame/save.xml @@ -17,7 +17,7 @@ selectDescription(); @@ -42,7 +42,7 @@ deleteGame(); - + Save saveGame(); Index: source/gui/CGUIList.h =================================================================== --- source/gui/CGUIList.h +++ source/gui/CGUIList.h @@ -15,7 +15,6 @@ * along with 0 A.D. If not, see . */ - #ifndef INCLUDED_CGUILIST #define INCLUDED_CGUILIST Index: source/gui/CGUISeries.h =================================================================== --- source/gui/CGUISeries.h +++ source/gui/CGUISeries.h @@ -15,7 +15,6 @@ * along with 0 A.D. If not, see . */ - #ifndef INCLUDED_CGUISERIES #define INCLUDED_CGUISERIES Index: source/gui/CIntList.h =================================================================== --- /dev/null +++ source/gui/CIntList.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2018 Wildfire Games. +* This file is part of 0 A.D. +* +* 0 A.D. is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License, or +* (at your option) any later version. +* +* 0 A.D. is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with 0 A.D. If not, see . +*/ + +#ifndef INCLUDED_CINTLIST +#define INCLUDED_CINTLIST + +#include + +class CIntList +{ +public: + /** + * List of items (as int) + */ + std::vector m_Items; +}; + +#endif Index: source/gui/CList.h =================================================================== --- source/gui/CList.h +++ source/gui/CList.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -19,9 +19,10 @@ #define INCLUDED_CLIST #include "IGUIScrollBar.h" +#include "CIntList.h" /** - * Create a list of elements, where one can be selected + * Create a list of elements, where multiple can be selected * by the user. The control will use a pre-processed * text-object for each element, which will be managed * by the IGUITextOwner structure. @@ -76,7 +77,6 @@ virtual void SelectPrevElement(); virtual void SelectFirstElement(); virtual void SelectLastElement(); - /** * Handle the \ tag. */ @@ -85,6 +85,11 @@ // Called every time the auto-scrolling should be checked. void UpdateAutoScroll(); + /** + * Draw selection on item + */ + virtual void DrawSelection(const int selected, const bool scrollbar, const float scroll, CGUISpriteInstance& sprite_selectarea, const int cell_id, const float bz, CRect& rect); + // Extended drawing interface, this is so that classes built on the this one // can use other sprite names. virtual void DrawList(const int& selected, const CStr& _sprite, const CStr& _sprite_selected, const CStr& _textcolor); @@ -107,6 +112,7 @@ virtual int GetHoveredItem(); + std::vector m_SelectedItems; private: // Whether the list's items have been modified since last handling a message. bool m_Modified; @@ -116,6 +122,21 @@ // Last time a click on an item was issued double m_LastItemClickTime; + + // Select items between last two clicks + bool m_IsMultiSelecting; + + // Add/Remove one item to/from selection + bool m_AddMultiSelection; + + // Used for multiselection + int m_MultiSelectionFromItem; + + /** + * Control multiselection + * If two items remain in multiselection and one is removed, select is changed to the not removed one + */ + void MultiSelectionControl(int& select); }; #endif // INCLUDED_CLIST Index: source/gui/CList.cpp =================================================================== --- source/gui/CList.cpp +++ source/gui/CList.cpp @@ -23,12 +23,13 @@ #include "lib/external_libraries/libsdl.h" #include "ps/CLogger.h" +#include "ps/Globals.h" #include "ps/Profile.h" #include "soundmanager/ISoundManager.h" CList::CList() - : m_Modified(false), m_PrevSelectedItem(-1), m_LastItemClickTime(0) + : m_Modified(false), m_PrevSelectedItem(-1), m_LastItemClickTime(0), m_AddMultiSelection(false), m_IsMultiSelecting(false) { // Add sprite_disabled! TODO @@ -45,6 +46,8 @@ AddSetting(GUIST_CColor, "textcolor"); AddSetting(GUIST_CColor, "textcolor_selected"); AddSetting(GUIST_int, "selected"); // Index selected. -1 is none. + AddSetting(GUIST_CIntList, "multiSelected"); + AddSetting(GUIST_bool, "multiSelection_enabled"); AddSetting(GUIST_bool, "auto_scroll"); AddSetting(GUIST_int, "hovered"); AddSetting(GUIST_CStrW, "tooltip"); @@ -146,6 +149,90 @@ } } +void CList::MultiSelectionControl(int& select) +{ + m_IsMultiSelecting = g_keys[SDLK_LSHIFT] || g_keys[SDLK_RSHIFT]; + m_AddMultiSelection = g_keys[SDLK_LCTRL] || g_keys[SDLK_RCTRL]; + + // add current item to selection + if (m_AddMultiSelection) + { + CIntList sel; + GUI::GetSetting(this, "multiSelected", sel); + m_MultiSelectionFromItem = select; + m_SelectedItems = sel.m_Items; + bool add = true; + size_t pos = -1; + for (size_t it = 0; it < m_SelectedItems.size(); ++it) + if (m_SelectedItems.at(it) == select) + { + add = false; + pos = it; + break; + } + if (add) + { + if (m_SelectedItems.empty()) + { + // avoid one item in multiselection + if (m_PrevSelectedItem == select) + return; + m_SelectedItems.push_back(m_PrevSelectedItem); + } + m_SelectedItems.push_back(select); + } + else + { + m_SelectedItems.erase(m_SelectedItems.begin() + pos); + // avoid one item in multiselection + if (m_SelectedItems.size() == 1) + { + // select last item in multiselection + select = m_SelectedItems.at(0); + m_SelectedItems.clear(); + } + } + + sel.m_Items = m_SelectedItems; + GUI::SetSetting(this, "multiSelected", sel); + } + // select everything from last clicked item to current + else if (m_IsMultiSelecting) + { + if (m_MultiSelectionFromItem == select) + return; + + CIntList sel; + GUI::GetSetting(this, "multiSelected", sel); + m_SelectedItems = sel.m_Items; + int firstId = m_MultiSelectionFromItem; + int lastId = select; + + if (select < m_MultiSelectionFromItem) + { + firstId = select; + lastId = m_MultiSelectionFromItem; + } + + m_SelectedItems.clear(); + for (size_t itemId = firstId; itemId < lastId + 1; itemId++) + m_SelectedItems.push_back(itemId); + + sel.m_Items = m_SelectedItems; + GUI::SetSetting(this, "multiSelected", sel); + } + // clear multi selection + else + { + CIntList sel; + GUI::GetSetting(this, "multiSelected", sel); + m_SelectedItems = sel.m_Items; + m_SelectedItems.clear(); + sel.m_Items = m_SelectedItems; + m_MultiSelectionFromItem = select; + GUI::SetSetting(this, "multiSelected", sel); + } +} void CList::HandleMessage(SGUIMessage& Message) { IGUIScrollBarOwner::HandleMessage(Message); @@ -205,6 +292,13 @@ int hovered = GetHoveredItem(); if (hovered == -1) break; + + bool multiSelectionEnabled; + GUI::GetSetting(this, "multiSelection_enabled", multiSelectionEnabled); + + if (multiSelectionEnabled) + MultiSelectionControl(hovered); + GUI::SetSetting(this, "selected", hovered); UpdateAutoScroll(); @@ -212,7 +306,8 @@ if (g_SoundManager && GUI::GetSetting(this, "sound_selected", soundPath) == PSRETURN_OK && !soundPath.empty()) g_SoundManager->PlayAsUI(soundPath.c_str(), false); - if (timer_Time() - m_LastItemClickTime < SELECT_DBLCLICK_RATE && hovered == m_PrevSelectedItem) + if (timer_Time() - m_LastItemClickTime < SELECT_DBLCLICK_RATE && hovered == m_PrevSelectedItem && + (!multiSelectionEnabled || (!m_IsMultiSelecting && !m_AddMultiSelection))) this->SendEvent(GUIM_MOUSE_DBLCLICK_LEFT_ITEM, "mouseleftdoubleclickitem"); else this->SendEvent(GUIM_MOUSE_PRESS_LEFT_ITEM, "mouseleftclickitem"); @@ -266,7 +361,6 @@ InReaction CList::ManuallyHandleEvent(const SDL_Event_* ev) { InReaction result = IN_PASS; - if (ev->ev.type == SDL_KEYDOWN) { int szChar = ev->ev.key.keysym.sym; @@ -311,7 +405,6 @@ result = IN_PASS; } } - return result; } @@ -323,6 +416,40 @@ DrawList(selected, "sprite", "sprite_selectarea", "textcolor"); } +void CList::DrawSelection(const int selected, const bool scrollbar, const float scroll, CGUISpriteInstance& sprite_selectarea, const int cell_id, const float bz, CRect& rect) +{ + if (!GetGUI()) + return; + if (selected < 0 || selected + 1 >= (int)m_ItemsYPositions.size()) + return; + + // Get rectangle of selection: + CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll, + rect.right, rect.top + m_ItemsYPositions[selected + 1] - scroll); + + if (rect_sel.top > rect.bottom || rect_sel.bottom < rect.top) + return; + + if (rect_sel.bottom > rect.bottom) + rect_sel.bottom = rect.bottom; + if (rect_sel.top < rect.top) + rect_sel.top = rect.top; + + if (scrollbar) + { + // Remove any overlapping area of the scrollbar. + if (rect_sel.right > GetScrollBar(0).GetOuterRect().left && + rect_sel.right <= GetScrollBar(0).GetOuterRect().right) + rect_sel.right = GetScrollBar(0).GetOuterRect().left; + + if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left && + rect_sel.left < GetScrollBar(0).GetOuterRect().right) + rect_sel.left = GetScrollBar(0).GetOuterRect().right; + } + + GetGUI()->DrawSprite(sprite_selectarea, cell_id, bz + 0.05f, rect_sel); +} + void CList::DrawList(const int& selected, const CStr& _sprite, const CStr& _sprite_selected, const CStr& _textcolor) { float bz = GetBufferedZ(); @@ -354,34 +481,20 @@ if (scrollbar) scroll = GetScrollBar(0).GetPos(); - if (selected >= 0 && selected+1 < (int)m_ItemsYPositions.size()) + CIntList sel; + GUI::GetSetting(this, "multiSelected", sel); + m_SelectedItems = sel.m_Items; + if (m_SelectedItems.size() > 0) { - // Get rectangle of selection: - CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll, - rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll); - - if (rect_sel.top <= rect.bottom && - rect_sel.bottom >= rect.top) - { - if (rect_sel.bottom > rect.bottom) - rect_sel.bottom = rect.bottom; - if (rect_sel.top < rect.top) - rect_sel.top = rect.top; - - if (scrollbar) - { - // Remove any overlapping area of the scrollbar. - if (rect_sel.right > GetScrollBar(0).GetOuterRect().left && - rect_sel.right <= GetScrollBar(0).GetOuterRect().right) - rect_sel.right = GetScrollBar(0).GetOuterRect().left; - - if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left && - rect_sel.left < GetScrollBar(0).GetOuterRect().right) - rect_sel.left = GetScrollBar(0).GetOuterRect().right; - } - - GetGUI()->DrawSprite(*sprite_selectarea, cell_id, bz+0.05f, rect_sel); - } + // Draw multi selection + for (size_t selection = 0; selection < m_SelectedItems.size(); selection++) + DrawSelection(m_SelectedItems[selection], scrollbar, scroll, *sprite_selectarea, cell_id, bz, rect); + } + else + { + // Draw item selection + if (selected != -1) + DrawSelection(selected, scrollbar, scroll, *sprite_selectarea, cell_id, bz, rect); } CColor color; Index: source/gui/COList.cpp =================================================================== --- source/gui/COList.cpp +++ source/gui/COList.cpp @@ -341,40 +341,19 @@ float scroll = 0.f; if (scrollbar) scroll = GetScrollBar(0).GetPos(); - - // Draw item selection - if (selected != -1) - { - ENSURE(selected >= 0 && selected+1 < (int)m_ItemsYPositions.size()); - - // Get rectangle of selection: - CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll, - rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll); - - if (rect_sel.top <= rect.bottom && - rect_sel.bottom >= rect.top) + + CIntList sel; + GUI::GetSetting(this, "multiSelected", sel); + m_SelectedItems = sel.m_Items; + if (m_SelectedItems.size() > 0) { - if (rect_sel.bottom > rect.bottom) - rect_sel.bottom = rect.bottom; - if (rect_sel.top < rect.top) - rect_sel.top = rect.top; - - if (scrollbar) - { - // Remove any overlapping area of the scrollbar. - if (rect_sel.right > GetScrollBar(0).GetOuterRect().left && - rect_sel.right <= GetScrollBar(0).GetOuterRect().right) - rect_sel.right = GetScrollBar(0).GetOuterRect().left; - - if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left && - rect_sel.left < GetScrollBar(0).GetOuterRect().right) - rect_sel.left = GetScrollBar(0).GetOuterRect().right; - } - - // Draw item selection - GetGUI()->DrawSprite(*sprite_selectarea, cell_id, bz+0.05f, rect_sel); - } + // Draw multi selection + for (size_t selection = 0; selection < m_SelectedItems.size(); ++selection) + DrawSelection(m_SelectedItems[selection], scrollbar, scroll, *sprite_selectarea, cell_id, bz, rect); } + // Draw item selection + else if (selected != -1) + DrawSelection(selected, scrollbar, scroll, *sprite_selectarea, cell_id, bz, rect); // Draw line above column header CGUISpriteInstance* sprite_heading = NULL; Index: source/gui/GUI.h =================================================================== --- source/gui/GUI.h +++ source/gui/GUI.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -44,6 +44,7 @@ #include "GUIbase.h" #include "GUItext.h" #include "GUIutil.h" +#include "CIntList.h" #include "IGUIButtonBehavior.h" #include "IGUIObject.h" #include "IGUIScrollBarOwner.h" // Required by IGUIScrollBar Index: source/gui/GUItypes.h =================================================================== --- source/gui/GUItypes.h +++ source/gui/GUItypes.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -42,3 +42,4 @@ TYPE(CPos) TYPE(CGUIList) TYPE(CGUISeries) +TYPE(CIntList) Index: source/gui/GUIutil.cpp =================================================================== --- source/gui/GUIutil.cpp +++ source/gui/GUIutil.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2018 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -266,6 +266,11 @@ return false; } +template <> +bool __ParseString(const CStrW& UNUSED(Value), CIntList& UNUSED(Output)) +{ + return false; +} //-------------------------------------------------------- CMatrix3D GetDefaultGuiMatrix() Index: source/gui/scripting/JSInterface_IGUIObject.cpp =================================================================== --- source/gui/scripting/JSInterface_IGUIObject.cpp +++ source/gui/scripting/JSInterface_IGUIObject.cpp @@ -293,7 +293,13 @@ ScriptInterface::ToJSVal(cx, vp, value.m_Items); break; } - + case GUIST_CIntList: + { + CIntList value; + GUI::GetSetting(e, propName, value); + ScriptInterface::ToJSVal(cx, vp, value.m_Items); + break; + } case GUIST_CGUISeries: { CGUISeries value; @@ -584,6 +590,19 @@ break; } + case GUIST_CIntList: + { + CIntList list; + if (ScriptInterface::FromJSVal(cx, vp, list.m_Items)) + GUI::SetSetting(e, propName, list); + else + { + JS_ReportError(cx, "Failed to get list '%s'", propName.c_str()); + return false; + } + break; + } + case GUIST_CGUISeries: { CGUISeries series;