HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
widget_draw_context.hpp
1// Copyright Take Vos 2020-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "widget_layout.hpp"
8#include "../GFX/module.hpp"
9#include "../geometry/module.hpp"
10#include "../unicode/module.hpp"
11#include "../text/module.hpp"
12#include "../font/module.hpp"
13#include "../color/module.hpp"
14#include "../utility/module.hpp"
15#include "../vector_span.hpp"
16
17namespace hi { inline namespace v1 {
18struct paged_image;
19
22enum class border_side {
25 on,
26
29 inside,
30
34};
35
36template<typename Context>
37concept draw_attribute = std::same_as<Context, quad_color> or std::same_as<Context, color> or
38 std::same_as<Context, border_side> or std::same_as<Context, line_end_cap> or std::same_as<Context, corner_radii> or
39 std::same_as<Context, aarectanglei> or std::same_as<Context, float> or std::same_as<Context, int>;
40
44 unsigned char num_colors = 0;
45 unsigned char num_line_caps = 0;
46
53
59
62 float line_width = 0.0f;
63
66 hi::border_side border_side = hi::border_side::on;
67
71
78
82
86
87 constexpr draw_attributes(draw_attributes const&) noexcept = default;
88 constexpr draw_attributes(draw_attributes&&) noexcept = default;
89 constexpr draw_attributes& operator=(draw_attributes const&) noexcept = default;
90 constexpr draw_attributes& operator=(draw_attributes&&) noexcept = default;
91 constexpr draw_attributes() noexcept = default;
92
113 template<draw_attribute... Args>
114 constexpr draw_attributes(Args const&...args) noexcept
115 {
116 add(args...);
117 }
118
119 constexpr void add() noexcept {}
120
121 template<draw_attribute T>
122 constexpr void add(T const& attribute) noexcept
123 {
124 if constexpr (std::is_same_v<T, quad_color>) {
125 if (num_colors++ == 0) {
126 fill_color = attribute;
127 } else {
128 line_color = attribute;
129 }
130 hi_axiom(num_colors <= 2);
131
132 } else if constexpr (std::is_same_v<T, color>) {
133 if (num_colors++ == 0) {
134 fill_color = quad_color{attribute};
135 } else {
136 line_color = quad_color{attribute};
137 }
138 // XXX Handle 4 colors.
139 //hi_axiom(num_colors <= 2);
140
141 } else if constexpr (std::is_same_v<T, line_end_cap>) {
142 if (num_line_caps++ == 0) {
143 begin_line_cap = attribute;
144 end_line_cap = attribute;
145 } else {
146 end_line_cap = attribute;
147 }
148 hi_axiom(num_line_caps <= 2);
149
150 } else if constexpr (std::is_same_v<T, hi::border_side>) {
151 border_side = attribute;
152#ifndef NDEBUG
153 hi_assert(not _has_border_side);
154 _has_border_side = true;
155#endif
156
157 } else if constexpr (std::is_same_v<T, corner_radii>) {
158 corner_radius = attribute;
159#ifndef NDEBUG
160 hi_assert(not _has_corner_radii);
161 _has_corner_radii = true;
162#endif
163
164 } else if constexpr (std::is_same_v<T, aarectanglei>) {
165 clipping_rectangle = attribute;
166#ifndef NDEBUG
167 hi_assert(not _has_clipping_rectangle);
168 _has_clipping_rectangle = true;
169#endif
170
171 } else if constexpr (std::is_same_v<T, float> or std::is_same_v<T, int>) {
172 line_width = narrow_cast<float>(attribute);
173#ifndef NDEBUG
174 hi_assert(not _has_line_width);
175 _has_line_width = true;
176#endif
177 } else {
179 }
180 }
181
182 template<draw_attribute First, draw_attribute Second, draw_attribute... Rest>
183 constexpr void add(First const& first, Second const& second, Rest const&...rest) noexcept
184 {
185 add(first);
186 add(second, rest...);
187 }
188
189private:
190#ifndef NDEBUG
191 bool _has_border_side = false;
192 bool _has_corner_radii = false;
193 bool _has_clipping_rectangle = false;
194 bool _has_line_width = false;
195#endif
196};
197
198template<typename Context>
199concept draw_quad_shape = std::same_as<Context, quad> or std::same_as<Context, rectangle> or std::same_as<Context, aarectangle> or
200 std::same_as<Context, aarectanglei>;
201
205public:
206 gfx_draw_context gfx_context;
207
210 utc_nanoseconds display_time_point;
211
212 widget_draw_context(widget_draw_context const& rhs) noexcept = default;
213 widget_draw_context(widget_draw_context&& rhs) noexcept = default;
214 widget_draw_context& operator=(widget_draw_context const& rhs) noexcept = default;
215 widget_draw_context& operator=(widget_draw_context&& rhs) noexcept = default;
216 ~widget_draw_context() = default;
217
218 widget_draw_context(gfx_draw_context const &gfx_context) noexcept;
219
226 void draw_box(widget_layout const& layout, quad const& box, draw_attributes const& attributes) const noexcept
227 {
228 return _draw_box(
229 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, attributes);
230 }
231
238 template<draw_quad_shape Shape, draw_attribute... Attributes>
239 void draw_box(widget_layout const& layout, Shape const& shape, Attributes const&...attributes) const noexcept
240 {
241 return draw_box(layout, make_quad(shape), draw_attributes{attributes...});
242 }
243
250 void draw_line(widget_layout const& layout, line_segment const& line, draw_attributes const& attributes) const noexcept
251 {
252 hilet box = make_rectangle(line, attributes.line_width, attributes.begin_line_cap, attributes.end_line_cap);
253
254 auto box_attributes = attributes;
255 box_attributes.line_width = 0.0f;
256 box_attributes.corner_radius =
257 make_corner_radii(attributes.line_width, attributes.begin_line_cap, attributes.end_line_cap);
258 return draw_box(layout, box, box_attributes);
259 }
260
267 template<draw_attribute... Attributes>
268 void draw_line(widget_layout const& layout, line_segment const& line, Attributes const&...attributes) const noexcept
269 {
270 return draw_line(layout, line, draw_attributes{attributes...});
271 }
272
279 void draw_circle(widget_layout const& layout, hi::circle const& circle, draw_attributes const& attributes) const noexcept
280 {
281 auto box_attributes = attributes;
282 box_attributes.corner_radius = make_corner_radii(circle);
283 return draw_box(layout, make_rectangle(circle), box_attributes);
284 }
285
292 template<draw_attribute... Attributes>
293 void draw_circle(widget_layout const& layout, hi::circle const& circle, Attributes const&...attributes) const noexcept
294 {
295 return draw_circle(layout, circle, draw_attributes{attributes...});
296 }
297
307 [[nodiscard]] bool
308 draw_image(widget_layout const& layout, quad const& box, paged_image& image, draw_attributes const& attributes) const noexcept
309 {
310 return _draw_image(layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, image);
311 }
312
322 template<draw_attribute... Attributes>
323 [[nodiscard]] bool
324 draw_image(widget_layout const& layout, draw_quad_shape auto const& box, paged_image& image, Attributes const&...attributes)
325 const noexcept
326 {
327 return draw_image(layout, make_quad(box), image, draw_attributes{attributes...});
328 }
329
337 void draw_glyph(widget_layout const& layout, quad const& box, hi::font const &font, glyph_id glyph, draw_attributes const& attributes)
338 const noexcept
339 {
340 return _draw_glyph(
341 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, font, glyph, attributes);
342 }
343
351 template<draw_quad_shape Shape, draw_attribute... Attributes>
352 void draw_glyph(widget_layout const& layout, Shape const& box, hi::font const &font, glyph_id glyph, Attributes const&...attributes)
353 const noexcept
354 {
355 return draw_glyph(layout, make_quad(box), font, glyph, draw_attributes{attributes...});
356 }
357
366 widget_layout const& layout,
367 quad const& box,
368 font_book::font_glyph_type font_glyph,
369 draw_attributes const& attributes) const noexcept
370 {
371 return _draw_glyph(
372 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
373 layout.to_window3() * box,
374 *font_glyph.font,
375 font_glyph.glyph,
376 attributes);
377 }
378
386 template<draw_quad_shape Shape, draw_attribute... Attributes>
388 widget_layout const& layout,
389 Shape const& box,
390 font_book::font_glyph_type font_glyph,
391 Attributes const&...attributes) const noexcept
392 {
393 return draw_glyph(layout, make_quad(box), font_glyph, draw_attributes{attributes...});
394 }
395
403 void
404 draw_text(widget_layout const& layout, matrix3 const& transform, text_shaper const& text, draw_attributes const& attributes)
405 const noexcept
406 {
407 return _draw_text(
408 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
409 layout.to_window3() * transform,
410 text,
411 attributes);
412 }
413
421 template<draw_attribute... Attributes>
422 void draw_text(widget_layout const& layout, matrix3 const& transform, text_shaper const& text, Attributes const&...attributes)
423 const noexcept
424 {
425 return draw_text(layout, transform, text, draw_attributes{attributes...});
426 }
427
434 template<draw_attribute... Attributes>
435 void draw_text(widget_layout const& layout, text_shaper const& text, Attributes const&...attributes) const noexcept
436 {
437 return draw_text(layout, geo::identity{}, text, draw_attributes{attributes...});
438 }
439
448 widget_layout const& layout,
449 text_shaper const& text,
450 text_selection const& selection,
451 draw_attributes const& attributes) const noexcept
452 {
453 return _draw_text_selection(
454 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3(), text, selection, attributes);
455 }
456
464 template<draw_attribute... Attributes>
466 widget_layout const& layout,
467 text_shaper const& text,
468 text_selection const& selection,
469 Attributes const&...attributes) const noexcept
470 {
471 return draw_text_selection(layout, text, selection, draw_attributes{attributes...});
472 }
473
484 widget_layout const& layout,
485 text_shaper const& text,
486 text_cursor cursor,
487 bool overwrite_mode,
488 bool dead_character_mode,
489 draw_attributes const& attributes) const noexcept
490 {
491 return _draw_text_cursors(
492 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
493 layout.to_window3(),
494 text,
495 cursor,
496 overwrite_mode,
497 dead_character_mode,
498 attributes);
499 }
500
510 template<draw_attribute... Attributes>
512 widget_layout const& layout,
513 text_shaper const& text,
514 text_cursor cursor,
515 bool overwrite_mode,
516 bool dead_character_mode,
517 Attributes const&...attributes) const noexcept
518 {
519 return draw_text_cursors(layout, text, cursor, overwrite_mode, dead_character_mode, draw_attributes{attributes...});
520 }
521
531 void draw_hole(widget_layout const& layout, quad const& box, draw_attributes const& attributes) const noexcept
532 {
533 return _override_alpha(
534 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, attributes);
535 }
536
546 template<draw_quad_shape Shape, draw_attribute... Attributes>
547 void draw_hole(widget_layout const& layout, Shape const& box, Attributes const&...attributes) const noexcept
548 {
549 return draw_hole(layout, make_quad(box), draw_attributes{attributes...});
550 }
551
559 [[nodiscard]] friend bool overlaps(widget_draw_context const& context, widget_layout const& layout) noexcept
560 {
561 return overlaps(context.gfx_context.scissor_rectangle, layout.clipping_rectangle_on_window());
562 }
563
564private:
565 template<draw_quad_shape Shape>
566 [[nodiscard]] constexpr static quad make_quad(Shape const& shape) noexcept
567 {
568 if constexpr (std::is_same_v<Shape, aarectanglei>) {
569 return narrow_cast<aarectangle>(shape);
570 } else {
571 return shape;
572 }
573 }
574
575 [[nodiscard]] constexpr static rectangle
576 make_rectangle(line_segment const& line, float width, line_end_cap c1, line_end_cap c2) noexcept
577 {
578 auto right = line.direction();
579
580 hilet radius = width * 0.5f;
581 hilet n = normal(right, 0.0f);
582 hilet up = n * width;
583 hilet t = normalize(right);
584
585 auto origin = line.origin() - n * radius;
586
587 // Extend the line by the radius for rounded end-caps.
588 hilet radius_offset = t * radius;
589 if (c1 == line_end_cap::round) {
590 origin -= radius_offset;
591 right += radius_offset;
592 }
593 if (c2 == line_end_cap::round) {
594 right += radius_offset;
595 }
596
597 return rectangle{origin, right, up};
598 }
599
600 [[nodiscard]] constexpr static rectangle make_rectangle(hi::circle const& circle) noexcept
601 {
602 hilet circle_ = f32x4{circle};
603 hilet origin = point3{circle_.xyz1() - circle_.ww00()};
604 hilet right = vector3{circle_.w000() * 2.0f};
605 hilet up = vector3{circle_._0w00() * 2.0f};
606 return rectangle{origin, right, up};
607 }
608
609 [[nodiscard]] constexpr static corner_radii make_corner_radii(float width, line_end_cap c1, line_end_cap c2) noexcept
610 {
611 auto r = f32x4::broadcast(width * 0.5f);
612
613 if (c1 == line_end_cap::flat) {
614 r = set_zero<0b0101>(r);
615 }
616 if (c2 == line_end_cap::flat) {
617 r = set_zero<0b1010>(r);
618 }
619
620 return corner_radii{r};
621 }
622
623 [[nodiscard]] constexpr static corner_radii make_corner_radii(hi::circle const& circle) noexcept
624 {
625 return corner_radii{f32x4{circle}.wwww()};
626 }
627
628 void _override_alpha(aarectanglei const& clipping_rectangle, quad box, draw_attributes const& attributes) const noexcept;
629
630 void _draw_box(aarectanglei const& clipping_rectangle, quad box, draw_attributes const& attributes) const noexcept;
631
632 void _draw_text(
633 aarectanglei const& clipping_rectangle,
634 matrix3 const& transform,
635 text_shaper const& text,
636 draw_attributes const& attributes) const noexcept;
637
638 void _draw_text_selection(
639 aarectanglei const& clipping_rectangle,
640 matrix3 const& transform,
641 text_shaper const& text,
642 text_selection const& selection,
643 draw_attributes const& attributes) const noexcept;
644
645 void _draw_text_insertion_cursor_empty(
646 aarectanglei const& clipping_rectangle,
647 matrix3 const& transform,
648 text_shaper const& text,
649 draw_attributes const& attributes) const noexcept;
650
651 void _draw_text_insertion_cursor(
652 aarectanglei const& clipping_rectangle,
653 matrix3 const& transform,
654 text_shaper const& text,
655 text_cursor cursor,
656 bool show_flag,
657 draw_attributes const& attributes) const noexcept;
658
659 void _draw_text_overwrite_cursor(
660 aarectanglei const& clipping_rectangle,
661 matrix3 const& transform,
662 text_shaper::char_const_iterator it,
663 draw_attributes const& attributes) const noexcept;
664
665 void _draw_text_cursors(
666 aarectanglei const& clipping_rectangle,
667 matrix3 const& transform,
668 text_shaper const& text,
669 text_cursor cursor,
670 bool overwrite_mode,
671 bool dead_character_mode,
672 draw_attributes const& attributes) const noexcept;
673
674 void _draw_glyph(
675 aarectanglei const& clipping_rectangle,
676 quad const& box,
677 hi::font const &font,
678 glyph_id const& glyph,
679 draw_attributes const& attributes) const noexcept;
680
681 [[nodiscard]] bool _draw_image(aarectanglei const& clipping_rectangle, quad const& box, paged_image const& image) const noexcept;
682};
683
684}} // namespace hi::v1
#define hi_static_no_default(...)
This part of the code should not be reachable, unless a programming bug.
Definition assert.hpp:323
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:199
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
line_end_cap
The way two lines should be joined.
Definition line_end_cap.hpp:17
@ flat
The end cap of the line is flat.
@ round
The end cap of the line is round.
@ rectangle
The gui_event has rectangle data.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
border_side
The side where the border is drawn.
Definition widget_draw_context.hpp:22
@ inside
The border is drawn inside the edge of a quad.
@ outside
The border is drawn outside the edge of a quad.
@ on
The border is drawn on the edge of a quad.
geo::matrix< 3 > matrix3
A 3D homogenious transformation matrix.
Definition matrix.hpp:614
@ normal
A font that is normal, non-italic.
A color for each corner of a quad.
Definition quad_color.hpp:19
static constexpr axis_aligned_rectangle large() noexcept
Create a large axis aligned rectangle.
Definition axis_aligned_rectangle.hpp:40
A type defining a 2D circle.
Definition circle.hpp:18
Identity transform.
Definition identity.hpp:20
Line segment.
Definition line_segment.hpp:19
A 2D or 3D homogenius matrix for transforming homogenious vectors and points.
Definition matrix.hpp:33
Definition gfx_draw_context.hpp:26
The draw attributes used to draw shaped into the draw context.
Definition widget_draw_context.hpp:43
hi::border_side border_side
The side on which side of the edge of a shape the border should be drawn.
Definition widget_draw_context.hpp:66
aarectanglei clipping_rectangle
The rectangle used the clip the shape when drawing.
Definition widget_draw_context.hpp:77
float line_width
The width of a line, or the width of a border.
Definition widget_draw_context.hpp:62
line_end_cap end_line_cap
The shape of the beginning of a line.
Definition widget_draw_context.hpp:85
quad_color fill_color
The fill color used for the color of a box inside the border.
Definition widget_draw_context.hpp:52
quad_color line_color
The line color used for the color of the border of the box.
Definition widget_draw_context.hpp:58
line_end_cap begin_line_cap
The shape of the beginning of a line.
Definition widget_draw_context.hpp:81
hi::corner_radii corner_radius
The radii of each corner of a quad.
Definition widget_draw_context.hpp:70
Draw context for drawing using the HikoGUI shaders.
Definition widget_draw_context.hpp:204
void draw_line(widget_layout const &layout, line_segment const &line, Attributes const &...attributes) const noexcept
Draw a line.
Definition widget_draw_context.hpp:268
void draw_glyph(widget_layout const &layout, Shape const &box, font_book::font_glyph_type font_glyph, Attributes const &...attributes) const noexcept
Draw a glyph.
Definition widget_draw_context.hpp:387
bool draw_image(widget_layout const &layout, quad const &box, paged_image &image, draw_attributes const &attributes) const noexcept
Draw an image.
Definition widget_draw_context.hpp:308
void draw_text_cursors(widget_layout const &layout, text_shaper const &text, text_cursor cursor, bool overwrite_mode, bool dead_character_mode, Attributes const &...attributes) const noexcept
Draw text cursors of shaped text.
Definition widget_draw_context.hpp:511
void draw_text_selection(widget_layout const &layout, text_shaper const &text, text_selection const &selection, Attributes const &...attributes) const noexcept
Draw text-selection of shaped text.
Definition widget_draw_context.hpp:465
void draw_circle(widget_layout const &layout, hi::circle const &circle, Attributes const &...attributes) const noexcept
Draw a circle.
Definition widget_draw_context.hpp:293
void draw_line(widget_layout const &layout, line_segment const &line, draw_attributes const &attributes) const noexcept
Draw a line.
Definition widget_draw_context.hpp:250
void draw_text_selection(widget_layout const &layout, text_shaper const &text, text_selection const &selection, draw_attributes const &attributes) const noexcept
Draw text-selection of shaped text.
Definition widget_draw_context.hpp:447
void draw_circle(widget_layout const &layout, hi::circle const &circle, draw_attributes const &attributes) const noexcept
Draw a circle.
Definition widget_draw_context.hpp:279
friend bool overlaps(widget_draw_context const &context, widget_layout const &layout) noexcept
Checks if a widget's layout overlaps with the part of the window that is being drawn.
Definition widget_draw_context.hpp:559
void draw_hole(widget_layout const &layout, quad const &box, draw_attributes const &attributes) const noexcept
Make a hole in the user interface.
Definition widget_draw_context.hpp:531
void draw_box(widget_layout const &layout, quad const &box, draw_attributes const &attributes) const noexcept
Draw a box.
Definition widget_draw_context.hpp:226
void draw_text(widget_layout const &layout, matrix3 const &transform, text_shaper const &text, Attributes const &...attributes) const noexcept
Draw shaped text.
Definition widget_draw_context.hpp:422
void draw_glyph(widget_layout const &layout, Shape const &box, hi::font const &font, glyph_id glyph, Attributes const &...attributes) const noexcept
Draw a glyph.
Definition widget_draw_context.hpp:352
void draw_hole(widget_layout const &layout, Shape const &box, Attributes const &...attributes) const noexcept
Make a hole in the user interface.
Definition widget_draw_context.hpp:547
bool draw_image(widget_layout const &layout, draw_quad_shape auto const &box, paged_image &image, Attributes const &...attributes) const noexcept
Draw an image.
Definition widget_draw_context.hpp:324
void draw_text(widget_layout const &layout, matrix3 const &transform, text_shaper const &text, draw_attributes const &attributes) const noexcept
Draw shaped text.
Definition widget_draw_context.hpp:404
void draw_glyph(widget_layout const &layout, quad const &box, hi::font const &font, glyph_id glyph, draw_attributes const &attributes) const noexcept
Draw a glyph.
Definition widget_draw_context.hpp:337
void draw_box(widget_layout const &layout, Shape const &shape, Attributes const &...attributes) const noexcept
Draw a box.
Definition widget_draw_context.hpp:239
void draw_glyph(widget_layout const &layout, quad const &box, font_book::font_glyph_type font_glyph, draw_attributes const &attributes) const noexcept
Draw a glyph.
Definition widget_draw_context.hpp:365
void draw_text(widget_layout const &layout, text_shaper const &text, Attributes const &...attributes) const noexcept
Draw shaped text.
Definition widget_draw_context.hpp:435
void draw_text_cursors(widget_layout const &layout, text_shaper const &text, text_cursor cursor, bool overwrite_mode, bool dead_character_mode, draw_attributes const &attributes) const noexcept
Draw text cursors of shaped text.
Definition widget_draw_context.hpp:483
utc_nanoseconds display_time_point
The time when the drawing will appear on the screen.
Definition widget_draw_context.hpp:210
The layout of a widget.
Definition widget_layout.hpp:37
Definition widget_draw_context.hpp:37
Definition widget_draw_context.hpp:199
T right(T... args)