From b8126ce3af625e4bd458d93f9e1985b730bda558 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 11 Apr 2005 20:35:56 +0000 Subject: [PATCH] * generator/ClassBase.cs (ParseImplements): record both managed and unmanaged interface declarations. (Implements): check recursively * generator/ObjectGen.cs (Generate): output managed interfaces * gtk/Gtk.metadata: make Container implement IEnumerable * gtk/Container.custom (GetEnumerator): implement (a simplified form of Children). (AllChildren): add this (which accumulates the results of Forall()). (ForAll): mark ForAll(bool,CallbackInvoker) obsolete and add a ForAll(bool,Gtk.Callback) overload to replace it. * sample/PolarFixed.cs: new silly but fully-functional demo of how to subclass container. * sample/CustomNotebook.cs: kill this, since it was really complicated, and never fully functional. * sample/GtkDemo/DemoImages.cs (ToggleSensitivity): Use foreach directly on the container, rather than on its .Children. svn path=/trunk/gtk-sharp/; revision=42805 --- ChangeLog | 26 ++ doc/ChangeLog | 4 + doc/en/Gtk/Container.xml | 98 +++++- generator/ClassBase.cs | 26 +- generator/ObjectGen.cs | 19 +- gtk/Container.custom | 56 ++- gtk/Gtk.metadata | 1 + sample/CustomNotebook.cs | 642 ----------------------------------- sample/GtkDemo/DemoImages.cs | 3 +- sample/Makefile.am | 6 +- sample/PolarFixed.cs | 236 +++++++++++++ 11 files changed, 439 insertions(+), 678 deletions(-) delete mode 100644 sample/CustomNotebook.cs create mode 100644 sample/PolarFixed.cs diff --git a/ChangeLog b/ChangeLog index 716ae538b..1f6e47f92 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +2005-04-11 Dan Winship + + * generator/ClassBase.cs (ParseImplements): record both managed + and unmanaged interface declarations. + (Implements): check recursively + + * generator/ObjectGen.cs (Generate): output managed interfaces + + * gtk/Gtk.metadata: make Container implement IEnumerable + + * gtk/Container.custom (GetEnumerator): implement (a simplified + form of Children). + (AllChildren): add this (which accumulates the results of + Forall()). + (ForAll): mark ForAll(bool,CallbackInvoker) obsolete and add a + ForAll(bool,Gtk.Callback) overload to replace it. + + * sample/PolarFixed.cs: new silly but fully-functional demo of + how to subclass container. + + * sample/CustomNotebook.cs: kill this, since it was really + complicated, and never fully functional. + + * sample/GtkDemo/DemoImages.cs (ToggleSensitivity): Use foreach + directly on the container, rather than on its .Children. + 2005-04-11 Mike Kestner * gtk/Quit.custom : obsolete AddFull and implement Add properly. diff --git a/doc/ChangeLog b/doc/ChangeLog index 548c42d9b..56e977836 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2005-04-08 Dan Winship + + * en/Gtk/Container.xml: document new children stuff + 2005-04-04 Dan Winship * en/Pango/Scale.xml: update diff --git a/doc/en/Gtk/Container.xml b/doc/en/Gtk/Container.xml index 8d8ee1885..7183b1b71 100644 --- a/doc/en/Gtk/Container.xml +++ b/doc/en/Gtk/Container.xml @@ -532,15 +532,72 @@ - Obtains the the container's non-internal children. + Obtains an array of the container's (non-internal) children. An array of non-internal children. - - See for details on what constitutes an "internal" child. - + + Returns the container's non-internal children; that is, generally, the + children that were explicitly added to the container by the application, as + opposed to those widgets that are internal implementation details of the + container. + + + If you simply want to do a loop on the + container's children, you do not need to use the Children property. + Just do: + + + +foreach (Widget w in myContainer) { + // Do something with w +} + + + + + Method + + System.Collections.IEnumerator + + + + Returns an for the container's children + a + + + implements + , so you can iterate + through its children like this: + + + +foreach (Widget w in myContainer) { + // Do something with w +} + + + + + + + + Property + + System.Collections.IEnumerable + + + + Allows you to enumerate all of the container's children. + an + + Enumerates all of the container's children, including those widgets that are + internal implementation details of the container. + + + Property @@ -573,7 +630,7 @@ - + Method @@ -585,9 +642,32 @@ Run a given callback for every object inside this container. - a , whether to include this container's children's children when running the callback. + a , whether to include "internal" children when running the callback. a - + + Deprecated: overload instead. + + + + + + Method + + System.Void + + + + + + + Run a given callback for every object inside this container. + a , whether to include "internal" children when running the callback. + a + + Overload this in subclasses of Gtk.Container to implement the + and + methods. + @@ -619,7 +699,7 @@ - Runs over every item in this container. + Runs over every item in this container. a a a , the data to pass to the callback method. @@ -644,4 +724,4 @@ - + \ No newline at end of file diff --git a/generator/ClassBase.cs b/generator/ClassBase.cs index 66957f59f..9ae2edb9e 100644 --- a/generator/ClassBase.cs +++ b/generator/ClassBase.cs @@ -33,7 +33,8 @@ namespace GtkSharp.Generation { protected Hashtable props = new Hashtable(); protected Hashtable sigs = new Hashtable(); protected Hashtable methods = new Hashtable(); - protected ArrayList interfaces = null; + protected ArrayList interfaces = new ArrayList(); + protected ArrayList managed_interfaces = new ArrayList(); protected ArrayList ctors = new ArrayList(); private bool ctors_initted = false; @@ -101,7 +102,7 @@ namespace GtkSharp.Generation { break; case "implements": - interfaces = ParseImplements (member); + ParseImplements (member); break; case "constructor": @@ -193,18 +194,17 @@ namespace GtkSharp.Generation { } } - private ArrayList ParseImplements (XmlElement member) + private void ParseImplements (XmlElement member) { - ArrayList ifaces = new ArrayList (); - foreach (XmlNode node in member.ChildNodes) { if (node.Name != "interface") continue; XmlElement element = (XmlElement) node; - ifaces.Add (element.GetAttribute ("cname")); + if (element.HasAttribute ("cname")) + interfaces.Add (element.GetAttribute ("cname")); + else if (element.HasAttribute ("name")) + managed_interfaces.Add (element.GetAttribute ("name")); } - - return ifaces; } protected bool IgnoreMethod (Method method) @@ -273,7 +273,7 @@ namespace GtkSharp.Generation { if (p == null && Parent != null) p = Parent.GetMethodRecursively (name, true); - if (check_self && p == null && interfaces != null) { + if (check_self && p == null) { foreach (string iface in interfaces) { ClassBase igen = SymbolTable.Table.GetClassGen (iface); p = igen.GetMethodRecursively (name, true); @@ -310,7 +310,7 @@ namespace GtkSharp.Generation { if (p == null && Parent != null) p = Parent.GetSignalRecursively (name, true); - if (check_self && p == null && interfaces != null) { + if (check_self && p == null) { foreach (string iface in interfaces) { ClassBase igen = SymbolTable.Table.GetClassGen (iface); p = igen.GetSignalRecursively (name, true); @@ -324,8 +324,10 @@ namespace GtkSharp.Generation { public bool Implements (string iface) { - if (interfaces != null) - return interfaces.Contains (iface); + if (interfaces.Contains (iface)) + return true; + else if (Parent != null) + return Parent.Implements (iface); else return false; } diff --git a/generator/ObjectGen.cs b/generator/ObjectGen.cs index 0271122d3..55ccb68d9 100644 --- a/generator/ObjectGen.cs +++ b/generator/ObjectGen.cs @@ -140,12 +140,15 @@ namespace GtkSharp.Generation { di.objects.Add (CName, QualifiedName); sw.Write (" : " + cs_parent); } - if (interfaces != null) { - foreach (string iface in interfaces) { - if (Parent != null && Parent.Implements (iface)) - continue; - sw.Write (", " + table.GetCSType (iface)); - } + foreach (string iface in interfaces) { + if (Parent != null && Parent.Implements (iface)) + continue; + sw.Write (", " + table.GetCSType (iface)); + } + foreach (string iface in managed_interfaces) { + if (Parent != null && Parent.Implements (iface)) + continue; + sw.Write (", " + iface); } sw.WriteLine (" {"); sw.WriteLine (); @@ -155,7 +158,7 @@ namespace GtkSharp.Generation { GenChildProperties (gen_info); bool has_sigs = (sigs != null && sigs.Count > 0); - if (!has_sigs && interfaces != null) { + if (!has_sigs) { foreach (string iface in interfaces) { ClassBase igen = table.GetClassGen (iface); if (igen != null && igen.Signals != null) { @@ -180,7 +183,7 @@ namespace GtkSharp.Generation { GenMethods (gen_info, null, null); - if (interfaces != null) { + if (interfaces.Count != 0) { Hashtable all_methods = new Hashtable (); Hashtable collisions = new Hashtable (); foreach (string iface in interfaces) { diff --git a/gtk/Container.custom b/gtk/Container.custom index 75f8ccf65..f07c9185b 100644 --- a/gtk/Container.custom +++ b/gtk/Container.custom @@ -48,6 +48,30 @@ public Widget[] Children { } } +public IEnumerator GetEnumerator () +{ + IntPtr list_ptr = gtk_container_get_children (Handle); + GLib.List list = new GLib.List (list_ptr); + return list.GetEnumerator (); +} + +class ChildAccumulator { + public ArrayList Children = new ArrayList (); + + public void Add (Gtk.Widget widget) + { + Children.Add (widget); + } +} + +public IEnumerable AllChildren { + get { + ChildAccumulator acc = new ChildAccumulator (); + Forall (new Gtk.Callback (acc.Add)); + return acc.Children; + } +} + [DllImport("libgtk-win32-2.0-0.dll")] static extern bool gtk_container_get_focus_chain (IntPtr raw, out IntPtr list_ptr); @@ -109,6 +133,7 @@ static extern void gtksharp_container_invoke_gtk_callback (IntPtr cb, IntPtr han [GLib.CDeclCallback] delegate void ForallDelegate (IntPtr container, bool include_internals, IntPtr cb, IntPtr data); +static ForallDelegate ForallOldCallback; static ForallDelegate ForallCallback; public struct CallbackInvoker { @@ -139,13 +164,34 @@ public struct CallbackInvoker { } } -static void Forall_cb (IntPtr container, bool include_internals, IntPtr cb, IntPtr data) +static void ForallOld_cb (IntPtr container, bool include_internals, IntPtr cb, IntPtr data) { Container obj = GLib.Object.GetObject (container, false) as Container; CallbackInvoker invoker = new CallbackInvoker (cb, data); obj.ForAll (include_internals, invoker); } +static void OverrideForallOld (GLib.GType gtype) +{ + if (ForallOldCallback == null) + ForallOldCallback = new ForallDelegate (ForallOld_cb); + gtksharp_container_override_forall (gtype, ForallOldCallback); +} + +[Obsolete ("Override the ForAll(bool,Gtk.Callback) method instead")] +[GLib.DefaultSignalHandler (Type=typeof(Gtk.Container), ConnectionMethod="OverrideForallOld")] +protected virtual void ForAll (bool include_internals, CallbackInvoker invoker) +{ + gtksharp_container_base_forall (Handle, include_internals, invoker.Callback, invoker.Data); +} + +static void Forall_cb (IntPtr container, bool include_internals, IntPtr cb, IntPtr data) +{ + Container obj = GLib.Object.GetObject (container, false) as Container; + CallbackInvoker invoker = new CallbackInvoker (cb, data); + obj.ForAll (include_internals, new Gtk.Callback (invoker.Invoke)); +} + static void OverrideForall (GLib.GType gtype) { if (ForallCallback == null) @@ -154,8 +200,14 @@ static void OverrideForall (GLib.GType gtype) } [GLib.DefaultSignalHandler (Type=typeof(Gtk.Container), ConnectionMethod="OverrideForall")] -protected virtual void ForAll (bool include_internals, CallbackInvoker invoker) +protected virtual void ForAll (bool include_internals, Gtk.Callback callback) { + CallbackInvoker invoker; + try { + invoker = (CallbackInvoker)callback.Target; + } catch { + throw new ApplicationException ("ForAll can only be called as \"base.ForAll()\". Use Forall() or Foreach()."); + } gtksharp_container_base_forall (Handle, include_internals, invoker.Callback, invoker.Data); } diff --git a/gtk/Gtk.metadata b/gtk/Gtk.metadata index c8b4cb73c..087ab339b 100644 --- a/gtk/Gtk.metadata +++ b/gtk/Gtk.metadata @@ -177,6 +177,7 @@ 1 1 out + 1 call call diff --git a/sample/CustomNotebook.cs b/sample/CustomNotebook.cs deleted file mode 100644 index 24b2a397f..000000000 --- a/sample/CustomNotebook.cs +++ /dev/null @@ -1,642 +0,0 @@ -using GLib; -using Gtk; -using System; -using System.Collections; - -class CustomNotebookTest { - static CustomNotebook cn; - static Notebook nb; - static int tabCount; - - public static int Main (string[] args) - { - Application.Init (); - Window win = new Window ("Custom Notebook Test"); - win.DeleteEvent += new DeleteEventHandler (OnQuit); - - VBox box = new VBox (false, 5); - Button addButton = new Button ("Add Tab"); - //addButton.Clicked += OnAddTab; - Button rmButton = new Button ("Remove Tab"); - rmButton.Clicked += OnRemoveTab; - box.PackStart (addButton, false, false, 0); - box.PackStart (rmButton, false, false, 0); - HPaned paned = new HPaned (); - - cn = new CustomNotebook (); - cn.BorderWidth = 5; - cn.Scrollable = false; - Gdk.Pixbuf icon = cn.RenderIcon (Stock.Execute, IconSize.Menu, ""); - //for (tabCount = 0; tabCount < 3; tabCount++) - cn.AppendPage (new Label ("Custom Notebook"), Stock.Execute, "extended tab" + tabCount); - cn.AppendPage (new Label ("Custom Notebook"), Stock.Execute, "tab" + (tabCount + 1)); - cn.AppendPage (new Label ("Custom Notebook"), Stock.Execute, "extended tab" + (tabCount + 2)); - paned.Pack1 (cn, true, false); - - nb = new Notebook (); - nb.BorderWidth = 5; - nb.Scrollable = false; - for (tabCount = 0; tabCount < 3; tabCount++) - nb.AppendPage (new Label ("Regular Notebook"), new Label ("tab" + tabCount)); - paned.Pack2 (nb, true, false); - box.PackEnd (paned, true, true, 0); - - win.Add (box); - win.ShowAll (); - Application.Run (); - return 0; - } - - /*static void OnAddTab (object sender, EventArgs args) - { - cn.AppendPage (new Label ("Custom Notebook"), Stock.Execute, "tab" + tabCount + 1); - cn.ShowAll (); - nb.AppendPage (new Label ("Regular Notebook"), new Label ("tab" + tabCount + 1)); - nb.ShowAll (); - tabCount++; - }*/ - - static void OnRemoveTab (object sender, EventArgs args) - { - } - - static void OnQuit (object sender, DeleteEventArgs args) - { - Application.Quit (); - } -} - -class CustomNotebookPage { - private Gdk.Rectangle allocation; - private Widget child = null; - private Gdk.Pixbuf icon = null; - private bool ellipsize = false; - private string label = null; - private Pango.Layout layout = null; - private int layoutWidth = -1; - private int layoutHeight = -1; - private Requisition requisition; - private string stockid = null; - - public Gdk.Rectangle Allocation { - get { - return allocation; - } - set { - allocation = value; - } - } - - public Widget Child { - get { - return child; - } - set { - child = value; - } - } - - public bool Ellipsize { - get { - return ellipsize; - } - set { - ellipsize = value; - } - } - - public Gdk.Pixbuf Icon { - get { - if (icon == null && StockId != null) { - icon = child.RenderIcon (StockId, IconSize.Menu, ""); - } - - return icon; - } - set { - icon = value; - } - } - - public string Label { - get { - return label; - } - set { - label = value; - layout = null; - layoutWidth = -1; - layoutHeight = -1; - } - } - - public Pango.Layout Layout { - get { - if (layout == null && Label != null) { - layout = child.CreatePangoLayout (label); - layout.GetPixelSize (out layoutWidth, out layoutHeight); - } - - return layout; - } - } - - public int LayoutWidth { - get { - if (Layout != null) - return layoutWidth; - else - return -1; - } - } - - public int LayoutHeight { - get { - if (Layout != null) - return layoutHeight; - else - return -1; - } - } - - public Requisition Requisition { - get { - return requisition; - } - set { - requisition = value; - } - } - - public string StockId { - get { - return stockid; - } - set { - stockid = value; - icon = null; - } - } - - public CustomNotebookPage (Widget child, string label) - { - Child = child; - Label = label; - } - - public CustomNotebookPage (Widget child, Gdk.Pixbuf icon, string label) - { - Child = child; - Icon = icon; - Label = label; - } - - public CustomNotebookPage (Widget child, string stockid, string label) - { - Child = child; - Label = label; - StockId = stockid; - } -} - -class CustomNotebook : Container { - private readonly int tabCurvature = 1; - private readonly int tabOverlap = 2; - private ArrayList pages = new ArrayList (); - private bool closable; - private bool scrollable; - private PositionType tabPosition; - private int tabHBorder; - private int tabVBorder; - - public bool Closable { - get { - return closable; - } - set { - closable = value; - } - } - - private CustomNotebookPage CurrentPage { - get { - return (CustomNotebookPage)pages[0]; - } - } - - public bool Scrollable { - get { - return scrollable; - } - set { - scrollable = value; - } - } - - public Gtk.PositionType TabPosition { - get { - return tabPosition; - } - set { - switch (value) { - case PositionType.Left: - case PositionType.Right: - Console.WriteLine ("PositionType.Left or Right is not supported by this widget"); - break; - default: - tabPosition = value; - break; - } - } - } - - /*static CustomNotebook () - { - Container.OverrideForall (CustomNotebook.GType); - }*/ - - public CustomNotebook () : base () - { - closable = true; - scrollable = false; - tabPosition = PositionType.Top; - tabHBorder = 2; - tabVBorder = 2; - - WidgetFlags |= WidgetFlags.NoWindow; - } - - public void AppendPage (Widget child, string label) - { - pages.Add (new CustomNotebookPage (child, label)); - child.Parent = this; - } - - public void AppendPage (Widget child, string stockid, string label) - { - pages.Add (new CustomNotebookPage (child, stockid, label)); - child.Parent = this; - } - - public void AppendPage (Widget child, Gdk.Pixbuf icon, string label) - { - pages.Add (new CustomNotebookPage (child, icon, label)); - child.Parent = this; - } - - private void EllipsizeLayout (Pango.Layout layout, int width) - { - if (width <= 0) { - layout.SetText (""); - return; - } - - int layoutWidth, layoutHeight; - layout.GetPixelSize (out layoutWidth, out layoutHeight); - if (layoutWidth <= width) - return; - - // Calculate ellipsis width. - Pango.Layout ell = layout.Copy (); - ell.SetText ("..."); - int ellWidth, ellHeight; - ell.GetPixelSize (out ellWidth, out ellHeight); - - if (width < ellWidth) { - // Not even ellipsis fits, so hide text. - layout.SetText (""); - return; - } - - // Shrink total available width by the width of the ellipsis. - width -= ellWidth; - string text = layout.Text; - Console.WriteLine ("layout text = {0}", text); - Console.WriteLine ("line count: {0}", layout.LineCount); - Pango.LayoutLine line = layout.Lines[0]; - //Console.WriteLine ("layout = {0}", line.layout.Text); - //Console.WriteLine ("line = {0}", line.Length); - int idx = 0, trailing = 0; - if (line.XToIndex (width * 1024, out idx, out trailing)) { - text = text.Substring (0, idx - 1); - text += "..."; - layout.SetText (text); - } - } - - protected override bool OnExposeEvent (Gdk.EventExpose args) - { - int x, y, width, height, gapX, gapWidth; - int bw = (int)BorderWidth; - - x = Allocation.X + bw; - y = Allocation.Y + bw; - width = Allocation.Width - 2 * bw; - height = Allocation.Height - 2 * bw; - - switch (TabPosition) { - case PositionType.Top: - y += CurrentPage.Allocation.Height; - height -= CurrentPage.Allocation.Height; - break; - case PositionType.Bottom: - height -= CurrentPage.Allocation.Height; - break; - case PositionType.Left: - case PositionType.Right: - break; - } - - gapX = gapWidth = 0; - switch (TabPosition) { - case PositionType.Top: - case PositionType.Bottom: - gapX = CurrentPage.Allocation.X - Allocation.X - bw; - gapWidth = CurrentPage.Allocation.Width; - break; - case PositionType.Left: - case PositionType.Right: - break; - } - - Style.PaintBoxGap (Style, GdkWindow, StateType.Normal, - ShadowType.Out, args.Area, this, - "notebook", x, y, width, height, - TabPosition, gapX, gapWidth); - - for (int i = pages.Count - 1; i >= 0; i--) { - CustomNotebookPage page = (CustomNotebookPage)pages[i]; - Gdk.Rectangle pageAlloc = page.Allocation; - - StateType state = page == CurrentPage ? StateType.Normal : StateType.Active; - Style.PaintExtension (Style, GdkWindow, state, - ShadowType.Out, args.Area, this, - "tab", pageAlloc.X, pageAlloc.Y, - pageAlloc.Width, pageAlloc.Height, - PositionType.Bottom); - - // FIXME: Only add YThickness when TabPosition = Top; - y = pageAlloc.Y + Style.YThickness + FocusLineWidth + tabVBorder; - height = pageAlloc.Height - Style.YThickness - 2 * (tabVBorder + FocusLineWidth); - if (page.Icon != null) { - x = pageAlloc.X + (pageAlloc.Width + 1 - - page.Icon.Width - - page.LayoutWidth) / 2; - int iconY = y + (height - page.Icon.Height) / 2; - - GdkWindow.DrawPixbuf (Style.BackgroundGC (State), - page.Icon, 0, 0, x, iconY, - page.Icon.Width, - page.Icon.Height, - Gdk.RgbDither.None, 0, 0); - x += page.Icon.Width + 1; - } else { - x = pageAlloc.X + (pageAlloc.Width - page.LayoutWidth) / 2; - } - - y += (height - page.LayoutHeight) / 2; - if (page.Ellipsize) { - width = pageAlloc.Width - (page.Icon.Width + 1); - Pango.Layout layout = page.Layout; - EllipsizeLayout (layout, width); - Console.WriteLine ("ellLayout = {0}", layout.Text); - Style.PaintLayout (Style, GdkWindow, State, - true, args.Area, this, null, - x, y, layout); - } else { - Style.PaintLayout (Style, GdkWindow, State, - true, args.Area, this, null, - x, y, page.Layout); - } - } - - return base.OnExposeEvent (args); - } - - protected override void ForAll (bool include_internals, CallbackInvoker invoker) - { - foreach (CustomNotebookPage page in pages) { - invoker.Invoke (page.Child); - } - } - - protected override void OnRealized () - { - WidgetFlags |= WidgetFlags.Realized; - - GdkWindow = ParentWindow; - Style = Style.Attach (GdkWindow); - } - - protected override void OnSizeAllocated (Gdk.Rectangle allocation) - { - base.OnSizeAllocated (allocation); - - if (pages.Count == 0) - return; - - int bw = (int)BorderWidth; - - Gdk.Rectangle childAlloc; - childAlloc.X = allocation.X + bw + Style.XThickness; - childAlloc.Y = allocation.Y + bw + Style.YThickness; - childAlloc.Width = Math.Max (1, allocation.Width - 2 * bw - - 2 * Style.XThickness); - childAlloc.Height = Math.Max (1, allocation.Height - 2 * bw - - 2 * Style.YThickness); - - switch (TabPosition) { - case PositionType.Top: - childAlloc.Y += CurrentPage.Requisition.Height; - childAlloc.Height = Math.Max (1, childAlloc.Height - - CurrentPage.Requisition.Height); - break; - case PositionType.Bottom: - childAlloc.Height = Math.Max (1, childAlloc.Height - - CurrentPage.Requisition.Height); - break; - case PositionType.Left: - case PositionType.Right: - break; - } - - foreach (CustomNotebookPage page in pages) { - page.Child.SizeAllocate (childAlloc); - } - - // gtk_notebook_pages_allocate. - childAlloc.X = allocation.X + bw; - childAlloc.Y = allocation.Y + bw; - - switch (TabPosition) { - case PositionType.Top: - childAlloc.Height = CurrentPage.Requisition.Height; - break; - case PositionType.Bottom: - childAlloc.Y = (allocation.Y + allocation.Height - - CurrentPage.Requisition.Height - bw); - childAlloc.Height = CurrentPage.Requisition.Height; - break; - case PositionType.Left: - case PositionType.Right: - break; - } - - bool ellipsize = false; - int avgWidth = 0; - int tabX = childAlloc.X; - if (!scrollable) { - int tabWidth = 0; - foreach (CustomNotebookPage page in pages) { - tabWidth += page.Requisition.Width; - } - - Console.WriteLine ("total tabwidth: {0}", tabWidth); - Console.WriteLine ("allocated width: {0}", childAlloc.Width); - - if (tabWidth > childAlloc.Width) { - ellipsize = true; - avgWidth = childAlloc.Width / pages.Count; - tabWidth = childAlloc.Width; - Console.WriteLine ("average tabwidth: {0}", avgWidth); - - int count = pages.Count; - foreach (CustomNotebookPage page in pages) { - if (page.Requisition.Width <= avgWidth) { - count--; - tabWidth -= page.Requisition.Width; - } - } - - Console.WriteLine ("number of pages exceeding that: {0}", count); - Console.WriteLine ("space per page available: {0}", tabWidth / count); - - // FIXME: check for TabPosition. - int maxWidth = tabWidth / count; - foreach (CustomNotebookPage page in pages) { - Gdk.Rectangle pageAlloc = page.Allocation; - pageAlloc.X = tabX; - pageAlloc.Y = childAlloc.Y; - - if (page.Requisition.Width > maxWidth) { - pageAlloc.Width = maxWidth + tabOverlap; - page.Ellipsize = true; - } else { - pageAlloc.Width = page.Requisition.Width + tabOverlap; - } - - pageAlloc.Height = childAlloc.Height; - tabX += pageAlloc.Width - tabOverlap; - - if (page != CurrentPage) { - pageAlloc.Y += Style.YThickness; - pageAlloc.Height -= Style.YThickness; - } - - page.Allocation = pageAlloc; - } - } - } else { - switch (TabPosition) { - case PositionType.Top: - case PositionType.Bottom: - foreach (CustomNotebookPage page in pages) { - Gdk.Rectangle pageAlloc = page.Allocation; - pageAlloc.X = tabX; - pageAlloc.Y = childAlloc.Y; - pageAlloc.Width = page.Requisition.Width + tabOverlap; - pageAlloc.Height = childAlloc.Height; - tabX += pageAlloc.Width - tabOverlap; - - if (page != CurrentPage) { - pageAlloc.Y += Style.YThickness; - pageAlloc.Height -= Style.YThickness; - } - - page.Allocation = pageAlloc; - } - break; - case PositionType.Left: - case PositionType.Right: - break; - } - } - } - - protected override void OnSizeRequested (ref Requisition requisition) - { - requisition.Width = requisition.Height = 0; - - foreach (CustomNotebookPage page in pages) { - if (!page.Child.Visible) - continue; - - Requisition childReq = page.Child.SizeRequest (); - requisition.Width = Math.Max (requisition.Width, childReq.Width); - requisition.Height = Math.Max (requisition.Height, childReq.Height); - } - - requisition.Width += 2 * Style.XThickness; - requisition.Height += 2 * Style.YThickness; - - int tabWidth = 0; - int tabHeight = 0; - int tabMax = 0; - int padding; - foreach (CustomNotebookPage page in pages) { - Requisition pageReq; - if (page.Icon != null) { - pageReq.Width = page.Icon.Width + page.LayoutWidth + - Style.XThickness * 2; - pageReq.Height = Math.Max (page.Icon.Height, page.LayoutHeight) + - Style.YThickness * 2; - } else { - pageReq.Width = page.LayoutWidth + Style.XThickness * 2; - pageReq.Height = page.LayoutHeight + Style.YThickness * 2; - } - - switch (TabPosition) { - case PositionType.Top: - case PositionType.Bottom: - pageReq.Height += (tabVBorder + FocusLineWidth) * 2; - tabHeight = Math.Max (tabHeight, pageReq.Height); - tabMax = Math.Max (tabMax, pageReq.Width); - break; - case PositionType.Left: - case PositionType.Right: - break; - } - - page.Requisition = pageReq; - } - - switch (TabPosition) { - case PositionType.Top: - case PositionType.Bottom: - padding = 2 * (tabCurvature + FocusLineWidth - + tabHBorder) - tabOverlap; - tabMax += padding; - - Requisition pageReq; - foreach (CustomNotebookPage page in pages) { - pageReq = page.Requisition; - pageReq.Width += padding; - tabWidth += pageReq.Width; - pageReq.Height = tabHeight; - page.Requisition = pageReq; - } - - /*if (!Scrollable) - requisition.Width = Math.Max (requisition.Width, - tabWidth + tabOverlap);*/ - requisition.Height += tabHeight; - break; - case PositionType.Left: - case PositionType.Right: - break; - } - - requisition.Width += (int)BorderWidth * 2; - requisition.Height += (int)BorderWidth * 2; - } -} diff --git a/sample/GtkDemo/DemoImages.cs b/sample/GtkDemo/DemoImages.cs index ede0cb39a..fe634b53c 100644 --- a/sample/GtkDemo/DemoImages.cs +++ b/sample/GtkDemo/DemoImages.cs @@ -122,8 +122,7 @@ namespace GtkDemo { ToggleButton toggle = o as ToggleButton; - Widget[] children = vbox.Children; - foreach (Widget widget in children) { + foreach (Widget widget in vbox) { // don't disable our toggle if (widget != toggle) widget.Sensitive = !toggle.Active; diff --git a/sample/Makefile.am b/sample/Makefile.am index c7d76a5c3..fbf7aab81 100755 --- a/sample/Makefile.am +++ b/sample/Makefile.am @@ -40,7 +40,7 @@ DOTNET_TARGETS= DOTNET_ASSEMBLY= endif -TARGETS = custom-notebook.exe custom-widget.exe custom-cellrenderer.exe gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe scribble-xinput.exe treeviewdemo.exe managedtreeviewdemo.exe nodeviewdemo.exe testdnd.exe actions.exe $(GNOMEVFS_TARGETS) $(GNOME_TARGETS) $(GLADE_TARGETS) $(VTE_TARGETS) $(DOTNET_TARGETS) +TARGETS = polarfixed.exe custom-widget.exe custom-cellrenderer.exe gtk-hello-world.exe button.exe calendar.exe subclass.exe menu.exe size.exe scribble.exe scribble-xinput.exe treeviewdemo.exe managedtreeviewdemo.exe nodeviewdemo.exe testdnd.exe actions.exe $(GNOMEVFS_TARGETS) $(GNOME_TARGETS) $(GLADE_TARGETS) $(VTE_TARGETS) $(DOTNET_TARGETS) DEBUGS = $(addsuffix .mdb, $(TARGETS)) @@ -124,8 +124,8 @@ custom-widget.exe: $(srcdir)/CustomWidget.cs $(assemblies) actions.exe: $(srcdir)/Actions.cs $(CSC) /debug /unsafe /out:actions.exe $(references) $(srcdir)/Actions.cs -custom-notebook.exe: $(srcdir)/CustomNotebook.cs $(assemblies) - $(CSC) /debug /out:custom-notebook.exe $(references) $(srcdir)/CustomNotebook.cs +polarfixed.exe: $(srcdir)/PolarFixed.cs $(assemblies) + $(CSC) /debug /out:polarfixed.exe $(references) $(srcdir)/PolarFixed.cs testvfs.exe: $(srcdir)/TestVfs.cs $(assemblies) $(CSC) /debug /out:testvfs.exe $(references) $(srcdir)/TestVfs.cs diff --git a/sample/PolarFixed.cs b/sample/PolarFixed.cs new file mode 100644 index 000000000..65d56b48e --- /dev/null +++ b/sample/PolarFixed.cs @@ -0,0 +1,236 @@ +// This is a completely pointless widget, but it shows how to subclass container... + +using System; +using System.Collections; +using Gtk; +using Gdk; + +class PolarFixed : Container { + ArrayList children; + + public PolarFixed () + { + children = new ArrayList (); + WidgetFlags |= WidgetFlags.NoWindow; + } + + // The child properties object + public class PolarFixedChild : ContainerChild { + double theta; + uint r; + + public PolarFixedChild (PolarFixed parent, Widget child, double theta, uint r) : base (parent, child) + { + this.theta = theta; + this.r = r; + } + + // We call parent.QueueResize() from the property setters here so that you + // can move the widget around just by changing its child properties (just + // like with a native container class). + + public double Theta { + get { return theta; } + set { + theta = value; + parent.QueueResize (); + } + } + + public uint R { + get { return r; } + set { + r = value; + parent.QueueResize (); + } + } + } + + // Override the child properties accessor to return the right object from + // "children". + public override ContainerChild this [Widget w] { + get { + foreach (PolarFixedChild pfc in children) { + if (pfc.Child == w) + return pfc; + } + return null; + } + } + + // Indicate the kind of children the container will accept. Most containers + // will accept any kind of child, so they should return Gtk.Widget.GType. + // The default is "GLib.GType.None", which technically means that no (new) + // children can be added to the container, though Container.Add does not + // enforce this. + public override GLib.GType ChildType () + { + return Gtk.Widget.GType; + } + + // Implement gtk_container_forall(), which is also used by + // Gtk.Container.Children and Gtk.Container.AllChildren. + protected override void ForAll (bool include_internals, Callback callback) + { + foreach (PolarFixedChild pfc in children) + callback (pfc.Child); + } + + // Invoked by Container.Add (w). It's good practice to have this do *something*, + // even if it's not something terribly useful. + protected override void OnAdded (Widget w) + { + Put (w, 0.0, 0); + } + + // our own adder method + public void Put (Widget w, double theta, uint r) + { + children.Add (new PolarFixedChild (this, w, theta, r)); + w.Parent = this; + QueueResize (); + } + + public void Move (Widget w, double theta, uint r) + { + PolarFixedChild pfc = (PolarFixedChild)this[w]; + if (pfc != null) { + pfc.Theta = theta; + pfc.R = r; + } + } + + // invoked by Container.Remove (w) + protected override void OnRemoved (Widget w) + { + PolarFixedChild pfc = (PolarFixedChild)this[w]; + if (pfc != null) { + pfc.Child.Unparent (); + children.Remove (pfc); + QueueResize (); + } + } + + // Handle size request + protected override void OnSizeRequested (ref Requisition req) + { + Requisition childReq; + int x, y; + + req.Width = req.Height = 0; + foreach (PolarFixedChild pfc in children) { + // Recursively SizeRequest each child + childReq = pfc.Child.SizeRequest (); + + // Figure out where we're going to put it + x = (int)(Math.Cos (pfc.Theta) * pfc.R) + childReq.Width / 2; + y = (int)(Math.Sin (pfc.Theta) * pfc.R) + childReq.Height / 2; + + // Update our own size request to fit it + if (req.Width < 2 * x) + req.Width = 2 * x; + if (req.Height < 2 * y) + req.Height = 2 * y; + } + + // Take Container.BorderWidth into account + req.Width += (int)(2 * BorderWidth); + req.Height += (int)(2 * BorderWidth); + } + + // Size allocation. Note that the allocation received may be smaller than what we + // requested. Some containers will take that into account by giving some or all + // of their children a smaller allocation than they requested. Other containers + // (like this one) just let their children get placed partly out-of-bounds if they + // aren't allocated enough room. + protected override void OnSizeAllocated (Rectangle allocation) + { + Requisition childReq; + int cx, cy, x, y; + + // This sets the "Allocation" property. For widgets that + // have a GdkWindow, it also calls GdkWindow.MoveResize() + base.OnSizeAllocated (allocation); + + // Figure out where the center of the grid will be + cx = allocation.X + (allocation.Width / 2); + cy = allocation.Y + (allocation.Height / 2); + + foreach (PolarFixedChild pfc in children) { + // Use ChildRequisition rather than SizeRequest(), + // to ask for "what this child requested in the + // last SizeRequest", rather than having it + // compute it anew. + childReq = pfc.Child.ChildRequisition; + + x = (int)(Math.Cos (pfc.Theta) * pfc.R) - childReq.Width / 2; + y = (int)(Math.Sin (pfc.Theta) * pfc.R) + childReq.Height / 2; + + allocation.X = cx + x; + allocation.Width = childReq.Width; + allocation.Y = cy - y; + allocation.Height = childReq.Height; + + pfc.Child.Allocation = allocation; + } + } +} + +class Test { + public static void Main () + { + uint r; + double theta; + + Application.Init (); + + Gtk.Window win = new Gtk.Window ("Polar Coordinate Container"); + win.DeleteEvent += Window_Delete; + + Notebook notebook = new Notebook (); + win.Add (notebook); + + // Clock + PolarFixed pf = new PolarFixed (); + notebook.AppendPage (pf, new Label ("Clock")); + + for (int hour = 1; hour <= 12; hour ++) { + theta = (Math.PI / 2) - hour * (Math.PI / 6); + if (theta < 0) + theta += 2 * Math.PI; + + Label l = new Label ("" + hour.ToString () + ""); + l.UseMarkup = true; + pf.Put (l, theta, 200); + } + + // Spiral + pf = new PolarFixed (); + notebook.AppendPage (pf, new Label ("Spiral")); + + r = 0; + theta = 0.0; + + foreach (string id in Gtk.Stock.ListIds ()) { + StockItem item = Gtk.Stock.Lookup (id); + if (item.Label == null) + continue; + + pf.Put (new Gtk.Button (id), theta, r); + + // Logarithmic spiral: r = a*e^(b*theta) + r += 5; + theta = 10 * Math.Log (10 * r); + } + + win.ShowAll (); + + Application.Run (); + } + + static void Window_Delete (object obj, DeleteEventArgs args) + { + Application.Quit (); + args.RetVal = true; + } +}