Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

objdiff-gui: Implement keyboard shortcuts #139

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3e42533
Fix missing dependency feature for objdiff-gui
LagoLunatic Nov 28, 2024
06c4d6e
Update .gitignore
LagoLunatic Nov 28, 2024
e448630
Add enter and back hotkeys
LagoLunatic Nov 28, 2024
76f1952
Add scroll hotkeys
LagoLunatic Nov 28, 2024
7d67700
Add hotkeys to select the next symbol above/below the current one in …
LagoLunatic Nov 28, 2024
5bffaa8
Do not clear highlighted symbol when backing out of diff view
LagoLunatic Nov 28, 2024
dfa145e
Do not clear highlighted symbol when hovering mouse over an unpaired …
LagoLunatic Nov 28, 2024
5af40e0
Auto-scroll the keyboard-selected symbols into view if offscreen
LagoLunatic Nov 28, 2024
5de087c
Fix some hotkeys stealing input from focused widgets
LagoLunatic Nov 28, 2024
0143046
Add Ctrl+F/S shortcuts for focusing the object and symbol filter text…
LagoLunatic Nov 28, 2024
4616058
Add space as alternative to enter hotkey
LagoLunatic Nov 28, 2024
98e971d
Add hotkeys to change target and base functions
LagoLunatic Nov 28, 2024
f2b410f
Split function diff view: Enable PageUp/PageDown/Home/End for scrolling
LagoLunatic Nov 28, 2024
d5dcc4f
Add escape as an alternative to back hotkey
LagoLunatic Nov 28, 2024
99641d2
Fix auto-scrolling to highlighted symbol only working for the left side
LagoLunatic Nov 29, 2024
446dd68
Simplify clearing of the autoscroll flag, remove &mut State
LagoLunatic Nov 29, 2024
ef27237
Found a better place to clear the autoscroll flag
LagoLunatic Nov 29, 2024
01a8524
Merge branch 'main' into hotkeys
LagoLunatic Dec 2, 2024
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ android.keystore
*.frag
*.vert
*.metal
.vscode/launch.json
.vscode/
2 changes: 1 addition & 1 deletion objdiff-gui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ exec = "0.3"

# native:
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tracing-subscriber = "0.3"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

# web:
[target.'cfg(target_arch = "wasm32")'.dependencies]
Expand Down
108 changes: 108 additions & 0 deletions objdiff-gui/src/hotkeys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use egui::{
style::ScrollAnimation, vec2, Context, Key, KeyboardShortcut, Modifiers, PointerButton,
};

fn any_widget_focused(ctx: &Context) -> bool { ctx.memory(|mem| mem.focused().is_some()) }

pub fn enter_pressed(ctx: &Context) -> bool {
if any_widget_focused(ctx) {
return false;
}
ctx.input_mut(|i| {
i.key_pressed(Key::Enter)
|| i.key_pressed(Key::Space)
|| i.pointer.button_pressed(PointerButton::Extra2)
})
}

pub fn back_pressed(ctx: &Context) -> bool {
if any_widget_focused(ctx) {
return false;
}
ctx.input_mut(|i| {
i.key_pressed(Key::Backspace)
|| i.key_pressed(Key::Escape)
|| i.pointer.button_pressed(PointerButton::Extra1)
})
}

pub fn up_pressed(ctx: &Context) -> bool {
if any_widget_focused(ctx) {
return false;
}
ctx.input_mut(|i| i.key_pressed(Key::ArrowUp) || i.key_pressed(Key::W))
}

pub fn down_pressed(ctx: &Context) -> bool {
if any_widget_focused(ctx) {
return false;
}
ctx.input_mut(|i| i.key_pressed(Key::ArrowDown) || i.key_pressed(Key::S))
}

pub fn page_up_pressed(ctx: &Context) -> bool { ctx.input_mut(|i| i.key_pressed(Key::PageUp)) }

pub fn page_down_pressed(ctx: &Context) -> bool { ctx.input_mut(|i| i.key_pressed(Key::PageDown)) }

pub fn home_pressed(ctx: &Context) -> bool { ctx.input_mut(|i| i.key_pressed(Key::Home)) }

pub fn end_pressed(ctx: &Context) -> bool { ctx.input_mut(|i| i.key_pressed(Key::End)) }

