Added help popup, Ctrl-Left and Right cursor movement by word
+using System.Collections;
+using System.IO;
+using System;
+using Cairo;
+using Pango;
+
+public struct HelpItem {
+ public string Key;
+ public string Text;
+
+ public HelpItem(string key, string text) {
+ Key = key;
+ Text = text;
+ }
+
+ public override string ToString() {
+ return "<b>" + Key + "</b>\t" + Text;
+ }
+}
+
+public class HelpBox {
+ private Pango.Context pc;
+ private Pango.FontDescription titleFont;
+ private Pango.FontDescription textFont;
+ private string helpTitle;
+ private HelpItem[] helpText;
+ private int Width = 480;
+ private int Height = 360;
+ private int Columns = 3;
+
+ public HelpBox(Pango.Context pc, string title, HelpItem[] items) {
+ this.pc = pc;
+ helpTitle = title;
+ helpText = items;
+ init();
+ }
+
+ public HelpBox(Pango.Context pc, string filename) {
+ StreamReader file = new StreamReader(filename);
+ string line;
+ ArrayList items = new ArrayList();
+
+ this.pc = pc;
+ helpTitle = file.ReadLine();
+ while ((line = file.ReadLine()) != null) {
+ string[] i = line.Split(null);
+ if (i.Length == 2) {
+ items.Add(new HelpItem(i[0], i[1]));
+ }
+ }
+ helpText = new HelpItem[items.Count];
+ for (int i = 0; i < items.Count; i++) {
+ helpText[i] = (HelpItem) items[i];
+ }
+ init();
+ }
+
+ private void init() {
+ titleFont = Pango.FontDescription.FromString("Helvetica Bold 24");
+ textFont = Pango.FontDescription.FromString("Helvetica 16");
+ Pango.FontMetrics fmTitle = pc.GetMetrics(titleFont, null);
+ Pango.FontMetrics fmText = pc.GetMetrics(textFont, null);
+ int hTitle = Pango.Units.ToPixels(fmTitle.Ascent + fmTitle.Descent);
+ int hText = Pango.Units.ToPixels(fmText.Ascent + fmText.Descent);
+
+ Width = 480;
+ for (int i = 0; i < helpText.Length; i++) {
+ Pango.Layout layout = new Pango.Layout(pc);
+ Pango.Rectangle r, r2;
+
+ layout.FontDescription = textFont;
+ layout.SetMarkup(helpText[i].ToString());
+ layout.GetExtents(out r, out r2);
+ int pw = Pango.Units.ToPixels(r2.Width);
+ if ((pw + 8) * Columns > Width) {
+ Width = (pw + 8) * Columns;
+ }
+ }
+ Height = hTitle + (helpText.Length / 3 + 1) * hText + 12;
+ }
+
+ public void draw(Cairo.Context gr, int width, int height) {
+ Pango.Layout layout;
+ Cairo.Rectangle r = new Cairo.Rectangle(
+ width / 2 - Width / 2,
+ height / 2 - Height / 2,
+ Width, Height);
+
+ gr.SetSourceRGBA(1.0, 1.0, 1.0, 0.8);
+ gr.NewPath();
+ gr.Rectangle(r);
+ gr.Fill();
+
+ gr.SetSourceRGB(0.0, 0.0, 0.0);
+ gr.NewPath();
+ gr.Rectangle(r);
+ gr.Stroke();
+
+ gr.MoveTo(r.X + 4, r.Y + 4);
+ layout = new Pango.Layout(pc);
+ layout.SetText(helpTitle);
+ layout.Width = Pango.Units.FromPixels((int)r.Width);
+ layout.FontDescription = titleFont;
+ Pango.CairoHelper.ShowLayout(gr, layout);
+
+ int ii = 0;
+ int ColumnWidth = Width / Columns;
+ int ColumnLines = helpText.Length / Columns + 1;
+ for (int i = 0; i < Columns; i++) {
+ gr.MoveTo(r.X + 4 + (i * ColumnWidth), r.Y + 38);
+ string column = "";
+ for (int j = 0; j < ColumnLines && ii < helpText.Length; j++) {
+ column += helpText[ii].ToString() + "\n";
+ ii++;
+ }
+ layout = new Pango.Layout(pc);
+ layout.SetMarkup(column);
+ layout.Width = Pango.Units.FromPixels(ColumnWidth);
+ layout.FontDescription = textFont;
+ Pango.CairoHelper.ShowLayout(gr, layout);
+ }
+ }
+}
CSFLAGS = -debug -pkg:gtk-sharp-2.0 -r:Mono.Cairo
SOURCES = main.cs Interfaces.cs TextDisplay.cs TextDocument.cs TextInput.cs \
- FileInput.cs
+ FileInput.cs HelpBox.cs
EXE = Nebula.exe
all: $(EXE)
using System;
+using System.Timers;
using Cairo;
using Pango;
+using Gdk;
using Gtk;
public class TextDisplay : DrawingArea, IKeyPress {
private TextDocument doc = null;
- private Font font;
+ private Pango.Font font;
// FIXME: Proportional fonts?
- private float fontwidth;
- private float fontheight;
+ 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);
+ 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));
}
gr.MoveTo(0, 0);
Pango.CairoHelper.ShowLayout(gr, layout);
- gr.Operator = Operator.Xor;
+ 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.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)
- {
+ protected override bool OnExposeEvent(Gdk.EventExpose args) {
Gdk.Window win = args.Window;
#if OLD_SYSTEMS
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);
+ 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;
+ }
+ }
}
public string GetTextWindow() {
string s = "";
- for (int i = textorigin.y; textorigin.y + i < text.Lines.Count && i < pageheight; i++) {
- string l = (string)text.Lines[i];
- s += l.Substring(textorigin.x) + "\n";
+ for (int i = 0; i <= pageheight + 1 && textorigin.y + i < text.Lines.Count; i++) {
+ string l = (string)text.Lines[textorigin.y + i];
+ if (textorigin.x > l.Length) {
+ s += "\n";
+ } else {
+ s += l.Substring(textorigin.x) + "\n";
+ }
}
return s;
}
cursor.y += pageheight;
break;
}
- FixTextWindow();
+ }
+
+ public void NextWord() {
+ if (cursor.x >= text.LineLength(cursor.y)) {
+ cursor.y++;
+ cursor.x = 0;
+ } else {
+ string s = (String)text.Lines[cursor.y];
+ int i = s.IndexOf(' ', cursor.x);
+ if (i == -1) {
+ cursor.y++;
+ cursor.x = 0;
+ } else {
+ cursor.x = i + 1;
+ }
+ }
+ }
+
+ public void PreviousWord() {
+ if (cursor.y > text.Lines.Count) {
+ cursor.x = 0;
+ cursor.y--;
+ } else if (cursor.y == text.Lines.Count) {
+ string s = (String)text.Lines[text.Lines.Count - 1];
+ int i = s.LastIndexOf(' ');
+ if (i == -1) {
+ cursor.x = 0;
+ } else {
+ cursor.x = i + 1;
+ }
+ cursor.y--;
+ } else if (cursor.x == 0 && cursor.y > 0) {
+ string s = (String)text.Lines[cursor.y - 1];
+ int i = s.LastIndexOf(' ');
+ if (i == -1) {
+ cursor.x = 0;
+ } else {
+ cursor.x = i + 1;
+ }
+ cursor.y--;
+ } else if (cursor.x == 0 && cursor.y == 0) {
+ return;
+ } else {
+ string s = (String)text.Lines[cursor.y];
+ if (cursor.x >= s.Length)
+ cursor.x = s.Length - 1;
+ int i = s.LastIndexOf(' ', cursor.x - 2, cursor.x - 2);
+ if (i == -1) {
+ cursor.x = 0;
+ } else {
+ cursor.x = i + 1;
+ }
+ }
}
[GLib.ConnectBefore ()]
public void KeyPress(object o, Gtk.KeyPressEventArgs args) {
if ((args.Event.State & Gdk.ModifierType.ControlMask) != 0) {
+ switch(args.Event.Key) {
+ case Gdk.Key.Right:
+ NextWord();
+ break;
+ case Gdk.Key.Left:
+ PreviousWord();
+ break;
+ }
} else if ((args.Event.State & Gdk.ModifierType.Mod1Mask) != 0) {
} else {
switch(args.Event.Key) {
break;
}
}
+ FixTextWindow();
}
public void AddChar(int c) {
+Control Hotkeys
+N New
+O Open
+S Save
+Q Quit
+-> Next Word
+<- Previous Word
window.ShowAll();
window.KeyPressEvent += new KeyPressEventHandler(KeyPress);
+ window.KeyReleaseEvent += display.KeyRelease;
SelectInput(display);
window.DeleteEvent += delegate(object o, DeleteEventArgs e) {
Application.Quit();
}
SelectInput(display);
stack.Remove(input);
- input.Destroy();
+ input = null;
};
break;
case Gdk.Key.s: