foxygit / doom Log in
commit 1de18c1397bfb069771c02336e47b89e098b6f43
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Tue May 23 00:07:02 2006 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Tue May 23 00:07:02 2006 +0000

    Add window action class for action area labels at the bottom of windows.
    Adjust txt_table_t to expand tables to their maximum width when they
    only have one column (ensures separators reach the window edges).

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 515
---
 textscreen/Makefile.am         |   1 +
 textscreen/txt_table.c         |   9 +++
 textscreen/txt_window.c        | 127 +++++++++++++++++++++++++++++++++++++++--
 textscreen/txt_window.h        |   7 +++
 textscreen/txt_window_action.c |  81 ++++++++++++++++++++++++++
 textscreen/txt_window_action.h |  42 ++++++++++++++
 6 files changed, 263 insertions(+), 4 deletions(-)

diff --git a/textscreen/Makefile.am b/textscreen/Makefile.am
index 004aea98..90b7e441 100644
--- a/textscreen/Makefile.am
+++ b/textscreen/Makefile.am
@@ -17,6 +17,7 @@ libtextscreen_a_SOURCES =                                 \
 	txt_table.c              txt_table.h              \
 	txt_widget.c             txt_widget.h             \
 	txt_window.c             txt_window.h             \
+	txt_window_action.c      txt_window_action.h      \
 	txt_font.h

 guitest_LDADD = @SDL_LIBS@ libtextscreen.a
diff --git a/textscreen/txt_table.c b/textscreen/txt_table.c
index ccf81db2..4c502c0c 100644
--- a/textscreen/txt_table.c
+++ b/textscreen/txt_table.c
@@ -365,6 +365,15 @@ static void TXT_TableDrawer(TXT_UNCAST_ARG(table), int w, int selected)

     CalcRowColSizes(table, row_heights, column_widths);

+    // If this table only has one column, expand column size to fit
+    // the display width.  Ensures that separators reach the window edges
+    // when drawing windows.
+
+    if (table->columns == 1)
+    {
+        column_widths[0] = w;
+    }
+
     // Draw all cells

     draw_y = origin_y;
diff --git a/textscreen/txt_window.c b/textscreen/txt_window.c
index f993a84e..b66995d7 100644
--- a/textscreen/txt_window.c
+++ b/textscreen/txt_window.c
@@ -33,8 +33,24 @@
 #include "txt_separator.h"
 #include "txt_window.h"

+void TXT_SetWindowAction(txt_window_t *window,
+                         txt_horiz_align_t position,
+                         txt_window_action_t *action)
+{
+    if (window->actions[position] != NULL)
+    {
+        TXT_DestroyWidget(window->actions[position]);
+    }
+
+    window->actions[position] = action;
+}
+
 txt_window_t *TXT_NewWindow(char *title)
 {
+    int i;
+    txt_window_action_t *cancel_action;
+    txt_window_action_t *accept_action;
+
     txt_window_t *win;

     win = malloc(sizeof(txt_window_t));
@@ -48,18 +64,41 @@ txt_window_t *TXT_NewWindow(char *title)
     win->vert_align = TXT_VERT_CENTER;

     TXT_AddWidget(win, TXT_NewSeparator(NULL));
+
+    for (i=0; i<3; ++i)
+        win->actions[i] = NULL;
+
     TXT_AddDesktopWindow(win);

+    // Default actions
+
+    cancel_action = TXT_NewWindowAction(KEY_ESCAPE, "Abort");
+    TXT_SetWindowAction(win, TXT_HORIZ_LEFT, cancel_action);
+    accept_action = TXT_NewWindowAction(KEY_ENTER, "Accept");
+    TXT_SetWindowAction(win, TXT_HORIZ_RIGHT, accept_action);
+
     return win;
 }

 void TXT_CloseWindow(txt_window_t *window)
 {
+    int i;
+
     free(window->title);

+    // Destroy all actions
+
+    for (i=0; i<3; ++i)
+    {
+        if (window->actions[i] != NULL)
+        {
+            TXT_DestroyWidget(window->actions[i]);
+        }
+    }
+
     // Destroy table and window

-    TXT_DestroyWidget((txt_widget_t *) window);
+    TXT_DestroyWidget(window);

     TXT_RemoveDesktopWindow(window);
 }
