1
0
mirror of https://github.com/OpenTTD/OpenTTD synced 2026-01-15 16:32:41 +01:00

Change: Ability to set aspect ratio of a widget.

This allows setting the shape of a widget without dealing with absolute pixel sizes.
This commit is contained in:
Peter Nelson
2024-03-27 09:02:40 +00:00
committed by Peter Nelson
parent f267b37a33
commit d43ff8dc49
4 changed files with 95 additions and 0 deletions

View File

@@ -925,6 +925,20 @@ NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp)
return (this->type == tp) ? this : nullptr;
}
void NWidgetBase::ApplyAspectRatio()
{
if (this->aspect_ratio == 0) return;
if (this->smallest_x == 0 || this->smallest_y == 0) return;
uint x = this->smallest_x;
uint y = this->smallest_y;
if ((this->aspect_flags & AspectFlags::ResizeX) == AspectFlags::ResizeX) x = std::max(this->smallest_x, static_cast<uint>(this->smallest_y * std::abs(this->aspect_ratio)));
if ((this->aspect_flags & AspectFlags::ResizeY) == AspectFlags::ResizeY) y = std::max(this->smallest_y, static_cast<uint>(this->smallest_x / std::abs(this->aspect_ratio)));
this->smallest_x = x;
this->smallest_y = y;
}
void NWidgetBase::AdjustPaddingForZoom()
{
this->padding = ScaleGUITrad(this->uz_padding);
@@ -942,6 +956,28 @@ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) :
this->fill_y = fill_y;
}
/**
* Set desired aspect ratio of this widget.
* @param ratio Desired aspect ratio, or 0 for none.
* @param flags Dimensions which should be resized.
*/
void NWidgetResizeBase::SetAspect(float ratio, AspectFlags flags)
{
this->aspect_ratio = ratio;
this->aspect_flags = flags;
}
/**
* Set desired aspect ratio of this widget, in terms of horizontal and vertical dimensions.
* @param x_ratio Desired horizontal component of aspect ratio.
* @param y_ratio Desired vertical component of aspect ratio.
* @param flags Dimensions which should be resized.
*/
void NWidgetResizeBase::SetAspect(int x_ratio, int y_ratio, AspectFlags flags)
{
this->SetAspect(static_cast<float>(x_ratio) / static_cast<float>(y_ratio), flags);
}
void NWidgetResizeBase::AdjustPaddingForZoom()
{
if (!this->absolute) {
@@ -1224,6 +1260,7 @@ void NWidgetStacked::SetupSmallestSize(Window *w)
this->fill_y = fill.height;
this->resize_x = resize.width;
this->resize_y = resize.height;
this->ApplyAspectRatio();
return;
}
@@ -1243,6 +1280,7 @@ void NWidgetStacked::SetupSmallestSize(Window *w)
this->fill_y = std::lcm(this->fill_y, child_wid->fill_y);
this->resize_x = std::lcm(this->resize_x, child_wid->resize_x);
this->resize_y = std::lcm(this->resize_y, child_wid->resize_y);
this->ApplyAspectRatio();
}
}
@@ -1405,6 +1443,11 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w)
this->smallest_y = cur_height; // Smallest height got changed, try again.
}
/* 2. For containers that must maintain equal width, extend child minimal size. */
for (const auto &child_wid : this->children) {
child_wid->smallest_y = this->smallest_y - child_wid->padding.Vertical();
child_wid->ApplyAspectRatio();
longest = std::max(longest, child_wid->smallest_x);
}
if (this->flags & NC_EQUALSIZE) {
for (const auto &child_wid : this->children) {
if (child_wid->fill_x == 1) child_wid->smallest_x = longest;
@@ -1594,6 +1637,11 @@ void NWidgetVertical::SetupSmallestSize(Window *w)
this->smallest_x = cur_width; // Smallest width got changed, try again.
}
/* 2. For containers that must maintain equal width, extend children minimal size. */
for (const auto &child_wid : this->children) {
child_wid->smallest_x = this->smallest_x - child_wid->padding.Horizontal();
child_wid->ApplyAspectRatio();
highest = std::max(highest, child_wid->smallest_y);
}
if (this->flags & NC_EQUALSIZE) {
for (const auto &child_wid : this->children) {
if (child_wid->fill_y == 1) child_wid->smallest_y = highest;
@@ -1730,6 +1778,7 @@ void NWidgetSpacer::SetupSmallestSize(Window *)
{
this->smallest_x = this->min_x;
this->smallest_y = this->min_y;
this->ApplyAspectRatio();
}
void NWidgetSpacer::FillWidgetLookup(WidgetLookup &)
@@ -1841,6 +1890,7 @@ void NWidgetMatrix::SetupSmallestSize(Window *w)
this->fill_y = fill.height;
this->resize_x = resize.width;
this->resize_y = resize.height;
this->ApplyAspectRatio();
}
void NWidgetMatrix::AssignSizePosition(SizingType, int x, int y, uint given_width, uint given_height, bool)
@@ -2089,6 +2139,7 @@ void NWidgetBackground::SetupSmallestSize(Window *w)
this->smallest_x += this->child->padding.Horizontal();
this->smallest_y += this->child->padding.Vertical();
}
this->ApplyAspectRatio();
} else {
Dimension d = {this->min_x, this->min_y};
Dimension fill = {this->fill_x, this->fill_y};
@@ -2117,6 +2168,7 @@ void NWidgetBackground::SetupSmallestSize(Window *w)
this->fill_y = fill.height;
this->resize_x = resize.width;
this->resize_y = resize.height;
this->ApplyAspectRatio();
}
}
@@ -2203,6 +2255,7 @@ void NWidgetViewport::SetupSmallestSize(Window *)
{
this->smallest_x = this->min_x;
this->smallest_y = this->min_y;
this->ApplyAspectRatio();
}
void NWidgetViewport::Draw(const Window *w)
@@ -2738,6 +2791,7 @@ void NWidgetLeaf::SetupSmallestSize(Window *w)
this->fill_y = fill.height;
this->resize_x = resize.width;
this->resize_y = resize.height;
this->ApplyAspectRatio();
}
void NWidgetLeaf::Draw(const Window *w)
@@ -3045,6 +3099,13 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
break;
}
case WPT_ASPECT: {
if (dest == nullptr) [[unlikely]] throw std::runtime_error("WPT_ASPECT requires NWidgetBase");
dest->aspect_ratio = nwid_begin->u.aspect.ratio;
dest->aspect_flags = nwid_begin->u.aspect.flags;
break;
}
case WPT_ENDCONTAINER:
return nwid_begin;