Skip to main content

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}