/TextDisplay.cs
using System;
using System.Timers;
using Cairo;
using Pango;
using Gdk;
using Gtk;
public class TextDisplay : DrawingArea, IKeyPress {
private TextDocument doc = null;
private Pango.Font font;
// FIXME: Proportional fonts?
private float fontWidth;
private float fontHeight;
private Timer helpTimer;
private HelpBox controlHelp;
private bool showHelp;
public TextDisplay() {
FontDescription fd = Pango.FontDescription.FromString("Courier 12");
font = this.PangoContext.LoadFont(fd);
FontMetrics fm = font.GetMetrics(null);
fontHeight = Pango.Units.ToPixels(fm.Ascent + fm.Descent);
fontWidth = fontHeight * 0.5333f;
Console.WriteLine("Using {0} {1}pt ({2}x{3}px)", fd.Family, fd.Size, fontWidth, fontHeight);
controlHelp = new HelpBox(this.PangoContext, "control_help");
ModifyBg(StateType.Normal, new Gdk.Color(0xFF, 0xFF, 0xFF));
}
public void SetDocument(TextDocument doc) {
this.doc = doc;
}
void draw(Cairo.Context gr, int width, int height) {
if (doc == null) return;
Pango.Layout layout = new Pango.Layout(this.PangoContext);
layout.Width = 0x7FFFFFFF; //Pango.Units.FromPixels(width);
layout.FontDescription = font.Describe();
//gr.Operator = Operator.Atop;
gr.SetSourceRGB(0,0,0);
layout.SetText(doc.GetTextWindow());
gr.MoveTo(0, 0);
Pango.CairoHelper.ShowLayout(gr, layout);
gr.SetSourceRGB(0.0, 0.0, 0.0);
gr.NewPath();
gr.Rectangle((doc.cursor.x - doc.textorigin.x)*fontWidth, (doc.cursor.y - doc.textorigin.y)*fontHeight, fontWidth, fontHeight);
gr.Fill();
if (showHelp) {
controlHelp.draw(gr, width, height);
}
}
protected override bool OnExposeEvent(Gdk.EventExpose args) {
Gdk.Window win = args.Window;
#if OLD_SYSTEMS
//
// For old versions of Gtk# (before 2.8), you need the helper class
// available in gtk-sharp/sample/GtkCairo.cs
//
Cairo.Context g = Gdk.Graphics.CreateDrawable (win);
#else
//
// Starting with Gtk 2.8 Gtk has direct support for
// Cairo, as its built on top of it, on older
// versions, a helper routine is used
//
Cairo.Context g = Gdk.CairoHelper.Create (args.Window);
#endif
int x, y, w, h, d;
win.GetGeometry(out x, out y, out w, out h, out d);
draw (g, w, h);
((IDisposable) g.Target).Dispose();
((IDisposable) g).Dispose();
return true;
}
protected override void OnSizeAllocated(Gdk.Rectangle r) {
base.OnSizeAllocated(r);
if (doc != null)
doc.SetPageSize((int)(r.Width / fontWidth) - 1, (int)(r.Height / fontHeight) - 1);
}
public void Update() {
QueueDraw();
}
public void ShowHelp() {
showHelp = true;
helpTimer = null;
QueueDraw();
}
public void HideHelp() {
if (helpTimer != null) {
helpTimer.Stop();
helpTimer = null;
}
if (showHelp)
showHelp = false;
QueueDraw();
}
[GLib.ConnectBefore ()]
public void KeyPress(object o, KeyPressEventArgs args) {
if (doc == null) return;
if ((args.Event.State & ModifierType.ControlMask) != 0) {
switch(args.Event.Key) {
default:
HideHelp();
break;
}
} else {
switch(args.Event.Key) {
case Gdk.Key.Control_L:
case Gdk.Key.Control_R:
helpTimer = new Timer();
helpTimer.Elapsed += delegate(object o2, ElapsedEventArgs e) {
ShowHelp();
};
helpTimer.AutoReset = false;
helpTimer.Interval = 1000;
helpTimer.Start();
break;
}
}
doc.KeyPress(o, args);
}
public void KeyRelease(object o, KeyReleaseEventArgs e) {
switch(e.Event.Key) {
case Gdk.Key.Control_L:
case Gdk.Key.Control_R:
HideHelp();
break;
}
}
}