Files
hcie-rust-v3.05/hcie-iced-app/crates/hcie-iced-gui/src/app/transform_dirty.rs
T
phantom a2846d8b3a 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.
2026-07-18 20:31:31 +03:00

87 lines
3.3 KiB
Rust

//! Selection-transform preview invalidation utilities.
//!
//! **Purpose:** Computes canvas-clipped dirty bounds for floating selection
//! previews so both their previous and current positions can be uploaded to the
//! persistent GPU texture during interactive movement.
//!
//! **Logic & Workflow:** Preview geometry is rounded exactly like the CPU
//! compositor, clamped to the canvas origin, and clipped at the right and
//! bottom canvas edges. Empty or fully out-of-canvas rectangles return `None`.
//!
//! **Side Effects / Dependencies:** The module is deterministic and has no I/O,
//! global state, allocation, engine dependency, or GPU dependency.
/// Calculates the clipped pixel bounds occupied by a transform preview.
///
/// **Purpose:** Produces the dirty rectangle that must be restored or redrawn
/// when a floating selection changes position or dimensions.
///
/// **Logic & Workflow:** Delegates to the shared rotated-corner AABB calculation
/// used by both preview and apply, clips it to the canvas, and rejects empty rectangles.
///
/// **Arguments:**
/// - `transform`: Floating selection source and affine geometry.
/// - `canvas_width`, `canvas_height`: Clipping dimensions of the document.
///
/// **Returns:** `Some([x0, y0, x1, y1])` for a non-empty clipped rectangle, or
/// `None` when the preview cannot affect the canvas.
///
/// **Side Effects / Dependencies:** None.
pub(crate) fn preview_bounds(
transform: &crate::selection::SelectionTransform,
canvas_width: u32,
canvas_height: u32,
) -> Option<[u32; 4]> {
crate::selection::transform::transformed_bounds(transform, canvas_width, canvas_height)
}
#[cfg(test)]
mod tests {
use crate::selection::SelectionTransform;
use iced::Vector;
use super::preview_bounds;
fn transform(x: f32, y: f32) -> SelectionTransform {
SelectionTransform {
pixels: vec![255; 30 * 40 * 4],
width: 30,
height: 40,
pos: Vector::new(x, y),
size: Vector::new(30.0, 40.0),
rotation: 0.0,
}
}
/// Verifies that consecutive preview positions expose both the old and new
/// rectangles needed by the caller's dirty-region union.
///
/// **Purpose:** Guards against stale GPU pixels remaining at an old drag
/// position when only the current preview rectangle is uploaded.
///
/// **Logic & Workflow:** Computes two partially overlapping positions and
/// confirms their bounds preserve the complete restoration/redraw extent.
///
/// **Arguments & Returns:** Takes no arguments and returns nothing;
/// assertion failures identify incorrect transform bounds.
///
/// **Side Effects / Dependencies:** None.
#[test]
fn consecutive_positions_retain_old_and_new_extents() {
let previous = preview_bounds(&transform(10.0, 20.0), 100, 100).unwrap();
let current = preview_bounds(&transform(25.0, 30.0), 100, 100).unwrap();
assert_eq!(previous, [10, 20, 40, 60]);
assert_eq!(current, [25, 30, 55, 70]);
assert_eq!(
[
previous[0].min(current[0]),
previous[1].min(current[1]),
previous[2].max(current[2]),
previous[3].max(current[3]),
],
[10, 20, 55, 70],
);
}
}