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>
38 std::same_as<Context, quad_color> or std::same_as<Context, color> or std::same_as<Context, border_side> or
39 std::same_as<Context, line_end_cap> or std::same_as<Context, corner_radii> or std::same_as<Context, corner_radiii> or
40 std::same_as<Context, aarectanglei> or std::same_as<Context, float> or std::same_as<Context, int>;
41
45 unsigned char num_colors = 0;
46 unsigned char num_line_caps = 0;
47
54
60
63 float line_width = 0.0f;
64
67 hi::border_side border_side = hi::border_side::on;
68
72
79
83
87
88 constexpr draw_attributes(draw_attributes const&) noexcept = default;
89 constexpr draw_attributes(draw_attributes&&) noexcept = default;
90 constexpr draw_attributes& operator=(draw_attributes const&) noexcept = default;
91 constexpr draw_attributes& operator=(draw_attributes&&) noexcept = default;
92 constexpr draw_attributes() noexcept = default;
93
114 template<draw_attribute... Args>
115 constexpr draw_attributes(Args const&...args) noexcept
116 {
117 add(args...);
118 }
119
120 constexpr void add() noexcept {}
121
122 template<draw_attribute T>
123 constexpr void add(T const& attribute) noexcept
124 {
125 if constexpr (std::is_same_v<T, quad_color>) {
126 if (num_colors++ == 0) {
127 fill_color = attribute;
128 } else {
129 line_color = attribute;
130 }
131 hi_axiom(num_colors <= 2);
132
133 } else if constexpr (std::is_same_v<T, color>) {
134 if (num_colors++ == 0) {
135 fill_color = quad_color{attribute};
136 } else {
137 line_color = quad_color{attribute};
138 }
139 // XXX Handle 4 colors.
140 // hi_axiom(num_colors <= 2);
141
142 } else if constexpr (std::is_same_v<T, line_end_cap>) {
143 if (num_line_caps++ == 0) {
144 begin_line_cap = attribute;
145 end_line_cap = attribute;
146 } else {
147 end_line_cap = attribute;
148 }
149 hi_axiom(num_line_caps <= 2);
150
151 } else if constexpr (std::is_same_v<T, hi::border_side>) {
152 border_side = attribute;
153#ifndef NDEBUG
154 hi_assert(not _has_border_side);
155 _has_border_side = true;
156#endif
157
158 } else if constexpr (std::is_same_v<T, corner_radii> or std::is_same_v<T, corner_radiii>) {
159 border_radius = narrow_cast<corner_radii>(attribute);
160#ifndef NDEBUG
161 hi_assert(not _has_corner_radii);
162 _has_corner_radii = true;
163#endif
164
165 } else if constexpr (std::is_same_v<T, aarectanglei>) {
166 clipping_rectangle = attribute;
167#ifndef NDEBUG
168 hi_assert(not _has_clipping_rectangle);
169 _has_clipping_rectangle = true;
170#endif
171
172 } else if constexpr (std::is_same_v<T, float> or std::is_same_v<T, int>) {
173 line_width = narrow_cast<float>(attribute);
174#ifndef NDEBUG
175 hi_assert(not _has_line_width);
176 _has_line_width = true;
177#endif
178 } else {
180 }
181 }
182
183 template<draw_attribute First, draw_attribute Second, draw_attribute... Rest>
184 constexpr void add(First const& first, Second const& second, Rest const&...rest) noexcept
185 {
186 add(first);
187 add(second, rest...);
188 }
189
190private:
191#ifndef NDEBUG
192 bool _has_border_side = false;
193 bool _has_corner_radii = false;
194 bool _has_clipping_rectangle = false;
195 bool _has_line_width = false;
196#endif
197};
198
199template<typename Context>
200concept draw_quad_shape = std::same_as<Context, quad> or std::same_as<Context, rectangle> or std::same_as<Context, aarectangle> or
201 std::same_as<Context, aarectanglei>;
202
206public:
207 gfx_draw_context gfx_context;
208
211 utc_nanoseconds display_time_point;
212
213 widget_draw_context(widget_draw_context& rhs) noexcept = delete;
214 widget_draw_context(widget_draw_context&& rhs) noexcept = default;
215 widget_draw_context& operator=(widget_draw_context& rhs) noexcept = delete;
216 widget_draw_context& operator=(widget_draw_context&& rhs) noexcept = default;
217 ~widget_draw_context() = default;
218
219 widget_draw_context(gfx_draw_context&& gfx_context) noexcept : gfx_context(std::move(gfx_context)) {}
220
227 void draw_box(widget_layout const& layout, quad const& box, draw_attributes const& attributes) noexcept
228 {
229 return _draw_box(
230 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, attributes);
231 }
232
239 template<draw_quad_shape Shape, draw_attribute... Attributes>
240 void draw_box(widget_layout const& layout, Shape const& shape, Attributes const&...attributes) noexcept
241 {
242 return draw_box(layout, make_quad(shape), draw_attributes{attributes...});
243 }
244
251 void draw_line(widget_layout const& layout, line_segment const& line, draw_attributes const& attributes) noexcept
252 {
253 hilet box = make_rectangle(line, attributes.line_width, attributes.begin_line_cap, attributes.end_line_cap);
254
255 auto box_attributes = attributes;
256 box_attributes.line_width = 0.0f;
257 box_attributes.border_radius =
258 make_corner_radii(attributes.line_width, attributes.begin_line_cap, attributes.end_line_cap);
259 return draw_box(layout, box, box_attributes);
260 }
261
268 template<draw_attribute... Attributes>
269 void draw_line(widget_layout const& layout, line_segment const& line, Attributes const&...attributes) noexcept
270 {
271 return draw_line(layout, line, draw_attributes{attributes...});
272 }
273
280 void draw_circle(widget_layout const& layout, hi::circle const& circle, draw_attributes const& attributes) noexcept
281 {
282 auto box_attributes = attributes;
283 box_attributes.border_radius = make_corner_radii(circle);
284 return draw_box(layout, make_rectangle(circle), box_attributes);
285 }
286
293 template<draw_attribute... Attributes>
294 void draw_circle(widget_layout const& layout, hi::circle const& circle, Attributes const&...attributes) noexcept
295 {
296 return draw_circle(layout, circle, draw_attributes{attributes...});
297 }
298
308 [[nodiscard]] bool
309 draw_image(widget_layout const& layout, quad const& box, paged_image& image, draw_attributes const& attributes) noexcept
310 {
311 return _draw_image(layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, image);
312 }
313
323 template<draw_attribute... Attributes>
324 [[nodiscard]] bool
325 draw_image(widget_layout const& layout, draw_quad_shape auto const& box, paged_image& image, Attributes const&...attributes)
326 noexcept
327 {
328 return draw_image(layout, make_quad(box), image, draw_attributes{attributes...});
329 }
330
339 widget_layout const& layout,
340 quad const& box,
341 hi::font const& font,
342 glyph_id glyph,
343 draw_attributes const& attributes) noexcept
344 {
345 return _draw_glyph(
346 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
347 layout.to_window3() * box,
348 font,
349 glyph,
350 attributes);
351 }
352
360 template<draw_quad_shape Shape, draw_attribute... Attributes>
362 widget_layout const& layout,
363 Shape const& box,
364 hi::font const& font,
365 glyph_id glyph,
366 Attributes const&...attributes) noexcept
367 {
368 return draw_glyph(layout, make_quad(box), font, glyph, draw_attributes{attributes...});
369 }
370
379 widget_layout const& layout,
380 quad const& box,
381 font_book::font_glyph_type font_glyph,
382 draw_attributes const& attributes) noexcept
383 {
384 return _draw_glyph(
385 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
386 layout.to_window3() * box,
387 *font_glyph.font,
388 font_glyph.glyph,
389 attributes);
390 }
391
399 template<draw_quad_shape Shape, draw_attribute... Attributes>
401 widget_layout const& layout,
402 Shape const& box,
403 font_book::font_glyph_type font_glyph,
404 Attributes const&...attributes) noexcept
405 {
406 return draw_glyph(layout, make_quad(box), font_glyph, draw_attributes{attributes...});
407 }
408
416 void
417 draw_text(widget_layout const& layout, matrix3 const& transform, text_shaper const& text, draw_attributes const& attributes)
418 noexcept
419 {
420 return _draw_text(
421 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
422 layout.to_window3() * transform,
423 text,
424 attributes);
425 }
426
434 template<draw_attribute... Attributes>
435 void draw_text(widget_layout const& layout, matrix3 const& transform, text_shaper const& text, Attributes const&...attributes)
436 noexcept
437 {
438 return draw_text(layout, transform, text, draw_attributes{attributes...});
439 }
440
447 template<draw_attribute... Attributes>
448 void draw_text(widget_layout const& layout, text_shaper const& text, Attributes const&...attributes) noexcept
449 {
450 return draw_text(layout, geo::identity{}, text, draw_attributes{attributes...});
451 }
452
461 widget_layout const& layout,
462 text_shaper const& text,
463 text_selection const& selection,
464 draw_attributes const& attributes) noexcept
465 {
466 return _draw_text_selection(
467 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3(), text, selection, attributes);
468 }
469
477 template<draw_attribute... Attributes>
479 widget_layout const& layout,
480 text_shaper const& text,
481 text_selection const& selection,
482 Attributes const&...attributes) noexcept
483 {
484 return draw_text_selection(layout, text, selection, draw_attributes{attributes...});
485 }
486
497 widget_layout const& layout,
498 text_shaper const& text,
499 text_cursor cursor,
500 bool overwrite_mode,
501 bool dead_character_mode,
502 draw_attributes const& attributes) noexcept
503 {
504 return _draw_text_cursors(
505 layout.clipping_rectangle_on_window(attributes.clipping_rectangle),
506 layout.to_window3(),
507 text,
508 cursor,
509 overwrite_mode,
510 dead_character_mode,
511 attributes);
512 }
513
523 template<draw_attribute... Attributes>
525 widget_layout const& layout,
526 text_shaper const& text,
527 text_cursor cursor,
528 bool overwrite_mode,
529 bool dead_character_mode,
530 Attributes const&...attributes) noexcept
531 {
532 return draw_text_cursors(layout, text, cursor, overwrite_mode, dead_character_mode, draw_attributes{attributes...});
533 }
534
544 void draw_hole(widget_layout const& layout, quad const& box, draw_attributes const& attributes) noexcept
545 {
546 return _override_alpha(
547 layout.clipping_rectangle_on_window(attributes.clipping_rectangle), layout.to_window3() * box, attributes);
548 }
549
559 template<draw_quad_shape Shape, draw_attribute... Attributes>
560 void draw_hole(widget_layout const& layout, Shape const& box, Attributes const&...attributes) noexcept
561 {
562 return draw_hole(layout, make_quad(box), draw_attributes{attributes...});
563 }
564
572 [[nodiscard]] friend bool overlaps(widget_draw_context const& context, widget_layout const& layout) noexcept
573 {
574 return overlaps(context.gfx_context.scissor_rectangle, layout.clipping_rectangle_on_window());
575 }
576
577private:
578 template<draw_quad_shape Shape>
579 [[nodiscard]] constexpr static quad make_quad(Shape const& shape) noexcept
580 {
581 if constexpr (std::is_same_v<Shape, aarectanglei>) {
582 return narrow_cast<aarectangle>(shape);
583 } else {
584 return shape;
585 }
586 }
587
588 [[nodiscard]] constexpr static rectangle
589 make_rectangle(line_segment const& line, float width, line_end_cap c1, line_end_cap c2) noexcept
590 {
591 auto right = line.direction();
592
593 hilet radius = width * 0.5f;
594 hilet n = normal(right, 0.0f);
595 hilet up = n * width;
596 hilet t = normalize(right);
597
598 auto origin = line.origin() - n * radius;
599
600 // Extend the line by the radius for rounded end-caps.
601 hilet radius_offset = t * radius;
602 if (c1 == line_end_cap::round) {
603 origin -= radius_offset;
604 right += radius_offset;
605 }
606 if (c2 == line_end_cap::round) {
607 right += radius_offset;
608 }
609
610 return rectangle{origin, right, up};
611 }
612
613 [[nodiscard]] constexpr static rectangle make_rectangle(hi::circle const& circle) noexcept
614 {
615 hilet circle_ = f32x4{circle};
616 hilet origin = point3{circle_.xyz1() - circle_.ww00()};
617 hilet right = vector3{circle_.w000() * 2.0f};
618 hilet up = vector3{circle_._0w00() * 2.0f};
619 return rectangle{origin, right, up};
620 }
621
622 [[nodiscard]] constexpr static corner_radii make_corner_radii(float width, line_end_cap c1, line_end_cap c2) noexcept
623 {
624 auto r = f32x4::broadcast(width * 0.5f);
625
626 if (c1 == line_end_cap::flat) {
627 r = set_zero<0b0101>(r);
628 }
629 if (c2 == line_end_cap::flat) {
630 r = set_zero<0b1010>(r);
631 }
632
633 return corner_radii{r};
634 }
635
636 [[nodiscard]] constexpr static corner_radii make_corner_radii(hi::circle const& circle) noexcept
637 {
638 return corner_radii{f32x4{circle}.wwww()};
639 }
640
641 void _override_alpha(aarectanglei const& clipping_rectangle, quad box, draw_attributes const& attributes) noexcept;
642
643 void _draw_box(aarectanglei const& clipping_rectangle, quad box, draw_attributes const& attributes) noexcept;
644
645 void _draw_text(
646 aarectanglei const& clipping_rectangle,
647 matrix3 const& transform,
648 text_shaper const& text,
649 draw_attributes const& attributes) noexcept;
650
651 void _draw_text_selection(
652 aarectanglei const& clipping_rectangle,
653 matrix3 const& transform,
654 text_shaper const& text,
655 text_selection const& selection,
656 draw_attributes const& attributes) noexcept;
657
658 void _draw_text_insertion_cursor_empty(
659 aarectanglei const& clipping_rectangle,
660 matrix3 const& transform,
661 text_shaper const& text,
662 draw_attributes const& attributes) noexcept;
663
664 void _draw_text_insertion_cursor(
665 aarectanglei const& clipping_rectangle,
666 matrix3 const& transform,
667 text_shaper const& text,
668 text_cursor cursor,
669 bool show_flag,
670 draw_attributes const& attributes) noexcept;
671
672 void _draw_text_overwrite_cursor(
673 aarectanglei const& clipping_rectangle,
674 matrix3 const& transform,
675 text_shaper::char_const_iterator it,
676 draw_attributes const& attributes) noexcept;
677
678 void _draw_text_cursors(
679 aarectanglei const& clipping_rectangle,
680 matrix3 const& transform,
681 text_shaper const& text,
682 text_cursor cursor,
683 bool overwrite_mode,
684 bool dead_character_mode,
685 draw_attributes const& attributes) noexcept;
686
687 void _draw_glyph(
688 aarectanglei const& clipping_rectangle,
689 quad const& box,
690 hi::font const& font,
691 glyph_id const& glyph,
692 draw_attributes const& attributes) noexcept;
693
694 [[nodiscard]] bool
695 _draw_image(aarectanglei const& clipping_rectangle, quad const& box, paged_image const& image) noexcept;
696};
697
698}} // 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:17
The draw attributes used to draw shaped into the draw context.
Definition widget_draw_context.hpp:44
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:67
aarectanglei clipping_rectangle
The rectangle used the clip the shape when drawing.
Definition widget_draw_context.hpp:78
float line_width
The width of a line, or the width of a border.
Definition widget_draw_context.hpp:63
line_end_cap end_line_cap
The shape of the beginning of a line.
Definition widget_draw_context.hpp:86
quad_color fill_color
The fill color used for the color of a box inside the border.
Definition widget_draw_context.hpp:53
quad_color line_color
The line color used for the color of the border of the box.
Definition widget_draw_context.hpp:59
line_end_cap begin_line_cap
The shape of the beginning of a line.
Definition widget_draw_context.hpp:82
hi::corner_radii border_radius
The radii of each corner of a quad.
Definition widget_draw_context.hpp:71
Draw context for drawing using the HikoGUI shaders.
Definition widget_draw_context.hpp:205
void draw_text_selection(widget_layout const &layout, text_shaper const &text, text_selection const &selection, draw_attributes const &attributes) noexcept
Draw text-selection of shaped text.
Definition widget_draw_context.hpp:460
void draw_hole(widget_layout const &layout, Shape const &box, Attributes const &...attributes) noexcept
Make a hole in the user interface.
Definition widget_draw_context.hpp:560
bool draw_image(widget_layout const &layout, draw_quad_shape auto const &box, paged_image &image, Attributes const &...attributes) noexcept
Draw an image.
Definition widget_draw_context.hpp:325
void draw_circle(widget_layout const &layout, hi::circle const &circle, draw_attributes const &attributes) noexcept
Draw a circle.
Definition widget_draw_context.hpp:280
void draw_circle(widget_layout const &layout, hi::circle const &circle, Attributes const &...attributes) noexcept
Draw a circle.
Definition widget_draw_context.hpp:294
void draw_line(widget_layout const &layout, line_segment const &line, Attributes const &...attributes) noexcept
Draw a line.
Definition widget_draw_context.hpp:269
void draw_text(widget_layout const &layout, text_shaper const &text, Attributes const &...attributes) noexcept
Draw shaped text.
Definition widget_draw_context.hpp:448
void draw_glyph(widget_layout const &layout, quad const &box, hi::font const &font, glyph_id glyph, draw_attributes const &attributes) noexcept
Draw a glyph.
Definition widget_draw_context.hpp:338
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:572
void draw_text(widget_layout const &layout, matrix3 const &transform, text_shaper const &text, Attributes const &...attributes) noexcept
Draw shaped text.
Definition widget_draw_context.hpp:435
void draw_text(widget_layout const &layout, matrix3 const &transform, text_shaper const &text, draw_attributes const &attributes) noexcept
Draw shaped text.
Definition widget_draw_context.hpp:417
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) noexcept
Draw text cursors of shaped text.
Definition widget_draw_context.hpp:496
void draw_box(widget_layout const &layout, Shape const &shape, Attributes const &...attributes) noexcept
Draw a box.
Definition widget_draw_context.hpp:240
bool draw_image(widget_layout const &layout, quad const &box, paged_image &image, draw_attributes const &attributes) noexcept
Draw an image.
Definition widget_draw_context.hpp:309
void draw_text_selection(widget_layout const &layout, text_shaper const &text, text_selection const &selection, Attributes const &...attributes) noexcept
Draw text-selection of shaped text.
Definition widget_draw_context.hpp:478
void draw_glyph(widget_layout const &layout, quad const &box, font_book::font_glyph_type font_glyph, draw_attributes const &attributes) noexcept
Draw a glyph.
Definition widget_draw_context.hpp:378
void draw_box(widget_layout const &layout, quad const &box, draw_attributes const &attributes) noexcept
Draw a box.
Definition widget_draw_context.hpp:227
void draw_glyph(widget_layout const &layout, Shape const &box, hi::font const &font, glyph_id glyph, Attributes const &...attributes) noexcept
Draw a glyph.
Definition widget_draw_context.hpp:361
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) noexcept
Draw text cursors of shaped text.
Definition widget_draw_context.hpp:524
void draw_line(widget_layout const &layout, line_segment const &line, draw_attributes const &attributes) noexcept
Draw a line.
Definition widget_draw_context.hpp:251
void draw_hole(widget_layout const &layout, quad const &box, draw_attributes const &attributes) noexcept
Make a hole in the user interface.
Definition widget_draw_context.hpp:544
utc_nanoseconds display_time_point
The time when the drawing will appear on the screen.
Definition widget_draw_context.hpp:211
void draw_glyph(widget_layout const &layout, Shape const &box, font_book::font_glyph_type font_glyph, Attributes const &...attributes) noexcept
Draw a glyph.
Definition widget_draw_context.hpp:400
The layout of a widget.
Definition widget_layout.hpp:37
Definition widget_draw_context.hpp:37
Definition widget_draw_context.hpp:200
T right(T... args)
T move(T... args)