Skip to content

Commit e066013

Browse files
emilklucasmerlin
andauthored
Toggle view-states without holding down keys (#7)
The most important thing for me is to easily be able to toggle between old/new in a flip-book like fashion. Previously that required holding down a key, which was annoying. Now you can press 2, then 3, then back to 2, etc. Easy. Clean. I think also the new UI is more self-explanatory, using radio buttons instead of checkboxes. Let me know if I broke some existing workflow. --------- Co-authored-by: Lucas Meurer <[email protected]>
1 parent ee97bcc commit e066013

File tree

5 files changed

+92
-65
lines changed

5 files changed

+92
-65
lines changed

src/app.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use crate::config::Config;
21
use crate::diff_image_loader::DiffImageLoader;
32
use crate::settings::Settings;
43
use crate::state::{AppState, AppStateRef, PageRef, SystemCommand, ViewerSystemCommand};
54
use crate::{DiffSource, bar, home, viewer};
6-
use eframe::egui::{Context, Key, Modifiers};
5+
use crate::{config::Config, state::View};
6+
use eframe::egui::{Context, Modifiers};
77
use eframe::{Frame, Storage, egui};
88
use egui_extras::install_image_loaders;
99
use egui_inbox::UiInbox;
@@ -172,21 +172,15 @@ impl App {
172172
state.send(ViewerSystemCommand::SelectSnapshot(new_index));
173173
}
174174

175-
let handle_key = |key: Key, toggle: &mut bool| {
176-
if ctx.input_mut(|i| i.key_pressed(key)) {
177-
*toggle = true;
175+
let mut new_view = vs.state.view;
176+
for view in View::ALL {
177+
if ctx.input_mut(|i| i.consume_key(Default::default(), view.key())) {
178+
new_view = view;
178179
}
179-
if ctx.input_mut(|i| i.key_released(key)) {
180-
*toggle = false;
181-
}
182-
};
183-
184-
let mut view_filter = vs.state.view_filter;
185-
handle_key(Key::Num1, &mut view_filter.show_old);
186-
handle_key(Key::Num2, &mut view_filter.show_new);
187-
handle_key(Key::Num3, &mut view_filter.show_diff);
188-
if view_filter != vs.state.view_filter {
189-
state.send(ViewerSystemCommand::SetViewFilter(view_filter));
180+
}
181+
182+
if new_view != vs.state.view {
183+
state.send(ViewerSystemCommand::SetView(new_view));
190184
}
191185
}
192186
}

src/cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub enum Commands {
1818
Files { directory: Option<String> },
1919
/// Compare images between current branch and default branch
2020
Git { repo_path: Option<String> },
21-
/// Compare images between PR branches from GitHub PR URL (needs to be run from within the repo)
21+
/// Compare images between PR branches from GitHub PR URL
2222
Pr { url: String },
2323
/// Load and compare snapshot files from a zip archive (URL or local file)
2424
Archive { source: String },

src/snapshot.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::diff_image_loader;
21
use crate::diff_image_loader::DiffOptions;
32
use crate::state::{AppStateRef, PageRef};
3+
use crate::{diff_image_loader, state::View};
44
use eframe::egui;
55
use eframe::egui::{Color32, ImageSource};
66
use std::path::PathBuf;
@@ -88,14 +88,14 @@ impl Snapshot {
8888
state: &AppStateRef<'a>,
8989
uri: String,
9090
opacity: f32,
91-
show_all: bool,
91+
blend_all: bool,
9292
) -> eframe::egui::Image<'a> {
9393
let mut image = eframe::egui::Image::new(uri)
9494
.texture_options(eframe::egui::TextureOptions {
9595
magnification: state.settings.texture_magnification,
9696
..eframe::egui::TextureOptions::default()
9797
})
98-
.tint(Color32::from_white_alpha(if show_all {
98+
.tint(Color32::from_white_alpha(if blend_all {
9999
(255.0 * opacity) as u8
100100
} else {
101101
u8::MAX
@@ -114,37 +114,37 @@ impl Snapshot {
114114
let PageRef::DiffViewer(vs) = &state.page else {
115115
return None;
116116
};
117-
let show_all = vs.view_filter.all();
118-
let show_old = vs.view_filter.show_old;
119-
(show_all || show_old)
117+
let blend_all = vs.view == View::BlendAll;
118+
let show_old = vs.view == View::Old;
119+
(blend_all || show_old)
120120
.then(|| self.old_uri())
121121
.flatten()
122-
.map(|uri| Self::make_image(state, uri, 1.0, show_all))
122+
.map(|uri| Self::make_image(state, uri, 1.0, blend_all))
123123
}
124124

125125
pub fn new_image<'a>(&self, state: &AppStateRef<'a>) -> Option<eframe::egui::Image<'a>> {
126126
let PageRef::DiffViewer(vs) = &state.page else {
127127
return None;
128128
};
129-
let show_all = vs.view_filter.all();
130-
let show_new = vs.view_filter.show_new;
131-
(show_all || show_new)
129+
let blend_all = vs.view == View::BlendAll;
130+
let show_new = vs.view == View::New;
131+
(blend_all || show_new)
132132
.then(|| self.new_uri())
133133
.flatten()
134-
.map(|new_uri| Self::make_image(state, new_uri, state.settings.new_opacity, show_all))
134+
.map(|new_uri| Self::make_image(state, new_uri, state.settings.new_opacity, blend_all))
135135
}
136136

137137
pub fn diff_image<'a>(&self, state: &AppStateRef<'a>) -> Option<eframe::egui::Image<'a>> {
138138
let PageRef::DiffViewer(vs) = &state.page else {
139139
return None;
140140
};
141-
let show_all = vs.view_filter.all();
142-
let show_diff = vs.view_filter.show_diff;
143-
(show_all || show_diff)
141+
let blend_all = vs.view == View::BlendAll;
142+
let show_diff = vs.view == View::Diff;
143+
(blend_all || show_diff)
144144
.then(|| self.diff_uri(state.settings.use_original_diff, state.settings.options))
145145
.flatten()
146146
.map(|diff_uri| {
147-
Self::make_image(state, diff_uri, state.settings.diff_opacity, show_all)
147+
Self::make_image(state, diff_uri, state.settings.diff_opacity, blend_all)
148148
})
149149
}
150150
}

src/state.rs

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::github::pr::GithubPr;
66
use crate::loaders::SnapshotLoader;
77
use crate::settings::Settings;
88
use crate::snapshot::Snapshot;
9-
use eframe::egui::Context;
9+
use eframe::egui::{self, Context};
1010
use egui_inbox::UiInboxSender;
1111
use octocrab::Octocrab;
1212
use std::ops::Deref;
@@ -31,7 +31,7 @@ pub struct ViewerState {
3131
/// If true, this item will scroll into view.
3232
pub index_just_selected: bool,
3333
pub filter: String,
34-
pub view_filter: ViewFilter,
34+
pub view: View,
3535
}
3636

3737
impl ViewerState {
@@ -52,19 +52,43 @@ impl ViewerState {
5252
}
5353
}
5454

55-
/// If any is true, only show those, but at full opacity
56-
///
57-
/// If all are false, show all at their set opacities
58-
#[derive(Default, Copy, Clone, PartialEq, Eq)]
59-
pub struct ViewFilter {
60-
pub show_old: bool,
61-
pub show_new: bool,
62-
pub show_diff: bool,
55+
#[derive(Copy, Clone, Default, PartialEq, Eq)]
56+
pub enum View {
57+
/// View all stacked on each other, with opacity settings.
58+
#[default]
59+
BlendAll,
60+
61+
/// View old image
62+
Old,
63+
64+
/// View new image
65+
New,
66+
67+
/// View diff
68+
Diff,
6369
}
6470

65-
impl ViewFilter {
66-
pub fn all(&self) -> bool {
67-
!self.show_old && !self.show_new && !self.show_diff
71+
impl std::fmt::Display for View {
72+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73+
match self {
74+
Self::BlendAll => write!(f, "Blend all"),
75+
Self::Old => write!(f, "Old"),
76+
Self::New => write!(f, "New"),
77+
Self::Diff => write!(f, "Diff"),
78+
}
79+
}
80+
}
81+
82+
impl View {
83+
pub const ALL: [Self; 4] = [Self::BlendAll, Self::Old, Self::New, Self::Diff];
84+
85+
pub fn key(self) -> egui::Key {
86+
match self {
87+
Self::BlendAll => egui::Key::Num1,
88+
Self::Old => egui::Key::Num2,
89+
Self::New => egui::Key::Num3,
90+
Self::Diff => egui::Key::Num4,
91+
}
6892
}
6993
}
7094

@@ -198,7 +222,7 @@ pub enum SystemCommand {
198222
pub enum ViewerSystemCommand {
199223
SetFilter(String),
200224
SelectSnapshot(usize),
201-
SetViewFilter(ViewFilter),
225+
SetView(View),
202226
}
203227

204228
impl From<ViewerSystemCommand> for SystemCommand {
@@ -217,7 +241,7 @@ impl AppState {
217241
index: 0,
218242
index_just_selected: true,
219243
loader,
220-
view_filter: ViewFilter::default(),
244+
view: View::default(),
221245
});
222246
}
223247
SystemCommand::GithubAuth(auth) => {
@@ -270,8 +294,8 @@ impl ViewerState {
270294
self.index_just_selected = true;
271295
}
272296
}
273-
ViewerSystemCommand::SetViewFilter(view_filter) => {
274-
self.view_filter = view_filter;
297+
ViewerSystemCommand::SetView(view_filter) => {
298+
self.view = view_filter;
275299
}
276300
}
277301
}

src/viewer/viewer_options.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,37 @@
1-
use crate::settings::ImageMode;
21
use crate::state::{SystemCommand, ViewerAppStateRef, ViewerSystemCommand};
3-
use eframe::egui::{Checkbox, Slider, TextureFilter, Ui};
2+
use crate::{settings::ImageMode, state::View};
3+
use eframe::egui::{self, Slider, TextureFilter, Ui};
44

55
pub fn viewer_options(ui: &mut Ui, state: &ViewerAppStateRef<'_>) {
66
let mut settings = state.app.settings.clone();
77

88
ui.group(|ui| {
9-
ui.strong("View only");
10-
let mut view_filter = state.view_filter;
11-
ui.add_enabled(
12-
false,
13-
Checkbox::new(&mut state.view_filter.all(), "All with opacity"),
14-
);
15-
ui.checkbox(&mut view_filter.show_old, "Old (1)");
16-
ui.checkbox(&mut view_filter.show_new, "New (2)");
17-
ui.checkbox(&mut view_filter.show_diff, "Diff (3)");
18-
if view_filter != state.view_filter {
19-
state
20-
.app
21-
.send(ViewerSystemCommand::SetViewFilter(view_filter));
9+
ui.strong("View");
10+
let mut new_view = state.view;
11+
12+
for view in View::ALL {
13+
ui.radio_value(
14+
&mut new_view,
15+
view,
16+
format!("{view} ({})", view.key().name()),
17+
);
18+
}
19+
20+
ui.label("Toggle old/new with SPACE");
21+
ui.input(|i| {
22+
if i.key_pressed(egui::Key::Space) {
23+
new_view = View::New;
24+
} else if i.key_released(egui::Key::Space) {
25+
new_view = View::Old;
26+
}
27+
});
28+
29+
if new_view != state.view {
30+
state.app.send(ViewerSystemCommand::SetView(new_view));
2231
}
2332
});
2433

25-
ui.add_enabled_ui(state.view_filter.all(), |ui| {
34+
ui.add_enabled_ui(state.view == View::BlendAll, |ui| {
2635
ui.add(Slider::new(&mut settings.new_opacity, 0.0..=1.0).text("New Opacity"));
2736
ui.add(Slider::new(&mut settings.diff_opacity, 0.0..=1.0).text("Diff Opacity"));
2837
});

0 commit comments

Comments
 (0)