1use std::rc::Rc;
2
3use cranpose_ui_graphics::{CommandRecording, DrawPrimitive, DrawScope, DrawScopeDefault};
4
5use crate::{modifier::Size, text::AppContextTextMeasurer};
6
7pub type DrawCommandFn = Rc<dyn Fn(&mut DrawScopeDefault)>;
13
14#[derive(Clone)]
16pub enum DrawCommand {
17 Behind(DrawCommandFn),
19 WithContent(DrawCommandFn),
22 Overlay(DrawCommandFn),
24}
25
26pub fn command_draw_scope(size: Size, recording: &mut CommandRecording) -> DrawScopeDefault<'_> {
31 DrawScopeDefault::with_text_measurer(size, AppContextTextMeasurer::shared(), recording)
32}
33
34#[derive(Default, Clone)]
36pub struct DrawCacheBuilder {
37 behind: Vec<DrawCommandFn>,
38 with_content: Vec<DrawCommandFn>,
39 overlay: Vec<DrawCommandFn>,
40}
41
42impl DrawCacheBuilder {
43 pub fn on_draw_behind(&mut self, f: impl Fn(&mut dyn DrawScope) + 'static) {
45 self.behind
46 .push(Rc::new(move |scope: &mut DrawScopeDefault| f(scope)));
47 }
48
49 pub fn finish(self) -> Vec<DrawCommand> {
51 let mut commands = Vec::new();
52 commands.extend(self.behind.into_iter().map(DrawCommand::Behind));
53 commands.extend(self.with_content.into_iter().map(DrawCommand::WithContent));
54 commands.extend(self.overlay.into_iter().map(DrawCommand::Overlay));
55 commands
56 }
57}
58
59pub fn execute_draw_commands(commands: &[DrawCommand], size: Size) -> Vec<DrawPrimitive> {
61 let mut primitives = Vec::new();
62 let mut recording = CommandRecording::default();
63 for command in commands {
64 match command {
65 DrawCommand::Behind(f) | DrawCommand::WithContent(f) | DrawCommand::Overlay(f) => {
66 let mut scope = command_draw_scope(size, &mut recording);
67 f(&mut scope);
68 primitives.extend(scope.into_primitives());
69 }
70 }
71 }
72 primitives
73}