feat: 实现多边形功能
This commit is contained in:
@@ -37,6 +37,20 @@ impl MSColor {
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Path2D {
|
||||
points: Vec<Point>,
|
||||
}
|
||||
|
||||
impl Path2D {
|
||||
pub fn new() -> Self {
|
||||
Self { points: vec![] }
|
||||
}
|
||||
|
||||
pub fn push(&mut self, point: Point) {
|
||||
self.points.push(point);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MSCanvas {
|
||||
width: i32,
|
||||
height: i32,
|
||||
@@ -50,6 +64,8 @@ pub struct MSCanvas {
|
||||
color: MSColor,
|
||||
|
||||
line_width: i32,
|
||||
|
||||
path2d: Path2D,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
@@ -62,6 +78,7 @@ impl MSCanvas {
|
||||
pixels_bak: Vec::new(),
|
||||
color: MSColor::BLACK,
|
||||
line_width: 1,
|
||||
path2d: Path2D::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,6 +652,37 @@ impl MSCanvas {
|
||||
let points = vec![begin, p1, p2, end];
|
||||
self.bezier(points);
|
||||
}
|
||||
|
||||
pub fn begin_path(&mut self) {
|
||||
self.path2d = Path2D::new();
|
||||
}
|
||||
|
||||
pub fn close_path(&mut self) {
|
||||
let points = &self.path2d.points;
|
||||
if points.len() < 3 {
|
||||
return;
|
||||
}
|
||||
self.path2d.push(points[0]);
|
||||
}
|
||||
|
||||
pub fn move_to(&mut self, point: Point) {
|
||||
self.path2d.push(point);
|
||||
}
|
||||
|
||||
pub fn line_to(&mut self, point: Point) {
|
||||
self.path2d.push(point);
|
||||
}
|
||||
|
||||
pub fn stroke(&mut self) {
|
||||
let mut points = self.path2d.points.clone();
|
||||
if points.len() < 2 {
|
||||
return;
|
||||
}
|
||||
// 连线
|
||||
for i in 0..(points.len() - 1) {
|
||||
self.draw_line_with_circle_brush(points[i], points[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn point_muln(point: Point, t: f32) -> Point {
|
||||
|
||||
96
src/paint.rs
96
src/paint.rs
@@ -53,6 +53,7 @@ enum Message {
|
||||
MousePressed(Point),
|
||||
MouseReleased(Point),
|
||||
MouseMoved(Point),
|
||||
MouseDoubleClick(Point),
|
||||
|
||||
Clear,
|
||||
SavePNG,
|
||||
@@ -94,6 +95,34 @@ enum Tool {
|
||||
Count,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Tool {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Tool::FreeFormSelect => "FreeFormSelect",
|
||||
Tool::Select => "Select",
|
||||
Tool::Eraser => "Eraser",
|
||||
Tool::FillWithColor => "FillWithColor",
|
||||
Tool::PickColor => "PickColor",
|
||||
Tool::Magnifier => "Magnifier",
|
||||
Tool::Pencil => "Pencil",
|
||||
Tool::Brush => "Brush",
|
||||
Tool::Airbrush => "Airbrush",
|
||||
Tool::Text => "Text",
|
||||
Tool::Line => "Line",
|
||||
Tool::Curve => "Curve",
|
||||
Tool::Rectangle => "Rectangle",
|
||||
Tool::Polygon => "Polygon",
|
||||
Tool::Ellipse => "Ellipse",
|
||||
Tool::RoundedRectangle => "RoundedRectangle",
|
||||
Tool::Count => "Count",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for Tool {
|
||||
fn from(tool: usize) -> Self {
|
||||
match tool {
|
||||
@@ -219,6 +248,8 @@ struct PaintApp {
|
||||
is_controlling: bool,
|
||||
control_points: Vec<Point>,
|
||||
|
||||
is_path_beginning: bool,
|
||||
|
||||
/// 用于显示的图像句柄缓存
|
||||
/// 每次像素变化后需要重新生成
|
||||
image_handle: image::Handle,
|
||||
@@ -249,6 +280,7 @@ impl PaintApp {
|
||||
end_point: Point::ORIGIN,
|
||||
is_controlling: false,
|
||||
control_points: Vec::with_capacity(2),
|
||||
is_path_beginning: false,
|
||||
image_handle: image::Handle::from_rgba(width as u32, height as u32, pixels),
|
||||
dirty: false,
|
||||
config,
|
||||
@@ -266,7 +298,8 @@ impl PaintApp {
|
||||
let canvas_area = mouse_area(image_widget)
|
||||
.on_press(|pos| Message::MousePressed(pos)) // 占位,实际逻辑在 on_drag 或自定义
|
||||
.on_release(|pos| Message::MouseReleased(pos))
|
||||
.on_move(|pos| Message::MouseMoved(pos));
|
||||
.on_move(|pos| Message::MouseMoved(pos))
|
||||
.on_double_click(|pos| Message::MouseDoubleClick(pos));
|
||||
// 注意:mouse_area 的 on_move 给出的坐标通常是相对于 widget 左上角的,这正是我们需要的!
|
||||
let canvas_area = container(canvas_area)
|
||||
.width(Length::Fill)
|
||||
@@ -293,7 +326,10 @@ impl PaintApp {
|
||||
.on_press(Message::ClickTool(Tool::from(i + 1)));
|
||||
columns.push(row![btn1, btn2].into());
|
||||
}
|
||||
let tool_config_area = container("").width(90).height(200).style(|theme: &Theme| {
|
||||
let tool_config_area = container(text(format!("{}", self.tool_selected)))
|
||||
.width(90)
|
||||
.height(200)
|
||||
.style(|theme: &Theme| {
|
||||
let palette = theme.extended_palette();
|
||||
|
||||
container::Style {
|
||||
@@ -408,6 +444,9 @@ impl PaintApp {
|
||||
Tool::Rectangle => {
|
||||
self.update_with_rectangle(message);
|
||||
}
|
||||
Tool::Polygon => {
|
||||
self.update_with_polygon(message);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -712,6 +751,49 @@ impl PaintApp {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_with_polygon(&mut self, message: Message) {
|
||||
match message {
|
||||
Message::MousePressed(pos) => {
|
||||
if self.is_path_beginning {
|
||||
self.is_drawing = true;
|
||||
self.canvas.restore_pixels();
|
||||
self.canvas.stroke();
|
||||
self.canvas
|
||||
.draw_line_with_circle_brush(self.begin_point, pos);
|
||||
self.dirty = true;
|
||||
} else {
|
||||
self.is_path_beginning = true;
|
||||
self.is_drawing = true;
|
||||
self.canvas.save_pixels();
|
||||
self.begin_point = pos;
|
||||
self.canvas.begin_path();
|
||||
self.canvas.move_to(pos);
|
||||
}
|
||||
}
|
||||
Message::MouseReleased(pos) => {
|
||||
self.canvas.line_to(pos);
|
||||
self.begin_point = pos;
|
||||
}
|
||||
Message::MouseMoved(pos) => {
|
||||
if self.is_drawing {
|
||||
self.canvas.restore_pixels();
|
||||
self.canvas.stroke();
|
||||
self.canvas
|
||||
.draw_line_with_circle_brush(self.begin_point, pos);
|
||||
self.dirty = true;
|
||||
}
|
||||
}
|
||||
Message::MouseDoubleClick(_pos) => {
|
||||
self.canvas.close_path();
|
||||
self.canvas.stroke();
|
||||
self.is_drawing = false;
|
||||
self.is_path_beginning = false;
|
||||
self.dirty = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
pub fn update_tool_states(&mut self, tool: Tool) {
|
||||
@@ -719,12 +801,22 @@ impl PaintApp {
|
||||
if idx >= self.tool_states.len() {
|
||||
return;
|
||||
}
|
||||
if self.tool_selected == Tool::Polygon {
|
||||
// 切换到其他工具,闭合路径
|
||||
self.canvas.close_path();
|
||||
self.canvas.stroke();
|
||||
self.dirty = true;
|
||||
}
|
||||
|
||||
let old_value = self.tool_states[idx];
|
||||
for i in 0..(Tool::Count as usize) {
|
||||
self.tool_states[i] = false;
|
||||
}
|
||||
self.tool_states[idx] = !old_value;
|
||||
self.tool_selected = idx.into();
|
||||
|
||||
self.is_drawing = false;
|
||||
self.is_path_beginning = false;
|
||||
}
|
||||
|
||||
/// 将原始字节转换为 Iced 的图像句柄
|
||||
|
||||
Reference in New Issue
Block a user