diff --git a/sc2/src/sc2code/controls.h b/sc2/src/sc2code/controls.h index 36958393a..8b2ae3016 100644 --- a/sc2/src/sc2code/controls.h +++ b/sc2/src/sc2code/controls.h @@ -122,6 +122,7 @@ typedef struct textentry_state // these are semi-private read-only BOOLEAN Initialized; + DWORD NextTime; // use this for input frame timing BOOLEAN Success; // edit confirmed or canceled UNICODE *CacheStr; // cached copy to revert immediate changes STRING JoyAlphaString; // joystick alphabet definition diff --git a/sc2/src/sc2code/libs/graphics/widgets.c b/sc2/src/sc2code/libs/graphics/widgets.c index bbd4536c5..511d42c65 100644 --- a/sc2/src/sc2code/libs/graphics/widgets.c +++ b/sc2/src/sc2code/libs/graphics/widgets.c @@ -593,11 +593,10 @@ Widget_HandleEventTextEntry (WIDGET *_self, int event) { WIDGET_TEXTENTRY *self = (WIDGET_TEXTENTRY *)_self; if (event == WIDGET_EVENT_SELECT) { - /* The TextEntry call goes here, editing self->value. - * The string should cap at self->maxlen - * characters. */ + if (!self->handleEventSelect) + return FALSE; + return (*self->handleEventSelect)(self); } - (void)self; return FALSE; } diff --git a/sc2/src/sc2code/libs/graphics/widgets.h b/sc2/src/sc2code/libs/graphics/widgets.h index caa6d62bd..bdba438f0 100644 --- a/sc2/src/sc2code/libs/graphics/widgets.h +++ b/sc2/src/sc2code/libs/graphics/widgets.h @@ -112,6 +112,13 @@ typedef struct _widget_slider { const char *tooltip[3]; } WIDGET_SLIDER; +typedef enum { + WTE_NORMAL = 0, + WTE_EDITING, + WTE_BLOCKCUR, + +} WIDGET_TEXTENTRY_STATE; + typedef struct _widget_textentry { struct _widget *parent; int (*handleEvent)(struct _widget *self, int event); @@ -119,9 +126,15 @@ typedef struct _widget_textentry { void (*draw)(struct _widget *self, int x, int y); int (*height)(struct _widget *self); int (*width)(struct _widget *self); + int (*handleEventSelect)(struct _widget_textentry *self); + // handleEventSelect is an overridable callback event + // called by the default handleEvent implementation + // can be NULL, in which case SELECT is ignored const char *category; char value[WIDGET_TEXTENTRY_WIDTH]; int maxlen; + WIDGET_TEXTENTRY_STATE state; + int cursor_pos; } WIDGET_TEXTENTRY; void DrawShadowedBox (PRECT r, COLOR bg, COLOR dark, COLOR medium); diff --git a/sc2/src/sc2code/setupmenu.c b/sc2/src/sc2code/setupmenu.c index c32363b10..26053d779 100644 --- a/sc2/src/sc2code/setupmenu.c +++ b/sc2/src/sc2code/setupmenu.c @@ -405,6 +405,81 @@ DoSetupMenu (PSETUP_MENU_STATE pInputState) (next == NULL)); } +static void +redraw_menu (void) +{ + BatchGraphics (); + (*next->draw)(next, 0, 0); + UnbatchGraphics (); +} + +static BOOLEAN +OnTextEntryChange (PTEXTENTRY_STATE pTES) +{ + WIDGET_TEXTENTRY *widget = (WIDGET_TEXTENTRY *) pTES->CbParam; + + widget->cursor_pos = pTES->CursorPos; + if (pTES->JoystickMode) + widget->state |= WTE_BLOCKCUR; + else + widget->state &= ~WTE_BLOCKCUR; + + // XXX TODO: Here, we can examine the text entered so far + // to make sure it fits on the screen, for example, + // and return FALSE to disallow the last change + + return TRUE; // allow change +} + +static BOOLEAN +OnTextEntryFrame (PTEXTENTRY_STATE pTES) +{ + WIDGET_TEXTENTRY *widget = (WIDGET_TEXTENTRY *) pTES->CbParam; + + redraw_menu (); + + SleepThreadUntil (pTES->NextTime); + pTES->NextTime = GetTimeCounter () + MENU_FRAME_RATE; + + return TRUE; // continue +} + +static int +OnTextEntryEvent (WIDGET_TEXTENTRY *widget) +{ // Going to edit the text + TEXTENTRY_STATE tes; + UNICODE revert_buf[256]; + + widget->cursor_pos = 0; + widget->state = WTE_EDITING; + redraw_menu (); + + // make a backup copy for revert on cancel + utf8StringCopy (revert_buf, sizeof (revert_buf), widget->value); + + // text entry setup + tes.Initialized = FALSE; + tes.MenuRepeatDelay = 0; + tes.NextTime = GetTimeCounter () + MENU_FRAME_RATE; + tes.BaseStr = widget->value; + tes.MaxSize = widget->maxlen; + tes.CursorPos = widget->cursor_pos; + tes.CbParam = widget; + tes.ChangeCallback = OnTextEntryChange; + tes.FrameCallback = OnTextEntryFrame; + + SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT); + if (!DoTextEntry (&tes)) + { // editing failed (canceled) -- revert the changes + utf8StringCopy (widget->value, widget->maxlen, revert_buf); + } + + widget->state = WTE_NORMAL; + redraw_menu (); + + return TRUE; // event handled +} + static stringbank *bank = NULL; static FRAME setup_frame = NULL; @@ -695,9 +770,12 @@ init_widgets (void) textentries[i].draw = Widget_DrawTextEntry; textentries[i].height = Widget_HeightOneLine; textentries[i].width = Widget_WidthFullScreen; + textentries[i].handleEventSelect = OnTextEntryEvent; textentries[i].category = NULL; textentries[i].value[0] = 0; textentries[i].maxlen = WIDGET_TEXTENTRY_WIDTH-1; + textentries[i].state = WTE_NORMAL; + textentries[i].cursor_pos = 0; } textentries[0].category = "TestText";