Changeset - r28103:044e5533f3ed
[Not reviewed]
master
0 2 0
Peter Nelson - 13 months ago 2023-10-27 19:01:54
peter1138@openttd.org
Codechange: Add ability to allocate PIP-space dynamically by ratio.

This can be used to space out, centre, start-align, or end-align widgets without additional spacers.
2 files changed with 102 insertions and 6 deletions:
0 comments (0 inline, 0 general)
src/widget.cpp
Show inline comments
 
@@ -1498,6 +1498,22 @@ void NWidgetPIPContainer::SetPIP(uint8_t
 
	this->pip_post = ScaleGUITrad(this->uz_pip_post);
 
}
 

	
 
/**
 
 * Set additional pre/inter/post space for the container.
 
 *
 
 * @param pip_ratio_pre   Ratio of additional space in front of the first child widget (above
 
 *                        for the vertical container, at the left for the horizontal container).
 
 * @param pip_ratio_inter Ratio of additional space between two child widgets.
 
 * @param pip_ratio_post  Ratio of additional space after the last child widget (below for the
 
 *                        vertical container, at the right for the horizontal container).
 
 */
 
void NWidgetPIPContainer::SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_ratio_post)
 
{
 
	this->pip_ratio_pre = pip_ratio_pre;
 
	this->pip_ratio_inter = pip_ratio_inter;
 
	this->pip_ratio_post = pip_ratio_post;
 
}
 

	
 
/** Horizontal container widget. */
 
NWidgetHorizontal::NWidgetHorizontal(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_HORIZONTAL, flags)
 
{
 
@@ -1562,6 +1578,7 @@ void NWidgetHorizontal::SetupSmallestSiz
 
		}
 
		this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y);
 
	}
 
	if (this->fill_x == 0 && this->pip_ratio_pre + this->pip_ratio_inter + this->pip_ratio_post > 0) this->fill_x = 1;
 
	/* 4. Increase by required PIP space. */
 
	this->smallest_x += this->pip_pre + this->gaps * this->pip_inter + this->pip_post;
 
}
 
@@ -1572,7 +1589,7 @@ void NWidgetHorizontal::AssignSizePositi
 

	
 
	/* Compute additional width given to us. */
 
	uint additional_length = given_width;
 
	if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) {
 
	if (this->pip_ratio_pre + this->pip_ratio_inter + this->pip_ratio_post != 0 || (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE))) {
 
		/* For EQUALSIZE containers this does not sum to smallest_x during initialisation */
 
		additional_length -= this->pip_pre + this->gaps * this->pip_inter + this->pip_post;
 
		for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
 
@@ -1653,8 +1670,21 @@ void NWidgetHorizontal::AssignSizePositi
 
	}
 
	assert(num_changing_childs == 0);
 

	
 
	uint pre = this->pip_pre;
 
	uint inter = this->pip_inter;
 

	
 
	if (additional_length > 0) {
 
		/* Allocate remaining space by pip ratios. If this doesn't round exactly, the unused space will fall into pip_post
 
		 * which is never explicitly needed. */
 
		int r = this->pip_ratio_pre + this->gaps * this->pip_ratio_inter + this->pip_ratio_post;
 
		if (r > 0) {
 
			pre += this->pip_ratio_pre * additional_length / r;
 
			if (this->gaps > 0) inter += this->pip_ratio_inter * additional_length / r;
 
		}
 
	}
 

	
 
	/* Third loop: Compute position and call the child. */
 
	uint position = rtl ? this->current_x - this->pip_pre : this->pip_pre; // Place to put next child relative to origin of the container.
 
	uint position = rtl ? this->current_x - pre : pre; // Place to put next child relative to origin of the container.
 
	NWidgetBase *child_wid = this->head;
 
	while (child_wid != nullptr) {
 
		uint child_width = child_wid->current_x;
 
@@ -1662,7 +1692,7 @@ void NWidgetHorizontal::AssignSizePositi
 
		uint child_y = y + child_wid->padding.top;
 

	
 
		child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl);
 
		uint padded_child_width = child_width + child_wid->padding.Horizontal() + this->pip_inter;
 
		uint padded_child_width = child_width + child_wid->padding.Horizontal() + inter;
 
		position = rtl ? position - padded_child_width : position + padded_child_width;
 

	
 
		child_wid = child_wid->next;
 
