diff --git a/sample/GtkDemo/DemoHyperText.cs b/sample/GtkDemo/DemoHyperText.cs new file mode 100644 index 000000000..370d9d8a6 --- /dev/null +++ b/sample/GtkDemo/DemoHyperText.cs @@ -0,0 +1,225 @@ +// +// Author: John Luke +// ported from gtk-demo in GTK+ +// Demostrates HyperLinks in the TextView +// + +using System; +using Gtk; + +namespace GtkDemo +{ + public class DemoHyperText : Gtk.Window + { + bool hoveringOverLink = false; + Gdk.Cursor handCursor, regularCursor; + TextIter lastIter; + + public DemoHyperText () : base ("HyperText") + { + this.DeleteEvent += new DeleteEventHandler (OnWindowDelete); + this.SetDefaultSize (450, 450); + CreateCursors (); + this.Add (CreateScrolledWindow ()); + this.ShowAll (); + } + + void CreateCursors () + { + handCursor = new Gdk.Cursor (Gdk.CursorType.Hand2); + regularCursor = new Gdk.Cursor (Gdk.CursorType.Xterm); + } + + ScrolledWindow CreateScrolledWindow () + { + ScrolledWindow sw = new ScrolledWindow (); + sw.Add (CreateTextView ()); + return sw; + } + + TextView CreateTextView () + { + TextTagTable ttt = new TextTagTable (); + TextBuffer buffer = new TextBuffer (ttt); + + TextView view = new TextView (); + view.WrapMode = WrapMode.Word; + view.KeyPressEvent += new KeyPressEventHandler (OnKeyPress); + view.MotionNotifyEvent += new MotionNotifyEventHandler (OnMotionNotify); + view.VisibilityNotifyEvent += new VisibilityNotifyEventHandler (OnVisibilityNotify); + view.ButtonReleaseEvent += new ButtonReleaseEventHandler (OnButtonRelease); + view.Buffer.InsertText += new InsertTextHandler (OnTextInserted); + + ShowPage (view.Buffer, 1); + return view; + } + + // Inserts a piece of text into the buffer, giving it the usual + // appearance of a hyperlink in a web browser: blue and underlined. + // Additionally, attaches some data on the tag, to make it recognizable + // as a link. + void InsertLink (TextBuffer buffer, TextIter iter, string text, int page) + { + TextTag tag = new TextTag ("link"); + tag.Foreground = "blue"; + tag.Underline = Pango.Underline.Single; + tag.Data.Add ("page", page); + buffer.TagTable.Add (tag); + + buffer.InsertWithTags (iter, text, tag); + } + + // Fills the buffer with text and interspersed links. In any real + // hypertext app, this method would parse a file to identify the links. + void ShowPage (TextBuffer buffer, int page) + { + buffer.Text = ""; + TextIter iter = buffer.GetIterAtOffset (0); + + if (page == 1) + { + buffer.Insert (iter, "Some text to show that simple "); + InsertLink (buffer, lastIter, "hypertext", 3); + buffer.Insert (lastIter, " can easily be realized with "); + InsertLink (buffer, lastIter, "tags", 2); + buffer.Insert (lastIter, "."); + } + else if (page == 2) + { + buffer.Insert (iter, + "A tag is an attribute that can be applied to some range of text. " + + "For example, a tag might be called \"bold\" and make the text inside " + + "the tag bold. However, the tag concept is more general than that; " + + "tags don't have to affect appearance. They can instead affect the " + + "behavior of mouse and key presses, \"lock\" a range of text so the " + + "user can't edit it, or countless other things.\n"); + InsertLink (buffer, lastIter, "Go back", 1); + } + else if (page == 3) + { + TextTag tag = new TextTag ("bold"); + tag.Weight = Pango.Weight.Bold; + buffer.InsertWithTags (iter, "hypertext:\n", tag); + buffer.Insert (lastIter, + "machine-readable text that is not sequential but is organized" + + "so that related items of information are connected.\n"); + InsertLink (buffer, lastIter, "Go back", 1); + } + } + + // Looks at all tags covering the position of iter in the text view, + // and if one of them is a link, follow it by showing the page identified + // by the data attached to it. + void FollowIfLink (TextView view, TextIter iter) + { + foreach (TextTag tag in iter.Tags) + { + int page = (int) tag.Data ["page"]; + if (page != 0) + ShowPage (view.Buffer, page); + } + } + + // Looks at all tags covering the position (x, y) in the text view, + // and if one of them is a link, change the cursor to the "hands" cursor + // typically used by web browsers. + + void SetCursorIfAppropriate (TextView view, int x, int y) + { + bool hovering = false; + TextIter iter = view.GetIterAtLocation (x, y); + + foreach (TextTag tag in iter.Tags) + { + int page = (int) tag.Data ["page"]; + if (page != 0) { + hovering = true; + break; + } + } + + if (hovering != hoveringOverLink) + { + hoveringOverLink = hovering; + if (hoveringOverLink) + view.GdkWindow.Cursor = handCursor; + else + view.GdkWindow.Cursor = regularCursor; + } + } + + void OnButtonRelease (object sender, ButtonReleaseEventArgs a) + { + if (a.Event.Button != 1) + return; + + TextView view = sender as TextView; + TextIter start, end, iter; + int x, y; + + view.Buffer.GetSelectionBounds (out start, out end); + if (start.Offset != end.Offset) + return; + + view.WindowToBufferCoords (TextWindowType.Widget, (int) a.Event.X, (int) a.Event.Y, out x, out y); + iter = view.GetIterAtLocation (x, y); + + FollowIfLink (view, iter); + } + + // Links can be activated by pressing Enter. + void OnKeyPress (object sender, KeyPressEventArgs a) + { + TextView view = sender as TextView; + + switch ((Gdk.Key) a.Event.KeyValue) { + case Gdk.Key.Return: + case Gdk.Key.KP_Enter: + TextIter iter = view.Buffer.GetIterAtMark (view.Buffer.InsertMark); + FollowIfLink (view, iter); + break; + default: + break; + } + } + + //Update the cursor image if the pointer moved. + void OnMotionNotify (object sender, MotionNotifyEventArgs a) + { + TextView view = sender as TextView; + int x, y; + + view.WindowToBufferCoords (TextWindowType.Widget, (int) a.Event.X, (int) a.Event.Y, out x, out y); + SetCursorIfAppropriate (view, x, y); + } + + // When inserting text, iters are invalidated + // but the default handler provides us the iter + // at the end of inserted text + void OnTextInserted (object sender, InsertTextArgs a) + { + lastIter = a.Pos; + } + + // Also update the cursor image if the window becomes visible + // (e.g. when a window covering it got iconified). + void OnVisibilityNotify (object sender, VisibilityNotifyEventArgs a) + { + TextView view = sender as TextView; + int wx, wy, bx, by; + + view.GetPointer (out wx, out wy); + view.WindowToBufferCoords (TextWindowType.Widget, wx, wy, out bx, out by); + SetCursorIfAppropriate (view, bx, by); + + } + + void OnWindowDelete (object sender, DeleteEventArgs a) + { + this.Hide (); + this.Destroy (); + a.RetVal = true; + } + } +} + diff --git a/sample/GtkDemo/DemoMain.cs b/sample/GtkDemo/DemoMain.cs index cc621b29e..365199414 100644 --- a/sample/GtkDemo/DemoMain.cs +++ b/sample/GtkDemo/DemoMain.cs @@ -7,7 +7,6 @@ using System; using System.IO; -using System.Collections; using System.Reflection; using Gdk; @@ -23,6 +22,8 @@ namespace GtkDemo private TextBuffer sourceBuffer = new TextBuffer (null); private TreeView treeView; private TreeStore store; + private TreeIter oldSelection; + public static void Main (string[] args) { Application.Init (); @@ -34,18 +35,14 @@ namespace GtkDemo { SetupDefaultIcon (); window = new Gtk.Window ("Gtk# Code Demos"); - window.SetDefaultSize (600,400); + window.SetDefaultSize (600, 400); window.DeleteEvent += new DeleteEventHandler (WindowDelete); HBox hbox = new HBox (false, 0); window.Add (hbox); - TreeView tree = CreateTree (); - tree.AppendColumn ("Widget (double click for demo)", new CellRendererText (), "text", 0); - tree.Model = FillTree (); - tree.Selection.Changed += new EventHandler (OnTreeChanged); - tree.RowActivated += new RowActivatedHandler (OnRowActivated); - hbox.PackStart (tree, false, false, 0); + treeView = CreateTree (); + hbox.PackStart (treeView, false, false, 0); Notebook notebook = new Notebook (); hbox.PackStart (notebook, true, true, 0); @@ -88,29 +85,41 @@ namespace GtkDemo sourceBuffer.Text = s; } + // this is to highlight the sourceBuffer private void Fontify () { } - // TODO: Display system error private void SetupDefaultIcon () { Gdk.Pixbuf pixbuf = Gdk.Pixbuf.LoadFromResource ("gtk-logo-rgb.gif"); if (pixbuf != null) { - // The gtk-logo-rgb icon has a white background, make it transparent + // The gtk-logo-rgb icon has a white background + // make it transparent instead Pixbuf transparent = pixbuf.AddAlpha (true, 0xff, 0xff, 0xff); Gtk.Window.DefaultIconList = new Gdk.Pixbuf [] {transparent}; } } - // BUG: I have to click twice close in order for the dialog to disappear - private void ResponseCallback (object obj, ResponseArgs args) + private TreeView CreateTree () { - Dialog dialog = (Dialog) obj ; - dialog.Destroy (); + TreeView view = new TreeView (); + view.Model = FillTree (); + + CellRendererText cr = new CellRendererText (); + TreeViewColumn column = new TreeViewColumn ("Widget (double click for demo)", cr, "text", 0); + column.AddAttribute (cr, "style" , 2); + view.AppendColumn (column); + + view.Selection.Changed += new EventHandler (OnTreeChanged); + view.RowActivated += new RowActivatedHandler (OnRowActivated); + view.ExpandAll (); + view.SetSizeRequest (200, -1); + view.Selection.Mode = Gtk.SelectionMode.Browse; + return view; } private ScrolledWindow CreateText (TextBuffer buffer, bool IsSource) @@ -119,11 +128,7 @@ namespace GtkDemo scrolledWindow.SetPolicy (PolicyType.Automatic, PolicyType.Automatic); scrolledWindow.ShadowType = ShadowType.In; - TextView textView = new TextView (); - - textView.Buffer = buffer; - // STUCK - + TextView textView = new TextView (buffer); textView.Editable = false; textView.CursorVisible = false; @@ -144,40 +149,39 @@ namespace GtkDemo } return scrolledWindow; - } + } - private TreeView CreateTree () - { - treeView = new TreeView (); - return treeView; - } - private TreeStore FillTree () { - store = new TreeStore (typeof (string)); - - store.AppendValues ("Application Window (75% complete)"); - store.AppendValues ("Button Boxes"); - store.AppendValues ("Change Display"); - store.AppendValues ("Color Selector"); - store.AppendValues ("Dialog and Message Boxes"); - store.AppendValues ("Drawing Area"); - store.AppendValues ("Images"); - store.AppendValues ("Item Factory (5% complete)"); - store.AppendValues ("Menus"); - store.AppendValues ("Paned Widget"); - store.AppendValues ("Pixbuf"); - store.AppendValues ("Size Groups"); - store.AppendValues ("Stock Item and Icon Browser (10% complete)"); - store.AppendValues ("Text Widget (95% complete)"); - TreeIter iter = store.AppendValues ("Tree View"); - store.AppendValues (iter, "Editable Cells"); - store.AppendValues (iter, "List Store"); - store.AppendValues (iter, "Tree Store"); + // title, filename, italic + store = new TreeStore (typeof (string), typeof (string), typeof (bool)); + TreeIter parent; + + store.AppendValues ("Application Window (75% complete)", "DemoApplicationWindow.cs", false); + store.AppendValues ("Button Boxes", "DemoButtonBox.cs", false); + store.AppendValues ("Change Display (0%)", "DemoChangeDisplay.cs", false); + store.AppendValues ("Color Selector", "DemoColorSelection.cs", false); + store.AppendValues ("Dialog and Message Boxes", "DemoDialog.cs", false); + store.AppendValues ("Drawing Area", "DemoDrawingArea.cs", false); + store.AppendValues ("Images", "DemoImages.cs", false); + store.AppendValues ("Item Factory (5% complete)", "DemoItemFactory.cs", false); + store.AppendValues ("Menus", "DemoMenus.cs", false); + store.AppendValues ("Paned Widget", "DemoPanes.cs", false); + store.AppendValues ("Pixbuf", "DemoPixbuf.cs", false); + store.AppendValues ("Size Groups", "DemoSizeGroup.cs", false); + store.AppendValues ("Stock Item and Icon Browser (10% complete)", "DemoStockBrowser.cs", false); + parent = store.AppendValues ("Text Widget"); + store.AppendValues (parent, "HyperText (50%)", "DemoHyperText.cs", false); + store.AppendValues (parent, "Multiple Views (95%)", "DemoTextView.cs", false); + parent = store.AppendValues ("Tree View"); + store.AppendValues (parent, "Editable Cells", "DemoEditableCells", false); + store.AppendValues (parent, "List Store", "DemoListStore.cs", false); + store.AppendValues (parent, "Tree Store", "DemoTreeStore.cs", false); return store; } + //FIXME: italicize selected row private void OnTreeChanged (object o, EventArgs args) { TreeIter iter; @@ -185,68 +189,13 @@ namespace GtkDemo if (treeView.Selection.GetSelected (out model, out iter)) { - TreePath path; - path = store.GetPath (iter); + string file = (string) model.GetValue (iter, 1); + if (file != null) + LoadFile (file); - switch (path.ToString()) { - - case "0": - LoadFile ("DemoApplicationWindow.cs"); - break; - case "1": - LoadFile ("DemoButtonBox.cs"); - break; - case "2": - // - break; - case "3": - LoadFile ("DemoColorSelection.cs"); - break; - case "4": - LoadFile ("DemoDialog.cs"); - break; - case "5": - LoadFile ("DemoDrawingArea.cs"); - break; - case "6": - LoadFile ("DemoImages.cs"); - break; - case "7": - LoadFile ("DemoItemFactory.cs"); - break; - case "8": - LoadFile ("DemoMenus.cs"); - break; - case "9": - LoadFile ("DemoPanes.cs"); - break; - case "10": - LoadFile ("DemoPixbuf.cs"); - break; - case "11": - LoadFile ("DemoSizeGroup.cs"); - break; - case "12": - LoadFile ("DemoStockBrowser.cs"); - break; - case "13": - LoadFile ("DemoTextView.cs"); - break; - case "14": - // do nothing - break; - case "14:0": - LoadFile ("DemoEditableCells.cs"); - break; - case "14:1": - LoadFile ("DemoListStore.cs"); - break; - case "14:2": - LoadFile ("DemoTreeStore.cs"); - break; - default: - break; - } + model.SetValue (iter, 2, true); + model.SetValue (oldSelection, 2, false); + oldSelection = iter; } } @@ -293,10 +242,16 @@ namespace GtkDemo new DemoStockBrowser (); break; case "13": + ToggleRow (args.Path); + break; + case "13:0": + new DemoHyperText (); + break; + case "13:1": new DemoTextView (); break; case "14": - // do nothing + ToggleRow (args.Path); break; case "14:0": new DemoEditableCells (); @@ -312,6 +267,15 @@ namespace GtkDemo } } + void ToggleRow (TreePath path) + { + bool isExpanded = treeView.GetRowExpanded (path); + if (isExpanded) + treeView.CollapseRow (path); + else + treeView.ExpandRow (path, false); + } + private void WindowDelete (object o, DeleteEventArgs args) { Application.Quit (); @@ -319,3 +283,4 @@ namespace GtkDemo } } } + diff --git a/sample/GtkDemo/Makefile.am b/sample/GtkDemo/Makefile.am index 3b5fd110f..896fc62d3 100644 --- a/sample/GtkDemo/Makefile.am +++ b/sample/GtkDemo/Makefile.am @@ -13,6 +13,7 @@ sources = \ DemoDialog.cs \ DemoDrawingArea.cs \ DemoEditableCells.cs \ + DemoHyperText.cs \ DemoImages.cs \ DemoItemFactory.cs \ DemoListStore.cs \ @@ -26,23 +27,24 @@ sources = \ DemoTreeStore.cs images = \ -/resource:$(srcdir)/images/gnome-foot.png,gnome-foot.png \ -/resource:$(srcdir)/images/MonoIcon.png,MonoIcon.png \ -/resource:$(srcdir)/images/gnome-calendar.png,gnome-calendar.png \ -/resource:$(srcdir)/images/gnome-gmush.png,gnome-gmush.png \ -/resource:$(srcdir)/images/gnu-keys.png,gnu-keys.png \ -/resource:$(srcdir)/images/gnome-applets.png,gnome-applets.png \ -/resource:$(srcdir)/images/gnome-gsame.png,gnome-gsame.png \ -/resource:$(srcdir)/images/alphatest.png,alphatest.png \ -/resource:$(srcdir)/images/gnome-gimp.png,gnome-gimp.png \ -/resource:$(srcdir)/images/apple-red.png,apple-red.png \ -/resource:$(srcdir)/images/background.jpg,background.jpg \ -/resource:$(srcdir)/images/gtk-logo-rgb.gif,gtk-logo-rgb.gif \ -/resource:$(srcdir)/images/floppybuddy.gif,floppybuddy.gif + images/gnome-foot.png,gnome-foot.png \ + images/MonoIcon.png,MonoIcon.png \ + images/gnome-calendar.png,gnome-calendar.png \ + images/gnome-gmush.png,gnome-gmush.png \ + images/gnu-keys.png,gnu-keys.png \ + images/gnome-applets.png,gnome-applets.png \ + images/gnome-gsame.png,gnome-gsame.png \ + images/alphatest.png,alphatest.png \ + images/gnome-gimp.png,gnome-gimp.png \ + images/apple-red.png,apple-red.png \ + images/background.jpg,background.jpg \ + images/gtk-logo-rgb.gif,gtk-logo-rgb.gif \ + images/floppybuddy.gif,floppybuddy.gif build_sources = $(addprefix $(srcdir)/, $(sources)) -resources = $(addprefix /resource:, $(sources)) +build_images = $(addprefix $(srcdir)/, $(images)) +resources = $(addprefix /resource:, $(build_sources), $(build_images)) GtkDemo.exe: $(build_sources) $(assemblies) - $(CSC) /debug /out:GtkDemo.exe $(build_sources) $(references) $(images) $(resources) + $(CSC) /debug /out:GtkDemo.exe $(build_sources) $(references) $(resources) diff --git a/sample/GtkDemo/TODO b/sample/GtkDemo/TODO index f3a452e2a..eea600ed9 100644 --- a/sample/GtkDemo/TODO +++ b/sample/GtkDemo/TODO @@ -1,6 +1,8 @@ General - general C#-ification - - embed PixBufs instead of loading from disk + +DemoMain + - syntax highlighting DemoApplicationWindow - ItemFactory stuff @@ -16,3 +18,6 @@ DemoStockBrowser DemoTextView - small issue with international text + +DemoHyperText + - finish