mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Implement scrolling and better zooming
This commit is contained in:
parent
a53a7f689d
commit
9085b882c6
3 changed files with 87 additions and 9 deletions
|
@ -128,6 +128,9 @@ fn run_main_loop(port: Port<Msg>,
|
|||
let page_size = @mut Size2D(0f32, 0f32);
|
||||
let window_size = @mut Size2D(800, 600);
|
||||
|
||||
// Keeps track of the current zoom factor
|
||||
let world_zoom = @mut 1f32;
|
||||
|
||||
let check_for_messages: @fn() = || {
|
||||
// Periodically check if the script task responded to our last resize event
|
||||
resize_rate_limiter.check_resize_response();
|
||||
|
@ -262,16 +265,65 @@ fn run_main_loop(port: Port<Msg>,
|
|||
*world_offset = world_offset_copy - delta;
|
||||
|
||||
// Clamp the world offset to the screen size.
|
||||
let max_x = (page_size.width - window_size.width as f32).max(&0.0);
|
||||
let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0);
|
||||
world_offset.x = world_offset.x.clamp(&0.0, &max_x);
|
||||
let max_y = (page_size.height - window_size.height as f32).max(&0.0);
|
||||
let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0);
|
||||
world_offset.y = world_offset.y.clamp(&0.0, &max_y);
|
||||
|
||||
debug!("compositor: scrolled to %?", *world_offset);
|
||||
|
||||
root_layer.common.set_transform(identity().translate(-world_offset.x,
|
||||
-world_offset.y,
|
||||
0.0));
|
||||
let mut scroll_transform = identity();
|
||||
|
||||
scroll_transform = scroll_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x,
|
||||
window_size.height as f32 / 2f32 * *world_zoom - world_offset.y,
|
||||
0.0);
|
||||
scroll_transform = scroll_transform.scale(*world_zoom, *world_zoom, 1f32);
|
||||
scroll_transform = scroll_transform.translate(window_size.width as f32 / -2f32,
|
||||
window_size.height as f32 / -2f32,
|
||||
0.0);
|
||||
|
||||
root_layer.common.set_transform(scroll_transform);
|
||||
|
||||
window.set_needs_display()
|
||||
}
|
||||
|
||||
|
||||
|
||||
// When the user pinch-zooms, scale the layer
|
||||
do window.set_zoom_callback |delta| {
|
||||
let zoom_const = 0.01;
|
||||
let old_world_zoom = *world_zoom;
|
||||
|
||||
// Determine zoom amount
|
||||
*world_zoom = (*world_zoom + delta.y * zoom_const).max(&1.0);
|
||||
|
||||
// Update world offset
|
||||
let corner_to_center_x = world_offset.x + window_size.width as f32 / 2f32;
|
||||
let new_corner_to_center_x = corner_to_center_x * *world_zoom / old_world_zoom;
|
||||
world_offset.x = world_offset.x + new_corner_to_center_x - corner_to_center_x;
|
||||
|
||||
let corner_to_center_y = world_offset.y + window_size.height as f32 / 2f32;
|
||||
let new_corner_to_center_y = corner_to_center_y * *world_zoom / old_world_zoom;
|
||||
world_offset.y = world_offset.y + new_corner_to_center_y - corner_to_center_y;
|
||||
|
||||
// Clamp to page bounds when zooming out
|
||||
let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0);
|
||||
world_offset.x = world_offset.x.clamp(&0.0, &max_x);
|
||||
let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0);
|
||||
world_offset.y = world_offset.y.clamp(&0.0, &max_y);
|
||||
|
||||
|
||||
// Apply transformations
|
||||
let mut zoom_transform = identity();
|
||||
zoom_transform = zoom_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x,
|
||||
window_size.height as f32 / 2f32 * *world_zoom - world_offset.y,
|
||||
0.0);
|
||||
zoom_transform = zoom_transform.scale(*world_zoom, *world_zoom, 1f32);
|
||||
zoom_transform = zoom_transform.translate(window_size.width as f32 / -2f32,
|
||||
window_size.height as f32 / -2f32,
|
||||
0.0);
|
||||
root_layer.common.set_transform(zoom_transform);
|
||||
|
||||
|
||||
window.set_needs_display()
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
|
||||
use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, MouseCallback};
|
||||
use windowing::{ResizeCallback, ScrollCallback, WindowMethods, WindowMouseEvent, WindowClickEvent};
|
||||
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
|
||||
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent, ZoomCallback};
|
||||
|
||||
use alert::{Alert, AlertMethods};
|
||||
use core::libc::c_int;
|
||||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use glut::glut::{DOUBLE, WindowHeight, WindowWidth};
|
||||
use glut::glut::{ACTIVE_CTRL, DOUBLE, WindowHeight, WindowWidth};
|
||||
use glut::glut;
|
||||
use glut::machack;
|
||||
|
||||
|
@ -39,8 +39,10 @@ pub struct Window {
|
|||
load_url_callback: Option<LoadUrlCallback>,
|
||||
mouse_callback: Option<MouseCallback>,
|
||||
scroll_callback: Option<ScrollCallback>,
|
||||
zoom_callback: Option<ZoomCallback>,
|
||||
|
||||
drag_origin: Point2D<c_int>,
|
||||
|
||||
mouse_down_button: @mut c_int,
|
||||
mouse_down_point: @mut Point2D<c_int>,
|
||||
}
|
||||
|
@ -61,12 +63,15 @@ impl WindowMethods<Application> for Window {
|
|||
load_url_callback: None,
|
||||
mouse_callback: None,
|
||||
scroll_callback: None,
|
||||
zoom_callback: None,
|
||||
|
||||
drag_origin: Point2D(0, 0),
|
||||
|
||||
mouse_down_button: @mut 0,
|
||||
mouse_down_point: @mut Point2D(0, 0),
|
||||
};
|
||||
|
||||
|
||||
// Register event handlers.
|
||||
do glut::reshape_func(window.glut_window) |width, height| {
|
||||
match window.resize_callback {
|
||||
|
@ -132,6 +137,11 @@ impl WindowMethods<Application> for Window {
|
|||
self.scroll_callback = Some(new_scroll_callback)
|
||||
}
|
||||
|
||||
/// Registers a zoom to be run when the user zooms.
|
||||
pub fn set_zoom_callback(&mut self, new_zoom_callback: ZoomCallback) {
|
||||
self.zoom_callback = Some(new_zoom_callback)
|
||||
}
|
||||
|
||||
/// Spins the event loop.
|
||||
pub fn check_loop(@mut self) {
|
||||
glut::check_loop()
|
||||
|
@ -147,8 +157,19 @@ impl Window {
|
|||
/// Helper function to handle keyboard events.
|
||||
fn handle_key(&self, key: u8) {
|
||||
debug!("got key: %d", key as int);
|
||||
if key == 12 { // ^L
|
||||
self.load_url()
|
||||
match key {
|
||||
12 => self.load_url(), // Ctrl+L
|
||||
k if k == ('=' as u8) && (glut::get_modifiers() & ACTIVE_CTRL) != 0 => { // Ctrl++
|
||||
for self.zoom_callback.each |&callback| {
|
||||
callback(Point2D(0.0, 20.0));
|
||||
}
|
||||
}
|
||||
k if k == 31 && (glut::get_modifiers() & ACTIVE_CTRL) != 0 => { // Ctrl+-
|
||||
for self.zoom_callback.each |&callback| {
|
||||
callback(Point2D(0.0, -20.0));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@ pub type MouseCallback = @fn(WindowMouseEvent);
|
|||
/// Type of the function that is called when the user scrolls.
|
||||
pub type ScrollCallback = @fn(Point2D<f32>);
|
||||
|
||||
///Type of the function that is called when the user zooms.
|
||||
pub type ZoomCallback = @fn(Point2D<f32>);
|
||||
|
||||
/// Methods for an abstract Application.
|
||||
pub trait ApplicationMethods {
|
||||
fn new() -> Self;
|
||||
|
@ -51,6 +54,8 @@ pub trait WindowMethods<A> {
|
|||
pub fn set_mouse_callback(&mut self, new_mouse_callback: MouseCallback);
|
||||
/// Registers a callback to run when the user scrolls.
|
||||
pub fn set_scroll_callback(&mut self, new_scroll_callback: ScrollCallback);
|
||||
/// Registers a callback to run when the user zooms.
|
||||
pub fn set_zoom_callback(&mut self, new_zoom_callback: ZoomCallback);
|
||||
|
||||
/// Spins the event loop.
|
||||
pub fn check_loop(@mut self);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue