feat: Implement rectangle

This commit is contained in:
2026-02-26 13:18:05 +08:00
parent 17cb31841f
commit 4216a6f507

View File

@@ -1,11 +1,11 @@
use crate::image_button::image_button;
use crate::mouse_area::mouse_area;
use iced::Theme;
use iced::padding;
use iced::widget::container;
use iced::widget::{Column, button, column, image, row};
use iced::{Border, Color, Length, Point, Task, Element, Renderer};
use iced::{Border, Color, Element, Length, Point, Renderer, Task};
use iced_core::color;
use crate::image_button::image_button;
use crate::mouse_area::mouse_area;
const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;
@@ -113,7 +113,12 @@ impl ColorU8 {
}
}
struct Paint {
pub fn point_to_i32(point: Point) -> Point<i32> {
Point::new(point.x as i32, point.y as i32)
}
struct PaintApp {
tool_states: [bool; Tool::Count as usize],
tool_selected: Tool,
@@ -141,7 +146,7 @@ struct Paint {
dirty: bool,
}
impl Paint {
impl PaintApp {
// region iced application (new view update)
pub fn new() -> Self {
@@ -179,11 +184,9 @@ impl Paint {
.width(Length::Fill)
.height(Length::Fill)
.padding(padding::left(5).top(5))
.style(|_| {
container::Style {
.style(|_| container::Style {
background: Some(color!(0x808080).into()),
..container::Style::default()
}
});
let mut columns: Vec<Element<'_, Message, Theme, Renderer>> = Vec::new();
@@ -197,7 +200,7 @@ impl Paint {
let btn2 = image_button(
format!("image/normal/normal_{:02}.jpg", i + 2),
format!("image/selected/selected_{:02}.jpg", i + 2),
self.tool_states[i+1],
self.tool_states[i + 1],
)
.on_press(Message::ClickTool(Tool::from(i + 1)));
columns.push(row![btn1, btn2].into());
@@ -253,6 +256,9 @@ impl Paint {
Tool::Line => {
self.update_with_line(message);
}
Tool::Rectangle => {
self.update_with_rectangle(message);
}
_ => {}
}
@@ -301,9 +307,8 @@ impl Paint {
pub fn update_with_pencil(&mut self, message: Message) {
match message {
Message::MousePressed(pos) => {
println!("pressed: {:?}", pos);
self.is_drawing = true;
self.draw_pixel_at1(pos);
self.draw_pixel_atp(pos);
self.begin_point = pos;
}
Message::MouseReleased(pos) => {
@@ -341,6 +346,27 @@ impl Paint {
}
}
pub fn update_with_rectangle(&mut self, message: Message) {
match message {
Message::MousePressed(pos) => {
self.is_drawing = true;
self.save_pixels();
self.begin_point = pos;
}
Message::MouseReleased(pos) => {
self.is_drawing = false;
self.begin_point = pos;
}
Message::MouseMoved(pos) => {
if self.is_drawing {
self.restore_pixels();
self.stroke_rect1(self.begin_point, pos, self.brush_radius * 2);
}
}
_ => {}
}
}
// endregion
pub fn update_tool_states(&mut self, tool: Tool) {
@@ -368,7 +394,7 @@ impl Paint {
/// draw method
#[allow(unused)]
impl Paint {
impl PaintApp {
fn pixel_at(&self, x: i32, y: i32) -> ColorU8 {
// 边界检查
if x < 0 || x >= WIDTH as i32 || y < 0 || y >= HEIGHT as i32 {
@@ -415,6 +441,7 @@ impl Paint {
}
}
#[inline]
fn draw_pixel_at_raw(&mut self, x: u32, y: u32) {
// 计算索引:(y * width + x) * 4
let index = ((y * WIDTH + x) * 4) as usize;
@@ -429,7 +456,7 @@ impl Paint {
self.dirty = true;
}
/// 核心绘图逻辑:直接在字节数组上操作
#[inline]
fn draw_pixel_at(&mut self, x: i32, y: i32) {
// 边界检查
if x < 0 || x >= WIDTH as i32 || y < 0 || y >= HEIGHT as i32 {
@@ -460,36 +487,21 @@ impl Paint {
self.dirty = true;
}
fn draw_pixel_at1(&mut self, pos: Point) {
fn draw_pixel_atp(&mut self, pos: Point) {
self.draw_pixel_at(pos.x as i32, pos.y as i32)
}
fn draw_lines(&mut self, points: &[Point]) {
if points.is_empty() {
return;
}
if points.len() == 1 {
self.draw_pixel_at1(points[0]);
return;
}
let mut begin = points[0];
for point in points.iter().skip(1) {
self.draw_line(begin, point.clone());
begin = point.clone();
fn draw_pixels(&mut self, points: Vec<Point<i32>>) {
for point in &points {
self.draw_pixel_at(point.x, point.y);
}
}
/// Bresenham's line drawing algorithm
fn draw_line(&mut self, begin: Point, end: Point) {
let x1 = begin.x as i32;
let y1 = begin.y as i32;
let x2 = end.x as i32;
let y2 = end.y as i32;
// draw start end point, 防止多条线段在连接点出现断开(比如 ab bc
self.draw_pixel_at(x1, y1);
self.draw_pixel_at(x2, y2);
fn bresenham_line(&mut self, begin: Point<i32>, end: Point<i32>) -> Vec<Point<i32>> {
let x1 = begin.x ;
let y1 = begin.y;
let x2 = end.x ;
let y2 = end.y;
let dx = (x2 - x1);
let dy = (y2 - y1);
@@ -503,17 +515,20 @@ impl Paint {
let xe;
let ye;
let mut points = Vec::new();
if dy1 <= dx1 {
if dx >= 0 {
x = x1;
y = y1;
xe = x2;
ye = y2;
} else {
x = x2;
y = y2;
xe = x1;
ye = y1;
}
self.draw_pixel_at(x, y);
points.push(Point::new(x, y));
while x < xe {
x += 1;
if px < 0 {
@@ -526,19 +541,21 @@ impl Paint {
}
px = px + 2 * (dy1 - dx1);
}
self.draw_pixel_at(x, y);
points.push(Point::new(x, y));
}
} else {
if dy >= 0 {
x = x1;
y = y1;
ye = y2;
xe = x2;
} else {
x = x2;
y = y2;
ye = y1;
xe = x1;
}
self.draw_pixel_at(x, y);
points.push(Point::new(x, y));
while y < ye {
y = y + 1;
if py <= 0 {
@@ -551,7 +568,36 @@ impl Paint {
}
py = py + 2 * (dx1 - dy1);
}
self.draw_pixel_at(x, y);
points.push(Point::new(x, y));
}
}
points.push(Point::new(xe, ye));
points
}
/// Bresenham's line drawing algorithm
fn draw_line(&mut self, begin: Point, end: Point) {
let points = self.bresenham_line(point_to_i32(begin), point_to_i32(end));
self.draw_pixels(points);
}
fn draw_line_thick(&mut self, begin: Point<i32>, end: Point<i32>, line_width: i32) {
if line_width <= 0 {
return;
}
let half = (line_width) / 2;
let points = self.bresenham_line(begin, end);
if line_width == 1 {
self.draw_pixels(points);
return;
}
for point in &points {
for dx in -half..=(line_width - 1 - half) {
for dy in -half..=(line_width - 1 - half) {
self.draw_pixel_at((point.x + dx), (point.y + dy));
}
}
}
}
@@ -727,10 +773,25 @@ impl Paint {
(iter_count, fill_count)
}
fn stroke_rect(&mut self, x: i32, y: i32, width: i32, height: i32, line_width: i32) {
self.draw_line_thick(Point::new(x, y), Point::new(x, y + height), line_width);
self.draw_line_thick(Point::new(x, y + height), Point::new(x + width, y + height), line_width);
self.draw_line_thick(Point::new(x + width, y + height), Point::new(x + width, y), line_width);
self.draw_line_thick(Point::new(x, y), Point::new(x + width, y), line_width);
}
fn stroke_rect1(&mut self, left_top: Point, right_bottom: Point, line_width: i32) {
let x = left_top.x as i32;
let y = left_top.y as i32;
let width = (right_bottom.x - left_top.x) as i32;
let height = (right_bottom.y - left_top.y) as i32;
self.stroke_rect(x, y, width, height, line_width);
}
}
pub fn main() -> iced::Result {
iced::application(Paint::new, Paint::update, Paint::view)
iced::application(PaintApp::new, PaintApp::update, PaintApp::view)
.theme(Theme::Dark)
.run()
}