Enlightenment CVS committal Author : raster Project : e17 Module : libs/etk
Dir : e17/libs/etk/src/lib Modified Files: etk_scrolled_view.c etk_scrolled_view.h Log Message: ticks finger scrolling stuff for etk. =================================================================== RCS file: /cvs/e/e17/libs/etk/src/lib/etk_scrolled_view.c,v retrieving revision 1.33 retrieving revision 1.34 diff -u -3 -r1.33 -r1.34 --- etk_scrolled_view.c 28 Sep 2007 20:01:27 -0000 1.33 +++ etk_scrolled_view.c 10 Apr 2008 09:03:08 -0000 1.34 @@ -37,7 +37,15 @@ static Etk_Bool _etk_scrolled_view_child_added_cb(Etk_Object *object, void *child, void *data); static Etk_Bool _etk_scrolled_view_child_removed_cb(Etk_Object *object, void *child, void *data); static Etk_Bool _etk_scrolled_view_child_scroll_size_changed_cb(Etk_Object *object, void *data); +static int _etk_scrolled_view_motive_bounce(void *data); + +static Etk_Bool _etk_scrolled_view_mouse_down(Etk_Object *object, Etk_Event_Mouse_Down *event, void *data); +static Etk_Bool _etk_scrolled_view_mouse_up(Etk_Object *object, Etk_Event_Mouse_Up *event, void *data); +static Etk_Bool _etk_scrolled_view_mouse_click(Etk_Object *object, Etk_Event_Mouse_Up *event, void *data); +static Etk_Bool _etk_scrolled_view_mouse_move(Etk_Object *object, Etk_Event_Mouse_Move *event, void *data); + +static Etk_Bool _etk_scrolled_view_bar_mouse_down(Etk_Object *object, Etk_Event_Mouse_Down *event, void *data); /************************** * * Implementation @@ -173,6 +181,106 @@ *vpolicy = scrolled_view ? scrolled_view->vpolicy : ETK_POLICY_AUTO; } +/** + * @brief Set the scrolled view dragable or not + * @param scrolled_view a scrolled view + * @param dragable The scrolled view is dragable or not? + */ +void etk_scrolled_view_dragable_set(Etk_Scrolled_View *scrolled_view, Etk_Bool dragable) +{ + if (!scrolled_view) + return; + scrolled_view->drag.dragable = dragable; +} + +/** + * @brief Get the scrolled view dragable flag + * @param scrolled_view a scrolled view + * @return Returns ETK_TURE if the scrolled view is dragable + */ +Etk_Bool etk_scrolled_view_dragable_get(Etk_Scrolled_View *scrolled_view) +{ + if (!scrolled_view) + return ETK_FALSE; + return scrolled_view->drag.dragable; +} + +/** + * @brief Set the scrolled view boucy or not. + * @param scrolled_view a scrolled view + * @param bouncy The scrolled view is bouncy or not (Default TRUE) + */ +void etk_scrolled_view_drag_bouncy_set(Etk_Scrolled_View *scrolled_view, Etk_Bool bouncy) +{ + if (!scrolled_view) + return; + scrolled_view->drag.bouncy = bouncy; +} + +/** + * @brief Get the scrolled view bouncy flag + * @param scrolled_view a scrolled view + * @return Returns ETK_TURE if the scrolled view is bouncy + */ +Etk_Bool etk_scrolled_view_drag_bouncy_get(Etk_Scrolled_View *scrolled_view) +{ + if (!scrolled_view) + return ETK_FALSE; + return scrolled_view->drag.bouncy; +} + +/** + * @brief Set the scrolled view sample interval to calculate the scrolling speed. + * @param scrolled_view a scrolled view + * @param interval The interval of sampling latest scrolling speed (minimial 0.2 second, default 0.5 second) + * @return Returns the actual sampling interval set. If scrolled_view is NULL returns 0.0f. + */ +double etk_scrolled_view_drag_sample_interval_magic_set(Etk_Scrolled_View *scrolled_view,double interval) +{ + if (!scrolled_view) + return 0.0f; + interval = interval >= 0.2f ? interval : 0.2f; + scrolled_view->drag.sample_magic = interval; + return scrolled_view->drag.sample_magic; +} + +/** + * @brief Get the scrolled view sample interval to calculate the scrolling speed. + * @param scrolled_view a scrolled view + * @return Returns the sampling interval. If scrolled_view is NULL return 0.0f. + */ +double etk_scrolled_view_drag_sample_interval_magic_get(Etk_Scrolled_View *scrolled_view) +{ + if (!scrolled_view) + return 0.0f; + return scrolled_view->drag.sample_magic; +} + +/** + * @brief Set the damping magic number of a dragable scrolled view + * @param scrolled_view a scrolled view + * @param damping The damping factor of the dragable scrolled view (default 100) + * @return Returns the actual damping factor set + */ +unsigned int etk_scrolled_view_drag_damping_magic_set(Etk_Scrolled_View *scrolled_view,unsigned int damping) +{ + if (!scrolled_view) + return 0; + scrolled_view->drag.damping_magic = damping; + return scrolled_view->drag.damping_magic; +} + +/** + * @brief Get the damping magic number of a dragable scrolled view + * @param scrolled_view a scrolled view + * @return Returns the actual damping factor + */ +unsigned int etk_scrolled_view_drag_damping_magic_get(Etk_Scrolled_View *scrolled_view) +{ + if (!scrolled_view) + return 0; + return scrolled_view->drag.damping_magic; +} /************************** * @@ -189,6 +297,14 @@ scrolled_view->hpolicy = ETK_POLICY_AUTO; scrolled_view->vpolicy = ETK_POLICY_AUTO; + scrolled_view->drag.bar_pressed = ETK_FALSE; + scrolled_view->drag.dragable = ETK_FALSE; + scrolled_view->drag.bouncy = ETK_TRUE; + + // FIXME This can be put in etk_config (Make whole system be configured) + etk_scrolled_view_drag_sample_interval_magic_set(scrolled_view,0.5f); + etk_scrolled_view_drag_damping_magic_set(scrolled_view,100); + scrolled_view->hscrollbar = etk_hscrollbar_new(0.0, 0.0, 0.0, 12.0, 50.0, 0.0); etk_widget_theme_parent_set(scrolled_view->hscrollbar, ETK_WIDGET(scrolled_view)); etk_widget_parent_set(scrolled_view->hscrollbar, ETK_WIDGET(scrolled_view)); @@ -205,11 +321,18 @@ ETK_WIDGET(scrolled_view)->size_allocate = _etk_scrolled_view_size_allocate; etk_signal_connect_by_code(ETK_WIDGET_KEY_DOWN_SIGNAL, ETK_OBJECT(scrolled_view), ETK_CALLBACK(_etk_scrolled_view_key_down_cb), NULL); + etk_signal_connect_by_code(ETK_WIDGET_MOUSE_DOWN_SIGNAL, ETK_OBJECT(scrolled_view), ETK_CALLBACK(_etk_scrolled_view_mouse_down), &scrolled_view->drag); + etk_signal_connect_by_code(ETK_WIDGET_MOUSE_UP_SIGNAL, ETK_OBJECT(scrolled_view), ETK_CALLBACK(_etk_scrolled_view_mouse_up), &scrolled_view->drag); + etk_signal_connect_by_code(ETK_WIDGET_MOUSE_CLICK_SIGNAL, ETK_OBJECT(scrolled_view), ETK_CALLBACK(_etk_scrolled_view_mouse_click), &scrolled_view->drag); + etk_signal_connect_by_code(ETK_WIDGET_MOUSE_MOVE_SIGNAL, ETK_OBJECT(scrolled_view), ETK_CALLBACK(_etk_scrolled_view_mouse_move), &scrolled_view->drag); etk_signal_connect_by_code(ETK_WIDGET_MOUSE_WHEEL_SIGNAL, ETK_OBJECT(scrolled_view), ETK_CALLBACK(_etk_scrolled_view_mouse_wheel), NULL); etk_signal_connect_by_code(ETK_CONTAINER_CHILD_ADDED_SIGNAL, ETK_OBJECT(scrolled_view), ETK_CALLBACK(_etk_scrolled_view_child_added_cb), NULL); etk_signal_connect_by_code(ETK_CONTAINER_CHILD_REMOVED_SIGNAL, ETK_OBJECT(scrolled_view), ETK_CALLBACK(_etk_scrolled_view_child_removed_cb), NULL); etk_signal_connect_by_code(ETK_RANGE_VALUE_CHANGED_SIGNAL, ETK_OBJECT(scrolled_view->hscrollbar), ETK_CALLBACK(_etk_scrolled_view_hscrollbar_value_changed_cb), scrolled_view); + etk_signal_connect_by_code(ETK_WIDGET_MOUSE_DOWN_SIGNAL, ETK_OBJECT(scrolled_view->hscrollbar), ETK_CALLBACK(_etk_scrolled_view_bar_mouse_down), scrolled_view); etk_signal_connect_by_code(ETK_RANGE_VALUE_CHANGED_SIGNAL, ETK_OBJECT(scrolled_view->vscrollbar), ETK_CALLBACK(_etk_scrolled_view_vscrollbar_value_changed_cb), scrolled_view); + etk_signal_connect_by_code(ETK_WIDGET_MOUSE_DOWN_SIGNAL, ETK_OBJECT(scrolled_view->vscrollbar), ETK_CALLBACK(_etk_scrolled_view_bar_mouse_down), scrolled_view); + } /* Sets the property whose id is "property_id" to the value "value" */ @@ -390,6 +513,94 @@ etk_widget_size_allocate(child, child_geometry); } +/* Check if reaching the boundary */ +static inline double _etk_scrolled_view_bounce_check (Etk_Range * range, double delta,double v) +{ + double pos = (range->value + delta); + if (pos <= range->lower) + { + pos = range->lower + (range->lower - pos); + v *= -1; + } + etk_range_value_set(range, pos); + if (pos > range->value) + v *= -1; + return v; +} + +/* Animator for inertial scrolling */ +static int _etk_scrolled_view_motive_bounce(void *data) +{ + Etk_Scrolled_View *scrolled_view = ETK_SCROLLED_VIEW(data); + struct Etk_Scrolled_View_Mouse_Drag *drag; + Etk_Range *vscrollbar_range; + Etk_Range *hscrollbar_range; + double delta_time; + double delta_V; + double delta_x; + double delta_y; + if (!scrolled_view) + return 0; + drag = &scrolled_view->drag; + if (drag->mouse_down) + return 0; + + // Using trapezoid method to calculate the distance. + delta_time = ecore_time_get() - drag->timestamp; + delta_V = delta_time * (drag->damping_magic + abs(drag->Vx)+ abs(drag->Vy))/2; + delta_time = delta_time < 0.01f ? 0.01f: delta_time; + + if (drag->Vx < delta_V && drag->Vx > -delta_V) + { + delta_x = 0; + drag->Vx = 0; + } + else if (drag->Vx > 0) + { + delta_x = ((drag->Vx * 2) - delta_V) * delta_time / 2; + drag->Vx = drag->Vx - delta_V; + } + else + { + delta_x = ((drag->Vx * 2) + delta_V) * delta_time / 2; + drag->Vx = drag->Vx + delta_V; + } + + if (drag->Vy < delta_V && drag->Vy > -delta_V) + { + drag->Vy = 0; + delta_y = 0; + } + else if(drag->Vy > 0) + { + delta_y = ((drag->Vy * 2) - delta_V) * delta_time / 2; + drag->Vy = drag->Vy - delta_V; + } else + { + delta_y = ((drag->Vy * 2) + delta_V) * delta_time / 2; + drag->Vy = drag->Vy + delta_V; + } + + if (drag->Vx == 0 && drag->Vy == 0) + return 0; + + vscrollbar_range = ETK_RANGE(scrolled_view->vscrollbar); + hscrollbar_range = ETK_RANGE(scrolled_view->hscrollbar); + if (drag->bouncy) + { + drag->Vx = _etk_scrolled_view_bounce_check(hscrollbar_range, delta_x, drag->Vx); + drag->Vy = _etk_scrolled_view_bounce_check(vscrollbar_range, delta_y, drag->Vy); + } + else + { + drag->Vx = drag->Vx == _etk_scrolled_view_bounce_check(hscrollbar_range, delta_x, drag->Vx) ? drag->Vx : 0.0f; + drag->Vy = drag->Vy == _etk_scrolled_view_bounce_check(vscrollbar_range, delta_y, drag->Vy) ? drag->Vy : 0.0f; + } + drag->timestamp = ecore_time_get(); + return 1; +} + + /************************** * * Callbacks and handlers @@ -431,6 +642,135 @@ return propagate; } +/* Called when mouse button has been pressed down */ +static Etk_Bool _etk_scrolled_view_mouse_down(Etk_Object *object, Etk_Event_Mouse_Down *event, void *data) +{ + Etk_Scrolled_View *scrolled_view; + Etk_Range *vscrollbar_range; + Etk_Range *hscrollbar_range; + struct Etk_Scrolled_View_Mouse_Drag *drag = (struct Etk_Scrolled_View_Mouse_Drag *) data; + + if (!(scrolled_view = ETK_SCROLLED_VIEW(object))) + return ETK_FALSE; + + if (!drag->dragable) + return ETK_FALSE; + + if (!drag->mouse_down && event->button) + { + vscrollbar_range = ETK_RANGE(scrolled_view->vscrollbar); + hscrollbar_range = ETK_RANGE(scrolled_view->hscrollbar); + drag->mouse_down = ETK_TRUE; + drag->timestamp = ecore_time_get(); + drag->old_timestamp = 0.0f; + drag->position = event->widget; + drag->bar_position.x = hscrollbar_range->value; + drag->bar_position.y = vscrollbar_range->value; + } + return ETK_FALSE; +} + +/* Called when mouse is dragging */ +static Etk_Bool _etk_scrolled_view_mouse_move(Etk_Object *object, Etk_Event_Mouse_Move *event, void *data) +{ + Etk_Scrolled_View *scrolled_view; + Etk_Range *vscrollbar_range; + Etk_Range *hscrollbar_range; + double delta_time; + struct Etk_Scrolled_View_Mouse_Drag *drag = (struct Etk_Scrolled_View_Mouse_Drag *) data; + + if (!(scrolled_view = ETK_SCROLLED_VIEW(object))) + return ETK_FALSE; + + if (!drag->dragable) + return ETK_FALSE; + + if (!drag->mouse_down) + return ETK_FALSE; + + if (!event->buttons) + return ETK_FALSE; + + vscrollbar_range = ETK_RANGE(scrolled_view->vscrollbar); + hscrollbar_range = ETK_RANGE(scrolled_view->hscrollbar); + if (drag->scroll_flag == 0) + { + drag->scroll_flag = (event->cur.widget.y - drag->position.y)/vscrollbar_range->step_increment || (event->cur.widget.x - drag->position.x)/hscrollbar_range->step_increment; + } + + if (drag->scroll_flag) + { + if (drag->bar_pressed==ETK_FALSE) + { + etk_range_value_set(vscrollbar_range, vscrollbar_range->value - (event->cur.widget.y - drag->position.y)); + etk_range_value_set(hscrollbar_range, hscrollbar_range->value - (event->cur.widget.x - drag->position.x)); + } + drag->position = event->cur.widget; + delta_time = ecore_time_get() - drag->timestamp; + // in case delta_time is zero + delta_time = delta_time == 0.0f ? drag->sample_magic : delta_time; + if (delta_time > drag->sample_magic || drag->old_timestamp == 0) + { + drag->old_timestamp = drag->timestamp; + drag->timestamp = ecore_time_get(); + drag->Vx = (hscrollbar_range->value - drag->bar_position.x) / delta_time; + drag->Vy = (vscrollbar_range->value - drag->bar_position.y) / delta_time; + drag->bar_position.x = hscrollbar_range->value; + drag->bar_position.y = vscrollbar_range->value; + } + return ETK_TRUE; + } + return ETK_FALSE; +} + +/* Called when mouse button has been released */ +static Etk_Bool _etk_scrolled_view_mouse_up(Etk_Object *object, Etk_Event_Mouse_Up *event, void *data) +{ + Etk_Scrolled_View *scrolled_view; + struct Etk_Scrolled_View_Mouse_Drag *drag = (struct Etk_Scrolled_View_Mouse_Drag *) data; + + if (!(scrolled_view = ETK_SCROLLED_VIEW(object))) + return ETK_FALSE; + + if (!drag->dragable) + return ETK_FALSE; + + if (!drag->mouse_down) + return ETK_FALSE; + + if (drag->bar_pressed == ETK_TRUE) + { + drag->bar_pressed = ETK_FALSE; + return ETK_FALSE; + } + + drag->mouse_down = ETK_FALSE; + + if (drag->scroll_flag) + { + drag->timestamp = ecore_time_get(); + ecore_animator_add(&_etk_scrolled_view_motive_bounce, scrolled_view); + return ETK_TRUE; + } + return ETK_FALSE; +} + +/* Called when mouse button has been clicked */ +static Etk_Bool _etk_scrolled_view_mouse_click (Etk_Object *object, Etk_Event_Mouse_Up *event, void *data) +{ + Etk_Scrolled_View *scrolled_view; + struct Etk_Scrolled_View_Mouse_Drag *drag = (struct Etk_Scrolled_View_Mouse_Drag *) data; + if (!(scrolled_view = ETK_SCROLLED_VIEW(object))) + return ETK_TRUE; + + if (drag->scroll_flag) + { + drag->scroll_flag = 0; + return ETK_TRUE; + } + return ETK_FALSE; +} + /* Called when the user wants to scroll the scrolled view with the mouse wheel */ static Etk_Bool _etk_scrolled_view_mouse_wheel(Etk_Object *object, Etk_Event_Mouse_Wheel *event, void *data) { @@ -457,6 +797,18 @@ return ETK_TRUE; } + +/* Called when dragging on the scrollbar */ +static Etk_Bool _etk_scrolled_view_bar_mouse_down(Etk_Object *object, Etk_Event_Mouse_Down *event, void *data) +{ + Etk_Scrolled_View *scrolled_view; + Etk_Widget *child; + if (!(scrolled_view = ETK_SCROLLED_VIEW(data)) || !(child = ETK_BIN(scrolled_view)->child) || !child->scroll) + return ETK_FALSE; + scrolled_view->drag.bar_pressed = ETK_TRUE; + return ETK_FALSE; +} + /* Called when the value of the vscrollbar has changed */ static Etk_Bool _etk_scrolled_view_vscrollbar_value_changed_cb(Etk_Object *object, double value, void *data) =================================================================== RCS file: /cvs/e/e17/libs/etk/src/lib/etk_scrolled_view.h,v retrieving revision 1.12 retrieving revision 1.13 diff -u -3 -r1.12 -r1.13 --- etk_scrolled_view.h 19 Sep 2007 20:16:26 -0000 1.12 +++ etk_scrolled_view.h 10 Apr 2008 09:03:08 -0000 1.13 @@ -33,9 +33,24 @@ ETK_POLICY_AUTO, /**< The scrollbar is shown and hidden automatically whether or not the child can fit * entirely in the scrolled view */ ETK_POLICY_SHOW, /**< The scrollbar is always visible */ - ETK_POLICY_HIDE /**< The scrollbar is always hidden */ + ETK_POLICY_HIDE, /**< The scrollbar is always hidden */ } Etk_Scrolled_View_Policy; +struct Etk_Scrolled_View_Mouse_Drag +{ + Etk_Bool mouse_down; + Etk_Bool bar_pressed; + Etk_Bool dragable; + Etk_Bool bouncy; + int scroll_flag; + Etk_Position position; + Etk_Position bar_position; + double sample_magic; + unsigned int damping_magic; + double timestamp; + double old_timestamp; + double Vx,Vy; +}; /** * @brief @widget The structure of a scrolled view @@ -52,9 +67,12 @@ Etk_Scrolled_View_Policy hpolicy; Etk_Scrolled_View_Policy vpolicy; + + struct Etk_Scrolled_View_Mouse_Drag drag; }; + Etk_Type *etk_scrolled_view_type_get(void); Etk_Widget *etk_scrolled_view_new(void); @@ -63,6 +81,14 @@ void etk_scrolled_view_add_with_viewport(Etk_Scrolled_View *scrolled_view, Etk_Widget *child); void etk_scrolled_view_policy_set(Etk_Scrolled_View *scrolled_view, Etk_Scrolled_View_Policy hpolicy, Etk_Scrolled_View_Policy vpolicy); void etk_scrolled_view_policy_get(Etk_Scrolled_View *scrolled_view, Etk_Scrolled_View_Policy *hpolicy, Etk_Scrolled_View_Policy *vpolicy); +void etk_scrolled_view_dragable_set(Etk_Scrolled_View *scrolled_view, Etk_Bool dragable); +Etk_Bool etk_scrolled_view_dragable_get(Etk_Scrolled_View *scrolled_view); +void etk_scrolled_view_drag_bouncy_set(Etk_Scrolled_View *scrolled_view, Etk_Bool bouncy); +Etk_Bool etk_scrolled_view_drag_bouncy_get(Etk_Scrolled_View *scrolled_view); +double etk_scrolled_view_drag_sample_interval_magic_set(Etk_Scrolled_View *scrolled_view,double interval); +double etk_scrolled_view_drag_sample_interval_magic_get(Etk_Scrolled_View *scrolled_view); +unsigned int etk_scrolled_view_drag_damping_magic_set(Etk_Scrolled_View *scrolled_view,unsigned int damping); +unsigned int etk_scrolled_view_drag_damping_magic_get(Etk_Scrolled_View *scrolled_view); /** @} */ ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone _______________________________________________ enlightenment-cvs mailing list enlightenment-cvs@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs