forked from 1b-agent/opencadstudio-upstream
Merge pull request #1795 from MarcelP102/Select-Color-Redesign
[UX] Select Color redesign and feature parity Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
843cbcd607
56 files changed
+4716
-606
No files matched your search
+267
-102
@@ -436,6 +436,41 @@ impl OpenCADStudio {
|
||||
let tab = &self.tabs[self.active_tab];
|
||||
(started, tab.id, tab.scene.geometry_epoch)
|
||||
});
|
||||
// The Select Color panel can open on top of another dialog, so it
|
||||
// takes the keyboard first: Esc cancels, Enter confirms, the arrows
|
||||
// walk the index palette, and every other keystroke is swallowed.
|
||||
if self.color_picker.is_some() {
|
||||
use crate::ui::color_select::ColorPickerMsg;
|
||||
match &msg {
|
||||
Message::CommandEscape => {
|
||||
return self.update(Message::ColorPicker(ColorPickerMsg::Cancel));
|
||||
}
|
||||
Message::CommandFinalize => {
|
||||
return self.update(Message::ColorPicker(ColorPickerMsg::Ok));
|
||||
}
|
||||
Message::ShortcutPressed(key) => match key.rsplit('+').next() {
|
||||
Some("ESCAPE") => {
|
||||
return self.update(Message::ColorPicker(ColorPickerMsg::Cancel));
|
||||
}
|
||||
Some("ENTER" | "RETURN") => {
|
||||
return self.update(Message::ColorPicker(ColorPickerMsg::Ok));
|
||||
}
|
||||
Some("TAB") => {
|
||||
return crate::ui::color_select::picker::focus_step(
|
||||
!key.contains("SHIFT+"),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Message::ArrowKeyPressed { direction, .. } => {
|
||||
return self.update(Message::ColorPicker(ColorPickerMsg::Arrow(*direction)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if is_modal_blocked_key_msg(&msg) {
|
||||
return Task::none();
|
||||
}
|
||||
}
|
||||
// A modal dialog must capture the keyboard the same way it already
|
||||
// captures the mouse. Otherwise keystrokes from the global key
|
||||
// subscription leak past the modal into the command line and fire as
|
||||
@@ -4330,38 +4365,7 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::LayerColorSet(color) => {
|
||||
let i = self.active_tab;
|
||||
// Apply to every selected layer (multi-select), not just one.
|
||||
let names = self.selected_layer_names(i);
|
||||
if !names.is_empty() {
|
||||
let undo = self.begin_layer_undo(i, "LAYER COLOR", &names);
|
||||
for name in &names {
|
||||
if let Some(dl) = self.tabs[i].scene.document.layers.get_mut(name) {
|
||||
dl.color = color;
|
||||
dl.color_name = None;
|
||||
dl.book_name = None;
|
||||
}
|
||||
}
|
||||
for pl in self.tabs[i].layers.layers.iter_mut() {
|
||||
if names.contains(&pl.name) {
|
||||
pl.color = color;
|
||||
pl.color_name = None;
|
||||
pl.book_name = None;
|
||||
}
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.commit_layer_undo(i, undo);
|
||||
// ByLayer color is baked into the cached wires at
|
||||
// tessellation time, so bump the geometry epoch to
|
||||
// invalidate the wire cache and repaint with the new color.
|
||||
self.tabs[i].scene.invalidate_layer_dependencies(&names);
|
||||
self.tabs[i].layers.color_picker_row = None;
|
||||
self.tabs[i].layers.color_full_palette = false;
|
||||
self.sync_ribbon_layers();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::LayerColorSet(color) => self.set_layer_color(color, None),
|
||||
|
||||
Message::LayerLinetypeSet(lt) => {
|
||||
let i = self.active_tab;
|
||||
@@ -4473,7 +4477,7 @@ impl OpenCADStudio {
|
||||
Message::PaneClicked(pane) => self.on_pane_clicked(pane),
|
||||
Message::PaneDragged(ev) => self.on_pane_dragged(ev),
|
||||
Message::PaneMove(idx, local) => {
|
||||
if self.color_pick_target.is_some() {
|
||||
if self.color_picker.is_some() {
|
||||
return Task::none();
|
||||
}
|
||||
let p = self.pane_canvas_point(idx, local);
|
||||
@@ -7432,22 +7436,7 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::PropColorChanged(color) => {
|
||||
let i = self.active_tab;
|
||||
let handles = self.property_target_handles(i);
|
||||
if handles.is_empty() {
|
||||
let task = self.on_ribbon_color_changed(color);
|
||||
self.refresh_properties();
|
||||
return task;
|
||||
}
|
||||
self.apply_property_op(i, "CHPROP", &handles, |app, handle| {
|
||||
if let Some(entity) = app.tabs[i].scene.document.get_entity_mut(handle) {
|
||||
crate::scene::view::dispatch::apply_color(entity, color);
|
||||
}
|
||||
});
|
||||
self.tabs[i].properties.color_picker_open = false;
|
||||
Task::none()
|
||||
}
|
||||
Message::PropColorChanged(color) => self.set_property_color(color, None),
|
||||
|
||||
Message::PropLwChanged(lw) => {
|
||||
let i = self.active_tab;
|
||||
@@ -8958,39 +8947,6 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::BgPickerOpen(target) => {
|
||||
self.bg_picker = Some(target);
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::BgPickerCancel => {
|
||||
self.bg_picker = None;
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::BgPickerSubmit(color) => {
|
||||
// Hand the result to the same handler the typed hex field
|
||||
// uses, so the wheel and the field cannot drift apart on
|
||||
// validation, persistence or the MatchTheme fallback.
|
||||
let hex = crate::app::config::rgb_to_hex([
|
||||
(color.r * 255.0).round() as u8,
|
||||
(color.g * 255.0).round() as u8,
|
||||
(color.b * 255.0).round() as u8,
|
||||
]);
|
||||
match self.bg_picker.take() {
|
||||
Some(crate::app::BgTarget::Model) => {
|
||||
Task::done(Message::ModelSpaceBgChanged(hex))
|
||||
}
|
||||
Some(crate::app::BgTarget::Paper) => {
|
||||
Task::done(Message::PaperSpaceBgChanged(hex))
|
||||
}
|
||||
Some(crate::app::BgTarget::Desk) => {
|
||||
Task::done(Message::DeskSpaceBgChanged(hex))
|
||||
}
|
||||
None => Task::none(),
|
||||
}
|
||||
}
|
||||
|
||||
Message::ModelSpaceBgChanged(hex) => {
|
||||
self.model_bg_input = hex.clone();
|
||||
if hex.trim().is_empty() {
|
||||
@@ -11922,10 +11878,21 @@ impl OpenCADStudio {
|
||||
) {
|
||||
self.graphic_attributes.open_menu = None;
|
||||
}
|
||||
self.color_pick_target = Some((target, color));
|
||||
|
||||
// Always open the shared CAD colour picker on the indexed ACI page.
|
||||
self.color_picker_tab = crate::app::ColorPickerTab::Index;
|
||||
let (current, varies, name) = self.color_picker_current(&target, color);
|
||||
let mut picker = crate::ui::color_select::ColorPicker::new(target, current, varies);
|
||||
if !matches!(picker.target, crate::app::ColorPickTarget::Interface(_)) {
|
||||
self.read_color_books();
|
||||
let by_layer = self.color_picker_layer_color(&picker.target);
|
||||
let tab = &self.tabs[self.active_tab];
|
||||
picker = picker.with_drawing(
|
||||
crate::ui::color_select::document::collect(&tab.scene.document),
|
||||
&tab.recent_colors,
|
||||
std::sync::Arc::clone(&self.color_books),
|
||||
name,
|
||||
by_layer,
|
||||
);
|
||||
}
|
||||
self.color_picker = Some(picker);
|
||||
self.modal_offset = iced::Vector::ZERO;
|
||||
self.ds_color_open = None;
|
||||
self.mls_color_open = None;
|
||||
@@ -11940,29 +11907,226 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::ColorPickerTabChanged(tab) => {
|
||||
self.color_picker_tab = tab;
|
||||
Task::none()
|
||||
}
|
||||
Message::ColorPickerColorChanged(color) => {
|
||||
if let Some((_, current)) = self.color_pick_target.as_mut() {
|
||||
*current = color;
|
||||
Message::ColorPicker(msg) => {
|
||||
let Some(picker) = self.color_picker.as_mut() else {
|
||||
return Task::none();
|
||||
};
|
||||
match picker.update(msg) {
|
||||
Some(crate::ui::color_select::Outcome::Commit(color, name)) => {
|
||||
self.update(Message::ColorWindowPick(color, name))
|
||||
}
|
||||
Some(crate::ui::color_select::Outcome::LoadBook) => Task::perform(
|
||||
crate::ui::color_select::book::load_from_dialog(),
|
||||
Message::ColorBookLoaded,
|
||||
),
|
||||
Some(crate::ui::color_select::Outcome::Cancel) => {
|
||||
self.color_picker = None;
|
||||
Task::none()
|
||||
}
|
||||
Some(crate::ui::color_select::Outcome::Screenshot) => {
|
||||
use crate::ui::color_select::{eyedropper::EyedropperMsg, ColorPickerMsg};
|
||||
match self.main_window {
|
||||
Some(id) => iced::window::screenshot(id).map(|shot| {
|
||||
Message::ColorPicker(ColorPickerMsg::Eyedropper(
|
||||
EyedropperMsg::Shot(shot),
|
||||
))
|
||||
}),
|
||||
// Nothing to capture: leave the eyedropper instead
|
||||
// of waiting for a screenshot that never comes.
|
||||
None => self.update(Message::ColorPicker(ColorPickerMsg::Cancel)),
|
||||
}
|
||||
}
|
||||
None => Task::none(),
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::CloseColorPicker => {
|
||||
self.color_pick_target = None;
|
||||
self.color_picker = None;
|
||||
Task::none()
|
||||
}
|
||||
|
||||
Message::ColorWindowPick(color) => {
|
||||
self.note_recent_color(color);
|
||||
self.on_color_window_pick(color)
|
||||
Message::ColorWindowPick(color, name) => {
|
||||
// Interface colours are not drawing colours: keep them out of
|
||||
// the recent list.
|
||||
if !matches!(
|
||||
self.color_picker.as_ref().map(|picker| &picker.target),
|
||||
Some(crate::app::ColorPickTarget::Interface(_))
|
||||
) {
|
||||
self.note_recent_color(color);
|
||||
}
|
||||
self.on_color_window_pick(color, name)
|
||||
}
|
||||
Message::ColorBookLoaded(Ok(book)) => {
|
||||
// A book loaded again replaces the earlier copy.
|
||||
let index = crate::ui::color_select::book::add_or_replace(
|
||||
std::sync::Arc::make_mut(&mut self.color_books),
|
||||
book,
|
||||
);
|
||||
if let Some(picker) = self.color_picker.as_mut() {
|
||||
picker.show_book(std::sync::Arc::clone(&self.color_books), index);
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::ColorBookLoaded(Err(error)) => {
|
||||
if let Some(picker) = self.color_picker.as_mut().filter(|_| error != "Cancelled") {
|
||||
picker.set_status(error);
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
Message::DsSetHandle { field, value } => self.on_ds_set_handle(field, value),
|
||||
}
|
||||
}
|
||||
|
||||
/// The colour the Select Color panel shows as "Current", and whether the
|
||||
/// selection it edits has mixed colours. A mixed selection starts from the
|
||||
/// colour of its most recently drawn object (the highest handle).
|
||||
/// Also returns the colour-book identity (`BOOK$NAME`) of that colour.
|
||||
fn color_picker_current(
|
||||
&self,
|
||||
target: &crate::app::ColorPickTarget,
|
||||
color: codec::types::Color,
|
||||
) -> (codec::types::Color, bool, Option<String>) {
|
||||
let i = self.active_tab;
|
||||
let document = &self.tabs[i].scene.document;
|
||||
let name_of = |handle| {
|
||||
document
|
||||
.get_entity(handle)
|
||||
.and_then(|entity| entity.common().color_name.clone())
|
||||
};
|
||||
match target {
|
||||
crate::app::ColorPickTarget::Properties => {}
|
||||
crate::app::ColorPickTarget::Ribbon => {
|
||||
return (color, false, self.ribbon.active_color_name());
|
||||
}
|
||||
crate::app::ColorPickTarget::Layer(layer) => {
|
||||
let name = document
|
||||
.layers
|
||||
.get(layer)
|
||||
.and_then(crate::ui::color_select::document::layer_identity);
|
||||
return (color, false, name);
|
||||
}
|
||||
_ => return (color, false, None),
|
||||
}
|
||||
let mut colors = self
|
||||
.property_target_handles(i)
|
||||
.into_iter()
|
||||
.filter_map(|handle| {
|
||||
document
|
||||
.get_entity(handle)
|
||||
.map(|entity| (handle, entity.common().color))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let Some(&(first_handle, first)) = colors.first() else {
|
||||
return (color, false, None);
|
||||
};
|
||||
if colors.iter().all(|&(_, c)| c == first) {
|
||||
return (first, false, name_of(first_handle));
|
||||
}
|
||||
colors.sort_by_key(|&(handle, _)| handle);
|
||||
let (newest_handle, newest) = colors.last().copied().unwrap_or((first_handle, color));
|
||||
(newest, true, name_of(newest_handle))
|
||||
}
|
||||
|
||||
/// The colour ByLayer stands for in the Select Color panel: the layer of
|
||||
/// the newest selected object, or the current layer for new objects.
|
||||
fn color_picker_layer_color(
|
||||
&self,
|
||||
target: &crate::app::ColorPickTarget,
|
||||
) -> Option<codec::types::Color> {
|
||||
let i = self.active_tab;
|
||||
let document = &self.tabs[i].scene.document;
|
||||
let layer = match target {
|
||||
crate::app::ColorPickTarget::Properties => self
|
||||
.property_target_handles(i)
|
||||
.into_iter()
|
||||
.max()
|
||||
.and_then(|handle| document.get_entity(handle))
|
||||
.map_or(self.tabs[i].active_layer.as_str(), |entity| {
|
||||
entity.as_entity().layer()
|
||||
}),
|
||||
crate::app::ColorPickTarget::Ribbon => self.tabs[i].active_layer.as_str(),
|
||||
_ => return None,
|
||||
};
|
||||
document.layers.get(layer).map(|layer| layer.color)
|
||||
}
|
||||
|
||||
/// Read the built-in colour book and every `.acb` in the colour book
|
||||
/// folder, once per session. A book in the folder replaces a built-in
|
||||
/// one of the same name.
|
||||
fn read_color_books(&mut self) {
|
||||
if std::mem::replace(&mut self.color_books_read, true) {
|
||||
return;
|
||||
}
|
||||
self.color_books = std::sync::Arc::new(crate::ui::color_select::book::read_all());
|
||||
}
|
||||
|
||||
/// Colour the selected objects (or set the current colour when nothing
|
||||
/// is selected). `name` is a colour-book identity, `BOOK$NAME`.
|
||||
pub(super) fn set_property_color(
|
||||
&mut self,
|
||||
color: codec::types::Color,
|
||||
name: Option<String>,
|
||||
) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
let handles = self.property_target_handles(i);
|
||||
if handles.is_empty() {
|
||||
let task = self.on_ribbon_color_changed(color);
|
||||
self.ribbon.active_color_book = name.map(|name| (color, name));
|
||||
self.refresh_properties();
|
||||
return task;
|
||||
}
|
||||
self.apply_property_op(i, "CHPROP", &handles, |app, handle| {
|
||||
if let Some(entity) = app.tabs[i].scene.document.get_entity_mut(handle) {
|
||||
crate::scene::view::dispatch::apply_named_color(entity, color, name.clone());
|
||||
}
|
||||
});
|
||||
self.tabs[i].properties.color_picker_open = false;
|
||||
Task::none()
|
||||
}
|
||||
|
||||
/// Colour every selected layer (multi-select), not just one. `name` is a
|
||||
/// colour-book identity, `BOOK$NAME`.
|
||||
pub(super) fn set_layer_color(
|
||||
&mut self,
|
||||
color: codec::types::Color,
|
||||
name: Option<&str>,
|
||||
) -> Task<Message> {
|
||||
let i = self.active_tab;
|
||||
// Layers keep the book and the colour name apart.
|
||||
let (book_name, color_name) = match name.map(|name| name.split_once('$')) {
|
||||
Some(Some((book, name))) => (Some(book), Some(name)),
|
||||
Some(None) => (None, name),
|
||||
None => (None, None),
|
||||
};
|
||||
let names = self.selected_layer_names(i);
|
||||
if !names.is_empty() {
|
||||
let undo = self.begin_layer_undo(i, "LAYER COLOR", &names);
|
||||
for name in &names {
|
||||
if let Some(dl) = self.tabs[i].scene.document.layers.get_mut(name) {
|
||||
dl.color = color;
|
||||
dl.color_name = color_name.map(str::to_string);
|
||||
dl.book_name = book_name.map(str::to_string);
|
||||
}
|
||||
}
|
||||
for pl in self.tabs[i].layers.layers.iter_mut() {
|
||||
if names.contains(&pl.name) {
|
||||
pl.color = color;
|
||||
pl.color_name = color_name.map(str::to_string);
|
||||
pl.book_name = book_name.map(str::to_string);
|
||||
}
|
||||
}
|
||||
self.tabs[i].dirty = true;
|
||||
self.commit_layer_undo(i, undo);
|
||||
// ByLayer color is baked into the cached wires at
|
||||
// tessellation time, so bump the geometry epoch to
|
||||
// invalidate the wire cache and repaint with the new color.
|
||||
self.tabs[i].scene.invalidate_layer_dependencies(&names);
|
||||
self.tabs[i].layers.color_picker_row = None;
|
||||
self.tabs[i].layers.color_full_palette = false;
|
||||
self.sync_ribbon_layers();
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
|
||||
pub(crate) fn note_recent_color(&mut self, color: codec::types::Color) {
|
||||
// Keep only real colours in the recent list. ByLayer / ByBlock / None
|
||||
// are logical CAD states rather than reusable colours.
|
||||
@@ -11971,12 +12135,13 @@ impl OpenCADStudio {
|
||||
codec::types::Color::Index(_) | codec::types::Color::Rgb { .. }
|
||||
) {
|
||||
// No duplicates: selecting an existing colour moves it to the front.
|
||||
if let Some(pos) = self.recent_colors.iter().position(|c| c == &color) {
|
||||
self.recent_colors.remove(pos);
|
||||
let recent = &mut self.tabs[self.active_tab].recent_colors;
|
||||
if let Some(pos) = recent.iter().position(|c| c == &color) {
|
||||
recent.remove(pos);
|
||||
}
|
||||
|
||||
self.recent_colors.insert(0, color);
|
||||
self.recent_colors.truncate(12);
|
||||
recent.insert(0, color);
|
||||
recent.truncate(12);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+54
-27
@@ -1136,42 +1136,60 @@ impl OpenCADStudio {
|
||||
Task::none()
|
||||
}
|
||||
|
||||
pub(super) fn on_color_window_pick(&mut self, color: codec::types::Color) -> Task<Message> {
|
||||
pub(super) fn on_color_window_pick(
|
||||
&mut self,
|
||||
color: codec::types::Color,
|
||||
name: Option<String>,
|
||||
) -> Task<Message> {
|
||||
if let Some(crate::app::ColorPickTarget::Interface(target)) = self
|
||||
.color_picker
|
||||
.as_ref()
|
||||
.map(|picker| picker.target.clone())
|
||||
{
|
||||
self.color_picker = None;
|
||||
let Some((r, g, b)) = crate::ui::color_select::math::color_rgb(color) else {
|
||||
return Task::none();
|
||||
};
|
||||
// Hand the result to the same handler the typed hex field uses, so
|
||||
// the picker and the field cannot drift apart on validation or
|
||||
// persistence.
|
||||
let hex = crate::app::config::rgb_to_hex([r, g, b]);
|
||||
use crate::app::UiColor;
|
||||
return Task::done(match target {
|
||||
UiColor::ModelBackground => Message::ModelSpaceBgChanged(hex),
|
||||
UiColor::PaperBackground => Message::PaperSpaceBgChanged(hex),
|
||||
UiColor::DeskBackground => Message::DeskSpaceBgChanged(hex),
|
||||
UiColor::Theme(index) => Message::OptionsThemeColorChanged(index, hex),
|
||||
UiColor::Crosshair => Message::CrosshairColorChanged(hex),
|
||||
UiColor::SnapMarker => Message::SnapMarkerColorChanged(hex),
|
||||
UiColor::CommandText => Message::CommandTextColorChanged(hex),
|
||||
});
|
||||
}
|
||||
if matches!(
|
||||
self.color_pick_target.as_ref().map(|(target, _)| target),
|
||||
self.color_picker.as_ref().map(|picker| &picker.target),
|
||||
Some(crate::app::ColorPickTarget::PlotStyle)
|
||||
) {
|
||||
self.color_pick_target = None;
|
||||
self.color_picker = None;
|
||||
|
||||
let rgb = match color {
|
||||
codec::types::Color::Rgb { r, g, b } => Some((r, g, b)),
|
||||
codec::types::Color::Index(index) => codec::types::aci_table::aci_to_rgb(index),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some((r, g, b)) = rgb {
|
||||
self.ps_color_buf = format!("#{r:02X}{g:02X}{b:02X}");
|
||||
if let Some((r, g, b)) = crate::ui::color_select::math::color_rgb(color) {
|
||||
self.ps_color_buf = crate::ui::color_select::math::hex_string(r, g, b);
|
||||
}
|
||||
|
||||
return self.on_plot_style_panel_apply();
|
||||
}
|
||||
let s = crate::ui::color_select::color_to_aci_string(color);
|
||||
let edit = match self.color_pick_target.take().map(|(target, _)| target) {
|
||||
let edit = match self.color_picker.take().map(|picker| picker.target) {
|
||||
Some(crate::app::ColorPickTarget::Gradient(index)) => {
|
||||
Some(Message::GraphicAttributes(GraphicAttributesMsg::Gradient(
|
||||
crate::ui::window::gradient_editor::GradientMsg::Color(index, color),
|
||||
)))
|
||||
}
|
||||
Some(crate::app::ColorPickTarget::ViewBackground(slot)) => {
|
||||
let rgb = match color {
|
||||
codec::types::Color::Rgb { r, g, b } => Some([r, g, b]),
|
||||
codec::types::Color::Index(index) => {
|
||||
codec::types::aci_table::aci_to_rgb(index).map(|(r, g, b)| [r, g, b])
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
rgb.map(|rgb| {
|
||||
Message::PdfDialog(crate::ui::window::pdf_dialogs::PdfDialogMsg::BgColor(slot, rgb))
|
||||
crate::ui::color_select::math::color_rgb(color).map(|(r, g, b)| {
|
||||
Message::PdfDialog(crate::ui::window::pdf_dialogs::PdfDialogMsg::BgColor(
|
||||
slot,
|
||||
[r, g, b],
|
||||
))
|
||||
})
|
||||
}
|
||||
Some(crate::app::ColorPickTarget::GraphicAttributesLine) => Some(
|
||||
@@ -1189,7 +1207,9 @@ impl OpenCADStudio {
|
||||
field: f,
|
||||
value: s,
|
||||
}),
|
||||
Some(crate::app::ColorPickTarget::Properties) => Some(Message::PropColorChanged(color)),
|
||||
Some(crate::app::ColorPickTarget::Properties) => {
|
||||
return self.set_property_color(color, name);
|
||||
}
|
||||
Some(crate::app::ColorPickTarget::PropertiesBg) => {
|
||||
Some(Message::PropBgColorChanged(color))
|
||||
}
|
||||
@@ -1197,13 +1217,17 @@ impl OpenCADStudio {
|
||||
Some(Message::PropColorFieldChanged { field, color })
|
||||
}
|
||||
Some(crate::app::ColorPickTarget::MText) => Some(Message::MTextColorChanged(color)),
|
||||
Some(crate::app::ColorPickTarget::Ribbon) => Some(Message::RibbonColorChanged(color)),
|
||||
Some(crate::app::ColorPickTarget::Layer(name)) => {
|
||||
Some(crate::app::ColorPickTarget::Ribbon) => {
|
||||
let task = self.update(Message::RibbonColorChanged(color));
|
||||
self.ribbon.active_color_book = name.map(|name| (color, name));
|
||||
return task;
|
||||
}
|
||||
Some(crate::app::ColorPickTarget::Layer(layer)) => {
|
||||
let i = self.active_tab;
|
||||
match self.layer_panel_index(i, &name) {
|
||||
match self.layer_panel_index(i, &layer) {
|
||||
Some(idx) => {
|
||||
self.tabs[i].layers.selected = Some(idx);
|
||||
Some(Message::LayerColorSet(color))
|
||||
return self.set_layer_color(color, name.as_deref());
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
@@ -1211,7 +1235,10 @@ impl OpenCADStudio {
|
||||
Some(crate::app::ColorPickTarget::LayerState(idx)) => {
|
||||
Some(Message::LayerStateEditorLayerColor(idx, color))
|
||||
}
|
||||
Some(crate::app::ColorPickTarget::PlotStyle) => None,
|
||||
// Handled before this match.
|
||||
Some(
|
||||
crate::app::ColorPickTarget::PlotStyle | crate::app::ColorPickTarget::Interface(_),
|
||||
) => None,
|
||||
None => None,
|
||||
};
|
||||
if let Some(m) = edit {
|
||||
|
||||
@@ -1144,7 +1144,7 @@ impl OpenCADStudio {
|
||||
p: Point,
|
||||
expected_viewport: Option<codec::Handle>,
|
||||
) -> Task<Message> {
|
||||
if self.color_pick_target.is_some() {
|
||||
if self.color_picker.is_some() {
|
||||
return Task::none();
|
||||
}
|
||||
|
||||
@@ -1232,7 +1232,7 @@ impl OpenCADStudio {
|
||||
// leaks through the stack to the pane mouse_area beneath and
|
||||
// would track the crosshair over the dropdown's empty areas.
|
||||
// Drop the move here instead. (#227)
|
||||
if self.ribbon.open_dropdown.is_some() || self.color_pick_target.is_some() {
|
||||
if self.ribbon.open_dropdown.is_some() || self.color_picker.is_some() {
|
||||
return Task::none();
|
||||
}
|
||||
let i = self.active_tab;
|
||||
|
||||
Reference in new issue
Block a user