forked from 1b-agent/opencadstudio-upstream
Merge PR #1215: add rectangle grip dimensions
This commit is contained in:
commit
7c5a388f19
12 files changed
+559
-64
No files matched your search
+140
-14
@@ -209,6 +209,8 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
GripEditMode::Lengthen
|
||||
| GripEditMode::Radius
|
||||
| GripEditMode::ArcLength
|
||||
| GripEditMode::RectangleWidth
|
||||
| GripEditMode::RectangleHeight
|
||||
)
|
||||
}) {
|
||||
self.command_line.input.push_str(&s);
|
||||
@@ -262,6 +264,8 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
GripEditMode::Lengthen
|
||||
| GripEditMode::Radius
|
||||
| GripEditMode::ArcLength
|
||||
| GripEditMode::RectangleWidth
|
||||
| GripEditMode::RectangleHeight
|
||||
)
|
||||
}) {
|
||||
self.command_line.input.pop();
|
||||
@@ -316,6 +320,12 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
crate::scene::model::object::GripMenuAction::ArcLength => {
|
||||
Some(GripEditMode::ArcLength)
|
||||
}
|
||||
crate::scene::model::object::GripMenuAction::RectangleWidth => {
|
||||
Some(GripEditMode::RectangleWidth)
|
||||
}
|
||||
crate::scene::model::object::GripMenuAction::RectangleHeight => {
|
||||
Some(GripEditMode::RectangleHeight)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
expected_mode.is_some_and(|mode| {
|
||||
@@ -368,6 +378,12 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
) | (
|
||||
GripEditMode::ArcLength,
|
||||
crate::scene::model::object::GripMenuAction::ArcLength,
|
||||
) | (
|
||||
GripEditMode::RectangleWidth,
|
||||
crate::scene::model::object::GripMenuAction::RectangleWidth,
|
||||
) | (
|
||||
GripEditMode::RectangleHeight,
|
||||
crate::scene::model::object::GripMenuAction::RectangleHeight,
|
||||
)
|
||||
)
|
||||
&& grip.handle == pending.handle
|
||||
@@ -407,13 +423,37 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
|
||||
if let Some(grip) = self.tabs[i].active_grip.clone() {
|
||||
if grip.mode == GripEditMode::Stretch {
|
||||
if matches!(grip.mode, GripEditMode::Stretch | GripEditMode::RectangleResize) {
|
||||
let dyn_locked = self.tabs[i]
|
||||
.dyn_fields
|
||||
.iter()
|
||||
.any(|field| field.buffer.is_some());
|
||||
|
||||
let target = if dyn_locked {
|
||||
let target = if matches!(grip.mode, GripEditMode::RectangleResize) {
|
||||
grip.rectangle_frame.map(|(opposite, width_axis, height_axis)| {
|
||||
let cursor_delta = self.tabs[i].last_cursor_world - opposite;
|
||||
let mut width = cursor_delta.dot(width_axis);
|
||||
let mut height = cursor_delta.dot(height_axis);
|
||||
for field in &self.tabs[i].dyn_fields {
|
||||
let value = field
|
||||
.buffer
|
||||
.as_ref()
|
||||
.and_then(|buffer| crate::app::expr_eval::eval_number(buffer));
|
||||
if let Some(value) = value {
|
||||
match field.role {
|
||||
crate::command::DynRole::Width => {
|
||||
width = value.abs().copysign(width);
|
||||
}
|
||||
crate::command::DynRole::Height => {
|
||||
height = value.abs().copysign(height);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
opposite + width_axis * width + height_axis * height
|
||||
})
|
||||
} else if dyn_locked {
|
||||
// Distance only:
|
||||
// keep the cursor's current direction.
|
||||
//
|
||||
@@ -490,10 +530,32 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
}
|
||||
let delta = target - grip.last_world;
|
||||
|
||||
let actions: Vec<_> = grip
|
||||
.targets
|
||||
.iter()
|
||||
.map(|target_grip| {
|
||||
let actions: Vec<_> = if let Some((opposite, width_axis, height_axis)) = grip.rectangle_frame {
|
||||
let opposite_id = (grip.grip_id + 2) % 4;
|
||||
let mut edits = Vec::with_capacity(3);
|
||||
for adjacent_id in [(opposite_id + 1) % 4, (opposite_id + 3) % 4] {
|
||||
if let Some(original) = self.tabs[i]
|
||||
.selected_grip_handles
|
||||
.iter()
|
||||
.zip(self.tabs[i].selected_grips.iter())
|
||||
.find(|(owner, candidate)| **owner == grip.handle && candidate.id == adjacent_id)
|
||||
.map(|(_, candidate)| candidate.world)
|
||||
{
|
||||
let d = original - opposite;
|
||||
let axis = if d.dot(width_axis).abs() >= d.dot(height_axis).abs() {
|
||||
width_axis
|
||||
} else {
|
||||
height_axis
|
||||
};
|
||||
edits.push((grip.handle, adjacent_id, GripApply::Absolute(
|
||||
opposite + axis * (target - opposite).dot(axis),
|
||||
)));
|
||||
}
|
||||
}
|
||||
edits.push((grip.handle, grip.grip_id, GripApply::Absolute(target)));
|
||||
edits
|
||||
} else {
|
||||
grip.targets.iter().map(|target_grip| {
|
||||
let apply = if target_grip.is_translate {
|
||||
GripApply::Translate(delta)
|
||||
} else {
|
||||
@@ -507,8 +569,8 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
target_grip.grip_id,
|
||||
apply,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
}).collect()
|
||||
};
|
||||
|
||||
for (handle, grip_id, apply) in actions {
|
||||
self.tabs[i]
|
||||
@@ -1324,6 +1386,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
if matches!(
|
||||
item.action,
|
||||
GripMenuAction::Stretch
|
||||
| GripMenuAction::RectangleResize
|
||||
| GripMenuAction::MoveWithText
|
||||
| GripMenuAction::MoveWithDimLine
|
||||
| GripMenuAction::MoveWithLeader
|
||||
@@ -1381,12 +1444,59 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
|| (!is_dimension && g.is_midpoint),
|
||||
)
|
||||
};
|
||||
self.tabs[i].active_grip = Some(GripEdit::single(
|
||||
popup.handle,
|
||||
grip_id,
|
||||
is_translate,
|
||||
g.world,
|
||||
));
|
||||
if matches!(item.action, GripMenuAction::RectangleResize) {
|
||||
let rectangle = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.get_entity(popup.handle)
|
||||
.and_then(|entity| {
|
||||
let AcadEntityType::LwPolyline(polyline) = entity else {
|
||||
return None;
|
||||
};
|
||||
let (frame, plane) =
|
||||
crate::entities::lwpolyline::rectangle_frame(polyline)?;
|
||||
let opposite = polyline
|
||||
.vertices
|
||||
.get((popup.grip_id + 2) % 4)?
|
||||
.location;
|
||||
Some((
|
||||
glam::DVec3::from_array(
|
||||
plane.point_at([opposite.x, opposite.y]),
|
||||
),
|
||||
glam::DVec3::from_array(plane.vector_at(frame.width_axis))
|
||||
.try_normalize()?,
|
||||
glam::DVec3::from_array(plane.vector_at(frame.height_axis))
|
||||
.try_normalize()?,
|
||||
))
|
||||
});
|
||||
if let Some((opposite, width_axis, height_axis)) = rectangle {
|
||||
if self.grip_originals.is_empty() {
|
||||
self.grip_originals = self.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.get_entity(popup.handle)
|
||||
.cloned()
|
||||
.map(|entity| vec![(popup.handle, entity)])
|
||||
.unwrap_or_default();
|
||||
}
|
||||
self.tabs[i].active_grip = Some(GripEdit::rectangle_resize(
|
||||
popup.handle,
|
||||
popup.grip_id,
|
||||
g.world,
|
||||
opposite,
|
||||
width_axis,
|
||||
height_axis,
|
||||
));
|
||||
self.sync_dyn_fields();
|
||||
}
|
||||
} else {
|
||||
self.tabs[i].active_grip = Some(GripEdit::single(
|
||||
popup.handle,
|
||||
grip_id,
|
||||
is_translate,
|
||||
g.world,
|
||||
));
|
||||
}
|
||||
}
|
||||
return Task::none();
|
||||
}
|
||||
@@ -1410,6 +1520,8 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
GripMenuAction::Lengthen
|
||||
| GripMenuAction::Radius
|
||||
| GripMenuAction::ArcLength
|
||||
| GripMenuAction::RectangleWidth
|
||||
| GripMenuAction::RectangleHeight
|
||||
) {
|
||||
if let Some((_, grip)) = self.tabs[i]
|
||||
.selected_grip_handles
|
||||
@@ -1439,6 +1551,16 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
popup.grip_id,
|
||||
grip.world,
|
||||
),
|
||||
GripMenuAction::RectangleWidth => GripEdit::rectangle_width(
|
||||
popup.handle,
|
||||
popup.grip_id,
|
||||
grip.world,
|
||||
),
|
||||
GripMenuAction::RectangleHeight => GripEdit::rectangle_height(
|
||||
popup.handle,
|
||||
popup.grip_id,
|
||||
grip.world,
|
||||
),
|
||||
_ => GripEdit::lengthen(
|
||||
popup.handle,
|
||||
popup.grip_id,
|
||||
@@ -1460,6 +1582,10 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
self.command_line.push_info(
|
||||
crate::t!("Specify point or enter arc length:").as_ref(),
|
||||
);
|
||||
} else if matches!(item.action, GripMenuAction::RectangleWidth) {
|
||||
self.command_line.push_info("Specify point or enter width:");
|
||||
} else if matches!(item.action, GripMenuAction::RectangleHeight) {
|
||||
self.command_line.push_info("Specify point or enter height:");
|
||||
} else {
|
||||
self.command_line.push_info(
|
||||
crate::t!("Specify point or enter distance:").as_ref(),
|
||||
|
||||
Reference in new issue
Block a user