summaryrefslogtreecommitdiff
path: root/endless
diff options
context:
space:
mode:
authorPhilip Chimento <philip@endlessm.com>2015-03-24 22:27:58 -0700
committerPhilip Chimento <philip@endlessm.com>2015-03-25 17:46:13 -0700
commitceeaf43e1d57a9c18ab18e45ecebad8e3c799165 (patch)
tree0ca5e353f765161939ccd27cd9fd5d1e5a16a236 /endless
parentab029d49fa0d40b027bc2a4e29defac176151eff (diff)
Make image credits discoverable
This adds a fourth topbar button, to the left of the minimize button, that is invisible by default. When you mouse over the space where it would be, it appears. When you click on it, it activates the image credits dialog. [endlessm/eos-sdk#2934]
Diffstat (limited to 'endless')
-rw-r--r--endless/eosapplication.c18
-rw-r--r--endless/eostopbar-private.h5
-rw-r--r--endless/eostopbar.c175
-rw-r--r--endless/eoswindow.c41
4 files changed, 234 insertions, 5 deletions
diff --git a/endless/eosapplication.c b/endless/eosapplication.c
index 91dbd73..510ff3b 100644
--- a/endless/eosapplication.c
+++ b/endless/eosapplication.c
@@ -612,6 +612,16 @@ eos_application_class_init (EosApplicationClass *klass)
}
static void
+set_image_credits_action_enabled (EosApplication *self,
+ gboolean enabled)
+{
+ GAction *action = g_action_map_lookup_action (G_ACTION_MAP (self),
+ "image-credits");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
+ /* action map owns action */
+}
+
+static void
eos_application_init (EosApplication *self)
{
EosApplicationPrivate *priv = eos_application_get_instance_private (self);
@@ -623,6 +633,7 @@ eos_application_init (EosApplication *self)
};
g_action_map_add_action_entries (G_ACTION_MAP (self), actions,
G_N_ELEMENTS (actions), self);
+ set_image_credits_action_enabled (self, FALSE);
g_signal_connect (self, "notify::application-id",
G_CALLBACK (on_app_id_set), self);
@@ -734,11 +745,8 @@ eos_application_set_image_attribution_file (EosApplication *self,
if (priv->image_attribution_file == NULL || file == NULL)
{
- GAction *action = g_action_map_lookup_action (G_ACTION_MAP (self),
- "image-credits");
- gboolean enabled = (file == NULL);
- g_simple_action_set_enabled (G_SIMPLE_ACTION (self), enabled);
- /* action map owns action */
+ gboolean enabled = (file != NULL);
+ set_image_credits_action_enabled (self, enabled);
}
g_clear_object (&priv->image_attribution_file);
diff --git a/endless/eostopbar-private.h b/endless/eostopbar-private.h
index 3d0f4a7..aa6e44b 100644
--- a/endless/eostopbar-private.h
+++ b/endless/eostopbar-private.h
@@ -57,6 +57,11 @@ void eos_top_bar_set_center_widget (EosTopBar *self,
void eos_top_bar_update_window_maximized (EosTopBar *self,
gboolean is_maximized);
+gboolean eos_top_bar_get_show_credits_button (EosTopBar *self);
+
+void eos_top_bar_set_show_credits_button (EosTopBar *self,
+ gboolean show_credits_button);
+
G_END_DECLS
#endif /* EOS_TOP_BAR_H */
diff --git a/endless/eostopbar.c b/endless/eostopbar.c
index 9d7f276..3c1596d 100644
--- a/endless/eostopbar.c
+++ b/endless/eostopbar.c
@@ -29,6 +29,7 @@
#define _EOS_TOP_BAR_MAXIMIZE_ICON_NAME "window-maximize-symbolic"
#define _EOS_TOP_BAR_UNMAXIMIZE_ICON_NAME "window-unmaximize-symbolic"
#define _EOS_TOP_BAR_CLOSE_ICON_NAME "window-close-symbolic"
+#define _EOS_TOP_BAR_CREDITS_ICON_NAME "user-info-symbolic"
typedef struct {
GtkWidget *actions_grid;
@@ -44,6 +45,13 @@ typedef struct {
GtkWidget *maximize_icon;
GtkWidget *close_button;
GtkWidget *close_icon;
+ GtkWidget *credits_button;
+ GtkWidget *credits_icon;
+ GtkWidget *credits_stack;
+
+ gboolean show_credits_button;
+ guint credits_enter_handler;
+ guint credits_leave_handler;
} EosTopBarPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (EosTopBar, eos_top_bar, GTK_TYPE_EVENT_BOX)
@@ -52,11 +60,58 @@ enum {
CLOSE_CLICKED,
MINIMIZE_CLICKED,
MAXIMIZE_CLICKED,
+ CREDITS_CLICKED,
LAST_SIGNAL
};
static guint top_bar_signals[LAST_SIGNAL] = { 0 };
+enum {
+ PROP_0,
+ PROP_SHOW_CREDITS_BUTTON,
+ NPROPS
+};
+
+static GParamSpec *eos_top_bar_props[NPROPS] = { NULL, };
+
+static void
+eos_top_bar_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EosTopBar *self = EOS_TOP_BAR (object);
+
+ switch (property_id)
+ {
+ case PROP_SHOW_CREDITS_BUTTON:
+ g_value_set_boolean (value, eos_top_bar_get_show_credits_button (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+eos_top_bar_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EosTopBar *self = EOS_TOP_BAR (object);
+
+ switch (property_id)
+ {
+ case PROP_SHOW_CREDITS_BUTTON:
+ eos_top_bar_set_show_credits_button (self, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
static void
eos_top_bar_get_preferred_height (GtkWidget *widget,
int *minimum,
@@ -98,6 +153,8 @@ eos_top_bar_class_init (EosTopBarClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ object_class->get_property = eos_top_bar_get_property;
+ object_class->set_property = eos_top_bar_set_property;
widget_class->get_preferred_height = eos_top_bar_get_preferred_height;
widget_class->draw = eos_top_bar_draw;
@@ -133,6 +190,19 @@ eos_top_bar_class_init (EosTopBarClass *klass)
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
+
+ top_bar_signals[CREDITS_CLICKED] =
+ g_signal_new ("credits-clicked", G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, 0, NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+
+ eos_top_bar_props[PROP_SHOW_CREDITS_BUTTON] =
+ g_param_spec_boolean ("show-credits-button", "Show credits button",
+ "Whether the credits button is discoverable",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, NPROPS, eos_top_bar_props);
}
static void
@@ -159,6 +229,23 @@ on_close_clicked_cb (GtkButton *button,
g_signal_emit (self, top_bar_signals[CLOSE_CLICKED], 0);
}
+static gboolean
+on_stack_hover (GtkStack *stack,
+ GdkEvent *event,
+ gpointer data)
+{
+ gboolean show = GPOINTER_TO_INT (data);
+ gtk_stack_set_visible_child_name (stack, show ? "button" : "blank");
+ return GDK_EVENT_PROPAGATE;
+}
+
+static void
+on_credits_clicked (GtkButton *button,
+ EosTopBar *self)
+{
+ g_signal_emit (self, top_bar_signals[CREDITS_CLICKED], 0);
+}
+
static void
eos_top_bar_init (EosTopBar *self)
{
@@ -236,10 +323,36 @@ eos_top_bar_init (EosTopBar *self)
gtk_container_add (GTK_CONTAINER (priv->close_button),
priv->close_icon);
+ /* This works like a revealer but it's really a GtkStack so that it takes up
+ space and presents a target even when it's not shown. */
+ priv->credits_stack = gtk_stack_new ();
+ gtk_stack_set_transition_type (GTK_STACK (priv->credits_stack),
+ GTK_STACK_TRANSITION_TYPE_CROSSFADE);
+ gtk_widget_add_events (priv->credits_stack,
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+ gtk_stack_add_named (GTK_STACK (priv->credits_stack),
+ gtk_event_box_new (), "blank");
+ priv->credits_button = g_object_new (GTK_TYPE_BUTTON,
+ "can-focus", FALSE,
+ "halign", GTK_ALIGN_END,
+ "valign", GTK_ALIGN_CENTER,
+ NULL);
+ priv->credits_icon =
+ gtk_image_new_from_icon_name (_EOS_TOP_BAR_CREDITS_ICON_NAME,
+ GTK_ICON_SIZE_SMALL_TOOLBAR);
+ g_object_set (priv->credits_icon,
+ "pixel-size", _EOS_TOP_BAR_ICON_SIZE_PX,
+ "margin", _EOS_TOP_BAR_BUTTON_PADDING_PX,
+ NULL);
+ gtk_container_add (GTK_CONTAINER (priv->credits_button), priv->credits_icon);
+ gtk_stack_add_named (GTK_STACK (priv->credits_stack),
+ priv->credits_button, "button");
+
gtk_container_add (GTK_CONTAINER (priv->actions_grid),
priv->left_top_bar_attach);
gtk_container_add (GTK_CONTAINER (priv->actions_grid),
priv->center_top_bar_attach);
+ gtk_container_add (GTK_CONTAINER (priv->actions_grid), priv->credits_stack);
gtk_container_add (GTK_CONTAINER (priv->actions_grid),
priv->minimize_button);
gtk_container_add (GTK_CONTAINER (priv->actions_grid),
@@ -258,6 +371,16 @@ eos_top_bar_init (EosTopBar *self)
G_CALLBACK (on_maximize_clicked_cb), self);
g_signal_connect (priv->close_button, "clicked",
G_CALLBACK (on_close_clicked_cb), self);
+ priv->credits_enter_handler =
+ g_signal_connect (priv->credits_stack, "enter-notify-event",
+ G_CALLBACK (on_stack_hover), GINT_TO_POINTER (TRUE));
+ priv->credits_leave_handler =
+ g_signal_connect (priv->credits_stack, "leave-notify-event",
+ G_CALLBACK (on_stack_hover), GINT_TO_POINTER (FALSE));
+ g_signal_handler_block (priv->credits_stack, priv->credits_enter_handler);
+ g_signal_handler_block (priv->credits_stack, priv->credits_leave_handler);
+ g_signal_connect (priv->credits_button, "clicked",
+ G_CALLBACK (on_credits_clicked), self);
}
GtkWidget *
@@ -355,3 +478,55 @@ eos_top_bar_update_window_maximized (EosTopBar *self,
else
gtk_style_context_remove_class (context, _EOS_STYLE_CLASS_UNMAXIMIZED);
}
+
+/*
+ * eos_top_bar_get_show_credits_button:
+ * @self: the top bar
+ *
+ * See eos_top_bar_set_show_credits_button().
+ *
+ * Returns: %TRUE if credits button should be discoverable, %FALSE if not.
+ */
+gboolean
+eos_top_bar_get_show_credits_button (EosTopBar *self)
+{
+ EosTopBarPrivate *priv = eos_top_bar_get_instance_private (self);
+ return priv->show_credits_button;
+}
+
+/*
+ * eos_top_bar_set_show_credits_button:
+ * @self: the top bar
+ * @show_credits_button: whether the credits button should be discoverable.
+ *
+ * Gets whether the credits button should be discoverable.
+ * Note that the credits button is not visible as such, but when the mouse
+ * hovers over it, it becomes visible if this is set to %TRUE.
+ * If this is %FALSE, the button never becomes visible.
+ */
+void
+eos_top_bar_set_show_credits_button (EosTopBar *self,
+ gboolean show_credits_button)
+{
+ EosTopBarPrivate *priv = eos_top_bar_get_instance_private (self);
+ if (priv->show_credits_button == show_credits_button)
+ return;
+
+ priv->show_credits_button = show_credits_button;
+ if (show_credits_button)
+ {
+ g_signal_handler_unblock (priv->credits_stack,
+ priv->credits_enter_handler);
+ g_signal_handler_unblock (priv->credits_stack,
+ priv->credits_leave_handler);
+ }
+ else
+ {
+ gtk_stack_set_visible_child_name (GTK_STACK (priv->credits_stack),
+ "blank");
+ g_signal_handler_block (priv->credits_stack, priv->credits_enter_handler);
+ g_signal_handler_block (priv->credits_stack, priv->credits_leave_handler);
+ }
+ g_object_notify_by_pspec (G_OBJECT (self),
+ eos_top_bar_props[PROP_SHOW_CREDITS_BUTTON]);
+}
diff --git a/endless/eoswindow.c b/endless/eoswindow.c
index 0b39ffb..d128a5e 100644
--- a/endless/eoswindow.c
+++ b/endless/eoswindow.c
@@ -342,6 +342,34 @@ update_page (EosWindow *self)
}
static void
+on_image_credits_enabled_changed (GActionGroup *group,
+ const gchar *action_name,
+ gboolean enabled,
+ EosWindow *self)
+{
+ EosWindowPrivate *priv = eos_window_get_instance_private (self);
+ eos_top_bar_set_show_credits_button (EOS_TOP_BAR (priv->top_bar), enabled);
+}
+
+static void
+eos_window_constructed (GObject *object)
+{
+ EosWindow *self = EOS_WINDOW (object);
+ EosWindowPrivate *priv = eos_window_get_instance_private (self);
+
+ G_OBJECT_CLASS (eos_window_parent_class)->constructed (object);
+
+ GtkApplication *application =
+ gtk_window_get_application (GTK_WINDOW (object));
+ GFile *credits_file =
+ eos_application_get_image_attribution_file (EOS_APPLICATION (application));
+ eos_top_bar_set_show_credits_button (EOS_TOP_BAR (priv->top_bar),
+ (credits_file != NULL));
+ g_signal_connect (application, "action-enabled-changed::image-credits",
+ G_CALLBACK (on_image_credits_enabled_changed), self);
+}
+
+static void
eos_window_get_property (GObject *object,
guint property_id,
GValue *value,
@@ -510,6 +538,7 @@ eos_window_class_init (EosWindowClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ object_class->constructed = eos_window_constructed;
object_class->get_property = eos_window_get_property;
object_class->set_property = eos_window_set_property;
object_class->finalize = eos_window_finalize;
@@ -631,6 +660,16 @@ on_close_clicked_cb (GtkWidget *top_bar,
gtk_window_close (GTK_WINDOW (self));
}
+static void
+on_credits_clicked (GtkWidget *top_bar,
+ EosWindow *self)
+{
+ GtkApplication *application = gtk_window_get_application (GTK_WINDOW (self));
+ /* application cannot be NULL */
+ g_action_group_activate_action (G_ACTION_GROUP (application), "image-credits",
+ NULL);
+}
+
static gboolean
on_window_state_event_cb (GtkWidget *widget,
GdkEventWindowState *event)
@@ -748,6 +787,8 @@ eos_window_init (EosWindow *self)
G_CALLBACK (on_maximize_clicked_cb), self);
g_signal_connect (priv->top_bar, "close-clicked",
G_CALLBACK (on_close_clicked_cb), self);
+ g_signal_connect (priv->top_bar, "credits-clicked",
+ G_CALLBACK (on_credits_clicked), self);
g_signal_connect (self, "window-state-event",
G_CALLBACK (on_window_state_event_cb), NULL);