summaryrefslogtreecommitdiff
path: root/textscreen
diff options
context:
space:
mode:
authorSimon Howard2011-06-13 22:21:37 +0000
committerSimon Howard2011-06-13 22:21:37 +0000
commit391e7466b1efb7cbede4a1c356a210d9e7ee616b (patch)
tree90d13346d9cd3636df44290ded13d59ae3712543 /textscreen
parentfa328faf056affa216f2f3a8764ca0d56262efe9 (diff)
parent822664b4ff873d462370e9e96a9d91e6066c221d (diff)
downloadchocolate-doom-391e7466b1efb7cbede4a1c356a210d9e7ee616b.tar.gz
chocolate-doom-391e7466b1efb7cbede4a1c356a210d9e7ee616b.tar.bz2
chocolate-doom-391e7466b1efb7cbede4a1c356a210d9e7ee616b.zip
Merge from trunk.
Subversion-branch: /branches/raven-branch Subversion-revision: 2347
Diffstat (limited to 'textscreen')
-rw-r--r--textscreen/txt_button.c8
-rw-r--r--textscreen/txt_checkbox.c8
-rw-r--r--textscreen/txt_desktop.c10
-rw-r--r--textscreen/txt_desktop.h9
-rw-r--r--textscreen/txt_dropdown.c27
-rw-r--r--textscreen/txt_gui.c4
-rw-r--r--textscreen/txt_gui.h4
-rw-r--r--textscreen/txt_inputbox.c8
-rw-r--r--textscreen/txt_label.c2
-rw-r--r--textscreen/txt_main.h24
-rw-r--r--textscreen/txt_radiobutton.c8
-rw-r--r--textscreen/txt_scrollpane.c40
-rw-r--r--textscreen/txt_sdl.c86
-rw-r--r--textscreen/txt_separator.c26
-rw-r--r--textscreen/txt_separator.h10
-rw-r--r--textscreen/txt_spinctrl.c10
-rw-r--r--textscreen/txt_table.c7
-rw-r--r--textscreen/txt_widget.c62
-rw-r--r--textscreen/txt_widget.h34
-rw-r--r--textscreen/txt_window.c15
-rw-r--r--textscreen/txt_window_action.c19
21 files changed, 350 insertions, 71 deletions
diff --git a/textscreen/txt_button.c b/textscreen/txt_button.c
index 85517b3d..536e5f56 100644
--- a/textscreen/txt_button.c
+++ b/textscreen/txt_button.c
@@ -46,16 +46,12 @@ static void TXT_ButtonDrawer(TXT_UNCAST_ARG(button), int selected)
w = button->widget.w;
- TXT_BGColor(TXT_COLOR_BLUE, 0);
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
- if (selected)
- {
- TXT_BGColor(TXT_COLOR_GREY, 0);
- }
+ TXT_SetWidgetBG(button, selected);
TXT_DrawString(button->label);
-
+
for (i=strlen(button->label); i < w; ++i)
{
TXT_DrawString(" ");
diff --git a/textscreen/txt_checkbox.c b/textscreen/txt_checkbox.c
index 35c5739d..f2183b7c 100644
--- a/textscreen/txt_checkbox.c
+++ b/textscreen/txt_checkbox.c
@@ -48,7 +48,7 @@ static void TXT_CheckBoxDrawer(TXT_UNCAST_ARG(checkbox), int selected)
w = checkbox->widget.w;
- TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_BGColor(TXT_WINDOW_BACKGROUND, 0);
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawString("(");
@@ -67,11 +67,7 @@ static void TXT_CheckBoxDrawer(TXT_UNCAST_ARG(checkbox), int selected)
TXT_DrawString(") ");
- if (selected)
- {
- TXT_BGColor(TXT_COLOR_GREY, 0);
- }
-
+ TXT_SetWidgetBG(checkbox, selected);
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
TXT_DrawString(checkbox->label);
diff --git a/textscreen/txt_desktop.c b/textscreen/txt_desktop.c
index f833441f..c497f0e3 100644
--- a/textscreen/txt_desktop.c
+++ b/textscreen/txt_desktop.c
@@ -61,6 +61,16 @@ void TXT_RemoveDesktopWindow(txt_window_t *win)
num_windows = to;
}
+txt_window_t *TXT_GetActiveWindow(void)
+{
+ if (num_windows == 0)
+ {
+ return NULL;
+ }
+
+ return all_windows[num_windows - 1];
+}
+
static void DrawDesktopBackground(const char *title)
{
int i;
diff --git a/textscreen/txt_desktop.h b/textscreen/txt_desktop.h
index 95343977..42a011e7 100644
--- a/textscreen/txt_desktop.h
+++ b/textscreen/txt_desktop.h
@@ -63,6 +63,15 @@ void TXT_ExitMainLoop(void);
void TXT_GUIMainLoop(void);
+/**
+ * Get the top window on the desktop that is currently receiving
+ * inputs.
+ *
+ * @return The active window, or NULL if no windows are present.
+ */
+
+txt_window_t *TXT_GetActiveWindow(void);
+
#endif /* #ifndef TXT_DESKTOP_H */
diff --git a/textscreen/txt_dropdown.c b/textscreen/txt_dropdown.c
index c8103302..c9a5d015 100644
--- a/textscreen/txt_dropdown.c
+++ b/textscreen/txt_dropdown.c
@@ -99,6 +99,22 @@ static int SelectorWindowListener(txt_window_t *window, int key, void *user_data
return 0;
}
+static int SelectorMouseListener(txt_window_t *window, int x, int y, int b,
+ void *unused)
+{
+ txt_widget_t *win;
+
+ win = (txt_widget_t *) window;
+
+ if (x < win->x || x > win->x + win->w || y < win->y || y > win->y + win->h)
+ {
+ TXT_CloseWindow(window);
+ return 1;
+ }
+
+ return 0;
+}
+
// Open the dropdown list window to select an item
static void OpenSelectorWindow(txt_dropdown_list_t *list)
@@ -158,6 +174,7 @@ static void OpenSelectorWindow(txt_dropdown_list_t *list)
// Catch presses of escape in this window and close it.
TXT_SetKeyListener(window, SelectorWindowListener, NULL);
+ TXT_SetMouseListener(window, SelectorMouseListener, NULL);
}
static int DropdownListWidth(txt_dropdown_list_t *list)
@@ -197,15 +214,7 @@ static void TXT_DropdownListDrawer(TXT_UNCAST_ARG(list), int selected)
// Set bg/fg text colors.
- if (selected)
- {
- TXT_BGColor(TXT_COLOR_GREY, 0);
- }
- else
- {
- TXT_BGColor(TXT_COLOR_BLUE, 0);
- }
-
+ TXT_SetWidgetBG(list, selected);
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
// Select a string to draw from the list, if the current value is
diff --git a/textscreen/txt_gui.c b/textscreen/txt_gui.c
index ec166415..d00e3a65 100644
--- a/textscreen/txt_gui.c
+++ b/textscreen/txt_gui.c
@@ -131,7 +131,7 @@ void TXT_DrawWindowFrame(const char *title, int x, int y, int w, int h)
int bx, by;
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
- TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_BGColor(TXT_WINDOW_BACKGROUND, 0);
for (y1=y; y1<y+h; ++y1)
{
@@ -191,7 +191,7 @@ void TXT_DrawSeparator(int x, int y, int w)
data = TXT_GetScreenData();
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
- TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_BGColor(TXT_WINDOW_BACKGROUND, 0);
if (!VALID_Y(y))
{
diff --git a/textscreen/txt_gui.h b/textscreen/txt_gui.h
index ad7ae428..06fc7a36 100644
--- a/textscreen/txt_gui.h
+++ b/textscreen/txt_gui.h
@@ -27,6 +27,9 @@
#ifndef TXT_GUI_H
#define TXT_GUI_H
+#define TXT_WINDOW_BACKGROUND TXT_COLOR_BLUE
+#define TXT_HOVER_BACKGROUND TXT_COLOR_CYAN
+
void TXT_DrawDesktopBackground(const char *title);
void TXT_DrawWindowFrame(const char *title, int x, int y, int w, int h);
void TXT_DrawSeparator(int x, int y, int w);
@@ -35,6 +38,7 @@ void TXT_DrawString(const char *s);
void TXT_DrawHorizScrollbar(int x, int y, int w, int cursor, int range);
void TXT_DrawVertScrollbar(int x, int y, int h, int cursor, int range);
+
void TXT_InitClipArea(void);
void TXT_PushClipArea(int x1, int x2, int y1, int y2);
void TXT_PopClipArea(void);
diff --git a/textscreen/txt_inputbox.c b/textscreen/txt_inputbox.c
index 852346f3..a28c342c 100644
--- a/textscreen/txt_inputbox.c
+++ b/textscreen/txt_inputbox.c
@@ -60,15 +60,9 @@ static void TXT_InputBoxDrawer(TXT_UNCAST_ARG(inputbox), int selected)
{
TXT_BGColor(TXT_COLOR_BLACK, 0);
}
- else if (selected)
- {
- TXT_BGColor(TXT_COLOR_GREY, 0);
- }
else
{
- // Not even selected
-
- TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_SetWidgetBG(inputbox, selected);
}
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
diff --git a/textscreen/txt_label.c b/textscreen/txt_label.c
index 0deea803..c973bce2 100644
--- a/textscreen/txt_label.c
+++ b/textscreen/txt_label.c
@@ -176,7 +176,7 @@ txt_label_t *TXT_NewLabel(char *text)
// Default colors
- label->bgcolor = TXT_COLOR_BLUE;
+ label->bgcolor = TXT_WINDOW_BACKGROUND;
label->fgcolor = TXT_COLOR_BRIGHT_WHITE;
TXT_SetLabel(label, text);
diff --git a/textscreen/txt_main.h b/textscreen/txt_main.h
index add30fa3..a415ee1b 100644
--- a/textscreen/txt_main.h
+++ b/textscreen/txt_main.h
@@ -34,10 +34,12 @@
// Special keypress values that correspond to mouse button clicks
-#define TXT_MOUSE_BASE 0x10000
-#define TXT_MOUSE_LEFT (TXT_MOUSE_BASE + 0)
-#define TXT_MOUSE_RIGHT (TXT_MOUSE_BASE + 1)
-#define TXT_MOUSE_MIDDLE (TXT_MOUSE_BASE + 2)
+#define TXT_MOUSE_BASE 0x10000
+#define TXT_MOUSE_LEFT (TXT_MOUSE_BASE + 0)
+#define TXT_MOUSE_RIGHT (TXT_MOUSE_BASE + 1)
+#define TXT_MOUSE_MIDDLE (TXT_MOUSE_BASE + 2)
+#define TXT_MOUSE_SCROLLUP (TXT_MOUSE_BASE + 3)
+#define TXT_MOUSE_SCROLLDOWN (TXT_MOUSE_BASE + 4)
#define TXT_MAX_MOUSE_BUTTONS 16
// Screen size
@@ -67,6 +69,16 @@ typedef enum
TXT_COLOR_BRIGHT_WHITE,
} txt_color_t;
+// Modifier keys.
+
+typedef enum
+{
+ TXT_MOD_SHIFT,
+ TXT_MOD_CTRL,
+ TXT_MOD_ALT,
+ TXT_NUM_MODIFIERS
+} txt_modifier_t;
+
// Initialize the screen
// Returns 1 if successful, 0 if failed.
@@ -92,6 +104,10 @@ void TXT_UpdateScreen(void);
int TXT_GetChar(void);
+// Read the current state of modifier keys that are held down.
+
+int TXT_GetModifierState(txt_modifier_t mod);
+
// Provides a short description of a key code, placing into the
// provided buffer.
diff --git a/textscreen/txt_radiobutton.c b/textscreen/txt_radiobutton.c
index 00c2c4fc..0755562d 100644
--- a/textscreen/txt_radiobutton.c
+++ b/textscreen/txt_radiobutton.c
@@ -48,7 +48,7 @@ static void TXT_RadioButtonDrawer(TXT_UNCAST_ARG(radiobutton), int selected)
w = radiobutton->widget.w;
- TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_BGColor(TXT_WINDOW_BACKGROUND, 0);
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawString("(");
@@ -67,11 +67,7 @@ static void TXT_RadioButtonDrawer(TXT_UNCAST_ARG(radiobutton), int selected)
TXT_DrawString(") ");
- if (selected)
- {
- TXT_BGColor(TXT_COLOR_GREY, 0);
- }
-
+ TXT_SetWidgetBG(radiobutton, selected);
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
TXT_DrawString(radiobutton->label);
diff --git a/textscreen/txt_scrollpane.c b/textscreen/txt_scrollpane.c
index 17c9bcbf..2fd45c55 100644
--- a/textscreen/txt_scrollpane.c
+++ b/textscreen/txt_scrollpane.c
@@ -416,6 +416,33 @@ static void TXT_ScrollPaneMousePress(TXT_UNCAST_ARG(scrollpane),
scrollbars = NeedsScrollbars(scrollpane);
+ if (b == TXT_MOUSE_SCROLLUP)
+ {
+ if (scrollbars & SCROLLBAR_VERTICAL)
+ {
+ scrollpane->y -= 3;
+ }
+ else if (scrollbars & SCROLLBAR_HORIZONTAL)
+ {
+ scrollpane->x -= 3;
+ }
+
+ return;
+ }
+ else if (b == TXT_MOUSE_SCROLLDOWN)
+ {
+ if (scrollbars & SCROLLBAR_VERTICAL)
+ {
+ scrollpane->y += 3;
+ }
+ else if (scrollbars & SCROLLBAR_HORIZONTAL)
+ {
+ scrollpane->x += 3;
+ }
+
+ return;
+ }
+
rel_x = x - scrollpane->widget.x;
rel_y = y - scrollpane->widget.y;
@@ -433,14 +460,15 @@ static void TXT_ScrollPaneMousePress(TXT_UNCAST_ARG(scrollpane),
else
{
int range = FullWidth(scrollpane) - scrollpane->w;
+ int bar_max = scrollpane->w - 3;
- scrollpane->x = ((rel_x - 1) * range) / (scrollpane->w - 3);
+ scrollpane->x = ((rel_x - 1) * range + (bar_max / 2)) / bar_max;
}
return;
}
- // Click on the horizontal scrollbar?
+ // Click on the vertical scrollbar?
if ((scrollbars & SCROLLBAR_VERTICAL) && rel_x == scrollpane->w)
{
if (rel_y == 0)
@@ -454,8 +482,9 @@ static void TXT_ScrollPaneMousePress(TXT_UNCAST_ARG(scrollpane),
else
{
int range = FullHeight(scrollpane) - scrollpane->h;
+ int bar_max = scrollpane->h - 3;
- scrollpane->y = ((rel_y - 1) * range) / (scrollpane->h - 3);
+ scrollpane->y = ((rel_y - 1) * range + (bar_max / 2)) / bar_max;
}
return;
@@ -465,7 +494,6 @@ static void TXT_ScrollPaneMousePress(TXT_UNCAST_ARG(scrollpane),
{
TXT_WidgetMousePress(scrollpane->child, x, y, b);
}
-
}
static void TXT_ScrollPaneLayout(TXT_UNCAST_ARG(scrollpane))
@@ -529,6 +557,10 @@ txt_scrollpane_t *TXT_NewScrollPane(int w, int h, TXT_UNCAST_ARG(target))
scrollpane->expand_w = w <= 0;
scrollpane->expand_h = h <= 0;
+ // Set parent pointer for inner widget.
+
+ target->parent = &scrollpane->widget;
+
return scrollpane;
}
diff --git a/textscreen/txt_sdl.c b/textscreen/txt_sdl.c
index 2fbaa316..477fdb52 100644
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -63,6 +63,8 @@ static int key_mapping = 1;
static TxtSDLEventCallbackFunc event_callback;
static void *event_callback_data;
+static int modifier_state[TXT_NUM_MODIFIERS];
+
// Font we are using:
static txt_font_t *font;
@@ -225,7 +227,7 @@ int TXT_Init(void)
// Ignore all mouse motion events
- SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
+// SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
// Repeat key presses so we can hold down arrows to scroll down the
// menu, for example. This is what setup.exe does.
@@ -479,6 +481,66 @@ static int SDLButtonToTXTButton(int button)
}
}
+static int MouseHasMoved(void)
+{
+ static int last_x = 0, last_y = 0;
+ int x, y;
+
+ TXT_GetMousePosition(&x, &y);
+
+ if (x != last_x || y != last_y)
+ {
+ last_x = x; last_y = y;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Examine a key press/release and update the modifier key state
+// if necessary.
+
+static void UpdateModifierState(SDL_keysym *sym, int pressed)
+{
+ txt_modifier_t mod;
+
+ switch (sym->sym)
+ {
+ case SDLK_LSHIFT:
+ case SDLK_RSHIFT:
+ mod = TXT_MOD_SHIFT;
+ break;
+
+ case SDLK_LCTRL:
+ case SDLK_RCTRL:
+ mod = TXT_MOD_CTRL;
+ break;
+
+ case SDLK_LALT:
+ case SDLK_RALT:
+#if !SDL_VERSION_ATLEAST(1, 3, 0)
+ case SDLK_LMETA:
+ case SDLK_RMETA:
+#endif
+ mod = TXT_MOD_ALT;
+ break;
+
+ default:
+ return;
+ }
+
+ if (pressed)
+ {
+ ++modifier_state[mod];
+ }
+ else
+ {
+ --modifier_state[mod];
+ }
+}
+
signed int TXT_GetChar(void)
{
SDL_Event ev;
@@ -508,12 +570,24 @@ signed int TXT_GetChar(void)
break;
case SDL_KEYDOWN:
+ UpdateModifierState(&ev.key.keysym, 1);
+
return TranslateKey(&ev.key.keysym);
+ case SDL_KEYUP:
+ UpdateModifierState(&ev.key.keysym, 0);
+ break;
+
case SDL_QUIT:
// Quit = escape
return 27;
+ case SDL_MOUSEMOTION:
+ if (MouseHasMoved())
+ {
+ return 0;
+ }
+
default:
break;
}
@@ -522,6 +596,16 @@ signed int TXT_GetChar(void)
return -1;
}
+int TXT_GetModifierState(txt_modifier_t mod)
+{
+ if (mod < TXT_NUM_MODIFIERS)
+ {
+ return modifier_state[mod] > 0;
+ }
+
+ return 0;
+}
+
static const char *SpecialKeyName(int key)
{
switch (key)
diff --git a/textscreen/txt_separator.c b/textscreen/txt_separator.c
index 6b779626..89db0b03 100644
--- a/textscreen/txt_separator.c
+++ b/textscreen/txt_separator.c
@@ -65,7 +65,7 @@ static void TXT_SeparatorDrawer(TXT_UNCAST_ARG(separator), int selected)
{
TXT_GotoXY(x, y);
- TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_BGColor(TXT_WINDOW_BACKGROUND, 0);
TXT_FGColor(TXT_COLOR_BRIGHT_GREEN);
TXT_DrawString(" ");
TXT_DrawString(separator->label);
@@ -80,6 +80,20 @@ static void TXT_SeparatorDestructor(TXT_UNCAST_ARG(separator))
free(separator->label);
}
+void TXT_SetSeparatorLabel(txt_separator_t *separator, char *label)
+{
+ free(separator->label);
+
+ if (label != NULL)
+ {
+ separator->label = strdup(label);
+ }
+ else
+ {
+ separator->label = NULL;
+ }
+}
+
txt_widget_class_t txt_separator_class =
{
TXT_NeverSelectable,
@@ -99,14 +113,8 @@ txt_separator_t *TXT_NewSeparator(char *label)
TXT_InitWidget(separator, &txt_separator_class);
- if (label != NULL)
- {
- separator->label = strdup(label);
- }
- else
- {
- separator->label = NULL;
- }
+ separator->label = NULL;
+ TXT_SetSeparatorLabel(separator, label);
return separator;
}
diff --git a/textscreen/txt_separator.h b/textscreen/txt_separator.h
index 2f2331da..f693d70e 100644
--- a/textscreen/txt_separator.h
+++ b/textscreen/txt_separator.h
@@ -59,6 +59,14 @@ extern txt_widget_class_t txt_separator_class;
txt_separator_t *TXT_NewSeparator(char *label);
-#endif /* #ifndef TXT_SEPARATOR_H */
+/**
+ * Change the label on a separator.
+ *
+ * @param separator The separator.
+ * @param label The new label.
+ */
+
+void TXT_SetSeparatorLabel(txt_separator_t *separator, char *label);
+#endif /* #ifndef TXT_SEPARATOR_H */
diff --git a/textscreen/txt_spinctrl.c b/textscreen/txt_spinctrl.c
index d775aecf..2b2d4d09 100644
--- a/textscreen/txt_spinctrl.c
+++ b/textscreen/txt_spinctrl.c
@@ -149,7 +149,7 @@ static void TXT_SpinControlDrawer(TXT_UNCAST_ARG(spincontrol), int selected)
unsigned int padding;
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
- TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_BGColor(TXT_WINDOW_BACKGROUND, 0);
TXT_DrawString("\x1b ");
@@ -161,13 +161,9 @@ static void TXT_SpinControlDrawer(TXT_UNCAST_ARG(spincontrol), int selected)
{
TXT_BGColor(TXT_COLOR_BLACK, 0);
}
- else if (selected)
- {
- TXT_BGColor(TXT_COLOR_GREY, 0);
- }
else
{
- TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_SetWidgetBG(spincontrol, selected);
}
if (!spincontrol->editing)
@@ -195,7 +191,7 @@ static void TXT_SpinControlDrawer(TXT_UNCAST_ARG(spincontrol), int selected)
}
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
- TXT_BGColor(TXT_COLOR_BLUE, 0);
+ TXT_BGColor(TXT_WINDOW_BACKGROUND, 0);
TXT_DrawString(" \x1a");
}
diff --git a/textscreen/txt_table.c b/textscreen/txt_table.c
index ffe6fd14..7a8624f0 100644
--- a/textscreen/txt_table.c
+++ b/textscreen/txt_table.c
@@ -173,6 +173,13 @@ void TXT_AddWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget))
sizeof(txt_widget_t *) * (table->num_widgets + 1));
table->widgets[table->num_widgets] = widget;
++table->num_widgets;
+
+ // Maintain parent pointer.
+
+ if (widget != NULL)
+ {
+ widget->parent = &table->widget;
+ }
}
// Add multiple widgets to a table.
diff --git a/textscreen/txt_widget.c b/textscreen/txt_widget.c
index 760943d5..d47a7507 100644
--- a/textscreen/txt_widget.c
+++ b/textscreen/txt_widget.c
@@ -24,6 +24,8 @@
#include "txt_io.h"
#include "txt_widget.h"
+#include "txt_gui.h"
+#include "txt_desktop.h"
typedef struct
{
@@ -82,6 +84,7 @@ void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class)
widget->widget_class = widget_class;
widget->callback_table = TXT_NewCallbackTable();
+ widget->parent = NULL;
// Visible by default.
@@ -237,3 +240,62 @@ int TXT_SelectableWidget(TXT_UNCAST_ARG(widget))
}
}
+int TXT_ContainsWidget(TXT_UNCAST_ARG(haystack), TXT_UNCAST_ARG(needle))
+{
+ TXT_CAST_ARG(txt_widget_t, haystack);
+ TXT_CAST_ARG(txt_widget_t, needle);
+
+ while (needle != NULL)
+ {
+ if (needle == haystack)
+ {
+ return 1;
+ }
+
+ needle = needle->parent;
+ }
+
+ return 0;
+}
+
+int TXT_HoveringOverWidget(TXT_UNCAST_ARG(widget))
+{
+ TXT_CAST_ARG(txt_widget_t, widget);
+ txt_window_t *active_window;
+ int x, y;
+
+ // We can only be hovering over widgets in the active window.
+
+ active_window = TXT_GetActiveWindow();
+
+ if (active_window == NULL || !TXT_ContainsWidget(active_window, widget))
+ {
+ return 0;
+ }
+
+ // Is the mouse cursor within the bounds of the widget?
+
+ TXT_GetMousePosition(&x, &y);
+
+ return (x >= widget->x && x < widget->x + widget->w
+ && y >= widget->y && y < widget->y + widget->h);
+}
+
+void TXT_SetWidgetBG(TXT_UNCAST_ARG(widget), int selected)
+{
+ TXT_CAST_ARG(txt_widget_t, widget);
+
+ if (selected)
+ {
+ TXT_BGColor(TXT_COLOR_GREY, 0);
+ }
+ else if (TXT_HoveringOverWidget(widget))
+ {
+ TXT_BGColor(TXT_HOVER_BACKGROUND, 0);
+ }
+ else
+ {
+ TXT_BGColor(TXT_WINDOW_BACKGROUND, 0);
+ }
+}
+
diff --git a/textscreen/txt_widget.h b/textscreen/txt_widget.h
index bb895f92..ebb5a292 100644
--- a/textscreen/txt_widget.h
+++ b/textscreen/txt_widget.h
@@ -102,6 +102,10 @@ struct txt_widget_s
int x, y;
unsigned int w, h;
+
+ // Pointer up to parent widget that contains this widget.
+
+ txt_widget_t *parent;
};
void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class);
@@ -146,6 +150,34 @@ void TXT_SetWidgetAlign(TXT_UNCAST_ARG(widget), txt_horiz_align_t horiz_align);
int TXT_SelectableWidget(TXT_UNCAST_ARG(widget));
-#endif /* #ifndef TXT_WIDGET_H */
+/**
+ * Query whether the mouse is hovering over the specified widget.
+ *
+ * @param widget The widget.
+ * @return Non-zero if the mouse cursor is over the widget.
+ */
+
+int TXT_HoveringOverWidget(TXT_UNCAST_ARG(widget));
+
+/**
+ * Set the background to draw the specified widget, depending on
+ * whether it is selected and the mouse is hovering over it.
+ *
+ * @param widget The widget.
+ * @param selected Whether the widget is selected.
+ */
+
+void TXT_SetWidgetBG(TXT_UNCAST_ARG(widget), int selected);
+
+/**
+ * Query whether the specified widget is contained within another
+ * widget.
+ *
+ * @param haystack The widget that might contain needle.
+ * @param needle The widget being queried.
+ */
+int TXT_ContainsWidget(TXT_UNCAST_ARG(haystack), TXT_UNCAST_ARG(needle));
+
+#endif /* #ifndef TXT_WIDGET_H */
diff --git a/textscreen/txt_window.c b/textscreen/txt_window.c
index 46e71d3a..cd8a6c7a 100644
--- a/textscreen/txt_window.c
+++ b/textscreen/txt_window.c
@@ -40,6 +40,13 @@ void TXT_SetWindowAction(txt_window_t *window,
}
window->actions[position] = action;
+
+ // Maintain parent pointer.
+
+ if (action != NULL)
+ {
+ action->widget.parent = &window->table.widget;
+ }
}
txt_window_t *TXT_NewWindow(char *title)
@@ -158,7 +165,7 @@ static void LayoutActionArea(txt_window_t *window)
TXT_CalcWidgetSize(widget);
- widget->x = window->window_x + 2;
+ widget->x = window->window_x + 1;
widget->y = window->window_y + window->window_h - widget->h - 1;
// Adjust available space:
@@ -175,7 +182,7 @@ static void LayoutActionArea(txt_window_t *window)
TXT_CalcWidgetSize(widget);
- widget->x = window->window_x + window->window_w - 2 - widget->w;
+ widget->x = window->window_x + window->window_w - 1 - widget->w;
widget->y = window->window_y + window->window_h - widget->h - 1;
// Adjust available space:
@@ -220,7 +227,7 @@ static void CalcActionAreaSize(txt_window_t *window,
txt_widget_t *widget;
int i;
- *w = 1;
+ *w = 0;
*h = 0;
// Calculate the width of all the action widgets and use this
@@ -233,7 +240,7 @@ static void CalcActionAreaSize(txt_window_t *window,
if (widget != NULL)
{
TXT_CalcWidgetSize(widget);
- *w += widget->w + 1;
+ *w += widget->w;
if (widget->h > *h)
{
diff --git a/textscreen/txt_window_action.c b/textscreen/txt_window_action.c
index e593b7b6..df0e4ea3 100644
--- a/textscreen/txt_window_action.c
+++ b/textscreen/txt_window_action.c
@@ -37,9 +37,10 @@ static void TXT_WindowActionSizeCalc(TXT_UNCAST_ARG(action))
TXT_GetKeyDescription(action->key, buf);
- // Minimum width is the string length + two spaces for padding
+ // Width is label length, plus key description length, plus '='
+ // and two surrounding spaces.
- action->widget.w = strlen(action->label) + strlen(buf) + 1;
+ action->widget.w = strlen(action->label) + strlen(buf) + 3;
action->widget.h = 1;
}
@@ -50,12 +51,24 @@ static void TXT_WindowActionDrawer(TXT_UNCAST_ARG(action), int selected)
TXT_GetKeyDescription(action->key, buf);
+ if (TXT_HoveringOverWidget(action))
+ {
+ TXT_BGColor(TXT_COLOR_BLACK, 0);
+ }
+ else
+ {
+ TXT_BGColor(TXT_WINDOW_BACKGROUND, 0);
+ }
+
+ TXT_DrawString(" ");
TXT_FGColor(TXT_COLOR_BRIGHT_GREEN);
TXT_DrawString(buf);
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawString("=");
+
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
TXT_DrawString(action->label);
+ TXT_DrawString(" ");
}
static void TXT_WindowActionDestructor(TXT_UNCAST_ARG(action))
@@ -69,7 +82,7 @@ static int TXT_WindowActionKeyPress(TXT_UNCAST_ARG(action), int key)
{
TXT_CAST_ARG(txt_window_action_t, action);
- if (key == action->key)
+ if (tolower(key) == tolower(action->key))
{
TXT_EmitSignal(action, "pressed");
return 1;