[libgda] Better mark data entries with invalid data



commit ed8a7b508165141b4da0afd45d04322882da02b6
Author: Vivien Malerba <malerba gnome-db org>
Date:   Mon Jun 21 20:52:38 2010 +0200

    Better mark data entries with invalid data

 libgda-ui/data-entries/Makefile.am         |    2 +
 libgda-ui/data-entries/gdaui-entry-shell.c |   36 ++-
 libgda-ui/data-entries/widget-embedder.c   |  439 ++++++++++++++++++++++++++++
 libgda-ui/data-entries/widget-embedder.h   |   51 ++++
 4 files changed, 516 insertions(+), 12 deletions(-)
---
diff --git a/libgda-ui/data-entries/Makefile.am b/libgda-ui/data-entries/Makefile.am
index be69277..1def51e 100644
--- a/libgda-ui/data-entries/Makefile.am
+++ b/libgda-ui/data-entries/Makefile.am
@@ -48,6 +48,8 @@ libgda_ui_data_entries_la_SOURCES = \
 	gdaui-entry-boolean.c \
 	gdaui-entry-combo.c \
 	gdaui-entry-none.c \
+	widget-embedder.c \
+	widget-embedder.h \
 	gdaui-entry-shell.c \
 	gdaui-entry-string.c \
 	gdaui-entry-number.c \
diff --git a/libgda-ui/data-entries/gdaui-entry-shell.c b/libgda-ui/data-entries/gdaui-entry-shell.c
index c18076f..e200cbc 100644
--- a/libgda-ui/data-entries/gdaui-entry-shell.c
+++ b/libgda-ui/data-entries/gdaui-entry-shell.c
@@ -24,7 +24,9 @@
 #include <libgda/gda-data-handler.h>
 #include <libgda-ui/internal/utility.h>
 #include <glib/gi18n-lib.h>
-
+#if GTK_CHECK_VERSION (2,18,0)
+#include "widget-embedder.h"
+#endif
 static void gdaui_entry_shell_class_init (GdauiEntryShellClass *class);
 static void gdaui_entry_shell_init (GdauiEntryShell *wid);
 static void gdaui_entry_shell_dispose (GObject *object);
