1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-22 23:33:04 +01:00

Move Ui window functions into Ui library (#22426)

* Move scroll widget functions

* Move window move functions

* De-snake

* Move further functions to ui

* Move widget function to widget file

* Move window create to ui
This commit is contained in:
Duncan
2024-07-31 15:06:19 +01:00
committed by GitHub
parent 681b54dc87
commit 3393fa36d3
8 changed files with 586 additions and 582 deletions

View File

@@ -802,7 +802,7 @@ private:
if ((flags & SDL_WINDOW_MINIMIZED) == 0) if ((flags & SDL_WINDOW_MINIMIZED) == 0)
{ {
WindowResizeGui(_width, _height); WindowResizeGui(_width, _height);
WindowRelocateWindows(_width, _height); Windows::WindowRelocateWindows(_width, _height);
} }
GfxInvalidateScreen(); GfxInvalidateScreen();

View File

@@ -1242,4 +1242,72 @@ namespace OpenRCT2::Ui
widget.content &= ~0xFF; widget.content &= ~0xFF;
widget.content |= newPercentage; widget.content |= newPercentage;
} }
/**
*
* rct2: 0x006EAF26
*/
void WidgetScrollUpdateThumbs(WindowBase& w, WidgetIndex widget_index)
{
const auto& widget = w.widgets[widget_index];
auto& scroll = w.scrolls[WindowGetScrollDataIndex(w, widget_index)];
if (scroll.flags & HSCROLLBAR_VISIBLE)
{
int32_t view_size = widget.width() - 21;
if (scroll.flags & VSCROLLBAR_VISIBLE)
view_size -= 11;
int32_t x = scroll.h_left * view_size;
if (scroll.h_right != 0)
x /= scroll.h_right;
scroll.h_thumb_left = x + 11;
x = widget.width() - 2;
if (scroll.flags & VSCROLLBAR_VISIBLE)
x -= 11;
x += scroll.h_left;
if (scroll.h_right != 0)
x = (x * view_size) / scroll.h_right;
x += 11;
view_size += 10;
scroll.h_thumb_right = std::min(x, view_size);
if (scroll.h_thumb_right - scroll.h_thumb_left < 20)
{
double barPosition = (scroll.h_thumb_right * 1.0) / view_size;
scroll.h_thumb_left = static_cast<int32_t>(std::lround(scroll.h_thumb_left - (20 * barPosition)));
scroll.h_thumb_right = static_cast<int32_t>(std::lround(scroll.h_thumb_right + (20 * (1 - barPosition))));
}
}
if (scroll.flags & VSCROLLBAR_VISIBLE)
{
int32_t view_size = widget.height() - 21;
if (scroll.flags & HSCROLLBAR_VISIBLE)
view_size -= 11;
int32_t y = scroll.v_top * view_size;
if (scroll.v_bottom != 0)
y /= scroll.v_bottom;
scroll.v_thumb_top = y + 11;
y = widget.height() - 2;
if (scroll.flags & HSCROLLBAR_VISIBLE)
y -= 11;
y += scroll.v_top;
if (scroll.v_bottom != 0)
y = (y * view_size) / scroll.v_bottom;
y += 11;
view_size += 10;
scroll.v_thumb_bottom = std::min(y, view_size);
if (scroll.v_thumb_bottom - scroll.v_thumb_top < 20)
{
double barPosition = (scroll.v_thumb_bottom * 1.0) / view_size;
scroll.v_thumb_top = static_cast<int32_t>(std::lround(scroll.v_thumb_top - (20 * barPosition)));
scroll.v_thumb_bottom = static_cast<int32_t>(std::lround(scroll.v_thumb_bottom + (20 * (1 - barPosition))));
}
}
}
} // namespace OpenRCT2::Ui } // namespace OpenRCT2::Ui

View File

@@ -190,4 +190,6 @@ namespace OpenRCT2::Ui
void WidgetSetCheckboxValue(WindowBase& w, WidgetIndex widgetIndex, bool value); void WidgetSetCheckboxValue(WindowBase& w, WidgetIndex widgetIndex, bool value);
void WidgetProgressBarSetNewPercentage(Widget& widget, uint8_t newPercentage); void WidgetProgressBarSetNewPercentage(Widget& widget, uint8_t newPercentage);
void WidgetScrollUpdateThumbs(WindowBase& w, WidgetIndex widget_index);
} // namespace OpenRCT2::Ui } // namespace OpenRCT2::Ui

View File

