forked from 1b-agent/opencadstudio-upstream
DIMAUNIT 4 is Surveyor's units, but format_angular_value matched only 0-3 and let 4 fall through the catch-all to decimal degrees. An angular dimension in a drawing authored with surveyor units therefore read as plain degrees, while AUNITS 4 in the same drawing writes a bearing for the coordinate readout — the two disagreed on one angle. Format the bearing from the dimension's own DMS path so it carries DIMADEC, DIMAZIN and DIMDSEP, quantise before picking the quadrant so a value just short of a cardinal does not quote a quarter turn, and offer the option in the dimension-style dialog.
1240 lines
45 KiB
Rust
1240 lines
45 KiB
Rust
//! Dimension Style Manager window — fills the entire OS window.
|
||
|
||
use crate::app::{ColorPickTarget, DsField, Message};
|
||
use iced::widget::{
|
||
button, canvas, checkbox, column, container, row, scrollable, text, text_input, Space,
|
||
};
|
||
use iced::{mouse, Background, Border, Element, Length, Point, Rectangle, Theme};
|
||
use crate::ui::style::common::muted_style;
|
||
use crate::t;
|
||
use std::borrow::Cow;
|
||
use std::fmt;
|
||
|
||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||
struct DimEnumChoice {
|
||
code: String,
|
||
label: String,
|
||
}
|
||
|
||
impl fmt::Display for DimEnumChoice {
|
||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
f.write_str(&self.label)
|
||
}
|
||
}
|
||
|
||
/// All DimStyle field values needed by the view.
|
||
pub struct DimStyleValues<'a> {
|
||
pub dimdle: &'a str,
|
||
pub dimdli: &'a str,
|
||
pub dimgap: &'a str,
|
||
pub dimexe: &'a str,
|
||
pub dimexo: &'a str,
|
||
pub dimsd1: bool,
|
||
pub dimsd2: bool,
|
||
pub dimse1: bool,
|
||
pub dimse2: bool,
|
||
pub dimasz: &'a str,
|
||
pub dimcen: &'a str,
|
||
pub dimtsz: &'a str,
|
||
pub dimtxt: &'a str,
|
||
pub dimtxsty: &'a str,
|
||
pub dimtad: &'a str,
|
||
pub dimtih: bool,
|
||
pub dimtoh: bool,
|
||
pub dimscale: &'a str,
|
||
pub dimlfac: &'a str,
|
||
pub dimlunit: &'a str,
|
||
pub dimdec: &'a str,
|
||
pub dimpost: &'a str,
|
||
pub dimtol: bool,
|
||
pub dimlim: bool,
|
||
pub dimtp: &'a str,
|
||
pub dimtm: &'a str,
|
||
pub dimtdec: &'a str,
|
||
pub dimtfac: &'a str,
|
||
pub annotative: bool,
|
||
pub dimclrd: &'a str,
|
||
pub dimlwd: &'a str,
|
||
pub dimclre: &'a str,
|
||
pub dimlwe: &'a str,
|
||
pub dimfxl: &'a str,
|
||
pub dimfxlon: bool,
|
||
pub dimsah: bool,
|
||
pub dimarcsym: &'a str,
|
||
pub dimjogang: &'a str,
|
||
pub dimclrt: &'a str,
|
||
pub dimjust: &'a str,
|
||
pub dimtvp: &'a str,
|
||
pub dimtfill: &'a str,
|
||
pub dimtfillclr: &'a str,
|
||
pub dimtxtdirection: bool,
|
||
pub dimatfit: &'a str,
|
||
pub dimtix: bool,
|
||
pub dimsoxd: bool,
|
||
pub dimtmove: &'a str,
|
||
pub dimupt: bool,
|
||
pub dimtofl: bool,
|
||
pub dimdsep: &'a str,
|
||
pub dimrnd: &'a str,
|
||
pub dimzin: &'a str,
|
||
pub dimfrac: &'a str,
|
||
pub dimaunit: &'a str,
|
||
pub dimadec: &'a str,
|
||
pub dimazin: &'a str,
|
||
pub dimalt: bool,
|
||
pub dimaltf: &'a str,
|
||
pub dimaltd: &'a str,
|
||
pub dimaltu: &'a str,
|
||
pub dimalttd: &'a str,
|
||
pub dimaltrnd: &'a str,
|
||
pub dimapost: &'a str,
|
||
pub dimaltz: &'a str,
|
||
pub dimalttz: &'a str,
|
||
pub dimtolj: &'a str,
|
||
pub dimtzin: &'a str,
|
||
// Resolved selected names for the block/linetype Handle fields.
|
||
pub dimblk_name: String,
|
||
pub dimblk1_name: String,
|
||
pub dimblk2_name: String,
|
||
pub dimldrblk_name: String,
|
||
pub dimltex_name: String,
|
||
pub dimltex1_name: String,
|
||
pub dimltex2_name: String,
|
||
// Dropdown option lists shared by the arrowhead / linetype fields.
|
||
pub block_opts: Vec<String>,
|
||
pub lt_opts: Vec<String>,
|
||
pub text_style_opts: Vec<String>,
|
||
pub text_style_fixed_height: Option<f64>,
|
||
pub compare_name: String,
|
||
pub compare_opts: Vec<String>,
|
||
pub comparison_sections: Vec<String>,
|
||
pub read_only: bool,
|
||
pub in_use: bool,
|
||
/// Colour field whose expanded palette is currently open.
|
||
pub color_open: Option<DsField>,
|
||
}
|
||
|
||
fn tab_btn_style(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
|
||
move |theme: &Theme, st| {
|
||
let palette = theme.palette();
|
||
let pair = match (active, st) {
|
||
(true, _) => palette.primary.strong,
|
||
(false, button::Status::Hovered | button::Status::Pressed) => {
|
||
palette.background.strong
|
||
}
|
||
_ => palette.background.weak,
|
||
};
|
||
button::Style {
|
||
background: Some(Background::Color(pair.color)),
|
||
text_color: pair.text,
|
||
border: Border {
|
||
color: palette.background.neutral.color,
|
||
width: 1.0,
|
||
radius: 3.0.into(),
|
||
},
|
||
..Default::default()
|
||
}
|
||
}
|
||
}
|
||
|
||
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
|
||
let palette = theme.palette();
|
||
let border = match status {
|
||
text_input::Status::Focused { .. } => palette.primary.base.color,
|
||
_ => palette.background.neutral.color,
|
||
};
|
||
text_input::Style {
|
||
background: Background::Color(palette.background.base.color),
|
||
border: Border {
|
||
color: border,
|
||
width: 1.0,
|
||
radius: 3.0.into(),
|
||
},
|
||
icon: palette.background.base.text,
|
||
placeholder: palette.background.base.text.scale_alpha(0.48),
|
||
value: palette.background.base.text,
|
||
selection: palette.primary.base.color.scale_alpha(0.5),
|
||
}
|
||
}
|
||
|
||
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
|
||
iced::widget::text::Style {
|
||
color: Some(theme.palette().primary.base.color),
|
||
}
|
||
}
|
||
|
||
struct DimensionPreview {
|
||
ext1: bool,
|
||
ext2: bool,
|
||
dim1: bool,
|
||
dim2: bool,
|
||
tick: bool,
|
||
arrow_size: f32,
|
||
text_above: bool,
|
||
basic: bool,
|
||
text: String,
|
||
}
|
||
|
||
impl canvas::Program<Message> for DimensionPreview {
|
||
type State = ();
|
||
|
||
fn draw(
|
||
&self,
|
||
_state: &(),
|
||
renderer: &iced::Renderer,
|
||
theme: &Theme,
|
||
bounds: Rectangle,
|
||
_cursor: mouse::Cursor,
|
||
) -> Vec<canvas::Geometry> {
|
||
let mut frame = canvas::Frame::new(renderer, bounds.size());
|
||
let palette = theme.palette();
|
||
let ink = palette.background.base.text.scale_alpha(0.88);
|
||
let guide = palette.primary.base.color;
|
||
let stroke = canvas::Stroke::default().with_color(ink).with_width(1.2);
|
||
let x1 = 52.0;
|
||
let x2 = (bounds.width - 52.0).max(x1 + 40.0);
|
||
let y = bounds.height * 0.58;
|
||
let object_y = bounds.height - 18.0;
|
||
|
||
let line = |a: Point, b: Point| canvas::Path::line(a, b);
|
||
frame.stroke(
|
||
&line(Point::new(x1 - 18.0, object_y), Point::new(x2 + 18.0, object_y)),
|
||
canvas::Stroke::default().with_color(ink.scale_alpha(0.38)).with_width(1.0),
|
||
);
|
||
if self.ext1 {
|
||
frame.stroke(&line(Point::new(x1, object_y), Point::new(x1, 22.0)), stroke.clone());
|
||
}
|
||
if self.ext2 {
|
||
frame.stroke(&line(Point::new(x2, object_y), Point::new(x2, 22.0)), stroke.clone());
|
||
}
|
||
|
||
let text_half = (self.text.chars().count() as f32 * 3.4 + 8.0).min((x2 - x1) * 0.34);
|
||
if self.dim1 {
|
||
frame.stroke(&line(Point::new(x1, y), Point::new((bounds.width * 0.5 - text_half).max(x1), y)), stroke.clone());
|
||
}
|
||
if self.dim2 {
|
||
frame.stroke(&line(Point::new((bounds.width * 0.5 + text_half).min(x2), y), Point::new(x2, y)), stroke.clone());
|
||
}
|
||
|
||
let size = self.arrow_size.clamp(5.0, 14.0);
|
||
for (tip_x, sign) in [(x1, 1.0_f32), (x2, -1.0_f32)] {
|
||
if self.tick {
|
||
frame.stroke(
|
||
&line(
|
||
Point::new(tip_x - size * 0.55, y + size * 0.75),
|
||
Point::new(tip_x + size * 0.55, y - size * 0.75),
|
||
),
|
||
canvas::Stroke::default().with_color(guide).with_width(1.6),
|
||
);
|
||
} else {
|
||
let arrow = canvas::Path::new(|path| {
|
||
path.move_to(Point::new(tip_x, y));
|
||
path.line_to(Point::new(tip_x + sign * size, y - size * 0.42));
|
||
path.line_to(Point::new(tip_x + sign * size, y + size * 0.42));
|
||
path.close();
|
||
});
|
||
frame.fill(&arrow, guide);
|
||
}
|
||
}
|
||
|
||
let text_y = if self.text_above { y - 16.0 } else { y };
|
||
if self.basic {
|
||
let frame_width = (self.text.chars().count() as f32 * 7.0 + 12.0)
|
||
.min((x2 - x1) * 0.8);
|
||
frame.stroke(
|
||
&canvas::Path::rectangle(
|
||
Point::new(bounds.width * 0.5 - frame_width * 0.5, text_y - 9.0),
|
||
iced::Size::new(frame_width, 18.0),
|
||
),
|
||
canvas::Stroke::default().with_color(ink).with_width(1.0),
|
||
);
|
||
}
|
||
frame.fill_text(canvas::Text {
|
||
content: self.text.clone(),
|
||
position: Point::new(bounds.width * 0.5, text_y),
|
||
color: ink,
|
||
size: iced::Pixels(12.0),
|
||
align_x: iced::advanced::text::Alignment::Center,
|
||
align_y: iced::alignment::Vertical::Center,
|
||
shaping: iced::advanced::text::Shaping::Advanced,
|
||
..Default::default()
|
||
});
|
||
vec![frame.into_geometry()]
|
||
}
|
||
}
|
||
|
||
fn hdivider<'a>(width: iced::Length) -> Element<'a, Message> {
|
||
container(Space::new().width(width).height(1))
|
||
.width(width)
|
||
.height(1)
|
||
.style(|theme: &Theme| container::Style {
|
||
background: Some(Background::Color(
|
||
theme.palette().background.neutral.color
|
||
)),
|
||
..Default::default()
|
||
})
|
||
.into()
|
||
}
|
||
|
||
pub fn view_window<'a>(
|
||
styles: Vec<String>,
|
||
selected: &'a str,
|
||
current: &'a str,
|
||
tab: u8,
|
||
vals: DimStyleValues<'a>,
|
||
rename_active: Option<&'a str>,
|
||
rename_buf: &'a str,
|
||
sizing: crate::ui::modal::ModalSizing,
|
||
) -> Element<'a, Message> {
|
||
// ── Tab bar ───────────────────────────────────────────────────────────
|
||
let tabs = row![
|
||
button(text(t!("Lines")).size(11))
|
||
.on_press(Message::DimStyleDialogTab(0))
|
||
.style(tab_btn_style(tab == 0))
|
||
.padding([4, 10]),
|
||
button(text(t!("Symbols and Arrows")).size(11))
|
||
.on_press(Message::DimStyleDialogTab(1))
|
||
.style(tab_btn_style(tab == 1))
|
||
.padding([4, 10]),
|
||
button(text(t!("Text")).size(11))
|
||
.on_press(Message::DimStyleDialogTab(2))
|
||
.style(tab_btn_style(tab == 2))
|
||
.padding([4, 10]),
|
||
button(text(t!("Fit")).size(11))
|
||
.on_press(Message::DimStyleDialogTab(3))
|
||
.style(tab_btn_style(tab == 3))
|
||
.padding([4, 10]),
|
||
button(text(t!("Primary Units")).size(11))
|
||
.on_press(Message::DimStyleDialogTab(4))
|
||
.style(tab_btn_style(tab == 4))
|
||
.padding([4, 10]),
|
||
button(text(t!("Alternate Units")).size(11))
|
||
.on_press(Message::DimStyleDialogTab(5))
|
||
.style(tab_btn_style(tab == 5))
|
||
.padding([4, 10]),
|
||
button(text(t!("Tolerances")).size(11))
|
||
.on_press(Message::DimStyleDialogTab(6))
|
||
.style(tab_btn_style(tab == 6))
|
||
.padding([4, 10]),
|
||
]
|
||
.spacing(2);
|
||
|
||
let lbl = |s: Cow<'static, str>| text(s).size(11).style(muted_style).width(180);
|
||
|
||
let mk_field = |fld: DsField, val: &'a str| -> Element<'a, Message> {
|
||
if vals.read_only {
|
||
crate::ui::read_only::field(val, 11.0, Length::Fixed(100.0))
|
||
} else {
|
||
text_input("", val)
|
||
.on_input(move |s| Message::DsEdit(fld.clone(), s))
|
||
.style(field_style)
|
||
.size(11)
|
||
.width(100)
|
||
.into()
|
||
}
|
||
};
|
||
|
||
let mk_field_enabled = |fld: DsField, val: &'a str, enabled: bool| -> Element<'a, Message> {
|
||
if enabled && !vals.read_only {
|
||
text_input("", val)
|
||
.on_input(move |value| Message::DsEdit(fld.clone(), value))
|
||
.style(field_style)
|
||
.size(11)
|
||
.width(100)
|
||
.into()
|
||
} else {
|
||
crate::ui::read_only::field(val, 11.0, Length::Fixed(100.0))
|
||
}
|
||
};
|
||
|
||
let chk = |label: Cow<'static, str>, val: bool, fld: DsField| -> Element<'a, Message> {
|
||
let item = checkbox(val).label(label).size(14).text_size(11);
|
||
if vals.read_only {
|
||
item.into()
|
||
} else {
|
||
item.on_toggle(move |_| Message::DsToggle(fld.clone())).into()
|
||
}
|
||
};
|
||
|
||
// Enum dropdown: maps the stored integer code to a named option and back,
|
||
// so the user picks "Above" rather than typing "1".
|
||
let enum_field = move |label: Cow<'static, str>,
|
||
fld: DsField,
|
||
val: &'a str,
|
||
opts: &'static [(&'static str, &'static str)]|
|
||
-> Element<'a, Message> {
|
||
let options: Vec<DimEnumChoice> = opts
|
||
.iter()
|
||
.map(|(code, label)| DimEnumChoice {
|
||
code: (*code).to_string(),
|
||
label: crate::i18n::translate(label).into_owned(),
|
||
})
|
||
.collect();
|
||
let cur = options
|
||
.iter()
|
||
.find(|choice| choice.code == val.trim())
|
||
.cloned()
|
||
.unwrap_or_else(|| DimEnumChoice {
|
||
code: val.to_string(),
|
||
label: val.to_string(),
|
||
});
|
||
let choice: Element<'a, Message> = if vals.read_only {
|
||
crate::ui::read_only::field(cur.to_string().as_str(), 11.0, Length::Fixed(150.0))
|
||
} else {
|
||
iced::widget::pick_list(Some(cur), options, |value| value.to_string())
|
||
.on_select(move |chosen: DimEnumChoice| {
|
||
Message::DsEdit(fld.clone(), chosen.code)
|
||
})
|
||
.text_size(11)
|
||
.width(150)
|
||
.into()
|
||
};
|
||
row![lbl(label), choice]
|
||
.spacing(8)
|
||
.align_y(iced::Center)
|
||
.into()
|
||
};
|
||
|
||
// Linear unit formats shared by DIMLUNIT / DIMALTU.
|
||
const OPT_LUNIT: &[(&str, &str)] = &[
|
||
("1", "Scientific"),
|
||
("2", "Decimal"),
|
||
("3", "Engineering"),
|
||
("4", "Architectural"),
|
||
("5", "Fractional"),
|
||
("6", "Windows desktop"),
|
||
];
|
||
const OPT_LINEWEIGHT: &[(&str, &str)] = &[
|
||
("-1", "By layer"),
|
||
("-2", "By block"),
|
||
("-3", "Default"),
|
||
("0", "0.00 mm"),
|
||
("5", "0.05 mm"),
|
||
("9", "0.09 mm"),
|
||
("13", "0.13 mm"),
|
||
("15", "0.15 mm"),
|
||
("18", "0.18 mm"),
|
||
("20", "0.20 mm"),
|
||
("25", "0.25 mm"),
|
||
("30", "0.30 mm"),
|
||
("35", "0.35 mm"),
|
||
("40", "0.40 mm"),
|
||
("50", "0.50 mm"),
|
||
("53", "0.53 mm"),
|
||
("60", "0.60 mm"),
|
||
("70", "0.70 mm"),
|
||
("80", "0.80 mm"),
|
||
("90", "0.90 mm"),
|
||
("100", "1.00 mm"),
|
||
("106", "1.06 mm"),
|
||
("120", "1.20 mm"),
|
||
("140", "1.40 mm"),
|
||
("158", "1.58 mm"),
|
||
("200", "2.00 mm"),
|
||
("211", "2.11 mm"),
|
||
];
|
||
let alternate_unit_name = OPT_LUNIT
|
||
.iter()
|
||
.find(|(code, _)| *code == vals.dimaltu.trim())
|
||
.map(|(_, label)| crate::i18n::translate(label).into_owned())
|
||
.unwrap_or_else(|| vals.dimaltu.to_string());
|
||
|
||
let zero_controls = |field: DsField,
|
||
value: &'a str,
|
||
show_feet_inches: bool,
|
||
enabled: bool|
|
||
-> Element<'a, Message> {
|
||
let raw = value.trim().parse::<i16>().unwrap_or(0);
|
||
let feet_modes = vec![
|
||
DimEnumChoice { code: "0".into(), label: t!("Suppress zero feet and zero inches").into_owned() },
|
||
DimEnumChoice { code: "1".into(), label: t!("Show zero feet and zero inches").into_owned() },
|
||
DimEnumChoice { code: "2".into(), label: t!("Show zero feet; suppress zero inches").into_owned() },
|
||
DimEnumChoice { code: "3".into(), label: t!("Suppress zero feet; show zero inches").into_owned() },
|
||
];
|
||
let feet_current = feet_modes[(raw & 3) as usize].clone();
|
||
let feet: Element<'a, Message> = if show_feet_inches {
|
||
let list = iced::widget::pick_list(Some(feet_current.clone()), feet_modes, |choice| choice.to_string())
|
||
.text_size(11)
|
||
.width(210);
|
||
let list: Element<'a, Message> = if enabled && !vals.read_only {
|
||
let target = field.clone();
|
||
list.on_select(move |choice| {
|
||
Message::DsZeroBase(target.clone(), choice.code.parse().unwrap_or(0))
|
||
}).into()
|
||
} else {
|
||
crate::ui::read_only::field(feet_current.to_string().as_str(), 11.0, Length::Fixed(210.0))
|
||
};
|
||
row![lbl(t!("Feet and inches")), list]
|
||
.spacing(8).align_y(iced::Center).into()
|
||
} else {
|
||
Space::new().height(0).into()
|
||
};
|
||
let leading = checkbox(raw & 4 != 0)
|
||
.label(t!("Suppress leading zeros"))
|
||
.size(14)
|
||
.text_size(11);
|
||
let trailing = checkbox(raw & 8 != 0)
|
||
.label(t!("Suppress trailing zeros"))
|
||
.size(14)
|
||
.text_size(11);
|
||
let leading: Element<'a, Message> = if enabled && !vals.read_only {
|
||
let target = field.clone();
|
||
leading.on_toggle(move |_| Message::DsZeroFlag(target.clone(), 4)).into()
|
||
} else {
|
||
leading.into()
|
||
};
|
||
let trailing: Element<'a, Message> = if enabled && !vals.read_only {
|
||
trailing.on_toggle(move |_| Message::DsZeroFlag(field.clone(), 8)).into()
|
||
} else {
|
||
trailing.into()
|
||
};
|
||
column![feet, leading, trailing].spacing(6).into()
|
||
};
|
||
|
||
// Shared colour selector (main dropdown + "more" palette), reusing the
|
||
// existing DsEdit path (the chosen colour is sent as an ACI string).
|
||
let color_open = vals.color_open.clone();
|
||
let color_row = move |label: Cow<'static, str>, fld: DsField, _val: &'a str| -> Element<'a, Message> {
|
||
if vals.read_only {
|
||
return row![
|
||
lbl(label),
|
||
crate::ui::read_only::field(_val, 11.0, Length::Fixed(150.0)),
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center)
|
||
.into();
|
||
}
|
||
let cur = crate::ui::color_select::aci_string_to_color(_val);
|
||
let open = color_open.as_ref() == Some(&fld);
|
||
let f_sel = fld.clone();
|
||
let selector = crate::ui::color_select::color_selector(
|
||
cur,
|
||
open,
|
||
crate::ui::color_select::ColorExtras {
|
||
by_layer: true,
|
||
by_block: true,
|
||
..Default::default()
|
||
},
|
||
move |c| Message::DsEdit(f_sel.clone(), crate::ui::color_select::color_to_aci_string(c)),
|
||
Message::DsColorMore(fld.clone()),
|
||
Message::OpenColorWindow(
|
||
ColorPickTarget::DimStyle(fld.clone()),
|
||
cur,
|
||
),
|
||
);
|
||
row![lbl(label), container(selector).width(150)]
|
||
.spacing(8)
|
||
.align_y(iced::Center)
|
||
.into()
|
||
};
|
||
|
||
// Block / linetype Handle dropdown: pick a block-record (arrowheads) or a
|
||
// linetype by name from the available records.
|
||
let hrow = move |label: Cow<'static, str>,
|
||
options: Vec<String>,
|
||
selected: String,
|
||
field: &'static str|
|
||
-> Element<'a, Message> {
|
||
let list: Element<'a, Message> = if vals.read_only {
|
||
crate::ui::read_only::field(&selected, 11.0, Length::Fixed(150.0))
|
||
} else {
|
||
iced::widget::pick_list(Some(selected), options, |value| value.to_string())
|
||
.on_select(move |value| Message::DsSetHandle { field, value })
|
||
.text_size(11)
|
||
.width(150)
|
||
.into()
|
||
};
|
||
row![lbl(label), list]
|
||
.spacing(8)
|
||
.align_y(iced::Center)
|
||
.into()
|
||
};
|
||
|
||
let hrow_enabled = move |label: Cow<'static, str>,
|
||
options: Vec<String>,
|
||
selected: String,
|
||
field: &'static str,
|
||
enabled: bool|
|
||
-> Element<'a, Message> {
|
||
let list = iced::widget::pick_list(Some(selected.clone()), options, |value| value.to_string())
|
||
.text_size(11)
|
||
.width(150);
|
||
let list: Element<'a, Message> = if enabled && !vals.read_only {
|
||
list.on_select(move |value| Message::DsSetHandle { field, value }).into()
|
||
} else {
|
||
crate::ui::read_only::field(&selected, 11.0, Length::Fixed(150.0))
|
||
};
|
||
row![lbl(label), list]
|
||
.spacing(8)
|
||
.align_y(iced::Center)
|
||
.into()
|
||
};
|
||
|
||
let text_style_field: Element<'a, Message> = if vals.read_only {
|
||
crate::ui::read_only::field(&vals.dimtxsty, 11.0, Length::Fixed(150.0))
|
||
} else {
|
||
iced::widget::pick_list(
|
||
Some(vals.dimtxsty.to_string()),
|
||
vals.text_style_opts.clone(),
|
||
|value| value.to_string(),
|
||
)
|
||
.on_select(|value| Message::DsEdit(DsField::Dimtxsty, value))
|
||
.text_size(11)
|
||
.width(150)
|
||
.into()
|
||
};
|
||
let text_height_note: Element<'a, Message> = if let Some(height) = vals.text_style_fixed_height {
|
||
text(t!("The selected text style fixes the height at %{height}.", height = height))
|
||
.size(10)
|
||
.style(muted_style)
|
||
.into()
|
||
} else {
|
||
Space::new().height(0).into()
|
||
};
|
||
let center_mode = vals.dimcen.trim().parse::<f64>().unwrap_or(0.0);
|
||
let tick_on = vals.dimtsz.trim().parse::<f64>().unwrap_or(0.0) > 0.0;
|
||
let center_choices = vec![
|
||
DimEnumChoice { code: "none".into(), label: t!("None").into_owned() },
|
||
DimEnumChoice { code: "mark".into(), label: t!("Center mark").into_owned() },
|
||
DimEnumChoice { code: "lines".into(), label: t!("Centerlines").into_owned() },
|
||
];
|
||
let center_current = if center_mode < 0.0 {
|
||
center_choices[2].clone()
|
||
} else if center_mode > 0.0 {
|
||
center_choices[1].clone()
|
||
} else {
|
||
center_choices[0].clone()
|
||
};
|
||
let center_method_field: Element<'a, Message> = if vals.read_only {
|
||
crate::ui::read_only::field(center_current.to_string().as_str(), 11.0, Length::Fixed(150.0))
|
||
} else {
|
||
iced::widget::pick_list(Some(center_current), center_choices, |choice| choice.to_string())
|
||
.on_select(|choice| Message::DsCenterMarkMode(choice.code))
|
||
.text_size(11)
|
||
.width(150)
|
||
.into()
|
||
};
|
||
let tolerance_choices = vec![
|
||
DimEnumChoice { code: "none".into(), label: t!("None").into_owned() },
|
||
DimEnumChoice { code: "symmetrical".into(), label: t!("Symmetrical").into_owned() },
|
||
DimEnumChoice { code: "deviation".into(), label: t!("Deviation").into_owned() },
|
||
DimEnumChoice { code: "limits".into(), label: t!("Limits").into_owned() },
|
||
DimEnumChoice { code: "basic".into(), label: t!("Basic").into_owned() },
|
||
];
|
||
let tolerance_current = if vals.dimgap.trim().starts_with('-') {
|
||
tolerance_choices[4].clone()
|
||
} else if vals.dimlim {
|
||
tolerance_choices[3].clone()
|
||
} else if vals.dimtol && vals.dimtp.trim() == vals.dimtm.trim() {
|
||
tolerance_choices[1].clone()
|
||
} else if vals.dimtol {
|
||
tolerance_choices[2].clone()
|
||
} else {
|
||
tolerance_choices[0].clone()
|
||
};
|
||
let tolerance_method_field: Element<'a, Message> = if vals.read_only {
|
||
crate::ui::read_only::field(tolerance_current.to_string().as_str(), 11.0, Length::Fixed(150.0))
|
||
} else {
|
||
iced::widget::pick_list(
|
||
Some(tolerance_current),
|
||
tolerance_choices,
|
||
|choice| choice.to_string(),
|
||
)
|
||
.on_select(|choice| Message::DsToleranceMode(choice.code))
|
||
.text_size(11)
|
||
.width(150)
|
||
.into()
|
||
};
|
||
|
||
let tab_content: Element<'_, Message> = match tab {
|
||
0 => column![
|
||
text(t!("Dimension Line")).size(11).style(primary_style),
|
||
row![
|
||
lbl(t!("Extend beyond ticks")),
|
||
mk_field(DsField::Dimdle, vals.dimdle)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Baseline spacing")),
|
||
mk_field(DsField::Dimdli, vals.dimdli)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Text gap")),
|
||
mk_field(DsField::Dimgap, vals.dimgap)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
chk(t!("Suppress first dimension line"), vals.dimsd1, DsField::Dimsd1),
|
||
chk(t!("Suppress second dimension line"), vals.dimsd2, DsField::Dimsd2),
|
||
text(t!("Extension Line")).size(11).style(primary_style),
|
||
row![
|
||
lbl(t!("Extend beyond dimension line")),
|
||
mk_field(DsField::Dimexe, vals.dimexe)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Offset from measured point")),
|
||
mk_field(DsField::Dimexo, vals.dimexo)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
chk(t!("Suppress first extension line"), vals.dimse1, DsField::Dimse1),
|
||
chk(t!("Suppress second extension line"), vals.dimse2, DsField::Dimse2),
|
||
color_row(t!("Dimension line color"), DsField::Dimclrd, vals.dimclrd),
|
||
enum_field(t!("Dimension lineweight"), DsField::Dimlwd, vals.dimlwd, OPT_LINEWEIGHT),
|
||
color_row(t!("Extension line color"), DsField::Dimclre, vals.dimclre),
|
||
enum_field(t!("Extension lineweight"), DsField::Dimlwe, vals.dimlwe, OPT_LINEWEIGHT),
|
||
chk(
|
||
t!("Use fixed-length extension lines"),
|
||
vals.dimfxlon,
|
||
DsField::Dimfxlon
|
||
),
|
||
row![
|
||
lbl(t!("Fixed length")),
|
||
mk_field_enabled(DsField::Dimfxl, vals.dimfxl, vals.dimfxlon)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
hrow(
|
||
t!("Dimension linetype"),
|
||
vals.lt_opts.clone(),
|
||
vals.dimltex_name.clone(),
|
||
"dimltex_handle"
|
||
),
|
||
hrow(
|
||
t!("First extension linetype"),
|
||
vals.lt_opts.clone(),
|
||
vals.dimltex1_name.clone(),
|
||
"dimltex1_handle"
|
||
),
|
||
hrow(
|
||
t!("Second extension linetype"),
|
||
vals.lt_opts.clone(),
|
||
vals.dimltex2_name.clone(),
|
||
"dimltex2_handle"
|
||
),
|
||
]
|
||
.spacing(7)
|
||
.into(),
|
||
1 => column![
|
||
text(t!("Arrowheads")).size(11).style(primary_style),
|
||
hrow_enabled(
|
||
t!("Both arrowheads"),
|
||
vals.block_opts.clone(),
|
||
vals.dimblk_name.clone(),
|
||
"dimblk",
|
||
!vals.dimsah && !tick_on
|
||
),
|
||
hrow_enabled(
|
||
t!("First arrowhead"),
|
||
vals.block_opts.clone(),
|
||
vals.dimblk1_name.clone(),
|
||
"dimblk1",
|
||
vals.dimsah && !tick_on
|
||
),
|
||
hrow_enabled(
|
||
t!("Second arrowhead"),
|
||
vals.block_opts.clone(),
|
||
vals.dimblk2_name.clone(),
|
||
"dimblk2",
|
||
vals.dimsah && !tick_on
|
||
),
|
||
hrow(
|
||
t!("Leader arrowhead"),
|
||
vals.block_opts.clone(),
|
||
vals.dimldrblk_name.clone(),
|
||
"dimldrblk"
|
||
),
|
||
row![
|
||
lbl(t!("Arrow size")),
|
||
mk_field_enabled(DsField::Dimasz, vals.dimasz, !tick_on)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![lbl(t!("Center marks")), center_method_field]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Center mark size")),
|
||
mk_field_enabled(DsField::Dimcen, vals.dimcen, center_mode != 0.0)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Tick size")),
|
||
mk_field(DsField::Dimtsz, vals.dimtsz)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
chk(
|
||
t!("Use different first and second arrowheads"),
|
||
vals.dimsah,
|
||
DsField::Dimsah
|
||
),
|
||
enum_field(
|
||
t!("Arc length symbol"),
|
||
DsField::Dimarcsym,
|
||
vals.dimarcsym,
|
||
&[("0", "Before text"), ("1", "Above text"), ("2", "None")],
|
||
),
|
||
row![
|
||
lbl(t!("Radius jog angle (°)")),
|
||
mk_field(DsField::Dimjogang, vals.dimjogang)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
]
|
||
.spacing(7)
|
||
.into(),
|
||
2 => column![
|
||
text(t!("Text")).size(11).style(primary_style),
|
||
row![
|
||
lbl(t!("Text height")),
|
||
mk_field_enabled(DsField::Dimtxt, vals.dimtxt, vals.text_style_fixed_height.is_none())
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
text_height_note,
|
||
row![
|
||
lbl(t!("Text style")),
|
||
text_style_field
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
enum_field(
|
||
t!("Vertical placement"),
|
||
DsField::Dimtad,
|
||
vals.dimtad,
|
||
&[
|
||
("0", "Centered"),
|
||
("1", "Above"),
|
||
("2", "Outside"),
|
||
("3", "JIS"),
|
||
("4", "Below"),
|
||
],
|
||
),
|
||
chk(t!("Keep text horizontal when inside"), vals.dimtih, DsField::Dimtih),
|
||
chk(t!("Keep text horizontal when outside"), vals.dimtoh, DsField::Dimtoh),
|
||
color_row(t!("Text color"), DsField::Dimclrt, vals.dimclrt),
|
||
enum_field(
|
||
t!("Horizontal placement"),
|
||
DsField::Dimjust,
|
||
vals.dimjust,
|
||
&[
|
||
("0", "Centered"),
|
||
("1", "At first ext"),
|
||
("2", "At second ext"),
|
||
("3", "Over first ext"),
|
||
("4", "Over second ext"),
|
||
],
|
||
),
|
||
row![
|
||
lbl(t!("Vertical offset")),
|
||
mk_field(DsField::Dimtvp, vals.dimtvp)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
enum_field(
|
||
t!("Text background"),
|
||
DsField::Dimtfill,
|
||
vals.dimtfill,
|
||
&[
|
||
("0", "None"),
|
||
("1", "Drawing background"),
|
||
("2", "Color"),
|
||
],
|
||
),
|
||
if vals.dimtfill.trim() == "2" {
|
||
color_row(t!("Background color"), DsField::Dimtfillclr, vals.dimtfillclr)
|
||
} else {
|
||
row![lbl(t!("Background color")), container(text(t!("Not applicable")).size(11).style(muted_style)).padding([4, 7]).width(150)]
|
||
.spacing(8).align_y(iced::Center).into()
|
||
},
|
||
chk(
|
||
t!("Read left to right"),
|
||
vals.dimtxtdirection,
|
||
DsField::Dimtxtdirection
|
||
),
|
||
]
|
||
.spacing(7)
|
||
.into(),
|
||
3 => column![
|
||
text(t!("Fit options")).size(11).style(primary_style),
|
||
enum_field(
|
||
t!("When space is limited"),
|
||
DsField::Dimatfit,
|
||
vals.dimatfit,
|
||
&[
|
||
("0", "Move text and arrows outside"),
|
||
("1", "Move arrows outside first"),
|
||
("2", "Move text outside first"),
|
||
("3", "Best fit"),
|
||
],
|
||
),
|
||
chk(t!("Always keep text between extension lines"), vals.dimtix, DsField::Dimtix),
|
||
chk(t!("Suppress arrows when they do not fit"), vals.dimsoxd, DsField::Dimsoxd),
|
||
text(t!("Text movement")).size(11).style(primary_style),
|
||
enum_field(
|
||
t!("When text is moved"),
|
||
DsField::Dimtmove,
|
||
vals.dimtmove,
|
||
&[
|
||
("0", "Keep dimension line with text"),
|
||
("1", "Add a leader"),
|
||
("2", "Move text freely"),
|
||
],
|
||
),
|
||
text(t!("Scale")).size(11).style(primary_style),
|
||
chk(t!("Annotative"), vals.annotative, DsField::Annotative),
|
||
row![
|
||
lbl(t!("Overall scale")),
|
||
if vals.annotative {
|
||
container(text(t!("Automatic")).size(11).style(muted_style))
|
||
.padding([4, 7])
|
||
.width(100)
|
||
.into()
|
||
} else {
|
||
mk_field(DsField::Dimscale, vals.dimscale)
|
||
}
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
text(t!("Fine tuning")).size(11).style(primary_style),
|
||
chk(t!("Place text manually while creating dimensions"), vals.dimupt, DsField::Dimupt),
|
||
chk(t!("Draw dimension line between extension lines"), vals.dimtofl, DsField::Dimtofl),
|
||
]
|
||
.spacing(8)
|
||
.into(),
|
||
4 => column![
|
||
text(t!("Linear dimensions")).size(11).style(primary_style),
|
||
enum_field(t!("Unit format"), DsField::Dimlunit, vals.dimlunit, OPT_LUNIT),
|
||
row![lbl(t!("Precision")), mk_field(DsField::Dimdec, vals.dimdec)]
|
||
.spacing(8).align_y(iced::Center),
|
||
if matches!(vals.dimlunit.trim(), "4" | "5") {
|
||
enum_field(
|
||
t!("Fraction format"),
|
||
DsField::Dimfrac,
|
||
vals.dimfrac,
|
||
&[("0", "Horizontal"), ("1", "Diagonal"), ("2", "Not stacked")],
|
||
)
|
||
} else {
|
||
row![lbl(t!("Fraction format")), container(text(t!("Not applicable")).size(11).style(muted_style)).padding([4, 7]).width(150)]
|
||
.spacing(8).align_y(iced::Center).into()
|
||
},
|
||
if vals.dimlunit.trim() == "2" {
|
||
enum_field(
|
||
t!("Decimal separator"),
|
||
DsField::Dimdsep,
|
||
vals.dimdsep,
|
||
&[("46", "Period"), ("44", "Comma"), ("32", "Space")],
|
||
)
|
||
} else {
|
||
row![lbl(t!("Decimal separator")), container(text(t!("Not applicable")).size(11).style(muted_style)).padding([4, 7]).width(150)]
|
||
.spacing(8).align_y(iced::Center).into()
|
||
},
|
||
row![lbl(t!("Round off")), mk_field(DsField::Dimrnd, vals.dimrnd)]
|
||
.spacing(8).align_y(iced::Center),
|
||
row![lbl(t!("Measurement template")), mk_field(DsField::Dimpost, vals.dimpost)]
|
||
.spacing(8).align_y(iced::Center),
|
||
text(t!("Use <> as the measured value; text before and after it becomes the prefix and suffix."))
|
||
.size(10).style(muted_style),
|
||
row![lbl(t!("Measurement scale")), mk_field(DsField::Dimlfac, vals.dimlfac)]
|
||
.spacing(8).align_y(iced::Center),
|
||
text(t!("Zero suppression")).size(11).style(primary_style),
|
||
zero_controls(
|
||
DsField::Dimzin,
|
||
vals.dimzin,
|
||
matches!(vals.dimlunit.trim(), "3" | "4"),
|
||
true,
|
||
),
|
||
text(t!("Angular dimensions")).size(11).style(primary_style),
|
||
enum_field(
|
||
t!("Unit format"),
|
||
DsField::Dimaunit,
|
||
vals.dimaunit,
|
||
&[("0", "Decimal degrees"), ("1", "Degrees, minutes, seconds"), ("2", "Gradians"), ("3", "Radians"), ("4", "Surveyor's units")],
|
||
),
|
||
row![lbl(t!("Precision")), mk_field(DsField::Dimadec, vals.dimadec)]
|
||
.spacing(8).align_y(iced::Center),
|
||
enum_field(
|
||
t!("Zero suppression"),
|
||
DsField::Dimazin,
|
||
vals.dimazin,
|
||
&[("0", "None"), ("1", "Leading"), ("2", "Trailing"), ("3", "Leading and trailing")],
|
||
),
|
||
]
|
||
.spacing(8)
|
||
.into(),
|
||
5 => column![
|
||
text(t!("Alternate Units")).size(11).style(primary_style),
|
||
chk(
|
||
t!("Display alternate units"),
|
||
vals.dimalt,
|
||
DsField::Dimalt
|
||
),
|
||
row![
|
||
lbl(t!("Multiplier")),
|
||
mk_field_enabled(DsField::Dimaltf, vals.dimaltf, vals.dimalt)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Precision")),
|
||
mk_field_enabled(DsField::Dimaltd, vals.dimaltd, vals.dimalt)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
if vals.dimalt {
|
||
enum_field(t!("Unit format"), DsField::Dimaltu, vals.dimaltu, OPT_LUNIT)
|
||
} else {
|
||
row![lbl(t!("Unit format")), container(text(alternate_unit_name).size(11).style(muted_style)).padding([4, 7]).width(150)]
|
||
.spacing(8).align_y(iced::Center).into()
|
||
},
|
||
row![
|
||
lbl(t!("Tolerance precision")),
|
||
mk_field_enabled(DsField::Dimalttd, vals.dimalttd, vals.dimalt)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Round off")),
|
||
mk_field_enabled(DsField::Dimaltrnd, vals.dimaltrnd, vals.dimalt)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Measurement template")),
|
||
mk_field_enabled(DsField::Dimapost, vals.dimapost, vals.dimalt)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
text(t!("Zero suppression")).size(11).style(primary_style),
|
||
zero_controls(
|
||
DsField::Dimaltz,
|
||
vals.dimaltz,
|
||
matches!(vals.dimaltu.trim(), "3" | "4"),
|
||
vals.dimalt,
|
||
),
|
||
text(t!("Tolerance zero suppression")).size(11).style(primary_style),
|
||
zero_controls(
|
||
DsField::Dimalttz,
|
||
vals.dimalttz,
|
||
matches!(vals.dimaltu.trim(), "3" | "4"),
|
||
vals.dimalt,
|
||
),
|
||
]
|
||
.spacing(7)
|
||
.into(),
|
||
_ => column![
|
||
text(t!("Tolerances")).size(11).style(primary_style),
|
||
row![
|
||
lbl(t!("Method")),
|
||
tolerance_method_field
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Upper value")),
|
||
mk_field_enabled(DsField::Dimtp, vals.dimtp, vals.dimtol || vals.dimlim)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Lower value")),
|
||
mk_field_enabled(
|
||
DsField::Dimtm,
|
||
vals.dimtm,
|
||
(vals.dimtol || vals.dimlim)
|
||
&& !(vals.dimtol && vals.dimtp.trim() == vals.dimtm.trim()),
|
||
)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Precision")),
|
||
mk_field_enabled(DsField::Dimtdec, vals.dimtdec, vals.dimtol || vals.dimlim)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
row![
|
||
lbl(t!("Height scale")),
|
||
mk_field_enabled(DsField::Dimtfac, vals.dimtfac, vals.dimtol || vals.dimlim)
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center),
|
||
enum_field(
|
||
t!("Vertical position"),
|
||
DsField::Dimtolj,
|
||
vals.dimtolj,
|
||
&[("0", "Bottom"), ("1", "Middle"), ("2", "Top")],
|
||
),
|
||
text(t!("Zero suppression")).size(11).style(primary_style),
|
||
zero_controls(
|
||
DsField::Dimtzin,
|
||
vals.dimtzin,
|
||
matches!(vals.dimlunit.trim(), "3" | "4"),
|
||
vals.dimtol || vals.dimlim,
|
||
),
|
||
]
|
||
.spacing(7)
|
||
.into(),
|
||
};
|
||
|
||
let precision = vals.dimdec.trim().parse::<usize>().unwrap_or(2).min(8);
|
||
let factor = vals.dimlfac.trim().parse::<f64>().unwrap_or(1.0);
|
||
let mut measured = format!("{:.*}", precision, 125.0 * factor);
|
||
let zero_flags = vals.dimzin.trim().parse::<i16>().unwrap_or(0);
|
||
if zero_flags & 8 != 0 && measured.contains('.') {
|
||
while measured.ends_with('0') {
|
||
measured.pop();
|
||
}
|
||
if measured.ends_with('.') {
|
||
measured.pop();
|
||
}
|
||
}
|
||
if zero_flags & 4 != 0 && measured.starts_with("0.") {
|
||
measured.remove(0);
|
||
}
|
||
if vals.dimdsep.trim() == "44" {
|
||
measured = measured.replace('.', ",");
|
||
} else if vals.dimdsep.trim() == "32" {
|
||
measured = measured.replace('.', " ");
|
||
}
|
||
let mut preview_text = if vals.dimpost.contains("<>") {
|
||
vals.dimpost.replace("<>", &measured)
|
||
} else {
|
||
format!("{measured}{}", vals.dimpost)
|
||
};
|
||
if vals.dimalt {
|
||
let alternate = 125.0 * vals.dimaltf.trim().parse::<f64>().unwrap_or(1.0);
|
||
let alt_precision = vals.dimaltd.trim().parse::<usize>().unwrap_or(2).min(8);
|
||
let alt_value = format!("{:.*}", alt_precision, alternate);
|
||
let alternate_text = if vals.dimapost.contains("<>") {
|
||
vals.dimapost.replace("<>", &alt_value)
|
||
} else {
|
||
format!("{alt_value}{}", vals.dimapost)
|
||
};
|
||
preview_text.push_str(&format!(" [{alternate_text}]"));
|
||
}
|
||
if vals.dimlim {
|
||
preview_text = format!(
|
||
"{} / {}",
|
||
preview_text,
|
||
vals.dimtm.trim()
|
||
);
|
||
} else if vals.dimtol {
|
||
if vals.dimtp.trim() == vals.dimtm.trim() {
|
||
preview_text.push_str(&format!(" ±{}", vals.dimtp.trim()));
|
||
} else {
|
||
preview_text.push_str(&format!(" +{} −{}", vals.dimtp.trim(), vals.dimtm.trim()));
|
||
}
|
||
}
|
||
let preview = canvas(DimensionPreview {
|
||
ext1: !vals.dimse1,
|
||
ext2: !vals.dimse2,
|
||
dim1: !vals.dimsd1,
|
||
dim2: !vals.dimsd2,
|
||
tick: vals.dimtsz.trim().parse::<f32>().unwrap_or(0.0) > 0.0,
|
||
arrow_size: vals.dimasz.trim().parse::<f32>().unwrap_or(1.0).abs() * 5.0 + 5.0,
|
||
text_above: vals.dimtad.trim() != "0",
|
||
basic: vals.dimgap.trim().starts_with('-'),
|
||
text: preview_text,
|
||
})
|
||
.width(Length::Fill)
|
||
.height(Length::Fixed(112.0));
|
||
let preview_panel = container(preview)
|
||
.width(Length::Fill)
|
||
.style(|theme: &Theme| container::Style {
|
||
background: Some(Background::Color(theme.palette().background.weak.color)),
|
||
border: Border {
|
||
color: theme.palette().background.neutral.color,
|
||
width: 1.0,
|
||
radius: 3.0.into(),
|
||
},
|
||
..Default::default()
|
||
});
|
||
let status = if vals.read_only {
|
||
t!("Referenced style · Read only")
|
||
} else if selected == current {
|
||
t!("Current style")
|
||
} else if vals.in_use {
|
||
t!("Used in drawing")
|
||
} else {
|
||
t!("Available style")
|
||
};
|
||
let comparison: Element<'a, Message> = if vals.compare_opts.is_empty() {
|
||
Space::new().height(0).into()
|
||
} else {
|
||
let summary = if vals.comparison_sections.is_empty() {
|
||
t!("No differences").into_owned()
|
||
} else {
|
||
format!("{}: {}", t!("Different sections"), vals.comparison_sections.join(", "))
|
||
};
|
||
row![
|
||
text(t!("Compare with")).size(10).style(muted_style),
|
||
iced::widget::pick_list(
|
||
Some(vals.compare_name.clone()),
|
||
vals.compare_opts.clone(),
|
||
|value| value.to_string(),
|
||
)
|
||
.on_select(Message::DimStyleDialogCompare)
|
||
.text_size(11)
|
||
.width(150),
|
||
text(summary).size(10).style(muted_style),
|
||
]
|
||
.spacing(8)
|
||
.align_y(iced::Center)
|
||
.into()
|
||
};
|
||
|
||
let right_panel = container(
|
||
column![
|
||
row![
|
||
text(selected).size(13).style(primary_style),
|
||
Space::new().width(Length::Fill),
|
||
text(status).size(10).style(muted_style),
|
||
]
|
||
.align_y(iced::Center),
|
||
preview_panel,
|
||
comparison,
|
||
tabs,
|
||
hdivider(Length::Fill),
|
||
scrollable(container(tab_content).padding([12, 12]).width(Length::Fill))
|
||
.width(Length::Fill)
|
||
.height(sizing.height),
|
||
]
|
||
.spacing(6)
|
||
.height(sizing.height),
|
||
)
|
||
.height(sizing.height)
|
||
.width(Length::Fill)
|
||
.padding(iced::Padding {
|
||
top: 12.0,
|
||
right: 0.0,
|
||
bottom: 12.0,
|
||
left: 0.0,
|
||
});
|
||
|
||
crate::ui::style::style_manager::view(crate::ui::style::style_manager::Scaffold {
|
||
sizing,
|
||
kind: crate::app::StyleKind::Dim,
|
||
styles: &styles,
|
||
selected,
|
||
current: Some(current),
|
||
rename_active,
|
||
rename_buf,
|
||
on_new: Message::DimStyleDialogNew,
|
||
on_copy: Message::DimStyleDialogCopy,
|
||
on_delete: Message::DimStyleDialogDelete,
|
||
on_select: Message::DimStyleDialogSelect,
|
||
on_set_current: Message::DimStyleDialogSetCurrent,
|
||
on_apply: Message::DimStyleDialogApply,
|
||
read_only: vals.read_only,
|
||
editor: right_panel.into(),
|
||
})
|
||
}
|