refactor: improve code readability by formatting and restructuring function parameters and logic
mandatory-regression-gate / deterministic-tests (push) Waiting to run
mandatory-regression-gate / protected-performance-path (push) Waiting to run

This commit is contained in:
Your Name
2026-07-25 16:56:28 +03:00
parent 45a231a456
commit 683dac06ec
4 changed files with 127 additions and 59 deletions
+31 -8
View File
@@ -117,17 +117,25 @@ impl Engine {
if mask.len() != full_size { if mask.len() != full_size {
let mut full_mask = vec![layer.mask_default_color; full_size]; let mut full_mask = vec![layer.mask_default_color; full_size];
if let Some(mb) = layer.mask_bounds { if let Some(mb) = layer.mask_bounds {
let (m_top, m_left, m_bottom, m_right) = let (m_top, m_left, m_bottom, m_right) = (
(mb[0].max(0) as u32, mb[1].max(0) as u32, mb[2].max(0) as u32, mb[3].max(0) as u32); mb[0].max(0) as u32,
mb[1].max(0) as u32,
mb[2].max(0) as u32,
mb[3].max(0) as u32,
);
let mw = (m_right - m_left) as usize; let mw = (m_right - m_left) as usize;
let mh = (m_bottom - m_top) as usize; let mh = (m_bottom - m_top) as usize;
if mw > 0 && mh > 0 && mask.len() == mw * mh { if mw > 0 && mh > 0 && mask.len() == mw * mh {
for y in 0..mh { for y in 0..mh {
let gy = m_top as usize + y; let gy = m_top as usize + y;
if gy >= ch as usize { break; } if gy >= ch as usize {
break;
}
for x in 0..mw { for x in 0..mw {
let gx = m_left as usize + x; let gx = m_left as usize + x;
if gx >= cw as usize { break; } if gx >= cw as usize {
break;
}
full_mask[gy * cw as usize + gx] = mask[y * mw + x]; full_mask[gy * cw as usize + gx] = mask[y * mw + x];
} }
} }
@@ -181,7 +189,9 @@ impl Engine {
let cw = self.document.canvas_width as usize; let cw = self.document.canvas_width as usize;
let ch = self.document.canvas_height as usize; let ch = self.document.canvas_height as usize;
let mask_len = cw * ch; let mask_len = cw * ch;
if mask_len == 0 { return; } if mask_len == 0 {
return;
}
if let Some(layer) = self.document.get_layer_by_id_mut(layer_id) { if let Some(layer) = self.document.get_layer_by_id_mut(layer_id) {
if layer.mask_pixels.is_none() { if layer.mask_pixels.is_none() {
@@ -294,7 +304,13 @@ impl Engine {
self.draw_target_pixels_or_mask( self.draw_target_pixels_or_mask(
layer_id, layer_id,
|pixels, lw, lh, mask_ref, active_stroke_mask, stroke_before_buf, sketch_history| { |pixels,
lw,
lh,
mask_ref,
active_stroke_mask,
stroke_before_buf,
sketch_history| {
let sketch_hist = if tip.style == BrushStyle::Sketch { let sketch_hist = if tip.style == BrushStyle::Sketch {
sketch_history sketch_history
} else { } else {
@@ -361,8 +377,15 @@ impl Engine {
if self.editing_mask { if self.editing_mask {
self.draw_target_pixels_or_mask( self.draw_target_pixels_or_mask(
layer_id, layer_id,
|pixels, lw, lh, mask_ref, active_stroke_mask, stroke_before_buf, _sketch_history| { |pixels,
let mut temp_layer = hcie_protocol::Layer::from_rgba("temp", lw, lh, pixels.to_vec()); lw,
lh,
mask_ref,
active_stroke_mask,
stroke_before_buf,
_sketch_history| {
let mut temp_layer =
hcie_protocol::Layer::from_rgba("temp", lw, lh, pixels.to_vec());
draw_brush_stroke( draw_brush_stroke(
&mut temp_layer, &mut temp_layer,
&[(x, y, pressure)], &[(x, y, pressure)],
+27 -28
View File
@@ -2901,11 +2901,14 @@ impl HcieIcedApp {
let paint_tool = let paint_tool =
matches!(tool, Tool::Pen | Tool::Brush | Tool::Eraser | Tool::Spray); matches!(tool, Tool::Pen | Tool::Brush | Tool::Eraser | Tool::Spray);
if paint_tool && (self.modifiers.control() || self.modifiers.logo()) { if paint_tool && (self.modifiers.control() || self.modifiers.logo()) {
let cx = canvas_x as u32;
let cy = canvas_y as u32;
let width = self.documents[self.active_doc].engine.canvas_width(); let width = self.documents[self.active_doc].engine.canvas_width();
if cx < width && cy < self.documents[self.active_doc].engine.canvas_height() { let height = self.documents[self.active_doc].engine.canvas_height();
let index = ((cy * width + cx) * 4) as usize; if canvas_x >= 0.0
&& canvas_y >= 0.0
&& (canvas_x as u32) < width
&& (canvas_y as u32) < height
{
let index = ((canvas_y as u32 * width + canvas_x as u32) * 4) as usize;
if index + 3 < self.documents[self.active_doc].composite_raw.len() { if index + 3 < self.documents[self.active_doc].composite_raw.len() {
let pixels = &self.documents[self.active_doc].composite_raw; let pixels = &self.documents[self.active_doc].composite_raw;
let color = [ let color = [
@@ -3247,13 +3250,11 @@ impl HcieIcedApp {
let is_ctrl = self.modifiers.control() || self.modifiers.logo(); let is_ctrl = self.modifiers.control() || self.modifiers.logo();
if is_ctrl { if is_ctrl {
// Pick color // Pick color
let cx = x as u32;
let cy = y as u32;
let w = self.documents[self.active_doc].engine.canvas_width(); let w = self.documents[self.active_doc].engine.canvas_width();
let h = self.documents[self.active_doc].engine.canvas_height(); let h = self.documents[self.active_doc].engine.canvas_height();
if cx < w && cy < h { if x >= 0.0 && y >= 0.0 && (x as u32) < w && (y as u32) < h {
let pixels = &self.documents[self.active_doc].composite_raw; let pixels = &self.documents[self.active_doc].composite_raw;
let idx = ((cy * w + cx) * 4) as usize; let idx = ((y as u32 * w + x as u32) * 4) as usize;
if idx + 3 < pixels.len() { if idx + 3 < pixels.len() {
let color = [ let color = [
pixels[idx], pixels[idx],
@@ -3719,7 +3720,9 @@ impl HcieIcedApp {
} }
Message::LayerSetEditMask(editing) => { Message::LayerSetEditMask(editing) => {
self.documents[self.active_doc].engine.set_editing_mask(editing); self.documents[self.active_doc]
.engine
.set_editing_mask(editing);
self.documents[self.active_doc].cached_layers = self.documents[self.active_doc].cached_layers =
self.documents[self.active_doc].engine.layer_infos(); self.documents[self.active_doc].engine.layer_infos();
} }
@@ -6711,10 +6714,8 @@ impl HcieIcedApp {
self.settings.tool_settings.vector_angle = angle.to_degrees(); self.settings.tool_settings.vector_angle = angle.to_degrees();
// Track snap state for visual overlay feedback // Track snap state for visual overlay feedback
let is_rotate = matches!( let is_rotate =
session.handle, matches!(session.handle, hcie_engine_api::VectorEditHandle::Rotate);
hcie_engine_api::VectorEditHandle::Rotate
);
let is_resize = matches!( let is_resize = matches!(
session.handle, session.handle,
hcie_engine_api::VectorEditHandle::TopLeft hcie_engine_api::VectorEditHandle::TopLeft
@@ -7784,7 +7785,8 @@ impl HcieIcedApp {
} }
Message::PasteImage => { Message::PasteImage => {
// Check internal clipboard first // Check internal clipboard first
if let Some(transform) = self.documents[self.active_doc].internal_clipboard.clone() { if let Some(transform) = self.documents[self.active_doc].internal_clipboard.clone()
{
// Enter transform mode with the clipboard content // Enter transform mode with the clipboard content
let mut placed = transform; let mut placed = transform;
placed.pos.x += 10.0; placed.pos.x += 10.0;
@@ -8481,12 +8483,10 @@ impl HcieIcedApp {
return self.update(Message::OpenFileRfd); return self.update(Message::OpenFileRfd);
} }
Message::FileOpened(Ok(path)) => { Message::FileOpened(Ok(path)) => match self.open_path_in_new_tab(path, true) {
match self.open_path_in_new_tab(path, true) { Ok(_) => return Task::perform(async {}, |_| Message::CompositeRefresh),
Ok(_) => return Task::perform(async {}, |_| Message::CompositeRefresh), Err(error) => log::error!("Failed to open file: {error}"),
Err(error) => log::error!("Failed to open file: {error}"), },
}
}
Message::FileOpened(Err(e)) => { Message::FileOpened(Err(e)) => {
log::error!("Failed to open file: {}", e); log::error!("Failed to open file: {}", e);
@@ -9153,9 +9153,7 @@ impl HcieIcedApp {
| crate::theme::ThemePreset::ProDark | crate::theme::ThemePreset::ProDark
| crate::theme::ThemePreset::Amoled => crate::theme::ThemePreset::ProLight, | crate::theme::ThemePreset::Amoled => crate::theme::ThemePreset::ProLight,
crate::theme::ThemePreset::PhotoshopLight crate::theme::ThemePreset::PhotoshopLight
| crate::theme::ThemePreset::ProLight => { | crate::theme::ThemePreset::ProLight => crate::theme::ThemePreset::Photopea,
crate::theme::ThemePreset::Photopea
}
}; };
self.theme_state.set_preset(new_preset); self.theme_state.set_preset(new_preset);
self.settings.theme_preset = new_preset; self.settings.theme_preset = new_preset;
@@ -10308,10 +10306,8 @@ mod cycle_one_ux_tests {
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
.unwrap() .unwrap()
.as_nanos(); .as_nanos();
let path = std::env::temp_dir().join(format!( let path =
"hcie-open-tab-{}-{unique}.png", std::env::temp_dir().join(format!("hcie-open-tab-{}-{unique}.png", std::process::id()));
std::process::id()
));
image::save_buffer( image::save_buffer(
&path, &path,
&[255, 0, 0, 255, 0, 255, 0, 255], &[255, 0, 0, 255, 0, 255, 0, 255],
@@ -10328,7 +10324,10 @@ mod cycle_one_ux_tests {
assert_eq!(app.active_doc, 1); assert_eq!(app.active_doc, 1);
assert_eq!(app.documents[0].name, original_name); assert_eq!(app.documents[0].name, original_name);
assert!(app.documents[0].source_path.is_none()); assert!(app.documents[0].source_path.is_none());
assert_eq!(app.documents[1].source_path.as_deref(), Some(path.as_path())); assert_eq!(
app.documents[1].source_path.as_deref(),
Some(path.as_path())
);
assert_eq!(app.documents[1].engine.canvas_width(), 2); assert_eq!(app.documents[1].engine.canvas_width(), 2);
assert_eq!(app.documents[1].engine.canvas_height(), 1); assert_eq!(app.documents[1].engine.canvas_height(), 1);
@@ -985,8 +985,7 @@ fn should_publish_cursor_status(
current: (u32, u32), current: (u32, u32),
elapsed: Option<std::time::Duration>, elapsed: Option<std::time::Duration>,
) -> bool { ) -> bool {
previous != Some(current) previous != Some(current) && elapsed.map_or(true, |duration| duration >= CURSOR_STATUS_INTERVAL)
&& elapsed.map_or(true, |duration| duration >= CURSOR_STATUS_INTERVAL)
} }
/// Canvas shader program — implements `iced::widget::shader::Program`. /// Canvas shader program — implements `iced::widget::shader::Program`.
@@ -110,23 +110,44 @@ impl Program<Message> for CanvasViewportProgram {
let mut frame = Frame::new(bounds.size()); let mut frame = Frame::new(bounds.size());
// Draw checkerboard background (tiled to cover display area) // Draw checkerboard background (tiled to cover display area)
let checker_pattern = canvas::Pattern::new(&cfg.checker_handle).mode(canvas::PatternMode::Repeat); let checker_pattern =
let checker_path = Path::rectangle(Point::new(origin_x, origin_y), Size::new(display_w, display_h)); canvas::Pattern::new(&cfg.checker_handle).mode(canvas::PatternMode::Repeat);
let checker_path = Path::rectangle(
Point::new(origin_x, origin_y),
Size::new(display_w, display_h),
);
frame.fill(&checker_path, checker_pattern); frame.fill(&checker_path, checker_pattern);
// Draw composite texture // Draw composite texture
let composite_image = canvas::Image::new(&cfg.composite_handle) let composite_image =
.destination_rectangle(Rectangle::new(Point::new(origin_x, origin_y), Size::new(display_w, display_h))); canvas::Image::new(&cfg.composite_handle).destination_rectangle(Rectangle::new(
Point::new(origin_x, origin_y),
Size::new(display_w, display_h),
));
frame.draw_image(composite_image); frame.draw_image(composite_image);
// Draw canvas border // Draw canvas border
let border_path = Path::rectangle(Point::new(origin_x, origin_y), Size::new(display_w, display_h)); let border_path = Path::rectangle(
frame.stroke(&border_path, Stroke::default().with_color(Color::from_rgb(0.35, 0.35, 0.35)).with_width(1.0)); Point::new(origin_x, origin_y),
Size::new(display_w, display_h),
);
frame.stroke(
&border_path,
Stroke::default()
.with_color(Color::from_rgb(0.35, 0.35, 0.35))
.with_width(1.0),
);
vec![frame.into_geometry()] vec![frame.into_geometry()]
} }
fn update(&self, state: &mut (), event: iced::Event, bounds: Rectangle, cursor: Cursor) -> (iced::widget::canvas::Status, Option<Message>) { fn update(
&self,
state: &mut (),
event: iced::Event,
bounds: Rectangle,
cursor: Cursor,
) -> (iced::widget::canvas::Status, Option<Message>) {
let mut program_state = self.state.lock().unwrap(); let mut program_state = self.state.lock().unwrap();
match event { match event {
@@ -140,17 +161,22 @@ impl Program<Message> for CanvasViewportProgram {
iced::mouse::Event::ButtonPressed(iced::mouse::Button::Left) => { iced::mouse::Event::ButtonPressed(iced::mouse::Button::Left) => {
if let Some(pos) = program_state.last_cursor { if let Some(pos) = program_state.last_cursor {
if bounds.contains(pos) { if bounds.contains(pos) {
let (cx, cy) = viewport_to_canvas(pos, bounds, &program_state.config); let (cx, cy) =
viewport_to_canvas(pos, bounds, &program_state.config);
if let Some((cx, cy)) = (cx, cy) { if let Some((cx, cy)) = (cx, cy) {
return (iced::widget::canvas::Status::Captured, Some(Message::CanvasPointerPressed { x: cx, y: cy })); return (
iced::widget::canvas::Status::Captured,
Some(Message::CanvasPointerPressed { x: cx, y: cy }),
);
} }
} }
} }
(iced::widget::canvas::Status::Captured, None) (iced::widget::canvas::Status::Captured, None)
} }
iced::mouse::Event::ButtonReleased(iced::mouse::Button::Left) => { iced::mouse::Event::ButtonReleased(iced::mouse::Button::Left) => (
(iced::widget::canvas::Status::Captured, Some(Message::CanvasPointerReleased)) iced::widget::canvas::Status::Captured,
} Some(Message::CanvasPointerReleased),
),
iced::mouse::Event::Scrolled { delta } => { iced::mouse::Event::Scrolled { delta } => {
if program_state.is_hovered { if program_state.is_hovered {
let scroll_delta = match delta { let scroll_delta = match delta {
@@ -164,7 +190,12 @@ impl Program<Message> for CanvasViewportProgram {
let new_zoom = (old_zoom * factor).clamp(0.1, 10.0); let new_zoom = (old_zoom * factor).clamp(0.1, 10.0);
if let Some(cursor_pos) = program_state.last_cursor { if let Some(cursor_pos) = program_state.last_cursor {
let (canvas_x, canvas_y) = viewport_to_canvas(cursor_pos, bounds, &program_state.config).unwrap_or((0.0, 0.0)); let (canvas_x, canvas_y) = viewport_to_canvas(
cursor_pos,
bounds,
&program_state.config,
)
.unwrap_or((0.0, 0.0));
// Calculate new pan_offset to keep cursor over same canvas point // Calculate new pan_offset to keep cursor over same canvas point
let display_w = program_state.config.engine_w as f32 * new_zoom; let display_w = program_state.config.engine_w as f32 * new_zoom;
@@ -174,11 +205,18 @@ impl Program<Message> for CanvasViewportProgram {
let new_default_origin_x = (bounds.width - display_w) / 2.0; let new_default_origin_x = (bounds.width - display_w) / 2.0;
let new_default_origin_y = (bounds.height - display_h) / 2.0; let new_default_origin_y = (bounds.height - display_h) / 2.0;
program_state.config.pan_offset.x = new_origin_x - new_default_origin_x; program_state.config.pan_offset.x =
program_state.config.pan_offset.y = new_origin_y - new_default_origin_y; new_origin_x - new_default_origin_x;
program_state.config.pan_offset.y =
new_origin_y - new_default_origin_y;
} }
program_state.config.zoom = new_zoom; program_state.config.zoom = new_zoom;
return (iced::widget::canvas::Status::Captured, Some(Message::CanvasZoom { delta: scroll_delta })); return (
iced::widget::canvas::Status::Captured,
Some(Message::CanvasZoom {
delta: scroll_delta,
}),
);
} }
} }
(iced::widget::canvas::Status::Ignored, None) (iced::widget::canvas::Status::Ignored, None)
@@ -190,7 +228,12 @@ impl Program<Message> for CanvasViewportProgram {
} }
} }
fn mouse_interaction(&self, _state: &(), bounds: Rectangle, cursor: Cursor) -> iced::mouse::Interaction { fn mouse_interaction(
&self,
_state: &(),
bounds: Rectangle,
cursor: Cursor,
) -> iced::mouse::Interaction {
if cursor.is_over(bounds) { if cursor.is_over(bounds) {
iced::mouse::Interaction::Crosshair iced::mouse::Interaction::Crosshair
} else { } else {
@@ -203,7 +246,11 @@ impl Program<Message> for CanvasViewportProgram {
/// ///
/// Returns signed canvas coordinates even when the cursor is outside the canvas /// Returns signed canvas coordinates even when the cursor is outside the canvas
/// image so brush strokes can start or continue beyond the visible edges. /// image so brush strokes can start or continue beyond the visible edges.
fn viewport_to_canvas(viewport_pos: Point, bounds: Rectangle, config: &CanvasViewportConfig) -> Option<(f32, f32)> { fn viewport_to_canvas(
viewport_pos: Point,
bounds: Rectangle,
config: &CanvasViewportConfig,
) -> Option<(f32, f32)> {
let display_w = config.engine_w as f32 * config.zoom; let display_w = config.engine_w as f32 * config.zoom;
let display_h = config.engine_h as f32 * config.zoom; let display_h = config.engine_h as f32 * config.zoom;