@@ -14,6 +14,7 @@
#include "Widget.h" #include "Widget.h"
#include <SDL.h> #include <SDL.h>
#include <algorithm>
#include <openrct2-ui/windows/Window.h> #include <openrct2-ui/windows/Window.h>
#include <openrct2/Context.h> #include <openrct2/Context.h>
#include <openrct2/Input.h> #include <openrct2/Input.h>
@@ -209,96 +210,6 @@ static ScreenCoordsXY GetCentrePositionForNewWindow(int32_t width, int32_t heigh
return ScreenCoordsXY{ (screenWidth - width) / 2, std::max(kTopToolbarHeight + 1, (screenHeight - height) / 2) }; return ScreenCoordsXY{ (screenWidth - width) / 2, std::max(kTopToolbarHeight + 1, (screenHeight - height) / 2) };
} }
WindowBase* WindowCreate(
std::unique_ptr<WindowBase>&& wp, WindowClass cls, ScreenCoordsXY pos, int32_t width, int32_t height, uint32_t flags)
{
if (flags & WF_AUTO_POSITION)
{
if (flags & WF_CENTRE_SCREEN)
{
pos = GetCentrePositionForNewWindow(width, height);
}
else
{
pos = GetAutoPositionForNewWindow(width, height);
}
}
// Check if there are any window slots left
// include kWindowLimitReserved for items such as the main viewport and toolbars to not appear to be counted.
if (g_window_list.size() >= static_cast<size_t>(Config::Get().general.WindowLimit + kWindowLimitReserved))
{
// Close least recently used window
for (auto& w : g_window_list)
{
if (w->flags & WF_DEAD)
continue;
if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT | WF_NO_AUTO_CLOSE)))
{
WindowClose(*w.get());
break;
}
}
}
// Find right position to insert new window
auto itDestPos = g_window_list.end();
if (flags & WF_STICK_TO_BACK)
{
for (auto it = g_window_list.begin(); it != g_window_list.end(); it++)
{
if ((*it)->flags & WF_DEAD)
continue;
if (!((*it)->flags & WF_STICK_TO_BACK))
{
itDestPos = it;
}
}
}
else if (!(flags & WF_STICK_TO_FRONT))
{
for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
{
if ((*it)->flags & WF_DEAD)
continue;
if (!((*it)->flags & WF_STICK_TO_FRONT))
{
itDestPos = it.base();
break;
}
}
}
auto itNew = g_window_list.insert(itDestPos, std::move(wp));
auto w = itNew->get();
// Setup window
w->classification = cls;
w->flags = flags;
// Play sounds and flash the window
if (!(flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)))
{
w->flags |= WF_WHITE_BORDER_MASK;
OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::WindowOpen, 0, pos.x + (width / 2));
}
w->windowPos = pos;
w->width = width;
w->height = height;
w->min_width = width;
w->max_width = width;
w->min_height = height;
w->max_height = height;
w->focus = std::nullopt;
ColourSchemeUpdate(w);
w->Invalidate();
w->OnOpen();
return w;
}
static int32_t WindowGetWidgetIndex(const WindowBase& w, Widget* widget) static int32_t WindowGetWidgetIndex(const WindowBase& w, Widget* widget)
{ {
int32_t i = 0; int32_t i = 0;
@@ -570,45 +481,6 @@ void ApplyScreenSaverLockSetting()
Config::Get().general.DisableScreensaver ? SDL_DisableScreenSaver() : SDL_EnableScreenSaver(); Config::Get().general.DisableScreensaver ? SDL_DisableScreenSaver() : SDL_EnableScreenSaver();
} }
/**
* Initialises scroll widgets to their virtual size.
* rct2: 0x006EAEB8
*/
void WindowInitScrollWidgets(WindowBase& w)
{
Widget* widget;
int32_t widget_index, scroll_index;
widget_index = 0;
scroll_index = 0;
for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++)
{
if (widget->type != WindowWidgetType::Scroll)
{
widget_index++;
continue;
}
auto& scroll = w.scrolls[scroll_index];
scroll.flags = 0;
ScreenSize scrollSize = w.OnScrollGetSize(scroll_index);
scroll.h_left = 0;
scroll.h_right = scrollSize.width + 1;
scroll.v_top = 0;
scroll.v_bottom = scrollSize.height + 1;
if (widget->content & SCROLL_HORIZONTAL)
scroll.flags |= HSCROLLBAR_VISIBLE;
if (widget->content & SCROLL_VERTICAL)
scroll.flags |= VSCROLLBAR_VISIBLE;
WidgetScrollUpdateThumbs(w, widget_index);
widget_index++;
scroll_index++;
}
}
/** /**
* *
* rct2: 0x006EB15C * rct2: 0x006EB15C
@@ -671,19 +543,6 @@ static void WindowInvalidatePressedImageButton(const WindowBase& w)
} }
} }
/**
*
* rct2: 0x006EA73F
*/
void InvalidateAllWindowsAfterInput()
{
WindowVisitEach([](WindowBase* w) {
WindowUpdateScrollWidgets(*w);
WindowInvalidatePressedImageButton(*w);
w->OnResize();
});
}
void Window::OnDraw(DrawPixelInfo& dpi) void Window::OnDraw(DrawPixelInfo& dpi)
{ {
WindowDrawWidgets(*this, dpi); WindowDrawWidgets(*this, dpi);
@@ -696,7 +555,7 @@ void Window::OnDrawWidget(WidgetIndex widgetIndex, DrawPixelInfo& dpi)
void Window::InitScrollWidgets() void Window::InitScrollWidgets()
{ {
WindowInitScrollWidgets(*this); Windows::WindowInitScrollWidgets(*this);
} }
void Window::InvalidateWidget(WidgetIndex widgetIndex) void Window::InvalidateWidget(WidgetIndex widgetIndex)
@@ -837,6 +696,96 @@ namespace OpenRCT2::Ui::Windows
static TextInputSession* _textInput; static TextInputSession* _textInput;
static WidgetIdentifier _currentTextBox = { { WindowClass::Null, 0 }, 0 }; static WidgetIdentifier _currentTextBox = { { WindowClass::Null, 0 }, 0 };
WindowBase* WindowCreate(
std::unique_ptr<WindowBase>&& wp, WindowClass cls, ScreenCoordsXY pos, int32_t width, int32_t height, uint32_t flags)
{
if (flags & WF_AUTO_POSITION)
{
if (flags & WF_CENTRE_SCREEN)
{
pos = GetCentrePositionForNewWindow(width, height);
}
else
{
pos = GetAutoPositionForNewWindow(width, height);
}
}
// Check if there are any window slots left
// include kWindowLimitReserved for items such as the main viewport and toolbars to not appear to be counted.
if (g_window_list.size() >= static_cast<size_t>(Config::Get().general.WindowLimit + kWindowLimitReserved))
{
// Close least recently used window
for (auto& w : g_window_list)
{
if (w->flags & WF_DEAD)
continue;
if (!(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT | WF_NO_AUTO_CLOSE)))
{
WindowClose(*w.get());
break;
}
}
}
// Find right position to insert new window
auto itDestPos = g_window_list.end();
if (flags & WF_STICK_TO_BACK)
{
for (auto it = g_window_list.begin(); it != g_window_list.end(); it++)
{
if ((*it)->flags & WF_DEAD)
continue;
if (!((*it)->flags & WF_STICK_TO_BACK))
{
itDestPos = it;
}
}
}
else if (!(flags & WF_STICK_TO_FRONT))
{
for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
{
if ((*it)->flags & WF_DEAD)
continue;
if (!((*it)->flags & WF_STICK_TO_FRONT))
{
itDestPos = it.base();
break;
}
}
}
auto itNew = g_window_list.insert(itDestPos, std::move(wp));
auto w = itNew->get();
// Setup window
w->classification = cls;
w->flags = flags;
// Play sounds and flash the window
if (!(flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)))
{
w->flags |= WF_WHITE_BORDER_MASK;
OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::WindowOpen, 0, pos.x + (width / 2));
}
w->windowPos = pos;
w->width = width;
w->height = height;
w->min_width = width;
w->max_width = width;
w->min_height = height;
w->max_height = height;
w->focus = std::nullopt;
ColourSchemeUpdate(w);
w->Invalidate();
w->OnOpen();
return w;
}
WindowBase* WindowGetListening() WindowBase* WindowGetListening()
{ {
for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++) for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
@@ -934,4 +883,376 @@ namespace OpenRCT2::Ui::Windows
{ {
return _currentTextBox; return _currentTextBox;
} }
void WindowResize(WindowBase& w, int32_t dw, int32_t dh)
{
if (dw == 0 && dh == 0)
return;
// Invalidate old region
w.Invalidate();
// Clamp new size to minimum and maximum
w.width = std::clamp<int32_t>(w.width + dw, w.min_width, w.max_width);
w.height = std::clamp<int32_t>(w.height + dh, w.min_height, w.max_height);
w.OnResize();
w.OnPrepareDraw();
// Update scroll widgets
for (auto& scroll : w.scrolls)
{
scroll.h_right = WINDOW_SCROLL_UNDEFINED;
scroll.v_bottom = WINDOW_SCROLL_UNDEFINED;
}
WindowUpdateScrollWidgets(w);
// Invalidate new region
w.Invalidate();
}
/**
*
* rct2: 0x006EAE4E
*
* @param w The window (esi).
*/
void WindowUpdateScrollWidgets(WindowBase& w)
{
int32_t scrollIndex, width, height, scrollPositionChanged;
WidgetIndex widgetIndex;
Widget* widget;
widgetIndex = 0;
scrollIndex = 0;
for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++, widgetIndex++)
{
if (widget->type != WindowWidgetType::Scroll)
continue;
auto& scroll = w.scrolls[scrollIndex];
ScreenSize scrollSize = w.OnScrollGetSize(scrollIndex);
width = scrollSize.width;
height = scrollSize.height;
if (height == 0)
{
scroll.v_top = 0;
}
else if (width == 0)
{
scroll.h_left = 0;
}
width++;
height++;
scrollPositionChanged = 0;
if ((widget->content & SCROLL_HORIZONTAL) && width != scroll.h_right)
{
scrollPositionChanged = 1;
scroll.h_right = width;
}
if ((widget->content & SCROLL_VERTICAL) && height != scroll.v_bottom)
{
scrollPositionChanged = 1;
scroll.v_bottom = height;
}
if (scrollPositionChanged)
{
WidgetScrollUpdateThumbs(w, widgetIndex);
w.Invalidate();
}
scrollIndex++;
}
}
/**
* Initialises scroll widgets to their virtual size.
* rct2: 0x006EAEB8
*/
void WindowInitScrollWidgets(WindowBase& w)
{
Widget* widget;
int32_t widget_index, scroll_index;
widget_index = 0;
scroll_index = 0;
for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++)
{
if (widget->type != WindowWidgetType::Scroll)
{
widget_index++;
continue;
}
auto& scroll = w.scrolls[scroll_index];
scroll.flags = 0;
ScreenSize scrollSize = w.OnScrollGetSize(scroll_index);
scroll.h_left = 0;
scroll.h_right = scrollSize.width + 1;
scroll.v_top = 0;
scroll.v_bottom = scrollSize.height + 1;
if (widget->content & SCROLL_HORIZONTAL)
scroll.flags |= HSCROLLBAR_VISIBLE;
if (widget->content & SCROLL_VERTICAL)
scroll.flags |= VSCROLLBAR_VISIBLE;
WidgetScrollUpdateThumbs(w, widget_index);
widget_index++;
scroll_index++;
}
}
static void SnapLeft(WindowBase& w, int32_t proximity)
{
const auto* mainWindow = WindowGetMain();
auto wBottom = w.windowPos.y + w.height;
auto wLeftProximity = w.windowPos.x - (proximity * 2);
auto wRightProximity = w.windowPos.x + (proximity * 2);
auto rightMost = INT32_MIN;
WindowVisitEach([&](WindowBase* w2) {
if (w2 == &w || w2 == mainWindow)
return;
auto right = w2->windowPos.x + w2->width;
if (wBottom < w2->windowPos.y || w.windowPos.y > w2->windowPos.y + w2->height)
return;
if (right < wLeftProximity || right > wRightProximity)
return;
rightMost = std::max(rightMost, right);
});
if (0 >= wLeftProximity && 0 <= wRightProximity)
rightMost = std::max(rightMost, 0);
if (rightMost != INT32_MIN)
w.windowPos.x = rightMost;
}
static void SnapTop(WindowBase& w, int32_t proximity)
{
const auto* mainWindow = WindowGetMain();
auto wRight = w.windowPos.x + w.width;
auto wTopProximity = w.windowPos.y - (proximity * 2);
auto wBottomProximity = w.windowPos.y + (proximity * 2);
auto bottomMost = INT32_MIN;
WindowVisitEach([&](WindowBase* w2) {
if (w2 == &w || w2 == mainWindow)
return;
auto bottom = w2->windowPos.y + w2->height;
if (wRight < w2->windowPos.x || w.windowPos.x > w2->windowPos.x + w2->width)
return;
if (bottom < wTopProximity || bottom > wBottomProximity)
return;
bottomMost = std::max(bottomMost, bottom);
});
if (0 >= wTopProximity && 0 <= wBottomProximity)
bottomMost = std::max(bottomMost, 0);
if (bottomMost != INT32_MIN)
w.windowPos.y = bottomMost;
}
static void SnapRight(WindowBase& w, int32_t proximity)
{
const auto* mainWindow = WindowGetMain();
auto wRight = w.windowPos.x + w.width;
auto wBottom = w.windowPos.y + w.height;
auto wLeftProximity = wRight - (proximity * 2);
auto wRightProximity = wRight + (proximity * 2);
auto leftMost = INT32_MAX;
WindowVisitEach([&](WindowBase* w2) {
if (w2 == &w || w2 == mainWindow)
return;
if (wBottom < w2->windowPos.y || w.windowPos.y > w2->windowPos.y + w2->height)
return;
if (w2->windowPos.x < wLeftProximity || w2->windowPos.x > wRightProximity)
return;
leftMost = std::min<int32_t>(leftMost, w2->windowPos.x);
});
auto screenWidth = ContextGetWidth();
if (screenWidth >= wLeftProximity && screenWidth <= wRightProximity)
leftMost = std::min(leftMost, screenWidth);
if (leftMost != INT32_MAX)
w.windowPos.x = leftMost - w.width;
}
static void SnapBottom(WindowBase& w, int32_t proximity)
{
const auto* mainWindow = WindowGetMain();
auto wRight = w.windowPos.x + w.width;
auto wBottom = w.windowPos.y + w.height;
auto wTopProximity = wBottom - (proximity * 2);
auto wBottomProximity = wBottom + (proximity * 2);
auto topMost = INT32_MAX;
WindowVisitEach([&](WindowBase* w2) {
if (w2 == &w || w2 == mainWindow)
return;
if (wRight < w2->windowPos.x || w.windowPos.x > w2->windowPos.x + w2->width)
return;
if (w2->windowPos.y < wTopProximity || w2->windowPos.y > wBottomProximity)
return;
topMost = std::min<int32_t>(topMost, w2->windowPos.y);
});
auto screenHeight = ContextGetHeight();
if (screenHeight >= wTopProximity && screenHeight <= wBottomProximity)
topMost = std::min(topMost, screenHeight);
if (topMost != INT32_MAX)
w.windowPos.y = topMost - w.height;
}
void WindowMoveAndSnap(WindowBase& w, ScreenCoordsXY newWindowCoords, int32_t snapProximity)
{
auto originalPos = w.windowPos;
int32_t minY = (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) ? 1 : kTopToolbarHeight + 2;
newWindowCoords.y = std::clamp(newWindowCoords.y, minY, ContextGetHeight() - 34);
if (snapProximity > 0)
{
w.windowPos = newWindowCoords;
SnapRight(w, snapProximity);
SnapBottom(w, snapProximity);
SnapLeft(w, snapProximity);
SnapTop(w, snapProximity);
if (w.windowPos == originalPos)
return;
newWindowCoords = w.windowPos;
w.windowPos = originalPos;
}
WindowSetPosition(w, newWindowCoords);
}
void WindowMovePosition(WindowBase& w, const ScreenCoordsXY& deltaCoords)
{
if (deltaCoords.x == 0 && deltaCoords.y == 0)
return;
// Invalidate old region
w.Invalidate();
// Translate window and viewport
w.windowPos += deltaCoords;
if (w.viewport != nullptr)
{
w.viewport->pos += deltaCoords;
}
// Invalidate new region
w.Invalidate();
}
void WindowSetPosition(WindowBase& w, const ScreenCoordsXY& screenCoords)
{
WindowMovePosition(w, screenCoords - w.windowPos);
}
/**
*
* rct2: 0x006ED710
* Called after a window resize to move windows if they
* are going to be out of sight.
*/
void WindowRelocateWindows(int32_t width, int32_t height)
{
int32_t new_location = 8;
WindowVisitEach([width, height, &new_location](WindowBase* w) {
// Work out if the window requires moving
if (w->windowPos.x + 10 < width)
{
if (w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))
{
if (w->windowPos.y - 22 < height)
{
return;
}
}
if (w->windowPos.y + 10 < height)
{
return;
}
}
// Calculate the new locations
auto newWinPos = w->windowPos;
w->windowPos = { new_location, new_location + kTopToolbarHeight + 1 };
// Move the next new location so windows are not directly on top
new_location += 8;
// Adjust the viewport if required.
if (w->viewport != nullptr)
{
w->viewport->pos -= newWinPos - w->windowPos;
}
});
}
void WindowSetResize(WindowBase& w, int32_t minWidth, int32_t minHeight, int32_t maxWidth, int32_t maxHeight)
{
w.min_width = minWidth;
w.min_height = minHeight;
w.max_width = maxWidth;
w.max_height = maxHeight;
// Clamp width and height to minimum and maximum
int32_t width = std::clamp<int32_t>(w.width, std::min(minWidth, maxWidth), std::max(minWidth, maxWidth));
int32_t height = std::clamp<int32_t>(w.height, std::min(minHeight, maxHeight), std::max(minHeight, maxHeight));
// Resize window if size has changed
if (w.width != width || w.height != height)
{
w.Invalidate();
w.width = width;
w.height = height;
w.Invalidate();
}
}
bool WindowCanResize(const WindowBase& w)
{
return (w.flags & WF_RESIZABLE) && (w.min_width != w.max_width || w.min_height != w.max_height);
}
/**
*
* rct2: 0x006EA73F
*/
void InvalidateAllWindowsAfterInput()
{
WindowVisitEach([](WindowBase* w) {
Windows::WindowUpdateScrollWidgets(*w);
WindowInvalidatePressedImageButton(*w);
w->OnResize();
});
}
} // namespace OpenRCT2::Ui::Windows } // namespace OpenRCT2::Ui::Windows