@@ -95,6 +134,65 @@ static void CalcWindowPosition(txt_window_t *window,
     }
 }

+static void DrawActionArea(txt_window_t *window,
+                           int window_x, int window_y,
+                           int window_w, int window_h)
+{
+    int ww, wh;
+
+    // Draw the left action
+
+    if (window->actions[TXT_HORIZ_LEFT] != NULL)
+    {
+        TXT_GotoXY(window_x + 2, window_y + window_h - 2);
+        TXT_DrawWidget(window->actions[TXT_HORIZ_LEFT], 0, 0);
+    }
+
+    // Draw the center action
+
+    if (window->actions[TXT_HORIZ_CENTER] != NULL)
+    {
+        TXT_CalcWidgetSize(window->actions[TXT_HORIZ_CENTER], &ww, &wh);
+        TXT_GotoXY(window_x + (window_w - ww - 2) / 2, window_y + window_h - 2);
+        TXT_DrawWidget(window->actions[TXT_HORIZ_CENTER], 0, 0);
+    }
+
+    // Draw the right action
+
+    if (window->actions[TXT_HORIZ_RIGHT] != NULL)
+    {
+        TXT_CalcWidgetSize(window->actions[TXT_HORIZ_RIGHT], &ww, &wh);
+        TXT_GotoXY(window_x + window_w - 2 - ww, window_y + window_h - 2);
+        TXT_DrawWidget(window->actions[TXT_HORIZ_RIGHT], 0, 0);
+    }
+}
+
+static int CalcActionAreaWidth(txt_window_t *window, int *widgets_w)
+{
+    int ww, wh;
+    int w;
+    int i;
+
+    w = 1;
+
+    // Calculate the width of all the action widgets and use this
+    // to create an overall min. width of the action area
+
+    for (i=0; i<3; ++i)
+    {
+        if (window->actions[i] != NULL)
+        {
+            TXT_CalcWidgetSize(window->actions[i], &ww, &wh);
+            w += ww + 1;
+        }
+    }
+
+    // If this is larger than the window size, adjust the window to fit.
+
+    if (w > *widgets_w)
+        *widgets_w = w;
+}
+
 void TXT_DrawWindow(txt_window_t *window)
 {
     int widgets_w, widgets_h;
@@ -104,7 +202,8 @@ void TXT_DrawWindow(txt_window_t *window)
     int i;
     int ww, wh;

-    TXT_CalcWidgetSize((txt_widget_t *) window, &widgets_w, &widgets_h);
+    TXT_CalcWidgetSize(window, &widgets_w, &widgets_h);
+    CalcActionAreaWidth(window, &widgets_w);

     // Actual window size after padding

@@ -123,11 +222,15 @@ void TXT_DrawWindow(txt_window_t *window)
     // Draw all widgets

     TXT_GotoXY(window_x + 1, window_y + 2);
-    TXT_DrawWidget((txt_widget_t *) window, widgets_w, 1);
+    TXT_DrawWidget(window, widgets_w, 1);

     // Separator for action area

     TXT_DrawSeparator(window_x, window_y + 2 + widgets_h, window_w);
+
+    // Action area at the window bottom
+
+    DrawActionArea(window, window_x, window_y, window_w, window_h);
 }

 void TXT_SetWindowPosition(txt_window_t *window,
@@ -143,8 +246,24 @@ void TXT_SetWindowPosition(txt_window_t *window,

 void TXT_WindowKeyPress(txt_window_t *window, int c)
 {
+    int i;
+
     // Send to the currently selected widget first

-    TXT_WidgetKeyPress((txt_widget_t *) window, c);
+    if (TXT_WidgetKeyPress(window, c))
+    {
+        return;
+    }
+
+    // Try all of the action buttons
+
+    for (i=0; i<3; ++i)
+    {
+        if (window->actions[i] != NULL
+         && TXT_WidgetKeyPress(window->actions[i], c))
+        {
+            return;
+        }
+    }
 }

diff --git a/textscreen/txt_window.h b/textscreen/txt_window.h
index 0afe81aa..2b72015e 100644
--- a/textscreen/txt_window.h
+++ b/textscreen/txt_window.h
@@ -43,6 +43,7 @@ typedef enum

 #include "txt_widget.h"
 #include "txt_table.h"
+#include "txt_window_action.h"

 struct txt_window_s
 {
@@ -59,6 +60,10 @@ struct txt_window_s
     txt_vert_align_t vert_align;
     txt_horiz_align_t horiz_align;
     int x, y;
+
+    // Actions that appear in the box at the bottom of the window
+
+    txt_window_action_t *actions[3];
 };

 txt_window_t *TXT_NewWindow(char *title);
@@ -67,6 +72,8 @@ void TXT_SetWindowPosition(txt_window_t *window,
                            txt_horiz_align_t horiz_align,
                            txt_vert_align_t vert_align,
                            int x, int y);
+void TXT_SetWindowAction(txt_window_t *window, txt_horiz_align_t position,
+                         txt_window_action_t *action);

 #endif /* #ifndef TXT_WINDOW_T */

diff --git a/textscreen/txt_window_action.c b/textscreen/txt_window_action.c
new file mode 100644
index 00000000..072a87c5
--- /dev/null
+++ b/textscreen/txt_window_action.c
@@ -0,0 +1,81 @@
+
+#include <string.h>
+
+#include "doomkeys.h"
+
+#include "txt_window_action.h"
+#include "txt_io.h"
+#include "txt_main.h"
+#include "txt_window.h"
+
+static void TXT_WindowActionSizeCalc(TXT_UNCAST_ARG(action),
+                                     int *w, int *h)
+{
+    TXT_CAST_ARG(txt_window_action_t, action);
+    char buf[10];
+
+    TXT_GetKeyDescription(action->key, buf);
+
+    // Minimum width is the string length + two spaces for padding
+
+    *w = strlen(action->label) + strlen(buf) + 1;
+    *h = 1;
+}
+
+static void TXT_WindowActionDrawer(TXT_UNCAST_ARG(action), int w, int selected)
+{
+    TXT_CAST_ARG(txt_window_action_t, action);
+    int i;
+    char buf[10];
+
+    TXT_GetKeyDescription(action->key, buf);
+
+    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);
+}
+
+static void TXT_WindowActionDestructor(TXT_UNCAST_ARG(action))
+{
+    TXT_CAST_ARG(txt_window_action_t, action);
+
+    free(action->label);
+}
+
+static int TXT_WindowActionKeyPress(TXT_UNCAST_ARG(action), int key)
+{
+    TXT_CAST_ARG(txt_window_action_t, action);
+
+    if (key == action->key)
+    {
+        TXT_EmitSignal(action, "pressed");
+        return 1;
+    }
+
+    return 0;
+}
+
+txt_widget_class_t txt_window_action_class =
+{
+    TXT_WindowActionSizeCalc,
+    TXT_WindowActionDrawer,
+    TXT_WindowActionKeyPress,
+    TXT_WindowActionDestructor,
+};
+
+txt_window_action_t *TXT_NewWindowAction(int key, char *label)
+{
+    txt_window_action_t *action;
+
+    action = malloc(sizeof(txt_window_action_t));
+
+    TXT_InitWidget(action, &txt_window_action_class);
+    action->key = key;
+    action->label = strdup(label);
+
+    return action;
+}
+
diff --git a/textscreen/txt_window_action.h b/textscreen/txt_window_action.h
new file mode 100644
index 00000000..d4194ddd
--- /dev/null
+++ b/textscreen/txt_window_action.h
@@ -0,0 +1,42 @@
+// Emacs style mode select   -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// $Id$
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2006 Simon Howard
+//
+// 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.
+//
+
+#ifndef TXT_WINDOW_ACTION_H
+#define TXT_WINDOW_ACTION_H
+
+typedef struct txt_window_action_s txt_window_action_t;
+
+#include "txt_widget.h"
+
+struct txt_window_action_s
+{
+    txt_widget_t widget;
+    char *label;
+    int key;
+};
+
+txt_window_action_t *TXT_NewWindowAction(int key, char *label);
+
+#endif /* #ifndef TXT_WINDOW_ACTION_H */
+