Library: Physics
Language: C (Maybe built on top of GLib? Qt already depends on GLib by default if available.)
Dependencies: possibly a physics engine such as Chipmunk
Quick overview
This provides a scrollable view. The content is a rectangle, and the viewport is a rectangle whose area is a subset of the content. The content and viewport can be thought of as boxes. The viewport may be dragged within the content.
While the user is interacting with the viewport by scrolling on an input device, the viewport follows the scroll motion. When the scrolling ceases, the viewport will continue moving. As it moves, friction will slow it down until it finally stops.
When the viewport hits the edge of the area, something happens. By default all motion of the viewport is stopped. The library may provide alternative behaviour, such as "bouncing", sliding along the edge and so on.
User stories
The physics library should do following:
- provide a viewport that can be scrolled and which slows down according to physical laws
- provide several different behaviours when the area hits the edge: stopping, bouncing like Android's list widget etc
- support setting friction and other such variables
- provide (possibly system global) default values for the above
- allow changing the scrolling speed and direction even if there is a scroll event ongoing
- the physical simulation is not tied to the system clock
- the source of motion can be a touch gesture, mouse flick, accelerometer, or any other device capable of providing velocity information
Functionality it will not have:
- it does not convert coordinate types (e.g. from touchpad device coordinates to pixels), it will only work in pixel units
- it does not support on-the-fly area or viewport resizing while preserving motion, resizes reset all existing state
- it is not thread-safe
API objects
PhysicsScroller
An opaque type for the scroller area.
API Functions
physics_scroller_new
PhysicsScroller physics_scroller_new( int area_width, int area_height, int viewport_width, int viewport_height)
Creates a new scroller with the given dimensions. Returns NULL on failure, such as having a viewport that is larger than the viewable area.
physics_scroller_delete
void physics_scroller_delete(PhysicsScroller scroller);
Deletes a scroller.
physics_scroller_reset
int PHYSICS_API physics_scroller_reset(PhysicsScroller scroller, int area_width, int area_height, int viewport_width, int viewport_height);
Resets the scroller with the new given dimensions. If dimensions are invalid, the state of the object is not changed. If they are valid, all old state is permanently destroyed. Using this is equivalent to deleting the old scroller and creating a new one with the given arguments.
scroller_get_viewport_location
void physics_scroller_get_viewport_location(PhysicsScroller scroller, int *x, int *y);
Get the location of the top left corner of the viewport.
set_scroller_set_viewport_location
void physics_scroller_set_viewport_location(PhysicsScroller scroller, int x, int y, int clamp_to_area);
Move viewport's top left corner to the desired location. If clamp_to_area is nonzero (true), the viewport is moved so it is wholly inside the area. If it is zero (false), the behaviour depends on edge behaviour type in a as-yet-unspecified manner. For example, the scroller may move the viewport inside the area with a smooth transition.
scroller_set_velocity
void physics_scroller_set_velocity(PhysicsScroller scroller, int dx_pixels_per_second, int dy_pixels_per_second);
Sets the scroller's instantaneous velocity. Causes the area to start moving to the specified direction once time is advanced.
physics_scroller_advance
int physics_scroller_advance(PhysicsScroller scroller, unsigned long time_in_millis);
Causes the scroller to simulate motion forward in time for the specified time. Returns 0 if the scroller has come to a stop (and thus further calls to this function would not do anything) and a nonzero value if the viewport is still in motion.
The advance time can be any positive value. It can be 1 millisecond, it can be 10 000 years. It can be different on every call. The scroller takes care of numerical stability issues.
Using the library
Note: the code samples in this section are descriptive, not normative.
Starting scroll motion
A user flicks on the view. This generates a flick event which gets sent to the application. It sets up the scroller with a call such as this.
physics_scroller_set_velocity(scroller, to_pixels(flick_event->x_speed), to_pixels(flick_event->y_speed));
Updating the scroll
The update is modeled after glib's g_timeout_add functionality. The scroller is told to advance forward some amount of time. It calculates its new location and returns false if the viewport has stopped and true if motion is still ongoing.
A periodically called update function would usually do something like this.
long now_time = get_time(); long delta_t = now_time - previous_time; bool motion_remaining; motion_remaining = physics_scroller_advance(scroller, delta_t); previous_time = now_time; redraw_canvas_and_other_such_things(); if(motion_remaining) more_to_come(); else motion_has_finished();