forked from 1b-agent/opencadstudio-upstream
fix: open-issue sweep — drawing, plot, snap, layout and UI fixes
Fixes: - Font prompt no longer lists bundled ltypeshp/qcadshp shape files (#1626) - Wide polylines step at a discontinuous segment width; PEDIT marks the current vertex; keyword steps refresh the command preview (#1628) - Radius-0 fillet drops the zero-length segment it left, so the corner fillets again (#1422) - FILLET Trim / No trim option (#1558) - True-colour wires plot in their own colour; colour picker stores the value it shows (#1621) - Model tab keeps its page setup; "Save changes to layout" in Model (#1620) - QNEW default template in Options > Files; .dwt in the open dialog (#1134, #1113) - GRIDUNIT / GRIDMODE / PERSPECTIVE variables (#1618, #1524) - PTYPE (#1433) - ZOOM nX / nXP (#1465) - CHSPACE between model and paper space through a viewport (#1428) - Moving a dimension keeps its automatic text placement - Shell icon; "&&" button labels (#1554) - LINETYPE Load from a .lin file (#1588) - XLINE / RAY hide the crosshair arms (#1437) - Dynamic-input boxes keep clear of the crosshair and each other (#1546) - Snap marker colour setting, dark default on light canvases (#1497, #1229, #1128) - Dimension style precision as a 0.00 pattern dropdown (#1426) - Node graph nodes left of the origin no longer clip away (#1592) - Collapse button in the command history header (#1094) - Freeze-in-current-viewport toggle in the ribbon layer list (#1466) - Geometric Center object snap for closed polylines (#1369) New strings translated in all 21 locales. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
abf302eba5
commit
178c7dff41
70 files changed
+1227
-145
No files matched your search
@@ -37,8 +37,11 @@ pub fn color_to_aci_string(c: AcadColor) -> String {
|
||||
/// Convert an Iced colour chosen by `iced_aw::ColorPicker` into a DWG true
|
||||
/// colour. ACI-only destinations map it to their closest indexed colour later.
|
||||
pub fn iced_to_acad_color(color: Color) -> AcadColor {
|
||||
let [r, g, b, _] = color.into_rgba8();
|
||||
AcadColor::Rgb { r, g, b }
|
||||
// Truncate the way the picker labels its channels, so the stored colour
|
||||
// is the one the dialog showed; rounding drifted dragged values by one
|
||||
// (#1621).
|
||||
let byte = |c: f32| (c * 255.0) as u8;
|
||||
AcadColor::Rgb { r: byte(color.r), g: byte(color.g), b: byte(color.b) }
|
||||
}
|
||||
|
||||
/// Return the closest CAD Color Index for an RGB colour.
|
||||
|
||||
@@ -985,8 +985,13 @@ impl CommandLine {
|
||||
.on_press(Message::CommandHistoryClear)
|
||||
.style(header_btn_style)
|
||||
.padding([2, 6]);
|
||||
// Collapses the console back to the single input line (#1094).
|
||||
let collapse_btn = button(crate::ui::icons::themed_arrow_down(11.0))
|
||||
.on_press(Message::CommandHistoryToggle)
|
||||
.style(header_btn_style)
|
||||
.padding([2, 6]);
|
||||
let header = container(
|
||||
row![Space::new().width(Length::Fill), copy_btn, clear_btn]
|
||||
row![Space::new().width(Length::Fill), copy_btn, clear_btn, collapse_btn]
|
||||
.spacing(6)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
|
||||
@@ -32,6 +32,8 @@ static REDO: &[u8] = include_bytes!("../../assets/icons/ui/redo.svg");
|
||||
static OSNAP_ENDPOINT: &[u8] = include_bytes!("../../assets/icons/osnap/endpoint.svg");
|
||||
static OSNAP_MIDPOINT: &[u8] = include_bytes!("../../assets/icons/osnap/midpoint.svg");
|
||||
static OSNAP_CENTER: &[u8] = include_bytes!("../../assets/icons/osnap/center.svg");
|
||||
static OSNAP_GEOMETRIC_CENTER: &[u8] =
|
||||
include_bytes!("../../assets/icons/osnap/geometric_center.svg");
|
||||
static OSNAP_NODE: &[u8] = include_bytes!("../../assets/icons/osnap/node.svg");
|
||||
static OSNAP_QUADRANT: &[u8] = include_bytes!("../../assets/icons/osnap/quadrant.svg");
|
||||
static OSNAP_INTERSECTION: &[u8] = include_bytes!("../../assets/icons/osnap/intersection.svg");
|
||||
@@ -51,6 +53,8 @@ static LAY_ON: &[u8] = include_bytes!("../../assets/icons/layers/layon.svg");
|
||||
static LAY_OFF: &[u8] = include_bytes!("../../assets/icons/layers/layoff.svg");
|
||||
static LAY_FRZ: &[u8] = include_bytes!("../../assets/icons/layers/layfrz.svg");
|
||||
static LAY_THW: &[u8] = include_bytes!("../../assets/icons/layers/laythw.svg");
|
||||
static LAY_VP_FRZ: &[u8] = include_bytes!("../../assets/icons/layers/layvpfrz.svg");
|
||||
static LAY_VP_THW: &[u8] = include_bytes!("../../assets/icons/layers/layvpthw.svg");
|
||||
static LAY_LCK: &[u8] = include_bytes!("../../assets/icons/layers/laylck.svg");
|
||||
static LAY_ULK: &[u8] = include_bytes!("../../assets/icons/layers/layulk.svg");
|
||||
|
||||
@@ -630,6 +634,7 @@ pub fn osnap(snap: crate::snap::SnapType) -> &'static [u8] {
|
||||
S::Endpoint => OSNAP_ENDPOINT,
|
||||
S::Midpoint => OSNAP_MIDPOINT,
|
||||
S::Center => OSNAP_CENTER,
|
||||
S::GeometricCenter => OSNAP_GEOMETRIC_CENTER,
|
||||
S::Node => OSNAP_NODE,
|
||||
S::Quadrant => OSNAP_QUADRANT,
|
||||
S::Intersection => OSNAP_INTERSECTION,
|
||||
@@ -694,6 +699,15 @@ pub fn layer_freeze(frozen: bool) -> &'static [u8] {
|
||||
}
|
||||
}
|
||||
|
||||
/// Freeze-in-current-viewport icon bytes (frozen / thawed).
|
||||
pub fn layer_vp_freeze(frozen: bool) -> &'static [u8] {
|
||||
if frozen {
|
||||
LAY_VP_FRZ
|
||||
} else {
|
||||
LAY_VP_THW
|
||||
}
|
||||
}
|
||||
|
||||
/// Layer lock icon bytes (locked / unlocked).
|
||||
pub fn layer_lock(locked: bool) -> &'static [u8] {
|
||||
if locked {
|
||||
|
||||
+1
-1
@@ -275,7 +275,7 @@ pub fn discard_guard<'a>(
|
||||
iced::widget::text(crate::t!("Unsaved changes will be discarded.")).size(13.5),
|
||||
Space::new().height(12),
|
||||
row![
|
||||
button(iced::widget::text(crate::t!("Discard && close")).size(12))
|
||||
button(iced::widget::text(crate::t!("Discard & close")).size(12))
|
||||
.on_press(on_discard)
|
||||
.padding([5, 14])
|
||||
.style(button::danger),
|
||||
|
||||
+11
-5
@@ -518,12 +518,20 @@ impl Graph {
|
||||
_ => None,
|
||||
};
|
||||
let zoom = self.zoom();
|
||||
// Lay the nodes out relative to the visible area's top-left rather
|
||||
// than the graph origin: a `pin` clips to its own bounds, so nodes
|
||||
// left of / above the origin vanished once panned or zoomed out (#1592).
|
||||
let shift = Vector::new(self.pan.x / zoom, self.pan.y / zoom);
|
||||
let mut nodes = stack![];
|
||||
for (node, node_sections) in self.engine.nodes.iter().zip(sections) {
|
||||
let Some(ui) = self.ui.get(&node.id) else {
|
||||
continue;
|
||||
};
|
||||
nodes = nodes.push(pin(self.node_view(node, node_sections)).x(ui.pos.x).y(ui.pos.y));
|
||||
nodes = nodes.push(
|
||||
pin(self.node_view(node, node_sections))
|
||||
.x(ui.pos.x + shift.x)
|
||||
.y(ui.pos.y + shift.y),
|
||||
);
|
||||
}
|
||||
let mut layers = stack![
|
||||
canvas(Wires { wires, pending, width: 2.0 * zoom.max(0.5) })
|
||||
@@ -531,7 +539,6 @@ impl Graph {
|
||||
.height(Length::Fill),
|
||||
Zoomed {
|
||||
content: nodes.width(Length::Fill).height(Length::Fill).into(),
|
||||
pan: self.pan,
|
||||
zoom,
|
||||
},
|
||||
];
|
||||
@@ -955,17 +962,16 @@ impl canvas::Program<Message> for Wires {
|
||||
}
|
||||
|
||||
/// Lays its content out in graph space and draws and hit-tests it through
|
||||
/// `pan` and `zoom`, so every widget inside scales as one picture.
|
||||
/// `zoom`, so every widget inside scales as one picture.
|
||||
struct Zoomed<'a> {
|
||||
content: Element<'a, Message>,
|
||||
pan: Vector,
|
||||
zoom: f32,
|
||||
}
|
||||
|
||||
impl Zoomed<'_> {
|
||||
/// Content coordinates → screen, for a layer whose top-left is `origin`.
|
||||
fn transformation(&self, origin: Point) -> Transformation {
|
||||
Transformation::translate(origin.x + self.pan.x, origin.y + self.pan.y)
|
||||
Transformation::translate(origin.x, origin.y)
|
||||
* Transformation::scale(self.zoom)
|
||||
* Transformation::translate(-origin.x, -origin.y)
|
||||
}
|
||||
|
||||
+70
-1
@@ -239,6 +239,12 @@ pub struct CrosshairOptions {
|
||||
/// the crosshair arms disappear and a blue pickbox remains — the
|
||||
/// screen-level "the client wants YOU to pick" signal.
|
||||
pub pick_pending: bool,
|
||||
/// Draw only the pickbox: the active command previews a line that the
|
||||
/// full-length arms would cover.
|
||||
pub hide_arms: bool,
|
||||
/// Explicit object-snap marker colour; `None` picks one that reads on
|
||||
/// the canvas.
|
||||
pub snap_color: Option<[u8; 3]>,
|
||||
}
|
||||
|
||||
/// Rendering style for the viewport grid.
|
||||
@@ -1517,6 +1523,10 @@ impl canvas::Program<Message> for SelectionCanvas {
|
||||
if let Some((sp, snap_type)) = self.snap {
|
||||
let (r, g, b) = if snap_type == SnapType::ObjectPick {
|
||||
(0.95_f32, 0.50, 0.08) // orange object-snap marker
|
||||
} else if let Some([r, g, b]) = self.crosshair.snap_color {
|
||||
(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0)
|
||||
} else if crate::ui::style::common::canvas_is_light(self.crosshair_bg) {
|
||||
(0.80, 0.45, 0.0) // dark amber: yellow vanishes on a light canvas
|
||||
} else {
|
||||
(1.0, 0.9, 0.1) // classic yellow OSNAP
|
||||
};
|
||||
@@ -1569,6 +1579,25 @@ impl canvas::Program<Message> for SelectionCanvas {
|
||||
let path = canvas::Path::circle(sp, r);
|
||||
frame.stroke(&path, stroke);
|
||||
}
|
||||
SnapType::GeometricCenter => {
|
||||
// Pentagon around a centre dot: the area centroid.
|
||||
let r = 6.5_f32;
|
||||
let path = canvas::Path::new(|b| {
|
||||
for k in 0..5 {
|
||||
let a = -std::f32::consts::FRAC_PI_2
|
||||
+ k as f32 * std::f32::consts::TAU / 5.0;
|
||||
let p = Point::new(sp.x + r * a.cos(), sp.y + r * a.sin());
|
||||
if k == 0 {
|
||||
b.move_to(p);
|
||||
} else {
|
||||
b.line_to(p);
|
||||
}
|
||||
}
|
||||
b.close();
|
||||
});
|
||||
frame.stroke(&path, stroke.clone());
|
||||
frame.fill(&canvas::Path::circle(sp, 1.6), marker);
|
||||
}
|
||||
SnapType::Node => {
|
||||
// Circle with an inscribed X.
|
||||
let r = 5.5_f32;
|
||||
@@ -1915,7 +1944,7 @@ impl canvas::Program<Message> for SelectionCanvas {
|
||||
// The arms stay only for the normal (non-pending) cursor: a
|
||||
// waiting pick shows the box alone, regardless of the UCS
|
||||
// rotation, so the square is unmistakable.
|
||||
if !pick_pending {
|
||||
if !pick_pending && !self.crosshair.hide_arms {
|
||||
for angle in base_angles {
|
||||
let rad = (angle + self.crosshair.snap_angle_deg as f64).to_radians();
|
||||
let dir = Point::new(rad.cos() as f32, -rad.sin() as f32);
|
||||
@@ -3363,6 +3392,37 @@ impl DynInputCanvas {
|
||||
(Self::box_content(b).len() as f32 * DYN_CHAR_W) + DYN_PAD * 2.0
|
||||
}
|
||||
|
||||
/// Slide a box centred at `center` straight away from the crosshair until
|
||||
/// it neither covers the aim point nor a box already placed (#1546).
|
||||
fn clear_of(center: Point, w: f32, cursor: Point, placed: &[iced::Rectangle]) -> Point {
|
||||
const KEEP: f32 = 18.0;
|
||||
let hits = |c: Point| {
|
||||
let r = iced::Rectangle {
|
||||
x: c.x - w * 0.5,
|
||||
y: c.y - DYN_BOX_H * 0.5,
|
||||
width: w,
|
||||
height: DYN_BOX_H,
|
||||
};
|
||||
r.expand(KEEP).contains(cursor) || placed.iter().any(|p| p.intersects(&r))
|
||||
};
|
||||
let (mut dx, mut dy) = (center.x - cursor.x, center.y - cursor.y);
|
||||
let len = (dx * dx + dy * dy).sqrt();
|
||||
if len < 1.0 {
|
||||
(dx, dy) = (0.0, 1.0);
|
||||
} else {
|
||||
(dx, dy) = (dx / len, dy / len);
|
||||
}
|
||||
let mut c = center;
|
||||
for _ in 0..60 {
|
||||
if !hits(c) {
|
||||
break;
|
||||
}
|
||||
c.x += dx * 4.0;
|
||||
c.y += dy * 4.0;
|
||||
}
|
||||
c
|
||||
}
|
||||
|
||||
/// Draw a value box centred at `center`, clamped inside `bounds`.
|
||||
fn draw_box(
|
||||
frame: &mut canvas::Frame,
|
||||
@@ -3647,6 +3707,7 @@ impl DynInputCanvas {
|
||||
}
|
||||
|
||||
// ── Box placement by role ──
|
||||
let mut placed: Vec<iced::Rectangle> = Vec::with_capacity(self.boxes.len());
|
||||
for b in &self.boxes {
|
||||
let center = b.center.unwrap_or_else(|| match b.role {
|
||||
DynRole::Angle => self.label_screen.unwrap_or_else(|| {
|
||||
@@ -3690,6 +3751,14 @@ impl DynInputCanvas {
|
||||
y: base.y + dy * len * 0.5 + ny * 16.0,
|
||||
},
|
||||
});
|
||||
let w = Self::box_width(b);
|
||||
let center = Self::clear_of(center, w, cursor, &placed);
|
||||
placed.push(iced::Rectangle {
|
||||
x: center.x - w * 0.5,
|
||||
y: center.y - DYN_BOX_H * 0.5,
|
||||
width: w,
|
||||
height: DYN_BOX_H,
|
||||
});
|
||||
Self::draw_box(frame, b, center, bounds, theme);
|
||||
}
|
||||
// Keep the tracking hint near the crosshair in guided layouts.
|
||||
|
||||
@@ -521,6 +521,7 @@ fn snap_override_items() -> Vec<MenuItem> {
|
||||
snap("Apparent Intersection", SnapType::ApparentIntersection),
|
||||
snap("Extension", SnapType::Extension),
|
||||
snap("Center", SnapType::Center),
|
||||
snap("Geometric Center", SnapType::GeometricCenter),
|
||||
snap("Quadrant", SnapType::Quadrant),
|
||||
snap("Tangent", SnapType::Tangent),
|
||||
snap("Perpendicular", SnapType::Perpendicular),
|
||||
|
||||
+13
-1
@@ -128,6 +128,8 @@ pub struct LayerInfo {
|
||||
pub visible: bool,
|
||||
pub frozen: bool,
|
||||
pub locked: bool,
|
||||
/// Layout with an active viewport: (its Layer Manager column, frozen there).
|
||||
pub vp_frozen: Option<(usize, bool)>,
|
||||
}
|
||||
|
||||
/// Full-screen backdrop for an open ribbon dropdown: closes the dropdown when
|
||||
@@ -1042,6 +1044,13 @@ impl Ribbon {
|
||||
crate::ui::icons::layer_lock(ll),
|
||||
Message::LayerToggleLock(info.name.clone()),
|
||||
);
|
||||
// Freeze in the current viewport only (#1466).
|
||||
let vp_freeze = info.vp_frozen.map(|(column, frozen)| {
|
||||
icon_btn(
|
||||
crate::ui::icons::layer_vp_freeze(frozen),
|
||||
Message::LayerToggleVpFreeze(info.name.clone(), column),
|
||||
)
|
||||
});
|
||||
let checkmark: Element<'_, Message> =
|
||||
crate::ui::icons::themed_check_cell(is_active);
|
||||
let label =
|
||||
@@ -1067,7 +1076,10 @@ impl Ribbon {
|
||||
.padding([4, 4]);
|
||||
|
||||
container(
|
||||
row![checkmark, vis, freeze, lock, select]
|
||||
row![checkmark, vis, freeze]
|
||||
.push(vp_freeze)
|
||||
.push(lock)
|
||||
.push(select)
|
||||
.spacing(5)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
|
||||
@@ -310,7 +310,7 @@ pub(super) const TOP_HIST_GAP: f32 = 4.0;
|
||||
|
||||
pub(crate) const UNDO_HISTORY_ID: &str = "UNDO_HISTORY";
|
||||
pub(crate) const REDO_HISTORY_ID: &str = "REDO_HISTORY";
|
||||
pub(super) const LAYER_COMBO_ID: &str = "LAYER_COMBO";
|
||||
pub(crate) const LAYER_COMBO_ID: &str = "LAYER_COMBO";
|
||||
/// Dropdown id for the tab-bar panel-density selector.
|
||||
pub(super) const COLLAPSE_MODE_ID: &str = "COLLAPSE_MODE";
|
||||
pub(super) const PROP_COLOR_ID: &str = "PROP_COLOR";
|
||||
|
||||
+28
-22
@@ -384,6 +384,29 @@ pub fn view_window<'a>(
|
||||
};
|
||||
|
||||
// Linear unit formats shared by DIMLUNIT / DIMALTU.
|
||||
// Precision reads as the number pattern it produces (#1426).
|
||||
const OPT_PREC: &[(&str, &str)] = &[
|
||||
("0", "0"),
|
||||
("1", "0.0"),
|
||||
("2", "0.00"),
|
||||
("3", "0.000"),
|
||||
("4", "0.0000"),
|
||||
("5", "0.00000"),
|
||||
("6", "0.000000"),
|
||||
("7", "0.0000000"),
|
||||
("8", "0.00000000"),
|
||||
];
|
||||
// A precision dropdown, or the read-only value while the option is off.
|
||||
let prec_field = move |label: Cow<'static, str>, fld: DsField, val: &'a str, enabled: bool| -> Element<'a, Message> {
|
||||
if enabled {
|
||||
enum_field(label, fld, val, OPT_PREC)
|
||||
} else {
|
||||
row![lbl(label), mk_field_enabled(fld, val, false)]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center)
|
||||
.into()
|
||||
}
|
||||
};
|
||||
const OPT_LUNIT: &[(&str, &str)] = &[
|
||||
("1", "Scientific"),
|
||||
("2", "Decimal"),
|
||||
@@ -900,8 +923,7 @@ pub fn view_window<'a>(
|
||||
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),
|
||||
prec_field(t!("Precision"), DsField::Dimdec, vals.dimdec, true),
|
||||
if matches!(vals.dimlunit.trim(), "4" | "5") {
|
||||
enum_field(
|
||||
t!("Fraction format"),
|
||||
@@ -946,8 +968,7 @@ pub fn view_window<'a>(
|
||||
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),
|
||||
prec_field(t!("Precision"), DsField::Dimadec, vals.dimadec, true),
|
||||
enum_field(
|
||||
t!("Zero suppression"),
|
||||
DsField::Dimazin,
|
||||
@@ -970,24 +991,14 @@ pub fn view_window<'a>(
|
||||
]
|
||||
.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),
|
||||
prec_field(t!("Precision"), DsField::Dimaltd, vals.dimaltd, vals.dimalt),
|
||||
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),
|
||||
prec_field(t!("Tolerance precision"), DsField::Dimalttd, vals.dimalttd, vals.dimalt),
|
||||
row![
|
||||
lbl(t!("Round off")),
|
||||
mk_field_enabled(DsField::Dimaltrnd, vals.dimaltrnd, vals.dimalt)
|
||||
@@ -1042,12 +1053,7 @@ pub fn view_window<'a>(
|
||||
]
|
||||
.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),
|
||||
prec_field(t!("Precision"), DsField::Dimtdec, vals.dimtdec, vals.dimtol || vals.dimlim),
|
||||
row![
|
||||
lbl(t!("Height scale")),
|
||||
mk_field_enabled(DsField::Dimtfac, vals.dimtfac, vals.dimtol || vals.dimlim)
|
||||
|
||||
@@ -218,7 +218,7 @@ pub fn view_window<'a>(
|
||||
.on_press(Message::AliasEditorApply)
|
||||
.padding([4, 16])
|
||||
.style(button::primary);
|
||||
let apply_exit = button(text(t!("Apply && Exit")).size(12))
|
||||
let apply_exit = button(text(t!("Apply & Exit")).size(12))
|
||||
.on_press(Message::AliasEditorApplyExit)
|
||||
.padding([4, 16])
|
||||
.style(button::primary);
|
||||
@@ -307,7 +307,7 @@ pub fn view_window<'a>(
|
||||
text(t!("Unsaved changes will be discarded.")).size(14),
|
||||
Space::new().height(10),
|
||||
row![
|
||||
button(text(t!("Discard && close")).size(12))
|
||||
button(text(t!("Discard & close")).size(12))
|
||||
.on_press(Message::AliasEditorCloseDiscard)
|
||||
.padding([4, 12])
|
||||
.style(button::danger),
|
||||
|
||||
@@ -209,11 +209,14 @@ pub fn view_window<'a>(
|
||||
zoom_factor_input: &'a str,
|
||||
drawing_prefs: DrawingPrefs,
|
||||
folders: Folders,
|
||||
qnew_template: &'a str,
|
||||
double_click_block_refedit: bool,
|
||||
double_click_block_attedit: bool,
|
||||
cursor_type: CursorType,
|
||||
crosshair_color: Option<[u8; 3]>,
|
||||
crosshair_color_input: &'a str,
|
||||
snap_marker_color: Option<[u8; 3]>,
|
||||
snap_marker_color_input: &'a str,
|
||||
lineweight_display_scale: i32,
|
||||
model_space: &'a crate::app::config::ModelSpaceThemeConfig,
|
||||
model_bg_input: &'a str,
|
||||
@@ -522,6 +525,24 @@ pub fn view_window<'a>(
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let snap_rgb = snap_marker_color.unwrap_or([255, 230, 26]);
|
||||
let snap_swatch = container(Space::new())
|
||||
.width(28)
|
||||
.height(22)
|
||||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(iced::Color::from_rgb8(
|
||||
snap_rgb[0],
|
||||
snap_rgb[1],
|
||||
snap_rgb[2],
|
||||
))),
|
||||
border: Border {
|
||||
color: theme.palette().background.strong.color,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let model_bg_rgb = model_space.custom_bg.unwrap_or(crate::app::config::CLASSIC_CAD_DARK_BG);
|
||||
|
||||
let paper_bg_rgb = model_space.custom_paper_bg.unwrap_or(crate::app::config::DEFAULT_PAPER_BG);
|
||||
@@ -769,6 +790,18 @@ pub fn view_window<'a>(
|
||||
.spacing(10)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.push(Space::new().height(10))
|
||||
.push(
|
||||
row![
|
||||
text(crate::t!("Snap marker color")).size(12).width(140),
|
||||
snap_swatch,
|
||||
text_input(crate::t!("#RRGGBB or blank").as_ref(), snap_marker_color_input)
|
||||
.on_input(Message::SnapMarkerColorChanged)
|
||||
.width(150),
|
||||
]
|
||||
.spacing(10)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.push(Space::new().height(6))
|
||||
.push(
|
||||
text(crate::t!("Leave the color blank to keep automatic viewport contrast."))
|
||||
@@ -1666,6 +1699,21 @@ pub fn view_window<'a>(
|
||||
folder_row(crate::t!("Plugins"), folders.plugins.clone()),
|
||||
Space::new().height(12),
|
||||
folder_row(crate::t!("Autosave files"), folders.autosave.clone()),
|
||||
Space::new().height(16),
|
||||
text(crate::t!("Default template for new drawings")).size(12),
|
||||
Space::new().height(4),
|
||||
row![
|
||||
text_input(crate::t!("Blank drawing").as_ref(), qnew_template)
|
||||
.on_input(Message::QnewTemplateChanged)
|
||||
.size(11)
|
||||
.width(Fill),
|
||||
button(text(crate::t!("Browse...")).size(11))
|
||||
.padding([4, 10])
|
||||
.style(button::secondary)
|
||||
.on_press(Message::QnewTemplateBrowse),
|
||||
]
|
||||
.spacing(10)
|
||||
.align_y(iced::Center),
|
||||
]
|
||||
.spacing(0)
|
||||
.width(sizing.width);
|
||||
|
||||
@@ -1553,7 +1553,7 @@ pub fn view_window(
|
||||
paper_space_option(s.paperspace_last, t!("Paper space last"), PlotFlag::PaperspaceLast),
|
||||
check(t!("Merge overlapping lines"), s.merge_lines, PlotFlag::MergeLines),
|
||||
check(t!("Plot stamp"), s.stamp, PlotFlag::Stamp),
|
||||
paper_space_option(s.save_to_layout, t!("Save changes to layout"), PlotFlag::SaveToLayout),
|
||||
check(t!("Save changes to layout"), s.save_to_layout, PlotFlag::SaveToLayout),
|
||||
]
|
||||
.spacing(6)
|
||||
.width(width),
|
||||
|
||||
@@ -241,7 +241,7 @@ pub fn view_window<'a>(
|
||||
.on_press(Message::ShortcutEditorApply)
|
||||
.padding([4, 16])
|
||||
.style(button::primary);
|
||||
let apply_exit = button(text(t!("Apply && Exit")).size(12))
|
||||
let apply_exit = button(text(t!("Apply & Exit")).size(12))
|
||||
.on_press(Message::ShortcutEditorApplyExit)
|
||||
.padding([4, 16])
|
||||
.style(button::primary);
|
||||
@@ -330,7 +330,7 @@ pub fn view_window<'a>(
|
||||
text(t!("Unsaved changes will be discarded.")).size(14),
|
||||
Space::new().height(10),
|
||||
row![
|
||||
button(text(t!("Discard && close")).size(12))
|
||||
button(text(t!("Discard & close")).size(12))
|
||||
.on_press(Message::ShortcutEditorCloseDiscard)
|
||||
.padding([4, 12])
|
||||
.style(button::danger),
|
||||
|
||||
Reference in new issue
Block a user