mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 21:48:12 +08:00
handle negative correctly,fix undo redo and abort
This commit is contained in:
@@ -127,7 +127,7 @@ pub const POINT_RADIUS_HANDLE_SEGMENT_THRESHOLD: f64 = 7.9;
|
|||||||
pub const NUMBER_OF_POINTS_DIAL_SPOKE_EXTENSION: f64 = 1.2;
|
pub const NUMBER_OF_POINTS_DIAL_SPOKE_EXTENSION: f64 = 1.2;
|
||||||
pub const NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH: f64 = 10.;
|
pub const NUMBER_OF_POINTS_DIAL_SPOKE_LENGTH: f64 = 10.;
|
||||||
pub const GIZMO_HIDE_THRESHOLD: f64 = 20.;
|
pub const GIZMO_HIDE_THRESHOLD: f64 = 20.;
|
||||||
pub const GRID_ROW_COLUMN_GIZMO_OFFSET: f64 = 10.;
|
pub const GRID_ROW_COLUMN_GIZMO_OFFSET: f64 = 15.;
|
||||||
|
|
||||||
// SCROLLBARS
|
// SCROLLBARS
|
||||||
pub const SCROLLBAR_SPACING: f64 = 0.1;
|
pub const SCROLLBAR_SPACING: f64 = 0.1;
|
||||||
|
|||||||
@@ -518,7 +518,7 @@ impl<'a> Selected<'a> {
|
|||||||
pen_handle: Option<&'a mut DVec2>,
|
pen_handle: Option<&'a mut DVec2>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// If user is using the Select tool then use the original layer transforms
|
// If user is using the Select tool then use the original layer transforms
|
||||||
if (*tool_type == ToolType::Select) && (*original_transforms == OriginalTransforms::Path(HashMap::new())) {
|
if (*tool_type == ToolType::Select || *tool_type == ToolType::Shape) && (*original_transforms == OriginalTransforms::Path(HashMap::new())) {
|
||||||
*original_transforms = OriginalTransforms::Layer(HashMap::new());
|
*original_transforms = OriginalTransforms::Layer(HashMap::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+169
-163
@@ -25,121 +25,6 @@ pub enum RowColumnGizmoState {
|
|||||||
Dragging,
|
Dragging,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
|
||||||
pub enum RowColumnGizmoType {
|
|
||||||
#[default]
|
|
||||||
None,
|
|
||||||
Top,
|
|
||||||
Down,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RowColumnGizmoType {
|
|
||||||
pub fn get_line_points(&self, grid_type: GridType, columns: u32, rows: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
|
||||||
match grid_type {
|
|
||||||
GridType::Rectangular => match self {
|
|
||||||
Self::Top => get_rectangle_top_line_points(columns, rows, spacing),
|
|
||||||
Self::Right => get_rectangle_right_line_points(columns, rows, spacing),
|
|
||||||
Self::Down => get_rectangle_bottom_line_points(columns, rows, spacing),
|
|
||||||
Self::Left => get_rectangle_left_line_points(columns, rows, spacing),
|
|
||||||
Self::None => panic!("RowColumnGizmoType::None does not have line points"),
|
|
||||||
},
|
|
||||||
GridType::Isometric => match self {
|
|
||||||
Self::Top => calculate_isometric_top_line_points(columns, spacing, angles),
|
|
||||||
Self::Right => calculate_isometric_right_line_points(columns, rows, spacing, angles),
|
|
||||||
Self::Down => calculate_isometric_bottom_line_points(columns, rows, spacing, angles),
|
|
||||||
Self::Left => calculate_isometric_left_line_points(rows, spacing, angles),
|
|
||||||
Self::None => panic!("RowColumnGizmoType::None does not have line points"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn line(&self, grid_type: GridType, columns: u32, rows: u32, spacing: DVec2, angles: DVec2, viewport: DAffine2) -> Line {
|
|
||||||
let (p0, p1) = self.get_line_points(grid_type, columns, rows, spacing, angles);
|
|
||||||
convert_to_gizmo_line(viewport.transform_point2(p0), viewport.transform_point2(p1))
|
|
||||||
}
|
|
||||||
fn opposite(&self, grid_type: GridType, columns: u32, rows: u32, spacing: DVec2, angles: DVec2, viewport: DAffine2) -> Line {
|
|
||||||
let opposite_gizmo_type = match self {
|
|
||||||
Self::Top => Self::Down,
|
|
||||||
Self::Right => Self::Left,
|
|
||||||
Self::Down => Self::Top,
|
|
||||||
Self::Left => Self::Right,
|
|
||||||
Self::None => panic!("RowColumnGizmoType::None does not have opposite"),
|
|
||||||
};
|
|
||||||
|
|
||||||
opposite_gizmo_type.line(grid_type, columns, rows, spacing, angles, viewport)
|
|
||||||
}
|
|
||||||
fn direction(&self, grid_type: GridType, columns: u32, rows: u32, spacing: DVec2, angles: DVec2, viewport: DAffine2) -> DVec2 {
|
|
||||||
match self {
|
|
||||||
RowColumnGizmoType::Top => {
|
|
||||||
if grid_type == GridType::Rectangular {
|
|
||||||
calculate_rectangle_top_direction(columns, rows, spacing, viewport)
|
|
||||||
} else {
|
|
||||||
-calculate_isometric_top_direction(angles, spacing, Some(viewport))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RowColumnGizmoType::Down => {
|
|
||||||
if grid_type == GridType::Rectangular {
|
|
||||||
-calculate_rectangle_top_direction(columns, rows, spacing, viewport)
|
|
||||||
} else {
|
|
||||||
calculate_isometric_top_direction(angles, spacing, Some(viewport))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RowColumnGizmoType::Right => {
|
|
||||||
if grid_type == GridType::Rectangular {
|
|
||||||
calculate_rectangle_side_direction(columns, rows, spacing, viewport)
|
|
||||||
} else {
|
|
||||||
calculate_isometric_side_direction(angles, spacing, Some(viewport))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RowColumnGizmoType::Left => {
|
|
||||||
if grid_type == GridType::Rectangular {
|
|
||||||
-calculate_rectangle_side_direction(columns, rows, spacing, viewport)
|
|
||||||
} else {
|
|
||||||
-calculate_isometric_side_direction(angles, spacing, Some(viewport))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a line"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn initial_dimension(&self, rows: u32, columns: u32) -> u32 {
|
|
||||||
match self {
|
|
||||||
RowColumnGizmoType::Top | RowColumnGizmoType::Down => rows,
|
|
||||||
RowColumnGizmoType::Right | RowColumnGizmoType::Left => columns,
|
|
||||||
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a mouse_icon"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spacing(&self, spacing: DVec2) -> f64 {
|
|
||||||
match self {
|
|
||||||
RowColumnGizmoType::Top | RowColumnGizmoType::Down => spacing.y,
|
|
||||||
RowColumnGizmoType::Right | RowColumnGizmoType::Left => spacing.x,
|
|
||||||
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a mouse_icon"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn index(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
RowColumnGizmoType::Top | RowColumnGizmoType::Down => GRID_ROW_INDEX,
|
|
||||||
RowColumnGizmoType::Right | RowColumnGizmoType::Left => GRID_COLUMNS_INDEX,
|
|
||||||
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a mouse_icon"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mouse_icon(&self) -> MouseCursorIcon {
|
|
||||||
match self {
|
|
||||||
RowColumnGizmoType::Top | RowColumnGizmoType::Down => MouseCursorIcon::NSResize,
|
|
||||||
RowColumnGizmoType::Right | RowColumnGizmoType::Left => MouseCursorIcon::EWResize,
|
|
||||||
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a mouse_icon"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn all() -> [Self; 4] {
|
|
||||||
[Self::Top, Self::Right, Self::Down, Self::Left]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct RowColumnGizmo {
|
pub struct RowColumnGizmo {
|
||||||
pub layer: Option<LayerNodeIdentifier>,
|
pub layer: Option<LayerNodeIdentifier>,
|
||||||
@@ -147,12 +32,15 @@ pub struct RowColumnGizmo {
|
|||||||
initial_rows: u32,
|
initial_rows: u32,
|
||||||
initial_columns: u32,
|
initial_columns: u32,
|
||||||
spacing: DVec2,
|
spacing: DVec2,
|
||||||
|
initial_mouse_start: Option<DVec2>,
|
||||||
gizmo_state: RowColumnGizmoState,
|
gizmo_state: RowColumnGizmoState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RowColumnGizmo {
|
impl RowColumnGizmo {
|
||||||
pub fn cleanup(&mut self) {
|
pub fn cleanup(&mut self) {
|
||||||
self.layer = None;
|
self.layer = None;
|
||||||
|
self.gizmo_state = RowColumnGizmoState::Inactive;
|
||||||
|
self.initial_mouse_start = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_state(&mut self, state: RowColumnGizmoState) {
|
pub fn update_state(&mut self, state: RowColumnGizmoState) {
|
||||||
@@ -186,6 +74,7 @@ impl RowColumnGizmo {
|
|||||||
self.initial_rows = rows;
|
self.initial_rows = rows;
|
||||||
self.initial_columns = columns;
|
self.initial_columns = columns;
|
||||||
self.spacing = spacing;
|
self.spacing = spacing;
|
||||||
|
self.initial_mouse_start = None;
|
||||||
self.update_state(RowColumnGizmoState::Hover);
|
self.update_state(RowColumnGizmoState::Hover);
|
||||||
responses.add(FrontendMessage::UpdateMouseCursor { cursor: self.gizmo_type.mouse_icon() });
|
responses.add(FrontendMessage::UpdateMouseCursor { cursor: self.gizmo_type.mouse_icon() });
|
||||||
}
|
}
|
||||||
@@ -199,8 +88,7 @@ impl RowColumnGizmo {
|
|||||||
let viewport = document.metadata().transform_to_viewport(layer);
|
let viewport = document.metadata().transform_to_viewport(layer);
|
||||||
|
|
||||||
if !matches!(self.gizmo_state, RowColumnGizmoState::Inactive) {
|
if !matches!(self.gizmo_state, RowColumnGizmoState::Inactive) {
|
||||||
let (p0, p1) = self.gizmo_type.get_line_points(grid_type, columns, rows, spacing, angles);
|
let line = self.gizmo_type.line(grid_type, columns, rows, spacing, angles, viewport);
|
||||||
let line = convert_to_gizmo_line(viewport.transform_point2(p0), viewport.transform_point2(p1));
|
|
||||||
let (p0, p1) = get_line_endpoints(line);
|
let (p0, p1) = get_line_endpoints(line);
|
||||||
overlay_context.dashed_line(p0, p1, None, None, Some(5.), Some(5.), Some(0.5));
|
overlay_context.dashed_line(p0, p1, None, None, Some(5.), Some(5.), Some(0.5));
|
||||||
|
|
||||||
@@ -212,15 +100,15 @@ impl RowColumnGizmo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>, drag_start: DVec2) {
|
pub fn update(&mut self, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, responses: &mut VecDeque<Message>, drag_start: DVec2) {
|
||||||
let Some(layer) = self.layer else { return };
|
let Some(layer) = self.layer else { return };
|
||||||
let viewport = document.metadata().transform_to_viewport(layer);
|
let viewport = document.metadata().transform_to_viewport(layer);
|
||||||
|
|
||||||
let Some((grid_type, spacing, columns, rows, angles)) = extract_grid_parameters(layer, document) else {
|
let Some((grid_type, spacing, columns, rows, angles)) = extract_grid_parameters(layer, document) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let direction = self.gizmo_type.direction(grid_type, columns, rows, spacing, angles, viewport);
|
let direction = self.gizmo_type.direction(grid_type, spacing, angles, viewport);
|
||||||
let delta_vector = input.mouse.position - drag_start;
|
let delta_vector = input.mouse.position - self.initial_mouse_start.unwrap_or(drag_start);
|
||||||
|
|
||||||
let viewport_spacing = get_viewport_grid_spacing(grid_type, angles, self.spacing, viewport);
|
let viewport_spacing = get_viewport_grid_spacing(grid_type, angles, self.spacing, viewport);
|
||||||
let delta = delta_vector.dot(direction);
|
let delta = delta_vector.dot(direction);
|
||||||
@@ -233,7 +121,7 @@ impl RowColumnGizmo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let dimensions_delta = new_dimension as i32 - self.gizmo_type.initial_dimension(rows, columns) as i32;
|
let dimensions_delta = new_dimension as i32 - self.gizmo_type.initial_dimension(rows, columns) as i32;
|
||||||
let transform = self.transform_grid(dimensions_delta, grid_type, columns, rows, viewport_spacing, angles, viewport);
|
let transform = self.transform_grid(dimensions_delta, grid_type, viewport_spacing, angles, viewport);
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SetInput {
|
responses.add(NodeGraphMessage::SetInput {
|
||||||
input_connector: InputConnector::node(node_id, self.gizmo_type.index()),
|
input_connector: InputConnector::node(node_id, self.gizmo_type.index()),
|
||||||
@@ -248,16 +136,23 @@ impl RowColumnGizmo {
|
|||||||
});
|
});
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
|
|
||||||
|
if self.initial_dimension() as i32 + dimensions_to_add < 1 {
|
||||||
|
self.initial_mouse_start = Some(input.mouse.position);
|
||||||
|
self.gizmo_type = self.gizmo_type.opposite_gizmo_type();
|
||||||
|
self.initial_rows = 1;
|
||||||
|
self.initial_columns = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_grid(&self, dimensions_delta: i32, grid_type: GridType, columns: u32, rows: u32, spacing: DVec2, angles: DVec2, viewport: DAffine2) -> DAffine2 {
|
fn transform_grid(&self, dimensions_delta: i32, grid_type: GridType, spacing: DVec2, angles: DVec2, viewport: DAffine2) -> DAffine2 {
|
||||||
match self.gizmo_type {
|
match self.gizmo_type {
|
||||||
RowColumnGizmoType::Top => {
|
RowColumnGizmoType::Top => {
|
||||||
let move_up_by = self.gizmo_type.direction(grid_type, columns, rows, spacing, angles, viewport) * dimensions_delta as f64 * spacing.y;
|
let move_up_by = self.gizmo_type.direction(grid_type, spacing, angles, viewport) * dimensions_delta as f64 * spacing.y;
|
||||||
DAffine2::from_translation(move_up_by)
|
DAffine2::from_translation(move_up_by)
|
||||||
}
|
}
|
||||||
RowColumnGizmoType::Left => {
|
RowColumnGizmoType::Left => {
|
||||||
let move_left_by = self.gizmo_type.direction(grid_type, columns, rows, spacing, angles, viewport) * dimensions_delta as f64 * spacing.x;
|
let move_left_by = self.gizmo_type.direction(grid_type, spacing, angles, viewport) * dimensions_delta as f64 * spacing.x;
|
||||||
DAffine2::from_translation(move_left_by)
|
DAffine2::from_translation(move_left_by)
|
||||||
}
|
}
|
||||||
RowColumnGizmoType::Down | RowColumnGizmoType::Right | RowColumnGizmoType::None => DAffine2::IDENTITY,
|
RowColumnGizmoType::Down | RowColumnGizmoType::Right | RowColumnGizmoType::None => DAffine2::IDENTITY,
|
||||||
@@ -330,38 +225,30 @@ fn get_viewport_grid_spacing(grid_type: GridType, angles: DVec2, spacing: DVec2,
|
|||||||
|
|
||||||
fn get_rectangle_top_line_points(columns: u32, rows: u32, spacing: DVec2) -> (DVec2, DVec2) {
|
fn get_rectangle_top_line_points(columns: u32, rows: u32, spacing: DVec2) -> (DVec2, DVec2) {
|
||||||
let (top_left, top_right, _, _) = get_corners(columns, rows, spacing);
|
let (top_left, top_right, _, _) = get_corners(columns, rows, spacing);
|
||||||
|
let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(spacing.x * 0.5, 0.) };
|
||||||
|
|
||||||
let offset = DVec2::new(spacing.x * 0.25, 0.);
|
(top_left + offset, top_right - offset)
|
||||||
let spacing_offset = DVec2::new(0., -GRID_ROW_COLUMN_GIZMO_OFFSET);
|
|
||||||
|
|
||||||
(top_left + offset + spacing_offset, top_right - offset + spacing_offset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rectangle_bottom_line_points(columns: u32, rows: u32, spacing: DVec2) -> (DVec2, DVec2) {
|
fn get_rectangle_bottom_line_points(columns: u32, rows: u32, spacing: DVec2) -> (DVec2, DVec2) {
|
||||||
let (_, _, bottom_right, bottom_left) = get_corners(columns, rows, spacing);
|
let (_, _, bottom_right, bottom_left) = get_corners(columns, rows, spacing);
|
||||||
|
let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(spacing.x * 0.5, 0.) };
|
||||||
|
|
||||||
let offset = DVec2::new(spacing.x * 0.25, 0.);
|
(bottom_left + offset, bottom_right - offset)
|
||||||
let spacing_offset = DVec2::new(0., GRID_ROW_COLUMN_GIZMO_OFFSET);
|
|
||||||
|
|
||||||
(bottom_left + offset + spacing_offset, bottom_right - offset + spacing_offset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rectangle_right_line_points(columns: u32, rows: u32, spacing: DVec2) -> (DVec2, DVec2) {
|
fn get_rectangle_right_line_points(columns: u32, rows: u32, spacing: DVec2) -> (DVec2, DVec2) {
|
||||||
let (_, top_right, bottom_right, _) = get_corners(columns, rows, spacing);
|
let (_, top_right, bottom_right, _) = get_corners(columns, rows, spacing);
|
||||||
|
let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(0., -spacing.y * 0.5) };
|
||||||
|
|
||||||
let offset = DVec2::new(0., -spacing.y * 0.25);
|
(top_right - offset, bottom_right + offset)
|
||||||
let spacing_offset = DVec2::new(GRID_ROW_COLUMN_GIZMO_OFFSET, 0.);
|
|
||||||
|
|
||||||
(top_right - offset + spacing_offset, bottom_right + offset + spacing_offset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rectangle_left_line_points(columns: u32, rows: u32, spacing: DVec2) -> (DVec2, DVec2) {
|
fn get_rectangle_left_line_points(columns: u32, rows: u32, spacing: DVec2) -> (DVec2, DVec2) {
|
||||||
let (top_left, _, _, bottom_left) = get_corners(columns, rows, spacing);
|
let (top_left, _, _, bottom_left) = get_corners(columns, rows, spacing);
|
||||||
let offset = DVec2::new(0., -spacing.y * 0.25);
|
let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(0., -spacing.y * 0.5) };
|
||||||
|
|
||||||
let spacing_offset = DVec2::new(GRID_ROW_COLUMN_GIZMO_OFFSET, 0.);
|
(top_left - offset, bottom_left + offset)
|
||||||
|
|
||||||
(top_left - offset - spacing_offset, bottom_left + offset - spacing_offset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_isometric_point(column: u32, row: u32, angles: DVec2, spacing: DVec2) -> DVec2 {
|
fn calculate_isometric_point(column: u32, row: u32, angles: DVec2, spacing: DVec2) -> DVec2 {
|
||||||
@@ -378,33 +265,31 @@ fn calculate_isometric_point(column: u32, row: u32, angles: DVec2, spacing: DVec
|
|||||||
DVec2::new(spacing.x * column as f64, spacing.y * row as f64 + offset_y_fraction * spacing.x)
|
DVec2::new(spacing.x * column as f64, spacing.y * row as f64 + offset_y_fraction * spacing.x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_isometric_top_line_points(columns: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
fn calculate_isometric_top_line_points(columns: u32, rows: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
||||||
let top_left = calculate_isometric_point(0, 0, angles, spacing);
|
let top_left = calculate_isometric_point(0, 0, angles, spacing);
|
||||||
let top_right = calculate_isometric_point(columns - 1, 0, angles, spacing);
|
let top_right = calculate_isometric_point(columns - 1, 0, angles, spacing);
|
||||||
|
|
||||||
let offset = DVec2::new(spacing.x * 0.25, 0.);
|
let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(spacing.x * 0.5, 0.) };
|
||||||
let isometric_spacing = calculate_isometric_offset(spacing, angles);
|
let isometric_spacing = calculate_isometric_offset(spacing, angles);
|
||||||
let isometric_offset = DVec2::new(0., isometric_spacing.y);
|
let isometric_offset = DVec2::new(0., isometric_spacing.y);
|
||||||
let end_isometric_offset = if columns % 2 == 0 { DVec2::ZERO } else { DVec2::new(0., isometric_spacing.y) };
|
let end_isometric_offset = if columns % 2 == 0 { DVec2::ZERO } else { DVec2::new(0., isometric_spacing.y) };
|
||||||
let spacing_offset = DVec2::new(0., -GRID_ROW_COLUMN_GIZMO_OFFSET);
|
|
||||||
|
|
||||||
(top_left + offset + spacing_offset - isometric_offset, top_right - offset + spacing_offset - end_isometric_offset)
|
(top_left + offset - isometric_offset, top_right - offset - end_isometric_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_isometric_bottom_line_points(columns: u32, rows: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
fn calculate_isometric_bottom_line_points(columns: u32, rows: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
||||||
let bottom_left = calculate_isometric_point(0, rows - 1, angles, spacing);
|
let bottom_left = calculate_isometric_point(0, rows - 1, angles, spacing);
|
||||||
let bottom_right = calculate_isometric_point(columns - 1, rows - 1, angles, spacing);
|
let bottom_right = calculate_isometric_point(columns - 1, rows - 1, angles, spacing);
|
||||||
|
|
||||||
let offset = DVec2::new(spacing.x * 0.25, 0.);
|
let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(spacing.x * 0.5, 0.) };
|
||||||
let isometric_offset = if columns % 2 == 0 {
|
let isometric_offset = if columns % 2 == 0 {
|
||||||
let offset = calculate_isometric_offset(spacing, angles);
|
let offset = calculate_isometric_offset(spacing, angles);
|
||||||
DVec2::new(0., offset.y)
|
DVec2::new(0., offset.y)
|
||||||
} else {
|
} else {
|
||||||
DVec2::ZERO
|
DVec2::ZERO
|
||||||
};
|
};
|
||||||
let spacing_offset = DVec2::new(0., GRID_ROW_COLUMN_GIZMO_OFFSET);
|
|
||||||
|
|
||||||
(bottom_left + offset + spacing_offset, bottom_right - offset + spacing_offset + isometric_offset)
|
(bottom_left + offset, bottom_right - offset + isometric_offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_isometric_offset(spacing: DVec2, angles: DVec2) -> DVec2 {
|
fn calculate_isometric_offset(spacing: DVec2, angles: DVec2) -> DVec2 {
|
||||||
@@ -417,34 +302,31 @@ fn calculate_isometric_offset(spacing: DVec2, angles: DVec2) -> DVec2 {
|
|||||||
fn calculate_isometric_right_line_points(columns: u32, rows: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
fn calculate_isometric_right_line_points(columns: u32, rows: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
||||||
let top_right = calculate_isometric_point(columns - 1, 0, angles, spacing);
|
let top_right = calculate_isometric_point(columns - 1, 0, angles, spacing);
|
||||||
let bottom_right = calculate_isometric_point(columns - 1, rows - 1, angles, spacing);
|
let bottom_right = calculate_isometric_point(columns - 1, rows - 1, angles, spacing);
|
||||||
let side_direction = calculate_isometric_side_direction(angles, spacing, None);
|
|
||||||
|
|
||||||
let offset = DVec2::new(0., -spacing.y * 0.25);
|
let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(0., -spacing.y * 0.5) };
|
||||||
let spacing_offset = GRID_ROW_COLUMN_GIZMO_OFFSET * side_direction;
|
|
||||||
|
|
||||||
(top_right - offset + spacing_offset, bottom_right + offset + spacing_offset)
|
(top_right - offset, bottom_right + offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_isometric_left_line_points(rows: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
fn calculate_isometric_left_line_points(columns: u32, rows: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
||||||
let top_left = calculate_isometric_point(0, 0, angles, spacing);
|
let top_left = calculate_isometric_point(0, 0, angles, spacing);
|
||||||
let bottom_left = calculate_isometric_point(0, rows - 1, angles, spacing);
|
let bottom_left = calculate_isometric_point(0, rows - 1, angles, spacing);
|
||||||
let side_direction = calculate_isometric_side_direction(angles, spacing, None);
|
|
||||||
|
|
||||||
let offset = DVec2::new(0., -spacing.y * 0.25);
|
let offset = if columns == 1 || rows == 1 { DVec2::ZERO } else { DVec2::new(0., -spacing.y * 0.5) };
|
||||||
let spacing_offset = GRID_ROW_COLUMN_GIZMO_OFFSET * side_direction;
|
|
||||||
|
|
||||||
(top_left - offset - spacing_offset, bottom_left + offset - spacing_offset)
|
(top_left - offset, bottom_left + offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_rectangle_side_direction(columns: u32, rows: u32, spacing: DVec2, viewport: DAffine2) -> DVec2 {
|
fn calculate_rectangle_side_direction(spacing: DVec2, viewport: DAffine2) -> DVec2 {
|
||||||
let (left, right, _, _) = get_corners(columns, rows, spacing);
|
let p0 = DVec2::ZERO;
|
||||||
(viewport.transform_point2(right) - viewport.transform_point2(left)).try_normalize().unwrap_or(DVec2::ZERO)
|
let p1 = DVec2::new(spacing.x, 0.);
|
||||||
|
(viewport.transform_point2(p1) - viewport.transform_point2(p0)).normalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_rectangle_top_direction(columns: u32, rows: u32, spacing: DVec2, viewport: DAffine2) -> DVec2 {
|
fn calculate_rectangle_top_direction(spacing: DVec2, viewport: DAffine2) -> DVec2 {
|
||||||
let (left, _, _, bottom_left) = get_corners(columns, rows, spacing);
|
let p0 = DVec2::ZERO;
|
||||||
|
let p1 = DVec2::new(0., spacing.y);
|
||||||
(viewport.transform_point2(left) - viewport.transform_point2(bottom_left)).try_normalize().unwrap_or(DVec2::ZERO)
|
(viewport.transform_point2(p0) - viewport.transform_point2(p1)).try_normalize().unwrap_or(DVec2::ZERO)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_isometric_side_direction(angles: DVec2, spacing: DVec2, viewport: Option<DAffine2>) -> DVec2 {
|
fn calculate_isometric_side_direction(angles: DVec2, spacing: DVec2, viewport: Option<DAffine2>) -> DVec2 {
|
||||||
@@ -472,3 +354,127 @@ fn calculate_isometric_top_direction(angles: DVec2, spacing: DVec2, viewport: Op
|
|||||||
|
|
||||||
(first_point - first_row_last_column).try_normalize().unwrap_or_default()
|
(first_point - first_row_last_column).try_normalize().unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
|
pub enum RowColumnGizmoType {
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
Top,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RowColumnGizmoType {
|
||||||
|
pub fn get_line_points(&self, grid_type: GridType, columns: u32, rows: u32, spacing: DVec2, angles: DVec2) -> (DVec2, DVec2) {
|
||||||
|
match grid_type {
|
||||||
|
GridType::Rectangular => match self {
|
||||||
|
Self::Top => get_rectangle_top_line_points(columns, rows, spacing),
|
||||||
|
Self::Right => get_rectangle_right_line_points(columns, rows, spacing),
|
||||||
|
Self::Down => get_rectangle_bottom_line_points(columns, rows, spacing),
|
||||||
|
Self::Left => get_rectangle_left_line_points(columns, rows, spacing),
|
||||||
|
Self::None => panic!("RowColumnGizmoType::None does not have line points"),
|
||||||
|
},
|
||||||
|
GridType::Isometric => match self {
|
||||||
|
Self::Top => calculate_isometric_top_line_points(columns, rows, spacing, angles),
|
||||||
|
Self::Right => calculate_isometric_right_line_points(columns, rows, spacing, angles),
|
||||||
|
Self::Down => calculate_isometric_bottom_line_points(columns, rows, spacing, angles),
|
||||||
|
Self::Left => calculate_isometric_left_line_points(columns, rows, spacing, angles),
|
||||||
|
Self::None => panic!("RowColumnGizmoType::None does not have line points"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line(&self, grid_type: GridType, columns: u32, rows: u32, spacing: DVec2, angles: DVec2, viewport: DAffine2) -> Line {
|
||||||
|
let (p0, p1) = self.get_line_points(grid_type, columns, rows, spacing, angles);
|
||||||
|
let direction = self.direction(grid_type, spacing, angles, viewport);
|
||||||
|
let gap = GRID_ROW_COLUMN_GIZMO_OFFSET * direction;
|
||||||
|
|
||||||
|
convert_to_gizmo_line(viewport.transform_point2(p0) + gap, viewport.transform_point2(p1) + gap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opposite(&self, grid_type: GridType, columns: u32, rows: u32, spacing: DVec2, angles: DVec2, viewport: DAffine2) -> Line {
|
||||||
|
let opposite_gizmo_type = self.opposite_gizmo_type();
|
||||||
|
opposite_gizmo_type.line(grid_type, columns, rows, spacing, angles, viewport)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opposite_gizmo_type(&self) -> Self {
|
||||||
|
return match self {
|
||||||
|
Self::Top => Self::Down,
|
||||||
|
Self::Right => Self::Left,
|
||||||
|
Self::Down => Self::Top,
|
||||||
|
Self::Left => Self::Right,
|
||||||
|
Self::None => panic!("RowColumnGizmoType::None does not have opposite"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn direction(&self, grid_type: GridType, spacing: DVec2, angles: DVec2, viewport: DAffine2) -> DVec2 {
|
||||||
|
match self {
|
||||||
|
RowColumnGizmoType::Top => {
|
||||||
|
if grid_type == GridType::Rectangular {
|
||||||
|
calculate_rectangle_top_direction(spacing, viewport)
|
||||||
|
} else {
|
||||||
|
-calculate_isometric_top_direction(angles, spacing, Some(viewport))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowColumnGizmoType::Down => {
|
||||||
|
if grid_type == GridType::Rectangular {
|
||||||
|
-calculate_rectangle_top_direction(spacing, viewport)
|
||||||
|
} else {
|
||||||
|
calculate_isometric_top_direction(angles, spacing, Some(viewport))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowColumnGizmoType::Right => {
|
||||||
|
if grid_type == GridType::Rectangular {
|
||||||
|
calculate_rectangle_side_direction(spacing, viewport)
|
||||||
|
} else {
|
||||||
|
calculate_isometric_side_direction(angles, spacing, Some(viewport))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowColumnGizmoType::Left => {
|
||||||
|
if grid_type == GridType::Rectangular {
|
||||||
|
-calculate_rectangle_side_direction(spacing, viewport)
|
||||||
|
} else {
|
||||||
|
-calculate_isometric_side_direction(angles, spacing, Some(viewport))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a line"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn initial_dimension(&self, rows: u32, columns: u32) -> u32 {
|
||||||
|
match self {
|
||||||
|
RowColumnGizmoType::Top | RowColumnGizmoType::Down => rows,
|
||||||
|
RowColumnGizmoType::Right | RowColumnGizmoType::Left => columns,
|
||||||
|
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a mouse_icon"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spacing(&self, spacing: DVec2) -> f64 {
|
||||||
|
match self {
|
||||||
|
RowColumnGizmoType::Top | RowColumnGizmoType::Down => spacing.y,
|
||||||
|
RowColumnGizmoType::Right | RowColumnGizmoType::Left => spacing.x,
|
||||||
|
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a mouse_icon"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
RowColumnGizmoType::Top | RowColumnGizmoType::Down => GRID_ROW_INDEX,
|
||||||
|
RowColumnGizmoType::Right | RowColumnGizmoType::Left => GRID_COLUMNS_INDEX,
|
||||||
|
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a mouse_icon"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_icon(&self) -> MouseCursorIcon {
|
||||||
|
match self {
|
||||||
|
RowColumnGizmoType::Top | RowColumnGizmoType::Down => MouseCursorIcon::NSResize,
|
||||||
|
RowColumnGizmoType::Right | RowColumnGizmoType::Left => MouseCursorIcon::EWResize,
|
||||||
|
RowColumnGizmoType::None => panic!("RowColumnGizmoType::None does not have a mouse_icon"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn all() -> [Self; 4] {
|
||||||
|
[Self::Top, Self::Right, Self::Down, Self::Left]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -567,6 +567,7 @@ impl Fsm for ShapeToolFsmState {
|
|||||||
|
|
||||||
if tool_data.gizmo_manger.handle_click() {
|
if tool_data.gizmo_manger.handle_click() {
|
||||||
tool_data.data.drag_start = document.metadata().document_to_viewport.inverse().transform_point2(mouse_pos);
|
tool_data.data.drag_start = document.metadata().document_to_viewport.inverse().transform_point2(mouse_pos);
|
||||||
|
responses.add(DocumentMessage::StartTransaction);
|
||||||
return ShapeToolFsmState::ModifyingGizmo;
|
return ShapeToolFsmState::ModifyingGizmo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,7 +686,6 @@ impl Fsm for ShapeToolFsmState {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
(ShapeToolFsmState::ModifyingGizmo, ShapeToolMessage::PointerMove(..)) => {
|
(ShapeToolFsmState::ModifyingGizmo, ShapeToolMessage::PointerMove(..)) => {
|
||||||
responses.add(DocumentMessage::StartTransaction);
|
|
||||||
tool_data.gizmo_manger.handle_update(tool_data.data.viewport_drag_start(document), document, input, responses);
|
tool_data.gizmo_manger.handle_update(tool_data.data.viewport_drag_start(document), document, input, responses);
|
||||||
|
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
|
|||||||
Reference in New Issue
Block a user