TachyonUI 0.1.0
High-performance UI for building tools.
Loading...
Searching...
No Matches
gui_icon_text_placement.h
Go to the documentation of this file.
1#pragma once
2
4
7
9
10#include <algorithm>
11
12namespace tachyon
13{
16
19 inline int32_t HorizontalAlignOffset(TextAlign horizontalAlignment, int32_t boxWidth, int32_t contentWidth)
20 {
21 switch (horizontalAlignment)
22 {
23 case TextAlign::Center: return (boxWidth - contentWidth) / 2;
24 case TextAlign::End:
26 case TextAlign::Bottom: return boxWidth - contentWidth;
27 default: return 0;
28 }
29 }
30
31 inline int32_t VerticalAlignOffset(TextAlign verticalAlignment, int32_t boxHeight, int32_t contentHeight)
32 {
33 switch (verticalAlignment)
34 {
35 case TextAlign::Center: return (boxHeight - contentHeight) / 2;
36 case TextAlign::End:
38 case TextAlign::Right: return boxHeight - contentHeight;
39 default: return 0;
40 }
41 }
42
57
59 const IntRect& rect,
60 int32_t textWidth,
61 int32_t textHeight,
62 const IconMeasurement& iconMeasurement,
63 IconSide iconSide,
64 int32_t iconTextGap,
65 TextAlign horizontalAlignment,
66 TextAlign verticalAlignment = TextAlign::Start)
67 {
68 IconTextPlacement out = {
69 .textRect = rect,
70 .iconRect = IntRect{ 0, 0, 0, 0 },
71 };
72
73 // Icon only: align it within `rect` directly. The text+icon model below
74 // centres the icon on the text line, which has no height here.
75 if (textWidth <= 0)
76 {
77 const int32_t iconX = rect.x + HorizontalAlignOffset(horizontalAlignment, rect.w, iconMeasurement.width);
78 const int32_t iconY = rect.y + VerticalAlignOffset(verticalAlignment, rect.h, iconMeasurement.height);
79 out.iconRect = IntRect{ iconX, iconY, iconMeasurement.width, iconMeasurement.height };
80 return out;
81 }
82
83 // Bounding box of the packed [icon][text] block, for text-align and
84 // -tachyon-vertical-text-align.
85 int32_t combinedWidth = textWidth;
86 int32_t combinedHeight = textHeight;
87 switch (iconSide)
88 {
89 case IconSide::None: break;
90 case IconSide::Left:
91 case IconSide::Right:
92 combinedWidth = textWidth + iconTextGap + iconMeasurement.width;
93 combinedHeight = std::max(textHeight, iconMeasurement.height);
94 break;
95 case IconSide::Top:
97 combinedWidth = std::max(textWidth, iconMeasurement.width);
98 combinedHeight = textHeight + iconTextGap + iconMeasurement.height;
99 break;
100 }
101
102 const int32_t textAlignmentOffsetX = HorizontalAlignOffset(horizontalAlignment, rect.w, combinedWidth);
103
104 // Block vertical offset - shifts iconRect.y AND textRect.y by the
105 // same amount so the icon/text pair tracks its alignment together.
106 const int32_t blockY = rect.y + VerticalAlignOffset(verticalAlignment, rect.h, combinedHeight);
107
108 switch (iconSide)
109 {
110 case IconSide::None: break;
111 case IconSide::Left:
112 {
113 const int32_t combinedStartX = rect.x + textAlignmentOffsetX;
114 out.iconRect = IntRect{
115 .x = combinedStartX,
116 .y = blockY + (combinedHeight - iconMeasurement.height) / 2,
117 .w = iconMeasurement.width,
118 .h = iconMeasurement.height
119 };
120 out.textRect.x = combinedStartX + iconMeasurement.width + iconTextGap;
121 out.textRect.w = (rect.x + rect.w) - out.textRect.x;
122 out.textRect.y = blockY + (combinedHeight - textHeight) / 2;
123 break;
124 }
125 case IconSide::Right:
126 {
127 const int32_t combinedStartX = rect.x + textAlignmentOffsetX;
128 out.iconRect = IntRect{
129 .x = combinedStartX + textWidth + iconTextGap,
130 .y = blockY + (combinedHeight - iconMeasurement.height) / 2,
131 .w = iconMeasurement.width,
132 .h = iconMeasurement.height
133 };
134 out.textRect.x = rect.x;
135 out.textRect.w = rect.w - iconTextGap - iconMeasurement.width;
136 out.textRect.y = blockY + (combinedHeight - textHeight) / 2;
137 break;
138 }
139 case IconSide::Top:
140 {
141 const int32_t combinedStartX = rect.x + textAlignmentOffsetX;
142 const int32_t iconCenterX = combinedStartX + combinedWidth / 2;
143 out.iconRect = IntRect{
144 .x = iconCenterX - iconMeasurement.width / 2,
145 .y = blockY,
146 .w = iconMeasurement.width,
147 .h = iconMeasurement.height
148 };
149 out.textRect.x = rect.x;
150 out.textRect.w = rect.w;
151 out.textRect.y = blockY + iconMeasurement.height + iconTextGap;
152 out.textRect.h = rect.h - iconMeasurement.height - iconTextGap;
153 break;
154 }
155 case IconSide::Bottom:
156 {
157 const int32_t combinedStartX = rect.x + textAlignmentOffsetX;
158 const int32_t iconCenterX = combinedStartX + combinedWidth / 2;
159 out.textRect.x = rect.x;
160 out.textRect.w = rect.w;
161 out.textRect.y = blockY;
162 out.textRect.h = textHeight - iconMeasurement.height - iconTextGap;
163 out.iconRect = IntRect{
164 .x = iconCenterX - iconMeasurement.width / 2,
165 .y = blockY + textHeight + iconTextGap,
166 .w = iconMeasurement.width,
167 .h = iconMeasurement.height
168 };
169 break;
170 }
171 }
172
173 (void)combinedHeight;
174 return out;
175 }
176
180 int32_t rectWidth,
181 const IconMeasurement& iconMeasurement,
182 IconSide iconSide,
183 int32_t iconTextGap,
184 bool hasIcon)
185 {
186 if (!hasIcon) return rectWidth;
187 if (iconSide == IconSide::Left || iconSide == IconSide::Right)
188 return std::max(0, rectWidth - iconTextGap - iconMeasurement.width);
189 return rectWidth;
190 }
191
192}
IconSide
Where an element's icon sits relative to its text (CSS: -tachyon-icon-side).
Definition gui_style.h:249
TextAlign
Alignment of text in its box (CSS: text-align, -tachyon-vertical-text-align).
Definition gui_style_text.h:68
@ Bottom
Definition gui_style.h:255
@ None
Definition gui_style.h:250
@ Right
Definition gui_style.h:253
@ Left
Definition gui_style.h:252
@ Top
Definition gui_style.h:254
@ Bottom
Horizontal: n/a (behaves like right). Vertical: bottom.
Definition gui_style_text.h:75
@ Center
Horizontal and vertical: center.
Definition gui_style_text.h:70
@ End
Horizontal: the language's end (right for LTR, left for RTL). Vertical: bottom.
Definition gui_style_text.h:71
@ Right
Horizontal: right. Vertical: n/a (behaves like bottom).
Definition gui_style_text.h:73
@ Start
Horizontal: the language's start (left for LTR, right for RTL). Vertical: top.
Definition gui_style_text.h:69
int32_t IconAwareLayoutMaxWidth(int32_t rectWidth, const IconMeasurement &iconMeasurement, IconSide iconSide, int32_t iconTextGap, bool hasIcon)
The max width to lay text out in: rectWidth minus the icon and gap for a Left / Right icon,...
Definition gui_icon_text_placement.h:179
int32_t HorizontalAlignOffset(TextAlign horizontalAlignment, int32_t boxWidth, int32_t contentWidth)
X offset, in pixels, of contentWidth content aligned inside a boxWidth box.
Definition gui_icon_text_placement.h:19
IconTextPlacement ComputeIconTextPlacement(const IntRect &rect, int32_t textWidth, int32_t textHeight, const IconMeasurement &iconMeasurement, IconSide iconSide, int32_t iconTextGap, TextAlign horizontalAlignment, TextAlign verticalAlignment=TextAlign::Start)
Definition gui_icon_text_placement.h:58
int32_t VerticalAlignOffset(TextAlign verticalAlignment, int32_t boxHeight, int32_t contentHeight)
Definition gui_icon_text_placement.h:31
Definition gui_logging.h:24
Definition gui_text_system.h:54
int32_t width
Definition gui_text_system.h:55
int32_t height
Definition gui_text_system.h:56
Placement of a text + icon pair inside rect:
Definition gui_icon_text_placement.h:53
IntRect textRect
Definition gui_icon_text_placement.h:54
IntRect iconRect
Definition gui_icon_text_placement.h:55
Definition gui_base_types.h:407