2026-02-24 13:52:06 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
use iced::widget::{Column, Row, button, column, text, Grid, row};
|
|
|
|
|
use iced::{Border, Color, Task};
|
|
|
|
|
use iced::padding;
|
|
|
|
|
use iced::widget::container;
|
|
|
|
|
use iced::Theme;
|
|
|
|
|
|
2026-02-23 17:43:03 +08:00
|
|
|
mod image_button;
|
|
|
|
|
|
|
|
|
|
#[derive(Default)]
|
2026-02-24 13:52:06 +08:00
|
|
|
struct Paint {
|
|
|
|
|
tool_pressed: [bool; Tool::Count as usize],
|
2026-02-23 17:43:03 +08:00
|
|
|
}
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub enum Message {
|
|
|
|
|
Decrement,
|
2026-02-24 13:52:06 +08:00
|
|
|
|
|
|
|
|
FreeFormSelectClicked,
|
|
|
|
|
SelectClicked,
|
|
|
|
|
EraserClicked,
|
|
|
|
|
FillWithColorClicked,
|
|
|
|
|
PickColorClicked,
|
|
|
|
|
MagnifierClicked,
|
|
|
|
|
PencilClicked,
|
|
|
|
|
BrushClicked,
|
|
|
|
|
AirbrushClicked,
|
|
|
|
|
TextClicked,
|
|
|
|
|
LineClicked,
|
|
|
|
|
CurveClicked,
|
|
|
|
|
RectangleClicked,
|
|
|
|
|
PolygonClicked,
|
|
|
|
|
EllipseClicked,
|
|
|
|
|
RoundedRectangleClicked,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Message {
|
|
|
|
|
pub fn to_tool_index(&self) -> usize {
|
|
|
|
|
match self {
|
|
|
|
|
Message::FreeFormSelectClicked => 0,
|
|
|
|
|
Message::SelectClicked => 1,
|
|
|
|
|
Message::EraserClicked => 2,
|
|
|
|
|
Message::FillWithColorClicked => 3,
|
|
|
|
|
Message::PickColorClicked => 4,
|
|
|
|
|
Message::MagnifierClicked => 5,
|
|
|
|
|
Message::PencilClicked => 6,
|
|
|
|
|
Message::BrushClicked => 7,
|
|
|
|
|
Message::AirbrushClicked => 8,
|
|
|
|
|
Message::TextClicked => 9,
|
|
|
|
|
Message::LineClicked => 10,
|
|
|
|
|
Message::CurveClicked => 11,
|
|
|
|
|
Message::RectangleClicked => 12,
|
|
|
|
|
Message::PolygonClicked => 13,
|
|
|
|
|
Message::EllipseClicked => 14,
|
|
|
|
|
Message::RoundedRectangleClicked => 15,
|
|
|
|
|
_ => usize::MAX,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub enum Tool {
|
|
|
|
|
FreeFormSelect,
|
|
|
|
|
Select,
|
|
|
|
|
Eraser,
|
|
|
|
|
FillWithColor,
|
|
|
|
|
PickColor,
|
|
|
|
|
Magnifier,
|
|
|
|
|
Pencil,
|
|
|
|
|
Brush,
|
|
|
|
|
Airbrush,
|
|
|
|
|
Text,
|
|
|
|
|
Line,
|
|
|
|
|
Curve,
|
|
|
|
|
Rectangle,
|
|
|
|
|
Polygon,
|
|
|
|
|
Ellipse,
|
|
|
|
|
RoundedRectangle,
|
|
|
|
|
|
|
|
|
|
Count,
|
2026-02-23 17:43:03 +08:00
|
|
|
}
|
2026-02-24 13:52:06 +08:00
|
|
|
|
|
|
|
|
impl Paint {
|
|
|
|
|
pub fn view(&self) -> Column<'_, Message> {
|
|
|
|
|
let mut grid = Grid::new();
|
|
|
|
|
grid = grid.columns(2).width(100);
|
|
|
|
|
|
|
|
|
|
for i in 0..(Tool::Count as usize) {
|
|
|
|
|
let msg = match i {
|
|
|
|
|
0 => Message::FreeFormSelectClicked,
|
|
|
|
|
1 => Message::SelectClicked,
|
|
|
|
|
2 => Message::EraserClicked,
|
|
|
|
|
3 => Message::FillWithColorClicked,
|
|
|
|
|
4 => Message::PickColorClicked,
|
|
|
|
|
5 => Message::MagnifierClicked,
|
|
|
|
|
6 => Message::PencilClicked,
|
|
|
|
|
7 => Message::BrushClicked,
|
|
|
|
|
8 => Message::AirbrushClicked,
|
|
|
|
|
9 => Message::TextClicked,
|
|
|
|
|
10 => Message::LineClicked,
|
|
|
|
|
11 => Message::CurveClicked,
|
|
|
|
|
12 => Message::RectangleClicked,
|
|
|
|
|
13 => Message::PolygonClicked,
|
|
|
|
|
14 => Message::EllipseClicked,
|
|
|
|
|
15 => Message::RoundedRectangleClicked,
|
|
|
|
|
_ => Message::FreeFormSelectClicked,
|
|
|
|
|
};
|
|
|
|
|
let btn = image_button::image_button(
|
|
|
|
|
format!("image/normal/normal_{:02}.jpg", i + 1),
|
|
|
|
|
format!("image/selected/selected_{:02}.jpg", i + 1),
|
|
|
|
|
self.tool_pressed[i],
|
|
|
|
|
).on_press(msg);
|
|
|
|
|
grid = grid.push(btn);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 17:43:03 +08:00
|
|
|
// We use a column: a simple vertical layout
|
|
|
|
|
column![
|
|
|
|
|
button("-").on_press(Message::Decrement),
|
2026-02-24 13:52:06 +08:00
|
|
|
|
|
|
|
|
container(grid).padding(padding::left(5).right(5).bottom(100)).style(|theme: &Theme| {
|
|
|
|
|
let palette = theme.extended_palette();
|
|
|
|
|
|
|
|
|
|
container::Style {
|
|
|
|
|
background: Some(Color::from_rgb8(192, 192, 192).into()),
|
|
|
|
|
text_color: Some(palette.background.weakest.text),
|
|
|
|
|
border: Border {
|
|
|
|
|
width: 1.0,
|
|
|
|
|
radius: 5.0.into(),
|
|
|
|
|
color: palette.background.weak.color,
|
|
|
|
|
},
|
|
|
|
|
..container::Style::default()
|
|
|
|
|
}
|
|
|
|
|
}),
|
2026-02-23 17:43:03 +08:00
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
pub fn update(&mut self, message: Message) {
|
2026-02-24 13:52:06 +08:00
|
|
|
self.press_tool(&message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn press_tool(&mut self, message: &Message) {
|
|
|
|
|
let idx = message.to_tool_index();
|
|
|
|
|
if idx == usize::MAX {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
let old_value = self.tool_pressed[idx];
|
|
|
|
|
for i in 0..(Tool::Count as usize) {
|
|
|
|
|
self.tool_pressed[i] = false;
|
2026-02-23 17:43:03 +08:00
|
|
|
}
|
2026-02-24 13:52:06 +08:00
|
|
|
self.tool_pressed[idx] = !old_value;
|
2026-02-23 17:43:03 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() -> iced::Result {
|
2026-02-24 13:52:06 +08:00
|
|
|
iced::run(Paint::update, Paint::view)
|
2026-02-23 17:43:03 +08:00
|
|
|
}
|