forked from 1b-agent/opencadstudio-upstream
Add a colour wheel for the viewport backgrounds
The Display page could only take a typed #RRGGBB, which is precise but no way to choose a colour by eye. The swatches are now buttons that open a wheel. The wheel does not replace the hex field, it sits beside it: typing an exact value stays the quickest way to reproduce a known colour. On submit it hands a hex string to the existing ModelSpaceBgChanged and friends rather than writing the config itself, so the two routes cannot drift apart on validation, persistence, or the MatchTheme fallback an empty field triggers. Also stops the Browser shipping in the default dock layout. It was added to the right edge, which shifted the block palette to index 1 and broke four dock tests that encode the existing arrangement. Those tests were right and the change was wrong: the earlier commit claimed to leave the layout alone. BROWSER now docks the panel on first use, so nobody's edges rearrange on upgrade for a panel they never asked for.
This commit is contained in:
6 files changed
+106
-53
No files matched your search
@@ -673,9 +673,20 @@ impl OpenCADStudio {
|
||||
"BROWSER" => {
|
||||
self.show_browser ^= true;
|
||||
if self.show_browser {
|
||||
// Dock it on first use rather than shipping it in the
|
||||
// default layout: an existing user's edges should not
|
||||
// rearrange themselves on upgrade for a panel they have
|
||||
// not asked for.
|
||||
let id = crate::ui::dock::PanelId::Browser;
|
||||
if self.dock.location(id).is_none() {
|
||||
// dock() clamps an out-of-range index to the end of
|
||||
// the edge, so this appends below whatever is there.
|
||||
self.dock
|
||||
.dock(id, crate::app::config::DockSide::Right, usize::MAX);
|
||||
}
|
||||
// Open expanded so it is usable straight away; the pin
|
||||
// button still collapses it.
|
||||
self.dock_expanded = Some(crate::ui::dock::PanelId::Browser);
|
||||
self.dock_expanded = Some(id);
|
||||
self.command_line
|
||||
.push_output(crate::t!("Browser opened.").as_ref());
|
||||
} else {
|
||||
|
||||
@@ -736,6 +736,9 @@ pub(super) struct OpenCADStudio {
|
||||
/// Whether the Browser panel is shown. Off until BROWSER opens it, so
|
||||
/// the default layout is unchanged for existing users.
|
||||
pub(crate) show_browser: bool,
|
||||
/// Which viewport background the colour wheel is editing, or `None` when
|
||||
/// it is closed. One slot, because only one wheel can be open at a time.
|
||||
pub(crate) bg_picker: Option<BgTarget>,
|
||||
/// General edge-stack dock layout for the side panels.
|
||||
pub(crate) dock: crate::ui::dock::DockState,
|
||||
/// Which panel is currently floated at full height (hovered, or a pinned
|
||||
@@ -1444,6 +1447,14 @@ pub struct SaveOutcome {
|
||||
refreshed_preview: Option<Option<acadrust::Preview>>,
|
||||
result: Result<(), crate::io::SaveFailure>,
|
||||
}
|
||||
/// Which viewport background a colour-wheel session is editing.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BgTarget {
|
||||
Model,
|
||||
Paper,
|
||||
Desk,
|
||||
}
|
||||
|
||||
/// Active page in the shared CAD colour picker.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum ColorPickerTab {
|
||||
@@ -2129,6 +2140,12 @@ pub enum Message {
|
||||
ModelSpaceModeChanged(config::ModelSpaceMode),
|
||||
/// Change Model Space custom background color as hex or empty for default.
|
||||
ModelSpaceBgChanged(String),
|
||||
/// Open the colour wheel on one of the viewport backgrounds.
|
||||
BgPickerOpen(BgTarget),
|
||||
/// Dismiss the wheel, changing nothing.
|
||||
BgPickerCancel,
|
||||
/// Accept the wheel's colour for whichever background it was opened on.
|
||||
BgPickerSubmit(iced::Color),
|
||||
/// Change Paper Space custom sheet background color as hex or empty for default.
|
||||
PaperSpaceBgChanged(String),
|
||||
/// Change Paper Space desk surround background (#RRGGBB).
|
||||
@@ -3933,6 +3950,7 @@ impl OpenCADStudio {
|
||||
show_block_palette: false,
|
||||
show_external_references: false,
|
||||
show_browser: false,
|
||||
bg_picker: None,
|
||||
block_palette: Default::default(),
|
||||
xref_manager: Default::default(),
|
||||
dock: Default::default(),
|
||||
|
||||
@@ -7068,6 +7068,39 @@ 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() {
|
||||
|
||||
@@ -358,6 +358,7 @@ impl OpenCADStudio {
|
||||
&self.model_bg_input,
|
||||
&self.paper_bg_input,
|
||||
&self.desk_bg_input,
|
||||
self.bg_picker,
|
||||
flow,
|
||||
)
|
||||
},
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@ impl Default for DockState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
left: vec![PanelId::Properties],
|
||||
right: vec![PanelId::Browser, PanelId::BlockPalette],
|
||||
right: vec![PanelId::BlockPalette],
|
||||
panels: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
+41
-51
@@ -146,6 +146,43 @@ impl<T> fmt::Display for Labelled<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A background swatch that opens the colour wheel when clicked.
|
||||
///
|
||||
/// The wheel sits alongside the hex field rather than replacing it: typing
|
||||
/// `#1E1E1E` stays the fastest way to reproduce an exact colour, while the
|
||||
/// wheel is for choosing one by eye.
|
||||
fn bg_swatch_picker<'a>(
|
||||
target: crate::app::BgTarget,
|
||||
rgb: [u8; 3],
|
||||
open: Option<crate::app::BgTarget>,
|
||||
) -> Element<'a, Message> {
|
||||
let colour = iced::Color::from_rgb8(rgb[0], rgb[1], rgb[2]);
|
||||
let swatch = container(Space::new())
|
||||
.width(28)
|
||||
.height(22)
|
||||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(colour)),
|
||||
border: Border {
|
||||
color: theme.palette().background.strong.color,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
let underlay = button(swatch)
|
||||
.on_press(Message::BgPickerOpen(target))
|
||||
.padding(0)
|
||||
.style(button::text);
|
||||
iced_aw::ColorPicker::new(
|
||||
open == Some(target),
|
||||
colour,
|
||||
underlay,
|
||||
Message::BgPickerCancel,
|
||||
Message::BgPickerSubmit,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn view_window<'a>(
|
||||
default_save_format: &'a str,
|
||||
@@ -172,6 +209,7 @@ pub fn view_window<'a>(
|
||||
model_bg_input: &'a str,
|
||||
paper_bg_input: &'a str,
|
||||
desk_bg_input: &'a str,
|
||||
bg_picker: Option<crate::app::BgTarget>,
|
||||
sizing: crate::ui::modal::ModalSizing,
|
||||
) -> Element<'a, Message> {
|
||||
let selected_format = crate::io::SAVE_FORMAT_OPTIONS
|
||||
@@ -455,58 +493,10 @@ pub fn view_window<'a>(
|
||||
});
|
||||
|
||||
let model_bg_rgb = model_space.custom_bg.unwrap_or(crate::app::config::CLASSIC_CAD_DARK_BG);
|
||||
let model_bg_swatch = container(Space::new())
|
||||
.width(28)
|
||||
.height(22)
|
||||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(iced::Color::from_rgb8(
|
||||
model_bg_rgb[0],
|
||||
model_bg_rgb[1],
|
||||
model_bg_rgb[2],
|
||||
))),
|
||||
border: Border {
|
||||
color: theme.palette().background.strong.color,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let paper_bg_rgb = model_space.custom_paper_bg.unwrap_or(crate::app::config::DEFAULT_PAPER_BG);
|
||||
let paper_bg_swatch = container(Space::new())
|
||||
.width(28)
|
||||
.height(22)
|
||||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(iced::Color::from_rgb8(
|
||||
paper_bg_rgb[0],
|
||||
paper_bg_rgb[1],
|
||||
paper_bg_rgb[2],
|
||||
))),
|
||||
border: Border {
|
||||
color: theme.palette().background.strong.color,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let desk_bg_rgb = model_space.custom_desk_bg.unwrap_or(crate::app::config::DEFAULT_DESK_BG);
|
||||
let desk_bg_swatch = container(Space::new())
|
||||
.width(28)
|
||||
.height(22)
|
||||
.style(move |theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(iced::Color::from_rgb8(
|
||||
desk_bg_rgb[0],
|
||||
desk_bg_rgb[1],
|
||||
desk_bg_rgb[2],
|
||||
))),
|
||||
border: Border {
|
||||
color: theme.palette().background.strong.color,
|
||||
width: 1.0,
|
||||
radius: 3.0.into(),
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let mode_options = crate::app::config::ModelSpaceMode::ALL
|
||||
.into_iter()
|
||||
@@ -641,7 +631,7 @@ pub fn view_window<'a>(
|
||||
display = display.push(Space::new().height(10)).push(
|
||||
row![
|
||||
text(crate::t!("Model background")).size(12).width(140),
|
||||
model_bg_swatch,
|
||||
bg_swatch_picker(crate::app::BgTarget::Model, model_bg_rgb, bg_picker),
|
||||
text_input("#RRGGBB", model_bg_input)
|
||||
.on_input(Message::ModelSpaceBgChanged)
|
||||
.width(150),
|
||||
@@ -654,7 +644,7 @@ pub fn view_window<'a>(
|
||||
display = display.push(Space::new().height(10)).push(
|
||||
row![
|
||||
text(crate::t!("Paper background")).size(12).width(140),
|
||||
paper_bg_swatch,
|
||||
bg_swatch_picker(crate::app::BgTarget::Paper, paper_bg_rgb, bg_picker),
|
||||
text_input("#RRGGBB", paper_bg_input)
|
||||
.on_input(Message::PaperSpaceBgChanged)
|
||||
.width(150),
|
||||
@@ -666,7 +656,7 @@ pub fn view_window<'a>(
|
||||
display = display.push(Space::new().height(10)).push(
|
||||
row![
|
||||
text(crate::t!("Desk surround")).size(12).width(140),
|
||||
desk_bg_swatch,
|
||||
bg_swatch_picker(crate::app::BgTarget::Desk, desk_bg_rgb, bg_picker),
|
||||
text_input("#RRGGBB", desk_bg_input)
|
||||
.on_input(Message::DeskSpaceBgChanged)
|
||||
.width(150),
|
||||
|
||||
Reference in new issue
Block a user