475 lines
11 KiB
C
475 lines
11 KiB
C
![]() |
// Emacs style mode select -*- C++ -*-
|
||
|
//-----------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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_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;
|
||
|
|
||
|
// Maintain parent pointer.
|
||
|
|
||
|
if (action != NULL)
|
||
|
{
|
||
|
action->widget.parent = &window->table.widget;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
txt_window_t *TXT_NewWindow(char *title)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
txt_window_t *win;
|
||
|
|
||
|
win = malloc(sizeof(txt_window_t));
|
||
|
|
||
|
TXT_InitTable(&win->table, 1);
|
||
|
|
||
|
if (title == NULL)
|
||
|
{
|
||
|
win->title = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
win->title = strdup(title);
|
||
|
}
|
||
|
|
||
|
win->x = TXT_SCREEN_W / 2;
|
||
|
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));
|
||
|
|
||
|
for (i=0; i<3; ++i)
|
||
|
win->actions[i] = NULL;
|
||
|
|
||
|
TXT_AddDesktopWindow(win);
|
||
|
|
||
|
// Default actions
|
||
|
|
||
|
TXT_SetWindowAction(win, TXT_HORIZ_LEFT, TXT_NewWindowEscapeAction(win));
|
||
|
TXT_SetWindowAction(win, TXT_HORIZ_RIGHT, TXT_NewWindowSelectAction(win));
|
||
|
|
||
|
return win;
|
||
|
}
|
||
|
|
||
|
void TXT_CloseWindow(txt_window_t *window)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
TXT_EmitSignal(window, "closed");
|
||
|
|
||
|
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(window);
|
||
|
|
||
|
TXT_RemoveDesktopWindow(window);
|
||
|
}
|
||
|
|
||
|
static void CalcWindowPosition(txt_window_t *window)
|
||
|
{
|
||
|
switch (window->horiz_align)
|
||
|
{
|
||
|
case TXT_HORIZ_LEFT:
|
||
|
window->window_x = window->x;
|
||
|
break;
|
||
|
case TXT_HORIZ_CENTER:
|
||
|
window->window_x = window->x - (window->window_w / 2);
|
||
|
break;
|
||
|
case TXT_HORIZ_RIGHT:
|
||
|
window->window_x = window->x - (window->window_w - 1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (window->vert_align)
|
||
|
{
|
||
|
case TXT_VERT_TOP:
|
||
|
window->window_y = window->y;
|
||
|
break;
|
||
|
case TXT_VERT_CENTER:
|
||
|
window->window_y = window->y - (window->window_h / 2);
|
||
|
break;
|
||
|
case TXT_VERT_BOTTOM:
|
||
|
window->window_y = window->y - (window->window_h - 1);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void LayoutActionArea(txt_window_t *window)
|
||
|
{
|
||
|
txt_widget_t *widget;
|
||
|
int space_available;
|
||
|
int space_left_offset;
|
||
|
|
||
|
// We need to calculate the available horizontal space for the center
|
||
|
// action widget, so that we can center it within it.
|
||
|
// To start with, we have the entire action area available.
|
||
|
|
||
|
space_available = window->window_w;
|
||
|
space_left_offset = 0;
|
||
|
|
||
|
// Left action
|
||
|
|
||
|
if (window->actions[TXT_HORIZ_LEFT] != NULL)
|
||
|
{
|
||
|
widget = (txt_widget_t *) window->actions[TXT_HORIZ_LEFT];
|
||
|
|
||
|
TXT_CalcWidgetSize(widget);
|
||
|
|
||
|
widget->x = window->window_x + 1;
|
||
|
widget->y = window->window_y + window->window_h - widget->h - 1;
|
||
|
|
||
|
// Adjust available space:
|
||
|
|
||
|
space_available -= widget->w;
|
||
|
space_left_offset += widget->w;
|
||
|
}
|
||
|
|
||
|
// Draw the right action
|
||
|
|
||
|
if (window->actions[TXT_HORIZ_RIGHT] != NULL)
|
||
|
{
|
||
|
widget = (txt_widget_t *) window->actions[TXT_HORIZ_RIGHT];
|
||
|
|
||
|
TXT_CalcWidgetSize(widget);
|
||
|
|
||
|
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:
|
||
|
|
||
|
space_available -= widget->w;
|
||
|
}
|
||
|
|
||
|
// Draw the center action
|
||
|
|
||
|
if (window->actions[TXT_HORIZ_CENTER] != NULL)
|
||
|
{
|
||
|
widget = (txt_widget_t *) window->actions[TXT_HORIZ_CENTER];
|
||
|
|
||
|
TXT_CalcWidgetSize(widget);
|
||
|
|
||
|
// The left and right widgets have left a space sandwiched between
|
||
|
// them. Center this widget within that space.
|
||
|
|
||
|
widget->x = window->window_x
|
||
|
+ space_left_offset
|
||
|
+ (space_available - widget->w) / 2;
|
||
|
widget->y = window->window_y + window->window_h - widget->h - 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void DrawActionArea(txt_window_t *window)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i=0; i<3; ++i)
|
||
|
{
|
||
|
if (window->actions[i] != NULL)
|
||
|
{
|
||
|
TXT_DrawWidget(window->actions[i], 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void CalcActionAreaSize(txt_window_t *window,
|
||
|
unsigned int *w, unsigned int *h)
|
||
|
{
|
||
|
txt_widget_t *widget;
|
||
|
int i;
|
||
|
|
||
|
*w = 0;
|
||
|
*h = 0;
|
||
|
|
||
|
// 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)
|
||
|
{
|
||
|
widget = (txt_widget_t *) window->actions[i];
|
||
|
|
||
|
if (widget != NULL)
|
||
|
{
|
||
|
TXT_CalcWidgetSize(widget);
|
||
|
*w += widget->w;
|
||
|
|
||
|
if (widget->h > *h)
|
||
|
{
|
||
|
*h = widget->h;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Sets size and position of all widgets in a window
|
||
|
|
||
|
void TXT_LayoutWindow(txt_window_t *window)
|
||
|
{
|
||
|
txt_widget_t *widgets = (txt_widget_t *) window;
|
||
|
unsigned int widgets_w;
|
||
|
unsigned int actionarea_w, actionarea_h;
|
||
|
|
||
|
// Calculate size of table
|
||
|
|
||
|
TXT_CalcWidgetSize(window);
|
||
|
|
||
|
// Widgets area: add one character of padding on each side
|
||
|
widgets_w = widgets->w + 2;
|
||
|
|
||
|
// Calculate the size of the action area
|
||
|
// Make window wide enough to action area
|
||
|
|
||
|
CalcActionAreaSize(window, &actionarea_w, &actionarea_h);
|
||
|
|
||
|
if (actionarea_w > widgets_w)
|
||
|
widgets_w = actionarea_w;
|
||
|
|
||
|
// Set the window size based on widgets_w
|
||
|
|
||
|
window->window_w = widgets_w + 2;
|
||
|
window->window_h = widgets->h + 1;
|
||
|
|
||
|
// If the window has a title, add an extra two lines
|
||
|
|
||
|
if (window->title != NULL)
|
||
|
{
|
||
|
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.
|
||
|
|
||
|
CalcWindowPosition(window);
|
||
|
|
||
|
// Set the table size and position
|
||
|
|
||
|
widgets->w = widgets_w - 2;
|
||
|
// widgets->h (already set)
|
||
|
widgets->x = window->window_x + 2;
|
||
|
widgets->y = window->window_y;
|
||
|
|
||
|
if (window->title != NULL)
|
||
|
{
|
||
|
widgets->y += 2;
|
||
|
}
|
||
|
|
||
|
// Layout the table and action area
|
||
|
|
||
|
LayoutActionArea(window);
|
||
|
TXT_LayoutWidget(widgets);
|
||
|
}
|
||
|
|
||
|
void TXT_DrawWindow(txt_window_t *window, int selected)
|
||
|
{
|
||
|
txt_widget_t *widgets;
|
||
|
|
||
|
TXT_LayoutWindow(window);
|
||
|
|
||
|
// Draw the window
|
||
|
|
||
|
TXT_DrawWindowFrame(window->title,
|
||
|
window->window_x, window->window_y,
|
||
|
window->window_w, window->window_h);
|
||
|
|
||
|
// Draw all widgets
|
||
|
|
||
|
TXT_DrawWidget(window, selected);
|
||
|
|
||
|
// 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);
|
||
|
|
||
|
// Action area at the window bottom
|
||
|
|
||
|
DrawActionArea(window);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TXT_SetWindowPosition(txt_window_t *window,
|
||
|
txt_horiz_align_t horiz_align,
|
||
|
txt_vert_align_t vert_align,
|
||
|
int x, int y)
|
||
|
{
|
||
|
window->vert_align = vert_align;
|
||
|
window->horiz_align = horiz_align;
|
||
|
window->x = x;
|
||
|
window->y = y;
|
||
|
}
|
||
|
|
||
|
static void MouseButtonPress(txt_window_t *window, int b)
|
||
|
{
|
||
|
int x, y;
|
||
|
int i;
|
||
|
txt_widget_t *widgets;
|
||
|
txt_widget_t *widget;
|
||
|
|
||
|
// Lay out the window, set positions and sizes of all widgets
|
||
|
|
||
|
TXT_LayoutWindow(window);
|
||
|
|
||
|
// Get the current mouse position
|
||
|
|
||
|
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;
|
||
|
|
||
|
if (x >= widgets->x && x < (signed) (widgets->x + widgets->w)
|
||
|
&& y >= widgets->y && y < (signed) (widgets->y + widgets->h))
|
||
|
{
|
||
|
TXT_WidgetMousePress(window, x, y, b);
|
||
|
}
|
||
|
|
||
|
// Was one of the action area buttons pressed?
|
||
|
|
||
|
for (i=0; i<3; ++i)
|
||
|
{
|
||
|
widget = (txt_widget_t *) window->actions[i];
|
||
|
|
||
|
if (widget != NULL
|
||
|
&& x >= widget->x && x < (signed) (widget->x + widget->w)
|
||
|
&& y >= widget->y && y < (signed) (widget->y + widget->h))
|
||
|
{
|
||
|
TXT_WidgetMousePress(widget, x, y, b);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void TXT_WindowKeyPress(txt_window_t *window, int c)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
// Is this a mouse button ?
|
||
|
|
||
|
if (c >= TXT_MOUSE_BASE && c < TXT_MOUSE_BASE + TXT_MAX_MOUSE_BUTTONS)
|
||
|
{
|
||
|
MouseButtonPress(window, c);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
// Try all of the action buttons
|
||
|
|
||
|
for (i=0; i<3; ++i)
|
||
|
{
|
||
|
if (window->actions[i] != NULL
|
||
|
&& TXT_WidgetKeyPress(window->actions[i], c))
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
|