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);
1274 if (this->
index >= 0) widget_lookup[this->
index] =
this;
1284 assert(
static_cast<size_t>(this->
shown_plane) < this->children.size());
1286 DrawOutline(w,
this);
1295 if (
static_cast<size_t>(this->
shown_plane) >= this->children.size())
return nullptr;
1315 this->flags = flags;
1318 void NWidgetPIPContainer::AdjustPaddingForZoom()
1323 NWidgetContainer::AdjustPaddingForZoom();
1379 uint max_vert_fill = 0;
1380 for (
const auto &child_wid : this->children) {
1381 child_wid->SetupSmallestSize(w);
1382 longest = std::max(longest, child_wid->smallest_x);
1383 max_vert_fill = std::max(max_vert_fill, child_wid->GetVerticalStepSize(
ST_SMALLEST));
1384 this->
smallest_y = std::max(this->
smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1385 if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) this->
gaps++;
1389 [[maybe_unused]] uint max_smallest = this->
smallest_y + 3 * max_vert_fill;
1392 for (
const auto &child_wid : this->children) {
1393 uint step_size = child_wid->GetVerticalStepSize(
ST_SMALLEST);
1394 uint child_height = child_wid->smallest_y + child_wid->padding.Vertical();
1395 if (step_size > 1 && child_height < cur_height) {
1396 uint remainder = (cur_height - child_height) % step_size;
1397 if (remainder > 0) {
1398 cur_height += step_size - remainder;
1399 assert(cur_height < max_smallest);
1409 for (
const auto &child_wid : this->children) {
1410 if (child_wid->fill_x == 1) child_wid->smallest_x = longest;
1414 for (
const auto &child_wid : this->children) {
1415 this->
smallest_x += child_wid->smallest_x + child_wid->padding.Horizontal();
1416 if (child_wid->fill_x > 0) {
1417 if (this->
fill_x == 0 || this->
fill_x > child_wid->fill_x) this->
fill_x = child_wid->fill_x;
1419 this->
fill_y = std::lcm(this->
fill_y, child_wid->fill_y);
1421 if (child_wid->resize_x > 0) {
1437 for (
const auto &child_wid : this->children) {
1438 if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) additional_length -= child_wid->smallest_x + child_wid->padding.Horizontal();
1457 int num_changing_childs = 0;
1458 uint biggest_stepsize = 0;
1459 for (
const auto &child_wid : this->children) {
1460 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1463 biggest_stepsize = std::max(biggest_stepsize, hor_step);
1465 child_wid->current_x = child_wid->smallest_x;
1468 uint vert_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing);
1469 child_wid->current_y =
ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding.Vertical(), vert_step);
1474 for (
const auto &child_wid : this->children) {
1475 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1476 if (hor_step == biggest_stepsize) {
1477 num_changing_childs++;
1483 while (biggest_stepsize > 0) {
1484 uint next_biggest_stepsize = 0;
1485 for (
const auto &child_wid : this->children) {
1486 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1487 if (hor_step > biggest_stepsize)
continue;
1488 if (hor_step == biggest_stepsize) {
1489 uint increment = additional_length / num_changing_childs;
1490 num_changing_childs--;
1491 if (hor_step > 1) increment -= increment % hor_step;
1492 child_wid->current_x = child_wid->smallest_x + increment;
1493 additional_length -= increment;
1496 next_biggest_stepsize = std::max(next_biggest_stepsize, hor_step);
1498 biggest_stepsize = next_biggest_stepsize;
1500 if (num_changing_childs == 0 && (
flags &
NC_BIGFIRST) && biggest_stepsize > 0) {
1502 for (
const auto &child_wid : this->children) {
1503 uint hor_step = child_wid->GetHorizontalStepSize(sizing);
1504 if (hor_step == biggest_stepsize) {
1505 num_changing_childs++;
1510 assert(num_changing_childs == 0);
1515 if (additional_length > 0) {
1526 uint position = rtl ? this->
current_x - pre : pre;
1527 for (
const auto &child_wid : this->children) {
1528 uint child_width = child_wid->current_x;
1529 uint child_x = x + (rtl ? position - child_width - child_wid->padding.left : position + child_wid->padding.left);
1530 uint child_y = y + child_wid->padding.top;
1532 child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl);
1533 if (child_wid->current_x != 0) {
1534 uint padded_child_width = child_width + child_wid->padding.Horizontal() + inter;
1535 position = rtl ? position - padded_child_width : position + padded_child_width;
1568 uint max_hor_fill = 0;
1569 for (
const auto &child_wid : this->children) {
1570 child_wid->SetupSmallestSize(w);
1571 highest = std::max(highest, child_wid->smallest_y);
1572 max_hor_fill = std::max(max_hor_fill, child_wid->GetHorizontalStepSize(
ST_SMALLEST));
1573 this->
smallest_x = std::max(this->
smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1574 if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) this->
gaps++;
1578 [[maybe_unused]] uint max_smallest = this->
smallest_x + 3 * max_hor_fill;
1581 for (
const auto &child_wid : this->children) {
1582 uint step_size = child_wid->GetHorizontalStepSize(
ST_SMALLEST);
1583 uint child_width = child_wid->smallest_x + child_wid->padding.Horizontal();
1584 if (step_size > 1 && child_width < cur_width) {
1585 uint remainder = (cur_width - child_width) % step_size;
1586 if (remainder > 0) {
1587 cur_width += step_size - remainder;
1588 assert(cur_width < max_smallest);
1598 for (
const auto &child_wid : this->children) {
1599 if (child_wid->fill_y == 1) child_wid->smallest_y = highest;
1603 for (
const auto &child_wid : this->children) {
1604 this->
smallest_y += child_wid->smallest_y + child_wid->padding.Vertical();
1605 if (child_wid->fill_y > 0) {
1606 if (this->
fill_y == 0 || this->
fill_y > child_wid->fill_y) this->
fill_y = child_wid->fill_y;
1608 this->
fill_x = std::lcm(this->
fill_x, child_wid->fill_x);
1610 if (child_wid->resize_y > 0) {
1626 for (
const auto &child_wid : this->children) {
1627 if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) additional_length -= child_wid->smallest_y + child_wid->padding.Vertical();
1637 int num_changing_childs = 0;
1638 uint biggest_stepsize = 0;
1639 for (
const auto &child_wid : this->children) {
1640 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1641 if (vert_step > 0) {
1643 biggest_stepsize = std::max(biggest_stepsize, vert_step);
1645 child_wid->current_y = child_wid->smallest_y;
1648 uint hor_step = (sizing ==
ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing);
1649 child_wid->current_x =
ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step);
1654 for (
const auto &child_wid : this->children) {
1655 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1656 if (vert_step == biggest_stepsize) {
1657 num_changing_childs++;
1663 while (biggest_stepsize > 0) {
1664 uint next_biggest_stepsize = 0;
1665 for (
const auto &child_wid : this->children) {
1666 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1667 if (vert_step > biggest_stepsize)
continue;
1668 if (vert_step == biggest_stepsize) {
1669 uint increment = additional_length / num_changing_childs;
1670 num_changing_childs--;
1671 if (vert_step > 1) increment -= increment % vert_step;
1672 child_wid->current_y = child_wid->smallest_y + increment;
1673 additional_length -= increment;
1676 next_biggest_stepsize = std::max(next_biggest_stepsize, vert_step);
1678 biggest_stepsize = next_biggest_stepsize;
1680 if (num_changing_childs == 0 && (
flags &
NC_BIGFIRST) && biggest_stepsize > 0) {
1682 for (
const auto &child_wid : this->children) {
1683 uint vert_step = child_wid->GetVerticalStepSize(sizing);
1684 if (vert_step == biggest_stepsize) {
1685 num_changing_childs++;
1690 assert(num_changing_childs == 0);
1695 if (additional_length > 0) {
1706 uint position = pre;
1707 for (
const auto &child_wid : this->children) {
1708 uint child_x = x + (rtl ? child_wid->padding.right : child_wid->padding.left);
1709 uint child_height = child_wid->current_y;
1711 child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding.top, child_wid->current_x, child_height, rtl);
1712 if (child_wid->current_y != 0) {
1713 position += child_height + child_wid->padding.Vertical() + inter;
1747 DrawOutline(w,
this);
1763 this->colour = colour;
1773 if (this->clicked >= 0 && this->
sb !=
nullptr && this->
widgets_x != 0) {
1789 this->count =
count;
1791 if (this->
sb ==
nullptr || this->
widgets_x == 0)
return;
1799 count *= (this->
sb->
IsVertical() ? this->children.front()->smallest_y : this->children.front()->smallest_x) + this->
pip_inter;
1827 assert(this->children.size() == 1);
1829 this->children.front()->SetupSmallestSize(w);
1832 Dimension size = {this->children.front()->smallest_x +
padding.width, this->children.front()->smallest_y +
padding.height};
1840 this->
fill_x = fill.width;
1841 this->
fill_y = fill.height;
1872 if (this->
index >= 0) widget_lookup[this->
index] =
this;
1881 int start_x, start_y, base_offs_x, base_offs_y;
1886 int widget_col = (rtl ?
1897 assert(child !=
nullptr);
1921 assert(child !=
nullptr);
1922 int start_x, start_y, base_offs_x, base_offs_y;
1925 int offs_y = base_offs_y;
1926 for (
int y = start_y; y < start_y + this->
widgets_y + 1; y++, offs_y += this->
widget_h) {
1928 if (offs_y + child->
smallest_y <= 0)
continue;
1929 if (offs_y >= (
int)this->
current_y)
break;
1934 int offs_x = base_offs_x;
1937 if (offs_x + child->
smallest_x <= 0)
continue;
1938 if (offs_x >= (
int)this->
current_x)
continue;
1951 DrawOutline(w,
this);
1967 if (this->
sb !=
nullptr) {
1975 base_offs_x += sub_x;
1977 base_offs_x -= sub_x;
1996 if (this->
child !=
nullptr) this->
child->parent =
this;
2009 if (this->
child ==
nullptr) {
2010 this->
child = std::make_unique<NWidgetVertical>();
2012 nwid->parent = this->
child.get();
2013 this->
child->Add(std::move(nwid));
2028 if (this->
child ==
nullptr) {
2029 this->
child = std::make_unique<NWidgetVertical>();
2031 this->
child->parent =
this;
2032 this->
child->SetPIP(pip_pre, pip_inter, pip_post);
2047 if (this->
child ==
nullptr) {
2048 this->
child = std::make_unique<NWidgetVertical>();
2050 this->
child->parent =
this;
2051 this->
child->SetPIPRatio(pip_ratio_pre, pip_ratio_inter, pip_ratio_post);
2054 void NWidgetBackground::AdjustPaddingForZoom()
2056 if (
child !=
nullptr)
child->AdjustPaddingForZoom();
2057 NWidgetCore::AdjustPaddingForZoom();
2062 if (this->
child !=
nullptr) {
2063 this->
child->SetupSmallestSize(w);
2073 if (w ==
nullptr)
return;
2087 this->
child->padding = WidgetDimensions::scaled.
bevel;
2101 d =
maxdim(d, background);
2103 if (this->
index >= 0) {
2105 switch (this->
type) {
2106 default: NOT_REACHED();
2116 this->
fill_x = fill.width;
2117 this->
fill_y = fill.height;
2127 if (this->
child !=
nullptr) {
2128 uint x_offset = (rtl ? this->
child->padding.right : this->
child->padding.left);
2129 uint width = given_width - this->
child->padding.Horizontal();
2130 uint height = given_height - this->
child->padding.Vertical();
2131 this->
child->AssignSizePosition(sizing, x + x_offset, y + this->
child->padding.top, width, height, rtl);
2137 if (this->
index >= 0) widget_lookup[this->
index] =
this;
2138 if (this->
child !=
nullptr) this->
child->FillWidgetLookup(widget_lookup);
2145 Rect r = this->GetCurrentRect();
2148 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top)
return;
2150 switch (this->
type) {
2171 if (this->
child !=
nullptr) this->
child->Draw(w);
2177 DrawOutline(w,
this);
2184 if (this->
child !=
nullptr) nwid = this->
child->GetWidgetFromPos(x, y);
2185 if (nwid ==
nullptr) nwid =
this;
2193 if (this->
child !=
nullptr) nwid = this->
child->GetWidgetOfType(tp);
2194 if (nwid ==
nullptr && this->
type == tp) nwid =
this;
2226 DrawOutline(w,
this);
2247 if (vp !=
nullptr) {
2290 int new_pos = list_position;
2361 switch (this->
type) {
2365 this->
SetDataTip(0x0, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST);
2371 this->
SetDataTip(0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST);
2374 default: NOT_REACHED();
2383 switch (this->
type) {
2385 this->
SetMinimalSizeAbsolute(NWidgetScrollbar::GetHorizontalDimension().width * 3, NWidgetScrollbar::GetHorizontalDimension().height);
2389 this->
SetMinimalSizeAbsolute(NWidgetScrollbar::GetVerticalDimension().width, NWidgetScrollbar::GetVerticalDimension().height * 3);
2392 default: NOT_REACHED();
2403 Rect r = this->GetCurrentRect();
2406 if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top)
return;
2422 DrawOutline(w,
this);
2425 void NWidgetScrollbar::InvalidateDimensionCache()
2431 Dimension NWidgetScrollbar::GetVerticalDimension()
2441 Dimension NWidgetScrollbar::GetHorizontalDimension()
2482 NWidgetLeaf::NWidgetLeaf(
WidgetType tp, Colours colour,
WidgetID index, uint32_t data,
StringID tip) :
NWidgetCore(tp, colour, index, 1, 1, data, tip)
2508 case NWID_PUSHBUTTON_DROPDOWN:
2523 this->
SetDataTip(data, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
2529 this->
SetDataTip(STR_NULL, STR_TOOLTIP_STICKY);
2535 this->
SetDataTip(STR_NULL, STR_TOOLTIP_SHADE);
2541 this->
SetDataTip(STR_NULL, STR_TOOLTIP_DEBUG);
2547 this->
SetDataTip(STR_NULL, STR_TOOLTIP_DEFSIZE);
2559 this->
SetDataTip(STR_NULL, STR_TOOLTIP_CLOSE_WINDOW);
2579 switch (this->
type) {
2648 size.width = std::max(size.width,
ScaleGUITrad(30) + sprite_size.width);
2715 case NWID_PUSHBUTTON_DROPDOWN: {
2737 this->
fill_x = fill.width;
2738 this->
fill_y = fill.height;
2752 new_dpi.left += this->
pos_x;
2753 new_dpi.top += this->
pos_y;
2757 Rect r = this->GetCurrentRect();
2760 switch (this->
type) {
2763 if (this->
index == -1 && _draw_widget_outlines) {
2793 case AWV_LEFT: sprite = SPR_ARROW_LEFT;
break;
2794 case AWV_RIGHT: sprite = SPR_ARROW_RIGHT;
break;
2795 default: NOT_REACHED();
2817 if (query !=
nullptr) query->DrawEditBox(w, this->
index);
2823 DrawCaption(r, this->
colour, w->
owner, this->text_colour, this->widget_data, this->align, this->text_size);
2859 case NWID_PUSHBUTTON_DROPDOWN:
2873 DrawOutline(w,
this);
2886 int button_width = this->
pos_x + this->
current_x - NWidgetLeaf::dropdown_dimension.width;
2887 return pt.x < button_width;
2889 int button_left = this->
pos_x + NWidgetLeaf::dropdown_dimension.width;
2890 return pt.x >= button_left;
2914 while (nwid_begin < nwid_end) {
2915 switch (nwid_begin->
type) {
2917 if (dest !=
nullptr)
return nwid_begin;
2918 dest = std::make_unique<NWidgetSpacer>(0, 0);
2922 if (dest !=
nullptr)
return nwid_begin;
2923 dest = std::make_unique<NWidgetHorizontal>(nwid_begin->u.
cont_flags);
2928 if (dest !=
nullptr)
return nwid_begin;
2929 dest = std::make_unique<NWidgetHorizontalLTR>(nwid_begin->u.
cont_flags);
2936 if (dest !=
nullptr)
return nwid_begin;
2942 if (dest !=
nullptr)
return nwid_begin;
2943 dest = std::make_unique<NWidgetVertical>(nwid_begin->u.
cont_flags);
2948 if (dest !=
nullptr)
return nwid_begin;
2955 if (dest !=
nullptr)
return nwid_begin;
2963 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_RESIZE requires NWidgetResizeBase");
2964 assert(nwid_begin->u.
xy.x >= 0 && nwid_begin->u.
xy.y >= 0);
2971 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_MINSIZE requires NWidgetResizeBase");
2972 assert(nwid_begin->u.
xy.x >= 0 && nwid_begin->u.
xy.y >= 0);
2979 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_MINTEXTLINES requires NWidgetResizeBase");
2987 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_TEXTSTYLE requires NWidgetCore");
2994 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_ALIGNMENT requires NWidgetCore");
3001 if (nwrb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_FILL requires NWidgetResizeBase");
3002 nwrb->
SetFill(nwid_begin->u.
xy.x, nwid_begin->u.
xy.y);
3008 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_DATATIP requires NWidgetCore");
3015 if (dest ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PADDING requires NWidgetBase");
3016 dest->SetPadding(nwid_begin->u.
padding);
3021 if (nwc !=
nullptr) nwc->
SetPIP(nwid_begin->u.
pip.pre, nwid_begin->u.
pip.inter, nwid_begin->u.
pip.
post);
3024 if (nwb !=
nullptr) nwb->
SetPIP(nwid_begin->u.
pip.pre, nwid_begin->u.
pip.inter, nwid_begin->u.
pip.
post);
3026 if (nwc ==
nullptr && nwb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PIPSPACE requires NWidgetPIPContainer or NWidgetBackground");
3037 if (nwc ==
nullptr && nwb ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_PIPRATIO requires NWidgetPIPContainer or NWidgetBackground");
3043 if (nwc ==
nullptr) [[unlikely]]
throw std::runtime_error(
"WPT_SCROLLBAR requires NWidgetCore");
3052 if (dest !=
nullptr)
return nwid_begin;
3053 dest = std::make_unique<NWidgetViewport>(nwid_begin->u.
widget.
index);
3058 if (dest !=
nullptr)
return nwid_begin;
3063 if (dest !=
nullptr)
return nwid_begin;
3064 dest = std::make_unique<NWidgetStacked>(nwid_begin->u.
widget.
index);
3070 if (dest !=
nullptr)
return nwid_begin;
3105 assert(parent ==
nullptr || (nwid_cont !=
nullptr && nwid_parent ==
nullptr) || (nwid_cont ==
nullptr && nwid_parent !=
nullptr));
3108 std::unique_ptr<NWidgetBase> sub_widget =
nullptr;
3109 bool fill_sub =
false;
3110 nwid_begin =
MakeNWidget(nwid_begin, nwid_end, sub_widget, &fill_sub);
3113 if (sub_widget ==
nullptr)
break;
3121 if (nwid_cont !=
nullptr) nwid_cont->
Add(std::move(sub_widget));
3122 if (nwid_parent !=
nullptr) nwid_parent->
Add(std::move(sub_widget));
3123 if (nwid_cont ==
nullptr && nwid_parent ==
nullptr) {
3124 parent = std::move(sub_widget);
3129 if (nwid_begin == nwid_end)
return nwid_begin;
3131 assert(nwid_begin < nwid_end);
3133 return nwid_begin + 1;
3146 if (container ==
nullptr) container = std::make_unique<NWidgetVertical>();
3149 if (nwid_part != nwid_end) [[unlikely]]
throw std::runtime_error(
"Did not consume all NWidgetParts");
3151 return std::move(container);
3166 *shade_select =
nullptr;
3169 std::unique_ptr<NWidgetBase> nwid =
nullptr;
3171 assert(nwid !=
nullptr);
3175 auto root = std::make_unique<NWidgetVertical>();
3176 root->Add(std::move(nwid));
3177 if (nwid_begin == nwid_end)
return root;
3181 auto shade_stack = std::make_unique<NWidgetStacked>(-1);
3182 *shade_select = shade_stack.get();
3184 shade_stack->
Add(
MakeNWidgets(nwid_begin, nwid_end, std::make_unique<NWidgetVertical>()));
3185 root->Add(std::move(shade_stack));
3190 return MakeNWidgets(nwid_begin, nwid_end, std::move(root));
3205 assert(max_length >= 1);
3206 std::unique_ptr<NWidgetVertical> vert =
nullptr;
3207 std::unique_ptr<NWidgetHorizontal> hor =
nullptr;
3214 for (
WidgetID widnum = widget_first; widnum <= widget_last; widnum++) {
3216 if (hor_length == max_length) {
3217 if (vert ==
nullptr) vert = std::make_unique<NWidgetVertical>();
3218 vert->Add(std::move(hor));
3222 if (hor ==
nullptr) {
3223 hor = std::make_unique<NWidgetHorizontal>();
3227 auto panel = std::make_unique<NWidgetBackground>(
WWT_PANEL, button_colour, widnum);
3228 panel->SetMinimalSize(sprite_size.width, sprite_size.height);
3229 panel->SetFill(1, 1);
3230 if (resizable) panel->SetResize(1, 0);
3231 panel->SetDataTip(0x0, button_tooltip);
3232 hor->Add(std::move(panel));
3235 if (vert ==
nullptr)
return hor;
3237 if (hor_length > 0 && hor_length < max_length) {
3239 auto spc = std::make_unique<NWidgetSpacer>(sprite_size.width, sprite_size.height);
3241 if (resizable) spc->SetResize(1, 0);
3242 hor->Add(std::move(spc));
3244 if (hor !=
nullptr) vert->Add(std::move(hor));