Add graphic attributes controls and layer creation

This commit is contained in:
Marcel committed 2026-09-29 20:57:52 +02:00
1 parent 85e2dda6ba
commit 3b74c7e7ea
9 files changed
+586 -52

No files matched your search

Generated
+12
View File
@@ -2571,6 +2571,8 @@ dependencies = [
"iced_core",
"iced_fonts_macros",
"iced_widget",
"num-format",
"num-traits",
"web-time",
]
@@ -3768,6 +3770,16 @@ dependencies = [
"syn 2.0.119",
]
[[package]]
name = "num-format"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
dependencies = [
"arrayvec",
"itoa",
]
[[package]]
name = "num-integer"
version = "0.1.46"
+1 -1
View File
@@ -26,7 +26,7 @@ url = "2"
iced = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39", features = ["image", "svg", "advanced", "canvas", "smol", "markdown"] }
iced_runtime = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
iced_core = { git = "https://github.com/iced-rs/iced.git", rev = "23604ff22ab0aad9e00b9327cb7b8546ed84db39" }
iced_aw = { git = "https://github.com/HakanSeven12/iced_aw.git", branch = "agent/fix-iced-fonts", features = ["menu", "context_menu", "color_picker", "drop_down"] }
iced_aw = { git = "https://github.com/HakanSeven12/iced_aw.git", branch = "agent/fix-iced-fonts", features = ["menu", "context_menu", "color_picker", "drop_down", "number_input"] }
bytemuck = { version = "1.25", features = ["derive"] }
glam = { version = "0.33", features = ["bytemuck"] }
rfd = "0.17"
+4
View File
@@ -3,6 +3,10 @@ use super::*;
impl OpenCADStudio {
pub(super) fn dispatch_layers(&mut self, cmd: &str, i: usize) -> Option<Task<Message>> {
match cmd {
cmd if cmd.starts_with("GRAPHICATTRIBUTELAYER ") => {
let name = cmd.trim_start_matches("GRAPHICATTRIBUTELAYER").trim();
return Some(self.create_graphic_attributes_layer(name));
}
// ── Layer object commands ──────────────────────────────────────
"LAYOFF" => {
let handles: Vec<_> = self.tabs[i]
+8
View File
@@ -769,6 +769,7 @@ pub(super) struct OpenCADStudio {
/// Whether the Properties panel is shown on the left (PROPERTIES).
show_properties: bool,
show_graphic_attributes: bool,
graphic_attributes_header_menu_open: bool,
graphic_attribute_menu_open: bool,
line_color_menu_open: bool,
line_linetype_menu_open: bool,
@@ -2066,6 +2067,12 @@ pub enum ArrowKey {
#[derive(Debug, Clone)]
pub enum Message {
ToggleGraphicAttributesHeaderMenu,
CloseGraphicAttributesHeaderMenu,
GraphicAttributesSetAllByLayer,
GraphicAttributesSetAllByBlock,
GraphicAttributesRemoveReferences,
GraphicAttributesCreateLayer,
ToggleGraphicAttributeDropdown,
CloseGraphicAttributeDropdown,
GraphicAttributeChanged(crate::ui::window::graphic_attributes::GraphicAttribute),
@@ -4161,6 +4168,7 @@ impl OpenCADStudio {
render_mode_preview: None,
show_properties: true,
show_graphic_attributes: true,
graphic_attributes_header_menu_open: false,
graphic_attribute_menu_open: false,
line_color_menu_open: false,
line_linetype_menu_open: false,
+408 -1
View File
@@ -130,7 +130,324 @@ fn close_fill_boundary(entity: &mut acadrust::EntityType) -> bool {
}
}
#[derive(Clone)]
struct ConcreteGraphicAttributes {
color: acadrust::types::Color,
linetype: String,
lineweight: acadrust::types::LineWeight,
transparency: acadrust::types::Transparency,
}
fn concrete_graphic_attributes(
color: acadrust::types::Color,
linetype: &str,
lineweight: acadrust::types::LineWeight,
transparency: acadrust::types::Transparency,
layer: Option<&acadrust::tables::Layer>,
) -> ConcreteGraphicAttributes {
let layer_color = layer.map_or(acadrust::types::Color::Index(7), |layer| {
match layer.color {
acadrust::types::Color::ByLayer | acadrust::types::Color::ByBlock => {
acadrust::types::Color::Index(7)
}
color => color,
}
});
let layer_linetype = layer
.map(|layer| layer.line_type.as_str())
.filter(|value| {
!value.is_empty()
&& !value.eq_ignore_ascii_case("ByLayer")
&& !value.eq_ignore_ascii_case("ByBlock")
})
.unwrap_or("Continuous");
let layer_lineweight = layer.map_or(acadrust::types::LineWeight::Default, |layer| {
match layer.line_weight {
acadrust::types::LineWeight::ByLayer | acadrust::types::LineWeight::ByBlock => {
acadrust::types::LineWeight::Default
}
value => value,
}
});
let layer_transparency = layer.map_or_else(
|| acadrust::types::Transparency::from_percent(0.0),
|layer| {
if layer.transparency.is_by_layer() || layer.transparency.is_by_block() {
acadrust::types::Transparency::from_percent(0.0)
} else {
layer.transparency
}
},
);
ConcreteGraphicAttributes {
color: match color {
acadrust::types::Color::ByLayer => layer_color,
acadrust::types::Color::ByBlock => acadrust::types::Color::Index(7),
value => value,
},
linetype: if linetype.is_empty() || linetype.eq_ignore_ascii_case("ByLayer") {
layer_linetype.to_owned()
} else if linetype.eq_ignore_ascii_case("ByBlock") {
"Continuous".to_owned()
} else {
linetype.to_owned()
},
lineweight: match lineweight {
acadrust::types::LineWeight::ByLayer => layer_lineweight,
acadrust::types::LineWeight::ByBlock => acadrust::types::LineWeight::Default,
value => value,
},
transparency: if transparency.is_by_layer() {
layer_transparency
} else if transparency.is_by_block() {
acadrust::types::Transparency::from_percent(0.0)
} else {
transparency
},
}
}
fn valid_layer_name(name: &str) -> bool {
!name.is_empty()
&& name.chars().count() <= 255
&& !name.chars().any(|character| {
matches!(
character,
'<' | '>' | '/' | '\\' | '"' | ':' | ';' | '?' | '*' | '|' | '=' | '`'
)
})
}
impl OpenCADStudio {
fn graphic_attribute_handles(&self, tab: usize) -> Vec<Handle> {
let selected = self.tabs[tab].scene.selected_handles_in_order();
let document = &self.tabs[tab].scene.document;
let mut seen = rustc_hash::FxHashSet::default();
crate::ui::window::graphic_attributes::line_handles(document, &selected)
.into_iter()
.chain(crate::ui::window::graphic_attributes::fill_handles(
document, &selected,
))
.filter(|handle| seen.insert(*handle))
.collect()
}
fn current_graphic_attributes(&self, tab: usize) -> ConcreteGraphicAttributes {
let document = &self.tabs[tab].scene.document;
let handles = self.graphic_attribute_handles(tab);
let draw_depth = self.tabs[tab].scene.draw_depth_map();
let entity = handles
.iter()
.filter_map(|handle| {
document.get_entity(*handle).map(|entity| {
let depth = draw_depth
.get(&handle.value())
.map_or(0.0, |value| value[0]);
(depth, entity)
})
})
.max_by(|(left, _), (right, _)| left.total_cmp(right))
.map(|(_, entity)| entity);
if let Some(entity) = entity {
let common = entity.common();
return concrete_graphic_attributes(
common.color,
&common.linetype,
common.line_weight,
common.transparency,
document.layers.get(&common.layer),
);
}
let header = &document.header;
let layer_name = if header.current_layer_name.is_empty() {
self.tabs[tab].active_layer.as_str()
} else {
header.current_layer_name.as_str()
};
concrete_graphic_attributes(
header.current_entity_color,
&header.current_linetype_name,
acadrust::types::LineWeight::from_value(header.current_line_weight),
document.current_entity_transparency(),
document.layers.get(layer_name),
)
}
pub(super) fn on_graphic_attributes_set_all(&mut self, by_layer: bool) -> iced::Task<Message> {
self.graphic_attributes_header_menu_open = false;
let i = self.active_tab;
let selected = self.tabs[i].scene.selected_handles_in_order();
let (color, linetype, lineweight, transparency) = if by_layer {
(
acadrust::types::Color::ByLayer,
"ByLayer",
acadrust::types::LineWeight::ByLayer,
acadrust::types::Transparency::BY_LAYER,
)
} else {
(
acadrust::types::Color::ByBlock,
"ByBlock",
acadrust::types::LineWeight::ByBlock,
acadrust::types::Transparency::BY_BLOCK,
)
};
if selected.is_empty() {
let header = &mut self.tabs[i].scene.document.header;
header.current_entity_color = color;
header.current_linetype_name = linetype.to_owned();
header.current_linetype_handle = acadrust::Handle::NULL;
header.current_line_weight = lineweight.value();
self.tabs[i]
.scene
.document
.set_current_entity_transparency(transparency);
self.tabs[i].dirty = true;
self.sync_ribbon_from_selection();
self.refresh_properties();
return iced::Task::none();
}
let handles: Vec<_> = self
.graphic_attribute_handles(i)
.into_iter()
.filter(|handle| !self.tabs[i].scene.is_layer_locked(*handle))
.collect();
self.apply_property_op(i, "Graphic Attributes", &handles, |app, handle| {
if let Some(entity) = app.tabs[i].scene.document.get_entity_mut(handle) {
crate::scene::view::dispatch::apply_color(entity, color);
crate::scene::view::dispatch::apply_common_prop(entity, "linetype", linetype);
crate::scene::view::dispatch::apply_line_weight(entity, lineweight);
entity.common_mut().transparency = transparency;
}
});
iced::Task::none()
}
pub(super) fn on_graphic_attributes_remove_references(&mut self) -> iced::Task<Message> {
self.graphic_attributes_header_menu_open = false;
let i = self.active_tab;
let selected = self.tabs[i].scene.selected_handles_in_order();
if selected.is_empty() {
let values = self.current_graphic_attributes(i);
let linetype_handle = self.tabs[i]
.scene
.document
.line_types
.iter()
.find(|linetype| linetype.name.eq_ignore_ascii_case(&values.linetype))
.map_or(acadrust::Handle::NULL, |linetype| linetype.handle);
let header = &mut self.tabs[i].scene.document.header;
header.current_entity_color = values.color;
header.current_linetype_name = values.linetype;
header.current_linetype_handle = linetype_handle;
header.current_line_weight = values.lineweight.value();
self.tabs[i]
.scene
.document
.set_current_entity_transparency(values.transparency);
self.tabs[i].dirty = true;
self.sync_ribbon_from_selection();
self.refresh_properties();
return iced::Task::none();
}
let handles: Vec<_> = self
.graphic_attribute_handles(i)
.into_iter()
.filter(|handle| !self.tabs[i].scene.is_layer_locked(*handle))
.collect();
let values: rustc_hash::FxHashMap<_, _> = handles
.iter()
.filter_map(|handle| {
let entity = self.tabs[i].scene.document.get_entity(*handle)?;
let common = entity.common();
Some((
*handle,
concrete_graphic_attributes(
common.color,
&common.linetype,
common.line_weight,
common.transparency,
self.tabs[i].scene.document.layers.get(&common.layer),
),
))
})
.collect();
self.apply_property_op(i, "Graphic Attributes", &handles, |app, handle| {
let Some(values) = values.get(&handle) else {
return;
};
if let Some(entity) = app.tabs[i].scene.document.get_entity_mut(handle) {
crate::scene::view::dispatch::apply_color(entity, values.color);
crate::scene::view::dispatch::apply_common_prop(
entity,
"linetype",
&values.linetype,
);
crate::scene::view::dispatch::apply_line_weight(entity, values.lineweight);
entity.common_mut().transparency = values.transparency;
}
});
iced::Task::none()
}
pub(crate) fn create_graphic_attributes_layer(
&mut self,
raw_name: &str,
) -> iced::Task<Message> {
let i = self.active_tab;
let name = raw_name.trim();
if !valid_layer_name(name) {
self.command_line
.push_error("Graphic Attributes: enter a valid layer name without <>/\\\":;?*|=`.");
return iced::Task::none();
}
if self.tabs[i]
.scene
.document
.layers
.iter()
.any(|layer| layer.name.eq_ignore_ascii_case(name))
{
self.command_line.push_error(
crate::tf!("Graphic Attributes: layer \"{name}\" already exists.").as_ref(),
);
return iced::Task::none();
}
let values = self.current_graphic_attributes(i);
let layer_name = name.to_owned();
let undo = self.begin_layer_undo(
i,
"Create layer with active settings",
std::slice::from_ref(&layer_name),
);
let mut layer = acadrust::tables::Layer::new(name);
layer.handle = self.tabs[i].scene.document.allocate_handle();
layer.color = values.color;
layer.line_type = values.linetype;
layer.line_weight = values.lineweight;
layer.transparency = values.transparency;
use acadrust::tables::Table;
if self.tabs[i].scene.document.layers.add(layer).is_err() {
self.command_line
.push_error("Graphic Attributes: the layer could not be created.");
return iced::Task::none();
}
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
self.command_line.push_output(
crate::tf!("Created layer \"{name}\" with the active Graphic Attributes settings.")
.as_ref(),
);
iced::Task::none()
}
pub(super) fn open_gradient_editor(&mut self) {
use crate::ui::window::gradient_editor::GradientEditorState;
let i = self.active_tab;
@@ -601,7 +918,7 @@ impl OpenCADStudio {
}
pub(super) fn on_line_linetype_scale(&mut self, scale: f64) -> iced::Task<Message> {
let scale = scale.clamp(0.01, 1000.0);
let scale = ((scale * 10.0).round() / 10.0).clamp(0.1, 1000.0);
let i = self.active_tab;
let selected = self.tabs[i].scene.selected_handles_in_order();
if selected.is_empty() {
@@ -1278,6 +1595,7 @@ impl OpenCADStudio {
}
PanelId::GraphicAttributes => {
self.show_graphic_attributes = false;
self.graphic_attributes_header_menu_open = false;
self.graphic_attribute_menu_open = false;
}
}
@@ -2270,6 +2588,17 @@ mod tests {
.abs()
< f64::EPSILON
);
let _ = app.update(Message::LineLinetypeScaleChanged(1.2000000000000002));
assert_eq!(
app.tabs[i]
.scene
.document
.get_entity(line)
.expect("line")
.common()
.linetype_scale,
1.2
);
let _ = app.on_line_transparency(acadrust::types::Transparency::from_percent(0.2));
assert!(
(app.tabs[i]
@@ -2433,6 +2762,84 @@ mod tests {
);
}
#[test]
fn graphic_attributes_bulk_modes_and_remove_references_preserve_visible_values() {
let mut app = fresh();
let i = app.active_tab;
{
let layer = app.tabs[i]
.scene
.document
.layers
.get_mut("0")
.expect("default layer");
layer.color = acadrust::types::Color::Index(3);
layer.line_type = "Continuous".to_string();
layer.line_weight = acadrust::types::LineWeight::Value(50);
layer.transparency = acadrust::types::Transparency::from_percent(0.25);
}
let handle = app.tabs[i].scene.add_entity(EntityType::Line(Line::new()));
app.tabs[i].scene.select_entity(handle, false);
let _ = app.on_graphic_attributes_set_all(false);
let common = app.tabs[i]
.scene
.document
.get_entity(handle)
.expect("line")
.common();
assert_eq!(common.color, acadrust::types::Color::ByBlock);
assert_eq!(common.linetype, "ByBlock");
assert_eq!(common.line_weight, acadrust::types::LineWeight::ByBlock);
assert!(common.transparency.is_by_block());
let _ = app.on_graphic_attributes_set_all(true);
let _ = app.on_graphic_attributes_remove_references();
let common = app.tabs[i]
.scene
.document
.get_entity(handle)
.expect("line")
.common();
assert_eq!(common.color, acadrust::types::Color::Index(3));
assert_eq!(common.linetype, "Continuous");
assert_eq!(common.line_weight, acadrust::types::LineWeight::Value(50));
assert!((common.transparency.as_percent() - 0.25).abs() < 0.01);
}
#[test]
fn graphic_attributes_create_layer_prompt_keeps_spaces_and_active_settings() {
let mut app = fresh();
let i = app.active_tab;
app.tabs[i].scene.deselect_all();
let _ = app.on_line_color(acadrust::types::Color::Index(2));
let _ = app.on_line_linetype("Continuous".to_string());
let _ = app.on_line_lineweight(acadrust::types::LineWeight::Value(35));
let _ = app.on_line_transparency(acadrust::types::Transparency::from_percent(0.3));
let _ = app.update(Message::GraphicAttributesCreateLayer);
assert_eq!(
app.tabs[i]
.active_cmd
.as_ref()
.map(|command| command.name()),
Some("GRAPHICATTRIBUTELAYER")
);
let _ = app.update(Message::CommandInput("Graphic Settings".to_string()));
let _ = app.update(Message::CommandFinalize);
let layer = app.tabs[i]
.scene
.document
.layers
.get("Graphic Settings")
.expect("created layer");
assert_eq!(layer.color, acadrust::types::Color::Index(2));
assert_eq!(layer.line_type, "Continuous");
assert_eq!(layer.line_weight, acadrust::types::LineWeight::Value(35));
assert!((layer.transparency.as_percent() - 0.3).abs() < 0.01);
}
/// A foreign document: the fresh scene's document plus one model-space LINE.
fn foreign_doc(app: &OpenCADStudio) -> acadrust::CadDocument {
let mut doc = app.tabs[app.active_tab].scene.document.clone();
+23
View File
@@ -9577,6 +9577,29 @@ impl OpenCADStudio {
Message::PlotDialogOpen => self.on_plot_dialog_open(),
Message::PlotDlg(m) => self.on_plot_dlg(m),
Message::BlockPalette(m) => self.on_block_palette(m),
Message::ToggleGraphicAttributesHeaderMenu => {
self.graphic_attributes_header_menu_open ^= true;
Task::none()
}
Message::CloseGraphicAttributesHeaderMenu => {
self.graphic_attributes_header_menu_open = false;
Task::none()
}
Message::GraphicAttributesSetAllByLayer => self.on_graphic_attributes_set_all(true),
Message::GraphicAttributesSetAllByBlock => self.on_graphic_attributes_set_all(false),
Message::GraphicAttributesRemoveReferences => {
self.on_graphic_attributes_remove_references()
}
Message::GraphicAttributesCreateLayer => {
self.graphic_attributes_header_menu_open = false;
let command = crate::command::FreeTextValuePromptCommand::new(
"GRAPHICATTRIBUTELAYER",
"Enter a name for the new layer:",
);
self.command_line.push_info(&command.prompt());
self.tabs[self.active_tab].active_cmd = Some(Box::new(command));
self.focus_cmd_input()
}
Message::ToggleGraphicAttributeDropdown => {
self.graphic_attribute_menu_open ^= true;
self.line_color_menu_open = false;
+1
View File
@@ -2953,6 +2953,7 @@ impl OpenCADStudio {
width,
auto_collapse,
side,
self.graphic_attributes_header_menu_open,
self.graphic_attribute_menu_open,
self.line_color_menu_open,
self.line_linetype_menu_open,
+40
View File
@@ -347,6 +347,46 @@ impl CadCommand for ValuePromptCommand {
}
}
/// One-value prompt that preserves spaces and letter casing. This is intended
/// for symbol names entered through the command line, where a space belongs to
/// the value instead of submitting the current token.
pub struct FreeTextValuePromptCommand {
name: &'static str,
prompt: &'static str,
}
impl FreeTextValuePromptCommand {
pub fn new(name: &'static str, prompt: &'static str) -> Self {
Self { name, prompt }
}
}
impl CadCommand for FreeTextValuePromptCommand {
fn name(&self) -> &'static str {
self.name
}
fn prompt(&self) -> String {
crate::t!(self.prompt).into_owned()
}
fn input_kind(&self) -> InputKind {
InputKind::FreeText
}
fn on_text_input(&mut self, text: &str) -> Option<CmdResult> {
Some(CmdResult::Dispatch(format!("{} {}", self.name, text.trim())))
}
fn on_point(&mut self, _pt: DVec3) -> CmdResult {
CmdResult::NeedPoint
}
fn on_enter(&mut self) -> CmdResult {
CmdResult::Dispatch(format!("{} ", self.name))
}
}
/// Interactive pick for `UCS FACE` and `UCS OBJECT`.
///
/// Hands the picked entity to the inline `UCS FACE <handle> <x,y,z>` /
+89 -50
View File
@@ -745,6 +745,7 @@ pub fn view<'a>(
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,
@@ -758,6 +759,57 @@ pub fn view<'a>(
gradient_editor: Option<&'a crate::ui::window::gradient_editor::GradientEditorState>,
gradient_color_picker_open: bool,
) -> Element<'a, 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 {
button::primary(theme, status)
} else {
button::subtle(theme, status)
}
})
.padding([3, 5]);
let menu: Element<'a, Message> = if header_menu_open {
let item = |label: &'static str, message| {
button(text(label).size(11))
.on_press(message)
.style(crate::ui::color_select::list_row_style)
.width(Fill)
.padding([4, 8])
};
let popup = container(column![
item(
"Set all attributes ByLayer",
Message::GraphicAttributesSetAllByLayer,
),
item(
"Set all attributes ByBlock",
Message::GraphicAttributesSetAllByBlock,
),
item(
"Remove ByLayer / ByBlock",
Message::GraphicAttributesRemoveReferences,
),
item(
"Create Layer with active settings",
Message::GraphicAttributesCreateLayer,
),
])
.style(crate::ui::color_select::popup_panel_style)
.padding(2);
iced_aw::DropDown::new(menu_button, popup, true)
.width(Length::Fixed(220.0))
.height(Length::Shrink)
.alignment(popup_alignment(side))
.offset(2.0)
.on_dismiss(Message::CloseGraphicAttributesHeaderMenu)
.into()
} else {
menu_button.into()
};
let pin_icon = if auto_collapse {
crate::ui::icons::themed_primary_weak_text(crate::ui::icons::PIN, 12.0)
} else {
@@ -793,6 +845,7 @@ pub fn view<'a>(
row![
text(crate::t!("Graphic Attributes")).size(12),
Space::new().width(Fill),
menu,
pin,
close
]
@@ -979,15 +1032,26 @@ pub fn view<'a>(
));
}
if let (Some(scale), Some(lineweight)) = (linetype_scale, lineweight) {
let scale_text = if scale.varies {
String::new()
let scale_field: Element<'_, Message> = if scale.varies {
text_input("*VARIES*", "")
.size(crate::ui::ROW_H * 0.42)
.padding([5, 5])
.style(crate::ui::properties::combo_input_style)
.width(Fill)
.into()
} else {
format!("{:.2}", scale.value)
};
let mut scale_input = text_input("*VARIES*", &scale_text)
.size(crate::ui::ROW_H * 0.42)
.padding([3, 5])
.style(move |theme: &Theme, status| {
let scale_value = ((scale.value * 10.0).round() / 10.0).clamp(0.1, 1000.0);
let mut input = iced_aw::number_input(
&scale_value,
0.1..=1000.0,
|value: f64| {
Message::LineLinetypeScaleChanged((value * 10.0).round() / 10.0)
},
)
.step(0.1)
.set_size(crate::ui::ROW_H * 0.42)
.padding([5, 5])
.input_style(move |theme: &Theme, status| {
let mut style = crate::ui::properties::combo_input_style(theme, status);
if continuous_linetype {
let disabled = theme.palette().background.base.text.scale_alpha(0.42);
@@ -996,29 +1060,26 @@ pub fn view<'a>(
}
style
})
.on_submit(Message::Noop)
.style(move |theme: &Theme, status| {
let text = theme.palette().background.base.text;
iced_aw::number_input::number_input::Style {
button_background: None,
icon_color: if continuous_linetype
|| status == iced_aw::style::Status::Disabled
{
text.scale_alpha(0.42)
} else {
text
},
}
})
.width(Fill);
if !continuous_linetype {
scale_input = scale_input.on_input(Message::LineLinetypeScaleInput);
}
let step = |up: bool| {
let icon: Element<'_, Message> = if up {
crate::ui::icons::themed_arrow_up(7.0)
} else {
crate::ui::icons::themed_arrow_down(7.0)
};
let button = button(icon)
.style(button::subtle)
.height(10)
.padding([0, 3]);
if continuous_linetype {
button
input = input.on_input_maybe(None::<fn(f64) -> Message>);
} else {
let delta = if up { 0.1 } else { -0.1 };
button.on_press(Message::LineLinetypeScaleChanged(
(scale.value + delta).clamp(0.01, 1000.0),
))
}
input = input.on_submit(Message::Noop);
}
input.into()
};
let scale_icon: Element<'_, Message> = if continuous_linetype {
crate::ui::icons::themed_disabled(
@@ -1031,28 +1092,6 @@ pub fn view<'a>(
PALETTE_CONTROL_ICON_SIZE,
)
};
let spinner_divider = container(Space::new())
.width(Fill)
.height(1)
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(theme.palette().background.neutral.color)),
..Default::default()
});
let spinner = container(column![step(true), spinner_divider, step(false)].spacing(0))
.height(COMPACT_BUTTON_HEIGHT)
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(theme.palette().background.base.color)),
border: Border {
color: theme.palette().background.neutral.color,
width: 1.0,
radius: 2.0.into(),
},
..Default::default()
});
let scale_field = row![scale_input, spinner]
.spacing(0)
.align_y(iced::Center)
.width(Fill);
let scale = row![scale_icon, scale_field]
.spacing(3)
.align_y(iced::Center)