pixcil/widget/
config.rs

1use super::frame_size::FrameSizeWidget;
2use super::{
3    FixedSizeWidget, VariableSizeWidget, Widget, block::BlockWidget, number_box::NumberBoxWidget,
4    pixel_size::PixelSizeWidget, toggle::ToggleWidget,
5};
6use crate::{app::App, event::Event, model::config::Animation, region_ext::RegionExt};
7use orfail::{OrFail, Result};
8use pagurus::image::Canvas;
9use pagurus::spatial::{Position, Region, Size};
10
11const MARGIN_X: u32 = 8;
12const MARGIN_Y: u32 = 14;
13
14#[derive(Debug)]
15pub struct ConfigWidget {
16    region: Region,
17
18    // Size settings
19    frame_size: BlockWidget<FrameSizeWidget>,
20    pixel_size: BlockWidget<PixelSizeWidget>,
21
22    // Preview settings
23    frame_preview: BlockWidget<ToggleWidget>,
24    frame_preview_scale: BlockWidget<NumberBoxWidget>,
25    silhouette: BlockWidget<ToggleWidget>,
26
27    // Layer / animation settings
28    layer_enable: BlockWidget<ToggleWidget>,
29    animation_enable: BlockWidget<ToggleWidget>,
30    fps: BlockWidget<NumberBoxWidget>,
31    apng: BlockWidget<ToggleWidget>,
32
33    // Gesture settings
34    gesture: BlockWidget<ToggleWidget>,
35}
36
37impl ConfigWidget {
38    pub fn new(app: &App) -> Self {
39        let frame_preview = app.models().config.frame_preview.get();
40        let frame_preview_scale = app.models().config.frame_preview_scale.get();
41        let silhouette_preview = app.models().config.silhouette_preview;
42        let layer = app.models().config.layer;
43        let animation = app.models().config.animation;
44        let apng = app.models().config.apng();
45        let gesture = app.models().config.gesture;
46        Self {
47            region: Region::default(),
48
49            // Size
50            frame_size: BlockWidget::new(
51                "FRAME SIZE".parse().expect("unreachable"),
52                FrameSizeWidget::new(app),
53            ),
54            pixel_size: BlockWidget::new(
55                "TOOL SIZE".parse().expect("unreachable"),
56                PixelSizeWidget::new(app),
57            ),
58
59            // Preview
60            frame_preview: BlockWidget::new(
61                "PREVIEW".parse().expect("unreachable"),
62                ToggleWidget::new(frame_preview),
63            ),
64            frame_preview_scale: BlockWidget::new(
65                "PREVIEW SCALE".parse().expect("unreachable"),
66                NumberBoxWidget::new(1, frame_preview_scale as u32, 32),
67            ),
68            silhouette: BlockWidget::new(
69                "SILHOUETTE".parse().expect("unreachable"),
70                ToggleWidget::new(silhouette_preview),
71            ),
72
73            // Layer / animation
74            layer_enable: BlockWidget::new(
75                "LAYER".parse().expect("unreachable"),
76                ToggleWidget::new(layer.is_enabled()),
77            ),
78            animation_enable: BlockWidget::new(
79                "ANIMATION".parse().expect("unreachable"),
80                ToggleWidget::new(animation.is_enabled()),
81            ),
82            fps: BlockWidget::new(
83                "FPS".parse().expect("unreachable"),
84                NumberBoxWidget::new(
85                    Animation::MIN_FPS as u32,
86                    animation.fps() as u32,
87                    Animation::MAX_FPS as u32,
88                ),
89            ),
90            apng: BlockWidget::new(
91                "APNG".parse().expect("unreachable"),
92                ToggleWidget::new(apng),
93            ),
94
95            // Gesture
96            gesture: BlockWidget::new(
97                "GESTURE".parse().expect("unreachable"),
98                ToggleWidget::new(gesture),
99            ),
100        }
101    }
102}
103
104impl Widget for ConfigWidget {
105    fn region(&self) -> Region {
106        self.region
107    }
108
109    fn render(&self, app: &App, canvas: &mut Canvas) {
110        // Size
111        self.frame_size.render_if_need(app, canvas);
112        self.pixel_size.render_if_need(app, canvas);
113
114        // Preview
115        self.frame_preview.render_if_need(app, canvas);
116        self.frame_preview_scale.render_if_need(app, canvas);
117        self.silhouette.render_if_need(app, canvas);
118
119        // Layer / animation
120        self.layer_enable.render_if_need(app, canvas);
121        self.animation_enable.render_if_need(app, canvas);
122        self.fps.render_if_need(app, canvas);
123        self.apng.render_if_need(app, canvas);
124
125        // Gesture
126        self.gesture.render_if_need(app, canvas);
127    }
128
129    fn handle_event(&mut self, app: &mut App, event: &mut Event) -> Result<()> {
130        // Size
131        let frame = app.models().config.frame;
132        self.frame_size.handle_event(app, event).or_fail()?;
133        app.models_mut()
134            .config
135            .frame
136            .set_from_pixel_size(self.frame_size.body().value());
137        if frame != app.models().config.frame {
138            app.request_redraw(app.screen_size().to_region());
139        }
140
141        self.pixel_size.handle_event(app, event).or_fail()?;
142        app.models_mut()
143            .config
144            .minimum_pixel_size
145            .set(self.pixel_size.body().value());
146
147        // Preview
148        self.frame_preview.handle_event(app, event).or_fail()?;
149        app.models_mut()
150            .config
151            .frame_preview
152            .set(self.frame_preview.body().is_on());
153        self.frame_preview_scale
154            .handle_event(app, event)
155            .or_fail()?;
156        app.models_mut()
157            .config
158            .frame_preview_scale
159            .set(self.frame_preview_scale.body().value() as u8)
160            .or_fail()?;
161        self.silhouette.handle_event(app, event).or_fail()?;
162        app.models_mut().config.silhouette_preview = self.silhouette.body().is_on();
163
164        // Layer / animation
165        let layer = app.models().config.layer;
166        self.layer_enable.handle_event(app, event).or_fail()?;
167        app.models_mut()
168            .config
169            .layer
170            .set_enabled(self.layer_enable.body().is_on());
171        if layer != app.models().config.layer {
172            app.request_redraw(app.screen_size().to_region());
173        }
174
175        let animation = app.models_mut().config.animation;
176        self.animation_enable.handle_event(app, event).or_fail()?;
177        app.models_mut()
178            .config
179            .animation
180            .set_enabled(self.animation_enable.body().is_on());
181
182        self.fps.handle_event(app, event).or_fail()?;
183        app.models_mut()
184            .config
185            .animation
186            .set_fps(self.fps.body().value() as u8);
187
188        self.apng.handle_event(app, event).or_fail()?;
189        app.models_mut().config.apng = Some(self.apng.body().is_on());
190
191        if animation != app.models_mut().config.animation {
192            app.request_redraw(app.screen_size().to_region());
193        }
194
195        // Gesture
196        self.gesture.handle_event(app, event).or_fail()?;
197        app.models_mut().config.gesture = self.gesture.body().is_on();
198
199        Ok(())
200    }
201
202    fn children(&mut self) -> Vec<&mut dyn Widget> {
203        vec![
204            // Size
205            &mut self.frame_size,
206            &mut self.pixel_size,
207            // Preview
208            &mut self.frame_preview,
209            &mut self.frame_preview_scale,
210            &mut self.silhouette,
211            // Layer / animation
212            &mut self.layer_enable,
213            &mut self.animation_enable,
214            &mut self.fps,
215            &mut self.apng,
216            // Gesture
217            &mut self.gesture,
218        ]
219    }
220}
221
222impl FixedSizeWidget for ConfigWidget {
223    fn requiring_size(&self, app: &App) -> Size {
224        // Frame size
225        let row1 = self.frame_size.requiring_size(app);
226
227        // Pixel size / gesture
228        let mut row2 = self.pixel_size.requiring_size(app);
229        row2.width += MARGIN_X + self.gesture.requiring_size(app).width;
230
231        // Preview
232        let mut row3 = self.frame_preview.requiring_size(app);
233        row3.width += MARGIN_X + self.frame_preview_scale.requiring_size(app).width;
234        row3.width += MARGIN_X + self.silhouette.requiring_size(app).width;
235
236        // Layer / animation
237        let mut row4 = self.layer_enable.requiring_size(app);
238        row4.width += MARGIN_X + self.animation_enable.requiring_size(app).width;
239        row4.width += MARGIN_X + self.fps.requiring_size(app).width;
240        row4.width += MARGIN_X + self.apng.requiring_size(app).width;
241
242        Size::from_wh(
243            row1.width.max(row2.width).max(row3.width).max(row4.width),
244            row1.height + MARGIN_Y + row2.height + MARGIN_Y + row3.height + MARGIN_Y + row4.height,
245        ) + MARGIN_X * 2
246    }
247
248    fn set_position(&mut self, app: &App, position: Position) {
249        self.region = Region::new(position, self.requiring_size(app));
250
251        let mut region = self.region.without_margin(MARGIN_X);
252
253        // Size, gesture
254        let mut frame_size_region = region;
255        frame_size_region.size = self.frame_size.requiring_size(app);
256        self.frame_size.set_region(app, frame_size_region);
257        region.consume_y(frame_size_region.size.height + MARGIN_Y);
258
259        let mut pixel_size_region = region;
260        pixel_size_region.size = self.pixel_size.requiring_size(app);
261        self.pixel_size.set_region(app, pixel_size_region);
262
263        let mut gesture_region = region;
264        gesture_region.position.x = pixel_size_region.end().x + MARGIN_X as i32;
265        gesture_region.size = self.gesture.requiring_size(app);
266        self.gesture.set_region(app, gesture_region);
267
268        region.consume_y(gesture_region.size.height + MARGIN_Y);
269
270        // Preview
271        let mut frame_preview_region = region;
272        frame_preview_region.size = self.frame_preview.requiring_size(app);
273        self.frame_preview.set_region(app, frame_preview_region);
274
275        let mut preview_scale_region = region;
276        preview_scale_region.position.x = frame_preview_region.end().x + MARGIN_X as i32;
277        preview_scale_region.size = self.frame_preview_scale.requiring_size(app);
278        self.frame_preview_scale
279            .set_region(app, preview_scale_region);
280
281        let mut silhouette_region = region;
282        silhouette_region.position.x = preview_scale_region.end().x + MARGIN_X as i32;
283        silhouette_region.size = self.silhouette.requiring_size(app);
284        self.silhouette.set_region(app, silhouette_region);
285
286        region.consume_y(frame_preview_region.size.height + MARGIN_Y);
287
288        // Layer / animation
289        let mut layer_enable_region = region;
290        layer_enable_region.size = self.layer_enable.requiring_size(app);
291        self.layer_enable.set_region(app, layer_enable_region);
292
293        let mut animation_enable_region = region;
294        animation_enable_region.position.x = layer_enable_region.end().x + MARGIN_X as i32;
295        animation_enable_region.size = self.animation_enable.requiring_size(app);
296        self.animation_enable
297            .set_region(app, animation_enable_region);
298
299        let mut fps_region = region;
300        fps_region.position.x = animation_enable_region.end().x + MARGIN_X as i32;
301        fps_region.size = self.fps.requiring_size(app);
302        self.fps.set_region(app, fps_region);
303
304        let mut apng_region = region;
305        apng_region.position.x = fps_region.end().x + MARGIN_X as i32;
306        apng_region.size = self.apng.requiring_size(app);
307        self.apng.set_region(app, apng_region);
308    }
309}