25#include "table/strings.h"
32static std::string GetStringForWidget(
const Window *w,
const NWidgetCore *nwid,
bool secondary =
false)
35 if (nwid->GetIndex() < 0) {
36 if (stringid == STR_NULL)
return {};
38 return GetString(stringid + (secondary ? 1 : 0));
41 return w->
GetWidgetString(nwid->GetIndex(), stringid + (secondary ? 1 : 0));
126 case SA_LEFT: p.x = r.left;
break;
128 case SA_RIGHT: p.x = r.right + 1 - d.width;
break;
129 default: NOT_REACHED();
132 case SA_TOP: p.y = r.top;
break;
134 case SA_BOTTOM: p.y = r.bottom + 1 - d.height;
break;
135 default: NOT_REACHED();
152 int rev_base = top + bottom;
155 button_size = NWidgetScrollbar::GetHorizontalDimension().width;
157 button_size = NWidgetScrollbar::GetVerticalDimension().height;
160 bottom -= button_size;
166 int height = bottom + 1 - top;
167 int slider_height = std::max(button_size, cap * height / count);
168 height -= slider_height;
171 bottom = top + slider_height - 1;
176 pt.x = rev_base - bottom;
177 pt.y = rev_base - top;
199 bool changed =
false;
204 button_size = NWidgetScrollbar::GetHorizontalDimension().width;
207 button_size = NWidgetScrollbar::GetVerticalDimension().height;
209 if (pos < mi + button_size) {
212 if (_scroller_click_timeout <= 1) {
213 _scroller_click_timeout = 3;
217 }
else if (pos >= ma - button_size) {
221 if (_scroller_click_timeout <= 1) {
222 _scroller_click_timeout = 3;
231 }
else if (pos > pt.y) {
234 _scrollbar_start_pos = pt.x - mi - button_size;
235 _scrollbar_size = ma - mi - button_size * 2 - (pt.y - pt.x);
237 _cursorpos_drag_start = _cursor.
pos;
271 assert(scrollbar !=
nullptr);
286 return (nw !=
nullptr) ? nw->GetIndex() : -1;
303 assert(colour < COLOUR_END);
311 Rect outer = {left, top, right, bottom};
315 GfxFillRect(outer.left, outer.top, inner.left - 1, outer.bottom, dark);
316 GfxFillRect(inner.left, outer.top, outer.right, inner.top - 1, dark);
317 GfxFillRect(inner.right + 1, inner.top, outer.right, inner.bottom, light);
318 GfxFillRect(inner.left, inner.bottom + 1, outer.right, outer.bottom, light);
321 GfxFillRect(outer.left, outer.top, inner.left - 1, inner.bottom, light);
322 GfxFillRect(inner.left, outer.top, inner.right, inner.top - 1, light);
323 GfxFillRect(inner.right + 1, outer.top, outer.right, inner.bottom, dark);
324 GfxFillRect(outer.left, inner.bottom + 1, outer.right, outer.bottom, dark);
325 interior = medium_dark;
328 GfxFillRect(inner.left, inner.top, inner.right, inner.bottom, interior);
338 d.height -= offset.y;
341 DrawSprite(img, pal, p.x - offset.x, p.y - offset.y);
358 if ((type & WWT_MASK) ==
WWT_IMGBTN_2 && clicked) img++;
359 DrawSpriteIgnorePadding(img, PAL_NONE, r, align);
389 DrawString(r_text.left, r_text.right, p.y, text, text_colour, align,
false, fs);
403 if (str.empty())
return;
407 DrawString(r.left, r.right, p.y, str, colour, align,
false, fs);
420 if (str.empty())
return;
424 DrawString(r.left, r.right, p.y, str, colour, align,
false, fs);
438 DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, {FrameFlag::Lowered, FrameFlag::Darkened});
452static inline void DrawMatrix(
const Rect &r, Colours colour,
bool clicked, uint32_t num_columns, uint32_t num_rows, uint resize_x, uint resize_y)
457 if (num_columns == 0) {
458 column_width = resize_x;
459 num_columns = r.
Width() / column_width;
461 column_width = r.
Width() / num_columns;
466 row_height = resize_y;
467 num_rows = r.
Height() / row_height;
469 row_height = r.
Height() / num_rows;
475 for (
int ctr = num_columns; ctr > 1; ctr--) {
481 for (
int ctr = num_rows; ctr > 1; ctr--) {
489 for (
int ctr = num_columns; ctr > 1; ctr--) {
495 for (
int ctr = num_rows; ctr > 1; ctr--) {
452static inline void DrawMatrix(
const Rect &r, Colours colour,
bool clicked, uint32_t num_columns, uint32_t num_rows, uint resize_x, uint resize_y) {
…}
512 int height = NWidgetScrollbar::GetVerticalDimension().height;
522 GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c2);
526 int left = r.left + r.
Width() * 3 / 11;
527 int right = r.left + r.
Width() * 8 / 11;
532 GfxFillRect(left - bl, r.top + height, left - 1, r.bottom - height, c1);
533 GfxFillRect(left, r.top + height, left + br - 1, r.bottom - height, c2);
534 GfxFillRect(right - bl, r.top + height, right - 1, r.bottom - height, c1);
535 GfxFillRect(right, r.top + height, right + br - 1, r.bottom - height, c2);
552 int width = NWidgetScrollbar::GetHorizontalDimension().width;
561 GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c2);
565 int top = r.top + r.
Height() * 3 / 11;
566 int bottom = r.top + r.
Height() * 8 / 11;
571 GfxFillRect(r.left + width, top - bt, r.right - width, top - 1, c1);
572 GfxFillRect(r.left + width, top, r.right - width, top + bb - 1, c2);
573 GfxFillRect(r.left + width, bottom - bt, r.right - width, bottom - 1, c1);
574 GfxFillRect(r.left + width, bottom, r.right - width, bottom + bb - 1, c2);
625 GfxFillRect(outer.left, inner.top, inner.left - 1, inner.bottom, c1);
626 GfxFillRect(inner.left, inside.top, inside.left - 1, inside.bottom, c2);
629 GfxFillRect(inside.right + 1, inner.top, inner.right, inside.bottom, c1);
630 GfxFillRect(inner.right + 1, outer.top, outer.right, inner.bottom, c2);
633 GfxFillRect(inner.left, inside.bottom + 1, inner.right, inner.bottom, c1);
634 GfxFillRect(outer.left, inner.bottom + 1, outer.right, outer.bottom, c2);
689static inline void DrawResizeBox(
const Rect &r, Colours colour,
bool at_left,
bool clicked,
bool bevel)
693 }
else if (clicked) {
689static inline void DrawResizeBox(
const Rect &r, Colours colour,
bool at_left,
bool clicked,
bool bevel) {
…}
706 if (colour != COLOUR_WHITE)
DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, {});
710 d.height -= offset.y;
727 bool company_owned = owner < MAX_COMPANIES;
737 if (str.empty())
return;
789 if (!widget->IsHighlighted())
continue;
791 Rect outer = widget->GetCurrentRect();
796 GfxFillRect(outer.left, outer.top, inner.left, inner.bottom, colour);
797 GfxFillRect(inner.left + 1, outer.top, inner.right - 1, inner.top, colour);
798 GfxFillRect(inner.right, outer.top, outer.right, inner.bottom, colour);
799 GfxFillRect(outer.left + 1, inner.bottom, outer.right - 1, outer.bottom, colour);
814 Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect();
817 Dimension dim = NWidgetScrollbar::GetVerticalDimension();
828 return NWidgetScrollbar::GetVerticalDimension().width + 1;
831bool _draw_widget_outlines;
928 if (this->
index >= 0) widget_lookup[this->
index] =
this;
964 return (this->
type == tp) ? this :
nullptr;
967void NWidgetBase::ApplyAspectRatio()
981void NWidgetBase::AdjustPaddingForZoom()
1017 this->
SetAspect(
static_cast<float>(x_ratio) /
static_cast<float>(y_ratio), flags);
1020void NWidgetResizeBase::AdjustPaddingForZoom()
1026 NWidgetBase::AdjustPaddingForZoom();
1050 this->min_x = std::max(this->min_x,
min_x);
1051 this->min_y = std::max(this->min_y,
min_y);
1103 d.height *= max_lines;
1119 if (
min_x == this->min_x &&
min_y == this->min_y)
return false;
1120 this->min_x =
min_x;
1121 this->min_y =
min_y;
1133 if (
min_y == this->min_y)
return false;
1134 this->min_y =
min_y;
1255 this->align =
align;
1283 if (this->
type == tp)
return this;
1284 for (
const auto &child_wid : this->
children) {
1286 if (nwid !=
nullptr)
return nwid;
1291void NWidgetContainer::AdjustPaddingForZoom()
1293 for (
const auto &child_wid : this->
children) {
1294 child_wid->AdjustPaddingForZoom();
1296 NWidgetBase::AdjustPaddingForZoom();
1305 assert(wid !=
nullptr);
1307 this->
children.push_back(std::move(wid));
1313 for (
const auto &child_wid : this->
children) {
1314 child_wid->FillWidgetLookup(widget_lookup);
1320 for (
const auto &child_wid : this->
children) {
1324 DrawOutline(w,
this);
1331 for (
const auto &child_wid : this->
children) {
1333 if (nwid !=
nullptr)
return nwid;
1351 this->
fill_x = fill.width;
1352 this->
fill_y = fill.height;
1355 this->ApplyAspectRatio();
1366 for (
const auto &child_wid : this->
children) {
1367 child_wid->SetupSmallestSize(w);
1369 this->
smallest_x = std::max(this->
smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1370 this->
smallest_y = std::max(this->
smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1371 this->
fill_x = std::lcm(this->
fill_x, child_wid->fill_x);
1372 this->
fill_y = std::lcm(this->
fill_y, child_wid->fill_y);
1375 this->ApplyAspectRatio();
1386 for (
const auto &child_wid : this->
children) {
1387 uint hor_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
1388 uint child_width =
ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step);
1389 uint child_pos_x = (rtl ? child_wid->padding.right : child_wid->padding.left);
1391 uint vert_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
1392 uint child_height =
ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding.Vertical(), vert_step);
1393 uint child_pos_y = child_wid->padding.top;
1395 child_wid->AssignSizePosition(sizing, x + child_pos_x, y + child_pos_y, child_width, child_height, rtl);
1415 DrawOutline(w,
this);
1461 for (
const auto &child_wid : this->
children) {
1462 child_wid->SetupSmallestSize(w);
1464 this->
smallest_x = std::max(this->
smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1465 this->
smallest_y = std::max(this->
smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1466 this->
fill_x = std::lcm(this->
fill_x, child_wid->fill_x);
1467 this->
fill_y = std::lcm(this->
fill_y, child_wid->fill_y);
1470 this->ApplyAspectRatio();
1479 for (
const auto &child_wid : this->
children) {
1480 uint hor_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
1481 uint child_width =
ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step);
1482 uint child_pos_x = (rtl ? child_wid->padding.right : child_wid->padding.left);
1484 uint vert_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
1485 uint child_height =
ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding.Vertical(), vert_step);
1486 uint child_pos_y = child_wid->padding.top;
1488 child_wid->AssignSizePosition(sizing, x + child_pos_x, y + child_pos_y, child_width, child_height, rtl);
1495 for (
auto it = std::rbegin(this->
children); it != std::rend(this->
children); ++it) {
1499 DrawOutline(w,
this);
1502void NWidgetPIPContainer::AdjustPaddingForZoom()
1507 NWidgetContainer::AdjustPaddingForZoom();
1558 uint max_vert_fill = 0;
1559 for (
const auto &child_wid : this->
children) {
1560 child_wid->SetupSmallestSize(w);
1561 longest = std::max(longest, child_wid->smallest_x);
1562 max_vert_fill = std::max(max_vert_fill, child_wid->GetVerticalStepSize(
ST_SMALLEST));
1563 this->
smallest_y = std::max(this->
smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1564 if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) this->
gaps++;
1568 [[maybe_unused]] uint max_smallest = this->
smallest_y + 3 * max_vert_fill;
1571 for (
const auto &child_wid : this->
children) {
1572 uint step_size = child_wid->GetVerticalStepSize(
ST_SMALLEST);
1573 uint child_height = child_wid->smallest_y + child_wid->padding.Vertical();
1574 if (step_size > 1 && child_height < cur_height) {
1575 uint remainder = (cur_height - child_height) % step_size;
1576 if (remainder > 0) {
1577 cur_height += step_size - remainder;
1578 assert(cur_height < max_smallest);
1587 for (
const auto &child_wid : this->
children) {
1588 child_wid->smallest_y = this->
smallest_y - child_wid->padding.Vertical();
1589 child_wid->ApplyAspectRatio();
1590 longest = std::max(longest, child_wid->smallest_x);
1593 for (
const auto &child_wid : this->
children) {
1594 if (child_wid->fill_x == 1) child_wid->smallest_x = longest;
1598 for (
const auto &child_wid : this->
children) {
1599 this->
smallest_x += child_wid->smallest_x + child_wid->padding.Horizontal();
1600 if (child_wid->fill_x > 0) {
1601 if (this->
fill_x == 0 || this->
fill_x > child_wid->fill_x) this->
fill_x = child_wid->fill_x;
1603 this->
fill_y = std::lcm(this->
fill_y, child_wid->fill_y);
1605 if (child_wid->resize_x > 0) {
1621 for (
const auto &child_wid : this->
children) {
1622 if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) additional_length -= child_wid->smallest_x + child_wid->padding.Horizontal();
1641 int num_changing_childs = 0;
1642 uint biggest_stepsize = 0;
1643 for (
const auto &child_wid : this->
children) {
1644 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1647 biggest_stepsize = std::max(biggest_stepsize, hor_step);
1649 child_wid->current_x = child_wid->smallest_x;
1652 uint vert_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
1653 child_wid->current_y =
ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding.Vertical(), vert_step);
1658 for (
const auto &child_wid : this->
children) {
1659 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1660 if (hor_step == biggest_stepsize) {
1661 num_changing_childs++;
1667 while (biggest_stepsize > 0) {
1668 uint next_biggest_stepsize = 0;
1669 for (
const auto &child_wid : this->
children) {
1670 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1671 if (hor_step > biggest_stepsize)
continue;
1672 if (hor_step == biggest_stepsize) {
1673 uint increment = additional_length / num_changing_childs;
1674 num_changing_childs--;
1675 if (hor_step > 1) increment -= increment % hor_step;
1676 child_wid->current_x = child_wid->smallest_x + increment;
1677 additional_length -= increment;
1680 next_biggest_stepsize = std::max(next_biggest_stepsize, hor_step);
1682 biggest_stepsize = next_biggest_stepsize;
1686 for (
const auto &child_wid : this->
children) {
1687 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1688 if (hor_step == biggest_stepsize) {
1689 num_changing_childs++;
1694 assert(num_changing_childs == 0);
1699 if (additional_length > 0) {
1710 uint position = rtl ? this->
current_x - pre : pre;
1711 for (
const auto &child_wid : this->
children) {
1712 uint child_width = child_wid->current_x;
1713 uint child_x = x + (rtl ? position - child_width - child_wid->padding.left : position + child_wid->padding.left);
1714 uint child_y = y + child_wid->padding.top;
1716 child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl);
1717 if (child_wid->current_x != 0) {
1718 uint padded_child_width = child_width + child_wid->padding.Horizontal() + inter;
1719 position = rtl ? position - padded_child_width : position + padded_child_width;
1741 uint max_hor_fill = 0;
1742 for (
const auto &child_wid : this->
children) {
1743 child_wid->SetupSmallestSize(w);
1744 highest = std::max(highest, child_wid->smallest_y);
1745 max_hor_fill = std::max(max_hor_fill, child_wid->GetHorizontalStepSize(
ST_SMALLEST));
1746 this->
smallest_x = std::max(this->
smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1747 if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) this->
gaps++;
1751 [[maybe_unused]] uint max_smallest = this->
smallest_x + 3 * max_hor_fill;
1754 for (
const auto &child_wid : this->
children) {
1755 uint step_size = child_wid->GetHorizontalStepSize(
ST_SMALLEST);
1756 uint child_width = child_wid->smallest_x + child_wid->padding.Horizontal();
1757 if (step_size > 1 && child_width < cur_width) {
1758 uint remainder = (cur_width - child_width) % step_size;
1759 if (remainder > 0) {
1760 cur_width += step_size - remainder;
1761 assert(cur_width < max_smallest);
1770 for (
const auto &child_wid : this->
children) {
1771 child_wid->smallest_x = this->
smallest_x - child_wid->padding.Horizontal();
1772 child_wid->ApplyAspectRatio();
1773 highest = std::max(highest, child_wid->smallest_y);
1776 for (
const auto &child_wid : this->
children) {
1777 if (child_wid->fill_y == 1) child_wid->smallest_y = highest;
1781 for (
const auto &child_wid : this->
children) {
1782 this->
smallest_y += child_wid->smallest_y + child_wid->padding.Vertical();
1783 if (child_wid->fill_y > 0) {
1784 if (this->
fill_y == 0 || this->
fill_y > child_wid->fill_y) this->
fill_y = child_wid->fill_y;
1786 this->
fill_x = std::lcm(this->
fill_x, child_wid->fill_x);
1788 if (child_wid->resize_y > 0) {
1804 for (
const auto &child_wid : this->
children) {
1805 if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) additional_length -= child_wid->smallest_y + child_wid->padding.Vertical();
1815 int num_changing_childs = 0;
1816 uint biggest_stepsize = 0;
1817 for (
const auto &child_wid : this->
children) {
1818 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1819 if (vert_step > 0) {
1821 biggest_stepsize = std::max(biggest_stepsize, vert_step);
1823 child_wid->current_y = child_wid->smallest_y;
1826 uint hor_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
1827 child_wid->current_x =
ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step);
1832 for (
const auto &child_wid : this->
children) {
1833 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1834 if (vert_step == biggest_stepsize) {
1835 num_changing_childs++;
1841 while (biggest_stepsize > 0) {
1842 uint next_biggest_stepsize = 0;
1843 for (
const auto &child_wid : this->
children) {
1844 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1845 if (vert_step > biggest_stepsize)
continue;
1846 if (vert_step == biggest_stepsize) {
1847 uint increment = additional_length / num_changing_childs;
1848 num_changing_childs--;
1849 if (vert_step > 1) increment -= increment % vert_step;
1850 child_wid->current_y = child_wid->smallest_y + increment;
1851 additional_length -= increment;
1854 next_biggest_stepsize = std::max(next_biggest_stepsize, vert_step);
1856 biggest_stepsize = next_biggest_stepsize;
1860 for (
const auto &child_wid : this->
children) {
1861 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1862 if (vert_step == biggest_stepsize) {
1863 num_changing_childs++;
1868 assert(num_changing_childs == 0);
1873 if (additional_length > 0) {
1884 uint position = pre;
1885 for (
const auto &child_wid : this->
children) {
1886 uint child_x = x + (rtl ? child_wid->padding.right : child_wid->padding.left);
1887 uint child_height = child_wid->current_y;
1889 child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding.top, child_wid->current_x, child_height, rtl);
1890 if (child_wid->current_y != 0) {
1891 position += child_height + child_wid->padding.Vertical() + inter;
1911 this->ApplyAspectRatio();
1922 DrawOutline(w,
this);
1943 if (this->clicked >= 0 && this->
sb !=
nullptr && this->
widgets_x != 0) {
1959 this->count =
count;
1961 if (this->
sb ==
nullptr || this->
widgets_x == 0)
return;
1997 assert(this->
children.size() == 1);
1999 this->
children.front()->SetupSmallestSize(w);
2002 Dimension size = {this->
children.front()->smallest_x + padding.width, this->
children.front()->smallest_y + padding.height};
2010 this->
fill_x = fill.width;
2011 this->
fill_y = fill.height;
2014 this->ApplyAspectRatio();
2046 int start_x, start_y, base_offs_x, base_offs_y;
2051 int widget_col = (rtl ?
2062 assert(child !=
nullptr);
2086 assert(child !=
nullptr);
2087 int start_x, start_y, base_offs_x, base_offs_y;
2090 int offs_y = base_offs_y;
2091 for (
int y = start_y; y < start_y + this->
widgets_y + 1; y++, offs_y += this->
widget_h) {
2093 if (offs_y + child->
smallest_y <= 0)
continue;
2094 if (offs_y >= (
int)this->
current_y)
break;
2099 int offs_x = base_offs_x;
2102 if (offs_x + child->
smallest_x <= 0)
continue;
2103 if (offs_x >= (
int)this->
current_x)
continue;
2116 DrawOutline(w,
this);
2132 if (this->
sb !=
nullptr) {
2140 base_offs_x += sub_x;
2142 base_offs_x -= sub_x;
2160 this->child = std::move(child);
2161 if (this->child !=
nullptr) this->child->parent =
this;
2174 if (this->
child ==
nullptr) {
2175 this->
child = std::make_unique<NWidgetVertical>();
2178 this->
child->Add(std::move(nwid));
2193 if (this->
child ==
nullptr) {
2194 this->
child = std::make_unique<NWidgetVertical>();
2196 this->
child->parent =
this;
2197 this->
child->SetPIP(pip_pre, pip_inter, pip_post);
2212 if (this->
child ==
nullptr) {
2213 this->
child = std::make_unique<NWidgetVertical>();
2215 this->
child->parent =
this;
2216 this->
child->SetPIPRatio(pip_ratio_pre, pip_ratio_inter, pip_ratio_post);
2219void NWidgetBackground::AdjustPaddingForZoom()
2221 if (
child !=
nullptr)
child->AdjustPaddingForZoom();
2222 NWidgetCore::AdjustPaddingForZoom();
2227 if (this->
child !=
nullptr) {
2228 this->
child->SetupSmallestSize(w);
2238 if (w ==
nullptr)
return;
2241 std::string text = GetStringForWidget(w,
this);
2254 this->
child->padding = WidgetDimensions::scaled.
bevel;
2259 this->ApplyAspectRatio();
2266 std::string text = GetStringForWidget(w,
this);
2269 d =
maxdim(d, background);
2271 if (this->
index >= 0) {
2273 switch (this->
type) {
2274 default: NOT_REACHED();
2284 this->
fill_x = fill.width;
2285 this->
fill_y = fill.height;
2288 this->ApplyAspectRatio();
2296 if (this->
child !=
nullptr) {
2297 uint x_offset = (rtl ? this->
child->padding.right : this->
child->padding.left);
2298 uint width = given_width - this->
child->padding.Horizontal();
2299 uint height = given_height - this->
child->padding.Vertical();
2300 this->
child->AssignSizePosition(sizing, x + x_offset, y + this->
child->padding.top, width, height, rtl);
2307 if (this->
child !=
nullptr) this->
child->FillWidgetLookup(widget_lookup);
2314 Rect r = this->GetCurrentRect();
2317 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top)
return;
2319 switch (this->
type) {
2337 if (this->
child !=
nullptr) this->
child->Draw(w);
2343 DrawOutline(w,
this);
2351 if (nwid ==
nullptr) nwid =
this;
2360 if (nwid ==
nullptr && this->
type == tp) nwid =
this;
2372 this->ApplyAspectRatio();
2389 if (this->
disp_flags.
Any({NWidgetDisplayFlag::ShadeGrey, NWidgetDisplayFlag::ShadeDimmed})) {
2393 DrawOutline(w,
this);
2413 if (w->
viewport ==
nullptr)
return;
2438 return (pos < 0 || pos >= this->
GetCount()) ? Scrollbar::npos :
pos;
2457 int new_pos = list_position;
2527 const int count = sb.
GetCount() * resize_step;
2528 const int position = sb.
GetPosition() * resize_step;
2532 r.bottom = r.top + count;
2536 r.right += position;
2537 r.left = r.right - count;
2540 r.right = r.left + count;
2557 switch (this->
type) {
2561 this->
SetToolTip(STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST);
2567 this->
SetToolTip(STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST);
2570 default: NOT_REACHED();
2579 switch (this->
type) {
2581 this->
SetMinimalSizeAbsolute(NWidgetScrollbar::GetHorizontalDimension().width * 3, NWidgetScrollbar::GetHorizontalDimension().height);
2585 this->
SetMinimalSizeAbsolute(NWidgetScrollbar::GetVerticalDimension().width, NWidgetScrollbar::GetVerticalDimension().height * 3);
2588 default: NOT_REACHED();
2599 Rect r = this->GetCurrentRect();
2602 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top)
return;
2618 DrawOutline(w,
this);
2621 void NWidgetScrollbar::InvalidateDimensionCache()
2627 Dimension NWidgetScrollbar::GetVerticalDimension()
2637 Dimension NWidgetScrollbar::GetHorizontalDimension()
2678NWidgetLeaf::NWidgetLeaf(
WidgetType tp, Colours colour,
WidgetID index,
const WidgetData &data,
StringID tip) :
NWidgetCore(tp, colour, index, 1, 1, data, tip)
2687 if (
colour != INVALID_COLOUR) [[unlikely]]
throw std::runtime_error(
"WWT_EMPTY should not have a colour");
2691 if (
colour != INVALID_COLOUR) [[unlikely]]
throw std::runtime_error(
"WWT_TEXT should not have a colour");
2697 if (colour != INVALID_COLOUR) [[unlikely]]
throw std::runtime_error(
"WWT_LABEL should not have a colour");
2712 case NWID_PUSHBUTTON_DROPDOWN:
2719 this->
SetAspect(WidgetDimensions::ASPECT_LEFT_RIGHT_BUTTON);
2731 this->
SetToolTip(STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
2678NWidgetLeaf::NWidgetLeaf(
WidgetType tp, Colours colour,
WidgetID index,
const WidgetData &data,
StringID tip) :
NWidgetCore(tp, colour, index, 1, 1, data, tip) {
…}
2793 switch (this->
type) {
2862 size.width = std::max(size.width,
ScaleGUITrad(30) + sprite_size.width);
2895 padding.height + std::max(di.height, dt.height)
2946 case NWID_PUSHBUTTON_DROPDOWN: {
2967 this->
fill_x = fill.width;
2968 this->
fill_y = fill.height;
2971 this->ApplyAspectRatio();
2983 new_dpi.left += this->
pos_x;
2984 new_dpi.top += this->
pos_y;
2988 Rect r = this->GetCurrentRect();
2991 switch (this->
type) {
2994 if (this->
index == -1 && _draw_widget_outlines) {
3005 Colours button_colour = this->
widget_data.alternate_colour;
3006 if (button_colour == INVALID_COLOUR) button_colour = this->
colour;
3007 DrawBoolButton(pt.x, pt.y, button_colour, this->colour, clicked, !this->IsDisabled());
3035 case AWV_LEFT: sprite = SPR_ARROW_LEFT;
break;
3036 case AWV_RIGHT: sprite = SPR_ARROW_RIGHT;
break;
3037 default: NOT_REACHED();
3052 DrawMatrix(r, this->
colour, clicked, this->
widget_data.matrix.width, this->widget_data.matrix.height, this->resize_x, this->resize_y);
3057 if (query !=
nullptr) query->DrawEditBox(w, this->
index);
3094 case NWID_PUSHBUTTON_DROPDOWN:
3108 DrawOutline(w,
this);
3121 int button_width = this->
pos_x + this->
current_x - NWidgetLeaf::dropdown_dimension.width;
3122 return pt.x < button_width;
3124 int button_left = this->
pos_x + NWidgetLeaf::dropdown_dimension.width;
3125 return pt.x >= button_left;
3149 switch (nwid.
type) {
3152 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_RESIZE requires NWidgetResizeBase");
3153 assert(nwid.u.
xy.x >= 0 && nwid.u.
xy.y >= 0);
3160 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_MINSIZE requires NWidgetResizeBase");
3161 assert(nwid.u.
xy.x >= 0 && nwid.u.
xy.y >= 0);
3168 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_MINTEXTLINES requires NWidgetResizeBase");
3176 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_TEXTSTYLE requires NWidgetCore");
3183 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_ALIGNMENT requires NWidgetCore");
3190 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_FILL requires NWidgetResizeBase");
3197 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_DATATIP requires NWidgetCore");
3204 if (dest ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PADDING requires NWidgetBase");
3215 if (nwc ==
nullptr && nwb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PIPSPACE requires NWidgetPIPContainer or NWidgetBackground");
3226 if (nwc ==
nullptr && nwb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PIPRATIO requires NWidgetPIPContainer or NWidgetBackground");
3232 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_SCROLLBAR requires NWidgetCore");
3238 if (dest ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_ASPECT requires NWidgetBase");
3260 switch (nwid.
type) {
3261 case NWID_SPACER:
return std::make_unique<NWidgetSpacer>(0, 0);
3299static std::span<const NWidgetPart>::iterator
MakeNWidget(std::span<const NWidgetPart>::iterator nwid_begin, std::span<const NWidgetPart>::iterator nwid_end, std::unique_ptr<NWidgetBase> &dest,
bool &fill_dest)
3303 if (
IsAttributeWidgetPartType(nwid_begin->type)) [[unlikely]]
throw std::runtime_error(
"Expected non-attribute NWidgetPart type");
3308 if (dest ==
nullptr)
return nwid_begin;
3299static std::span<const NWidgetPart>::iterator
MakeNWidget(std::span<const NWidgetPart>::iterator nwid_begin, std::span<const NWidgetPart>::iterator nwid_end, std::unique_ptr<NWidgetBase> &dest,
bool &fill_dest) {
…}
3339static std::span<const NWidgetPart>::iterator
MakeWidgetTree(std::span<const NWidgetPart>::iterator nwid_begin, std::span<const NWidgetPart>::iterator nwid_end, std::unique_ptr<NWidgetBase> &parent)
3345 assert(parent ==
nullptr || (nwid_cont !=
nullptr && nwid_parent ==
nullptr) || (nwid_cont ==
nullptr && nwid_parent !=
nullptr));
3347 while (nwid_begin != nwid_end) {
3348 std::unique_ptr<NWidgetBase> sub_widget =
nullptr;
3349 bool fill_sub =
false;
3350 nwid_begin =
MakeNWidget(nwid_begin, nwid_end, sub_widget, fill_sub);
3353 if (sub_widget ==
nullptr)
break;
3361 if (nwid_cont !=
nullptr) nwid_cont->
Add(std::move(sub_widget));
3362 if (nwid_parent !=
nullptr) nwid_parent->
Add(std::move(sub_widget));
3363 if (nwid_cont ==
nullptr && nwid_parent ==
nullptr) {
3364 parent = std::move(sub_widget);
3369 if (nwid_begin == nwid_end)
return nwid_begin;
3371 assert(nwid_begin < nwid_end);
3373 return std::next(nwid_begin);
3339static std::span<const NWidgetPart>::iterator
MakeWidgetTree(std::span<const NWidgetPart>::iterator nwid_begin, std::span<const NWidgetPart>::iterator nwid_end, std::unique_ptr<NWidgetBase> &parent) {
…}
3383std::unique_ptr<NWidgetBase>
MakeNWidgets(std::span<const NWidgetPart> nwid_parts, std::unique_ptr<NWidgetBase> &&container)
3385 if (container ==
nullptr) container = std::make_unique<NWidgetVertical>();
3386 [[maybe_unused]]
auto nwid_part =
MakeWidgetTree(std::begin(nwid_parts), std::end(nwid_parts), container);
3388 if (nwid_part != std::end(nwid_parts)) [[unlikely]]
throw std::runtime_error(
"Did not consume all NWidgetParts");
3390 return std::move(container);
3383std::unique_ptr<NWidgetBase>
MakeNWidgets(std::span<const NWidgetPart> nwid_parts, std::unique_ptr<NWidgetBase> &&container) {
…}
3404 auto nwid_begin = std::begin(nwid_parts);
3405 auto nwid_end = std::end(nwid_parts);
3407 *shade_select =
nullptr;
3410 std::unique_ptr<NWidgetBase> nwid =
nullptr;
3412 assert(nwid !=
nullptr);
3416 auto root = std::make_unique<NWidgetVertical>();
3417 root->Add(std::move(nwid));
3418 if (nwid_begin == nwid_end)
return root;
3422 auto shade_stack = std::make_unique<NWidgetStacked>(-1);
3423 *shade_select = shade_stack.get();
3425 shade_stack->
Add(
MakeNWidgets({nwid_begin, nwid_end}, std::make_unique<NWidgetVertical>()));
3426 root->Add(std::move(shade_stack));
3431 return MakeNWidgets({nwid_begin, nwid_end}, std::move(root));
3446 assert(max_length >= 1);
3447 std::unique_ptr<NWidgetVertical> vert =
nullptr;
3448 std::unique_ptr<NWidgetHorizontal> hor =
nullptr;
3455 for (
WidgetID widnum = widget_first; widnum <= widget_last; widnum++) {
3457 if (hor_length == max_length) {
3458 if (vert ==
nullptr) vert = std::make_unique<NWidgetVertical>();
3459 vert->Add(std::move(hor));
3463 if (hor ==
nullptr) {
3464 hor = std::make_unique<NWidgetHorizontal>();
3468 auto panel = std::make_unique<NWidgetBackground>(
WWT_PANEL, button_colour, widnum);
3469 panel->SetMinimalSize(sprite_size.width, sprite_size.height);
3470 panel->SetFill(1, 1);
3471 if (resizable) panel->SetResize(1, 0);
3472 panel->SetToolTip(button_tooltip);
3473 hor->Add(std::move(panel));
3476 if (vert ==
nullptr)
return hor;
3478 if (hor_length > 0 && hor_length < max_length) {
3480 auto spc = std::make_unique<NWidgetSpacer>(sprite_size.width, sprite_size.height);
3482 if (resizable) spc->SetResize(1, 0);
3483 hor->Add(std::move(spc));
3485 if (hor !=
nullptr) vert->Add(std::move(hor));
Class for backupping variables and making sure they are restored later.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
ReferenceThroughBaseContainer< std::array< Colours, MAX_COMPANIES > > _company_colours
NOSAVE: can be determined from company structs.
Functions related to 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.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
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.
void DrawRectOutline(const Rect &r, int colour, int width, int dash)
Draw the outline of a Rect.
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.
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height)
Set up a clipping area for only drawing into a certain area.
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
FontSize
Available font sizes.
@ FS_NORMAL
Index of the normal font in the font tables.
StringAlignment
How to align the to-be drawn text.
@ SA_TOP
Top align the text.
@ SA_LEFT
Left align the text.
@ SA_HOR_MASK
Mask for horizontal alignment.
@ SA_RIGHT
Right align the text (must be a single bit).
@ SA_HOR_CENTER
Horizontally center the text.
@ SA_VERT_MASK
Mask for vertical alignment.
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
@ SA_BOTTOM
Bottom align the text.
@ SA_CENTER
Center both horizontally and vertically.
@ SA_VERT_CENTER
Vertically center the text.
uint32_t PaletteID
The number of the palette.
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
@ FILLRECT_RECOLOUR
Apply a recolour sprite to the screen content.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
void AddDirtyBlock(int left, int top, int right, int bottom)
Extend the internal _invalid_rect rectangle to contain the rectangle defined by the given parameters.
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
static const uint8_t PC_WHITE
White palette colour.
static const uint8_t PC_BLACK
Black palette colour.
Base for the GUIs that have an edit box in them.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
void DrawBoolButton(int x, int y, Colours button_colour, Colours background, bool state, bool clickable)
Draw a toggle button.
Functions for setting GUIs.
#define SETTING_BUTTON_WIDTH
Width of setting buttons.
#define SETTING_BUTTON_HEIGHT
Height of setting buttons.
Types related to global configuration settings.
This file contains all sprite-related enums and defines.
static constexpr uint8_t PALETTE_TEXT_RECOLOUR
Set if palette is actually a magic text recolour.
static const PaletteID PALETTE_TO_TRANSPARENT
This sets the sprite to transparent.
static const PaletteID PALETTE_NEWSPAPER
Recolour sprite for newspaper-greying.
Definition of base types and functions in a cross-platform compatible way.
The colour translation of GRF's strings.
static const uint8_t _string_colourmap[17]
Colour mapping for TextColour.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
TextDirection _current_text_dir
Text direction of the currently selected language.
Functions related to OTTD's strings.
Types related to strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_LTR
Text is written left-to-right by default.
@ TD_RTL
Text is written right-to-left by default.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
GUISettings gui
settings related to the GUI
Point pos
logical mouse position
Dimensions (a width and height) of a rectangle in 2D.
Data about how and where to blit pixels.
bool scale_bevels
bevels are scaled with GUI scale.
bool newgrf_developer_tools
activate NewGRF developer tools and allow modifying NewGRFs in an existing game
uint8_t lines
Number of text lines.
uint8_t spacing
Extra spacing around lines.
FontSize size
Font size of text lines.
TextColour colour
TextColour for DrawString.
FontSize size
Font size of text.
Coordinates of a point in 2D.
Data stored about a string that can be modified in the GUI.
Padding dimensions to apply to each side of a Rect.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
int Width() const
Get width of Rect.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
int Height() const
Get height of Rect.
Rect Expand(int s) const
Copy and expand Rect by s pixels.
Data structure for viewport, display of a part of the world.
int top
Screen coordinate top edge of the viewport.
int width
Screen width of the viewport.
ZoomLevel zoom
The zoom level of the viewport.
int virtual_width
width << zoom
int left
Screen coordinate left edge of the viewport.
int height
Screen height of the viewport.
int virtual_height
height << zoom
Data structure for an opened window.
virtual void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize)
Update size and resize step of a widget in the window.
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
void DrawWidgets() const
Paint all widgets of a window.
std::unique_ptr< ViewportData > viewport
Pointer to viewport data, if present.
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
WidgetID mouse_capture_widget
ID of current mouse capture widget (e.g. dragged scrollbar). -1 if no widget has mouse capture.
virtual void OnScrollbarScroll(WidgetID widget)
Notify window that a scrollbar position has been updated.
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
virtual bool IsNewGRFInspectable() const
Is the data related to this window NewGRF inspectable?
void DrawViewport() const
Draw the viewport of this window.
virtual void DrawWidget(const Rect &r, WidgetID widget) const
Draw the contents of a nested widget.
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
int left
x position of left edge of the window
bool IsShaded() const
Is window shaded currently?
int top
y position of top edge of the window
const QueryString * GetQueryString(WidgetID widnum) const
Return the querystring associated to a editbox.
WidgetLookup widget_lookup
Indexed access to the nested widget tree. Do not access directly, use Window::GetWidget() instead.
int GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height=-1) const
Compute the row of a widget that a user clicked in.
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
WindowFlags flags
Window flags.
std::unique_ptr< NWidgetBase > nested_root
Root of the nested tree.
int height
Height of the window (number of pixels down in y direction)
int width
width of the window (number of pixels to the right in x direction)
Functions related to transparency.
TransparencyOptionBits _transparency_opt
The bits that should be transparent.
uint TransparencyOptionBits
transparency option bits
@ TO_TEXT
loading and cost/income text
void InitializeWindowViewport(Window *w, int x, int y, int width, int height, std::variant< TileIndex, VehicleID > focus, ZoomLevel zoom)
Initialize viewport of the window for use.
Functions related to (drawing on) viewports.
bool _window_highlight_colour
If false, highlight is white, otherwise the by the widget defined colour.
Functions, definitions and such used only by the GUI.
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
@ Transparent
Makes the background transparent if set.
@ BorderOnly
Draw border only, no background.
@ Darkened
If set the background is darker, allows for lowered frames with normal background colour when used wi...
@ Lowered
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
@ SizingLeft
Window is being resized towards the left.
@ Highlighted
Window has a widget that has a highlight.
@ SizingRight
Window is being resized towards the right.
@ WhiteBorder
Window white border counter bit mask.
@ Sticky
Window is made sticky by user.
SortButtonState
State of a sort direction button.
@ SBS_DOWN
Sort ascending.
@ SBS_OFF
Do not sort (with this button).
EventState
State of handling an event.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
Functions related to zooming.
int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZoomLevel::Min) When shifting right,...
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
ZoomLevel
All zoom levels we know.
@ Normal
The normal zoom level.