View File

@@ -45,6 +45,42 @@ ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w);
namespace OpenRCT2::Ui::Windows namespace OpenRCT2::Ui::Windows
{ {
WindowBase* WindowCreate(
std::unique_ptr<WindowBase>&& w, WindowClass cls, ScreenCoordsXY pos, int32_t width, int32_t height, uint32_t flags);
template<typename T, typename... TArgs, typename std::enable_if<std::is_base_of<WindowBase, T>::value>::type* = nullptr>
T* WindowCreate(
WindowClass cls, const ScreenCoordsXY& pos = {}, int32_t width = 0, int32_t height = 0, uint32_t flags = 0,
TArgs&&... args)
{
return static_cast<T*>(WindowCreate(std::make_unique<T>(std::forward<TArgs>(args)...), cls, pos, width, height, flags));
}
template<typename T, typename... TArgs, typename std::enable_if<std::is_base_of<WindowBase, T>::value>::type* = nullptr>
T* WindowCreate(WindowClass cls, int32_t width, int32_t height, uint32_t flags, TArgs&&... args)
{
return static_cast<T*>(
WindowCreate(std::make_unique<T>(std::forward<TArgs>(args)...), cls, {}, width, height, flags | WF_AUTO_POSITION));
}
template<typename T, typename std::enable_if<std::is_base_of<WindowBase, T>::value>::type* = nullptr>
T* WindowFocusOrCreate(WindowClass cls, const ScreenCoordsXY& pos, int32_t width, int32_t height, uint32_t flags = 0)
{
auto* w = WindowBringToFrontByClass(cls);
if (w == nullptr)
{
w = WindowCreate<T>(cls, pos, width, height, flags);
}
return static_cast<T*>(w);
}
template<typename T, typename std::enable_if<std::is_base_of<WindowBase, T>::value>::type* = nullptr>
T* WindowFocusOrCreate(WindowClass cls, int32_t width, int32_t height, uint32_t flags = 0)
{
auto* w = WindowBringToFrontByClass(cls);
if (w == nullptr)
{
w = WindowCreate<T>(cls, width, height, flags);
}
return static_cast<T*>(w);
}
void RideConstructionToolupdateEntranceExit(const ScreenCoordsXY& screenCoords); void RideConstructionToolupdateEntranceExit(const ScreenCoordsXY& screenCoords);
void RideConstructionToolupdateConstruct(const ScreenCoordsXY& screenCoords); void RideConstructionToolupdateConstruct(const ScreenCoordsXY& screenCoords);
void RideConstructionTooldownConstruct(const ScreenCoordsXY& screenCoords); void RideConstructionTooldownConstruct(const ScreenCoordsXY& screenCoords);
@@ -86,4 +122,18 @@ namespace OpenRCT2::Ui::Windows
bool IsUsingWidgetTextBox(); bool IsUsingWidgetTextBox();
bool TextBoxCaretIsFlashed(); bool TextBoxCaretIsFlashed();
const WidgetIdentifier& GetCurrentTextBox(); const WidgetIdentifier& GetCurrentTextBox();
void WindowResize(WindowBase& w, int32_t dw, int32_t dh);
void WindowInitScrollWidgets(WindowBase& w);
void WindowUpdateScrollWidgets(WindowBase& w);
void WindowMovePosition(WindowBase& w, const ScreenCoordsXY& screenCoords);
void WindowSetPosition(WindowBase& w, const ScreenCoordsXY& screenCoords);
void WindowMoveAndSnap(WindowBase& w, ScreenCoordsXY newWindowCoords, int32_t snapProximity);
void WindowRelocateWindows(int32_t width, int32_t height);
void WindowSetResize(WindowBase& w, int32_t minWidth, int32_t minHeight, int32_t maxWidth, int32_t maxHeight);
bool WindowCanResize(const WindowBase& w);
void InvalidateAllWindowsAfterInput();
} // namespace OpenRCT2::Ui::Windows } // namespace OpenRCT2::Ui::Windows

View File

@@ -62,5 +62,3 @@ enum
SCROLL_VERTICAL = (1 << 1), SCROLL_VERTICAL = (1 << 1),
SCROLL_BOTH = SCROLL_HORIZONTAL | SCROLL_VERTICAL SCROLL_BOTH = SCROLL_HORIZONTAL | SCROLL_VERTICAL
}; };
void WidgetScrollUpdateThumbs(WindowBase& w, WidgetIndex widget_index);

