static void _update_logo (MexContentTile *tile) { ClutterActor *image; GError *err = NULL; const gchar *logo_url; logo_url = mex_content_get_metadata (tile->priv->content, MEX_CONTENT_METADATA_STATION_LOGO); if (!logo_url) { mex_tile_set_primary_icon (MEX_TILE (tile), NULL); return; } image = mx_image_new (); if (g_str_has_prefix (logo_url, "file://")) logo_url = logo_url + 7; mx_image_set_from_file_at_size (MX_IMAGE (image), logo_url, 26, 26, &err); if (err) { g_warning ("Could not load station logo: %s", err->message); g_clear_error (&err); return; } mex_tile_set_primary_icon (MEX_TILE (tile), image); }
static void mex_tile_get_preferred_height (ClutterActor *actor, gfloat for_width, gfloat *min_height_p, gfloat *nat_height_p) { MxPadding padding; gfloat box_height, label_h, icon1_h, icon2_h; MexTilePrivate *priv = MEX_TILE (actor)->priv; CLUTTER_ACTOR_CLASS (mex_tile_parent_class)-> get_preferred_height (actor, for_width, NULL, nat_height_p); mx_widget_get_padding (MX_WIDGET (actor), &padding); for_width -= padding.left + padding.right; /* Header */ clutter_actor_get_preferred_height (priv->box_layout, for_width, NULL, &label_h); if (priv->icon1) clutter_actor_get_preferred_height (priv->icon1, for_width, NULL, &icon1_h); else icon1_h = 0; if (priv->icon2) clutter_actor_get_preferred_height (priv->icon2, for_width, NULL, &icon2_h); else icon2_h = 0; box_height = MAX (label_h, MAX (icon1_h, icon2_h)) + ((priv->header_padding) ? priv->header_padding->top + priv->header_padding->bottom : 0); /* Override the minimum height with the height of the box */ if (min_height_p) *min_height_p = box_height; if (nat_height_p) { gdouble progress; /* When the timeline is at 0.5, the actor isn't visible - this is * the time where we switch sizes between the natural height and the * box height. */ if (clutter_alpha_get_alpha (priv->important_alpha) < 0.5) progress = 0.0; else progress = 1.0; if (*nat_height_p < box_height) *nat_height_p = box_height; else if (progress == 0.0) *nat_height_p = box_height; else if (progress < 1.0) *nat_height_p = (box_height * (1.0 - progress)) + (*nat_height_p * progress); } }
static void mex_content_box_notify_key_focus_cb (ClutterStage *stage, GParamSpec *pspec, MexContentBox *self) { MexContentBoxPrivate *priv = self->priv; ClutterActor *focus = clutter_stage_get_key_focus (stage); if (focus == priv->tile) { gboolean show_info; if (mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_SYNOPSIS) || mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_DATE) || mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_CREATION_DATE) || mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_DURATION)) show_info = TRUE; else { MexActionManager *manager = mex_action_manager_get_default (); GList *actions = mex_action_manager_get_actions_for_content (manager, priv->content); if (actions && actions->next) show_info = TRUE; else show_info = FALSE; g_list_free (actions); } if (show_info) { ClutterActor *icon = mx_icon_new (); mx_stylable_set_style_class (MX_STYLABLE (icon), "Info"); mex_tile_set_secondary_icon (MEX_TILE (priv->tile), icon); } } else mex_tile_set_secondary_icon (MEX_TILE (priv->tile), NULL); }
static void mex_tile_actor_removed (ClutterActor *container, ClutterActor *actor) { MexTilePrivate *priv = MEX_TILE (container)->priv; if (priv->child == actor) priv->child = NULL; }
static void mex_tile_paint (ClutterActor *actor) { MexTilePrivate *priv = MEX_TILE (actor)->priv; MxPadding padding; ClutterActorBox box; CLUTTER_ACTOR_CLASS (mex_tile_parent_class)->paint (actor); clutter_actor_paint (priv->child); mx_widget_get_padding (MX_WIDGET (actor), &padding); if (priv->header_visible) { clutter_actor_get_allocation_box (actor, &box); if (priv->header_background_color) { cogl_set_source_color4ub (priv->header_background_color->red, priv->header_background_color->green, priv->header_background_color->blue, priv->header_background_color->alpha); cogl_rectangle (padding.left, padding.top, box.x2 - box.x1 - padding.right, priv->header_height); } if (cogl_material_get_n_layers (priv->material) > 0) { guint8 opacity; opacity = clutter_actor_get_paint_opacity (actor); cogl_material_set_color4ub (priv->material, opacity, opacity, opacity, opacity); cogl_set_source (priv->material); cogl_rectangle (padding.left, padding.top, box.x2 - box.x1 - padding.right, priv->header_height); } clutter_actor_paint (priv->box_layout); if (priv->icon1) clutter_actor_paint (priv->icon1); if (priv->icon2) clutter_actor_paint (priv->icon2); } }
static void _update_title (MexContentTile *tile) { MexContentTilePrivate *priv = tile->priv; const gchar *title; /* set title */ title = mex_content_get_metadata (priv->content, MEX_CONTENT_METADATA_TITLE); mex_tile_set_label (MEX_TILE (tile), title); }
static gboolean mex_content_box_key_press_event_cb (ClutterActor *actor, ClutterKeyEvent *event, MexExpanderBox *drawer) { gboolean open; MexActionManager *manager = mex_action_manager_get_default (); MexContentBoxPrivate *priv = MEX_CONTENT_BOX (drawer)->priv; if (event->keyval != MEX_KEY_OK && event->keyval != MEX_KEY_INFO) { return FALSE; } if (event->keyval == MEX_KEY_OK) { GList *actions; actions = mex_action_manager_get_actions_for_content (manager, priv->content); if (actions) { MxAction *action = actions->data; mex_action_set_content (action, priv->content); mex_action_set_context (action, priv->model); g_signal_emit_by_name (action, "activated", 0); g_list_free (actions); return TRUE; } } open = !mex_expander_box_get_open (drawer); /* We only want to expand the box if we have either more than one action, * or we have description metadata. We already track this when determining * if the info icon should be visible, so use that to determine whether * we should allow opening here. */ if (open && !mex_tile_get_secondary_icon (MEX_TILE (priv->tile))) return FALSE; mex_expander_box_set_open (drawer, open); mex_expander_box_set_open (MEX_EXPANDER_BOX (priv->box), open); return TRUE; }
static void mex_tile_finalize (GObject *object) { MexTile *self = MEX_TILE (object); if (self->priv->header_background_color) { g_boxed_free (CLUTTER_TYPE_COLOR, self->priv->header_background_color); self->priv->header_background_color = NULL; } G_OBJECT_CLASS (mex_tile_parent_class)->finalize (object); }
static void mex_tile_actor_added (ClutterActor *container, ClutterActor *actor) { MexTilePrivate *priv = MEX_TILE (container)->priv; if (MX_IS_TOOLTIP (actor)) return; if (priv->child) clutter_actor_remove_child (container, priv->child); priv->child = actor; }
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 mex_tile_dispose (GObject *object) { MexTile *self = MEX_TILE (object); MexTilePrivate *priv = self->priv; /* Use icon setting functions to remove icons */ mex_tile_set_primary_icon (self, NULL); mex_tile_set_secondary_icon (self, NULL); if (priv->box_layout) { clutter_actor_destroy (priv->box_layout); priv->box_layout = NULL; /* box_layout contains label and secondary_label */ priv->label = NULL; priv->secondary_label = NULL; } if (priv->header_padding) { g_boxed_free (MX_TYPE_PADDING, priv->header_padding); priv->header_padding = NULL; } if (priv->important_alpha) { g_object_unref (priv->important_alpha); priv->important_alpha = NULL; } if (priv->timeline) { clutter_timeline_stop (priv->timeline); g_object_unref (priv->timeline); priv->timeline = NULL; } if (priv->material) { cogl_object_unref (priv->material); priv->material = NULL; } G_OBJECT_CLASS (mex_tile_parent_class)->dispose (object); }
static void mex_content_box_init (MexContentBox *self) { MexContentBoxPrivate *priv = self->priv = CONTENT_BOX_PRIVATE (self); ClutterActor *icon; clutter_actor_push_internal (CLUTTER_ACTOR (self)); priv->info_panel = mex_info_panel_new (MEX_INFO_PANEL_MODE_SIMPLE); clutter_actor_set_parent (priv->info_panel, CLUTTER_ACTOR (self)); /* monitor key press events */ g_signal_connect (self, "key-press-event", G_CALLBACK (mex_content_box_key_press_event_cb), NULL); /* Create tile */ icon = mx_icon_new (); priv->tile = mex_content_tile_new (); clutter_actor_set_parent (priv->tile, CLUTTER_ACTOR (self)); g_object_set (G_OBJECT (priv->tile), "thumb-width", DEFAULT_THUMB_WIDTH, "thumb-height", DEFAULT_THUMB_HEIGHT, NULL); mx_stylable_set_style_class (MX_STYLABLE (icon), "Info"); mex_tile_set_secondary_icon (MEX_TILE (priv->tile), icon); clutter_actor_set_reactive (priv->tile, TRUE); g_signal_connect (priv->tile, "button-release-event", G_CALLBACK (mex_content_box_tile_clicked_cb), self); /* Create the action list */ priv->action_list = mex_action_list_new (); clutter_actor_set_parent (priv->action_list, CLUTTER_ACTOR (self)); clutter_actor_pop_internal (CLUTTER_ACTOR (self)); priv->timeline = clutter_timeline_new (200); priv->alpha = clutter_alpha_new_full (priv->timeline, CLUTTER_EASE_OUT_CUBIC); g_signal_connect_swapped (priv->timeline, "new-frame", G_CALLBACK (clutter_actor_queue_relayout), self); g_signal_connect (priv->timeline, "completed", G_CALLBACK (mex_content_box_timeline_completed), self); }
static void mex_tile_get_preferred_width (ClutterActor *actor, gfloat for_height, gfloat *min_height_p, gfloat *nat_height_p) { MexTilePrivate *priv = MEX_TILE (actor)->priv; MxPadding padding; mx_widget_get_padding (MX_WIDGET (actor), &padding); for_height -= padding.top + padding.bottom; clutter_actor_get_preferred_width (priv->child, for_height, min_height_p, nat_height_p); if (min_height_p) *min_height_p += padding.top + padding.bottom; if (nat_height_p) *nat_height_p += padding.top + padding.bottom; }
static void mex_tile_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { MexTile *self = MEX_TILE (object); switch (property_id) { case PROP_PRIMARY_ICON: mex_tile_set_primary_icon (self, g_value_get_object (value)); break; case PROP_SECONDARY_ICON: mex_tile_set_secondary_icon (self, g_value_get_object (value)); break; case PROP_LABEL: mex_tile_set_label (self, g_value_get_string (value)); break; case PROP_SECONDARY_LABEL: mex_tile_set_secondary_label (self, g_value_get_string (value)); break; case PROP_HEADER_VISIBLE: mex_tile_set_header_visible (self, g_value_get_boolean (value)); break; case PROP_IMPORTANT: mex_tile_set_important (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } }
static void mex_column_add (ClutterContainer *container, ClutterActor *actor) { MexColumn *self = MEX_COLUMN (container); MexColumnPrivate *priv = self->priv; if (priv->sort_func) priv->children = g_list_insert_sorted_with_data (priv->children, actor, (GCompareDataFunc)priv->sort_func, priv->sort_data); else priv->children = g_list_append (priv->children, actor); priv->n_items ++; /* Expand/collapse any drawer that gets added as appropriate */ if (MEX_IS_EXPANDER_BOX (actor)) { g_signal_connect (actor, "notify::open", G_CALLBACK (expander_box_open_notify), container); mex_expander_box_set_important (MEX_EXPANDER_BOX (actor), priv->has_focus); if (MEX_IS_CONTENT_BOX (actor)) { ClutterActor *tile = mex_content_box_get_tile (MEX_CONTENT_BOX (actor)); mex_tile_set_important (MEX_TILE (tile), priv->has_focus); } } clutter_actor_set_parent (actor, CLUTTER_ACTOR (self)); g_signal_emit_by_name (self, "actor-added", actor); }
int main (int argc, char **argv) { const ClutterColor red = { 0xff, 0x00, 0x00, 0xff }; ClutterActor *stage, *box, *tile, *rectangle; clutter_init (&argc, &argv); mex_style_load_default (); stage = clutter_stage_get_default (); clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE); tile = mex_tile_new_with_label ("Red rectangle"); mex_tile_set_important (MEX_TILE (tile), TRUE); rectangle = clutter_rectangle_new_with_color (&red); clutter_actor_set_size (rectangle, 300, 300); mx_bin_set_child (MX_BIN (tile), rectangle); box = mex_expander_box_new (); clutter_container_add (CLUTTER_CONTAINER (box), tile, clutter_text_new_with_text ("Sans 16", "Hello"), NULL); clutter_container_add_actor (CLUTTER_CONTAINER (stage), box); clutter_actor_set_reactive (rectangle, TRUE); g_signal_connect_swapped (rectangle, "enter-event", G_CALLBACK (toggle_important), box); clutter_actor_show (stage); clutter_main (); return 0; }
gboolean mex_content_box_get_important (MexContentBox *box) { return mex_tile_get_important (MEX_TILE (box->priv->tile)); }
void mex_content_box_set_important (MexContentBox *box, gboolean important) { mex_tile_set_important (MEX_TILE (box->priv->tile), important); }
static void mex_content_box_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { MexContentBox *self = MEX_CONTENT_BOX (object); MexContentBoxPrivate *priv = self->priv; switch (property_id) { case PROP_MEDIA_URL: g_free (priv->media_url); priv->media_url = g_value_dup_string (value); break; case PROP_LOGO_URL: /* FIXME: We want the logo URL to be file:// to share the same * underlying texture. This should be handled by a generic "download * queue + texture cache" thingy that caches the same URL to a local * file and hands over a ClutterTexure (or a MagicTexture) with the * same underlying Cogl texture */ { MxTextureCache *cache; ClutterActor *logo, *logo_frame; GFile *file; gchar *path; gint bw, bh; gfloat ratio; g_free (priv->logo_url); priv->logo_url = g_value_dup_string (value); if (priv->logo_url == NULL) break; file = g_file_new_for_uri (priv->logo_url); path = g_file_get_path (file); g_object_unref (file); if (G_UNLIKELY (path == NULL)) { g_warning ("The logo URL provided is not local, refusing to load it"); break; } cache = mx_texture_cache_get_default (); logo = mx_texture_cache_get_actor (cache, path); if (G_UNLIKELY (logo == NULL)) { g_warning ("Could not retrieve texture for %s", path); break; } logo_frame = mex_aspect_frame_new (); /* FIXME, had to set the size (for now?) provides some GObject properties * to tune that? expose it in the CSS */ clutter_actor_set_size (logo_frame, 60, 40); clutter_texture_get_base_size (CLUTTER_TEXTURE (logo), &bw, &bh); ratio = bh / 40.; mex_aspect_frame_set_ratio (MEX_ASPECT_FRAME (logo_frame), ratio); clutter_container_add_actor (CLUTTER_CONTAINER (logo_frame), logo); mex_tile_set_primary_icon (MEX_TILE (priv->tile), logo_frame); } break; case PROP_THUMB_WIDTH: priv->thumb_width = g_value_get_int (value); g_object_set (G_OBJECT (priv->tile), "thumb-width", priv->thumb_width, NULL); break; case PROP_THUMB_HEIGHT: priv->thumb_height = g_value_get_int (value); g_object_set (G_OBJECT (priv->tile), "thumb-height", priv->thumb_height, NULL); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } }
static void mex_tile_allocate (ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags) { MxPadding padding; ClutterActorBox child_box; gfloat available_width, available_height; ClutterEffect *fade; MexTilePrivate *priv = MEX_TILE (actor)->priv; CLUTTER_ACTOR_CLASS (mex_tile_parent_class)->allocate (actor, box, flags); mx_widget_get_padding (MX_WIDGET (actor), &padding); available_width = box->x2 - box->x1 - padding.left - padding.right; available_height = box->y2 - box->y1 - padding.top - padding.bottom; if (priv->child) { gfloat child_width, full_width, full_height; clutter_actor_get_preferred_size (priv->child, NULL, NULL, &full_width, &full_height); child_box.y1 = padding.top; if (clutter_alpha_get_alpha (priv->important_alpha) < 0.5) { child_width = full_width * (available_height / full_height); if (child_width > available_width) child_width = available_width; child_box.y2 = child_box.y1 + available_height; /* When we're in unimportant state, make sure the label * doesn't overlap the image. */ if (available_height < full_height) available_width -= child_width * ((0.5 - clutter_alpha_get_alpha (priv->important_alpha)) * 2); } else { child_width = available_width; clutter_actor_set_clip_to_allocation ( actor, (full_height > available_height)); child_box.y2 = child_box.y1 + full_height; } child_box.x2 = box->x2 - box->x1 - padding.right; child_box.x1 = child_box.x2 - child_width; mx_allocate_align_fill (priv->child, &child_box, MX_ALIGN_MIDDLE, MX_ALIGN_MIDDLE, FALSE, FALSE); clutter_actor_allocate (priv->child, &child_box, flags); } /* Allocate Header */ if (priv->header_visible) { gfloat icon1_w, icon1_h, icon2_w, icon2_h, label_h, label_w, header_h; gfloat middle_w; if (priv->header_padding) { padding.top += priv->header_padding->top; padding.right += priv->header_padding->right; padding.bottom += priv->header_padding->bottom; padding.left += priv->header_padding->left; } clutter_actor_get_preferred_size (priv->box_layout, NULL, NULL, &label_w, &label_h); if (priv->icon1) clutter_actor_get_preferred_size (priv->icon1, NULL, NULL, &icon1_w, &icon1_h); else icon1_h = icon1_w = 0; if (priv->icon2) clutter_actor_get_preferred_size (priv->icon2, NULL, NULL, &icon2_w, &icon2_h); else icon2_h = icon2_w = 0; header_h = MAX (icon1_h, MAX (icon2_h, label_h)); /* primary icon */ if (priv->icon1) { child_box.y1 = padding.top + (header_h / 2.0) - (icon1_h / 2.0); child_box.x1 = padding.left; child_box.y2 = child_box.y1 + icon1_h; child_box.x2 = child_box.x1 + icon1_w; clutter_actor_allocate (priv->icon1, &child_box, flags); child_box.x1 += icon1_w + 8; } else child_box.x1 = padding.left; /* label */ child_box.x2 = child_box.x1 + label_w; child_box.y1 = (int) (padding.top + (header_h / 2.0) - (label_h / 2.0)); child_box.y2 = child_box.y1 + label_h; fade = clutter_actor_get_effect (priv->box_layout, "fade"); middle_w = available_width - icon1_w - icon2_w; if (priv->header_padding) middle_w -= priv->header_padding->left + priv->header_padding->right; clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (fade), !(middle_w > label_w)); mx_fade_effect_set_bounds (MX_FADE_EFFECT (fade), 0, 0, middle_w, 0); clutter_actor_allocate (priv->box_layout, &child_box, flags); /* secondary icon */ if (priv->icon2) { child_box.x2 = (box->x2 - box->x1) - padding.right; child_box.x1 = child_box.x2 - icon2_w; child_box.y1 = padding.top + (header_h / 2.0) - (icon2_h / 2.0); child_box.y2 = child_box.y1 + icon2_h; clutter_actor_allocate (priv->icon2, &child_box, flags); } priv->header_height = header_h; if (priv->header_padding) priv->header_height += priv->header_padding->top + priv->header_padding->bottom; } }
static void add_pictures (ClutterActor *box) { GList *files = get_pictures (); while (files) { gint w, h, i; ClutterActor *drawer, *drawer2, *tile, *texture, *menu, *description; gchar *file = files->data; /* Create texture */ texture = clutter_texture_new_from_file (file, NULL); clutter_texture_get_base_size (CLUTTER_TEXTURE (texture), &w, &h); clutter_actor_set_size (texture, 300, 300.0/w * h); /* Create menu */ menu = mx_box_layout_new (); mx_box_layout_set_orientation (MX_BOX_LAYOUT (menu), MX_ORIENTATION_VERTICAL); for (i = 0; i < 4; i++) { ClutterActor *button, *layout, *icon, *label; button = mx_button_new (); layout = mx_box_layout_new (); icon = mx_icon_new (); label = mx_label_new (); mx_box_layout_set_spacing (MX_BOX_LAYOUT (layout), 8); mx_icon_set_icon_size (MX_ICON (icon), 16); clutter_actor_set_size (icon, 16, 16); clutter_container_add (CLUTTER_CONTAINER (layout), icon, label, NULL); mx_bin_set_child (MX_BIN (button), layout); mx_bin_set_alignment (MX_BIN (button), MX_ALIGN_START, MX_ALIGN_MIDDLE); clutter_container_add_actor (CLUTTER_CONTAINER (menu), button); mx_box_layout_child_set_x_fill (MX_BOX_LAYOUT (menu), button, TRUE); switch (i) { case 0: mx_icon_set_icon_name (MX_ICON (icon), "dialog-information"); mx_label_set_text (MX_LABEL (label), "This"); break; case 1: mx_icon_set_icon_name (MX_ICON (icon), "dialog-question"); mx_label_set_text (MX_LABEL (label), "is"); break; case 2: mx_icon_set_icon_name (MX_ICON (icon), "dialog-warning"); mx_label_set_text (MX_LABEL (label), "a"); break; case 3: mx_icon_set_icon_name (MX_ICON (icon), "dialog-error"); mx_label_set_text (MX_LABEL (label), "menu"); break; } } /* Create description */ description = mx_label_new_with_text ("Here you could put a very " "long description of whatever " "is above it. Or you could put " "another focusable widget here " "and it'd be navigable, like " "the menu on the right. Whoo!"); clutter_text_set_line_wrap ((ClutterText *)mx_label_get_clutter_text ( MX_LABEL (description)), TRUE); drawer = mex_expander_box_new (); mex_expander_box_set_important_on_focus (MEX_EXPANDER_BOX (drawer), TRUE); drawer2 = mex_expander_box_new (); mex_expander_box_set_grow_direction (MEX_EXPANDER_BOX (drawer2), MEX_EXPANDER_BOX_RIGHT); mex_expander_box_set_important (MEX_EXPANDER_BOX (drawer2), TRUE); tile = mex_tile_new_with_label (file); mex_tile_set_important (MEX_TILE (tile), TRUE); mx_bin_set_child (MX_BIN (tile), texture); clutter_container_add (CLUTTER_CONTAINER (drawer2), tile, menu, NULL); clutter_container_add (CLUTTER_CONTAINER (drawer), drawer2, description, NULL); g_signal_connect (drawer, "notify::open", G_CALLBACK (sync_drawer2_cb), drawer2); clutter_container_add_actor (CLUTTER_CONTAINER (box), drawer); clutter_actor_set_reactive (texture, TRUE); g_signal_connect (texture, "enter-event", G_CALLBACK (texture_enter_cb), drawer); g_signal_connect (texture, "leave-event", G_CALLBACK (texture_leave_cb), drawer); g_signal_connect (texture, "button-press-event", G_CALLBACK (texture_clicked_cb), drawer); g_free (file); files = g_list_delete_link (files, files); } }
static gboolean _create_settings_dialog (MexInfoBar *self) { MexInfoBarPrivate *priv = self->priv; ClutterActor *dialog, *network_graphic; ClutterActor *network_tile, *dialog_layout, *dialog_label; ClutterActor *network_button; MxAction *close_dialog, *network_settings; dialog = mx_dialog_new (); mx_stylable_set_style_class (MX_STYLABLE (dialog), "MexInfoBarDialog"); dialog_label = mx_label_new_with_text (_("Settings")); mx_stylable_set_style_class (MX_STYLABLE (dialog_label), "DialogHeader"); /* Create actions for settings dialog */ network_settings = _action_new_from_desktop_file ("mex-networks.desktop"); close_dialog = mx_action_new_full ("close", _("Close"), G_CALLBACK (_close_dialog_cb), self); dialog_layout = mx_table_new (); mx_table_set_column_spacing (MX_TABLE (dialog_layout), 10); mx_table_set_row_spacing (MX_TABLE (dialog_layout), 30); mx_table_insert_actor (MX_TABLE (dialog_layout), CLUTTER_ACTOR (dialog_label), 0, 0); if (network_settings) { gchar *tmp; network_graphic = mx_image_new (); mx_stylable_set_style_class (MX_STYLABLE (network_graphic), "NetworkGraphic"); tmp = g_build_filename (mex_get_data_dir (), "style", "graphic-network.png", NULL); mx_image_set_from_file (MX_IMAGE (network_graphic), tmp, NULL); g_free (tmp); network_tile = mex_tile_new (); mex_tile_set_label (MEX_TILE (network_tile), _("Network")); mex_tile_set_important (MEX_TILE (network_tile), TRUE); network_button = mx_button_new (); mx_button_set_action (MX_BUTTON (network_button), network_settings); mx_bin_set_child (MX_BIN (network_tile), network_button); mx_bin_set_child (MX_BIN (network_button), network_graphic); mx_table_insert_actor (MX_TABLE (dialog_layout), CLUTTER_ACTOR (network_tile), 1, 1); } if (!network_settings) { ClutterActor *no_settings; no_settings = mx_label_new_with_text (_("No settings helpers installed")); clutter_actor_destroy (priv->settings_button); mx_table_insert_actor (MX_TABLE (dialog_layout), CLUTTER_ACTOR (no_settings), 1, 0); } mx_bin_set_child (MX_BIN (dialog), dialog_layout); mx_dialog_add_action (MX_DIALOG (dialog), close_dialog); priv->settings_dialog = g_object_ref (dialog); return TRUE; }
static void mex_column_notify_focused_cb (MxFocusManager *manager, GParamSpec *pspec, MexColumn *self) { GList *c; guint offset, increment; ClutterActor *focused, *focused_cell; gboolean cell_has_focus, has_focus, open, set_tile_important; MexColumnPrivate *priv = self->priv; focused = (ClutterActor *)mx_focus_manager_get_focused (manager); /* Check if we have focus, and what child is focused */ focused_cell = NULL; set_tile_important = FALSE; cell_has_focus = has_focus = FALSE; if (focused) { gboolean contains_column = FALSE; ClutterActor *parent = clutter_actor_get_parent (focused); while (parent) { if (parent == (ClutterActor *)self) { has_focus = TRUE; if (!priv->has_focus) { set_tile_important = TRUE; priv->has_focus = TRUE; } if (focused != priv->header) { cell_has_focus = TRUE; focused_cell = focused; } break; } else if (MEX_IS_COLUMN (parent)) { contains_column = TRUE; } focused = parent; parent = clutter_actor_get_parent (focused); } if (!contains_column) has_focus = TRUE; } if (!has_focus && priv->has_focus) { priv->has_focus = FALSE; set_tile_important = TRUE; } /* Scroll the adjustment to the top */ if (!cell_has_focus && priv->adjustment) mx_adjustment_interpolate (priv->adjustment, 0, 250, CLUTTER_EASE_OUT_CUBIC); /* Open/close boxes as appropriate */ offset = 0; increment = 150; /* If we're changing the tile importance, initialise the state manager */ if (set_tile_important && priv->n_items > 0) { if (priv->expand_timeline) g_object_unref (priv->expand_timeline); priv->expand_timeline = clutter_timeline_new (priv->n_items * increment); clutter_timeline_set_delay (priv->expand_timeline, 350); } /* Loop through children and set the expander box important/unimportant * as necessary, and if necessary, do the same for the tile inside the * expander-box. */ open = has_focus && !cell_has_focus; for (c = priv->children; c; c = c->next) { gchar signal_name[32+16]; ClutterActor *child = c->data; if ((!priv->collapse && priv->has_focus) || (child == focused_cell)) open = TRUE; if (!MEX_IS_EXPANDER_BOX (child)) continue; /* Note, 'marker-reached::' is 16 characters long */ g_snprintf (signal_name, G_N_ELEMENTS (signal_name), "marker-reached::%p", child); if (MEX_IS_CONTENT_BOX (child)) { ClutterActor *tile = mex_content_box_get_tile (MEX_CONTENT_BOX (child)); mex_tile_set_important (MEX_TILE (tile), priv->has_focus); } if (!open) { if (priv->expand_timeline) { if (clutter_timeline_has_marker (priv->expand_timeline, signal_name + 16)) clutter_timeline_remove_marker (priv->expand_timeline, signal_name + 16); g_signal_handlers_disconnect_by_func (priv->expand_timeline, mex_column_expand_drawer_cb, child); } mex_expander_box_set_important (MEX_EXPANDER_BOX (child), FALSE); } else if (set_tile_important) { mex_expander_box_set_important (MEX_EXPANDER_BOX (child), FALSE); clutter_timeline_add_marker_at_time (priv->expand_timeline, signal_name + 16, offset); g_signal_connect_swapped (priv->expand_timeline, signal_name, G_CALLBACK (mex_column_expand_drawer_cb), child); offset += increment; } else mex_expander_box_set_important (MEX_EXPANDER_BOX (child), TRUE); } if (priv->expand_timeline && set_tile_important && (offset >= increment)) clutter_timeline_start (priv->expand_timeline); }