This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
chocolate-doom-wii/textscreen/txt_dropdown.c

305 lines
6.9 KiB
C
Raw Permalink Normal View History

//
// 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;
}