static void mx_combo_box_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { MxComboBoxPrivate *priv = MX_COMBO_BOX (object)->priv; switch (property_id) { case PROP_ACTIVE_TEXT: g_value_set_string (value, clutter_text_get_text ((ClutterText*) priv->label)); break; case PROP_ACTIVE_ICON_NAME: g_value_set_string (value, mx_combo_box_get_active_icon_name ( MX_COMBO_BOX (object))); break; case PROP_INDEX: g_value_set_int (value, priv->index); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } }
int main(int argc, char *argv[]) { clutter_init(&argc, &argv); ClutterActor *stage = NULL; ClutterColor black = { 0x00, 0x00, 0x00, 0xff }; stage = clutter_stage_get_default(); clutter_stage_set_title(CLUTTER_STAGE(stage), "Mx test"); clutter_stage_set_color(CLUTTER_STAGE(stage), &black); clutter_actor_set_size(stage, WIN_W, WIN_H); Assistant *assistant = g_new0(Assistant, 1); assistant->script = require_script(GUI_SCRIPT); assistant->stage = stage; ClutterActor *root = CLUTTER_ACTOR(require_object_from_script(assistant->script, "root")); assistant->slider = CLUTTER_ACTOR(require_object_from_script(assistant->script, "slider")); assistant->combo_box = CLUTTER_ACTOR(require_object_from_script(assistant->script, "combo_box")); clutter_container_add_actor(CLUTTER_CONTAINER(stage), root); // Combo box contents: MxComboBox *combo_box = MX_COMBO_BOX(assistant->combo_box); mx_combo_box_append_text(combo_box, "Foo"); mx_combo_box_append_text(combo_box, "Spam"); mx_combo_box_append_text(combo_box, "Lorem ipsum"); mx_combo_box_set_index(combo_box, 0); // DONE g_signal_connect(stage, "key-press-event", G_CALLBACK(key_event_cb), assistant); clutter_script_connect_signals(assistant->script, assistant); assistant->ready_ = TRUE; clutter_actor_show(stage); clutter_main(); return 0; }
static void anerley_presence_chooser_init (AnerleyPresenceChooser *self) { MxComboBox *combo = MX_COMBO_BOX (self); AnerleyPresenceChooserPrivate *priv = GET_PRIVATE (self); priv->am = tp_account_manager_dup (); g_signal_connect (priv->am, "most-available-presence-changed", G_CALLBACK (_account_manager_presence_changed), self); priv->combo_entries = g_array_sized_new (FALSE, TRUE, sizeof (ComboEntry), 7); /* add some entries */ _append_presence (combo, TP_CONNECTION_PRESENCE_TYPE_AVAILABLE); _append_presence (combo, TP_CONNECTION_PRESENCE_TYPE_BUSY); _append_presence (combo, TP_CONNECTION_PRESENCE_TYPE_AWAY); _append_presence (combo, TP_CONNECTION_PRESENCE_TYPE_OFFLINE); /* FIXME: Hidden ? */ g_signal_connect (self, "notify::index", G_CALLBACK (_combo_index_changed), NULL); tp_proxy_prepare_async (TP_PROXY (priv->am), NULL, (GAsyncReadyCallback)_account_manager_ready, self); }
static void create_new_chooser (MnbPeoplePanel *self) { MnbPeoplePanelPrivate *priv = GET_PRIVATE (self); priv->new_chooser = mx_combo_box_new (); mx_combo_box_append_text (MX_COMBO_BOX (priv->new_chooser), _("New contact")); mx_combo_box_append_text (MX_COMBO_BOX (priv->new_chooser), _("New group chat")); mx_combo_box_set_active_text (MX_COMBO_BOX (priv->new_chooser), _("New")); g_signal_connect (priv->new_chooser, "notify::index", G_CALLBACK (new_index_changed_cb), self); }
static void _combo_index_changed (AnerleyPresenceChooser *self, GParamSpec *pspec, gpointer user_data) { AnerleyPresenceChooserPrivate *priv = GET_PRIVATE (self); MxComboBox *combo = MX_COMBO_BOX (self); gint index = mx_combo_box_get_index (combo); ComboEntry *entry; gchar *message; if (index >= 0) entry = &g_array_index (priv->combo_entries, ComboEntry, index); else return; priv->presence = entry->presence; /* Get current message to not modify it */ tp_account_manager_get_most_available_presence (priv->am, NULL, &message); tp_account_manager_set_all_requested_presences (priv->am, entry->presence, presences[entry->presence].status, message); g_free (message); }
static void mx_combo_box_dispose (GObject *object) { MxComboBoxPrivate *priv = MX_COMBO_BOX (object)->priv; if (priv->label) { clutter_actor_destroy (priv->label); priv->label = NULL; } if (priv->icon) { clutter_actor_destroy (priv->icon); priv->icon = NULL; } if (priv->marker) { clutter_actor_destroy (priv->marker); priv->marker = NULL; } G_OBJECT_CLASS (mx_combo_box_parent_class)->dispose (object); }
static void update_combox_index (AnerleyPresenceChooser *self) { AnerleyPresenceChooserPrivate *priv = GET_PRIVATE (self); MxComboBox *combo = MX_COMBO_BOX (self); g_signal_handlers_block_by_func (combo, _combo_index_changed, NULL); switch (priv->presence) { case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE: mx_combo_box_set_index (combo, 0); break; case TP_CONNECTION_PRESENCE_TYPE_BUSY: mx_combo_box_set_index (combo, 1); break; case TP_CONNECTION_PRESENCE_TYPE_AWAY: case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY: mx_combo_box_set_index (combo, 2); break; default: mx_combo_box_set_index (combo, 3); break; } g_signal_handlers_unblock_by_func (combo, _combo_index_changed, NULL); }
static void mx_combo_box_apply_style (MxWidget *widget, MxStyle *style) { MxComboBoxPrivate *priv = MX_COMBO_BOX (widget)->priv; if (priv->icon != NULL) mx_stylable_set_style (MX_STYLABLE (priv->icon), style); }
static void mx_combo_box_finalize (GObject *object) { MxComboBoxPrivate *priv = MX_COMBO_BOX (object)->priv; if (priv->actions) { g_slist_foreach (priv->actions, (GFunc) g_object_unref, NULL); g_slist_free (priv->actions); } G_OBJECT_CLASS (mx_combo_box_parent_class)->finalize (object); }
static gboolean mx_combo_box_key_press_event (ClutterActor *actor, ClutterKeyEvent *event) { switch (event->keyval) { case CLUTTER_KEY_Return: return mx_combo_box_open_menu (MX_COMBO_BOX (actor)); default: return FALSE; } }
static void mx_combo_box_paint (ClutterActor *actor) { MxComboBoxPrivate *priv = MX_COMBO_BOX (actor)->priv; CLUTTER_ACTOR_CLASS (mx_combo_box_parent_class)->paint (actor); clutter_actor_paint (priv->label); if (priv->icon) clutter_actor_paint (priv->icon); if (priv->marker) clutter_actor_paint (priv->marker); }
static gboolean mx_combo_box_touch_event (ClutterActor *actor, ClutterTouchEvent *event) { switch (event->type) { case CLUTTER_TOUCH_BEGIN: return mx_combo_box_open_menu (MX_COMBO_BOX (actor)); default: return FALSE; } return FALSE; }
static void mx_combo_box_get_preferred_height (ClutterActor *actor, gfloat for_width, gfloat *min_height_p, gfloat *natural_height_p) { MxComboBoxPrivate *priv = MX_COMBO_BOX (actor)->priv; gfloat min_label_h, nat_label_h; gfloat min_icon_h = 0, nat_icon_h = 0; gfloat min_marker_h = 0, nat_marker_h = 0; gfloat min_h, nat_h; MxPadding padding; mx_widget_get_padding (MX_WIDGET (actor), &padding); clutter_actor_get_preferred_height (priv->label, -1, &min_label_h, &nat_label_h); if (priv->icon) { clutter_actor_get_preferred_height (priv->icon, -1, &min_icon_h, &nat_icon_h); } if (priv->marker) { clutter_actor_get_preferred_height (priv->marker, -1, &min_marker_h, &nat_marker_h); } min_h = MAX (MAX (min_icon_h, min_label_h), min_marker_h); nat_h = MAX (MAX (nat_icon_h, nat_label_h), nat_marker_h); if (min_height_p) *min_height_p = padding.top + padding.bottom + min_h; if (natural_height_p) *natural_height_p = padding.top + padding.bottom + nat_h; }
static void create_sort_by_chooser (MnbPeoplePanel *self) { MnbPeoplePanelPrivate *priv = GET_PRIVATE (self); priv->sort_by_chooser = mx_combo_box_new (); mx_combo_box_append_text (MX_COMBO_BOX (priv->sort_by_chooser), _("Sort by:")); mx_combo_box_append_text (MX_COMBO_BOX (priv->sort_by_chooser), _("- Presence")); mx_combo_box_append_text (MX_COMBO_BOX (priv->sort_by_chooser), _("- Name")); mx_combo_box_append_text (MX_COMBO_BOX (priv->sort_by_chooser), _("Show:")); mx_combo_box_append_text (MX_COMBO_BOX (priv->sort_by_chooser), _("- Only online")); mx_combo_box_append_text (MX_COMBO_BOX (priv->sort_by_chooser), _("- All contacts")); mx_combo_box_set_active_text (MX_COMBO_BOX (priv->sort_by_chooser), _("Sort by")); g_signal_connect (priv->sort_by_chooser, "notify::index", G_CALLBACK (sort_by_index_changed_cb), self); }
static ClutterActor * create_property_editor (GObject *object, GParamSpec *pspec) { ClutterActor *box, *label, *value; gint i; /* skip properties that are not writable */ if (!(pspec->flags & G_PARAM_WRITABLE)) return NULL; /* skip other properties */ for (i = 0; i < G_N_ELEMENTS (skip_properties); i++) { if (g_str_equal (pspec->name, skip_properties[i])) return NULL; } box = mx_box_layout_new (); label = mx_label_new_with_text (pspec->name); clutter_actor_set_width (label, 150); clutter_actor_add_child (box, label); if (pspec->value_type == G_TYPE_BOOLEAN) { value = mx_toggle_new (); g_object_bind_property (object, pspec->name, value, "active", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } else if (pspec->value_type == G_TYPE_STRING) { value = mx_entry_new (); g_object_bind_property (object, pspec->name, value, "text", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } else if (pspec->value_type == G_TYPE_INT || pspec->value_type == G_TYPE_UINT || pspec->value_type == G_TYPE_FLOAT || pspec->value_type == G_TYPE_DOUBLE) { value = mx_entry_new (); g_object_bind_property_full (object, pspec->name, value, "text", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE, num_to_string, string_to_num, NULL, NULL); } else if (g_type_is_a (pspec->value_type, G_TYPE_ENUM)) { GEnumValue *evalue; GEnumClass *eclass; gint init = 0; value = mx_combo_box_new (); clutter_actor_set_width (value, 100); eclass = g_type_class_ref (pspec->value_type); while ((evalue = g_enum_get_value (eclass, init))) { mx_combo_box_append_text (MX_COMBO_BOX (value), evalue->value_nick); init++; } g_type_class_unref (eclass); g_object_bind_property (object, pspec->name, value, "index", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); } else value = NULL; if (value) { clutter_actor_add_child (box, value); return box; } else return NULL; }
static void mx_combo_box_allocate (ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags) { MxComboBoxPrivate *priv = MX_COMBO_BOX (actor)->priv; MxPadding padding; gfloat x, y, width, height; gfloat min_menu_h, nat_menu_h; gfloat label_h; gfloat nat_icon_h, icon_h, icon_w; gfloat nat_marker_h, marker_h, marker_w; ClutterActorBox childbox; ClutterActor *menu, *stage; CLUTTER_ACTOR_CLASS (mx_combo_box_parent_class)->allocate (actor, box, flags); mx_widget_get_padding (MX_WIDGET (actor), &padding); x = padding.left; y = padding.top; width = box->x2 - box->x1 - padding.left - padding.right; height = box->y2 - box->y1 - padding.top - padding.bottom; icon_w = marker_w = 0; if (priv->icon) { /* Allocate the icon, if there is one, the space not used by the text */ clutter_actor_get_preferred_height (priv->icon, -1, NULL, &nat_icon_h); if (height >= nat_icon_h) { icon_h = nat_icon_h; clutter_actor_get_preferred_width (priv->icon, -1, NULL, &icon_w); } else { icon_h = height; clutter_actor_get_preferred_width (priv->icon, icon_h, NULL, &icon_w); } childbox.x1 = (int)(x); childbox.y1 = (int)(y + (height - icon_h) / 2); childbox.x2 = (int)(x + icon_w); childbox.y2 = (int)(childbox.y1 + icon_h); clutter_actor_allocate (priv->icon, &childbox, flags); icon_w += priv->spacing; } if (priv->marker) { clutter_actor_get_preferred_height (priv->marker, -1, NULL, &nat_marker_h); if (height >= nat_marker_h) { marker_h = nat_marker_h; clutter_actor_get_preferred_width (priv->marker, -1, NULL, &marker_w); } else { marker_h = height; clutter_actor_get_preferred_width (priv->marker, marker_h, NULL, &marker_w); } childbox.x2 = (int)(x + width); childbox.x1 = (int)(childbox.x2 - marker_w); childbox.y1 = (int)(y + (height - marker_h) / 2); childbox.y2 = (int)(childbox.y1 + marker_h); clutter_actor_allocate (priv->marker, &childbox, flags); marker_w += priv->spacing; } clutter_actor_get_preferred_height (priv->label, -1, NULL, &label_h); childbox.x1 = (int)(x + icon_w); childbox.y1 = (int)(y + (height / 2 - label_h / 2)); childbox.x2 = (int)(x + width - marker_w); childbox.y2 = (int)(childbox.y1 + label_h); clutter_actor_allocate (priv->label, &childbox, flags); menu = (ClutterActor*) mx_widget_get_menu (MX_WIDGET (actor)); clutter_actor_get_preferred_height (menu, (box->x2 - box->x1), &min_menu_h, &nat_menu_h); childbox.x1 = 0; childbox.x2 = (box->x2 - box->x1); childbox.y1 = (box->y2 - box->y1); childbox.y2 = childbox.y1 + nat_menu_h; stage = clutter_actor_get_stage (actor); if (stage != NULL) { ClutterVertex point = { 0, }; gfloat stage_w, stage_h, combo_h = box->y2 - box->y1; clutter_actor_get_size (stage, &stage_w, &stage_h); point.y = combo_h + nat_menu_h; clutter_actor_apply_transform_to_point (actor, &point, &point); /* If the menu would appear off the stage, flip it around. */ if ((point.y < 0) || (point.y >= stage_h)) { childbox.y1 = -nat_menu_h; point.y = -nat_menu_h; clutter_actor_apply_transform_to_point (actor, &point, &point); /* if the menu would still appear out of the stage, force * it to appear on the top of the stage. */ if (point.y < 0) { gfloat xactor, yactor; clutter_actor_get_transformed_position (actor, &xactor, &yactor); childbox.y1 = -yactor; } } point.y = childbox.y1 + nat_menu_h; clutter_actor_apply_transform_to_point (actor, &point, &point); if (point.y >= stage_h) { gfloat xactor, yactor; clutter_actor_get_transformed_position (actor, &xactor, &yactor); /* * clamp so that the menu doesn't appear out of the screen */ clutter_actor_transform_stage_point (actor, xactor, stage_h, NULL, &childbox.y2); /* * The previous transformation can lead to negative height * allocation if the top-left corner of the menu is already * flipped around. This happens when you put a combobox deep * enough in a scrollview taller that the stage. */ childbox.y2 = MAX (childbox.y1, childbox.y2); } else { childbox.y2 = childbox.y1 + nat_menu_h; } } clutter_actor_allocate (menu, &childbox, flags); }
static gboolean mx_combo_box_button_press_event (ClutterActor *actor, ClutterButtonEvent *event) { return mx_combo_box_open_menu (MX_COMBO_BOX (actor)); }
static void mx_combo_box_allocate (ClutterActor *actor, const ClutterActorBox *box, ClutterAllocationFlags flags) { MxComboBoxPrivate *priv = MX_COMBO_BOX (actor)->priv; MxPadding padding; gfloat x, y, width, height; gfloat min_menu_h, nat_menu_h; gfloat label_h; gfloat nat_icon_h, icon_h, icon_w; gfloat nat_marker_h, marker_h, marker_w; ClutterActorBox childbox; ClutterActor *menu, *stage; CLUTTER_ACTOR_CLASS (mx_combo_box_parent_class)->allocate (actor, box, flags); mx_widget_get_padding (MX_WIDGET (actor), &padding); x = padding.left; y = padding.top; width = box->x2 - box->x1 - padding.left - padding.right; height = box->y2 - box->y1 - padding.top - padding.bottom; icon_w = marker_w = 0; if (priv->icon) { /* Allocate the icon, if there is one, the space not used by the text */ clutter_actor_get_preferred_height (priv->icon, -1, NULL, &nat_icon_h); if (height >= nat_icon_h) { icon_h = nat_icon_h; clutter_actor_get_preferred_width (priv->icon, -1, NULL, &icon_w); } else { icon_h = height; clutter_actor_get_preferred_width (priv->icon, icon_h, NULL, &icon_w); } childbox.x1 = (int)(x); childbox.y1 = (int)(y + (height - icon_h) / 2); childbox.x2 = (int)(x + icon_w); childbox.y2 = (int)(childbox.y1 + icon_h); clutter_actor_allocate (priv->icon, &childbox, flags); icon_w += priv->spacing; } if (priv->marker) { clutter_actor_get_preferred_height (priv->marker, -1, NULL, &nat_marker_h); if (height >= nat_marker_h) { marker_h = nat_marker_h; clutter_actor_get_preferred_width (priv->marker, -1, NULL, &marker_w); } else { marker_h = height; clutter_actor_get_preferred_width (priv->marker, marker_h, NULL, &marker_w); } childbox.x2 = (int)(x + width); childbox.x1 = (int)(childbox.x2 - marker_w); childbox.y1 = (int)(y + (height - marker_h) / 2); childbox.y2 = (int)(childbox.y1 + marker_h); clutter_actor_allocate (priv->marker, &childbox, flags); marker_w += priv->spacing; } clutter_actor_get_preferred_height (priv->label, -1, NULL, &label_h); childbox.x1 = (int)(x + icon_w); childbox.y1 = (int)(y + (height / 2 - label_h / 2)); childbox.x2 = (int)(x + width - marker_w); childbox.y2 = (int)(childbox.y1 + label_h); clutter_actor_allocate (priv->label, &childbox, flags); menu = (ClutterActor*) mx_widget_get_menu (MX_WIDGET (actor)); clutter_actor_get_preferred_height (menu, (box->x2 - box->x1), &min_menu_h, &nat_menu_h); childbox.x1 = 0; childbox.x2 = (box->x2 - box->x1); childbox.y1 = (box->y2 - box->y1); stage = clutter_actor_get_stage (actor); if (stage != NULL) { ClutterVertex point = { 0, }; gfloat stage_w, stage_h, combo_h = box->y2 - box->y1; clutter_actor_get_size (stage, &stage_w, &stage_h); point.y = combo_h + nat_menu_h; clutter_actor_apply_transform_to_point (actor, &point, &point); /* If the menu would appear off the stage, flip it around. */ if ((point.x < 0) || (point.x >= stage_w) || (point.y < 0) || (point.y >= stage_h)) { childbox.y1 = -nat_menu_h; } } childbox.y2 = childbox.y1 + nat_menu_h; clutter_actor_allocate (menu, &childbox, flags); }
static void mx_combo_box_get_preferred_width (ClutterActor *actor, gfloat for_height, gfloat *min_width_p, gfloat *natural_height_p) { gfloat height; gfloat min_w, nat_w; gfloat min_label_w, nat_label_w; gfloat min_icon_w = 0, nat_icon_w = 0; gfloat min_menu_w = 0, nat_menu_w = 0; gfloat min_marker_w = 0, nat_marker_w = 0; MxComboBoxPrivate *priv = MX_COMBO_BOX (actor)->priv; MxPadding padding; ClutterActor *menu; mx_widget_get_padding (MX_WIDGET (actor), &padding); height = for_height - padding.top - padding.bottom; menu = (ClutterActor *) mx_widget_get_menu (MX_WIDGET (actor)); if (menu) { clutter_actor_get_preferred_width (menu, -1, &min_menu_w, &nat_menu_w); } clutter_actor_get_preferred_width (priv->label, height, &min_label_w, &nat_label_w); min_w = min_label_w; nat_w = nat_label_w; if (priv->icon) { clutter_actor_get_preferred_width (priv->icon, height, &min_icon_w, &nat_icon_w); min_w += min_icon_w + priv->spacing; nat_w += nat_icon_w + priv->spacing; } if (min_menu_w > min_w) min_w = min_menu_w; if (nat_menu_w > nat_w) nat_w = nat_menu_w; if (priv->marker) { clutter_actor_get_preferred_width (priv->marker, height, &min_marker_w, &nat_marker_w); min_w += min_marker_w + priv->spacing; nat_w += nat_marker_w + priv->spacing; } if (min_width_p) *min_width_p = padding.left + padding.right + min_w; if (natural_height_p) *natural_height_p = padding.left + padding.right + nat_w; }