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_device`].
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;
46#[allow(unused)] use crate::theme::DrawCx;
47
48pub use draw::{Draw, DrawIface, DrawImpl};
49pub use draw_rounded::{DrawRounded, DrawRoundedImpl};
50pub use draw_shared::{AllocError, ImageFormat, ImageHandle, ImageId};
51pub use draw_shared::{DrawShared, DrawSharedImpl, SharedState};
52use std::time::{Duration, Instant};
53
54/// Animation status
55#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
56#[crate::impl_default(AnimationState::None)]
57pub(crate) enum AnimationState {
58 /// No frames are queued
59 None,
60 /// Animation in progress: draw at the next frame time
61 Animate,
62 /// Timed-animation in progress: draw at the given time
63 Timed(Instant),
64}
65
66impl AnimationState {
67 /// Merge two states (take earliest)
68 fn merge_in(&mut self, rhs: AnimationState) {
69 use AnimationState::*;
70 *self = match (*self, rhs) {
71 (Animate, _) | (_, Animate) => Animate,
72 (Timed(t1), Timed(t2)) => Timed(t1.min(t2)),
73 (Timed(t), _) | (_, Timed(t)) => Timed(t),
74 (None, None) => None,
75 }
76 }
77}
78
79/// Per-window "draw" data common to all backends
80#[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
81#[cfg_attr(docsrs, doc(cfg(internal_doc)))]
82#[derive(Debug, Default)]
83pub struct WindowCommon {
84 pub(crate) anim: AnimationState,
85 pub(crate) dur_text: std::time::Duration,
86}
87
88impl WindowCommon {
89 /// Report performance counter: text assembly duration
90 ///
91 /// This may be reported multiple times per frame; the sum is output.
92 pub fn report_dur_text(&mut self, dur: Duration) {
93 self.dur_text += dur;
94 }
95
96 /// Check whether immediate redraw is required, and if so clear it
97 pub fn immediate_redraw(&mut self) -> bool {
98 match self.anim {
99 AnimationState::None => return false,
100 // AnimationState::Timed(_) => return false,
101 AnimationState::Timed(when) if when > Instant::now() => return false,
102 _ => (),
103 }
104 self.anim = AnimationState::None;
105 true
106 }
107
108 /// Get the next resume time due to animation
109 pub fn next_resume(&self) -> Option<Instant> {
110 match self.anim {
111 AnimationState::Timed(when) => Some(when),
112 _ => None,
113 }
114 }
115}
116
117/// Draw pass identifier
118///
119/// This is a numerical identifier for the draw pass (see [`DrawIface::new_pass`]).
120#[derive(Copy, Clone)]
121pub struct PassId(u32);
122
123impl PassId {
124 /// Construct a new pass from a `u32` identifier
125 #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
126 #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
127 #[inline]
128 pub const fn new(n: u32) -> Self {
129 PassId(n)
130 }
131
132 /// The pass number
133 ///
134 /// This value is returned as `usize` but is always safe to store `as u32`.
135 #[inline]
136 pub fn pass(self) -> usize {
137 self.0.cast()
138 }
139
140 /// The depth value
141 ///
142 /// This is a historical left-over and always returns 0.0.
143 #[inline]
144 pub fn depth(self) -> f32 {
145 0.0
146 }
147}
148
149/// Type of draw pass
150#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
151pub enum PassType {
152 /// New pass is clipped and offset relative to parent
153 Clip,
154 /// New pass is an overlay
155 ///
156 /// An overlay is a layer drawn over the base window, for example a tooltip
157 /// or combobox menu. The rect and offset are relative to the base window.
158 /// The theme may draw a shadow or border around this rect.
159 Overlay,
160}