Skip to content

Commit 1f8786a

Browse files
committed
Implemented child_window resizing (#419)
1 parent 486128b commit 1f8786a

File tree

6 files changed

+217
-3
lines changed

6 files changed

+217
-3
lines changed

examples/child_window/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ auto background = box(bkd_color);
1515
auto make_child_window(rect bounds, char const* title)
1616
{
1717
using cycfi::elements::image;
18-
return closable_child_window(
18+
return standard_child_window(
1919
title,
2020
bounds,
2121
scroller(image{"deep_space.jpg"})

lib/include/elements/element/child_window.hpp

+35
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,41 @@ namespace cycfi::elements
110110
return {std::forward<Subject>(subject)};
111111
}
112112

113+
struct resizable_tracker_info : tracker_info
114+
{
115+
using tracker_info::tracker_info;
116+
117+
enum handle : unsigned char
118+
{
119+
top = 1,
120+
left = 2,
121+
bottom = 4,
122+
right = 8
123+
};
124+
125+
unsigned char _handle = 0;
126+
};
127+
128+
class resizable_base : public tracker<proxy_base, resizable_tracker_info>
129+
{
130+
public:
131+
132+
using tracker = tracker<proxy_base, resizable_tracker_info>;
133+
134+
bool cursor(context const& ctx, point p, cursor_tracking status) override;
135+
element* hit_test(context const& ctx, point p, bool leaf, bool control) override;
136+
bool click(context const& ctx, mouse_button btn) override;
137+
void drag(context const& ctx, mouse_button btn) override;
138+
void keep_tracking(context const& ctx, tracker_info& track_info) override;
139+
};
140+
141+
template <concepts::Element Subject>
142+
inline proxy<remove_cvref_t<Subject>, resizable_base>
143+
resizable(Subject&& subject)
144+
{
145+
return {std::forward<Subject>(subject)};
146+
}
147+
113148
/**
114149
* \class closable_element
115150
*

lib/include/elements/element/style/child_window.hpp

+37
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ namespace cycfi::elements
4343
// Closable Child Window (movable and closable)
4444
////////////////////////////////////////////////////////////////////////////
4545
template <typename Content>
46+
[[deprecated("Use standard_child_window(...) instead")]]
4647
auto closable_child_window(std::string title, rect bounds, Content&& content)
4748
{
4849
return child_window(bounds,
@@ -66,6 +67,7 @@ namespace cycfi::elements
6667
}
6768

6869
template <typename Content>
70+
[[deprecated("Use standard_child_window(...) instead")]]
6971
auto closable_child_window(std::string title, point pos, Content&& content)
7072
{
7173
return closable_child_window(
@@ -74,6 +76,41 @@ namespace cycfi::elements
7476
std::forward<Content>(content)
7577
);
7678
}
79+
80+
template <typename Content>
81+
auto standard_child_window(std::string title, rect bounds, Content&& content)
82+
{
83+
return child_window(bounds,
84+
resizable(
85+
pane_ex(
86+
movable(
87+
layer(
88+
closable(
89+
align_right_middle(
90+
plain_icon_button(icons::cancel, 0.8)
91+
)
92+
),
93+
title_bar{}
94+
)
95+
),
96+
title,
97+
std::forward<Content>(content),
98+
get_theme().child_window_title_size,
99+
get_theme().child_window_opacity
100+
)
101+
)
102+
);
103+
}
104+
105+
template <typename Content>
106+
auto standard_child_window(std::string title, point pos, Content&& content)
107+
{
108+
return standard_child_window(
109+
title,
110+
rect{pos.x, pos.y, pos.x, pos.y},
111+
std::forward<Content>(content)
112+
);
113+
}
77114
}
78115

79116
#endif

lib/src/element/child_window.cpp

+139
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,147 @@ namespace cycfi::elements
9595
}
9696
}
9797

98+
bool resizable_base::cursor(context const& ctx, point p, cursor_tracking /* status */)
99+
{
100+
auto outer = ctx.bounds.inset(-5);
101+
auto inner = ctx.bounds.inset(5);
102+
if (ctx.enabled && is_enabled() && outer.includes(p) && !inner.includes(p))
103+
{
104+
auto const& b = ctx.bounds;
105+
bool h_resize = false;
106+
bool v_resize = false;
107+
if (p.x > b.left - 5 && p.x < b.left + 5)
108+
h_resize = true;
109+
else if (p.x > b.right - 5 && p.x < b.right + 5)
110+
h_resize = true;
111+
112+
if (p.y > b.top - 5 && p.y < b.top + 5)
113+
v_resize = true;
114+
else if (p.y > b.bottom - 5 && p.y < b.bottom + 5)
115+
v_resize = true;
116+
117+
if (h_resize != v_resize)
118+
set_cursor(h_resize? cursor_type::h_resize : cursor_type::v_resize);
119+
return true;
120+
}
121+
return false;
122+
}
123+
124+
element* resizable_base::hit_test(context const& ctx, point p, bool leaf, bool control)
125+
{
126+
auto outer = ctx.bounds.inset(-5);
127+
auto inner = ctx.bounds.inset(5);
128+
if (ctx.enabled && is_enabled() && outer.includes(p) && !inner.includes(p))
129+
return this;
130+
return proxy_base::hit_test(ctx, p, leaf, control);
131+
}
132+
133+
bool resizable_base::click(context const& ctx, mouse_button btn)
134+
{
135+
if (proxy_base::click(ctx, btn))
136+
return true;
137+
138+
if (ctx.enabled && is_enabled())
139+
{
140+
bool r = tracker::click(ctx, btn);
141+
auto state = get_state();
142+
if (state)
143+
{
144+
auto outer = ctx.bounds.inset(-5);
145+
auto inner = ctx.bounds.inset(5);
146+
if (outer.includes(btn.pos) && !inner.includes(btn.pos))
147+
{
148+
auto const& b = ctx.bounds;
149+
if (btn.pos.x > b.left - 5 && btn.pos.x < b.left + 5)
150+
state->_handle = resizable_tracker_info::left;
151+
else if (btn.pos.x > b.right - 5 && btn.pos.x < b.right + 5)
152+
state->_handle = resizable_tracker_info::right;
153+
154+
if (btn.pos.y > b.top - 5 && btn.pos.y < b.top + 5)
155+
state->_handle |= resizable_tracker_info::top;
156+
else if (btn.pos.y > b.bottom - 5 && btn.pos.y < b.bottom + 5)
157+
state->_handle |= resizable_tracker_info::bottom;
158+
}
159+
}
160+
return r;
161+
}
162+
return false;
163+
}
164+
165+
void resizable_base::drag(context const& ctx, mouse_button btn)
166+
{
167+
auto state = get_state();
168+
if (!state)
169+
{
170+
proxy_base::drag(ctx, btn);
171+
}
172+
else
173+
{
174+
tracker::drag(ctx, btn);
175+
}
176+
}
177+
178+
void resizable_base::keep_tracking(context const& ctx, tracker_info& track_info)
179+
{
180+
if (track_info.current != track_info.previous)
181+
{
182+
auto fl = find_parent<floating_element*>(ctx);
183+
if (fl)
184+
{
185+
auto p = track_info.current;
186+
auto b = fl->bounds();
187+
if (auto state = get_state(); state && state->_handle)
188+
{
189+
if (state->_handle & resizable_tracker_info::left)
190+
b.left = p.x;
191+
else if (state->_handle & resizable_tracker_info::right)
192+
b.right = p.x;
193+
194+
if (state->_handle & resizable_tracker_info::top)
195+
b.top = p.y;
196+
else if (state->_handle & resizable_tracker_info::bottom)
197+
b.bottom = p.y;
198+
199+
auto width = b.width();
200+
auto height = b.height();
201+
auto ob = fl->bounds();
202+
203+
auto limits = fl->subject().limits(ctx);
204+
205+
// Constrain width
206+
if (width < limits.min.x || width > limits.max.x)
207+
{
208+
if (state->_handle & resizable_tracker_info::left)
209+
b.left = ob.left;
210+
else if (state->_handle & resizable_tracker_info::right)
211+
b.right = ob.right;
212+
}
213+
214+
// Constrain height
215+
if (height < limits.min.y || height > limits.max.y)
216+
{
217+
if (state->_handle & resizable_tracker_info::top)
218+
b.top = ob.top;
219+
else if (state->_handle & resizable_tracker_info::bottom)
220+
b.bottom = ob.bottom;
221+
}
222+
if (b != ob)
223+
{
224+
fl->bounds(b);
225+
ctx.view.refresh();
226+
}
227+
}
228+
}
229+
}
230+
}
231+
98232
void close_floating_element(context& ctx, floating_element* fl)
99233
{
100234
ctx.view.remove(fl->shared_from_this());
101235
}
236+
237+
void minimize_floating_element(context& ctx, floating_element* fl)
238+
{
239+
ctx.view.remove(fl->shared_from_this());
240+
}
102241
}

lib/src/element/floating.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ namespace cycfi::elements
3535
this->bounds(ctx.bounds);
3636
}
3737
}
38+

lib/src/element/port.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,10 @@ namespace cycfi::elements
317317
view_limits e_limits = subject().limits(ctx);
318318
theme const& thm = get_theme();
319319

320-
r.has_h = e_limits.min.x > ctx.bounds.width() && allow_hscroll();
321-
r.has_v = e_limits.min.y > ctx.bounds.height() && allow_vscroll();
320+
auto delta_x = e_limits.min.x - ctx.bounds.width();
321+
auto delta_y = e_limits.min.y - ctx.bounds.height();
322+
r.has_h = delta_x > 4.0 && allow_hscroll();
323+
r.has_v = delta_y > 4.0 && allow_vscroll();
322324

323325
if (r.has_v)
324326
{

0 commit comments

Comments
 (0)