feat(styles): overhaul style managers

Unify editor layouts, live previews, comparisons, read-only behavior, and localized controls across all named style managers.

Refs #629
This commit is contained in:
Hakan Seven committed 2026-08-03 02:01:47 +03:00
1 parent d06a1022f2
commit 25515fa33c
27 files changed
+5506 -1662

No files matched your search

+60 -1
View File
@@ -670,9 +670,18 @@ pub(super) struct OpenCADStudio {
// ── MLineStyle Dialog ─────────────────────────────────────────────────
mlstyle_selected: String,
mlstyle_tab: u8,
mlstyle_compare: String,
mln_description: String,
mln_start_angle: String,
mln_end_angle: String,
mln_fill_color: String,
mln_elements: Vec<[String; 3]>,
// ── MLeaderStyle Dialog ───────────────────────────────────────────────
mleaderstyle_selected: String,
mleaderstyle_tab: u8,
mleaderstyle_compare: String,
/// Colour field whose expanded palette is open (line/text/block).
mls_color_open: Option<&'static str>,
mls_landing_distance: String,
@@ -697,6 +706,8 @@ pub(super) struct OpenCADStudio {
// ── TableStyle Dialog ─────────────────────────────────────────────────
tablestyle_selected: String,
tablestyle_tab: u8,
tablestyle_compare: String,
/// Edit buffers for the table style's general margins.
ts_hmargin: String,
ts_vmargin: String,
@@ -732,6 +743,8 @@ pub(super) struct OpenCADStudio {
// ── TextStyle Font Browser ────────────────────────────────────────────
textstyle_selected: String,
textstyle_tab: u8,
textstyle_compare: String,
/// Edit buffer for font file name.
textstyle_font: String,
/// Edit buffer for width factor.
@@ -868,8 +881,10 @@ pub(super) struct OpenCADStudio {
dimstyle_selected: String,
/// Which colour field currently has its expanded palette open (if any).
ds_color_open: Option<DsField>,
/// Active tab: 0=Lines, 1=Arrows, 2=Text, 3=Scale/Units, 4=Tolerances.
/// Active property group in the dimension style manager.
dimstyle_tab: u8,
/// Style used by the manager's comparison summary.
dimstyle_compare: String,
// Edit buffers (strings while typing):
ds_dimdle: String,
ds_dimdli: String,
@@ -2438,6 +2453,8 @@ pub enum Message {
#[allow(dead_code)]
TextStyleDialogClose,
TextStyleDialogSelect(String),
TextStyleDialogTab(u8),
TextStyleDialogCompare(String),
TextStyleDialogSetCurrent,
TextStyleDialogNew,
TextStyleDialogCopy,
@@ -2465,6 +2482,8 @@ pub enum Message {
#[allow(dead_code)]
TableStyleDialogClose,
TableStyleDialogSelect(String),
TableStyleDialogTab(u8),
TableStyleDialogCompare(String),
TableStyleDialogNew,
TableStyleDialogCopy,
TableStyleDialogDelete,
@@ -2523,16 +2542,32 @@ pub enum Message {
#[allow(dead_code)]
MlStyleDialogClose,
MlStyleDialogSelect(String),
MlStyleDialogTab(u8),
MlStyleDialogCompare(String),
MlStyleDialogSetCurrent,
MlStyleApply,
MlStyleDialogNew,
MlStyleDialogCopy,
MlStyleDialogDelete,
MlStyleEdit {
field: &'static str,
value: String,
},
MlStyleToggle(&'static str),
MlStyleElementEdit {
index: usize,
field: &'static str,
value: String,
},
MlStyleElementAdd,
MlStyleElementDelete(usize),
// ── MLeaderStyle Dialog ───────────────────────────────────────────────
MLeaderStyleDialogOpen,
#[allow(dead_code)]
MLeaderStyleDialogClose,
MLeaderStyleDialogSelect(String),
MLeaderStyleDialogTab(u8),
MLeaderStyleDialogCompare(String),
MLeaderStyleDialogSetCurrent,
MLeaderStyleDialogNew,
MLeaderStyleDialogCopy,
@@ -2565,6 +2600,8 @@ pub enum Message {
DimStyleDialogSelect(String),
/// Switch the active tab.
DimStyleDialogTab(u8),
/// Change the style used by the comparison summary.
DimStyleDialogCompare(String),
/// Create a new empty style (prompts via command line).
DimStyleDialogNew,
DimStyleDialogCopy,
@@ -2575,6 +2612,14 @@ pub enum Message {
// Field edit messages:
DsEdit(DsField, String),
DsToggle(DsField),
/// Select the mutually-exclusive tolerance presentation.
DsToleranceMode(String),
/// Change the feet/inches mode in a zero-suppression bit field.
DsZeroBase(DsField, i16),
/// Toggle leading/trailing suppression in a zero-suppression bit field.
DsZeroFlag(DsField, i16),
/// Select no center mark, a mark, or centerlines.
DsCenterMarkMode(String),
/// Toggle the expanded colour palette for a DimStyle colour field.
DsColorMore(DsField),
/// Open the `iced_aw` colour picker for a field and its current colour.
@@ -2887,6 +2932,8 @@ impl OpenCADStudio {
style_rename_buf: String::new(),
style_stage: None,
textstyle_selected: "Standard".to_string(),
textstyle_tab: 0,
textstyle_compare: String::new(),
textstyle_font: String::new(),
textstyle_width: "1.0".to_string(),
textstyle_oblique: "0.0".to_string(),
@@ -2895,6 +2942,8 @@ impl OpenCADStudio {
textstyle_ttf: String::new(),
// TableStyle dialog
tablestyle_selected: "Standard".to_string(),
tablestyle_tab: 0,
tablestyle_compare: String::new(),
ts_hmargin: "1.5".to_string(),
ts_vmargin: "1.5".to_string(),
ts_description: String::new(),
@@ -2911,8 +2960,17 @@ impl OpenCADStudio {
ts_border_spacing: Default::default(),
// MLineStyle dialog
mlstyle_selected: "Standard".to_string(),
mlstyle_tab: 0,
mlstyle_compare: String::new(),
mln_description: String::new(),
mln_start_angle: "90".to_string(),
mln_end_angle: "90".to_string(),
mln_fill_color: "256".to_string(),
mln_elements: Vec::new(),
// MLeaderStyle dialog
mleaderstyle_selected: "Standard".to_string(),
mleaderstyle_tab: 0,
mleaderstyle_compare: String::new(),
mls_color_open: None,
mls_landing_distance: String::new(),
mls_landing_gap: String::new(),
@@ -2937,6 +2995,7 @@ impl OpenCADStudio {
dimstyle_selected: "Standard".to_string(),
ds_color_open: None,
dimstyle_tab: 0,
dimstyle_compare: String::new(),
ds_dimdle: "0".to_string(),
ds_dimdli: "3.75".to_string(),
ds_dimgap: "0.625".to_string(),
+29 -1
View File
@@ -301,7 +301,7 @@ impl OpenCADStudio {
}
}
fn style_in_use(&self, kind: StyleKind, name: &str) -> bool {
pub(super) fn style_in_use(&self, kind: StyleKind, name: &str) -> bool {
use acadrust::entities::EntityType;
let i = self.active_tab;
@@ -613,6 +613,20 @@ impl OpenCADStudio {
pub(super) fn style_delete(&mut self, kind: StyleKind) {
let name = self.style_selected(kind);
if matches!(kind, StyleKind::Dim)
&& self.tabs[self.active_tab]
.scene
.document
.dim_styles
.get(&name)
.is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
})
{
self.command_line
.push_error(crate::t!("Referenced styles are read only.").as_ref());
return;
}
if name.eq_ignore_ascii_case("Standard") {
self.command_line
.push_error(crate::t!("Cannot delete the Standard style.").as_ref());
@@ -657,6 +671,20 @@ impl OpenCADStudio {
if new.is_empty() || new.eq_ignore_ascii_case(&old) {
return;
}
if matches!(kind, StyleKind::Dim)
&& self.tabs[self.active_tab]
.scene
.document
.dim_styles
.get(&old)
.is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
})
{
self.command_line
.push_error(crate::t!("Referenced styles are read only.").as_ref());
return;
}
if old.eq_ignore_ascii_case("Standard") {
self.command_line
.push_error(crate::t!("Cannot rename the Standard style.").as_ref());
+208 -8
View File
@@ -5408,11 +5408,25 @@ impl OpenCADStudio {
self.load_textstyle_bufs(i);
Task::none()
}
Message::TextStyleDialogTab(tab) => {
self.textstyle_tab = tab;
Task::none()
}
Message::TextStyleDialogCompare(name) => {
self.textstyle_compare = name;
Task::none()
}
Message::TextStyleDialogSetCurrent => {
// Staged: persists on Apply.
let i = self.active_tab;
let name = self.textstyle_selected.clone();
if self.tabs[i].scene.document.text_styles.get(&name).is_some() {
if self.tabs[i]
.scene
.document
.text_styles
.get(&name)
.is_some_and(|style| !style.xref_dependent)
{
self.tabs[i].scene.document.header.current_text_style_name = name.clone();
self.sync_ribbon_styles();
self.command_line
@@ -5468,9 +5482,13 @@ impl OpenCADStudio {
let i = self.active_tab;
let name = self.textstyle_selected.clone();
if let Some(s) = self.tabs[i].scene.document.text_styles.get_mut(&name) {
if s.xref_dependent {
return Task::none();
}
match field {
"backward" => s.flags.backward = !s.flags.backward,
"upside_down" => s.flags.upside_down = !s.flags.upside_down,
"vertical" => s.is_vertical = !s.is_vertical,
"annotative" => s.annotative = !s.annotative,
_ => {}
}
@@ -5481,8 +5499,17 @@ impl OpenCADStudio {
Message::TextStyleFontPick(font_file) => {
// Staged: update the buffer + live style; persist on Apply.
let i = self.active_tab;
self.textstyle_font = font_file.clone();
let name = self.textstyle_selected.clone();
if self.tabs[i]
.scene
.document
.text_styles
.get(&name)
.is_some_and(|style| style.xref_dependent)
{
return Task::none();
}
self.textstyle_font = font_file.clone();
if let Some(s) = self.tabs[i].scene.document.text_styles.get_mut(&name) {
s.font_file = font_file;
}
@@ -5516,12 +5543,23 @@ impl OpenCADStudio {
Task::none()
}
Message::TableStyleDialogSelect(name) => {
for row in 0..3 {
let _ = self.on_table_style_cell_apply(row);
}
self.stage_tablestyle_bufs();
self.tablestyle_selected = name;
let i = self.active_tab;
self.load_tablestyle_bufs(i);
Task::none()
}
Message::TableStyleDialogTab(tab) => {
self.tablestyle_tab = tab;
Task::none()
}
Message::TableStyleDialogCompare(name) => {
self.tablestyle_compare = name;
Task::none()
}
Message::TableStyleEdit { field, value } => {
match field {
@@ -5534,6 +5572,9 @@ impl OpenCADStudio {
}
Message::TableStyleApply => {
for row in 0..3 {
let _ = self.on_table_style_cell_apply(row);
}
self.stage_tablestyle_bufs();
self.style_stage_commit();
Task::none()
@@ -5728,7 +5769,18 @@ impl OpenCADStudio {
Task::none()
}
Message::MlStyleDialogSelect(name) => {
self.stage_mlstyle_bufs();
self.mlstyle_selected = name;
let i = self.active_tab;
self.load_mlstyle_bufs(i);
Task::none()
}
Message::MlStyleDialogTab(tab) => {
self.mlstyle_tab = tab;
Task::none()
}
Message::MlStyleDialogCompare(name) => {
self.mlstyle_compare = name;
Task::none()
}
Message::MlStyleDialogSetCurrent => {
@@ -5749,13 +5801,8 @@ impl OpenCADStudio {
}
Task::none()
}
// Placeholder so the Multiline manager has the same Set Current +
// Apply pair as every other style manager. The editor is currently
// read-only, so there is nothing to apply yet — wire this up when
// editable MLineStyle properties land.
Message::MlStyleApply => {
// Multiline styles have no editable properties yet; Apply still
// commits any staged structural / current-style changes.
self.stage_mlstyle_bufs();
self.style_stage_commit();
Task::none()
}
@@ -5771,6 +5818,66 @@ impl OpenCADStudio {
self.style_delete(crate::app::StyleKind::MLine);
Task::none()
}
Message::MlStyleEdit { field, value } => {
match field {
"description" => self.mln_description = value,
"start_angle" => self.mln_start_angle = value,
"end_angle" => self.mln_end_angle = value,
"fill_color" => self.mln_fill_color = value,
_ => {}
}
self.stage_mlstyle_bufs();
Task::none()
}
Message::MlStyleToggle(field) => {
let i = self.active_tab;
if let Some(style) = self.mlstyle_mut(i) {
match field {
"fill" => style.flags.fill_on = !style.flags.fill_on,
"joints" => style.flags.display_joints = !style.flags.display_joints,
"start_square" => style.flags.start_square_cap = !style.flags.start_square_cap,
"start_inner" => style.flags.start_inner_arcs_cap = !style.flags.start_inner_arcs_cap,
"start_round" => style.flags.start_round_cap = !style.flags.start_round_cap,
"end_square" => style.flags.end_square_cap = !style.flags.end_square_cap,
"end_inner" => style.flags.end_inner_arcs_cap = !style.flags.end_inner_arcs_cap,
"end_round" => style.flags.end_round_cap = !style.flags.end_round_cap,
_ => {}
}
}
Task::none()
}
Message::MlStyleElementEdit { index, field, value } => {
if let Some(element) = self.mln_elements.get_mut(index) {
match field {
"offset" => element[0] = value,
"color" => element[1] = value,
"linetype" => element[2] = value,
_ => {}
}
}
self.stage_mlstyle_bufs();
Task::none()
}
Message::MlStyleElementAdd => {
let i = self.active_tab;
if let Some(style) = self.mlstyle_mut(i) {
style
.elements
.push(acadrust::objects::MLineStyleElement::default());
}
self.load_mlstyle_bufs(i);
Task::none()
}
Message::MlStyleElementDelete(index) => {
let i = self.active_tab;
if let Some(style) = self.mlstyle_mut(i) {
if style.elements.len() > 1 && index < style.elements.len() {
style.elements.remove(index);
}
}
self.load_mlstyle_bufs(i);
Task::none()
}
// ── MLeaderStyle Dialog ───────────────────────────────────────────
Message::MLeaderStyleDialogOpen => self.on_mleader_style_dialog_open(),
@@ -5785,6 +5892,14 @@ impl OpenCADStudio {
self.load_mleaderstyle_bufs(i);
Task::none()
}
Message::MLeaderStyleDialogTab(tab) => {
self.mleaderstyle_tab = tab;
Task::none()
}
Message::MLeaderStyleDialogCompare(name) => {
self.mleaderstyle_compare = name;
Task::none()
}
Message::MLeaderStyleDialogSetCurrent => self.on_mleader_style_dialog_set_current(),
Message::MLeaderStyleDialogNew => {
self.style_new(crate::app::StyleKind::MLeader);
@@ -5864,6 +5979,10 @@ impl OpenCADStudio {
self.dimstyle_tab = tab;
Task::none()
}
Message::DimStyleDialogCompare(name) => {
self.dimstyle_compare = name;
Task::none()
}
Message::DimStyleDialogNew => {
self.style_new(crate::app::StyleKind::Dim);
Task::none()
@@ -5875,6 +5994,19 @@ impl OpenCADStudio {
Message::DimStyleDialogSetCurrent => {
// Staged: persists on Apply.
let i = self.active_tab;
let read_only = self.tabs[i]
.scene
.document
.dim_styles
.get(&self.dimstyle_selected)
.is_some_and(|style| {
style.xref_reference
|| style.xref_dependent
|| !style.xref_handle.is_null()
});
if read_only {
return Task::none();
}
self.tabs[i].scene.document.header.current_dimstyle_name =
self.dimstyle_selected.clone();
self.sync_ribbon_styles();
@@ -5894,7 +6026,75 @@ impl OpenCADStudio {
Task::none()
}
Message::DsToggle(field) => {
let separate_arrows = field == crate::app::DsField::Dimsah;
self.apply_ds_toggle(field);
if separate_arrows && self.ds_dimsah {
let i = self.active_tab;
if let Some(style) = self.tabs[i]
.scene
.document
.dim_styles
.get_mut(&self.dimstyle_selected)
{
if style.dimblk1.is_null() {
style.dimblk1 = style.dimblk;
}
if style.dimblk2.is_null() {
style.dimblk2 = style.dimblk1;
}
}
}
Task::none()
}
Message::DsToleranceMode(mode) => {
self.ds_dimlim = mode == "limits";
self.ds_dimtol = matches!(mode.as_str(), "symmetrical" | "deviation");
if mode == "symmetrical" {
self.ds_dimtm = self.ds_dimtp.clone();
}
let gap = self.ds_dimgap.trim().parse::<f64>().unwrap_or(0.625).abs();
self.ds_dimgap = if mode == "basic" {
format!("-{}", gap.max(f64::EPSILON))
} else {
format!("{}", gap)
};
Task::none()
}
Message::DsZeroBase(field, base) => {
let current = match &field {
crate::app::DsField::Dimzin => &self.ds_dimzin,
crate::app::DsField::Dimaltz => &self.ds_dimaltz,
crate::app::DsField::Dimalttz => &self.ds_dimalttz,
crate::app::DsField::Dimtzin => &self.ds_dimtzin,
_ => return Task::none(),
}
.trim()
.parse::<i16>()
.unwrap_or(0);
self.apply_ds_edit(field, ((current & !3) | (base & 3)).to_string());
Task::none()
}
Message::DsZeroFlag(field, bit) => {
let current = match &field {
crate::app::DsField::Dimzin => &self.ds_dimzin,
crate::app::DsField::Dimaltz => &self.ds_dimaltz,
crate::app::DsField::Dimalttz => &self.ds_dimalttz,
crate::app::DsField::Dimtzin => &self.ds_dimtzin,
_ => return Task::none(),
}
.trim()
.parse::<i16>()
.unwrap_or(0);
self.apply_ds_edit(field, (current ^ bit).to_string());
Task::none()
}
Message::DsCenterMarkMode(mode) => {
let size = self.ds_dimcen.trim().parse::<f64>().unwrap_or(0.09).abs();
self.ds_dimcen = match mode.as_str() {
"mark" => size.max(f64::EPSILON).to_string(),
"lines" => format!("-{}", size.max(f64::EPSILON)),
_ => "0".to_string(),
};
Task::none()
}
Message::DsColorMore(field) => {
+140 -9
View File
@@ -22,6 +22,91 @@ use iced::{mouse, Point, Task};
impl OpenCADStudio {
pub(in crate::app) fn mlstyle_mut(
&mut self,
tab: usize,
) -> Option<&mut acadrust::objects::MLineStyle> {
use acadrust::objects::ObjectType;
let name = self.mlstyle_selected.clone();
self.tabs[tab]
.scene
.document
.objects
.values_mut()
.find_map(|object| match object {
ObjectType::MLineStyle(style) if style.name == name => Some(style),
_ => None,
})
}
pub(in crate::app) fn load_mlstyle_bufs(&mut self, tab: usize) {
use acadrust::objects::ObjectType;
let name = self.mlstyle_selected.clone();
let Some((description, start_angle, end_angle, fill_color, elements)) = self.tabs[tab]
.scene
.document
.objects
.values()
.find_map(|object| match object {
ObjectType::MLineStyle(style) if style.name == name => Some((
style.description.clone(),
style.start_angle.to_degrees(),
style.end_angle.to_degrees(),
style.fill_color.index().unwrap_or(256),
style
.elements
.iter()
.map(|element| {
[
format!("{}", element.offset),
element.color.index().unwrap_or(256).to_string(),
element.linetype.clone(),
]
})
.collect::<Vec<_>>(),
)),
_ => None,
})
else {
return;
};
self.mln_description = description;
self.mln_start_angle = format!("{start_angle:.4}");
self.mln_end_angle = format!("{end_angle:.4}");
self.mln_fill_color = fill_color.to_string();
self.mln_elements = elements;
}
pub(in crate::app) fn stage_mlstyle_bufs(&mut self) {
let tab = self.active_tab;
let description = self.mln_description.clone();
let start_angle = self.mln_start_angle.trim().parse::<f64>().ok();
let end_angle = self.mln_end_angle.trim().parse::<f64>().ok();
let fill_color = self.mln_fill_color.trim().parse::<i16>().ok();
let elements = self.mln_elements.clone();
if let Some(style) = self.mlstyle_mut(tab) {
style.description = description;
if let Some(value) = start_angle {
style.start_angle = value.to_radians();
}
if let Some(value) = end_angle {
style.end_angle = value.to_radians();
}
if let Some(value) = fill_color {
style.fill_color = acadrust::types::Color::from_index(value);
}
for (element, values) in style.elements.iter_mut().zip(elements) {
if let Ok(value) = values[0].trim().parse::<f64>() {
element.offset = value;
}
if let Ok(value) = values[1].trim().parse::<i16>() {
element.color = acadrust::types::Color::from_index(value);
}
element.linetype = values[2].clone();
}
}
}
pub(in crate::app) fn tablestyle_mut(&mut self, tab: usize) -> Option<&mut acadrust::objects::TableStyle> {
use acadrust::objects::ObjectType;
let name = self.tablestyle_selected.clone();
@@ -163,8 +248,8 @@ impl OpenCADStudio {
self.mls_text_height = format!("{:.4}", s.text_height);
self.mls_scale_factor = format!("{:.4}", s.scale_factor);
self.mls_break_gap = format!("{:.4}", s.break_gap_size);
self.mls_first_seg_angle = format!("{:.4}", s.first_segment_angle);
self.mls_second_seg_angle = format!("{:.4}", s.second_segment_angle);
self.mls_first_seg_angle = format!("{:.4}", s.first_segment_angle.to_degrees());
self.mls_second_seg_angle = format!("{:.4}", s.second_segment_angle.to_degrees());
self.mls_max_points = s.max_leader_points.to_string();
self.mls_default_text = s.default_text.clone();
self.mls_line_color = s
@@ -184,7 +269,7 @@ impl OpenCADStudio {
.index()
.map(|c| c.to_string())
.unwrap_or_default();
self.mls_block_rotation = format!("{:.4}", s.block_content_rotation);
self.mls_block_rotation = format!("{:.4}", s.block_content_rotation.to_degrees());
self.mls_block_scale_x = format!("{:.4}", s.block_content_scale_x);
self.mls_block_scale_y = format!("{:.4}", s.block_content_scale_y);
self.mls_block_scale_z = format!("{:.4}", s.block_content_scale_z);
@@ -273,6 +358,20 @@ impl OpenCADStudio {
pub(in crate::app) fn apply_dimstyle_bufs(&mut self, tab: usize) {
let doc = &mut self.tabs[tab].scene.document;
let read_only = doc
.dim_styles
.get(&self.dimstyle_selected)
.is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
});
if read_only {
return;
}
let text_style_handle = doc
.text_styles
.get(&self.ds_dimtxsty)
.map(|style| style.handle)
.unwrap_or(acadrust::types::Handle::NULL);
let Some(ds) = doc.dim_styles.get_mut(&self.dimstyle_selected) else {
return;
};
@@ -323,6 +422,7 @@ impl OpenCADStudio {
ds.dimlim = self.ds_dimlim;
ds.dimpost = self.ds_dimpost.clone();
ds.dimtxsty = self.ds_dimtxsty.clone();
ds.dimtxsty_handle = text_style_handle;
ds.annotative = self.ds_annotative;
set_i16!(dimclrd, self.ds_dimclrd);
set_i16!(dimlwd, self.ds_dimlwd);
@@ -392,7 +492,15 @@ impl OpenCADStudio {
Dimlunit => self.ds_dimlunit = val,
Dimdec => self.ds_dimdec = val,
Dimpost => self.ds_dimpost = val,
Dimtp => self.ds_dimtp = val,
Dimtp => {
let symmetrical = self.ds_dimtol
&& !self.ds_dimlim
&& self.ds_dimtp.trim() == self.ds_dimtm.trim();
self.ds_dimtp = val.clone();
if symmetrical {
self.ds_dimtm = val;
}
}
Dimtm => self.ds_dimtm = val,
Dimtdec => self.ds_dimtdec = val,
Dimtfac => self.ds_dimtfac = val,
@@ -518,6 +626,9 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
let bigfont = self.textstyle_bigfont.clone();
let ttf = self.textstyle_ttf.clone();
if let Some(s) = self.tabs[i].scene.document.text_styles.get_mut(&name) {
if s.xref_dependent {
return;
}
s.font_file = font;
s.big_font_file = bigfont;
s.true_type_font = ttf;
@@ -629,6 +740,7 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
.unwrap_or_else(|| "Standard".to_string())
};
self.active_modal = Some(crate::app::ModalKind::MlStyle);
self.load_mlstyle_bufs(i);
self.style_stage_begin();
Task::none()
}
@@ -818,7 +930,10 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
pub(super) fn on_mleader_style_set_handle(&mut self, field: &'static str, value: String) -> Task<Message> {
let i = self.active_tab;
let doc = &self.tabs[i].scene.document;
let handle: Option<acadrust::types::Handle> = if value == "None" {
let handle: Option<acadrust::types::Handle> = if value == "None"
|| value == "ByBlock"
|| value == "Closed filled"
{
None
} else {
match field {
@@ -897,10 +1012,10 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
s.break_gap_size = v;
}
if let Some(v) = fsa {
s.first_segment_angle = v;
s.first_segment_angle = v.to_radians();
}
if let Some(v) = ssa {
s.second_segment_angle = v;
s.second_segment_angle = v.to_radians();
}
if let Some(v) = mp {
s.max_leader_points = v;
@@ -920,7 +1035,7 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
s.block_content_color = acadrust::types::Color::from_index(v);
}
if let Some(v) = brot {
s.block_content_rotation = v;
s.block_content_rotation = v.to_radians();
}
if let Some(v) = bsx {
s.block_content_scale_x = v;
@@ -962,6 +1077,14 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
.unwrap_or_else(|| "Standard".to_string())
};
self.dimstyle_selected = selected.clone();
self.dimstyle_compare = self.tabs[i]
.scene
.document
.dim_styles
.iter()
.map(|style| style.name.clone())
.find(|name| !name.eq_ignore_ascii_case(&selected))
.unwrap_or_default();
self.load_dimstyle_bufs(i);
self.active_modal = Some(crate::app::ModalKind::DimStyle);
self.style_stage_begin();
@@ -1018,6 +1141,11 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
"dimltex_handle" | "dimltex1_handle" | "dimltex2_handle"
);
let doc = &self.tabs[i].scene.document;
if doc.dim_styles.get(&name).is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
}) {
return Task::none();
}
let handle = if value == "Default" || value == "ByBlock" {
acadrust::types::Handle::NULL
} else if is_lt {
@@ -1037,7 +1165,10 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
if let Some(ds) = self.tabs[i].scene.document.dim_styles.get_mut(&name) {
match field {
"dimblk" => ds.dimblk = handle,
"dimblk1" => ds.dimblk1 = handle,
"dimblk1" => {
ds.dimblk1 = handle;
ds.dimblk2 = handle;
}
"dimblk2" => ds.dimblk2 = handle,
"dimldrblk" => ds.dimldrblk = handle,
"dimltex_handle" => ds.dimltex_handle = handle,
+423 -47
View File
@@ -362,6 +362,7 @@ impl OpenCADStudio {
),
super::super::ModalKind::TextStyle => {
let tab = &self.tabs[self.active_tab];
let doc = &tab.scene.document;
let styles: Vec<String> = tab
.scene
.document
@@ -369,23 +370,77 @@ impl OpenCADStudio {
.iter()
.map(|s| s.name.clone())
.collect();
let (backward, upside_down, annotative) = tab
.scene
.document
let selected_style = doc
.text_styles
.get(&self.textstyle_selected)
.map(|s| (s.flags.backward, s.flags.upside_down, s.annotative))
.unwrap_or((false, false, false));
.get(&self.textstyle_selected);
let (backward, upside_down, vertical, annotative, read_only) = selected_style
.map(|style| {
(
style.flags.backward,
style.flags.upside_down,
style.is_vertical,
style.annotative,
style.xref_dependent,
)
})
.unwrap_or((false, false, false, false, false));
let in_use = self.style_in_use(
crate::app::StyleKind::Text,
&self.textstyle_selected,
);
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.textstyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.textstyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (selected_style, doc.text_styles.get(&compare_name)) {
if (
&a.font_file,
&a.big_font_file,
&a.true_type_font,
a.is_shape_file,
) != (
&b.font_file,
&b.big_font_file,
&b.true_type_font,
b.is_shape_file,
) {
comparison_sections.push(crate::i18n::translate("Fonts").into_owned());
}
if (a.height, a.width_factor, a.oblique_angle, a.last_height)
!= (b.height, b.width_factor, b.oblique_angle, b.last_height)
{
comparison_sections.push(crate::i18n::translate("Size").into_owned());
}
if (a.flags, a.is_vertical, a.annotative)
!= (b.flags, b.is_vertical, b.annotative)
{
comparison_sections.push(crate::i18n::translate("Effects").into_owned());
}
}
sized_flow(
ex,
860,
480,
960,
680,
|flow| {
crate::ui::style::textstyle::view_window(
crate::ui::style::textstyle::TextStyleView {
styles: styles.clone(),
selected: &self.textstyle_selected,
current: &tab.scene.document.header.current_text_style_name,
tab: self.textstyle_tab,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
read_only,
in_use,
font_buf: &self.textstyle_font,
width_buf: &self.textstyle_width,
oblique_buf: &self.textstyle_oblique,
@@ -394,6 +449,7 @@ impl OpenCADStudio {
ttf_buf: &self.textstyle_ttf,
backward,
upside_down,
vertical,
annotative,
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
@@ -420,18 +476,60 @@ impl OpenCADStudio {
ObjectType::MLineStyle(s) if s.name == self.mlstyle_selected => Some(s),
_ => None,
});
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.mlstyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.mlstyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let compare_style = tab.scene.document.objects.values().find_map(|object| match object {
ObjectType::MLineStyle(style) if style.name == compare_name => Some(style),
_ => None,
});
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (selected_style, compare_style) {
if (&a.description, a.flags, a.fill_color, a.start_angle, a.end_angle)
!= (&b.description, b.flags, b.fill_color, b.start_angle, b.end_angle)
{
comparison_sections.push(crate::i18n::translate("Caps and Fill").into_owned());
}
if a.elements != b.elements {
comparison_sections.push(crate::i18n::translate("Elements").into_owned());
}
}
let in_use = self.style_in_use(
crate::app::StyleKind::MLine,
&self.mlstyle_selected,
);
sized_flow(
ex,
620,
420,
960,
680,
|flow| {
crate::ui::style::mlstyle::view_window(
styles.clone(),
&self.mlstyle_selected,
selected_style,
tab.scene.document.header.multiline_style.clone(),
self.style_rename.as_deref(),
&self.style_rename_buf,
crate::ui::style::mlstyle::MlStyleView {
styles: styles.clone(),
selected: &self.mlstyle_selected,
style: selected_style,
current: tab.scene.document.header.multiline_style.clone(),
tab: self.mlstyle_tab,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
in_use,
description: &self.mln_description,
start_angle: &self.mln_start_angle,
end_angle: &self.mln_end_angle,
fill_color: &self.mln_fill_color,
elements: &self.mln_elements,
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
},
flow,
)
},
@@ -454,32 +552,89 @@ impl OpenCADStudio {
ObjectType::TableStyle(s) if s.name == self.tablestyle_selected => Some(s),
_ => None,
});
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.tablestyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.tablestyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let compare_style = tab.scene.document.objects.values().find_map(|object| match object {
ObjectType::TableStyle(style) if style.name == compare_name => Some(style),
_ => None,
});
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (selected_style, compare_style) {
if (
&a.description,
a.flow_direction,
a.horizontal_margin,
a.vertical_margin,
a.title_suppressed,
a.header_suppressed,
a.annotative,
) != (
&b.description,
b.flow_direction,
b.horizontal_margin,
b.vertical_margin,
b.title_suppressed,
b.header_suppressed,
b.annotative,
) {
comparison_sections.push(crate::i18n::translate("General").into_owned());
}
for (label, different) in [
("Data Row", a.data_row_style != b.data_row_style),
("Header Row", a.header_row_style != b.header_row_style),
("Title Row", a.title_row_style != b.title_row_style),
] {
if different {
comparison_sections.push(crate::i18n::translate(label).into_owned());
}
}
}
let in_use = self.style_in_use(
crate::app::StyleKind::Table,
&self.tablestyle_selected,
);
sized_flow(
ex,
620,
420,
960,
680,
|flow| {
crate::ui::style::tablestyle::view_window(
styles.clone(),
&self.tablestyle_selected,
&self.ribbon.active_table_style,
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,
self.style_rename.as_deref(),
&self.style_rename_buf,
self.ts_color_open,
crate::ui::style::tablestyle::TableStyleView {
styles: styles.clone(),
selected: &self.tablestyle_selected,
current: &tab.scene.document.header.current_table_style_name,
style: selected_style,
tab: self.tablestyle_tab,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
in_use,
hmargin: &self.ts_hmargin,
vmargin: &self.ts_vmargin,
description: &self.ts_description,
cell_textstyle: &self.ts_cell_textstyle,
cell_height: &self.ts_cell_height,
cell_textcolor: &self.ts_cell_textcolor,
cell_fillcolor: &self.ts_cell_fillcolor,
cell_datatype: &self.ts_cell_datatype,
cell_unittype: &self.ts_cell_unittype,
cell_format: &self.ts_cell_format,
border_lw: &self.ts_border_lw,
border_color: &self.ts_border_color,
border_spacing: &self.ts_border_spacing,
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
color_open: self.ts_color_open,
},
flow,
)
},
@@ -507,7 +662,9 @@ impl OpenCADStudio {
let doc = &tab.scene.document;
let mut block_opts: Vec<String> = vec!["None".to_string()];
block_opts.extend(doc.block_records.iter().map(|b| b.name.clone()));
let mut lt_opts: Vec<String> = vec!["None".to_string()];
let mut arrow_opts: Vec<String> = vec!["Closed filled".to_string()];
arrow_opts.extend(doc.block_records.iter().map(|b| b.name.clone()));
let mut lt_opts: Vec<String> = vec!["ByBlock".to_string()];
lt_opts.extend(doc.line_types.iter().map(|lt| lt.name.clone()));
let mut textstyle_opts: Vec<String> = vec!["None".to_string()];
textstyle_opts.extend(doc.text_styles.iter().map(|t| t.name.clone()));
@@ -529,8 +686,8 @@ impl OpenCADStudio {
.iter()
.find(|lt| lt.handle == h)
.map(|lt| lt.name.clone())
.unwrap_or_else(|| "None".to_string()),
None => "None".to_string(),
.unwrap_or_else(|| "ByBlock".to_string()),
None => "ByBlock".to_string(),
}
};
let opt_ts = |h: Option<acadrust::types::Handle>| -> String {
@@ -548,16 +705,153 @@ impl OpenCADStudio {
match selected_style {
Some(s) => (
opt_lt(s.line_type_handle),
opt_block(s.arrowhead_handle),
s.arrowhead_handle
.and_then(|handle| {
doc.block_records
.iter()
.find(|record| record.handle == handle)
.map(|record| record.name.clone())
})
.unwrap_or_else(|| "Closed filled".to_string()),
opt_ts(s.text_style_handle),
opt_block(s.block_content_handle),
),
None => Default::default(),
};
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.mleaderstyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.mleaderstyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let compare_style = doc.objects.values().find_map(|object| match object {
ObjectType::MultiLeaderStyle(style) if style.name == compare_name => Some(style),
_ => None,
});
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (selected_style, compare_style) {
if (
&a.description,
a.path_type,
a.line_color,
a.line_type_handle,
a.line_weight,
a.arrowhead_handle,
a.arrowhead_size,
a.break_gap_size,
) != (
&b.description,
b.path_type,
b.line_color,
b.line_type_handle,
b.line_weight,
b.arrowhead_handle,
b.arrowhead_size,
b.break_gap_size,
) {
comparison_sections.push(crate::i18n::translate("Leader Format").into_owned());
}
if (
a.enable_landing,
a.enable_dogleg,
a.landing_distance,
a.landing_gap,
a.scale_factor,
a.align_space,
a.max_leader_points,
a.first_segment_angle,
a.second_segment_angle,
a.leader_draw_order,
a.multileader_draw_order,
a.is_annotative,
) != (
b.enable_landing,
b.enable_dogleg,
b.landing_distance,
b.landing_gap,
b.scale_factor,
b.align_space,
b.max_leader_points,
b.first_segment_angle,
b.second_segment_angle,
b.leader_draw_order,
b.multileader_draw_order,
b.is_annotative,
) {
comparison_sections.push(crate::i18n::translate("Leader Structure").into_owned());
}
if (
a.content_type,
&a.default_text,
a.text_style_handle,
a.text_height,
a.text_color,
a.text_angle_type,
a.text_alignment,
) != (
b.content_type,
&b.default_text,
b.text_style_handle,
b.text_height,
b.text_color,
b.text_angle_type,
b.text_alignment,
) || (
a.text_left_attachment,
a.text_right_attachment,
a.text_top_attachment,
a.text_bottom_attachment,
a.text_attachment_direction,
a.text_frame,
a.text_always_left,
) != (
b.text_left_attachment,
b.text_right_attachment,
b.text_top_attachment,
b.text_bottom_attachment,
b.text_attachment_direction,
b.text_frame,
b.text_always_left,
) {
comparison_sections.push(crate::i18n::translate("Content").into_owned());
}
if (
a.block_content_handle,
a.block_content_color,
a.block_content_connection,
a.block_content_rotation,
a.block_content_scale_x,
a.block_content_scale_y,
a.block_content_scale_z,
a.enable_block_scale,
a.enable_block_rotation,
) != (
b.block_content_handle,
b.block_content_color,
b.block_content_connection,
b.block_content_rotation,
b.block_content_scale_x,
b.block_content_scale_y,
b.block_content_scale_z,
b.enable_block_scale,
b.enable_block_rotation,
) {
comparison_sections.push(crate::i18n::translate("Block Content").into_owned());
}
}
let in_use = self.style_in_use(
crate::app::StyleKind::MLeader,
&self.mleaderstyle_selected,
);
sized_flow(
ex,
560,
560,
960,
680,
|flow| {
crate::ui::style::mleaderstyle::view_window(
crate::ui::style::mleaderstyle::MLeaderStyleView {
@@ -565,6 +859,11 @@ impl OpenCADStudio {
selected: &self.mleaderstyle_selected,
style: selected_style,
current: tab.active_mleader_style.clone(),
tab: self.mleaderstyle_tab,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
in_use,
landing_distance: &self.mls_landing_distance,
landing_gap: &self.mls_landing_gap,
arrowhead_size: &self.mls_arrowhead_size,
@@ -585,6 +884,7 @@ impl OpenCADStudio {
block_scale_y: &self.mls_block_scale_y,
block_scale_z: &self.mls_block_scale_z,
block_opts: block_opts.clone(),
arrow_opts: arrow_opts.clone(),
lt_opts: lt_opts.clone(),
textstyle_opts: textstyle_opts.clone(),
line_type_name: line_type_name.clone(),
@@ -630,6 +930,13 @@ impl OpenCADStudio {
);
let mut lt_opts: Vec<String> = vec!["ByBlock".to_string()];
lt_opts.extend(doc.line_types.iter().map(|lt| lt.name.clone()));
let text_style_opts: Vec<String> =
doc.text_styles.iter().map(|style| style.name.clone()).collect();
let text_style_fixed_height = doc
.text_styles
.get(&self.ds_dimtxsty)
.map(|style| style.height)
.filter(|height| *height > 0.0);
let blk_name = |h: acadrust::types::Handle| -> String {
if h.is_null() {
"Default".to_string()
@@ -653,6 +960,70 @@ impl OpenCADStudio {
}
};
let ds_sel = doc.dim_styles.get(&self.dimstyle_selected);
let read_only = ds_sel.is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
});
let in_use = doc.entities().any(|entity| {
matches!(entity, acadrust::EntityType::Dimension(dimension)
if dimension.base().style_name.eq_ignore_ascii_case(&self.dimstyle_selected))
});
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.dimstyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.dimstyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (ds_sel, doc.dim_styles.get(&compare_name)) {
if (a.dimdle, a.dimdli, a.dimgap, a.dimclrd, a.dimlwd, a.dimsd1, a.dimsd2)
!= (b.dimdle, b.dimdli, b.dimgap, b.dimclrd, b.dimlwd, b.dimsd1, b.dimsd2)
|| (a.dimexe, a.dimexo, a.dimclre, a.dimlwe, a.dimse1, a.dimse2, a.dimfxl, a.dimfxlon)
!= (b.dimexe, b.dimexo, b.dimclre, b.dimlwe, b.dimse1, b.dimse2, b.dimfxl, b.dimfxlon)
|| (a.dimltex_handle, a.dimltex1_handle, a.dimltex2_handle)
!= (b.dimltex_handle, b.dimltex1_handle, b.dimltex2_handle)
{
comparison_sections.push(crate::i18n::translate("Lines").into_owned());
}
if (a.dimasz, a.dimblk, a.dimblk1, a.dimblk2, a.dimldrblk, a.dimsah, a.dimcen, a.dimtsz)
!= (b.dimasz, b.dimblk, b.dimblk1, b.dimblk2, b.dimldrblk, b.dimsah, b.dimcen, b.dimtsz)
|| (a.dimarcsym, a.dimjogang) != (b.dimarcsym, b.dimjogang)
{
comparison_sections.push(crate::i18n::translate("Symbols and Arrows").into_owned());
}
if (a.dimclrt, a.dimtxt, &a.dimtxsty, a.dimjust, a.dimtad, a.dimtvp)
!= (b.dimclrt, b.dimtxt, &b.dimtxsty, b.dimjust, b.dimtad, b.dimtvp)
|| (a.dimtih, a.dimtoh, a.dimtfill, a.dimtfillclr, a.dimtxtdirection)
!= (b.dimtih, b.dimtoh, b.dimtfill, b.dimtfillclr, b.dimtxtdirection)
{
comparison_sections.push(crate::i18n::translate("Text").into_owned());
}
if (a.dimatfit, a.dimtix, a.dimsoxd, a.dimtmove, a.dimupt, a.dimtofl, a.dimscale, a.annotative)
!= (b.dimatfit, b.dimtix, b.dimsoxd, b.dimtmove, b.dimupt, b.dimtofl, b.dimscale, b.annotative)
{
comparison_sections.push(crate::i18n::translate("Fit").into_owned());
}
if (a.dimlfac, a.dimlunit, a.dimdec, &a.dimpost, a.dimdsep, a.dimrnd, a.dimzin, a.dimfrac)
!= (b.dimlfac, b.dimlunit, b.dimdec, &b.dimpost, b.dimdsep, b.dimrnd, b.dimzin, b.dimfrac)
|| (a.dimaunit, a.dimadec, a.dimazin) != (b.dimaunit, b.dimadec, b.dimazin)
{
comparison_sections.push(crate::i18n::translate("Primary Units").into_owned());
}
if (a.dimalt, a.dimaltf, a.dimaltd, a.dimaltu, a.dimalttd, a.dimaltrnd, &a.dimapost, a.dimaltz, a.dimalttz)
!= (b.dimalt, b.dimaltf, b.dimaltd, b.dimaltu, b.dimalttd, b.dimaltrnd, &b.dimapost, b.dimaltz, b.dimalttz)
{
comparison_sections.push(crate::i18n::translate("Alternate Units").into_owned());
}
if (a.dimtol, a.dimlim, a.dimtp, a.dimtm, a.dimtdec, a.dimtfac, a.dimtolj, a.dimtzin)
!= (b.dimtol, b.dimlim, b.dimtp, b.dimtm, b.dimtdec, b.dimtfac, b.dimtolj, b.dimtzin)
{
comparison_sections.push(crate::i18n::translate("Tolerances").into_owned());
}
}
let (
dimblk_name,
dimblk1_name,
@@ -673,7 +1044,7 @@ impl OpenCADStudio {
),
None => Default::default(),
};
sized_flow(ex, 720, 560, |flow| {
sized_flow(ex, 960, 680, |flow| {
crate::ui::style::dimstyle::view_window(
styles.clone(),
&self.dimstyle_selected,
@@ -734,14 +1105,12 @@ impl OpenCADStudio {
dimtmove: &self.ds_dimtmove,
dimupt: self.ds_dimupt,
dimtofl: self.ds_dimtofl,
dimfit: &self.ds_dimfit,
dimdsep: &self.ds_dimdsep,
dimrnd: &self.ds_dimrnd,
dimzin: &self.ds_dimzin,
dimfrac: &self.ds_dimfrac,
dimaunit: &self.ds_dimaunit,
dimadec: &self.ds_dimadec,
dimunit: &self.ds_dimunit,
dimazin: &self.ds_dimazin,
dimalt: self.ds_dimalt,
dimaltf: &self.ds_dimaltf,
@@ -763,6 +1132,13 @@ impl OpenCADStudio {
dimltex2_name: dimltex2_name.clone(),
block_opts: block_opts.clone(),
lt_opts: lt_opts.clone(),
text_style_opts: text_style_opts.clone(),
text_style_fixed_height,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
read_only,
in_use,
color_open: self.ds_color_open.clone(),
},
self.style_rename.as_deref(),