From de6a3e21ab86f938fc9e057a19333f266721ec2a Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Fri, 22 Mar 2024 19:11:28 +0900 Subject: [PATCH] Make background color configurable --- CHANGELOG.md | 1 + src/model.rs | 14 ++++++++++---- src/model/config.rs | 3 +++ src/widget/color_selector.rs | 37 +++++++++++++++++++++++++++++++----- src/widget/pixel_canvas.rs | 7 +++++-- src/widget/preview.rs | 7 +++++-- 6 files changed, 56 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d063150..50e7f3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Make background color configurable - Add auto generated color palette block to the color selector window - Add touch gesture support - If the `gesture` setting is enabled, the following gestures will become available: diff --git a/src/model.rs b/src/model.rs index 8418533..e7920d0 100644 --- a/src/model.rs +++ b/src/model.rs @@ -58,6 +58,10 @@ impl Models { } pub fn to_png(&self) -> Result> { + let bg_color = self + .config + .background_color + .unwrap_or(Rgba::new(0, 0, 0, 0)); let frame_count = self.config.animation.enabled_frame_count(); let frames = (0..frame_count) .map(|frame| { @@ -66,10 +70,12 @@ impl Models { .get_preview_region(&self.config, frame as usize) .pixels() .flat_map(|position| { - let color = self - .pixel_canvas - .get_pixel(&self.config, position) - .unwrap_or(Rgba::new(0, 0, 0, 0)); + let color = + if let Some(c) = self.pixel_canvas.get_pixel(&self.config, position) { + c.alpha_blend(bg_color) + } else { + bg_color + }; [color.r, color.g, color.b, color.a].into_iter() }) .collect::>() diff --git a/src/model/config.rs b/src/model/config.rs index 81cded9..494a226 100644 --- a/src/model/config.rs +++ b/src/model/config.rs @@ -32,6 +32,7 @@ pub struct ConfigModel { pub silhouette_preview: bool, pub gesture: bool, + pub background_color: Option, } impl Serialize for ConfigModel { @@ -50,6 +51,7 @@ impl Serialize for ConfigModel { self.attrs.serialize(writer).or_fail()?; self.silhouette_preview.serialize(writer).or_fail()?; self.gesture.serialize(writer).or_fail()?; + self.background_color.serialize(writer).or_fail()?; Ok(()) } } @@ -71,6 +73,7 @@ impl Deserialize for ConfigModel { attrs: Deserialize::deserialize_or_default(reader).or_fail()?, silhouette_preview: Deserialize::deserialize_or_default(reader).or_fail()?, gesture: Deserialize::deserialize_or_default(reader).or_fail()?, + background_color: Deserialize::deserialize_or_default(reader).or_fail()?, }) } } diff --git a/src/widget/color_selector.rs b/src/widget/color_selector.rs index de30af4..8e40e59 100644 --- a/src/widget/color_selector.rs +++ b/src/widget/color_selector.rs @@ -22,6 +22,7 @@ pub struct ColorSelectorWidget { alpha: BlockWidget, palette: BlockWidget, replace: BlockWidget, + background: BlockWidget, } impl ColorSelectorWidget { @@ -63,6 +64,10 @@ impl ColorSelectorWidget { "REPLACE OLD COLOR PIXELS".parse().expect("unreachable"), ToggleWidget::default_off(), ), + background: BlockWidget::new( + "BACKGROUND COLOR".parse().expect("unreachable"), + ToggleWidget::default_off(), + ), } } @@ -142,6 +147,7 @@ impl Widget for ColorSelectorWidget { self.palette.render_if_need(app, canvas); } self.replace.render_if_need(app, canvas); + self.background.render_if_need(app, canvas); } fn handle_event(&mut self, app: &mut App, event: &mut Event) -> Result<()> { @@ -177,6 +183,19 @@ impl Widget for ColorSelectorWidget { } } + let old_background_mode = self.background.body().is_on(); + self.background.handle_event(app, event).or_fail()?; + if self.background.body().is_on() + && (old_background_mode == false || old_color != new_color) + { + if new_color.a == 0 { + app.models_mut().config.background_color = None; + } else { + app.models_mut().config.background_color = Some(new_color); + } + app.request_redraw(app.screen_size().to_region()); + } + Ok(()) } @@ -187,6 +206,7 @@ impl Widget for ColorSelectorWidget { &mut self.alpha, &mut self.palette, &mut self.replace, + &mut self.background, ] } } @@ -203,7 +223,8 @@ impl FixedSizeWidget for ColorSelectorWidget { } else { self.palette.requiring_size(app) }; - let replace = self.alpha.requiring_size(app); + let replace = self.replace.requiring_size(app); + let background = self.background.requiring_size(app); Size::from_wh( preview @@ -212,7 +233,7 @@ impl FixedSizeWidget for ColorSelectorWidget { .max(hsv.width) .max(alpha.width) .max(palette.width) - .max(replace.width), + .max(replace.width + MARGIN + background.width), preview.height + MARGIN + hsv.height @@ -223,7 +244,7 @@ impl FixedSizeWidget for ColorSelectorWidget { + MARGIN + palette.height + MARGIN - + replace.height, + + replace.height.max(background.height), ) } @@ -250,8 +271,14 @@ impl FixedSizeWidget for ColorSelectorWidget { offset.y = self.palette.region().end().y + MARGIN as i32; } - let mut replace_region = Region::new(offset, self.replace.requiring_size(app)); - replace_region.size.width = self.region.size.width; + let replace_region = Region::new(offset, self.replace.requiring_size(app)); self.replace.set_region(app, replace_region); + + let mut background_region = Region::new( + offset.move_x((MARGIN + replace_region.size.width) as i32), + self.background.requiring_size(app), + ); + background_region.size.width += (self.region.end().x - background_region.end().x) as u32; + self.background.set_region(app, background_region); } } diff --git a/src/widget/pixel_canvas.rs b/src/widget/pixel_canvas.rs index 16e4011..ea6bb37 100644 --- a/src/widget/pixel_canvas.rs +++ b/src/widget/pixel_canvas.rs @@ -4,7 +4,7 @@ use super::{ use crate::{ app::App, canvas_ext::CanvasExt, - color, + color::{self, CANVAS_BACKGROUND}, event::Event, gesture::{GestureEvent, GestureRecognizer}, io::IoRequest, @@ -267,7 +267,10 @@ impl Widget for PixelCanvasWidget { fn render(&self, app: &App, canvas: &mut Canvas) { let preview_mode = app.models().preview_mode; - canvas.fill_rectangle(self.region, color::CANVAS_BACKGROUND); + canvas.fill_rectangle(self.region, CANVAS_BACKGROUND); + if let Some(bg) = app.models().config.background_color { + canvas.fill_rectangle(self.region, bg.into()); + } if preview_mode { if app.models().config.animation.enabled_frame_count() > 1 { self.render_frame_edges(app, canvas); diff --git a/src/widget/preview.rs b/src/widget/preview.rs index e1786d6..7b0e75f 100644 --- a/src/widget/preview.rs +++ b/src/widget/preview.rs @@ -2,7 +2,7 @@ use super::{FixedSizeWidget, Widget}; use crate::{ app::App, canvas_ext::CanvasExt, - color, + color::{self, PREVIEW_BACKGROUND}, event::Event, pixel::{PixelPosition, PixelRegion, PixelSize}, region_ext::RegionExt, @@ -172,7 +172,10 @@ impl Widget for PreviewFrameWidget { } fn render(&self, app: &App, canvas: &mut Canvas) { - canvas.fill_rectangle(self.region, color::PREVIEW_BACKGROUND); + canvas.fill_rectangle(self.region, PREVIEW_BACKGROUND); + if let Some(bg) = app.models().config.background_color { + canvas.fill_rectangle(self.region, bg.into()); + } self.render_pixels(app, canvas); }