From 160f58e90a4d6f0ad9169ed4c306cbbfabf2b64e Mon Sep 17 00:00:00 2001 From: eschweic Date: Wed, 5 Jun 2013 15:35:53 -0700 Subject: [PATCH] Impelemented zooming and slightly better scrolling. --- src/components/main/compositing/mod.rs | 62 +++++++++++++++++-- .../main/platform/common/glut_windowing.rs | 29 +++++++-- src/components/main/windowing.rs | 5 ++ 3 files changed, 86 insertions(+), 10 deletions(-) diff --git a/src/components/main/compositing/mod.rs b/src/components/main/compositing/mod.rs index c0b08be2f15..b4af9306c15 100644 --- a/src/components/main/compositing/mod.rs +++ b/src/components/main/compositing/mod.rs @@ -126,6 +126,9 @@ fn run_main_loop(port: Port, 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(); @@ -248,16 +251,65 @@ fn run_main_loop(port: Port, *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() } diff --git a/src/components/main/platform/common/glut_windowing.rs b/src/components/main/platform/common/glut_windowing.rs index 613064f2110..a073fa37822 100644 --- a/src/components/main/platform/common/glut_windowing.rs +++ b/src/components/main/platform/common/glut_windowing.rs @@ -8,7 +8,7 @@ /// least on desktops. It is designed for testing Servo without the need of a UI. use windowing::{ApplicationMethods, CompositeCallback, LoadUrlCallback, ClickCallback}; -use windowing::{ResizeCallback, ScrollCallback, WindowMethods}; +use windowing::{ResizeCallback, ScrollCallback, ZoomCallback, WindowMethods}; use alert::{Alert, AlertMethods}; use core::libc::c_int; @@ -37,8 +37,10 @@ pub struct Window { load_url_callback: Option, click_callback: Option, scroll_callback: Option, + zoom_callback: Option, drag_origin: Point2D, + down_button: c_int } impl WindowMethods for Window { @@ -57,10 +59,14 @@ impl WindowMethods for Window { load_url_callback: None, click_callback: None, scroll_callback: None, + zoom_callback: None, drag_origin: Point2D(0, 0), + down_button: 0 // FIXME: Hacky solution to 2 button mouse. + // Replace with tkuehn's code. }; + // Register event handlers. do glut::reshape_func(window.glut_window) |width, height| { match window.resize_callback { @@ -78,8 +84,9 @@ impl WindowMethods for Window { do glut::keyboard_func |key, _, _| { window.handle_key(key) } - do glut::mouse_func |_, _, x, y| { + do glut::mouse_func |button, _, x, y| { window.handle_click(x, y); + window.down_button = button; window.start_drag(x, y) } do glut::motion_func |x, y| { @@ -124,6 +131,11 @@ impl WindowMethods 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() @@ -163,9 +175,16 @@ impl Window { let delta = new_point - self.drag_origin; self.drag_origin = new_point; - match self.scroll_callback { - None => {} - Some(callback) => callback(Point2D(delta.x as f32, delta.y as f32)), + if self.down_button == 2 { + match self.zoom_callback { + None => {} + Some(callback) => callback(Point2D(delta.x as f32, delta.y as f32)), + } + } else { + match self.scroll_callback { + None => {} + Some(callback) => callback(Point2D(delta.x as f32, delta.y as f32)), + } } } diff --git a/src/components/main/windowing.rs b/src/components/main/windowing.rs index 9a9cefaf03b..a37676afff2 100644 --- a/src/components/main/windowing.rs +++ b/src/components/main/windowing.rs @@ -23,6 +23,9 @@ pub type ClickCallback = @fn(Point2D); /// Type of the function that is called when the user scrolls. pub type ScrollCallback = @fn(Point2D); +///Type of the function that is called when the user zooms. +pub type ZoomCallback = @fn(Point2D); + /// Methods for an abstract Application. pub trait ApplicationMethods { fn new() -> Self; @@ -46,6 +49,8 @@ pub trait WindowMethods { pub fn set_click_callback(&mut self, new_click_callback: ClickCallback); /// 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);