135
149
protected virtual void HAdjustmentValueChanged ()
137
if (this.textEditorData.HAdjustment.Value != System.Math.Ceiling (this.textEditorData.HAdjustment.Value)) {
138
this.textEditorData.HAdjustment.Value = System.Math.Ceiling (this.textEditorData.HAdjustment.Value);
151
double value = this.textEditorData.HAdjustment.Value;
152
if (value != System.Math.Round (value)) {
153
this.textEditorData.HAdjustment.Value = System.Math.Round (value);
141
/* if (this.containerChildren.Count > 0)
144
157
textViewMargin.HideCodeSegmentPreviewWindow ();
145
int curHAdjustment = (int)this.textEditorData.HAdjustment.Value;
146
if (oldHAdjustment == curHAdjustment)
149
QueueDrawArea (this.textViewMargin.XOffset, 0, this.Allocation.Width - this.textViewMargin.XOffset, this.Allocation.Height);
158
QueueDrawArea ((int)this.textViewMargin.XOffset, 0, this.Allocation.Width - (int)this.textViewMargin.XOffset, this.Allocation.Height);
150
159
OnHScroll (EventArgs.Empty);
153
162
void VAdjustmentValueChanged (object sender, EventArgs args)
155
165
VAdjustmentValueChanged ();
252
254
doc.TextReplaced += OnDocumentStateChanged;
253
255
doc.TextSet += OnTextSet;
256
doc.LineChanged += UpdateLinesOnTextMarkerHeightChange;
257
doc.MarkerAdded += HandleTextEditorDataDocumentMarkerChange;
258
doc.MarkerRemoved += HandleTextEditorDataDocumentMarkerChange;
255
260
textEditorData.CurrentMode = initialMode;
257
262
// this.Events = EventMask.AllEventsMask;
258
263
this.Events = EventMask.PointerMotionMask | EventMask.ButtonPressMask | EventMask.ButtonReleaseMask | EventMask.EnterNotifyMask | EventMask.LeaveNotifyMask | EventMask.VisibilityNotifyMask | EventMask.FocusChangeMask | EventMask.ScrollMask | EventMask.KeyPressMask | EventMask.KeyReleaseMask;
259
264
this.DoubleBuffered = true;
260
this.AppPaintable = false;
261
265
base.CanFocus = true;
262
this.RedrawOnAllocate = false;
263
266
WidgetFlags |= WidgetFlags.NoWindow;
264
267
iconMargin = new IconMargin (this);
265
268
gutterMargin = new GutterMargin (this);
266
269
dashedLineMargin = new DashedLineMargin (this);
267
dashedLineMargin.UseBGColor = false;
268
270
foldMarkerMargin = new FoldMarkerMargin (this);
269
271
textViewMargin = new TextViewMargin (this);
314
imContext.RetrieveSurrounding += delegate (object o, RetrieveSurroundingArgs args) {
315
//use a single line of context, whole document would be very expensive
316
//FIXME: UTF16 surrogates handling for caret offset? only matters for astral plane
317
imContext.SetSurrounding (Document.GetLineText (Caret.Line, false), Caret.Column);
321
imContext.SurroundingDeleted += delegate (object o, SurroundingDeletedArgs args) {
322
//FIXME: UTF16 surrogates handling for offset and NChars? only matters for astral plane
323
var line = Document.GetLine (Caret.Line);
324
((IBuffer)Document).Remove (line.Offset + args.Offset, args.NChars);
311
328
using (Pixmap inv = new Pixmap (null, 1, 1, 1)) {
312
329
invisibleCursor = new Cursor (inv, inv, Gdk.Color.Zero, Gdk.Color.Zero, 0, 0);
315
332
InitAnimations ();
316
333
this.Document.EndUndo += HandleDocumenthandleEndUndo;
335
TextEditorAccessible.Factory.Init (this);
319
339
void HandleDocumenthandleEndUndo (object sender, Document.UndoOperationEventArgs e)
618
655
imContext = imContext.Kill (x => x.Commit -= IMCommit);
620
if (this.textEditorData.HAdjustment != null) {
657
if (this.textEditorData.HAdjustment != null)
621
658
this.textEditorData.HAdjustment.ValueChanged -= HAdjustmentValueChanged;
622
this.textEditorData.HAdjustment = null;
624
if (this.textEditorData.VAdjustment != null) {
660
if (this.textEditorData.VAdjustment != null)
625
661
this.textEditorData.VAdjustment.ValueChanged -= VAdjustmentValueChanged;
626
this.textEditorData.VAdjustment = null;
663
foreach (Margin margin in this.margins) {
664
if (margin is IDisposable)
665
((IDisposable)margin).Dispose ();
629
if (margins != null) {
630
foreach (Margin margin in this.margins) {
631
if (margin is IDisposable)
632
((IDisposable)margin).Dispose ();
639
dashedLineMargin = null;
640
foldMarkerMargin = null;
641
textViewMargin = null;
642
this.textEditorData = this.textEditorData.Kill (x => x.SelectionChanged -= TextEditorDataSelectionChanged);
668
this.textEditorData.SelectionChanged -= TextEditorDataSelectionChanged;
669
this.textEditorData.Dispose ();
643
670
this.Realized -= OptionsChanged;
647
675
internal void RedrawMargin (Margin margin)
651
QueueDrawArea (margin.XOffset, 0, GetMarginWidth (margin), this.Allocation.Height);
679
QueueDrawArea ((int)margin.XOffset, 0, GetMarginWidth (margin), this.Allocation.Height);
654
682
public void RedrawMarginLine (Margin margin, int logicalLine)
785
/// <summary>Handles key input after key mapping and input methods.</summary>
786
/// <param name="key">The mapped keycode.</param>
787
/// <param name="unicodeChar">A UCS4 character. If this is nonzero, it overrides the keycode.</param>
788
/// <param name="modifier">Keyboard modifier, excluding any consumed by key mapping or IM.</param>
756
789
public void SimulateKeyPress (Gdk.Key key, uint unicodeChar, ModifierType modifier)
758
ModifierType filteredModifiers = modifier & (ModifierType.ShiftMask | ModifierType.Mod1Mask | ModifierType.ControlMask | ModifierType.MetaMask | ModifierType.SuperMask);
760
ModifierType modifiersThatPermitChars = ModifierType.ShiftMask;
762
modifiersThatPermitChars |= ModifierType.Mod1Mask;
764
if ((filteredModifiers & ~modifiersThatPermitChars) != 0)
791
ModifierType filteredModifiers = modifier & (ModifierType.ShiftMask | ModifierType.Mod1Mask
792
| ModifierType.ControlMask | ModifierType.MetaMask | ModifierType.SuperMask);
767
793
CurrentMode.InternalHandleKeypress (this, textEditorData, key, unicodeChar, filteredModifiers);
768
794
RequestResetCaretBlink ();
771
bool IMFilterKeyPress (Gdk.EventKey evt)
797
bool IMFilterKeyPress (Gdk.EventKey evt, Gdk.Key mappedKey, uint mappedChar, Gdk.ModifierType mappedModifiers)
773
799
if (lastIMEvent == evt)
776
if (evt.Type == EventType.KeyPress)
802
if (evt.Type == EventType.KeyPress) {
777
803
lastIMEvent = evt;
804
lastIMEventMappedChar = mappedChar;
805
lastIMEventMappedKey = mappedKey;
806
lastIMEventMappedModifier = mappedModifiers;
779
809
if (imContext.FilterKeypress (evt)) {
780
810
imContextActive = true;
1025
1052
double x = e.X;
1026
1053
double y = e.Y;
1027
1054
Gdk.ModifierType mod = e.State;
1029
Margin margin = GetMarginAtX ((int)x, out startPos);
1030
if (textViewMargin.inDrag && margin == this.textViewMargin && Gtk.Drag.CheckThreshold (this, pressPositionX, pressPositionY, (int)x, (int)y)) {
1056
Margin margin = GetMarginAtX (x, out startPos);
1057
if (textViewMargin.inDrag && margin == this.textViewMargin && Gtk.Drag.CheckThreshold (this, (int)pressPositionX, (int)pressPositionY, (int)x, (int)y)) {
1031
1058
dragContents = new ClipboardActions.CopyOperation ();
1032
1059
dragContents.CopyData (textEditorData);
1033
1060
DragContext context = Gtk.Drag.Begin (this, ClipboardActions.CopyOperation.targetList, DragAction.Move | DragAction.Copy, 1, e);
1034
CodeSegmentPreviewWindow window = new CodeSegmentPreviewWindow (this, true, textEditorData.SelectionRange, 300, 300);
1036
Gtk.Drag.SetIconWidget (context, window, 0, 0);
1061
if (!Platform.IsMac) {
1062
CodeSegmentPreviewWindow window = new CodeSegmentPreviewWindow (this, true, textEditorData.SelectionRange, 300, 300);
1063
Gtk.Drag.SetIconWidget (context, window, 0, 0);
1037
1065
selection = Selection.Clone (MainSelection);
1038
1066
textViewMargin.inDrag = false;
1041
1068
FireMotionEvent (x, y, mod);
1042
1069
if (mouseButtonPressed != 0) {
1217
1229
// int yMargin = 1 * this.LineHeight;
1218
int caretPosition = LineToVisualY (p.Line);
1230
double caretPosition = LineToY (p.Line);
1219
1231
this.textEditorData.VAdjustment.Value = caretPosition - this.textEditorData.VAdjustment.PageSize / 2;
1221
1233
if (this.textEditorData.HAdjustment.Upper < Allocation.Width) {
1222
1234
this.textEditorData.HAdjustment.Value = 0;
1224
int caretX = textViewMargin.ColumnToVisualX (Document.GetLine (p.Line), p.Column);
1225
int textWith = Allocation.Width - textViewMargin.XOffset;
1236
double caretX = ColumnToX (Document.GetLine (p.Line), p.Column);
1237
double textWith = Allocation.Width - textViewMargin.XOffset;
1226
1238
if (this.textEditorData.HAdjustment.Value > caretX) {
1227
1239
this.textEditorData.HAdjustment.Value = caretX;
1228
1240
} else if (this.textEditorData.HAdjustment.Value + textWith < caretX + TextViewMargin.CharWidth) {
1229
int adjustment = System.Math.Max (0, caretX - textWith + TextViewMargin.CharWidth);
1241
double adjustment = System.Math.Max (0, caretX - textWith + TextViewMargin.CharWidth);
1230
1242
this.textEditorData.HAdjustment.Value = adjustment;
1373
1387
return this.textViewMargin.GetWidth (text);
1376
void RenderMargins (Gdk.Drawable win, Gdk.Rectangle area)
1390
void UpdateMarginXOffsets ()
1378
this.TextViewMargin.rulerX = Options.RulerColumn * this.TextViewMargin.CharWidth - (int)this.textEditorData.HAdjustment.Value;
1379
int reminder = (int)this.textEditorData.VAdjustment.Value % LineHeight;
1380
int startLine = CalculateLineNumber (area.Top - reminder + (int)this.textEditorData.VAdjustment.Value);
1381
int startY = LineToVisualY (startLine);
1382
if (area.Top == 0 && startY > 0) {
1384
startY -= GetLineHeight (Document.GetLine (startLine));
1393
foreach (Margin margin in this.margins) {
1394
if (!margin.IsVisible)
1396
margin.XOffset = curX;
1397
curX += margin.Width;
1388
int curY = startY - (int)this.textEditorData.VAdjustment.Value;
1401
void RenderMargins (Cairo.Context cr, Cairo.Context textViewCr, Cairo.Rectangle cairoRectangle)
1403
this.TextViewMargin.rulerX = Options.RulerColumn * this.TextViewMargin.CharWidth - this.textEditorData.HAdjustment.Value;
1404
int startLine = YToLine (cairoRectangle.Y + this.textEditorData.VAdjustment.Value);
1405
double startY = LineToY (startLine);
1406
double curY = startY - this.textEditorData.VAdjustment.Value;
1389
1407
bool setLongestLine = false;
1390
bool renderFirstLine = true;
1391
1408
for (int visualLineNumber = startLine; ; visualLineNumber++) {
1392
1409
int logicalLineNumber = visualLineNumber;
1393
1410
LineSegment line = Document.GetLine (logicalLineNumber);
1394
int lineHeight = GetLineHeight (line);
1411
double lineHeight = GetLineHeight (line);
1396
1413
foreach (FoldSegment fs in Document.GetStartFoldings (line).Where (fs => fs.IsFolded)) {
1397
1414
lastFold = System.Math.Max (fs.EndOffset, lastFold);
1416
if (lastFold >= DocumentLocation.MinLine)
1400
1417
visualLineNumber = Document.OffsetToLineNumber (lastFold);
1401
1418
foreach (Margin margin in this.margins) {
1402
1419
if (!margin.IsVisible)
1405
if (renderFirstLine)
1406
margin.XOffset = curX;
1407
margin.Draw (win, area, logicalLineNumber, margin.XOffset, curY, lineHeight);
1408
margin.EndRender (win, area, margin.XOffset);
1409
if (renderFirstLine)
1410
curX += margin.Width;
1422
margin.Draw (margin == textViewMargin ? textViewCr : cr, cairoRectangle, line, logicalLineNumber, margin.XOffset, curY, lineHeight);
1411
1423
} catch (Exception e) {
1412
1424
System.Console.WriteLine (e);
1415
renderFirstLine = false;
1416
1427
// take the line real render width from the text view margin rendering (a line can consist of more than
1417
1428
// one line and be longer (foldings!) ex. : someLine1[...]someLine2[...]someLine3)
1418
int lineWidth = textViewMargin.lastLineRenderWidth + (int)HAdjustment.Value;
1429
double lineWidth = textViewMargin.lastLineRenderWidth + HAdjustment.Value;
1419
1430
if (longestLine == null || lineWidth > longestLineWidth) {
1420
1431
longestLine = line;
1421
1432
longestLineWidth = lineWidth;
1422
1433
setLongestLine = true;
1424
1435
curY += lineHeight;
1425
if (curY > area.Bottom)
1436
if (curY > cairoRectangle.Y + cairoRectangle.Height)
1465
1476
UpdateAdjustments ();
1467
RenderMargins (e.Window, e.Region.Clipbox);
1478
var area = e.Region.Clipbox;
1479
var cairoArea = new Cairo.Rectangle (area.X, area.Y, area.Width, area.Height);
1480
using (Cairo.Context cr = Gdk.CairoHelper.Create (e.Window))
1481
using (Cairo.Context textViewCr = Gdk.CairoHelper.Create (e.Window)) {
1482
UpdateMarginXOffsets ();
1484
cr.LineWidth = Options.Zoom;
1485
textViewCr.LineWidth = Options.Zoom;
1486
textViewCr.Rectangle (textViewMargin.XOffset, 0, Allocation.Width - textViewMargin.XOffset, Allocation.Height);
1489
RenderMargins (cr, textViewCr, cairoArea);
1469
1491
#if DEBUG_EXPOSE
1470
Console.WriteLine ("{0} expose {1},{2} {3}x{4}", (long)(DateTime.Now - started).TotalMilliseconds,
1471
e.Area.X, e.Area.Y, e.Area.Width, e.Area.Height);
1492
Console.WriteLine ("{0} expose {1},{2} {3}x{4}", (long)(DateTime.Now - started).TotalMilliseconds,
1493
e.Area.X, e.Area.Y, e.Area.Width, e.Area.Height);
1473
if (requestResetCaretBlink) {
1474
textViewMargin.ResetCaretBlink ();
1475
requestResetCaretBlink = false;
1478
foreach (Animation animation in actors) {
1479
animation.Drawer.Draw (e.Window);
1482
if (e.Area.Contains (TextViewMargin.caretX, TextViewMargin.caretY))
1483
textViewMargin.DrawCaret (e.Window);
1495
if (requestResetCaretBlink && HasFocus) {
1496
textViewMargin.ResetCaretBlink ();
1497
requestResetCaretBlink = false;
1500
foreach (Animation animation in actors) {
1501
animation.Drawer.Draw (cr);
1504
if (HasFocus && e.Area.Contains ((int)TextViewMargin.caretX, (int)TextViewMargin.caretY))
1505
textViewMargin.DrawCaret (e.Window);
1507
OnPainted (new PaintEventArgs (cr, cairoArea));
1488
#region TextEditorData functions
1513
protected virtual void OnPainted (PaintEventArgs e)
1515
EventHandler<PaintEventArgs> handler = this.Painted;
1516
if (handler != null)
1520
public event EventHandler<PaintEventArgs> Painted;
1522
#region TextEditorData delegation
1523
public string EolMarker {
1525
return textEditorData.EolMarker;
1489
1529
public Mono.TextEditor.Highlighting.Style ColorStyle {
1491
1531
return this.textEditorData.ColorStyle;
1716
#region Document delegation
1719
return Document.Length;
1723
public string Text {
1725
return Document.Text;
1728
Document.Text = value;
1732
public string GetTextBetween (int startOffset, int endOffset)
1734
return Document.GetTextBetween (startOffset, endOffset);
1737
public string GetTextBetween (DocumentLocation start, DocumentLocation end)
1739
return Document.GetTextBetween (start, end);
1742
public string GetTextBetween (int startLine, int startColumn, int endLine, int endColumn)
1744
return Document.GetTextBetween (startLine, startColumn, endLine, endColumn);
1747
public string GetTextAt (int offset, int count)
1749
return Document.GetTextAt (offset, count);
1752
public string GetTextAt (ISegment segment)
1754
return Document.GetTextAt (segment);
1757
public char GetCharAt (int offset)
1759
return Document.GetCharAt (offset);
1762
public IEnumerable<LineSegment> Lines {
1764
return Document.Lines;
1768
public int LineCount {
1770
return Document.LineCount;
1774
public int LocationToOffset (int line, int column)
1776
return Document.LocationToOffset (line, column);
1779
public int LocationToOffset (DocumentLocation location)
1781
return Document.LocationToOffset (location);
1784
public DocumentLocation OffsetToLocation (int offset)
1786
return Document.OffsetToLocation (offset);
1789
public string GetLineIndent (int lineNumber)
1791
return Document.GetLineIndent (lineNumber);
1794
public string GetLineIndent (LineSegment segment)
1796
return Document.GetLineIndent (segment);
1799
public LineSegment GetLine (int lineNumber)
1801
return Document.GetLine (lineNumber);
1804
public LineSegment GetLineByOffset (int offset)
1806
return Document.GetLineByOffset (offset);
1809
public int OffsetToLineNumber (int offset)
1811
return Document.OffsetToLineNumber (offset);
1662
1815
#region Search & Replace
1664
1817
bool highlightSearchPattern = false;
1729
1882
return textEditorData.SearchBackward (fromOffset);
1732
class HighlightSearchResultAnimation : IAnimationDrawer, IDisposable
1735
SearchResult result;
1736
Gdk.Pixbuf textImage = null;
1738
public double Percent { get; set; }
1740
public HighlightSearchResultAnimation (TextEditor editor, SearchResult result)
1742
this.editor = editor;
1743
this.result = result;
1746
public Gdk.Rectangle AnimationBounds {
1748
// LineSegment line = editor.Document.GetLineByOffset (result.Offset);
1749
int lineNr = editor.Document.OffsetToLineNumber (result.Offset);
1750
int y = editor.LineToVisualY (lineNr) - (int)editor.VAdjustment.Value;
1751
return new Gdk.Rectangle (0, y - editor.LineHeight , editor.Allocation.Width, editor.LineHeight * 3);
1755
public void Draw (Drawable drawable)
1757
LineSegment line = editor.Document.GetLineByOffset (result.Offset);
1758
int lineNr = editor.Document.OffsetToLineNumber (result.Offset);
1759
SyntaxMode mode = editor.Document.SyntaxMode != null && editor.Options.EnableSyntaxHighlighting ? editor.Document.SyntaxMode : SyntaxMode.Default;
1761
TextViewMargin.LayoutWrapper lineLayout = editor.textViewMargin.CreateLinePartLayout (mode, line, line.Offset, line.EditableLength, -1, -1);
1762
if (lineLayout == null)
1765
int index = result.Offset - line.Offset - 1;
1767
lineLayout.Layout.IndexToLineX (index, true, out l, out x1);
1771
index = result.Offset - line.Offset - 1 + result.Length;
1774
lineLayout.Layout.IndexToLineX (index, true, out l, out x2);
1775
x1 /= (int)Pango.Scale.PangoScale;
1776
x2 /= (int)Pango.Scale.PangoScale;
1777
int y = editor.LineToVisualY (lineNr) - (int)editor.VAdjustment.Value;
1778
using (Cairo.Context cr = Gdk.CairoHelper.Create (drawable)) {
1779
cr.Rectangle (editor.TextViewMargin.XOffset, 0, editor.Allocation.Width - editor.TextViewMargin.XOffset, editor.Allocation.Height);
1783
int width = (int)(x2 - x1);
1785
int rx = (int)(editor.TextViewMargin.XOffset - editor.HAdjustment.Value + x1 - border);
1786
int ry = (int)(y) - border;
1787
int rw = width + border * 2;
1788
int rh = (int)(editor.LineHeight) + border * 2;
1790
int iw = width, ih = editor.LineHeight;
1791
if (textImage == null) {
1792
using (Gdk.Pixmap pixmap = new Gdk.Pixmap (drawable, iw, ih)) {
1793
using (var bgGc = new Gdk.GC(pixmap)) {
1794
bgGc.RgbFgColor = editor.ColorStyle.SearchTextMainBg;
1795
pixmap.DrawRectangle (bgGc, true, 0, 0, iw, ih);
1796
using (var layout = PangoUtil.CreateLayout (editor)) {
1797
layout.FontDescription = editor.Options.Font;
1798
layout.SetMarkup (editor.Document.SyntaxMode.GetMarkup (editor.Document, editor.Options, editor.ColorStyle, result.Offset, result.Length, true));
1799
pixmap.DrawLayout (bgGc, 0, 0, layout);
1802
textImage = Pixbuf.FromDrawable (pixmap, Colormap.System, 0, 0, 0, 0, iw, ih);
1806
cr.Translate (rx + rw / 2, ry + rh / 2);
1808
Cairo.Color color = Mono.TextEditor.Highlighting.Style.ToCairoColor (editor.ColorStyle.SearchTextBg);
1810
double scale2 = (1 + 1.1 * Percent / 6);
1811
cr.Scale (scale2, scale2 * 1.2);
1813
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, -rw / 2, -rh / 2, (int)(System.Math.Min (10, width ) * editor.Options.Zoom), rw, rh);
1817
double scale = 1 + Percent / 12;
1818
cr.Scale (scale, scale);
1819
double textx = -rw / 2;
1820
double texty = -rh / 2;
1821
cr.TransformPoint (ref textx, ref texty);
1823
double textr = +rw / 2;
1824
double textb = +rh / 2;
1825
cr.TransformPoint (ref textr, ref textb);
1827
cr.Color = new Cairo.Color (0, 0, 0, 0.3);
1828
//because the initial highlight is not rounded, so the rounding scales to make the transition smoother
1829
int rounding = (int)(-rw / 2 + 2 * editor.Options.Zoom * Percent);
1830
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, rounding, (int)(-rh / 2 + 2 * editor.Options.Zoom), (int)(System.Math.Min (10, width ) * editor.Options.Zoom), rw, rh);
1833
cr.Color = Mono.TextEditor.Highlighting.Style.ToCairoColor (editor.ColorStyle.SearchTextMainBg);
1834
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, -rw / 2, -rh / 2, (int)(System.Math.Min (10, width ) * editor.Options.Zoom), rw, rh);
1838
tw = (int) System.Math.Ceiling (iw * scale);
1839
th = (int) System.Math.Ceiling (ih * scale);
1840
tx = rx - (int) System.Math.Ceiling ((double)(tw - iw) / 2) + border;
1841
ty = ry - (int) System.Math.Ceiling ((double)(th - ih) / 2) + border;
1843
using (var scaled = textImage.ScaleSimple (tw, th, InterpType.Bilinear)) {
1844
if (scaled != null) {
1845
using (var gc = new Gdk.GC (drawable)) {
1846
gc.ClipRectangle = new Rectangle (editor.TextViewMargin.XOffset, 0, editor.Allocation.Width - editor.TextViewMargin.XOffset, editor.Allocation.Height);
1847
scaled.RenderToDrawable (drawable, gc, 0, 0, tx, ty, tw, th, RgbDither.None, 0, 0);
1851
} catch (Exception e) {
1852
Console.WriteLine ("got exception in search result animation:" + e);
1856
if (lineLayout.IsUncached)
1857
lineLayout.Dispose ();
1860
public void Dispose ()
1862
if (this.textImage != null) {
1863
this.textImage.Dispose ();
1864
this.textImage = null;
1870
1885
class CaretPulseAnimation : IAnimationDrawer
1872
1887
TextEditor editor;
1891
1906
this.editor = editor;
1894
public void Draw (Drawable drawable)
1909
public void Draw (Cairo.Context cr)
1896
int x = editor.TextViewMargin.caretX;
1897
int y = editor.TextViewMargin.caretY;
1911
double x = editor.TextViewMargin.caretX;
1912
double y = editor.TextViewMargin.caretY;
1898
1913
if (editor.Caret.Mode != CaretMode.Block)
1899
1914
x -= editor.TextViewMargin.charWidth / 2;
1900
using (Cairo.Context cr = Gdk.CairoHelper.Create (drawable)) {
1901
cr.Rectangle (editor.TextViewMargin.XOffset, 0, editor.Allocation.Width - editor.TextViewMargin.XOffset, editor.Allocation.Height);
1915
cr.Rectangle (editor.TextViewMargin.XOffset, 0, editor.Allocation.Width - editor.TextViewMargin.XOffset, editor.Allocation.Height);
1904
double extend = Percent * 5;
1905
int width = (int)(editor.TextViewMargin.charWidth + 2 * extend * editor.Options.Zoom / 2);
1906
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true,
1907
(int)(x - extend * editor.Options.Zoom / 2),
1908
(int)(y - extend * editor.Options.Zoom),
1909
System.Math.Min (editor.TextViewMargin.charWidth / 2, width),
1911
(int)(editor.LineHeight + 2 * extend * editor.Options.Zoom));
1912
Cairo.Color color = Mono.TextEditor.Highlighting.Style.ToCairoColor (editor.ColorStyle.Caret.Color);
1914
cr.LineWidth = editor.Options.Zoom;
1918
double extend = Percent * 5;
1919
double width = editor.TextViewMargin.charWidth + 2 * extend * editor.Options.Zoom / 2;
1920
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true,
1921
x - extend * editor.Options.Zoom / 2,
1922
y - extend * editor.Options.Zoom,
1923
System.Math.Min (editor.TextViewMargin.charWidth / 2, width),
1925
editor.LineHeight + 2 * extend * editor.Options.Zoom);
1926
Cairo.Color color = Mono.TextEditor.Highlighting.Style.ToCairoColor (editor.ColorStyle.Caret.Color);
1928
cr.LineWidth = editor.Options.Zoom;
1957
1971
this.region = region;
1960
public void Draw (Drawable drawable)
1974
public void Draw (Cairo.Context cr)
1962
1976
int x = region.X;
1963
1977
int y = region.Y;
1964
1978
int animationPosition = (int)(Percent * 100);
1966
using (Cairo.Context cr = Gdk.CairoHelper.Create (drawable)) {
1967
cr.Rectangle (editor.TextViewMargin.XOffset, 0, editor.Allocation.Width - editor.TextViewMargin.XOffset, editor.Allocation.Height);
1980
cr.Rectangle (editor.TextViewMargin.XOffset, 0, editor.Allocation.Width - editor.TextViewMargin.XOffset, editor.Allocation.Height);
1970
int width = (int)(region.Width + 2 * animationPosition * editor.Options.Zoom / 2);
1971
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true,
1972
(int)(x - animationPosition * editor.Options.Zoom / 2),
1973
(int)(y - animationPosition * editor.Options.Zoom),
1974
System.Math.Min (editor.TextViewMargin.charWidth / 2, width),
1976
(int)(region.Height + 2 * animationPosition * editor.Options.Zoom));
1977
Cairo.Color color = Mono.TextEditor.Highlighting.Style.ToCairoColor (editor.ColorStyle.Caret.Color);
1979
cr.LineWidth = editor.Options.Zoom;
1983
int width = (int)(region.Width + 2 * animationPosition * editor.Options.Zoom / 2);
1984
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true,
1985
(int)(x - animationPosition * editor.Options.Zoom / 2),
1986
(int)(y - animationPosition * editor.Options.Zoom),
1987
System.Math.Min (editor.TextViewMargin.charWidth / 2, width),
1989
(int)(region.Height + 2 * animationPosition * editor.Options.Zoom));
1990
Cairo.Color color = Mono.TextEditor.Highlighting.Style.ToCairoColor (editor.ColorStyle.Caret.Color);
1992
cr.LineWidth = editor.Options.Zoom;
1986
/* Gdk.Rectangle RangeToRectangle (int offset, int length)
1988
DocumentLocation startLocation = Document.OffsetToLocation (offset);
1989
DocumentLocation endLocation = Document.OffsetToLocation (offset + length);
1991
if (startLocation.Column < 0 || startLocation.Line < 0 || endLocation.Column < 0 || endLocation.Line < 0)
1992
return Gdk.Rectangle.Zero;
1994
return RangeToRectangle (startLocation, endLocation);
1997
1999
Gdk.Rectangle RangeToRectangle (DocumentLocation start, DocumentLocation end)
1999
2001
if (start.Column < 0 || start.Line < 0 || end.Column < 0 || end.Line < 0)
2000
2002
return Gdk.Rectangle.Zero;
2002
Gdk.Point startPt = this.textViewMargin.LocationToDisplayCoordinates (start);
2003
Gdk.Point endPt = this.textViewMargin.LocationToDisplayCoordinates (end);
2004
var startPt = this.LocationToPoint (start);
2005
var endPt = this.LocationToPoint (end);
2004
2006
int width = endPt.X - startPt.X;
2006
2008
if (startPt.Y != endPt.Y || startPt.X < 0 || startPt.Y < 0 || width < 0)
2007
2009
return Gdk.Rectangle.Zero;
2009
return new Gdk.Rectangle (startPt.X, startPt.Y, width, this.textViewMargin.LineHeight);
2011
return new Gdk.Rectangle (startPt.X, startPt.Y, width, (int)this.textViewMargin.LineHeight);
2012
/* void AnimationTimer (object sender, EventArgs args)
2014
if (animation != null) {
2015
animation.LifeTime--;
2016
if (animation.LifeTime < 0)
2018
Application.Invoke (delegate {
2022
animationTimer.Stop ();
2027
2015
/// Initiate a pulse at the specified document location
2056
2043
StartAnimation (new TextEditor.CaretPulseAnimation (this));
2059
Animation searchResultAnimation;
2046
SearchHighlightPopupWindow popupWindow = null;
2048
public void StopSearchResultAnimation ()
2050
if (popupWindow == null)
2052
popupWindow.StopPlaying ();
2060
2055
public void AnimateSearchResult (SearchResult result)
2057
if (!IsComposited || !Options.EnableAnimations)
2062
2059
TextViewMargin.MainSearchResult = result;
2063
2060
if (result != null) {
2064
if (searchResultAnimation != null)
2065
RemoveAnimation (searchResultAnimation);
2066
var anim = new TextEditor.HighlightSearchResultAnimation (this, result);
2067
searchResultAnimation = StartAnimation (anim, 180, Easing.Sine);
2061
if (popupWindow != null) {
2062
popupWindow.StopPlaying ();
2063
popupWindow.Destroy ();
2065
popupWindow = new SearchHighlightPopupWindow (this);
2066
popupWindow.Result = result;
2067
popupWindow.Popup ();
2068
popupWindow.Destroyed += delegate {
2074
class SearchHighlightPopupWindow : BounceFadePopupWindow
2076
public SearchResult Result {
2081
public SearchHighlightPopupWindow (TextEditor editor) : base (editor)
2085
public override void Popup ()
2087
ExpandWidth = (uint)Editor.LineHeight;
2088
ExpandHeight = (uint)Editor.LineHeight / 2;
2089
BounceEasing = Easing.Sine;
2094
protected override void OnAnimationCompleted ()
2096
Move (Screen.Width, Screen.Height);
2097
base.OnAnimationCompleted ();
2102
internal override void StopPlaying ()
2104
Move (Screen.Width, Screen.Height);
2105
base.StopPlaying ();
2108
protected override void OnDestroyed ()
2110
base.OnDestroyed ();
2115
protected override Rectangle CalculateInitialBounds ()
2117
LineSegment line = Editor.Document.GetLineByOffset (Result.Offset);
2118
int lineNr = Editor.Document.OffsetToLineNumber (Result.Offset);
2119
SyntaxMode mode = Editor.Document.SyntaxMode != null && Editor.Options.EnableSyntaxHighlighting ? Editor.Document.SyntaxMode : SyntaxMode.Default;
2120
int logicalRulerColumn = line.GetLogicalColumn(Editor.GetTextEditorData(), Editor.Options.RulerColumn);
2121
var lineLayout = Editor.textViewMargin.CreateLinePartLayout(mode, line, logicalRulerColumn, line.Offset, line.EditableLength, -1, -1);
2122
if (lineLayout == null)
2123
return Gdk.Rectangle.Zero;
2126
int index = Result.Offset - line.Offset - 1;
2128
lineLayout.Layout.IndexToLineX (index, true, out l, out x1);
2133
index = Result.Offset - line.Offset - 1 + Result.Length;
2135
lineLayout.Layout.IndexToLineX (index, true, out l, out x2);
2138
Console.WriteLine ("Invalid end index :" + index);
2141
double y = Editor.LineToY (lineNr) - Editor.VAdjustment.Value ;
2142
double w = (x2 - x1) / Pango.Scale.PangoScale;
2143
double spaceX = System.Math.Ceiling (w / 3);
2144
double spaceY = Editor.LineHeight;
2148
return new Gdk.Rectangle ((int)(x1 / Pango.Scale.PangoScale + Editor.TextViewMargin.XOffset + Editor.TextViewMargin.TextStartPosition - Editor.HAdjustment.Value - spaceX),
2150
(int)(w + spaceX * 2),
2151
(int)(Editor.LineHeight + spaceY * 2));
2154
Pango.Layout layout = null;
2155
int layoutWidth, layoutHeight;
2157
protected override bool OnExposeEvent (Gdk.EventExpose evnt)
2160
using (var cr = Gdk.CairoHelper.Create (evnt.Window)) {
2161
cr.SetSourceRGBA (1, 1, 1, 0);
2162
cr.Operator = Cairo.Operator.Source;
2165
using (var cr = Gdk.CairoHelper.Create (evnt.Window)) {
2166
cr.Translate (width / 2, height / 2);
2167
cr.Scale (1 + scale / 4, 1 + scale / 4);
2168
if (layout == null) {
2169
layout = cr.CreateLayout ();
2170
layout.FontDescription = Editor.Options.Font;
2171
string markup = Editor.Document.SyntaxMode.GetMarkup (Editor.Document, Editor.Options, Editor.ColorStyle, Result.Offset, Result.Length, true);
2172
layout.SetMarkup (markup);
2173
layout.GetPixelSize (out layoutWidth, out layoutHeight);
2176
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, -layoutWidth / 2 - 2 + 2, -Editor.LineHeight / 2 + 2, System.Math.Min (10, layoutWidth), layoutWidth + 4, Editor.LineHeight);
2177
var color = TextViewMargin.DimColor (Editor.ColorStyle.SearchTextMainBg, 0.3);
2178
color.A = 0.5 * opacity;
2182
FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, -layoutWidth / 2 -2, -Editor.LineHeight / 2, System.Math.Min (10, layoutWidth), layoutWidth + 4, Editor.LineHeight);
2183
using (var gradient = new Cairo.LinearGradient (0, -Editor.LineHeight / 2, 0, Editor.LineHeight / 2)) {
2184
color = TextViewMargin.DimColor (Editor.ColorStyle.SearchTextMainBg, 1.1);
2186
gradient.AddColorStop (0, color);
2187
color = TextViewMargin.DimColor (Editor.ColorStyle.SearchTextMainBg, 0.9);
2189
gradient.AddColorStop (1, color);
2190
cr.Pattern = gradient;
2193
cr.Color = new Cairo.Color (0, 0, 0);
2194
cr.Translate (-layoutWidth / 2, -layoutHeight / 2);
2195
cr.ShowLayout (layout);
2198
} catch (Exception e) {
2199
Console.WriteLine ("Exception in animation:" + e);
2071
2205
public SearchResult FindPrevious (bool setSelection)
2073
2207
SearchResult result = textEditorData.FindPrevious (setSelection);
2298
public override ContainerChild this [Widget w] {
2300
foreach (EditorContainerChild info in containerChildren.ToArray ()) {
2301
if (info.Child == w || (info.Child is AnimatedWidget && ((AnimatedWidget)info.Child).Widget == w))
2308
public class EditorContainerChild : Container.ContainerChild
2310
public int X { get; set; }
2311
public int Y { get; set; }
2312
public bool FixedPosition { get; set; }
2313
public EditorContainerChild (Container parent, Widget child) : base (parent, child)
2318
public override GLib.GType ChildType ()
2320
return Gtk.Widget.GType;
2323
List<EditorContainerChild> containerChildren = new List<EditorContainerChild> ();
2325
public void AddTopLevelWidget (Gtk.Widget w, int x, int y)
2328
EditorContainerChild info = new EditorContainerChild (this, w);
2331
containerChildren.Add (info);
2334
public void MoveTopLevelWidget (Gtk.Widget w, int x, int y)
2336
foreach (EditorContainerChild info in containerChildren.ToArray ()) {
2337
if (info.Child == w || (info.Child is AnimatedWidget && ((AnimatedWidget)info.Child).Widget == w)) {
2346
public void MoveTopLevelWidgetX (Gtk.Widget w, int x)
2348
foreach (EditorContainerChild info in containerChildren.ToArray ()) {
2349
if (info.Child == w || (info.Child is AnimatedWidget && ((AnimatedWidget)info.Child).Widget == w)) {
2358
public void MoveToTop (Gtk.Widget w)
2360
EditorContainerChild editorContainerChild = containerChildren.FirstOrDefault (c => c.Child == w);
2361
if (editorContainerChild == null)
2362
throw new Exception ("child " + w + " not found.");
2363
List<EditorContainerChild> newChilds = new List<EditorContainerChild> (containerChildren.Where (child => child != editorContainerChild));
2364
newChilds.Add (editorContainerChild);
2365
this.containerChildren = newChilds;
2366
w.GdkWindow.Raise ();
2369
protected override void OnAdded (Widget widget)
2371
AddTopLevelWidget (widget, 0, 0);
2374
protected override void OnRemoved (Widget widget)
2376
foreach (EditorContainerChild info in containerChildren.ToArray ()) {
2377
if (info.Child == widget) {
2379
containerChildren.Remove (info);
2385
protected override void OnSizeRequested (ref Gtk.Requisition requisition)
2387
base.OnSizeRequested (ref requisition);
2389
// Ignore the size of top levels. They are supposed to fit the available space
2390
foreach (EditorContainerChild tchild in containerChildren.ToArray ())
2391
tchild.Child.SizeRequest ();
2395
protected override void ForAll (bool include_internals, Gtk.Callback callback)
2397
foreach (EditorContainerChild child in containerChildren.ToArray ()) {
2398
callback (child.Child);
2442
#region Coordinate transformation
2443
public DocumentLocation PointToLocation (double xp, double yp)
2445
return TextViewMargin.PointToLocation (xp, yp);
2448
public DocumentLocation PointToLocation (Cairo.Point p)
2450
return TextViewMargin.PointToLocation (p);
2453
public DocumentLocation PointToLocation (Cairo.PointD p)
2455
return TextViewMargin.PointToLocation (p);
2458
public Cairo.Point LocationToPoint (DocumentLocation loc)
2460
return TextViewMargin.LocationToPoint (loc);
2463
public Cairo.Point LocationToPoint (int line, int column)
2465
return TextViewMargin.LocationToPoint (line, column);
2468
public Cairo.Point LocationToPoint (int line, int column, bool useAbsoluteCoordinates)
2470
return TextViewMargin.LocationToPoint (line, column, useAbsoluteCoordinates);
2473
public Cairo.Point LocationToPoint (DocumentLocation loc, bool useAbsoluteCoordinates)
2475
return TextViewMargin.LocationToPoint (loc, useAbsoluteCoordinates);
2478
public double ColumnToX (LineSegment line, int column)
2480
return TextViewMargin.ColumnToX (line, column);
2484
/// Calculates the line number at line start (in one visual line could be several logical lines be displayed).
2486
public int YToLine (double yPos)
2488
return TextViewMargin.YToLine (yPos);
2491
public double LineToY (int logicalLine)
2493
return TextViewMargin.LineToY (logicalLine);
2496
public double GetLineHeight (LineSegment line)
2498
return TextViewMargin.GetLineHeight (line);
2501
public double GetLineHeight (int logicalLineNumber)
2503
return TextViewMargin.GetLineHeight (logicalLineNumber);
2403
2507
#region Animation
2404
2508
Stage<Animation> animationStage = new Stage<Animation> ();
2530
2634
requestResetCaretBlink = true;
2533
public int CalculateLineNumber (int yPos)
2536
foreach (LineSegment extendedTextMarkerLine in Document.LinesWithExtendingTextMarkers) {
2537
int lineNumber = Document.OffsetToLineNumber (extendedTextMarkerLine.Offset);
2538
int y = LineToVisualY (lineNumber);
2540
int curLineHeight = GetLineHeight (extendedTextMarkerLine);
2541
delta += curLineHeight - LineHeight;
2542
if (y <= yPos && yPos < y + curLineHeight)
2546
return Document.VisualToLogicalLine ((yPos - delta) / LineHeight);
2547
/* LineSegment logicalLineSegment = Document.GetLine (logicalLine);
2548
foreach (LineSegment extendedTextMarkerLine in Document.LinesWithExtendingTextMarkers) {
2549
if (logicalLineSegment != null && extendedTextMarkerLine.Offset > logicalLineSegment.Offset)
2551
int curLineHeight = GetLineHeight (extendedTextMarkerLine) - LineHeight;
2553
if (curLineHeight != 0) {
2554
logicalLine -= curLineHeight / LineHeight;
2555
logicalLineSegment = Document.GetLine (logicalLine - 1);
2559
return logicalLine;*/
2562
public int LineToVisualY (int logicalLine)
2565
LineSegment logicalLineSegment = Document.GetLine (logicalLine);
2566
foreach (LineSegment extendedTextMarkerLine in Document.LinesWithExtendingTextMarkers) {
2567
if (extendedTextMarkerLine == null)
2569
if (logicalLineSegment != null && extendedTextMarkerLine.Offset >= logicalLineSegment.Offset)
2571
delta += GetLineHeight (extendedTextMarkerLine) - LineHeight;
2574
int visualLine = Document.LogicalToVisualLine (logicalLine);
2575
return visualLine * LineHeight + delta;
2578
public int GetLineHeight (LineSegment line)
2580
if (line == null || line.MarkerCount == 0)
2582
foreach (var marker in line.Markers) {
2583
IExtendingTextMarker extendingTextMarker = marker as IExtendingTextMarker;
2584
if (extendingTextMarker == null)
2586
return extendingTextMarker.GetLineHeight (this);
2591
public int GetLineHeight (int logicalLineNumber)
2593
return GetLineHeight (Document.GetLine (logicalLineNumber));
2596
2637
void UpdateLinesOnTextMarkerHeightChange (object sender, LineEventArgs e)
2598
2639
if (!e.Line.Markers.Any (m => m is IExtendingTextMarker))
2600
int currentHeight = GetLineHeight (e.Line);
2641
double currentHeight = GetLineHeight (e.Line);
2602
2643
if (!lineHeights.TryGetValue (e.Line.Offset, out h))
2603
2644
h = TextViewMargin.LineHeight;
2604
2645
if (h != currentHeight)
2605
2646
textEditorData.Document.CommitLineToEndUpdate (textEditorData.Document.OffsetToLineNumber (e.Line.Offset));
2606
2647
lineHeights[e.Line.Offset] = currentHeight;
2654
bool highlightCaretLine;
2656
public SetCaret (TextEditor view, int line, int column, bool highlightCaretLine)
2660
this.column = column;
2661
this.highlightCaretLine = highlightCaretLine;
2664
public void Run (object sender, EventArgs e)
2666
if (view.isDisposed)
2668
line = System.Math.Min (line, view.Document.LineCount);
2669
view.Caret.AutoScrollToCaret = false;
2671
view.Caret.Location = new DocumentLocation (line, column);
2673
view.CenterToCaret ();
2674
if (view.TextViewMargin.XOffset == 0)
2675
view.HAdjustment.Value = 0;
2676
view.SizeAllocated -= Run;
2678
view.Caret.AutoScrollToCaret = true;
2679
if (highlightCaretLine) {
2680
view.TextViewMargin.HighlightCaretLine = true;
2681
view.StartCaretPulseAnimation ();
2687
public void SetCaretTo (int line, int column)
2689
SetCaretTo (line, column, true);
2692
public void SetCaretTo (int line, int column, bool highlight)
2694
if (line < DocumentLocation.MinLine)
2695
throw new ArgumentException ("line < MinLine");
2696
if (column < DocumentLocation.MinColumn)
2697
throw new ArgumentException ("column < MinColumn");
2700
SetCaret setCaret = new SetCaret (this, line, column, highlight);
2701
SizeAllocated += setCaret.Run;
2703
new SetCaret (this, line, column, highlight).Run (null, null);
2610
2708
public interface ITextEditorDataProvider
2612
2710
TextEditorData GetTextEditorData ();
2714
public sealed class PaintEventArgs : EventArgs
2716
public Cairo.Context Context {
2721
public Cairo.Rectangle Area {
2726
public PaintEventArgs (Cairo.Context context, Cairo.Rectangle area)
2728
this.Context = context;