feat(tablestyle): complete field coverage (flow, description, cell data + borders)
Table Style editor now exposes every TableStyle / RowCellStyle field: - General: description, flow direction (Down/Up dropdown). - Per cell: data type, unit type, format string, plus all six borders (left/right/top/bottom/horizontal-inside/vertical-inside) with line type (Single/Double), line weight, color (ACI), double-line spacing and a visibility toggle. Border type/visibility apply immediately; the numeric border fields and data/unit/format are written by the existing "Apply cell" button. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
6ae24cceee
commit
10d674f606
4 changed files with 308 additions and 43 deletions
|
|
@ -323,11 +323,21 @@ pub(super) struct OpenCADStudio {
|
|||
/// Edit buffers for the table style's general margins.
|
||||
ts_hmargin: String,
|
||||
ts_vmargin: String,
|
||||
/// General table-style description buffer.
|
||||
ts_description: 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],
|
||||
ts_cell_datatype: [String; 3],
|
||||
ts_cell_unittype: [String; 3],
|
||||
ts_cell_format: [String; 3],
|
||||
/// Per-cell, per-border numeric buffers ([cell][border], border order:
|
||||
/// 0=left 1=right 2=top 3=bottom 4=horizontal-inside 5=vertical-inside).
|
||||
ts_border_lw: [[String; 6]; 3],
|
||||
ts_border_color: [[String; 6]; 3],
|
||||
ts_border_spacing: [[String; 6]; 3],
|
||||
|
||||
// ── TextStyle Font Browser ────────────────────────────────────────────
|
||||
textstyle_selected: String,
|
||||
|
|
@ -1043,6 +1053,26 @@ pub enum Message {
|
|||
},
|
||||
/// Write a cell's edit buffers back into the selected table style.
|
||||
TableStyleCellApply(u8),
|
||||
/// Set the table flow direction from the dropdown.
|
||||
TableStyleSetFlow(String),
|
||||
/// Update a per-cell, per-border numeric edit buffer.
|
||||
TableStyleBorderEdit {
|
||||
cell: u8,
|
||||
border: u8,
|
||||
field: &'static str,
|
||||
value: String,
|
||||
},
|
||||
/// Set a border's line type (Single / Double).
|
||||
TableStyleBorderSetType {
|
||||
cell: u8,
|
||||
border: u8,
|
||||
value: String,
|
||||
},
|
||||
/// Toggle a border's visibility.
|
||||
TableStyleBorderToggleInvisible {
|
||||
cell: u8,
|
||||
border: u8,
|
||||
},
|
||||
// ── MLineStyle Dialog ─────────────────────────────────────────────────
|
||||
MlStyleDialogOpen,
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -1247,10 +1277,17 @@ 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()],
|
||||
ts_description: String::new(),
|
||||
ts_cell_textstyle: Default::default(),
|
||||
ts_cell_height: Default::default(),
|
||||
ts_cell_textcolor: Default::default(),
|
||||
ts_cell_fillcolor: Default::default(),
|
||||
ts_cell_datatype: Default::default(),
|
||||
ts_cell_unittype: Default::default(),
|
||||
ts_cell_format: Default::default(),
|
||||
ts_border_lw: Default::default(),
|
||||
ts_border_color: Default::default(),
|
||||
ts_border_spacing: Default::default(),
|
||||
// MLineStyle dialog
|
||||
mlstyle_selected: "Standard".to_string(),
|
||||
// MLeaderStyle dialog
|
||||
|
|
|
|||
|
|
@ -5755,6 +5755,7 @@ impl OpenCADStudio {
|
|||
match field {
|
||||
"hmargin" => self.ts_hmargin = value,
|
||||
"vmargin" => self.ts_vmargin = value,
|
||||
"description" => self.ts_description = value,
|
||||
_ => {}
|
||||
}
|
||||
Task::none()
|
||||
|
|
@ -5766,6 +5767,7 @@ impl OpenCADStudio {
|
|||
let name = self.tablestyle_selected.clone();
|
||||
let h: Option<f64> = self.ts_hmargin.trim().parse().ok();
|
||||
let v: Option<f64> = self.ts_vmargin.trim().parse().ok();
|
||||
let desc = self.ts_description.clone();
|
||||
self.push_undo_snapshot(i, "TABLESTYLE EDIT");
|
||||
for obj in self.tabs[i].scene.document.objects.values_mut() {
|
||||
if let ObjectType::TableStyle(s) = obj {
|
||||
|
|
@ -5776,6 +5778,7 @@ impl OpenCADStudio {
|
|||
if let Some(v) = v {
|
||||
s.vertical_margin = v;
|
||||
}
|
||||
s.description = desc.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5783,6 +5786,20 @@ impl OpenCADStudio {
|
|||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleSetFlow(value) => {
|
||||
use acadrust::objects::TableFlowDirection;
|
||||
let i = self.active_tab;
|
||||
if let Some(s) = self.tablestyle_mut(i) {
|
||||
s.flow_direction = match value.as_str() {
|
||||
"Up" => TableFlowDirection::Up,
|
||||
_ => TableFlowDirection::Down,
|
||||
};
|
||||
self.push_undo_snapshot(i, "TABLESTYLE EDIT");
|
||||
self.tabs[i].dirty = true;
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleCellEdit { row, field, value } => {
|
||||
let r = row as usize;
|
||||
if r < 3 {
|
||||
|
|
@ -5791,12 +5808,69 @@ impl OpenCADStudio {
|
|||
"height" => self.ts_cell_height[r] = value,
|
||||
"textcolor" => self.ts_cell_textcolor[r] = value,
|
||||
"fillcolor" => self.ts_cell_fillcolor[r] = value,
|
||||
"datatype" => self.ts_cell_datatype[r] = value,
|
||||
"unittype" => self.ts_cell_unittype[r] = value,
|
||||
"format" => self.ts_cell_format[r] = value,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleBorderEdit {
|
||||
cell,
|
||||
border,
|
||||
field,
|
||||
value,
|
||||
} => {
|
||||
let (c, b) = (cell as usize, border as usize);
|
||||
if c < 3 && b < 6 {
|
||||
match field {
|
||||
"lw" => self.ts_border_lw[c][b] = value,
|
||||
"color" => self.ts_border_color[c][b] = value,
|
||||
"spacing" => self.ts_border_spacing[c][b] = value,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleBorderSetType {
|
||||
cell,
|
||||
border,
|
||||
value,
|
||||
} => {
|
||||
use acadrust::objects::TableBorderType;
|
||||
let i = self.active_tab;
|
||||
if let Some(s) = self.tablestyle_mut(i) {
|
||||
if let Some(bd) = Self::ts_cell_of(s, cell).and_then(|c| Self::ts_border_of(c, border))
|
||||
{
|
||||
bd.border_type = match value.as_str() {
|
||||
"Double" => TableBorderType::Double,
|
||||
_ => TableBorderType::Single,
|
||||
};
|
||||
}
|
||||
self.push_undo_snapshot(i, "TABLESTYLE EDIT");
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleBorderToggleInvisible { cell, border } => {
|
||||
let i = self.active_tab;
|
||||
if let Some(s) = self.tablestyle_mut(i) {
|
||||
if let Some(bd) = Self::ts_cell_of(s, cell).and_then(|c| Self::ts_border_of(c, border))
|
||||
{
|
||||
bd.is_invisible = !bd.is_invisible;
|
||||
}
|
||||
self.push_undo_snapshot(i, "TABLESTYLE EDIT");
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::TableStyleCellToggleFill(row) => {
|
||||
let i = self.active_tab;
|
||||
if let Some(s) = self.tablestyle_mut(i) {
|
||||
|
|
@ -5844,6 +5918,18 @@ impl OpenCADStudio {
|
|||
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();
|
||||
let dtype: Option<i32> = self.ts_cell_datatype[r].trim().parse().ok();
|
||||
let utype: Option<i32> = self.ts_cell_unittype[r].trim().parse().ok();
|
||||
let fmt = self.ts_cell_format[r].clone();
|
||||
// Per-border numeric edits for this cell.
|
||||
let border_vals: [(Option<i16>, Option<i16>, Option<f64>); 6] =
|
||||
std::array::from_fn(|b| {
|
||||
(
|
||||
self.ts_border_lw[r][b].trim().parse().ok(),
|
||||
self.ts_border_color[r][b].trim().parse().ok(),
|
||||
self.ts_border_spacing[r][b].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;
|
||||
|
|
@ -5857,6 +5943,26 @@ impl OpenCADStudio {
|
|||
if let Some(v) = fc {
|
||||
c.fill_color = acadrust::types::Color::from_index(v);
|
||||
}
|
||||
if let Some(v) = dtype {
|
||||
c.data_type = v;
|
||||
}
|
||||
if let Some(v) = utype {
|
||||
c.unit_type = v;
|
||||
}
|
||||
c.format_string = fmt;
|
||||
for (b, (lw, color, spacing)) in border_vals.into_iter().enumerate() {
|
||||
if let Some(bd) = Self::ts_border_of(c, b as u8) {
|
||||
if let Some(v) = lw {
|
||||
bd.line_weight = acadrust::types::LineWeight::from_value(v);
|
||||
}
|
||||
if let Some(v) = color {
|
||||
bd.color = acadrust::types::Color::from_index(v);
|
||||
}
|
||||
if let Some(v) = spacing {
|
||||
bd.double_line_spacing = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.push_undo_snapshot(i, "TABLESTYLE EDIT");
|
||||
self.tabs[i].dirty = true;
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
|
|
@ -7115,6 +7221,23 @@ impl OpenCADStudio {
|
|||
}
|
||||
}
|
||||
|
||||
/// Mutable access to a cell's border by index
|
||||
/// (0=left 1=right 2=top 3=bottom 4=horizontal-inside 5=vertical-inside).
|
||||
fn ts_border_of(
|
||||
c: &mut acadrust::objects::RowCellStyle,
|
||||
border: u8,
|
||||
) -> Option<&mut acadrust::objects::TableCellBorder> {
|
||||
match border {
|
||||
0 => Some(&mut c.left_border),
|
||||
1 => Some(&mut c.right_border),
|
||||
2 => Some(&mut c.top_border),
|
||||
3 => Some(&mut c.bottom_border),
|
||||
4 => Some(&mut c.horizontal_inside_border),
|
||||
5 => Some(&mut c.vertical_inside_border),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Populate margin + per-cell edit buffers from the selected table style.
|
||||
fn load_tablestyle_bufs(&mut self, tab: usize) {
|
||||
use acadrust::objects::ObjectType;
|
||||
|
|
@ -7133,6 +7256,7 @@ impl OpenCADStudio {
|
|||
};
|
||||
self.ts_hmargin = format!("{:.4}", s.horizontal_margin);
|
||||
self.ts_vmargin = format!("{:.4}", s.vertical_margin);
|
||||
self.ts_description = s.description.clone();
|
||||
for (r, c) in [&s.data_row_style, &s.header_row_style, &s.title_row_style]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
|
|
@ -7143,6 +7267,23 @@ impl OpenCADStudio {
|
|||
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();
|
||||
self.ts_cell_datatype[r] = c.data_type.to_string();
|
||||
self.ts_cell_unittype[r] = c.unit_type.to_string();
|
||||
self.ts_cell_format[r] = c.format_string.clone();
|
||||
let borders = [
|
||||
&c.left_border,
|
||||
&c.right_border,
|
||||
&c.top_border,
|
||||
&c.bottom_border,
|
||||
&c.horizontal_inside_border,
|
||||
&c.vertical_inside_border,
|
||||
];
|
||||
for (b, bd) in borders.into_iter().enumerate() {
|
||||
self.ts_border_lw[r][b] = bd.line_weight.value().to_string();
|
||||
self.ts_border_color[r][b] =
|
||||
bd.color.index().map(|v| v.to_string()).unwrap_or_default();
|
||||
self.ts_border_spacing[r][b] = format!("{:.4}", bd.double_line_spacing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -119,10 +119,17 @@ impl OpenCADStudio {
|
|||
selected_style,
|
||||
&self.ts_hmargin,
|
||||
&self.ts_vmargin,
|
||||
&self.ts_description,
|
||||
&self.ts_cell_textstyle,
|
||||
&self.ts_cell_height,
|
||||
&self.ts_cell_textcolor,
|
||||
&self.ts_cell_fillcolor,
|
||||
&self.ts_cell_datatype,
|
||||
&self.ts_cell_unittype,
|
||||
&self.ts_cell_format,
|
||||
&self.ts_border_lw,
|
||||
&self.ts_border_color,
|
||||
&self.ts_border_spacing,
|
||||
);
|
||||
}
|
||||
if Some(window_id) == self.mlstyle_window {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
use crate::app::Message;
|
||||
use iced::widget::{
|
||||
button, checkbox, column, container, pick_list, row, scrollable, text, text_input, Space,
|
||||
button, checkbox, column, container, pick_list, row, scrollable, text, text_input, Column,
|
||||
Space,
|
||||
};
|
||||
use iced::{Background, Border, Color, Element, Fill, Theme};
|
||||
|
||||
|
|
@ -133,10 +134,17 @@ pub fn view_window<'a>(
|
|||
selected_style: Option<&'a acadrust::objects::TableStyle>,
|
||||
hmargin_buf: &'a str,
|
||||
vmargin_buf: &'a str,
|
||||
description_buf: &'a str,
|
||||
cell_textstyle: &'a [String; 3],
|
||||
cell_height: &'a [String; 3],
|
||||
cell_textcolor: &'a [String; 3],
|
||||
cell_fillcolor: &'a [String; 3],
|
||||
cell_datatype: &'a [String; 3],
|
||||
cell_unittype: &'a [String; 3],
|
||||
cell_format: &'a [String; 3],
|
||||
border_lw: &'a [[String; 6]; 3],
|
||||
border_color: &'a [[String; 6]; 3],
|
||||
border_spacing: &'a [[String; 6]; 3],
|
||||
) -> Element<'a, Message> {
|
||||
// ── Toolbar ───────────────────────────────────────────────────────────
|
||||
let toolbar = container(
|
||||
|
|
@ -235,48 +243,99 @@ pub fn view_window<'a>(
|
|||
.align_y(iced::Center)
|
||||
.into()
|
||||
};
|
||||
column![
|
||||
text(row_label).size(11).color(ACCENT),
|
||||
cell_in(" Text style:", "Standard", &cell_textstyle[r], "textstyle"),
|
||||
cell_in(" Text height:", "0.18", &cell_height[r], "height"),
|
||||
cell_in(" Text color (ACI):", "256", &cell_textcolor[r], "textcolor"),
|
||||
cell_in(" Fill color (ACI):", "256", &cell_fillcolor[r], "fillcolor"),
|
||||
row![
|
||||
text(" Alignment:").size(11).color(DIM).width(150),
|
||||
pick_list(
|
||||
[
|
||||
"TopLeft",
|
||||
"TopCenter",
|
||||
"TopRight",
|
||||
"MiddleLeft",
|
||||
"MiddleCenter",
|
||||
"MiddleRight",
|
||||
"BottomLeft",
|
||||
"BottomCenter",
|
||||
"BottomRight",
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>(),
|
||||
Some(format!("{:?}", rs.alignment)),
|
||||
move |value| Message::TableStyleCellSetAlign { row, value },
|
||||
)
|
||||
.text_size(11)
|
||||
.width(140),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
checkbox(rs.fill_enabled)
|
||||
.label(" Background fill enabled")
|
||||
.on_toggle(move |_| Message::TableStyleCellToggleFill(row))
|
||||
.size(14)
|
||||
.text_size(11),
|
||||
let mut col = Column::new()
|
||||
.spacing(3)
|
||||
.push(text(row_label).size(11).color(ACCENT))
|
||||
.push(cell_in(" Text style:", "Standard", &cell_textstyle[r], "textstyle"))
|
||||
.push(cell_in(" Text height:", "0.18", &cell_height[r], "height"))
|
||||
.push(cell_in(" Text color (ACI):", "256", &cell_textcolor[r], "textcolor"))
|
||||
.push(cell_in(" Fill color (ACI):", "256", &cell_fillcolor[r], "fillcolor"))
|
||||
.push(
|
||||
row![
|
||||
text(" Alignment:").size(11).color(DIM).width(150),
|
||||
pick_list(
|
||||
[
|
||||
"TopLeft",
|
||||
"TopCenter",
|
||||
"TopRight",
|
||||
"MiddleLeft",
|
||||
"MiddleCenter",
|
||||
"MiddleRight",
|
||||
"BottomLeft",
|
||||
"BottomCenter",
|
||||
"BottomRight",
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>(),
|
||||
Some(format!("{:?}", rs.alignment)),
|
||||
move |value| Message::TableStyleCellSetAlign { row, value },
|
||||
)
|
||||
.text_size(11)
|
||||
.width(140),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.push(
|
||||
checkbox(rs.fill_enabled)
|
||||
.label(" Background fill enabled")
|
||||
.on_toggle(move |_| Message::TableStyleCellToggleFill(row))
|
||||
.size(14)
|
||||
.text_size(11),
|
||||
)
|
||||
.push(cell_in(" Data type:", "0", &cell_datatype[r], "datatype"))
|
||||
.push(cell_in(" Unit type:", "0", &cell_unittype[r], "unittype"))
|
||||
.push(cell_in(" Format string:", "", &cell_format[r], "format"))
|
||||
.push(text(" Borders (type / weight / color / spacing / hidden)").size(10).color(DIM));
|
||||
|
||||
let borders: [(&'static str, &acadrust::objects::TableCellBorder); 6] = [
|
||||
("L", &rs.left_border),
|
||||
("R", &rs.right_border),
|
||||
("T", &rs.top_border),
|
||||
("B", &rs.bottom_border),
|
||||
("H", &rs.horizontal_inside_border),
|
||||
("V", &rs.vertical_inside_border),
|
||||
];
|
||||
for (b, (bname, bd)) in borders.into_iter().enumerate() {
|
||||
let bu = b as u8;
|
||||
col = col.push(
|
||||
row![
|
||||
text(format!(" {bname}")).size(11).color(DIM).width(28),
|
||||
pick_list(
|
||||
["Single", "Double"].iter().map(|s| s.to_string()).collect::<Vec<_>>(),
|
||||
Some(format!("{:?}", bd.border_type)),
|
||||
move |value| Message::TableStyleBorderSetType { cell: row, border: bu, value },
|
||||
)
|
||||
.text_size(10)
|
||||
.width(74),
|
||||
text_input("wt", &border_lw[r][b])
|
||||
.on_input(move |v| Message::TableStyleBorderEdit { cell: row, border: bu, field: "lw", value: v })
|
||||
.size(10)
|
||||
.width(46),
|
||||
text_input("clr", &border_color[r][b])
|
||||
.on_input(move |v| Message::TableStyleBorderEdit { cell: row, border: bu, field: "color", value: v })
|
||||
.size(10)
|
||||
.width(46),
|
||||
text_input("gap", &border_spacing[r][b])
|
||||
.on_input(move |v| Message::TableStyleBorderEdit { cell: row, border: bu, field: "spacing", value: v })
|
||||
.size(10)
|
||||
.width(46),
|
||||
checkbox(bd.is_invisible)
|
||||
.on_toggle(move |_| Message::TableStyleBorderToggleInvisible { cell: row, border: bu })
|
||||
.size(13),
|
||||
]
|
||||
.spacing(5)
|
||||
.align_y(iced::Center),
|
||||
);
|
||||
}
|
||||
|
||||
col.push(
|
||||
button(text("Apply cell").size(11))
|
||||
.on_press(Message::TableStyleCellApply(row))
|
||||
.style(btn_s(true))
|
||||
.padding([4, 12]),
|
||||
]
|
||||
.spacing(3)
|
||||
)
|
||||
.into()
|
||||
};
|
||||
|
||||
|
|
@ -284,6 +343,27 @@ pub fn view_window<'a>(
|
|||
scrollable(
|
||||
column![
|
||||
info_row("Name:", s.name.clone()),
|
||||
row![
|
||||
text("Description:").size(11).color(DIM).width(160),
|
||||
text_input("", description_buf)
|
||||
.on_input(|v| Message::TableStyleEdit { field: "description", value: v })
|
||||
.size(11)
|
||||
.width(160),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
row![
|
||||
text("Flow direction:").size(11).color(DIM).width(160),
|
||||
pick_list(
|
||||
["Down", "Up"].iter().map(|s| s.to_string()).collect::<Vec<_>>(),
|
||||
Some(format!("{:?}", s.flow_direction)),
|
||||
Message::TableStyleSetFlow,
|
||||
)
|
||||
.text_size(11)
|
||||
.width(100),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
checkbox(s.annotative)
|
||||
.label("Annotative")
|
||||
.on_toggle(|_| Message::TableStyleToggleAnnotative)
|
||||
|
|
|
|||
Loading…
Reference in a new issue