From 8741ed033996e3cfed28cfc97753ef0cd2c40b17 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 20 May 2006 20:49:50 +0000 Subject: Add table class. Allow widgets with heights of more than one line. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 492 --- textscreen/Makefile.am | 1 + textscreen/txt_button.c | 5 +- textscreen/txt_checkbox.c | 5 +- textscreen/txt_separator.c | 8 +- textscreen/txt_table.c | 397 +++++++++++++++++++++++++++++++++++++++++++++ textscreen/txt_table.h | 58 +++++++ textscreen/txt_widget.c | 4 +- textscreen/txt_widget.h | 4 +- textscreen/txt_window.c | 17 +- 9 files changed, 481 insertions(+), 18 deletions(-) create mode 100644 textscreen/txt_table.c create mode 100644 textscreen/txt_table.h (limited to 'textscreen') diff --git a/textscreen/Makefile.am b/textscreen/Makefile.am index 5f13215b..90949e5c 100644 --- a/textscreen/Makefile.am +++ b/textscreen/Makefile.am @@ -12,6 +12,7 @@ libtextscreen_a_SOURCES = \ txt_main.c txt_main.h \ txt_button.c txt_button.h \ txt_separator.c txt_separator.h\ + txt_table.c txt_table.h \ txt_widget.c txt_widget.h \ txt_window.c txt_window.h \ txt_font.h diff --git a/textscreen/txt_button.c b/textscreen/txt_button.c index 35457d69..57b91c96 100644 --- a/textscreen/txt_button.c +++ b/textscreen/txt_button.c @@ -7,13 +7,14 @@ #include "txt_widget.h" #include "txt_window.h" -static int TXT_ButtonSizeCalc(txt_widget_t *widget) +static void TXT_ButtonSizeCalc(txt_widget_t *widget, int *w, int *h) { txt_button_t *button = (txt_button_t *) widget; // Minimum width is the string length + two spaces for padding - return strlen(button->label) + 2; + *w = strlen(button->label) + 2; + *h = 1; } static void TXT_ButtonDrawer(txt_widget_t *widget, int w, int selected) diff --git a/textscreen/txt_checkbox.c b/textscreen/txt_checkbox.c index e8222606..b413874e 100644 --- a/textscreen/txt_checkbox.c +++ b/textscreen/txt_checkbox.c @@ -8,13 +8,14 @@ #include "txt_main.h" #include "txt_window.h" -static int TXT_CheckBoxSizeCalc(txt_widget_t *widget) +static void TXT_CheckBoxSizeCalc(txt_widget_t *widget, int *w, int *h) { txt_checkbox_t *checkbox = (txt_checkbox_t *) widget; // Minimum width is the string length + two spaces for padding - return strlen(checkbox->label) + 6; + *w = strlen(checkbox->label) + 6; + *h = 1; } static void TXT_CheckBoxDrawer(txt_widget_t *widget, int w, int selected) diff --git a/textscreen/txt_separator.c b/textscreen/txt_separator.c index b430f831..2013edac 100644 --- a/textscreen/txt_separator.c +++ b/textscreen/txt_separator.c @@ -7,7 +7,7 @@ #include "txt_widget.h" #include "txt_window.h" -static int TXT_SeparatorSizeCalc(txt_widget_t *widget) +static void TXT_SeparatorSizeCalc(txt_widget_t *widget, int *w, int *h) { txt_separator_t *separator = (txt_separator_t *) widget; @@ -15,12 +15,14 @@ static int TXT_SeparatorSizeCalc(txt_widget_t *widget) { // Minimum width is the string length + two spaces for padding - return strlen(separator->label) + 2; + *w = strlen(separator->label) + 2; } else { - return 0; + *w = 0; } + + *h = 1; } static void TXT_SeparatorDrawer(txt_widget_t *widget, int w, int selected) diff --git a/textscreen/txt_table.c b/textscreen/txt_table.c new file mode 100644 index 00000000..a23faeaf --- /dev/null +++ b/textscreen/txt_table.c @@ -0,0 +1,397 @@ +// 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. +// + +#include +#include + +#include "doomkeys.h" + +#include "txt_desktop.h" +#include "txt_gui.h" +#include "txt_main.h" +#include "txt_separator.h" +#include "txt_table.h" + +static void TXT_TableDestructor(txt_widget_t *widget) +{ + txt_table_t *table = (txt_table_t *) widget; + int i; + + // Free all widgets + + for (i=0; inum_widgets; ++i) + { + TXT_DestroyWidget(table->widgets[i]); + } + + // Free table resources + + free(table->widgets); +} + +// ------------- + +static int TableRows(txt_table_t *table) +{ + return (table->num_widgets + table->columns - 1) / table->columns; +} + +static void CalcRowColSizes(txt_table_t *table, + int *row_heights, + int *col_widths) +{ + int table_height; + int x, y; + int rows; + int ww, wh; + + rows = TableRows(table); + + memset(col_widths, 0, sizeof(int) * table->columns); + + for (y=0; ycolumns; ++x) + { + if (y * table->columns + x >= table->num_widgets) + break; + + TXT_CalcWidgetSize(table->widgets[y * table->columns + x], + &ww, &wh); + + if (wh > row_heights[y]) + row_heights[y] = wh; + if (ww > col_widths[x]) + col_widths[x] = ww; + } + } +} + +static void TXT_CalcTableSize(txt_widget_t *widget, int *w, int *h) +{ + txt_table_t *table = (txt_table_t *) widget; + int *column_widths; + int *row_heights; + int x, y; + int rows; + + rows = TableRows(table); + + row_heights = malloc(sizeof(int) * rows); + column_widths = malloc(sizeof(int) * table->columns); + + CalcRowColSizes(table, row_heights, column_widths); + + *w = 0; + + for (x=0; xcolumns; ++x) + { + *w += column_widths[x]; + } + + *h = 0; + + for (y=0; ycolumns); + row_heights = malloc(sizeof(int) * rows); + + CalcRowColSizes(table, row_heights, column_widths); + + // Draw all cells + + draw_y = origin_y; + + for (y=0; ycolumns; ++x) + { + if (y * table->columns + x >= table->num_widgets) + break; + + TXT_GotoXY(draw_x, draw_y); + + TXT_DrawWidget(table->widgets[y * table->columns + x], + column_widths[x], + selected && x == table->selected_x + && y == table->selected_y); + + draw_x += column_widths[x]; + } + + draw_y += row_heights[y]; + } + + free(row_heights); + free(column_widths); +} + +void TXT_AddTableWidget(void *uncast_table, void *uncast_widget) +{ + txt_widget_t *widget; + txt_table_t *table; + + table = (txt_table_t *) uncast_table; + widget = (txt_widget_t *) uncast_widget; + + if (table->num_widgets > 0) + { + txt_widget_t *last_widget; + + last_widget = table->widgets[table->num_widgets - 1]; + + if (widget->widget_class == &txt_separator_class + && last_widget->widget_class == &txt_separator_class) + { + // The previous widget added was a separator; replace + // it with this one. + // + // This way, if the first widget added to a window is + // a separator, it replaces the "default" separator that + // the window itself adds on creation. + + table->widgets[table->num_widgets - 1] = widget; + + TXT_DestroyWidget(last_widget); + + return; + } + } + + table->widgets = realloc(table->widgets, + sizeof(txt_widget_t *) * (table->num_widgets + 1)); + table->widgets[table->num_widgets] = widget; + ++table->num_widgets; +} + +#define SELECTABLE_WIDGET(w) ((w)->selectable && (w)->visible) + +// Tries to locate a selectable widget in the given row, returning +// the column number of the first column available or -1 if none are +// available in the given row. +// +// Starts from start_col, then searches nearby columns. + +static int FindSelectableColumn(txt_table_t *table, int row, int start_col) +{ + int x; + int i; + + for (x=0; xcolumns; ++x) + { + // Search to the right + + i = table->columns * row + start_col + x; + + if (i >= 0 && i < table->num_widgets + && SELECTABLE_WIDGET(table->widgets[i])) + { + return start_col + x; + } + + // Search to the left + + i = table->columns * row + start_col - x; + + if (i >= 0 && i < table->num_widgets + && SELECTABLE_WIDGET(table->widgets[i])) + { + return start_col - x; + } + } + + // None available + + return -1; +} + +static int TXT_TableKeyPress(txt_widget_t *widget, int key) +{ + txt_table_t *table = (txt_table_t *) widget; + int selected; + int rows; + + rows = TableRows(table); + + // Send to the currently selected widget first + + selected = table->selected_y * table->columns + table->selected_x; + + if (selected >= 0 && selected < table->num_widgets) + { + if (TXT_WidgetKeyPress(table->widgets[selected], key)) + { + return 1; + } + } + + if (key == KEY_DOWNARROW) + { + int new_x, new_y; + + // Move cursor down to the next selectable widget + + for (new_y = table->selected_y + 1; new_y < rows; ++new_y) + { + new_x = FindSelectableColumn(table, new_y, table->selected_x); + + if (new_x >= 0) + { + // Found a selectable widget in this column! + + table->selected_x = new_x; + table->selected_y = new_y; + + return 1; + } + } + } + + if (key == KEY_UPARROW) + { + int new_x, new_y; + + // Move cursor up to the next selectable widget + + for (new_y = table->selected_y - 1; new_y >= 0; --new_y) + { + new_x = FindSelectableColumn(table, new_y, table->selected_x); + + if (new_x >= 0) + { + // Found a selectable widget in this column! + + table->selected_x = new_x; + table->selected_y = new_y; + + return 1; + } + } + } + + if (key == KEY_LEFTARROW) + { + int new_x; + int i; + + // Move cursor left + + for (new_x = table->selected_x - 1; new_x >= 0; --new_x) + { + i = table->selected_y * table->columns + new_x; + + if (i >= 0 && i < table->num_widgets + && SELECTABLE_WIDGET(table->widgets[i])) + { + // Found a selectable widget! + + table->selected_x = new_x; + + return 1; + } + } + } + + if (key == KEY_RIGHTARROW) + { + int new_x; + int i; + + // Move cursor left + + for (new_x = table->selected_x + 1; new_x < table->columns; ++new_x) + { + i = table->selected_y * table->columns + new_x; + + if (i >= 0 && i < table->num_widgets + && SELECTABLE_WIDGET(table->widgets[i])) + { + // Found a selectable widget! + + table->selected_x = new_x; + + return 1; + } + } + } + + return 0; +} + +txt_widget_class_t txt_table_class = +{ + TXT_CalcTableSize, + TXT_TableDrawer, + TXT_TableKeyPress, + TXT_TableDestructor, +}; + +void TXT_InitTable(txt_table_t *table, int columns) +{ + table->columns = columns; + table->widgets = NULL; + table->num_widgets = 0; + table->widget.widget_class = &txt_table_class; + table->widget.visible = 1; + table->widget.selectable = 1; +} + +txt_table_t *TXT_NewTable(int columns) +{ + txt_table_t *table; + + table = malloc(sizeof(txt_table_t)); + + TXT_InitTable(table, columns); + + return table; +} + diff --git a/textscreen/txt_table.h b/textscreen/txt_table.h new file mode 100644 index 00000000..75582878 --- /dev/null +++ b/textscreen/txt_table.h @@ -0,0 +1,58 @@ +// 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_TABLE_H +#define TXT_TABLE_H + +typedef struct txt_table_s txt_table_t; + +#include "txt_widget.h" + +struct txt_table_s +{ + txt_widget_t widget; + + // Widgets in this table + // The widget at (x,y) in the table is widgets[columns * y + x] + + txt_widget_t **widgets; + int num_widgets; + + // Number of columns + + int columns; + + // Currently selected + + int selected_x; + int selected_y; +}; + +txt_table_t *TXT_NewTable(int columns); +void TXT_InitTable(txt_table_t *table, int columns); +void TXT_AddTableWidget(void *table, void *widget); + +#endif /* #ifndef TXT_TABLE_T */ + + diff --git a/textscreen/txt_widget.c b/textscreen/txt_widget.c index de79beb7..c10699b5 100644 --- a/textscreen/txt_widget.c +++ b/textscreen/txt_widget.c @@ -2,9 +2,9 @@ #include "txt_widget.h" -int TXT_WidgetWidth(txt_widget_t *widget) +void TXT_CalcWidgetSize(txt_widget_t *widget, int *w, int *h) { - return widget->widget_class->size_calc(widget); + return widget->widget_class->size_calc(widget, w, h); } void TXT_DrawWidget(txt_widget_t *widget, int w, int selected) diff --git a/textscreen/txt_widget.h b/textscreen/txt_widget.h index 9852f732..d852ccd1 100644 --- a/textscreen/txt_widget.h +++ b/textscreen/txt_widget.h @@ -30,7 +30,7 @@ typedef struct txt_widget_class_s txt_widget_class_t; typedef struct txt_widget_s txt_widget_t; -typedef int (*TxtWidgetSizeCalc)(txt_widget_t *widget); +typedef void (*TxtWidgetSizeCalc)(txt_widget_t *widget, int *w, int *h); typedef void (*TxtWidgetDrawer)(txt_widget_t *widget, int w, int selected); typedef void (*TxtWidgetDestroy)(txt_widget_t *widget); typedef int (*TxtWidgetKeyPress)(txt_widget_t *widget, int key); @@ -50,7 +50,7 @@ struct txt_widget_s int visible; }; -int TXT_WidgetWidth(txt_widget_t *widget); +void TXT_CalcWidgetSize(txt_widget_t *widget, int *w, int *h); void TXT_DrawWidget(txt_widget_t *widget, int w, int selected); int TXT_WidgetKeyPress(txt_widget_t *widget, int key); void TXT_DestroyWidget(txt_widget_t *widget); diff --git a/textscreen/txt_window.c b/textscreen/txt_window.c index 85c6c5d1..fb08162e 100644 --- a/textscreen/txt_window.c +++ b/textscreen/txt_window.c @@ -79,21 +79,21 @@ static void CalcWindowSize(txt_window_t *window, int *w, int *h) int max_width; int height; int i; - int ww; + int ww, wh; max_width = 10; height = 0; for (i=0; inum_widgets; ++i) { - ww = TXT_WidgetWidth(window->widgets[i]); + TXT_CalcWidgetSize(window->widgets[i], &ww, &wh); if (ww > max_width) max_width = ww; if (window->widgets[i]->visible) { - height += 1; + height += wh; } } @@ -139,6 +139,7 @@ void TXT_DrawWindow(txt_window_t *window) int x, y; int window_x, window_y; int i; + int ww, wh; CalcWindowSize(window, &widgets_w, &widgets_h); @@ -163,12 +164,14 @@ void TXT_DrawWindow(txt_window_t *window) for (i=0; inum_widgets; ++i) { - TXT_GotoXY(x, y); - TXT_DrawWidget(window->widgets[i], widgets_w, i == window->selected); - if (window->widgets[i]->visible) { - y += 1; + TXT_GotoXY(x, y); + TXT_DrawWidget(window->widgets[i], + widgets_w, + i == window->selected); + TXT_CalcWidgetSize(window->widgets[i], &ww, &wh); + y += wh; } } -- cgit v1.2.3