summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorP. F. Chimento <philip.chimento@gmail.com>2013-07-24 10:17:19 -0700
committerP. F. Chimento <philip.chimento@gmail.com>2013-07-24 10:17:19 -0700
commit3bbf1c4223d4b05a790b22e24c74ec144ce48c34 (patch)
tree94b1329b4a7ec8ce999183e027040b11e3023f2a
parent1ff95e823772b048a5c966235a7f3a7b5ab3681a (diff)
parentb6d8e1da288e7b1dab3cc792f8b7dd449f6db6cd (diff)
Merge pull request #170 from endlessm/issues/146
#146 Layout of `EosActionMenu`
-rw-r--r--endless/eosactionmenu-private.h6
-rw-r--r--endless/eosactionmenu.c94
-rw-r--r--test/smoke-tests/action-buttons.js25
-rw-r--r--test/smoke-tests/eosactionbutton.css1
-rw-r--r--test/test-action-menu.c52
5 files changed, 150 insertions, 28 deletions
diff --git a/endless/eosactionmenu-private.h b/endless/eosactionmenu-private.h
index 8b3755e..4393fdc 100644
--- a/endless/eosactionmenu-private.h
+++ b/endless/eosactionmenu-private.h
@@ -37,21 +37,21 @@ typedef struct _EosActionMenuPrivate EosActionMenuPrivate;
struct _EosActionMenu
{
- GtkGrid parent;
+ GtkFrame parent;
EosActionMenuPrivate *priv;
};
struct _EosActionMenuClass
{
- GtkGridClass parent_class;
+ GtkFrameClass parent_class;
};
GType eos_action_menu_get_type (void) G_GNUC_CONST;
GtkWidget *eos_action_menu_new ();
-void eos_action_menu_add_action (EosActionMenu *menu,
+void eos_action_menu_add_action (EosActionMenu *menu,
GtkAction *action);
GtkAction *eos_action_menu_get_action (EosActionMenu *menu,
diff --git a/endless/eosactionmenu.c b/endless/eosactionmenu.c
index e3466e2..0f45305 100644
--- a/endless/eosactionmenu.c
+++ b/endless/eosactionmenu.c
@@ -17,13 +17,17 @@
*/
-G_DEFINE_TYPE (EosActionMenu, eos_action_menu, GTK_TYPE_GRID)
+G_DEFINE_TYPE (EosActionMenu, eos_action_menu, GTK_TYPE_FRAME)
#define EOS_ACTION_MENU_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), EOS_TYPE_ACTION_MENU, EosActionMenuPrivate))
struct _EosActionMenuPrivate
{
+ GtkWidget *overlay;
+ GtkWidget *center_grid;
+ GtkWidget *bottom_grid;
+
GtkActionGroup *action_group;
};
@@ -58,13 +62,44 @@ eos_action_menu_init (EosActionMenu *self)
context = gtk_widget_get_style_context (GTK_WIDGET (self));
gtk_style_context_add_class (context, _EOS_STYLE_CLASS_ACTION_MENU);
+ priv->overlay = gtk_overlay_new ();
+ g_object_set (G_OBJECT (priv->overlay),
+ "halign", GTK_ALIGN_FILL,
+ "valign", GTK_ALIGN_FILL,
+ "hexpand", TRUE,
+ "vexpand", TRUE,
+ NULL);
+
+ priv->center_grid = gtk_grid_new ();
+ g_object_set (G_OBJECT (priv->center_grid),
+ "orientation", GTK_ORIENTATION_VERTICAL,
+ "halign", GTK_ALIGN_CENTER,
+ "valign", GTK_ALIGN_CENTER,
+ NULL);
+
+ priv->bottom_grid = gtk_grid_new ();
+ g_object_set (G_OBJECT (priv->bottom_grid),
+ "orientation", GTK_ORIENTATION_VERTICAL,
+ "halign", GTK_ALIGN_CENTER,
+ "valign", GTK_ALIGN_END,
+ NULL);
+
+ // this is ugly, but needed so the overlay takes all the available space
+ GtkWidget* placeholder = gtk_event_box_new();
+ gtk_widget_set_hexpand (placeholder, TRUE);
+ gtk_widget_set_vexpand (placeholder, TRUE);
+ gtk_container_add (GTK_CONTAINER (priv->overlay), placeholder);
+
+ gtk_overlay_add_overlay (GTK_OVERLAY (priv->overlay), priv->center_grid);
+ gtk_overlay_add_overlay (GTK_OVERLAY (priv->overlay), priv->bottom_grid);
+
+ gtk_container_add (GTK_CONTAINER (self), priv->overlay);
+
// TODO : name?
priv->action_group = gtk_action_group_new ("EosActionMenu");
gtk_widget_set_hexpand (GTK_WIDGET (self), TRUE);
gtk_widget_set_vexpand (GTK_WIDGET (self), TRUE);
- gtk_widget_set_halign (GTK_WIDGET (self), GTK_ALIGN_CENTER);
- gtk_widget_set_valign (GTK_WIDGET (self), GTK_ALIGN_CENTER);
}
/* ******* LIFECYCLE ******* */
@@ -99,8 +134,15 @@ eos_action_menu_finalize (GObject *object)
* @menu: a #EosActionMenu
* @action: a #GtkAction: name, label, icon-name, is-important.
*
- * Adds an action to the #EosActionMenu, using its name, label, icon-name and
- * is-important properties.
+ * Adds an action to the #EosActionMenu, using its #GtkAction:name,
+ * #GtkAction:label, #GtkAction:icon-name, #GtkAction:is-important and
+ * #GtkAction:stock-id properties.
+ *
+ * Cancel, close and delete actions are placed at the bottom of the menu. To
+ * indicate this, set the #GtkAction:stock-id property to one of
+ * #GTK_STOCK_CANCEL, #GTK_STOCK_CLOSE or #GTK_STOCK_DELETE. All other values of
+ * this property will be ignored.
+ *
*/
void
eos_action_menu_add_action (EosActionMenu *menu,
@@ -125,9 +167,16 @@ eos_action_menu_add_action (EosActionMenu *menu,
gtk_activatable_set_related_action (GTK_ACTIVATABLE (action_button), action);
- // TODO : maybe we need a finer control, taking is-important into account?
- gtk_grid_attach_next_to (GTK_GRID (menu), action_button, NULL,
- GTK_POS_BOTTOM, 1, 1);
+ if (g_strcmp0 (gtk_action_get_stock_id (action), GTK_STOCK_CANCEL) == 0 ||
+ g_strcmp0 (gtk_action_get_stock_id (action), GTK_STOCK_CLOSE) == 0 ||
+ g_strcmp0 (gtk_action_get_stock_id (action), GTK_STOCK_DELETE) == 0)
+ {
+ gtk_container_add (GTK_CONTAINER (priv->bottom_grid), action_button);
+ }
+ else
+ {
+ gtk_container_add (GTK_CONTAINER (priv->center_grid), action_button);
+ }
}
}
@@ -179,10 +228,37 @@ eos_action_menu_remove_action (EosActionMenu *menu,
GtkAction *action)
{
EosActionMenuPrivate *priv;
+ GList *children, *i;
+ GtkWidget *target_child = NULL;
+
g_return_if_fail (EOS_IS_ACTION_MENU (menu));
+ g_return_if_fail (GTK_IS_ACTION (action));
priv = menu->priv;
gtk_action_group_remove_action(priv->action_group, action);
+
+ children = gtk_container_get_children (GTK_CONTAINER (priv->center_grid));
+
+ children = g_list_concat (children,
+ gtk_container_get_children (GTK_CONTAINER (priv->bottom_grid)));
+
+ for (i = children; i != NULL; i = i->next)
+ {
+ GtkWidget *child = i->data;
+ GtkAction *childs_action = gtk_activatable_get_related_action (GTK_ACTIVATABLE (child));
+
+ if (childs_action != NULL &&
+ g_strcmp0 (gtk_action_get_name (childs_action), gtk_action_get_name (action)) == 0)
+ {
+ target_child = child;
+ break;
+ }
+ }
+
+ if (target_child != NULL)
+ {
+ gtk_widget_destroy (target_child);
+ }
}
/*
@@ -205,7 +281,7 @@ eos_action_menu_remove_action_by_name (EosActionMenu *menu,
action = gtk_action_group_get_action (priv->action_group, name);
if (action)
{
- gtk_action_group_remove_action (priv->action_group, action);
+ eos_action_menu_remove_action (menu, action);
}
}
diff --git a/test/smoke-tests/action-buttons.js b/test/smoke-tests/action-buttons.js
index 7997793..476912a 100644
--- a/test/smoke-tests/action-buttons.js
+++ b/test/smoke-tests/action-buttons.js
@@ -24,9 +24,9 @@ const TestApplication = new Lang.Class ({
this._darkSwitch = new Gtk.Switch ({active: false});
this._darkSwitch.connect ('notify::active', Lang.bind (this, function (active) {
if (this._darkSwitch.get_active()) {
- this._menu_panel.get_style_context().add_class('dark');
+ this._menu.get_style_context().add_class('dark');
} else {
- this._menu_panel.get_style_context().remove_class('dark');
+ this._menu.get_style_context().remove_class('dark');
}
}));
this._content.attach(new Gtk.Label ({label: 'Dark action menu'}), 0, 0, 1, 1);
@@ -57,23 +57,17 @@ const TestApplication = new Lang.Class ({
'label-position': Gtk.PositionType.RIGHT
}), 1, 2, 1, 1);
- this._menu = new Endless.ActionMenu ();
+ this._menu = new Endless.ActionMenu ({name: 'menu'});
- // put the ActionMenu in a panel, as GtkGrid doesn't expand if none of its children want to
- this._menu_panel = new Gtk.Frame ({name: 'menu'});
- this._menu_panel.add (this._menu);
- this._menu_panel.set_hexpand (true);
- this._menu_panel.set_vexpand (true);
-
// the ActionMenu takes 1/6 of the width
this._page.set_column_homogeneous (true);
this._page.attach (this._content, 0, 0, 5, 1);
- this._page.attach (this._menu_panel, 5, 0, 1, 1);
+ this._page.attach (this._menu, 5, 0, 1, 1);
this._menu.add_action ({
name: 'select',
'icon-name': 'object-select-symbolic',
- label: 'select stuff',
+ label: 'SELECT',
'is-important': true },
Lang.bind(this, function () {
var md = new Gtk.MessageDialog({modal:true, title:"Information",
@@ -86,19 +80,20 @@ const TestApplication = new Lang.Class ({
this._menu.add_action ({
name: 'delete',
'icon-name': 'edit-delete-symbolic',
- label: 'delete stuff',
- 'is-important': false });
+ label: 'DELETE',
+ 'is-important': false,
+ 'stock-id': Gtk.STOCK_DELETE });
this._menu.add_action ({
name: 'smile',
'icon-name': 'face-smile-symbolic',
- label: 'smile',
+ label: 'SMILE',
'is-important': false });
this._menu.add_action ({
name: 'sadface',
'icon-name': 'face-sad-symbolic',
- label: 'sadface',
+ label: 'SAD FACE',
'is-important': false });
this._pm = new Endless.PageManager();
diff --git a/test/smoke-tests/eosactionbutton.css b/test/smoke-tests/eosactionbutton.css
index b01e3cf..189a15a 100644
--- a/test/smoke-tests/eosactionbutton.css
+++ b/test/smoke-tests/eosactionbutton.css
@@ -8,6 +8,7 @@ GtkWindow {
background-color: mix(white, black, 0.2);
border-color: mix(white, black, 0.5);
border-width: 0 0 0 6px;
+ padding: 30px;
}
.dark#menu {
diff --git a/test/test-action-menu.c b/test/test-action-menu.c
index b12ff8d..e066b70 100644
--- a/test/test-action-menu.c
+++ b/test/test-action-menu.c
@@ -5,6 +5,8 @@
#include "run-tests.h"
+#include "endless/eosactionmenu.c"
+
#define ADD_ACTION_MENU_TEST(path, test_func) \
g_test_add ((path), ActionMenuFixture, NULL, \
am_fixture_setup, (test_func), am_fixture_teardown)
@@ -55,7 +57,7 @@ test_am_add_action (ActionMenuFixture *fixture,
eos_action_menu_add_action (fixture->action_menu, fixture->action1);
- GtkWidget *button = gtk_grid_get_child_at (GTK_GRID (fixture->action_menu), 0, 0);
+ GtkWidget *button = gtk_grid_get_child_at (GTK_GRID (fixture->action_menu->priv->center_grid), 0, 0);
g_assert (EOS_IS_ACTION_BUTTON (button));
@@ -103,6 +105,35 @@ test_am_list_actions (ActionMenuFixture *fixture,
g_assert (g_list_find (list, fixture->action3) == NULL);
}
+static gboolean
+menu_contains_button_with_label (EosActionMenu *menu, const gchar* button_label)
+{
+ GList* children;
+ gboolean found = FALSE;
+
+ children = gtk_container_get_children (GTK_CONTAINER (menu->priv->center_grid));
+
+ children = g_list_concat (children,
+ gtk_container_get_children (GTK_CONTAINER (menu->priv->bottom_grid)));
+
+ for (GList *i = children; i != NULL ; i = i->next)
+ {
+ if (EOS_IS_ACTION_BUTTON (i->data))
+ {
+ if (g_strcmp0 (eos_action_button_get_label (EOS_ACTION_BUTTON (i->data)),
+ button_label) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+
+ g_list_free (children);
+
+ return found;
+}
+
static void
test_am_remove_action (ActionMenuFixture *fixture,
gconstpointer unused)
@@ -121,6 +152,14 @@ test_am_remove_action (ActionMenuFixture *fixture,
g_assert (g_list_find (list, fixture->action2) == NULL);
g_assert (g_list_find (list, fixture->action3) != NULL);
+ // the buttons have been removed as well
+ g_assert (menu_contains_button_with_label (fixture->action_menu,
+ gtk_action_get_label (fixture->action1)));
+ g_assert (!menu_contains_button_with_label (fixture->action_menu,
+ gtk_action_get_label (fixture->action2)));
+ g_assert (menu_contains_button_with_label (fixture->action_menu,
+ gtk_action_get_label (fixture->action3)));
+
eos_action_menu_remove_action (fixture->action_menu, fixture->action1);
eos_action_menu_remove_action (fixture->action_menu, fixture->action3);
@@ -129,6 +168,10 @@ test_am_remove_action (ActionMenuFixture *fixture,
g_assert (g_list_find (list, fixture->action1) == NULL);
g_assert (g_list_find (list, fixture->action2) == NULL);
g_assert (g_list_find (list, fixture->action3) == NULL);
+
+ // the container is empty
+ g_assert (gtk_container_get_children (GTK_CONTAINER (fixture->action_menu->priv->center_grid)) == NULL);
+ g_assert (gtk_container_get_children (GTK_CONTAINER (fixture->action_menu->priv->bottom_grid)) == NULL);
}
static void
@@ -146,6 +189,13 @@ test_am_remove_action_by_name (ActionMenuFixture *fixture,
g_assert (g_list_find (list, fixture->action1) != NULL);
g_assert (g_list_find (list, fixture->action2) == NULL);
g_assert (g_list_find (list, fixture->action3) != NULL);
+
+ g_assert (menu_contains_button_with_label (fixture->action_menu,
+ gtk_action_get_label (fixture->action1)));
+ g_assert (!menu_contains_button_with_label (fixture->action_menu,
+ gtk_action_get_label (fixture->action2)));
+ g_assert (menu_contains_button_with_label (fixture->action_menu,
+ gtk_action_get_label (fixture->action3)));
}
void