diff --git a/crates/ui-egui/src/chrome/control_bar.rs b/crates/ui-egui/src/chrome/control_bar.rs index 88cc6dde0..9afbe838e 100644 --- a/crates/ui-egui/src/chrome/control_bar.rs +++ b/crates/ui-egui/src/chrome/control_bar.rs @@ -338,7 +338,8 @@ pub fn control_bar(app: &mut VectorcraftApp, ui: &mut Ui) { ui.add_space(4.0); ui.separator(); } - if ui.link(egui::RichText::new(tl!("Opacity:")).size(12.0).color(t.text).underline()).clicked() { + // A click opens the Transparency panel; a drag scrubs the field (#4088). + if crate::scrub::link_label(ui, egui::RichText::new(tl!("Opacity:")).size(12.0).color(t.text).underline()).clicked() { app.ui.open_panel = Some("transparency".into()); } if let Some(o) = widgets::plain_field(ui, "cb-opacity", opacity as f64 * 100.0, "%", 0, 56.0) diff --git a/crates/ui-egui/src/panels/stroke.rs b/crates/ui-egui/src/panels/stroke.rs index fb9269fcf..f6ece0ac5 100644 --- a/crates/ui-egui/src/panels/stroke.rs +++ b/crates/ui-egui/src/panels/stroke.rs @@ -137,10 +137,12 @@ pub(crate) fn weight_field(app: &mut VectorcraftApp, ui: &mut Ui, id: &str, weig } /// The underlined Stroke link (`label`: the Control bar's "Stroke:", the Properties panel's -/// "Stroke"): a click toggles the Stroke panel in a popover under it. +/// "Stroke"): a click toggles the Stroke panel in a popover under it, and a drag scrubs the weight +/// field after it ([`crate::scrub`]). pub(crate) fn link(app: &mut VectorcraftApp, ui: &mut Ui, label: &str) { let t = Tokens::get(ui.ctx()); - let resp = ui.link(egui::RichText::new(label).size(12.0).color(t.text).underline()).on_hover_text(tl!("Stroke options")); + // A drag on it scrubs the weight field after it (#4088). + let resp = crate::scrub::link_label(ui, egui::RichText::new(label).size(12.0).color(t.text).underline()).on_hover_text(tl!("Stroke options")); widgets::popover(&resp, resp.clicked(), |ui| { ui.set_width(260.0); show(app, ui); diff --git a/crates/ui-egui/src/scrub.rs b/crates/ui-egui/src/scrub.rs index 832b82870..70ceb5060 100644 --- a/crates/ui-egui/src/scrub.rs +++ b/crates/ui-egui/src/scrub.rs @@ -1,8 +1,10 @@ //! Scrubbing numeric fields (#400, beyond Illustrator; Photoshop's scrubby labels): a horizontal //! drag on a numeric field's label (`W:`, `Opacity:`, the Character panel's size icon) steps the //! field's value by one unit every [`PX_PER_STEP`] points, ten with Shift and a tenth with -//! Ctrl/Cmd, as the arrow keys step a focused field; a click on the label focuses the field. The -//! text box itself never scrubs, and a field without a label doesn't. +//! Ctrl/Cmd, as the arrow keys step a focused field; a click on the label focuses the field. A +//! label that is a link (the Control bar's `Stroke:` and `Opacity:`, which open their panels; +//! #4088) scrubs its field the same way, and a click on it still follows the link. The text box +//! itself never scrubs, and a field without a label doesn't. //! //! The panels apply each value the drag passes as they apply a typed one, so the art follows the //! drag live; the app holds an undo group open meanwhile ([`begin_frame`], [`end_frame`]), so the @@ -113,24 +115,44 @@ pub(crate) fn end_frame(app: &mut VectorcraftApp, ctx: &Context) { struct Label { rect: Rect, pass: u64, + /// The label is a link, this widget: a click follows it instead of focusing the field. + link: Option, } /// Note the label (text or icon) drawn at `rect`: a numeric field drawn right after it on the /// same line takes it as its label, which scrubs the field. pub(crate) fn note_label(ui: &Ui, rect: Rect) { + note(ui, rect, None); +} + +/// A link that labels the numeric field drawn after it (it opens a panel when clicked): a drag on +/// it scrubs the field, and a click stays the link's. Its text can't be selected, which a drag +/// across it would otherwise do. +pub(crate) fn link_label(ui: &mut Ui, text: egui::RichText) -> Response { + let link = ui + .scope(|ui| { + ui.style_mut().interaction.selectable_labels = false; + ui.link(text) + }) + .inner; + note(ui, link.rect, Some(link.id)); + link +} + +fn note(ui: &Ui, rect: Rect, link: Option) { let pass = ui.ctx().cumulative_pass_nr(); - ui.data_mut(|d| d.insert_temp(label_id(), Label { rect, pass })); + ui.data_mut(|d| d.insert_temp(label_id(), Label { rect, pass, link })); } /// The label noted just before the field at `field`, on its line. -fn take_label(ui: &Ui, field: Rect) -> Option { +fn take_label(ui: &Ui, field: Rect) -> Option