@@ -1744,6 +1774,7 @@ void NWidgetVertical::SetupSmallestSize(
 
		}
 
		this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x);
 
	}
 
	if (this->fill_y == 0 && this->pip_ratio_pre + this->pip_ratio_inter + this->pip_ratio_post > 0) this->fill_y = 1;
 
	/* 4. Increase by required PIP space. */
 
	this->smallest_y += this->pip_pre + this->gaps * this->pip_inter + this->pip_post;
 
}
 
@@ -1754,7 +1785,7 @@ void NWidgetVertical::AssignSizePosition
 

	
 
	/* Compute additional height given to us. */
 
	uint additional_length = given_height;
 
	if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) {
 
	if (this->pip_ratio_pre + this->pip_ratio_inter + this->pip_ratio_post != 0 || (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE))) {
 
		/* For EQUALSIZE containers this does not sum to smallest_y during initialisation */
 
		additional_length -= this->pip_pre + this->gaps * this->pip_inter + this->pip_post;
 
		for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
 
@@ -1826,14 +1857,27 @@ void NWidgetVertical::AssignSizePosition
 
	}
 
	assert(num_changing_childs == 0);
 

	
 
	uint pre = this->pip_pre;
 
	uint inter = this->pip_inter;
 

	
 
	if (additional_length > 0) {
 
		/* Allocate remaining space by pip ratios. If this doesn't round exactly, the unused space will fall into pip_post
 
		 * which is never explicitly needed. */
 
		int r = this->pip_ratio_pre + this->gaps * this->pip_ratio_inter + this->pip_ratio_post;
 
		if (r > 0) {
 
			pre += this->pip_ratio_pre * additional_length / r;
 
			if (this->gaps > 0) inter += this->pip_ratio_inter * additional_length / r;
 
		}
 
	}
 

	
 
	/* Third loop: Compute position and call the child. */
 
	uint position = this->pip_pre; // Place to put next child relative to origin of the container.
 
	uint position = pre; // Place to put next child relative to origin of the container.
 
	for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
 
		uint child_x = x + (rtl ? child_wid->padding.right : child_wid->padding.left);
 
		uint child_height = child_wid->current_y;
 

	
 
		child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding.top, child_wid->current_x, child_height, rtl);
 
		position += child_height + child_wid->padding.Vertical() + this->pip_inter;
 
		position += child_height + child_wid->padding.Vertical() + inter;
 
	}
 
}
 

	
 
@@ -2170,6 +2214,24 @@ void NWidgetBackground::SetPIP(uint8_t p
 
	this->child->SetPIP(pip_pre, pip_inter, pip_post);
 
}
 

	
 
/**
 
 * Set additional pre/inter/post space ratios for the background widget.
 
 *
 
 * @param pip_ratio_pre   Ratio of additional space in front of the first child widget (above
 
 *                        for the vertical container, at the left for the horizontal container).
 
 * @param pip_ratio_inter Ratio of additional space between two child widgets.
 
 * @param pip_ratio_post  Ratio of additional space after the last child widget (below for the
 
 *                        vertical container, at the right for the horizontal container).
 
 * @note Using this function implies that the widget has (or will have) child widgets.
 
 */
 
void NWidgetBackground::SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_ratio_post)
 
{
 
	if (this->child == nullptr) {
 
		this->child = new NWidgetVertical();
 
	}
 
	this->child->SetPIPRatio(pip_ratio_pre, pip_ratio_inter, pip_ratio_post);
 
}
 

	
 
