1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-17 20:13:07 +01:00
Files
OpenRCT2/src/windows/dropdown.c
Duncan Frost e04165eef4 Refactoring and bug fixing.
Noticed a bug that was causing path bits to fail to be changed.
Reduced compile warnings by using ints for coordinates.
Rearanged colour picker to stop bug that prevents its use when first clicked.
2015-04-23 20:40:53 +01:00

439 lines
13 KiB
C

/*****************************************************************************
* Copyright (c) 2014 Ted John
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* This file is part of OpenRCT2.
*
* OpenRCT2 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 3 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, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "../addresses.h"
#include "../input.h"
#include "../interface/widget.h"
#include "../interface/window.h"
#include "../localisation/localisation.h"
#include "../scenario.h"
#include "../sprites.h"
#include "dropdown.h"
int gAppropriateImageDropdownItemsPerRow[] = {
1, 1, 1, 1, 2, 2, 3, 3, 4,
3, 5, 4, 4, 5, 5, 5, 4, 5,
6, 5, 5, 7, 4, 5, 6, 5, 6,
6, 6, 6, 6, 8, 8, 0
};
enum {
WIDX_BACKGROUND,
};
static rct_widget window_dropdown_widgets[] = {
{ WWT_IMGBTN, 0, 0, 0, 0, 0, -1, STR_NONE },
{ WIDGETS_END },
};
int _dropdown_num_columns;
int _dropdown_num_rows;
int _dropdown_item_width;
int _dropdown_item_height;
int _dropdown_highlighted_index;
int gDropdownNumItems;
uint16 gDropdownItemsFormat[64];
sint64 gDropdownItemsArgs[64];
// Replaces 0x009DED38
uint32 gDropdownItemsChecked;
static void window_dropdown_emptysub() { }
static void window_dropdown_paint();
static void* window_dropdown_events[] = {
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_emptysub,
window_dropdown_paint,
window_dropdown_emptysub
};
/**
* Shows a text dropdown menu.
* rct2: 0x006ECFB9
*
* @param x (cx)
* @param y (dx)
* @param extray (di)
* @param flags (bh)
* @param num_items (bx)
* @param colour (al)
*/
void window_dropdown_show_text(int x, int y, int extray, uint8 colour, uint8 flags, int num_items)
{
int i, string_width, max_string_width;
char buffer[256];
// Calculate the longest string width
max_string_width = 0;
for (i = 0; i < num_items; i++) {
format_string(buffer, gDropdownItemsFormat[i], (void*)(&gDropdownItemsArgs[i]));
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, sint16) = 224;
string_width = gfx_get_string_width(buffer);
max_string_width = max(string_width, max_string_width);
}
window_dropdown_show_text_custom_width(x, y, extray, colour, flags, num_items, max_string_width + 3);
}
/**
* Shows a text dropdown menu.
* rct2: 0x006ECFB9, although 0x006ECE50 is real version
*
* @param x (cx)
* @param y (dx)
* @param extray (di)
* @param flags (bh)
* @param num_items (bx)
* @param colour (al)
*/
void window_dropdown_show_text_custom_width(int x, int y, int extray, uint8 colour, uint8 flags, int num_items, int width)
{
rct_window* w;
// Copy the formats and arguments until all use of it is decompiled
memcpy((void*)0x009DEBA4, gDropdownItemsFormat, 40 * 2);
memcpy((void*)0x009DEBF4, gDropdownItemsArgs, 40 * 8);
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(INPUT_FLAG_1 | INPUT_FLAG_2);
if (flags & 0x80)
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_1;
window_dropdown_close();
_dropdown_num_columns = 1;
_dropdown_item_width = width;
_dropdown_item_height = 10;
if (flags & 0x40)
_dropdown_item_height = flags & 0x3F;
// Set the widgets
gDropdownNumItems = num_items;
_dropdown_num_rows = num_items;
width = _dropdown_item_width * _dropdown_num_columns + 3;
int height = _dropdown_item_height * _dropdown_num_rows + 3;
if (x + width > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16))
x = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - width);
if (y + height > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16))
y = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - height);
window_dropdown_widgets[WIDX_BACKGROUND].bottom = _dropdown_item_height * num_items + 3;
window_dropdown_widgets[WIDX_BACKGROUND].right = _dropdown_item_width + 3;
// Create the window
w = window_create(
x, y + extray,
window_dropdown_widgets[WIDX_BACKGROUND].right + 1,
window_dropdown_widgets[WIDX_BACKGROUND].bottom + 1,
(uint32*)window_dropdown_events,
WC_DROPDOWN,
0x02
);
w->widgets = window_dropdown_widgets;
if (colour & 0x80)
w->flags |= WF_TRANSPARENT;
w->colours[0] = colour;
// Input state
_dropdown_highlighted_index = -1;
RCT2_GLOBAL(0x009DED34, sint32) = 0;
gDropdownItemsChecked = 0;
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_DROPDOWN_ACTIVE;
// Copy the following properties until all use of it is decompiled
RCT2_GLOBAL(0x009DEBA0, sint16) = gDropdownNumItems;
RCT2_GLOBAL(0x009DED44, sint32) = _dropdown_num_columns;
RCT2_GLOBAL(0x009DED48, sint32) = _dropdown_num_rows;
RCT2_GLOBAL(0x009DED40, sint32) = _dropdown_item_width;
RCT2_GLOBAL(0x009DED3C, sint32) = _dropdown_item_height;
RCT2_GLOBAL(0x009DEBA2, sint16) = _dropdown_highlighted_index;
}
/**
* Shows an image dropdown menu.
* rct2: 0x006ECFB9
*
* @param x (cx)
* @param y (dx)
* @param extray (di)
* @param flags (bh)
* @param numItems (bx)
* @param colour (al)
* @param itemWidth (bp)
* @param itemHeight (ah)
* @param numColumns (bl)
*/
void window_dropdown_show_image(int x, int y, int extray, uint8 colour, uint8 flags, int numItems, int itemWidth, int itemHeight, int numColumns)
{
int width, height;
rct_window* w;
// Copy the formats and arguments until all use of it is decompiled
memcpy((void*)0x009DEBA4, gDropdownItemsFormat, 40 * 2);
memcpy((void*)0x009DEBF4, gDropdownItemsArgs, 40 * 8);
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~(INPUT_FLAG_1 | INPUT_FLAG_2);
if (flags & 0x80)
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) |= INPUT_FLAG_1;
// Close existing dropdown
window_dropdown_close();
// Set and calculate num items, rows and columns
_dropdown_item_width = itemWidth;
_dropdown_item_height = itemHeight;
gDropdownNumItems = numItems;
_dropdown_num_columns = numColumns;
_dropdown_num_rows = gDropdownNumItems / _dropdown_num_columns;
if (gDropdownNumItems % _dropdown_num_columns != 0)
_dropdown_num_rows++;
// Calculate position and size
width = _dropdown_item_width * _dropdown_num_columns + 3;
height = _dropdown_item_height * _dropdown_num_rows + 3;
if (x + width > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16))
x = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_WIDTH, sint16) - width);
if (y + height > RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16))
y = max(0, RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_HEIGHT, sint16) - height);
window_dropdown_widgets[WIDX_BACKGROUND].right = width;
window_dropdown_widgets[WIDX_BACKGROUND].bottom = height;
// Create the window
w = window_create(
x, y + extray,
window_dropdown_widgets[WIDX_BACKGROUND].right + 1,
window_dropdown_widgets[WIDX_BACKGROUND].bottom + 1,
(uint32*)window_dropdown_events,
WC_DROPDOWN,
WF_STICK_TO_FRONT
);
w->widgets = window_dropdown_widgets;
if (colour & 0x80)
w->flags |= WF_TRANSPARENT;
w->colours[0] = colour;
// Input state
_dropdown_highlighted_index = -1;
RCT2_GLOBAL(0x009DED34, sint32) = 0;
gDropdownItemsChecked = 0;
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, sint8) = INPUT_STATE_DROPDOWN_ACTIVE;
// Copy the following properties until all use of it is decompiled
RCT2_GLOBAL(0x009DEBA0, sint16) = gDropdownNumItems;
RCT2_GLOBAL(0x009DED44, sint32) = _dropdown_num_columns;
RCT2_GLOBAL(0x009DED48, sint32) = _dropdown_num_rows;
RCT2_GLOBAL(0x009DED40, sint32) = _dropdown_item_width;
RCT2_GLOBAL(0x009DED3C, sint32) = _dropdown_item_height;
RCT2_GLOBAL(0x009DEBA2, sint16) = _dropdown_highlighted_index;
}
void window_dropdown_close()
{
window_close_by_class(WC_DROPDOWN);
}
static void window_dropdown_paint()
{
rct_window *w;
rct_drawpixelinfo *dpi;
window_paint_get_registers(w, dpi);
window_draw_widgets(w, dpi);
_dropdown_highlighted_index = RCT2_GLOBAL(0x009DEBA2, sint16);
{
int i, cell_x, cell_y, l, t, r, b, item, image, colour;
for (i = 0; i < gDropdownNumItems; i++) {
cell_x = i % _dropdown_num_columns;
cell_y = i / _dropdown_num_columns;
if (gDropdownItemsFormat[i] == DROPDOWN_SEPARATOR) {
l = w->x + 2 + (cell_x * _dropdown_item_width);
t = w->y + 2 + (cell_y * _dropdown_item_height);
r = l + _dropdown_item_width - 1;
t += (_dropdown_item_height / 2);
b = t;
if (w->colours[0] & 0x80) {
gfx_fill_rect(dpi, l, t, r, b, (RCT2_ADDRESS(0x009DEDF4, uint8)[w->colours[0]] | 0x02000000) + 1);
gfx_fill_rect(dpi, l, t + 1, r, b + 1, (RCT2_ADDRESS(0x009DEDF4, uint8)[w->colours[0]] | 0x02000000) + 2);
} else {
gfx_fill_rect(dpi, l, t, r, b,
*((char*)(0x00141FC47 + (w->colours[0] * 8))));
gfx_fill_rect(dpi, l, t + 1, r, b + 1,
*((char*)(0x00141FC4B + (w->colours[0] * 8))));
}
} else {
//
if (i == _dropdown_highlighted_index) {
l = w->x + 2 + (cell_x * _dropdown_item_width);
t = w->y + 2 + (cell_y * _dropdown_item_height);
r = l + _dropdown_item_width - 1;
b = t + _dropdown_item_height - 1;
gfx_fill_rect(dpi, l, t, r, b, 0x2000000 | 0x2F);
}
item = gDropdownItemsFormat[i];
if (item == (uint16)-1 || item == (uint16)-2) {
// Image item
image = *((uint32*)&gDropdownItemsArgs[i]);
if (item == (uint16)-2 && _dropdown_highlighted_index == i)
image++;
gfx_draw_sprite(
dpi,
image,
w->x + 2 + (cell_x * _dropdown_item_width),
w->y + 2 + (cell_y * _dropdown_item_height), 0
);
} else {
// Text item
if (i < 32)
if (gDropdownItemsChecked & (1 << i))
item++;
// Calculate colour
colour = w->colours[0] & 0x7F;
if (i == _dropdown_highlighted_index)
colour = 2;
if (RCT2_GLOBAL(0x009DED34, uint32) & (1 << i))
if (i < 32)
colour = (w->colours[0] & 0x7F) | 0x40;
// Draw item string
gfx_draw_string_left_clipped(
dpi,
item,
(void*)(&gDropdownItemsArgs[i]), colour,
w->x + 2 + (cell_x * _dropdown_item_width),
w->y + 1 + (cell_y * _dropdown_item_height),
w->width - 5
);
}
}
}
}
}
/* New function based on 6e914e
* returns -1 if index is invalid
*/
int dropdown_index_from_point(int x, int y, rct_window* w){
int top = y - w->y - 2;
if (top < 0) return -1;
int left = x - w->x;
if (left >= w->width) return -1;
left -= 2;
if (left < 0) return -1;
// _dropdown_item_width
int column_no = left / RCT2_GLOBAL(0x009DED40, sint32);
// _dropdown_no_columns
if (column_no >= RCT2_GLOBAL(0x009DED44, sint32)) return -1;
// _dropdown_item_height
int row_no = top / RCT2_GLOBAL(0x9DED3C, uint8);
// _dropdown_no_rows
if (row_no >= RCT2_GLOBAL(0x009DED48, sint32)) return -1;
// _dropdown_no_columns
int dropdown_index = row_no * RCT2_GLOBAL(0x009DED44, sint32) + column_no;
// _dropdown_no_items
if (dropdown_index >= RCT2_GLOBAL(0x009DEBA0, sint16)) return -1;
return dropdown_index;
}
void window_dropdown_show_colour(rct_window *w, rct_widget *widget, uint8 dropdownColour, uint8 selectedColour)
{
window_dropdown_show_colour_available(w, widget, dropdownColour, selectedColour, 0xFFFFFFFF);
}
/**
* rct2: 0x006ED43D
* al: dropdown colour
* ah: selected colour
* esi: window
* edi: widget
* ebp: unknown
*/
void window_dropdown_show_colour_available(rct_window *w, rct_widget *widget, uint8 dropdownColour, uint8 selectedColour,
uint32 availableColours)
{
int i, numItems;
// Count number of available colours
numItems = 0;
for (i = 0; i < 32; i++)
if (availableColours & (1 << i))
numItems++;
// Set items
for (i = 0; i < 32; i++) {
if (availableColours & (1 << i)) {
if (selectedColour == i)
RCT2_GLOBAL(0x009DEBA2, sint16) = i;
gDropdownItemsFormat[i] = 0xFFFE;
gDropdownItemsArgs[i] = ((uint64)i << 32) | (0x20000000 | (i << 19) | 5059);
}
}
// Show dropdown
window_dropdown_show_image(
w->x + widget->left,
w->y + widget->top,
widget->bottom - widget->top + 1,
dropdownColour,
0x80,
numItems,
12,
12,
gAppropriateImageDropdownItemsPerRow[numItems]
);
}