mirror of
https://gitlab.freedesktop.org/pipewire/helvum
synced 2026-03-15 19:46:10 +08:00
zooming: Add support for zooming via zoom gesture (two finger touchpad/touchscreen zooming)
This commit is contained in:
committed by
Tom Wagner
parent
1d10c179cc
commit
b115e6f50c
@@ -77,7 +77,7 @@ mod imp {
|
|||||||
zoom_set_action.connect_activate(
|
zoom_set_action.connect_activate(
|
||||||
clone!(@weak self.graphview as graphview => move|_, param| {
|
clone!(@weak self.graphview as graphview => move|_, param| {
|
||||||
let zoom_factor = param.unwrap().get::<f64>().unwrap();
|
let zoom_factor = param.unwrap().get::<f64>().unwrap();
|
||||||
graphview.set_zoom_factor(zoom_factor)
|
graphview.set_zoom_factor(zoom_factor, None)
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
window.add_action(&zoom_set_action);
|
window.add_action(&zoom_set_action);
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ mod imp {
|
|||||||
pub zoom_factor: Cell<f64>,
|
pub zoom_factor: Cell<f64>,
|
||||||
/// This keeps track of an ongoing node drag operation.
|
/// This keeps track of an ongoing node drag operation.
|
||||||
pub dragged_node: RefCell<Option<DragState>>,
|
pub dragged_node: RefCell<Option<DragState>>,
|
||||||
|
// Memorized data for an in-progress zoom gesture
|
||||||
|
pub zoom_gesture_initial_zoom: Cell<Option<f64>>,
|
||||||
|
pub zoom_gesture_anchor: Cell<Option<(f64, f64)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
@@ -87,6 +90,7 @@ mod imp {
|
|||||||
|
|
||||||
self.setup_node_dragging();
|
self.setup_node_dragging();
|
||||||
self.setup_scroll_zooming();
|
self.setup_scroll_zooming();
|
||||||
|
self.setup_zoom_gesture();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispose(&self, _obj: &Self::Type) {
|
fn dispose(&self, _obj: &Self::Type) {
|
||||||
@@ -316,10 +320,7 @@ mod imp {
|
|||||||
.widget()
|
.widget()
|
||||||
.downcast::<super::GraphView>()
|
.downcast::<super::GraphView>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
widget.set_zoom_factor(
|
widget.set_zoom_factor(widget.zoom_factor() + (0.1 * -delta_y), None);
|
||||||
(widget.zoom_factor() + (0.1 * -delta_y))
|
|
||||||
.clamp(super::GraphView::ZOOM_MIN, super::GraphView::ZOOM_MAX),
|
|
||||||
);
|
|
||||||
|
|
||||||
gtk::Inhibit(true)
|
gtk::Inhibit(true)
|
||||||
} else {
|
} else {
|
||||||
@@ -329,6 +330,34 @@ mod imp {
|
|||||||
obj.add_controller(&scroll_controller);
|
obj.add_controller(&scroll_controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_zoom_gesture(&self) {
|
||||||
|
let zoom_gesture = gtk::GestureZoom::new();
|
||||||
|
zoom_gesture.connect_begin(|gesture, _| {
|
||||||
|
let widget = gesture.widget().downcast::<super::GraphView>().unwrap();
|
||||||
|
|
||||||
|
widget
|
||||||
|
.imp()
|
||||||
|
.zoom_gesture_initial_zoom
|
||||||
|
.set(Some(widget.zoom_factor()));
|
||||||
|
widget
|
||||||
|
.imp()
|
||||||
|
.zoom_gesture_anchor
|
||||||
|
.set(gesture.bounding_box_center());
|
||||||
|
});
|
||||||
|
zoom_gesture.connect_scale_changed(move |gesture, delta| {
|
||||||
|
let widget = gesture.widget().downcast::<super::GraphView>().unwrap();
|
||||||
|
|
||||||
|
let initial_zoom = widget
|
||||||
|
.imp()
|
||||||
|
.zoom_gesture_initial_zoom
|
||||||
|
.get()
|
||||||
|
.expect("Initial zoom not set during zoom gesture");
|
||||||
|
|
||||||
|
widget.set_zoom_factor(initial_zoom * delta, gesture.bounding_box_center());
|
||||||
|
});
|
||||||
|
self.instance().add_controller(&zoom_gesture);
|
||||||
|
}
|
||||||
|
|
||||||
fn snapshot_background(&self, widget: &super::GraphView, snapshot: >k::Snapshot) {
|
fn snapshot_background(&self, widget: &super::GraphView, snapshot: >k::Snapshot) {
|
||||||
// Grid size and line width during neutral zoom (factor 1.0).
|
// Grid size and line width during neutral zoom (factor 1.0).
|
||||||
const NORMAL_GRID_SIZE: f32 = 20.0;
|
const NORMAL_GRID_SIZE: f32 = 20.0;
|
||||||
@@ -555,10 +584,38 @@ impl GraphView {
|
|||||||
///
|
///
|
||||||
/// A factor of 1.0 is equivalent to 100% zoom, 0.5 to 50% zoom etc.
|
/// A factor of 1.0 is equivalent to 100% zoom, 0.5 to 50% zoom etc.
|
||||||
///
|
///
|
||||||
/// Note that the zoom level is limited to between 30% and 300%.
|
/// An optional anchor (in canvas-space coordinates) can be specified, which will be used as the center of the zoom,
|
||||||
/// See [`ZOOM_MIN`] and [`ZOOM_MAX`].
|
/// so that its position stays fixed.
|
||||||
pub fn set_zoom_factor(&self, scale_factor: f64) {
|
/// If no anchor is specified, the middle of the screen is used instead.
|
||||||
self.set_property("zoom-factor", scale_factor)
|
///
|
||||||
|
/// Note that the zoom level is [clamped](`f64::clamp`) to between 30% and 300%.
|
||||||
|
/// See [`Self::ZOOM_MIN`] and [`Self::ZOOM_MAX`].
|
||||||
|
pub fn set_zoom_factor(&self, zoom_factor: f64, anchor: Option<(f64, f64)>) {
|
||||||
|
let zoom_factor = zoom_factor.clamp(Self::ZOOM_MIN, Self::ZOOM_MAX);
|
||||||
|
|
||||||
|
let (anchor_x_screen, anchor_y_screen) = anchor.unwrap_or_else(|| {
|
||||||
|
(
|
||||||
|
self.allocation().width() as f64 / 2.0,
|
||||||
|
self.allocation().height() as f64 / 2.0,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let old_zoom = self.imp().zoom_factor.get();
|
||||||
|
let hadjustment_ref = self.imp().hadjustment.borrow();
|
||||||
|
let vadjustment_ref = self.imp().vadjustment.borrow();
|
||||||
|
let hadjustment = hadjustment_ref.as_ref().unwrap();
|
||||||
|
let vadjustment = vadjustment_ref.as_ref().unwrap();
|
||||||
|
|
||||||
|
let x_total = (anchor_x_screen + hadjustment.value()) / old_zoom;
|
||||||
|
let y_total = (anchor_y_screen + vadjustment.value()) / old_zoom;
|
||||||
|
|
||||||
|
let new_hadjustment = x_total * zoom_factor - anchor_x_screen;
|
||||||
|
let new_vadjustment = y_total * zoom_factor - anchor_y_screen;
|
||||||
|
|
||||||
|
hadjustment.set_value(new_hadjustment);
|
||||||
|
vadjustment.set_value(new_vadjustment);
|
||||||
|
|
||||||
|
self.set_property("zoom-factor", zoom_factor);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_node(&self, id: u32, node: Node, node_type: Option<NodeType>) {
|
pub fn add_node(&self, id: u32, node: Node, node_type: Option<NodeType>) {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ mod imp {
|
|||||||
.connect_clicked(clone!(@weak obj => move |_| {
|
.connect_clicked(clone!(@weak obj => move |_| {
|
||||||
let graphview = obj.imp().graphview.borrow();
|
let graphview = obj.imp().graphview.borrow();
|
||||||
if let Some(ref graphview) = *graphview {
|
if let Some(ref graphview) = *graphview {
|
||||||
graphview.set_zoom_factor(graphview.zoom_factor() - 0.1);
|
graphview.set_zoom_factor(graphview.zoom_factor() - 0.1, None);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ mod imp {
|
|||||||
.connect_clicked(clone!(@weak obj => move |_| {
|
.connect_clicked(clone!(@weak obj => move |_| {
|
||||||
let graphview = obj.imp().graphview.borrow();
|
let graphview = obj.imp().graphview.borrow();
|
||||||
if let Some(ref graphview) = *graphview {
|
if let Some(ref graphview) = *graphview {
|
||||||
graphview.set_zoom_factor(graphview.zoom_factor() + 0.1);
|
graphview.set_zoom_factor(graphview.zoom_factor() + 0.1, None);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ mod imp {
|
|||||||
if let Ok(zoom_factor) = entry.text().trim_matches('%').parse::<f64>() {
|
if let Ok(zoom_factor) = entry.text().trim_matches('%').parse::<f64>() {
|
||||||
let graphview = obj.imp().graphview.borrow();
|
let graphview = obj.imp().graphview.borrow();
|
||||||
if let Some(ref graphview) = *graphview {
|
if let Some(ref graphview) = *graphview {
|
||||||
graphview.set_zoom_factor(zoom_factor / 100.0);
|
graphview.set_zoom_factor(zoom_factor / 100.0, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user