/* The value of a scrollbar has changed */ static void _xfdashboard_viewpad_on_scrollbar_value_changed(XfdashboardViewpad *self, gfloat inValue, gpointer inUserData) { XfdashboardViewpadPrivate *priv; ClutterActor *scrollbar; gfloat x, y, w, h; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(inUserData)); priv=self->priv; scrollbar=CLUTTER_ACTOR(inUserData); /* Update clipping */ if(clutter_actor_has_clip(CLUTTER_ACTOR(priv->activeView))) { clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, &w, &h); if(scrollbar==priv->hScrollbar) x=inValue; else if(scrollbar==priv->vScrollbar) y=inValue; } else { x=y=0.0f; clutter_actor_get_size(CLUTTER_ACTOR(priv->activeView), &w, &h); } clutter_actor_set_clip(CLUTTER_ACTOR(priv->activeView), x, y, w, h); /* Update viewport */ _xfdashboard_viewpad_update_view_viewport(self); }
static void clip_notify_cb (ClutterActor *actor, GParamSpec *pspec, ChamplainViewport *self) { gfloat width, height; ChamplainViewportPrivate *priv = self->priv; if (!priv->sync_adjustments) return; if (!clutter_actor_has_clip (actor)) { if (priv->hadjustment) g_object_set (priv->hadjustment, "page-size", (gdouble) 1.0, NULL); if (priv->vadjustment) g_object_set (priv->vadjustment, "page-size", (gdouble) 1.0, NULL); return; } clutter_actor_get_clip (actor, NULL, NULL, &width, &height); if (priv->hadjustment) g_object_set (priv->hadjustment, "page-size", (gdouble) width, NULL); if (priv->vadjustment) g_object_set (priv->vadjustment, "page-size", (gdouble) height, NULL); }
/* Update view depending on scrollbar values */ static void _xfdashboard_viewpad_update_view_viewport(XfdashboardViewpad *self) { XfdashboardViewpadPrivate *priv; ClutterMatrix transform; gfloat x, y, w, h; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); priv=self->priv; /* Check for active view */ if(priv->activeView==NULL) { g_warning(_("Cannot update viewport of view because no one is active")); return; } /* Get offset from scrollbars and view size from clipping */ if(clutter_actor_has_clip(CLUTTER_ACTOR(priv->activeView))) { clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, &w, &h); } else { x=y=0.0f; clutter_actor_get_size(CLUTTER_ACTOR(priv->activeView), &w, &h); } /* To avoid blur convert float to ints (virtually) */ x=ceil(x); y=ceil(y); w=ceil(w); h=ceil(h); /* Set transformation (offset) */ cogl_matrix_init_identity(&transform); cogl_matrix_translate(&transform, -x, -y, 0.0f); clutter_actor_set_transform(CLUTTER_ACTOR(priv->activeView), &transform); /* Set new clipping */ clutter_actor_set_clip(CLUTTER_ACTOR(priv->activeView), x, y, w, h); }
/* Scroll to requested position in view */ static void _xfdashboard_viewpad_on_view_scroll_to(XfdashboardViewpad *self, gfloat inX, gfloat inY, gpointer inUserData) { XfdashboardViewpadPrivate *priv; XfdashboardView *view; gfloat x, y, w, h; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); g_return_if_fail(XFDASHBOARD_IS_VIEW(inUserData)); priv=self->priv; view=XFDASHBOARD_VIEW(inUserData); /* If to-scroll view is the active view in viewpad * just set scrollbar value to the new ones */ if(view==priv->activeView) { if(inX>=0.0f) xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->hScrollbar), inX); if(inY>=0.0f) xfdashboard_scrollbar_set_value(XFDASHBOARD_SCROLLBAR(priv->vScrollbar), inY); } /* If to-scroll view is not the active one update its clipping */ else { if(clutter_actor_has_clip(CLUTTER_ACTOR(view))) { clutter_actor_get_clip(CLUTTER_ACTOR(view), &x, &y, &w, &h); if(inX>=0.0f) x=inX; if(inY>=0.0f) y=inY; } else { x=y=0.0f; clutter_actor_get_size(CLUTTER_ACTOR(view), &w, &h); } clutter_actor_set_clip(CLUTTER_ACTOR(view), x, y, w, h); } }
IO_METHOD(IoClutterActor, hasClip) { return IOBOOL(self, clutter_actor_has_clip(IOCACTOR(self))); }
/* Allocate position and size of actor and its children */ static void _xfdashboard_viewpad_allocate(ClutterActor *self, const ClutterActorBox *inBox, ClutterAllocationFlags inFlags) { XfdashboardViewpadPrivate *priv=XFDASHBOARD_VIEWPAD(self)->priv; ClutterActorClass *actorClass=CLUTTER_ACTOR_CLASS(xfdashboard_viewpad_parent_class); gfloat viewWidth, viewHeight; gfloat vScrollbarWidth, vScrollbarHeight; gfloat hScrollbarWidth, hScrollbarHeight; gboolean hScrollbarVisible, vScrollbarVisible; ClutterActorBox *box; gfloat x, y, w, h; /* Chain up to store the allocation of the actor */ if(actorClass->allocate) actorClass->allocate(self, inBox, inFlags); /* Initialize largest possible allocation for view and determine * real size of view to show. The real size is used to determine * scroll bar visibility if policy is automatic */ viewWidth=clutter_actor_box_get_width(inBox); viewHeight=clutter_actor_box_get_height(inBox); /* Determine visibility of scroll bars */ hScrollbarVisible=FALSE; if(priv->hScrollbarPolicy==XFDASHBOARD_POLICY_ALWAYS || (priv->hScrollbarPolicy==XFDASHBOARD_POLICY_AUTOMATIC && xfdashboard_scrollbar_get_range(XFDASHBOARD_SCROLLBAR(priv->hScrollbar))>viewWidth)) { hScrollbarVisible=TRUE; } if(xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_FIT_MODE_HORIZONTAL || xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_FIT_MODE_BOTH) { hScrollbarVisible=FALSE; } vScrollbarVisible=FALSE; if(priv->vScrollbarPolicy==XFDASHBOARD_POLICY_ALWAYS || (priv->vScrollbarPolicy==XFDASHBOARD_POLICY_AUTOMATIC && xfdashboard_scrollbar_get_range(XFDASHBOARD_SCROLLBAR(priv->vScrollbar))>viewHeight)) { vScrollbarVisible=TRUE; } if(xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_FIT_MODE_VERTICAL || xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))==XFDASHBOARD_FIT_MODE_BOTH) { vScrollbarVisible=FALSE; } /* Set allocation for visible scroll bars */ vScrollbarWidth=0.0f; vScrollbarHeight=viewHeight; clutter_actor_get_preferred_width(priv->vScrollbar, -1, NULL, &vScrollbarWidth); hScrollbarWidth=viewWidth; hScrollbarHeight=0.0f; clutter_actor_get_preferred_height(priv->hScrollbar, -1, NULL, &hScrollbarHeight); if(hScrollbarVisible && vScrollbarVisible) { vScrollbarHeight-=hScrollbarHeight; hScrollbarWidth-=vScrollbarWidth; } if(vScrollbarVisible==FALSE) box=clutter_actor_box_new(0, 0, 0, 0); else box=clutter_actor_box_new(viewWidth-vScrollbarWidth, 0, viewWidth, vScrollbarHeight); clutter_actor_allocate(priv->vScrollbar, box, inFlags); clutter_actor_box_free(box); if(hScrollbarVisible==FALSE) box=clutter_actor_box_new(0, 0, 0, 0); else box=clutter_actor_box_new(0, viewHeight-hScrollbarHeight, hScrollbarWidth, viewHeight); clutter_actor_allocate(priv->hScrollbar, box, inFlags); clutter_actor_box_free(box); /* Reduce allocation for view by any visible scroll bar * and set allocation and clipping of view */ if(priv->activeView) { /* Set allocation */ if(vScrollbarVisible) viewWidth-=vScrollbarWidth; if(hScrollbarVisible) viewHeight-=hScrollbarHeight; x=y=0.0f; if(clutter_actor_has_clip(CLUTTER_ACTOR(priv->activeView))) { clutter_actor_get_clip(CLUTTER_ACTOR(priv->activeView), &x, &y, NULL, NULL); } switch(xfdashboard_view_get_fit_mode(XFDASHBOARD_VIEW(priv->activeView))) { case XFDASHBOARD_FIT_MODE_BOTH: w=viewWidth; h=viewHeight; break; case XFDASHBOARD_FIT_MODE_HORIZONTAL: w=viewWidth; clutter_actor_get_preferred_height(CLUTTER_ACTOR(priv->activeView), w, NULL, &h); break; case XFDASHBOARD_FIT_MODE_VERTICAL: h=viewHeight; clutter_actor_get_preferred_width(CLUTTER_ACTOR(priv->activeView), h, NULL, &w); break; default: clutter_actor_get_preferred_size(CLUTTER_ACTOR(priv->activeView), NULL, NULL, &w, &h); break; } box=clutter_actor_box_new(0, 0, w, h); clutter_actor_allocate(CLUTTER_ACTOR(priv->activeView), box, inFlags); clutter_actor_box_free(box); clutter_actor_set_clip(CLUTTER_ACTOR(priv->activeView), x, y, viewWidth, viewHeight); } /* Only set value if it changes */ if(priv->hScrollbarVisible!=hScrollbarVisible) { /* Set new value */ priv->hScrollbarVisible=hScrollbarVisible; /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_HSCROLLBAR_VISIBLE]); } if(priv->vScrollbarVisible!=vScrollbarVisible) { /* Set new value */ priv->vScrollbarVisible=vScrollbarVisible; /* Notify about property change */ g_object_notify_by_pspec(G_OBJECT(self), XfdashboardViewpadProperties[PROP_VSCROLLBAR_VISIBLE]); } }
/* Ensure that a child of a view is visible by scrolling if needed */ static void _xfdashboard_viewpad_on_view_ensure_visible(XfdashboardViewpad *self, ClutterActor *inActor, gpointer inUserData) { XfdashboardViewpadPrivate *priv; XfdashboardView *view; ClutterVertex origin; ClutterVertex transformedUpperLeft; ClutterVertex transformedLowerRight; gfloat x, y, w, h; gboolean needScrolling; g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(self)); g_return_if_fail(CLUTTER_IS_ACTOR(inActor)); g_return_if_fail(XFDASHBOARD_IS_VIEW(inUserData)); priv=self->priv; view=XFDASHBOARD_VIEW(inUserData); needScrolling=FALSE; origin.z=0.0f; /* Get position and size of view but respect scrolled position */ if(view==priv->activeView) { x=xfdashboard_scrollbar_get_value(XFDASHBOARD_SCROLLBAR(priv->hScrollbar)); y=xfdashboard_scrollbar_get_value(XFDASHBOARD_SCROLLBAR(priv->vScrollbar)); clutter_actor_get_size(CLUTTER_ACTOR(self), &w, &h); } else { if(clutter_actor_has_clip(CLUTTER_ACTOR(view))) { clutter_actor_get_clip(CLUTTER_ACTOR(view), &x, &y, &w, &h); } else { x=y=0.0f; clutter_actor_get_size(CLUTTER_ACTOR(view), &w, &h); } } /* Check that upper left point of actor is visible otherwise set flag for scrolling */ origin.x=origin.y=0.0f; clutter_actor_apply_relative_transform_to_point(inActor, CLUTTER_ACTOR(view), &origin, &transformedUpperLeft); if(transformedUpperLeft.x<x || transformedUpperLeft.x>(x+w) || transformedUpperLeft.y<y || transformedUpperLeft.y>(y+h)) { needScrolling=TRUE; } /* Check that lower right point of actor is visible otherwise set flag for scrolling */ clutter_actor_get_size(inActor, &origin.x, &origin.y); clutter_actor_apply_relative_transform_to_point(inActor, CLUTTER_ACTOR(view), &origin, &transformedLowerRight); if(transformedLowerRight.x<x || transformedLowerRight.x>(x+w) || transformedLowerRight.y<y || transformedLowerRight.y>(y+h)) { needScrolling=TRUE; } /* Check if we need to scroll */ if(needScrolling) { gfloat distanceUpperLeft; gfloat distanceLowerRight; /* Find shortest way to scroll and then scroll */ distanceUpperLeft=sqrtf(powf(transformedUpperLeft.x-x, 2.0f)+powf(transformedUpperLeft.y-y, 2.0f)); distanceLowerRight=sqrtf(powf(transformedLowerRight.x-(x+w), 2.0f)+powf(transformedLowerRight.y-(y+h), 2.0f)); if(distanceUpperLeft<=distanceLowerRight) { _xfdashboard_viewpad_on_view_scroll_to(self, transformedUpperLeft.x, transformedUpperLeft.y, view); } else { _xfdashboard_viewpad_on_view_scroll_to(self, transformedUpperLeft.x, transformedLowerRight.y-h, view); } } }