305 lines
6.9 KiB
C
305 lines
6.9 KiB
C
//
|
|
// Copyright(C) 2005-2014 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.
|
|
//
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "doomkeys.h"
|
|
|
|
#include "txt_button.h"
|
|
#include "txt_dropdown.h"
|
|
#include "txt_gui.h"
|
|
#include "txt_io.h"
|
|
#include "txt_main.h"
|
|
#include "txt_window.h"
|
|
|
|
typedef struct
|
|
{
|
|
txt_window_t *window;
|
|
txt_dropdown_list_t *list;
|
|
int item;
|
|
} callback_data_t;
|
|
|
|
// Check if the selected value for a list is valid
|
|
|
|
static int ValidSelection(txt_dropdown_list_t *list)
|
|
{
|
|
return *list->variable >= 0 && *list->variable < list->num_values;
|
|
}
|
|
|
|
// Calculate the Y position for the selector window
|
|
|
|
static int SelectorWindowY(txt_dropdown_list_t *list)
|
|
{
|
|
int result;
|
|
|
|
if (ValidSelection(list))
|
|
{
|
|
result = list->widget.y - 1 - *list->variable;
|
|
}
|
|
else
|
|
{
|
|
result = list->widget.y - 1 - (list->num_values / 2);
|
|
}
|
|
|
|
// Keep dropdown inside the screen.
|
|
|
|
if (result < 1)
|
|
{
|
|
result = 1;
|
|
}
|
|
else if (result + list->num_values > (TXT_SCREEN_H - 3))
|
|
{
|
|
result = TXT_SCREEN_H - list->num_values - 3;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Called when a button in the selector window is pressed
|
|
|
|
static void ItemSelected(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(callback_data))
|
|
{
|
|
TXT_CAST_ARG(callback_data_t, callback_data);
|
|
|
|
// Set the variable
|
|
|
|
*callback_data->list->variable = callback_data->item;
|
|
|
|
TXT_EmitSignal(callback_data->list, "changed");
|
|
|
|
// Close the window
|
|
|
|
TXT_CloseWindow(callback_data->window);
|
|
}
|
|
|
|
// Free callback data when the window is closed
|
|
|
|
static void FreeCallbackData(TXT_UNCAST_ARG(list),
|
|
TXT_UNCAST_ARG(callback_data))
|
|
{
|
|
TXT_CAST_ARG(callback_data_t, callback_data);
|
|
|
|
free(callback_data);
|
|
}
|
|
|
|
// Catch presses of escape and close the window.
|
|
|
|
static int SelectorWindowListener(txt_window_t *window, int key, void *user_data)
|
|
{
|
|
if (key == KEY_ESCAPE)
|
|
{
|
|
TXT_CloseWindow(window);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int SelectorMouseListener(txt_window_t *window, int x, int y, int b,
|
|
void *unused)
|
|
{
|
|
txt_widget_t *win;
|
|
|
|
win = (txt_widget_t *) window;
|
|
|
|
if (x < win->x || x > win->x + win->w || y < win->y || y > win->y + win->h)
|
|
{
|
|
TXT_CloseWindow(window);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Open the dropdown list window to select an item
|
|
|
|
static void OpenSelectorWindow(txt_dropdown_list_t *list)
|
|
{
|
|
txt_window_t *window;
|
|
int i;
|
|
|
|
// Open a simple window with no title bar or action buttons.
|
|
|
|
window = TXT_NewWindow(NULL);
|
|
|
|
TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
|
|
TXT_SetWindowAction(window, TXT_HORIZ_CENTER, NULL);
|
|
TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
|
|
|
|
// Position the window so that the currently selected item appears
|
|
// over the top of the list widget.
|
|
|
|
TXT_SetWindowPosition(window, TXT_HORIZ_LEFT, TXT_VERT_TOP,
|
|
list->widget.x - 2, SelectorWindowY(list));
|
|
|
|
// Add a button to the window for each option in the list.
|
|
|
|
for (i=0; i<list->num_values; ++i)
|
|
{
|
|
txt_button_t *button;
|
|
callback_data_t *data;
|
|
|
|
button = TXT_NewButton(list->values[i]);
|
|
|
|
TXT_AddWidget(window, button);
|
|
|
|
// Callback struct
|
|
|
|
data = malloc(sizeof(callback_data_t));
|
|
data->list = list;
|
|
data->window = window;
|
|
data->item = i;
|
|
|
|
// When the button is pressed, invoke the button press callback
|
|
|
|
TXT_SignalConnect(button, "pressed", ItemSelected, data);
|
|
|
|
// When the window is closed, free back the callback struct
|
|
|
|
TXT_SignalConnect(window, "closed", FreeCallbackData, data);
|
|
|
|
// Is this the currently-selected value? If so, select the button
|
|
// in the window as the default.
|
|
|
|
if (i == *list->variable)
|
|
{
|
|
TXT_SelectWidget(window, button);
|
|
}
|
|
}
|
|
|
|
// Catch presses of escape in this window and close it.
|
|
|
|
TXT_SetKeyListener(window, SelectorWindowListener, NULL);
|
|
TXT_SetMouseListener(window, SelectorMouseListener, NULL);
|
|
}
|
|
|
|
static int DropdownListWidth(txt_dropdown_list_t *list)
|
|
{
|
|
int i;
|
|
int result;
|
|
|
|
// Find the maximum string width
|
|
|
|
result = 0;
|
|
|
|
for (i=0; i<list->num_values; ++i)
|
|
{
|
|
int w = strlen(list->values[i]);
|
|
if (w > result)
|
|
{
|
|
result = w;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void TXT_DropdownListSizeCalc(TXT_UNCAST_ARG(list))
|
|
{
|
|
TXT_CAST_ARG(txt_dropdown_list_t, list);
|
|
|
|
list->widget.w = DropdownListWidth(list);
|
|
list->widget.h = 1;
|
|
}
|
|
|
|
static void TXT_DropdownListDrawer(TXT_UNCAST_ARG(list))
|
|
{
|
|
TXT_CAST_ARG(txt_dropdown_list_t, list);
|
|
unsigned int i;
|
|
const char *str;
|
|
|
|
// Set bg/fg text colors.
|
|
|
|
TXT_SetWidgetBG(list);
|
|
|
|
// Select a string to draw from the list, if the current value is
|
|
// in range. Otherwise fall back to a default.
|
|
|
|
if (ValidSelection(list))
|
|
{
|
|
str = list->values[*list->variable];
|
|
}
|
|
else
|
|
{
|
|
str = "???";
|
|
}
|
|
|
|
// Draw the string and fill to the end with spaces
|
|
|
|
TXT_DrawString(str);
|
|
|
|
for (i=strlen(str); i<list->widget.w; ++i)
|
|
{
|
|
TXT_DrawString(" ");
|
|
}
|
|
}
|
|
|
|
static void TXT_DropdownListDestructor(TXT_UNCAST_ARG(list))
|
|
{
|
|
}
|
|
|
|
static int TXT_DropdownListKeyPress(TXT_UNCAST_ARG(list), int key)
|
|
{
|
|
TXT_CAST_ARG(txt_dropdown_list_t, list);
|
|
|
|
if (key == KEY_ENTER)
|
|
{
|
|
OpenSelectorWindow(list);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void TXT_DropdownListMousePress(TXT_UNCAST_ARG(list),
|
|
int x, int y, int b)
|
|
{
|
|
TXT_CAST_ARG(txt_dropdown_list_t, list);
|
|
|
|
// Left mouse click does the same as selecting and pressing enter
|
|
|
|
if (b == TXT_MOUSE_LEFT)
|
|
{
|
|
TXT_DropdownListKeyPress(list, KEY_ENTER);
|
|
}
|
|
}
|
|
|
|
txt_widget_class_t txt_dropdown_list_class =
|
|
{
|
|
TXT_AlwaysSelectable,
|
|
TXT_DropdownListSizeCalc,
|
|
TXT_DropdownListDrawer,
|
|
TXT_DropdownListKeyPress,
|
|
TXT_DropdownListDestructor,
|
|
TXT_DropdownListMousePress,
|
|
NULL,
|
|
};
|
|
|
|
txt_dropdown_list_t *TXT_NewDropdownList(int *variable, char **values,
|
|
int num_values)
|
|
{
|
|
txt_dropdown_list_t *list;
|
|
|
|
list = malloc(sizeof(txt_dropdown_list_t));
|
|
|
|
TXT_InitWidget(list, &txt_dropdown_list_class);
|
|
list->variable = variable;
|
|
list->values = values;
|
|
list->num_values = num_values;
|
|
|
|
return list;
|
|
}
|
|
|