diff --git a/ChangeLog b/ChangeLog index c2ecdea27..9e52bf3de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2004-05-14 Todd Berman + + * glib/Object.cs: make static GLib.Object.LookupGType protected for now. + * gtk/CellRenderer.custom: code to allow for subclassing and + implementing a custom cell renderer. + * gtk/Makefile.am: add custom to build. + * gtk/glue/Makefile.am: add glue to build. + * gtk/glue/cellrenderer.c: glue code to override get_size and render + from cellrenderer. + * sample/CustomCellRenderer.cs: new sample to show how to implement a + custom cell renderer. + * sample/Makefile.am: add CustomCellRenderer sample. + 2004-05-13 Todd Berman * *.pc.in: add .dll to the end of the Libs: references, and convert diff --git a/glib/Object.cs b/glib/Object.cs index ec6c00c3b..5fa4aa011 100644 --- a/glib/Object.cs +++ b/glib/Object.cs @@ -144,7 +144,7 @@ namespace GLib { return LookupGType (GetType ()); } - private static GType LookupGType (System.Type t) + protected static GType LookupGType (System.Type t) { if (g_types.Contains (t)) return (GType) g_types [t]; diff --git a/gtk/CellRenderer.custom b/gtk/CellRenderer.custom new file mode 100644 index 000000000..bae2ecb2a --- /dev/null +++ b/gtk/CellRenderer.custom @@ -0,0 +1,89 @@ +// +// CellRenderer.custom - Gtk CellRenderer class customizations +// +// Author: Todd Berman +// +// Copyright (C) 2004 Todd Berman +// +// This code is inserted after the automatically generated code. +// + + public CellRenderer () : base (IntPtr.Zero) + { + if (GetType () != typeof (CellRenderer)) { + CreateNativeObject (new string[0], new GLib.Value[0]); + return; + } + throw new InvalidOperationException ("You MUST subclass this class"); + } + + [DllImport("gtksharpglue")] + static extern void gtksharp_cellrenderer_base_get_size (IntPtr handle, IntPtr widget, Gdk.Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height); + + [DllImport("gtksharpglue")] + static extern void gtksharp_cellrenderer_override_get_size (GLib.GType gtype, GetSizeDelegate cb); + + delegate void GetSizeDelegate (IntPtr item, IntPtr widget, ref Gdk.Rectangle cell_area, IntPtr x_offset, IntPtr y_offset, IntPtr width, IntPtr height); + + static GetSizeDelegate GetSizeCallback; + + static void GetSize_cb (IntPtr item, IntPtr widget, ref Gdk.Rectangle cell_area, IntPtr x_offset, IntPtr y_offset, IntPtr width, IntPtr height) + { + CellRenderer obj = GLib.Object.GetObject (item, false) as CellRenderer; + Gtk.Widget widg = GLib.Object.GetObject (widget, false) as Gtk.Widget; + int a, b, c, d; + + obj.OnGetSize (widg, cell_area, out a, out b, out c, out d); + if (x_offset != IntPtr.Zero) + Marshal.WriteInt32 (x_offset, a); + if (y_offset != IntPtr.Zero) + Marshal.WriteInt32 (y_offset, b); + if (!(cell_area.Equals (Gdk.Rectangle.Zero))) { + if (width != IntPtr.Zero) + Marshal.WriteInt32 (width, c); + if (height != IntPtr.Zero) + Marshal.WriteInt32 (height, d); + } + } + + protected static void OverrideGetSize (GLib.GType gtype) + { + if (GetSizeCallback == null) + GetSizeCallback = new GetSizeDelegate (GetSize_cb); + gtksharp_cellrenderer_override_get_size (gtype, GetSizeCallback); + } + + protected virtual void OnGetSize (Gtk.Widget widget, Gdk.Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height) + { + gtksharp_cellrenderer_base_get_size (Handle, widget.Handle, cell_area, out x_offset, out y_offset, out width, out height); + } + + [DllImport("gtksharpglue")] + static extern void gtksharp_cellrenderer_base_render (IntPtr handle, IntPtr window, IntPtr widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gdk.Rectangle expose_area, Gtk.CellRendererState flags); + + [DllImport("gtksharpglue")] + static extern void gtksharp_cellrenderer_override_render (GLib.GType gtype, RenderDelegate cb); + + delegate void RenderDelegate (IntPtr item, IntPtr window, IntPtr widget, ref Gdk.Rectangle background_area, ref Gdk.Rectangle cell_area, ref Gdk.Rectangle expose_area, Gtk.CellRendererState flags); + + static RenderDelegate RenderCallback; + + static void Render_cb (IntPtr item, IntPtr window, IntPtr widget, ref Gdk.Rectangle background_area, ref Gdk.Rectangle cell_area, ref Gdk.Rectangle expose_area, Gtk.CellRendererState flags) + { + CellRenderer obj = GLib.Object.GetObject (item, false) as CellRenderer; + Gdk.Drawable wind = GLib.Object.GetObject (window, false) as Gdk.Drawable; + Gtk.Widget widg = GLib.Object.GetObject (widget, false) as Gtk.Widget; + obj.OnRender (wind, widg, background_area, cell_area, expose_area, flags); + } + + protected static void OverrideRender (GLib.GType gtype) + { + if (RenderCallback == null) + RenderCallback = new RenderDelegate (Render_cb); + gtksharp_cellrenderer_override_render (gtype, RenderCallback); + } + + protected virtual void OnRender (Gdk.Drawable window, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gdk.Rectangle expose_area, Gtk.CellRendererState flags) + { + gtksharp_cellrenderer_base_render (Handle, window.Handle, widget.Handle, background_area, cell_area, expose_area, flags); + } diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 2d6a97902..8d247f17f 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -33,6 +33,7 @@ customs = \ Adjustment.custom \ Button.custom \ Calendar.custom \ + CellRenderer.custom \ CheckMenuItem.custom \ Clipboard.custom \ ColorSelection.custom \ diff --git a/gtk/glue/Makefile.am b/gtk/glue/Makefile.am index 47f6a1007..05260e926 100644 --- a/gtk/glue/Makefile.am +++ b/gtk/glue/Makefile.am @@ -3,6 +3,7 @@ lib_LTLIBRARIES = libgtksharpglue.la libgtksharpglue_la_SOURCES = \ adjustment.c \ button.c \ + cellrenderer.c \ clipboard.c \ colorseldialog.c \ combo.c \ diff --git a/gtk/glue/cellrenderer.c b/gtk/glue/cellrenderer.c new file mode 100644 index 000000000..8fd15e16e --- /dev/null +++ b/gtk/glue/cellrenderer.c @@ -0,0 +1,50 @@ +/* cellrenderer.c : Glue for overriding pieces of GtkCellRenderer + * + * Author: Todd Berman (tberman@sevenl.net) + * + * Copyright (C) 2004 Todd Berman + */ + +#include + +void gtksharp_cellrenderer_base_get_size (GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height); + +void +gtksharp_cellrenderer_base_get_size (GtkCellRenderer *cell, GtkWidget *widget, GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height) +{ + GtkCellRendererClass *parent = g_type_class_peek_parent (G_OBJECT_GET_CLASS (cell)); + if (parent->get_size) + (*parent->get_size) (cell, widget, cell_area, x_offset, y_offset, width, height); +} + +void gtksharp_cellrenderer_override_get_size (GType gtype, gpointer cb); + +void +gtksharp_cellrenderer_override_get_size (GType gtype, gpointer cb) +{ + GtkCellRendererClass *klass = g_type_class_peek (gtype); + if (!klass) + klass = g_type_class_ref (gtype); + ((GtkCellRendererClass *) klass)->get_size = cb; +} + +void gtksharp_cellrenderer_base_render (GtkCellRenderer *cell, GdkDrawable *window, GtkWidget *widget, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags); + +void +gtksharp_cellrenderer_base_render (GtkCellRenderer *cell, GdkDrawable *window, GtkWidget *widget, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags) +{ + GtkCellRendererClass *parent = g_type_class_peek_parent (G_OBJECT_GET_CLASS (cell)); + if (parent->render) + (*parent->render) (cell, window, widget, background_area, cell_area, expose_area, flags); +} + +void gtksharp_cellrenderer_override_render (GType gtype, gpointer cb); + +void +gtksharp_cellrenderer_override_render (GType gtype, gpointer cb) +{ + GtkCellRendererClass *klass = g_type_class_peek (gtype); + if (!klass) + klass = g_type_class_ref (gtype); + ((GtkCellRendererClass *) klass)->render = cb; +} diff --git a/sample/CustomCellRenderer.cs b/sample/CustomCellRenderer.cs new file mode 100644 index 000000000..3ceef9d51 --- /dev/null +++ b/sample/CustomCellRenderer.cs @@ -0,0 +1,150 @@ +// CustomCellRenderer.cs : C# implementation of an example custom cellrenderer +// from http://scentric.net/tutorial/sec-custom-cell-renderers.html +// +// Author: Todd Berman +// +// (c) 2004 Todd Berman + +using System; + +using Gtk; +using Gdk; +using GLib; + +public class CustomCellRenderer : CellRenderer +{ + + private float percent; + + public float Percentage + { + get { + return percent; + } + set { + percent = value; + } + } + + static CustomCellRenderer () + { + OverrideGetSize (GLib.Object.LookupGType (typeof (CustomCellRenderer))); + OverrideRender (GLib.Object.LookupGType (typeof (CustomCellRenderer))); + } + + protected override void OnGetSize (Widget widget, Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height) + { + int calc_width = (int) this.Xpad * 2 + 100; + int calc_height = (int) this.Ypad * 2 + 10; + + width = calc_width; + height = calc_height; + + x_offset = 0; + y_offset = 0; + if (!cell_area.Equals (Rectangle.Zero)) { + x_offset = (int) (this.Xalign * (this.Width - calc_width)); + x_offset = Math.Max (x_offset, 0); + + y_offset = (int) (this.Yalign * (this.Height - calc_height)); + y_offset = Math.Max (y_offset, 0); + } + } + + protected override void OnRender (Drawable window, Widget widget, Rectangle background_area, Rectangle cell_area, Rectangle expose_area, CellRendererState flags) + { + int width = 0, height = 0, x_offset = 0, y_offset = 0; + StateType state; + OnGetSize (widget, cell_area, out x_offset, out y_offset, out width, out height); + + if (widget.HasFocus) + state = StateType.Active; + else + state = StateType.Normal; + + width -= (int) this.Xpad * 2; + height -= (int) this.Ypad * 2; + + + //FIXME: Style.PaintBox needs some customization so that if you pass it + //a Gdk.Rectangle.Zero it gives a clipping area big enough to draw + //everything + Gdk.Rectangle clipping_area = new Gdk.Rectangle ((int) (cell_area.X + x_offset + this.Xpad), (int) (cell_area.Y + y_offset + this.Ypad), width - 1, height - 1); + + Style.PaintBox (widget.Style, (Gdk.Window) window, StateType.Normal, ShadowType.In, clipping_area, widget, "trough", (int) (cell_area.X + x_offset + this.Xpad), (int) (cell_area.Y + y_offset + this.Ypad), width - 1, height - 1); + + Gdk.Rectangle clipping_area2 = new Gdk.Rectangle ((int) (cell_area.X + x_offset + this.Xpad), (int) (cell_area.Y + y_offset + this.Ypad), (int) (width * Percentage), height - 1); + + Style.PaintBox (widget.Style, (Gdk.Window) window, state, ShadowType.Out, clipping_area2, widget, "bar", (int) (cell_area.X + x_offset + this.Xpad), (int) (cell_area.Y + y_offset + this.Ypad), (int) (width * Percentage), height - 1); + } +} + +public class Driver : Gtk.Window +{ + public static void Main () + { + Application.Init (); + new Driver (); + Application.Run (); + } + + ListStore liststore; + + void ProgressData (Gtk.TreeViewColumn tree_column, Gtk.CellRenderer cell, Gtk.TreeModel tree_model, Gtk.TreeIter iter) + { + float perc = (float) liststore.GetValue (iter, 0); + ((CustomCellRenderer)cell).Percentage = perc; + } + + public Driver () : base ("CustomCellRenderer") + { + DefaultSize = new Size (150, 100); + this.DeleteEvent += new DeleteEventHandler (window_delete); + + liststore = new ListStore (typeof (float), typeof (string)); + liststore.AppendValues (0.5f, "0.5"); + + TreeView view = new TreeView (liststore); + + view.AppendColumn ("Progress", new CellRendererText (), "text", 1); + + //Note: This *MUST* be done here, as its the only place Progress is + //accessible. Maybe there should be an attribute that will do some + //magic for you and register a property with the gobject system. + view.AppendColumn ("Progress", new CustomCellRenderer (), new TreeCellDataFunc (ProgressData)); + + this.Add (view); + this.ShowAll (); + + Gtk.Timeout.Add (50, new Gtk.Function (update_percent)); + } + + bool increasing = true; + bool update_percent () + { + TreeIter iter; + liststore.GetIterFirst (out iter); + float perc = (float) liststore.GetValue (iter, 0); + + if ((perc > 0.99) || (perc < 0.01 && perc > 0)) { + increasing = !increasing; + } + + if (increasing) + perc += 0.01f; + else + perc -= 0.01f; + + liststore.SetValue (iter, 0, perc); + liststore.SetValue (iter, 1, perc.ToString ()); + + return true; + } + + void window_delete (object obj, DeleteEventArgs args) + { + Application.Quit (); + args.RetVal = true; + } +} + diff --git a/sample/Makefile.am b/sample/Makefile.am index 6b358643e..88fe0cbb7 100755 --- a/sample/Makefile.am +++ b/sample/Makefile.am @@ -24,7 +24,7 @@ VTE_TARGETS= VTE_ASSEMBLY= endif -TARGETS = gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe treeviewdemo.exe managedtreeviewdemo.exe testdnd.exe $(GNOME_TARGETS) $(GLADE_TARGETS) $(VTE_TARGETS) +TARGETS = custom-cellrenderer.exe gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe treeviewdemo.exe managedtreeviewdemo.exe testdnd.exe $(GNOME_TARGETS) $(GLADE_TARGETS) $(VTE_TARGETS) assemblies=../glib/glib-sharp.dll ../pango/pango-sharp.dll ../atk/atk-sharp.dll ../gdk/gdk-sharp.dll ../gtk/gtk-sharp.dll $(GNOME_ASSEMBLY) $(GLADE_ASSEMBLY) $(VTE_ASSEMBLY) references=$(addprefix -r , $(assemblies)) @@ -86,6 +86,9 @@ testdnd.exe: $(srcdir)/TestDnd.cs $(assemblies) vte-example.exe: $(srcdir)/VteTest.cs $(assemblies) $(CSC) -g --unsafe -o vte-example.exe $(references) $(srcdir)/VteTest.cs +custom-cellrenderer.exe: $(srcdir)/CustomCellRenderer.cs $(assemblies) + $(CSC) -g -o custom-cellrenderer.exe $(references) $(srcdir)/CustomCellRenderer.cs + EXTRA_DIST = \ HelloWorld.cs \ GnomeHelloWorld.cs \ @@ -105,5 +108,5 @@ EXTRA_DIST = \ test.glade \ CairoSample.cs \ TestDnd.cs \ - VteTest.cs - + VteTest.cs \ + CustomCellRenderer.cs