mirror of https://github.com/OpenTTD/OpenTTD.git
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:
parent
f267b37a33
commit
d43ff8dc49
|
@ -127,6 +127,7 @@ public:
|
|||
}
|
||||
|
||||
this->smallest_x = this->children.front()->smallest_x + this->children.back()->smallest_x; // First and last are always shown, rest not
|
||||
this->ApplyAspectRatio();
|
||||
}
|
||||
|
||||
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
|
||||
|
|
|
@ -1869,6 +1869,7 @@ public:
|
|||
this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : std::min(display->fill_y, bar->fill_y);
|
||||
this->resize_x = std::max(display->resize_x, bar->resize_x);
|
||||
this->resize_y = std::min(display->resize_y, bar->resize_y);
|
||||
this->ApplyAspectRatio();
|
||||
}
|
||||
|
||||
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ enum WidgetType {
|
|||
WPT_ENDCONTAINER, ///< Widget part to denote end of a container.
|
||||
WPT_FUNCTION, ///< Widget part for calling a user function.
|
||||
WPT_SCROLLBAR, ///< Widget part for attaching a scrollbar.
|
||||
WPT_ASPECT, ///< Widget part for sepcifying aspect ratio.
|
||||
|
||||
/* Pushable window widget types. */
|
||||
WWT_MASK = 0x7F,
|
||||
|
@ -119,6 +120,13 @@ enum SizingType {
|
|||
ST_RESIZE, ///< Resize the nested widget tree.
|
||||
};
|
||||
|
||||
enum class AspectFlags : uint8_t {
|
||||
ResizeX = 1U << 0,
|
||||
ResizeY = 1U << 1,
|
||||
ResizeXY = ResizeX | ResizeY,
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(AspectFlags)
|
||||
|
||||
/* Forward declarations. */
|
||||
class NWidgetCore;
|
||||
class Scrollbar;
|
||||
|
@ -136,6 +144,7 @@ class NWidgetBase : public ZeroedMemoryAllocator {
|
|||
public:
|
||||
NWidgetBase(WidgetType tp);
|
||||
|
||||
void ApplyAspectRatio();
|
||||
virtual void AdjustPaddingForZoom();
|
||||
virtual void SetupSmallestSize(Window *w) = 0;
|
||||
virtual void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) = 0;
|
||||
|
@ -232,6 +241,8 @@ public:
|
|||
/* Current widget size (that is, after resizing). */
|
||||
uint current_x; ///< Current horizontal size (after resizing).
|
||||
uint current_y; ///< Current vertical size (after resizing).
|
||||
float aspect_ratio = 0; ///< Desired aspect ratio of widget.
|
||||
AspectFlags aspect_flags = AspectFlags::ResizeX; ///< Which dimensions can be resized.
|
||||
|
||||
int pos_x; ///< Horizontal position of top-left corner of the widget in the window.
|
||||
int pos_y; ///< Vertical position of top-left corner of the widget in the window.
|
||||
|
@ -298,6 +309,8 @@ public:
|
|||
void SetMinimalTextLines(uint8_t min_lines, uint8_t spacing, FontSize size);
|
||||
void SetFill(uint fill_x, uint fill_y);
|
||||
void SetResize(uint resize_x, uint resize_y);
|
||||
void SetAspect(float ratio, AspectFlags flags = AspectFlags::ResizeX);
|
||||
void SetAspect(int x_ratio, int y_ratio, AspectFlags flags = AspectFlags::ResizeX);
|
||||
|
||||
bool UpdateMultilineWidgetSize(const std::string &str, int max_lines);
|
||||
bool UpdateSize(uint min_x, uint min_y);
|
||||
|
@ -1045,6 +1058,11 @@ struct NWidgetPartAlignment {
|
|||
StringAlignment align; ///< Alignment of text/image.
|
||||
};
|
||||
|
||||
struct NWidgetPartAspect {
|
||||
float ratio;
|
||||
AspectFlags flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pointer to function returning a nested widget.
|
||||
* @return Nested widget (tree).
|
||||
|
@ -1068,6 +1086,7 @@ struct NWidgetPart {
|
|||
NWidgetPartAlignment align; ///< Part with internal alignment.
|
||||
NWidgetFunctionType *func_ptr; ///< Part with a function call.
|
||||
NWidContainerFlags cont_flags; ///< Part with container flags.
|
||||
NWidgetPartAspect aspect; ///< Part to set aspect ratio.
|
||||
|
||||
/* Constructors for each NWidgetPartUnion data type. */
|
||||
constexpr NWidgetPartUnion() : xy() {}
|
||||
|
@ -1081,6 +1100,7 @@ struct NWidgetPart {
|
|||
constexpr NWidgetPartUnion(NWidgetPartAlignment align) : align(align) {}
|
||||
constexpr NWidgetPartUnion(NWidgetFunctionType *func_ptr) : func_ptr(func_ptr) {}
|
||||
constexpr NWidgetPartUnion(NWidContainerFlags cont_flags) : cont_flags(cont_flags) {}
|
||||
constexpr NWidgetPartUnion(NWidgetPartAspect aspect) : aspect(aspect) {}
|
||||
} u;
|
||||
|
||||
/* Constructors for each NWidgetPart data type. */
|
||||
|
@ -1095,6 +1115,7 @@ struct NWidgetPart {
|
|||
constexpr NWidgetPart(WidgetType type, NWidgetPartAlignment align) : type(type), u(align) {}
|
||||
constexpr NWidgetPart(WidgetType type, NWidgetFunctionType *func_ptr) : type(type), u(func_ptr) {}
|
||||
constexpr NWidgetPart(WidgetType type, NWidContainerFlags cont_flags) : type(type), u(cont_flags) {}
|
||||
constexpr NWidgetPart(WidgetType type, NWidgetPartAspect aspect) : type(type), u(aspect) {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1266,6 +1287,17 @@ constexpr NWidgetPart SetScrollbar(WidgetID index)
|
|||
return NWidgetPart{WPT_SCROLLBAR, NWidgetPartWidget{INVALID_COLOUR, index}};
|
||||
}
|
||||
|
||||
/**
|
||||
* Widget part function for setting the aspect ratio.
|
||||
* @param ratio Desired aspect ratio, or 0 for none.
|
||||
* @param flags Dimensions which should be resized.
|
||||
* @ingroup NestedWidgetParts
|
||||
*/
|
||||
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags = AspectFlags::ResizeX)
|
||||
{
|
||||
return NWidgetPart{WPT_ASPECT, NWidgetPartAspect{ratio, flags}};
|
||||
}
|
||||
|
||||
/**
|
||||
* Widget part function for starting a new 'real' widget.
|
||||
* @param tp Type of the new nested widget.
|
||||
|
|
Loading…
Reference in New Issue