shithub: choc

Download patch

ref: 5e303c43dab6c433bc3b59dd34d4672317c5f4e1
parent: b20f94345cd4eb779acf08f3017d02d56aaad9a6
author: Simon Howard <fraggle@gmail.com>
date: Thu Aug 31 14:11:26 EDT 2006

Add window listener functions to allow spying on keys and mouse buttons
received by windows. Emit a 'closed' signal when a window is closed.
Allow windows to have no action buttons.

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 576

--- a/textscreen/txt_window.c
+++ b/textscreen/txt_window.c
@@ -62,6 +62,8 @@
     win->y = TXT_SCREEN_H / 2;
     win->horiz_align = TXT_HORIZ_CENTER;
     win->vert_align = TXT_VERT_CENTER;
+    win->key_listener = NULL;
+    win->mouse_listener = NULL;
 
     TXT_AddWidget(win, TXT_NewSeparator(NULL));
 
@@ -82,6 +84,8 @@
 {
     int i;
 
+    TXT_EmitSignal(window, "closed");
+
     free(window->title);
 
     // Destroy all actions
@@ -143,7 +147,7 @@
         TXT_CalcWidgetSize(widget);
 
         widget->x = window->window_x + 2;
-        widget->y = window->window_y + window->window_h - 2;
+        widget->y = window->window_y + window->window_h - widget->h - 1;
     }
 
     // Draw the center action
@@ -155,7 +159,7 @@
         TXT_CalcWidgetSize(widget);
 
         widget->x = window->window_x + (window->window_w - widget->w - 2) / 2;
-        widget->y = window->window_y + window->window_h - 2;
+        widget->y = window->window_y + window->window_h - widget->h - 1;
     }
 
     // Draw the right action
@@ -167,7 +171,7 @@
         TXT_CalcWidgetSize(widget);
 
         widget->x = window->window_x + window->window_w - 2 - widget->w;
-        widget->y = window->window_y + window->window_h - 2;
+        widget->y = window->window_y + window->window_h - widget->h - 1;
     }
 }
 
@@ -184,13 +188,13 @@
     }
 }
 
-static int ActionAreaWidth(txt_window_t *window)
+static void CalcActionAreaSize(txt_window_t *window, int *w, int *h)
 {
     txt_widget_t *widget;
-    int w;
     int i;
 
-    w = 1;
+    *w = 1;
+    *h = 0;
 
     // Calculate the width of all the action widgets and use this
     // to create an overall min. width of the action area
@@ -202,11 +206,14 @@
         if (widget != NULL)
         {
             TXT_CalcWidgetSize(widget);
-            w += widget->w + 1;
+            *w += widget->w + 1;
+
+            if (widget->h > *h)
+            {
+                *h = widget->h;
+            }
         }
     }
-
-    return w;
 }
 
 // Sets size and position of all widgets in a window
@@ -215,7 +222,7 @@
 {
     txt_widget_t *widgets = (txt_widget_t *) window;
     int widgets_w;
-    int actionarea_w;
+    int actionarea_w, actionarea_h;
 
     // Calculate size of table
     
@@ -227,7 +234,7 @@
     // Calculate the size of the action area
     // Make window wide enough to action area
   
-    actionarea_w = ActionAreaWidth(window);
+    CalcActionAreaSize(window, &actionarea_w, &actionarea_h);
     
     if (actionarea_w > widgets_w)
         widgets_w = actionarea_w;
@@ -235,7 +242,7 @@
     // Set the window size based on widgets_w
    
     window->window_w = widgets_w + 2;
-    window->window_h = widgets->h + 3;
+    window->window_h = widgets->h + 1;
 
     // If the window has a title, add an extra two lines
 
@@ -244,6 +251,13 @@
         window->window_h += 2;
     }
 
+    // If the window has an action area, add extra lines
+
+    if (actionarea_h > 0)
+    {
+        window->window_h += actionarea_h + 1;
+    }
+
     // Use the x,y position as the centerpoint and find the location to 
     // draw the window.
 
@@ -254,8 +268,13 @@
     widgets->w = widgets_w - 2;
     // widgets->h        (already set)
     widgets->x = window->window_x + 2;
-    widgets->y = window->window_y + window->window_h - widgets->h - 3;
+    widgets->y = window->window_y;
 
