astrognome/src/ag-icon-view.c

424 lines
12 KiB
C

#include "ag-enumtypes.h"
#include "ag-icon-view.h"
#include "ag-db.h"
#include "ag-chart-renderer.h"
typedef struct _AgIconViewPrivate {
AgIconViewMode mode;
AgChartRenderer *thumb_renderer;
GtkCellRenderer *text_renderer;
GtkListStore *model;
} AgIconViewPrivate;
enum {
PROP_0,
PROP_MODE,
PROP_LAST
};
enum {
AG_ICON_VIEW_COLUMN_SELECTED,
AG_ICON_VIEW_COLUMN_ITEM,
AG_ICON_VIEW_COLUMN_COLUMNS
};
G_DEFINE_TYPE_WITH_PRIVATE(AgIconView, ag_icon_view, GTK_TYPE_ICON_VIEW);
static GParamSpec *properties[PROP_LAST];
void
ag_icon_view_set_mode(AgIconView *icon_view, AgIconViewMode mode)
{
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(icon_view);
if (priv->mode != mode) {
priv->mode = mode;
if (mode != AG_ICON_VIEW_MODE_SELECTION) {
ag_icon_view_unselect_all(icon_view);
}
ag_chart_renderer_set_toggle_visible(priv->thumb_renderer, (mode == AG_ICON_VIEW_MODE_SELECTION));
gtk_widget_queue_draw(GTK_WIDGET(icon_view));
g_object_notify_by_pspec(
G_OBJECT(icon_view),
properties[PROP_MODE]
);
}
}
AgIconViewMode
ag_icon_view_get_mode(AgIconView *icon_view)
{
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(icon_view);
return priv->mode;
}
static void
ag_icon_view_set_property(GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *param_spec)
{
switch (prop_id) {
case PROP_MODE:
ag_icon_view_set_mode(
AG_ICON_VIEW(gobject),
g_value_get_enum(value)
);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
break;
}
}
static void
ag_icon_view_get_property(GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *param_spec)
{
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(
AG_ICON_VIEW(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, param_spec);
break;
}
}
static void
ag_icon_view_selection_changed(AgIconView *icon_view)
{
g_signal_emit_by_name(icon_view, "selection-changed");
}
static void
ag_icon_view_item_activated(AgIconView *icon_view, GtkTreePath *path)
{
g_signal_emit_by_name(icon_view, "item-activated", path);
}
static gboolean
ag_icon_view_button_press_event_cb(GtkWidget *widget,
GdkEventButton *event)
{
GtkTreePath *path;
GtkIconView *gtk_icon_view = GTK_ICON_VIEW(widget);
AgIconView *ag_icon_view = AG_ICON_VIEW(widget);
path = gtk_icon_view_get_path_at_pos(gtk_icon_view, ((GdkEventButton *)event)->x, ((GdkEventButton *)event)->y);
if (path != NULL) {
gboolean selected;
AgDbChartSave *chart_save;
GtkListStore *store = GTK_LIST_STORE(gtk_icon_view_get_model(gtk_icon_view));
if (event->button == GDK_BUTTON_SECONDARY) {
ag_icon_view_set_mode(ag_icon_view, AG_ICON_VIEW_MODE_SELECTION);
}
if (ag_icon_view_get_mode(ag_icon_view) == AG_ICON_VIEW_MODE_SELECTION) {
GtkTreeIter iter;
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path)) {
gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, AG_ICON_VIEW_COLUMN_SELECTED, &selected, AG_ICON_VIEW_COLUMN_ITEM, &chart_save, -1);
gtk_list_store_set(store, &iter, AG_ICON_VIEW_COLUMN_SELECTED, !selected, -1);
ag_icon_view_selection_changed(ag_icon_view);
}
} else {
ag_icon_view_item_activated(ag_icon_view, path);
}
}
return FALSE;
}
static void
ag_icon_view_class_init(AgIconViewClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
gobject_class->set_property = ag_icon_view_set_property;
gobject_class->get_property = ag_icon_view_get_property;
widget_class->button_press_event = ag_icon_view_button_press_event_cb;
properties[PROP_MODE] = g_param_spec_enum(
"mode",
"Mode",
"Mode",
AG_TYPE_ICON_VIEW_MODE,
AG_ICON_VIEW_MODE_NORMAL,
G_PARAM_STATIC_NAME
| G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
| G_PARAM_READABLE
| G_PARAM_WRITABLE
);
g_object_class_install_property(
gobject_class,
PROP_MODE,
properties[PROP_MODE]
);
}
static void
ag_icon_view_chart_renderer_func(GtkCellLayout *layout,
GtkCellRenderer *renderer,
GtkTreeModel *model,
GtkTreeIter *iter,
AgIconView *icon_view)
{
AgDbChartSave *chart_save;
gtk_tree_model_get(model, iter, AG_ICON_VIEW_COLUMN_ITEM, &chart_save, -1);
if (chart_save) {
g_object_set(renderer, "pixbuf", NULL, NULL);
}
}
static void
ag_icon_view_text_renderer_func(GtkCellLayout *layout,
GtkCellRenderer *renderer,
GtkTreeModel *model,
GtkTreeIter *iter,
AgIconView *icon_view)
{
AgDbChartSave *chart_save;
gtk_tree_model_get(model, iter, AG_ICON_VIEW_COLUMN_ITEM, &chart_save, -1);
if (chart_save) {
gchar *text;
text = g_markup_escape_text(chart_save->name, -1);
g_object_set(renderer, "markup", text, NULL);
g_free(text);
}
}
static void
ag_icon_view_init(AgIconView *icon_view)
{
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(icon_view);
guint tile_width,
tile_height;
priv->model = gtk_list_store_new(
AG_ICON_VIEW_COLUMN_COLUMNS,
G_TYPE_BOOLEAN,
AG_TYPE_DB_CHART_SAVE
);
gtk_icon_view_set_model(
GTK_ICON_VIEW(icon_view),
GTK_TREE_MODEL(priv->model)
);
gtk_icon_view_set_selection_mode(
GTK_ICON_VIEW(icon_view),
GTK_SELECTION_NONE
);
priv->mode = AG_ICON_VIEW_MODE_NORMAL;
gtk_icon_view_set_item_padding(GTK_ICON_VIEW(icon_view), 0);
gtk_icon_view_set_margin(GTK_ICON_VIEW(icon_view), 12);
tile_width = AG_CHART_RENDERER_TILE_SIZE
+ 2 * AG_CHART_RENDERER_TILE_MARGIN;
tile_height = AG_CHART_RENDERER_TILE_SIZE
+ AG_CHART_RENDERER_TILE_MARGIN
+ AG_CHART_RENDERER_TILE_MARGIN_BOTTOM;
priv->thumb_renderer = ag_chart_renderer_new();
gtk_cell_renderer_set_alignment(
GTK_CELL_RENDERER(priv->thumb_renderer),
0.5, 0.5
);
gtk_cell_renderer_set_fixed_size(
GTK_CELL_RENDERER(priv->thumb_renderer),
tile_width, tile_height
);
gtk_cell_layout_pack_start(
GTK_CELL_LAYOUT(icon_view),
GTK_CELL_RENDERER(priv->thumb_renderer),
FALSE
);
gtk_cell_layout_add_attribute(
GTK_CELL_LAYOUT(icon_view),
GTK_CELL_RENDERER(priv->thumb_renderer),
"checked", AG_ICON_VIEW_COLUMN_SELECTED
);
gtk_cell_layout_set_cell_data_func(
GTK_CELL_LAYOUT(icon_view),
GTK_CELL_RENDERER(priv->thumb_renderer),
(GtkCellLayoutDataFunc)ag_icon_view_chart_renderer_func,
icon_view,
NULL
);
priv->text_renderer = gtk_cell_renderer_text_new();
gtk_cell_renderer_set_alignment(
GTK_CELL_RENDERER(priv->text_renderer),
0.5, 0.5
);
gtk_cell_layout_pack_start(
GTK_CELL_LAYOUT(icon_view),
priv->text_renderer,
TRUE
);
gtk_cell_layout_set_cell_data_func(
GTK_CELL_LAYOUT(icon_view),
GTK_CELL_RENDERER(priv->text_renderer),
(GtkCellLayoutDataFunc)ag_icon_view_text_renderer_func,
icon_view,
NULL
);
}
void
ag_icon_view_add_chart(AgIconView *icon_view, AgDbChartSave *chart_save)
{
GtkTreeIter iter;
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(icon_view);
g_debug("Adding chart for %s", chart_save->name);
gtk_list_store_append(priv->model, &iter);
gtk_list_store_set(
priv->model, &iter,
AG_ICON_VIEW_COLUMN_SELECTED, FALSE,
AG_ICON_VIEW_COLUMN_ITEM, chart_save,
-1
);
}
static gboolean
ag_icon_view_check_selected(GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
GList **list)
{
gboolean selected;
gtk_tree_model_get(model, iter, AG_ICON_VIEW_COLUMN_SELECTED, &selected, -1);
if (selected) {
*list = g_list_prepend(*list, path);
}
return FALSE;
}
GList *
ag_icon_view_get_selected_items(AgIconView *icon_view)
{
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(icon_view);
GList *items = NULL;
gtk_tree_model_foreach(GTK_TREE_MODEL(priv->model), (GtkTreeModelForeachFunc)ag_icon_view_check_selected, &items);
return g_list_reverse(items);
}
static gboolean
ag_icon_view_change_item_selection(GtkListStore *model,
GtkTreePath *path,
GtkTreeIter *iter,
gboolean *selected)
{
gtk_list_store_set(model, iter, AG_ICON_VIEW_COLUMN_SELECTED, *selected, -1);
return FALSE;
}
void
ag_icon_view_select_all(AgIconView *icon_view)
{
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(icon_view);
gboolean selected = TRUE;
gtk_tree_model_foreach(
GTK_TREE_MODEL(priv->model),
(GtkTreeModelForeachFunc)ag_icon_view_change_item_selection,
&selected
);
ag_icon_view_selection_changed(icon_view);
}
void
ag_icon_view_unselect_all(AgIconView *icon_view)
{
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(icon_view);
gboolean selected = FALSE;
gtk_tree_model_foreach(
GTK_TREE_MODEL(priv->model),
(GtkTreeModelForeachFunc)ag_icon_view_change_item_selection,
&selected
);
ag_icon_view_selection_changed(icon_view);
}
AgDbChartSave *
ag_icon_view_get_chart_save_at_path(AgIconView *icon_view,
const GtkTreePath *path)
{
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(icon_view);
GtkTreeIter iter;
AgDbChartSave *save_data;
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->model), &iter, (GtkTreePath *)path)) {
gtk_tree_model_get(
GTK_TREE_MODEL(priv->model), &iter,
AG_ICON_VIEW_COLUMN_ITEM, &save_data,
-1
);
} else {
g_warning("Invalid tree path");
save_data = NULL;
}
return save_data;
}
void
ag_icon_view_remove_selected(AgIconView *icon_view)
{
AgIconViewPrivate *priv = ag_icon_view_get_instance_private(icon_view);
GList *paths = g_list_reverse(ag_icon_view_get_selected_items(icon_view)),
*l;
for (l = paths; l; l = g_list_next(l)) {
GtkTreeIter iter;
GtkTreePath *path = l->data;
if (gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->model), &iter, path)) {
gtk_list_store_remove(priv->model, &iter);
}
}
ag_icon_view_selection_changed(icon_view);
}