pub fn check_scroll_hotkeys(ui: &mut egui::Ui, include_small_increments: bool) {
let ui_height = ui.available_rect_before_wrap().height();
if up_pressed(ui.ctx()) && include_small_increments {
ui.scroll_with_delta_animation(vec2(0.0, ui_height / 10.0), ScrollAnimation::none());
} else if down_pressed(ui.ctx()) && include_small_increments {
ui.scroll_with_delta_animation(vec2(0.0, -ui_height / 10.0), ScrollAnimation::none());
} else if page_up_pressed(ui.ctx()) {
ui.scroll_with_delta_animation(vec2(0.0, ui_height), ScrollAnimation::none());
} else if page_down_pressed(ui.ctx()) {
ui.scroll_with_delta_animation(vec2(0.0, -ui_height), ScrollAnimation::none());
} else if home_pressed(ui.ctx()) {
ui.scroll_with_delta_animation(vec2(0.0, f32::INFINITY), ScrollAnimation::none());
} else if end_pressed(ui.ctx()) {
ui.scroll_with_delta_animation(vec2(0.0, -f32::INFINITY), ScrollAnimation::none());
}
}

pub fn consume_up_key(ctx: &Context) -> bool {
if any_widget_focused(ctx) {
return false;
}
ctx.input_mut(|i| {
i.consume_key(Modifiers::NONE, Key::ArrowUp) || i.consume_key(Modifiers::NONE, Key::W)
})
}

pub fn consume_down_key(ctx: &Context) -> bool {
if any_widget_focused(ctx) {
return false;
}
ctx.input_mut(|i| {
i.consume_key(Modifiers::NONE, Key::ArrowDown) || i.consume_key(Modifiers::NONE, Key::S)
})
}

const OBJECT_FILTER_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::F);

pub fn consume_object_filter_shortcut(ctx: &Context) -> bool {
ctx.input_mut(|i| i.consume_shortcut(&OBJECT_FILTER_SHORTCUT))
}

const SYMBOL_FILTER_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::S);

pub fn consume_symbol_filter_shortcut(ctx: &Context) -> bool {
ctx.input_mut(|i| i.consume_shortcut(&SYMBOL_FILTER_SHORTCUT))
}

const CHANGE_TARGET_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::T);

pub fn consume_change_target_shortcut(ctx: &Context) -> bool {
ctx.input_mut(|i| i.consume_shortcut(&CHANGE_TARGET_SHORTCUT))
}

const CHANGE_BASE_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::B);

