feat: Implement rectangle
This commit is contained in:
143
src/paint.rs
143
src/paint.rs
@@ -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();
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user