feat(table): complete editing workflow

This commit is contained in:
Hakan Seven committed 2026-08-25 00:25:13 +03:00
commit f40b172eb0
14 files changed
+3406 -389

No files matched your search

+65 -1
View File
@@ -2127,6 +2127,29 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
self.tabs[i].scene.bump_entities(&changes);
}
}
} else if field == "tbl_style_handle" {
let style_handle = self.tabs[i]
.scene
.document
.objects
.iter()
.find_map(|(handle, object)| match object {
acadrust::objects::ObjectType::TableStyle(style)
if style.name.eq_ignore_ascii_case(value.trim()) =>
{
Some(*handle)
}
_ => None,
});
if let Some(style_handle) = style_handle {
for &handle in &handles {
if let Some(acadrust::EntityType::Table(table)) =
self.tabs[i].scene.document.get_entity_mut(handle)
{
table.table_style_handle = Some(style_handle);
}
}
}
} else if field == "transparency" {
for &handle in &handles {
if self.tabs[i].scene.is_layer_locked(handle) {
@@ -2266,6 +2289,15 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
}
}
}
if field.starts_with("tbl_") {
for &handle in &handles {
if let Some(acadrust::EntityType::Table(table)) =
self.tabs[i].scene.document.get_entity_mut(handle)
{
table.block_record_handle = None;
}
}
}
self.invalidate_property_targets(i, &handles);
self.tabs[i].dirty = true;
self.tabs[i].properties.edit_choice_open = false;
@@ -2382,7 +2414,30 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
return Task::none();
}
self.push_undo_snapshot(i, "CHPROP");
if field == "block" {
if field == "tbl_style_handle" {
let style_handle = self.tabs[i]
.scene
.document
.objects
.iter()
.find_map(|(handle, object)| match object {
acadrust::objects::ObjectType::TableStyle(style)
if style.name.eq_ignore_ascii_case(val.trim()) =>
{
Some(*handle)
}
_ => None,
});
if let Some(style_handle) = style_handle {
for &handle in &handles {
if let Some(acadrust::EntityType::Table(table)) =
self.tabs[i].scene.document.get_entity_mut(handle)
{
table.table_style_handle = Some(style_handle);
}
}
}
} else if field == "block" {
// Name row on a block reference: an existing name
// re-points the selected inserts; a new one renames
// the definition they share. Commit closes the list.
@@ -2563,6 +2618,15 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
}
}
}
if field.starts_with("tbl_") {
for &handle in &handles {
if let Some(acadrust::EntityType::Table(table)) =
self.tabs[i].scene.document.get_entity_mut(handle)
{
table.block_record_handle = None;
}
}
}
self.invalidate_property_targets(i, &handles);
self.tabs[i].dirty = true;
self.refresh_properties();
+105
View File
@@ -4651,6 +4651,47 @@ impl OpenCADStudio {
}
}
}
"tbl_title_suppressed" | "tbl_header_suppressed" => {
let next = {
let document = &self.tabs[i].scene.document;
let Some(acadrust::EntityType::Table(table)) =
document.get_entity(handle)
else {
continue;
};
let table_style = table.table_style_handle.and_then(|style_handle| {
document.objects.get(&style_handle).and_then(|object| {
match object {
acadrust::objects::ObjectType::TableStyle(style) => {
Some(style)
}
_ => None,
}
})
});
let current = if field == "tbl_title_suppressed" {
crate::entities::table::resolved_title_suppressed(
table,
table_style,
)
} else {
crate::entities::table::resolved_header_suppressed(
table,
table_style,
)
};
!current
};
if let Some(entity) =
self.tabs[i].scene.document.get_entity_mut(handle)
{
crate::scene::view::dispatch::apply_geom_prop(
entity,
field,
if next { "true" } else { "false" },
);
}
}
_ => {
if let Some(entity) =
self.tabs[i].scene.document.get_entity_mut(handle)
@@ -4662,6 +4703,15 @@ impl OpenCADStudio {
}
}
}
if field.starts_with("tbl_") {
for &handle in &handles {
if let Some(acadrust::EntityType::Table(table)) =
self.tabs[i].scene.document.get_entity_mut(handle)
{
table.block_record_handle = None;
}
}
}
self.invalidate_property_targets(i, &handles);
self.tabs[i].dirty = true;
self.refresh_properties();
@@ -4677,6 +4727,9 @@ impl OpenCADStudio {
match self.tabs[i].scene.document.get_entity(handles[0]) {
Some(acadrust::EntityType::LwPolyline(p)) => p.vertices.len(),
Some(acadrust::EntityType::Polyline2D(p)) => p.vertices.len(),
Some(acadrust::EntityType::Table(table)) => {
table.row_count().saturating_mul(table.column_count())
}
_ => 0,
}
} else {
@@ -4688,6 +4741,7 @@ impl OpenCADStudio {
let next = (cur + delta as i64).rem_euclid(n as i64) as usize;
self.tabs[i].properties.prop_vertex = next;
self.tabs[i].properties.prop_vertex_indicator_active = next != cur as usize;
crate::entities::table::set_prop_current_cell(next);
self.refresh_properties();
}
Task::none()
@@ -4894,6 +4948,57 @@ impl OpenCADStudio {
}
return Task::none();
}
if matches!(
field.as_str(),
"tbl_cell_content_color" | "tbl_cell_background_color"
) {
let cell_index = self.tabs[i].properties.prop_vertex;
if !handles.is_empty() {
self.push_undo_snapshot(i, "TABLE CELL COLOR");
for &handle in &handles {
let Some(acadrust::EntityType::Table(table)) =
self.tabs[i].scene.document.get_entity_mut(handle)
else {
continue;
};
let columns = table.column_count();
if columns == 0 {
continue;
}
if let Some(cell) = table.cell_mut(
cell_index / columns,
cell_index % columns,
) {
use acadrust::entities::table::CellStateFlags;
if cell.state.intersects(
CellStateFlags::FORMAT_LOCKED
| CellStateFlags::FORMAT_READ_ONLY,
) {
continue;
}
let style = cell.style.get_or_insert_with(Default::default);
if field == "tbl_cell_content_color" {
style.content_color = color;
style.property_flags.insert(
acadrust::entities::table::CellStylePropertyFlags::CONTENT_COLOR,
);
} else {
style.background_color = color;
style.fill_enabled = true;
style.property_flags.insert(
acadrust::entities::table::CellStylePropertyFlags::BACKGROUND_COLOR,
);
}
}
table.block_record_handle = None;
}
self.invalidate_property_targets(i, &handles);
self.tabs[i].properties.open_color_field = None;
self.tabs[i].dirty = true;
self.refresh_properties();
}
return Task::none();
}
if !handles.is_empty() {
self.push_undo_snapshot(i, "CHPROP");
let idx = if field == "gradient_color_2" { 1 } else { 0 };
+98
View File
@@ -4392,6 +4392,104 @@ impl OpenCADStudio {
).as_ref());
return Task::none();
}
let table_editor = self.tabs[i]
.scene
.document
.get_entity(handle)
.and_then(|entity| match entity {
AcadEntityType::Table(table) => {
let horizontal = glam::DVec3::new(
table.horizontal_direction.x,
table.horizontal_direction.y,
table.horizontal_direction.z,
)
.normalize_or(glam::DVec3::X);
let normal = glam::DVec3::new(
table.normal.x,
table.normal.y,
table.normal.z,
)
.normalize_or(glam::DVec3::Z);
let mut down = horizontal
.cross(normal)
.normalize_or(glam::DVec3::NEG_Y);
let table_style = table.table_style_handle.and_then(|style_handle| {
self.tabs[i]
.scene
.document
.objects
.get(&style_handle)
.and_then(|object| match object {
acadrust::objects::ObjectType::TableStyle(style) => {
Some(style)
}
_ => None,
})
});
let flows_up = crate::entities::table::resolved_flow_up(
table,
table_style,
);
if flows_up {
down = -down;
}
let origin = glam::DVec3::new(
table.insertion_point.x,
table.insertion_point.y,
table.insertion_point.z,
);
let relative = click_world - origin;
let x = relative.dot(horizontal);
let y = relative.dot(down);
if x < 0.0 || y < 0.0 {
return None;
}
let column = table
.columns
.iter()
.scan(0.0, |offset, column| {
*offset += column.width;
Some(*offset)
})
.position(|end| x <= end)?;
let row = table
.rows
.iter()
.scan(0.0, |offset, row| {
*offset += row.height;
Some(*offset)
})
.position(|end| y <= end)?;
let locked = table.cell(row, column).is_some_and(|cell| {
use acadrust::entities::table::CellStateFlags;
cell.state.intersects(
CellStateFlags::CONTENT_LOCKED
| CellStateFlags::CONTENT_READ_ONLY,
)
});
Some((
(!locked).then(|| {
crate::modules::annotate::table_cmd::TableCellEditCommand::new(
handle, table, row, column,
)
}),
row * table.column_count() + column,
))
}
_ => None,
});
if let Some((command, cell_index)) = table_editor {
self.tabs[i].properties.prop_vertex = cell_index;
self.tabs[i].properties.prop_vertex_indicator_active = true;
crate::entities::table::set_prop_current_cell(cell_index);
self.refresh_properties();
if let Some(command) = command {
self.command_line
.push_info(&crate::command::CadCommand::prompt(&command));
self.tabs[i].active_cmd = Some(Box::new(command));
}
return Task::none();
}
// Any text-bearing entity opens its in-place editor
// (plain box or rich MText editor, per type). A
// Leader resolves to the entity it annotates.