forked from 1b-agent/opencadstudio-upstream
Refactor FILTER validation and operator normalization (v2.2)
This commit is contained in:
1 parent
390e12169a
commit
7c61583ac2
2 files changed
+145
-70
No files matched your search
+81
-68
@@ -106,6 +106,7 @@ pub(in crate::app) use file::background_task;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub(in crate::app) use file::native_paths_match;
|
||||
mod page_setup_import;
|
||||
mod qselect;
|
||||
mod style;
|
||||
pub(in crate::app) mod util;
|
||||
mod viewport;
|
||||
@@ -7011,14 +7012,7 @@ impl OpenCADStudio {
|
||||
if matches!(scope, crate::app::QSelectScope::CurrentSelection) {
|
||||
state.append = false;
|
||||
}
|
||||
if matches!(
|
||||
state.operator,
|
||||
crate::app::QSelectOp::Gt | crate::app::QSelectOp::Lt
|
||||
) && !state.property.as_ref().is_some_and(|property| {
|
||||
matches!(property.editor, crate::app::QSelectValueEditor::Number)
|
||||
}) {
|
||||
state.operator = crate::app::QSelectOp::Eq;
|
||||
}
|
||||
state.normalize_operator();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
@@ -7042,14 +7036,7 @@ impl OpenCADStudio {
|
||||
state.property = kept_property;
|
||||
state.value.clear();
|
||||
state.error = None;
|
||||
if matches!(
|
||||
state.operator,
|
||||
crate::app::QSelectOp::Gt | crate::app::QSelectOp::Lt
|
||||
) && !state.property.as_ref().is_some_and(|property| {
|
||||
matches!(property.editor, crate::app::QSelectValueEditor::Number)
|
||||
}) {
|
||||
state.operator = crate::app::QSelectOp::Eq;
|
||||
}
|
||||
state.normalize_operator();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
@@ -7059,14 +7046,7 @@ impl OpenCADStudio {
|
||||
state.property = p;
|
||||
state.value.clear();
|
||||
state.error = None;
|
||||
if matches!(
|
||||
state.operator,
|
||||
crate::app::QSelectOp::Gt | crate::app::QSelectOp::Lt
|
||||
) && !state.property.as_ref().is_some_and(|property| {
|
||||
matches!(property.editor, crate::app::QSelectValueEditor::Number)
|
||||
}) {
|
||||
state.operator = crate::app::QSelectOp::Eq;
|
||||
}
|
||||
state.normalize_operator();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
@@ -7105,47 +7085,77 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::QSelectPickObject => self.on_qselect_pick_object(),
|
||||
Message::QSelectAddCondition => {
|
||||
if let Some(state) = self.qselect.as_mut() {
|
||||
let condition = state.draft_condition();
|
||||
if let Some(error) = condition.validation_error() {
|
||||
state.error = Some(error);
|
||||
return Task::none();
|
||||
}
|
||||
if let Some(index) = state.editing_condition.take() {
|
||||
if let Some(existing) = state.conditions.get_mut(index) { *existing = condition; }
|
||||
} else { state.conditions.push(condition); }
|
||||
state.error = None;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::QSelectEditCondition(index) => {
|
||||
let condition = self.qselect.as_ref().and_then(|state| state.conditions.get(index).cloned());
|
||||
if let Some(condition) = condition {
|
||||
let scope = self.qselect.as_ref().unwrap().scope;
|
||||
let properties = self.tabs[self.active_tab].scene.qselect_properties(condition.type_filter.as_deref(), scope);
|
||||
if let Some(state) = self.qselect.as_mut() {
|
||||
state.available_properties = properties;
|
||||
state.type_filter = condition.type_filter;
|
||||
state.property = condition.property;
|
||||
state.operator = condition.operator;
|
||||
state.value = condition.value;
|
||||
state.editing_condition = Some(index);
|
||||
state.error = None;
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::QSelectRemoveCondition(index) => {
|
||||
if let Some(state) = self.qselect.as_mut() {
|
||||
if index < state.conditions.len() {
|
||||
state.conditions.remove(index);
|
||||
state.editing_condition = match state.editing_condition {
|
||||
Some(editing) if editing == index => None,
|
||||
Some(editing) if editing > index => Some(editing - 1),
|
||||
other => other,
|
||||
};
|
||||
}
|
||||
state.error = None;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::QSelectClearConditions => {
|
||||
if let Some(state) = self.qselect.as_mut() {
|
||||
state.conditions.clear();
|
||||
state.editing_condition = None;
|
||||
state.error = None;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::QSelectCancelEdit => {
|
||||
if let Some(state) = self.qselect.as_mut() {
|
||||
state.editing_condition = None;
|
||||
state.error = None;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::QSelectApply => {
|
||||
let validation_error = self.qselect.as_ref().and_then(|state| {
|
||||
let candidate_count = self.tabs[self.active_tab]
|
||||
.scene
|
||||
.qselect_candidate_count(state.scope);
|
||||
if candidate_count == 0 {
|
||||
if self.tabs[self.active_tab].scene.qselect_candidate_count(state.scope) == 0 {
|
||||
Some(crate::t!("No objects are available in this scope.").into_owned())
|
||||
} else if let Some(property) = state.property.as_ref() {
|
||||
if matches!(state.operator, crate::app::QSelectOp::Any) {
|
||||
None
|
||||
} else if matches!(
|
||||
state.operator,
|
||||
crate::app::QSelectOp::Gt | crate::app::QSelectOp::Lt
|
||||
) && !matches!(
|
||||
property.editor,
|
||||
crate::app::QSelectValueEditor::Number
|
||||
) {
|
||||
Some(
|
||||
crate::t!("This operator requires a numeric property.")
|
||||
.into_owned(),
|
||||
)
|
||||
} else {
|
||||
match &property.editor {
|
||||
crate::app::QSelectValueEditor::Number
|
||||
if crate::entities::common::parse_f64(&state.value)
|
||||
.is_none() =>
|
||||
{
|
||||
Some(crate::t!("Enter a valid number.").into_owned())
|
||||
}
|
||||
crate::app::QSelectValueEditor::Choice(_)
|
||||
if state.value.is_empty() =>
|
||||
{
|
||||
Some(crate::t!("Choose a value.").into_owned())
|
||||
}
|
||||
crate::app::QSelectValueEditor::Text
|
||||
| crate::app::QSelectValueEditor::Number
|
||||
| crate::app::QSelectValueEditor::Choice(_) => None,
|
||||
}
|
||||
}
|
||||
} else if state.editing_condition.is_some() {
|
||||
Some(crate::t!("Update or cancel the condition edit before applying.").into_owned())
|
||||
} else if state.conditions.is_empty() {
|
||||
state.draft_condition().validation_error()
|
||||
} else {
|
||||
None
|
||||
state.conditions.iter().find_map(|condition| condition.validation_error())
|
||||
}
|
||||
});
|
||||
if let Some(error) = validation_error {
|
||||
@@ -7160,13 +7170,11 @@ impl OpenCADStudio {
|
||||
self.qselect_settings = Some((&state).into());
|
||||
self.reset_modal_geometry();
|
||||
let i = self.active_tab;
|
||||
let matched = self.tabs[i].scene.qselect(
|
||||
state.scope,
|
||||
state.type_filter.as_deref(),
|
||||
state.property.as_ref().map(|p| p.field.as_str()),
|
||||
state.operator,
|
||||
&state.value,
|
||||
state.mode,
|
||||
let conditions = if state.conditions.is_empty() {
|
||||
vec![state.draft_condition()]
|
||||
} else { state.conditions.clone() };
|
||||
let matched = self.tabs[i].scene.qselect_conditions(
|
||||
state.scope, &conditions, state.mode,
|
||||
state.append && matches!(state.scope, crate::app::QSelectScope::CurrentSpace),
|
||||
);
|
||||
self.command_line
|
||||
@@ -7190,6 +7198,11 @@ impl OpenCADStudio {
|
||||
.collect();
|
||||
wblock.error_message = None;
|
||||
self.active_modal = Some(super::ModalKind::WriteBlock);
|
||||
} else {
|
||||
// FILTER may be opened from a still-focused command input.
|
||||
// Release text focus so Delete and clipboard shortcuts act
|
||||
// on the resulting pick-first selection, not on that input.
|
||||
return self.unfocus_widgets();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user