Skip to content

Commit 2b6482f

Browse files
committed
Merge branch 'improved-cursor-handling' into cursor-handling-overhaul
1 parent 46c613f commit 2b6482f

File tree

12 files changed

+311
-191
lines changed

12 files changed

+311
-191
lines changed

lib/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ set(ELEMENTS_SOURCES
3535
src/element/slider.cpp
3636
src/element/text.cpp
3737
src/element/tile.cpp
38+
src/element/tooltip.cpp
3839
src/support/canvas.cpp
3940
src/support/draw_utils.cpp
4041
src/support/font.cpp

lib/include/elements/element/composite.hpp

+27-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <vector>
1414
#include <array>
15+
#include <set>
1516

1617
namespace cycfi { namespace elements
1718
{
@@ -66,11 +67,11 @@ namespace cycfi { namespace elements
6667

6768
// Composite
6869

70+
using weak_element_ptr = std::weak_ptr<elements::element>;
71+
6972
struct hit_info
7073
{
71-
using weak_ptr = std::weak_ptr<elements::element>;
72-
73-
weak_ptr element;
74+
element_ptr element;
7475
rect bounds = rect{};
7576
int index = -1;
7677
};
@@ -79,15 +80,18 @@ namespace cycfi { namespace elements
7980
virtual rect bounds_of(context const& ctx, std::size_t index) const = 0;
8081
virtual bool reverse_index() const { return false; }
8182

83+
template <typename F>
84+
void for_each(F&& f, bool reverse = false) const;
85+
8286
private:
8387

8488
void new_focus(context const& ctx, int index);
8589

8690
int _focus = -1;
8791
int _saved_focus = -1;
88-
int _drag_tracking = -1;
89-
hit_info _click_info;
90-
hit_info _cursor_info;
92+
int _click_tracking = -1;
93+
int _cursor_tracking = -1;
94+
std::set<int> _cursor_hovering;
9195
};
9296

9397
////////////////////////////////////////////////////////////////////////////
@@ -164,6 +168,23 @@ namespace cycfi { namespace elements
164168
{
165169
return _container.at(_first + ix);
166170
}
171+
172+
template <typename F>
173+
inline void composite_base::for_each(F&& f, bool reverse) const
174+
{
175+
if (reverse_index() ^ reverse)
176+
{
177+
for (int ix = int(size())-1; ix >= 0; --ix)
178+
if (!f(ix, at(ix)))
179+
break;
180+
}
181+
else
182+
{
183+
for (std::size_t ix = 0; ix < size(); ++ix)
184+
if (!f(ix, at(ix)))
185+
break;
186+
}
187+
}
167188
}}
168189

169190
#endif

lib/include/elements/element/menu.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ namespace cycfi { namespace elements
5555

5656
void layout_menu(context const& ctx);
5757

58-
using popup_ptr = std::shared_ptr<basic_popup_element>;
58+
using popup_menu_ptr = std::shared_ptr<basic_popup_menu_element>;
5959

60-
popup_ptr _popup;
60+
popup_menu_ptr _popup;
6161
menu_position _position;
6262
};
6363

@@ -70,7 +70,7 @@ namespace cycfi { namespace elements
7070
template <typename Menu>
7171
inline void basic_menu::menu(Menu&& menu_)
7272
{
73-
_popup = std::dynamic_pointer_cast<basic_popup_element>(share(basic_popup(menu_)));
73+
_popup = share(basic_popup_menu(std::forward<Menu>(menu_)));
7474
}
7575

7676
////////////////////////////////////////////////////////////////////////////

lib/include/elements/element/popup.hpp

+27-6
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,21 @@ namespace cycfi { namespace elements
1919
{
2020
public:
2121

22-
using click_function = std::function<void(view& view_)>;
22+
using cursor_function = std::function<void(point p, cursor_tracking status)>;
2323

2424
basic_popup_element(rect bounds = {})
2525
: floating_element(bounds)
2626
{}
2727

28+
bool wants_control() const override { return true; }
2829
element* hit_test(context const& ctx, point p) override;
29-
element* click(context const& ctx, mouse_button btn) override;
3030
bool cursor(context const& ctx, point p, cursor_tracking status) override;
3131

32-
void open(view& view_, click_function on_click = {});
32+
bool is_open(view& view_) const;
33+
void open(view& view_);
3334
void close(view& view_);
3435

35-
private:
36-
37-
click_function _on_click;
36+
cursor_function on_cursor = [](auto, auto){};
3837
};
3938

4039
template <typename Subject>
@@ -43,6 +42,28 @@ namespace cycfi { namespace elements
4342
{
4443
return { std::forward<Subject>(subject), bounds };
4544
}
45+
46+
////////////////////////////////////////////////////////////////////////////
47+
// Popup Menu
48+
////////////////////////////////////////////////////////////////////////////
49+
class basic_popup_menu_element : public basic_popup_element
50+
{
51+
public:
52+
53+
using basic_popup_element::basic_popup_element;
54+
using click_function = std::function<void()>;
55+
56+
element* hit_test(context const& ctx, point p) override;
57+
element* click(context const& ctx, mouse_button btn) override;
58+
click_function on_click = [](){};
59+
};
60+
61+
template <typename Subject>
62+
inline proxy<remove_cvref_t<Subject>, basic_popup_menu_element>
63+
basic_popup_menu(Subject&& subject, rect bounds = {})
64+
{
65+
return { std::forward<Subject>(subject), bounds };
66+
}
4667
}}
4768

4869
#endif

lib/include/elements/element/port.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ namespace cycfi { namespace elements
188188
bool allow_hscroll() const { return !(_traits & no_hscroll); }
189189
bool allow_vscroll() const { return !(_traits & no_vscroll); }
190190

191+
point _cursor;
191192
point _offset;
192193
tracking_status _tracking;
193194
int _traits;

lib/include/elements/element/tooltip.hpp

+15-68
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define ELEMENTS_TOOLTIP_AUGUST_27_2020
88

99
#include <elements/element/proxy.hpp>
10+
#include <elements/element/popup.hpp>
1011
#include <infra/support.hpp>
1112
#include <functional>
1213

@@ -15,94 +16,40 @@ namespace cycfi { namespace elements
1516
////////////////////////////////////////////////////////////////////////////
1617
// Tooltip elements
1718
////////////////////////////////////////////////////////////////////////////
18-
template <typename Subject, typename Tip>
19-
class tooltip_element : public proxy<Subject>
19+
class tooltip_element : public proxy_base
2020
{
2121
public:
2222

23-
using base_type = proxy<Subject>;
23+
using base_type = proxy_base;
24+
using on_hover_function = std::function<void(bool visible)>;
2425

25-
tooltip_element(Subject subject, Tip tip, duration delay)
26-
: base_type(std::move(subject))
27-
, _tip(std::move(tip))
26+
template <typename Tip>
27+
tooltip_element(Tip&& tip, duration delay)
28+
: _tip(share(basic_popup(std::forward<Tip>(tip))))
2829
, _delay(delay)
2930
{}
3031

31-
void draw(context const& ctx) override;
3232
bool cursor(context const& ctx, point p, cursor_tracking status) override;
33-
34-
Subject const& tip() const { return _tip; }
35-
Subject& tip() { return _tip; }
36-
37-
using on_hover_function = std::function<void(bool visible)>;
33+
bool key(context const& ctx, key_info k) override;
3834

3935
on_hover_function on_hover = [](bool){};
4036

4137
private:
4238

43-
rect tip_bounds(context const& ctx) const;
44-
39+
using popup_ptr = std::shared_ptr<basic_popup_element>;
4540
enum status { tip_hidden, tip_delayed, tip_visible };
4641

47-
Tip _tip;
42+
rect tip_bounds(context const& ctx) const;
43+
void close_tip(view& view_);
44+
45+
popup_ptr _tip;
4846
status _tip_status = tip_hidden;
4947
duration _delay;
48+
bool _cursor_in_tip = false;
5049
};
5150

5251
template <typename Subject, typename Tip>
53-
inline rect tooltip_element<Subject, Tip>::tip_bounds(context const& ctx) const
54-
{
55-
auto limits_ = _tip.limits(ctx);
56-
auto w = limits_.min.x;
57-
auto h = limits_.min.y;
58-
return rect{ 0, 0, w, h }.move_to(ctx.bounds.left, ctx.bounds.top-h);
59-
}
60-
61-
template <typename Subject, typename Tip>
62-
inline void tooltip_element<Subject, Tip>::draw(context const& ctx)
63-
{
64-
base_type::draw(ctx);
65-
if (_tip_status == tip_visible)
66-
{
67-
context tctx { ctx, &_tip, tip_bounds(ctx) };
68-
_tip.draw(tctx);
69-
}
70-
}
71-
72-
template <typename Subject, typename Tip>
73-
inline bool tooltip_element<Subject, Tip>::cursor(context const& ctx, point p, cursor_tracking status)
74-
{
75-
if (status != cursor_tracking::leaving)
76-
{
77-
if (_tip_status != tip_visible)
78-
{
79-
_tip_status = tip_delayed;
80-
auto refresh_rect = max(ctx.bounds, tip_bounds(ctx));
81-
ctx.view.post(std::chrono::duration_cast<std::chrono::milliseconds>(_delay),
82-
[this, &view = ctx.view, refresh_rect]()
83-
{
84-
if (_tip_status == tip_delayed)
85-
{
86-
on_hover(true);
87-
_tip_status = tip_visible;
88-
view.refresh(refresh_rect);
89-
}
90-
}
91-
);
92-
}
93-
}
94-
else
95-
{
96-
_tip_status = tip_hidden;
97-
on_hover(false);
98-
ctx.view.refresh(max(ctx.bounds, tip_bounds(ctx)));
99-
}
100-
101-
return base_type::cursor(ctx, p, status);
102-
}
103-
104-
template <typename Subject, typename Tip>
105-
inline tooltip_element<remove_cvref_t<Subject>, remove_cvref_t<Tip>>
52+
inline proxy<remove_cvref_t<Subject>, tooltip_element>
10653
tooltip(Subject&& subject, Tip&& tip, duration delay = milliseconds{ 500 })
10754
{
10855
return { std::forward<Subject>(subject), std::forward<Tip>(tip), delay };

lib/infra

0 commit comments

Comments
 (0)