Implement scrolling and better zooming

This commit is contained in:
eschweic 2013-06-06 16:10:19 -07:00 committed by Patrick Walton
parent a53a7f689d
commit 9085b882c6
3 changed files with 87 additions and 9 deletions

View file

@ -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()
}

View file

@ -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));
}
}
_ => {}
}
}

View file

@ -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);