25#include "table/strings.h"
32static std::string GetStringForWidget(
const Window *w,
const NWidgetCore *nwid,
bool secondary =
false)
36 if (stringid == STR_NULL)
return {};
38 return GetString(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;
960 return (this->
type == tp) ? this :
nullptr;
963void NWidgetBase::ApplyAspectRatio()
977void NWidgetBase::AdjustPaddingForZoom()
1013 this->
SetAspect(
static_cast<float>(x_ratio) /
static_cast<float>(y_ratio), flags);
1016void NWidgetResizeBase::AdjustPaddingForZoom()
1022 NWidgetBase::AdjustPaddingForZoom();
1046 this->min_x = std::max(this->min_x,
min_x);
1047 this->min_y = std::max(this->min_y,
min_y);
1099 d.height *= max_lines;
1115 if (
min_x == this->min_x &&
min_y == this->min_y)
return false;
1116 this->min_x =
min_x;
1117 this->min_y =
min_y;
1129 if (
min_y == this->min_y)
return false;
1130 this->min_y =
min_y;
1251 this->align =
align;
1283 if (this->
index >= 0) widget_lookup[this->
index] =
this;
1293 if (this->
type == tp)
return this;
1294 for (
const auto &child_wid : this->
children) {
1296 if (nwid !=
nullptr)
return nwid;
1301void NWidgetContainer::AdjustPaddingForZoom()
1303 for (
const auto &child_wid : this->
children) {
1304 child_wid->AdjustPaddingForZoom();
1306 NWidgetBase::AdjustPaddingForZoom();
1315 assert(wid !=
nullptr);
1317 this->
children.push_back(std::move(wid));
1322 for (
const auto &child_wid : this->
children) {
1329 for (
const auto &child_wid : this->
children) {
1333 DrawOutline(w,
this);
1340 for (
const auto &child_wid : this->
children) {
1342 if (nwid !=
nullptr)
return nwid;
1360 this->
fill_x = fill.width;
1361 this->
fill_y = fill.height;
1364 this->ApplyAspectRatio();
1375 for (
const auto &child_wid : this->
children) {
1376 child_wid->SetupSmallestSize(w);
1378 this->
smallest_x = std::max(this->
smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1379 this->
smallest_y = std::max(this->
smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1380 this->
fill_x = std::lcm(this->
fill_x, child_wid->fill_x);
1381 this->
fill_y = std::lcm(this->
fill_y, child_wid->fill_y);
1384 this->ApplyAspectRatio();
1395 for (
const auto &child_wid : this->
children) {
1396 uint hor_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
1397 uint child_width =
ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step);
1398 uint child_pos_x = (rtl ? child_wid->padding.right : child_wid->padding.left);
1400 uint vert_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
1401 uint child_height =
ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding.Vertical(), vert_step);
1402 uint child_pos_y = child_wid->padding.top;
1404 child_wid->AssignSizePosition(sizing, x + child_pos_x, y + child_pos_y, child_width, child_height, rtl);
1413 if (this->
index >= 0) widget_lookup[this->
index] =
this;
1425 DrawOutline(w,
this);
1473 for (
const auto &child_wid : this->
children) {
1474 child_wid->SetupSmallestSize(w);
1476 this->
smallest_x = std::max(this->
smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1477 this->
smallest_y = std::max(this->
smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1478 this->
fill_x = std::lcm(this->
fill_x, child_wid->fill_x);
1479 this->
fill_y = std::lcm(this->
fill_y, child_wid->fill_y);
1482 this->ApplyAspectRatio();
1491 for (
const auto &child_wid : this->
children) {
1492 uint hor_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
1493 uint child_width =
ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step);
1494 uint child_pos_x = (rtl ? child_wid->padding.right : child_wid->padding.left);
1496 uint vert_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
1497 uint child_height =
ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding.Vertical(), vert_step);
1498 uint child_pos_y = child_wid->padding.top;
1500 child_wid->AssignSizePosition(sizing, x + child_pos_x, y + child_pos_y, child_width, child_height, rtl);
1507 for (
auto it = std::rbegin(this->
children); it != std::rend(this->
children); ++it) {
1511 DrawOutline(w,
this);
1516 this->flags = flags;
1519void NWidgetPIPContainer::AdjustPaddingForZoom()
1524 NWidgetContainer::AdjustPaddingForZoom();
1580 uint max_vert_fill = 0;
1581 for (
const auto &child_wid : this->
children) {
1583 longest = std::max(longest, child_wid->smallest_x);
1584 max_vert_fill = std::max(max_vert_fill, child_wid->GetVerticalStepSize(
ST_SMALLEST));
1585 this->
smallest_y = std::max(this->
smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1586 if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) this->
gaps++;
1590 [[maybe_unused]] uint max_smallest = this->
smallest_y + 3 * max_vert_fill;
1593 for (
const auto &child_wid : this->
children) {
1594 uint step_size = child_wid->GetVerticalStepSize(
ST_SMALLEST);
1595 uint child_height = child_wid->smallest_y + child_wid->padding.Vertical();
1596 if (step_size > 1 && child_height < cur_height) {
1597 uint remainder = (cur_height - child_height) % step_size;
1598 if (remainder > 0) {
1599 cur_height += step_size - remainder;
1600 assert(cur_height < max_smallest);
1609 for (
const auto &child_wid : this->
children) {
1610 child_wid->smallest_y = this->
smallest_y - child_wid->padding.Vertical();
1611 child_wid->ApplyAspectRatio();
1612 longest = std::max(longest, child_wid->smallest_x);
1615 for (
const auto &child_wid : this->
children) {
1616 if (child_wid->fill_x == 1) child_wid->smallest_x = longest;
1620 for (
const auto &child_wid : this->
children) {
1621 this->
smallest_x += child_wid->smallest_x + child_wid->padding.Horizontal();
1622 if (child_wid->fill_x > 0) {
1623 if (this->
fill_x == 0 || this->
fill_x > child_wid->fill_x) this->
fill_x = child_wid->fill_x;
1625 this->
fill_y = std::lcm(this->
fill_y, child_wid->fill_y);
1627 if (child_wid->resize_x > 0) {
1643 for (
const auto &child_wid : this->
children) {
1644 if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) additional_length -= child_wid->smallest_x + child_wid->padding.Horizontal();
1663 int num_changing_childs = 0;
1664 uint biggest_stepsize = 0;
1665 for (
const auto &child_wid : this->
children) {
1666 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1669 biggest_stepsize = std::max(biggest_stepsize, hor_step);
1671 child_wid->current_x = child_wid->smallest_x;
1674 uint vert_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
1675 child_wid->current_y =
ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding.Vertical(), vert_step);
1680 for (
const auto &child_wid : this->
children) {
1681 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1682 if (hor_step == biggest_stepsize) {
1683 num_changing_childs++;
1689 while (biggest_stepsize > 0) {
1690 uint next_biggest_stepsize = 0;
1691 for (
const auto &child_wid : this->
children) {
1692 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1693 if (hor_step > biggest_stepsize)
continue;
1694 if (hor_step == biggest_stepsize) {
1695 uint increment = additional_length / num_changing_childs;
1696 num_changing_childs--;
1697 if (hor_step > 1) increment -= increment % hor_step;
1698 child_wid->current_x = child_wid->smallest_x + increment;
1699 additional_length -= increment;
1702 next_biggest_stepsize = std::max(next_biggest_stepsize, hor_step);
1704 biggest_stepsize = next_biggest_stepsize;
1708 for (
const auto &child_wid : this->
children) {
1709 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1710 if (hor_step == biggest_stepsize) {
1711 num_changing_childs++;
1716 assert(num_changing_childs == 0);
1721 if (additional_length > 0) {
1732 uint position = rtl ? this->
current_x - pre : pre;
1733 for (
const auto &child_wid : this->
children) {
1734 uint child_width = child_wid->current_x;
1735 uint child_x = x + (rtl ? position - child_width - child_wid->padding.left : position + child_wid->padding.left);
1736 uint child_y = y + child_wid->padding.top;
1738 child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl);
1739 if (child_wid->current_x != 0) {
1740 uint padded_child_width = child_width + child_wid->padding.Horizontal() + inter;
1741 position = rtl ? position - padded_child_width : position + padded_child_width;
1774 uint max_hor_fill = 0;
1775 for (
const auto &child_wid : this->
children) {
1777 highest = std::max(highest, child_wid->smallest_y);
1778 max_hor_fill = std::max(max_hor_fill, child_wid->GetHorizontalStepSize(
ST_SMALLEST));
1779 this->
smallest_x = std::max(this->
smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1780 if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) this->
gaps++;
1784 [[maybe_unused]] uint max_smallest = this->
smallest_x + 3 * max_hor_fill;
1787 for (
const auto &child_wid : this->
children) {
1788 uint step_size = child_wid->GetHorizontalStepSize(
ST_SMALLEST);
1789 uint child_width = child_wid->smallest_x + child_wid->padding.Horizontal();
1790 if (step_size > 1 && child_width < cur_width) {
1791 uint remainder = (cur_width - child_width) % step_size;
1792 if (remainder > 0) {
1793 cur_width += step_size - remainder;
1794 assert(cur_width < max_smallest);
1803 for (
const auto &child_wid : this->
children) {
1804 child_wid->smallest_x = this->
smallest_x - child_wid->padding.Horizontal();
1805 child_wid->ApplyAspectRatio();
1806 highest = std::max(highest, child_wid->smallest_y);
1809 for (
const auto &child_wid : this->
children) {
1810 if (child_wid->fill_y == 1) child_wid->smallest_y = highest;
1814 for (
const auto &child_wid : this->
children) {
1815 this->
smallest_y += child_wid->smallest_y + child_wid->padding.Vertical();
1816 if (child_wid->fill_y > 0) {
1817 if (this->
fill_y == 0 || this->
fill_y > child_wid->fill_y) this->
fill_y = child_wid->fill_y;
1819 this->
fill_x = std::lcm(this->
fill_x, child_wid->fill_x);
1821 if (child_wid->resize_y > 0) {
1837 for (
const auto &child_wid : this->
children) {
1838 if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) additional_length -= child_wid->smallest_y + child_wid->padding.Vertical();
1848 int num_changing_childs = 0;
1849 uint biggest_stepsize = 0;
1850 for (
const auto &child_wid : this->
children) {
1851 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1852 if (vert_step > 0) {
1854 biggest_stepsize = std::max(biggest_stepsize, vert_step);
1856 child_wid->current_y = child_wid->smallest_y;
1859 uint hor_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
1860 child_wid->current_x =
ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step);
1865 for (
const auto &child_wid : this->
children) {
1866 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1867 if (vert_step == biggest_stepsize) {
1868 num_changing_childs++;
1874 while (biggest_stepsize > 0) {
1875 uint next_biggest_stepsize = 0;
1876 for (
const auto &child_wid : this->
children) {
1877 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1878 if (vert_step > biggest_stepsize)
continue;
1879 if (vert_step == biggest_stepsize) {
1880 uint increment = additional_length / num_changing_childs;
1881 num_changing_childs--;
1882 if (vert_step > 1) increment -= increment % vert_step;
1883 child_wid->current_y = child_wid->smallest_y + increment;
1884 additional_length -= increment;
1887 next_biggest_stepsize = std::max(next_biggest_stepsize, vert_step);
1889 biggest_stepsize = next_biggest_stepsize;
1893 for (
const auto &child_wid : this->
children) {
1894 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1895 if (vert_step == biggest_stepsize) {
1896 num_changing_childs++;
1901 assert(num_changing_childs == 0);
1906 if (additional_length > 0) {
1917 uint position = pre;
1918 for (
const auto &child_wid : this->
children) {
1919 uint child_x = x + (rtl ? child_wid->padding.right : child_wid->padding.left);
1920 uint child_height = child_wid->current_y;
1922 child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding.top, child_wid->current_x, child_height, rtl);
1923 if (child_wid->current_y != 0) {
1924 position += child_height + child_wid->padding.Vertical() + inter;
1944 this->ApplyAspectRatio();
1959 DrawOutline(w,
this);
1975 this->colour = colour;
1985 if (this->clicked >= 0 && this->
sb !=
nullptr && this->
widgets_x != 0) {
2001 this->count =
count;
2003 if (this->
sb ==
nullptr || this->
widgets_x == 0)
return;
2039 assert(this->
children.size() == 1);
2041 this->
children.front()->SetupSmallestSize(w);
2044 Dimension size = {this->
children.front()->smallest_x + padding.width, this->
children.front()->smallest_y + padding.height};
2052 this->
fill_x = fill.width;
2053 this->
fill_y = fill.height;
2056 this->ApplyAspectRatio();
2085 if (this->
index >= 0) widget_lookup[this->
index] =
this;
2094 int start_x, start_y, base_offs_x, base_offs_y;
2099 int widget_col = (rtl ?
2110 assert(child !=
nullptr);
2134 assert(child !=
nullptr);
2135 int start_x, start_y, base_offs_x, base_offs_y;
2138 int offs_y = base_offs_y;
2139 for (
int y = start_y; y < start_y + this->
widgets_y + 1; y++, offs_y += this->
widget_h) {
2141 if (offs_y + child->
smallest_y <= 0)
continue;
2142 if (offs_y >= (
int)this->
current_y)
break;
2147 int offs_x = base_offs_x;
2150 if (offs_x + child->
smallest_x <= 0)
continue;
2151 if (offs_x >= (
int)this->
current_x)
continue;
2164 DrawOutline(w,
this);
2180 if (this->
sb !=
nullptr) {
2188 base_offs_x += sub_x;
2190 base_offs_x -= sub_x;
2208 this->child = std::move(child);
2209 if (this->child !=
nullptr) this->child->parent =
this;
2222 if (this->
child ==
nullptr) {
2223 this->
child = std::make_unique<NWidgetVertical>();
2226 this->
child->Add(std::move(nwid));
2241 if (this->
child ==
nullptr) {
2242 this->
child = std::make_unique<NWidgetVertical>();
2244 this->
child->parent =
this;
2245 this->
child->SetPIP(pip_pre, pip_inter, pip_post);
2260 if (this->
child ==
nullptr) {
2261 this->
child = std::make_unique<NWidgetVertical>();
2263 this->
child->parent =
this;
2264 this->
child->SetPIPRatio(pip_ratio_pre, pip_ratio_inter, pip_ratio_post);
2267void NWidgetBackground::AdjustPaddingForZoom()
2269 if (
child !=
nullptr)
child->AdjustPaddingForZoom();
2270 NWidgetCore::AdjustPaddingForZoom();
2275 if (this->
child !=
nullptr) {
2276 this->
child->SetupSmallestSize(w);
2286 if (w ==
nullptr)
return;
2289 std::string text = GetStringForWidget(w,
this);
2302 this->
child->padding = WidgetDimensions::scaled.
bevel;
2307 this->ApplyAspectRatio();
2314 std::string text = GetStringForWidget(w,
this);
2317 d =
maxdim(d, background);
2319 if (this->
index >= 0) {
2321 switch (this->
type) {
2322 default: NOT_REACHED();
2332 this->
fill_x = fill.width;
2333 this->
fill_y = fill.height;
2336 this->ApplyAspectRatio();
2344 if (this->
child !=
nullptr) {
2345 uint x_offset = (rtl ? this->
child->padding.right : this->
child->padding.left);
2346 uint width = given_width - this->
child->padding.Horizontal();
2347 uint height = given_height - this->
child->padding.Vertical();
2348 this->
child->AssignSizePosition(sizing, x + x_offset, y + this->
child->padding.top, width, height, rtl);
2354 if (this->
index >= 0) widget_lookup[this->
index] =
this;
2355 if (this->
child !=
nullptr) this->
child->FillWidgetLookup(widget_lookup);
2362 Rect r = this->GetCurrentRect();
2365 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top)
return;
2367 switch (this->
type) {
2385 if (this->
child !=
nullptr) this->
child->Draw(w);
2391 DrawOutline(w,
this);
2399 if (nwid ==
nullptr) nwid =
this;
2408 if (nwid ==
nullptr && this->
type == tp) nwid =
this;
2420 this->ApplyAspectRatio();
2437 if (this->
disp_flags.
Any({NWidgetDisplayFlag::ShadeGrey, NWidgetDisplayFlag::ShadeDimmed})) {
2441 DrawOutline(w,
this);
2461 if (w->
viewport ==
nullptr)
return;
2486 return (pos < 0 || pos >= this->
GetCount()) ? Scrollbar::npos :
pos;
2505 int new_pos = list_position;
2575 const int count = sb.
GetCount() * resize_step;
2576 const int position = sb.
GetPosition() * resize_step;
2580 r.bottom = r.top + count;
2584 r.right += position;
2585 r.left = r.right - count;
2588 r.right = r.left + count;
2605 switch (this->
type) {
2609 this->
SetToolTip(STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST);
2615 this->
SetToolTip(STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST);
2618 default: NOT_REACHED();
2627 switch (this->
type) {
2629 this->
SetMinimalSizeAbsolute(NWidgetScrollbar::GetHorizontalDimension().width * 3, NWidgetScrollbar::GetHorizontalDimension().height);
2633 this->
SetMinimalSizeAbsolute(NWidgetScrollbar::GetVerticalDimension().width, NWidgetScrollbar::GetVerticalDimension().height * 3);
2636 default: NOT_REACHED();
2647 Rect r = this->GetCurrentRect();
2650 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top)
return;
2666 DrawOutline(w,
this);
2669 void NWidgetScrollbar::InvalidateDimensionCache()
2675 Dimension NWidgetScrollbar::GetVerticalDimension()
2685 Dimension NWidgetScrollbar::GetHorizontalDimension()
2726NWidgetLeaf::NWidgetLeaf(
WidgetType tp, Colours colour,
WidgetID index,
const WidgetData &data,
StringID tip) :
NWidgetCore(tp, colour, index, 1, 1, data, tip)
2735 if (
colour != INVALID_COLOUR) [[unlikely]]
throw std::runtime_error(
"WWT_EMPTY should not have a colour");
2739 if (
colour != INVALID_COLOUR) [[unlikely]]
throw std::runtime_error(
"WWT_TEXT should not have a colour");
2745 if (colour != INVALID_COLOUR) [[unlikely]]
throw std::runtime_error(
"WWT_LABEL should not have a colour");
2760 case NWID_PUSHBUTTON_DROPDOWN:
2767 this->
SetAspect(WidgetDimensions::ASPECT_LEFT_RIGHT_BUTTON);
2779 this->
SetToolTip(STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
2726NWidgetLeaf::NWidgetLeaf(
WidgetType tp, Colours colour,
WidgetID index,
const WidgetData &data,
StringID tip) :
NWidgetCore(tp, colour, index, 1, 1, data, tip) {
…}
2841 switch (this->
type) {
2910 size.width = std::max(size.width,
ScaleGUITrad(30) + sprite_size.width);
2943 padding.height + std::max(di.height, dt.height)
2994 case NWID_PUSHBUTTON_DROPDOWN: {
3015 this->
fill_x = fill.width;
3016 this->
fill_y = fill.height;
3019 this->ApplyAspectRatio();
3031 new_dpi.left += this->
pos_x;
3032 new_dpi.top += this->
pos_y;
3036 Rect r = this->GetCurrentRect();
3039 switch (this->
type) {
3042 if (this->
index == -1 && _draw_widget_outlines) {
3053 Colours button_colour = this->
widget_data.alternate_colour;
3054 if (button_colour == INVALID_COLOUR) button_colour = this->
colour;
3055 DrawBoolButton(pt.x, pt.y, button_colour, this->colour, clicked, !this->IsDisabled());
3083 case AWV_LEFT: sprite = SPR_ARROW_LEFT;
break;
3084 case AWV_RIGHT: sprite = SPR_ARROW_RIGHT;
break;
3085 default: NOT_REACHED();
3100 DrawMatrix(r, this->
colour, clicked, this->
widget_data.matrix.width, this->widget_data.matrix.height, this->resize_x, this->resize_y);
3105 if (query !=
nullptr) query->DrawEditBox(w, this->
index);
3142 case NWID_PUSHBUTTON_DROPDOWN:
3156 DrawOutline(w,
this);
3169 int button_width = this->
pos_x + this->
current_x - NWidgetLeaf::dropdown_dimension.width;
3170 return pt.x < button_width;
3172 int button_left = this->
pos_x + NWidgetLeaf::dropdown_dimension.width;
3173 return pt.x >= button_left;
3197 switch (nwid.
type) {
3200 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_RESIZE requires NWidgetResizeBase");
3201 assert(nwid.u.
xy.x >= 0 && nwid.u.
xy.y >= 0);
3208 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_MINSIZE requires NWidgetResizeBase");
3209 assert(nwid.u.
xy.x >= 0 && nwid.u.
xy.y >= 0);
3216 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_MINTEXTLINES requires NWidgetResizeBase");
3224 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_TEXTSTYLE requires NWidgetCore");
3231 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_ALIGNMENT requires NWidgetCore");
3238 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_FILL requires NWidgetResizeBase");
3245 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_DATATIP requires NWidgetCore");
3252 if (dest ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PADDING requires NWidgetBase");
3263 if (nwc ==
nullptr && nwb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PIPSPACE requires NWidgetPIPContainer or NWidgetBackground");
3274 if (nwc ==
nullptr && nwb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PIPRATIO requires NWidgetPIPContainer or NWidgetBackground");
3280 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_SCROLLBAR requires NWidgetCore");
3286 if (dest ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_ASPECT requires NWidgetBase");
3308 switch (nwid.
type) {
3309 case NWID_SPACER:
return std::make_unique<NWidgetSpacer>(0, 0);
3347static 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)
3351 if (
IsAttributeWidgetPartType(nwid_begin->type)) [[unlikely]]
throw std::runtime_error(
"Expected non-attribute NWidgetPart type");
3356 if (dest ==
nullptr)
return nwid_begin;
3347static 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) {
…}
3387static 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)
3393 assert(parent ==
nullptr || (nwid_cont !=
nullptr && nwid_parent ==
nullptr) || (nwid_cont ==
nullptr && nwid_parent !=
nullptr));
3395 while (nwid_begin != nwid_end) {
3396 std::unique_ptr<NWidgetBase> sub_widget =
nullptr;
3397 bool fill_sub =
false;
3398 nwid_begin =
MakeNWidget(nwid_begin, nwid_end, sub_widget, fill_sub);
3401 if (sub_widget ==
nullptr)
break;
3409 if (nwid_cont !=
nullptr) nwid_cont->
Add(std::move(sub_widget));
3410 if (nwid_parent !=
nullptr) nwid_parent->
Add(std::move(sub_widget));
3411 if (nwid_cont ==
nullptr && nwid_parent ==
nullptr) {
3412 parent = std::move(sub_widget);
3417 if (nwid_begin == nwid_end)
return nwid_begin;
3419 assert(nwid_begin < nwid_end);
3421 return std::next(nwid_begin);
3387static 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) {
…}
3431std::unique_ptr<NWidgetBase>
MakeNWidgets(std::span<const NWidgetPart> nwid_parts, std::unique_ptr<NWidgetBase> &&container)
3433 if (container ==
nullptr) container = std::make_unique<NWidgetVertical>();
3434 [[maybe_unused]]
auto nwid_part =
MakeWidgetTree(std::begin(nwid_parts), std::end(nwid_parts), container);
3436 if (nwid_part != std::end(nwid_parts)) [[unlikely]]
throw std::runtime_error(
"Did not consume all NWidgetParts");
3438 return std::move(container);
3431std::unique_ptr<NWidgetBase>
MakeNWidgets(std::span<const NWidgetPart> nwid_parts, std::unique_ptr<NWidgetBase> &&container) {
…}
3452 auto nwid_begin = std::begin(nwid_parts);
3453 auto nwid_end = std::end(nwid_parts);
3455 *shade_select =
nullptr;
3458 std::unique_ptr<NWidgetBase> nwid =
nullptr;
3460 assert(nwid !=
nullptr);
3464 auto root = std::make_unique<NWidgetVertical>();
3465 root->Add(std::move(nwid));
3466 if (nwid_begin == nwid_end)
return root;
3470 auto shade_stack = std::make_unique<NWidgetStacked>(-1);
3471 *shade_select = shade_stack.get();
3473 shade_stack->
Add(
MakeNWidgets({nwid_begin, nwid_end}, std::make_unique<NWidgetVertical>()));
3474 root->Add(std::move(shade_stack));
3479 return MakeNWidgets({nwid_begin, nwid_end}, std::move(root));
3494 assert(max_length >= 1);
3495 std::unique_ptr<NWidgetVertical> vert =
nullptr;
3496 std::unique_ptr<NWidgetHorizontal> hor =
nullptr;
3503 for (
WidgetID widnum = widget_first; widnum <= widget_last; widnum++) {
3505 if (hor_length == max_length) {
3506 if (vert ==
nullptr) vert = std::make_unique<NWidgetVertical>();
3507 vert->Add(std::move(hor));
3511 if (hor ==
nullptr) {
3512 hor = std::make_unique<NWidgetHorizontal>();
3516 auto panel = std::make_unique<NWidgetBackground>(
WWT_PANEL, button_colour, widnum);
3517 panel->SetMinimalSize(sprite_size.width, sprite_size.height);
3518 panel->SetFill(1, 1);
3519 if (resizable) panel->SetResize(1, 0);
3520 panel->SetToolTip(button_tooltip);
3521 hor->Add(std::move(panel));
3524 if (vert ==
nullptr)
return hor;
3526 if (hor_length > 0 && hor_length < max_length) {
3528 auto spc = std::make_unique<NWidgetSpacer>(sprite_size.width, sprite_size.height);
3530 if (resizable) spc->SetResize(1, 0);
3531 hor->Add(std::move(spc));
3533 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.