kas_core/draw/mod.rs
1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4// https://www.apache.org/licenses/LICENSE-2.0
5
6//! # Draw APIs
7//!
8//! Multiple drawing APIs are available. Each has a slightly different purpose:
9//!
10//! - High-level "themed widget components" are available through
11//! [`DrawCx`]. This is the primary drawing interface for widgets.
12//! - Basic drawing components (shapes) are available through [`DrawIface`]
13//! in this module. This can be accessed via [`DrawCx::draw`].
14//! - The graphics backend may support custom pipelines, for example
15//! [`kas-wgpu::draw::CustomPipe`](https://docs.rs/kas-wgpu/*/kas_wgpu/draw/trait.CustomPipe.html)
16//! (used by the [Mandlebrot example](https://github.com/kas-gui/kas/tree/master/examples/mandlebrot)).
17//!
18//! Text may be drawn by either [`DrawCx`] or [`DrawIface`] with a slightly
19//! different API (using theme properties or directly specifying colors and effects).
20//!
21//! ## Draw order
22//!
23//! All draw operations happen within a "draw pass". The first pass corresponds
24//! to the window, while additional passes may be clipped and offset (see
25//! [`DrawIface::new_pass`]). Draw passes are executed sequentially in the order
26//! defined.
27//!
28//! Within each pass, draw operations may be batched, thus draw operations may
29//! not happen in the order queued. Exact behaviour is defined by the graphics
30//! backend. In general, it may be expected that batches are executed in the
31//! following order:
32//!
33//! 1. Square-edged primitives (e.g. [`Draw::rect`])
34//! 2. Images
35//! 3. Rounded or other partially-transparent primitives (e.g. [`DrawRounded::circle`])
36//! 4. Custom draw routines (`CustomPipe`)
37//! 5. Text
38
39pub mod color;
40
41#[allow(clippy::module_inception)] mod draw;
42mod draw_rounded;
43mod draw_shared;
44
45use crate::cast::Cast;
46use crate::geom::{Quad, Size};
47#[allow(unused)] use crate::theme::DrawCx;
48
49pub use draw::{Draw, DrawIface, DrawImpl};
50pub use draw_rounded::{DrawRounded, DrawRoundedImpl};
51pub use draw_shared::{AllocError, ImageFormat, ImageHandle, ImageId, UploadError};
52pub use draw_shared::{DrawShared, DrawSharedImpl, SharedState};
53use std::time::{Duration, Instant};
54
55/// An allocation within a texture
56#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
57#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
58#[derive(Debug)]
59pub struct Allocation {
60 /// Atlas (texture) number
61 pub atlas: u32,
62 /// Allocation identifier within the atlas
63 pub alloc: u32,
64 /// Origin within the texture
65 ///
66 /// (Integer coordinates, for use when uploading.)
67 pub origin: (u32, u32),
68 /// Texture coordinates (for drawing)
69 pub tex_quad: Quad,
70}
71
72/// Support allocation of sprites within a texture
73#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
74#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
75pub trait Allocator {
76 fn allocate(&mut self, size: Size) -> Result<Allocation, AllocError>;
77 fn deallocate(&mut self, atlas: u32, alloc: u32);
78}
79
80/// Animation status
81#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
82#[crate::impl_default(AnimationState::None)]
83pub(crate) enum AnimationState {
84 /// No frames are queued
85 None,
86 /// Animation in progress: draw at the next frame time
87 Animate,
88 /// Timed-animation in progress: draw at the given time
89 Timed(Instant),
90}
91
92impl AnimationState {
93 /// Merge two states (take earliest)
94 fn merge_in(&mut self, rhs: AnimationState) {
95 use AnimationState::*;
96 *self = match (*self, rhs) {
97 (Animate, _) | (_, Animate) => Animate,
98 (Timed(t1), Timed(t2)) => Timed(t1.min(t2)),
99 (Timed(t), _) | (_, Timed(t)) => Timed(t),
100 (None, None) => None,
101 }
102 }
103}
104
105/// Per-window "draw" data common to all backends
106#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
107#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
108#[derive(Debug, Default)]
109pub struct WindowCommon {
110 pub(crate) anim: AnimationState,
111 pub(crate) dur_text: std::time::Duration,
112}
113
114impl WindowCommon {
115 /// Report performance counter: text assembly duration
116 ///
117 /// This may be reported multiple times per frame; the sum is output.
118 pub fn report_dur_text(&mut self, dur: Duration) {
119 self.dur_text += dur;
120 }
121
122 /// Check whether immediate redraw is required, and if so clear it
123 pub fn immediate_redraw(&mut self) -> bool {
124 match self.anim {
125 AnimationState::None => return false,
126 // AnimationState::Timed(_) => return false,
127 AnimationState::Timed(when) if when > Instant::now() => return false,
128 _ => (),
129 }
130 self.anim = AnimationState::None;
131 true
132 }
133
134 /// Get the next resume time due to animation
135 pub fn next_resume(&self) -> Option<Instant> {
136 match self.anim {
137 AnimationState::Timed(when) => Some(when),
138 _ => None,
139 }
140 }
141}
142
143/// Draw pass identifier
144///
145/// This is a numerical identifier for the draw pass (see [`DrawIface::new_pass`]).
146#[derive(Copy, Clone, Debug)]
147pub struct PassId(u32);
148
149impl PassId {
150 /// Construct a new pass from a `u32` identifier
151 #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
152 #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
153 #[inline]
154 pub const fn new(n: u32) -> Self {
155 PassId(n)
156 }
157
158 /// The pass number
159 ///
160 /// This value is returned as `usize` but is always safe to store `as u32`.
161 #[inline]
162 pub fn pass(self) -> usize {
163 self.0.cast()
164 }
165
166 /// The depth value
167 ///
168 /// This is a historical left-over and always returns 0.0.
169 #[inline]
170 pub fn depth(self) -> f32 {
171 0.0
172 }
173}
174
175/// Type of draw pass
176#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
177pub enum PassType {
178 /// New pass is clipped and offset relative to parent
179 Clip,
180 /// New pass is an overlay
181 ///
182 /// An overlay is a layer drawn over the base window, for example a tooltip
183 /// or combobox menu. The rect and offset are relative to the base window.
184 /// The theme may draw a shadow or border around this rect.
185 Overlay,
186}