Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
buttons.hpp
Go to the documentation of this file.
1#pragma once
2
3// Extended button types for Pulp UI.
4// TextButton, HyperlinkButton, ArrowButton, ShapeButton, ImageButton.
5
6#include <pulp/view/view.hpp>
9#include <string>
10#include <functional>
11
12namespace pulp::view {
13
14// ── TextButton ──────────────────────────────────────────────────────────
15// Push button with text label. Triggers an action on click (not a toggle).
16
17class TextButton : public View {
18public:
19 // Visual variants matching the Ink & Signal design language. `secondary`
20 // (the default) is the historical neutral filled+border face, so existing
21 // UIs are unchanged; `primary` is an accent-filled call-to-action; `ghost`
22 // is transparent with accent text.
23 enum class Style { primary, secondary, ghost };
24
25 // A TextButton is a push button, not a checkbox: it fires on_click and
26 // carries no checked state. It announced itself as AccessRole::toggle
27 // (NSAccessibilityCheckBoxRole / AT-SPI TOGGLE_BUTTON) until the role
28 // vocabulary grew a `button` literal, so every screen reader told the user
29 // "checkbox" and offered a state it does not have.
30 // A button is one target, including whatever is drawn inside it. Children
31 // default to `auto_`, and hit_test() returns the topmost hit-testable view
32 // — so an icon or label centred in a button silently swallowed the click
33 // and on_click never fired. Clicking the button's few bare pixels worked,
34 // which made it look intermittent rather than broken. `box_only` is the
35 // React-Native-shaped way to say "me, never my children"; a button that
36 // genuinely needs an interactive child can opt back out with
37 // set_pointer_events(PointerEvents::auto_).
49
50 void set_label(std::string text) { label_ = std::move(text); set_derived_access_label(label_); }
51 const std::string& label() const { return label_; }
52
53 void set_style(Style s) { style_ = s; }
54 Style style() const { return style_; }
55
56 void set_enabled(bool e) { enabled_ = e; }
57 bool is_enabled() const { return enabled_; }
58
60 std::function<void()> on_click;
61
62 void paint(canvas::Canvas& canvas) override;
63 void on_mouse_down(Point pos) override;
64 void on_mouse_up(Point pos) override;
65 void on_mouse_enter() override;
66 void on_mouse_leave() override;
67 bool wants_mouse_input() const override { return true; }
68
69 bool is_pressed() const { return pressed_; }
70
71 float intrinsic_height() const override { return 36.0f; }
72
76
77private:
78 std::string label_;
79 Style style_ = Style::secondary;
80 bool enabled_ = true;
81 bool hovered_ = false;
82 bool pressed_ = false;
83};
84
85// ── HyperlinkButton ─────────────────────────────────────────────────────
86// Button that opens a URL in the system browser.
87
88class HyperlinkButton : public View {
89public:
91 HyperlinkButton(std::string text, std::string url)
92 : text_(std::move(text)), url_(std::move(url)) {
95 set_focusable(true);
96 }
97
98 void set_text(std::string text) { text_ = std::move(text); set_derived_access_label(text_); }
99 const std::string& text() const { return text_; }
100
101 void set_url(std::string url) { url_ = std::move(url); }
102 const std::string& url() const { return url_; }
103
104 void paint(canvas::Canvas& canvas) override;
105 void on_mouse_down(Point pos) override;
106 void on_mouse_enter() override;
107 void on_mouse_leave() override;
108 bool wants_mouse_input() const override { return true; }
109
110private:
111 std::string text_;
112 std::string url_;
113 bool hovered_ = false;
114};
115
116// ── ArrowButton ─────────────────────────────────────────────────────────
117// Small button with a directional arrow (for steppers, scrolling, etc.)
118
119enum class ArrowDirection { up, down, left, right };
120
121// ArrowButton / ShapeButton / ImageButton carry no text, so nothing can be
122// derived as an accessible name. They claim AccessRole::button — which is what
123// they ARE — but the shared exposure gate (is_accessibility_element, in
124// accessibility.hpp) keeps a nameless button OUT of the tree: announcing an unnamed
125// "button" for every transport arrow and icon in a UI is a WCAG 4.1.2 failure,
126// not an improvement. Call set_access_label("Play") and the button appears,
127// correctly roled, on every platform. No name is invented for you: "Down" or
128// "star.png" would be a plausible-sounding lie about what the control does.
129class ArrowButton : public View {
130public:
132 explicit ArrowButton(ArrowDirection dir) : direction_(dir) {
134 set_focusable(true);
135 }
136
137 void set_direction(ArrowDirection dir) { direction_ = dir; }
138 ArrowDirection direction() const { return direction_; }
139
140 std::function<void()> on_click;
141
142 void paint(canvas::Canvas& canvas) override;
143 void on_mouse_down(Point pos) override;
144 bool wants_mouse_input() const override { return true; }
145
146private:
148};
149
150// ── ShapeButton ─────────────────────────────────────────────────────────
151// Button that draws a custom shape (via path callback).
152
153class ShapeButton : public View {
154public:
156
158 using ShapeDrawFn = std::function<void(canvas::Canvas&, float width, float height, bool hovered, bool pressed)>;
159 void set_shape(ShapeDrawFn fn) { draw_fn_ = std::move(fn); }
160
161 std::function<void()> on_click;
162
163 void paint(canvas::Canvas& canvas) override;
164 void on_mouse_down(Point pos) override;
165 void on_mouse_enter() override;
166 void on_mouse_leave() override;
167 bool wants_mouse_input() const override { return true; }
168
169private:
170 ShapeDrawFn draw_fn_;
171 bool hovered_ = false;
172 bool pressed_ = false;
173};
174
175// ── ImageButton ─────────────────────────────────────────────────────────
176// Button that displays an image, with separate images for normal/hover/down states.
177
178class ImageButton : public View {
179public:
181
182 void set_image(std::string path) { normal_path_ = std::move(path); }
183 void set_hover_image(std::string path) { hover_path_ = std::move(path); }
184 void set_pressed_image(std::string path) { pressed_path_ = std::move(path); }
185
186 std::function<void()> on_click;
187
188 void paint(canvas::Canvas& canvas) override;
189 void on_mouse_down(Point pos) override;
190 void on_mouse_enter() override;
191 void on_mouse_leave() override;
192 bool wants_mouse_input() const override { return true; }
193
194private:
195 std::string normal_path_;
196 std::string hover_path_;
197 std::string pressed_path_;
198 bool hovered_ = false;
199 bool pressed_ = false;
200};
201
202// ── ResizableCorner ─────────────────────────────────────────────────────
203// Drag handle for resizing a parent view or window.
204
205class ResizableCorner : public View {
206public:
208
210 std::function<void(float dx, float dy)> on_resize;
211
212 void paint(canvas::Canvas& canvas) override;
213 void on_mouse_event(const MouseEvent& event) override;
214 void on_mouse_down(Point pos) override;
215 void on_mouse_drag(Point pos) override;
216 bool wants_mouse_input() const override { return true; }
217
218 float intrinsic_height() const override { return 16.0f; }
219
220private:
221 float drag_start_x_ = 0;
222 float drag_start_y_ = 0;
223 float movement_x_ = 0;
224 float movement_y_ = 0;
225 bool native_drag_pending_ = false;
226};
227
228} // namespace pulp::view
Definition canvas.hpp:240
void set_direction(ArrowDirection dir)
Definition buttons.hpp:137
ArrowDirection direction() const
Definition buttons.hpp:138
ArrowButton()
Definition buttons.hpp:131
std::function< void()> on_click
Definition buttons.hpp:140
ArrowButton(ArrowDirection dir)
Definition buttons.hpp:132
void paint(canvas::Canvas &canvas) override
bool wants_mouse_input() const override
True if this widget handles mouse down/drag through virtual methods even when it does not expose JS p...
Definition buttons.hpp:144
void on_mouse_down(Point pos) override
void set_url(std::string url)
Definition buttons.hpp:101
void on_mouse_leave() override
const std::string & text() const
Definition buttons.hpp:99
HyperlinkButton(std::string text, std::string url)
Definition buttons.hpp:91
void on_mouse_down(Point pos) override
HyperlinkButton()
Definition buttons.hpp:90
void on_mouse_enter() override
void set_text(std::string text)
Definition buttons.hpp:98
void paint(canvas::Canvas &canvas) override
const std::string & url() const
Definition buttons.hpp:102
bool wants_mouse_input() const override
True if this widget handles mouse down/drag through virtual methods even when it does not expose JS p...
Definition buttons.hpp:108
void set_image(std::string path)
Definition buttons.hpp:182
void on_mouse_down(Point pos) override
void set_pressed_image(std::string path)
Definition buttons.hpp:184
std::function< void()> on_click
Definition buttons.hpp:186
bool wants_mouse_input() const override
True if this widget handles mouse down/drag through virtual methods even when it does not expose JS p...
Definition buttons.hpp:192
void on_mouse_leave() override
void on_mouse_enter() override
ImageButton()
Definition buttons.hpp:180
void set_hover_image(std::string path)
Definition buttons.hpp:183
void paint(canvas::Canvas &canvas) override
void on_mouse_event(const MouseEvent &event) override
Mouse down with full event context.
ResizableCorner()
Definition buttons.hpp:207
float intrinsic_height() const override
Definition buttons.hpp:218
void paint(canvas::Canvas &canvas) override
void on_mouse_down(Point pos) override
std::function< void(float dx, float dy)> on_resize
Called during drag with (dx, dy) delta from the drag start.
Definition buttons.hpp:210
void on_mouse_drag(Point pos) override
bool wants_mouse_input() const override
True if this widget handles mouse down/drag through virtual methods even when it does not expose JS p...
Definition buttons.hpp:216
void paint(canvas::Canvas &canvas) override
void on_mouse_down(Point pos) override
bool wants_mouse_input() const override
True if this widget handles mouse down/drag through virtual methods even when it does not expose JS p...
Definition buttons.hpp:167
ShapeButton()
Definition buttons.hpp:155
std::function< void(canvas::Canvas &, float width, float height, bool hovered, bool pressed)> ShapeDrawFn
Set the shape drawing function. Called during paint with the button's bounds.
Definition buttons.hpp:158
std::function< void()> on_click
Definition buttons.hpp:161
void on_mouse_leave() override
void on_mouse_enter() override
void set_shape(ShapeDrawFn fn)
Definition buttons.hpp:159
void on_mouse_enter() override
bool is_enabled() const
Definition buttons.hpp:57
void on_mouse_down(Point pos) override
TextButton(std::string label)
Definition buttons.hpp:43
bool is_pressed() const
Definition buttons.hpp:69
bool wants_mouse_input() const override
True if this widget handles mouse down/drag through virtual methods even when it does not expose JS p...
Definition buttons.hpp:67
void paint_label(canvas::Canvas &canvas)
The stock label rendering, split out of paint() so a delegate that skins only the button FACE still g...
Style style() const
Definition buttons.hpp:54
Style
Definition buttons.hpp:23
@ secondary
Definition buttons.hpp:23
@ primary
Definition buttons.hpp:23
@ ghost
Definition buttons.hpp:23
void paint(canvas::Canvas &canvas) override
float intrinsic_height() const override
Definition buttons.hpp:71
std::function< void()> on_click
Called when the button is clicked.
Definition buttons.hpp:60
void on_mouse_leave() override
void set_style(Style s)
Definition buttons.hpp:53
void on_mouse_up(Point pos) override
void set_enabled(bool e)
Definition buttons.hpp:56
TextButton()
Definition buttons.hpp:38
const std::string & label() const
Definition buttons.hpp:51
void set_label(std::string text)
Definition buttons.hpp:50
void set_pointer_events(PointerEvents p)
Definition view.hpp:732
@ link
Definition view.hpp:990
@ button
Definition view.hpp:990
@ box_only
Definition view.hpp:731
void set_derived_access_label(std::string label)
The CONTENT-DERIVED accessible name: a widget's visible text (Label::set_text, Knob/Fader/Toggleset_l...
Definition view.hpp:1020
@ text
Definition view.hpp:2742
void set_access_role(AccessRole role)
Definition view.hpp:995
void set_focusable(bool f)
Definition view.hpp:669
Definition affine_transform.hpp:24
Hover-cursor tracking for platform window hosts.
Definition fwd.hpp:27
ArrowDirection
Definition buttons.hpp:119
@ up
Definition buttons.hpp:119
@ down
Definition buttons.hpp:119
@ right
Definition buttons.hpp:119
@ path
Definition anchor_strategy.hpp:42
@ right
Definition border_style.hpp:31
@ left
Definition border_style.hpp:31
@ pressed
Definition widgets.hpp:1731
@ hovered
Definition widgets.hpp:1731
@ s
Definition input_events.hpp:41
@ e
Definition input_events.hpp:39
@ height
Definition css_animation.hpp:128
@ width
Definition css_animation.hpp:127
STL namespace.
Rich mouse/pointer event with position, modifiers, button state, pointer ID, and stylus properties.
Definition input_events.hpp:104
Definition geometry.hpp:20
A pluggable paint delegate for Pulp's stock widgets.