void NWidgetBackground::AdjustPaddingForZoom()
 
{
 
	if (child != nullptr) child->AdjustPaddingForZoom();
 
@@ -3178,6 +3240,15 @@ static const NWidgetPart *MakeNWidget(co
 
				break;
 
			}
 

	
 
			case WPT_PIPRATIO: {
 
				NWidgetPIPContainer *nwc = dynamic_cast<NWidgetPIPContainer *>(*dest);
 
				if (nwc != nullptr) nwc->SetPIPRatio(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post);
 

	
 
				NWidgetBackground *nwb = dynamic_cast<NWidgetBackground *>(*dest);
 
				if (nwb != nullptr) nwb->SetPIPRatio(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post);
 
				break;
 
			}
 

	
 
			case WPT_SCROLLBAR: {
 
				NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(*dest);
 
				if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_SCROLLBAR requires NWidgetCore");
src/widget_type.h
Show inline comments
 
@@ -87,6 +87,7 @@ enum WidgetType {
 
	WPT_DATATIP,      ///< Widget part for specifying data and tooltip.
 
	WPT_PADDING,      ///< Widget part for specifying a padding.
 
	WPT_PIPSPACE,     ///< Widget part for specifying pre/inter/post space for containers.
 
	WPT_PIPRATIO,     ///< Widget part for specifying pre/inter/post ratio for containers.
 
	WPT_TEXTSTYLE,    ///< Widget part for specifying text colour.
 
	WPT_ALIGNMENT,    ///< Widget part for specifying text/image alignment.
 
	WPT_ENDCONTAINER, ///< Widget part to denote end of a container.
 
@@ -482,12 +483,16 @@ public:
 

	
 
	void AdjustPaddingForZoom() override;
 
	void SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip_post);
 
	void SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_rato_post);
 

	
 
protected:
 
	NWidContainerFlags flags; ///< Flags of the container.
 
	uint8_t pip_pre;            ///< Amount of space before first widget.
 
	uint8_t pip_inter;          ///< Amount of space between widgets.
 
	uint8_t pip_post;           ///< Amount of space after last widget.
 
	uint8_t pip_ratio_pre;      ///< Ratio of remaining space before first widget.
 
	uint8_t pip_ratio_inter;    ///< Ratio of remaining space between widgets.
 
	uint8_t pip_ratio_post;     ///< Ratio of remaining space after last widget.
 

	
 
	uint8_t uz_pip_pre;         ///< Unscaled space before first widget.
 
	uint8_t uz_pip_inter;       ///< Unscaled space between widgets.
 
@@ -598,6 +603,7 @@ public:
 

	
 
	void Add(NWidgetBase *nwid);
 
	void SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip_post);
 
	void SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_ratio_post);
 

	
 
	void AdjustPaddingForZoom() override;
 
	void SetupSmallestSize(Window *w, bool init_array) override;
 
@@ -1229,6 +1235,25 @@ static inline NWidgetPart SetPIP(uint8_t
 
}
 

	
 
/**
 
 * Widget part function for setting a pre/inter/post ratio.
 
 * @param pre The ratio of space before the first widget.
 
 * @param inter The ratio of space between widgets.
 
 * @param post The ratio of space after the last widget.
 
 * @ingroup NestedWidgetParts
 
 */
 
static inline NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post)
 
{
 
	NWidgetPart part;
 

	
 
	part.type = WPT_PIPRATIO;
 
	part.u.pip.pre = ratio_pre;
 
	part.u.pip.inter = ratio_inter;
 
	part.u.pip.post = ratio_post;
 

	
 
	return part;
 
}
 

	
 
/**
 
 * Attach a scrollbar to a widget.
 
 * The scrollbar is controlled when using the mousewheel on the widget.
 
 * Multiple widgets can refer to the same scrollbar to make the mousewheel work in all of them.
0 comments (0 inline, 0 general)