mirror of https://codeberg.org/topola/topola.git
feat(topola-egui): Allow using Shift+{arrow keys} to scroll viewport using keyboard
Fixes #188.
This commit is contained in:
parent
7d59ffd5be
commit
b5b14e6329
|
|
@ -81,12 +81,16 @@ impl Trigger {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Switch {
|
impl Switch {
|
||||||
pub fn toggle_widget(&self, _ctx: &egui::Context, ui: &mut egui::Ui, selected: &mut bool) {
|
pub fn toggle_widget(&self, ui: &mut egui::Ui, selected: &mut bool) {
|
||||||
ui.toggle_value(selected, self.action.widget_text());
|
ui.toggle_value(selected, self.action.widget_text());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn checkbox(&self, ui: &mut egui::Ui, selected: &mut bool) {
|
||||||
|
ui.checkbox(selected, self.action.widget_text());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn consume_key_enabled(
|
pub fn consume_key_enabled(
|
||||||
&mut self,
|
&self,
|
||||||
ctx: &egui::Context,
|
ctx: &egui::Context,
|
||||||
_ui: &mut egui::Ui,
|
_ui: &mut egui::Ui,
|
||||||
selected: &mut bool,
|
selected: &mut bool,
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,7 @@ pub struct ViewActions {
|
||||||
pub zoom_to_fit: Switch,
|
pub zoom_to_fit: Switch,
|
||||||
pub show_ratsnest: Switch,
|
pub show_ratsnest: Switch,
|
||||||
pub show_navmesh: Switch,
|
pub show_navmesh: Switch,
|
||||||
|
pub show_topo_navmesh: Switch,
|
||||||
pub show_bboxes: Switch,
|
pub show_bboxes: Switch,
|
||||||
pub show_origin_destination: Switch,
|
pub show_origin_destination: Switch,
|
||||||
pub show_appearance_panel: Switch,
|
pub show_appearance_panel: Switch,
|
||||||
|
|
@ -177,6 +178,8 @@ impl ViewActions {
|
||||||
zoom_to_fit: Action::new_keyless(tr.text("tr-menu-view-zoom-to-fit")).into_switch(),
|
zoom_to_fit: Action::new_keyless(tr.text("tr-menu-view-zoom-to-fit")).into_switch(),
|
||||||
show_ratsnest: Action::new_keyless(tr.text("tr-menu-view-show-ratsnest")).into_switch(),
|
show_ratsnest: Action::new_keyless(tr.text("tr-menu-view-show-ratsnest")).into_switch(),
|
||||||
show_navmesh: Action::new_keyless(tr.text("tr-menu-view-show-navmesh")).into_switch(),
|
show_navmesh: Action::new_keyless(tr.text("tr-menu-view-show-navmesh")).into_switch(),
|
||||||
|
show_topo_navmesh: Action::new_keyless(tr.text("tr-menu-view-show-topo-navmesh"))
|
||||||
|
.into_switch(),
|
||||||
show_bboxes: Action::new_keyless(tr.text("tr-menu-view-show-bboxes")).into_switch(),
|
show_bboxes: Action::new_keyless(tr.text("tr-menu-view-show-bboxes")).into_switch(),
|
||||||
show_origin_destination: Action::new_keyless(
|
show_origin_destination: Action::new_keyless(
|
||||||
tr.text("tr-menu-view-show-origin-destination"),
|
tr.text("tr-menu-view-show-origin-destination"),
|
||||||
|
|
@ -196,42 +199,30 @@ impl ViewActions {
|
||||||
viewport: &mut Viewport,
|
viewport: &mut Viewport,
|
||||||
have_workspace: bool,
|
have_workspace: bool,
|
||||||
) {
|
) {
|
||||||
ui.toggle_value(
|
self.zoom_to_fit
|
||||||
&mut viewport.scheduled_zoom_to_fit,
|
.toggle_widget(ui, &mut viewport.scheduled_zoom_to_fit);
|
||||||
tr.text("tr-menu-view-zoom-to-fit"),
|
|
||||||
);
|
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
ui.add_enabled_ui(have_workspace, |ui| {
|
ui.add_enabled_ui(have_workspace, |ui| {
|
||||||
ui.checkbox(
|
self.show_ratsnest.checkbox(ui, &mut menu_bar.show_ratsnest);
|
||||||
&mut menu_bar.show_ratsnest,
|
self.show_navmesh.checkbox(ui, &mut menu_bar.show_navmesh);
|
||||||
tr.text("tr-menu-view-show-ratsnest"),
|
self.show_topo_navmesh
|
||||||
);
|
.checkbox(ui, &mut menu_bar.show_topo_navmesh);
|
||||||
ui.checkbox(
|
self.show_bboxes.checkbox(ui, &mut menu_bar.show_bboxes);
|
||||||
&mut menu_bar.show_navmesh,
|
self.show_origin_destination
|
||||||
tr.text("tr-menu-view-show-navmesh"),
|
.checkbox(ui, &mut menu_bar.show_origin_destination);
|
||||||
);
|
|
||||||
ui.checkbox(
|
|
||||||
&mut menu_bar.show_topo_navmesh,
|
|
||||||
tr.text("tr-menu-view-show-topo-navmesh"),
|
|
||||||
);
|
|
||||||
ui.checkbox(
|
|
||||||
&mut menu_bar.show_bboxes,
|
|
||||||
tr.text("tr-menu-view-show-bboxes"),
|
|
||||||
);
|
|
||||||
ui.checkbox(
|
|
||||||
&mut menu_bar.show_origin_destination,
|
|
||||||
tr.text("tr-menu-view-show-origin-destination"),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
self.show_appearance_panel
|
||||||
|
.checkbox(ui, &mut menu_bar.show_appearance_panel);
|
||||||
|
|
||||||
ui.checkbox(
|
ui.separator();
|
||||||
&mut menu_bar.show_appearance_panel,
|
ui.label(tr.text("tr-menu-view-kdb-scroll-delta-factor"));
|
||||||
tr.text("tr-menu-view-show-layer-manager"),
|
ui.add(egui::widgets::Slider::new(
|
||||||
);
|
&mut viewport.kbd_scroll_delta_factor,
|
||||||
|
1.0..=100.0,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -259,7 +250,7 @@ impl PlaceActions {
|
||||||
is_placing_via: &mut bool,
|
is_placing_via: &mut bool,
|
||||||
) -> egui::InnerResponse<()> {
|
) -> egui::InnerResponse<()> {
|
||||||
ui.add_enabled_ui(have_workspace, |ui| {
|
ui.add_enabled_ui(have_workspace, |ui| {
|
||||||
self.place_via.toggle_widget(ctx, ui, is_placing_via);
|
self.place_via.toggle_widget(ui, is_placing_via);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ use topola::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config, error_dialog::ErrorDialog, menu_bar::MenuBar, status_bar::StatusBar,
|
actions::Actions, config::Config, error_dialog::ErrorDialog, menu_bar::MenuBar,
|
||||||
translator::Translator, viewport::Viewport, workspace::Workspace,
|
status_bar::StatusBar, translator::Translator, viewport::Viewport, workspace::Workspace,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,14 @@ use topola::{
|
||||||
router::navmesh::NavvertexIndex,
|
router::navmesh::NavvertexIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{config::Config, menu_bar::MenuBar, painter::Painter, workspace::Workspace};
|
use crate::{
|
||||||
|
actions::Actions, config::Config, menu_bar::MenuBar, painter::Painter, workspace::Workspace,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct Viewport {
|
pub struct Viewport {
|
||||||
pub transform: egui::emath::TSTransform,
|
pub transform: egui::emath::TSTransform,
|
||||||
|
/// how much should a single arrow key press scroll
|
||||||
|
pub kbd_scroll_delta_factor: f32,
|
||||||
pub scheduled_zoom_to_fit: bool,
|
pub scheduled_zoom_to_fit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,6 +42,7 @@ impl Viewport {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
transform: egui::emath::TSTransform::new([0.0, 0.0].into(), 0.01),
|
transform: egui::emath::TSTransform::new([0.0, 0.0].into(), 0.01),
|
||||||
|
kbd_scroll_delta_factor: 5.0,
|
||||||
scheduled_zoom_to_fit: false,
|
scheduled_zoom_to_fit: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,6 +57,7 @@ impl Viewport {
|
||||||
egui::CentralPanel::default()
|
egui::CentralPanel::default()
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
egui::Frame::canvas(ui.style()).show(ui, |ui| {
|
egui::Frame::canvas(ui.style()).show(ui, |ui| {
|
||||||
|
// TODO: only request re-render if anything changed
|
||||||
ui.ctx().request_repaint();
|
ui.ctx().request_repaint();
|
||||||
|
|
||||||
let (id, viewport_rect) = ui.allocate_space(ui.available_size());
|
let (id, viewport_rect) = ui.allocate_space(ui.available_size());
|
||||||
|
|
@ -68,7 +74,52 @@ impl Viewport {
|
||||||
|
|
||||||
self.transform.translation +=
|
self.transform.translation +=
|
||||||
latest_pos.to_vec2() * (old_scaling - self.transform.scaling);
|
latest_pos.to_vec2() * (old_scaling - self.transform.scaling);
|
||||||
self.transform.translation += ctx.input(|i| i.smooth_scroll_delta);
|
|
||||||
|
// disable built-in behavior of arrow keys
|
||||||
|
if response.has_focus() {
|
||||||
|
response.ctx.memory_mut(|m| {
|
||||||
|
// we are only allowed to modify the focus lock filter if we have focus
|
||||||
|
m.set_focus_lock_filter(
|
||||||
|
id,
|
||||||
|
egui::EventFilter {
|
||||||
|
horizontal_arrows: true,
|
||||||
|
vertical_arrows: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.transform.translation += ctx.input_mut(|i| {
|
||||||
|
// handle scrolling
|
||||||
|
let mut scroll_delta = core::mem::take(&mut i.smooth_scroll_delta);
|
||||||
|
|
||||||
|
// arrow keys
|
||||||
|
let kbd_sdf = self.kbd_scroll_delta_factor;
|
||||||
|
let mut pressed = |key| {
|
||||||
|
i.consume_shortcut(&egui::KeyboardShortcut::new(
|
||||||
|
egui::Modifiers::SHIFT,
|
||||||
|
key,
|
||||||
|
))
|
||||||
|
};
|
||||||
|
use egui::Key;
|
||||||
|
scroll_delta.y += if pressed(Key::ArrowDown) {
|
||||||
|
kbd_sdf
|
||||||
|
} else if pressed(Key::ArrowUp) {
|
||||||
|
-kbd_sdf
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
scroll_delta.x += if pressed(Key::ArrowRight) {
|
||||||
|
kbd_sdf
|
||||||
|
} else if pressed(Key::ArrowLeft) {
|
||||||
|
-kbd_sdf
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
scroll_delta
|
||||||
|
});
|
||||||
|
|
||||||
let mut painter = Painter::new(ui, self.transform, menu_bar.show_bboxes);
|
let mut painter = Painter::new(ui, self.transform, menu_bar.show_bboxes);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ tr-menu-view-show-topo-navmesh = Show Topological Navmesh
|
||||||
tr-menu-view-show-bboxes = Show BBoxes
|
tr-menu-view-show-bboxes = Show BBoxes
|
||||||
tr-menu-view-show-origin-destination = Show Origin–Destination
|
tr-menu-view-show-origin-destination = Show Origin–Destination
|
||||||
tr-menu-view-show-layer-manager = Show Layer Manager
|
tr-menu-view-show-layer-manager = Show Layer Manager
|
||||||
|
tr-menu-view-kdb-scroll-delta-factor = Keyboard scroll delta factor
|
||||||
tr-menu-view-frame-timestep = Frame Timestep
|
tr-menu-view-frame-timestep = Frame Timestep
|
||||||
|
|
||||||
tr-menu-place = Place
|
tr-menu-place = Place
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue