Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions crates/app/src/ui/affordance.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//! Shared visual language for click-to-enter surfaces.
//!
//! Ribbon buttons signal clickability by tinting their leading glyph with the
//! theme accent (`Visuals::hyperlink_color`, see `ribbon_button`). Task-card
//! rows that open an editor or reveal content on click reuse the same colour
//! through these helpers, so "this text is clickable" reads identically on
//! every surface instead of each card inventing its own (or, worse, plain
//! text that gives no signal until hovered).

use egui::{Color32, Response, TextFormat, TextStyle, Ui, Visuals, text::LayoutJob};

/// The accent that marks a clickable surface — the exact colour the Ribbon
/// paints its enabled, unchecked button glyphs with.
pub(crate) fn clickable_tint(visuals: &Visuals) -> Color32 {
visuals.hyperlink_color
}

/// A selectable row that reads as clickable while idle: the leading glyph
/// carries the clickable accent while the label keeps the theme text colour,
/// mirroring Ribbon buttons. A selected row falls back to the selection
/// styling wholesale so the accent never fights the checked state.
pub(crate) fn selectable_row(
ui: &mut Ui,
selected: bool,
glyph: &str,
label: impl Into<String>,
) -> Response {
let font_id = TextStyle::Body.resolve(ui.style());
let glyph_color = if selected {
Color32::PLACEHOLDER
} else {
clickable_tint(ui.visuals())
};
let mut job = LayoutJob::default();
job.append(
glyph,
0.0,
TextFormat {
font_id: font_id.clone(),
color: glyph_color,
..Default::default()
},
);
job.append(
&format!(" {}", label.into()),
0.0,
TextFormat {
font_id,
color: Color32::PLACEHOLDER,
..Default::default()
},
);
ui.selectable_label(selected, job)
}

#[cfg(test)]
mod tests {
use super::*;

/// The clickable accent must stay the colour Ribbon glyphs use, in both
/// themes, so every "this is clickable" mark reads as one language.
#[test]
fn clickable_tint_matches_the_ribbon_glyph_colour() {
for visuals in [Visuals::light(), Visuals::dark()] {
assert_eq!(clickable_tint(&visuals), visuals.hyperlink_color);
}
}
}
1 change: 1 addition & 0 deletions crates/app/src/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod affordance;
pub(crate) mod align;
pub(crate) mod arithmetic;
pub(crate) mod batch_workflow;
Expand Down
35 changes: 18 additions & 17 deletions crates/app/src/ui/tools/craft/results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,23 +234,24 @@ fn overview(
});
for (position, summary) in run.region_summaries.iter().enumerate() {
let selected = app.session.ui.craft_component_region == Some(summary.region);
if ui
.selectable_label(
selected,
format!(
"{} · {:.4}–{:.4} ppm · coherent amplitude {:.4} · {} component(s)",
if exploratory {
"Full bandwidth".into()
} else {
format!("Signal {}", position + 1)
},
summary.start_ppm,
summary.end_ppm,
summary.coherent_amplitude_t0,
summary.component_count,
),
)
.clicked()
if crate::ui::affordance::selectable_row(
ui,
selected,
egui_phosphor::regular::WAVEFORM,
format!(
"{} · {:.4}–{:.4} ppm · coherent amplitude {:.4} · {} component(s)",
if exploratory {
"Full bandwidth".into()
} else {
format!("Signal {}", position + 1)
},
summary.start_ppm,
summary.end_ppm,
summary.coherent_amplitude_t0,
summary.component_count,
),
)
.clicked()
{
app.session.ui.craft_component_region = Some(summary.region);
app.session.ui.craft_result_tab = CraftResultTab::Components;
Expand Down
17 changes: 7 additions & 10 deletions crates/app/src/ui/tools/processing/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,16 +482,13 @@ fn step_row(
egui::Frame::group(ui.style()).show(ui, |ui| {
ui.horizontal_wrapped(|ui| {
crate::ui::properties::panel::processing_step_section(app, &target, ui);
let response = ui
.selectable_label(
expanded,
format!(
"{} {}",
editors::kind_icon(&step.kind),
editors::kind_label(&step.kind)
),
)
.on_hover_text(editors::kind_summary(&step.kind));
let response = crate::ui::affordance::selectable_row(
ui,
expanded,
editors::kind_icon(&step.kind),
editors::kind_label(&step.kind),
)
.on_hover_text(editors::kind_summary(&step.kind));
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.menu_button(icon::DOTS_THREE, |ui| {
row_menu(
Expand Down
10 changes: 7 additions & 3 deletions crates/app/src/ui/tools/region_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,13 @@ fn region_task_body(app: &mut PlotxApp, di: usize, ui: &mut Ui) {
} else {
format!("{:.3}–{:.3} {axis_unit}", region.lo_min(), region.hi_max())
};
if ui
.add(Button::selectable(selected == Some(region.id), interval))
.clicked()
if crate::ui::affordance::selectable_row(
ui,
selected == Some(region.id),
icon::SELECTION,
interval,
)
.clicked()
{
select_id = Some(region.id);
}
Expand Down
Loading