summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Mittendrein <git@maxmitti.tk>2018-11-07 23:52:08 +0100
committerMarkus Mittendrein <git@maxmitti.tk>2018-11-07 23:52:08 +0100
commite8cf85636f2a4fcf1cc41fc5f56f9b90bbb013ec (patch)
treeae68f772c7e22a256f0adb57372d107aa1daf62b
parent91056c65c208eb85fa9d860a21c0cf823fb82a62 (diff)
downloadDTMenuDebug.c4d-e8cf85636f2a4fcf1cc41fc5f56f9b90bbb013ec.tar.gz
DTMenuDebug.c4d-e8cf85636f2a4fcf1cc41fc5f56f9b90bbb013ec.zip
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
-rw-r--r--Graphics.pngbin13307 -> 13698 bytes
-rw-r--r--Script.c219
2 files changed, 154 insertions, 65 deletions
diff --git a/Graphics.png b/Graphics.png
index 4b53b19..a9ad684 100644
--- a/Graphics.png
+++ b/Graphics.png
Binary files differ
diff --git a/Script.c b/Script.c
index 029e1c7..16d6699 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;
@@ -169,7 +170,6 @@ static const Menu_Layout__NoFlagMask = 3;
local settings;
local createEntries;
-local entryCount;
local currentColumn;
local columnCount;
local columnEntries;
@@ -181,13 +181,14 @@ local refreshing;
local msgBoardMode;
local msgBoardEntry;
local noSelectionCallbacks;
+local multiColumnMode;
local subMenu;
local vars;
func Initialize()
{
currentColumnSelections = [-1];
- columnEntries = [[]];
+ columnEntries = [];
msgBoardEntry = [];
vars = [];
}
@@ -209,7 +210,7 @@ func Create(array cSettings, array cEntries)
settings[DT_Menu_Settings_InstantDescriptionPosition] = [40, -60];
}
- entryCount = 0;
+ multiColumnMode = false;
columnCount = 0;
columnOffsets = [];
@@ -231,7 +232,9 @@ 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(columnCount > 1 && settings[DT_Menu_Settings_Style] != C4MN_Style_Context)
{
@@ -242,38 +245,42 @@ func Create(array cSettings, array cEntries)
if(!(settings[DT_Menu_Settings_Object])) { FatalError("Assertion failed: CreateNewMenu: menu object is missing; assertion code: settings[DT_Menu_Settings_Object]"); }
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);
@@ -281,11 +288,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]);
}
}
else
@@ -303,7 +310,7 @@ func Create(array cSettings, array cEntries)
func LeaveSubMenuColumn()
{
- if(!(currentColumn > 0)) { FatalError("Assertion failed: LeaveSubMenuColumn: currentColumn is not a submenu; can't leave; assertion code: currentColumn > 0"); }
+ if(!(!multiColumnMode && currentColumn > 0)) { FatalError("Assertion failed: LeaveSubMenuColumn: currentColumn is not a submenu; can't leave; assertion code: !multiColumnMode && currentColumn > 0"); }
SelectEntry(currentColumnSelections[currentColumn - 1], currentColumn - 1);
Refresh(GetSelection(Menu_Selection_WithColumn));
}
@@ -509,7 +516,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)
{
@@ -520,11 +527,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];
}
@@ -532,10 +548,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]));
@@ -543,7 +558,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)
{
@@ -555,6 +570,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()");
+ }
+ }
+ }
else
{
Log("WARNING: DT_Menu::HandleEntries: ignoring invalid Non-Entry/Factory: %v", entry);
@@ -579,18 +629,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;
}
}
@@ -648,8 +701,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];
@@ -681,7 +733,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]);
@@ -708,7 +760,7 @@ func React(reaction, array entryIndex, int refreshDelayed)
}
else if(reaction == Menu_React_Back)
{
- if(currentColumn > 0)
+ if(currentColumn > 0 && !multiColumnMode)
{
LeaveSubMenuColumn();
}
@@ -728,7 +780,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)
{
@@ -790,7 +842,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
{
@@ -908,6 +961,11 @@ func OnMenuSelection(int selection, object menuObject)
}
return;
}
+ else if(multiColumnMode)
+ {
+ SelectEntry(GetLength(columnEntries[column]) - 1, column);
+ return;
+ }
skipHandling = true;
}
@@ -954,11 +1012,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)
@@ -991,7 +1051,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])
{
@@ -1033,11 +1093,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]);
@@ -1045,15 +1102,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;
}
}
@@ -1096,7 +1154,7 @@ global func Menu_Size(int width, int height) { if(!(width >= 0 && height >= 0))
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) { if(!(interval >= 0)) { FatalError("Assertion failed: Menu_RefreshInterval: Negative interval doesn't make sense; assertion code: interval >= 0"); }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]); }
@@ -1278,6 +1336,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)]);
@@ -2126,7 +2210,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;
@@ -2164,7 +2248,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;
}
@@ -2286,6 +2370,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)