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; } } }