2014-04-09 15:43:27 +02:00
|
|
|
/*****************************************************************************
|
2020-07-21 15:04:34 +02:00
|
|
|
* Copyright (c) 2014-2020 OpenRCT2 developers
|
2014-04-09 15:43:27 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* For a complete list of all authors, please refer to contributors.md
|
|
|
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
2014-04-09 15:43:27 +02:00
|
|
|
*
|
2018-06-15 14:07:34 +02:00
|
|
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
2014-04-09 15:43:27 +02:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2018-08-12 13:50:40 +02:00
|
|
|
#include <algorithm>
|
2021-10-28 22:38:23 +02:00
|
|
|
#include <bitset>
|
2018-11-21 23:16:04 +01:00
|
|
|
#include <iterator>
|
2018-06-22 23:21:44 +02:00
|
|
|
#include <openrct2-ui/interface/Dropdown.h>
|
|
|
|
#include <openrct2-ui/interface/Widget.h>
|
2017-12-07 22:33:11 +01:00
|
|
|
#include <openrct2/Context.h>
|
|
|
|
#include <openrct2/Input.h>
|
2021-12-12 22:16:17 +01:00
|
|
|
#include <openrct2/core/BitSet.hpp>
|
2018-06-22 23:21:44 +02:00
|
|
|
#include <openrct2/drawing/Drawing.h>
|
2021-12-12 00:06:06 +01:00
|
|
|
#include <openrct2/localisation/Formatter.h>
|
2018-01-06 18:32:25 +01:00
|
|
|
#include <openrct2/localisation/Localisation.h>
|
2017-12-07 22:33:11 +01:00
|
|
|
#include <openrct2/sprites.h>
|
2014-04-09 15:43:27 +02:00
|
|
|
|
2021-12-12 22:16:17 +01:00
|
|
|
using namespace OpenRCT2;
|
|
|
|
|
2017-07-23 07:36:43 +02:00
|
|
|
// The maximum number of rows to list before items overflow into new columns
|
2019-10-24 05:38:13 +02:00
|
|
|
constexpr int32_t DROPDOWN_TEXT_MAX_ROWS = 32;
|
2017-07-23 07:36:43 +02:00
|
|
|
|
2019-10-24 05:38:13 +02:00
|
|
|
constexpr int32_t DROPDOWN_ITEM_HEIGHT = 12;
|
2017-10-19 16:28:16 +02:00
|
|
|
|
2020-03-21 15:22:18 +01:00
|
|
|
static constexpr const uint8_t _appropriateImageDropdownItemsPerRow[34] = {
|
2020-03-06 15:06:28 +01:00
|
|
|
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, 8,
|
2018-07-23 14:10:54 +02:00
|
|
|
};
|
2014-04-18 20:00:27 +02:00
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
enum
|
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
WIDX_BACKGROUND,
|
2014-04-09 15:43:27 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static rct_widget window_dropdown_widgets[] = {
|
2020-11-27 04:14:20 +01:00
|
|
|
MakeWidget({ 0, 0 }, { 1, 1 }, WindowWidgetType::ImgBtn, WindowColour::Primary),
|
2021-09-26 11:11:42 +02:00
|
|
|
WIDGETS_END,
|
2014-04-09 15:43:27 +02:00
|
|
|
};
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
static int32_t _dropdown_num_columns;
|
|
|
|
static int32_t _dropdown_num_rows;
|
|
|
|
static int32_t _dropdown_item_width;
|
|
|
|
static int32_t _dropdown_item_height;
|
2017-08-06 14:41:13 +02:00
|
|
|
static bool _dropdown_list_vertically;
|
2014-04-09 15:43:27 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t gDropdownNumItems;
|
2022-02-12 23:57:22 +01:00
|
|
|
Dropdown::Item gDropdownItems[Dropdown::ItemsMaxSize];
|
2021-12-05 18:14:52 +01:00
|
|
|
static ImageId _dropdownItemsImages[Dropdown::ItemsMaxSize];
|
2015-09-01 08:08:28 +02:00
|
|
|
bool gDropdownIsColour;
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t gDropdownLastColourHover;
|
|
|
|
int32_t gDropdownHighlightedIndex;
|
|
|
|
int32_t gDropdownDefaultIndex;
|
2021-12-05 18:14:52 +01:00
|
|
|
static bool _dropdownPrepareUseImages;
|
|
|
|
static bool _dropdownUseImages;
|
2015-10-14 21:54:02 +02:00
|
|
|
|
2022-02-13 00:08:06 +01:00
|
|
|
static void ResetDropdownFlags()
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < std::size(gDropdownItems); i++)
|
|
|
|
{
|
|
|
|
gDropdownItems[i].Flags = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-03 09:16:06 +01:00
|
|
|
bool Dropdown::IsChecked(int32_t index)
|
2015-10-14 21:54:02 +02:00
|
|
|
{
|
2022-02-13 00:08:06 +01:00
|
|
|
if (index < 0 || index >= static_cast<int32_t>(std::size(gDropdownItems)))
|
2017-08-01 00:56:52 +02:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2022-02-13 00:08:06 +01:00
|
|
|
return gDropdownItems[index].IsChecked();
|
2015-10-14 21:54:02 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 09:16:06 +01:00
|
|
|
bool Dropdown::IsDisabled(int32_t index)
|
2016-01-18 00:37:14 +01:00
|
|
|
{
|
2022-02-13 00:08:06 +01:00
|
|
|
if (index < 0 || index >= static_cast<int32_t>(std::size(gDropdownItems)))
|
2017-08-01 00:56:52 +02:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2022-02-13 00:08:06 +01:00
|
|
|
return gDropdownItems[index].IsDisabled();
|
2016-01-18 00:37:14 +01:00
|
|
|
}
|
|
|
|
|
2020-11-03 09:16:06 +01:00
|
|
|
void Dropdown::SetChecked(int32_t index, bool value)
|
2015-10-14 21:54:02 +02:00
|
|
|
{
|
2022-02-13 00:08:06 +01:00
|
|
|
if (index < 0 || index >= static_cast<int32_t>(std::size(gDropdownItems)))
|
2017-08-01 00:56:52 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2022-02-13 00:08:06 +01:00
|
|
|
if (value)
|
|
|
|
gDropdownItems[index].Flags |= EnumValue(Dropdown::ItemFlag::IsChecked);
|
|
|
|
else
|
|
|
|
gDropdownItems[index].Flags &= ~EnumValue(Dropdown::ItemFlag::IsChecked);
|
2015-10-14 21:54:02 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 09:16:06 +01:00
|
|
|
void Dropdown::SetDisabled(int32_t index, bool value)
|
2015-10-14 21:54:02 +02:00
|
|
|
{
|
2022-02-13 00:08:06 +01:00
|
|
|
if (index < 0 || index >= static_cast<int32_t>(std::size(gDropdownItems)))
|
2017-08-01 00:56:52 +02:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2022-02-13 00:08:06 +01:00
|
|
|
if (value)
|
|
|
|
gDropdownItems[index].Flags |= EnumValue(Dropdown::ItemFlag::IsDisabled);
|
|
|
|
else
|
|
|
|
gDropdownItems[index].Flags &= ~EnumValue(Dropdown::ItemFlag::IsDisabled);
|
2015-10-14 21:54:02 +02:00
|
|
|
}
|
2014-04-09 15:43:27 +02:00
|
|
|
|
2021-12-05 18:14:52 +01:00
|
|
|
void Dropdown::SetImage(int32_t index, ImageId image)
|
|
|
|
{
|
|
|
|
if (index < 0 || index >= static_cast<int32_t>(std::size(_dropdownItemsImages)))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
_dropdownItemsImages[index] = image;
|
|
|
|
_dropdownPrepareUseImages = true;
|
|
|
|
}
|
|
|
|
|
2021-11-23 14:18:07 +01:00
|
|
|
static void WindowDropdownPaint(rct_window* w, rct_drawpixelinfo* dpi);
|
2015-07-10 02:39:16 +02:00
|
|
|
|
2018-05-16 20:41:29 +02:00
|
|
|
// clang-format off
|
2020-09-28 20:36:15 +02:00
|
|
|
static rct_window_event_list window_dropdown_events([](auto& events)
|
|
|
|
{
|
2021-11-23 14:18:07 +01:00
|
|
|
events.paint = &WindowDropdownPaint;
|
2020-09-28 20:36:15 +02:00
|
|
|
});
|
2018-05-16 20:41:29 +02:00
|
|
|
// clang-format on
|
2014-04-09 15:43:27 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
|
|
|
*/
|
2020-11-03 09:16:06 +01:00
|
|
|
void WindowDropdownShowText(const ScreenCoordsXY& screenPos, int32_t extray, uint8_t colour, uint8_t flags, size_t num_items)
|
2014-04-20 04:31:54 +02:00
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t string_width, max_string_width;
|
2017-06-06 23:24:18 +02:00
|
|
|
char buffer[256];
|
|
|
|
|
|
|
|
// Calculate the longest string width
|
|
|
|
max_string_width = 0;
|
2018-06-22 23:21:44 +02:00
|
|
|
for (size_t i = 0; i < num_items; i++)
|
|
|
|
{
|
2022-02-12 23:57:22 +01:00
|
|
|
format_string(buffer, 256, gDropdownItems[i].Format, static_cast<void*>(&gDropdownItems[i].Args));
|
2021-02-27 18:15:44 +01:00
|
|
|
string_width = gfx_get_string_width(buffer, FontSpriteBase::MEDIUM);
|
2018-06-20 17:11:35 +02:00
|
|
|
max_string_width = std::max(string_width, max_string_width);
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 09:16:06 +01:00
|
|
|
WindowDropdownShowTextCustomWidth(screenPos, extray, colour, 0, flags, num_items, max_string_width + 3);
|
2014-04-20 04:31:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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)
|
2017-02-16 19:35:59 +01:00
|
|
|
* @param custom_height (ah) requires flag set as well
|
2014-04-20 04:31:54 +02:00
|
|
|
*/
|
2020-11-03 09:16:06 +01:00
|
|
|
void WindowDropdownShowTextCustomWidth(
|
2020-05-01 20:48:20 +02:00
|
|
|
const ScreenCoordsXY& screenPos, int32_t extray, uint8_t colour, uint8_t custom_height, uint8_t flags, size_t num_items,
|
|
|
|
int32_t width)
|
2014-04-09 15:43:27 +02:00
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
rct_window* w;
|
|
|
|
|
2020-04-19 14:08:22 +02:00
|
|
|
input_set_flag(static_cast<INPUT_FLAGS>(INPUT_FLAG_DROPDOWN_STAY_OPEN | INPUT_FLAG_DROPDOWN_MOUSE_UP), false);
|
2020-11-03 09:16:06 +01:00
|
|
|
if (flags & Dropdown::Flag::StayOpen)
|
2017-06-06 23:24:18 +02:00
|
|
|
input_set_flag(INPUT_FLAG_DROPDOWN_STAY_OPEN, true);
|
|
|
|
|
2020-11-03 09:16:06 +01:00
|
|
|
WindowDropdownClose();
|
2018-06-22 23:21:44 +02:00
|
|
|
|
2017-07-23 07:36:43 +02:00
|
|
|
// Set and calculate num items, rows and columns
|
2017-06-06 23:24:18 +02:00
|
|
|
_dropdown_item_width = width;
|
2020-11-03 09:16:06 +01:00
|
|
|
_dropdown_item_height = (flags & Dropdown::Flag::CustomHeight) ? custom_height : DROPDOWN_ITEM_HEIGHT;
|
2020-04-18 13:32:48 +02:00
|
|
|
gDropdownNumItems = static_cast<int32_t>(num_items);
|
2017-07-25 06:49:11 +02:00
|
|
|
// There must always be at least one column to prevent dividing by zero
|
2017-07-25 10:43:01 +02:00
|
|
|
if (gDropdownNumItems == 0)
|
|
|
|
{
|
2017-07-25 06:49:11 +02:00
|
|
|
_dropdown_num_columns = 1;
|
2021-10-20 18:50:21 +02:00
|
|
|
_dropdown_num_rows = 1;
|
2017-07-25 06:49:11 +02:00
|
|
|
}
|
2017-07-25 10:43:01 +02:00
|
|
|
else
|
|
|
|
{
|
2017-07-25 06:49:11 +02:00
|
|
|
_dropdown_num_columns = (gDropdownNumItems + DROPDOWN_TEXT_MAX_ROWS - 1) / DROPDOWN_TEXT_MAX_ROWS;
|
|
|
|
_dropdown_num_rows = (gDropdownNumItems + _dropdown_num_columns - 1) / _dropdown_num_columns;
|
|
|
|
}
|
2018-06-22 23:21:44 +02:00
|
|
|
|
2017-07-23 07:36:43 +02:00
|
|
|
// Text dropdowns are listed horizontally
|
|
|
|
_dropdown_list_vertically = true;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
|
|
|
width = _dropdown_item_width * _dropdown_num_columns + 3;
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t height = _dropdown_item_height * _dropdown_num_rows + 3;
|
|
|
|
int32_t screenWidth = context_get_width();
|
|
|
|
int32_t screenHeight = context_get_height();
|
2020-05-01 20:48:20 +02:00
|
|
|
auto boundedScreenPos = screenPos;
|
|
|
|
if (screenPos.x + width > screenWidth)
|
|
|
|
boundedScreenPos.x = std::max(0, screenWidth - width);
|
|
|
|
if (screenPos.y + height > screenHeight)
|
|
|
|
boundedScreenPos.y = std::max(0, screenHeight - height);
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2017-07-23 07:36:43 +02:00
|
|
|
window_dropdown_widgets[WIDX_BACKGROUND].right = width;
|
|
|
|
window_dropdown_widgets[WIDX_BACKGROUND].bottom = height;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
|
|
|
// Create the window
|
2020-11-04 05:52:23 +01:00
|
|
|
w = WindowCreate(
|
2020-05-01 20:48:20 +02:00
|
|
|
boundedScreenPos + ScreenCoordsXY{ 0, extray }, window_dropdown_widgets[WIDX_BACKGROUND].right + 1,
|
2019-10-19 13:07:03 +02:00
|
|
|
window_dropdown_widgets[WIDX_BACKGROUND].bottom + 1, &window_dropdown_events, WC_DROPDOWN, WF_STICK_TO_FRONT);
|
2017-06-06 23:24:18 +02:00
|
|
|
w->widgets = window_dropdown_widgets;
|
|
|
|
if (colour & COLOUR_FLAG_TRANSLUCENT)
|
|
|
|
w->flags |= WF_TRANSPARENT;
|
|
|
|
w->colours[0] = colour;
|
|
|
|
|
|
|
|
// Input state
|
|
|
|
gDropdownHighlightedIndex = -1;
|
2022-02-13 00:08:06 +01:00
|
|
|
ResetDropdownFlags();
|
2017-06-06 23:24:18 +02:00
|
|
|
gDropdownIsColour = false;
|
|
|
|
gDropdownDefaultIndex = -1;
|
2020-07-28 00:51:10 +02:00
|
|
|
input_set_state(InputState::DropdownActive);
|
2014-04-09 15:43:27 +02:00
|
|
|
}
|
|
|
|
|
2014-04-18 20:00:27 +02:00
|
|
|
/**
|
2014-04-20 04:31:54 +02:00
|
|
|
* Shows an image dropdown menu.
|
2014-04-18 20:00:27 +02:00
|
|
|
* 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)
|
|
|
|
*/
|
2020-11-03 09:16:06 +01:00
|
|
|
void WindowDropdownShowImage(
|
2018-07-21 13:51:54 +02:00
|
|
|
int32_t x, int32_t y, int32_t extray, uint8_t colour, uint8_t flags, int32_t numItems, int32_t itemWidth,
|
|
|
|
int32_t itemHeight, int32_t numColumns)
|
2014-04-18 20:00:27 +02:00
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t width, height;
|
2017-06-06 23:24:18 +02:00
|
|
|
rct_window* w;
|
|
|
|
|
2020-04-19 14:08:22 +02:00
|
|
|
input_set_flag(static_cast<INPUT_FLAGS>(INPUT_FLAG_DROPDOWN_STAY_OPEN | INPUT_FLAG_DROPDOWN_MOUSE_UP), false);
|
2020-11-03 09:16:06 +01:00
|
|
|
if (flags & Dropdown::Flag::StayOpen)
|
2017-06-06 23:24:18 +02:00
|
|
|
input_set_flag(INPUT_FLAG_DROPDOWN_STAY_OPEN, true);
|
|
|
|
|
|
|
|
// Close existing dropdown
|
2020-11-03 09:16:06 +01:00
|
|
|
WindowDropdownClose();
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2021-12-05 18:14:52 +01:00
|
|
|
if (_dropdownPrepareUseImages)
|
|
|
|
{
|
|
|
|
_dropdownPrepareUseImages = false;
|
|
|
|
_dropdownUseImages = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_dropdownUseImages = false;
|
|
|
|
}
|
|
|
|
|
2017-06-06 23:24:18 +02:00
|
|
|
// Set and calculate num items, rows and columns
|
|
|
|
_dropdown_item_width = itemWidth;
|
|
|
|
_dropdown_item_height = itemHeight;
|
|
|
|
gDropdownNumItems = numItems;
|
2021-10-20 18:50:21 +02:00
|
|
|
// There must always be at least one column and row to prevent dividing by zero
|
2017-07-25 10:43:01 +02:00
|
|
|
if (gDropdownNumItems == 0)
|
|
|
|
{
|
2017-07-25 06:49:11 +02:00
|
|
|
_dropdown_num_columns = 1;
|
2021-10-20 18:50:21 +02:00
|
|
|
_dropdown_num_rows = 1;
|
2017-07-25 06:49:11 +02:00
|
|
|
}
|
2017-07-25 10:43:01 +02:00
|
|
|
else
|
|
|
|
{
|
2021-10-20 18:50:21 +02:00
|
|
|
_dropdown_num_columns = std::max(1, numColumns);
|
2017-07-25 06:49:11 +02:00
|
|
|
_dropdown_num_rows = gDropdownNumItems / _dropdown_num_columns;
|
|
|
|
if (gDropdownNumItems % _dropdown_num_columns != 0)
|
|
|
|
_dropdown_num_rows++;
|
|
|
|
}
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2017-07-23 07:36:43 +02:00
|
|
|
// image dropdowns are listed horizontally
|
|
|
|
_dropdown_list_vertically = false;
|
|
|
|
|
2017-06-06 23:24:18 +02:00
|
|
|
// Calculate position and size
|
|
|
|
width = _dropdown_item_width * _dropdown_num_columns + 3;
|
|
|
|
height = _dropdown_item_height * _dropdown_num_rows + 3;
|
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t screenWidth = context_get_width();
|
|
|
|
int32_t screenHeight = context_get_height();
|
2017-06-06 23:24:18 +02:00
|
|
|
if (x + width > screenWidth)
|
2018-06-20 17:11:35 +02:00
|
|
|
x = std::max(0, screenWidth - width);
|
2017-06-06 23:24:18 +02:00
|
|
|
if (y + height > screenHeight)
|
2018-06-20 17:11:35 +02:00
|
|
|
y = std::max(0, screenHeight - height);
|
2017-06-06 23:24:18 +02:00
|
|
|
window_dropdown_widgets[WIDX_BACKGROUND].right = width;
|
|
|
|
window_dropdown_widgets[WIDX_BACKGROUND].bottom = height;
|
|
|
|
|
|
|
|
// Create the window
|
2020-11-04 05:52:23 +01:00
|
|
|
w = WindowCreate(
|
2019-10-19 13:07:03 +02:00
|
|
|
ScreenCoordsXY(x, y + extray), window_dropdown_widgets[WIDX_BACKGROUND].right + 1,
|
|
|
|
window_dropdown_widgets[WIDX_BACKGROUND].bottom + 1, &window_dropdown_events, WC_DROPDOWN, WF_STICK_TO_FRONT);
|
2017-06-06 23:24:18 +02:00
|
|
|
w->widgets = window_dropdown_widgets;
|
|
|
|
if (colour & COLOUR_FLAG_TRANSLUCENT)
|
|
|
|
w->flags |= WF_TRANSPARENT;
|
|
|
|
w->colours[0] = colour;
|
|
|
|
|
|
|
|
// Input state
|
|
|
|
gDropdownHighlightedIndex = -1;
|
2022-02-13 00:08:06 +01:00
|
|
|
ResetDropdownFlags();
|
2017-06-06 23:24:18 +02:00
|
|
|
gDropdownIsColour = false;
|
|
|
|
gDropdownDefaultIndex = -1;
|
2020-07-28 00:51:10 +02:00
|
|
|
input_set_state(InputState::DropdownActive);
|
2014-04-18 20:00:27 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 09:16:06 +01:00
|
|
|
void WindowDropdownClose()
|
2014-04-09 15:43:27 +02:00
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
window_close_by_class(WC_DROPDOWN);
|
2014-04-09 15:43:27 +02:00
|
|
|
}
|
|
|
|
|
2021-11-23 14:18:07 +01:00
|
|
|
static void WindowDropdownPaint(rct_window* w, rct_drawpixelinfo* dpi)
|
2014-04-09 15:43:27 +02:00
|
|
|
{
|
2020-11-04 05:52:23 +01:00
|
|
|
WindowDrawWidgets(w, dpi);
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t highlightedIndex = gDropdownHighlightedIndex;
|
2018-06-22 23:21:44 +02:00
|
|
|
for (int32_t i = 0; i < gDropdownNumItems; i++)
|
|
|
|
{
|
2021-10-15 01:46:45 +02:00
|
|
|
ScreenCoordsXY cellCoords;
|
2018-06-22 23:21:44 +02:00
|
|
|
if (_dropdown_list_vertically)
|
2021-10-15 01:46:45 +02:00
|
|
|
cellCoords = { i / _dropdown_num_rows, i % _dropdown_num_rows };
|
2018-06-22 23:21:44 +02:00
|
|
|
else
|
2021-10-15 01:46:45 +02:00
|
|
|
cellCoords = { i % _dropdown_num_columns, i / _dropdown_num_columns };
|
|
|
|
|
|
|
|
ScreenCoordsXY screenCoords = w->windowPos
|
|
|
|
+ ScreenCoordsXY{ 2 + (cellCoords.x * _dropdown_item_width), 2 + (cellCoords.y * _dropdown_item_height) };
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2022-02-12 23:57:22 +01:00
|
|
|
if (gDropdownItems[i].IsSeparator())
|
2018-06-22 23:21:44 +02:00
|
|
|
{
|
2021-10-15 01:46:45 +02:00
|
|
|
const ScreenCoordsXY leftTop = screenCoords + ScreenCoordsXY{ 0, (_dropdown_item_height / 2) };
|
|
|
|
const ScreenCoordsXY rightBottom = leftTop + ScreenCoordsXY{ _dropdown_item_width - 1, 0 };
|
|
|
|
const ScreenCoordsXY shadowOffset{ 0, 1 };
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
if (w->colours[0] & COLOUR_FLAG_TRANSLUCENT)
|
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
translucent_window_palette palette = TranslucentWindowPalettes[BASE_COLOUR(w->colours[0])];
|
2021-10-15 01:46:45 +02:00
|
|
|
gfx_filter_rect(dpi, { leftTop, rightBottom }, palette.highlight);
|
|
|
|
gfx_filter_rect(dpi, { leftTop + shadowOffset, rightBottom + shadowOffset }, palette.shadow);
|
2018-06-22 23:21:44 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-10-15 01:46:45 +02:00
|
|
|
gfx_fill_rect(dpi, { leftTop, rightBottom }, ColourMapA[w->colours[0]].mid_dark);
|
|
|
|
gfx_fill_rect(dpi, { leftTop + shadowOffset, rightBottom + shadowOffset }, ColourMapA[w->colours[0]].lightest);
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
2018-06-22 23:21:44 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (i == highlightedIndex)
|
|
|
|
{
|
2021-10-15 01:46:45 +02:00
|
|
|
// Darken the cell's background slightly when highlighted
|
|
|
|
const ScreenCoordsXY rightBottom = screenCoords
|
|
|
|
+ ScreenCoordsXY{ _dropdown_item_width - 1, _dropdown_item_height - 1 };
|
|
|
|
gfx_filter_rect(dpi, { screenCoords, rightBottom }, FilterPaletteID::PaletteDarken3);
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
|
|
|
|
2022-02-12 23:57:22 +01:00
|
|
|
rct_string_id item = gDropdownItems[i].Format;
|
2020-11-03 09:16:06 +01:00
|
|
|
if (item == Dropdown::FormatLandPicker || item == Dropdown::FormatColourPicker)
|
2018-06-22 23:21:44 +02:00
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
// Image item
|
2021-12-05 18:14:52 +01:00
|
|
|
auto image = _dropdownUseImages ? _dropdownItemsImages[i]
|
2022-02-12 23:57:22 +01:00
|
|
|
: ImageId::FromUInt32(static_cast<uint32_t>(gDropdownItems[i].Args));
|
2020-11-03 09:16:06 +01:00
|
|
|
if (item == Dropdown::FormatColourPicker && highlightedIndex == i)
|
2021-12-05 18:14:52 +01:00
|
|
|
image = image.WithIndexOffset(1);
|
|
|
|
gfx_draw_sprite(dpi, image, screenCoords);
|
2018-06-22 23:21:44 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-06-06 23:24:18 +02:00
|
|
|
// Text item
|
2021-10-15 01:46:45 +02:00
|
|
|
if (i < Dropdown::ItemsMaxSize && Dropdown::IsChecked(i))
|
|
|
|
item++;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
|
|
|
// Calculate colour
|
2021-02-28 00:22:24 +01:00
|
|
|
colour_t colour = NOT_TRANSLUCENT(w->colours[0]);
|
2017-06-06 23:24:18 +02:00
|
|
|
if (i == highlightedIndex)
|
|
|
|
colour = COLOUR_WHITE;
|
2021-10-15 01:46:45 +02:00
|
|
|
if (i < Dropdown::ItemsMaxSize && Dropdown::IsDisabled(i))
|
|
|
|
colour = NOT_TRANSLUCENT(w->colours[0]) | COLOUR_FLAG_INSET;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
|
|
|
// Draw item string
|
2022-02-12 23:57:22 +01:00
|
|
|
Formatter ft(reinterpret_cast<uint8_t*>(&gDropdownItems[i].Args));
|
2021-02-28 00:22:24 +01:00
|
|
|
DrawTextEllipsised(dpi, screenCoords, w->width - 5, item, ft, { colour });
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-04-21 11:27:48 +02:00
|
|
|
}
|
2014-09-13 09:29:27 +02:00
|
|
|
|
2015-12-11 16:38:37 +01:00
|
|
|
/**
|
|
|
|
* New function based on 6e914e
|
2014-09-13 09:29:27 +02:00
|
|
|
* returns -1 if index is invalid
|
|
|
|
*/
|
2020-11-03 09:16:06 +01:00
|
|
|
int32_t DropdownIndexFromPoint(const ScreenCoordsXY& loc, rct_window* w)
|
2015-10-14 21:54:02 +02:00
|
|
|
{
|
2020-03-07 22:20:16 +01:00
|
|
|
int32_t top = loc.y - w->windowPos.y - 2;
|
2018-06-22 23:21:44 +02:00
|
|
|
if (top < 0)
|
|
|
|
return -1;
|
2014-09-13 09:29:27 +02:00
|
|
|
|
2020-03-07 22:20:16 +01:00
|
|
|
int32_t left = loc.x - w->windowPos.x;
|
2018-06-22 23:21:44 +02:00
|
|
|
if (left >= w->width)
|
|
|
|
return -1;
|
2017-06-06 23:24:18 +02:00
|
|
|
left -= 2;
|
2018-06-22 23:21:44 +02:00
|
|
|
if (left < 0)
|
|
|
|
return -1;
|
2014-09-13 09:29:27 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t column_no = left / _dropdown_item_width;
|
2018-06-22 23:21:44 +02:00
|
|
|
if (column_no >= _dropdown_num_columns)
|
|
|
|
return -1;
|
2015-10-14 21:54:02 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t row_no = top / _dropdown_item_height;
|
2018-06-22 23:21:44 +02:00
|
|
|
if (row_no >= _dropdown_num_rows)
|
|
|
|
return -1;
|
2014-09-13 09:29:27 +02:00
|
|
|
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t dropdown_index;
|
2017-07-23 07:36:43 +02:00
|
|
|
if (_dropdown_list_vertically)
|
|
|
|
dropdown_index = column_no * _dropdown_num_rows + row_no;
|
|
|
|
else
|
|
|
|
dropdown_index = row_no * _dropdown_num_columns + column_no;
|
|
|
|
|
2018-06-22 23:21:44 +02:00
|
|
|
if (dropdown_index >= gDropdownNumItems)
|
|
|
|
return -1;
|
2014-09-13 09:29:27 +02:00
|
|
|
|
2017-06-06 23:24:18 +02:00
|
|
|
return dropdown_index;
|
2014-09-13 09:29:27 +02:00
|
|
|
}
|
2014-09-14 19:43:36 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* rct2: 0x006ED43D
|
|
|
|
*/
|
2020-11-03 09:16:06 +01:00
|
|
|
void WindowDropdownShowColour(rct_window* w, rct_widget* widget, uint8_t dropdownColour, uint8_t selectedColour)
|
2014-09-14 19:43:36 +02:00
|
|
|
{
|
2018-06-20 17:28:51 +02:00
|
|
|
int32_t defaultIndex = -1;
|
2017-06-06 23:24:18 +02:00
|
|
|
// Set items
|
2018-06-20 17:28:51 +02:00
|
|
|
for (uint64_t i = 0; i < COLOUR_COUNT; i++)
|
2017-06-20 10:40:38 +02:00
|
|
|
{
|
|
|
|
if (selectedColour == i)
|
|
|
|
defaultIndex = i;
|
2017-06-06 23:24:18 +02:00
|
|
|
|
2022-02-12 23:57:22 +01:00
|
|
|
gDropdownItems[i].Format = Dropdown::FormatColourPicker;
|
|
|
|
gDropdownItems[i].Args = (i << 32) | (SPRITE_ID_PALETTE_COLOUR_1(i) | SPR_PALETTE_BTN);
|
2017-06-06 23:24:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Show dropdown
|
2020-11-03 09:16:06 +01:00
|
|
|
WindowDropdownShowImage(
|
2020-06-25 03:44:00 +02:00
|
|
|
w->windowPos.x + widget->left, w->windowPos.y + widget->top, widget->height() + 1, dropdownColour,
|
2020-11-03 09:16:06 +01:00
|
|
|
Dropdown::Flag::StayOpen, COLOUR_COUNT, 12, 12, _appropriateImageDropdownItemsPerRow[COLOUR_COUNT]);
|
2017-06-06 23:24:18 +02:00
|
|
|
|
|
|
|
gDropdownIsColour = true;
|
|
|
|
gDropdownLastColourHover = -1;
|
|
|
|
gDropdownDefaultIndex = defaultIndex;
|
2014-09-14 19:43:36 +02:00
|
|
|
}
|
2020-03-06 15:06:28 +01:00
|
|
|
|
2020-11-03 09:16:06 +01:00
|
|
|
uint32_t DropdownGetAppropriateImageDropdownItemsPerRow(uint32_t numItems)
|
2020-03-06 15:06:28 +01:00
|
|
|
{
|
|
|
|
return numItems < std::size(_appropriateImageDropdownItemsPerRow) ? _appropriateImageDropdownItemsPerRow[numItems] : 8;
|
|
|
|
}
|