summaryrefslogtreecommitdiff
path: root/src/libs/graphics/widgets.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/graphics/widgets.c')
-rw-r--r--src/libs/graphics/widgets.c941
1 files changed, 941 insertions, 0 deletions
diff --git a/src/libs/graphics/widgets.c b/src/libs/graphics/widgets.c
new file mode 100644
index 0000000..0c444bc
--- /dev/null
+++ b/src/libs/graphics/widgets.c
@@ -0,0 +1,941 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "gfx_common.h"
+#include "widgets.h"
+#include "libs/strlib.h"
+
+WIDGET *widget_focus = NULL;
+
+/* Some basic color defines */
+#define WIDGET_ACTIVE_COLOR \
+ BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x00), 0x0E)
+#define WIDGET_INACTIVE_COLOR \
+ BUILD_COLOR (MAKE_RGB15 (0x18, 0x18, 0x1F), 0x00)
+#define WIDGET_INACTIVE_SELECTED_COLOR \
+ BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F)
+#define WIDGET_CURSOR_COLOR \
+ BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x00), 0x00)
+#define WIDGET_DIALOG_COLOR \
+ BUILD_COLOR (MAKE_RGB15 (0x14, 0x14, 0x14), 0x07)
+#define WIDGET_DIALOG_TEXT_COLOR \
+ BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x00), 0x00)
+
+static Color win_bg_clr =
+ BUILD_COLOR (MAKE_RGB15_INIT (0x18, 0x18, 0x1F), 0x00);
+static Color win_medium_clr =
+ BUILD_COLOR (MAKE_RGB15_INIT (0x10, 0x10, 0x18), 0x00);
+static Color win_dark_clr =
+ BUILD_COLOR (MAKE_RGB15_INIT (0x08, 0x08, 0x10), 0x00);
+
+static FONT cur_font;
+
+void
+DrawShadowedBox (RECT *r, Color bg, Color dark, Color medium)
+{
+ RECT t;
+ Color oldcolor;
+
+ BatchGraphics ();
+
+ t.corner.x = r->corner.x - 2;
+ t.corner.y = r->corner.y - 2;
+ t.extent.width = r->extent.width + 4;
+ t.extent.height = r->extent.height + 4;
+ oldcolor = SetContextForeGroundColor (dark);
+ DrawFilledRectangle (&t);
+
+ t.corner.x += 2;
+ t.corner.y += 2;
+ t.extent.width -= 2;
+ t.extent.height -= 2;
+ SetContextForeGroundColor (medium);
+ DrawFilledRectangle (&t);
+
+ t.corner.x -= 1;
+ t.corner.y += r->extent.height + 1;
+ t.extent.height = 1;
+ DrawFilledRectangle (&t);
+
+ t.corner.x += r->extent.width + 2;
+ t.corner.y -= r->extent.height + 2;
+ t.extent.width = 1;
+ DrawFilledRectangle (&t);
+
+ SetContextForeGroundColor (bg);
+ DrawFilledRectangle (r);
+
+ SetContextForeGroundColor (oldcolor);
+ UnbatchGraphics ();
+}
+
+// windowRect, if not NULL, will be filled with the dimensions of the
+// window drawn.
+void
+DrawLabelAsWindow (WIDGET_LABEL *label, RECT *windowRect)
+{
+ Color oldfg = SetContextForeGroundColor (WIDGET_DIALOG_TEXT_COLOR);
+ FONT oldfont = 0;
+ FRAME oldFontEffect = SetContextFontEffect (NULL);
+ RECT r;
+ TEXT t;
+ int i, win_w, win_h;
+
+ if (cur_font)
+ oldfont = SetContextFont (cur_font);
+
+ /* Compute the dimensions of the label */
+ win_h = label->height ((WIDGET *)label) + 16;
+ win_w = 0;
+ for (i = 0; i < label->line_count; i++)
+ {
+ int len = utf8StringCount (label->lines[i]);
+ if (len > win_w)
+ {
+ win_w = len;
+ }
+ }
+ win_w = (win_w * 6) + 16;
+
+ BatchGraphics ();
+ r.corner.x = (ScreenWidth - win_w) >> 1;
+ r.corner.y = (ScreenHeight - win_h) >> 1;
+ r.extent.width = win_w;
+ r.extent.height = win_h;
+ DrawShadowedBox (&r, win_bg_clr, win_dark_clr, win_medium_clr);
+
+ t.baseline.x = r.corner.x + (r.extent.width >> 1);
+ t.baseline.y = r.corner.y + 16;
+ for (i = 0; i < label->line_count; i++)
+ {
+ t.pStr = label->lines[i];
+ t.align = ALIGN_CENTER;
+ t.CharCount = (COUNT)~0;
+ font_DrawText (&t);
+ t.baseline.y += 8;
+ }
+
+ UnbatchGraphics ();
+
+ SetContextFontEffect (oldFontEffect);
+ if (oldfont)
+ SetContextFont (oldfont);
+ SetContextForeGroundColor (oldfg);
+
+ if (windowRect != NULL) {
+ // Add the outer border added by DrawShadowedBox.
+ // XXX: It may be nicer to add a border size parameter to
+ // DrawShadowedBox, instead of assuming 2 here.
+ windowRect->corner.x = r.corner.x - 2;
+ windowRect->corner.y = r.corner.y - 2;
+ windowRect->extent.width = r.extent.width + 4;
+ windowRect->extent.height = r.extent.height + 4;
+ }
+}
+
+void
+Widget_SetWindowColors (Color bg, Color dark, Color medium)
+{
+ win_bg_clr = bg;
+ win_dark_clr = dark;
+ win_medium_clr = medium;
+}
+
+FONT
+Widget_SetFont (FONT newFont)
+{
+ FONT oldFont = cur_font;
+ cur_font = newFont;
+ return oldFont;
+}
+
+static void
+Widget_DrawToolTips (int numlines, const char **tips)
+{
+ RECT r;
+ FONT oldfont = 0;
+ FRAME oldFontEffect = SetContextFontEffect (NULL);
+ Color oldtext = SetContextForeGroundColor (WIDGET_INACTIVE_SELECTED_COLOR);
+ TEXT t;
+ int i;
+
+ if (cur_font)
+ oldfont = SetContextFont (cur_font);
+
+ r.corner.x = 2;
+ r.corner.y = 2;
+ r.extent.width = ScreenWidth - 4;
+ r.extent.height = ScreenHeight - 4;
+
+ t.align = ALIGN_CENTER;
+ t.CharCount = ~0;
+ t.baseline.x = r.corner.x + (r.extent.width >> 1);
+ t.baseline.y = r.corner.y + (r.extent.height - 8 - 8 * numlines);
+
+ for (i = 0; i < numlines; i++)
+ {
+ t.pStr = tips[i];
+ font_DrawText(&t);
+ t.baseline.y += 8;
+ }
+
+ SetContextFontEffect (oldFontEffect);
+ if (oldfont)
+ SetContextFont (oldfont);
+ SetContextForeGroundColor (oldtext);
+}
+
+void
+Widget_DrawMenuScreen (WIDGET *_self, int x, int y)
+{
+ RECT r;
+ Color title, oldtext;
+ Color inactive, default_color, selected;
+ FONT oldfont = 0;
+ FRAME oldFontEffect = SetContextFontEffect (NULL);
+ TEXT t;
+ int widget_index, height, widget_y;
+
+ WIDGET_MENU_SCREEN *self = (WIDGET_MENU_SCREEN *)_self;
+
+ if (cur_font)
+ oldfont = SetContextFont (cur_font);
+
+ r.corner.x = 2;
+ r.corner.y = 2;
+ r.extent.width = ScreenWidth - 4;
+ r.extent.height = ScreenHeight - 4;
+
+ title = WIDGET_INACTIVE_SELECTED_COLOR;
+ selected = WIDGET_ACTIVE_COLOR;
+ inactive = WIDGET_INACTIVE_COLOR;
+ default_color = title;
+
+ DrawStamp (&self->bgStamp);
+
+ oldtext = SetContextForeGroundColor (title);
+ t.baseline.x = r.corner.x + (r.extent.width >> 1);
+ t.baseline.y = r.corner.y + 8;
+ t.pStr = self->title;
+ t.align = ALIGN_CENTER;
+ t.CharCount = ~0;
+ font_DrawText (&t);
+ t.baseline.y += 8;
+ t.pStr = self->subtitle;
+ font_DrawText (&t);
+
+ height = 0;
+ for (widget_index = 0; widget_index < self->num_children; widget_index++)
+ {
+ WIDGET *child = self->child[widget_index];
+ height += (*child->height)(child);
+ height += 8; /* spacing */
+ }
+
+ height -= 8;
+
+ widget_y = (ScreenHeight - height) >> 1;
+ for (widget_index = 0; widget_index < self->num_children; widget_index++)
+ {
+ WIDGET *c = self->child[widget_index];
+ (*c->draw)(c, 0, widget_y);
+ widget_y += (*c->height)(c) + 8;
+ }
+
+ SetContextFontEffect (oldFontEffect);
+ if (oldfont)
+ SetContextFont (oldfont);
+ SetContextForeGroundColor (oldtext);
+
+ (void) x;
+ (void) y;
+}
+
+void
+Widget_DrawChoice (WIDGET *_self, int x, int y)
+{
+ WIDGET_CHOICE *self = (WIDGET_CHOICE *)_self;
+ Color oldtext;
+ Color inactive, default_color, selected;
+ FONT oldfont = 0;
+ FRAME oldFontEffect = SetContextFontEffect (NULL);
+ TEXT t;
+ int i, home_x, home_y;
+
+ if (cur_font)
+ oldfont = SetContextFont (cur_font);
+
+ default_color = WIDGET_INACTIVE_SELECTED_COLOR;
+ selected = WIDGET_ACTIVE_COLOR;
+ inactive = WIDGET_INACTIVE_COLOR;
+
+ t.baseline.x = x;
+ t.baseline.y = y;
+ t.align = ALIGN_LEFT;
+ t.CharCount = ~0;
+ t.pStr = self->category;
+ if (widget_focus == _self)
+ {
+ oldtext = SetContextForeGroundColor (selected);
+ }
+ else
+ {
+ oldtext = SetContextForeGroundColor (default_color);
+ }
+ font_DrawText (&t);
+
+ home_x = t.baseline.x + 3 * (ScreenWidth / ((self->maxcolumns + 1) * 2));
+ home_y = t.baseline.y;
+ t.align = ALIGN_CENTER;
+ for (i = 0; i < self->numopts; i++)
+ {
+ t.baseline.x = home_x + ((i % 3) *
+ (ScreenWidth / (self->maxcolumns + 1)));
+ t.baseline.y = home_y + (8 * (i / 3));
+ t.pStr = self->options[i].optname;
+ if ((widget_focus == _self) &&
+ (self->highlighted == i))
+ {
+ SetContextForeGroundColor (selected);
+ Widget_DrawToolTips (3, self->options[i].tooltip);
+ }
+ else if (i == self->selected)
+ {
+ SetContextForeGroundColor (default_color);
+ }
+ else
+ {
+ SetContextForeGroundColor (inactive);
+ }
+ font_DrawText (&t);
+ }
+ SetContextFontEffect (oldFontEffect);
+ if (oldfont)
+ SetContextFont (oldfont);
+ SetContextForeGroundColor (oldtext);
+}
+
+void
+Widget_DrawButton (WIDGET *_self, int x, int y)
+{
+ WIDGET_BUTTON *self = (WIDGET_BUTTON *)_self;
+ Color oldtext;
+ Color inactive, selected;
+ FONT oldfont = 0;
+ FRAME oldFontEffect = SetContextFontEffect (NULL);
+ TEXT t;
+
+ if (cur_font)
+ oldfont = SetContextFont (cur_font);
+
+ selected = WIDGET_ACTIVE_COLOR;
+ inactive = WIDGET_INACTIVE_COLOR;
+
+ t.baseline.x = 160;
+ t.baseline.y = y;
+ t.align = ALIGN_CENTER;
+ t.CharCount = ~0;
+ t.pStr = self->name;
+ if (widget_focus == _self)
+ {
+ Widget_DrawToolTips (3, self->tooltip);
+ oldtext = SetContextForeGroundColor (selected);
+ }
+ else
+ {
+ oldtext = SetContextForeGroundColor (inactive);
+ }
+ font_DrawText (&t);
+ SetContextFontEffect (oldFontEffect);
+ if (oldfont)
+ SetContextFont (oldfont);
+ SetContextForeGroundColor (oldtext);
+ (void) x;
+}
+
+void
+Widget_DrawLabel (WIDGET *_self, int x, int y)
+{
+ WIDGET_LABEL *self = (WIDGET_LABEL *)_self;
+ Color oldtext = SetContextForeGroundColor (WIDGET_INACTIVE_SELECTED_COLOR);
+ FONT oldfont = 0;
+ FRAME oldFontEffect = SetContextFontEffect (NULL);
+ TEXT t;
+ int i;
+
+ if (cur_font)
+ oldfont = SetContextFont (cur_font);
+
+ t.baseline.x = 160;
+ t.baseline.y = y;
+ t.align = ALIGN_CENTER;
+ t.CharCount = ~0;
+
+ for (i = 0; i < self->line_count; i++)
+ {
+ t.pStr = self->lines[i];
+ font_DrawText (&t);
+ t.baseline.y += 8;
+ }
+ SetContextFontEffect (oldFontEffect);
+ if (oldfont)
+ SetContextFont (oldfont);
+ SetContextForeGroundColor (oldtext);
+ (void) x;
+}
+
+void
+Widget_DrawSlider(WIDGET *_self, int x, int y)
+{
+ WIDGET_SLIDER *self = (WIDGET_SLIDER *)_self;
+ Color oldtext;
+ Color inactive, default_color, selected;
+ FONT oldfont = 0;
+ FRAME oldFontEffect = SetContextFontEffect (NULL);
+ TEXT t;
+ RECT r;
+ int tick = (ScreenWidth - x) / 8;
+
+ if (cur_font)
+ oldfont = SetContextFont (cur_font);
+
+ default_color = WIDGET_INACTIVE_SELECTED_COLOR;
+ selected = WIDGET_ACTIVE_COLOR;
+ inactive = WIDGET_INACTIVE_COLOR;
+
+ t.baseline.x = x;
+ t.baseline.y = y;
+ t.align = ALIGN_LEFT;
+ t.CharCount = ~0;
+ t.pStr = self->category;
+ if (widget_focus == _self)
+ {
+ Widget_DrawToolTips (3, self->tooltip);
+ oldtext = SetContextForeGroundColor (selected);
+ }
+ else
+ {
+ oldtext = SetContextForeGroundColor (default_color);
+ }
+ font_DrawText (&t);
+
+ r.corner.x = t.baseline.x + 3 * tick;
+ r.corner.y = t.baseline.y - 4;
+ r.extent.height = 2;
+ r.extent.width = 3 * tick;
+ DrawFilledRectangle (&r);
+
+ r.extent.width = 3;
+ r.extent.height = 8;
+ r.corner.y = t.baseline.y - 7;
+ r.corner.x = t.baseline.x + 3 * tick + (3 * tick * (self->value - self->min) /
+ (self->max - self->min)) - 1;
+ DrawFilledRectangle (&r);
+
+ (*self->draw_value)(self, t.baseline.x + 7 * tick, t.baseline.y);
+
+ SetContextFontEffect (oldFontEffect);
+ if (oldfont)
+ SetContextFont (oldfont);
+ SetContextForeGroundColor (oldtext);
+}
+
+void
+Widget_Slider_DrawValue (WIDGET_SLIDER *self, int x, int y)
+{
+ TEXT t;
+ char buffer[16];
+
+ sprintf (buffer, "%d", self->value);
+
+ t.baseline.x = x;
+ t.baseline.y = y;
+ t.align = ALIGN_CENTER;
+ t.CharCount = ~0;
+ t.pStr = buffer;
+
+ font_DrawText (&t);
+}
+
+void
+Widget_DrawTextEntry (WIDGET *_self, int x, int y)
+{
+ WIDGET_TEXTENTRY *self = (WIDGET_TEXTENTRY *)_self;
+ Color oldtext;
+ Color inactive, default_color, selected;
+ FONT oldfont = 0;
+ FRAME oldFontEffect = SetContextFontEffect (NULL);
+ TEXT t;
+
+ if (cur_font)
+ oldfont = SetContextFont (cur_font);
+
+ default_color = WIDGET_INACTIVE_SELECTED_COLOR;
+ selected = WIDGET_ACTIVE_COLOR;
+ inactive = WIDGET_INACTIVE_COLOR;
+
+ BatchGraphics ();
+
+ t.baseline.x = x;
+ t.baseline.y = y;
+ t.align = ALIGN_LEFT;
+ t.CharCount = ~0;
+ t.pStr = self->category;
+ if (widget_focus == _self)
+ {
+ oldtext = SetContextForeGroundColor (selected);
+ }
+ else
+ {
+ oldtext = SetContextForeGroundColor (default_color);
+ }
+ font_DrawText (&t);
+
+ /* Force string termination */
+ self->value[WIDGET_TEXTENTRY_WIDTH-1] = 0;
+
+ t.baseline.y = y;
+ t.CharCount = utf8StringCount (self->value);
+ t.pStr = self->value;
+
+ if (!(self->state & WTE_EDITING))
+ { // normal or selected state
+ t.baseline.x = 160;
+ t.align = ALIGN_CENTER;
+
+ if (widget_focus == _self)
+ {
+ oldtext = SetContextForeGroundColor (selected);
+ }
+ else
+ {
+ oldtext = SetContextForeGroundColor (inactive);
+ }
+ font_DrawText (&t);
+ }
+ else
+ { // editing state
+ COUNT i;
+ RECT text_r;
+ BYTE char_deltas[WIDGET_TEXTENTRY_WIDTH];
+ BYTE *pchar_deltas;
+ RECT r;
+ SIZE leading;
+
+ t.baseline.x = 90;
+ t.align = ALIGN_LEFT;
+
+ // calc background box dimensions
+ // XXX: this may need some tuning, especially if a
+ // different font is used. The font 'leading' values
+ // are not what they should be.
+#define BOX_VERT_OFFSET 2
+ GetContextFontLeading (&leading);
+ r.corner.x = t.baseline.x - 1;
+ r.corner.y = t.baseline.y - leading + BOX_VERT_OFFSET;
+ r.extent.width = ScreenWidth - r.corner.x - 10;
+ r.extent.height = leading + 2;
+
+ TextRect (&t, &text_r, char_deltas);
+#if 0
+ // XXX: this should potentially be used in ChangeCallback
+ if ((text_r.extent.width + 2) >= r.extent.width)
+ { // the text does not fit the input box size and so
+ // will not fit when displayed later
+ UnbatchGraphics ();
+ // disallow the change
+ return (FALSE);
+ }
+#endif
+
+ oldtext = SetContextForeGroundColor (selected);
+ DrawFilledRectangle (&r);
+
+ // calculate the cursor position and draw it
+ pchar_deltas = char_deltas;
+ for (i = self->cursor_pos; i > 0; --i)
+ r.corner.x += (SIZE)*pchar_deltas++;
+ if (self->cursor_pos < t.CharCount) /* cursor mid-line */
+ --r.corner.x;
+ if (self->state & WTE_BLOCKCUR)
+ { // Use block cursor for keyboardless systems
+ if (self->cursor_pos == t.CharCount)
+ { // cursor at end-line -- use insertion point
+ r.extent.width = 1;
+ }
+ else if (self->cursor_pos + 1 == t.CharCount)
+ { // extra pixel for last char margin
+ r.extent.width = (SIZE)*pchar_deltas + 2;
+ }
+ else
+ { // normal mid-line char
+ r.extent.width = (SIZE)*pchar_deltas + 1;
+ }
+ }
+ else
+ { // Insertion point cursor
+ r.extent.width = 1;
+ }
+ // position cursor within input field rect
+ ++r.corner.x;
+ ++r.corner.y;
+ r.extent.height -= 2;
+ SetContextForeGroundColor (WIDGET_CURSOR_COLOR);
+ DrawFilledRectangle (&r);
+
+ SetContextForeGroundColor (inactive);
+ font_DrawText (&t);
+ }
+
+ UnbatchGraphics ();
+ SetContextFontEffect (oldFontEffect);
+ if (oldfont)
+ SetContextFont (oldfont);
+ SetContextForeGroundColor (oldtext);
+}
+
+void
+Widget_DrawControlEntry (WIDGET *_self, int x, int y)
+{
+ WIDGET_CONTROLENTRY *self = (WIDGET_CONTROLENTRY *)_self;
+ Color oldtext;
+ Color inactive, default_color, selected;
+ FONT oldfont = 0;
+ FRAME oldFontEffect = SetContextFontEffect (NULL);
+ TEXT t;
+ int i, home_x, home_y;
+
+ if (cur_font)
+ oldfont = SetContextFont (cur_font);
+
+ default_color = WIDGET_INACTIVE_SELECTED_COLOR;
+ selected = WIDGET_ACTIVE_COLOR;
+ inactive = WIDGET_INACTIVE_COLOR;
+
+ t.baseline.x = x;
+ t.baseline.y = y;
+ t.align = ALIGN_LEFT;
+ t.CharCount = ~0;
+ t.pStr = self->category;
+ if (widget_focus == _self)
+ {
+ oldtext = SetContextForeGroundColor (selected);
+ }
+ else
+ {
+ oldtext = SetContextForeGroundColor (default_color);
+ }
+ font_DrawText (&t);
+
+ // 3 * ScreenWidth / ((self->maxcolumns + 1) * 2)) as per CHOICE, but only two options.
+ home_x = t.baseline.x + (ScreenWidth / 2);
+ home_y = t.baseline.y;
+ t.align = ALIGN_CENTER;
+ for (i = 0; i < 2; i++)
+ {
+ t.baseline.x = home_x + ((i % 3) * (ScreenWidth / 3)); // self->maxcolumns + 1 as per CHOICE.
+ t.baseline.y = home_y + (8 * (i / 3));
+ t.pStr = self->controlname[i];
+ if (!t.pStr[0])
+ {
+ t.pStr = "---";
+ }
+ if ((widget_focus == _self) &&
+ (self->highlighted == i))
+ {
+ SetContextForeGroundColor (selected);
+ }
+ else
+ {
+ SetContextForeGroundColor (default_color);
+ }
+ font_DrawText (&t);
+ }
+ SetContextFontEffect (oldFontEffect);
+ if (oldfont)
+ SetContextFont (oldfont);
+ SetContextForeGroundColor (oldtext);
+}
+
+int
+Widget_HeightChoice (WIDGET *_self)
+{
+ return ((((WIDGET_CHOICE *)_self)->numopts + 2) / 3) * 8;
+}
+
+int
+Widget_HeightFullScreen (WIDGET *_self)
+{
+ (void)_self;
+ return ScreenHeight;
+}
+
+int
+Widget_HeightOneLine (WIDGET *_self)
+{
+ (void)_self;
+ return 8;
+}
+
+int
+Widget_HeightLabel (WIDGET *_self)
+{
+ WIDGET_LABEL *self = (WIDGET_LABEL *)_self;
+ return self->line_count * 8;
+}
+
+int
+Widget_WidthFullScreen (WIDGET *_self)
+{
+ (void)_self;
+ return ScreenWidth;
+}
+
+int
+Widget_ReceiveFocusSimple (WIDGET *_self, int event)
+{
+ widget_focus = _self;
+ (void)event;
+ return TRUE;
+}
+
+int
+Widget_ReceiveFocusChoice (WIDGET *_self, int event)
+{
+ WIDGET_CHOICE *self = (WIDGET_CHOICE *)_self;
+ widget_focus = _self;
+ self->highlighted = self->selected;
+ (void)event;
+ return TRUE;
+}
+
+int
+Widget_ReceiveFocusControlEntry (WIDGET *_self, int event)
+{
+ WIDGET_CONTROLENTRY *self = (WIDGET_CONTROLENTRY *)_self;
+ int oldval = 0;
+ if (widget_focus->tag == WIDGET_TYPE_CONTROLENTRY)
+ {
+ oldval = ((WIDGET_CONTROLENTRY *)widget_focus)->highlighted;
+ }
+ widget_focus = _self;
+ self->highlighted = oldval;
+ (void)event;
+ return TRUE;
+}
+
+int
+Widget_ReceiveFocusMenuScreen (WIDGET *_self, int event)
+{
+ WIDGET_MENU_SCREEN *self = (WIDGET_MENU_SCREEN *)_self;
+ int x, last_x, dx;
+ for (x = 0; x < self->num_children; x++)
+ {
+ self->child[x]->parent = _self;
+ }
+ if (event == WIDGET_EVENT_UP)
+ {
+ x = self->num_children - 1;
+ dx = -1;
+ last_x = -1;
+ }
+ else if (event == WIDGET_EVENT_DOWN)
+ {
+ x = 0;
+ dx = 1;
+ last_x = self->num_children;
+ }
+ else
+ {
+ /* Leave highlighted value the same */
+ WIDGET *child = self->child[self->highlighted];
+ child->receiveFocus (child, event);
+ return TRUE;
+ }
+ for ( ; x != last_x; x += dx)
+ {
+ WIDGET *child = self->child[x];
+ if ((*child->receiveFocus)(child, event))
+ {
+ self->highlighted = x;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+int
+Widget_ReceiveFocusRefuseFocus (WIDGET *self, int event)
+{
+ (void)self;
+ (void)event;
+ return FALSE;
+}
+
+int
+Widget_HandleEventIgnoreAll (WIDGET *self, int event)
+{
+ (void)event;
+ (void)self;
+ return FALSE;
+}
+
+int
+Widget_HandleEventChoice (WIDGET *_self, int event)
+{
+ WIDGET_CHOICE *self = (WIDGET_CHOICE *)_self;
+ switch (event)
+ {
+ case WIDGET_EVENT_LEFT:
+ self->highlighted -= 1;
+ if (self->highlighted < 0)
+ self->highlighted = self->numopts - 1;
+ return TRUE;
+ case WIDGET_EVENT_RIGHT:
+ self->highlighted += 1;
+ if (self->highlighted >= self->numopts)
+ self->highlighted = 0;
+ return TRUE;
+ case WIDGET_EVENT_SELECT:
+ {
+ int oldval = self->selected;
+ self->selected = self->highlighted;
+ if (self->onChange)
+ {
+ (*(self->onChange))(self, oldval);
+ }
+ return TRUE;
+ }
+ default:
+ return FALSE;
+ }
+}
+
+int
+Widget_HandleEventSlider (WIDGET *_self, int event)
+{
+ WIDGET_SLIDER *self = (WIDGET_SLIDER *)_self;
+ switch (event)
+ {
+ case WIDGET_EVENT_LEFT:
+ self->value -= self->step;
+ if (self->value < self->min)
+ self->value = self->min;
+ return TRUE;
+ case WIDGET_EVENT_RIGHT:
+ self->value += self->step;
+ if (self->value > self->max)
+ self->value = self->max;
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+int
+Widget_HandleEventMenuScreen (WIDGET *_self, int event)
+{
+ WIDGET_MENU_SCREEN *self = (WIDGET_MENU_SCREEN *)_self;
+ int x, last_x, dx;
+ switch (event)
+ {
+ case WIDGET_EVENT_UP:
+ dx = -1;
+ break;
+ case WIDGET_EVENT_DOWN:
+ dx = 1;
+ break;
+ case WIDGET_EVENT_CANCEL:
+ /* On cancel, shift focus to last element and send a SELECT. */
+ self->highlighted = self->num_children - 1;
+ widget_focus = self->child[self->highlighted];
+ return (widget_focus->handleEvent)(widget_focus, WIDGET_EVENT_SELECT);
+ default:
+ return FALSE;
+ }
+ last_x = self->highlighted;
+ x = self->highlighted + dx;
+ while (x != last_x)
+ {
+ WIDGET *child;
+ if (x == -1)
+ x = self->num_children - 1;
+ if (x == self->num_children)
+ x = 0;
+ child = self->child[x];
+ if ((*child->receiveFocus)(child, event))
+ {
+ self->highlighted = x;
+ return TRUE;
+ }
+ x += dx;
+ }
+ return FALSE;
+}
+
+int
+Widget_HandleEventTextEntry (WIDGET *_self, int event)
+{
+ WIDGET_TEXTENTRY *self = (WIDGET_TEXTENTRY *)_self;
+ if (event == WIDGET_EVENT_SELECT) {
+ if (!self->handleEventSelect)
+ return FALSE;
+ return (*self->handleEventSelect)(self);
+ }
+ return FALSE;
+}
+
+int
+Widget_HandleEventControlEntry (WIDGET *_self, int event)
+{
+ WIDGET_CONTROLENTRY *self = (WIDGET_CONTROLENTRY *)_self;
+ if (event == WIDGET_EVENT_SELECT)
+ {
+ if (self->onChange)
+ {
+ (self->onChange)(self);
+ return TRUE;
+ }
+ }
+ if (event == WIDGET_EVENT_DELETE)
+ {
+ if (self->onDelete)
+ {
+ (self->onDelete)(self);
+ return TRUE;
+ }
+ }
+ if ((event == WIDGET_EVENT_RIGHT) ||
+ (event == WIDGET_EVENT_LEFT))
+ {
+ self->highlighted = 1-self->highlighted;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int
+Widget_Event (int event)
+{
+ WIDGET *widget = widget_focus;
+ while (widget != NULL)
+ {
+ if ((*widget->handleEvent)(widget, event))
+ return TRUE;
+ widget = widget->parent;
+ }
+ return FALSE;
+}