@@ -53,7 +55,7 @@ enum {
 };
 
 struct  _GdauiEntryShellPriv {
-        GtkWidget           *top_box;
+        GtkWidget           *embedder;
 	GtkWidget           *hbox;
         GtkWidget           *button;
         GtkStyle            *orig_style;
@@ -138,12 +140,12 @@ show_all (GtkWidget *widget)
 static void
 gdaui_entry_shell_init (GdauiEntryShell * shell)
 {
-	GtkWidget *button, *hbox, *vbox, *arrow;
+	GtkWidget *button, *hbox, *arrow;
 	GValue *gval;
 
 	/* Private structure */
 	shell->priv = g_new0 (GdauiEntryShellPriv, 1);
-	shell->priv->top_box = NULL;
+	shell->priv->embedder = NULL;
 	shell->priv->button = NULL;
 	shell->priv->show_actions = TRUE;
 	shell->priv->data_handler = NULL;
@@ -167,10 +169,13 @@ gdaui_entry_shell_init (GdauiEntryShell * shell)
 	shell->priv->hbox = hbox;
 
 	/* vbox to insert the real widget to edit data */
-	vbox = gtk_vbox_new (FALSE, 0);
-	gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
-	shell->priv->top_box = vbox;
-	gtk_widget_show (vbox);
+#if GTK_CHECK_VERSION (2,18,0)
+	shell->priv->embedder = widget_embedder_new ();
+#else
+	shell->priv->embedder = gtk_vbox_new (FALSE, 0);
+#endif
+	gtk_box_pack_start (GTK_BOX (hbox), shell->priv->embedder, TRUE, TRUE, 0);
+	gtk_widget_show (shell->priv->embedder);	
 
 	/* button to change the entry's state and to display that state */
 	arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
@@ -301,8 +306,11 @@ gdaui_entry_shell_pack_entry (GdauiEntryShell *shell, GtkWidget *main_widget)
 {
 	g_return_if_fail (GDAUI_IS_ENTRY_SHELL (shell));
 	g_return_if_fail (main_widget && GTK_IS_WIDGET (main_widget));
-
-	gtk_box_pack_start (GTK_BOX (shell->priv->top_box), main_widget, TRUE, TRUE, 0);
+#if GTK_CHECK_VERSION (2,18,0)
+	gtk_container_add (GTK_CONTAINER (shell->priv->embedder), main_widget);
+#else
+	gtk_box_pack_start (GTK_BOX (shell->priv->embedder), main_widget, TRUE, TRUE, 0);
+#endif
 
 	/* signals */
 	g_signal_connect (G_OBJECT (shell), "contents-modified",
@@ -462,8 +470,12 @@ gdaui_entry_shell_set_unknown (GdauiEntryShell *shell, gboolean unknown)
 {
 	g_return_if_fail (GDAUI_IS_ENTRY_SHELL (shell));
 
+#if GTK_CHECK_VERSION (2,18,0)
+	widget_embedder_set_valid ((WidgetEmbedder*) shell->priv->embedder, !unknown);
+#else
 	if (unknown)
-		gtk_widget_hide (shell->priv->hbox);
+		gtk_widget_hide (shell->priv->embedder);
 	else
-		gtk_widget_show (shell->priv->hbox);
+		gtk_widget_show (shell->priv->embedder);
+#endif
 }
diff --git a/libgda-ui/data-entries/widget-embedder.c b/libgda-ui/data-entries/widget-embedder.c
new file mode 100644
index 0000000..df0fa59
--- /dev/null
+++ b/libgda-ui/data-entries/widget-embedder.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2010 Vivien Malerba <malerba gnome-db org>
+ *               1997-2000 GTK+ Team and others.
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+#include "widget-embedder.h"
+#if GTK_CHECK_VERSION (2,18,0)
+static void     widget_embedder_realize       (GtkWidget       *widget);
+static void     widget_embedder_unrealize     (GtkWidget       *widget);
+static void     widget_embedder_size_request  (GtkWidget       *widget,
+                                               GtkRequisition  *requisition);
+static void     widget_embedder_size_allocate (GtkWidget       *widget,
+                                               GtkAllocation   *allocation);
+static gboolean widget_embedder_damage        (GtkWidget       *widget,
+                                               GdkEventExpose  *event);
+static gboolean widget_embedder_expose        (GtkWidget       *widget,
+                                               GdkEventExpose  *offscreen);
+
+static void     widget_embedder_add           (GtkContainer    *container,
+                                               GtkWidget       *child);
+static void     widget_embedder_remove        (GtkContainer    *container,
+                                               GtkWidget       *widget);
+static void     widget_embedder_forall        (GtkContainer    *container,
+                                               gboolean         include_internals,
+                                               GtkCallback      callback,
+                                               gpointer         callback_data);
+static GType    widget_embedder_child_type    (GtkContainer    *container);
+
+G_DEFINE_TYPE (WidgetEmbedder, widget_embedder, GTK_TYPE_CONTAINER);
+
+static void
+to_child (WidgetEmbedder *bin,
+          double         widget_x,
+          double         widget_y,
+          double        *x_out,
+          double        *y_out)
+{
+	*x_out = widget_x;
+	*y_out = widget_y;
+}
+
+static void
+to_parent (WidgetEmbedder *bin,
+           double         offscreen_x,
+           double         offscreen_y,
+           double        *x_out,
+           double        *y_out)
+{
+	*x_out = offscreen_x;
+	*y_out = offscreen_y;
+}
+
+static void
+widget_embedder_class_init (WidgetEmbedderClass *klass)
+{
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+	GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+	widget_class->realize = widget_embedder_realize;
+	widget_class->unrealize = widget_embedder_unrealize;
+	widget_class->size_request = widget_embedder_size_request;
+	widget_class->size_allocate = widget_embedder_size_allocate;
+	widget_class->expose_event = widget_embedder_expose;
+
+	g_signal_override_class_closure (g_signal_lookup ("damage-event", GTK_TYPE_WIDGET),
+					 WIDGET_EMBEDDER_TYPE,
+					 g_cclosure_new (G_CALLBACK (widget_embedder_damage),
+							 NULL, NULL));
+
+	container_class->add = widget_embedder_add;
+	container_class->remove = widget_embedder_remove;
+	container_class->forall = widget_embedder_forall;
+	container_class->child_type = widget_embedder_child_type;
+}
+
+static void
+widget_embedder_init (WidgetEmbedder *bin)
+{
+	gtk_widget_set_has_window (GTK_WIDGET (bin), TRUE);
+	bin->valid = TRUE;
+}
+
+GtkWidget *
+widget_embedder_new (void)
+{
+	return g_object_new (WIDGET_EMBEDDER_TYPE, NULL);
+}
+
+static GdkWindow *
+pick_offscreen_child (GdkWindow     *offscreen_window,
+                      double         widget_x,
+                      double         widget_y,
+                      WidgetEmbedder *bin)
+{
+	GtkAllocation child_area;
+	double x, y;
+
+	if (bin->child && gtk_widget_get_visible (bin->child)) {
+		to_child (bin, widget_x, widget_y, &x, &y);
+		
+		gtk_widget_get_allocation ((GtkWidget*) bin, &child_area);
+		if (x >= 0 && x < child_area.width &&
+		    y >= 0 && y < child_area.height)
+			return bin->offscreen_window;
+	}
+
+	return NULL;
+}
+
+static void
+offscreen_window_to_parent (GdkWindow     *offscreen_window,
+                            double         offscreen_x,
+                            double         offscreen_y,
+                            double        *parent_x,
+                            double        *parent_y,
+                            WidgetEmbedder *bin)
+{
+	to_parent (bin, offscreen_x, offscreen_y, parent_x, parent_y);
+}
+
+static void
+offscreen_window_from_parent (GdkWindow     *window,
+                              double         parent_x,
+                              double         parent_y,
+                              double        *offscreen_x,
+                              double        *offscreen_y,
+                              WidgetEmbedder *bin)
+{
+	to_child (bin, parent_x, parent_y, offscreen_x, offscreen_y);
+}
+
+static void
+widget_embedder_realize (GtkWidget *widget)
+{
+	WidgetEmbedder *bin = WIDGET_EMBEDDER (widget);
+	GdkWindowAttr attributes;
+	gint attributes_mask;
+	gint border_width;
+	GtkRequisition child_requisition;
+	GtkAllocation allocation;
+
+	gtk_widget_set_realized (widget, TRUE);
+
+	border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+
+	gtk_widget_get_allocation (widget, &allocation);
+	attributes.x = allocation.x + border_width;
+	attributes.y = allocation.y + border_width;
+	attributes.width = allocation.width - 2 * border_width;
+	attributes.height = allocation.height - 2 * border_width;
+	attributes.window_type = GDK_WINDOW_CHILD;
+	attributes.event_mask = gtk_widget_get_events (widget)
+		| GDK_EXPOSURE_MASK
+		| GDK_POINTER_MOTION_MASK
+		| GDK_BUTTON_PRESS_MASK
+		| GDK_BUTTON_RELEASE_MASK
+		| GDK_SCROLL_MASK
+		| GDK_ENTER_NOTIFY_MASK
+		| GDK_LEAVE_NOTIFY_MASK;
+
+	attributes.visual = gtk_widget_get_visual (widget);
+	attributes.colormap = gtk_widget_get_colormap (widget);
+	attributes.wclass = GDK_INPUT_OUTPUT;
+
+	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+	GdkWindow *win;
+	win = gdk_window_new (gtk_widget_get_parent_window (widget),
+			      &attributes, attributes_mask);
+	gtk_widget_set_window (widget, win);
+	gdk_window_set_user_data (win, widget);
+	g_signal_connect (win, "pick-embedded-child",
+			  G_CALLBACK (pick_offscreen_child), bin);
+
+	attributes.window_type = GDK_WINDOW_OFFSCREEN;
+
+	child_requisition.width = child_requisition.height = 0;
+	if (bin->child && gtk_widget_get_visible (bin->child)) {
+		GtkAllocation allocation;
+		gtk_widget_get_allocation (bin->child, &allocation);
+		attributes.width = allocation.width;
+		attributes.height = allocation.height;
+	}
+	bin->offscreen_window = gdk_window_new (gtk_widget_get_root_window (widget),
+						&attributes, attributes_mask);
+	gdk_window_set_user_data (bin->offscreen_window, widget);
+	if (bin->child)
+		gtk_widget_set_parent_window (bin->child, bin->offscreen_window);
+	gdk_offscreen_window_set_embedder (bin->offscreen_window, win);
+	g_signal_connect (bin->offscreen_window, "to-embedder",
+			  G_CALLBACK (offscreen_window_to_parent), bin);
+	g_signal_connect (bin->offscreen_window, "from-embedder",
+			  G_CALLBACK (offscreen_window_from_parent), bin);
+
+	GtkStyle *style;
+	style = gtk_widget_get_style (widget);
+	style = gtk_style_attach (style, win);
+	gtk_widget_set_style (widget, style);
+
+	gtk_style_set_background (style, win, GTK_STATE_NORMAL);
+	gtk_style_set_background (style, bin->offscreen_window, GTK_STATE_NORMAL);
+	gdk_window_show (bin->offscreen_window);
+}
+
+static void
+widget_embedder_unrealize (GtkWidget *widget)
+{
+	WidgetEmbedder *bin = WIDGET_EMBEDDER (widget);
+
+	gdk_window_set_user_data (bin->offscreen_window, NULL);
+	gdk_window_destroy (bin->offscreen_window);
+	bin->offscreen_window = NULL;
+
+	GTK_WIDGET_CLASS (widget_embedder_parent_class)->unrealize (widget);
+}
+
+static GType
+widget_embedder_child_type (GtkContainer *container)
+{
+	WidgetEmbedder *bin = WIDGET_EMBEDDER (container);
+
+	if (bin->child)
+		return G_TYPE_NONE;
+
+	return GTK_TYPE_WIDGET;
+}
+
+static void
+widget_embedder_add (GtkContainer *container,
+                     GtkWidget    *widget)
+{
+	WidgetEmbedder *bin = WIDGET_EMBEDDER (container);
+
+	if (!bin->child) {
+		gtk_widget_set_parent_window (widget, bin->offscreen_window);
+		gtk_widget_set_parent (widget, GTK_WIDGET (bin));
+		bin->child = widget;
+	}
+	else
+		g_warning ("WidgetEmbedder cannot have more than one child\n");
+}
+
+static void
+widget_embedder_remove (GtkContainer *container,
+                        GtkWidget    *widget)
+{
+	WidgetEmbedder *bin = WIDGET_EMBEDDER (container);
+	gboolean was_visible;
+
+	was_visible = gtk_widget_get_visible (widget);
+
+	if (bin->child == widget) {
+		gtk_widget_unparent (widget);
+		
+		bin->child = NULL;
+		
+		if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
+			gtk_widget_queue_resize (GTK_WIDGET (container));
+	}
+}
+
+static void
+widget_embedder_forall (GtkContainer *container,
+                        gboolean      include_internals,
+                        GtkCallback   callback,
+                        gpointer      callback_data)
+{
+	WidgetEmbedder *bin = WIDGET_EMBEDDER (container);
+
+	g_return_if_fail (callback != NULL);
+
+	if (bin->child)
+		(*callback) (bin->child, callback_data);
+}
+
+static void
+widget_embedder_size_request (GtkWidget      *widget,
+                              GtkRequisition *requisition)
+{
+	WidgetEmbedder *bin = WIDGET_EMBEDDER (widget);
+	GtkRequisition child_requisition;
+
+	child_requisition.width = 0;
+	child_requisition.height = 0;
+
+	if (bin->child && gtk_widget_get_visible (bin->child))
+		gtk_widget_size_request (bin->child, &child_requisition);
+
+	guint border_width;
+	border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+	requisition->width = border_width * 2 + child_requisition.width;
+	requisition->height = border_width * 2 + child_requisition.height;
+}
+
+static void
+widget_embedder_size_allocate (GtkWidget     *widget,
+                               GtkAllocation *allocation)
+{
+	WidgetEmbedder *bin = WIDGET_EMBEDDER (widget);
+	gint border_width;
+	gint w, h;
+
+	gtk_widget_set_allocation (widget, allocation);
+
+	border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+
+	w = allocation->width - border_width * 2;
+	h = allocation->height - border_width * 2;
+
+	if (gtk_widget_get_realized (widget)) {
+		GdkWindow *win;
+		win = gtk_widget_get_window (widget);
+		gdk_window_move_resize (win,
+					allocation->x + border_width,
+					allocation->y + border_width,
+					w, h);
+	}
+
+	if (bin->child && gtk_widget_get_visible (bin->child)){
+		GtkRequisition child_requisition;
+		GtkAllocation child_allocation;
+		
+		gtk_widget_get_child_requisition (bin->child, &child_requisition);
+		child_allocation.x = 0;
+		child_allocation.y = 0;
+		child_allocation.height = child_requisition.height;
+		child_allocation.width = w;
+		
+		if (gtk_widget_get_realized (widget))
+			gdk_window_move_resize (bin->offscreen_window,
+						child_allocation.x,
+						child_allocation.y,
+						child_allocation.width,
+						child_allocation.height);
+		
+		child_allocation.x = child_allocation.y = 0;
+		gtk_widget_size_allocate (bin->child, &child_allocation);
+	}
+}
+
+static gboolean
+widget_embedder_damage (GtkWidget      *widget,
+                        GdkEventExpose *event)
+{
+	gdk_window_invalidate_rect (gtk_widget_get_window (widget), NULL, FALSE);
+
+	return TRUE;
+}
+
+static gboolean
+widget_embedder_expose (GtkWidget      *widget,
+                        GdkEventExpose *event)
+{
+	WidgetEmbedder *bin = WIDGET_EMBEDDER (widget);
+	gint width, height;
+
+	if (gtk_widget_is_drawable (widget)) {
+		GdkWindow *win;
+		win = gtk_widget_get_window (widget);
+		if (event->window == win) {
+			GdkPixmap *pixmap;
+			cairo_t *cr;
+
+			if (bin->child && gtk_widget_get_visible (bin->child)) {
+				GtkAllocation child_area;
+				pixmap = gdk_offscreen_window_get_pixmap (bin->offscreen_window);
+
+				gtk_widget_get_allocation (bin->child, &child_area);
+				cr = gdk_cairo_create (win);
+				
+				/* clip */
+				gdk_drawable_get_size (pixmap, &width, &height);
+				cairo_rectangle (cr, 0, 0, width, height);
+				cairo_clip (cr);
+
+				/* paint */
+				gdk_cairo_set_source_pixmap (cr, pixmap, 0, 0);
+				cairo_paint (cr);
+
+				if (! bin->valid) {
+					/* draw */
+					gint i;
+					cairo_set_source_rgba (cr, .5, .5, .5, .4);
+
+					width = child_area.width;
+					height = child_area.height;
+					for (i = 0; ; i++) {
+						gint x = 10 * i;
+						if (x > width + height)
+							break;
+						cairo_move_to (cr, x, 0);
+						cairo_line_to (cr, x - height, height);
+						cairo_stroke (cr);
+					}
+				}
+				cairo_destroy (cr);
+			}
+		}
+		else if (event->window == bin->offscreen_window) {
+			gtk_paint_flat_box (gtk_widget_get_style (widget), event->window,
+					    GTK_STATE_NORMAL, GTK_SHADOW_NONE,
+					    &event->area, widget, "blah",
+					    0, 0, -1, -1);
+			
+			if (bin->child)
+				gtk_container_propagate_expose (GTK_CONTAINER (widget),
+								bin->child,
+								event);
+		}
+	}
+
+	return FALSE;
+}
+
+/**
+ * widget_embedder_set_valid
+ */
+void
+widget_embedder_set_valid (WidgetEmbedder *bin, gboolean valid)
+{
+	bin->valid = valid;
+	gtk_widget_queue_draw (GTK_WIDGET (bin));
+}
+
+#endif
diff --git a/libgda-ui/data-entries/widget-embedder.h b/libgda-ui/data-entries/widget-embedder.h
new file mode 100644
index 0000000..687ce5d
--- /dev/null
+++ b/libgda-ui/data-entries/widget-embedder.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Vivien Malerba <malerba gnome-db org>
+ *               1997-2000 GTK+ Team and others.
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+#include <gtk/gtk.h>
+
+#if GTK_CHECK_VERSION(2,18,0)
+#define WIDGET_EMBEDDER_TYPE              (widget_embedder_get_type ())
+#define WIDGET_EMBEDDER(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), WIDGET_EMBEDDER_TYPE, WidgetEmbedder))
+#define WIDGET_EMBEDDER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), WIDGET_EMBEDDER_TYPE, WidgetEmbedderClass))
+#define IS_WIDGET_EMBEDDER(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WIDGET_EMBEDDER_TYPE))
+#define IS_WIDGET_EMBEDDER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), WIDGET_EMBEDDER_TYPE))
+#define WIDGET_EMBEDDER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), WIDGET_EMBEDDER_TYPE, WidgetEmbedderClass))
+
+typedef struct _WidgetEmbedder   WidgetEmbedder;
+typedef struct _WidgetEmbedderClass  WidgetEmbedderClass;
+
+struct _WidgetEmbedder
+{
+	GtkContainer container;
+
+	GtkWidget *child;
+	GdkWindow *offscreen_window;
+	gboolean   valid;
+};
+
+struct _WidgetEmbedderClass
+{
+	GtkContainerClass parent_class;
+};
+
+GType      widget_embedder_get_type  (void) G_GNUC_CONST;
+GtkWidget* widget_embedder_new       (void);
+void       widget_embedder_set_valid (WidgetEmbedder *bin, gboolean valid);
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]