View File

@@ -576,63 +576,6 @@ void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIn
}); });
} }
/**
*
* rct2: 0x006EAE4E
*
* @param w The window (esi).
*/
void WindowUpdateScrollWidgets(WindowBase& w)
{
int32_t scrollIndex, width, height, scrollPositionChanged;
WidgetIndex widgetIndex;
Widget* widget;
widgetIndex = 0;
scrollIndex = 0;
for (widget = w.widgets; widget->type != WindowWidgetType::Last; widget++, widgetIndex++)
{
if (widget->type != WindowWidgetType::Scroll)
continue;
auto& scroll = w.scrolls[scrollIndex];
ScreenSize scrollSize = w.OnScrollGetSize(scrollIndex);
width = scrollSize.width;
height = scrollSize.height;
if (height == 0)
{
scroll.v_top = 0;
}
else if (width == 0)
{
scroll.h_left = 0;
}
width++;
height++;
scrollPositionChanged = 0;
if ((widget->content & SCROLL_HORIZONTAL) && width != scroll.h_right)
{
scrollPositionChanged = 1;
scroll.h_right = width;
}
if ((widget->content & SCROLL_VERTICAL) && height != scroll.v_bottom)
{
scrollPositionChanged = 1;
scroll.v_bottom = height;
}
if (scrollPositionChanged)
{
WidgetScrollUpdateThumbs(w, widgetIndex);
w.Invalidate();
}
scrollIndex++;
}
}
int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index) int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index)
{ {
int32_t i, result; int32_t i, result;
@@ -1211,78 +1154,6 @@ void WindowDrawViewport(DrawPixelInfo& dpi, WindowBase& w)
ViewportRender(dpi, w.viewport, { { dpi.x, dpi.y }, { dpi.x + dpi.width, dpi.y + dpi.height } }); ViewportRender(dpi, w.viewport, { { dpi.x, dpi.y }, { dpi.x + dpi.width, dpi.y + dpi.height } });
} }
void WindowSetPosition(WindowBase& w, const ScreenCoordsXY& screenCoords)
{
WindowMovePosition(w, screenCoords - w.windowPos);
}
void WindowMovePosition(WindowBase& w, const ScreenCoordsXY& deltaCoords)
{
if (deltaCoords.x == 0 && deltaCoords.y == 0)
return;
// Invalidate old region
w.Invalidate();
// Translate window and viewport
w.windowPos += deltaCoords;
if (w.viewport != nullptr)
{
w.viewport->pos += deltaCoords;
}
// Invalidate new region
w.Invalidate();
}
void WindowResize(WindowBase& w, int32_t dw, int32_t dh)
{
if (dw == 0 && dh == 0)
return;
// Invalidate old region
w.Invalidate();
// Clamp new size to minimum and maximum
w.width = std::clamp<int32_t>(w.width + dw, w.min_width, w.max_width);
w.height = std::clamp<int32_t>(w.height + dh, w.min_height, w.max_height);
w.OnResize();
w.OnPrepareDraw();
// Update scroll widgets
for (auto& scroll : w.scrolls)
{
scroll.h_right = WINDOW_SCROLL_UNDEFINED;
scroll.v_bottom = WINDOW_SCROLL_UNDEFINED;
}
WindowUpdateScrollWidgets(w);
// Invalidate new region
w.Invalidate();
}
void WindowSetResize(WindowBase& w, int32_t minWidth, int32_t minHeight, int32_t maxWidth, int32_t maxHeight)
{
w.min_width = minWidth;
w.min_height = minHeight;
w.max_width = maxWidth;
w.max_height = maxHeight;
// Clamp width and height to minimum and maximum
int32_t width = std::clamp<int32_t>(w.width, std::min(minWidth, maxWidth), std::max(minWidth, maxWidth));
int32_t height = std::clamp<int32_t>(w.height, std::min(minHeight, maxHeight), std::max(minHeight, maxHeight));
// Resize window if size has changed
if (w.width != width || w.height != height)
{
w.Invalidate();
w.width = width;
w.height = height;
w.Invalidate();
}
}
/** /**
* *
* rct2: 0x006EE212 * rct2: 0x006EE212
@@ -1345,47 +1216,6 @@ void ToolCancel()
} }
} }
/**
*
* rct2: 0x006ED710
* Called after a window resize to move windows if they
* are going to be out of sight.
*/
void WindowRelocateWindows(int32_t width, int32_t height)
{
int32_t new_location = 8;
WindowVisitEach([width, height, &new_location](WindowBase* w) {
// Work out if the window requires moving
if (w->windowPos.x + 10 < width)
{
if (w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))
{
if (w->windowPos.y - 22 < height)
{
return;
}
}
if (w->windowPos.y + 10 < height)
{
return;
}
}
// Calculate the new locations
auto newWinPos = w->windowPos;
w->windowPos = { new_location, new_location + kTopToolbarHeight + 1 };
// Move the next new location so windows are not directly on top
new_location += 8;
// Adjust the viewport if required.
if (w->viewport != nullptr)
{
w->viewport->pos -= newWinPos - w->windowPos;
}
});
}
/** /**
* rct2: 0x0066B905 * rct2: 0x0066B905
*/ */
@@ -1515,157 +1345,6 @@ void WindowUpdateViewportRideMusic()
} }
} }
static void window_snap_left(WindowBase& w, int32_t proximity)
{
const auto* mainWindow = WindowGetMain();
auto wBottom = w.windowPos.y + w.height;
auto wLeftProximity = w.windowPos.x - (proximity * 2);
auto wRightProximity = w.windowPos.x + (proximity * 2);
auto rightMost = INT32_MIN;
WindowVisitEach([&](WindowBase* w2) {
if (w2 == &w || w2 == mainWindow)
return;
auto right = w2->windowPos.x + w2->width;
if (wBottom < w2->windowPos.y || w.windowPos.y > w2->windowPos.y + w2->height)
return;
if (right < wLeftProximity || right > wRightProximity)
return;
rightMost = std::max(rightMost, right);
});
if (0 >= wLeftProximity && 0 <= wRightProximity)
rightMost = std::max(rightMost, 0);
if (rightMost != INT32_MIN)
w.windowPos.x = rightMost;
}
static void window_snap_top(WindowBase& w, int32_t proximity)
{
const auto* mainWindow = WindowGetMain();
auto wRight = w.windowPos.x + w.width;
auto wTopProximity = w.windowPos.y - (proximity * 2);
auto wBottomProximity = w.windowPos.y + (proximity * 2);
auto bottomMost = INT32_MIN;
WindowVisitEach([&](WindowBase* w2) {
if (w2 == &w || w2 == mainWindow)
return;
auto bottom = w2->windowPos.y + w2->height;
if (wRight < w2->windowPos.x || w.windowPos.x > w2->windowPos.x + w2->width)
return;
if (bottom < wTopProximity || bottom > wBottomProximity)
return;
bottomMost = std::max(bottomMost, bottom);
});
if (0 >= wTopProximity && 0 <= wBottomProximity)
bottomMost = std::max(bottomMost, 0);
if (bottomMost != INT32_MIN)
w.windowPos.y = bottomMost;
}
static void window_snap_right(WindowBase& w, int32_t proximity)
{
const auto* mainWindow = WindowGetMain();
auto wRight = w.windowPos.x + w.width;
auto wBottom = w.windowPos.y + w.height;
auto wLeftProximity = wRight - (proximity * 2);
auto wRightProximity = wRight + (proximity * 2);
auto leftMost = INT32_MAX;
WindowVisitEach([&](WindowBase* w2) {
if (w2 == &w || w2 == mainWindow)
return;
if (wBottom < w2->windowPos.y || w.windowPos.y > w2->windowPos.y + w2->height)
return;
if (w2->windowPos.x < wLeftProximity || w2->windowPos.x > wRightProximity)
return;
leftMost = std::min<int32_t>(leftMost, w2->windowPos.x);
});
auto screenWidth = ContextGetWidth();
if (screenWidth >= wLeftProximity && screenWidth <= wRightProximity)
leftMost = std::min(leftMost, screenWidth);
if (leftMost != INT32_MAX)
w.windowPos.x = leftMost - w.width;
}
static void window_snap_bottom(WindowBase& w, int32_t proximity)
{
const auto* mainWindow = WindowGetMain();
auto wRight = w.windowPos.x + w.width;
auto wBottom = w.windowPos.y + w.height;
auto wTopProximity = wBottom - (proximity * 2);
auto wBottomProximity = wBottom + (proximity * 2);
auto topMost = INT32_MAX;
WindowVisitEach([&](WindowBase* w2) {
if (w2 == &w || w2 == mainWindow)
return;
if (wRight < w2->windowPos.x || w.windowPos.x > w2->windowPos.x + w2->width)
return;
if (w2->windowPos.y < wTopProximity || w2->windowPos.y > wBottomProximity)
return;
topMost = std::min<int32_t>(topMost, w2->windowPos.y);
});
auto screenHeight = ContextGetHeight();
if (screenHeight >= wTopProximity && screenHeight <= wBottomProximity)
topMost = std::min(topMost, screenHeight);
if (topMost != INT32_MAX)
w.windowPos.y = topMost - w.height;
}
void WindowMoveAndSnap(WindowBase& w, ScreenCoordsXY newWindowCoords, int32_t snapProximity)
{
auto originalPos = w.windowPos;
int32_t minY = (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) ? 1 : kTopToolbarHeight + 2;
newWindowCoords.y = std::clamp(newWindowCoords.y, minY, ContextGetHeight() - 34);
if (snapProximity > 0)
{
w.windowPos = newWindowCoords;
window_snap_right(w, snapProximity);
window_snap_bottom(w, snapProximity);
window_snap_left(w, snapProximity);
window_snap_top(w, snapProximity);
if (w.windowPos == originalPos)
return;
newWindowCoords = w.windowPos;
w.windowPos = originalPos;
}
WindowSetPosition(w, newWindowCoords);
}
int32_t WindowCanResize(const WindowBase& w)
{
return (w.flags & WF_RESIZABLE) && (w.min_width != w.max_width || w.min_height != w.max_height);
}
/** /**
* *
* rct2: 0x006EE3C3 * rct2: 0x006EE3C3
@@ -1803,74 +1482,6 @@ Viewport* WindowGetViewport(WindowBase* w)
return w->viewport; return w->viewport;
} }
/**
*
* rct2: 0x006EAF26
*/
void WidgetScrollUpdateThumbs(WindowBase& w, WidgetIndex widget_index)
{
const auto& widget = w.widgets[widget_index];
auto& scroll = w.scrolls[WindowGetScrollDataIndex(w, widget_index)];
if (scroll.flags & HSCROLLBAR_VISIBLE)
{
int32_t view_size = widget.width() - 21;
if (scroll.flags & VSCROLLBAR_VISIBLE)
view_size -= 11;
int32_t x = scroll.h_left * view_size;
if (scroll.h_right != 0)
x /= scroll.h_right;
scroll.h_thumb_left = x + 11;
x = widget.width() - 2;
if (scroll.flags & VSCROLLBAR_VISIBLE)
x -= 11;
x += scroll.h_left;
if (scroll.h_right != 0)
x = (x * view_size) / scroll.h_right;
x += 11;
view_size += 10;
scroll.h_thumb_right = std::min(x, view_size);
if (scroll.h_thumb_right - scroll.h_thumb_left < 20)
{
double barPosition = (scroll.h_thumb_right * 1.0) / view_size;
scroll.h_thumb_left = static_cast<int32_t>(std::lround(scroll.h_thumb_left - (20 * barPosition)));
scroll.h_thumb_right = static_cast<int32_t>(std::lround(scroll.h_thumb_right + (20 * (1 - barPosition))));
}
}
if (scroll.flags & VSCROLLBAR_VISIBLE)
{
int32_t view_size = widget.height() - 21;
if (scroll.flags & HSCROLLBAR_VISIBLE)
view_size -= 11;
int32_t y = scroll.v_top * view_size;
if (scroll.v_bottom != 0)
y /= scroll.v_bottom;
scroll.v_thumb_top = y + 11;
y = widget.height() - 2;
if (scroll.flags & HSCROLLBAR_VISIBLE)
y -= 11;
y += scroll.v_top;
if (scroll.v_bottom != 0)
y = (y * view_size) / scroll.v_bottom;
y += 11;
view_size += 10;
scroll.v_thumb_bottom = std::min(y, view_size);
if (scroll.v_thumb_bottom - scroll.v_thumb_top < 20)
{
double barPosition = (scroll.v_thumb_bottom * 1.0) / view_size;
scroll.v_thumb_top = static_cast<int32_t>(std::lround(scroll.v_thumb_top - (20 * barPosition)));
scroll.v_thumb_bottom = static_cast<int32_t>(std::lround(scroll.v_thumb_bottom + (20 * (1 - barPosition))));
}
}
}
void WindowBase::ResizeFrame() void WindowBase::ResizeFrame()
{ {
// Frame // Frame

View File

@@ -509,41 +509,6 @@ WindowBase* WindowBringToFrontByClass(WindowClass cls);
WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags); WindowBase* WindowBringToFrontByClassWithFlags(WindowClass cls, uint16_t flags);
WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number); WindowBase* WindowBringToFrontByNumber(WindowClass cls, rct_windownumber number);
WindowBase* WindowCreate(
std::unique_ptr<WindowBase>&& w, WindowClass cls, ScreenCoordsXY pos, int32_t width, int32_t height, uint32_t flags);
template<typename T, typename... TArgs, typename std::enable_if<std::is_base_of<WindowBase, T>::value>::type* = nullptr>
T* WindowCreate(
WindowClass cls, const ScreenCoordsXY& pos = {}, int32_t width = 0, int32_t height = 0, uint32_t flags = 0, TArgs&&... args)
{
return static_cast<T*>(WindowCreate(std::make_unique<T>(std::forward<TArgs>(args)...), cls, pos, width, height, flags));
}
template<typename T, typename... TArgs, typename std::enable_if<std::is_base_of<WindowBase, T>::value>::type* = nullptr>
T* WindowCreate(WindowClass cls, int32_t width, int32_t height, uint32_t flags, TArgs&&... args)
{
return static_cast<T*>(
WindowCreate(std::make_unique<T>(std::forward<TArgs>(args)...), cls, {}, width, height, flags | WF_AUTO_POSITION));
}
template<typename T, typename std::enable_if<std::is_base_of<WindowBase, T>::value>::type* = nullptr>
T* WindowFocusOrCreate(WindowClass cls, const ScreenCoordsXY& pos, int32_t width, int32_t height, uint32_t flags = 0)
{
auto* w = WindowBringToFrontByClass(cls);
if (w == nullptr)
{
w = WindowCreate<T>(cls, pos, width, height, flags);
}
return static_cast<T*>(w);
}
template<typename T, typename std::enable_if<std::is_base_of<WindowBase, T>::value>::type* = nullptr>
T* WindowFocusOrCreate(WindowClass cls, int32_t width, int32_t height, uint32_t flags = 0)
{
auto* w = WindowBringToFrontByClass(cls);
if (w == nullptr)
{
w = WindowCreate<T>(cls, width, height, flags);
}
return static_cast<T*>(w);
}
void WindowClose(WindowBase& window); void WindowClose(WindowBase& window);
void WindowFlushDead(); void WindowFlushDead();
void WindowCloseByClass(WindowClass cls); void WindowCloseByClass(WindowClass cls);
@@ -566,8 +531,7 @@ void WindowInvalidateAll();
void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex); void WidgetInvalidate(WindowBase& w, WidgetIndex widgetIndex);
void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex); void WidgetInvalidateByClass(WindowClass cls, WidgetIndex widgetIndex);
void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex); void WidgetInvalidateByNumber(WindowClass cls, rct_windownumber number, WidgetIndex widgetIndex);
void WindowInitScrollWidgets(WindowBase& w);
void WindowUpdateScrollWidgets(WindowBase& w);
int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index); int32_t WindowGetScrollDataIndex(const WindowBase& w, WidgetIndex widget_index);
void WindowPushOthersRight(WindowBase& w); void WindowPushOthersRight(WindowBase& w);
@@ -590,11 +554,6 @@ void WindowDraw(DrawPixelInfo& dpi, WindowBase& w, int32_t left, int32_t top, in
void WindowDrawWidgets(WindowBase& w, DrawPixelInfo& dpi); void WindowDrawWidgets(WindowBase& w, DrawPixelInfo& dpi);
void WindowDrawViewport(DrawPixelInfo& dpi, WindowBase& w); void WindowDrawViewport(DrawPixelInfo& dpi, WindowBase& w);
void WindowSetPosition(WindowBase& w, const ScreenCoordsXY& screenCoords);
void WindowMovePosition(WindowBase& w, const ScreenCoordsXY& screenCoords);
void WindowResize(WindowBase& w, int32_t dw, int32_t dh);
void WindowSetResize(WindowBase& w, int32_t minWidth, int32_t minHeight, int32_t maxWidth, int32_t maxHeight);
bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool); bool ToolSet(const WindowBase& w, WidgetIndex widgetIndex, Tool tool);
void ToolCancel(); void ToolCancel();
@@ -605,16 +564,11 @@ void WindowUpdateViewportRideMusic();
Viewport* WindowGetViewport(WindowBase* window); Viewport* WindowGetViewport(WindowBase* window);
// Open window functions // Open window functions
void WindowRelocateWindows(int32_t width, int32_t height);
void WindowResizeGui(int32_t width, int32_t height); void WindowResizeGui(int32_t width, int32_t height);
void WindowResizeGuiScenarioEditor(int32_t width, int32_t height); void WindowResizeGuiScenarioEditor(int32_t width, int32_t height);
void InvalidateAllWindowsAfterInput();
void TextinputCancel(); void TextinputCancel();
void WindowMoveAndSnap(WindowBase& w, ScreenCoordsXY newWindowCoords, int32_t snapProximity);
int32_t WindowCanResize(const WindowBase& w);
bool WindowIsVisible(WindowBase& w); bool WindowIsVisible(WindowBase& w);
bool SceneryToolIsActive(); bool SceneryToolIsActive();