10 #include "../stdafx.h"
11 #include "../window_gui.h"
12 #include "../window_func.h"
13 #include "../company_base.h"
14 #include "../company_gui.h"
15 #include "../timer/timer_game_tick.h"
16 #include "../timer/timer_game_calendar.h"
17 #include "../viewport_func.h"
18 #include "../zoom_func.h"
19 #include "../smallmap_gui.h"
20 #include "../core/geometry_func.hpp"
21 #include "../widgets/link_graph_legend_widget.h"
22 #include "../strings_func.h"
25 #include "table/strings.h"
27 #include "../safeguards.h"
35 0x0f, 0xd1, 0xd0, 0x57,
36 0x55, 0x53, 0xbf, 0xbd,
37 0xba, 0xb9, 0xb7, 0xb5
40 0x0f, 0xd1, 0xd0, 0x57,
41 0x55, 0x53, 0x96, 0x95,
42 0x94, 0x93, 0x92, 0x91
45 0x0f, 0x0b, 0x09, 0x07,
46 0x05, 0x03, 0xbf, 0xbd,
47 0xba, 0xb9, 0xb7, 0xb5
50 0x0f, 0x0b, 0x0a, 0x09,
51 0x08, 0x07, 0x06, 0x05,
52 0x04, 0x03, 0x02, 0x01
63 dpi->left = dpi->top = 0;
81 if (sta->rect.IsEmpty())
continue;
85 StationID from = sta->index;
94 ConstNode &from_node = lg[sta->goods[c].node];
96 for (
const Edge &edge : from_node.
edges) {
97 StationID to = lg[edge.
dest_node].station;
107 if (stb->
rect.IsEmpty())
continue;
130 return pt.x > dpi->left - padding && pt.y > dpi->top - padding &&
131 pt.x < dpi->left + dpi->width + padding &&
132 pt.y < dpi->top + dpi->height + padding;
145 const int left = dpi->left - padding;
146 const int right = dpi->left + dpi->width + padding;
147 const int top = dpi->top - padding;
148 const int bottom = dpi->top + dpi->height + padding;
155 const uint8_t INSIDE = 0;
156 const uint8_t LEFT = 1;
157 const uint8_t RIGHT = 2;
158 const uint8_t BOTTOM = 4;
159 const uint8_t TOP = 8;
166 auto out_code = [&](
int x,
int y) -> uint8_t {
167 uint8_t out = INSIDE;
170 }
else if (x > right) {
175 }
else if (y > bottom) {
181 uint8_t c0 = out_code(x0, y0);
182 uint8_t c1 = out_code(x1, y1);
185 if (c0 == 0 || c1 == 0)
return true;
186 if ((c0 & c1) != 0)
return false;
189 x0 = x0 + (int)(((int64_t) (x1 - x0)) * ((int64_t) (top - y0)) / ((int64_t) (y1 - y0)));
191 }
else if (c0 & BOTTOM) {
192 x0 = x0 + (int)(((int64_t) (x1 - x0)) * ((int64_t) (bottom - y0)) / ((int64_t) (y1 - y0)));
194 }
else if (c0 & RIGHT) {
195 y0 = y0 + (int)(((int64_t) (y1 - y0)) * ((int64_t) (right - x0)) / ((int64_t) (x1 - x0)));
197 }
else if (c0 & LEFT) {
198 y0 = y0 + (int)(((int64_t) (y1 - y0)) * ((int64_t) (left - x0)) / ((int64_t) (x1 - x0)));
202 c0 = out_code(x0, y0);
248 cargo.
Usage() * 32 / (cargo.
capacity + 1) < std::max(new_usg, new_plan) * 32 / (new_cap + 1)) {
249 cargo.
cargo = new_cargo;
251 cargo.
usage = new_usg;
255 if (new_shared) cargo.
shared =
true;
282 for (
const auto &j : i.second) {
285 if (!this->
IsLinkVisible(pta, ptb, dpi, width + 2))
continue;
299 uint usage_or_plan = std::min(cargo.
capacity * 2 + 1, cargo.
Usage());
302 int dash = cargo.
shared ? width * 4 : 0;
307 if (
abs(pta.x - ptb.x) <
abs(pta.y - ptb.y)) {
308 int offset_x = (pta.y > ptb.y ? 1 : -1) * side * width;
309 GfxDrawLine(pta.x + offset_x, pta.y, ptb.x + offset_x, ptb.y, colour, width, dash);
311 int offset_y = (pta.x < ptb.x ? 1 : -1) * side * width;
312 GfxDrawLine(pta.x, pta.y + offset_y, ptb.x, ptb.y + offset_y, colour, width, dash);
315 GfxDrawLine(pta.x, pta.y, ptb.x, ptb.y,
GetColourGradient(COLOUR_GREY, SHADE_DARKEST), width);
327 if (st ==
nullptr)
continue;
331 uint r = width * 2 + width * 2 * std::min(200U, i.second) / 200;
352 int w2 = size / 2 + size % 2;
355 GfxFillRect(x - w1 - borderwidth, y - w1 - borderwidth, x + w2 + borderwidth, y + w2 + borderwidth, border_colour);
356 GfxFillRect(x - w1, y - w1, x + w2, y + w2, colour);
359 bool LinkGraphOverlay::ShowTooltip(
Point pt, TooltipCloseCondition close_cond)
361 for (
auto i(this->
cached_links.crbegin()); i != this->cached_links.crend(); ++i) {
364 for (
auto j(i->second.crbegin()); j != i->second.crend(); ++j) {
366 if (i->first == j->first)
continue;
370 float dist =
std::abs((int64_t)(ptb.x - pta.x) * (int64_t)(pta.y - pt.y) - (int64_t)(pta.x - pt.x) * (int64_t)(ptb.y - pta.y)) /
371 std::sqrt((int64_t)(ptb.x - pta.x) * (int64_t)(ptb.x - pta.x) + (int64_t)(ptb.y - pta.y) * (int64_t)(ptb.y - pta.y));
372 const auto &link = j->second;
373 if (dist <= 4 && link.Usage() > 0 &&
374 pt.x + 2 >= std::min(pta.x, ptb.x) &&
375 pt.x - 2 <= std::max(pta.x, ptb.x) &&
376 pt.y + 2 >= std::min(pta.y, ptb.y) &&
377 pt.y - 2 <= std::max(pta.y, ptb.y)) {
378 static std::string tooltip_extension;
379 tooltip_extension.clear();
381 uint32_t back_time = 0;
384 const auto &back = k->second;
385 back_time = back.time;
386 if (back.Usage() > 0) {
389 SetDParam(2, back.Usage() * 100 / (back.capacity + 1));
390 tooltip_extension =
GetString(STR_LINKGRAPH_STATS_TOOLTIP_RETURN_EXTENSION);
394 const auto time = link.time ? back_time ? ((link.time + back_time) / 2) : link.time : back_time;
403 SetDParam(4, link.Usage() * 100 / (link.capacity + 1));
459 std::unique_ptr<NWidgetBase> MakeSaturationLegendLinkGraphGUI()
461 auto panel = std::make_unique<NWidgetVertical>(
NC_EQUALSIZE);
463 auto wid = std::make_unique<NWidgetBackground>(
WWT_PANEL, COLOUR_DARK_GREEN, i + WID_LGL_SATURATION_FIRST);
464 wid->SetMinimalSize(50, 0);
465 wid->SetMinimalTextLines(1, 0,
FS_SMALL);
467 wid->SetResize(0, 0);
468 panel->Add(std::move(wid));
473 std::unique_ptr<NWidgetBase> MakeCargoesLegendLinkGraphGUI()
476 static const uint ENTRIES_PER_COL = 5;
477 auto panel = std::make_unique<NWidgetHorizontal>(
NC_EQUALSIZE);
478 std::unique_ptr<NWidgetVertical> col =
nullptr;
480 for (uint i = 0; i < num_cargo; ++i) {
481 if (i % ENTRIES_PER_COL == 0) {
482 if (col !=
nullptr) panel->Add(std::move(col));
485 auto wid = std::make_unique<NWidgetBackground>(
WWT_PANEL, COLOUR_GREY, i + WID_LGL_CARGO_FIRST);
486 wid->SetMinimalSize(25, 0);
487 wid->SetMinimalTextLines(1, 0,
FS_SMALL);
489 wid->SetResize(0, 0);
490 col->Add(std::move(wid));
493 for (uint i = num_cargo; i <
Ceil(num_cargo, ENTRIES_PER_COL); ++i) {
494 auto spc = std::make_unique<NWidgetSpacer>(25, 0);
495 spc->SetMinimalTextLines(1, 0,
FS_SMALL);
497 spc->SetResize(0, 0);
498 col->Add(std::move(spc));
501 if (col !=
nullptr) panel->Add(std::move(col));
506 static constexpr
NWidgetPart _nested_linkgraph_legend_widgets[] = {
536 static_assert(WID_LGL_SATURATION_LAST - WID_LGL_SATURATION_FIRST ==
540 WDP_AUTO,
"toolbar_linkgraph", 0, 0,
543 _nested_linkgraph_legend_widgets
551 AllocateWindowDescFront<LinkGraphLegendWindow>(_linkgraph_legend_desc, 0);
554 LinkGraphLegendWindow::LinkGraphLegendWindow(
WindowDesc &desc,
int window_number) :
Window(desc)
558 this->InitNested(window_number);
559 this->InvalidateData(0);
569 this->overlay = overlay;
570 CompanyMask companies = this->overlay->GetCompanyMask();
576 CargoTypes cargoes = this->overlay->GetCargoMask();
577 for (uint c = 0; c < this->num_cargo; c++) {
584 if (
IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) {
586 if (widget == WID_LGL_SATURATION_FIRST) {
587 str = STR_LINKGRAPH_LEGEND_UNUSED;
588 }
else if (widget == WID_LGL_SATURATION_LAST) {
589 str = STR_LINKGRAPH_LEGEND_OVERLOADED;
590 }
else if (widget == (WID_LGL_SATURATION_LAST + WID_LGL_SATURATION_FIRST) / 2) {
591 str = STR_LINKGRAPH_LEGEND_SATURATED;
593 if (str != STR_NULL) {
595 dim.width += padding.width;
596 dim.height += padding.height;
600 if (
IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) {
603 dim.width += padding.width;
604 dim.height += padding.height;
609 void LinkGraphLegendWindow::DrawWidget(
const Rect &r,
WidgetID widget)
const
612 if (
IsInsideMM(widget, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST + 1)) {
618 if (
IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) {
622 if (widget == WID_LGL_SATURATION_FIRST) {
623 str = STR_LINKGRAPH_LEGEND_UNUSED;
624 }
else if (widget == WID_LGL_SATURATION_LAST) {
625 str = STR_LINKGRAPH_LEGEND_OVERLOADED;
626 }
else if (widget == (WID_LGL_SATURATION_LAST + WID_LGL_SATURATION_FIRST) / 2) {
627 str = STR_LINKGRAPH_LEGEND_SATURATED;
629 if (str != STR_NULL) {
633 if (
IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) {
636 DrawString(br.left, br.right,
CenterBounds(br.top, br.bottom,
GetCharacterHeight(
FS_SMALL)), cargo->
abbrev,
GetContrastColour(cargo->legend_colour, 73),
SA_HOR_CENTER,
false,
FS_SMALL);
640 bool LinkGraphLegendWindow::OnTooltip([[maybe_unused]]
Point,
WidgetID widget, TooltipCloseCondition close_cond)
642 if (
IsInsideMM(widget, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST + 1)) {
644 GuiShowTooltips(
this, STR_LINKGRAPH_LEGEND_SELECT_COMPANIES, close_cond);
646 SetDParam(0, STR_LINKGRAPH_LEGEND_SELECT_COMPANIES);
648 GuiShowTooltips(
this, STR_LINKGRAPH_LEGEND_COMPANY_TOOLTIP, close_cond, 2);
652 if (
IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) {
671 this->overlay->SetCompanyMask(mask);
680 for (uint c = 0; c < num_cargo; c++) {
684 this->overlay->SetCargoMask(mask);
687 void LinkGraphLegendWindow::OnClick([[maybe_unused]]
Point pt,
WidgetID widget, [[maybe_unused]]
int click_count)
690 if (
IsInsideMM(widget, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST + 1)) {
695 }
else if (widget == WID_LGL_COMPANIES_ALL || widget == WID_LGL_COMPANIES_NONE) {
702 }
else if (
IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) {
705 }
else if (widget == WID_LGL_CARGOES_ALL || widget == WID_LGL_CARGOES_NONE) {
706 for (uint c = 0; c < this->num_cargo; c++) {
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
uint GetFlowVia(StationID via) const
Get the sum of flows via a specific station from this FlowStatMap.
bool IsPointVisible(Point pt, const DrawPixelInfo *dpi, int padding=0) const
Determine if a certain point is inside the given DPI, with some lee way.
void SetCargoMask(CargoTypes cargo_mask)
Set a new cargo mask and rebuild the cache.
CargoTypes cargo_mask
Bitmask of cargos to be displayed.
static void DrawVertex(int x, int y, int size, int colour, int border_colour)
Draw a square symbolizing a producer of cargo.
Window * window
Window to be drawn into.
void DrawLinks(const DrawPixelInfo *dpi) const
Draw the cached links or part of them into the given area.
void SetCompanyMask(CompanyMask company_mask)
Set a new company mask and rebuild the cache.
static const uint8_t LINK_COLOURS[][12]
Colours for the various "load" states of links.
StationSupplyList cached_stations
Cache for stations to be drawn.
LinkMap cached_links
Cache for links to reduce recalculation.
bool IsLinkVisible(Point pta, Point ptb, const DrawPixelInfo *dpi, int padding=0) const
Determine if a certain link crosses through the area given by the dpi with some lee way.
Point GetStationMiddle(const Station *st) const
Determine the middle of a station in the current window.
void Draw(const DrawPixelInfo *dpi)
Draw the linkgraph overlay or some part of it, in the area given.
bool dirty
Set if overlay should be rebuilt.
const WidgetID widget_id
ID of Widget in Window to be drawn to.
void DrawContent(Point pta, Point ptb, const LinkProperties &cargo) const
Draw one specific link.
CompanyMask company_mask
Bitmask of companies to be displayed.
uint scale
Width of link lines.
void GetWidgetDpi(DrawPixelInfo *dpi) const
Get a DPI for the widget we will be drawing to.
static void AddStats(CargoID new_cargo, uint new_cap, uint new_usg, uint new_flow, uint32_t time, bool new_shared, LinkProperties &cargo)
Add information from a given pair of link stat and flow stat to the given link properties.
void AddLinks(const Station *sta, const Station *stb)
Add all "interesting" links between the given stations to the cache.
void DrawStationDots(const DrawPixelInfo *dpi) const
Draw dots for stations into the smallmap.
void SetDirty()
Mark the linkgraph dirty to be rebuilt next time Draw() is called.
void RebuildCache()
Rebuild the cache and recalculate which links and stations to be shown.
A connected component of a link graph.
uint Monthly(uint base) const
Scale a value to its monthly equivalent, based on last compression.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
void DrawCompanyIcon(CompanyID c, int x, int y)
Draw the icon of a company.
Owner
Enum for all companies/owners.
@ COMPANY_FIRST
First company, same as owner.
@ OWNER_NONE
The tile has no ownership.
@ MAX_COMPANIES
Maximum number of companies.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
@ SA_HOR_CENTER
Horizontally center the text.
@ FS_SMALL
Index of the small font in the font tables.
@ TC_FORCED
Ignore colour changes from strings.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
std::unique_ptr< NWidgetBase > MakeCompanyButtonRowsLinkGraphGUI()
Make a number of rows with buttons for each company for the linkgraph legend window.
void ShowLinkGraphLegend()
Open a link graph legend window.
Declaration of linkgraph overlay GUI.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
constexpr uint Ceil(uint a, uint b)
Computes ceil(a / b) * b for non-negative a and b.
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
void GuiShowTooltips(Window *parent, StringID str, TooltipCloseCondition close_tooltip, uint paramcount)
Shows a tooltip.
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
TextColour GetContrastColour(uint8_t background, uint8_t threshold)
Determine a contrasty text colour for a coloured background.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
ClientSettings _settings_client
The current settings for this game.
Point GetSmallMapStationMiddle(const Window *w, const Station *st)
Determine the middle of a station in the smallmap window.
#define lengthof(array)
Return the length of an fixed size array.
void AppendStringInPlace(std::string &result, StringID string)
Resolve the given StringID and append in place into an existing std::string with all the associated D...
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Owner owner
The owner of this station.
StationRect rect
NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions.
Specification of a cargo type.
StringID abbrev
Two letter abbreviation for this cargo type.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo ID.
StringID name
Name of this type of cargo.
GUISettings gui
settings related to the GUI
Dimensions (a width and height) of a rectangle in 2D.
Data about how and where to blit pixels.
uint8_t linkgraph_colours
linkgraph overlay colours
VehicleSettings vehicle
options for vehicles
Stores station stats for a single cargo.
FlowStatMap flows
Planned flows through this station.
NodeID node
ID of node in link graph referring to this goods entry.
LinkGraphID link_graph
Link graph this station belongs to.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Invalidate the data of this window if the cargoes or companies have changed.
void SetOverlay(std::shared_ptr< LinkGraphOverlay > overlay)
Set the overlay belonging to this menu and import its company/cargo settings.
void UpdateOverlayCompanies()
Update the overlay with the new company selection.
void UpdateOverlayCargoes()
Update the overlay with the new cargo selection.
An edge in the link graph.
uint32_t TravelTime() const
Get edge's average travel time.
NodeID dest_node
Destination of the edge.
uint usage
Usage of the link.
uint capacity
Capacity of the link.
std::vector< BaseEdge > edges
Sorted list of outgoing edges from this node.
uint supply
Supply at the station.
Monthly statistics for a link between two stations.
uint usage
Actual usage of the link.
bool shared
If this is a shared link to be drawn dashed.
CargoID cargo
Cargo type of the link.
uint planned
Planned usage of the link.
uint Usage() const
Return the usage of the link to display.
uint capacity
Capacity of the link.
uint32_t time
Travel time of the link.
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
static Titem * Get(size_t index)
Returns Titem with given index.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Specification of a rectangle with absolute coordinates of all edges.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Iterable ensemble of each set bit in a value.
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
static Station * Get(size_t index)
Gets station with given index.
static bool IsValidID(size_t index)
Tests whether given index is a valid index for station of this type.
GoodsEntry goods[NUM_CARGO]
Goods at this station.
uint8_t road_side
the side of the road vehicles drive on
High level window description.
Data structure for an opened window.
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
ViewportData * viewport
Pointer to viewport data, if present.
bool IsWidgetLowered(WidgetID widget_index) const
Gets the lowered state of a widget.
bool IsWidgetDisabled(WidgetID widget_index) const
Gets the enabled/disabled status of a widget.
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
void ToggleWidgetLoweredState(WidgetID widget_index)
Invert the lowered/raised status of a widget.
Window * GetMainWindow()
Get the main window, i.e.
@ WDP_AUTO
Find a place automatically.
@ WC_LINKGRAPH_LEGEND
Linkgraph legend; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.