2005-01-02 19:16:41 +00:00
|
|
|
/* Text Widget/Hypertext
|
|
|
|
*
|
2005-04-01 21:08:14 +00:00
|
|
|
* Usually, tags modify the appearance of text in the view, e.g. making it
|
|
|
|
* bold or colored or underlined. But tags are not restricted to appearance.
|
|
|
|
* They can also affect the behavior of mouse and key presses, as this demo
|
2005-01-02 19:16:41 +00:00
|
|
|
* shows.
|
|
|
|
*/
|
|
|
|
|
2004-08-28 03:30:33 +00:00
|
|
|
using System;
|
2005-06-22 19:18:19 +00:00
|
|
|
using System.Collections;
|
2004-08-28 03:30:33 +00:00
|
|
|
using Gtk;
|
|
|
|
|
|
|
|
namespace GtkDemo
|
|
|
|
{
|
2004-12-12 22:11:44 +00:00
|
|
|
[Demo ("Hyper Text", "DemoHyperText.cs", "Text Widget")]
|
2004-08-28 03:30:33 +00:00
|
|
|
public class DemoHyperText : Gtk.Window
|
|
|
|
{
|
|
|
|
bool hoveringOverLink = false;
|
|
|
|
Gdk.Cursor handCursor, regularCursor;
|
|
|
|
|
|
|
|
public DemoHyperText () : base ("HyperText")
|
|
|
|
{
|
|
|
|
handCursor = new Gdk.Cursor (Gdk.CursorType.Hand2);
|
|
|
|
regularCursor = new Gdk.Cursor (Gdk.CursorType.Xterm);
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
SetDefaultSize (450, 450);
|
2004-08-28 03:30:33 +00:00
|
|
|
|
|
|
|
TextView view = new TextView ();
|
|
|
|
view.WrapMode = WrapMode.Word;
|
2005-04-01 21:08:14 +00:00
|
|
|
view.KeyPressEvent += new KeyPressEventHandler (KeyPress);
|
|
|
|
view.WidgetEventAfter += new WidgetEventAfterHandler (EventAfter);
|
|
|
|
view.MotionNotifyEvent += new MotionNotifyEventHandler (MotionNotify);
|
|
|
|
view.VisibilityNotifyEvent += new VisibilityNotifyEventHandler (VisibilityNotify);
|
|
|
|
|
|
|
|
ScrolledWindow sw = new ScrolledWindow ();
|
|
|
|
sw.SetPolicy (Gtk.PolicyType.Automatic, Gtk.PolicyType.Automatic);
|
|
|
|
Add (sw);
|
|
|
|
sw.Add (view);
|
2004-08-28 03:30:33 +00:00
|
|
|
|
|
|
|
ShowPage (view.Buffer, 1);
|
2005-04-01 21:08:14 +00:00
|
|
|
ShowAll ();
|
2004-08-28 03:30:33 +00:00
|
|
|
}
|
|
|
|
|
2005-06-22 19:18:19 +00:00
|
|
|
Hashtable tag_pages = new Hashtable ();
|
|
|
|
|
2004-08-28 03:30:33 +00:00
|
|
|
// 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.
|
2004-12-03 18:00:30 +00:00
|
|
|
void InsertLink (TextBuffer buffer, ref TextIter iter, string text, int page)
|
2004-08-28 03:30:33 +00:00
|
|
|
{
|
2005-04-01 21:08:14 +00:00
|
|
|
TextTag tag = new TextTag (null);
|
2004-08-28 03:30:33 +00:00
|
|
|
tag.Foreground = "blue";
|
|
|
|
tag.Underline = Pango.Underline.Single;
|
2005-06-22 19:18:19 +00:00
|
|
|
tag_pages [tag] = page;
|
2004-08-28 03:30:33 +00:00
|
|
|
buffer.TagTable.Add (tag);
|
2004-12-03 18:00:30 +00:00
|
|
|
buffer.InsertWithTags (ref iter, text, tag);
|
2004-08-28 03:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 = "";
|
2005-04-01 21:08:14 +00:00
|
|
|
TextIter iter = buffer.StartIter;
|
2004-08-28 03:30:33 +00:00
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
if (page == 1) {
|
2004-12-03 18:00:30 +00:00
|
|
|
buffer.Insert (ref iter, "Some text to show that simple ");
|
|
|
|
InsertLink (buffer, ref iter, "hypertext", 3);
|
|
|
|
buffer.Insert (ref iter, " can easily be realized with ");
|
|
|
|
InsertLink (buffer, ref iter, "tags", 2);
|
|
|
|
buffer.Insert (ref iter, ".");
|
2005-04-01 21:08:14 +00:00
|
|
|
} else if (page == 2) {
|
|
|
|
buffer.Insert (ref 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");
|
2004-12-03 18:00:30 +00:00
|
|
|
InsertLink (buffer, ref iter, "Go back", 1);
|
2005-04-01 21:08:14 +00:00
|
|
|
} else if (page == 3) {
|
2005-03-24 04:32:49 +00:00
|
|
|
TextTag tag = buffer.TagTable.Lookup ("bold");
|
|
|
|
if (tag == null) {
|
|
|
|
tag = new TextTag ("bold");
|
|
|
|
tag.Weight = Pango.Weight.Bold;
|
|
|
|
buffer.TagTable.Add (tag);
|
|
|
|
}
|
2004-12-03 18:00:30 +00:00
|
|
|
buffer.InsertWithTags (ref iter, "hypertext:\n", tag);
|
|
|
|
buffer.Insert (ref iter,
|
2005-04-01 21:08:14 +00:00
|
|
|
"machine-readable text that is not sequential but is organized " +
|
|
|
|
"so that related items of information are connected.\n");
|
2004-12-03 18:00:30 +00:00
|
|
|
InsertLink (buffer, ref iter, "Go back", 1);
|
2004-08-28 03:30:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
// Looks at all tags covering the position of iter in the text view,
|
2004-08-28 03:30:33 +00:00
|
|
|
// 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)
|
|
|
|
{
|
2005-04-01 21:08:14 +00:00
|
|
|
foreach (TextTag tag in iter.Tags) {
|
2005-06-22 19:18:19 +00:00
|
|
|
object page = tag_pages [tag];
|
2005-04-01 21:08:14 +00:00
|
|
|
if (page is int)
|
|
|
|
ShowPage (view.Buffer, (int)page);
|
2004-08-28 03:30:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
// Looks at all tags covering the position (x, y) in the text view,
|
2004-08-28 03:30:33 +00:00
|
|
|
// 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);
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
foreach (TextTag tag in iter.Tags) {
|
2005-06-22 19:18:19 +00:00
|
|
|
if (tag_pages [tag] is int) {
|
2004-08-28 03:30:33 +00:00
|
|
|
hovering = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
if (hovering != hoveringOverLink) {
|
|
|
|
Gdk.Window window = view.GetWindow (Gtk.TextWindowType.Text);
|
|
|
|
|
2004-08-28 03:30:33 +00:00
|
|
|
hoveringOverLink = hovering;
|
|
|
|
if (hoveringOverLink)
|
2005-04-01 21:08:14 +00:00
|
|
|
window.Cursor = handCursor;
|
2004-08-28 03:30:33 +00:00
|
|
|
else
|
2005-04-01 21:08:14 +00:00
|
|
|
window.Cursor = regularCursor;
|
2004-08-28 03:30:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
// Links can be activated by pressing Enter.
|
|
|
|
void KeyPress (object sender, KeyPressEventArgs args)
|
2004-08-28 03:30:33 +00:00
|
|
|
{
|
2005-04-01 21:08:14 +00:00
|
|
|
TextView view = sender as TextView;
|
|
|
|
|
|
|
|
switch ((Gdk.Key) args.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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Links can also be activated by clicking.
|
|
|
|
void EventAfter (object sender, WidgetEventAfterArgs args)
|
|
|
|
{
|
|
|
|
if (args.Event.Type != Gdk.EventType.ButtonRelease)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Gdk.EventButton evt = (Gdk.EventButton)args.Event;
|
|
|
|
|
|
|
|
if (evt.Button != 1)
|
|
|
|
return;
|
2004-08-28 03:30:33 +00:00
|
|
|
|
|
|
|
TextView view = sender as TextView;
|
|
|
|
TextIter start, end, iter;
|
|
|
|
int x, y;
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
// we shouldn't follow a link if the user has selected something
|
2004-08-28 03:30:33 +00:00
|
|
|
view.Buffer.GetSelectionBounds (out start, out end);
|
|
|
|
if (start.Offset != end.Offset)
|
|
|
|
return;
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
view.WindowToBufferCoords (TextWindowType.Widget, (int) evt.X, (int) evt.Y, out x, out y);
|
2004-08-28 03:30:33 +00:00
|
|
|
iter = view.GetIterAtLocation (x, y);
|
|
|
|
|
|
|
|
FollowIfLink (view, iter);
|
|
|
|
}
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
// Update the cursor image if the pointer moved.
|
|
|
|
void MotionNotify (object sender, MotionNotifyEventArgs args)
|
2004-08-28 03:30:33 +00:00
|
|
|
{
|
|
|
|
TextView view = sender as TextView;
|
|
|
|
int x, y;
|
2005-04-01 21:08:14 +00:00
|
|
|
Gdk.ModifierType state;
|
2004-08-28 03:30:33 +00:00
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
view.WindowToBufferCoords (TextWindowType.Widget, (int) args.Event.X, (int) args.Event.Y, out x, out y);
|
2004-08-28 03:30:33 +00:00
|
|
|
SetCursorIfAppropriate (view, x, y);
|
2005-04-01 21:08:14 +00:00
|
|
|
|
|
|
|
view.GdkWindow.GetPointer (out x, out y, out state);
|
2004-08-28 03:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Also update the cursor image if the window becomes visible
|
|
|
|
// (e.g. when a window covering it got iconified).
|
2005-04-01 21:08:14 +00:00
|
|
|
void VisibilityNotify (object sender, VisibilityNotifyEventArgs a)
|
2004-08-28 03:30:33 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2005-04-01 21:08:14 +00:00
|
|
|
protected override bool OnDeleteEvent (Gdk.Event evt)
|
2004-08-28 03:30:33 +00:00
|
|
|
{
|
2005-04-01 21:08:14 +00:00
|
|
|
Destroy ();
|
|
|
|
return true;
|
2004-08-28 03:30:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|