340 lines
8.4 KiB
C
340 lines
8.4 KiB
C
#include "ag-header-bar.h"
|
|
#include "ag-enumtypes.h"
|
|
|
|
#define DEFAULT_MODE AG_HEADER_BAR_MODE_LIST
|
|
|
|
typedef struct {
|
|
GtkWidget *selection_cancel_button;
|
|
GtkWidget *left_stack;
|
|
GtkWidget *right_stack;
|
|
|
|
AgHeaderBarMode mode;
|
|
} AgHeaderBarPrivate;
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_MODE,
|
|
PROP_COUNT
|
|
};
|
|
|
|
enum {
|
|
SIGNAL_MODE_CHANGED,
|
|
SIGNAL_COUNT
|
|
};
|
|
|
|
static void ag_header_bar_dispose(GObject *gobject);
|
|
static void ag_header_bar_finalize(GObject *gobject);
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE(AgHeaderBar, ag_header_bar, GTK_TYPE_HEADER_BAR);
|
|
|
|
#define GET_PRIV(v, o) AgHeaderBarPrivate *v = ag_header_bar_get_instance_private(o);
|
|
|
|
static GParamSpec *properties[PROP_COUNT];
|
|
static guint signals[SIGNAL_COUNT] = { 0 };
|
|
|
|
static void
|
|
ag_header_bar_selection_mode_cb(GtkButton *button,
|
|
AgHeaderBar *header_bar)
|
|
{
|
|
GET_PRIV(priv, header_bar);
|
|
|
|
/* If we are not in list mode, this transition is invalid */
|
|
if (priv->mode != AG_HEADER_BAR_MODE_LIST) {
|
|
g_warning("Invalid header bar mode transition!");
|
|
|
|
return;
|
|
}
|
|
|
|
g_signal_emit(
|
|
header_bar,
|
|
signals[SIGNAL_MODE_CHANGED], 0,
|
|
AG_HEADER_BAR_MODE_SELECTION
|
|
);
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_selection_cancel_cb(GtkButton *button,
|
|
AgHeaderBar *header_bar)
|
|
{
|
|
GET_PRIV(priv, header_bar);
|
|
|
|
/* If we are not in selection mode, this transition is invalid */
|
|
if (priv->mode != AG_HEADER_BAR_MODE_SELECTION) {
|
|
g_warning("Invalid header bar mode transition!");
|
|
|
|
return;
|
|
}
|
|
|
|
g_signal_emit(
|
|
header_bar,
|
|
signals[SIGNAL_MODE_CHANGED], 0,
|
|
AG_HEADER_BAR_MODE_LIST
|
|
);
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_back_cb(GtkButton *button,
|
|
AgHeaderBar *header_bar)
|
|
{
|
|
GET_PRIV(priv, header_bar);
|
|
|
|
/* If we are not in chart mode, this transition is invalid */
|
|
if (priv->mode != AG_HEADER_BAR_MODE_CHART) {
|
|
g_warning("Invalid header bar mode transition!");
|
|
|
|
return;
|
|
}
|
|
|
|
g_signal_emit(
|
|
header_bar,
|
|
signals[SIGNAL_MODE_CHANGED], 0,
|
|
AG_HEADER_BAR_MODE_LIST
|
|
);
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_set_selection_mode(AgHeaderBar *header_bar, gboolean state)
|
|
{
|
|
GtkStyleContext *style;
|
|
GET_PRIV(priv, header_bar);
|
|
|
|
if (state == (priv->mode == AG_HEADER_BAR_MODE_SELECTION)) {
|
|
return;
|
|
}
|
|
|
|
style = gtk_widget_get_style_context(GTK_WIDGET(header_bar));
|
|
|
|
if (state) {
|
|
// Enabling selection mode
|
|
gtk_stack_set_visible_child_name(
|
|
GTK_STACK(priv->right_stack),
|
|
"selection"
|
|
);
|
|
gtk_widget_hide(priv->left_stack);
|
|
gtk_style_context_add_class(style, "selection-mode");
|
|
} else {
|
|
// Disabling selection mode
|
|
gtk_widget_show(priv->left_stack);
|
|
gtk_style_context_remove_class(style, "selection-mode");
|
|
}
|
|
|
|
gtk_header_bar_set_show_close_button(
|
|
GTK_HEADER_BAR(header_bar),
|
|
!state
|
|
);
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_set_mode_internal(AgHeaderBar *header_bar,
|
|
AgHeaderBarMode mode,
|
|
gboolean force)
|
|
{
|
|
gboolean invalid = FALSE;
|
|
AgHeaderBarMode old_mode;
|
|
GET_PRIV(priv, header_bar);
|
|
|
|
if (!force && (priv->mode == mode)) {
|
|
return;
|
|
}
|
|
|
|
old_mode = priv->mode;
|
|
|
|
switch (mode) {
|
|
case AG_HEADER_BAR_MODE_LIST:
|
|
gtk_stack_set_visible_child_name(
|
|
GTK_STACK(priv->left_stack),
|
|
"list"
|
|
);
|
|
gtk_stack_set_visible_child_name(
|
|
GTK_STACK(priv->right_stack),
|
|
"list"
|
|
);
|
|
ag_header_bar_set_selection_mode(header_bar, FALSE);
|
|
|
|
break;
|
|
|
|
case AG_HEADER_BAR_MODE_CHART:
|
|
gtk_stack_set_visible_child_name(
|
|
GTK_STACK(priv->left_stack),
|
|
"chart"
|
|
);
|
|
gtk_stack_set_visible_child_name(
|
|
GTK_STACK(priv->right_stack),
|
|
"chart"
|
|
);
|
|
ag_header_bar_set_selection_mode(header_bar, FALSE);
|
|
|
|
break;
|
|
|
|
case AG_HEADER_BAR_MODE_SELECTION:
|
|
ag_header_bar_set_selection_mode(header_bar, TRUE);
|
|
|
|
break;
|
|
|
|
default:
|
|
invalid = TRUE;
|
|
g_warning("Invalid header bar mode!");
|
|
|
|
break;
|
|
}
|
|
|
|
if (invalid) {
|
|
priv->mode = old_mode;
|
|
} else {
|
|
priv->mode = mode;
|
|
g_object_notify_by_pspec(G_OBJECT(header_bar), properties[PROP_MODE]);
|
|
}
|
|
}
|
|
|
|
void
|
|
ag_header_bar_set_mode(AgHeaderBar *header_bar,
|
|
AgHeaderBarMode mode)
|
|
{
|
|
ag_header_bar_set_mode_internal(header_bar, mode, FALSE);
|
|
}
|
|
|
|
AgHeaderBarMode
|
|
ag_header_bar_get_mode(AgHeaderBar *header_bar)
|
|
{
|
|
GET_PRIV(priv, header_bar);
|
|
|
|
return priv->mode;
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_set_property(GObject *gobject,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
switch (prop_id) {
|
|
case PROP_MODE:
|
|
ag_header_bar_set_mode(
|
|
AG_HEADER_BAR(gobject),
|
|
g_value_get_enum(value)
|
|
);
|
|
|
|
return;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_get_property(GObject *gobject,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GET_PRIV(priv, AG_HEADER_BAR(gobject));
|
|
|
|
switch (prop_id) {
|
|
case PROP_MODE:
|
|
g_value_set_enum(value, priv->mode);
|
|
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_dispose(GObject *gobject)
|
|
{
|
|
G_OBJECT_CLASS(ag_header_bar_parent_class)->dispose(gobject);
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_finalize(GObject *gobject)
|
|
{
|
|
g_signal_handlers_destroy(gobject);
|
|
G_OBJECT_CLASS(ag_header_bar_parent_class)->finalize(gobject);
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_class_init(AgHeaderBarClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = (GObjectClass *)klass;
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
|
|
|
|
gobject_class->dispose = ag_header_bar_dispose;
|
|
gobject_class->finalize = ag_header_bar_finalize;
|
|
gobject_class->set_property = ag_header_bar_set_property;
|
|
gobject_class->get_property = ag_header_bar_get_property;
|
|
|
|
properties[PROP_MODE] = g_param_spec_enum(
|
|
"mode",
|
|
"Mode",
|
|
"Header bar mode",
|
|
AG_TYPE_HEADER_BAR_MODE,
|
|
AG_HEADER_BAR_MODE_LIST,
|
|
G_PARAM_STATIC_STRINGS
|
|
| G_PARAM_READWRITE
|
|
);
|
|
g_object_class_install_property(
|
|
gobject_class,
|
|
PROP_MODE,
|
|
properties[PROP_MODE]
|
|
);
|
|
|
|
signals[SIGNAL_MODE_CHANGED] = g_signal_new(
|
|
"mode-changed",
|
|
AG_TYPE_HEADER_BAR,
|
|
G_SIGNAL_RUN_FIRST,
|
|
0,
|
|
NULL, NULL,
|
|
NULL,
|
|
G_TYPE_NONE,
|
|
1,
|
|
AG_TYPE_HEADER_BAR_MODE
|
|
);
|
|
|
|
gtk_widget_class_set_template_from_resource(
|
|
widget_class,
|
|
"/eu/polonkai/gergely/Astrognome/ui/ag-header-bar.ui"
|
|
);
|
|
|
|
gtk_widget_class_bind_template_child_private(
|
|
widget_class,
|
|
AgHeaderBar,
|
|
selection_cancel_button
|
|
);
|
|
gtk_widget_class_bind_template_child_private(
|
|
widget_class,
|
|
AgHeaderBar,
|
|
left_stack
|
|
);
|
|
gtk_widget_class_bind_template_child_private(
|
|
widget_class,
|
|
AgHeaderBar,
|
|
right_stack
|
|
);
|
|
|
|
gtk_widget_class_bind_template_callback(
|
|
widget_class,
|
|
ag_header_bar_selection_mode_cb
|
|
);
|
|
gtk_widget_class_bind_template_callback(
|
|
widget_class,
|
|
ag_header_bar_selection_cancel_cb
|
|
);
|
|
gtk_widget_class_bind_template_callback(
|
|
widget_class,
|
|
ag_header_bar_back_cb
|
|
);
|
|
}
|
|
|
|
static void
|
|
ag_header_bar_init(AgHeaderBar *header_bar)
|
|
{
|
|
gtk_widget_init_template(GTK_WIDGET(header_bar));
|
|
|
|
ag_header_bar_set_mode_internal(header_bar, DEFAULT_MODE, TRUE);
|
|
}
|