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}