+    if (window->title != NULL)
+    {
+        widgets->y += 2;
+    }
+
     // Layout the table and action area
 
     LayoutActionArea(window);
@@ -281,16 +300,21 @@
 
     TXT_DrawWidget(window, selected);
 
-    // Separator for action area
+    // Draw an action area, if we have one
 
-    widgets = (txt_widget_t *) window;
+    if (widgets->y + widgets->h < window->window_y + window->window_h - 1)
+    {
+        // Separator for action area
 
-    TXT_DrawSeparator(window->window_x, widgets->y + widgets->h, 
-                      window->window_w);
+        widgets = (txt_widget_t *) window;
 
-    // Action area at the window bottom
+        TXT_DrawSeparator(window->window_x, widgets->y + widgets->h, 
+                          window->window_w);
 
-    DrawActionArea(window);
+        // Action area at the window bottom
+
+        DrawActionArea(window);
+    }
 }
 
 void TXT_SetWindowPosition(txt_window_t *window,
@@ -319,6 +343,20 @@
 
     TXT_GetMousePosition(&x, &y);
 
+    // Try the mouse button listener
+    // This happens whether it is in the window range or not
+
+    if (window->mouse_listener != NULL)
+    {
+        // Mouse listener can eat button presses
+
+        if (window->mouse_listener(window, x, y, b, 
+                                   window->mouse_listener_data))
+        {
+            return;
+        }
+    }
+    
     // Is it within the table range?
 
     widgets = (txt_widget_t *) window;
@@ -351,14 +389,28 @@
 
     // Is this a mouse button ?
     
-    if (c == TXT_MOUSE_LEFT)
+    if (c == TXT_MOUSE_LEFT
+     || c == TXT_MOUSE_MIDDLE
+     || c == TXT_MOUSE_RIGHT)
     {
         MouseButtonPress(window, c);
         return;
     }
-    
-    // Send to the currently selected widget first
 
+    // Try the window key spy
+
+    if (window->key_listener != NULL)
+    {
+        // key listener can eat keys
+
+        if (window->key_listener(window, c, window->key_listener_data))
+        {
+            return;
+        }
+    }
+
+    // Send to the currently selected widget 
+
     if (TXT_WidgetKeyPress(window, c))
     {
         return;
@@ -374,5 +426,20 @@
             return;
         }
     }
+}
+
+void TXT_SetKeyListener(txt_window_t *window, TxtWindowKeyPress key_listener, 
+                        void *user_data)
+{
+    window->key_listener = key_listener;
+    window->key_listener_data = user_data;
+}
+
+void TXT_SetMouseListener(txt_window_t *window, 
+                          TxtWindowMousePress mouse_listener,
+                          void *user_data)
+{
+    window->mouse_listener = mouse_listener;
+    window->mouse_listener_data = user_data;
 }
 
--- a/textscreen/txt_window.h
+++ b/textscreen/txt_window.h
@@ -31,6 +31,13 @@
 #include "txt_table.h"
 #include "txt_window_action.h"
 
+// Callback function for window key presses
+
+typedef int (*TxtWindowKeyPress)(txt_window_t *window, int key, void *user_data);
+typedef int (*TxtWindowMousePress)(txt_window_t *window, 
+                                   int x, int y, int b, 
+                                   void *user_data);
+
 struct txt_window_s
 {
     // Base class: all windows are tables with one column.
@@ -51,6 +58,13 @@
 
     txt_window_action_t *actions[3];
 
+    // Callback functions to invoke when keys/mouse buttons are pressed
+
+    TxtWindowKeyPress key_listener;
+    void *key_listener_data;
+    TxtWindowMousePress mouse_listener;
+    void *mouse_listener_data;
+
     // These are set automatically when the window is drawn
 
     int window_x, window_y;
@@ -65,6 +79,12 @@
                            int x, int y);
 void TXT_SetWindowAction(txt_window_t *window, txt_horiz_align_t position, 
                          txt_window_action_t *action);
+void TXT_SetKeyListener(txt_window_t *window, 
+                        TxtWindowKeyPress key_listener, 
+                        void *user_data);
+void TXT_SetMouseListener(txt_window_t *window, 
+                          TxtWindowMousePress mouse_listener,
+                          void *user_data);
 
 #endif /* #ifndef TXT_WINDOW_T */