mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-22 06:23:04 +01:00
Move WindowCreate and WindowFocusOrCreate into WindowManager (#23643)
* Move WindowBringToFront into WindowManager * Move WindowCreate and WindowFocusOrCreate into WindowManager * Cut back on Context/UiContext includes
This commit is contained in:
@@ -19,7 +19,9 @@
|
||||
#include <openrct2-ui/input/MouseInput.h>
|
||||
#include <openrct2-ui/input/ShortcutManager.h>
|
||||
#include <openrct2-ui/windows/Window.h>
|
||||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Input.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/core/Console.hpp>
|
||||
#include <openrct2/core/Guard.hpp>
|
||||
@@ -30,6 +32,7 @@
|
||||
#include <openrct2/ride/Ride.h>
|
||||
#include <openrct2/ride/RideConstruction.h>
|
||||
#include <openrct2/ride/Vehicle.h>
|
||||
#include <openrct2/ui/UiContext.h>
|
||||
#include <openrct2/ui/WindowManager.h>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
@@ -323,7 +326,7 @@ public:
|
||||
case INTENT_ACTION_NEW_SCENERY:
|
||||
{
|
||||
// Check if window is already open
|
||||
auto* window = WindowBringToFrontByClass(WindowClass::Scenery);
|
||||
auto* window = BringToFrontByClass(WindowClass::Scenery);
|
||||
if (window == nullptr)
|
||||
ToggleSceneryWindow();
|
||||
|
||||
@@ -647,6 +650,270 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool WindowFitsBetweenOthers(const ScreenCoordsXY& loc, int32_t width, int32_t height)
|
||||
{
|
||||
for (auto& w : g_window_list)
|
||||
{
|
||||
if (w->flags & WF_DEAD)
|
||||
continue;
|
||||
if (w->flags & WF_STICK_TO_BACK)
|
||||
continue;
|
||||
|
||||
if (loc.x + width <= w->windowPos.x)
|
||||
continue;
|
||||
if (loc.x >= w->windowPos.x + w->width)
|
||||
continue;
|
||||
if (loc.y + height <= w->windowPos.y)
|
||||
continue;
|
||||
if (loc.y >= w->windowPos.y + w->height)
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool WindowFitsWithinSpace(const ScreenCoordsXY& loc, int32_t width, int32_t height)
|
||||
{
|
||||
if (loc.x < 0)
|
||||
return false;
|
||||
if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
|
||||
return false;
|
||||
if (loc.x + width > ContextGetWidth())
|
||||
return false;
|
||||
if (loc.y + height > ContextGetHeight())
|
||||
return false;
|
||||
return WindowFitsBetweenOthers(loc, width, height);
|
||||
}
|
||||
|
||||
static bool WindowFitsOnScreen(const ScreenCoordsXY& loc, int32_t width, int32_t height)
|
||||
{
|
||||
uint16_t screenWidth = ContextGetWidth();
|
||||
uint16_t screenHeight = ContextGetHeight();
|
||||
int32_t unk;
|
||||
|
||||
unk = -(width / 4);
|
||||
if (loc.x < unk)
|
||||
return false;
|
||||
unk = screenWidth + (unk * 2);
|
||||
if (loc.x > unk)
|
||||
return false;
|
||||
if (loc.y <= kTopToolbarHeight && !(gScreenFlags & SCREEN_FLAGS_TITLE_DEMO))
|
||||
return false;
|
||||
unk = screenHeight - (height / 4);
|
||||
if (loc.y > unk)
|
||||
return false;
|
||||
return WindowFitsBetweenOthers(loc, width, height);
|
||||
}
|
||||
|
||||
static ScreenCoordsXY ClampWindowToScreen(
|
||||
const ScreenCoordsXY& pos, const int32_t screenWidth, const int32_t screenHeight, const int32_t width,
|
||||
const int32_t height)
|
||||
{
|
||||
auto screenPos = pos;
|
||||
if (width > screenWidth || screenPos.x < 0)
|
||||
screenPos.x = 0;
|
||||
else if (screenPos.x + width > screenWidth)
|
||||
screenPos.x = screenWidth - width;
|
||||
|
||||
auto toolbarAllowance = (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) ? 0 : (kTopToolbarHeight + 1);
|
||||
if (height - toolbarAllowance > screenHeight || screenPos.y < toolbarAllowance)
|
||||
screenPos.y = toolbarAllowance;
|
||||
else if (screenPos.y + height - toolbarAllowance > screenHeight)
|
||||
screenPos.y = screenHeight + toolbarAllowance - height;
|
||||
|
||||
return screenPos;
|
||||
}
|
||||
|
||||
static ScreenCoordsXY GetAutoPositionForNewWindow(int32_t width, int32_t height)
|
||||
{
|
||||
auto uiContext = GetContext()->GetUiContext();
|
||||
auto screenWidth = uiContext->GetWidth();
|
||||
auto screenHeight = uiContext->GetHeight();
|
||||
|
||||
// Place window in an empty corner of the screen
|
||||
const ScreenCoordsXY cornerPositions[] = {
|
||||
{ 0, 30 }, // topLeft
|
||||
{ screenWidth - width, 30 }, // topRight
|
||||
{ 0, screenHeight - 34 - height }, // bottomLeft
|
||||
{ screenWidth - width, screenHeight - 34 - height }, // bottomRight
|
||||
};
|
||||
|
||||
for (const auto& cornerPos : cornerPositions)
|
||||
{
|
||||
if (WindowFitsWithinSpace(cornerPos, width, height))
|
||||
{
|
||||
return ClampWindowToScreen(cornerPos, screenWidth, screenHeight, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
// Place window next to another
|
||||
for (auto& w : g_window_list)
|
||||
{
|
||||
if (w->flags & WF_DEAD)
|
||||
continue;
|
||||
if (w->flags & WF_STICK_TO_BACK)
|
||||
continue;
|
||||
|
||||
const ScreenCoordsXY offsets[] = {
|
||||
{ w->width + 2, 0 },
|
||||
{ -w->width - 2, 0 },
|
||||
{ 0, w->height + 2 },
|
||||
{ 0, -w->height - 2 },
|
||||
{ w->width + 2, -w->height - 2 },
|
||||
{ -w->width - 2, -w->height - 2 },
|
||||
{ w->width + 2, w->height + 2 },
|
||||
{ -w->width - 2, w->height + 2 },
|
||||
};
|
||||
|
||||
for (const auto& offset : offsets)
|
||||
{
|
||||
auto screenPos = w->windowPos + offset;
|
||||
if (WindowFitsWithinSpace(screenPos, width, height))
|
||||
{
|
||||
return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overlap
|
||||
for (auto& w : g_window_list)
|
||||
{
|
||||
if (w->flags & WF_DEAD)
|
||||
continue;
|
||||
if (w->flags & WF_STICK_TO_BACK)
|
||||
continue;
|
||||
|
||||
const ScreenCoordsXY offsets[] = {
|
||||
{ w->width + 2, 0 },
|
||||
{ -w->width - 2, 0 },
|
||||
{ 0, w->height + 2 },
|
||||
{ 0, -w->height - 2 },
|
||||
};
|
||||
|
||||
for (const auto& offset : offsets)
|
||||
{
|
||||
auto screenPos = w->windowPos + offset;
|
||||
if (WindowFitsOnScreen(screenPos, width, height))
|
||||
{
|
||||
return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cascade
|
||||
auto screenPos = ScreenCoordsXY{ 0, 30 };
|
||||
for (auto& w : g_window_list)
|
||||
{
|
||||
if (screenPos == w->windowPos)
|
||||
{
|
||||
screenPos.x += 5;
|
||||
screenPos.y += 5;
|
||||
}
|
||||
}
|
||||
|
||||
return ClampWindowToScreen(screenPos, screenWidth, screenHeight, width, height);
|
||||
}
|
||||
|
||||
static ScreenCoordsXY GetCentrePositionForNewWindow(int32_t width, int32_t height)
|
||||
{
|
||||
auto uiContext = GetContext()->GetUiContext();
|
||||
auto screenWidth = uiContext->GetWidth();
|
||||
auto screenHeight = uiContext->GetHeight();
|
||||
return ScreenCoordsXY{ (screenWidth - width) / 2, std::max(kTopToolbarHeight + 1, (screenHeight - height) / 2) };
|
||||
}
|
||||
|
||||
WindowBase* Create(
|
||||
std::unique_ptr<WindowBase>&& wp, WindowClass cls, ScreenCoordsXY pos, int32_t width, int32_t height,
|
||||
uint32_t flags) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first window with the specified window class.
|
||||
* rct2: 0x006EA8A0
|
||||
@@ -762,6 +1029,82 @@ public:
|
||||
// Return the widget index
|
||||
return widget_index;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006ECDA4
|
||||
*/
|
||||
WindowBase* BringToFront(WindowBase& w) override
|
||||
{
|
||||
if (!(w.flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)))
|
||||
{
|
||||
auto itSourcePos = WindowGetIterator(&w);
|
||||
if (itSourcePos != g_window_list.end())
|
||||
{
|
||||
// Insert in front of the first non-stick-to-front window
|
||||
auto itDestPos = g_window_list.begin();
|
||||
for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
|
||||
{
|
||||
auto& w2 = *it;
|
||||
if (!(w2->flags & WF_STICK_TO_FRONT))
|
||||
{
|
||||
itDestPos = it.base();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_window_list.splice(itDestPos, g_window_list, itSourcePos);
|
||||
w.Invalidate();
|
||||
|
||||
if (w.windowPos.x + w.width < 20)
|
||||
{
|
||||
int32_t i = 20 - w.windowPos.x;
|
||||
w.windowPos.x += i;
|
||||
if (w.viewport != nullptr)
|
||||
w.viewport->pos.x += i;
|
||||
w.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
return &w;
|
||||
}
|
||||
|
||||
WindowBase* BringToFrontByClassWithFlags(WindowClass cls, uint16_t flags) override
|
||||
{
|
||||
WindowBase* w = FindByClass(cls);
|
||||
if (w != nullptr)
|
||||
{
|
||||
w->flags |= flags;
|
||||
w->Invalidate();
|
||||
w = BringToFront(*w);
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
WindowBase* BringToFrontByClass(WindowClass cls) override
|
||||
{
|
||||
return BringToFrontByClassWithFlags(cls, WF_WHITE_BORDER_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006ED78A
|
||||
* cls (cl)
|
||||
* number (dx)
|
||||
*/
|
||||
WindowBase* BringToFrontByNumber(WindowClass cls, rct_windownumber number) override
|
||||
{
|
||||
WindowBase* w = FindByNumber(cls, number);
|
||||
if (w != nullptr)
|
||||
{
|
||||
w->flags |= WF_WHITE_BORDER_MASK;
|
||||
w->Invalidate();
|
||||
w = BringToFront(*w);
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<IWindowManager> OpenRCT2::Ui::CreateWindowManager()
|
||||
|
||||
Reference in New Issue
Block a user