25#include "table/strings.h"
63 dpi->left = dpi->top = 0;
81 if (sta->rect.IsEmpty())
continue;
85 StationID from = sta->index;
94 ConstNode &from_node = lg[sta->goods[cargo].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);
223 if (lg[ge.
node].HasEdgeTo(to->
goods[cargo].node)) {
224 ConstEdge &edge = lg[ge.
node][to->
goods[cargo].node];
229 this->cached_links[from->index][to->index]);
250 cargo.
Usage() * 32 / (cargo.
capacity + 1) < std::max(new_usg, new_plan) * 32 / (new_cap + 1)) {
251 cargo.
cargo = new_cargo;
253 cargo.
usage = new_usg;
257 if (new_shared) cargo.
shared =
true;
284 for (
const auto &j : i.second) {
287 if (!this->
IsLinkVisible(pta, ptb, dpi, width + 2))
continue;
301 uint usage_or_plan = std::min(cargo.
capacity * 2 + 1, cargo.
Usage());
304 int dash = cargo.
shared ? width * 4 : 0;
309 if (
abs(pta.
x - ptb.
x) <
abs(pta.
y - ptb.
y)) {
310 int offset_x = (pta.
y > ptb.
y ? 1 : -1) * side * width;
311 GfxDrawLine(pta.
x + offset_x, pta.
y, ptb.
x + offset_x, ptb.
y, colour, width, dash);
313 int offset_y = (pta.
x < ptb.
x ? 1 : -1) * side * width;
314 GfxDrawLine(pta.
x, pta.
y + offset_y, ptb.
x, ptb.
y + offset_y, colour, width, dash);
329 if (st ==
nullptr)
continue;
333 uint r = width * 2 + width * 2 * std::min(200U, i.second) / 200;
354 int w2 = size / 2 + size % 2;
357 GfxFillRect(x - w1 - borderwidth, y - w1 - borderwidth, x + w2 + borderwidth, y + w2 + borderwidth, border_colour);
358 GfxFillRect(x - w1, y - w1, x + w2, y + w2, colour);
361bool LinkGraphOverlay::ShowTooltip(
Point pt, TooltipCloseCondition close_cond)
363 for (
auto i(this->
cached_links.crbegin()); i != this->cached_links.crend(); ++i) {
366 for (
auto j(i->second.crbegin()); j != i->second.crend(); ++j) {
368 if (i->first == j->first)
continue;
372 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)) /
373 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));
374 const auto &link = j->second;
375 if (dist <= 4 && link.Usage() > 0 &&
376 pt.
x + 2 >= std::min(pta.
x, ptb.
x) &&
377 pt.
x - 2 <= std::max(pta.
x, ptb.
x) &&
378 pt.
y + 2 >= std::min(pta.
y, ptb.
y) &&
379 pt.
y - 2 <= std::max(pta.
y, ptb.
y)) {
380 static std::string tooltip_extension;
381 tooltip_extension.clear();
383 uint32_t back_time = 0;
386 const auto &back = k->second;
387 back_time = back.time;
388 if (back.Usage() > 0) {
389 tooltip_extension =
GetString(STR_LINKGRAPH_STATS_TOOLTIP_RETURN_EXTENSION,
390 back.cargo, back.Usage(), back.Usage() * 100 / (back.capacity + 1));
394 const auto time = link.time ? back_time ? ((link.time + back_time) / 2) : link.time : back_time;
397 AppendStringWithArgsInPlace(tooltip_extension, STR_LINKGRAPH_STATS_TOOLTIP_TIME_EXTENSION, params);
401 link.cargo, link.Usage(), i->first, j->first, link.Usage() * 100 / (link.capacity + 1), tooltip_extension),
418 if (this->
window->viewport !=
nullptr) {
419 return GetViewportStationMiddle(*this->
window->viewport, st);
454std::unique_ptr<NWidgetBase> MakeSaturationLegendLinkGraphGUI()
458 auto wid = std::make_unique<NWidgetBackground>(
WWT_PANEL, COLOUR_DARK_GREEN, i + WID_LGL_SATURATION_FIRST);
459 wid->SetMinimalSize(50, 0);
460 wid->SetMinimalTextLines(1, 0,
FS_SMALL);
462 wid->SetResize(0, 0);
463 panel->Add(std::move(wid));
468std::unique_ptr<NWidgetBase> MakeCargoesLegendLinkGraphGUI()
471 static const uint ENTRIES_PER_COL = 5;
473 std::unique_ptr<NWidgetVertical> col =
nullptr;
475 for (uint i = 0; i < num_cargo; ++i) {
476 if (i % ENTRIES_PER_COL == 0) {
477 if (col !=
nullptr) panel->Add(std::move(col));
480 auto wid = std::make_unique<NWidgetBackground>(
WWT_PANEL, COLOUR_GREY, i + WID_LGL_CARGO_FIRST);
481 wid->SetMinimalSize(25, 0);
482 wid->SetMinimalTextLines(1, 0,
FS_SMALL);
484 wid->SetResize(0, 0);
485 col->Add(std::move(wid));
488 for (uint i = num_cargo; i <
Ceil(num_cargo, ENTRIES_PER_COL); ++i) {
489 auto spc = std::make_unique<NWidgetSpacer>(25, 0);
490 spc->SetMinimalTextLines(1, 0,
FS_SMALL);
492 spc->SetResize(0, 0);
493 col->Add(std::move(spc));
496 if (col !=
nullptr) panel->Add(std::move(col));
501static constexpr std::initializer_list<NWidgetPart> _nested_linkgraph_legend_widgets = {
531static_assert(WID_LGL_SATURATION_LAST - WID_LGL_SATURATION_FIRST ==
535 WDP_AUTO,
"toolbar_linkgraph", 0, 0,
538 _nested_linkgraph_legend_widgets
551 this->InitNested(window_number);
552 this->InvalidateData(0);
562 this->overlay = std::move(overlay);
563 CompanyMask companies = this->overlay->GetCompanyMask();
564 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
569 CargoTypes cargoes = this->overlay->GetCargoMask();
570 for (uint c = 0; c < this->num_cargo; c++) {
577 if (
IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) {
579 if (widget == WID_LGL_SATURATION_FIRST) {
580 str = STR_LINKGRAPH_LEGEND_UNUSED;
581 }
else if (widget == WID_LGL_SATURATION_LAST) {
582 str = STR_LINKGRAPH_LEGEND_OVERLOADED;
583 }
else if (widget == (WID_LGL_SATURATION_LAST + WID_LGL_SATURATION_FIRST) / 2) {
584 str = STR_LINKGRAPH_LEGEND_SATURATED;
586 if (str != STR_NULL) {
588 dim.width += padding.width;
589 dim.height += padding.height;
593 if (
IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) {
596 dim.width += padding.width;
597 dim.height += padding.height;
605 if (
IsInsideMM(widget, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST + 1)) {
607 CompanyID cid = (CompanyID)(widget - WID_LGL_COMPANY_FIRST);
611 if (
IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) {
615 if (widget == WID_LGL_SATURATION_FIRST) {
616 str = STR_LINKGRAPH_LEGEND_UNUSED;
617 }
else if (widget == WID_LGL_SATURATION_LAST) {
618 str = STR_LINKGRAPH_LEGEND_OVERLOADED;
619 }
else if (widget == (WID_LGL_SATURATION_LAST + WID_LGL_SATURATION_FIRST) / 2) {
620 str = STR_LINKGRAPH_LEGEND_SATURATED;
622 if (str != STR_NULL) {
626 if (
IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) {
629 DrawString(br.left, br.right,
CentreBounds(br.top, br.bottom,
GetCharacterHeight(
FS_SMALL)), cargo->
abbrev,
GetContrastColour(cargo->legend_colour, 73),
SA_HOR_CENTER,
false,
FS_SMALL);
635 if (
IsInsideMM(widget, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST + 1)) {
641 STR_LINKGRAPH_LEGEND_SELECT_COMPANIES,
642 widget - WID_LGL_COMPANY_FIRST),
647 if (
IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) {
661 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
666 this->overlay->SetCompanyMask(mask);
675 for (uint c = 0; c < num_cargo; c++) {
679 this->overlay->SetCargoMask(mask);
685 if (
IsInsideMM(widget, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST + 1)) {
690 }
else if (widget == WID_LGL_COMPANIES_ALL || widget == WID_LGL_COMPANIES_NONE) {
691 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
697 }
else if (
IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) {
700 }
else if (widget == WID_LGL_CARGOES_ALL || widget == WID_LGL_CARGOES_NONE) {
701 for (uint c = 0; c < this->num_cargo; c++) {
722 for (CompanyID i = CompanyID::Begin(); i < MAX_COMPANIES; ++i) {
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
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.
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.
static void DrawVertex(int x, int y, int size, PixelColour colour, PixelColour border_colour)
Draw a square symbolizing a producer of cargo.
void SetCompanyMask(CompanyMask company_mask)
Set a new company mask and rebuild the cache.
static const PixelColour LINK_COLOURS[][12]
Colours for the various "load" states of links.
static void AddStats(CargoType 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.
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.
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.
Definition of stuff that is very close to a company, like the company struct itself.
void DrawCompanyIcon(CompanyID c, int x, int y)
Draw the icon of a company.
GUI Functions related to companies.
static constexpr Owner OWNER_NONE
The tile has no ownership.
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.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
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, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
@ FS_SMALL
Index of the small font in the font tables.
@ SA_HOR_CENTER
Horizontally center the text.
@ 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.
#define Point
Macro that prevents name conflicts between included headers.
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
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.
void GuiShowTooltips(Window *parent, EncodedString &&text, TooltipCloseCondition close_tooltip)
Shows a tooltip.
TextColour GetContrastColour(PixelColour background, uint8_t threshold)
Determine a contrasty text colour for a coloured background.
PixelColour GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
A number of safeguards to prevent using unsafe methods.
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.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Functions related to OTTD's strings.
auto MakeParameters(Args &&... args)
Helper to create the StringParameters with its own buffer with the given parameter values.
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.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
StringID abbrev
Two letter abbreviation for this cargo type.
StringID name
Name of this type of cargo.
Dimensions (a width and height) of a rectangle in 2D.
Data about how and where to blit pixels.
FlowStatMap flows
Planned flows through this station.
Stores station stats for a single cargo.
NodeID node
ID of node in link graph referring to this goods entry.
const GoodsEntryData & GetData() const
Get optional cargo packet/flow data.
LinkGraphID link_graph
Link graph this station belongs to.
bool HasData() const
Test if this goods entry has optional cargo packet/flow data.
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 OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
bool OnTooltip(Point pt, WidgetID widget, TooltipCloseCondition close_cond) override
Event to display a custom tooltip.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void UpdateOverlayCargoes()
Update the overlay with the new cargo selection.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
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.
CargoType 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.
Colour for pixel/line drawing.
static LinkGraph * Get(auto index)
static bool IsValidID(auto index)
Specification of a rectangle with absolute coordinates of all edges.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
static bool IsValidID(auto index)
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
static Station * Get(auto index)
static Station * GetIfValid(auto index)
std::array< GoodsEntry, NUM_CARGO > goods
Goods at this station.
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.
ResizeInfo resize
Resize information.
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.
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.
Definition of the game-calendar-timer.
Definition of the tick-based game-timer.
Functions related to (drawing on) viewports.
Window * GetMainWindow()
Get the main window, i.e.
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
Twindow * AllocateWindowDescFront(WindowDesc &desc, WindowNumber window_number, Targs... extra_arguments)
Open a new window.
@ WDP_AUTO
Find a place automatically.
@ WC_LINKGRAPH_LEGEND
Linkgraph legend; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Functions related to zooming.