diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 57a609b06..50e07f5b2 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -1195,6 +1195,8 @@ CCMD(undocolorpic) DEFINE_FIELD(DMenu, mParentMenu) +DEFINE_FIELD(DMenu, mMouseCapture); +DEFINE_FIELD(DMenu, mBackbuttonSelected); DEFINE_FIELD(DMenuDescriptor, mMenuName) DEFINE_FIELD(DMenuDescriptor, mNetgameMessage) diff --git a/src/menu/menu.h b/src/menu/menu.h index 3924ab869..c9307a0ef 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -253,9 +253,7 @@ class DMenu : public DObject DECLARE_CLASS (DMenu, DObject) HAS_OBJECT_POINTERS -protected: - bool mMouseCapture; - bool mBackbuttonSelected; + public: enum @@ -271,6 +269,8 @@ public: }; TObjPtr mParentMenu; + bool mMouseCapture; + bool mBackbuttonSelected; DMenu(DMenu *parent = NULL); virtual bool Responder (event_t *ev); @@ -354,7 +354,7 @@ extern FOptionMap OptionValues; class DTextEnterMenu : public DMenu { - DECLARE_ABSTRACT_CLASS(DTextEnterMenu, DMenu) + DECLARE_CLASS(DTextEnterMenu, DMenu) public: FString mEnterString; @@ -370,12 +370,7 @@ public: bool AllowColors; - // [TP] Added allowcolors - DTextEnterMenu(DMenu *parent, const char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors = false); - - bool MenuEvent (int mkey, bool fromcontroller); - bool Responder(event_t *ev); - bool MouseEvent(int type, int x, int y); + DTextEnterMenu() {} }; diff --git a/src/menu/menuinput.cpp b/src/menu/menuinput.cpp index f880fabfd..404b955a0 100644 --- a/src/menu/menuinput.cpp +++ b/src/menu/menuinput.cpp @@ -44,249 +44,10 @@ // [TP] New #includes #include "v_text.h" -IMPLEMENT_CLASS(DTextEnterMenu, true, false) - -#define INPUTGRID_WIDTH 13 -#define INPUTGRID_HEIGHT 5 - -// Heretic and Hexen do not, by default, come with glyphs for all of these -// characters. Oh well. Doom and Strife do. -static const char InputGridChars[INPUTGRID_WIDTH * INPUTGRID_HEIGHT] = - "ABCDEFGHIJKLM" - "NOPQRSTUVWXYZ" - "0123456789+-=" - ".,!?@'\":;[]()" - "<>^#$%&*/_ \b"; - +IMPLEMENT_CLASS(DTextEnterMenu, false, false) CVAR(Bool, m_showinputgrid, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -//============================================================================= -// -// -// -//============================================================================= - -// [TP] Added allowcolors -DTextEnterMenu::DTextEnterMenu(DMenu *parent, const char *textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors) -: DMenu(parent) -{ - mEnterString = textbuffer; - mEnterSize = maxlen < 0 ? UINT_MAX : unsigned(maxlen); - mSizeMode = sizemode; - mInputGridOkay = showgrid || m_showinputgrid; - if (mEnterString.IsNotEmpty()) - { - InputGridX = INPUTGRID_WIDTH - 1; - InputGridY = INPUTGRID_HEIGHT - 1; - } - else - { - // If we are naming a new save, don't start the cursor on "end". - InputGridX = 0; - InputGridY = 0; - } - AllowColors = allowcolors; // [TP] -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DTextEnterMenu::Responder(event_t *ev) -{ - if (ev->type == EV_GUI_Event) - { - // Save game and player name string input - if (ev->subtype == EV_GUI_Char) - { - mInputGridOkay = false; - if (mEnterString.Len() < mEnterSize && - (mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8)) - { - mEnterString.AppendFormat("%c", (char)ev->data1); - } - return true; - } - char ch = (char)ev->data1; - if ((ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat) && ch == '\b') - { - if (mEnterString.IsNotEmpty()) - { - mEnterString.Truncate(mEnterString.Len() - 1); - } - } - else if (ev->subtype == EV_GUI_KeyDown) - { - if (ch == GK_ESCAPE) - { - DMenu *parent = mParentMenu; - Close(); - parent->CallMenuEvent(MKEY_Abort, false); - return true; - } - else if (ch == '\r') - { - if (mEnterString.IsNotEmpty()) - { - // [TP] If we allow color codes, colorize the string now. - if (AllowColors) - mEnterString = strbin1(mEnterString); - - DMenu *parent = mParentMenu; - parent->CallMenuEvent(MKEY_Input, false); - Close(); - return true; - } - } - } - if (ev->subtype == EV_GUI_KeyDown || ev->subtype == EV_GUI_KeyRepeat) - { - return true; - } - } - return Super::Responder(ev); -} - -//============================================================================= -// -// -// -//============================================================================= - -bool DTextEnterMenu::MouseEvent(int type, int x, int y) -{ - const int cell_width = 18 * CleanXfac; - const int cell_height = 12 * CleanYfac; - const int screen_y = screen->GetHeight() - INPUTGRID_HEIGHT * cell_height; - const int screen_x = (screen->GetWidth() - INPUTGRID_WIDTH * cell_width) / 2; - - if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y) - { - InputGridX = (x - screen_x) / cell_width; - InputGridY = (y - screen_y) / cell_height; - if (type == DMenu::MOUSE_Release) - { - if (CallMenuEvent(MKEY_Enter, true)) - { - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); - if (m_use_mouse == 2) InputGridX = InputGridY = -1; - return true; - } - } - } - else - { - InputGridX = InputGridY = -1; - } - return Super::MouseEvent(type, x, y); -} - - - -//============================================================================= -// -// -// -//============================================================================= - -bool DTextEnterMenu::MenuEvent (int key, bool fromcontroller) -{ - if (key == MKEY_Back) - { - mParentMenu->CallMenuEvent(MKEY_Abort, false); - return Super::MenuEvent(key, fromcontroller); - } - if (fromcontroller) - { - mInputGridOkay = true; - } - - if (mInputGridOkay) - { - int ch; - - if (InputGridX == -1 || InputGridY == -1) - { - InputGridX = InputGridY = 0; - } - switch (key) - { - case MKEY_Down: - InputGridY = (InputGridY + 1) % INPUTGRID_HEIGHT; - return true; - - case MKEY_Up: - InputGridY = (InputGridY + INPUTGRID_HEIGHT - 1) % INPUTGRID_HEIGHT; - return true; - - case MKEY_Right: - InputGridX = (InputGridX + 1) % INPUTGRID_WIDTH; - return true; - - case MKEY_Left: - InputGridX = (InputGridX + INPUTGRID_WIDTH - 1) % INPUTGRID_WIDTH; - return true; - - case MKEY_Clear: - if (mEnterString.IsNotEmpty()) - { - mEnterString.Truncate(mEnterString.Len() - 1); - } - return true; - - case MKEY_Enter: - assert(unsigned(InputGridX) < INPUTGRID_WIDTH && unsigned(InputGridY) < INPUTGRID_HEIGHT); - if (mInputGridOkay) - { - ch = InputGridChars[InputGridX + InputGridY * INPUTGRID_WIDTH]; - if (ch == 0) // end - { - if (mEnterString.IsNotEmpty()) - { - DMenu *parent = mParentMenu; - Close(); - parent->CallMenuEvent(MKEY_Input, false); - return true; - } - } - else if (ch == '\b') // bs - { - if (mEnterString.IsNotEmpty()) - { - mEnterString.Truncate(mEnterString.Len() - 1); - } - } - else if (mEnterString.Len() < mEnterSize && - (mSizeMode == 2/*entering player name*/ || (size_t)SmallFont->StringWidth(mEnterString) < (mEnterSize-1)*8)) - { - mEnterString += char(ch); - } - } - return true; - - default: - break; // Keep GCC quiet - } - } - return false; -} - -DEFINE_ACTION_FUNCTION(DTextEnterMenu, Open) -{ - PARAM_PROLOGUE; - PARAM_OBJECT(parent, DMenu); - PARAM_STRING(text); - PARAM_INT(maxlen); - PARAM_INT(sizemode); - PARAM_BOOL(fromcontroller); - auto m = new DTextEnterMenu(parent, text.GetChars(), maxlen, sizemode, fromcontroller, false); - M_ActivateMenu(m); - ACTION_RETURN_OBJECT(m); -} - DEFINE_FIELD(DTextEnterMenu, mEnterString); DEFINE_FIELD(DTextEnterMenu, mEnterSize); DEFINE_FIELD(DTextEnterMenu, mEnterPos); diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 4fb167f56..986f0f1f2 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -1213,10 +1213,12 @@ DEFINE_ACTION_FUNCTION(FStringStruct, Mid) ACTION_RETURN_STRING(s); } -DEFINE_ACTION_FUNCTION(FStringStruct, Len) +DEFINE_ACTION_FUNCTION(FStringStruct, Truncate) { PARAM_SELF_STRUCT_PROLOGUE(FString); - ACTION_RETURN_INT((int)self->Len()); + PARAM_UINT(len); + self->Truncate(len); + return 0; } // CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int. @@ -1239,3 +1241,10 @@ DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt) ACTION_RETURN_INT(0); ACTION_RETURN_INT((*self)[pos]); } + +DEFINE_ACTION_FUNCTION(FStringStruct, Filter) +{ + PARAM_SELF_STRUCT_PROLOGUE(FString); + ACTION_RETURN_STRING(strbin1(*self)); +} + diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index aa191c34e..de5132716 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -8,6 +8,8 @@ #include "doomerrors.h" #include "memarena.h" +class DObject; + extern FMemArena ClassDataAllocator; #define MAX_RETURNS 8 // Maximum number of results a function called by script code can return diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index 43d1df05a..9ae86abb5 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -578,9 +578,10 @@ struct StringStruct native native void Replace(String pattern, String replacement); native String Mid(int pos = 0, int len = 2147483647); - native int Len(); + native void Truncate(int newlen); native String CharAt(int pos); native int CharCodeAt(int pos); + native String Filter(); } class Floor : Thinker native diff --git a/wadsrc/static/zscript/menu/menu.txt b/wadsrc/static/zscript/menu/menu.txt index 103d75104..2f5d9454a 100644 --- a/wadsrc/static/zscript/menu/menu.txt +++ b/wadsrc/static/zscript/menu/menu.txt @@ -87,6 +87,8 @@ class Menu : Object native }; native Menu mParentMenu; + native bool mMouseCapture; + native bool mBackbuttonSelected; void Init(Menu parent) { diff --git a/wadsrc/static/zscript/menu/textentermenu.txt b/wadsrc/static/zscript/menu/textentermenu.txt index c99285145..c48f6854f 100644 --- a/wadsrc/static/zscript/menu/textentermenu.txt +++ b/wadsrc/static/zscript/menu/textentermenu.txt @@ -16,9 +16,47 @@ class TextEnterMenu : Menu native native int InputGridY; native bool AllowColors; - native static TextEnterMenu Open(Menu parent, String text, int maxlen, int sizemode, bool fromcontroller); - - + //============================================================================= + // + // + // + //============================================================================= + + // [TP] Added allowcolors + private void Init(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid, bool allowcolors) + { + Super.init(parent); + mEnterString = textbuffer; + mEnterSize = maxlen < 0 ? 0x7fffffff : maxlen; + mSizeMode = sizemode; + mInputGridOkay = showgrid || m_showinputgrid; + if (mEnterString.Length() > 0) + { + InputGridX = INPUTGRID_WIDTH - 1; + InputGridY = INPUTGRID_HEIGHT - 1; + } + else + { + // If we are naming a new save, don't start the cursor on "end". + InputGridX = 0; + InputGridY = 0; + } + AllowColors = allowcolors; // [TP] + } + + static TextEnterMenu Open(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid = false, bool allowcolors = false) + { + let me = new("TextEnterMenu"); + me.Init(parent, textbuffer, maxlen, sizemode, showgrid, allowcolors); + return me; + } + + //============================================================================= + // + // + // + //============================================================================= + String GetText() { return mEnterString; @@ -29,6 +67,195 @@ class TextEnterMenu : Menu native return mInputGridOkay; } + + //============================================================================= + // + // + // + //============================================================================= + + override bool Responder(InputEventData ev) + { + if (ev.type == InputEventData.GUI_Event) + { + // Save game and player name string input + if (ev.subtype == InputEventData.GUI_Char) + { + mInputGridOkay = false; + if (mEnterString.Length() < mEnterSize && + (mSizeMode == 2/*entering player name*/ || SmallFont.StringWidth(mEnterString) < (mEnterSize-1)*8)) + { + mEnterString.AppendFormat("%c", ev.data1); + } + return true; + } + int ch = ev.data1; + if ((ev.subtype == InputEventData.GUI_KeyDown || ev.subtype == InputEventData.GUI_KeyRepeat) && ch == 8) + { + if (mEnterString.Length() > 0) + { + mEnterString.Truncate(mEnterString.Length() - 1); + } + } + else if (ev.subtype == InputEventData.GUI_KeyDown) + { + if (ch == UIEvent.Key_ESCAPE) + { + Menu parent = mParentMenu; + Close(); + parent.MenuEvent(MKEY_Abort, false); + return true; + } + else if (ch == 13) + { + if (mEnterString.Length() > 0) + { + // [TP] If we allow color codes, colorize the string now. + if (AllowColors) + mEnterString = mEnterString.Filter(); + + Menu parent = mParentMenu; + parent.MenuEvent(MKEY_Input, false); + Close(); + return true; + } + } + } + if (ev.subtype == InputEventData.GUI_KeyDown || ev.subtype == InputEventData.GUI_KeyRepeat) + { + return true; + } + } + return Super.Responder(ev); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MouseEvent(int type, int x, int y) + { + if (mMouseCapture || m_use_mouse == 1) + { + int cell_width = 18 * CleanXfac; + int cell_height = 12 * CleanYfac; + int screen_y = screen.GetHeight() - INPUTGRID_HEIGHT * cell_height; + int screen_x = (screen.GetWidth() - INPUTGRID_WIDTH * cell_width) / 2; + + if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y) + { + InputGridX = (x - screen_x) / cell_width; + InputGridY = (y - screen_y) / cell_height; + if (type == MOUSE_Release) + { + if (MenuEvent(MKEY_Enter, true)) + { + MenuSound("menu/choose"); + if (m_use_mouse == 2) InputGridX = InputGridY = -1; + return true; + } + } + } + else + { + InputGridX = InputGridY = -1; + } + } + return Super.MouseEvent(type, x, y); + } + + //============================================================================= + // + // + // + //============================================================================= + + override bool MenuEvent (int key, bool fromcontroller) + { + String InputGridChars = Chars; + if (key == MKEY_Back) + { + mParentMenu.MenuEvent(MKEY_Abort, false); + return Super.MenuEvent(key, fromcontroller); + } + if (fromcontroller) + { + mInputGridOkay = true; + } + + if (mInputGridOkay) + { + int ch; + + if (InputGridX == -1 || InputGridY == -1) + { + InputGridX = InputGridY = 0; + } + switch (key) + { + case MKEY_Down: + InputGridY = (InputGridY + 1) % INPUTGRID_HEIGHT; + return true; + + case MKEY_Up: + InputGridY = (InputGridY + INPUTGRID_HEIGHT - 1) % INPUTGRID_HEIGHT; + return true; + + case MKEY_Right: + InputGridX = (InputGridX + 1) % INPUTGRID_WIDTH; + return true; + + case MKEY_Left: + InputGridX = (InputGridX + INPUTGRID_WIDTH - 1) % INPUTGRID_WIDTH; + return true; + + case MKEY_Clear: + if (mEnterString.Length() > 0) + { + mEnterString.Truncate(mEnterString.Length() - 1); + } + return true; + + case MKEY_Enter: + if (mInputGridOkay) + { + String c = InputGridChars.CharAt(InputGridX + InputGridY * INPUTGRID_WIDTH); + int ch = c.CharCodeAt(0); + if (ch == 0) // end + { + if (mEnterString.Length() > 0) + { + Menu parent = mParentMenu; + Close(); + parent.MenuEvent(MKEY_Input, false); + return true; + } + } + else if (ch == 8) // bs + { + if (mEnterString.Length() > 0) + { + mEnterString.Truncate(mEnterString.Length() - 1); + } + } + else if (mEnterString.Length() < mEnterSize && + (mSizeMode == 2/*entering player name*/ || SmallFont.StringWidth(mEnterString) < (mEnterSize-1)*8)) + { + mEnterString = mEnterString .. c; + } + } + return true; + + default: + break; // Keep GCC quiet + } + } + return false; + } + + //============================================================================= // //