static void mx_expander_get_preferred_height (ClutterActor *actor, gfloat for_width, gfloat *min_height, gfloat *pref_height) { MxExpanderPrivate *priv = MX_EXPANDER (actor)->priv; ClutterActor *child; MxPadding padding; gfloat min_child_h, pref_child_h, min_label_h, pref_label_h, arrow_h; gfloat available_w; child = mx_bin_get_child (MX_BIN (actor)); mx_widget_get_padding (MX_WIDGET (actor), &padding); available_w = for_width - padding.left - padding.right; if (child) { clutter_actor_get_preferred_height (child, available_w, &min_child_h, &pref_child_h); min_child_h += priv->spacing; pref_child_h += priv->spacing; /* allocate the space multiplied by the progress of the "expansion" * animation */ min_child_h *= priv->progress; pref_child_h *= priv->progress; } else { min_child_h = 0; pref_child_h = 0; } clutter_actor_get_preferred_height (priv->label, available_w, &min_label_h, &pref_label_h); clutter_actor_get_preferred_height (priv->arrow, -1, NULL, &arrow_h); min_label_h = MAX (min_label_h, arrow_h); pref_label_h = MAX (pref_label_h, arrow_h); if (min_height) *min_height = padding.top + min_child_h + min_label_h + padding.bottom; if (pref_height) *pref_height = padding.top + pref_child_h + pref_label_h + padding.bottom; }
static void mx_expander_foreach (ClutterContainer *container, ClutterCallback callback, gpointer user_data) { ClutterActor *child; child = mx_bin_get_child (MX_BIN (container)); if (child) callback (child, user_data); }
static void tile_created_cb (MexProxy *proxy, GObject *content, GObject *object, gpointer controls) { const gchar *mime_type; ClutterEffect *effect; ClutterColor color = { 0, 0, 0, 60 }; /* filter out folders */ mime_type = mex_content_get_metadata (MEX_CONTENT (content), MEX_CONTENT_METADATA_MIMETYPE); if (g_strcmp0 (mime_type, "x-grl/box") == 0) { g_signal_stop_emission_by_name (proxy, "object-created"); return; } mex_tile_set_important (MEX_TILE (object), TRUE); clutter_actor_set_reactive (CLUTTER_ACTOR (object), TRUE); g_object_set (object, "thumb-height", 140, "thumb-width", 250, NULL); g_signal_connect (object, "key-press-event", G_CALLBACK (key_press_event_cb), controls); g_signal_connect (object, "button-release-event", G_CALLBACK (button_release_event_cb), controls); effect = g_object_new (MEX_TYPE_SHADOW, "radius-x", 15, "radius-y", 15, "color", &color, "enabled", FALSE, NULL); clutter_actor_add_effect_with_name (CLUTTER_ACTOR (object), "shadow", effect); effect = g_object_new (MEX_TYPE_SHADOW, "radius-x", 15, "radius-y", 15, "color", &color, NULL); clutter_actor_add_effect_with_name (mx_bin_get_child (MX_BIN (object)), "shadow", effect); g_signal_connect (object, "focus-in", G_CALLBACK (tile_focus_in_cb), NULL); g_signal_connect (object, "focus-out", G_CALLBACK (tile_focus_out_cb), NULL); tile_focus_out_cb (MX_BIN (object)); }
static void tile_focus_in_cb (MxBin *actor) { ClutterActorMeta *shadow; shadow = (ClutterActorMeta*) clutter_actor_get_effect (CLUTTER_ACTOR (actor), "shadow"); clutter_actor_meta_set_enabled (shadow, TRUE); shadow = (ClutterActorMeta*) clutter_actor_get_effect (mx_bin_get_child (actor), "shadow"); clutter_actor_meta_set_enabled (shadow, FALSE); }
static void update_playing (MxButton *button, gboolean playing) { ClutterActor *child; child = mx_bin_get_child (MX_BIN (button)); if (playing) { mx_stylable_set_style_class (MX_STYLABLE (button), "PauseButton"); mx_icon_set_icon_name (MX_ICON (child), "media-playback-pause"); } else { mx_stylable_set_style_class (MX_STYLABLE (button), "PlayButton"); mx_icon_set_icon_name (MX_ICON (child), "media-playback-start"); } /* stop button? meh */ }
static void mx_expander_get_preferred_width (ClutterActor *actor, gfloat for_height, gfloat *min_width, gfloat *pref_width) { MxExpanderPrivate *priv = MX_EXPANDER (actor)->priv; ClutterActor *child; MxPadding padding; gfloat min_child_w, pref_child_w, min_label_w, pref_label_w, arrow_w; child = mx_bin_get_child (MX_BIN (actor)); mx_widget_get_padding (MX_WIDGET (actor), &padding); if (child) { clutter_actor_get_preferred_width (child, -1, &min_child_w, &pref_child_w); } else { min_child_w = 0; pref_child_w = 0; } clutter_actor_get_preferred_width (priv->label, -1, &min_label_w, &pref_label_w); clutter_actor_get_preferred_width (priv->arrow, -1, NULL, &arrow_w); /* TODO: create a style property for this padding between arrow and label */ if (arrow_w) arrow_w += 6.0f; if (min_width) *min_width = padding.left + MAX (min_child_w, min_label_w + arrow_w) + padding.right; if (pref_width) *pref_width = padding.left + MAX (pref_child_w, pref_label_w + arrow_w) + padding.right; }
static void timeline_complete (ClutterTimeline *timeline, ClutterActor *expander) { guchar opacity; ClutterActor *child; MxExpanderPrivate *priv = MX_EXPANDER (expander)->priv; g_signal_emit (expander, expander_signals[EXPAND_COMPLETE], 0); /* if the expander is now closed, update the style */ if (!priv->expanded) { clutter_actor_set_name (priv->arrow, "mx-expander-arrow-closed"); mx_stylable_set_style_class (MX_STYLABLE (expander), "closed-expander"); clutter_actor_queue_relayout (expander); } child = mx_bin_get_child (MX_BIN (expander)); if (!child) return; /* continue only if we are "opening" */ if (!priv->expanded) return; /* we can't do an animation if there is already one in progress, * because we cannot get the actors original opacity */ if (clutter_actor_get_animation (child)) { clutter_actor_show (child); return; } opacity = clutter_actor_get_opacity (child); clutter_actor_set_opacity (child, 0); clutter_actor_show (child); clutter_actor_animate (child, CLUTTER_EASE_IN_SINE, 100, "opacity", opacity, NULL); }
static void mx_expander_add (ClutterContainer *container, ClutterActor *actor) { MxExpander *expander = MX_EXPANDER (container); MxExpanderPrivate *priv = expander->priv; /* Override the container add method so we can hide the actor if the expander is not expanded */ /* chain up */ container_parent_class->add (container, actor); if (!priv->expanded) { actor = mx_bin_get_child (MX_BIN (container)); if (actor) clutter_actor_hide (actor); } }
static void mx_expander_update (MxExpander *expander) { MxExpanderPrivate *priv = expander->priv; ClutterActor *child; if (priv->expanded) { clutter_actor_set_name (priv->arrow, "mx-expander-arrow-open"); mx_stylable_set_style_class (MX_STYLABLE (expander), "open-expander"); } /* closed state is set when animation is finished */ child = mx_bin_get_child (MX_BIN (expander)); if (!child) return; /* setup and start the expansion animation */ if (!priv->expanded) { clutter_actor_hide (child); clutter_timeline_set_direction (priv->timeline, CLUTTER_TIMELINE_BACKWARD); } else { clutter_timeline_set_direction (priv->timeline, CLUTTER_TIMELINE_FORWARD); } if (!clutter_timeline_is_playing (priv->timeline)) clutter_timeline_rewind (priv->timeline); clutter_timeline_start (priv->timeline); }
static void mx_button_update_contents (MxButton *self) { MxButtonPrivate *priv = self->priv; ClutterActor *child; gboolean icon_visible, label_visible; const gchar *text; /* If the icon doesn't have a name set, treat it as * not-visible. */ if (priv->icon_visible && mx_icon_get_icon_name (MX_ICON (priv->icon))) icon_visible = TRUE; else icon_visible = FALSE; text = clutter_text_get_text (CLUTTER_TEXT (priv->label)); if (priv->label_visible && text && (strcmp (text, "") != 0)) label_visible = TRUE; else label_visible = FALSE; /* replace any custom content */ child = mx_bin_get_child (MX_BIN (self)); if (child != priv->hbox) mx_bin_set_child (MX_BIN (self), priv->hbox); /* Handle the simple cases first */ if (!icon_visible && !label_visible) { clutter_actor_hide (priv->hbox); return; } /* ensure the hbox is visible */ clutter_actor_show (priv->hbox); if (icon_visible && !label_visible) { clutter_actor_show (priv->icon); clutter_actor_hide (priv->label); clutter_actor_set_child_below_sibling (priv->hbox, priv->icon, NULL); return; } if (!icon_visible && label_visible) { clutter_actor_hide (priv->icon); clutter_actor_show (priv->label); clutter_actor_set_child_below_sibling (priv->hbox, priv->label, NULL); return; } /* Both the icon and text are visible, handle this case */ clutter_actor_show (priv->icon); clutter_actor_show (priv->label); switch (priv->icon_position) { case MX_POSITION_TOP: mx_box_layout_set_orientation (MX_BOX_LAYOUT (priv->hbox), MX_ORIENTATION_VERTICAL); clutter_actor_set_child_below_sibling (priv->hbox, priv->icon, NULL); clutter_container_child_set (CLUTTER_CONTAINER (priv->hbox), priv->label, "x-align", MX_ALIGN_MIDDLE, "y-align", MX_ALIGN_END, NULL); clutter_container_child_set (CLUTTER_CONTAINER (priv->hbox), priv->icon, "x-align", MX_ALIGN_MIDDLE, "y-align", MX_ALIGN_START, NULL); break; case MX_POSITION_RIGHT: mx_box_layout_set_orientation (MX_BOX_LAYOUT (priv->hbox), MX_ORIENTATION_HORIZONTAL); clutter_actor_set_child_above_sibling (priv->hbox, priv->icon, NULL); clutter_container_child_set (CLUTTER_CONTAINER (priv->hbox), priv->label, "x-align", MX_ALIGN_START, "y-align", MX_ALIGN_MIDDLE, NULL); clutter_container_child_set (CLUTTER_CONTAINER (priv->hbox), priv->icon, "x-align", MX_ALIGN_END, "y-align", MX_ALIGN_MIDDLE, NULL); break; case MX_POSITION_BOTTOM: mx_box_layout_set_orientation (MX_BOX_LAYOUT (priv->hbox), MX_ORIENTATION_VERTICAL); clutter_actor_set_child_above_sibling (priv->hbox, priv->icon, NULL); mx_box_layout_child_set_x_align (MX_BOX_LAYOUT (priv->hbox), priv->label, MX_ALIGN_MIDDLE); clutter_container_child_set (CLUTTER_CONTAINER (priv->hbox), priv->label, "x-align", MX_ALIGN_MIDDLE, "y-align", MX_ALIGN_START, NULL); clutter_container_child_set (CLUTTER_CONTAINER (priv->hbox), priv->icon, "x-align", MX_ALIGN_MIDDLE, "y-align", MX_ALIGN_END, NULL); break; case MX_POSITION_LEFT: mx_box_layout_set_orientation (MX_BOX_LAYOUT (priv->hbox), MX_ORIENTATION_HORIZONTAL); clutter_actor_set_child_below_sibling (priv->hbox, priv->icon, NULL); clutter_container_child_set (CLUTTER_CONTAINER (priv->hbox), priv->label, "x-align", MX_ALIGN_END, "y-align", MX_ALIGN_MIDDLE, NULL); clutter_container_child_set (CLUTTER_CONTAINER (priv->hbox), priv->icon, "x-align", MX_ALIGN_START, "y-align", MX_ALIGN_MIDDLE, NULL); break; } }
static void mx_viewport_allocate (ClutterActor *self, const ClutterActorBox *box, ClutterAllocationFlags flags) { MxViewportPrivate *priv = MX_VIEWPORT (self)->priv; MxPadding padding; ClutterActor *child; gfloat width, height; gfloat available_width, available_height; /* Chain up. */ CLUTTER_ACTOR_CLASS (mx_viewport_parent_class)-> allocate (self, box, flags); mx_widget_get_padding (MX_WIDGET (self), &padding); available_width = box->x2 - box->x1 - padding.left - padding.right; available_height = box->y2 - box->y1 - padding.top - padding.bottom; child = mx_bin_get_child (MX_BIN (self)); if (child) { gfloat natural_width, natural_height; ClutterActorBox child_box; MxAlign x_align, y_align; gboolean x_fill, y_fill; clutter_actor_get_preferred_size (child, NULL, NULL, &natural_width, &natural_height); mx_bin_get_fill (MX_BIN (self), &x_fill, &y_fill); if (x_fill && (available_width > natural_width)) width = available_width; else width = natural_width; if (y_fill && (available_height > natural_height)) height = available_height; else height = natural_height; mx_bin_get_alignment (MX_BIN (self), &x_align, &y_align); if (!x_fill && width < available_width) { switch (x_align) { case MX_ALIGN_START: child_box.x1 = padding.left; break; case MX_ALIGN_MIDDLE: child_box.x1 = padding.left + (available_width - width) / 2.f; break; case MX_ALIGN_END: child_box.x1 = box->x2 - box->x1 - padding.right - width; break; } } else child_box.x1 = padding.left; if (!y_fill && height < available_height) { switch (y_align) { case MX_ALIGN_START: child_box.y1 = padding.top; break; case MX_ALIGN_MIDDLE: child_box.y1 = padding.top + (available_height - height) / 2.f; break; case MX_ALIGN_END: child_box.y1 = box->y2 - box->y1 - padding.bottom - height; break; } } else child_box.y1 = padding.top; child_box.x2 = child_box.x1 + width; child_box.y2 = child_box.y1 + height; clutter_actor_allocate (child, &child_box, flags); } else { width = 0; height = 0; } /* Refresh adjustments */ if (priv->sync_adjustments) { if (priv->hadjustment) { g_object_set (G_OBJECT (priv->hadjustment), "lower", 0.0, "page-size", available_width, "upper", width, "page-increment", available_width / 3, "step-increment", available_width / 12, NULL); } if (priv->vadjustment) { g_object_set (G_OBJECT (priv->vadjustment), "lower", 0.0, "page-size", available_height, "upper", height, "page-increment", available_height / 3, "step-increment", available_height / 12, NULL); } } }
static void mex_media_controls_init (MexMediaControls *self) { ClutterActor *actor; ClutterScript *script; GError *err = NULL; MxAdjustment *adjustment; ClutterActor *related_box; gchar *tmp; MexMediaControlsPrivate *priv = self->priv = MEDIA_CONTROLS_PRIVATE (self); priv->script = script = clutter_script_new (); tmp = g_build_filename (mex_get_data_dir (), "json", "media-controls.json", NULL); clutter_script_load_from_file (script, tmp, &err); g_free (tmp); if (err) g_error ("Could not load media controls interface: %s", err->message); priv->vbox = (ClutterActor*) clutter_script_get_object (script, "media-controls"); clutter_actor_set_parent (priv->vbox, CLUTTER_ACTOR (self)); /* add shadow to media controls box */ actor = (ClutterActor *) clutter_script_get_object (script, "media-controls-box"); clutter_actor_add_effect (actor, CLUTTER_EFFECT (mex_shadow_new ())); /* vertical fade effect */ priv->vertical_effect = mx_fade_effect_new (); clutter_actor_add_effect (priv->vbox, priv->vertical_effect); mx_scrollable_get_adjustments (MX_SCROLLABLE (mx_bin_get_child (MX_BIN (priv->vbox))), NULL, &adjustment); g_signal_connect (adjustment, "changed", G_CALLBACK (notify_vertical_changed_cb), self); g_signal_connect (adjustment, "notify::value", G_CALLBACK (notify_vertical_value_cb), self); /* horizontal fade effect */ priv->horizontal_effect = mx_fade_effect_new (); related_box = (ClutterActor *) clutter_script_get_object (priv->script, "related-box"); clutter_actor_add_effect (related_box, priv->horizontal_effect); mx_scrollable_get_adjustments (MX_SCROLLABLE (related_box), &adjustment, NULL); g_signal_connect (adjustment, "changed", G_CALLBACK (notify_horizontal_changed_cb), self); g_signal_connect (adjustment, "notify::value", G_CALLBACK (notify_horizontal_value_cb), self); /* slider setup */ priv->slider = (ClutterActor*) clutter_script_get_object (script, "slider"); g_signal_connect (priv->slider, "notify::value", G_CALLBACK (slider_value_changed_cb), self); g_signal_connect (priv->slider, "captured-event", G_CALLBACK (slider_captured_event), self); priv->play_pause_action = (MxAction*) clutter_script_get_object (script, "play-pause-action"); priv->stop_action = (MxAction*) clutter_script_get_object (script, "stop-action"); priv->add_to_queue_action = (MxAction*) clutter_script_get_object (script, "add-to-queue-action"); priv->queue_button = (ClutterActor *) clutter_script_get_object (script, "add-to-queue-button"); g_signal_connect (priv->play_pause_action, "activated", G_CALLBACK (mex_media_controls_play_cb), self); g_signal_connect (priv->stop_action, "activated", G_CALLBACK (mex_media_controls_stop_cb), self); #if 0 g_signal_connect (priv->add_to_queue_action, "activated", G_CALLBACK (mex_media_controls_add_to_queue_cb), self); #endif /* proxy setup */ priv->proxy_model = MEX_VIEW_MODEL (mex_view_model_new (NULL)); /* FIXME: Set an arbitrary 200-item limit as we can't handle large * amounts of actors without massive slow-down. */ mex_view_model_set_limit (priv->proxy_model, 200); priv->proxy = mex_content_proxy_new (MEX_MODEL (priv->proxy_model), CLUTTER_CONTAINER (related_box), MEX_TYPE_CONTENT_TILE); g_signal_connect (priv->proxy, "object-created", G_CALLBACK (tile_created_cb), self); priv->is_disabled = TRUE; }
static void mx_expander_allocate (ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags) { ClutterActor *child; MxExpanderPrivate *priv = MX_EXPANDER (actor)->priv; ClutterActorBox child_box; MxPadding padding; gfloat label_w, label_h; gfloat available_w, available_h, min_w, min_h, arrow_h, arrow_w; MxAlign x_align, y_align; gboolean x_fill, y_fill; /* chain up to store allocation */ CLUTTER_ACTOR_CLASS (mx_expander_parent_class)->allocate (actor, box, flags); mx_widget_get_padding (MX_WIDGET (actor), &padding); g_object_get (G_OBJECT (actor), "x-align", &x_align, "y-align", &y_align, "x-fill", &x_fill, "y-fill", &y_fill, NULL); available_w = (box->x2 - box->x1) - padding.left - padding.right; available_h = (box->y2 - box->y1) - padding.top - padding.bottom; /* arrow */ clutter_actor_get_preferred_width (priv->arrow, -1, NULL, &arrow_w); arrow_w = MIN (arrow_w, available_w); clutter_actor_get_preferred_height (priv->arrow, -1, NULL, &arrow_h); arrow_h = MIN (arrow_h, available_h); child_box.x1 = padding.left; child_box.x2 = child_box.x1 + arrow_w; child_box.y1 = padding.top; child_box.y2 = child_box.y1 + arrow_h; clutter_actor_allocate (priv->arrow, &child_box, flags); /* label */ min_h = 0; min_w = 0; clutter_actor_get_preferred_width (priv->label, available_h, &min_w, &label_w); label_w = CLAMP (label_w, min_w, available_w); clutter_actor_get_preferred_height (priv->label, label_w, &min_h, &label_h); label_h = CLAMP (label_h, min_h, available_h); /* TODO: make a style property for padding between arrow and label */ child_box.x1 = padding.left + arrow_w + 6.0f; child_box.x2 = child_box.x1 + label_w; child_box.y1 = padding.top; child_box.y2 = child_box.y1 + MAX (label_h, arrow_h); mx_allocate_align_fill (priv->label, &child_box, MX_ALIGN_START, MX_ALIGN_MIDDLE, FALSE, FALSE); clutter_actor_allocate (priv->label, &child_box, flags); /* remove label height and spacing for child calculations */ available_h -= MAX (label_h, arrow_h) + priv->spacing; /* child */ child = mx_bin_get_child (MX_BIN (actor)); if (child && CLUTTER_ACTOR_IS_VISIBLE (child)) { child_box.x1 = padding.left; child_box.x2 = child_box.x1 + available_w; child_box.y1 = padding.top + priv->spacing + MAX (label_h, arrow_h); child_box.y2 = child_box.y1 + available_h; mx_allocate_align_fill (child, &child_box, x_align, y_align, x_fill, y_fill); clutter_actor_allocate (child, &child_box, flags); } }