GtkSharp/sample/GtkDemo/DemoHyperText.cs

226 lines
6.3 KiB
C#
Raw Normal View History

//
// Author: John Luke <john.luke@gmail.com>
// 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;
}
}
}