Loading...
Searching...
No Matches
Painter.hpp
1#pragma once
2#include <score/model/Skin.hpp>
3
4#include <QFlags>
5#include <QGradient>
6#include <QGraphicsItem>
7#include <QGraphicsSceneMouseEvent>
8#include <QPainter>
9#include <QPolygon>
10
11#include <avnd/concepts/painter.hpp>
12
13#include <cmath>
14
15namespace oscr
16{
18{
19 uint8_t r, g, b, a;
20};
22{
23 QPainter& painter;
24 QGraphicsItem& item;
25 QPainterPath path;
26
27 void begin_path() { path = QPainterPath{}; }
28 void close_path() { path.closeSubpath(); }
29 void stroke() { painter.strokePath(path, painter.pen()); }
30 void fill() { painter.fillPath(path, painter.brush()); }
31 void update() { item.update(); }
32
33 void move_to(double x, double y) { path.moveTo(x, y); }
34 void line_to(double x, double y) { path.lineTo(x, y); }
35 void arc_to(double x, double y, double w, double h, double start, double length)
36 {
37 path.arcTo(x, y, w, h, start, length);
38 }
39
40 void cubic_to(double c1x, double c1y, double c2x, double c2y, double endx, double endy)
41 {
42 path.cubicTo(c1x, c1y, c2x, c2y, endx, endy);
43 }
44
45 void quad_to(double x1, double y1, double x2, double y2)
46 {
47 path.quadTo(x1, y1, x2, y2);
48 }
49
50 void translate(double x, double y) { painter.translate(x, y); }
51 void scale(double x, double y) { painter.scale(x, y); }
52 void rotate(double a) { painter.rotate(a); }
53 void reset_transform() { painter.resetTransform(); }
54
55 // Colors:
56 void set_stroke_color(rgba_color c)
57 {
58 QPen p = painter.pen();
59 p.setColor(qRgba(c.r, c.g, c.b, c.a));
60 painter.setPen(p);
61 }
62
63 void set_stroke_width(double w)
64 {
65 QPen p = painter.pen();
66 p.setWidth(w);
67 painter.setPen(p);
68 }
69
70 void set_fill_color(rgba_color c)
71 {
72 painter.setBrush(QColor(qRgba(c.r, c.g, c.b, c.a)));
73 }
74
75 void set_linear_gradient(
76 double x1, double y1, double x2, double y2, rgba_color c1, rgba_color c2)
77 {
78 QLinearGradient gradient(QPointF(x1, y1), QPointF(x2, y2));
79 gradient.setColorAt(0, QColor(qRgba(c1.r, c1.g, c1.b, c1.a)));
80 gradient.setColorAt(1, QColor(qRgba(c2.r, c2.g, c2.b, c2.a)));
81 painter.setBrush(gradient);
82 }
83
84 void set_radial_gradient(double cx, double cy, double cr, rgba_color c1, rgba_color c2)
85 {
86 QRadialGradient gradient(cx, cy, cr);
87 gradient.setColorAt(0, QColor(qRgba(c1.r, c1.g, c1.b, c1.a)));
88 gradient.setColorAt(1, QColor(qRgba(c2.r, c2.g, c2.b, c2.a)));
89 painter.setBrush(gradient);
90 }
91
92 void set_conical_gradient(double x, double y, double a, rgba_color c1, rgba_color c2)
93 {
94 QConicalGradient gradient(x, y, a);
95 gradient.setColorAt(0, QColor(qRgba(c1.r, c1.g, c1.b, c1.a)));
96 gradient.setColorAt(1, QColor(qRgba(c2.r, c2.g, c2.b, c2.a)));
97 painter.setBrush(gradient);
98 }
99
100 // Text:
101 void set_font(std::string_view f)
102 {
103 auto font = painter.font();
104 font.setFamily(QString::fromUtf8(f.data(), f.size()));
105 painter.setFont(font);
106 }
107
108 void set_font_size(double f)
109 {
110 auto font = painter.font();
111 font.setPointSize(f);
112 painter.setFont(font);
113 }
114
115 void draw_text(double x, double y, std::string_view str)
116 {
117 path.addText(x, y, painter.font(), QString::fromUtf8(str.data(), str.size()));
118 }
119
120 // Drawing
121 void draw_line(double x1, double y1, double x2, double y2)
122 {
123 path.moveTo(x1, y1);
124 path.lineTo(x2, y2);
125 }
126
127 // x1, y1, x2 , y2, x3, y3
128 void draw_triangle(double x1, double y1, double x2, double y2, double x3, double y3)
129 {
130 path.moveTo(x1, y1);
131 path.lineTo(x2, y2);
132 path.lineTo(x3, y3);
133 path.lineTo(x1, y1);
134 painter.drawPath(path);
135 }
136
137 // x , y , w , h
138 void draw_rect(double x, double y, double w, double h) { path.addRect(x, y, w, h); }
139
140 // x , y , w , h
141 void draw_rounded_rect(double x, double y, double w, double h, double r)
142 {
143 path.addRoundedRect(x, y, w, h, r, r);
144 }
145
146 // x , y , filename
147 void draw_pixmap(double x, double y, const QString& str)
148 {
149 painter.drawPixmap(x, y, str);
150 }
151
152 // x , y , w , h
153 void draw_ellipse(double x, double y, double w, double h)
154 {
155 path.addEllipse(x, y, w, h);
156 }
157
158 // cx, cy, radius
159 void draw_circle(double cx, double cy, double cr)
160 {
161 path.addEllipse(QPointF{cx, cy}, cr, cr);
162 }
163
164 // tab, count
165 void draw_polygon(const double* tab, int count)
166 {
167 QPolygonF poly;
168 double x, y;
169 for(int i = 0; i < count * 2; i += 2)
170 {
171 x = tab[i];
172 y = tab[i + 1];
173 poly << QPointF(x, y);
174 }
175 path.addPolygon(poly);
176 }
177
178 void draw_bytes(
179 int x, int y, int w, int h, const unsigned char* image, int img_w, int img_h)
180 {
181 auto img = QImage(image, img_w, img_h, QImage::Format_RGBA8888);
182 auto prev = painter.renderHints() & QPainter::SmoothPixmapTransform;
183 painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
184 painter.drawImage(
185 QRect(x, y, w, h), img, QRect(0, 0, img_w, img_h), Qt::ImageConversionFlags{});
186
187 painter.setRenderHint(QPainter::SmoothPixmapTransform, prev);
188 }
189};
190static_assert(avnd::painter<QPainterAdapter>);
191
192template <typename Item, typename Control = void>
193class CustomItem : public QGraphicsItem
194{
195public:
196 // Item may be T::item_type or T&
197 using item_type = std::decay_t<Item>;
198
199 // // Case T::item_type
200 // explicit CustomItem() { init(); }
201
202 // Case T&
203 explicit CustomItem(Item t)
204 : impl{t}
205 {
206 this->setFlag(QGraphicsItem::ItemClipsToShape);
207 this->setFlag(QGraphicsItem::ItemClipsChildrenToShape);
208
209 if constexpr(requires { this->impl.update = [this] {}; })
210 {
211 this->impl.update = [this] { this->update(); };
212 }
213 }
214
215 QRectF boundingRect() const override
216 {
217 return {0., 0., item_type::width(), item_type::height()};
218 }
219
220 void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
221 override
222 {
223 auto& skin = score::Skin::instance();
224 painter->setRenderHint(QPainter::Antialiasing, true);
225 painter->setPen(skin.Dark.main.pen1);
226 impl.paint(QPainterAdapter{*painter, *this, {}});
227 painter->setRenderHint(QPainter::Antialiasing, false);
228 }
229
231 {
232 enum button
233 {
234 no_button,
235 left = (1 << 1),
236 right = (1 << 2),
237 middle = (1 << 3)
238 };
239 friend button& operator|=(button& lhs, button rhs) noexcept
240 {
241 return (
242 enum button&)(reinterpret_cast<std::underlying_type_t<enum button>&>(lhs) |= reinterpret_cast<std::underlying_type_t<enum button>&>(rhs));
243 }
244 enum modifier
245 {
246 no_modifier,
247 shift = (1 << 1),
248 ctrl = (1 << 2),
249 alt = (1 << 3),
250 meta = (1 << 4)
251 };
252 friend modifier& operator|=(modifier& lhs, modifier rhs) noexcept
253 {
254 return (
255 enum modifier&)(reinterpret_cast<std::underlying_type_t<enum modifier>&>(lhs) |= reinterpret_cast<std::underlying_type_t<enum modifier>&>(rhs));
256 }
257
258 float x, y;
259
260 enum button button = {};
261 enum button held_buttons = {};
262 enum modifier modifiers = {};
263 };
264
265protected:
266 static custom_mouse_event make_event(QGraphicsSceneMouseEvent* event) noexcept
267 {
269
270 p.x = event->pos().x();
271 p.y = event->pos().y();
272
273 if(event->button() == Qt::LeftButton)
274 p.button = custom_mouse_event::left;
275 else if(event->button() == Qt::RightButton)
276 p.button = custom_mouse_event::right;
277 else if(event->button() == Qt::MiddleButton)
278 p.button = custom_mouse_event::middle;
279
280 if(event->buttons() & Qt::LeftButton)
281 p.held_buttons |= p.left;
282 if(event->buttons() & Qt::RightButton)
283 p.held_buttons |= p.right;
284 if(event->buttons() & Qt::MiddleButton)
285 p.held_buttons |= p.middle;
286
287 if(event->modifiers() & Qt::ShiftModifier)
288 p.modifiers |= p.shift;
289 if(event->modifiers() & Qt::AltModifier)
290 p.modifiers |= p.alt;
291 if(event->modifiers() & Qt::ControlModifier)
292 p.modifiers |= p.ctrl;
293 if(event->modifiers() & Qt::MetaModifier)
294 p.modifiers |= p.meta;
295
296 return p;
297 }
298
299 void mousePressEvent(QGraphicsSceneMouseEvent* event) override
300 {
301 if constexpr(requires { impl.mouse_press(0, 0); })
302 {
303 if(impl.mouse_press(event->pos().x(), event->pos().y()))
304 event->accept();
305 }
306 else if constexpr(requires { impl.mouse_press(custom_mouse_event{}); })
307 {
308 if(impl.mouse_press(make_event(event)))
309 event->accept();
310 }
311 update();
312 }
313
314 void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override
315 {
316 if constexpr(requires { impl.mouse_move(0, 0); })
317 {
318 impl.mouse_move(event->pos().x(), event->pos().y());
319 event->accept();
320 }
321 else if constexpr(requires { impl.mouse_move(custom_mouse_event{}); })
322 {
323 impl.mouse_move(make_event(event));
324 event->accept();
325 }
326 update();
327 }
328
329 void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override
330 {
331 if constexpr(requires { impl.mouse_release(0, 0); })
332 {
333 impl.mouse_release(event->pos().x(), event->pos().y());
334 event->accept();
335 }
336 else if constexpr(requires { impl.mouse_release(custom_mouse_event{}); })
337 {
338 impl.mouse_release(make_event(event));
339 event->accept();
340 }
341 update();
342 }
343
344protected:
345 Item impl;
346};
347
348template <typename Item>
349class CustomControl : public CustomItem<Item>
350{
351public:
353 explicit CustomControl(
354 Item item_init, Process::ControlInlet& ctl, const score::DocumentContext& ctx)
355 : CustomItem<Item>{item_init}
356 , cmd{ctx.commandStack}
357 {
358 if constexpr(requires { this->impl.transaction; })
359 {
360 this->impl.transaction.start = [] {
361
362 };
363 this->impl.transaction.update = [this, &ctl](const auto& value) {
364 auto val = oscr::to_ossia_value(value);
365 cmd.submit<Process::SetControlValue>(ctl, val);
366
367 this->impl.value = value; //impl.value_to_control(Control{}
368 this->update();
369 };
370 this->impl.transaction.commit = [this] { cmd.commit(); };
371 this->impl.transaction.rollback = [this] { cmd.rollback(); };
372 }
373 }
374};
375}
The OngoingCommandDispatcher class.
Definition OngoingCommandDispatcher.hpp:27
void submit(Args &&... args)
Definition OngoingCommandDispatcher.hpp:37
void commit()
Definition OngoingCommandDispatcher.hpp:61
void rollback()
If the command has to be reverted, for instance when pressing escape.
Definition OngoingCommandDispatcher.hpp:71
Definition Port.hpp:203
Definition SetControlValue.hpp:13
Definition Painter.hpp:350
Definition Painter.hpp:194
Definition Factories.hpp:19
Definition Painter.hpp:231
Definition Painter.hpp:22
Definition Painter.hpp:18
Definition DocumentContext.hpp:18