Add table class. Allow widgets with heights of more than one line.
Subversion-branch: /trunk/chocolate-doom Subversion-revision: 492
This commit is contained in:
parent
6ecffa76f7
commit
8741ed0339
9 changed files with 481 additions and 18 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
397
textscreen/txt_table.c
Normal file
397
textscreen/txt_table.c
Normal file
|
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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; i<table->num_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; y<rows; ++y)
|
||||
{
|
||||
row_heights[y] = 0;
|
||||
|
||||
for (x=0; x<table->columns; ++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; x<table->columns; ++x)
|
||||
{
|
||||
*w += column_widths[x];
|
||||
}
|
||||
|
||||
*h = 0;
|
||||
|
||||
for (y=0; y<rows; ++y)
|
||||
{
|
||||
*h += row_heights[y];
|
||||
}
|
||||
|
||||
free(row_heights);
|
||||
free(column_widths);
|
||||
}
|
||||
|
||||
static void TXT_TableDrawer(txt_widget_t *widget, int w, int selected)
|
||||
{
|
||||
txt_table_t *table = (txt_table_t *) widget;
|
||||
int *column_widths;
|
||||
int *row_heights;
|
||||
int origin_x, origin_y;
|
||||
int draw_x, draw_y;
|
||||
int x, y;
|
||||
int rows;
|
||||
|
||||
TXT_GetXY(&origin_x, &origin_y);
|
||||
|
||||
// Work out the column widths and row heights
|
||||
|
||||
rows = TableRows(table);
|
||||
|
||||
column_widths = malloc(sizeof(int) * table->columns);
|
||||
row_heights = malloc(sizeof(int) * rows);
|
||||
|
||||
CalcRowColSizes(table, row_heights, column_widths);
|
||||
|
||||
// Draw all cells
|
||||
|
||||
draw_y = origin_y;
|
||||
|
||||
for (y=0; y<rows; ++y)
|
||||
{
|
||||
draw_x = origin_x;
|
||||
|
||||
for (x=0; x<table->columns; ++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; x<table->columns; ++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;
|
||||
}
|
||||
|
||||
58
textscreen/txt_table.h
Normal file
58
textscreen/txt_table.h
Normal file
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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; i<window->num_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; i<window->num_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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue