From 500e5129648d4631720cab8f639dbdfcf96e4311 Mon Sep 17 00:00:00 2001 From: Markus Mittendrein Date: Mon, 2 Jan 2017 19:32:34 +0100 Subject: Initial --- DefCore.txt | 7 + DescDE.txt | 1 + DescUS.txt | 1 + Graphics.png | Bin 0 -> 10647 bytes Names.txt | 2 + Script.c | 1650 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ StringTblDE.txt | 7 + StringTblUS.txt | 7 + 8 files changed, 1675 insertions(+) create mode 100644 DefCore.txt create mode 100644 DescDE.txt create mode 100644 DescUS.txt create mode 100644 Graphics.png create mode 100644 Names.txt create mode 100644 Script.c create mode 100644 StringTblDE.txt create mode 100644 StringTblUS.txt diff --git a/DefCore.txt b/DefCore.txt new file mode 100644 index 0000000..637655d --- /dev/null +++ b/DefCore.txt @@ -0,0 +1,7 @@ +[DefCore] +id=MN7I +Name=Menu +Version=4,9,5 +Category=C4D_StaticBack +Width=64 +Height=64 diff --git a/DescDE.txt b/DescDE.txt new file mode 100644 index 0000000..ce6bc05 --- /dev/null +++ b/DescDE.txt @@ -0,0 +1 @@ +Eine neue Objektdefinition. \ No newline at end of file diff --git a/DescUS.txt b/DescUS.txt new file mode 100644 index 0000000..1dfbcf7 --- /dev/null +++ b/DescUS.txt @@ -0,0 +1 @@ +A new object definition. \ No newline at end of file diff --git a/Graphics.png b/Graphics.png new file mode 100644 index 0000000..737dfed Binary files /dev/null and b/Graphics.png differ diff --git a/Names.txt b/Names.txt new file mode 100644 index 0000000..a955359 --- /dev/null +++ b/Names.txt @@ -0,0 +1,2 @@ +DE:Menü +US:Menu diff --git a/Script.c b/Script.c new file mode 100644 index 0000000..8191582 --- /dev/null +++ b/Script.c @@ -0,0 +1,1650 @@ +#strict 2 + +static const DT_Menu = MN7I; +static const DT_Menu_Combined = -1; + +// Enums and bitfields + +/* +static const DT_Menu_Settings_Symbol = 0; +static const DT_Menu_Settings_Object = 0 + 1; +static const DT_Menu_Settings_Extra = 0 + 1 + 1; +static const DT_Menu_Settings_Caption = 0 + 1 + 1 + 1; +static const DT_Menu_Settings_ExtraData = 0 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_Style = 0 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_KeepOpen = 0 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_Parent = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_Size = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_RefreshInterval = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_Selection = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_ConditionDisableMode = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_ConditionAllowSelection = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_Callbacks = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_Decoration = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_RequireAction = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Settings_KeepParentOnClose = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +*/ + +static const DT_Menu_Settings_Symbol = 0; +static const DT_Menu_Settings_Object = 1; +static const DT_Menu_Settings_Extra = 2; +static const DT_Menu_Settings_Caption = 3; +static const DT_Menu_Settings_ExtraData = 4; +static const DT_Menu_Settings_Style = 5; +static const DT_Menu_Settings_KeepOpen = 6; +static const DT_Menu_Settings_Parent = 7; +static const DT_Menu_Settings_Size = 8; +static const DT_Menu_Settings_RefreshInterval = 9; +static const DT_Menu_Settings_Selection = 10; +static const DT_Menu_Settings_ConditionDisableMode = 11; +static const DT_Menu_Settings_ConditionAllowSelection = 12; +static const DT_Menu_Settings_Callbacks = 13; +static const DT_Menu_Settings_Decoration = 14; +static const DT_Menu_Settings_RequireAction = 15; +static const DT_Menu_Settings_KeepParentOnClose = 16; + +/* +static const DT_Menu_KeepOpen_Not = 0x0; +static const DT_Menu_KeepOpen_Keep = 0x1; +static const DT_Menu_KeepOpen_Force = 0x2; +static const DT_Menu_KeepOpen_Permanent = 0x2 << 1; +static const DT_Menu_KeepOpen_Refresh = 0x2 << 1 << 1; +static const DT_Menu_KeepOpen_RefreshContinously = 0x2 << 1 << 1 << 1; +static const DT_Menu_KeepOpen_Refresh_Mask = 24; // DT_Menu_KeepOpen_Refresh | DT_Menu_KeepOpen_RefreshContinously +*/ + +static const DT_Menu_KeepOpen_Not = 0; +static const DT_Menu_KeepOpen_Keep = 1; +static const DT_Menu_KeepOpen_Force = 2; +static const DT_Menu_KeepOpen_Permanent = 4; +static const DT_Menu_KeepOpen_Refresh = 8; +static const DT_Menu_KeepOpen_RefreshContinously = 16; +static const DT_Menu_KeepOpen_Refresh_Mask = 24; // DT_Menu_KeepOpen_Refresh | DT_Menu_KeepOpen_RefreshContinously + +/* +static const DT_Menu_Type_Setting = 0; +static const DT_Menu_Type_Entry = 0 + 1; +static const DT_Menu_Type_Factory = 0 + 1 + 1; +*/ + +//static const DT_Menu_Type_Combined = -1; +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_Action_Normal = 0; +static const DT_Menu_Action_Special2 = 0 + 1; +static const DT_Menu_Action_Close = 0 + 1 + 1; +*/ + +static const DT_Menu_Action_Normal = 0; +static const DT_Menu_Action_Special2 = 1; +static const DT_Menu_Action_Close = 2; + +/* +static const DT_Menu_Callback_MenuObject = -3; +static const DT_Menu_Callback_Global = -3 + 1; +static const DT_Menu_Callback_Scenario = -3 + 1 + 1; +*/ + +static const DT_Menu_Callback_MenuObject = -3; +static const DT_Menu_Callback_Scenario = -2; +static const DT_Menu_Callback_Global = -1; + +/* +static const Menu_React_Menu_React_Override = -1; +static const Menu_React_None = -1 + 1; +static const Menu_React_Close = -1 + 1 + 1; +static const Menu_React_Refresh = -1 + 1 + 1 + 1; +static const Menu_React_KeepOpen = -1 + 1 + 1 + 1 + 1; +static const Menu_React_Back = -1 + 1 + 1 + 1 + 1 + 1; +static const Menu_React_SelectionOffset = -1 + 1 + 1 + 1 + 1 + 1 + 1; +static const Menu_React_SelectionChange = -1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const Menu_React_ShowSubmenu = -1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +*/ + +static const Menu_React_OverrideReaction = -1; +static const Menu_React_None = 0; +static const Menu_React_Close = 1; +static const Menu_React_Refresh = 2; +static const Menu_React_KeepOpen = 3; +static const Menu_React_Back= 4; +static const Menu_React_SelectionOffset = 5; +static const Menu_React_SelectionChange = 6; +static const Menu_React_ShowSubmenu = 7; + +global func Menu_React_OffsetSelection(int offset) { return [Menu_React_SelectionOffset, offset]; } +global func Menu_React_OverrideSelection(int override) { return [Menu_React_SelectionChange, override]; } +global func Menu_React_Override(override) { return [Menu_React_OverrideReaction, override]; } + +/* +static const Menu_ConditionReact_Default = 0; +static const Menu_ConditionReact_Show = 0 + 1; +static const Menu_ConditionReact_Hide = 0 + 1 + 1; +static const Menu_ConditionReact_GrayOut = 0 + 1 + 1 + 1; +static const Menu_ConditionReact_CustomFormat = 0 + 1 + 1 + 1 + 1; +*/ + +static const Menu_ConditionReact_Default = 0; +static const Menu_ConditionReact_Show = 1; +static const Menu_ConditionReact_Hide = 2; +static const Menu_ConditionReact_GrayOut = 3; +static const Menu_ConditionReact_CustomFormat = 4; + +global func Menu_ConditionReact_CustomColor(int color) { return [Menu_ConditionReact_CustomFormat, Format("%%s", color)]; } +global func Menu_ConditionReact_Format(string format) { return [Menu_ConditionReact_CustomFormat, format]; } + +/* +static const Menu_Condition_Default = 0; +static const Menu_Condition_AllowSelection = 0 + 1; +static const Menu_Condition_DenySelection = 0 + 1 + 1; +*/ + +static const Menu_Condition_Default = 0; +static const Menu_Condition_AllowSelection = 1; +static const Menu_Condition_DenySelection = 2; + +/* +static const DT_Menu_Entry_Caption = 0; +static const DT_Menu_Entry_Callbacks = 0 + 1; +static const DT_Menu_Entry_Symbol = 0 + 1 + 1; +static const DT_Menu_Entry_Count = 0 + 1 + 1 + 1; +static const DT_Menu_Entry_InfoCaption = 0 + 1 + 1 + 1 + 1; +static const DT_Menu_Entry_Extra = 0 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Entry_XPar1 = 0 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Entry_XPar2 = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Entry_Args = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Entry_Condition = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Entry_Placeholder = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +*/ + +static const DT_Menu_Entry_Caption = 0; +static const DT_Menu_Entry_Callbacks = 1; +static const DT_Menu_Entry_Symbol = 2; +static const DT_Menu_Entry_Count = 3; +static const DT_Menu_Entry_InfoCaption = 4; +static const DT_Menu_Entry_Extra = 5; +static const DT_Menu_Entry_XPar1 = 6; +static const DT_Menu_Entry_XPar2 = 7; +static const DT_Menu_Entry_Args = 8; +static const DT_Menu_Entry_Condition = 9; +static const DT_Menu_Entry_Placeholder = 10; + +/* + static const Menu_CallbackType_None = 0x0; +static const Menu_CallbackType_Special2 = 0x1; +static const Menu_CallbackType_Normal = 0x2; +static const Menu_CallbackType_Close = 0x2 << 1; +static const Menu_CallbackType_Selection = 0x2 << 1 << 1; +static const Menu_CallbackType_Deselection = 0x2 << 1 << 1 << 1; +static const Menu_CallbackType_ValueChanged = 0x2 << 1 << 1 << 1 << 1; +static const Menu_CallbackType_InputAborted = 0x2 << 1 << 1 << 1 << 1 << 1; +static const Menu_CallbackType_Defaults = 0x3; // Menu_CallbackType_Normal | Menu_CallbackType_Special2 +static const Menu_CallbackType_All = 0x7f; // Menu_CallbackType_Normal | Menu_CallbackType_Special2 | Menu_CallbackType_Close | Menu_CallbackType_Selection | Menu_CallbackType_Deselection | Menu_CallbackType_ValueChanged | Menu_CallbackType_InputAborted +*/ + +static const Menu_CallbackType_None = 0x0; +static const Menu_CallbackType_Special2 = 0x1; +static const Menu_CallbackType_Normal = 0x2; +static const Menu_CallbackType_Close = 0x4; +static const Menu_CallbackType_Selection = 0x8; +static const Menu_CallbackType_Deselection = 0x10; +static const Menu_CallbackType_ValueChanged = 0x20; +static const Menu_CallbackType_InputAborted = 0x40; +static const Menu_CallbackType_Defaults = 0x3; // Menu_CallbackType_Normal | Menu_CallbackType_Special2 +static const Menu_CallbackType_All = 0x7f; // Menu_CallbackType_Normal | Menu_CallbackType_Special2 | Menu_CallbackType_Close | Menu_CallbackType_Selection | Menu_CallbackType_Deselection | Menu_CallbackType_ValueChanged | Menu_CallbackType_InputAborted + + +/* +static const Menu_AdaptorType_Boolean = 0; +static const Menu_AdaptorType_Integer = 0 + 1; +static const Menu_AdaptorType_String = 0 + 1 + 1; +static const Menu_AdaptorType_ID = 0 + 1 + 1 + 1; +static const Menu_AdaptorType_Enum = 0 + 1 + 1 + 1 + 1; +static const Menu_AdaptorType_BitField = 0 + 1 + 1 + 1 + 1 + 1; +*/ + +static const Menu_AdaptorType_Boolean = 0; +static const Menu_AdaptorType_Integer = 1; +static const Menu_AdaptorType_String = 2; +static const Menu_AdaptorType_ID = 3; +static const Menu_AdaptorType_Enum = 4; +static const Menu_AdaptorType_BitField = 5; + +/* +static const DT_Menu_Adaptor_Type = 0; +static const DT_Menu_Adaptor_Variable = 0 + 1; +static const DT_Menu_Adaptor_Callbacks = 0 + 1 + 1; +static const DT_Menu_Adaptor_MessageBoardText = 0 + 1 + 1 + 1; +static const DT_Menu_Adaptor_Limits = 0 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_StepSize = 0 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_LayoutVals = 0 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_NoEmptyString = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_EntryIndex = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_Bit = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_WrapAround = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_Args = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_EnumSubmenu = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_EnumSubmenuCaption = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +static const DT_Menu_Adaptor_EnumSubmenuSymbol = 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; +*/ + +static const DT_Menu_Adaptor_Type = 0; +static const DT_Menu_Adaptor_Variable = 1; +static const DT_Menu_Adaptor_Callbacks = 2; +static const DT_Menu_Adaptor_MessageBoardText = 3; +static const DT_Menu_Adaptor_Limits = 4; +static const DT_Menu_Adaptor_StepSize = 5; +static const DT_Menu_Adaptor_LayoutVals = 6; +static const DT_Menu_Adaptor_NoEmptyString = 7; +static const DT_Menu_Adaptor_EntryIndex = 8; +static const DT_Menu_Adaptor_Bit = 9; +static const DT_Menu_Adaptor_WrapAround = 10; +static const DT_Menu_Adaptor_Args = 11; +static const DT_Menu_Adaptor_EnumSubmenu = 12; +static const DT_Menu_Adaptor_EnumSubmenuCaption = 13; +static const DT_Menu_Adaptor_EnumSubmenuSymbol = 14; + + +static const Menu_Layout_Symbol = 1; +static const Menu_Layout_InfoCaption = 2; + +static const Menu_Layout__CaptionPos = 3; +static const Menu_Layout__ValuePos = 4; +// static const Menu_Layout__InputValuePos = 5; TODO + +static const Menu_Layout_Caption = 4; +static const Menu_Layout_Value = 8; +// static const Menu_Layout_InputValue = 16; TODO +static const Menu_Layout__NoFlagMask = 3; + +// ---------------------------------------------------------------------------- + + +local settings; +local entries; +local createEntries; +local entryCount; +local currentSelection; +local suspended; +local closing; +local selectionOffset; +local selectionOverride; +local msgBoardMode; +local msgBoardEntry; +local noSelectionCallbacks; +local subMenu; + +func Initialize() +{ + +} + +func Destruction() +{ + Close(); +} + +func Create(array cSettings, array cEntries) +{ + settings = cSettings; + entries = []; + createEntries = cEntries; + currentSelection = -1; + settings[DT_Menu_Settings_ConditionDisableMode] = settings[DT_Menu_Settings_ConditionDisableMode] || Menu_ConditionReact_Hide; + + if(settings[DT_Menu_Settings_Parent]) settings[DT_Menu_Settings_Parent]->Suspend(); + + CreateMenu(settings[DT_Menu_Settings_Symbol], settings[DT_Menu_Settings_Object], this, settings[DT_Menu_Settings_Extra], settings[DT_Menu_Settings_Caption], settings[DT_Menu_Settings_ExtraData], settings[DT_Menu_Settings_Style], true, MN7I); + + if(GetType(settings[DT_Menu_Settings_Size]) == C4V_Array) SetMenuSize(settings[DT_Menu_Settings_Size][0], settings[DT_Menu_Settings_Size][1], settings[DT_Menu_Settings_Object]); + + entryCount = 0; + AddEntries(cEntries, entryCount); + + SelectEntry(settings[DT_Menu_Settings_Selection]); + + if(settings[DT_Menu_Settings_Decoration]) + { + SetMenuDecoration(settings[DT_Menu_Settings_Decoration], settings[DT_Menu_Settings_Object]); + } + + if(!GetEffect("Menu", this)) AddEffect("Menu", this, 1, 1, this, 0); +} + +func SelectEntry(int selection) +{ + if(selection < 0) selection = entryCount + selection; + SelectMenuItem(selection, settings[DT_Menu_Settings_Object]); +} + +func ActivateEntry(int index, int action) +{ + if(index < 0) index = entryCount + index; + if(index >= entryCount || index < 0) + { + return; + } + + SelectEntry(index); + + var entry = entries[index]; + if(entry[0] == DT_Menu_Type_Entry) + { + MenuItemCommand(entry[1][DT_Menu_Entry_Symbol], index, action); + } +} + +/*func FxMenuStart(object target, int effectNumber, int temp) +{ + +}*/ + +func FxMenuTimer(object target, int effectNumber, int effectTime) +{ + if(!settings[DT_Menu_Settings_Object]) + { + return Close(); + } + else if(settings[DT_Menu_Settings_RequireAction]) + { + var obj = settings[DT_Menu_Settings_Object]; + var requirement = settings[DT_Menu_Settings_RequireAction]; + if(GetAction(obj) != requirement[0] || (requirement[1] && GetActionTarget(0, obj) != requirement[1])) + { + return Close(); + } + } + + if(suspended) return; + + if(msgBoardMode != 0 && !TestMessageBoard(GetOwner(settings[DT_Menu_Settings_Object]), true)) + { + var entry = entries[msgBoardEntry]; + var args = entry[1][DT_Menu_Entry_Args]; + var reaction = CallCallbacks(args[DT_Menu_Adaptor_Callbacks], Menu_CallbackType_InputAborted, [Menu_CallbackType_InputAborted, entry[1][DT_Menu_Entry_Symbol], settings[DT_Menu_Settings_Object], entry[DT_Menu_Entry_Args]]); + if(reaction != Menu_React_None) + { + React(reaction, msgBoardEntry); + } + msgBoardMode = 0; + } + + if(!GetMenu(settings[DT_Menu_Settings_Object])) + { + if(settings[DT_Menu_Settings_KeepOpen] & (DT_Menu_KeepOpen_Refresh_Mask | DT_Menu_KeepOpen_Force)) + { + Refresh(currentSelection); + } + else + { + return FX_Execute_Kill; + } + } + + if(settings[DT_Menu_Settings_KeepOpen] & DT_Menu_KeepOpen_RefreshContinously && !(effectTime % settings[DT_Menu_Settings_RefreshInterval])) + { + Refresh(currentSelection); + } +} + +func FxMenuStop(object target, int effectNumber, int reason, bool temp) +{ + if(temp) + { + return; + } + CloseMenu(settings[DT_Menu_Settings_Object]); + if(settings[DT_Menu_Settings_Parent]) settings[DT_Menu_Settings_Parent]->Suspend(true); + RemoveObject(this); +} + +func CallCallbacks(array callbacks, int type, args, defaultRet, bool noGlobalCallbacks) +{ + var ret = defaultRet; + if(callbacks) + { + for(var callback in callbacks) + { + if(callback[1] & type) + { + ret = CallA(callback[0], args); + break; + } + } + } + + + if(!noGlobalCallbacks) + { + var globalRet = CallCallbacks(settings[DT_Menu_Settings_Callbacks], type, [ret, args], defaultRet, true); + if(GetType(globalRet) == C4V_Array && globalRet[0] == Menu_React_OverrideReaction) + { + ret = globalRet[1]; + } + } + + return ret; +} + +func Close(bool closeParents) +{ + closing = true; + if(subMenu) + { + subMenu->Close(); + } + if(closeParents && settings[DT_Menu_Settings_Parent]) settings[DT_Menu_Settings_Parent]->Close(true); + RemoveEffect("Menu", this); +} + +func Suspend(bool cont) +{ + if(suspended == !cont) return; + if(suspended = !cont) + { + CloseMenu(settings[DT_Menu_Settings_Object]); + } + else if(!closing) + { + Refresh(currentSelection); + } +} + +func AddEntries(array entries, &i) +{ + for(var entry in entries) + { + if(entry[0] == DT_Menu_Type_Entry) + { + var condition = entry[1][DT_Menu_Entry_Condition], conditionRet; + var caption = entry[1][DT_Menu_Entry_Caption], noCommand = !entry[1][DT_Menu_Entry_Placeholder] || (entry[1][DT_Menu_Entry_Placeholder] != true && !entry[1][DT_Menu_Entry_Callbacks]); + if(condition) + { + if(noCommand || condition[1] == Menu_Condition_DenySelection || (condition[1] == Menu_Condition_Default && !settings[DT_Menu_Settings_ConditionAllowSelection])) + { + noCommand = true; + } + + conditionRet = CallA(condition[0], [entry[1][DT_Menu_Entry_Symbol], settings[DT_Menu_Settings_Object], entry[1][DT_Menu_Entry_Args]]) || settings[DT_Menu_Settings_ConditionDisableMode]; + if(conditionRet == Menu_ConditionReact_Hide) + { + continue; + } + else if(conditionRet == Menu_ConditionReact_GrayOut) + { + caption = Format("%s", caption); + } + else if(GetType(conditionRet) == C4V_Array && conditionRet[0] == Menu_ConditionReact_CustomFormat) + { + caption = Format(conditionRet[1], caption); + } + else + { + noCommand = false; + } + } + + var symbol = entry[1][DT_Menu_Entry_Symbol], symbolID = 0; + if(GetType(symbol) == C4V_Array) + { + if(GetType(symbol[0]) == C4V_C4ID) + { + symbolID = symbol[0]; + if(symbol[1]) + { + entry[1][DT_Menu_Entry_Extra] |= C4MN_Add_ImgIndexed; + entry[1][DT_Menu_Entry_XPar1] = symbol[1]; + } + } + else if(GetType(symbol[0]) == C4V_C4Object) + { + entry[1][DT_Menu_Entry_Extra] |= C4MN_Add_ImgObject; + entry[1][DT_Menu_Entry_XPar1] = symbol[0]; + symbolID = GetID(symbol[0]); + } + } + else + { + symbolID = symbol; + } + entry[1][DT_Menu_Entry_Symbol] = symbolID; + + LocalN("entries")[i] = entry; + AddMenuItem(caption, !noCommand && "MenuItemCommand", symbolID, settings[DT_Menu_Settings_Object], entry[1][DT_Menu_Entry_Count], i++, entry[1][DT_Menu_Entry_InfoCaption], entry[1][DT_Menu_Entry_Extra], entry[1][DT_Menu_Entry_XPar1], entry[1][DT_Menu_Entry_XPar2]); + + if(GetType(symbol) == C4V_Array && GetType(symbol[0]) == C4V_C4Object && symbol[1]) + { + RemoveObject(symbol[0]); + } + } + else if(entry[0] == DT_Menu_Type_Factory) + { + for(var callback in entry[1][0]) + { + var factoryResult = CallA(callback, [entry[1][1], i]); + if(GetType(factoryResult) == C4V_Array) + { + var newEntries = []; + UncombineAndDistinguish(factoryResult, settings, newEntries); + AddEntries(newEntries, i); + } + else if(factoryResult == Menu_React_Close) + { + return Close(); + } + } + } + } +} + +func React(reaction, int itemNumber, int refreshDelayed) +{ + if(reaction == Menu_React_Close) + { + Close(!settings[DT_Menu_Settings_KeepParentOnClose]); + } + else if(reaction == Menu_React_Back) + { + Close(); + } + else if(reaction == Menu_React_Refresh || (settings[DT_Menu_Settings_KeepOpen] & DT_Menu_KeepOpen_Refresh)) + { + Refresh(itemNumber, refreshDelayed); + } + else if(reaction == Menu_React_KeepOpen && (settings[DT_Menu_Settings_KeepOpen] == DT_Menu_KeepOpen_Not || settings[DT_Menu_Settings_KeepOpen] == DT_Menu_KeepOpen_Permanent)) + { +// Refresh(itemNumber, refreshDelayed); + } + else if(GetType(reaction) == C4V_Array) + { + if(reaction[0] == Menu_React_SelectionOffset) + { + selectionOffset = reaction[1]; + } + else if(reaction[0] == Menu_React_SelectionChange) + { + selectionOverride = reaction[1] + 1; + } + } +} + +func CheckCondition(array entry) +{ + var condition = entry[DT_Menu_Entry_Condition]; + return !condition || (CallA(condition[0], [entry[DT_Menu_Entry_Symbol], settings[DT_Menu_Settings_Object], entry[DT_Menu_Entry_Args]]) || settings[DT_Menu_Settings_ConditionDisableMode]) == Menu_ConditionReact_Show; +} + +func MenuItemCommand(id ID, int itemNumber, int action) +{ + var entry = entries[itemNumber]; + var condition = entry[1][DT_Menu_Entry_Condition]; + action = action || Menu_CallbackType_Normal; + var reaction; + if(CheckCondition(entry[1])) + { + reaction = CallCallbacks(entry[1][DT_Menu_Entry_Callbacks], action, [action, ID, settings[DT_Menu_Settings_Object], entry[1][DT_Menu_Entry_Args]]); + } + else + { + if(condition[1] == Menu_Condition_AllowSelection) + { + reaction = Menu_React_KeepOpen; + } + else + { + reaction = Menu_React_Refresh; + } + } + React(reaction, itemNumber); +} + +func SubmenuItemCallback(int action, id ID, object menuObject, args) +{ + var reaction = CallCallbacks(args[0], action, CreateFilledArray(action, ID, menuObject, args[1], ...), Menu_React_None); + + if(((action & Menu_CallbackType_Defaults) && reaction == Menu_React_None) || reaction == Menu_React_ShowSubmenu) + { + subMenu = CreateNewMenu(args[2], settings, this); + return Menu_React_None; + } + else + { + return reaction; + } +} + +func MenuQueryCancel(int selection, object menuObject) +{ + if(selection != -1) + { + var entry = entries[selection]; + var reaction; + if(entry[0] == DT_Menu_Type_Entry) + { + if(CheckCondition(entry[1])) + { + reaction = CallCallbacks(entry[1][DT_Menu_Entry_Callbacks], Menu_CallbackType_Close, [Menu_CallbackType_Close, entry[1][DT_Menu_Entry_Symbol], settings[DT_Menu_Settings_Object], entry[1][DT_Menu_Entry_Args]]); + } + } + + React(reaction, selection, true); + } + + if(settings[DT_Menu_Settings_KeepOpen] != DT_Menu_KeepOpen_Not && settings[DT_Menu_Settings_KeepOpen] != DT_Menu_KeepOpen_Permanent) + { + return true; + } +} + +func OnMenuSelection(int selection, object menuObject) +{ + if(selection != currentSelection) + { + var oldSelection = currentSelection; + var entry = entries[currentSelection]; + if(!noSelectionCallbacks && entry[0] == DT_Menu_Type_Entry && CheckCondition(entry[1]) && currentSelection != -1) + { + CallCallbacks(entry[1][DT_Menu_Entry_Callbacks], Menu_CallbackType_Deselection, [Menu_CallbackType_Deselection, entry[1][DT_Menu_Entry_Symbol], settings[DT_Menu_Settings_Object], entry[1][DT_Menu_Entry_Args], oldSelection, selection]); + } + entry = entries[currentSelection = selection]; + if(!noSelectionCallbacks && entry[0] == DT_Menu_Type_Entry && CheckCondition(entry[1])) + { + CallCallbacks(entry[1][DT_Menu_Entry_Callbacks], Menu_CallbackType_Selection, [Menu_CallbackType_Selection, entry[1][DT_Menu_Entry_Symbol], settings[DT_Menu_Settings_Object], entry[1][DT_Menu_Entry_Args], selection, oldSelection]); + } + } +} + +func Refresh(int selection, bool delayed) +{ + if(suspended) + { + return; + } + + if(delayed) + { + ScheduleCall(this, "Refresh", 1, 0, selection); + } + else + { + var disabledCallbacks; + if(!noSelectionCallbacks) + { + disabledCallbacks = noSelectionCallbacks = true; + } + + CloseMenu(settings[DT_Menu_Settings_Object]); + Create(settings, createEntries); + var newSelection = selection; + selectionOverride && (newSelection = selectionOverride-1); + SelectEntry(BoundBy(newSelection + selectionOffset, 0, entryCount-1)); + selectionOffset = 0; + selectionOverride = 0; + + if(disabledCallbacks) + { + noSelectionCallbacks = false; + } + } +} + +// ---------------------------------------------------------------------------- + +global func Menu__Setting(array setting) { return [DT_Menu_Type_Setting, setting]; } + +global func Menu_Symbol(id symbol) { return Menu__Setting([DT_Menu_Settings_Symbol, symbol]); } +global func Menu_Object(object obj) { return Menu__Setting([DT_Menu_Settings_Object, obj]); } +global func Menu__Extra(int extra, int data) { return Menu_Combined([Menu__Setting([DT_Menu_Settings_Extra, extra]), Menu_ExtraData(data)]); } +global func Menu_Size(int width, int height) { return Menu__Setting([DT_Menu_Settings_Size, [width, height]]); } +global func Menu_ExtraData(int data) { return Menu__Setting([DT_Menu_Settings_ExtraData, data]); } +global func Menu_Caption(string caption) { return Menu__Setting([DT_Menu_Settings_Caption, caption]); } +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__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]); } + +global func Menu_Extra_None() { return Menu__Extra(C4MN_Extra_None); } +global func Menu_Extra_Components() { return Menu__Extra(C4MN_Extra_Components); } +global func Menu_Extra_Value() { return Menu__Extra(C4MN_Extra_Value); } +global func Menu_Extra_MagicValue(int compare) { return Menu__Extra(C4MN_Extra_MagicValue, compare); } +global func Menu_Extra_Info() { return Menu__Extra(C4MN_Extra_Info); } +global func Menu_Extra_ComponentsMagic() { return Menu__Extra(C4MN_Extra_ComponentsMagic); } + +global func Menu_Style_Normal() { return Menu__Style(C4MN_Style_Normal); } +global func Menu_Style_Context() { return Menu__Style(C4MN_Style_Context); } +global func Menu_Style_Info() { return Menu__Style(C4MN_Style_Info); } +global func Menu_Style_Dialog() { return Menu__Style(C4MN_Style_Dialog); } +global func Menu_Style_EqualItemHeight() { return Menu__Style(C4MN_Style_EqualItemHeight); } + +global func Menu_DontKeepOpen() { return Menu__KeepOpen(DT_Menu_KeepOpen_Not); } +global func Menu_KeepOpen() { return Menu__KeepOpen(DT_Menu_KeepOpen_Keep); } +global func Menu_ForceKeepOpen() { return Menu__KeepOpen(DT_Menu_KeepOpen_Force); } +global func Menu_Refresh() { return Menu__KeepOpen(DT_Menu_KeepOpen_Refresh); } +global func Menu_RefreshContinously(int interval) { return Menu_Combined([Menu__KeepOpen(DT_Menu_KeepOpen_RefreshContinously), Menu_RefreshInterval(interval)]); } +global func Menu_Permanent() { return Menu__KeepOpen(DT_Menu_KeepOpen_Permanent); } + +global func Menu_ConditionAllowSelection() { return Menu__Setting([DT_Menu_Settings_ConditionAllowSelection, true]);} +global func Menu_ConditionDenySelection() { return Menu__Setting([DT_Menu_Settings_ConditionAllowSelection, false]);} + +global func Menu_Callbacks(array callbacks) { return Menu__Setting([DT_Menu_Settings_Callbacks, callbacks]); } +global func Menu_Decoration(id decoration) { return Menu__Setting([DT_Menu_Settings_Decoration, decoration]); } +global func Menu_RequireAction(string action, object target) { return Menu__Setting([DT_Menu_Settings_RequireAction, [action, target]]); } +global func Menu_KeepParentOnClose(bool dontKeep) { return Menu__Setting([DT_Menu_Settings_KeepParentOnClose, !dontKeep]); } +global func Menu_ConditionDisableMode(mode) { return Menu__Setting([DT_Menu_Settings_ConditionDisableMode, mode]);} + +global func Menu_Callback(array callback, int types) +{ + return [callback, types || Menu_CallbackType_Defaults]; +} + +global func Menu_Entry_Caption(string Caption) { return [DT_Menu_Entry_Caption, Caption]; } +global func Menu_Entry_Callbacks(array Callbacks) { return [DT_Menu_Entry_Callbacks, Callbacks]; } +global func Menu_Entry_Count(int Count) { return [DT_Menu_Entry_Count, Count]; } +global func Menu_Entry_InfoCaption(string InfoCaption) { return [DT_Menu_Entry_InfoCaption, InfoCaption]; } +global func Menu_Entry_Extra(int Extra) { return [DT_Menu_Entry_Extra, Extra]; } +global func Menu_Entry_XPar1(XPar1) { return [DT_Menu_Entry_XPar1, XPar1]; } +global func Menu_Entry_XPar2(XPar2) { return [DT_Menu_Entry_XPar2, XPar2]; } +global func Menu_Entry_Args(Args) { return [DT_Menu_Entry_Args, Args]; } +global func Menu_Entry_Placeholder(bool Placeholder) { return [DT_Menu_Entry_Placeholder, Placeholder]; } +global func Menu_Entry_Symbol(symbol, extra) +{ + if(GetType(symbol) == C4V_Array) + { + return [DT_Menu_Entry_Symbol, symbol]; + } + else + { + return [DT_Menu_Entry_Symbol, [symbol, extra]]; + } +} +global func Menu_Entry_Condition(callback, int allowDisabledSelection) { return [DT_Menu_Entry_Condition, [callback, allowDisabledSelection]]; } +global func Menu_Entry_VariableCondition(array scopedVar, compare, int disableMode, bool invert, int allowDisabledSelection) +{ + return Menu_Entry_Condition(BindCallback(MN7I->MenuObjectCallback("VariableCondition"), [Bind(scopedVar), Bind(compare), Bind(disableMode), Bind(invert)]), allowDisabledSelection); +} +global func VariableCondition(array scopedVar, compare, int disableMode, bool invert) +{ + var disable = ScopedVar(scopedVar) != compare; + if(invert) + { + disable = !disable; + } + if(disable) + { + return disableMode; + } + else + + { + return Menu_ConditionReact_Show; + } +} +global func Menu_Entry_Object(object obj) +{ + return Menu_Combined([Menu_Entry_Symbol(obj), Menu_Entry_Caption(GetName(obj)), Menu_Entry_InfoCaption(GetDesc(obj))]); +} + +global func Menu_Entry(caption, array callback, id symbol, int count, string infoCaption, args, int extra, XPar1, XPar2) +{ + if(!caption) + { + caption = [Menu_Entry_Placeholder(false)]; + } + if(GetType(caption) == C4V_Array) // then caption is an array of named args + { + var namedArgs = []; + namedArgs[DT_Menu_Entry_Caption] = ""; + namedArgs[DT_Menu_Entry_Placeholder] = -1; + MN7I->NamedArgs(caption, namedArgs); + if(!namedArgs[DT_Menu_Entry_InfoCaption]) + { + namedArgs[DT_Menu_Entry_Extra] |= C4MN_Add_ForceNoDesc; + } + return [DT_Menu_Type_Entry, namedArgs]; + } + else // unnamed arguments for shorter code + { + var ret = [DT_Menu_Type_Entry, [caption || "", [Menu_Callback(callback)], symbol, count, infoCaption, extra, XPar1, XPar2, args]]; + ret[1][DT_Menu_Entry_Placeholder] = -1; + if(!infoCaption) + { + ret[1][DT_Menu_Entry_Extra] |= C4MN_Add_ForceNoDesc; + } + return ret; + } +} +global func Menu_AutoEntry(id_or_obj, array callbacks, int count) +{ + var id, id_, obj; + if(GetType(id_or_obj) == C4V_C4ID) + { + id_ = id = id_or_obj; + } + else if(GetType(id_or_obj) == C4V_C4Object) + { + obj = id_or_obj; + id = GetID(obj); + } + else + { + FatalError("Menu_AutoEntry: No ID or object given."); + return; + } + + return [DT_Menu_Type_Entry, [GetName(obj, id_), callbacks, id, count, GetDesc(obj, id_)]]; +} + +global func Menu_SubMenu(array entrySettings, array menuEntry_Settings) +{ + var ret = Menu_Entry(entrySettings); + ret[1][DT_Menu_Entry_Args] = [ret[1][DT_Menu_Entry_Callbacks], ret[1][DT_Menu_Entry_Args], menuEntry_Settings]; + ret[1][DT_Menu_Entry_Callbacks] = [Menu_Callback(MN7I->MenuObjectCallback("SubmenuItemCallback"), Menu_CallbackType_All)]; + return ret; +} + +global func Menu_Factory(array callbacks, args) +{ + return [DT_Menu_Type_Factory, [callbacks, args]]; +} + +global func Menu_Decline(array callbacks, string caption, string infoCaption, args) +{ + caption || (caption = "$Decline$"); + caption = Format("{{MN7I:2}} %s", caption); + return Menu_Entry(caption, MN7I->MenuObjectCallback("DeclineAcceptCommand"), 0, 0, infoCaption, [callbacks, args]); +} + +global func Menu_Accept(array callback, string caption, string infoCaption, args) +{ + caption || (caption = "$Accept$"); + caption = Format("{{MN7I:1}} %s", caption); + return Menu_Entry(caption, MN7I->MenuObjectCallback("DeclineAcceptCommand"), 0, 0, infoCaption, [callback, args]); +} + +global func Menu_Back(array callback, string caption, string infoCaption, args) +{ + caption || (caption = "$Back$"); + caption = Format("{{MN7I:5}} %s", caption); + return Menu_Entry(caption, MN7I->MenuObjectCallback("BackCommand"), 0, 0, infoCaption, [callback, args]); +} + +global func Menu_Adaptor_Type(int Type) { return [DT_Menu_Adaptor_Type, Type]; } +global func Menu_Adaptor_Variable(array Variable) { return [DT_Menu_Adaptor_Variable, Variable]; } +global func Menu_Adaptor_Callbacks(array Callbacks) { return [DT_Menu_Adaptor_Callbacks, Callbacks]; } +global func Menu_Adaptor_MessageBoardText(string MessageBoardText) { return [DT_Menu_Adaptor_MessageBoardText, MessageBoardText]; } +global func Menu_Adaptor_WrapAround(bool WrapAround) { return [DT_Menu_Adaptor_WrapAround, WrapAround]; } +global func Menu_Adaptor_EnumSubmenuSymbol(id EnumSubmenuSymbol) { return [DT_Menu_Adaptor_EnumSubmenuSymbol, EnumSubmenuSymbol]; } +global func Menu_Adaptor_EnumSubmenu(int callbackType) { return [DT_Menu_Adaptor_EnumSubmenu, callbackType]; } +global func Menu_Adaptor_Limits(int min, int max) { return [DT_Menu_Adaptor_Limits, [min, max]]; } +global func Menu_Adaptor_StepSize(int step, force) { return [DT_Menu_Adaptor_StepSize, [step, force]]; } +global func Menu_Adaptor_Enum(array enumVals, array layout, bool valuesAsSeparateLists) +{ + MN7I->AdaptorLayout(layout, enumVals, valuesAsSeparateLists); + return Menu_Combined([Menu_Adaptor_Type(Menu_AdaptorType_Enum), [DT_Menu_Adaptor_LayoutVals, [enumVals, layout]]]); +} +global func Menu_Adaptor_BitField(array fieldVals, array layout, bool valuesAsSeparateLists) +{ + MN7I->AdaptorLayout(layout, fieldVals, valuesAsSeparateLists); + return Menu_Combined([Menu_Adaptor_Type(Menu_AdaptorType_BitField), [DT_Menu_Adaptor_LayoutVals, [fieldVals, layout]]]); +} +global func Menu_Adaptor_NoEmptyString() { return [DT_Menu_Adaptor_NoEmptyString, true]; } +global func Menu_Adaptor_EnumSubmenuCaption(string menuCaption, string entryCaption) +{ + return [DT_Menu_Adaptor_EnumSubmenuCaption, [menuCaption, entryCaption]]; +} +global func Menu_Adaptor_Boolean() { return Menu_Adaptor_Type(Menu_AdaptorType_Boolean); } +global func Menu_Adaptor_Integer() { return Menu_Adaptor_Type(Menu_AdaptorType_Integer); } +global func Menu_Adaptor_String() { return Menu_Adaptor_Type(Menu_AdaptorType_String); } +global func Menu_Adaptor_ID() { return Menu_Adaptor_Type(Menu_AdaptorType_ID); } + +func AdaptorLayout(array& layout, array& vals, bool valuesAsSeparateLists) +{ + layout = layout || [Menu_Layout_Value | Menu_Layout_Caption]; + var layoutMap = []; + var index = 1; + for(var val in layout) + { + var noFlag = val & Menu_Layout__NoFlagMask; + + if(noFlag) + { + layoutMap[noFlag] = index; + } + + if(val & Menu_Layout_Caption) + { + layoutMap[Menu_Layout__CaptionPos] = index; + } + + if(val & Menu_Layout_Value) + { + layoutMap[Menu_Layout__ValuePos] = index; + } + +// if(val & Menu_Layout_InputValue) TODO +// { +// layoutMap[Menu_Layout__InputValuePos] = index; +// } + + ++index; + } + + layout = layoutMap; + + if(valuesAsSeparateLists) + { + var tempVals = vals; + var vals = []; + + for(var i = 0; i < GetLength(tempVals[0]); ++i) + { + vals[i] = []; + + for(var j = 0; j < GetLength(tempVals); ++j) + { + vals[i][j] = tempVals[j][i]; + } + } + } +} + +global func Menu_Adaptor(array entrySettings, array adaptorSettings) +{ + var adaptorArgs = []; + + adaptorArgs[DT_Menu_Adaptor_WrapAround] = -1; + adaptorArgs[DT_Menu_Adaptor_EnumSubmenu] = Menu_CallbackType_Special2; + + MN7I->NamedArgs(adaptorSettings, adaptorArgs); + + if(adaptorArgs[DT_Menu_Adaptor_WrapAround] == -1) + { + if(adaptorArgs[DT_Menu_Adaptor_Type] == Menu_AdaptorType_Integer) + { + adaptorArgs[DT_Menu_Adaptor_WrapAround] = false; + } + else if(adaptorArgs[DT_Menu_Adaptor_Type] == Menu_AdaptorType_Enum) + { + adaptorArgs[DT_Menu_Adaptor_WrapAround] = true; + } + } + + return Menu_Factory([MN7I->MenuObjectCallback("AdaptorFactory")], [Menu_Entry(entrySettings)[1], adaptorArgs, entrySettings]); +} + +func EnumValPos(array enumVals, array layout, val) +{ + for(var i = 0; i < GetLength(enumVals); ++i) + { + if(enumVals[i][layout[Menu_Layout__ValuePos] - 1] == val) + { + return i; + } + } + return -1; +} + +func BooleanToggleCaption(bool val, string caption) +{ + val = !!val; + return Format("{{MN7I:%d}} %s", [2, 1][val], [RGB(128, 128, 128), RGB(255, 255, 255)][val], caption); +} + +func InlineSymbol(string& caption, symbol) +{ + caption = Format("{{%i:%d}} %s", symbol[0], symbol[1], caption); +} + +func ExtraSymbol(string& caption, &symbol, extraSymbol) +{ + if(GetType(extraSymbol) == C4V_C4ID) + { + extraSymbol = [extraSymbol]; + } + + if(symbol && extraSymbol && GetType(extraSymbol[0]) == C4V_C4ID) + { + InlineSymbol(caption, extraSymbol); + } + else + { + symbol = extraSymbol; + } +} + +func EnumEntrySettings(string& caption, &symbol, string& infoCaption, int index, array args, array entry) +{ + var layoutVals = args[DT_Menu_Adaptor_LayoutVals]; + var layout = layoutVals[1]; + layoutVals = layoutVals[0]; + + caption = entry[DT_Menu_Entry_Caption]; + if(layout[Menu_Layout__CaptionPos]) + { + caption = Format(caption, layoutVals[index][layout[Menu_Layout__CaptionPos] - 1]); + } + + if(layout[Menu_Layout_Symbol]) + { + ExtraSymbol(caption, symbol, layoutVals[index][layout[Menu_Layout_Symbol] - 1]); + } + + if(layout[Menu_Layout_InfoCaption]) + { + infoCaption = Format(infoCaption, layoutVals[index][layout[Menu_Layout_InfoCaption] - 1]); + } +} + +func AdaptorFactory(args, int entryIndex) +{ + var entry = args[0]; + var entrySettings = args[2]; + args = args[1]; + var caption; + var infoCaption = entry[DT_Menu_Entry_InfoCaption]; + var symbol = entry[DT_Menu_Entry_Symbol]; + var val = ScopedVar(args[DT_Menu_Adaptor_Variable]); + var defaultMsgboardText = "$EnterValue$"; + + var retSubmenu; + + args[DT_Menu_Adaptor_Args] = entry[DT_Menu_Entry_Args]; + args[DT_Menu_Adaptor_EntryIndex] = entryIndex; + args[DT_Menu_Adaptor_Callbacks] = args[DT_Menu_Adaptor_Callbacks] || []; + if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_Boolean) + { + caption = BooleanToggleCaption(val, entry[DT_Menu_Entry_Caption]); + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_String) + { + caption = Format(entry[DT_Menu_Entry_Caption], val); + defaultMsgboardText = "$EnterText$"; + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_Integer) + { + var limits = args[DT_Menu_Adaptor_Limits], max, min; + var wrapAround = args[DT_Menu_Adaptor_WrapAround]; + if(limits && !wrapAround) + { + if(val >= limits[1]) + { + max = true; + } + if(val <= limits[0]) + { + min = true; + } + } + caption = Format("%s %s %s", ["{{MN7I:3}}", "{{MN7I:3}}"][max], Format(entry[DT_Menu_Entry_Caption], val), ["{{MN7I:4}}", "{{MN7I:4}}"][min]); + defaultMsgboardText = "$EnterNumber$"; + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_ID) + { + var text = ""; + if(val) + { + text = Format("{{%i}} %s", val, GetName(0, val)); + } + caption = Format(entry[DT_Menu_Entry_Caption], text); + defaultMsgboardText = "$EnterIDOrName$"; + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_Enum) + { + var layoutVals = args[DT_Menu_Adaptor_LayoutVals]; + var layout = layoutVals[1]; + layoutVals = layoutVals[0]; + + var index = EnumValPos(layoutVals, layout, val); + + if(index == -1) + { + ScopedVar(args[DT_Menu_Adaptor_Variable]) = layoutVals[0][layout[Menu_Layout__ValuePos] - 1]; + index = 0; + } + + var submenuSymbol = symbol; + + EnumEntrySettings(caption, symbol, infoCaption, index, args, entry); + + if(args[DT_Menu_Adaptor_EnumSubmenu] != Menu_CallbackType_None) + { + args[DT_Menu_Adaptor_MessageBoardText] = args[DT_Menu_Adaptor_MessageBoardText] || defaultMsgboardText; + + var submenuCaption = args[DT_Menu_Adaptor_EnumSubmenuCaption]; + + if(submenuCaption && submenuCaption[0]) + { + submenuCaption = submenuCaption[0]; + } + else + { + submenuCaption = caption; + } + + retSubmenu = [ + Menu_KeepParentOnClose(), + Menu_Caption(submenuCaption), + Menu_DontKeepOpen(), + + Menu_Factory([MenuObjectCallback("AdaptorEnumSubmenuFactory")], [args, entry]) + ]; + + if(args[DT_Menu_Adaptor_EnumSubmenuSymbol]) + { + submenuSymbol = [args[DT_Menu_Adaptor_EnumSubmenuSymbol]]; + } + else if(!submenuSymbol && symbol && GetType(symbol[0]) == C4V_C4ID) + { + submenuSymbol = symbol; + } + + if(submenuSymbol && GetType(submenuSymbol[0]) == C4V_C4ID) + { + ArrayAppend(retSubmenu, Menu_Symbol(submenuSymbol[0])); + } + } + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_BitField) + { + args[DT_Menu_Adaptor_MessageBoardText] = args[DT_Menu_Adaptor_MessageBoardText] || defaultMsgboardText; + + var layoutVals = args[DT_Menu_Adaptor_LayoutVals]; + var layout = layoutVals[1]; + layoutVals = layoutVals[0]; + + var fieldValue = ScopedVar(args[DT_Menu_Adaptor_Variable]); + var ret = []; + + for(var val in layoutVals) + { + caption = entry[DT_Menu_Entry_Caption] || "%s"; + if(layout[Menu_Layout__CaptionPos]) + { + caption = Format(caption, val[layout[Menu_Layout__CaptionPos] - 1]); + } + caption = BooleanToggleCaption(fieldValue & (1 << val[layout[Menu_Layout__ValuePos] - 1]), caption); + + symbol = entry[DT_Menu_Entry_Symbol]; + if(layout[Menu_Layout_Symbol]) + { + ExtraSymbol(caption, symbol, val[layout[Menu_Layout_Symbol] - 1]); + } + + if(layout[Menu_Layout_InfoCaption]) + { + infoCaption = Format(infoCaption, val[layout[Menu_Layout_InfoCaption] - 1]); + } + + args[DT_Menu_Adaptor_Bit] = val[layout[Menu_Layout__ValuePos] - 1]; + + ArrayAppend(ret, Menu_Entry([Menu_Combined(entrySettings), Menu_Entry_Caption(caption), Menu_Entry_Callbacks([Menu_Callback(MenuObjectCallback("AdaptorCommand"), Menu_CallbackType_All)]), Menu_Entry_Symbol(symbol), Menu_Entry_InfoCaption(infoCaption), Menu_Entry_Args(args)])); + } + + return ret; + } + args[DT_Menu_Adaptor_MessageBoardText] = args[DT_Menu_Adaptor_MessageBoardText] || defaultMsgboardText; + if(!retSubmenu) + { + return [Menu_Entry([Menu_Combined(entrySettings), Menu_Entry_Caption(caption), Menu_Entry_Callbacks([Menu_Callback(MenuObjectCallback("AdaptorCommand"), Menu_CallbackType_All)]), Menu_Entry_Symbol(symbol), Menu_Entry_InfoCaption(infoCaption), Menu_Entry_Args(args)])]; + } + else + { + return [Menu_SubMenu([Menu_Combined(entrySettings), Menu_Entry_Caption(caption), Menu_Entry_Callbacks([Menu_Callback(MenuObjectCallback("AdaptorCommand"), Menu_CallbackType_All)]), Menu_Entry_Symbol(symbol), Menu_Entry_InfoCaption(infoCaption), Menu_Entry_Args(args)], retSubmenu)]; + } +} + +func AdaptorEnumSubmenuFactory(array args) +{ + var entry = args[1]; + args = args[0]; + var layoutVals = args[DT_Menu_Adaptor_LayoutVals]; + var layout = layoutVals[1]; + layoutVals = layoutVals[0]; + + var ret = [Menu_Selection(EnumValPos(layoutVals, layout, ScopedVar(args[DT_Menu_Adaptor_Variable])))]; + + var caption, infoCaption, symbol; + + var submenuCaption = args[DT_Menu_Adaptor_EnumSubmenuCaption]; + if(submenuCaption && submenuCaption[1]) + { + entry[DT_Menu_Entry_Caption] = submenuCaption[1]; + } + + for(var i = 0; i < GetLength(layoutVals); ++i) + { + symbol = 0; + EnumEntrySettings(caption, symbol, infoCaption, i, args, entry); + ArrayAppend(ret, Menu_Entry([Menu_Entry_Caption(caption), Menu_Entry_Symbol(symbol), Menu_Entry_InfoCaption(infoCaption), Menu_Entry_Callbacks([Menu_Callback(MenuObjectCallback("AdaptorEnumSubmenuItem"))]), Menu_Entry_Args([i, args])])); + } + + return ret; +} + +func AdaptorEnumSubmenuItem(int action, id ID, object obj, args) +{ + var index = args[0]; + args = args[1]; + + var val = ScopedVar(args[DT_Menu_Adaptor_Variable]); + var oldVal = val; + + var enumVals = args[DT_Menu_Adaptor_LayoutVals]; + var layout = enumVals[1]; + enumVals = enumVals[0]; + + ScopedVar(args[DT_Menu_Adaptor_Variable]) = val = enumVals[index][layout[Menu_Layout__ValuePos] - 1]; + var reaction = CallCallbacks(args[DT_Menu_Adaptor_Callbacks], Menu_CallbackType_ValueChanged, [Menu_CallbackType_ValueChanged, ID, obj, args[DT_Menu_Adaptor_Args], val, oldVal, true]); + if(reaction != Menu_React_None) + { + return reaction; + } + + return Menu_React_Back; +} + +func WrapOrBind(int val, array limits, bool wrap) +{ + if(!limits) + { + return val; + } + + var min = limits[0]; + var max = limits[1]; + + if(val < min) + { + if(wrap) + { + return max; + } + else + { + return min; + } + } + else if(val > max) + { + if(wrap) + { + return min; + } + else + { + return max; + } + } + else + { + return val; + } +} + +func AdaptorCommand(int action, id ID, object obj, args) // TODO: Callback bei CallMessageBoard? +{ + var callbackArgs = args[DT_Menu_Adaptor_Args]; + var val = ScopedVar(args[DT_Menu_Adaptor_Variable]); + var oldVal = val; + var reaction = CallCallbacks(args[DT_Menu_Adaptor_Callbacks], action, CreateFilledArray(action, ID, obj, callbackArgs, ...), Menu_React_Refresh, true); + if(reaction != Menu_React_Refresh) + { + return reaction; + } + if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_Boolean) + { + if(action & (Menu_CallbackType_Normal | Menu_CallbackType_Special2)) + { + ScopedVar(args[DT_Menu_Adaptor_Variable]) = val = !val; + reaction = CallCallbacks(args[DT_Menu_Adaptor_Callbacks], Menu_CallbackType_ValueChanged, [Menu_CallbackType_ValueChanged, ID, obj, callbackArgs, val, oldVal]); + if(reaction != Menu_React_None) + { + return reaction; + } + } + else + { + return Menu_React_KeepOpen; + } + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_Integer) + { + var limits = args[DT_Menu_Adaptor_Limits]; + var wrapAround = args[DT_Menu_Adaptor_WrapAround]; + var step = args[DT_Menu_Adaptor_StepSize]; + var stepSize = 1; + if(step) + { + stepSize = step[0]; + } + if(action == Menu_CallbackType_Special2) + { + if(msgBoardMode == 0) + { + msgBoardMode = Menu_AdaptorType_Integer + 1; + msgBoardEntry = args[DT_Menu_Adaptor_EntryIndex]; + CallMessageBoard(this, false, args[DT_Menu_Adaptor_MessageBoardText], GetOwner(obj)); + } + return Menu_React_KeepOpen; + } + else if(action == Menu_CallbackType_Normal) + { + val += stepSize; + } + else if(action == Menu_CallbackType_Close) + { + val -= stepSize; + } + else + { + return Menu_React_KeepOpen; + } + + val = WrapOrBind(val, limits, wrapAround); + + if(val != oldVal) + { + ScopedVar(args[DT_Menu_Adaptor_Variable]) = val; + reaction = CallCallbacks(args[DT_Menu_Adaptor_Callbacks], Menu_CallbackType_ValueChanged, [Menu_CallbackType_ValueChanged, ID, obj, callbackArgs, val, oldVal]); + if(reaction != Menu_React_None) + { + return reaction; + } + } + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_String) + { + if(action & (Menu_CallbackType_Normal | Menu_CallbackType_Special2)) + { + if(msgBoardMode == 0) + { + msgBoardMode = Menu_AdaptorType_String + 1; + msgBoardEntry = args[DT_Menu_Adaptor_EntryIndex]; + CallMessageBoard(this, false, args[DT_Menu_Adaptor_MessageBoardText], GetOwner(obj)); + } + } + if(action == Menu_CallbackType_Close) + { + return Menu_React_None; + } + else + { + return Menu_React_KeepOpen; + } + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_ID) + { + if(action & (Menu_CallbackType_Normal | Menu_CallbackType_Special2)) + { + if(msgBoardMode == 0) + { + msgBoardMode = Menu_AdaptorType_ID + 1; + msgBoardEntry = args[DT_Menu_Adaptor_EntryIndex]; + CallMessageBoard(this, false, args[DT_Menu_Adaptor_MessageBoardText], GetOwner(obj)); + } + } + return Menu_React_KeepOpen; + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_Enum) + { + if(GetType(args[DT_Menu_Adaptor_EnumSubmenu]) == C4V_Bool) + { + if(action & Menu_CallbackType_Defaults) + { + return Menu_React_ShowSubmenu; + } + else + { + return Menu_React_None; + } + } + + if(args[DT_Menu_Adaptor_EnumSubmenu] & action) + { + return Menu_React_ShowSubmenu; + } + + var enumVals = args[DT_Menu_Adaptor_LayoutVals]; + var layout = enumVals[1]; + enumVals = enumVals[0]; + + var index = EnumValPos(enumVals, layout, val); + var wrapAround = args[DT_Menu_Adaptor_WrapAround]; + + if(action & (Menu_CallbackType_Normal | Menu_CallbackType_Special2)) + { + ++index; + } + else if(action == Menu_CallbackType_Close) + { + --index; + } + else + { + return Menu_React_None; + } + + index = WrapOrBind(index, [0, GetLength(enumVals) - 1], wrapAround); + + ScopedVar(args[DT_Menu_Adaptor_Variable]) = val = enumVals[index][layout[Menu_Layout__ValuePos] - 1]; + reaction = CallCallbacks(args[DT_Menu_Adaptor_Callbacks], Menu_CallbackType_ValueChanged, [Menu_CallbackType_ValueChanged, ID, obj, callbackArgs, val, oldVal]); + if(reaction != Menu_React_None) + { + return reaction; + } + } + else if(args[DT_Menu_Adaptor_Type] == Menu_AdaptorType_BitField) + { + if(action & (Menu_CallbackType_Normal | Menu_CallbackType_Special2)) + { + ScopedVar(args[DT_Menu_Adaptor_Variable]) = (val ^= (1 << args[DT_Menu_Adaptor_Bit])); + reaction = CallCallbacks(args[DT_Menu_Adaptor_Callbacks], Menu_CallbackType_ValueChanged, [Menu_CallbackType_ValueChanged, ID, obj, callbackArgs, val, oldVal]); + if(reaction != Menu_React_None) + { + return reaction; + } + } + else + { + return Menu_React_KeepOpen; + } + } + + return Menu_React_Refresh; +} + +func InputCallback(string input, int plr) +{ + var entry = entries[msgBoardEntry]; + var args = entry[1][DT_Menu_Entry_Args]; + var callbackArgs = args[DT_Menu_Adaptor_Args]; + var oldVal = ScopedVar(args[DT_Menu_Adaptor_Variable]); + var val = input; + if(msgBoardMode - 1 == Menu_AdaptorType_Integer) + { + var int = ParseInt(input); + var limits = args[DT_Menu_Adaptor_Limits]; + var step = args[DT_Menu_Adaptor_StepSize]; + if(GetType(int) == C4V_Int || GetType(int) == C4V_Any) + { + if(step && step[1]) + { + var s = step[0]; + if(GetType(step[1]) == C4V_Int) + { + s = step[1]; + } + int = ((int + s / 2) / s) * s; + } + if(limits) + { + int = BoundBy(int, limits[0], limits[1]); + } + ScopedVar(args[DT_Menu_Adaptor_Variable]) = val = int; + } + else + { + val = oldVal; + } + } + else if(msgBoardMode - 1 == Menu_AdaptorType_String) + { + if(args[DT_Menu_Adaptor_NoEmptyString] && (!input || input == "")) + { + val = oldVal; + } + else + { + ScopedVar(args[DT_Menu_Adaptor_Variable]) = input; + } + } + else if(msgBoardMode - 1 == Menu_AdaptorType_ID) + { + val = GetIDByName(input); // WARNING: desyncs between clients with different languages + if(!val && GetLength(input) == 4) val = C4Id(input); + if(!GetName(0, val)) val = 0; + ScopedVar(args[DT_Menu_Adaptor_Variable]) = val; + } + msgBoardMode = 0; + if(val != oldVal) + { + var reaction = CallCallbacks(args[DT_Menu_Adaptor_Callbacks], Menu_CallbackType_ValueChanged, [Menu_CallbackType_ValueChanged, entry[1][DT_Menu_Entry_Symbol], settings[DT_Menu_Settings_Object], callbackArgs, val, oldVal]); + if(reaction != Menu_React_None) + { + return React(reaction, msgBoardEntry); + } + } + Refresh(msgBoardEntry); +} + +global func Menu_Combined(array combined) { return [DT_Menu_Combined, combined]; } + +global func CreateNewMenu(array menu, inheritSettings, object parentMenu) +{ + var settings = inheritSettings; + + 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_Callbacks] = 0; // Global callbacks can't be inherited (maybe filter callbacks) + + settings[DT_Menu_Settings_Parent] = parentMenu; + + var entries = []; + + MN7I->UncombineAndDistinguish(menu, settings, entries); + + var menuObj = CreateObject(MN7I); + + menuObj->Create(settings, entries); + + return menuObj; +} + +func NamedArg(array namedArg, array &args) +{ + args[namedArg[0]] = namedArg[1]; +} + +func UncombineAndDistinguish(array combined, array &settings, array &entries) +{ + for(var val in combined) + { + if(val[0] == DT_Menu_Type_Setting) + { + if((val[1][0] == DT_Menu_Settings_Style && val[1][1] == C4MN_Style_EqualItemHeight) || settings[DT_Menu_Settings_Style] == C4MN_Style_EqualItemHeight) + { + settings[DT_Menu_Settings_Style] |= val[1][1]; + } + else + { + NamedArg(val[1], settings); + } + } + else if(val[0] == DT_Menu_Type_Entry || val[0] == DT_Menu_Type_Factory) + { + entries[GetLength(entries)] = val; + } + else if(val[0] == DT_Menu_Combined) + { + UncombineAndDistinguish(val[1], settings, entries); + } + } +} + +func NamedArgs(array namedArgs, array& args) +{ + for(var arg in namedArgs) + { + if(arg[0] == DT_Menu_Combined) + { + NamedArgs(arg[1], args); + } + else + { + NamedArg(arg, args); + } + } +} + +func DeclineAcceptCommand(int action, id ID, object obj, args) +{ + if(args[0]) + { + var reaction = CallA(args[0], [action, ID, settings[DT_Menu_Settings_Object], args[1]]); + if(reaction != Menu_React_None) return reaction; + } + return Menu_React_Close; +} + +func BackCommand(int action, id ID, object obj, args) +{ + if(args[0]) + { + var reaction = CallA(args[0], [action, ID, settings[DT_Menu_Settings_Object], args[1]]); + if(reaction != Menu_React_None) return reaction; + } + return Menu_React_Back; +} + +func MenuObjectCallback(string name) +{ + return [CallbackTarget_Scenario - 1, name]; +} + +func CallCustom(callback, args) +{ + if(GetType(callback) == C4V_Array && GetLength(callback) == 2 && callback[0] == CallbackTarget_Scenario - 1) + { + return CallA(ObjectCallback(callback[1], this), args, ...); + } + else + { + return _inherited(callback, args, ...); + } +} + +func Update() +{ + return Refresh(currentSelection); +} + +func GetSelection() +{ + return currentSelection; +} + +func GetObject() +{ + return settings[DT_Menu_Settings_Object]; +} +// TODO: Erstellungskontext in CreateNewMenu speichern, damit Callbacks ohne explizite Kontextangabe im "Erzeuger" aufgerufen werden können +// TODO: RefreshDelayed noch im gleichen Frame im Effekttimer, wenn möglich (also kein Umhergehüpfe); noch relevant? +// TODO: Created-Callback, Refresh-Callback, u.ä., Menu_Entry (optional) mit "benannten" Argumenten und Menu_AutoEntry dadurch ersetzen, Adapter-Factories (inline oder als SubMenu (optional side by side)), (Objekt-Selector mit Find_*-Filter als Ausgangsbasis (??)) +// TODO: Vordefiniertes Condition-Callback für Variablenvergleiche (mit ScopedVar() und Vergleichswert) +// TODO: SelectionMenu wie in ObjectsAppend mit SelectMark aber flexibler (vgl. SelectionMenu und Leitung trennen-Menü) +// TODO: Flexibles Side by Side Submenu wie bei Sensor base für Ziel hinzufügen +// TODO: Menüglobale (wird bei jeder Eintragsaktion aufgerufen; vor (wie ein Filter) oder nach Eintragcallback; optional nur wenn das Callback React_None zurückgibt; Callback-Reaction als Parameter) Callbacks (vorallem Close) +// TODO: List-Factory (wie Factory, nur dass ein Array mit Args übergeben werden _muss_, worüber im Menüsystem iteriert wird)(Erspart eine explizite Schleife) diff --git a/StringTblDE.txt b/StringTblDE.txt new file mode 100644 index 0000000..85bc5b6 --- /dev/null +++ b/StringTblDE.txt @@ -0,0 +1,7 @@ +Accept=Bestätigen +Decline=Abbrechen +Back=Zurück +EnterValue=Wert +EnterNumber=Zahl +EnterText=Text +EnterIDOrName=ID oder Name diff --git a/StringTblUS.txt b/StringTblUS.txt new file mode 100644 index 0000000..1a30f7d --- /dev/null +++ b/StringTblUS.txt @@ -0,0 +1,7 @@ +Accept=Accept +Decline=Decline +Back=Back +EnterValue=Value +EnterNumber=Number +EnterText=Text +EnterIDOrName=ID or name -- cgit v1.2.3-54-g00ecf