feat: 实现喷枪功能

This commit is contained in:
2026-02-28 14:32:39 +08:00
parent 3ed3c12f47
commit a9243c498f
4 changed files with 197 additions and 12 deletions

View File

@@ -1,6 +1,7 @@
use ::image::{ImageBuffer, ImageError, Rgba};
use iced::Theme;
use iced::padding;
use iced::time::{self, Instant, milliseconds};
use iced::widget::container;
use iced::widget::{Column, button, column, image, pick_list, row, text};
use iced::{Border, Color, Element, Length, Point, Renderer, Task};
@@ -67,9 +68,11 @@ enum Message {
/// 全局鼠标释放
WindowMouseRelease,
Tick(Instant),
}
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Tool {
FreeFormSelect,
Select,
@@ -143,12 +146,16 @@ impl From<Tool> for usize {
pub enum ConfigOption {
EraserWidth,
LineWidth,
AirbrushRadius,
AirbrushDensity,
}
#[derive(Debug, Clone, Copy)]
struct Config {
eraser_width: i32,
line_width: i32,
airbrush_radius: i32,
airbrush_density: i32,
}
impl Default for Config {
@@ -161,6 +168,8 @@ impl Config {
const DEFAULT: Config = Config {
line_width: 1,
eraser_width: 4,
airbrush_radius: 4,
airbrush_density: 16,
};
fn incr(&mut self, option: ConfigOption, step: i32) {
match option {
@@ -176,6 +185,18 @@ impl Config {
self.line_width = Self::DEFAULT.line_width;
}
}
ConfigOption::AirbrushRadius => {
self.airbrush_radius += step;
if self.airbrush_radius < Self::DEFAULT.airbrush_radius {
self.airbrush_radius = Self::DEFAULT.airbrush_radius;
}
}
ConfigOption::AirbrushDensity => {
self.airbrush_density += step;
if self.airbrush_density < Self::DEFAULT.airbrush_density {
self.airbrush_density = Self::DEFAULT.airbrush_density;
}
}
}
}
}
@@ -297,27 +318,47 @@ impl PaintApp {
let mut debug_area = row![
column![
text("Eraser Width "),
text("Eraser Width"),
row![
button("+").on_press(Message::Increment(ConfigOption::EraserWidth)),
text(self.config.eraser_width).size(20).center(),
button("-").on_press(Message::Decrement(ConfigOption::EraserWidth)),
],
],
]
.padding(padding::right(5)),
column![
text("Line Width "),
text("Line Width"),
row![
button("+").on_press(Message::Increment(ConfigOption::LineWidth)),
text(self.config.line_width).size(20).center(),
button("-").on_press(Message::Decrement(ConfigOption::LineWidth)),
],
],
]
.padding(padding::right(5)),
pick_list(
&BrushKind::ALL[..],
self.brush_selected,
Message::BrushSelected,
)
.placeholder("Brush..."),
column![
text("Airbrush Radius"),
row![
button("+").on_press(Message::Increment(ConfigOption::AirbrushRadius)),
text(self.config.airbrush_radius).size(20).center(),
button("-").on_press(Message::Decrement(ConfigOption::AirbrushRadius)),
],
]
.padding(padding::right(5)),
column![
text("Airbrush Density"),
row![
button("+").on_press(Message::Increment(ConfigOption::AirbrushDensity)),
text(self.config.airbrush_density).size(20).center(),
button("-").on_press(Message::Decrement(ConfigOption::AirbrushDensity)),
],
]
.padding(padding::right(5)),
];
debug_area = debug_area.padding(padding::top(10).left(5).bottom(10));
@@ -345,6 +386,9 @@ impl PaintApp {
Tool::Brush => {
self.update_with_brush(message);
}
Tool::Airbrush => {
self.update_with_airbrush(message);
}
Tool::Line => {
self.update_with_line(message);
}
@@ -394,6 +438,16 @@ impl PaintApp {
// 处理鼠标在 canvas_area 外面释放
self.is_drawing = false;
}
Message::Tick(_) => {
if self.is_drawing && self.tool_selected == Tool::Airbrush {
self.canvas.spray_paint(
self.begin_point,
self.config.airbrush_radius,
self.config.airbrush_density as u32,
);
self.dirty = true;
}
}
_ => {}
}
@@ -409,13 +463,15 @@ impl PaintApp {
}
pub fn subscription(&self) -> Subscription<Message> {
event::listen().filter_map(|event| match event {
let ev = event::listen().filter_map(|event| match event {
// 只关心鼠标释放事件
iced::Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => {
Some(Message::WindowMouseRelease)
}
_ => None,
})
});
let tick = time::every(milliseconds(50)).map(Message::Tick);
return Subscription::batch(vec![ev, tick]);
}
// endregion
@@ -468,6 +524,7 @@ impl PaintApp {
self.is_drawing = true;
self.canvas.draw_pixel_at(pos);
self.begin_point = pos;
self.dirty = true;
}
Message::MouseReleased(pos) => {
self.is_drawing = false;
@@ -516,6 +573,37 @@ impl PaintApp {
}
}
pub fn update_with_airbrush(&mut self, message: Message) {
match message {
Message::MousePressed(pos) => {
self.is_drawing = true;
self.canvas.spray_paint(
pos,
self.config.airbrush_radius,
self.config.airbrush_density as u32,
);
self.begin_point = pos;
self.dirty = true;
}
Message::MouseReleased(pos) => {
self.is_drawing = false;
self.begin_point = pos;
}
Message::MouseMoved(pos) => {
if self.is_drawing {
self.canvas.spray_paint(
pos,
self.config.airbrush_radius,
self.config.airbrush_density as u32,
);
self.begin_point = pos;
self.dirty = true;
}
}
_ => {}
}
}
pub fn update_with_line(&mut self, message: Message) {
match message {
Message::MousePressed(pos) => {