1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-29 09:44:52 +01:00
Files
OpenRCT2/src/openrct2-ui/interface/Widget.h
2025-06-10 23:21:15 +02:00

273 lines
10 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2025 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#pragma once
#include "Window.h"
#include <openrct2-ui/UiStringIds.h>
#include <openrct2/drawing/Drawing.h>
#include <openrct2/interface/Widget.h>
namespace OpenRCT2::Ui
{
ImageId getColourButtonImage(colour_t colour);
Widget* getWidgetByIndex(WindowBase& w, WidgetIndex widgetIndex);
constexpr uint32_t kWidgetContentEmpty = 0xFFFFFFFF;
constexpr auto kBarBlink = (1u << 31);
constexpr uint8_t kScrollBarWidth = 10;
constexpr ScreenSize kTabSize = { 31, 27 };
constexpr const char* kBlackUpArrowString = u8"{BLACK}▲";
constexpr const char* kBlackDownArrowString = u8"{BLACK}▼";
constexpr const char* kBlackLeftArrowString = u8"{BLACK}◀";
constexpr const char* kBlackRightArrowString = u8"{BLACK}▶";
constexpr const char* kCheckMarkString = u8"";
constexpr const char* kEyeString = u8"👁";
enum class WindowColour : uint8_t
{
primary,
secondary,
tertiary,
quaternary,
};
constexpr Widget makeWidget(
const ScreenCoordsXY& origin, const ScreenSize& size, WidgetType type, WindowColour colour,
uint32_t content = kWidgetContentEmpty, StringId tooltip = kStringIdNone)
{
Widget out = {};
out.left = origin.x;
out.right = origin.x + size.width - 1;
out.top = origin.y;
out.bottom = origin.y + size.height - 1;
out.type = type;
out.colour = static_cast<uint8_t>(colour);
out.content = content;
out.tooltip = tooltip;
return out;
}
constexpr Widget makeWidget(
const ScreenCoordsXY& origin, const ScreenSize& size, WidgetType type, WindowColour colour, ImageId image,
StringId tooltip = kStringIdNone)
{
Widget out = {};
out.left = origin.x;
out.right = origin.x + size.width - 1;
out.top = origin.y;
out.bottom = origin.y + size.height - 1;
out.type = type;
out.colour = static_cast<uint8_t>(colour);
out.image = image;
out.tooltip = tooltip;
return out;
}
constexpr Widget makeRemapWidget(
const ScreenCoordsXY& origin, const ScreenSize& size, WidgetType type, WindowColour colour, ImageIndex content,
StringId tooltip = kStringIdNone)
{
return makeWidget(origin, size, type, colour, ImageId(content, FilterPaletteID::PaletteNull), tooltip);
}
constexpr Widget makeTab(const ScreenCoordsXY& origin, StringId tooltip = kStringIdNone)
{
const ScreenSize size = kTabSize;
const WidgetType type = WidgetType::tab;
const WindowColour colour = WindowColour::secondary;
const auto content = ImageId(kImageIndexUndefined);
return makeWidget(origin, size, type, colour, content, tooltip);
}
constexpr Widget makeProgressBar(
const ScreenCoordsXY& origin, const ScreenSize& size, colour_t colour, uint8_t lowerBlinkBound = 0,
uint8_t upperBlinkBound = 0)
{
Widget out = {};
out.left = origin.x;
out.right = origin.x + size.width - 1;
out.top = origin.y;
out.bottom = origin.y + size.height - 1;
out.type = WidgetType::progressBar;
out.colour = colour;
out.content = 0 | (lowerBlinkBound << 8) | (upperBlinkBound << 16);
out.tooltip = kStringIdNone;
return out;
}
namespace Detail
{
template<typename T, typename Enable = void>
struct WidgetsCount
{
static constexpr size_t count = 0;
};
template<typename T>
struct WidgetsCount<T, std::enable_if_t<std::is_base_of_v<Widget, T>>>
{
static constexpr size_t count = 1;
};
template<typename T, std::size_t N>
struct WidgetsCount<std::array<T, N>, std::enable_if_t<std::is_base_of_v<Widget, T>>>
{
static constexpr size_t count = N;
};
template<typename T>
struct IsWidgetsArray : std::false_type
{
};
template<std::size_t N>
struct IsWidgetsArray<std::array<Widget, N>> : std::true_type
{
};
} // namespace Detail
template<typename... TArgs>
constexpr auto makeWidgets(TArgs&&... args)
{
constexpr auto totalCount = [&]() {
size_t count = 0;
((count += Detail::WidgetsCount<std::decay_t<decltype(args)>>::count), ...);
return count;
}();
std::array<Widget, totalCount> res{};
size_t index = 0;
const auto append = [&](auto&& val) {
if constexpr (Detail::IsWidgetsArray<std::decay_t<decltype(val)>>::value)
{
for (auto&& widget : val)
{
res[index] = std::move(widget);
index++;
}
}
else
{
res[index] = std::move(val);
index++;
}
};
((append(args)), ...);
return res;
}
constexpr std::array<Widget, 3> makeWindowShim(StringId title, ScreenSize size)
{
// clang-format off
std::array<Widget, 3> out = {
makeWidget({ 0, 0 }, { size.width, size.height }, WidgetType::frame, WindowColour::primary),
makeWidget({ 1, 1 }, { size.width - 1, kTitleHeightNormal }, WidgetType::caption, WindowColour::primary, title, STR_WINDOW_TITLE_TIP),
makeWidget({ size.width - 12, 2 }, { 11, 11 }, WidgetType::closeBox, WindowColour::primary, kWidgetContentEmpty, STR_CLOSE_WINDOW_TIP),
};
// clang-format on
out[2].string = kCloseBoxStringBlackNormal;
return out;
}
constexpr Widget makeSpinnerDecreaseWidget(
const ScreenCoordsXY& origin, const ScreenSize& size, [[maybe_unused]] WidgetType type, WindowColour colour,
[[maybe_unused]] uint32_t content = kWidgetContentEmpty, StringId tooltip = kStringIdNone)
{
const int16_t xPos = origin.x + size.width - 26;
const int16_t yPos = origin.y + 1;
const uint16_t width = 13;
const uint16_t height = size.height - 2;
return makeWidget({ xPos, yPos }, { width, height }, WidgetType::button, colour, STR_NUMERIC_DOWN, tooltip);
}
constexpr Widget makeSpinnerIncreaseWidget(
const ScreenCoordsXY& origin, const ScreenSize& size, [[maybe_unused]] WidgetType type, WindowColour colour,
[[maybe_unused]] uint32_t content = kWidgetContentEmpty, StringId tooltip = kStringIdNone)
{
const int16_t xPos = origin.x + size.width - 13;
const int16_t yPos = origin.y + 1;
const uint16_t width = 12;
const uint16_t height = size.height - 2;
return makeWidget({ xPos, yPos }, { width, height }, WidgetType::button, colour, STR_NUMERIC_UP, tooltip);
}
constexpr std::array<Widget, 3> makeSpinnerWidgets(
const ScreenCoordsXY& origin, const ScreenSize& size, WidgetType type, WindowColour colour,
uint32_t content = kWidgetContentEmpty, StringId tooltip = kStringIdNone)
{
return makeWidgets(
makeWidget(origin, size, type, colour, content, tooltip),
makeSpinnerIncreaseWidget(origin, size, type, colour, content, tooltip),
makeSpinnerDecreaseWidget(origin, size, type, colour, content, tooltip));
};
constexpr Widget makeDropdownBoxWidget(
const ScreenCoordsXY& origin, const ScreenSize& size, [[maybe_unused]] WidgetType type, WindowColour colour,
[[maybe_unused]] uint32_t content = kWidgetContentEmpty, StringId tooltip = kStringIdNone)
{
return makeWidget(origin, size, type, colour, content);
}
constexpr Widget makeDropdownButtonWidget(
const ScreenCoordsXY& origin, const ScreenSize& size, [[maybe_unused]] WidgetType type, WindowColour colour,
[[maybe_unused]] uint32_t content = kWidgetContentEmpty, StringId tooltip = kStringIdNone)
{
const int16_t xPos = origin.x + size.width - 11;
const int16_t yPos = origin.y + 1;
const uint16_t width = 11;
const uint16_t height = size.height - 2;
return makeWidget({ xPos, yPos }, { width, height }, WidgetType::button, colour, STR_DROPDOWN_GLYPH, tooltip);
}
constexpr std::array<Widget, 2> makeDropdownWidgets(
const ScreenCoordsXY& origin, const ScreenSize& size, WidgetType type, WindowColour colour, uint32_t content,
StringId tooltip = kStringIdNone)
{
return makeWidgets(
makeDropdownBoxWidget(origin, size, type, colour, content, tooltip),
makeDropdownButtonWidget(origin, size, type, colour, content, tooltip));
};
void widgetDraw(RenderTarget& rt, WindowBase& w, WidgetIndex widgetIndex);
bool widgetIsDisabled(const WindowBase& w, WidgetIndex widgetIndex);
bool widgetIsHoldable(const WindowBase& w, WidgetIndex widgetIndex);
bool widgetIsVisible(const WindowBase& w, WidgetIndex widgetIndex);
bool widgetIsPressed(const WindowBase& w, WidgetIndex widgetIndex);
bool widgetIsHighlighted(const WindowBase& w, WidgetIndex widgetIndex);
void widgetScrollGetPart(
WindowBase& w, const Widget* widget, const ScreenCoordsXY& screenCoords, ScreenCoordsXY& retScreenCoords,
int32_t* output_scroll_area, int32_t* scroll_id);
void widgetSetEnabled(WindowBase& w, WidgetIndex widgetIndex, bool enabled);
void widgetSetDisabled(WindowBase& w, WidgetIndex widgetIndex, bool value);
void widgetSetHoldable(WindowBase& w, WidgetIndex widgetIndex, bool value);
void widgetSetVisible(WindowBase& w, WidgetIndex widgetIndex, bool value);
void widgetSetPressed(WindowBase& w, WidgetIndex widgetIndex, bool value);
void widgetSetCheckboxValue(WindowBase& w, WidgetIndex widgetIndex, bool value);
void widgetProgressBarSetNewPercentage(Widget& widget, uint8_t newPercentage);
void widgetScrollUpdateThumbs(WindowBase& w, WidgetIndex widget_index);
} // namespace OpenRCT2::Ui