Skip to content

Commit 96294e6

Browse files
committed
text: fix ellipsizing, layouting, etc.
1 parent 0f124a0 commit 96294e6

12 files changed

Lines changed: 427 additions & 110 deletions

File tree

src/element/LinearLayout.hpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ namespace Hyprtoolkit::LinearLayout {
3131

3232
std::vector<size_t> sizes;
3333
sizes.resize(C.size());
34+
std::vector<double> preferredSizes;
35+
preferredSizes.resize(C.size());
3436

3537
size_t i = 0;
3638
for (i = 0; i < C.size(); ++i) {
@@ -39,6 +41,7 @@ namespace Hyprtoolkit::LinearLayout {
3941
Vector2D cSize = childSize(child);
4042
if (cSize == Vector2D{-1, -1})
4143
cSize = Horizontal ? Vector2D{1.F, box.h} : Vector2D{box.w, 1.F};
44+
preferredSizes.at(i) = axisPrimary(cSize);
4245

4346
if (used + axisPrimary(cSize) > MAX + 1) {
4447
// we exceeded our available space.
@@ -56,7 +59,7 @@ namespace Hyprtoolkit::LinearLayout {
5659
// (needs > 0 below), the current child is dropped and we
5760
// expand the previous one to cover the gap; minor visual
5861
// artefact in degenerate cases but the layout stays sane.
59-
float needs = (used + axisPrimary(cSize)) - (MAX + 1);
62+
float needs = (used + axisPrimary(cSize)) - MAX;
6063
for (int j = (int)i - 1; j >= 0; --j) {
6164
const auto& prevChild = C.at(j);
6265
const auto MIN = prevChild->minimumSize(box.size());
@@ -91,11 +94,12 @@ namespace Hyprtoolkit::LinearLayout {
9194
child->impl->setFailedPositioning(true);
9295
if (i != 0) {
9396
const auto& lastChild = C.at(i - 1);
97+
const auto AVAILABLE = std::max(0.0, MAX - used);
9498

95-
if (lastChild->maximumSize(box.size()) && sizes.at(i - 1) + MAX - used > axisPrimary(*lastChild->maximumSize(box.size())))
99+
if (lastChild->maximumSize(box.size()) && sizes.at(i - 1) + AVAILABLE > axisPrimary(*lastChild->maximumSize(box.size())))
96100
continue; // too bad, we'll have a gap
97101

98-
sizes.at(i - 1) += MAX - used;
102+
sizes.at(i - 1) += AVAILABLE;
99103
}
100104
continue;
101105
} else {
@@ -104,15 +108,19 @@ namespace Hyprtoolkit::LinearLayout {
104108

105109
// recalc used, we changed prior sizes
106110
used = 0;
107-
for (const auto& s : sizes)
108-
used += s + gap;
111+
for (size_t j = 0; j <= i; ++j) {
112+
if (!C.at(j)->impl->failedPositioning)
113+
used += sizes.at(j) + gap;
114+
}
109115

110116
continue;
111117
}
112118
}
113119

114120
// squeeze the last element in
115-
sizes.at(i) = MAX - used;
121+
child->impl->setFailedPositioning(false);
122+
sizes.at(i) = std::max(0.0, MAX - used);
123+
used = MAX + gap; // the common final-gap removal below still runs
116124
continue;
117125
}
118126

@@ -142,17 +150,19 @@ namespace Hyprtoolkit::LinearLayout {
142150
if (child->impl->failedPositioning)
143151
continue;
144152

145-
Vector2D cSize = childSize(child);
153+
Vector2D cSize = childSize(child);
154+
const double ROOM = grows(child) ? 0 : std::max(0.0, MAX - used);
155+
const bool SQUEEZED = sizes.at(i) + ROOM + 1 < preferredSizes.at(i);
146156

147-
CBox childBox;
157+
CBox childBox;
148158
if constexpr (Horizontal) {
149159
cSize.y = std::clamp(cSize.y, 0.0, box.h);
150160
childBox = CBox{box.x + (double)cursor, box.y + ((box.h - cSize.y) / 2), (double)sizes.at(i), cSize.y};
151-
g_positioner->position(child, childBox, Vector2D{childBox.w + (MAX - used), box.h});
161+
g_positioner->position(child, childBox, Vector2D{SQUEEZED ? childBox.w + ROOM : -1, box.h});
152162
} else {
153163
cSize.x = std::clamp(cSize.x, 0.0, box.w);
154164
childBox = CBox{box.x + ((box.w - cSize.x) / 2), box.y + (double)cursor, cSize.x, (double)sizes.at(i)};
155-
g_positioner->position(child, childBox, Vector2D{box.w, childBox.h + (MAX - used)});
165+
g_positioner->position(child, childBox, Vector2D{box.w, SQUEEZED ? childBox.h + ROOM : -1});
156166
}
157167

158168
cursor += (size_t)((Horizontal ? childBox.w : childBox.h) + gap);

src/element/columnLayout/ColumnLayout.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@
88

99
#include "../Element.hpp"
1010
#include "../LinearLayout.hpp"
11+
#include "../text/Text.hpp"
1112

1213
using namespace Hyprtoolkit;
1314

15+
static Vector2D childSizeForConstraint(const SP<IElement>& child, const Vector2D& constraint, const Vector2D& textConstraint) {
16+
const auto CHILD_CONSTRAINT = dynamicPointerCast<CTextElement>(child) ? textConstraint : constraint;
17+
if (const auto PREFERRED = child->preferredSize(CHILD_CONSTRAINT))
18+
return *PREFERRED;
19+
if (const auto MINIMUM = child->minimumSize(CHILD_CONSTRAINT))
20+
return *MINIMUM;
21+
return {-1, -1};
22+
}
23+
1424
SP<CColumnLayoutElement> CColumnLayoutElement::create(const SColumnLayoutData& data) {
1525
auto p = SP<CColumnLayoutElement>(new CColumnLayoutElement(data));
1626
p->impl->self = p;
@@ -51,11 +61,8 @@ Hyprutils::Math::Vector2D CColumnLayoutElement::size() {
5161
}
5262

5363
Hyprutils::Math::Vector2D CColumnLayoutElement::childSize(Hyprutils::Memory::CSharedPointer<IElement> child) {
54-
if (child->preferredSize(impl->position.size()))
55-
return *child->preferredSize(impl->position.size());
56-
else if (child->minimumSize(impl->position.size()))
57-
return *child->minimumSize(impl->position.size());
58-
return {-1, -1};
64+
const auto CONSTRAINT = impl->position.size();
65+
return childSizeForConstraint(child, CONSTRAINT, {CONSTRAINT.x, -1.F});
5966
}
6067

6168
std::optional<Hyprutils::Math::Vector2D> CColumnLayoutElement::preferredSize(const Hyprutils::Math::Vector2D& parent) {
@@ -64,10 +71,12 @@ std::optional<Hyprutils::Math::Vector2D> CColumnLayoutElement::preferredSize(con
6471
if (calc.x != -1 && calc.y != -1)
6572
return calc;
6673

67-
Vector2D max;
74+
const Vector2D TEXT_CONSTRAINT{calc.x > 0 ? std::max(1.0, calc.x - impl->margin * 2.F) : -1.F, -1.F};
75+
Vector2D max;
6876
for (const auto& child : impl->children) {
69-
max.x = std::max(childSize(child).x, max.x);
70-
max.y += childSize(child).y + m_impl->data.gap;
77+
const auto CHILD_SIZE = childSizeForConstraint(child, parent, TEXT_CONSTRAINT);
78+
max.x = std::max(CHILD_SIZE.x, max.x);
79+
max.y += CHILD_SIZE.y + m_impl->data.gap;
7180
}
7281

7382
if (!impl->children.empty())
@@ -88,9 +97,12 @@ std::optional<Hyprutils::Math::Vector2D> CColumnLayoutElement::preferredSize(con
8897
}
8998

9099
std::optional<Hyprutils::Math::Vector2D> CColumnLayoutElement::minimumSize(const Hyprutils::Math::Vector2D& parent) {
91-
Vector2D min;
100+
const auto CALC = m_impl->data.size.calculate(parent);
101+
const Vector2D TEXT_CONSTRAINT = {CALC.x > 0 ? std::max(1.0, CALC.x - impl->margin * 2.F) : -1.F, -1.F};
102+
Vector2D min;
92103
for (const auto& child : impl->children) {
93-
min.x = std::max(min.x, childSize(child).x);
104+
const auto CHILD_SIZE = childSizeForConstraint(child, parent, TEXT_CONSTRAINT);
105+
min.x = std::max(min.x, CHILD_SIZE.x);
94106
}
95107

96108
return min;

src/element/rowLayout/RowLayout.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,19 @@
88

99
#include "../Element.hpp"
1010
#include "../LinearLayout.hpp"
11+
#include "../text/Text.hpp"
1112

1213
using namespace Hyprtoolkit;
1314

15+
static Vector2D childSizeForConstraint(const SP<IElement>& child, const Vector2D& constraint, const Vector2D& textConstraint) {
16+
const auto CHILD_CONSTRAINT = dynamicPointerCast<CTextElement>(child) ? textConstraint : constraint;
17+
if (const auto PREFERRED = child->preferredSize(CHILD_CONSTRAINT))
18+
return *PREFERRED;
19+
if (const auto MINIMUM = child->minimumSize(CHILD_CONSTRAINT))
20+
return *MINIMUM;
21+
return {-1, -1};
22+
}
23+
1424
SP<CRowLayoutElement> CRowLayoutElement::create(const SRowLayoutData& data) {
1525
auto p = SP<CRowLayoutElement>(new CRowLayoutElement(data));
1626
p->impl->self = p;
@@ -39,11 +49,8 @@ void CRowLayoutElement::reposition(const Hyprutils::Math::CBox& sbox, const Hypr
3949
}
4050

4151
Hyprutils::Math::Vector2D CRowLayoutElement::childSize(Hyprutils::Memory::CSharedPointer<IElement> child) {
42-
if (child->preferredSize(impl->position.size()))
43-
return *child->preferredSize(impl->position.size());
44-
else if (child->minimumSize(impl->position.size()))
45-
return *child->minimumSize(impl->position.size());
46-
return {-1, -1};
52+
const auto CONSTRAINT = impl->position.size();
53+
return childSizeForConstraint(child, CONSTRAINT, {-1.F, CONSTRAINT.y});
4754
}
4855

4956
Hyprutils::Math::Vector2D CRowLayoutElement::size() {
@@ -56,10 +63,12 @@ std::optional<Hyprutils::Math::Vector2D> CRowLayoutElement::preferredSize(const
5663
if (calc.x != -1 && calc.y != -1)
5764
return calc;
5865

59-
Vector2D max;
66+
const Vector2D TEXT_CONSTRAINT{-1.F, calc.y > 0 ? calc.y : -1.F};
67+
Vector2D max;
6068
for (const auto& child : impl->children) {
61-
max.x += childSize(child).x + m_impl->data.gap;
62-
max.y = std::max(max.y, childSize(child).y);
69+
const auto CHILD_SIZE = childSizeForConstraint(child, parent, TEXT_CONSTRAINT);
70+
max.x += CHILD_SIZE.x + m_impl->data.gap;
71+
max.y = std::max(max.y, CHILD_SIZE.y);
6372
}
6473

6574
if (!impl->children.empty())
@@ -80,9 +89,12 @@ std::optional<Hyprutils::Math::Vector2D> CRowLayoutElement::preferredSize(const
8089
}
8190

8291
std::optional<Hyprutils::Math::Vector2D> CRowLayoutElement::minimumSize(const Hyprutils::Math::Vector2D& parent) {
83-
Vector2D min;
92+
const auto CALC = m_impl->data.size.calculate(parent);
93+
const Vector2D TEXT_CONSTRAINT = {-1.F, CALC.y > 0 ? CALC.y : -1.F};
94+
Vector2D min;
8495
for (const auto& child : impl->children) {
85-
min.y = std::max(min.y, childSize(child).y);
96+
const auto CHILD_SIZE = childSizeForConstraint(child, parent, TEXT_CONSTRAINT);
97+
min.y = std::max(min.y, CHILD_SIZE.y);
8698
}
8799

88100
return min;

src/element/spinbox/SpinboxSpinner.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@ SP<CSpinboxSpinner> CSpinboxSpinner::create(SP<CSpinboxElement> data) {
2020
return p;
2121
}
2222

23-
constexpr float ANGLE_SIZE = 12.F;
24-
constexpr float INNER_MARG = 2.F;
23+
constexpr float ANGLE_SIZE = 12.F;
24+
constexpr float INNER_MARG = 2.F;
25+
constexpr float INNER_GAP = 6.F;
26+
constexpr float INNER_FIXED_WIDTH = 2.F * ANGLE_SIZE + 4.F * INNER_GAP + 2.F * INNER_MARG;
2527

2628
CSpinboxSpinner::CSpinboxSpinner(SP<CSpinboxElement> data) : IElement(), m_parent(data) {
2729
;
2830
}
2931

3032
void CSpinboxSpinner::init() {
31-
m_layout = CRowLayoutBuilder::begin()->gap(6)->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence();
33+
m_layout = CRowLayoutBuilder::begin()->gap(INNER_GAP)->size({CDynamicSize::HT_SIZE_AUTO, CDynamicSize::HT_SIZE_AUTO, {1, 1}})->commence();
3234

3335
m_layout->setPositionFlag(HT_POSITION_FLAG_CENTER, true);
3436
m_layout->setPositionMode(HT_POSITION_ABSOLUTE);
@@ -39,6 +41,7 @@ void CSpinboxSpinner::init() {
3941
->color([] { return g_palette->m_colors.text; })
4042
->callback([this] { impl->window->scheduleReposition(impl->self); })
4143
->commence();
44+
m_label->setGrow(true, false);
4245

4346
m_background = CRectangleBuilder::begin()
4447
->color([] { return g_palette->m_colors.base; })
@@ -66,8 +69,8 @@ void CSpinboxSpinner::init() {
6669
.spinner = m_self,
6770
});
6871

69-
m_leftPad = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_PERCENT, {0.F, 1.F}})->commence();
70-
m_rightPad = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_PERCENT, {0.F, 1.F}})->commence();
72+
m_leftPad = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {0.F, 0.F}})->commence();
73+
m_rightPad = CNullBuilder::begin()->size({CDynamicSize::HT_SIZE_ABSOLUTE, CDynamicSize::HT_SIZE_ABSOLUTE, {0.F, 0.F}})->commence();
7174

7275
m_layout->addChild(m_leftPad);
7376
m_layout->addChild(m_left);
@@ -115,7 +118,8 @@ void CSpinboxSpinner::paint() {
115118
void CSpinboxSpinner::reposition(const Hyprutils::Math::CBox& box, const Hyprutils::Math::Vector2D& maxSize) {
116119
IElement::reposition(box);
117120

118-
g_positioner->positionChildren(impl->self.lock());
121+
g_positioner->position(m_background, impl->position);
122+
g_positioner->position(m_layout, impl->position, impl->position.size());
119123
}
120124

121125
Hyprutils::Math::Vector2D CSpinboxSpinner::size() {
@@ -127,11 +131,11 @@ std::optional<Vector2D> CSpinboxSpinner::preferredSize(const Hyprutils::Math::Ve
127131
}
128132

129133
std::optional<Vector2D> CSpinboxSpinner::minimumSize(const Hyprutils::Math::Vector2D& parent) {
130-
return m_layout->preferredSize(parent);
134+
return Vector2D{INNER_FIXED_WIDTH, ANGLE_SIZE + 2.F * INNER_MARG};
131135
}
132136

133137
std::optional<Vector2D> CSpinboxSpinner::maximumSize(const Hyprutils::Math::Vector2D& parent) {
134-
return m_layout->preferredSize(parent);
138+
return preferredSize(parent);
135139
}
136140

137141
bool CSpinboxSpinner::acceptsMouseInput() {

0 commit comments

Comments
 (0)