From 2961e47f954d3ac209ce33524202879f1e8f683d Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Wed, 7 Nov 2018 23:51:41 +0100 Subject: Add Menu_Columns() Allow specifying a column in Menu_Selection() (the column is ignored in column submenus) Fix Graphics Don't let nested factories overwrite their parents factories' args Update InstantDescription in Refresh() Clean up and fix Refresh() a bit --- Script.c | 217 ++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 153 insertions(+), 64 deletions(-) (limited to 'Script.c') diff --git a/Script.c b/Script.c index e3f5c94..3a7a104 100644 --- a/Script.c +++ b/Script.c @@ -41,6 +41,7 @@ static const DT_Menu_KeepOpen_Refresh_Mask = 0x18; // DT_Menu_KeepOpen_Refresh | static const DT_Menu_Type_Setting = 0; static const DT_Menu_Type_Entry = 1; static const DT_Menu_Type_Factory = 2; +static const DT_Menu_Type_Columns = 3; static const DT_Menu_Action_Normal = 0; static const DT_Menu_Action_Special2 = 1; @@ -164,7 +165,6 @@ static const Menu_Layout__NoFlagMask = 3; local settings; local createEntries; -local entryCount; local currentColumn; local columnCount; local columnEntries; @@ -176,13 +176,14 @@ local refreshing; local msgBoardMode; local msgBoardEntry; local noSelectionCallbacks; +local multiColumnMode; local subMenu; local vars; func Initialize() { currentColumnSelections = [-1]; - columnEntries = [[]]; + columnEntries = []; msgBoardEntry = []; vars = []; } @@ -204,7 +205,7 @@ func Create(array cSettings, array cEntries) settings[DT_Menu_Settings_InstantDescriptionPosition] = [40, -60]; } - entryCount = 0; + multiColumnMode = false; columnCount = 0; columnOffsets = []; @@ -226,44 +227,50 @@ func Create(array cSettings, array cEntries) factoryArgs[Menu_CallbackArg_Menu] = this; factoryArgs[Menu_CallbackArg_MenuObject] = settings[DT_Menu_Settings_Object]; - HandleEntries(createEntries, entryCount, columnEntries[0], settings, factoryArgs, 0); + var index = 0; + columnEntries[0] = []; + HandleEntries(createEntries, index, columnEntries[0], settings, factoryArgs, 0, true); if(settings[DT_Menu_Settings_Parent]) settings[DT_Menu_Settings_Parent]->Suspend(); var title = settings[DT_Menu_Settings_Title]; - var submenuTitle; - // update submenu columns if necessary and build title - for(var i = 0; i < GetLength(currentColumnSelections); ++i) - { - // TODO: cascade? then remove the columnSelection == -1 check - var columnSelection = currentColumnSelections[i]; - if((columnSelection == -1) || !columnEntries[i]) - { - break; - } - var submenuData = columnEntries[i][columnSelection][DT_Menu_Entry_SubMenuColumnData]; - if(submenuData) + if(!multiColumnMode) + { + var submenuTitle; + // update submenu columns if necessary and build title + for(var i = 0; i < GetLength(currentColumnSelections); ++i) { - columnEntries[i + 1] = submenuData[2]; - - var submenuSettings = submenuData[0]; - /*var */submenuTitle = submenuSettings[DT_Menu_Settings_Title] || ""; - if(submenuSettings[DT_Menu_Settings_Icon]) + // TODO: cascade? then remove the columnSelection == -1 check + var columnSelection = currentColumnSelections[i]; + if((columnSelection == -1) || !columnEntries[i]) { - submenuTitle = Format("{{%i}} %s", submenuSettings[DT_Menu_Settings_Icon], submenuTitle); + break; } - // because of the engine such long titles are not nice; maybe do "... > last Submenu Title" - // the engine makes entry columns at least as long as the title is... - // title = Format("%s {{MN7I:6}} %s", title, submenuTitle); + var submenuData = columnEntries[i][columnSelection][DT_Menu_Entry_SubMenuColumnData]; + if(submenuData) + { + columnEntries[i + 1] = submenuData[2]; + + var submenuSettings = submenuData[0]; + /*var */submenuTitle = submenuSettings[DT_Menu_Settings_Title] || ""; + if(submenuSettings[DT_Menu_Settings_Icon]) + { + submenuTitle = Format("{{%i}} %s", submenuSettings[DT_Menu_Settings_Icon], submenuTitle); + } + + // because of the engine such long titles are not nice; maybe do "... > last Submenu Title" + // the engine makes entry columns at least as long as the title is... + // title = Format("%s {{MN7I:7}} %s", title, submenuTitle); + } } - } - if(submenuTitle) - { - title = Format("... {{MN7I:6}} %s", submenuTitle); + if(submenuTitle) + { + title = Format("... {{MN7I:7}} %s", submenuTitle); + } } CreateMenu(settings[DT_Menu_Settings_Icon], settings[DT_Menu_Settings_Object], this, settings[DT_Menu_Settings_Extra], title, settings[DT_Menu_Settings_ExtraData], settings[DT_Menu_Settings_Style], true, MN7I); @@ -271,11 +278,11 @@ func Create(array cSettings, array cEntries) AddEntries(); - if(entryCount > 0) + if(GetLength(columnEntries[0]) > 0) { if(!refreshing) { - SelectEntry(settings[DT_Menu_Settings_Selection]); + SelectEntry(settings[DT_Menu_Settings_Selection][0], settings[DT_Menu_Settings_Selection][1]); } } @@ -485,7 +492,7 @@ func Suspend(bool cont) } } -func HandleEntries(array factoryEntries, int& i, array& ret, array& retSettings, array& factoryArgs, int column) +func HandleEntries(array factoryEntries, int& i, array& ret, array& retSettings, array& factoryArgs, int column, bool isMainColumn) { if(column >= columnCount) { @@ -496,11 +503,20 @@ func HandleEntries(array factoryEntries, int& i, array& ret, array& retSettings, { if(entry[0] == DT_Menu_Type_Entry) { + if(multiColumnMode && isMainColumn) + { + FatalError("DT_Menu::HandleEntries: if Menu_Columns() is used, all entries must occur inside it"); + } // is it an extra column submenu? if(entry[2]) { + if(multiColumnMode) + { + FatalError("DT_Menu::HandleEntries: Menu_Columns() and Submenu columns can not be used together"); + } + var index = 0; - HandleEntries(entry[2][1], index, entry[2][2], entry[2][0], factoryArgs, column + 1); + HandleEntries(entry[2][1], index, entry[2][2], entry[2][0], factoryArgs, column + 1, false); entry[1][DT_Menu_Entry_SubMenuColumnData] = entry[2]; } @@ -508,10 +524,9 @@ func HandleEntries(array factoryEntries, int& i, array& ret, array& retSettings, } else if(entry[0] == DT_Menu_Type_Factory) { - factoryArgs[Menu_CallbackArg_Args] = entry[1][1]; - for(var callback in entry[1][0]) { + factoryArgs[Menu_CallbackArg_Args] = entry[1][1]; factoryArgs[Menu_CallbackArg_EntryNumber] = i; factoryArgs[Menu_CallbackArg_EntryColumn] = column; var factoryResult = CallA(callback, BindCallbackArgs(factoryArgs, entry[1][2])); @@ -519,7 +534,7 @@ func HandleEntries(array factoryEntries, int& i, array& ret, array& retSettings, { var newEntries = []; UncombineAndDistinguish(factoryResult, retSettings, newEntries); - HandleEntries(newEntries, i, ret, retSettings, factoryArgs); + HandleEntries(newEntries, i, ret, retSettings, factoryArgs, column, isMainColumn); } else if(factoryResult == Menu_React_Close) { @@ -527,6 +542,41 @@ func HandleEntries(array factoryEntries, int& i, array& ret, array& retSettings, } } } + else if(entry[0] == DT_Menu_Type_Columns) + { + if(multiColumnMode) + { + FatalError("DT_Menu::HandleEntries: only one Menu_Columns() can appear in the whole menu"); + } + + if(columnCount > 1) + { + FatalError("DT_Menu::HandleEntries: Menu_Columns() and Submenu columns can not be used together"); + } + + if(GetLength(columnEntries[0]) > 0) + { + FatalError("DT_Menu::HandleEntries: if Menu_Columns() is used, all entries must occur inside it"); + } + + multiColumnMode = true; + + var j = 0; + for(var columnData in entry[1]) + { + columnEntries[j] = []; + + var index = 0; + var tempSettings = []; + HandleEntries(columnData, index, columnEntries[j], settings, factoryArgs, j, false); + ++j; + + if(GetLength(tempSettings) > 0) + { + FatalError("DT_Menu::HandleEntries: menu settings can not appear in Menu_Columns()"); + } + } + } } } @@ -547,18 +597,21 @@ func AddEntries() SetMenuSize(columnCount, entriesCount, settings[DT_Menu_Settings_Object]); } - for(var i = 1; i < GetLength(columnEntries); ++i) + if(!multiColumnMode) { - var column = columnEntries[i]; - if(column) + for(var i = 1; i < GetLength(columnEntries); ++i) { - var offset = currentColumnSelections[i - 1] + columnOffsets[i - 1]; - var entryCount = GetLength(column); - if(offset + entryCount > entriesCount) + var column = columnEntries[i]; + if(column) { - offset = entriesCount - entryCount; + var offset = currentColumnSelections[i - 1] + columnOffsets[i - 1]; + var entryCount = GetLength(column); + if(offset + entryCount > entriesCount) + { + offset = entriesCount - entryCount; + } + columnOffsets[i] = offset; } - columnOffsets[i] = offset; } } @@ -616,8 +669,7 @@ func AddEntries() entry[DT_Menu_Entry_XPar1] = icon[1]; } } - - if(GetType(icon[0]) == C4V_C4Object) + else if(GetType(icon[0]) == C4V_C4Object) { entry[DT_Menu_Entry_Extra] |= C4MN_Add_ImgObject; entry[DT_Menu_Entry_XPar1] = icon[0]; @@ -649,7 +701,7 @@ func AddEntries() if(entry[DT_Menu_Entry_SubMenuColumnData] && currentColumnSelections[j] == rowIndex) { - text = Format("%s {{MN7I:6}}", text); + text = Format("%s {{MN7I:7}}", text); } AddMenuItem(text, !noCommand && "MenuItemCommand", iconID, settings[DT_Menu_Settings_Object], entry[DT_Menu_Entry_Count], entryIndex, showDesc && entry[DT_Menu_Entry_Description], entry[DT_Menu_Entry_Extra], entry[DT_Menu_Entry_XPar1], entry[DT_Menu_Entry_XPar2]); @@ -676,7 +728,7 @@ func React(reaction, array entryIndex, int refreshDelayed) } else if(reaction == Menu_React_Back) { - if(currentColumn > 0) + if(currentColumn > 0 && !multiColumnMode) { LeaveSubMenuColumn(); } @@ -696,7 +748,7 @@ func React(reaction, array entryIndex, int refreshDelayed) if(reaction[0] == Menu_React_SelectionOffset) { selection[0] += reaction[1]; - selection[0] %= entryCount; + selection[0] %= GetLength(columnEntries[currentColumn]); } else if(reaction[0] == Menu_React_SelectionChange) { @@ -758,7 +810,8 @@ func SubmenuItemCallback(int action, object menuObject, args, array allArgs) { if(args[3]) { - SelectEntry(columnEntries[currentColumn][currentColumnSelections[currentColumn]][DT_Menu_Entry_SubMenuColumnData][0][DT_Menu_Settings_Selection], currentColumn + 1); + var targetSelection = columnEntries[currentColumn][currentColumnSelections[currentColumn]][DT_Menu_Entry_SubMenuColumnData][0][DT_Menu_Settings_Selection]; + SelectEntry(targetSelection && targetSelection[0], currentColumn + 1); } else { @@ -876,6 +929,11 @@ func OnMenuSelection(int selection, object menuObject) } return; } + else if(multiColumnMode) + { + SelectEntry(GetLength(columnEntries[column]) - 1, column); + return; + } skipHandling = true; } @@ -922,11 +980,13 @@ func OnMenuSelection(int selection, object menuObject) selection = currentColumnSelections[column]; } - if(selection + columnOffsets[currentColumn] == oldColumnOldSelection + columnOffsets[oldColumn]) + // navigating between submenu columns; not in multiColumnMode + if(!multiColumnMode && (selection + columnOffsets[currentColumn] == oldColumnOldSelection + columnOffsets[oldColumn])) { if(currentColumn == oldColumn + 1 && oldIsColumnSubmenu) { var targetSelection = columnEntries[currentColumn - 1][oldColumnOldSelection][DT_Menu_Entry_SubMenuColumnData][0][DT_Menu_Settings_Selection]; + targetSelection = targetSelection && targetSelection[0]; // column submenu was entered through pressing right; select the first entry // but only if it's not there yet if(selection != targetSelection) @@ -959,7 +1019,7 @@ func OnMenuSelection(int selection, object menuObject) } // update submenu column if necessary - if(selection != oldColumnSelection) + if(!multiColumnMode && selection != oldColumnSelection) { if(entry[DT_Menu_Entry_SubMenuColumnData]) { @@ -1001,11 +1061,8 @@ func Refresh(array selection, bool delayed) } else { - var disabledCallbacks; - if(!noSelectionCallbacks) - { - disabledCallbacks = noSelectionCallbacks = true; - } + var oldNoSelectionCallbacks = noSelectionCallbacks; + noSelectionCallbacks = true; CloseMenu(settings[DT_Menu_Settings_Object]); @@ -1013,15 +1070,16 @@ func Refresh(array selection, bool delayed) refreshing = true; Create(settings, createEntries); refreshing = oldRefreshing; - var column = selection[1]; + var column = BoundBy(selection[1], 0, columnCount); selection = selection[0]; - // TODO: BoundBy for column? SelectEntry(BoundBy(selection, 0, GetLength(columnEntries[column]) - 1), column); - if(disabledCallbacks) + if(settings[DT_Menu_Settings_InstantDescription]) { - noSelectionCallbacks = false; + ShowInstantDescription(columnEntries[currentColumn][selection]); } + + noSelectionCallbacks = oldNoSelectionCallbacks; } } @@ -1064,7 +1122,7 @@ global func Menu_Size(int width, int height) { return Menu__Setting([DT_Menu_Set global func Menu_ExtraData(int data) { return Menu__Setting([DT_Menu_Settings_ExtraData, data]); } global func Menu_Title(string title) { return Menu__Setting([DT_Menu_Settings_Title, title]); } global func Menu_RefreshInterval(int interval) { return Menu__Setting([DT_Menu_Settings_RefreshInterval, interval + !interval]); } -global func Menu_Selection(int selection) { return Menu__Setting([DT_Menu_Settings_Selection, selection]); } +global func Menu_Selection(int selection, int column) { return Menu__Setting([DT_Menu_Settings_Selection, [selection, column]]); } global func Menu__Style(int style) { return Menu__Setting([DT_Menu_Settings_Style, style]); } global func Menu__KeepOpen(int mode) { return Menu__Setting([DT_Menu_Settings_KeepOpen, mode]); } @@ -1200,6 +1258,32 @@ global func Menu_Factory(array callbacks, args, array binding) return [DT_Menu_Type_Factory, [callbacks, args, binding || [Menu_CallbackArg_Args, Menu_CallbackArg_EntryNumber, Menu_CallbackArg_Menu]]]; } +// Menu_Columns +// ([ +// [ first column entries ], +// [ second column entries ], +// ... +// ]) +global func Menu_Columns(array columns) +{ + var preparedColunmns = CreateArray(GetLength(columns)); + + for(var i = 0; i < GetLength(columns); ++i) + { + preparedColunmns[i] = []; + + var tempSettings = []; + MN7I->UncombineAndDistinguish(columns[i], tempSettings, preparedColunmns[i]); + + if(GetLength(tempSettings) > 0) + { + FatalError("DT_Menu::Menu_Columns: menu settings can not appear in Menu_Columns()"); + } + } + + return [DT_Menu_Type_Columns, preparedColunmns]; +} + global func Menu_Text(string text, bool allowSelection) { return Menu_Entry([Menu_Entry_Text(text), Menu_Entry_Placeholder(allowSelection)]); @@ -2002,7 +2086,7 @@ global func CreateNewMenu(array menu, inheritSettings, object parentMenu) if(GetType(settings) != C4V_Array) settings = []; settings[DT_Menu_Settings_Style] &= ~C4MN_Style_EqualItemHeight; // EqualItemHeight can't be inherited - settings[DT_Menu_Settings_Selection] = 0; // Selection can't be inherited + settings[DT_Menu_Settings_Selection] = []; // Selection can't be inherited settings[DT_Menu_Settings_Callbacks] = 0; // Global callbacks can't be inherited (maybe filter callbacks) settings[DT_Menu_Settings_Parent] = parentMenu; @@ -2038,7 +2122,7 @@ func UncombineAndDistinguish(array combined, array &settings, array &entries) NamedArg(val[1], settings); } } - else if(val[0] == DT_Menu_Type_Entry || val[0] == DT_Menu_Type_Factory) + else if(val[0] == DT_Menu_Type_Entry || val[0] == DT_Menu_Type_Factory || val[0] == DT_Menu_Type_Columns) { entries[GetLength(entries)] = val; } @@ -2154,6 +2238,11 @@ func GetSelection(int mode) } else if(mode == Menu_Selection_SubMenuColumnChain) { + if(multiColumnMode) + { + FatalError("DT_Menu::GetSelection: Menu_Selection_SubMenuColumnChain doesn't make sense when Menu_Columns() are used"); + } + var ret = []; for(var i = 0; i < columnEntries; ++i) -- cgit v1.2.3-54-g00ecf