static void child_vadjustment_notify_cb (GObject *gobject, GParamSpec *arg1, gpointer user_data) { MxAdjustment *vadjust; ClutterActor *actor = CLUTTER_ACTOR (gobject); MxScrollViewPrivate *priv = MX_SCROLL_VIEW (user_data)->priv; vadjust = mx_scroll_bar_get_adjustment (MX_SCROLL_BAR(priv->vscroll)); if (vadjust) g_signal_handlers_disconnect_by_func (vadjust, child_adjustment_changed_cb, priv->vscroll); mx_scrollable_get_adjustments (MX_SCROLLABLE(actor), NULL, &vadjust); if (vadjust) { mx_scroll_bar_set_adjustment (MX_SCROLL_BAR(priv->vscroll), vadjust); g_signal_connect (vadjust, "changed", G_CALLBACK ( child_adjustment_changed_cb), priv->vscroll); child_adjustment_changed_cb (vadjust, priv->vscroll); } }
static gboolean mx_scroll_view_gesture_slide_event_cb (ClutterGesture *gesture, ClutterGestureSlideEvent *event, MxScrollView *scrollview) { MxScrollViewPrivate *priv = scrollview->priv; gdouble step, value, final; MxAdjustment *adjustment; ClutterInterval *interval; ClutterTimeline *timeline; if (!priv->enable_gestures) return FALSE; if (!priv->animation) { priv->animation = clutter_animation_new (); clutter_animation_set_duration (priv->animation, 1000); clutter_animation_set_mode (priv->animation, CLUTTER_EASE_OUT_CUBIC); } if (event->direction > 2) adjustment = mx_scroll_bar_get_adjustment (MX_SCROLL_BAR(priv->hscroll)); else adjustment = mx_scroll_bar_get_adjustment (MX_SCROLL_BAR(priv->vscroll)); g_object_get (adjustment, "page-increment", &step, "value", &value, NULL); clutter_animation_set_object (priv->animation, G_OBJECT (adjustment)); if (event->direction % 2) /* up, left (1, 3) */ final = value + step; else /* down, right (2, 4) */ final = value - step;
static void bar_reactive_notify_cb (GObject *gobject, GParamSpec *arg1, gpointer user_data) { MxScrollBar *bar = MX_SCROLL_BAR (gobject); clutter_actor_set_reactive (bar->priv->handle, clutter_actor_get_reactive (CLUTTER_ACTOR (bar))); }
static void mx_scroll_bar_map (ClutterActor *actor) { MxScrollBarPrivate *priv = MX_SCROLL_BAR (actor)->priv; CLUTTER_ACTOR_CLASS (mx_scroll_bar_parent_class)->map (actor); clutter_actor_map (priv->bw_stepper); clutter_actor_map (priv->fw_stepper); clutter_actor_map (priv->trough); if (priv->handle) clutter_actor_map (priv->handle); }
static void mx_scroll_bar_style_changed (MxWidget *widget, MxStyleChangedFlags flags) { MxScrollBarPrivate *priv = MX_SCROLL_BAR (widget)->priv; mx_stylable_get (MX_STYLABLE (widget), "mx-min-size", &priv->handle_min_size, NULL); mx_stylable_style_changed ((MxStylable *) priv->bw_stepper, flags); mx_stylable_style_changed ((MxStylable *) priv->fw_stepper, flags); mx_stylable_style_changed ((MxStylable *) priv->trough, flags); mx_stylable_style_changed ((MxStylable *) priv->handle, flags); }
static void mx_scroll_bar_pick (ClutterActor *actor, const ClutterColor *pick_color) { MxScrollBarPrivate *priv = MX_SCROLL_BAR (actor)->priv; CLUTTER_ACTOR_CLASS (mx_scroll_bar_parent_class)->pick (actor, pick_color); clutter_actor_paint (priv->bw_stepper); clutter_actor_paint (priv->fw_stepper); clutter_actor_paint (priv->trough); if (priv->handle && priv->adjustment) clutter_actor_paint (priv->handle); }
static void mx_scroll_bar_get_preferred_height (ClutterActor *actor, gfloat for_width, gfloat *min_height, gfloat *pref_height) { MxScrollBarPrivate *priv = MX_SCROLL_BAR (actor)->priv; MxPadding padding; gfloat height; mx_widget_get_padding (MX_WIDGET (actor), &padding); if (priv->orientation == MX_ORIENTATION_HORIZONTAL) { gfloat bg_h, h_h, bs_h, fs_h; clutter_actor_get_preferred_height (priv->bw_stepper, -1, NULL, &bs_h); clutter_actor_get_preferred_height (priv->fw_stepper, -1, NULL, &fs_h); clutter_actor_get_preferred_height (priv->trough, -1, NULL, &bg_h); clutter_actor_get_preferred_height (priv->handle, -1, NULL, &h_h); h_h += padding.top + padding.bottom; bs_h += padding.top + padding.bottom; fs_h += padding.top + padding.bottom; height = MAX (bg_h, MAX (h_h, MAX (bs_h, fs_h))); } else { gfloat fs_h, bs_h; clutter_actor_get_preferred_height (priv->bw_stepper, -1, NULL, &bs_h); clutter_actor_get_preferred_height (priv->fw_stepper, -1, NULL, &fs_h); height = padding.top + fs_h + priv->handle_min_size + bs_h + padding.bottom; } if (min_height) *min_height = height; if (pref_height) *pref_height = height; }
static void mx_scroll_bar_get_preferred_width (ClutterActor *actor, gfloat for_height, gfloat *min_width, gfloat *pref_width) { MxScrollBarPrivate *priv = MX_SCROLL_BAR (actor)->priv; MxPadding padding; gfloat width; mx_widget_get_padding (MX_WIDGET (actor), &padding); if (priv->orientation == MX_ORIENTATION_VERTICAL) { gfloat bg_w, h_w, bs_w, fs_w; clutter_actor_get_preferred_width (priv->bw_stepper, -1, NULL, &bs_w); clutter_actor_get_preferred_width (priv->fw_stepper, -1, NULL, &fs_w); clutter_actor_get_preferred_width (priv->trough, -1, NULL, &bg_w); clutter_actor_get_preferred_width (priv->handle, -1, NULL, &h_w); h_w += padding.left + padding.right; bs_w += padding.left + padding.right; fs_w += padding.left + padding.right; width = MAX (bg_w, MAX (h_w, MAX (bs_w, fs_w))); } else { gfloat fs_w, bs_w; clutter_actor_get_preferred_width (priv->bw_stepper, -1, NULL, &bs_w); clutter_actor_get_preferred_width (priv->fw_stepper, -1, NULL, &fs_w); width = padding.left + fs_w + priv->handle_min_size + bs_w + padding.right; } if (min_width) *min_width = width; if (pref_width) *pref_width = width; }
static void mx_scroll_bar_apply_style (MxWidget *widget, MxStyle *style) { MxScrollBarPrivate *priv = MX_SCROLL_BAR (widget)->priv; if (priv->bw_stepper != NULL) mx_stylable_set_style (MX_STYLABLE (priv->bw_stepper), style); if (priv->fw_stepper != NULL) mx_stylable_set_style (MX_STYLABLE (priv->fw_stepper), style); if (priv->trough != NULL) mx_stylable_set_style (MX_STYLABLE (priv->trough), style); if (priv->handle != NULL) mx_stylable_set_style (MX_STYLABLE (priv->handle), style); }
static gboolean mx_scroll_bar_scroll_event (ClutterActor *actor, ClutterScrollEvent *event) { MxScrollBarPrivate *priv = MX_SCROLL_BAR (actor)->priv; gdouble lower, step, upper, value; if (priv->adjustment) { g_object_get (priv->adjustment, "lower", &lower, "step-increment", &step, "upper", &upper, "value", &value, NULL); } else { return FALSE; } switch (event->direction) { case CLUTTER_SCROLL_UP: case CLUTTER_SCROLL_LEFT: if (value == lower) return FALSE; else mx_adjustment_interpolate_relative (priv->adjustment, -step, 250, CLUTTER_EASE_OUT_CUBIC); break; case CLUTTER_SCROLL_DOWN: case CLUTTER_SCROLL_RIGHT: if (value == upper) return FALSE; else mx_adjustment_interpolate_relative (priv->adjustment, step, 250, CLUTTER_EASE_OUT_CUBIC); break; } return TRUE; }
static GObject* mx_scroll_bar_constructor (GType type, guint n_properties, GObjectConstructParam *properties) { GObjectClass *gobject_class; GObject *obj; MxScrollBar *bar; gobject_class = G_OBJECT_CLASS (mx_scroll_bar_parent_class); obj = gobject_class->constructor (type, n_properties, properties); bar = MX_SCROLL_BAR (obj); g_signal_connect (bar, "notify::reactive", G_CALLBACK (bar_reactive_notify_cb), NULL); return obj; }
static void mx_scroll_bar_dispose (GObject *gobject) { MxScrollBar *bar = MX_SCROLL_BAR (gobject); MxScrollBarPrivate *priv = bar->priv; if (priv->adjustment) mx_scroll_bar_set_adjustment (bar, NULL); if (priv->handle) { g_signal_handlers_disconnect_by_func (priv->handle, G_CALLBACK (handle_button_press_event_cb), bar); clutter_actor_unparent (priv->handle); priv->handle = NULL; } if (priv->bw_stepper) { clutter_actor_unparent (priv->bw_stepper); priv->bw_stepper = NULL; } if (priv->fw_stepper) { clutter_actor_unparent (priv->fw_stepper); priv->fw_stepper = NULL; } if (priv->trough) { clutter_actor_unparent (priv->trough); priv->trough = NULL; } G_OBJECT_CLASS (mx_scroll_bar_parent_class)->dispose (gobject); }
static void mx_scroll_bar_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { MxScrollBar *bar = MX_SCROLL_BAR (gobject); switch (prop_id) { case PROP_ADJUSTMENT: mx_scroll_bar_set_adjustment (bar, g_value_get_object (value)); break; case PROP_ORIENTATION: mx_scroll_bar_set_orientation (bar, g_value_get_enum (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } }
static void mx_scroll_bar_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { MxScrollBarPrivate *priv = MX_SCROLL_BAR (gobject)->priv; switch (prop_id) { case PROP_ADJUSTMENT: g_value_set_object (value, priv->adjustment); break; case PROP_ORIENTATION: g_value_set_enum (value, priv->orientation); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } }
static void mx_scroll_view_paint (ClutterActor *actor) { ClutterActorBox box; gfloat w, h; MxAdjustment *vadjustment = NULL, *hadjustment = NULL; MxScrollViewPrivate *priv = MX_SCROLL_VIEW (actor)->priv; ClutterColor *color; guint8 r, g, b; const gint shadow = 15; mx_stylable_get (MX_STYLABLE (actor), "background-color", &color, NULL); r = color->red; g = color->green; b = color->blue; clutter_color_free (color); /* MxBin will paint the child */ CLUTTER_ACTOR_CLASS (mx_scroll_view_parent_class)->paint (actor); clutter_actor_get_allocation_box (actor, &box); w = box.x2 - box.x1; h = box.y2 - box.y1; /* paint our custom children */ if (CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll)) { clutter_actor_paint (priv->hscroll); clutter_actor_get_allocation_box (priv->hscroll, &box); h -= (box.y2 - box.y1); hadjustment = mx_scroll_bar_get_adjustment (MX_SCROLL_BAR(priv->hscroll)); } if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll)) { clutter_actor_paint (priv->vscroll); clutter_actor_get_allocation_box (priv->vscroll, &box); w -= (box.x2 - box.x1); vadjustment = mx_scroll_bar_get_adjustment (MX_SCROLL_BAR(priv->vscroll)); } /* set up the matrial using dummy set source call */ cogl_set_source_color4ub (0, 0, 0, 0); if (vadjustment) { gdouble len; if ((len = mx_adjustment_get_value (vadjustment)) > 0) { CoglTextureVertex top[4] = { { 0,}, }; if (len > shadow) len = shadow; top[1].x = w; top[2].x = w; top[2].y = len; top[3].y = len; cogl_color_set_from_4ub (&top[0].color, r, g, b, 0xff); cogl_color_set_from_4ub (&top[1].color, r, g, b, 0xff); cogl_color_set_from_4ub (&top[2].color, 0, 0, 0, 0); cogl_color_set_from_4ub (&top[3].color, 0, 0, 0, 0); cogl_polygon (top, 4, TRUE); } if ((len = (mx_adjustment_get_upper (vadjustment) - mx_adjustment_get_page_size (vadjustment)) - mx_adjustment_get_value (vadjustment)) > 0) { CoglTextureVertex bottom[4] = { {0, }, }; if (len > shadow) len = shadow; bottom[0].x = w; bottom[0].y = h; bottom[1].y = h; bottom[2].y = h - len; bottom[3].x = w; bottom[3].y = h - len; cogl_color_set_from_4ub (&bottom[0].color, r, g, b, 0xff); cogl_color_set_from_4ub (&bottom[1].color, r, g, b, 0xff); cogl_color_set_from_4ub (&bottom[2].color, 0, 0, 0, 0); cogl_color_set_from_4ub (&bottom[3].color, 0, 0, 0, 0); cogl_polygon (bottom, 4, TRUE); } } if (hadjustment) { gdouble len; if ((len = mx_adjustment_get_value (hadjustment)) > 0) { CoglTextureVertex left[4] = { { 0, }, }; if (len > shadow) len = shadow; left[0].y = h; left[2].x = len; left[3].x = len; left[3].y = h; cogl_color_set_from_4ub (&left[0].color, r, g, b, 0xff); cogl_color_set_from_4ub (&left[1].color, r, g, b, 0xff); cogl_color_set_from_4ub (&left[2].color, 0, 0, 0, 0); cogl_color_set_from_4ub (&left[3].color, 0, 0, 0, 0); cogl_polygon (left, 4, TRUE); } if ((len = (mx_adjustment_get_upper (hadjustment) - mx_adjustment_get_page_size (hadjustment)) - mx_adjustment_get_value (hadjustment)) > 0) { CoglTextureVertex right[4] = { { 0, }, }; if (len > shadow) len = shadow; right[0].x = w; right[1].x = w; right[1].y = h; right[2].x = w - len; right[2].y = h; right[3].x = w - len; cogl_color_set_from_4ub (&right[0].color, r, g, b, 0xff); cogl_color_set_from_4ub (&right[1].color, r, g, b, 0xff); cogl_color_set_from_4ub (&right[2].color, 0, 0, 0, 0); cogl_color_set_from_4ub (&right[3].color, 0, 0, 0, 0); cogl_polygon (right, 4, TRUE); } } }
static void mx_scroll_bar_allocate (ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags) { MxScrollBarPrivate *priv = MX_SCROLL_BAR (actor)->priv; MxPadding padding; ClutterActorBox bw_box, fw_box, trough_box; gfloat x, y, width, height, stepper_size; /* Chain up */ CLUTTER_ACTOR_CLASS (mx_scroll_bar_parent_class)->allocate (actor, box, flags); mx_widget_get_padding (MX_WIDGET (actor), &padding); /* calculate the child area */ x = padding.left; y = padding.top; width = (box->x2 - box->x1) - padding.left - padding.right; height = (box->y2 - box->y1) - padding.top - padding.bottom; if (priv->orientation == MX_ORIENTATION_VERTICAL) { stepper_size = width; /* Backward stepper */ bw_box.x1 = x; bw_box.y1 = y; bw_box.x2 = bw_box.x1 + stepper_size; bw_box.y2 = bw_box.y1 + stepper_size; clutter_actor_allocate (priv->bw_stepper, &bw_box, flags); /* Forward stepper */ fw_box.x1 = x; fw_box.y1 = y + height - stepper_size; fw_box.x2 = fw_box.x1 + stepper_size; fw_box.y2 = fw_box.y1 + stepper_size; clutter_actor_allocate (priv->fw_stepper, &fw_box, flags); /* Trough */ trough_box.x1 = x; trough_box.y1 = y + stepper_size; trough_box.x2 = x + width; trough_box.y2 = y + height - stepper_size; clutter_actor_allocate (priv->trough, &trough_box, flags); } else { stepper_size = height; /* Backward stepper */ bw_box.x1 = x; bw_box.y1 = y; bw_box.x2 = bw_box.x1 + stepper_size; bw_box.y2 = bw_box.y1 + stepper_size; clutter_actor_allocate (priv->bw_stepper, &bw_box, flags); /* Forward stepper */ fw_box.x1 = x + width - stepper_size; fw_box.y1 = y; fw_box.x2 = fw_box.x1 + stepper_size; fw_box.y2 = fw_box.y1 + stepper_size; clutter_actor_allocate (priv->fw_stepper, &fw_box, flags); /* Trough */ trough_box.x1 = x + stepper_size; trough_box.y1 = y; trough_box.x2 = x + width - stepper_size; trough_box.y2 = y + height; clutter_actor_allocate (priv->trough, &trough_box, flags); } if (priv->adjustment) { gfloat handle_size, position, avail_size, handle_pos; gdouble value, lower, upper, page_size, increment; ClutterActorBox handle_box = { 0, }; guint min_size, max_size; mx_adjustment_get_values (priv->adjustment, &value, &lower, &upper, NULL, NULL, &page_size); value = mx_adjustment_get_value (priv->adjustment); if ((upper == lower) || (page_size >= (upper - lower))) increment = 1.0; else increment = page_size / (upper - lower); min_size = priv->handle_min_size; mx_stylable_get (MX_STYLABLE (actor), "mx-max-size", &max_size, NULL); if (upper - lower - page_size <= 0) position = 0; else position = (value - lower) / (upper - lower - page_size); if (priv->orientation == MX_ORIENTATION_VERTICAL) { avail_size = height - stepper_size * 2; handle_size = increment * avail_size; handle_size = CLAMP (handle_size, min_size, max_size); handle_box.x1 = x; handle_pos = bw_box.y2 + position * (avail_size - handle_size); handle_box.y1 = CLAMP (handle_pos, bw_box.y2, fw_box.y1 - min_size); handle_box.x2 = handle_box.x1 + width; handle_box.y2 = CLAMP (handle_pos + handle_size, bw_box.y2 + min_size, fw_box.y1); } else { avail_size = width - stepper_size * 2; handle_size = increment * avail_size; handle_size = CLAMP (handle_size, min_size, max_size); handle_pos = bw_box.x2 + position * (avail_size - handle_size); handle_box.x1 = CLAMP (handle_pos, bw_box.x2, fw_box.x1 - min_size); handle_box.y1 = y; handle_box.x2 = CLAMP (handle_pos + handle_size, bw_box.x2 + min_size, fw_box.x1); handle_box.y2 = handle_box.y1 + height; } /* snap to pixel */ handle_box.x1 = (int) handle_box.x1; handle_box.y1 = (int) handle_box.y1; handle_box.x2 = (int) handle_box.x2; handle_box.y2 = (int) handle_box.y2; clutter_actor_allocate (priv->handle, &handle_box, flags); } }
static gboolean mx_scroll_view_scroll_event (ClutterActor *self, ClutterScrollEvent *event) { MxScrollViewPrivate *priv = MX_SCROLL_VIEW (self)->priv; gdouble lower, value, upper, step; MxAdjustment *vadjustment, *hadjustment; /* don't handle scroll events if requested not to */ if (!priv->mouse_scroll) return FALSE; hadjustment = mx_scroll_bar_get_adjustment (MX_SCROLL_BAR(priv->hscroll)); vadjustment = mx_scroll_bar_get_adjustment (MX_SCROLL_BAR(priv->vscroll)); switch (event->direction) { case CLUTTER_SCROLL_UP: case CLUTTER_SCROLL_DOWN: if (vadjustment) g_object_get (vadjustment, "lower", &lower, "step-increment", &step, "value", &value, "upper", &upper, NULL); else return FALSE; break; case CLUTTER_SCROLL_LEFT: case CLUTTER_SCROLL_RIGHT: if (hadjustment) g_object_get (hadjustment, "lower", &lower, "step-increment", &step, "value", &value, "upper", &upper, NULL); else return FALSE; break; } switch (event->direction) { case CLUTTER_SCROLL_UP: if (value == lower) return FALSE; else mx_adjustment_interpolate_relative (vadjustment, -step, 250, CLUTTER_EASE_OUT_CUBIC); break; case CLUTTER_SCROLL_DOWN: if (value == upper) return FALSE; else mx_adjustment_interpolate_relative (vadjustment, step, 250, CLUTTER_EASE_OUT_CUBIC); break; case CLUTTER_SCROLL_LEFT: if (value == lower) return FALSE; else mx_adjustment_interpolate_relative (hadjustment, -step, 250, CLUTTER_EASE_OUT_CUBIC); break; case CLUTTER_SCROLL_RIGHT: if (value == upper) return FALSE; else mx_adjustment_interpolate_relative (hadjustment, step, 250, CLUTTER_EASE_OUT_CUBIC); break; } return TRUE; }