GtkSharp/sample/GtkDemo/DemoHyperText.cs
Dan Winship 246d4e1620 * samples/GtkDemo/*.cs: General fixup and cleanup; Remove some
gratuitous differences from the C version. Make comment and indent
	style consistent. Don't use "this." where not needed. Override
	OnDeleteEvent rather than connecting one's own DeleteEvent signal.

	* sample/GtkDemo/DemoApplicationWindow.cs (static
	DemoApplicationWindow): register the Gtk logo icon with
	StockManager so it shows up correctly in the toolbar.
	(AddActions): Register the radio items as radio items so they work
	right.

	* sample/GtkDemo/DemoHyperText.cs (EventAfter): handle
	link-clicking from Widget.WidgetEventAfter (as in the C version),
	rather than ButtonRelease, now that WidgetEventAfter is wrapped.

	* sample/GtkDemo/DemoImages.cs (DemoImages): use
	Gtk.Image.LoadFromResource (particularly to make the animation
	work right).
	(OnDestroyed): handle clean up (remove the timeout, etc)

	* sample/GtkDemo/DemoMain.cs (LoadStream): Fix handling of blank
	lines and whitespace to match the C version.

	* sample/GtkDemo/DemoPixbuf.cs (Expose): Use
	System.Runtime.InteropServices.Marshal.Copy() to copy
	pixbuf.Pixels to pass to DrawRgbImageDithalign, to make this more
	like the C version (and probably faster?)
	(timeout): Remove the FIXME since it seems to work now

	* sample/GtkDemo/DemoStockBrowser.cs: Simplify a bunch. Use
	reflection to get the C# names of the stock icons rather than
	trying to correctly re-mangle the ids. Display the Label with the
	accelerator underlined.

	* sample/GtkDemo/DemoTextView.cs (AttachWidgets): use
	Gtk.Image.LoadFromResource, so the image is properly loaded as an
	animation, not a static image. Don't set the combobox's "Active"
	property (for consistency with the C version).
	(InsertText): Fix miscellaneous differences with the C version.
	Remove some leftover cruft from earlier workarounds for gtk# bugs.

	* sample/GtkDemo/DemoTreeStore.cs (AddColumns): Make this more
	like the C version so the checkboxes are sensitized and hidden
	correctly on a per-row basis.

	* sample/GtkDemo/DemoUIManager.cs: Make the radio menu items work.

	* sample/GtkDemo/README: 
	* sample/GtkDemo/TODO: update

svn path=/trunk/gtk-sharp/; revision=42481
2005-04-01 21:08:14 +00:00

205 lines
6.4 KiB
C#

/* Text Widget/Hypertext
*
* 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
* shows.
*/
using System;
using Gtk;
namespace GtkDemo
{
[Demo ("Hyper Text", "DemoHyperText.cs", "Text Widget")]
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);
SetDefaultSize (450, 450);
TextView view = new TextView ();
view.WrapMode = WrapMode.Word;
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);
ShowPage (view.Buffer, 1);
ShowAll ();
}
// 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, ref TextIter iter, string text, int page)
{
TextTag tag = new TextTag (null);
tag.Foreground = "blue";
tag.Underline = Pango.Underline.Single;
tag.PersistentData.Add ("page", page);
buffer.TagTable.Add (tag);
buffer.InsertWithTags (ref 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.StartIter;
if (page == 1) {
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, ".");
} 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");
InsertLink (buffer, ref iter, "Go back", 1);
} else if (page == 3) {
TextTag tag = buffer.TagTable.Lookup ("bold");
if (tag == null) {
tag = new TextTag ("bold");
tag.Weight = Pango.Weight.Bold;
buffer.TagTable.Add (tag);
}
buffer.InsertWithTags (ref iter, "hypertext:\n", tag);
buffer.Insert (ref iter,
"machine-readable text that is not sequential but is organized " +
"so that related items of information are connected.\n");
InsertLink (buffer, ref iter, "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) {
object page = tag.PersistentData ["page"];
if (page is int)
ShowPage (view.Buffer, (int)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) {
if (tag.PersistentData ["page"] is int) {
hovering = true;
break;
}
}
if (hovering != hoveringOverLink) {
Gdk.Window window = view.GetWindow (Gtk.TextWindowType.Text);
hoveringOverLink = hovering;
if (hoveringOverLink)
window.Cursor = handCursor;
else
window.Cursor = regularCursor;
}
}
// Links can be activated by pressing Enter.
void KeyPress (object sender, KeyPressEventArgs args)
{
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;
TextView view = sender as TextView;
TextIter start, end, iter;
int x, y;
// we shouldn't follow a link if the user has selected something
view.Buffer.GetSelectionBounds (out start, out end);
if (start.Offset != end.Offset)
return;
view.WindowToBufferCoords (TextWindowType.Widget, (int) evt.X, (int) evt.Y, out x, out y);
iter = view.GetIterAtLocation (x, y);
FollowIfLink (view, iter);
}
// Update the cursor image if the pointer moved.
void MotionNotify (object sender, MotionNotifyEventArgs args)
{
TextView view = sender as TextView;
int x, y;
Gdk.ModifierType state;
view.WindowToBufferCoords (TextWindowType.Widget, (int) args.Event.X, (int) args.Event.Y, out x, out y);
SetCursorIfAppropriate (view, x, y);
view.GdkWindow.GetPointer (out x, out y, out state);
}
// Also update the cursor image if the window becomes visible
// (e.g. when a window covering it got iconified).
void VisibilityNotify (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);
}
protected override bool OnDeleteEvent (Gdk.Event evt)
{
Destroy ();
return true;
}
}
}