[gnome-disk-utility] add some experimental code for grid-based layout
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnome-disk-utility] add some experimental code for grid-based layout
- Date: Mon, 30 Mar 2009 10:35:05 -0400 (EDT)
commit ba32ed65991f520258aa5bb56f7bbb04763e4346
Author: David Zeuthen <davidz redhat com>
Date: Mon Mar 30 10:32:34 2009 -0400
add some experimental code for grid-based layout
---
configure.ac | 2 +
src/Makefile.am | 2 +-
src/playground/Makefile.am | 4 +
src/playground/grid/Makefile.am | 56 +++
src/playground/grid/gdu-grid-element.c | 811 ++++++++++++++++++++++++++++++++
src/playground/grid/gdu-grid-element.h | 58 +++
src/playground/grid/gdu-grid-hbox.c | 169 +++++++
src/playground/grid/gdu-grid-hbox.h | 38 ++
src/playground/grid/gdu-grid-types.h | 17 +
src/playground/grid/gdu-grid-view.c | 455 ++++++++++++++++++
src/playground/grid/gdu-grid-view.h | 47 ++
src/playground/grid/grid.c | 58 +++
12 files changed, 1716 insertions(+), 1 deletions(-)
diff --git a/configure.ac b/configure.ac
index b4a4255..2b5c27a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -177,6 +177,8 @@ src/gdu/gdu.pc
src/gdu-gtk/Makefile
src/gdu-gtk/gdu-gtk.pc
src/palimpsest/Makefile
+src/playground/Makefile
+src/playground/grid/Makefile
po/Makefile.in
data/Makefile
data/icons/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 2ea64de..181303f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = gdu gdu-gtk palimpsest
+SUBDIRS = gdu gdu-gtk palimpsest playground
clean-local :
rm -f *~
diff --git a/src/playground/Makefile.am b/src/playground/Makefile.am
new file mode 100644
index 0000000..9f742eb
--- /dev/null
+++ b/src/playground/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = grid
+
+clean-local :
+ rm -f *~
diff --git a/src/playground/grid/Makefile.am b/src/playground/grid/Makefile.am
new file mode 100644
index 0000000..a07e341
--- /dev/null
+++ b/src/playground/grid/Makefile.am
@@ -0,0 +1,56 @@
+
+NULL =
+
+noinst_PROGRAMS = grid
+
+grid_SOURCES = \
+ grid.c \
+ gdu-grid-types.h \
+ gdu-grid-element.h gdu-grid-element.c \
+ gdu-grid-hbox.h gdu-grid-hbox.c \
+ gdu-grid-view.h gdu-grid-view.c \
+ $(NULL)
+
+grid_CPPFLAGS = \
+ -I$(top_srcdir)/src/ \
+ -I$(top_builddir)/src/ \
+ -DG_LOG_DOMAIN=\"TestGrid\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ $(DISABLE_DEPRECATED) \
+ -DGDU_API_IS_SUBJECT_TO_CHANGE \
+ -DGDU_GTK_API_IS_SUBJECT_TO_CHANGE \
+ $(AM_CPPFLAGS)
+
+grid_CFLAGS = \
+ $(GLIB2_CFLAGS) \
+ $(GOBJECT2_CFLAGS) \
+ $(GIO2_CFLAGS) \
+ $(GIO_UNIX2_CFLAGS) \
+ $(DBUS_GLIB_CFLAGS) \
+ $(POLKIT_DBUS_CFLAGS) \
+ $(POLKIT_GNOME_CFLAGS) \
+ $(GNOME_KEYRING_CFLAGS) \
+ $(GTK2_CFLAGS) \
+ $(LIBSEXY_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(AM_CFLAGS)
+
+grid_LDFLAGS = \
+ $(AM_LDFLAGS)
+
+grid_LDADD = \
+ $(GLIB2_LIBS) \
+ $(GIO2_LIBS) \
+ $(GIO_UNIX2_LIBS) \
+ $(DBUS_GLIB_LIBS) \
+ $(POLKIT_DBUS_LIBS) \
+ $(POLKIT_GNOME_LIBS) \
+ $(GNOME_KEYRING_LIBS) \
+ $(GTK2_LIBS) \
+ $(LIBSEXY_LIBS) \
+ $(INTLLIBS) \
+ $(top_builddir)/src/gdu/libgdu.la \
+ $(top_builddir)/src/gdu-gtk/libgdu-gtk.la
+
+clean-local :
+ rm -f *~
diff --git a/src/playground/grid/gdu-grid-element.c b/src/playground/grid/gdu-grid-element.c
new file mode 100644
index 0000000..5f8b506
--- /dev/null
+++ b/src/playground/grid/gdu-grid-element.c
@@ -0,0 +1,811 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+#include <math.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+#include <X11/XKBlib.h>
+
+#define GDU_GTK_API_IS_SUBJECT_TO_CHANGE
+#include <gdu-gtk/gdu-gtk.h>
+
+#include "gdu-grid-view.h"
+#include "gdu-grid-element.h"
+
+struct GduGridElementPrivate
+{
+ GduGridView *view;
+ GduPresentable *presentable;
+ guint minimum_size;
+ gdouble percent_size;
+ GduGridElementFlags flags;
+};
+
+enum
+{
+ PROP_0,
+ PROP_VIEW,
+ PROP_PRESENTABLE,
+ PROP_MINIMUM_SIZE,
+ PROP_PERCENT_SIZE,
+ PROP_FLAGS,
+};
+
+G_DEFINE_TYPE (GduGridElement, gdu_grid_element, GTK_TYPE_DRAWING_AREA)
+
+static void
+gdu_grid_element_finalize (GObject *object)
+{
+ GduGridElement *element = GDU_GRID_ELEMENT (object);
+
+ if (element->priv->presentable != NULL)
+ g_object_unref (element->priv->presentable);
+
+ if (G_OBJECT_CLASS (gdu_grid_element_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (gdu_grid_element_parent_class)->finalize (object);
+}
+
+static void
+gdu_grid_element_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GduGridElement *element = GDU_GRID_ELEMENT (object);
+
+ switch (property_id) {
+ case PROP_VIEW:
+ g_value_set_object (value, element->priv->view);
+ break;
+
+ case PROP_PRESENTABLE:
+ g_value_set_object (value, element->priv->presentable);
+ break;
+
+ case PROP_MINIMUM_SIZE:
+ g_value_set_uint (value, element->priv->minimum_size);
+ break;
+
+ case PROP_PERCENT_SIZE:
+ g_value_set_double (value, element->priv->percent_size);
+ break;
+
+ case PROP_FLAGS:
+ g_value_set_uint (value, element->priv->flags);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+gdu_grid_element_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GduGridElement *element = GDU_GRID_ELEMENT (object);
+
+ switch (property_id) {
+ case PROP_VIEW:
+ /* don't increase reference count */
+ element->priv->view = g_value_get_object (value);
+ break;
+
+ case PROP_PRESENTABLE:
+ element->priv->presentable = g_value_dup_object (value);
+ break;
+
+ case PROP_MINIMUM_SIZE:
+ element->priv->minimum_size = g_value_get_uint (value);
+ break;
+
+ case PROP_PERCENT_SIZE:
+ element->priv->percent_size = g_value_get_double (value);
+ break;
+
+ case PROP_FLAGS:
+ element->priv->flags = g_value_get_uint (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+round_rect (cairo_t *cr,
+ gdouble x, gdouble y,
+ gdouble w, gdouble h,
+ gdouble r,
+ gboolean top_left_round,
+ gboolean top_right_round,
+ gboolean bottom_right_round,
+ gboolean bottom_left_round)
+{
+ if (top_left_round) {
+ cairo_move_to (cr,
+ x + r, y);
+ } else {
+ cairo_move_to (cr,
+ x, y);
+ }
+
+ if (top_right_round) {
+ cairo_line_to (cr,
+ x + w - r, y);
+ cairo_curve_to (cr,
+ x + w, y,
+ x + w, y,
+ x + w, y + r);
+ } else {
+ cairo_line_to (cr,
+ x + w, y);
+ }
+
+ if (bottom_right_round) {
+ cairo_line_to (cr,
+ x + w, y + h - r);
+ cairo_curve_to (cr,
+ x + w, y + h,
+ x + w, y + h,
+ x + w - r, y + h);
+ } else {
+ cairo_line_to (cr,
+ x + w, y + h);
+ }
+
+ if (bottom_left_round) {
+ cairo_line_to (cr,
+ x + r, y + h);
+ cairo_curve_to (cr,
+ x, y + h,
+ x, y + h,
+ x, y + h - r);
+ } else {
+ cairo_line_to (cr,
+ x, y + h);
+ }
+
+ if (top_left_round) {
+ cairo_line_to (cr,
+ x, y + r);
+ cairo_curve_to (cr,
+ x, y,
+ x, y,
+ x + r, y);
+ } else {
+ cairo_line_to (cr,
+ x, y);
+ }
+}
+
+static void
+render_pixbuf (cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ GdkPixbuf *pixbuf)
+{
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
+ cairo_rectangle (cr,
+ x,
+ y,
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf));
+ cairo_fill (cr);
+}
+
+static gboolean
+gdu_grid_element_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GduGridElement *element = GDU_GRID_ELEMENT (widget);
+ cairo_t *cr;
+ gdouble width, height;
+ gdouble rect_x, rect_y, rect_width, rect_height;
+ gboolean is_selected;
+ gboolean has_focus;
+ GduGridElementFlags f;
+ gdouble fill_red;
+ gdouble fill_green;
+ gdouble fill_blue;
+ gdouble fill_selected_red;
+ gdouble fill_selected_green;
+ gdouble fill_selected_blue;
+ gdouble focus_rect_red;
+ gdouble focus_rect_green;
+ gdouble focus_rect_blue;
+ gdouble focus_rect_selected_red;
+ gdouble focus_rect_selected_green;
+ gdouble focus_rect_selected_blue;
+ gdouble stroke_red;
+ gdouble stroke_green;
+ gdouble stroke_blue;
+ gdouble stroke_selected_red;
+ gdouble stroke_selected_green;
+ gdouble stroke_selected_blue;
+ gdouble text_red;
+ gdouble text_green;
+ gdouble text_blue;
+ gdouble text_selected_red;
+ gdouble text_selected_green;
+ gdouble text_selected_blue;
+ gdouble border_width;
+
+ f = element->priv->flags;
+
+ width = widget->allocation.width;
+ height = widget->allocation.height;
+
+ border_width = 4;
+
+ rect_x = 0.5;
+ rect_y = 0.5;
+ rect_width = width;
+ rect_height = height;
+ if (f & GDU_GRID_ELEMENT_FLAGS_EDGE_LEFT) {
+ rect_x += border_width;
+ rect_width -= border_width;
+ }
+ if (f & GDU_GRID_ELEMENT_FLAGS_EDGE_TOP) {
+ rect_y += border_width;
+ rect_height -= border_width;
+ }
+ if (f & GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT) {
+ rect_width -= border_width;
+ }
+ if (f & GDU_GRID_ELEMENT_FLAGS_EDGE_BOTTOM) {
+ rect_height -= border_width;
+ }
+
+ cr = gdk_cairo_create (widget->window);
+ cairo_rectangle (cr,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_clip (cr);
+
+ has_focus = GTK_WIDGET_HAS_FOCUS (widget);
+ if (element->priv->presentable != NULL)
+ is_selected = gdu_grid_view_is_selected (element->priv->view, element->priv->presentable);
+ else
+ is_selected = FALSE;
+
+ fill_red = 1;
+ fill_green = 1;
+ fill_blue = 1;
+ fill_selected_red = 0.40;
+ fill_selected_green = 0.60;
+ fill_selected_blue = 0.80;
+ focus_rect_red = 0.75;
+ focus_rect_green = 0.75;
+ focus_rect_blue = 0.75;
+ focus_rect_selected_red = 0.70;
+ focus_rect_selected_green = 0.70;
+ focus_rect_selected_blue = 0.80;
+ stroke_red = 0.75;
+ stroke_green = 0.75;
+ stroke_blue = 0.75;
+ stroke_selected_red = 0.3;
+ stroke_selected_green = 0.45;
+ stroke_selected_blue = 0.6;
+ text_red = 0;
+ text_green = 0;
+ text_blue = 0;
+ text_selected_red = 1;
+ text_selected_green = 1;
+ text_selected_blue = 1;
+
+ /* draw element */
+ if (is_selected) {
+ cairo_pattern_t *gradient;
+ gradient = cairo_pattern_create_radial (rect_x + rect_width / 2,
+ rect_y + rect_height / 2,
+ 0.0,
+ rect_x + rect_width / 2,
+ rect_y + rect_height / 2,
+ rect_width/2.0);
+ cairo_pattern_add_color_stop_rgb (gradient,
+ 0.0,
+ 1.0 * fill_selected_red,
+ 1.0 * fill_selected_green,
+ 1.0 * fill_selected_blue);
+ cairo_pattern_add_color_stop_rgb (gradient,
+ 1.0,
+ 0.8 * fill_selected_red,
+ 0.8 * fill_selected_green,
+ 0.8 * fill_selected_blue);
+ cairo_set_source (cr, gradient);
+ cairo_pattern_destroy (gradient);
+ } else {
+ cairo_set_source_rgb (cr, fill_red, fill_green, fill_blue);
+ }
+ f = element->priv->flags;
+ round_rect (cr,
+ rect_x, rect_y,
+ rect_width, rect_height,
+ 20,
+ (f & GDU_GRID_ELEMENT_FLAGS_EDGE_LEFT) && (f & GDU_GRID_ELEMENT_FLAGS_EDGE_TOP),
+ (f & GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT) && (f & GDU_GRID_ELEMENT_FLAGS_EDGE_TOP),
+ (f & GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT) && (f & GDU_GRID_ELEMENT_FLAGS_EDGE_BOTTOM),
+ (f & GDU_GRID_ELEMENT_FLAGS_EDGE_LEFT) && (f & GDU_GRID_ELEMENT_FLAGS_EDGE_BOTTOM));
+ cairo_fill_preserve (cr);
+ if (is_selected)
+ cairo_set_source_rgb (cr, stroke_selected_red, stroke_selected_green, stroke_selected_blue);
+ else
+ cairo_set_source_rgb (cr, stroke_red, stroke_green, stroke_blue);
+ cairo_set_line_width (cr, 1);
+ cairo_stroke (cr);
+
+ /* draw focus indicator */
+ if (has_focus) {
+ gdouble dashes[] = {2.0};
+ round_rect (cr,
+ rect_x + 3, rect_y + 3,
+ rect_width - 3 * 2, rect_height - 3 * 2,
+ 20,
+ (f & GDU_GRID_ELEMENT_FLAGS_EDGE_LEFT) && (f & GDU_GRID_ELEMENT_FLAGS_EDGE_TOP),
+ (f & GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT) && (f & GDU_GRID_ELEMENT_FLAGS_EDGE_TOP),
+ (f & GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT) && (f & GDU_GRID_ELEMENT_FLAGS_EDGE_BOTTOM),
+ (f & GDU_GRID_ELEMENT_FLAGS_EDGE_LEFT) && (f & GDU_GRID_ELEMENT_FLAGS_EDGE_BOTTOM));
+ if (is_selected)
+ cairo_set_source_rgb (cr, focus_rect_selected_red, focus_rect_selected_green, focus_rect_selected_blue);
+ else
+ cairo_set_source_rgb (cr, focus_rect_red, focus_rect_green, focus_rect_blue);
+ cairo_set_dash (cr, dashes, 1, 0.0);
+ cairo_set_line_width (cr, 1.0);
+ cairo_stroke (cr);
+ }
+
+ /* adjust clip rect */
+ cairo_rectangle (cr,
+ rect_x + 3, rect_y + 3,
+ rect_width - 3 * 2, rect_height - 3 * 2);
+ cairo_clip (cr);
+
+ /* draw icons/text */
+ if (GDU_IS_DRIVE (element->priv->presentable)) {
+ GdkPixbuf *pixbuf;
+ gint icon_width;
+ cairo_text_extents_t te;
+ gchar *s;
+ gdouble y;
+ gint line_height;
+
+ y = 0;
+
+ pixbuf = gdu_util_get_pixbuf_for_presentable (element->priv->presentable, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ icon_width = 0;
+ if (pixbuf != NULL) {
+ icon_width = gdk_pixbuf_get_width (pixbuf);
+ render_pixbuf (cr,
+ ceil (rect_x) + 4,
+ ceil (rect_y) + 4,
+ pixbuf);
+ g_object_unref (pixbuf);
+ }
+
+ if (is_selected)
+ cairo_set_source_rgb (cr, text_selected_red, text_selected_green, text_selected_blue);
+ else
+ cairo_set_source_rgb (cr, text_red, text_green, text_blue);
+
+ /* drive name */
+ s = gdu_presentable_get_name (element->priv->presentable);
+ cairo_select_font_face (cr,
+ "sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size (cr, 8.0);
+ cairo_text_extents (cr, s, &te);
+ cairo_move_to (cr,
+ ceil (ceil (rect_x) + 4 + icon_width + 4 - te.x_bearing),
+ ceil (ceil (rect_y) + te.height - te.y_bearing));
+ cairo_show_text (cr, s);
+ g_free (s);
+ line_height = te.height + 4;
+ y += line_height;
+
+
+ GduDevice *d;
+ d = gdu_presentable_get_device (element->priv->presentable);
+ if (d != NULL) {
+ s = g_strdup (gdu_device_get_device_file (d));
+ } else {
+ s = g_strdup (" ");
+ }
+ cairo_select_font_face (cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, 8.0);
+ cairo_text_extents (cr, s, &te);
+ cairo_move_to (cr, ceil (ceil (rect_x) + 4 + icon_width + 4 - te.x_bearing),
+ ceil (ceil (rect_y) + te.height - te.y_bearing + y));
+ cairo_show_text (cr, s);
+ g_free (s);
+ y += line_height;
+
+ //s = g_strdup ("foobar");
+ //cairo_select_font_face (cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ //cairo_set_font_size (cr, 8.0);
+ //cairo_text_extents (cr, s, &te);
+ //cairo_move_to (cr, ceil (ceil (rect_x) + 4 - te.x_bearing),
+ // ceil (ceil (rect_y) + te.height - te.y_bearing + y));
+ //cairo_show_text (cr, s);
+ //g_free (s);
+ //y += line_height;
+
+ if (d != NULL)
+ g_object_unref (d);
+
+ } else {
+ gchar *s;
+ gchar *s1;
+ cairo_text_extents_t te;
+ cairo_text_extents_t te1;
+ GduDevice *d;
+ gdouble text_height;
+
+ d = gdu_presentable_get_device (element->priv->presentable);
+
+ s = NULL;
+ s1 = NULL;
+ if (d != NULL && g_strcmp0 (gdu_device_id_get_usage (d), "filesystem") == 0) {
+ gchar *fstype_str;
+ gchar *size_str;
+ s = g_strdup (gdu_device_id_get_label (d));
+ fstype_str = gdu_util_get_fstype_for_display (gdu_device_id_get_type (d),
+ gdu_device_id_get_version (d),
+ FALSE);
+ size_str = gdu_util_get_size_for_display (gdu_device_get_size (d), FALSE);
+ s1 = g_strdup_printf ("%s %s", size_str, fstype_str);
+ g_free (fstype_str);
+ g_free (size_str);
+ } else if (d != NULL && gdu_device_is_partition (d) &&
+ (g_strcmp0 (gdu_device_partition_get_type (d), "0x05") == 0 ||
+ g_strcmp0 (gdu_device_partition_get_type (d), "0x0f") == 0 ||
+ g_strcmp0 (gdu_device_partition_get_type (d), "0x85") == 0)) {
+ s = g_strdup (_("Extended"));
+ s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->priv->presentable), FALSE);
+ } else if (d != NULL && g_strcmp0 (gdu_device_id_get_usage (d), "crypto") == 0) {
+ s = g_strdup (_("Encrypted"));
+ s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->priv->presentable), FALSE);
+ } else if (!gdu_presentable_is_allocated (element->priv->presentable)) {
+ s = g_strdup (_("Free"));
+ s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->priv->presentable), FALSE);
+ } else if (!gdu_presentable_is_recognized (element->priv->presentable)) {
+ s = g_strdup (_("Unknown"));
+ s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->priv->presentable), FALSE);
+ }
+
+ if (s == NULL)
+ s = gdu_presentable_get_name (element->priv->presentable);
+ if (s1 == NULL)
+ s1 = g_strdup ("");
+
+ if (is_selected)
+ cairo_set_source_rgb (cr, text_selected_red, text_selected_green, text_selected_blue);
+ else
+ cairo_set_source_rgb (cr, text_red, text_green, text_blue);
+ cairo_select_font_face (cr, "sans",
+ CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, 8.0);
+
+ cairo_text_extents (cr, s, &te);
+ cairo_text_extents (cr, s1, &te1);
+
+ text_height = te.height + te1.height;
+
+ cairo_move_to (cr,
+ ceil (rect_x + rect_width / 2 - te.width/2 - te.x_bearing),
+ ceil (rect_y + rect_height / 2 - 2 - text_height/2 - te.y_bearing));
+ cairo_show_text (cr, s);
+ cairo_move_to (cr,
+ ceil (rect_x + rect_width / 2 - te1.width/2 - te1.x_bearing),
+ ceil (rect_y + rect_height / 2 + 2 - te1.y_bearing));
+ cairo_show_text (cr, s1);
+ g_free (s);
+ g_free (s1);
+
+ if (d != NULL)
+ g_object_unref (d);
+ }
+
+
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+static gboolean
+is_ctrl_pressed (void)
+{
+ gboolean ret;
+ XkbStateRec state;
+ Bool status;
+
+ ret = FALSE;
+
+ gdk_error_trap_push ();
+ status = XkbGetState (GDK_DISPLAY (), XkbUseCoreKbd, &state);
+ gdk_error_trap_pop ();
+
+ if (status == Success) {
+ ret = ((state.mods & ControlMask) != 0);
+ }
+
+ return ret;
+}
+
+static gboolean
+gdu_grid_element_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ GduGridElement *element = GDU_GRID_ELEMENT (widget);
+ gboolean handled;
+
+ handled = FALSE;
+
+ if (event->type != GDK_KEY_PRESS)
+ goto out;
+
+ if (event->keyval == GDK_space) {
+ //g_debug ("Space pressed on %p - setting as selected", widget);
+ if (!is_ctrl_pressed ()) {
+ gdu_grid_view_selection_clear (element->priv->view);
+ gdu_grid_view_selection_add (element->priv->view, element->priv->presentable);
+ } else {
+ if (!gdu_grid_view_is_selected (element->priv->view, element->priv->presentable))
+ gdu_grid_view_selection_add (element->priv->view, element->priv->presentable);
+ else
+ gdu_grid_view_selection_remove (element->priv->view, element->priv->presentable);
+ }
+ gtk_widget_grab_focus (widget);
+ handled = TRUE;
+ }
+
+ out:
+ return handled;
+}
+
+static gboolean
+gdu_grid_element_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GduGridElement *element = GDU_GRID_ELEMENT (widget);
+ gboolean handled;
+
+ handled = FALSE;
+
+ if (event->type != GDK_BUTTON_PRESS)
+ goto out;
+
+ if (event->button == 1) {
+ //g_debug ("Left button pressed on %p - setting as selected", widget);
+ if (!is_ctrl_pressed ()) {
+ gdu_grid_view_selection_clear (element->priv->view);
+ gdu_grid_view_selection_add (element->priv->view, element->priv->presentable);
+ } else {
+ if (!gdu_grid_view_is_selected (element->priv->view, element->priv->presentable))
+ gdu_grid_view_selection_add (element->priv->view, element->priv->presentable);
+ else
+ gdu_grid_view_selection_remove (element->priv->view, element->priv->presentable);
+ }
+ gtk_widget_grab_focus (widget);
+ handled = TRUE;
+ }
+
+ out:
+ return handled;
+}
+
+static gboolean
+gdu_grid_element_focus (GtkWidget *widget,
+ GtkDirectionType direction)
+{
+ GduGridElement *element = GDU_GRID_ELEMENT (widget);
+ gboolean handled;
+
+ handled = GTK_WIDGET_CLASS (gdu_grid_element_parent_class)->focus (widget, direction);
+
+ switch (direction) {
+ case GTK_DIR_UP:
+ case GTK_DIR_DOWN:
+ case GTK_DIR_LEFT:
+ case GTK_DIR_RIGHT:
+ if (!is_ctrl_pressed ()) {
+ gdu_grid_view_selection_clear (element->priv->view);
+ gdu_grid_view_selection_add (element->priv->view, element->priv->presentable);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return handled;
+}
+
+static void
+gdu_grid_element_realize (GtkWidget *widget)
+{
+ GduGridElement *element = GDU_GRID_ELEMENT (widget);
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask = gtk_widget_get_events (widget) |
+ GDK_KEY_PRESS_MASK |
+ GDK_EXPOSURE_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+ widget->window = gtk_widget_get_parent_window (widget);
+ g_object_ref (widget->window);
+
+ widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
+ &attributes, attributes_mask);
+ gdk_window_set_user_data (widget->window, element);
+
+ widget->style = gtk_style_attach (widget->style, widget->window);
+
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+}
+
+#if 0
+static void
+gdu_grid_element_unrealize (GtkWidget *widget)
+{
+ GduGridElement *element = GDU_GRID_ELEMENT (widget);
+
+ if (element->priv->event_window != NULL) {
+ gdk_window_set_user_data (element->priv->event_window, NULL);
+ gdk_window_destroy (element->priv->event_window);
+ element->priv->event_window = NULL;
+ }
+
+ GTK_WIDGET_CLASS (gdu_grid_element_parent_class)->unrealize (widget);
+}
+#endif
+
+static void
+gdu_grid_element_class_init (GduGridElementClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GduGridElementPrivate));
+
+ object_class->get_property = gdu_grid_element_get_property;
+ object_class->set_property = gdu_grid_element_set_property;
+ object_class->finalize = gdu_grid_element_finalize;
+
+ widget_class->realize = gdu_grid_element_realize;
+ //widget_class->unrealize = gdu_grid_element_unrealize;
+ widget_class->expose_event = gdu_grid_element_expose_event;
+ widget_class->key_press_event = gdu_grid_element_key_press_event;
+ widget_class->button_press_event = gdu_grid_element_button_press_event;
+ widget_class->focus = gdu_grid_element_focus;
+
+ g_object_class_install_property (object_class,
+ PROP_VIEW,
+ g_param_spec_object ("view",
+ _("View"),
+ _("The GduGridView object that the element is associated with"),
+ GDU_TYPE_GRID_VIEW,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_PRESENTABLE,
+ g_param_spec_object ("presentable",
+ _("Presentable"),
+ _("The presentable shown or NULL if this is a element representing lack of media"),
+ GDU_TYPE_PRESENTABLE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_MINIMUM_SIZE,
+ g_param_spec_uint ("minimum-size",
+ _("Minimum Size"),
+ _("The mininum size of the element"),
+ 0,
+ G_MAXUINT,
+ 40,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_PERCENT_SIZE,
+ g_param_spec_double ("percent-size",
+ _("Percent Size"),
+ _("The size in percent this element should claim or 0 to always claim the specified minimum size"),
+ 0.0,
+ 100.0,
+ 0.0,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_FLAGS, /* TODO: proper type */
+ g_param_spec_uint ("flags",
+ _("Flags"),
+ _("Flags for the element"),
+ 0,
+ G_MAXUINT,
+ 0,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gdu_grid_element_init (GduGridElement *element)
+{
+ element->priv = G_TYPE_INSTANCE_GET_PRIVATE (element, GDU_TYPE_GRID_ELEMENT, GduGridElementPrivate);
+
+ GTK_WIDGET_SET_FLAGS (element, GTK_CAN_FOCUS);
+}
+
+GtkWidget *
+gdu_grid_element_new (GduGridView *view,
+ GduPresentable *presentable,
+ guint minimum_size,
+ gdouble percent_size,
+ GduGridElementFlags flags)
+{
+ return GTK_WIDGET (g_object_new (GDU_TYPE_GRID_ELEMENT,
+ "view", view,
+ "presentable", presentable,
+ "minimum-size", minimum_size,
+ "percent-size", percent_size,
+ "flags", flags,
+ NULL));
+}
+
+GduGridView *
+gdu_grid_element_get_view (GduGridElement *element)
+{
+ return g_object_ref (element->priv->view);
+}
+
+GduPresentable *
+gdu_grid_element_get_presentable (GduGridElement *element)
+{
+ return g_object_ref (element->priv->presentable);
+}
+
+guint
+gdu_grid_element_get_minimum_size (GduGridElement *element)
+{
+ return element->priv->minimum_size;
+}
+
+gdouble
+gdu_grid_element_get_percent_size (GduGridElement *element)
+{
+ return element->priv->percent_size;
+}
+
+GduGridElementFlags
+gdu_grid_element_get_flags (GduGridElement *element)
+{
+ return element->priv->flags;
+}
+
diff --git a/src/playground/grid/gdu-grid-element.h b/src/playground/grid/gdu-grid-element.h
new file mode 100644
index 0000000..cd64b0f
--- /dev/null
+++ b/src/playground/grid/gdu-grid-element.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+#ifndef __GDU_GRID_ELEMENT_H
+#define __GDU_GRID_ELEMENT_H
+
+#include "gdu-grid-types.h"
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_GRID_ELEMENT gdu_grid_element_get_type()
+#define GDU_GRID_ELEMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_GRID_ELEMENT, GduGridElement))
+#define GDU_GRID_ELEMENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_GRID_ELEMENT, GduGridElementClass))
+#define GDU_IS_GRID_ELEMENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_GRID_ELEMENT))
+#define GDU_IS_GRID_ELEMENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_GRID_ELEMENT))
+#define GDU_GRID_ELEMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_GRID_ELEMENT, GduGridElementClass))
+
+typedef struct GduGridElementClass GduGridElementClass;
+typedef struct GduGridElementPrivate GduGridElementPrivate;
+
+struct GduGridElement
+{
+ GtkDrawingArea parent;
+
+ /*< private >*/
+ GduGridElementPrivate *priv;
+};
+
+struct GduGridElementClass
+{
+ GtkDrawingAreaClass parent_class;
+};
+
+typedef enum
+{
+ GDU_GRID_ELEMENT_FLAGS_NONE = 0,
+ GDU_GRID_ELEMENT_FLAGS_EDGE_TOP = (1<<0),
+ GDU_GRID_ELEMENT_FLAGS_EDGE_BOTTOM = (1<<1),
+ GDU_GRID_ELEMENT_FLAGS_EDGE_LEFT = (1<<2),
+ GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT = (1<<3)
+} GduGridElementFlags;
+
+GType gdu_grid_element_get_type (void) G_GNUC_CONST;
+GtkWidget* gdu_grid_element_new (GduGridView *view,
+ GduPresentable *presentable,
+ guint minimum_size,
+ gdouble percent_size,
+ GduGridElementFlags flags);
+GduGridView *gdu_grid_element_get_view (GduGridElement *element);
+GduPresentable *gdu_grid_element_get_presentable (GduGridElement *element);
+guint gdu_grid_element_get_minimum_size (GduGridElement *element);
+gdouble gdu_grid_element_get_percent_size (GduGridElement *element);
+GduGridElementFlags gdu_grid_element_get_flags (GduGridElement *element);
+
+G_END_DECLS
+
+
+
+#endif /* __GDU_GRID_ELEMENT_H */
diff --git a/src/playground/grid/gdu-grid-hbox.c b/src/playground/grid/gdu-grid-hbox.c
new file mode 100644
index 0000000..38890c4
--- /dev/null
+++ b/src/playground/grid/gdu-grid-hbox.c
@@ -0,0 +1,169 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+#include <glib/gi18n.h>
+
+#include "gdu-grid-hbox.h"
+#include "gdu-grid-element.h"
+
+struct GduGridHBoxPrivate
+{
+ guint dummy;
+};
+
+G_DEFINE_TYPE (GduGridHBox, gdu_grid_hbox, GTK_TYPE_HBOX)
+
+static void
+gdu_grid_hbox_finalize (GObject *object)
+{
+ //GduGridHBox *hbox = GDU_GRID_HBOX (object);
+
+ if (G_OBJECT_CLASS (gdu_grid_hbox_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (gdu_grid_hbox_parent_class)->finalize (object);
+}
+
+static guint
+get_desired_width (GduGridHBox *hbox)
+{
+ guint width;
+ GList *children;
+ GList *l;
+
+ width = 0;
+
+ children = GTK_BOX (hbox)->children;
+ if (children == NULL)
+ goto out;
+
+ for (l = children; l != NULL; l = l->next) {
+ GtkBoxChild *child = l->data;
+ GduGridElement *e;
+
+ if (GTK_IS_VBOX (child->widget)) {
+ e = GDU_GRID_ELEMENT (((GtkBoxChild *) ((GTK_BOX (child->widget)->children)->data))->widget);
+ } else {
+ e = GDU_GRID_ELEMENT (child->widget);
+ }
+
+ width += gdu_grid_element_get_minimum_size (e);
+ }
+
+ out:
+ return width;
+}
+
+static void
+gdu_grid_hbox_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ requisition->width = get_desired_width (GDU_GRID_HBOX (widget));
+ requisition->height = 80;
+}
+
+static void
+gdu_grid_hbox_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GList *children;
+ GList *l;
+ guint n;
+ guint num_children;
+ gint x;
+ guint *children_sizes;
+ guint used_size;
+ guint extra_space;
+ guint desired_width;
+
+ children = GTK_BOX (widget)->children;
+ if (children == NULL)
+ goto out;
+
+ num_children = g_list_length (children);
+
+ children_sizes = g_new0 (guint, num_children);
+
+ /* distribute size.. give at least minimum_width (since that is guaranteed to work) and
+ * then assign extra space based on the percentage
+ */
+ desired_width = get_desired_width (GDU_GRID_HBOX (widget));
+ if (desired_width < allocation->width)
+ extra_space = allocation->width - desired_width;
+ else
+ extra_space = 0;
+
+ used_size = 0;
+ for (l = children, n = 0; l != NULL; l = l->next, n++) {
+ GtkBoxChild *child = l->data;
+ GduGridElement *e;
+ guint width;
+ guint e_minimum;
+ gdouble e_percent;
+
+ if (GTK_IS_VBOX (child->widget)) {
+ e = GDU_GRID_ELEMENT (((GtkBoxChild *) ((GTK_BOX (child->widget)->children)->data))->widget);
+ } else {
+ e = GDU_GRID_ELEMENT (child->widget);
+ }
+
+ e_minimum = gdu_grid_element_get_minimum_size (e);
+ e_percent = gdu_grid_element_get_percent_size (e);
+
+ width = e_minimum + e_percent * extra_space;
+
+ /* fix up last child so it's aligned with the right border */
+ if (l->next == NULL) {
+ if (e_percent != 0.0) {
+ width = allocation->width - used_size;
+ }
+ }
+
+ children_sizes[n] = width;
+ used_size += width;
+ }
+
+ x = 0;
+ for (l = children, n = 0; l != NULL; l = l->next, n++) {
+ GtkBoxChild *child = l->data;
+ GtkAllocation child_allocation;
+
+ child_allocation.x = allocation->x + x;
+ child_allocation.y = allocation->y;
+ child_allocation.width = children_sizes[n];
+ child_allocation.height = allocation->height;
+ x += children_sizes[n];
+
+ gtk_widget_size_allocate (child->widget, &child_allocation);
+ }
+
+ g_free (children_sizes);
+
+ out:
+ ;
+}
+
+static void
+gdu_grid_hbox_class_init (GduGridHBoxClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GduGridHBoxPrivate));
+
+ object_class->finalize = gdu_grid_hbox_finalize;
+
+ widget_class->size_request = gdu_grid_hbox_size_request;
+ widget_class->size_allocate = gdu_grid_hbox_size_allocate;
+}
+
+static void
+gdu_grid_hbox_init (GduGridHBox *box)
+{
+}
+
+GtkWidget *
+gdu_grid_hbox_new (void)
+{
+ return GTK_WIDGET (g_object_new (GDU_TYPE_GRID_HBOX,
+ NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/playground/grid/gdu-grid-hbox.h b/src/playground/grid/gdu-grid-hbox.h
new file mode 100644
index 0000000..b3dc5d5
--- /dev/null
+++ b/src/playground/grid/gdu-grid-hbox.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+#ifndef __GDU_GRID_HBOX_H
+#define __GDU_GRID_HBOX_H
+
+#include "gdu-grid-types.h"
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_GRID_HBOX gdu_grid_hbox_get_type()
+#define GDU_GRID_HBOX(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_GRID_HBOX, GduGridHBox))
+#define GDU_GRID_HBOX_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_GRID_HBOX, GduGridHBoxClass))
+#define GDU_IS_GRID_HBOX(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_GRID_HBOX))
+#define GDU_IS_GRID_HBOX_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_GRID_HBOX))
+#define GDU_GRID_HBOX_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_GRID_HBOX, GduGridHBoxClass))
+
+typedef struct GduGridHBoxClass GduGridHBoxClass;
+typedef struct GduGridHBoxPrivate GduGridHBoxPrivate;
+
+struct GduGridHBox
+{
+ GtkHBox parent;
+
+ /*< private >*/
+ GduGridHBoxPrivate *priv;
+};
+
+struct GduGridHBoxClass
+{
+ GtkHBoxClass parent_class;
+};
+
+GType gdu_grid_hbox_get_type (void) G_GNUC_CONST;
+GtkWidget* gdu_grid_hbox_new (void);
+
+G_END_DECLS
+
+#endif /* __GDU_GRID_HBOX_H */
diff --git a/src/playground/grid/gdu-grid-types.h b/src/playground/grid/gdu-grid-types.h
new file mode 100644
index 0000000..14d969d
--- /dev/null
+++ b/src/playground/grid/gdu-grid-types.h
@@ -0,0 +1,17 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+#ifndef __GDU_GRID_TYPES_H
+#define __GDU_GRID_TYPES_H
+
+#include <gtk/gtk.h>
+#include <gdu/gdu.h>
+
+G_BEGIN_DECLS
+
+typedef struct GduGridView GduGridView;
+typedef struct GduGridHBox GduGridHBox;
+typedef struct GduGridElement GduGridElement;
+
+G_END_DECLS
+
+#endif /* __GDU_GRID_TYPES_H */
diff --git a/src/playground/grid/gdu-grid-view.c b/src/playground/grid/gdu-grid-view.c
new file mode 100644
index 0000000..936e2ad
--- /dev/null
+++ b/src/playground/grid/gdu-grid-view.c
@@ -0,0 +1,455 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+#include <glib/gi18n.h>
+
+#include "gdu-grid-view.h"
+#include "gdu-grid-element.h"
+#include "gdu-grid-hbox.h"
+
+struct GduGridViewPrivate
+{
+ GduPool *pool;
+ GList *elements;
+
+ /* GList of GduPresentable of the currently selected elements */
+ GList *selected;
+};
+
+enum
+{
+ PROP_0,
+ PROP_POOL,
+};
+
+static void on_presentable_added (GduPool *pool,
+ GduPresentable *presentable,
+ GduGridView *view);
+static void on_presentable_removed (GduPool *pool,
+ GduPresentable *presentable,
+ GduGridView *view);
+static void on_presentable_changed (GduPool *pool,
+ GduPresentable *presentable,
+ GduGridView *view);
+
+G_DEFINE_TYPE (GduGridView, gdu_grid_view, GTK_TYPE_VBOX)
+
+static void
+gdu_grid_view_finalize (GObject *object)
+{
+ GduGridView *view = GDU_GRID_VIEW (object);
+
+ g_list_foreach (view->priv->selected, (GFunc) g_object_unref, NULL);
+ g_list_free (view->priv->selected);
+
+ g_list_free (view->priv->elements);
+
+ g_signal_handlers_disconnect_by_func (view->priv->pool, on_presentable_added, view);
+ g_signal_handlers_disconnect_by_func (view->priv->pool, on_presentable_removed, view);
+ g_signal_handlers_disconnect_by_func (view->priv->pool, on_presentable_changed, view);
+ g_object_unref (view->priv->pool);
+
+ if (G_OBJECT_CLASS (gdu_grid_view_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (gdu_grid_view_parent_class)->finalize (object);
+}
+
+static void
+gdu_grid_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GduGridView *view = GDU_GRID_VIEW (object);
+
+ switch (property_id) {
+ case PROP_POOL:
+ g_value_set_object (value, view->priv->pool);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+gdu_grid_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GduGridView *view = GDU_GRID_VIEW (object);
+
+ switch (property_id) {
+ case PROP_POOL:
+ view->priv->pool = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static gint
+presentable_sort_offset (GduPresentable *a, GduPresentable *b)
+{
+ guint64 oa, ob;
+
+ oa = gdu_presentable_get_offset (a);
+ ob = gdu_presentable_get_offset (b);
+
+ if (oa < ob)
+ return -1;
+ else if (oa > ob)
+ return 1;
+ else
+ return 0;
+}
+
+static void
+recompute_grid (GduGridView *view)
+{
+ GList *presentables;
+ GList *l;
+ GList *children;
+
+ children = gtk_container_get_children (GTK_CONTAINER (view));
+ for (l = children; l != NULL; l = l->next) {
+ gtk_container_remove (GTK_CONTAINER (view), GTK_WIDGET (l->data));
+ }
+ g_list_free (children);
+
+ g_list_free (view->priv->elements);
+ view->priv->elements = NULL;
+
+ presentables = gdu_pool_get_presentables (view->priv->pool);
+ presentables = g_list_sort (presentables, (GCompareFunc) gdu_presentable_compare);
+ for (l = presentables; l != NULL; l = l->next) {
+ GduPresentable *p = GDU_PRESENTABLE (l->data);
+ GtkWidget *element;
+ GtkWidget *hbox;
+ guint64 size;
+ GList *enclosed_partitions;
+ GList *ll;
+
+ if (!GDU_IS_DRIVE (p))
+ continue;
+
+ size = gdu_presentable_get_size (p);
+
+ hbox = gdu_grid_hbox_new ();
+ gtk_box_pack_start (GTK_BOX (view),
+ hbox,
+ FALSE,
+ FALSE,
+ 0);
+
+ enclosed_partitions = gdu_pool_get_enclosed_presentables (view->priv->pool, p);
+ enclosed_partitions = g_list_sort (enclosed_partitions, (GCompareFunc) presentable_sort_offset);
+
+ element = gdu_grid_element_new (view,
+ p,
+ 180,
+ 0.0,
+ GDU_GRID_ELEMENT_FLAGS_EDGE_TOP |
+ GDU_GRID_ELEMENT_FLAGS_EDGE_BOTTOM |
+ GDU_GRID_ELEMENT_FLAGS_EDGE_LEFT |
+ (enclosed_partitions == NULL ? GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT : 0));
+ view->priv->elements = g_list_prepend (view->priv->elements, element);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ element,
+ FALSE,
+ FALSE,
+ 0);
+
+ for (ll = enclosed_partitions; ll != NULL; ll = ll->next) {
+ GduPresentable *ep = GDU_PRESENTABLE (ll->data);
+ GList *enclosed_logical_partitions;
+ gboolean is_last;
+
+ is_last = (ll->next == NULL);
+
+ /* handle extended partitions */
+ enclosed_logical_partitions = gdu_pool_get_enclosed_presentables (view->priv->pool, ep);
+ if (enclosed_logical_partitions != NULL) {
+ GList *lll;
+ guint64 esize;
+ GtkWidget *vbox;
+ GtkWidget *hbox2;
+ guint num_logical_partitions;
+
+ num_logical_partitions = g_list_length (enclosed_logical_partitions);
+
+ vbox = gtk_vbox_new (TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ vbox,
+ FALSE,
+ FALSE,
+ 0);
+
+ /* the extended partition */
+ esize = gdu_presentable_get_size (ep);
+ element = gdu_grid_element_new (view,
+ ep,
+ 60 * num_logical_partitions,
+ ((gdouble) esize) / size,
+ GDU_GRID_ELEMENT_FLAGS_EDGE_TOP |
+ (is_last ? GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT : 0));
+ view->priv->elements = g_list_prepend (view->priv->elements, element);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ element,
+ TRUE,
+ TRUE,
+ 0);
+
+ /* hbox for logical partitions */
+ hbox2 = gdu_grid_hbox_new ();
+ gtk_box_pack_start (GTK_BOX (vbox),
+ hbox2,
+ TRUE,
+ TRUE,
+ 0);
+
+ /* handle logical partitions in extended partition */
+ enclosed_logical_partitions = g_list_sort (enclosed_logical_partitions,
+ (GCompareFunc) presentable_sort_offset);
+ for (lll = enclosed_logical_partitions; lll != NULL; lll = lll->next) {
+ GduPresentable *lp = GDU_PRESENTABLE (lll->data);
+ guint64 lsize;
+ gboolean is_last_logical;
+
+ is_last_logical = (is_last && (lll->next == NULL));
+
+ lsize = gdu_presentable_get_size (lp);
+ element = gdu_grid_element_new (view,
+ lp,
+ 60,
+ ((gdouble) lsize) / esize,
+ GDU_GRID_ELEMENT_FLAGS_EDGE_BOTTOM |
+ (is_last_logical ? GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT : 0));
+ view->priv->elements = g_list_prepend (view->priv->elements, element);
+ gtk_box_pack_start (GTK_BOX (hbox2),
+ element,
+ FALSE,
+ FALSE,
+ 0);
+ }
+ g_list_foreach (enclosed_logical_partitions, (GFunc) g_object_unref, NULL);
+ g_list_free (enclosed_logical_partitions);
+ } else {
+ guint64 psize;
+
+ /* primary partition */
+ psize = gdu_presentable_get_size (ep);
+ element = gdu_grid_element_new (view,
+ ep,
+ 60,
+ ((gdouble) psize) / size,
+ GDU_GRID_ELEMENT_FLAGS_EDGE_TOP |
+ GDU_GRID_ELEMENT_FLAGS_EDGE_BOTTOM |
+ (is_last ? GDU_GRID_ELEMENT_FLAGS_EDGE_RIGHT : 0));
+ view->priv->elements = g_list_prepend (view->priv->elements, element);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ element,
+ FALSE,
+ FALSE,
+ 0);
+ }
+
+ }
+ g_list_foreach (enclosed_partitions, (GFunc) g_object_unref, NULL);
+ g_list_free (enclosed_partitions);
+
+ gtk_widget_show_all (GTK_WIDGET (hbox));
+ }
+ g_list_foreach (presentables, (GFunc) g_object_unref, NULL);
+ g_list_free (presentables);
+}
+
+static void
+gdu_grid_view_constructed (GObject *object)
+{
+ GduGridView *view = GDU_GRID_VIEW (object);
+
+ recompute_grid (view);
+
+ g_signal_connect (view->priv->pool, "presentable-added", G_CALLBACK (on_presentable_added), view);
+ g_signal_connect (view->priv->pool, "presentable-removed", G_CALLBACK (on_presentable_removed), view);
+ g_signal_connect (view->priv->pool, "presentable-changed", G_CALLBACK (on_presentable_changed), view);
+
+ if (G_OBJECT_CLASS (gdu_grid_view_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (gdu_grid_view_parent_class)->constructed (object);
+}
+
+static void
+gdu_grid_view_class_init (GduGridViewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GduGridViewPrivate));
+
+ object_class->get_property = gdu_grid_view_get_property;
+ object_class->set_property = gdu_grid_view_set_property;
+ object_class->constructed = gdu_grid_view_constructed;
+ object_class->finalize = gdu_grid_view_finalize;
+
+ g_object_class_install_property (object_class,
+ PROP_POOL,
+ g_param_spec_object ("pool",
+ _("Pool"),
+ _("The pool of devices to show"),
+ GDU_TYPE_POOL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gdu_grid_view_init (GduGridView *view)
+{
+ view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view, GDU_TYPE_GRID_VIEW, GduGridViewPrivate);
+}
+
+GtkWidget *
+gdu_grid_view_new (GduPool *pool)
+{
+ return GTK_WIDGET (g_object_new (GDU_TYPE_GRID_VIEW,
+ "pool", pool,
+ NULL));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* TODO: It would be a lot more efficient to just add/remove elements as appropriate.. also,
+ * if we did that we wouldn't be screwing a11y users over
+ */
+
+static void
+on_presentable_added (GduPool *pool,
+ GduPresentable *presentable,
+ GduGridView *view)
+{
+ recompute_grid (view);
+}
+
+
+static void
+on_presentable_removed (GduPool *pool,
+ GduPresentable *presentable,
+ GduGridView *view)
+{
+ gdu_grid_view_selection_remove (view, presentable);
+ recompute_grid (view);
+}
+
+static void
+on_presentable_changed (GduPool *pool,
+ GduPresentable *presentable,
+ GduGridView *view)
+{
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GduGridElement *
+get_element_for_presentable (GduGridView *view,
+ GduPresentable *presentable)
+{
+ GduGridElement *ret;
+ GList *l;
+
+ ret = NULL;
+
+ for (l = view->priv->elements; l != NULL && ret == NULL; l = l->next) {
+ GduGridElement *e = GDU_GRID_ELEMENT (l->data);
+ GduPresentable *p;
+ p = gdu_grid_element_get_presentable (e);
+ if (p != NULL) {
+ if (p == presentable)
+ ret = e;
+ g_object_unref (p);
+ }
+ }
+
+ return ret;
+}
+
+GList *
+gdu_grid_view_selection_get (GduGridView *view)
+{
+ GList *ret;
+ ret = g_list_copy (view->priv->selected);
+ g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+ return ret;
+}
+
+void
+gdu_grid_view_selection_add (GduGridView *view,
+ GduPresentable *presentable)
+{
+ GduGridElement *e;
+
+ g_return_if_fail (presentable != NULL);
+
+ view->priv->selected = g_list_prepend (view->priv->selected, g_object_ref (presentable));
+
+ e = get_element_for_presentable (view, presentable);
+ if (e != NULL) {
+ gtk_widget_queue_draw (GTK_WIDGET (e));
+ }
+}
+
+void
+gdu_grid_view_selection_remove (GduGridView *view,
+ GduPresentable *presentable)
+{
+ GList *l;
+ for (l = view->priv->selected; l != NULL; l = l->next) {
+ if (l->data == presentable) {
+ GduGridElement *e;
+ e = get_element_for_presentable (view, presentable);
+ if (e != NULL) {
+ gtk_widget_queue_draw (GTK_WIDGET (e));
+ }
+ view->priv->selected = g_list_remove (view->priv->selected, presentable);
+ g_object_unref (presentable);
+ break;
+ }
+ }
+}
+
+gboolean
+gdu_grid_view_is_selected (GduGridView *view,
+ GduPresentable *presentable)
+{
+ GList *l;
+ gboolean ret;
+
+ ret = FALSE;
+
+ for (l = view->priv->selected; l != NULL; l = l->next) {
+ if (l->data == presentable) {
+ ret = TRUE;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void
+gdu_grid_view_selection_clear (GduGridView *view)
+{
+ GList *l;
+ for (l = view->priv->selected; l != NULL; l = l->next) {
+ GduGridElement *e;
+ e = get_element_for_presentable (view, l->data);
+ if (e != NULL) {
+ gtk_widget_queue_draw (GTK_WIDGET (e));
+ }
+ }
+
+ g_list_foreach (view->priv->selected, (GFunc) g_object_unref, NULL);
+ g_list_free (view->priv->selected);
+ view->priv->selected = NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/playground/grid/gdu-grid-view.h b/src/playground/grid/gdu-grid-view.h
new file mode 100644
index 0000000..9e00e54
--- /dev/null
+++ b/src/playground/grid/gdu-grid-view.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+#ifndef __GDU_GRID_VIEW_H
+#define __GDU_GRID_VIEW_H
+
+#include "gdu-grid-types.h"
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_GRID_VIEW gdu_grid_view_get_type()
+#define GDU_GRID_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_GRID_VIEW, GduGridView))
+#define GDU_GRID_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_GRID_VIEW, GduGridViewClass))
+#define GDU_IS_GRID_VIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_GRID_VIEW))
+#define GDU_IS_GRID_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_GRID_VIEW))
+#define GDU_GRID_VIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_GRID_VIEW, GduGridViewClass))
+
+typedef struct GduGridViewClass GduGridViewClass;
+typedef struct GduGridViewPrivate GduGridViewPrivate;
+
+struct GduGridView
+{
+ GtkVBox parent;
+
+ /*< private >*/
+ GduGridViewPrivate *priv;
+};
+
+struct GduGridViewClass
+{
+ GtkVBoxClass parent_class;
+};
+
+GType gdu_grid_view_get_type (void) G_GNUC_CONST;
+GtkWidget *gdu_grid_view_new (GduPool *pool);
+
+gboolean gdu_grid_view_is_selected (GduGridView *view,
+ GduPresentable *presentable);
+GList *gdu_grid_view_selection_get (GduGridView *view);
+void gdu_grid_view_selection_add (GduGridView *view,
+ GduPresentable *presentable);
+void gdu_grid_view_selection_remove (GduGridView *view,
+ GduPresentable *presentable);
+void gdu_grid_view_selection_clear (GduGridView *view);
+
+G_END_DECLS
+
+#endif /* __GDU_GRID_VIEW_H */
diff --git a/src/playground/grid/grid.c b/src/playground/grid/grid.c
new file mode 100644
index 0000000..7a86120
--- /dev/null
+++ b/src/playground/grid/grid.c
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+
+#include <gtk/gtk.h>
+#include <gdu/gdu.h>
+
+#include "gdu-grid-view.h"
+
+int
+main (int argc, char *argv[])
+{
+ GduPool *pool;
+ GtkWidget *window;
+ GtkWidget *vbox;
+ GtkWidget *scrolled_window;
+ GtkWidget *grid_view;
+
+ gtk_init (&argc, &argv);
+
+ pool = gdu_pool_new ();
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ grid_view = gdu_grid_view_new (pool);
+
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), grid_view);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ scrolled_window,
+ TRUE,
+ TRUE,
+ 0);
+
+ /* add a dummy button box for now.. just to test focus */
+ GtkWidget *button_box;
+ button_box = gtk_hbutton_box_new ();
+ gtk_container_add (GTK_CONTAINER (button_box), gtk_button_new_from_stock (GTK_STOCK_OK));
+ gtk_container_add (GTK_CONTAINER (button_box), gtk_button_new_from_stock (GTK_STOCK_APPLY));
+ gtk_container_add (GTK_CONTAINER (button_box), gtk_button_new_from_stock (GTK_STOCK_CANCEL));
+ gtk_box_pack_start (GTK_BOX (vbox),
+ button_box,
+ FALSE,
+ FALSE,
+ 0);
+
+ gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
+ gtk_widget_show_all (window);
+ gtk_main ();
+
+ g_object_unref (pool);
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]