23 #include "table/strings.h"
112 case SA_LEFT: p.x = r.left;
break;
114 case SA_RIGHT: p.x = r.right + 1 - d.width;
break;
115 default: NOT_REACHED();
118 case SA_TOP: p.y = r.top;
break;
120 case SA_BOTTOM: p.y = r.bottom + 1 - d.height;
break;
121 default: NOT_REACHED();
138 int rev_base = top + bottom;
141 button_size = NWidgetScrollbar::GetHorizontalDimension().width;
143 button_size = NWidgetScrollbar::GetVerticalDimension().height;
146 bottom -= button_size;
148 int height = (bottom - top);
153 if (count != 0) top += height * pos / count;
155 if (cap > count) cap = count;
156 if (count != 0) bottom -= (count - pos - cap) * height / count;
160 pt.x = rev_base - bottom;
161 pt.y = rev_base - top;
183 bool changed =
false;
188 button_size = NWidgetScrollbar::GetHorizontalDimension().width;
191 button_size = NWidgetScrollbar::GetVerticalDimension().height;
193 if (pos < mi + button_size) {
196 if (_scroller_click_timeout <= 1) {
197 _scroller_click_timeout = 3;
201 }
else if (pos >= ma - button_size) {
205 if (_scroller_click_timeout <= 1) {
206 _scroller_click_timeout = 3;
215 }
else if (pos > pt.y) {
218 _scrollbar_start_pos = pt.x - mi - button_size;
219 _scrollbar_size = ma - mi - button_size * 2;
221 _cursorpos_drag_start = _cursor.
pos;
254 assert(scrollbar !=
nullptr);
269 return (nw !=
nullptr) ? nw->
index : -1;
283 assert(colour < COLOUR_END);
295 Rect outer = {left, top, right, bottom};
299 GfxFillRect(outer.left, outer.top, inner.left - 1, outer.bottom, dark);
300 GfxFillRect(inner.left, outer.top, outer.right, inner.top - 1, dark);
301 GfxFillRect(inner.right + 1, inner.top, outer.right, inner.bottom, light);
302 GfxFillRect(inner.left, inner.bottom + 1, outer.right, outer.bottom, light);
303 interior = (flags &
FR_DARKENED ? medium_dark : medium_light);
305 GfxFillRect(outer.left, outer.top, inner.left - 1, inner.bottom, light);
306 GfxFillRect(inner.left, outer.top, inner.right, inner.top - 1, light);
307 GfxFillRect(inner.right + 1, outer.top, outer.right, inner.bottom, dark);
308 GfxFillRect(outer.left, inner.bottom + 1, outer.right, outer.bottom, dark);
309 interior = medium_dark;
312 GfxFillRect(inner.left, inner.top, inner.right, inner.bottom, interior);
322 d.height -= offset.y;
325 DrawSprite(img, pal, p.x - offset.x, p.y - offset.y);
342 if ((type & WWT_MASK) ==
WWT_IMGBTN_2 && clicked) img++;
343 DrawSpriteIgnorePadding(img, PAL_NONE, r, align);
358 if (str == STR_NULL)
return;
362 DrawString(r.left, r.right, p.y, str, colour, align,
false, fs);
377 if (str != STR_NULL)
DrawString(r.left, r.right, p.y, str, colour, align,
false, fs);
404 static inline void DrawMatrix(
const Rect &r, Colours colour,
bool clicked, uint16_t data, uint resize_x, uint resize_y)
410 if (num_columns == 0) {
411 column_width = resize_x;
412 num_columns = r.
Width() / column_width;
414 column_width = r.
Width() / num_columns;
420 row_height = resize_y;
421 num_rows = r.
Height() / row_height;
423 row_height = r.
Height() / num_rows;
429 for (
int ctr = num_columns; ctr > 1; ctr--) {
435 for (
int ctr = num_rows; ctr > 1; ctr--) {
443 for (
int ctr = num_columns; ctr > 1; ctr--) {
449 for (
int ctr = num_rows; ctr > 1; ctr--) {
466 int height = NWidgetScrollbar::GetVerticalDimension().height;
476 GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c2);
480 int left = r.left + r.
Width() * 3 / 11;
481 int right = r.left + r.
Width() * 8 / 11;
486 GfxFillRect(left - bl, r.top + height, left - 1, r.bottom - height, c1);
487 GfxFillRect(left, r.top + height, left + br - 1, r.bottom - height, c2);
488 GfxFillRect(right - bl, r.top + height, right - 1, r.bottom - height, c1);
489 GfxFillRect(right, r.top + height, right + br - 1, r.bottom - height, c2);
506 int width = NWidgetScrollbar::GetHorizontalDimension().width;
515 GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c2);
519 int top = r.top + r.
Height() * 3 / 11;
520 int bottom = r.top + r.
Height() * 8 / 11;
525 GfxFillRect(r.left + width, top - bt, r.right - width, top - 1, c1);
526 GfxFillRect(r.left + width, top, r.right - width, top + bb - 1, c2);
527 GfxFillRect(r.left + width, bottom - bt, r.right - width, bottom - 1, c1);
528 GfxFillRect(r.left + width, bottom, r.right - width, bottom + bb - 1, c2);
579 GfxFillRect(outer.left, inner.top, inner.left - 1, inner.bottom, c1);
580 GfxFillRect(inner.left, inside.top, inside.left - 1, inside.bottom, c2);
583 GfxFillRect(inside.right + 1, inner.top, inner.right, inside.bottom, c1);
584 GfxFillRect(inner.right + 1, outer.top, outer.right, inner.bottom, c2);
587 GfxFillRect(inner.left, inside.bottom + 1, inner.right, inner.bottom, c1);
588 GfxFillRect(outer.left, inner.bottom + 1, outer.right, outer.bottom, c2);
643 static inline void DrawResizeBox(
const Rect &r, Colours colour,
bool at_left,
bool clicked,
bool bevel)
647 }
else if (clicked) {
660 if (colour != COLOUR_WHITE)
DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_NONE);
664 d.height -= offset.y;
691 if (str != STR_NULL) {
716 if (str != STR_NULL) {
722 if (str != STR_NULL) {
743 if (!widget->IsHighlighted())
continue;
745 Rect outer = widget->GetCurrentRect();
750 GfxFillRect(outer.left, outer.top, inner.left, inner.bottom, colour);
751 GfxFillRect(inner.left + 1, outer.top, inner.right - 1, inner.top, colour);
752 GfxFillRect(inner.right, outer.top, outer.right, inner.bottom, colour);
753 GfxFillRect(outer.left + 1, inner.bottom, outer.right - 1, outer.bottom, colour);
768 Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect();
771 Dimension dim = NWidgetScrollbar::GetVerticalDimension();
782 return NWidgetScrollbar::GetVerticalDimension().width + 1;
785 bool _draw_widget_outlines;
925 return (this->
type == tp) ? this :
nullptr;
928 void NWidgetBase::AdjustPaddingForZoom()
945 void NWidgetResizeBase::AdjustPaddingForZoom()
951 NWidgetBase::AdjustPaddingForZoom();
975 this->min_x = std::max(this->min_x,
min_x);
976 this->min_y = std::max(this->min_y,
min_y);
1028 d.height *= max_lines;
1044 if (
min_x == this->min_x &&
min_y == this->min_y)
return false;
1045 this->min_x =
min_x;
1046 this->min_y =
min_y;
1058 if (
min_y == this->min_y)
return false;
1059 this->min_y =
min_y;
1126 this->align =
align;
1131 if (this->
index >= 0) widget_lookup[this->
index] =
this;
1141 if (this->
type == tp)
return this;
1142 for (
const auto &child_wid : this->
children) {
1144 if (nwid !=
nullptr)
return nwid;
1149 void NWidgetContainer::AdjustPaddingForZoom()
1151 for (
const auto &child_wid : this->
children) {
1152 child_wid->AdjustPaddingForZoom();
1154 NWidgetBase::AdjustPaddingForZoom();
1163 assert(wid !=
nullptr);
1165 this->children.push_back(std::move(wid));
1170 for (
const auto &child_wid : this->children) {
1171 child_wid->FillWidgetLookup(widget_lookup);
1177 for (
const auto &child_wid : this->children) {
1181 DrawOutline(w,
this);
1188 for (
const auto &child_wid : this->children) {
1190 if (nwid !=
nullptr)
return nwid;
1202 void NWidgetStacked::AdjustPaddingForZoom()
1204 for (
const auto &child_wid : this->children) {
1205 child_wid->AdjustPaddingForZoom();
1207 NWidgetContainer::AdjustPaddingForZoom();
1223 this->
fill_x = fill.width;
1224 this->
fill_y = fill.height;
1237 for (
const auto &child_wid : this->children) {
1238 child_wid->SetupSmallestSize(w);
1240 this->
smallest_x = std::max(this->
smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1241 this->
smallest_y = std::max(this->
smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1242 this->
fill_x = std::lcm(this->
fill_x, child_wid->fill_x);
1243 this->
fill_y = std::lcm(this->
fill_y, child_wid->fill_y);
1256 for (
const auto &child_wid : this->children) {
1257 uint hor_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
1258 uint child_width =
ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step);
1259 uint child_pos_x = (rtl ? child_wid->padding.right : child_wid->padding.left);
1261 uint vert_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
1262 uint child_height =
ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding.Vertical(), vert_step);
1263 uint child_pos_y = child_wid->padding.top;
1265 child_wid->AssignSizePosition(sizing, x + child_pos_x, y + child_pos_y, child_width, child_height, rtl);
1271 if (this->
index >= 0) widget_lookup[this->
index] =
this;
1279 assert(
static_cast<size_t>(this->
shown_plane) < this->children.size());
1281 DrawOutline(w,
this);
1290 if (
static_cast<size_t>(this->
shown_plane) >= this->children.size())
return nullptr;
1308 this->flags = flags;
1311 void NWidgetPIPContainer::AdjustPaddingForZoom()
1316 NWidgetContainer::AdjustPaddingForZoom();
1372 uint max_vert_fill = 0;
1373 for (
const auto &child_wid : this->children) {
1374 child_wid->SetupSmallestSize(w);
1375 longest = std::max(longest, child_wid->smallest_x);
1376 max_vert_fill = std::max(max_vert_fill, child_wid->GetVerticalStepSize(
ST_SMALLEST));
1377 this->
smallest_y = std::max(this->
smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1378 if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) this->
gaps++;
1382 [[maybe_unused]] uint max_smallest = this->
smallest_y + 3 * max_vert_fill;
1385 for (
const auto &child_wid : this->children) {
1386 uint step_size = child_wid->GetVerticalStepSize(
ST_SMALLEST);
1387 uint child_height = child_wid->smallest_y + child_wid->padding.Vertical();
1388 if (step_size > 1 && child_height < cur_height) {
1389 uint remainder = (cur_height - child_height) % step_size;
1390 if (remainder > 0) {
1391 cur_height += step_size - remainder;
1392 assert(cur_height < max_smallest);
1402 for (
const auto &child_wid : this->children) {
1403 if (child_wid->fill_x == 1) child_wid->smallest_x = longest;
1407 for (
const auto &child_wid : this->children) {
1408 this->
smallest_x += child_wid->smallest_x + child_wid->padding.Horizontal();
1409 if (child_wid->fill_x > 0) {
1410 if (this->
fill_x == 0 || this->
fill_x > child_wid->fill_x) this->
fill_x = child_wid->fill_x;
1412 this->
fill_y = std::lcm(this->
fill_y, child_wid->fill_y);
1414 if (child_wid->resize_x > 0) {
1430 for (
const auto &child_wid : this->children) {
1431 if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) additional_length -= child_wid->smallest_x + child_wid->padding.Horizontal();
1450 int num_changing_childs = 0;
1451 uint biggest_stepsize = 0;
1452 for (
const auto &child_wid : this->children) {
1453 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1456 biggest_stepsize = std::max(biggest_stepsize, hor_step);
1458 child_wid->current_x = child_wid->smallest_x;
1461 uint vert_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
1462 child_wid->current_y =
ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding.Vertical(), vert_step);
1467 for (
const auto &child_wid : this->children) {
1468 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1469 if (hor_step == biggest_stepsize) {
1470 num_changing_childs++;
1476 while (biggest_stepsize > 0) {
1477 uint next_biggest_stepsize = 0;
1478 for (
const auto &child_wid : this->children) {
1479 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1480 if (hor_step > biggest_stepsize)
continue;
1481 if (hor_step == biggest_stepsize) {
1482 uint increment = additional_length / num_changing_childs;
1483 num_changing_childs--;
1484 if (hor_step > 1) increment -= increment % hor_step;
1485 child_wid->current_x = child_wid->smallest_x + increment;
1486 additional_length -= increment;
1489 next_biggest_stepsize = std::max(next_biggest_stepsize, hor_step);
1491 biggest_stepsize = next_biggest_stepsize;
1493 if (num_changing_childs == 0 && (
flags &
NC_BIGFIRST) && biggest_stepsize > 0) {
1495 for (
const auto &child_wid : this->children) {
1496 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1497 if (hor_step == biggest_stepsize) {
1498 num_changing_childs++;
1503 assert(num_changing_childs == 0);
1508 if (additional_length > 0) {
1519 uint position = rtl ? this->
current_x - pre : pre;
1520 for (
const auto &child_wid : this->children) {
1521 uint child_width = child_wid->current_x;
1522 uint child_x = x + (rtl ? position - child_width - child_wid->padding.left : position + child_wid->padding.left);
1523 uint child_y = y + child_wid->padding.top;
1525 child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl);
1526 if (child_wid->current_x != 0) {
1527 uint padded_child_width = child_width + child_wid->padding.Horizontal() + inter;
1528 position = rtl ? position - padded_child_width : position + padded_child_width;
1561 uint max_hor_fill = 0;
1562 for (
const auto &child_wid : this->children) {
1563 child_wid->SetupSmallestSize(w);
1564 highest = std::max(highest, child_wid->smallest_y);
1565 max_hor_fill = std::max(max_hor_fill, child_wid->GetHorizontalStepSize(
ST_SMALLEST));
1566 this->
smallest_x = std::max(this->
smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1567 if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) this->
gaps++;
1571 [[maybe_unused]] uint max_smallest = this->
smallest_x + 3 * max_hor_fill;
1574 for (
const auto &child_wid : this->children) {
1575 uint step_size = child_wid->GetHorizontalStepSize(
ST_SMALLEST);
1576 uint child_width = child_wid->smallest_x + child_wid->padding.Horizontal();
1577 if (step_size > 1 && child_width < cur_width) {
1578 uint remainder = (cur_width - child_width) % step_size;
1579 if (remainder > 0) {
1580 cur_width += step_size - remainder;
1581 assert(cur_width < max_smallest);
1591 for (
const auto &child_wid : this->children) {
1592 if (child_wid->fill_y == 1) child_wid->smallest_y = highest;
1596 for (
const auto &child_wid : this->children) {
1597 this->
smallest_y += child_wid->smallest_y + child_wid->padding.Vertical();
1598 if (child_wid->fill_y > 0) {
1599 if (this->
fill_y == 0 || this->
fill_y > child_wid->fill_y) this->
fill_y = child_wid->fill_y;
1601 this->
fill_x = std::lcm(this->
fill_x, child_wid->fill_x);
1603 if (child_wid->resize_y > 0) {
1619 for (
const auto &child_wid : this->children) {
1620 if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) additional_length -= child_wid->smallest_y + child_wid->padding.Vertical();
1630 int num_changing_childs = 0;
1631 uint biggest_stepsize = 0;
1632 for (
const auto &child_wid : this->children) {
1633 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1634 if (vert_step > 0) {
1636 biggest_stepsize = std::max(biggest_stepsize, vert_step);
1638 child_wid->current_y = child_wid->smallest_y;
1641 uint hor_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
1642 child_wid->current_x =
ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step);
1647 for (
const auto &child_wid : this->children) {
1648 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1649 if (vert_step == biggest_stepsize) {
1650 num_changing_childs++;
1656 while (biggest_stepsize > 0) {
1657 uint next_biggest_stepsize = 0;
1658 for (
const auto &child_wid : this->children) {
1659 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1660 if (vert_step > biggest_stepsize)
continue;
1661 if (vert_step == biggest_stepsize) {
1662 uint increment = additional_length / num_changing_childs;
1663 num_changing_childs--;
1664 if (vert_step > 1) increment -= increment % vert_step;
1665 child_wid->current_y = child_wid->smallest_y + increment;
1666 additional_length -= increment;
1669 next_biggest_stepsize = std::max(next_biggest_stepsize, vert_step);
1671 biggest_stepsize = next_biggest_stepsize;
1673 if (num_changing_childs == 0 && (
flags &
NC_BIGFIRST) && biggest_stepsize > 0) {
1675 for (
const auto &child_wid : this->children) {
1676 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1677 if (vert_step == biggest_stepsize) {
1678 num_changing_childs++;
1683 assert(num_changing_childs == 0);
1688 if (additional_length > 0) {
1699 uint position = pre;
1700 for (
const auto &child_wid : this->children) {
1701 uint child_x = x + (rtl ? child_wid->padding.right : child_wid->padding.left);
1702 uint child_height = child_wid->current_y;
1704 child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding.top, child_wid->current_x, child_height, rtl);
1705 if (child_wid->current_y != 0) {
1706 position += child_height + child_wid->padding.Vertical() + inter;
1740 DrawOutline(w,
this);
1756 this->colour = colour;
1766 if (this->clicked >= 0 && this->
sb !=
nullptr && this->
widgets_x != 0) {
1782 this->count =
count;
1784 if (this->
sb ==
nullptr || this->
widgets_x == 0)
return;
1792 count *= (this->
sb->
IsVertical() ? this->children.front()->smallest_y : this->children.front()->smallest_x) + this->
pip_inter;
1820 assert(this->children.size() == 1);
1822 this->children.front()->SetupSmallestSize(w);
1825 Dimension size = {this->children.front()->smallest_x +
padding.width, this->children.front()->smallest_y +
padding.height};
1833 this->
fill_x = fill.width;
1834 this->
fill_y = fill.height;
1865 if (this->
index >= 0) widget_lookup[this->
index] =
this;
1874 int start_x, start_y, base_offs_x, base_offs_y;
1879 int widget_col = (rtl ?
1890 assert(child !=
nullptr);
1914 assert(child !=
nullptr);
1915 int start_x, start_y, base_offs_x, base_offs_y;
1918 int offs_y = base_offs_y;
1919 for (
int y = start_y; y < start_y + this->
widgets_y + 1; y++, offs_y += this->
widget_h) {
1921 if (offs_y + child->
smallest_y <= 0)
continue;
1922 if (offs_y >= (
int)this->
current_y)
break;
1927 int offs_x = base_offs_x;
1930 if (offs_x + child->
smallest_x <= 0)
continue;
1931 if (offs_x >= (
int)this->
current_x)
continue;
1944 DrawOutline(w,
this);
1960 if (this->
sb !=
nullptr) {
1968 base_offs_x += sub_x;
1970 base_offs_x -= sub_x;
1989 if (this->
child !=
nullptr) this->
child->parent =
this;
2002 if (this->
child ==
nullptr) {
2003 this->
child = std::make_unique<NWidgetVertical>();
2005 nwid->parent = this->
child.get();
2006 this->
child->Add(std::move(nwid));
2021 if (this->
child ==
nullptr) {
2022 this->
child = std::make_unique<NWidgetVertical>();
2024 this->
child->parent =
this;
2025 this->
child->SetPIP(pip_pre, pip_inter, pip_post);
2040 if (this->
child ==
nullptr) {
2041 this->
child = std::make_unique<NWidgetVertical>();
2043 this->
child->parent =
this;
2044 this->
child->SetPIPRatio(pip_ratio_pre, pip_ratio_inter, pip_ratio_post);
2047 void NWidgetBackground::AdjustPaddingForZoom()
2049 if (
child !=
nullptr)
child->AdjustPaddingForZoom();
2050 NWidgetCore::AdjustPaddingForZoom();
2055 if (this->
child !=
nullptr) {
2056 this->
child->SetupSmallestSize(w);
2066 if (w ==
nullptr)
return;
2080 this->
child->padding = WidgetDimensions::scaled.
bevel;
2094 d =
maxdim(d, background);
2096 if (this->
index >= 0) {
2098 switch (this->
type) {
2099 default: NOT_REACHED();
2109 this->
fill_x = fill.width;
2110 this->
fill_y = fill.height;
2120 if (this->
child !=
nullptr) {
2121 uint x_offset = (rtl ? this->
child->padding.right : this->
child->padding.left);
2122 uint width = given_width - this->
child->padding.Horizontal();
2123 uint height = given_height - this->
child->padding.Vertical();
2124 this->
child->AssignSizePosition(sizing, x + x_offset, y + this->
child->padding.top, width, height, rtl);
2130 if (this->
index >= 0) widget_lookup[this->
index] =
this;
2131 if (this->
child !=
nullptr) this->
child->FillWidgetLookup(widget_lookup);
2138 Rect r = this->GetCurrentRect();
2141 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top)
return;
2143 switch (this->
type) {
2164 if (this->
child !=
nullptr) this->
child->Draw(w);
2170 DrawOutline(w,
this);
2177 if (this->
child !=
nullptr) nwid = this->
child->GetWidgetFromPos(x, y);
2178 if (nwid ==
nullptr) nwid =
this;
2186 if (this->
child !=
nullptr) nwid = this->
child->GetWidgetOfType(tp);
2187 if (nwid ==
nullptr && this->
type == tp) nwid =
this;
2219 DrawOutline(w,
this);
2240 if (vp !=
nullptr) {
2283 int new_pos = list_position;
2354 switch (this->
type) {
2358 this->
SetDataTip(0x0, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST);
2364 this->
SetDataTip(0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST);
2367 default: NOT_REACHED();
2376 switch (this->
type) {
2378 this->
SetMinimalSizeAbsolute(NWidgetScrollbar::GetHorizontalDimension().width * 3, NWidgetScrollbar::GetHorizontalDimension().height);
2382 this->
SetMinimalSizeAbsolute(NWidgetScrollbar::GetVerticalDimension().width, NWidgetScrollbar::GetVerticalDimension().height * 3);
2385 default: NOT_REACHED();
2396 Rect r = this->GetCurrentRect();
2399 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top)
return;
2415 DrawOutline(w,
this);
2418 void NWidgetScrollbar::InvalidateDimensionCache()
2424 Dimension NWidgetScrollbar::GetVerticalDimension()
2434 Dimension NWidgetScrollbar::GetHorizontalDimension()
2475 NWidgetLeaf::NWidgetLeaf(
WidgetType tp, Colours colour,
WidgetID index, uint32_t data,
StringID tip) :
NWidgetCore(tp, colour, index, 1, 1, data, tip)
2501 case NWID_PUSHBUTTON_DROPDOWN:
2516 this->
SetDataTip(data, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
2522 this->
SetDataTip(STR_NULL, STR_TOOLTIP_STICKY);
2528 this->
SetDataTip(STR_NULL, STR_TOOLTIP_SHADE);
2534 this->
SetDataTip(STR_NULL, STR_TOOLTIP_DEBUG);
2540 this->
SetDataTip(STR_NULL, STR_TOOLTIP_DEFSIZE);
2552 this->
SetDataTip(STR_NULL, STR_TOOLTIP_CLOSE_WINDOW);
2572 switch (this->
type) {
2641 size.width = std::max(size.width,
ScaleGUITrad(30) + sprite_size.width);
2708 case NWID_PUSHBUTTON_DROPDOWN: {
2730 this->
fill_x = fill.width;
2731 this->
fill_y = fill.height;
2745 new_dpi.left += this->
pos_x;
2746 new_dpi.top += this->
pos_y;
2750 Rect r = this->GetCurrentRect();
2753 switch (this->
type) {
2756 if (this->
index == -1 && _draw_widget_outlines) {
2786 case AWV_LEFT: sprite = SPR_ARROW_LEFT;
break;
2787 case AWV_RIGHT: sprite = SPR_ARROW_RIGHT;
break;
2788 default: NOT_REACHED();
2810 if (query !=
nullptr) query->DrawEditBox(w, this->
index);
2816 DrawCaption(r, this->
colour, w->
owner, this->text_colour, this->widget_data, this->align, this->text_size);
2852 case NWID_PUSHBUTTON_DROPDOWN:
2866 DrawOutline(w,
this);
2879 int button_width = this->
pos_x + this->
current_x - NWidgetLeaf::dropdown_dimension.width;
2880 return pt.x < button_width;
2882 int button_left = this->
pos_x + NWidgetLeaf::dropdown_dimension.width;
2883 return pt.x >= button_left;
2907 while (nwid_begin < nwid_end) {
2908 switch (nwid_begin->
type) {
2910 if (dest !=
nullptr)
return nwid_begin;
2911 dest = std::make_unique<NWidgetSpacer>(0, 0);
2915 if (dest !=
nullptr)
return nwid_begin;
2916 dest = std::make_unique<NWidgetHorizontal>(nwid_begin->u.
cont_flags);
2921 if (dest !=
nullptr)
return nwid_begin;
2922 dest = std::make_unique<NWidgetHorizontalLTR>(nwid_begin->u.
cont_flags);
2929 if (dest !=
nullptr)
return nwid_begin;
2935 if (dest !=
nullptr)
return nwid_begin;
2936 dest = std::make_unique<NWidgetVertical>(nwid_begin->u.
cont_flags);
2941 if (dest !=
nullptr)
return nwid_begin;
2948 if (dest !=
nullptr)
return nwid_begin;
2956 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_RESIZE requires NWidgetResizeBase");
2957 assert(nwid_begin->u.
xy.x >= 0 && nwid_begin->u.
xy.y >= 0);
2964 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_MINSIZE requires NWidgetResizeBase");
2965 assert(nwid_begin->u.
xy.x >= 0 && nwid_begin->u.
xy.y >= 0);
2972 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_MINTEXTLINES requires NWidgetResizeBase");
2980 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_TEXTSTYLE requires NWidgetCore");
2987 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_ALIGNMENT requires NWidgetCore");
2994 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_FILL requires NWidgetResizeBase");
2995 nwrb->
SetFill(nwid_begin->u.
xy.x, nwid_begin->u.
xy.y);
3001 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_DATATIP requires NWidgetCore");
3008 if (dest ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PADDING requires NWidgetBase");
3009 dest->SetPadding(nwid_begin->u.
padding);
3014 if (nwc !=
nullptr) nwc->
SetPIP(nwid_begin->u.
pip.pre, nwid_begin->u.
pip.inter, nwid_begin->u.
pip.
post);
3017 if (nwb !=
nullptr) nwb->
SetPIP(nwid_begin->u.
pip.pre, nwid_begin->u.
pip.inter, nwid_begin->u.
pip.
post);
3019 if (nwc ==
nullptr && nwb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PIPSPACE requires NWidgetPIPContainer or NWidgetBackground");
3030 if (nwc ==
nullptr && nwb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PIPRATIO requires NWidgetPIPContainer or NWidgetBackground");
3036 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_SCROLLBAR requires NWidgetCore");
3045 if (dest !=
nullptr)
return nwid_begin;
3046 dest = std::make_unique<NWidgetViewport>(nwid_begin->u.
widget.
index);
3051 if (dest !=
nullptr)
return nwid_begin;
3056 if (dest !=
nullptr)
return nwid_begin;
3057 dest = std::make_unique<NWidgetStacked>(nwid_begin->u.
widget.
index);
3063 if (dest !=
nullptr)
return nwid_begin;
3098 assert(parent ==
nullptr || (nwid_cont !=
nullptr && nwid_parent ==
nullptr) || (nwid_cont ==
nullptr && nwid_parent !=
nullptr));
3101 std::unique_ptr<NWidgetBase> sub_widget =
nullptr;
3102 bool fill_sub =
false;
3103 nwid_begin =
MakeNWidget(nwid_begin, nwid_end, sub_widget, &fill_sub);
3106 if (sub_widget ==
nullptr)
break;
3114 if (nwid_cont !=
nullptr) nwid_cont->
Add(std::move(sub_widget));
3115 if (nwid_parent !=
nullptr) nwid_parent->
Add(std::move(sub_widget));
3116 if (nwid_cont ==
nullptr && nwid_parent ==
nullptr) {
3117 parent = std::move(sub_widget);
3122 if (nwid_begin == nwid_end)
return nwid_begin;
3124 assert(nwid_begin < nwid_end);
3126 return nwid_begin + 1;
3139 if (container ==
nullptr) container = std::make_unique<NWidgetVertical>();
3142 if (nwid_part != nwid_end) [[unlikely]]
throw std::runtime_error(
"Did not consume all NWidgetParts");
3144 return std::move(container);
3159 *shade_select =
nullptr;
3162 std::unique_ptr<NWidgetBase> nwid =
nullptr;
3164 assert(nwid !=
nullptr);
3168 auto root = std::make_unique<NWidgetVertical>();
3169 root->Add(std::move(nwid));
3170 if (nwid_begin == nwid_end)
return root;
3174 auto shade_stack = std::make_unique<NWidgetStacked>(-1);
3175 *shade_select = shade_stack.get();
3177 shade_stack->
Add(
MakeNWidgets(nwid_begin, nwid_end, std::make_unique<NWidgetVertical>()));
3178 root->Add(std::move(shade_stack));
3183 return MakeNWidgets(nwid_begin, nwid_end, std::move(root));
3198 assert(max_length >= 1);
3199 std::unique_ptr<NWidgetVertical> vert =
nullptr;
3200 std::unique_ptr<NWidgetHorizontal> hor =
nullptr;
3207 for (
WidgetID widnum = widget_first; widnum <= widget_last; widnum++) {
3209 if (hor_length == max_length) {
3210 if (vert ==
nullptr) vert = std::make_unique<NWidgetVertical>();
3211 vert->Add(std::move(hor));
3215 if (hor ==
nullptr) {
3216 hor = std::make_unique<NWidgetHorizontal>();
3220 auto panel = std::make_unique<NWidgetBackground>(
WWT_PANEL, button_colour, widnum);
3221 panel->SetMinimalSize(sprite_size.width, sprite_size.height);
3222 panel->SetFill(1, 1);
3223 if (resizable) panel->SetResize(1, 0);
3224 panel->SetDataTip(0x0, button_tooltip);
3225 hor->Add(std::move(panel));
3228 if (vert ==
nullptr)
return hor;
3230 if (hor_length > 0 && hor_length < max_length) {
3232 auto spc = std::make_unique<NWidgetSpacer>(sprite_size.width, sprite_size.height);
3234 if (resizable) spc->SetResize(1, 0);
3235 hor->Add(std::move(spc));
3237 if (hor !=
nullptr) vert->Add(std::move(hor));