pub fn consume_change_base_shortcut(ctx: &Context) -> bool {
ctx.input_mut(|i| i.consume_shortcut(&CHANGE_BASE_SHORTCUT))
}
1 change: 1 addition & 0 deletions objdiff-gui/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod app;
mod app_config;
mod config;
mod fonts;
mod hotkeys;
mod jobs;
mod update;
mod views;
Expand Down
7 changes: 6 additions & 1 deletion objdiff-gui/src/views/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use strum::{EnumMessage, VariantArray};
use crate::{
app::{AppConfig, AppState, AppStateRef, ObjectConfig},
config::ProjectObjectNode,
hotkeys,
jobs::{
check_update::{start_check_update, CheckUpdateResult},
update::start_update,
Expand Down Expand Up @@ -254,7 +255,11 @@ pub fn config_ui(
}
} else {
let had_search = !config_state.object_search.is_empty();
egui::TextEdit::singleline(&mut config_state.object_search).hint_text("Filter").ui(ui);
let response =
egui::TextEdit::singleline(&mut config_state.object_search).hint_text("Filter").ui(ui);
if hotkeys::consume_object_filter_shortcut(ui.ctx()) {
response.request_focus();
}

let mut root_open = None;
let mut node_open = NodeOpen::Default;
Expand Down
17 changes: 11 additions & 6 deletions objdiff-gui/src/views/data_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ use objdiff_core::{
};
use time::format_description;

use crate::views::{
appearance::Appearance,
column_layout::{render_header, render_table},
symbol_diff::{DiffViewAction, DiffViewNavigation, DiffViewState},
write_text,
use crate::{
hotkeys,
views::{
appearance::Appearance,
column_layout::{render_header, render_table},
symbol_diff::{DiffViewAction, DiffViewNavigation, DiffViewState},
write_text,
},
};

const BYTES_PER_ROW: usize = 16;
Expand Down Expand Up @@ -176,6 +179,8 @@ fn data_table_ui(
let left_diffs = left_section.map(|(_, section)| split_diffs(&section.data_diff));
let right_diffs = right_section.map(|(_, section)| split_diffs(&section.data_diff));

hotkeys::check_scroll_hotkeys(ui, true);

render_table(ui, available_width, 2, config.code_font.size, total_rows, |row, column| {
let i = row.index();
let address = i * BYTES_PER_ROW;
Expand Down Expand Up @@ -224,7 +229,7 @@ pub fn data_diff_ui(
render_header(ui, available_width, 2, |ui, column| {
if column == 0 {
// Left column
if ui.button("⏴ Back").clicked() {
if ui.button("⏴ Back").clicked() || hotkeys::back_pressed(ui.ctx()) {
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::symbol_diff()));
}

Expand Down
21 changes: 13 additions & 8 deletions objdiff-gui/src/views/extab_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ use objdiff_core::{
};
use time::format_description;

use crate::views::{
appearance::Appearance,
column_layout::{render_header, render_strips},
function_diff::FunctionDiffContext,
symbol_diff::{
match_color_for_symbol, DiffViewAction, DiffViewNavigation, DiffViewState, SymbolRefByName,
View,
use crate::{
hotkeys,
views::{
appearance::Appearance,
column_layout::{render_header, render_strips},
function_diff::FunctionDiffContext,
symbol_diff::{
match_color_for_symbol, DiffViewAction, DiffViewNavigation, DiffViewState,
SymbolRefByName, View,
},
},
};

Expand Down Expand Up @@ -136,7 +139,7 @@ pub fn extab_diff_ui(
if column == 0 {
// Left column
ui.horizontal(|ui| {
if ui.button("⏴ Back").clicked() {
if ui.button("⏴ Back").clicked() || hotkeys::back_pressed(ui.ctx()) {
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::symbol_diff()));
}
ui.separator();
Expand Down Expand Up @@ -232,6 +235,8 @@ pub fn extab_diff_ui(
}
});

hotkeys::check_scroll_hotkeys(ui, true);

// Table
render_strips(ui, available_width, 2, |ui, column| {
if column == 0 {
Expand Down
30 changes: 16 additions & 14 deletions objdiff-gui/src/views/function_diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ use objdiff_core::{
};
use time::format_description;

use crate::views::{
appearance::Appearance,
column_layout::{render_header, render_strips, render_table},
symbol_diff::{
match_color_for_symbol, symbol_list_ui, DiffViewAction, DiffViewNavigation, DiffViewState,
SymbolDiffContext, SymbolFilter, SymbolRefByName, SymbolViewState, View,
use crate::{
hotkeys,
views::{
appearance::Appearance,
column_layout::{render_header, render_strips, render_table},
symbol_diff::{
match_color_for_symbol, symbol_list_ui, DiffViewAction, DiffViewNavigation,
DiffViewState, SymbolDiffContext, SymbolFilter, SymbolRefByName, SymbolViewState, View,
},
},
};

Expand Down Expand Up @@ -432,6 +435,7 @@ fn asm_table_ui(
};
if left_len.is_some() && right_len.is_some() {
// Joint view
hotkeys::check_scroll_hotkeys(ui, true);
render_table(
ui,
available_width,
Expand Down Expand Up @@ -467,6 +471,7 @@ fn asm_table_ui(
if column == 0 {
if let Some(ctx) = left_ctx {
if ctx.has_symbol() {
hotkeys::check_scroll_hotkeys(ui, false);
render_table(
ui,
available_width / 2.0,
Expand Down Expand Up @@ -512,9 +517,6 @@ fn asm_table_ui(
SymbolRefByName::new(right_symbol, right_section),
));
}
DiffViewAction::SetSymbolHighlight(_, _) => {
// Ignore
}
_ => {
ret = Some(action);
}
Expand All @@ -527,6 +529,7 @@ fn asm_table_ui(
} else if column == 1 {
if let Some(ctx) = right_ctx {
if ctx.has_symbol() {
hotkeys::check_scroll_hotkeys(ui, false);
render_table(
ui,
available_width / 2.0,
Expand Down Expand Up @@ -572,9 +575,6 @@ fn asm_table_ui(
right_symbol_ref,
));
}
DiffViewAction::SetSymbolHighlight(_, _) => {
// Ignore
}
_ => {
ret = Some(action);
}
Expand Down Expand Up @@ -675,7 +675,7 @@ pub fn function_diff_ui(
if column == 0 {
// Left column
ui.horizontal(|ui| {
if ui.button("⏴ Back").clicked() {
if ui.button("⏴ Back").clicked() || hotkeys::back_pressed(ui.ctx()) {
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::symbol_diff()));
}
ui.separator();
Expand Down Expand Up @@ -708,10 +708,11 @@ pub fn function_diff_ui(
.color(appearance.highlight_color),
);
if right_ctx.is_some_and(|m| m.has_symbol())
&& ui
&& (ui
.button("Change target")
.on_hover_text_at_pointer("Choose a different symbol to use as the target")
.clicked()
|| hotkeys::consume_change_target_shortcut(ui.ctx()))
{
if let Some(symbol_ref) = state.symbol_state.right_symbol.as_ref() {
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
Expand Down Expand Up @@ -785,6 +786,7 @@ pub fn function_diff_ui(
"Choose a different symbol to use as the base",
)
.clicked()
|| hotkeys::consume_change_base_shortcut(ui.ctx())
{
if let Some(symbol_ref) = state.symbol_state.left_symbol.as_ref() {
ret = Some(DiffViewAction::SelectingRight(symbol_ref.clone()));
Expand Down
Loading