forked from 1b-agent/opencadstudio-upstream
feat(tablestyle): per-cell editing for Data/Header/Title rows
Each row's RowCellStyle is now editable in the Table Style manager: text style name, text height, text & fill color (ACI), background-fill toggle, and alignment (cycle through the 9 anchor positions). Margin and per-cell buffers load on open/select via a shared load_tablestyle_bufs; edits write through objects.values_mut() and bump geometry so tables using the style re-render. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
e0c5db9e0c
commit
df44031ae8
4 files changed
+221
-20
No files matched your search
@@ -315,6 +315,11 @@ pub(super) struct OpenCADStudio {
|
||||
/// Edit buffers for the table style's general margins.
|
||||
ts_hmargin: String,
|
||||
ts_vmargin: String,
|
||||
/// Per-cell edit buffers, indexed 0=Data, 1=Header, 2=Title.
|
||||
ts_cell_textstyle: [String; 3],
|
||||
ts_cell_height: [String; 3],
|
||||
ts_cell_textcolor: [String; 3],
|
||||
ts_cell_fillcolor: [String; 3],
|
||||
|
||||
// ── TextStyle Font Browser ────────────────────────────────────────────
|
||||
textstyle_selected: String,
|
||||
@@ -1013,6 +1018,18 @@ pub enum Message {
|
||||
TableStyleEdit { field: &'static str, value: String },
|
||||
/// Write the general edit buffers back into the selected table style.
|
||||
TableStyleApply,
|
||||
/// Update a per-cell edit buffer (row 0=Data,1=Header,2=Title).
|
||||
TableStyleCellEdit {
|
||||
row: u8,
|
||||
field: &'static str,
|
||||
value: String,
|
||||
},
|
||||
/// Toggle background fill on a cell style.
|
||||
TableStyleCellToggleFill(u8),
|
||||
/// Cycle the alignment of a cell style.
|
||||
TableStyleCellCycleAlign(u8),
|
||||
/// Write a cell's edit buffers back into the selected table style.
|
||||
TableStyleCellApply(u8),
|
||||
// ── MLineStyle Dialog ─────────────────────────────────────────────────
|
||||
MlStyleDialogOpen,
|
||||
#[allow(dead_code)]
|
||||
@@ -1202,6 +1219,10 @@ impl OpenCADStudio {
|
||||
tablestyle_selected: "Standard".to_string(),
|
||||
ts_hmargin: "1.5".to_string(),
|
||||
ts_vmargin: "1.5".to_string(),
|
||||
ts_cell_textstyle: [String::new(), String::new(), String::new()],
|
||||
ts_cell_height: [String::new(), String::new(), String::new()],
|
||||
ts_cell_textcolor: [String::new(), String::new(), String::new()],
|
||||
ts_cell_fillcolor: [String::new(), String::new(), String::new()],
|
||||
// MLineStyle dialog
|
||||
mlstyle_selected: "Standard".to_string(),
|
||||
// MLeaderStyle dialog
|
||||
|
||||
+142
-9
@@ -5724,6 +5724,7 @@ impl OpenCADStudio {
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| "Standard".to_string());
|
||||
self.load_tablestyle_bufs(i);
|
||||
if let Some(id) = self.tablestyle_window {
|
||||
return window::gain_focus(id);
|
||||
}
|
||||
@@ -5744,17 +5745,9 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
Message::TableStyleDialogSelect(name) => {
|
||||
use acadrust::objects::ObjectType;
|
||||
self.tablestyle_selected = name;
|
||||
let i = self.active_tab;
|
||||
for obj in self.tabs[i].scene.document.objects.values() {
|
||||
if let ObjectType::TableStyle(s) = obj {
|
||||
if s.name == self.tablestyle_selected {
|
||||
self.ts_hmargin = format!("{:.4}", s.horizontal_margin);
|
||||
self.ts_vmargin = format!("{:.4}", s.vertical_margin);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.load_tablestyle_bufs(i);
|
||||
Task::none()
|
||||
}
|
||||
|
||||
@@ -5790,6 +5783,87 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleCellEdit { row, field, value } => {
|
||||
let r = row as usize;
|
||||
if r < 3 {
|
||||
match field {
|
||||
"textstyle" => self.ts_cell_textstyle[r] = value,
|
||||
"height" => self.ts_cell_height[r] = value,
|
||||
"textcolor" => self.ts_cell_textcolor[r] = value,
|
||||
"fillcolor" => self.ts_cell_fillcolor[r] = value,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleCellToggleFill(row) => {
|
||||
let i = self.active_tab;
|
||||
if let Some(s) = self.tablestyle_mut(i) {
|
||||
if let Some(c) = Self::ts_cell_of(s, row) {
|
||||
c.fill_enabled = !c.fill_enabled;
|
||||
}
|
||||
self.push_undo_snapshot(i, "TABLESTYLE EDIT");
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleCellCycleAlign(row) => {
|
||||
use acadrust::objects::CellAlignment;
|
||||
let i = self.active_tab;
|
||||
if let Some(s) = self.tablestyle_mut(i) {
|
||||
if let Some(c) = Self::ts_cell_of(s, row) {
|
||||
c.alignment = match c.alignment {
|
||||
CellAlignment::TopLeft => CellAlignment::TopCenter,
|
||||
CellAlignment::TopCenter => CellAlignment::TopRight,
|
||||
CellAlignment::TopRight => CellAlignment::MiddleLeft,
|
||||
CellAlignment::MiddleLeft => CellAlignment::MiddleCenter,
|
||||
CellAlignment::MiddleCenter => CellAlignment::MiddleRight,
|
||||
CellAlignment::MiddleRight => CellAlignment::BottomLeft,
|
||||
CellAlignment::BottomLeft => CellAlignment::BottomCenter,
|
||||
CellAlignment::BottomCenter => CellAlignment::BottomRight,
|
||||
CellAlignment::BottomRight => CellAlignment::TopLeft,
|
||||
};
|
||||
}
|
||||
self.push_undo_snapshot(i, "TABLESTYLE EDIT");
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleCellApply(row) => {
|
||||
let i = self.active_tab;
|
||||
let r = row as usize;
|
||||
if r >= 3 {
|
||||
return Task::none();
|
||||
}
|
||||
let ts = self.ts_cell_textstyle[r].trim().to_string();
|
||||
let height: Option<f64> = self.ts_cell_height[r].trim().parse().ok();
|
||||
let tc: Option<i16> = self.ts_cell_textcolor[r].trim().parse().ok();
|
||||
let fc: Option<i16> = self.ts_cell_fillcolor[r].trim().parse().ok();
|
||||
if let Some(c) = self.tablestyle_mut(i).and_then(|s| Self::ts_cell_of(s, row)) {
|
||||
if !ts.is_empty() {
|
||||
c.text_style_name = ts;
|
||||
}
|
||||
if let Some(h) = height {
|
||||
c.text_height = h;
|
||||
}
|
||||
if let Some(v) = tc {
|
||||
c.text_color = acadrust::types::Color::from_index(v);
|
||||
}
|
||||
if let Some(v) = fc {
|
||||
c.fill_color = acadrust::types::Color::from_index(v);
|
||||
}
|
||||
self.push_undo_snapshot(i, "TABLESTYLE EDIT");
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleToggle(field) => {
|
||||
use acadrust::objects::ObjectType;
|
||||
let i = self.active_tab;
|
||||
@@ -6844,6 +6918,65 @@ impl OpenCADStudio {
|
||||
Some(task)
|
||||
}
|
||||
|
||||
/// Mutable access to the currently selected table style.
|
||||
fn tablestyle_mut(&mut self, tab: usize) -> Option<&mut acadrust::objects::TableStyle> {
|
||||
use acadrust::objects::ObjectType;
|
||||
let name = self.tablestyle_selected.clone();
|
||||
self.tabs[tab]
|
||||
.scene
|
||||
.document
|
||||
.objects
|
||||
.values_mut()
|
||||
.find_map(|o| match o {
|
||||
ObjectType::TableStyle(s) if s.name == name => Some(s),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Mutable access to a table style's cell style by row (0=Data,1=Header,2=Title).
|
||||
fn ts_cell_of(
|
||||
s: &mut acadrust::objects::TableStyle,
|
||||
row: u8,
|
||||
) -> Option<&mut acadrust::objects::RowCellStyle> {
|
||||
match row {
|
||||
0 => Some(&mut s.data_row_style),
|
||||
1 => Some(&mut s.header_row_style),
|
||||
2 => Some(&mut s.title_row_style),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Populate margin + per-cell edit buffers from the selected table style.
|
||||
fn load_tablestyle_bufs(&mut self, tab: usize) {
|
||||
use acadrust::objects::ObjectType;
|
||||
let name = self.tablestyle_selected.clone();
|
||||
let Some(s) = self.tabs[tab]
|
||||
.scene
|
||||
.document
|
||||
.objects
|
||||
.values()
|
||||
.find_map(|o| match o {
|
||||
ObjectType::TableStyle(s) if s.name == name => Some(s),
|
||||
_ => None,
|
||||
})
|
||||
else {
|
||||
return;
|
||||
};
|
||||
self.ts_hmargin = format!("{:.4}", s.horizontal_margin);
|
||||
self.ts_vmargin = format!("{:.4}", s.vertical_margin);
|
||||
for (r, c) in [&s.data_row_style, &s.header_row_style, &s.title_row_style]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
self.ts_cell_textstyle[r] = c.text_style_name.clone();
|
||||
self.ts_cell_height[r] = format!("{:.4}", c.text_height);
|
||||
self.ts_cell_textcolor[r] =
|
||||
c.text_color.index().map(|v| v.to_string()).unwrap_or_default();
|
||||
self.ts_cell_fillcolor[r] =
|
||||
c.fill_color.index().map(|v| v.to_string()).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
|
||||
/// Mutable access to the currently selected multileader style.
|
||||
fn mleaderstyle_mut(
|
||||
&mut self,
|
||||
|
||||
@@ -119,6 +119,10 @@ impl OpenCADStudio {
|
||||
selected_style,
|
||||
&self.ts_hmargin,
|
||||
&self.ts_vmargin,
|
||||
&self.ts_cell_textstyle,
|
||||
&self.ts_cell_height,
|
||||
&self.ts_cell_textcolor,
|
||||
&self.ts_cell_fillcolor,
|
||||
);
|
||||
}
|
||||
if Some(window_id) == self.mlstyle_window {
|
||||
|
||||
Reference in new issue
Block a user