mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-15 19:13:07 +01:00
Extract window specific logic from Graph.cpp
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
#include "../UiStringIds.h"
|
||||
|
||||
#include <openrct2-ui/interface/Graph.h>
|
||||
#include <openrct2/Context.h>
|
||||
#include <openrct2/Date.h>
|
||||
#include <openrct2/localisation/Formatter.h>
|
||||
#include <openrct2/localisation/Localisation.Date.h>
|
||||
@@ -110,13 +109,9 @@ namespace OpenRCT2::Graph
|
||||
namespace OpenRCT2::Graph
|
||||
{
|
||||
constexpr int32_t kDashLength = 2;
|
||||
constexpr ScreenCoordsXY kFinanceTopLeftPadding{ 88, 20 };
|
||||
constexpr ScreenCoordsXY kFinanceBottomRightPadding{ 15, 18 };
|
||||
constexpr uint8_t kNumFinanceGraphYLabels = 5;
|
||||
|
||||
template<typename T, T TkNoValue>
|
||||
static void DrawMonths(
|
||||
DrawPixelInfo& dpi, const T* series, int32_t count, const ScreenRect& bounds, const int32_t xStep)
|
||||
static void DrawMonths(DrawPixelInfo& dpi, const T* series, int32_t count, const ScreenRect& bounds, const int32_t xStep)
|
||||
{
|
||||
auto& date = GetDate();
|
||||
int32_t currentMonth = date.GetMonth();
|
||||
@@ -143,38 +138,23 @@ namespace OpenRCT2::Graph
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, T TkNoValue>
|
||||
template<typename T>
|
||||
static void DrawHoveredValue(
|
||||
DrawPixelInfo& dpi, const T* series, const int32_t count, const ScreenRect& bounds, const int32_t xStep,
|
||||
DrawPixelInfo& dpi, const T value, const int32_t hoverIdx, const ScreenRect& bounds, const int32_t xStep,
|
||||
const T minValue, const T maxValue)
|
||||
{
|
||||
const ScreenCoordsXY cursorPos = ContextGetCursorPositionScaled();
|
||||
if (!bounds.Contains(cursorPos))
|
||||
return;
|
||||
|
||||
int32_t i = (count - 1) - (cursorPos.x - bounds.GetLeft() + (xStep / 2)) / xStep;
|
||||
if (i < 0)
|
||||
i = 1;
|
||||
if (i > count - 1)
|
||||
i = count - 1;
|
||||
|
||||
T value = series[i];
|
||||
if (value == TkNoValue)
|
||||
return;
|
||||
const int32_t screenRange = bounds.GetHeight();
|
||||
const int32_t valueRange = maxValue - minValue;
|
||||
int32_t test = bounds.GetBottom() - ((value - minValue) * screenRange) / valueRange;
|
||||
ScreenCoordsXY coords = { bounds.GetRight() - i * xStep, test };
|
||||
|
||||
const int32_t yPosition = bounds.GetBottom() - ((value - minValue) * screenRange) / valueRange;
|
||||
ScreenCoordsXY coords = { bounds.GetRight() - hoverIdx * xStep, yPosition };
|
||||
// Line needs to be shifted over 1 pixel to match with the month ticks.
|
||||
ScreenCoordsXY lineCoords = { coords.x + 1, coords.y };
|
||||
|
||||
GfxDrawDashedLine(dpi, { { lineCoords.x, bounds.GetTop() }, lineCoords }, kDashLength, PALETTE_INDEX_10);
|
||||
GfxDrawDashedLine(
|
||||
dpi, { { lineCoords.x, bounds.GetTop() }, { lineCoords.x, bounds.GetBottom() } }, kDashLength, PALETTE_INDEX_10);
|
||||
GfxDrawDashedLine(dpi, { { bounds.GetLeft(), lineCoords.y }, lineCoords }, kDashLength, PALETTE_INDEX_10);
|
||||
|
||||
if (cursorPos.y > coords.y)
|
||||
{
|
||||
GfxDrawDashedLine(dpi, { lineCoords, { lineCoords.x, cursorPos.y } }, kDashLength, PALETTE_INDEX_10);
|
||||
}
|
||||
|
||||
auto ft = Formatter();
|
||||
ft.Add<money64>(value);
|
||||
DrawTextBasic(
|
||||
@@ -240,60 +220,41 @@ namespace OpenRCT2::Graph
|
||||
}
|
||||
}
|
||||
|
||||
void DrawFinanceGraph(
|
||||
DrawPixelInfo& dpi, const money64 (&series)[128], const ScreenRect& graphBounds, const bool centred,
|
||||
const ColourWithFlags lineCol)
|
||||
void DrawFinanceGraph(DrawPixelInfo& dpi, const GraphProperties<money64>& p)
|
||||
{
|
||||
constexpr int32_t count = 64; // todo for whatever reason this is 64.
|
||||
|
||||
ScreenRect internalBounds{ graphBounds.Point1 + kFinanceTopLeftPadding,
|
||||
graphBounds.Point2 - kFinanceBottomRightPadding };
|
||||
const int32_t yLabelStepPx = (internalBounds.GetBottom() - internalBounds.GetTop()) / (kNumFinanceGraphYLabels - 1);
|
||||
const int32_t xStepPx = (internalBounds.GetRight() - internalBounds.GetLeft()) / (count - 1);
|
||||
|
||||
// adjust bounds to be exact multiples of the steps.
|
||||
internalBounds.Point2 = internalBounds.Point1
|
||||
+ ScreenCoordsXY{ xStepPx * (count - 1), yLabelStepPx * (kNumFinanceGraphYLabels - 1) };
|
||||
|
||||
money64 graphMaximum = centred ? 12.00_GBP : 24.00_GBP;
|
||||
for (int32_t i = 0; i < count; i++)
|
||||
{
|
||||
auto currentValue = series[i];
|
||||
if (currentValue == kMoney64Undefined)
|
||||
continue;
|
||||
while (std::abs(currentValue) > graphMaximum)
|
||||
graphMaximum *= 2;
|
||||
}
|
||||
const money64 graphMinimum = centred ? -graphMaximum : 0.00_GBP;
|
||||
|
||||
const money64 yLabelStep = (graphMaximum - graphMinimum) / (kNumFinanceGraphYLabels - 1);
|
||||
money64 curLabel = graphMaximum;
|
||||
int32_t curScreenPos = internalBounds.GetTop() - 5;
|
||||
for (uint8_t i = 0; i < kNumFinanceGraphYLabels; i++)
|
||||
money64 curLabel = p.max;
|
||||
int32_t curScreenPos = p.internalBounds.GetTop() - 5;
|
||||
const money64 yLabelStep = (p.max - p.min) / (p.numYLabels - 1);
|
||||
for (int32_t i = 0; i < p.numYLabels; i++)
|
||||
{
|
||||
Formatter ft;
|
||||
ft.Add<money64>(curLabel);
|
||||
DrawTextBasic(
|
||||
dpi, { internalBounds.GetLeft(), curScreenPos }, STR_FINANCES_FINANCIAL_GRAPH_CASH_VALUE, ft,
|
||||
dpi, { p.internalBounds.GetLeft(), curScreenPos }, STR_FINANCES_FINANCIAL_GRAPH_CASH_VALUE, ft,
|
||||
{ FontStyle::Small, TextAlignment::RIGHT });
|
||||
GfxFillRectInset(
|
||||
dpi, { { internalBounds.GetLeft(), curScreenPos + 5 }, { internalBounds.GetRight(), curScreenPos + 5 } },
|
||||
lineCol, INSET_RECT_FLAG_BORDER_INSET);
|
||||
curScreenPos += yLabelStepPx;
|
||||
dpi, { { p.internalBounds.GetLeft(), curScreenPos + 5 }, { p.internalBounds.GetRight(), curScreenPos + 5 } },
|
||||
p.lineCol, INSET_RECT_FLAG_BORDER_INSET);
|
||||
curScreenPos += p.yLabelStepPx;
|
||||
curLabel -= yLabelStep;
|
||||
}
|
||||
|
||||
DrawMonths<money64, kMoney64Undefined>(dpi, series, count, internalBounds, xStepPx);
|
||||
DrawLine<money64, kMoney64Undefined, true>(dpi, series, count, internalBounds, xStepPx, graphMinimum, graphMaximum);
|
||||
DrawLine<money64, kMoney64Undefined, false>(dpi, series, count, internalBounds, xStepPx, graphMinimum, graphMaximum);
|
||||
DrawHoveredValue<money64, kMoney64Undefined>(dpi, series, count, internalBounds, xStepPx, graphMinimum, graphMaximum);
|
||||
DrawMonths<money64, kMoney64Undefined>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx);
|
||||
DrawLine<money64, kMoney64Undefined, true>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
|
||||
DrawLine<money64, kMoney64Undefined, false>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
|
||||
if (p.hoverIdx >= 0 && p.hoverIdx < p.numPoints)
|
||||
{
|
||||
money64 value = p.series[p.hoverIdx];
|
||||
if (value != kMoney64Undefined)
|
||||
DrawHoveredValue<money64>(dpi, value, p.hoverIdx, p.internalBounds, p.xStepPx, p.min, p.max);
|
||||
}
|
||||
|
||||
// todo debug code.
|
||||
ScreenCoordsXY bottomLeft{ internalBounds.Point1.x, internalBounds.Point2.y };
|
||||
ScreenCoordsXY topRight{ internalBounds.Point2.x, internalBounds.Point1.y };
|
||||
GfxDrawLine(dpi, { internalBounds.Point1, topRight }, 33);
|
||||
GfxDrawLine(dpi, { internalBounds.Point1, bottomLeft }, 33);
|
||||
GfxDrawLine(dpi, { bottomLeft, internalBounds.Point2 }, 33);
|
||||
GfxDrawLine(dpi, { topRight, internalBounds.Point2 }, 33);
|
||||
ScreenCoordsXY bottomLeft{ p.internalBounds.Point1.x, p.internalBounds.Point2.y };
|
||||
ScreenCoordsXY topRight{ p.internalBounds.Point2.x, p.internalBounds.Point1.y };
|
||||
GfxDrawLine(dpi, { p.internalBounds.Point1, topRight }, 33);
|
||||
GfxDrawLine(dpi, { p.internalBounds.Point1, bottomLeft }, 33);
|
||||
GfxDrawLine(dpi, { bottomLeft, p.internalBounds.Point2 }, 33);
|
||||
GfxDrawLine(dpi, { topRight, p.internalBounds.Point2 }, 33);
|
||||
}
|
||||
} // namespace OpenRCT2::Graph
|
||||
|
||||
@@ -9,14 +9,62 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <openrct2/Context.h>
|
||||
#include <openrct2/core/Money.hpp>
|
||||
#include <openrct2/drawing/Drawing.h>
|
||||
#include <openrct2/world/Location.hpp>
|
||||
|
||||
namespace OpenRCT2::Graph
|
||||
{
|
||||
template<typename T> struct GraphProperties
|
||||
{
|
||||
ScreenRect internalBounds;
|
||||
T* series;
|
||||
T min;
|
||||
T max;
|
||||
int32_t hoverIdx;
|
||||
int32_t numPoints;
|
||||
int32_t numYLabels;
|
||||
int32_t xStepPx;
|
||||
int32_t yLabelStepPx;
|
||||
ColourWithFlags lineCol;
|
||||
|
||||
void RecalculateLayout(const ScreenRect newBounds, const int32_t newNumYLabels, const int32_t newNumPoints)
|
||||
{
|
||||
yLabelStepPx = (newBounds.GetBottom() - newBounds.GetTop()) / (newNumYLabels - 1);
|
||||
xStepPx = (newBounds.GetRight() - newBounds.GetLeft()) / (newNumPoints - 1);
|
||||
// adjust bounds to be exact multiples of the steps.
|
||||
internalBounds = { newBounds.Point1,
|
||||
newBounds.Point1
|
||||
+ ScreenCoordsXY{ xStepPx * (newNumPoints - 1), yLabelStepPx * (newNumYLabels - 1) } };
|
||||
numPoints = newNumPoints;
|
||||
numYLabels = newNumYLabels;
|
||||
}
|
||||
|
||||
bool UpdateHoverIdx()
|
||||
{
|
||||
const ScreenCoordsXY cursorPos = ContextGetCursorPositionScaled();
|
||||
|
||||
int32_t i = -1;
|
||||
if (internalBounds.Contains(cursorPos))
|
||||
{
|
||||
i = (numPoints - 1) - (cursorPos.x - internalBounds.GetLeft() + (xStepPx / 2)) / xStepPx;
|
||||
if (i < 0)
|
||||
i = 1;
|
||||
if (i > numPoints - 1)
|
||||
i = numPoints - 1;
|
||||
}
|
||||
|
||||
if (hoverIdx != i)
|
||||
{
|
||||
hoverIdx = i;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void Draw(DrawPixelInfo& dpi, uint8_t* history, int32_t count, const ScreenCoordsXY& screenPos);
|
||||
|
||||
void DrawFinanceGraph(
|
||||
DrawPixelInfo& dpi, const money64 (&series)[128], const ScreenRect& graphBounds, bool centred, ColourWithFlags lineCol);
|
||||
void DrawFinanceGraph(DrawPixelInfo& dpi, const GraphProperties<money64>& p);
|
||||
} // namespace OpenRCT2::Graph
|
||||
|
||||
@@ -177,6 +177,8 @@ static Widget _windowFinancesResearchWidgets[] =
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Constants
|
||||
|
||||
static constexpr StringId _windowFinancesSummaryRowLabels[EnumValue(ExpenditureType::Count)] = {
|
||||
STR_FINANCES_SUMMARY_RIDE_CONSTRUCTION,
|
||||
STR_FINANCES_SUMMARY_RIDE_RUNNING_COSTS,
|
||||
@@ -217,12 +219,19 @@ static Widget _windowFinancesResearchWidgets[] =
|
||||
};
|
||||
static_assert(std::size(_windowFinancesPageHoldDownWidgets) == WINDOW_FINANCES_PAGE_COUNT);
|
||||
|
||||
static constexpr ScreenCoordsXY kGraphTopLeftPadding{ 88, 20 };
|
||||
static constexpr ScreenCoordsXY kGraphBottomRightPadding{ 15, 18 };
|
||||
static constexpr uint8_t kGraphNumYLabels = 5;
|
||||
static constexpr int32_t kGraphNumPoints = 64; // todo. was always 64 in original code.
|
||||
|
||||
#pragma endregion
|
||||
|
||||
class FinancesWindow final : public Window
|
||||
{
|
||||
private:
|
||||
uint32_t _lastPaintedMonth;
|
||||
uint32_t _lastPaintedMonth = std::numeric_limits<uint32_t>::max();
|
||||
ScreenRect _graphBounds;
|
||||
Graph::GraphProperties<money64> _graphProps{};
|
||||
|
||||
void SetDisabledTabs()
|
||||
{
|
||||
@@ -235,12 +244,23 @@ static Widget _windowFinancesResearchWidgets[] =
|
||||
SetPage(WINDOW_FINANCES_PAGE_SUMMARY);
|
||||
_lastPaintedMonth = std::numeric_limits<uint32_t>::max();
|
||||
ResearchUpdateUncompletedTypes();
|
||||
_graphProps.lineCol = colours[2];
|
||||
_graphProps.hoverIdx = -1;
|
||||
}
|
||||
|
||||
void OnUpdate() override
|
||||
{
|
||||
frame_no++;
|
||||
InvalidateWidget(WIDX_TAB_1 + page);
|
||||
|
||||
if (page == WINDOW_FINANCES_PAGE_VALUE_GRAPH || page == WINDOW_FINANCES_PAGE_PROFIT_GRAPH
|
||||
|| page == WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH)
|
||||
{
|
||||
if (_graphProps.UpdateHoverIdx())
|
||||
{
|
||||
InvalidateWidget(WIDX_BACKGROUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnMouseDown(WidgetIndex widgetIndex) override
|
||||
@@ -318,6 +338,33 @@ static Widget _windowFinancesResearchWidgets[] =
|
||||
case WINDOW_FINANCES_PAGE_RESEARCH:
|
||||
WindowResearchFundingPrepareDraw(this, WIDX_RESEARCH_FUNDING);
|
||||
break;
|
||||
case WINDOW_FINANCES_PAGE_VALUE_GRAPH:
|
||||
case WINDOW_FINANCES_PAGE_PROFIT_GRAPH:
|
||||
case WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH:
|
||||
{
|
||||
// recalculate size for graph pages only.
|
||||
Widget* pageWidget;
|
||||
switch (page)
|
||||
{
|
||||
case WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH:
|
||||
pageWidget = &_windowFinancesCashWidgets[WIDX_PAGE_BACKGROUND];
|
||||
break;
|
||||
case WINDOW_FINANCES_PAGE_VALUE_GRAPH:
|
||||
pageWidget = &_windowFinancesParkValueWidgets[WIDX_PAGE_BACKGROUND];
|
||||
break;
|
||||
case WINDOW_FINANCES_PAGE_PROFIT_GRAPH:
|
||||
pageWidget = &_windowFinancesProfitWidgets[WIDX_PAGE_BACKGROUND];
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
_graphBounds = { windowPos + ScreenCoordsXY{ pageWidget->left + 4, pageWidget->top + 15 },
|
||||
windowPos + ScreenCoordsXY{ pageWidget->right - 4, pageWidget->bottom - 4 } };
|
||||
_graphProps.RecalculateLayout(
|
||||
{ _graphBounds.Point1 + kGraphTopLeftPadding, _graphBounds.Point2 - kGraphBottomRightPadding },
|
||||
kGraphNumYLabels, kGraphNumPoints);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,16 +516,26 @@ static Widget _windowFinancesResearchWidgets[] =
|
||||
{
|
||||
width = WW_RESEARCH;
|
||||
height = WH_RESEARCH;
|
||||
flags &= ~WF_RESIZABLE;
|
||||
}
|
||||
else if (p == WINDOW_FINANCES_PAGE_SUMMARY)
|
||||
{
|
||||
width = WW_OTHER_TABS;
|
||||
height = WH_SUMMARY;
|
||||
flags &= ~WF_RESIZABLE;
|
||||
}
|
||||
else if (
|
||||
p == WINDOW_FINANCES_PAGE_VALUE_GRAPH || p == WINDOW_FINANCES_PAGE_PROFIT_GRAPH
|
||||
|| p == WINDOW_FINANCES_PAGE_FINANCIAL_GRAPH)
|
||||
{
|
||||
flags |= WF_RESIZABLE;
|
||||
WindowSetResize(*this, WW_OTHER_TABS, WH_OTHER_TABS, 2000, 2000);
|
||||
}
|
||||
else
|
||||
{
|
||||
width = WW_OTHER_TABS;
|
||||
height = WH_OTHER_TABS;
|
||||
flags &= ~WF_RESIZABLE;
|
||||
}
|
||||
OnResize();
|
||||
OnPrepareDraw();
|
||||
@@ -782,26 +839,35 @@ static Widget _windowFinancesResearchWidgets[] =
|
||||
}
|
||||
|
||||
void OnDrawGraph(
|
||||
DrawPixelInfo& dpi, const money64 currentValue, money64 (&series)[128], const StringId fmt,
|
||||
const bool centred) const
|
||||
DrawPixelInfo& dpi, const money64 currentValue, money64 (&series)[kFinanceGraphSize], const StringId fmt, const bool centred)
|
||||
{
|
||||
const Widget* pageWidget = &_windowFinancesCashWidgets[WIDX_PAGE_BACKGROUND];
|
||||
auto graphTopLeft = windowPos + ScreenCoordsXY{ pageWidget->left + 4, pageWidget->top + 15 };
|
||||
auto graphBottomRight = windowPos + ScreenCoordsXY{ pageWidget->right - 4, pageWidget->bottom - 4 };
|
||||
ScreenRect graphBounds(graphTopLeft, graphBottomRight);
|
||||
|
||||
auto ft = Formatter();
|
||||
ft.Add<money64>(currentValue);
|
||||
DrawTextBasic(dpi, graphTopLeft - ScreenCoordsXY{ 0, 11 }, fmt, ft);
|
||||
DrawTextBasic(dpi, _graphBounds.Point1 - ScreenCoordsXY{ 0, 11 }, fmt, ft);
|
||||
|
||||
// Graph
|
||||
GfxFillRectInset(dpi, graphBounds, colours[1], INSET_RECT_F_30);
|
||||
GfxFillRectInset(dpi, _graphBounds, colours[1], INSET_RECT_F_30);
|
||||
|
||||
for (int i = 0; i < 128; i++) // TODO debug
|
||||
series[i] = i % 2 * 96.00_GBP;
|
||||
// series[i] = 0;
|
||||
|
||||
Graph::DrawFinanceGraph(dpi, series, graphBounds, centred, colours[2]);
|
||||
money64 max = centred ? 12.00_GBP : 24.00_GBP;
|
||||
for (int32_t i = 0; i < kGraphNumPoints; i++)
|
||||
{
|
||||
auto val = series[i];
|
||||
if (val == kMoney64Undefined)
|
||||
continue;
|
||||
while (std::abs(val) > max)
|
||||
max *= 2;
|
||||
}
|
||||
const money64 min = centred ? -max : 0.00_GBP;
|
||||
|
||||
_graphProps.min = min;
|
||||
_graphProps.max = max;
|
||||
_graphProps.series = series;
|
||||
|
||||
Graph::DrawFinanceGraph(dpi, _graphProps);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user