Add AgIconView class

It is a subclass of GtkIconView specialised in displayind Astrognome
chart previews as icons.
This commit is contained in:
Gergely Polonkai 2014-09-26 14:52:43 +02:00
parent 13728943d6
commit a18e11f023
6 changed files with 612 additions and 2 deletions

4
.gitignore vendored
View File

@ -40,8 +40,8 @@ Makefile.in
/data/astrognome.desktop.in
# Generated files
/src/ag-resources.c
/src/ag-resources.h
/src/ag-resources.[ch]
/src/ag-enumtypes.[ch]
# Geonames related things
/data/geonames/*.txt

View File

@ -1,15 +1,27 @@
RESOURCE_DIR = $(srcdir)/resources
resource_files = $(shell glib-compile-resources --sourcedir=$(RESOURCE_DIR) --generate-dependencies $(srcdir)/ag.gresource.xml)
ag_enum_headers = ag-icon-view.h
ag-resources.c: ag.gresource.xml $(resource_files)
glib-compile-resources --target=$@ --sourcedir=$(RESOURCE_DIR) --generate-source --c-name ag $(srcdir)/ag.gresource.xml
ag-resources.h: ag.gresource.xml $(resource_files)
glib-compile-resources --target=$@ --sourcedir=$(RESOURCE_DIR) --generate-header --c-name ag $(srcdir)/ag.gresource.xml
ag-enumtypes.h: $(ag_enum_headers) ag-enumtypes.h.template
$(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
ag-enumtypes.h.tmp && mv ag-enumtypes.h.tmp ag-enumtypes.h
ag-enumtypes.c: $(ag_enum_headers) ag-enumtypes.c.template
$(GLIB_MKENUMS) --template $(filter %.template,$^) $(filter-out %.template,$^) > \
ag-enumtypes.c.tmp && mv ag-enumtypes.c.tmp ag-enumtypes.c
BUILT_SOURCES = \
ag-resources.h \
ag-resources.c \
ag-enumtypes.h \
ag-enumtypes.c \
$(NULL)
astrognome_source_files = \
@ -20,6 +32,7 @@ astrognome_source_files = \
ag-preferences.c \
ag-db.c \
ag-display-theme.c \
ag-icon-view.c \
ag-chart-renderer.c \
astrognome.c \
$(NULL)

View File

@ -0,0 +1,63 @@
/*** BEGIN file-header ***/
/* ag-enumtypes.c - Enumeration types for Astrognome
*
* Copyright © 2013 Gergely Polonkai
*
* Astrognome is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* Astrognome is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "ag-enumtypes.h"
#include "@filename@"
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type(void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter(&g_define_type_id__volatile)) {
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{
@VALUENAME@,
"@VALUENAME@",
"@valuenick@"
},
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType g_define_type_id = g_@type@_register_static(
g_intern_static_string("@EnumName@"),
values
);
g_once_init_leave(&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}
/*** END value-tail ***/

View File

@ -0,0 +1,42 @@
/*** BEGIN file-header ***/
/* ag-enumtypes.h - Enumeration types for Astrognome
*
* Copyright © 2013 Gergely Polonkai
*
* Astrognome is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* Astrognome is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __AG_ENUM_TYPES_H__
#define __AG_ENUM_TYPES_H__
#include <glib-object.h>
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
#include "@filename@"
/*** END file-production ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type(void);
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
/*** END value-header ***/
/*** BEGIN file-tail ***/
#endif /* __AG_ENUM_TYPES_H__ */
/*** END file-tail ***/

423
src/ag-icon-view.c Normal file
View File

@ -0,0 +1,423 @@
#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);
}

69
src/ag-icon-view.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef __AG_ICON_VIEW_H__
#define __AG_ICON_VIEW_H__
#include <gtk/gtk.h>
#include "ag-db.h"
G_BEGIN_DECLS
#define AG_TYPE_ICON_VIEW \
(ag_icon_view_get_type())
#define AG_ICON_VIEW(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
AG_TYPE_ICON_VIEW, \
AgIconView))
#define AG_ICON_VIEW_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
AG_TYPE_ICON_VIEW, \
AgIconViewClass))
#define IS_AG_ICON_VIEW(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
AG_TYPE_ICON_VIEW))
#define IS_AG_ICON_VIEW_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
AG_TYPE_ICON_VIEW))
#define AG_ICON_VIEW_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
AG_TYPE_ICON_VIEW, \
AgIconViewClass))
typedef struct _AgIconView AgIconView;
typedef struct _AgIconViewClass AgIconViewClass;
struct _AgIconViewClass
{
GtkIconViewClass parent_class;
};
struct _AgIconView
{
GtkIconView parent;
};
typedef enum {
AG_ICON_VIEW_MODE_NORMAL,
AG_ICON_VIEW_MODE_SELECTION
} AgIconViewMode;
GType ag_icon_view_get_type (void) G_GNUC_CONST;
void ag_icon_view_set_mode(AgIconView *icon_view, AgIconViewMode mode);
AgIconViewMode ag_icon_view_get_mode(AgIconView *icon_view);
void ag_icon_view_add_chart(AgIconView *icon_view, AgDbChartSave *chart_save);
GList *ag_icon_view_get_selected_items(AgIconView *icon_view);
AgDbChartSave *ag_icon_view_get_chart_save_at_path(AgIconView *icon_view, const GtkTreePath *path);
void ag_icon_view_select_all(AgIconView *icon_view);
void ag_icon_view_unselect_all(AgIconView *icon_view);
void ag_icon_view_remove_selected(AgIconView *icon_view);
G_END_DECLS
#endif /* __AG_ICON_VIEW_H__ */