A GOOD MILESTONE : Refactor title bar and toolbar typography, improve tooltip styles, and enhance selection transform functionality

- Updated typography constants for menu bar and tooltips to improve readability and consistency.
- Adjusted button padding and widths in the title bar for better layout.
- Replaced tooltip implementation with a new balloon tooltip style for improved visual feedback.
- Enhanced selection transform logic to support rotation and resizing, ensuring accurate hit testing and bounds calculations.
- Added tests for selection clearing and transformed bounds to ensure functionality and prevent regressions.
- Introduced a new module for managing selection transform dirty bounds during interactive previews.
This commit is contained in:
2026-07-18 20:31:31 +03:00
parent b2c88e5471
commit a2846d8b3a
16 changed files with 1361 additions and 526 deletions
+56 -4
View File
@@ -3400,11 +3400,32 @@ impl Engine {
}
/// Clear pixels only within the active selection mask. If no selection, clears all.
/// Records a full-layer draw snapshot so the operation is undoable.
pub fn clear_selection_pixels(&mut self) {
let mask = self.cached_selection_mask.clone();
let mask = self.document.selection_mask.clone();
let active_idx = self.document.active_layer;
log::debug!(
"[Engine::clear_selection_pixels] active_layer={}, selection_active={}, document_mask_len={:?}, stroke_cache_mask_len={:?}",
active_idx,
self.document.selection_active,
mask.as_ref().map(Vec::len),
self.cached_selection_mask.as_ref().map(Vec::len),
);
if let Some(ref mask_data) = mask {
let w = self.document.canvas_width as usize;
let h = self.document.canvas_height as usize;
let selected_pixels = mask_data.iter().filter(|coverage| **coverage > 0).count();
log::debug!(
"[Engine::clear_selection_pixels] clearing selected region: canvas={}x{}, selected_pixels={}",
w,
h,
selected_pixels,
);
let before_pixels = self
.document
.active_layer()
.map(|layer| layer.pixels.clone())
.unwrap_or_default();
if let Some(layer) = self.document.active_layer_mut() {
for y in 0..h {
for x in 0..w {
@@ -3418,14 +3439,45 @@ impl Engine {
}
}
layer.dirty = true;
self.document.composite_dirty = true;
self.document.modified = true;
}
self.document.push_draw_snapshot(
active_idx,
before_pixels,
None,
"Clear Selection".to_string(),
);
self.document.composite_dirty = true;
self.document.modified = true;
} else {
self.clear_active_layer_pixels();
log::debug!(
"[Engine::clear_selection_pixels] no active document mask; clearing the entire active layer"
);
self.clear_active_layer_pixels_undoable();
}
}
/// Clears the entire active layer and records an undo snapshot.
pub fn clear_active_layer_pixels_undoable(&mut self) {
let active_idx = self.document.active_layer;
let before_pixels = self
.document
.active_layer()
.map(|layer| layer.pixels.clone())
.unwrap_or_default();
if let Some(layer) = self.document.active_layer_mut() {
layer.pixels.fill(0);
layer.dirty = true;
}
self.document.push_draw_snapshot(
active_idx,
before_pixels,
None,
"Clear Layer".to_string(),
);
self.document.composite_dirty = true;
self.document.modified = true;
}
pub fn set_active_layer_pixels(&mut self, pixels: Vec<u8>) {
if let Some(layer) = self.document.active_layer_mut() {
layer.pixels = pixels;