Skip to content

Commit

Permalink
Provide an option to pan to item when clicking on an ItemLink.
Browse files Browse the repository at this point in the history
  • Loading branch information
elliottslaughter committed Feb 6, 2024
1 parent 90f9660 commit 283585d
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 11 deletions.
67 changes: 56 additions & 11 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,27 @@ struct IntervalSelectState {
stop_error: Option<IntervalSelectError>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
enum ItemLinkNavigationMode {
Zoom,
Pan,
}

impl Default for ItemLinkNavigationMode {
fn default() -> Self {
ItemLinkNavigationMode::Zoom
}
}

impl ItemLinkNavigationMode {
fn label_text(&self) -> &'static str {
match *self {
ItemLinkNavigationMode::Zoom => "Zoom to Item",
ItemLinkNavigationMode::Pan => "Pan to Item",
}
}
}

#[derive(Debug, Clone, Default, Deserialize, Serialize)]
struct Context {
#[serde(skip)]
Expand Down Expand Up @@ -252,6 +273,8 @@ struct Context {
#[serde(skip)]
slot_rect: Option<Rect>,

item_link_mode: ItemLinkNavigationMode,

toggle_dark_mode: bool,

debug: bool,
Expand Down Expand Up @@ -2109,22 +2132,33 @@ impl ProfApp {
layout.size().y + style.spacing.item_spacing.y * 2.0
}

fn render_field_as_text(field: &Field) -> Vec<(String, Option<&'static str>)> {
fn render_field_as_text(
field: &Field,
mode: ItemLinkNavigationMode,
) -> Vec<(String, Option<&'static str>)> {
match field {
Field::I64(value) => vec![(format!("{value}"), None)],
Field::U64(value) => vec![(format!("{value}"), None)],
Field::String(value) => vec![(value.to_string(), None)],
Field::Interval(value) => vec![(format!("{value}"), None)],
Field::ItemLink(ItemLink { title, .. }) => {
vec![(title.to_string(), Some("Zoom to Item"))]
vec![(title.to_string(), Some(mode.label_text()))]
}
Field::Vec(fields) => fields.iter().flat_map(Self::render_field_as_text).collect(),
Field::Vec(fields) => fields
.iter()
.flat_map(|f| Self::render_field_as_text(f, mode))
.collect(),
Field::Empty => vec![("".to_string(), None)],
}
}

fn compute_field_height(field: &Field, width: f32, ui: &mut egui::Ui) -> f32 {
let text = Self::render_field_as_text(field);
fn compute_field_height(
field: &Field,
width: f32,
mode: ItemLinkNavigationMode,
ui: &mut egui::Ui,
) -> f32 {
let text = Self::render_field_as_text(field, mode);
text.into_iter()
.map(|(mut v, b)| {
// Hack: if we have button text, guess how much space it will need
Expand All @@ -2140,6 +2174,7 @@ impl ProfApp {

fn render_field_as_ui(
field: &Field,
mode: ItemLinkNavigationMode,
ui: &mut egui::Ui,
) -> Option<(ItemUID, ItemLocator, Interval)> {
let mut result = None;
Expand All @@ -2161,7 +2196,7 @@ impl ProfApp {
interval,
entry_id,
}) => {
if label_button(ui, title, "Zoom to Item") {
if label_button(ui, title, mode.label_text()) {
result = Some((
*item_uid,
ItemLocator {
Expand All @@ -2176,7 +2211,7 @@ impl ProfApp {
ui.vertical(|ui| {
for f in fields {
ui.horizontal(|ui| {
if let Some(x) = Self::render_field_as_ui(f, ui) {
if let Some(x) = Self::render_field_as_ui(f, mode, ui) {
result = Some(x);
}
});
Expand Down Expand Up @@ -2208,14 +2243,15 @@ impl ProfApp {
let width = body.widths()[1];

let ui = body.ui_mut();
let height = Self::compute_field_height(field, width, ui);
let height = Self::compute_field_height(field, width, cx.item_link_mode, ui);

body.row(height, |mut row| {
row.col(|ui| {
ui.strong(k);
});
row.col(|ui| {
if let Some(x) = Self::render_field_as_ui(field, ui) {
if let Some(x) = Self::render_field_as_ui(field, cx.item_link_mode, ui)
{
result = Some(x);
}
});
Expand All @@ -2232,7 +2268,7 @@ impl ProfApp {
}
});
ui.with_layout(egui::Layout::top_down(egui::Align::Center), |ui| {
if ui.button("Zoom to Item").clicked() {
if ui.button(cx.item_link_mode.label_text()).clicked() {
result = Some((
item_meta.item_uid,
item_loc.clone(),
Expand Down Expand Up @@ -2467,7 +2503,16 @@ impl eframe::App for ProfApp {
enabled
});
if let Some((item_uid, item_loc, interval)) = zoom_target {
let interval = interval.grow(interval.duration_ns() / 20);
let interval = match cx.item_link_mode {
// In Zoom mode, put the item in the center of the view
// interval with a small amount of padding on either side.
ItemLinkNavigationMode::Zoom => interval.grow(interval.duration_ns() / 20),
// In Pan mode, maintain the current window size but shift
// the center to place the item in the middle of it.
ItemLinkNavigationMode::Pan => cx
.view_interval
.translate(cx.view_interval.center().0 - interval.center().0),
};
ProfApp::zoom(cx, interval);
window.expand_slot(&item_loc.entry_id);
window.config.scroll_to_item = Some(item_loc);
Expand Down
3 changes: 3 additions & 0 deletions src/timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ impl Interval {
pub fn new(start: Timestamp, stop: Timestamp) -> Self {
Self { start, stop }
}
pub fn center(self) -> Timestamp {
Timestamp(self.start.0 + self.duration_ns() / 2)
}
pub fn duration_ns(self) -> i64 {
self.stop.0 - self.start.0
}
Expand Down

0 comments on commit 283585d

Please sign in to comment.