Skip to main content

cranpose_render_pixels/
scene.rs

1use std::rc::Rc;
2
3use cranpose_core::NodeId;
4pub use cranpose_render_common::graph_scene::{ClickAction, HitRegion, Scene};
5use cranpose_ui::{TextLayoutOptions, TextStyle};
6use cranpose_ui_graphics::{
7    ArcGeometry, BlendMode, Brush, Color, ColorFilter, ImageBitmap, ImageSampling, Point, Rect,
8    RoundedCornerShape, Stroke,
9};
10
11#[derive(Clone)]
12pub(crate) struct DrawShape {
13    pub rect: Rect,
14    pub snap_anchor: Option<Point>,
15    pub snap_to_pixel_grid: bool,
16    pub brush: Brush,
17    pub shape: Option<RoundedCornerShape>,
18    /// `Some` strokes the outline of `rect`/`shape` instead of filling it.
19    /// `rect` is already inflated by half the stroke width.
20    pub stroke: Option<Stroke>,
21    /// `Some` replaces the rect geometry with a circular band, in `rect` units.
22    pub arc: Option<ArcGeometry>,
23    pub z_index: usize,
24    pub clip: Option<Rect>,
25    pub blend_mode: BlendMode,
26}
27
28#[derive(Clone)]
29pub(crate) struct TextDraw {
30    pub node_id: NodeId,
31    pub rect: Rect,
32    pub snap_anchor: Option<Point>,
33    pub text: Rc<cranpose_ui::text::AnnotatedString>,
34    pub color: Color,
35    pub text_style: TextStyle,
36    pub font_size: f32,
37    pub scale: f32,
38    pub layout_options: TextLayoutOptions,
39    pub z_index: usize,
40    pub clip: Option<Rect>,
41}
42
43#[derive(Clone)]
44pub(crate) struct ImageDraw {
45    pub rect: Rect,
46    pub snap_anchor: Option<Point>,
47    pub image: ImageBitmap,
48    pub alpha: f32,
49    pub color_filter: Option<ColorFilter>,
50    pub sampling: ImageSampling,
51    pub z_index: usize,
52    pub clip: Option<Rect>,
53    pub blend_mode: BlendMode,
54    /// Source sub-region in image-pixel coordinates. `None` means full image.
55    pub src_rect: Option<Rect>,
56}
57
58pub(crate) struct RasterScene {
59    pub shapes: Vec<DrawShape>,
60    pub images: Vec<ImageDraw>,
61    pub texts: Vec<TextDraw>,
62    pub next_z: usize,
63}
64
65impl RasterScene {
66    pub fn new() -> Self {
67        Self {
68            shapes: Vec::new(),
69            images: Vec::new(),
70            texts: Vec::new(),
71            next_z: 0,
72        }
73    }
74
75    pub fn push_shape(
76        &mut self,
77        rect: Rect,
78        brush: Brush,
79        shape: Option<RoundedCornerShape>,
80        clip: Option<Rect>,
81        blend_mode: BlendMode,
82    ) {
83        let z_index = self.next_z;
84        self.next_z += 1;
85        self.shapes.push(DrawShape {
86            rect,
87            snap_anchor: None,
88            snap_to_pixel_grid: false,
89            brush,
90            shape,
91            stroke: None,
92            arc: None,
93            z_index,
94            clip,
95            blend_mode,
96        });
97    }
98
99    pub fn push_pixel_snapped_shape(
100        &mut self,
101        rect: Rect,
102        brush: Brush,
103        shape: Option<RoundedCornerShape>,
104        clip: Option<Rect>,
105        blend_mode: BlendMode,
106    ) {
107        let z_index = self.next_z;
108        self.next_z += 1;
109        self.shapes.push(DrawShape {
110            rect,
111            snap_anchor: None,
112            snap_to_pixel_grid: true,
113            brush,
114            shape,
115            stroke: None,
116            arc: None,
117            z_index,
118            clip,
119            blend_mode,
120        });
121    }
122
123    #[allow(clippy::too_many_arguments)]
124    pub fn push_shape_with_stroke_and_arc(
125        &mut self,
126        rect: Rect,
127        brush: Brush,
128        shape: Option<RoundedCornerShape>,
129        stroke: Option<Stroke>,
130        arc: Option<ArcGeometry>,
131        clip: Option<Rect>,
132        blend_mode: BlendMode,
133    ) {
134        let z_index = self.next_z;
135        self.next_z += 1;
136        self.shapes.push(DrawShape {
137            rect,
138            snap_anchor: None,
139            snap_to_pixel_grid: false,
140            brush,
141            shape,
142            stroke,
143            arc,
144            z_index,
145            clip,
146            blend_mode,
147        });
148    }
149
150    #[allow(clippy::too_many_arguments)]
151    pub fn push_image_with_geometry(
152        &mut self,
153        rect: Rect,
154        _local_rect: Rect,
155        _quad: [[f32; 2]; 4],
156        image: ImageBitmap,
157        alpha: f32,
158        color_filter: Option<ColorFilter>,
159        sampling: ImageSampling,
160        clip: Option<Rect>,
161        src_rect: Option<Rect>,
162        blend_mode: BlendMode,
163    ) {
164        let z_index = self.next_z;
165        self.next_z += 1;
166        self.images.push(ImageDraw {
167            rect,
168            snap_anchor: None,
169            image,
170            alpha: alpha.clamp(0.0, 1.0),
171            color_filter,
172            sampling,
173            z_index,
174            clip,
175            blend_mode,
176            src_rect,
177        });
178    }
179
180    #[allow(clippy::too_many_arguments)]
181    pub fn push_text(
182        &mut self,
183        node_id: NodeId,
184        rect: Rect,
185        text: Rc<cranpose_ui::text::AnnotatedString>,
186        color: Color,
187        text_style: TextStyle,
188        font_size: f32,
189        scale: f32,
190        layout_options: TextLayoutOptions,
191        clip: Option<Rect>,
192    ) {
193        let z_index = self.next_z;
194        self.next_z += 1;
195        self.texts.push(TextDraw {
196            node_id,
197            rect,
198            snap_anchor: None,
199            text,
200            color,
201            text_style,
202            font_size,
203            scale,
204            layout_options,
205            z_index,
206            clip,
207        });
208    }
209}
210
211impl Default for RasterScene {
212    fn default() -> Self {
213        Self::new()
214    }
215}