forked from 1b-agent/opencadstudio-upstream
Add Graphic Attributes palette toggle and persistence
This commit is contained in:
1 parent
3b74c7e7ea
commit
3e45331de1
14 files changed
+193
-44
No files matched your search
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Graphic Attributes">
|
||||
<rect x="4.25" y="3.75" width="15.5" height="16.5" rx="1.75" fill="none" stroke="#B4B6B9" stroke-width="1.5"/>
|
||||
<path d="M7 8h10M7 12h4" fill="none" stroke="#B4B6B9" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<rect x="7" y="15" width="10" height="2.5" rx="0.75" fill="#6DB7ED"/>
|
||||
<path d="M13 11.25h4v1.5h-4z" fill="#6DB7ED"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 445 B |
@@ -472,6 +472,11 @@ impl OpenCADStudio {
|
||||
return Some(Task::done(Message::ToggleProperties));
|
||||
}
|
||||
|
||||
// ── GRAPHICATTRIBUTES — toggle Graphic Attributes palette ───────────
|
||||
"GRAPHICATTRIBUTES" => {
|
||||
return Some(Task::done(Message::ToggleGraphicAttributes));
|
||||
}
|
||||
|
||||
// ── FILETAB — toggle file/document tabs ──────────────────────────────
|
||||
"FILETAB" => {
|
||||
return Some(Task::done(Message::ToggleFileTabs));
|
||||
|
||||
@@ -386,6 +386,7 @@ inventory::submit!(crate::command::CommandRegistration {
|
||||
"DSETTINGS",
|
||||
"PARAMETERS",
|
||||
"GRID",
|
||||
"GRAPHICATTRIBUTES",
|
||||
"ISODRAFT",
|
||||
"ISOPLANE",
|
||||
"OSNAP",
|
||||
|
||||
@@ -30,6 +30,8 @@ pub struct AppConfig {
|
||||
/// General edge-stack dock layout (which panels are docked, side, order,
|
||||
/// width and auto-collapse) for the Properties panel and block palette.
|
||||
pub dock: crate::ui::dock::DockState,
|
||||
/// Whether the optional Graphic Attributes palette is visible.
|
||||
pub show_graphic_attributes: bool,
|
||||
/// Add a newly selected annotation scale to existing annotative objects.
|
||||
pub annotation_auto_scale: i8,
|
||||
/// Ribbon collapse density.
|
||||
@@ -52,6 +54,7 @@ impl Default for AppConfig {
|
||||
start: StartConfig::default(),
|
||||
statusbar: StatusBarConfig::default(),
|
||||
dock: crate::ui::dock::DockState::default(),
|
||||
show_graphic_attributes: false,
|
||||
annotation_auto_scale: -4,
|
||||
ribbon: RibbonConfig::default(),
|
||||
plot: PlotDialogState::default(),
|
||||
@@ -601,6 +604,18 @@ mod tests {
|
||||
assert_eq!(deserialized.model_space.selection_window_color, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn graphic_attributes_visibility_defaults_off_and_round_trips() {
|
||||
let missing: AppConfig = serde_json::from_str("{}").expect("deserialize old config");
|
||||
assert!(!missing.show_graphic_attributes);
|
||||
|
||||
let mut original = AppConfig::default();
|
||||
original.show_graphic_attributes = true;
|
||||
let serialized = serde_json::to_string(&original).expect("serialize config");
|
||||
let restored: AppConfig = serde_json::from_str(&serialized).expect("deserialize config");
|
||||
assert!(restored.show_graphic_attributes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_theme_name() {
|
||||
assert_eq!(parse_theme_name("light"), Some(iced::Theme::Light));
|
||||
|
||||
+3
-1
@@ -2807,6 +2807,8 @@ pub enum Message {
|
||||
ToggleViewCube,
|
||||
/// Toggle the Properties panel visibility (PROPERTIES).
|
||||
ToggleProperties,
|
||||
/// Toggle the Graphic Attributes panel visibility (GRAPHICATTRIBUTES).
|
||||
ToggleGraphicAttributes,
|
||||
/// Toggle the document file tabs at the top (FILETAB).
|
||||
ToggleFileTabs,
|
||||
/// Toggle the layout tabs at the bottom (LAYOUTTAB).
|
||||
@@ -4167,7 +4169,7 @@ impl OpenCADStudio {
|
||||
render_mode_menu_open: false,
|
||||
render_mode_preview: None,
|
||||
show_properties: true,
|
||||
show_graphic_attributes: true,
|
||||
show_graphic_attributes: false,
|
||||
graphic_attributes_header_menu_open: false,
|
||||
graphic_attribute_menu_open: false,
|
||||
line_color_menu_open: false,
|
||||
|
||||
@@ -130,7 +130,6 @@ fn close_fill_boundary(entity: &mut acadrust::EntityType) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ConcreteGraphicAttributes {
|
||||
color: acadrust::types::Color,
|
||||
linetype: String,
|
||||
@@ -212,7 +211,8 @@ fn valid_layer_name(name: &str) -> bool {
|
||||
!name.is_empty()
|
||||
&& name.chars().count() <= 255
|
||||
&& !name.chars().any(|character| {
|
||||
matches!(
|
||||
character.is_control()
|
||||
|| matches!(
|
||||
character,
|
||||
'<' | '>' | '/' | '\\' | '"' | ':' | ';' | '?' | '*' | '|' | '=' | '`'
|
||||
)
|
||||
@@ -918,7 +918,10 @@ impl OpenCADStudio {
|
||||
}
|
||||
|
||||
pub(super) fn on_line_linetype_scale(&mut self, scale: f64) -> iced::Task<Message> {
|
||||
let scale = ((scale * 10.0).round() / 10.0).clamp(0.1, 1000.0);
|
||||
let Some(scale) = crate::ui::window::graphic_attributes::normalized_linetype_scale(scale)
|
||||
else {
|
||||
return iced::Task::none();
|
||||
};
|
||||
let i = self.active_tab;
|
||||
let selected = self.tabs[i].scene.selected_handles_in_order();
|
||||
if selected.is_empty() {
|
||||
@@ -1595,8 +1598,12 @@ impl OpenCADStudio {
|
||||
}
|
||||
PanelId::GraphicAttributes => {
|
||||
self.show_graphic_attributes = false;
|
||||
self.ribbon.set_graphic_attributes(false);
|
||||
self.graphic_attributes_header_menu_open = false;
|
||||
self.graphic_attribute_menu_open = false;
|
||||
self.gradient_editor = None;
|
||||
self.hatch_editor_handles = None;
|
||||
self.save_config();
|
||||
}
|
||||
}
|
||||
if self.dock_expanded == Some(id) {
|
||||
@@ -2588,6 +2595,17 @@ mod tests {
|
||||
.abs()
|
||||
< f64::EPSILON
|
||||
);
|
||||
let _ = app.update(Message::LineLinetypeScaleChanged(f64::NAN));
|
||||
assert_eq!(
|
||||
app.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.get_entity(line)
|
||||
.expect("line")
|
||||
.common()
|
||||
.linetype_scale,
|
||||
2.5
|
||||
);
|
||||
let _ = app.update(Message::LineLinetypeScaleChanged(1.2000000000000002));
|
||||
assert_eq!(
|
||||
app.tabs[i]
|
||||
@@ -2817,6 +2835,14 @@ mod tests {
|
||||
let _ = app.on_line_lineweight(acadrust::types::LineWeight::Value(35));
|
||||
let _ = app.on_line_transparency(acadrust::types::Transparency::from_percent(0.3));
|
||||
|
||||
let _ = app.create_graphic_attributes_layer("Invalid\nLayer");
|
||||
assert!(app.tabs[i]
|
||||
.scene
|
||||
.document
|
||||
.layers
|
||||
.get("Invalid\nLayer")
|
||||
.is_none());
|
||||
|
||||
let _ = app.update(Message::GraphicAttributesCreateLayer);
|
||||
assert_eq!(
|
||||
app.tabs[i]
|
||||
|
||||
@@ -1086,6 +1086,7 @@ impl OpenCADStudio {
|
||||
dock.ensure_settings();
|
||||
dock
|
||||
},
|
||||
show_graphic_attributes: self.show_graphic_attributes,
|
||||
annotation_auto_scale: self.annotation_auto_scale,
|
||||
ribbon: crate::app::config::RibbonConfig {
|
||||
collapse: self.ribbon.collapse_mode(),
|
||||
@@ -1144,6 +1145,9 @@ impl OpenCADStudio {
|
||||
let mut dock = cfg.dock;
|
||||
dock.ensure_settings();
|
||||
self.dock = dock;
|
||||
self.show_graphic_attributes = cfg.show_graphic_attributes;
|
||||
self.ribbon
|
||||
.set_graphic_attributes(self.show_graphic_attributes);
|
||||
self.annotation_auto_scale = cfg.annotation_auto_scale.clamp(-4, 4);
|
||||
self.ribbon.set_collapse_mode(cfg.ribbon.collapse);
|
||||
self.plot_dialog = cfg.plot;
|
||||
|
||||
@@ -4229,6 +4229,19 @@ impl OpenCADStudio {
|
||||
self.ribbon.set_properties(self.show_properties);
|
||||
Task::none()
|
||||
}
|
||||
Message::ToggleGraphicAttributes => {
|
||||
self.show_graphic_attributes ^= true;
|
||||
self.ribbon
|
||||
.set_graphic_attributes(self.show_graphic_attributes);
|
||||
if !self.show_graphic_attributes {
|
||||
self.graphic_attributes_header_menu_open = false;
|
||||
self.graphic_attribute_menu_open = false;
|
||||
self.gradient_editor = None;
|
||||
self.hatch_editor_handles = None;
|
||||
}
|
||||
self.save_config();
|
||||
Task::none()
|
||||
}
|
||||
Message::ToggleFileTabs => {
|
||||
self.show_file_tabs ^= true;
|
||||
self.ribbon.set_file_tabs(self.show_file_tabs);
|
||||
@@ -11220,6 +11233,30 @@ mod prop_pointer_tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod graphic_attributes_visibility_tests {
|
||||
use super::Message;
|
||||
use crate::app::OpenCADStudio;
|
||||
|
||||
#[test]
|
||||
fn graphic_attributes_starts_hidden_and_toggle_is_persisted() {
|
||||
let mut app = OpenCADStudio::new_for_test();
|
||||
app.apply_config(crate::app::config::AppConfig::default());
|
||||
assert!(!app.show_graphic_attributes);
|
||||
assert!(!app.ribbon.show_graphic_attributes);
|
||||
|
||||
let _ = app.update(Message::ToggleGraphicAttributes);
|
||||
assert!(app.show_graphic_attributes);
|
||||
assert!(app.ribbon.show_graphic_attributes);
|
||||
assert!(app.current_config().show_graphic_attributes);
|
||||
|
||||
let _ = app.update(Message::ToggleGraphicAttributes);
|
||||
assert!(!app.show_graphic_attributes);
|
||||
assert!(!app.ribbon.show_graphic_attributes);
|
||||
assert!(!app.current_config().show_graphic_attributes);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod free_text_entry_tests {
|
||||
//! The free-form text prompts (table cell content, TEXT / MTEXT bodies)
|
||||
|
||||
+22
-9
@@ -308,6 +308,10 @@ pub struct ValuePromptCommand {
|
||||
prompt: &'static str,
|
||||
}
|
||||
|
||||
fn dispatch_prompt_value(name: &str, text: &str) -> CmdResult {
|
||||
CmdResult::Dispatch(format!("{name} {}", text.trim()))
|
||||
}
|
||||
|
||||
impl ValuePromptCommand {
|
||||
pub fn new(name: &'static str, prompt: &'static str) -> Self {
|
||||
Self { name, prompt }
|
||||
@@ -328,12 +332,7 @@ impl CadCommand for ValuePromptCommand {
|
||||
}
|
||||
|
||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||
let t = text.trim();
|
||||
if t.is_empty() {
|
||||
Some(CmdResult::Dispatch(format!("{} ", self.name)))
|
||||
} else {
|
||||
Some(CmdResult::Dispatch(format!("{} {t}", self.name)))
|
||||
}
|
||||
Some(dispatch_prompt_value(self.name, text))
|
||||
}
|
||||
|
||||
fn on_point(&mut self, _pt: DVec3) -> CmdResult {
|
||||
@@ -343,7 +342,7 @@ impl CadCommand for ValuePromptCommand {
|
||||
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
// Bare Enter → report the current value via the inline handler.
|
||||
CmdResult::Dispatch(format!("{} ", self.name))
|
||||
dispatch_prompt_value(self.name, "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,7 +374,7 @@ impl CadCommand for FreeTextValuePromptCommand {
|
||||
}
|
||||
|
||||
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
|
||||
Some(CmdResult::Dispatch(format!("{} {}", self.name, text.trim())))
|
||||
Some(dispatch_prompt_value(self.name, text))
|
||||
}
|
||||
|
||||
fn on_point(&mut self, _pt: DVec3) -> CmdResult {
|
||||
@@ -383,7 +382,7 @@ impl CadCommand for FreeTextValuePromptCommand {
|
||||
}
|
||||
|
||||
fn on_enter(&mut self) -> CmdResult {
|
||||
CmdResult::Dispatch(format!("{} ", self.name))
|
||||
dispatch_prompt_value(self.name, "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3079,6 +3078,20 @@ mod constraint_registry_tests {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn prompt_dispatch_trims_values_and_preserves_empty_argument() {
|
||||
let CmdResult::Dispatch(value) = dispatch_prompt_value("TEST", " value with spaces ")
|
||||
else {
|
||||
panic!("prompt input should dispatch a command");
|
||||
};
|
||||
assert_eq!(value, "TEST value with spaces");
|
||||
|
||||
let CmdResult::Dispatch(value) = dispatch_prompt_value("TEST", " ") else {
|
||||
panic!("empty prompt input should dispatch a command");
|
||||
};
|
||||
assert_eq!(value, "TEST ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mid2point_command() {
|
||||
let mut cmd = Mid2PointCommand::new();
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
use crate::modules::{IconKind, ModuleEvent, ToolDef};
|
||||
|
||||
pub const ICON: IconKind = IconKind::Svg(include_bytes!(
|
||||
"../../../assets/icons/graphic_attributes.svg"
|
||||
));
|
||||
|
||||
pub fn tool() -> ToolDef {
|
||||
ToolDef {
|
||||
id: "GRAPHICATTRIBUTES",
|
||||
label: "Graphic Attributes",
|
||||
icon: ICON,
|
||||
event: ModuleEvent::Command("GRAPHICATTRIBUTES".to_string()),
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
mod cascade;
|
||||
mod file_tabs;
|
||||
mod graphic_attributes_palette;
|
||||
mod layout_tabs;
|
||||
pub mod limits;
|
||||
mod orbit;
|
||||
@@ -120,6 +121,7 @@ impl CadModule for ViewModule {
|
||||
tools: vec![
|
||||
RibbonItem::LargeTool(tool_palettes::tool()),
|
||||
RibbonItem::LargeTool(properties_palette::tool()),
|
||||
RibbonItem::LargeTool(graphic_attributes_palette::tool()),
|
||||
RibbonItem::LargeTool(sheetset::tool()),
|
||||
],
|
||||
},
|
||||
|
||||
@@ -54,6 +54,8 @@ pub struct Ribbon {
|
||||
pub show_ucs_icon: bool,
|
||||
/// Properties panel (PROPERTIES) visibility — drives the Properties button highlight.
|
||||
pub show_properties: bool,
|
||||
/// Graphic Attributes panel visibility — drives its ribbon button highlight.
|
||||
pub show_graphic_attributes: bool,
|
||||
/// File tabs (FILETAB) visibility — drives the File Tabs button highlight.
|
||||
pub show_file_tabs: bool,
|
||||
/// Layout tabs (LAYOUTTAB) visibility — drives the Layout Tabs button highlight.
|
||||
@@ -162,6 +164,7 @@ impl Ribbon {
|
||||
show_viewcube: true,
|
||||
show_ucs_icon: true,
|
||||
show_properties: true,
|
||||
show_graphic_attributes: false,
|
||||
show_file_tabs: true,
|
||||
show_layout_tabs: true,
|
||||
open_dropdown: None,
|
||||
@@ -315,6 +318,9 @@ impl Ribbon {
|
||||
pub fn set_properties(&mut self, on: bool) {
|
||||
self.show_properties = on;
|
||||
}
|
||||
pub fn set_graphic_attributes(&mut self, on: bool) {
|
||||
self.show_graphic_attributes = on;
|
||||
}
|
||||
pub fn set_file_tabs(&mut self, on: bool) {
|
||||
self.show_file_tabs = on;
|
||||
}
|
||||
@@ -332,6 +338,7 @@ impl Ribbon {
|
||||
show_viewcube: self.show_viewcube,
|
||||
show_ucs_icon: self.show_ucs_icon,
|
||||
show_properties: self.show_properties,
|
||||
show_graphic_attributes: self.show_graphic_attributes,
|
||||
show_block_palette,
|
||||
show_file_tabs: self.show_file_tabs,
|
||||
show_layout_tabs: self.show_layout_tabs,
|
||||
|
||||
@@ -37,6 +37,7 @@ pub(super) struct ToggleState {
|
||||
pub show_viewcube: bool,
|
||||
pub show_ucs_icon: bool,
|
||||
pub show_properties: bool,
|
||||
pub show_graphic_attributes: bool,
|
||||
pub show_block_palette: bool,
|
||||
pub show_file_tabs: bool,
|
||||
pub show_layout_tabs: bool,
|
||||
@@ -374,6 +375,7 @@ pub(super) fn is_active_tool(
|
||||
"NAVVCUBE" => state.show_viewcube,
|
||||
"UCSICON" => state.show_ucs_icon,
|
||||
"PROPERTIES" => state.show_properties,
|
||||
"GRAPHICATTRIBUTES" => state.show_graphic_attributes,
|
||||
"BLOCKPALETTE" => state.show_block_palette,
|
||||
"FILETAB" => state.show_file_tabs,
|
||||
"LAYOUTTAB" => state.show_layout_tabs,
|
||||
|
||||
@@ -57,10 +57,19 @@ struct LinetypeScaleInfo {
|
||||
|
||||
const PALETTE_CONTROL_ICON_SIZE: f32 = 20.0;
|
||||
const COMPACT_BUTTON_HEIGHT: f32 = 22.0;
|
||||
const LINETYPE_SCALE_MIN: f64 = 0.1;
|
||||
const LINETYPE_SCALE_MAX: f64 = 1000.0;
|
||||
const LINETYPE_SCALE_STEP: f64 = 0.1;
|
||||
const TRANSPARENCY_ICON: &[u8] =
|
||||
include_bytes!("../../../assets/icons/attributes/transparency.svg");
|
||||
const LINEWEIGHT_ICON: &[u8] = include_bytes!("../../../assets/icons/attributes/lineweight.svg");
|
||||
|
||||
pub(crate) fn normalized_linetype_scale(value: f64) -> Option<f64> {
|
||||
value
|
||||
.is_finite()
|
||||
.then(|| ((value * 10.0).round() / 10.0).clamp(LINETYPE_SCALE_MIN, LINETYPE_SCALE_MAX))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum GraphicAttribute {
|
||||
Varies,
|
||||
@@ -737,42 +746,24 @@ fn transparency_control<'a>(
|
||||
row![control, more].spacing(4).align_y(iced::Center).into()
|
||||
}
|
||||
|
||||
pub fn view<'a>(
|
||||
document: &'a CadDocument,
|
||||
properties: &'a crate::ui::properties::PropertiesPanel,
|
||||
selected: &[Handle],
|
||||
draw_depth: &rustc_hash::FxHashMap<u64, [f32; 2]>,
|
||||
width: f32,
|
||||
auto_collapse: bool,
|
||||
side: crate::app::config::DockSide,
|
||||
header_menu_open: bool,
|
||||
menu_open: bool,
|
||||
line_color_menu_open: bool,
|
||||
line_linetype_menu_open: bool,
|
||||
line_lineweight_menu_open: bool,
|
||||
line_transparency_menu_open: bool,
|
||||
solid_color_menu_open: bool,
|
||||
transparency_menu_open: bool,
|
||||
hatch_editor_open: bool,
|
||||
hatch_pattern_search: &'a str,
|
||||
hatch_pattern_focus: usize,
|
||||
gradient_editor: Option<&'a crate::ui::window::gradient_editor::GradientEditorState>,
|
||||
gradient_color_picker_open: bool,
|
||||
) -> Element<'a, Message> {
|
||||
fn header_menu(side: crate::app::config::DockSide, open: bool) -> Element<'static, Message> {
|
||||
let menu_button = button(crate::ui::icons::themed_secondary(
|
||||
crate::ui::icons::MENU,
|
||||
12.0,
|
||||
))
|
||||
.on_press(Message::ToggleGraphicAttributesHeaderMenu)
|
||||
.style(move |theme: &Theme, status| {
|
||||
if header_menu_open {
|
||||
if open {
|
||||
button::primary(theme, status)
|
||||
} else {
|
||||
button::subtle(theme, status)
|
||||
}
|
||||
})
|
||||
.padding([3, 5]);
|
||||
let menu: Element<'a, Message> = if header_menu_open {
|
||||
if !open {
|
||||
return menu_button.into();
|
||||
}
|
||||
|
||||
let item = |label: &'static str, message| {
|
||||
button(text(label).size(11))
|
||||
.on_press(message)
|
||||
@@ -807,9 +798,31 @@ pub fn view<'a>(
|
||||
.offset(2.0)
|
||||
.on_dismiss(Message::CloseGraphicAttributesHeaderMenu)
|
||||
.into()
|
||||
} else {
|
||||
menu_button.into()
|
||||
};
|
||||
}
|
||||
|
||||
pub fn view<'a>(
|
||||
document: &'a CadDocument,
|
||||
properties: &'a crate::ui::properties::PropertiesPanel,
|
||||
selected: &[Handle],
|
||||
draw_depth: &rustc_hash::FxHashMap<u64, [f32; 2]>,
|
||||
width: f32,
|
||||
auto_collapse: bool,
|
||||
side: crate::app::config::DockSide,
|
||||
header_menu_open: bool,
|
||||
menu_open: bool,
|
||||
line_color_menu_open: bool,
|
||||
line_linetype_menu_open: bool,
|
||||
line_lineweight_menu_open: bool,
|
||||
line_transparency_menu_open: bool,
|
||||
solid_color_menu_open: bool,
|
||||
transparency_menu_open: bool,
|
||||
hatch_editor_open: bool,
|
||||
hatch_pattern_search: &'a str,
|
||||
hatch_pattern_focus: usize,
|
||||
gradient_editor: Option<&'a crate::ui::window::gradient_editor::GradientEditorState>,
|
||||
gradient_color_picker_open: bool,
|
||||
) -> Element<'a, Message> {
|
||||
let menu = header_menu(side, header_menu_open);
|
||||
let pin_icon = if auto_collapse {
|
||||
crate::ui::icons::themed_primary_weak_text(crate::ui::icons::PIN, 12.0)
|
||||
} else {
|
||||
@@ -1040,15 +1053,17 @@ pub fn view<'a>(
|
||||
.width(Fill)
|
||||
.into()
|
||||
} else {
|
||||
let scale_value = ((scale.value * 10.0).round() / 10.0).clamp(0.1, 1000.0);
|
||||
let scale_value = normalized_linetype_scale(scale.value).unwrap_or(1.0);
|
||||
let mut input = iced_aw::number_input(
|
||||
&scale_value,
|
||||
0.1..=1000.0,
|
||||
LINETYPE_SCALE_MIN..=LINETYPE_SCALE_MAX,
|
||||
|value: f64| {
|
||||
Message::LineLinetypeScaleChanged((value * 10.0).round() / 10.0)
|
||||
Message::LineLinetypeScaleChanged(
|
||||
normalized_linetype_scale(value).unwrap_or(1.0),
|
||||
)
|
||||
},
|
||||
)
|
||||
.step(0.1)
|
||||
.step(LINETYPE_SCALE_STEP)
|
||||
.set_size(crate::ui::ROW_H * 0.42)
|
||||
.padding([5, 5])
|
||||
.input_style(move |theme: &Theme, status| {
|
||||
|
||||
Reference in new issue
Block a user