~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to src/core/Mono.Texteditor/Mono.TextEditor/Gui/TextViewMargin.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
27
//
28
 
 
29
28
using System;
30
29
using System.Linq;
31
30
using System.Collections.Generic;
44
43
        {
45
44
                readonly TextEditor textEditor;
46
45
                Pango.TabArray tabArray;
47
 
                
48
 
                Pango.Layout markerLayout;
49
 
                
50
 
                Pango.Layout tabMarkerLayout, spaceMarkerLayout, invalidLineLayout;
51
 
                Pango.Layout macEolLayout, unixEolLayout, windowEolLayout, eofEolLayout;
52
 
                
 
46
                Pango.Layout markerLayout, defaultLayout;
 
47
                Pango.Layout macEolLayout, unixEolLayout, windowsEolLayout, eofEolLayout;
53
48
                internal double charWidth;
54
 
                
55
49
                int highlightBracketOffset = -1;
56
50
                
57
 
                
58
51
                double LineHeight {
59
52
                        get {
60
53
                                return textEditor.LineHeight;
66
59
                }
67
60
 
68
61
                double xOffset;
 
62
 
69
63
                public override double XOffset {
70
64
                        get {
71
65
                                return xOffset;
87
81
                /// the same as the option, but is unset when the caret moves.
88
82
                /// </summary>
89
83
                bool highlightCaretLine;
 
84
 
90
85
                public bool HighlightCaretLine {
91
86
                        get {
92
87
                                return highlightCaretLine;
137
132
                        textEditor.Document.LineChanged += TextEditorDocumentLineChanged;
138
133
                        textEditor.GetTextEditorData ().SearchChanged += HandleSearchChanged;
139
134
                        markerLayout = PangoUtil.CreateLayout (textEditor);
 
135
                        defaultLayout = PangoUtil.CreateLayout (textEditor);
140
136
 
141
137
                        textEditor.Document.EndUndo += HandleEndUndo;
142
138
                        textEditor.SelectionChanged += UpdateBracketHighlighting;
143
139
                        textEditor.Document.Undone += HandleUndone; 
144
140
                        textEditor.Document.Redone += HandleUndone;
145
 
                        
 
141
                        textEditor.TextArea.FocusInEvent += HandleFocusInEvent;
 
142
                        textEditor.TextArea.FocusOutEvent += HandleFocusOutEvent;
146
143
                        Caret.PositionChanged += UpdateBracketHighlighting;
147
144
                        textEditor.VScroll += HandleVAdjustmentValueChanged;
148
145
                }
149
146
 
 
147
                void HandleFocusInEvent (object o, FocusInEventArgs args)
 
148
                {
 
149
                        selectionColor = ColorStyle.SelectedText;
 
150
                        currentLineColor = ColorStyle.LineMarker;
 
151
                }
 
152
 
 
153
                void HandleFocusOutEvent (object o, FocusOutEventArgs args)
 
154
                {
 
155
                        selectionColor = ColorStyle.SelectedInactiveText;
 
156
                        currentLineColor = ColorStyle.LineMarkerInactive;
 
157
                }
 
158
 
150
159
                void HandleUndone (object sender, EventArgs e)
151
160
                {
152
161
                        UpdateBracketHighlighting (this, EventArgs.Empty);
179
188
                }
180
189
 
181
190
                List<DocumentLine> linesToRemove = new List<DocumentLine> ();
 
191
 
182
192
                void HandleVAdjustmentValueChanged (object sender, EventArgs e)
183
193
                {
184
194
                        int startLine = (int)(textEditor.GetTextEditorData ().VAdjustment.Value / LineHeight);
200
210
                        selectedRegions.Clear ();
201
211
                }
202
212
 
203
 
                public class SearchWorkerArguments {
 
213
                public class SearchWorkerArguments
 
214
                {
204
215
                        public int FirstLine { get; set; }
 
216
 
205
217
                        public int LastLine { get; set; }
 
218
 
206
219
                        public List<TextSegment> OldRegions { get; set; }
 
220
 
207
221
                        public ISearchEngine Engine { get; set; }
 
222
 
 
223
                        public string Text { get; set; }
208
224
                }
209
225
 
210
226
                public void RefreshSearchMarker ()
215
231
                                        FirstLine = YToLine (textEditor.VAdjustment.Value),
216
232
                                        LastLine = YToLine (textEditor.Allocation.Height + textEditor.VAdjustment.Value),
217
233
                                        OldRegions = selectedRegions,
218
 
                                        Engine = textEditor.GetTextEditorData ().SearchEngine.Clone ()
 
234
                                        Engine = textEditor.GetTextEditorData ().SearchEngine.Clone (),
 
235
                                        Text = textEditor.Text
219
236
                                };
220
237
 
221
238
                                if (string.IsNullOrEmpty (textEditor.SearchPattern)) {
244
261
                                        return;
245
262
                                SearchResult result = null;
246
263
                                try {
247
 
                                        result = args.Engine.SearchForward (worker, offset);
 
264
                                        result = args.Engine.SearchForward (worker, args, offset);
248
265
                                } catch (Exception ex) {
249
266
                                        Console.WriteLine ("Got exception while search forward:" + ex);
250
267
                                        break;
262
279
                                for (int i = 0; i < newRegions.Count; i++) {
263
280
                                        if (worker.CancellationPending)
264
281
                                                return;
265
 
                                        if (args.OldRegions[i].Offset != newRegions[i].Offset || args.OldRegions[i].Length != newRegions[i].Length) {
266
 
                                                int lineNumber = Document.OffsetToLineNumber (args.OldRegions[i].Offset);
 
282
                                        if (args.OldRegions [i].Offset != newRegions [i].Offset || args.OldRegions [i].Length != newRegions [i].Length) {
 
283
                                                int lineNumber = Document.OffsetToLineNumber (args.OldRegions [i].Offset);
267
284
                                                if (lineNumber > args.LastLine)
268
285
                                                        break;
269
286
                                                if (lineNumber >= args.FirstLine)
309
326
                        RefreshSearchMarker ();
310
327
                }
311
328
 
312
 
 
313
 
 
314
329
                protected virtual void OnSearchRegionsUpdated (EventArgs e)
315
330
                {
316
331
                        EventHandler handler = this.SearchRegionsUpdated;
320
335
 
321
336
                public event EventHandler SearchRegionsUpdated;
322
337
 
323
 
 
324
338
                void DisposeSearchPatternWorker ()
325
339
                {
326
340
                        if (searchPatternWorker == null)
332
346
                        searchPatternWorker = null;
333
347
                }
334
348
 
335
 
 
336
349
                System.ComponentModel.BackgroundWorker searchPatternWorker;
337
350
                System.ComponentModel.BackgroundWorker highlightBracketWorker;
338
351
                Gdk.Cursor xtermCursor = new Gdk.Cursor (Gdk.CursorType.Xterm);
415
428
                        highlightBracketWorker = null;
416
429
                }
417
430
 
 
431
                Pango.Rectangle unixEolLayoutRect;
 
432
                Pango.Rectangle macEolLayoutRect;
 
433
                Pango.Rectangle windowsEolLayoutRect;
 
434
                Pango.Rectangle eofEolLayoutRect;
 
435
 
418
436
                protected internal override void OptionsChanged ()
419
437
                {
420
438
                        DisposeGCs ();
421
439
 
422
 
                        markerLayout.FontDescription = textEditor.Options.Font;
 
440
                        var markerFont = textEditor.Options.Font.Copy ();
 
441
                        markerFont.Size = markerFont.Size * 8 / 10;
 
442
                        markerLayout.FontDescription = markerFont;
423
443
                        markerLayout.FontDescription.Weight = Pango.Weight.Normal;
424
 
                        markerLayout.FontDescription.Style = Pango.Style.Italic;
425
 
                        markerLayout.SetText ("_");
426
 
                        int w, h;
427
 
                        markerLayout.GetSize (out w, out h);
428
 
                        
429
 
                        this.charWidth = w / Pango.Scale.PangoScale;
 
444
                        markerLayout.FontDescription.Style = Pango.Style.Normal;
 
445
 
430
446
                        if (textEditor.preeditString != null && textEditor.preeditAttrs != null) {
431
447
                                using (var preeditLayout = PangoUtil.CreateLayout (textEditor)) {
432
448
                                        preeditLayout.SetText (textEditor.preeditString);
433
449
                                        preeditLayout.Attributes = textEditor.preeditAttrs;
434
 
                                        preeditLayout.GetSize (out w, out h);
435
450
                                }
436
451
                        }
437
 
                        this.textEditor.GetTextEditorData ().LineHeight = System.Math.Ceiling (h / Pango.Scale.PangoScale);
438
 
                        
439
 
                        markerLayout.FontDescription.Weight = Pango.Weight.Normal;
440
452
 
441
 
                        Pango.Font font = textEditor.PangoContext.LoadFont (markerLayout.FontDescription);
442
 
                        if (font != null) {
443
 
                                Pango.FontMetrics metrics = font.GetMetrics (null);
 
453
                        defaultLayout.FontDescription = textEditor.Options.Font;
 
454
                        using (var metrics = textEditor.PangoContext.GetMetrics (textEditor.Options.Font, textEditor.PangoContext.Language)) {
 
455
                                this.textEditor.GetTextEditorData ().LineHeight = System.Math.Ceiling (0.5 + (metrics.Ascent + metrics.Descent) / Pango.Scale.PangoScale);
444
456
                                this.charWidth = metrics.ApproximateCharWidth / Pango.Scale.PangoScale;
 
457
                        }
445
458
 
446
 
                                font.Dispose ();
 
459
                        // Gutter font may be bigger
 
460
                        using (var metrics = textEditor.PangoContext.GetMetrics (textEditor.Options.GutterFont, textEditor.PangoContext.Language)) {
 
461
                                this.textEditor.GetTextEditorData ().LineHeight = System.Math.Max (this.textEditor.GetTextEditorData ().LineHeight, System.Math.Ceiling (0.5 + (metrics.Ascent + metrics.Descent) / Pango.Scale.PangoScale));
447
462
                        }
448
463
 
449
464
                        textEditor.LineHeight = System.Math.Max (1, LineHeight);
450
465
 
451
 
                        if (textEditor.Options.ShowInvalidLines && invalidLineLayout == null) {
452
 
                                invalidLineLayout = PangoUtil.CreateLayout (textEditor);
453
 
                                invalidLineLayout.SetText ("~");
454
 
                        }
455
 
                        
456
 
                        if (invalidLineLayout != null)
457
 
                                invalidLineLayout.FontDescription = textEditor.Options.Font;
458
 
                        
459
 
                        if (textEditor.Options.ShowEolMarkers && unixEolLayout == null) {
 
466
                        if (unixEolLayout == null) {
460
467
                                unixEolLayout = PangoUtil.CreateLayout (textEditor);
461
 
                                unixEolLayout.SetText ("\\n");
462
468
                                macEolLayout = PangoUtil.CreateLayout (textEditor);
463
 
                                macEolLayout.SetText ("\\r");
464
 
                                windowEolLayout = PangoUtil.CreateLayout (textEditor);
465
 
                                windowEolLayout.SetText ("\\r\\n");
 
469
                                windowsEolLayout = PangoUtil.CreateLayout (textEditor);
466
470
                                eofEolLayout = PangoUtil.CreateLayout (textEditor);
467
 
                                eofEolLayout.SetText ("<EOF>");
468
 
                        }
469
 
                        
470
 
                        if (unixEolLayout != null)
471
 
                                unixEolLayout.FontDescription = macEolLayout.FontDescription = windowEolLayout.FontDescription = eofEolLayout.FontDescription = textEditor.Options.Font;
472
 
                        
473
 
                        if (textEditor.Options.ShowTabs && tabMarkerLayout == null) {
474
 
                                tabMarkerLayout = PangoUtil.CreateLayout (textEditor);
475
 
                                tabMarkerLayout.SetText ("Ā»");
476
 
                        }
477
 
                        if (tabMarkerLayout != null)
478
 
                                tabMarkerLayout.FontDescription = textEditor.Options.Font;
479
 
 
480
 
                        if (textEditor.Options.ShowSpaces && spaceMarkerLayout == null) {
481
 
                                spaceMarkerLayout = PangoUtil.CreateLayout (textEditor);
482
 
                                spaceMarkerLayout.SetText ("Ā·");
483
 
                        }
484
 
                        if (spaceMarkerLayout != null)
485
 
                                spaceMarkerLayout.FontDescription = textEditor.Options.Font;
486
 
                        
487
 
                        DecorateLineFg -= DecorateTabs;
488
 
                        DecorateLineFg -= DecorateSpaces;
489
 
                        DecorateLineFg -= DecorateTabsAndSpaces;
490
 
                        
491
 
                        if (textEditor.Options.ShowTabs && textEditor.Options.ShowSpaces) {
492
 
                                DecorateLineFg += DecorateTabsAndSpaces;
493
 
                        } else if (textEditor.Options.ShowTabs) {
494
 
                                DecorateLineFg += DecorateTabs;
495
 
                        } else if (textEditor.Options.ShowSpaces) {
496
 
                                DecorateLineFg += DecorateSpaces;
497
 
                        } 
498
 
                        
 
471
                        }
 
472
 
 
473
                        var font = textEditor.Options.Font.Copy ();
 
474
                        font.Size = font.Size * 3 / 4;
 
475
                        unixEolLayout.FontDescription = macEolLayout.FontDescription = windowsEolLayout.FontDescription = eofEolLayout.FontDescription = font;
 
476
 
 
477
                        unixEolLayout.SetText ("\\n");
 
478
                        Pango.Rectangle logRect;
 
479
                        unixEolLayout.GetPixelExtents (out logRect, out unixEolLayoutRect);
 
480
 
 
481
                        macEolLayout.SetText ("\\r");
 
482
                        macEolLayout.GetPixelExtents (out logRect, out macEolLayoutRect);
 
483
 
 
484
                        windowsEolLayout.SetText ("\\r\\n");
 
485
                        windowsEolLayout.GetPixelExtents (out logRect, out windowsEolLayoutRect);
 
486
 
 
487
                        eofEolLayout.SetText ("<EOF>");
 
488
                        eofEolLayout.GetPixelExtents (out logRect, out eofEolLayoutRect);
 
489
 
499
490
                        DecorateLineBg -= DecorateMatchingBracket;
500
491
                        if (textEditor.Options.HighlightMatchingBracket && !Document.ReadOnly)
501
492
                                DecorateLineBg += DecorateMatchingBracket;
508
499
                        var tabWidthLayout = PangoUtil.CreateLayout (textEditor, (new string (' ', textEditor.Options.TabSize)));
509
500
                        tabWidthLayout.Alignment = Pango.Alignment.Left;
510
501
                        tabWidthLayout.FontDescription = textEditor.Options.Font;
511
 
                        int tabWidth;
 
502
                        int tabWidth, h;
512
503
                        tabWidthLayout.GetSize (out tabWidth, out h);
513
504
                        tabWidthLayout.Dispose ();
514
505
                        tabArray = new Pango.TabArray (1, false);
516
507
 
517
508
                        DisposeLayoutDict ();
518
509
                        chunkDict.Clear ();
 
510
                        caretX = caretY = -LineHeight;
519
511
                }
520
512
 
521
513
                void DisposeGCs ()
522
514
                {
523
515
                        ShowTooltip (TextSegment.Invalid, Gdk.Rectangle.Zero);
524
516
                }
525
 
                
526
517
 
527
518
                public override void Dispose ()
528
519
                {
538
529
                        textEditor.Document.Redone -= HandleUndone;
539
530
                        
540
531
                        textEditor.Document.EndUndo -= UpdateBracketHighlighting;
 
532
                        textEditor.TextArea.FocusInEvent -= HandleFocusInEvent;
 
533
                        textEditor.TextArea.FocusOutEvent -= HandleFocusOutEvent;
541
534
                        Caret.PositionChanged -= UpdateBracketHighlighting;
542
535
 
543
536
                        textEditor.GetTextEditorData ().SearchChanged -= HandleSearchChanged;
548
541
                        DisposeGCs ();
549
542
                        if (markerLayout != null)
550
543
                                markerLayout.Dispose ();
551
 
                        if (tabMarkerLayout != null)
552
 
                                tabMarkerLayout.Dispose ();
553
 
                        if (spaceMarkerLayout != null)
554
 
                                spaceMarkerLayout.Dispose ();
555
 
                        if (invalidLineLayout != null)
556
 
                                invalidLineLayout.Dispose ();
 
544
 
 
545
                        if (defaultLayout!= null) 
 
546
                                defaultLayout.Dispose ();
557
547
                        if (unixEolLayout != null) {
558
548
                                macEolLayout.Dispose ();
559
549
                                unixEolLayout.Dispose ();
560
 
                                windowEolLayout.Dispose ();
 
550
                                windowsEolLayout.Dispose ();
561
551
                                eofEolLayout.Dispose ();
562
552
                        }
563
553
                        
568
558
                }
569
559
 
570
560
                #region Caret blinking
571
 
                bool caretBlink = true;
572
 
                uint blinkTimeout = 0;
573
 
                
 
561
                internal bool caretBlink = true;
 
562
                uint blinkTimeout = 0, startBlinkTimeout = 0;
 
563
 
574
564
                // constants taken from gtk.
575
565
                const int cursorOnMultiplier = 2;
576
566
                const int cursorOffMultiplier = 1;
577
567
                const int cursorDivider = 3;
578
568
                
579
 
                public void ResetCaretBlink ()
 
569
                public void ResetCaretBlink (uint delay = 0)
580
570
                {
581
571
                        StopCaretThread ();
582
572
                        blinkTimeout = GLib.Timeout.Add ((uint)(Gtk.Settings.Default.CursorBlinkTime * cursorOnMultiplier / cursorDivider), UpdateCaret);
585
575
 
586
576
                internal void StopCaretThread ()
587
577
                {
 
578
                        if (startBlinkTimeout != 0) {
 
579
                                GLib.Source.Remove (startBlinkTimeout);
 
580
                                startBlinkTimeout = 0;
 
581
                        }
 
582
 
588
583
                        if (blinkTimeout == 0)
589
584
                                return;
590
585
                        GLib.Source.Remove (blinkTimeout);
595
590
                bool UpdateCaret ()
596
591
                {
597
592
                        caretBlink = !caretBlink;
598
 
                        //                      int multiplier = caretBlink ? cursorOnMultiplier : cursorOffMultiplier;
599
 
                        if (caretBlink) {
600
 
                                if (Caret.IsVisible)
601
 
                                        DrawCaret (textEditor.GdkWindow, textEditor.Allocation);
602
 
                        } else {
603
 
                                textEditor.QueueDrawArea (caretRectangle.X,
604
 
                                                          (int)(caretRectangle.Y + (textEditor.VAdjustment.Value - caretVAdjustmentValue)),
605
 
                                                          caretRectangle.Width,
606
 
                                                          caretRectangle.Height);
607
 
                        }
 
593
                        textEditor.TextArea.QueueDrawArea (caretRectangle.X - (int)textEditor.Options.Zoom,
 
594
                                                  (int)(caretRectangle.Y + (textEditor.VAdjustment.Value - caretVAdjustmentValue)),
 
595
                                                  caretRectangle.Width + 2 * (int)textEditor.Options.Zoom,
 
596
                                                  caretRectangle.Height);
 
597
                        OnCaretBlink (EventArgs.Empty);
608
598
                        return true;
609
599
                }
 
600
 
 
601
                internal event EventHandler CaretBlink;
 
602
                void OnCaretBlink (EventArgs e)
 
603
                {
 
604
                        var handler = CaretBlink;
 
605
                        if (handler != null)
 
606
                                handler (this, e);
 
607
                }
610
608
                #endregion
611
609
                
612
610
                internal double caretX;
613
611
                internal double caretY;
614
612
 
 
613
                public Cairo.PointD CaretVisualLocation {
 
614
                        get {
 
615
                                return new Cairo.PointD (caretX, caretY);
 
616
                        }
 
617
                }
 
618
 
615
619
                void SetVisibleCaretPosition (double x, double y)
616
620
                {
617
621
                        if (x == caretX && y == caretY)
630
634
                public static Gdk.Rectangle EmptyRectangle = new Gdk.Rectangle (0, 0, 0, 0);
631
635
                Gdk.Rectangle caretRectangle;
632
636
                double caretVAdjustmentValue;
 
637
 
633
638
                char GetCaretChar ()
634
639
                {
635
640
                        var offset = Caret.Offset;
637
642
                        if (offset >= 0 && offset < Document.TextLength) {
638
643
                                caretChar = Document.GetCharAt (offset);
639
644
                        } else {
640
 
                                if (textEditor.Options.ShowEolMarkers) {
641
 
                                        // <EOF>
642
 
                                        return '<';
643
 
                                }
644
645
                                caretChar = '\0';
645
646
                        }
646
647
 
647
648
                        switch (caretChar) {
648
649
                        case ' ':
649
 
                                if (textEditor.Options.ShowSpaces)
650
 
                                        return 'Ā·';
651
650
                                break;
652
651
                        case '\t':
653
 
                                if (textEditor.Options.ShowTabs)
654
 
                                        return 'Ā»';
655
652
                                break;
656
653
                        case '\n':
657
654
                        case '\r':
658
 
                                if (textEditor.Options.ShowEolMarkers)
659
 
                                        return '\\';
660
655
                                break;
661
656
                        }
662
657
                        return caretChar;
669
664
                        if (win == null || Settings.Default.CursorBlink && !Caret.IsVisible || !caretBlink)
670
665
                                return;
671
666
                        using (Cairo.Context cr = Gdk.CairoHelper.Create (win)) {
672
 
                                cr.LineWidth = textEditor.Options.Zoom;
 
667
                                cr.Rectangle (XOffset, 0, textEditor.Allocation.Width - XOffset, textEditor.Allocation.Height);
 
668
                                cr.Clip ();
 
669
                                cr.LineWidth = System.Math.Max (1, System.Math.Floor (textEditor.Options.Zoom));
673
670
                                cr.Antialias = Cairo.Antialias.None;
674
671
                                var curRect = new Gdk.Rectangle ((int)caretX, (int)caretY, (int)this.charWidth, (int)LineHeight - 1);
675
672
                                if (curRect != caretRectangle) {
676
673
                                        caretRectangle = curRect;
677
 
                                        textEditor.QueueDrawArea (caretRectangle.X,
 
674
                                        textEditor.TextArea.QueueDrawArea (caretRectangle.X - (int)textEditor.Options.Zoom,
678
675
                                                       (int)(caretRectangle.Y + (-textEditor.VAdjustment.Value + caretVAdjustmentValue)),
679
 
                                                       caretRectangle.Width + 1,
 
676
                                                    caretRectangle.Width + (int)textEditor.Options.Zoom,
680
677
                                                       caretRectangle.Height + 1);
681
678
                                        caretVAdjustmentValue = textEditor.VAdjustment.Value;
682
679
                                }
683
 
                                cr.Color = textEditor.ColorStyle.Default.CairoColor;
 
680
 
 
681
 
 
682
                                var fgColor = textEditor.ColorStyle.PlainText.Foreground;
 
683
//                              var bgColor = textEditor.ColorStyle.Default.CairoBackgroundColor;
 
684
                                var line = Document.GetLine (Caret.Line);
 
685
                                if (line != null) {
 
686
                                        foreach (var marker in line.Markers) {
 
687
                                                var style = marker as StyleTextLineMarker;
 
688
                                                if (style == null)
 
689
                                                        continue;
 
690
        //                                      if (style.IncludedStyles.HasFlag (StyleTextLineMarker.StyleFlag.BackgroundColor))
 
691
        //                                              bgColor = style.BackgroundColor;
 
692
                                                if (style.IncludedStyles.HasFlag (StyleTextLineMarker.StyleFlag.Color))
 
693
                                                        fgColor = style.Color;
 
694
                                        }
 
695
                                }
 
696
                                /*
 
697
                                var foreground = ((HslColor)fgColor).ToPixel ();
 
698
                                var background = ((HslColor)color).ToPixel ();
 
699
                                var caretColor = (foreground ^ background) & 0xFFFFFF;
 
700
                                color = HslColor.FromPixel (caretColor);*/
 
701
                                var color = fgColor;
 
702
 
684
703
                                switch (Caret.Mode) {
685
704
                                case CaretMode.Insert:
686
 
                                        cr.DrawLine (textEditor.ColorStyle.Default.CairoColor,
 
705
                                        cr.DrawLine (color,
687
706
                                                     caretRectangle.X + 0.5, 
688
707
                                                     caretRectangle.Y + 0.5,
689
708
                                                     caretRectangle.X + 0.5,
690
709
                                                     caretRectangle.Y + caretRectangle.Height);
691
710
                                        break;
692
711
                                case CaretMode.Block:
 
712
                                        cr.Color = color;
693
713
                                        cr.Rectangle (caretRectangle.X + 0.5, caretRectangle.Y + 0.5, caretRectangle.Width, caretRectangle.Height);
694
714
                                        cr.Fill ();
695
715
                                        char caretChar = GetCaretChar ();
698
718
                                                        layout.FontDescription = textEditor.Options.Font;
699
719
                                                        layout.SetText (caretChar.ToString ());
700
720
                                                        cr.MoveTo (caretRectangle.X, caretRectangle.Y);
701
 
                                                        cr.Color = textEditor.ColorStyle.Default.CairoBackgroundColor;
 
721
                                                        cr.Color = textEditor.ColorStyle.PlainText.Background;
702
722
                                                        cr.ShowLayout (layout);
703
723
                                                }
704
724
                                        }
705
725
                                        break;
706
726
                                case CaretMode.Underscore:
707
 
                                        cr.DrawLine (textEditor.ColorStyle.Default.CairoColor,
 
727
                                        cr.DrawLine (color,
708
728
                                                     caretRectangle.X + 0.5, 
709
729
                                                     caretRectangle.Y + caretRectangle.Height + 0.5,
710
730
                                                     caretRectangle.X + caretRectangle.Width,
745
765
                                get;
746
766
                                private set;
747
767
                        }
 
768
 
748
769
                        public int Length {
749
770
                                get;
750
771
                                private set;
751
772
                        }
 
773
 
752
774
                        public int MarkerLength {
753
775
                                get;
754
776
                                private set;
755
777
                        }
 
778
 
756
779
                        public Mono.TextEditor.Highlighting.CloneableStack<Mono.TextEditor.Highlighting.Span> Spans {
757
780
                                get;
758
781
                                private set;
779
802
                                get;
780
803
                                private set;
781
804
                        }
 
805
 
782
806
                        public int SelectionStart {
783
807
                                get;
784
808
                                private set;
785
809
                        }
 
810
 
786
811
                        public int SelectionEnd {
787
812
                                get;
788
813
                                private set;
851
876
                        }
852
877
                        var wrapper = new LayoutWrapper (PangoUtil.CreateLayout (textEditor));
853
878
                        wrapper.IsUncached = containsPreedit;
854
 
 
855
879
                        if (logicalRulerColumn < 0)
856
880
                                logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn);
857
881
                        var atts = new FastPangoAttrList ();
858
882
                        wrapper.Layout.Alignment = Pango.Alignment.Left;
859
883
                        wrapper.Layout.FontDescription = textEditor.Options.Font;
860
884
                        wrapper.Layout.Tabs = tabArray;
 
885
                        if (textEditor.Options.WrapLines) {
 
886
                                wrapper.Layout.Wrap = Pango.WrapMode.WordChar;
 
887
                                wrapper.Layout.Width = (int)((textEditor.Allocation.Width - XOffset - TextStartPosition) * Pango.Scale.PangoScale);
 
888
                        }
861
889
                        StringBuilder textBuilder = new StringBuilder ();
862
890
                        var chunks = GetCachedChunks (mode, Document, textEditor.ColorStyle, line, offset, length);
 
891
                        wrapper.Chunks = chunks;
863
892
                        foreach (var chunk in chunks) {
864
893
                                try {
865
894
                                        textBuilder.Append (Document.GetTextAt (chunk));
883
912
                        uint oldEndIndex = 0;
884
913
                        foreach (Chunk chunk in chunks) {
885
914
                                ChunkStyle chunkStyle = chunk != null ? textEditor.ColorStyle.GetChunkStyle (chunk) : null;
886
 
                                foreach (TextMarker marker in line.Markers)
 
915
                                foreach (TextLineMarker marker in line.Markers)
887
916
                                        chunkStyle = marker.GetStyle (chunkStyle);
888
917
 
889
918
                                if (chunkStyle != null) {
893
922
                                        uint startIndex = (uint)(oldEndIndex);
894
923
                                        uint endIndex = (uint)(startIndex + chunk.Length);
895
924
                                        oldEndIndex = endIndex;
896
 
 
 
925
                                        var markers = Document.GetTextSegmentMarkersAt (line).Where (m => m.IsVisible).ToArray ();
897
926
                                        HandleSelection (lineOffset, logicalRulerColumn, selectionStart, selectionEnd, chunk.Offset, chunk.EndOffset, delegate(int start, int end) {
898
927
                                                if (containsPreedit) {
899
928
                                                        if (textEditor.preeditOffset < start)
903
932
                                                }
904
933
                                                var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex);
905
934
                                                var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex);
906
 
                                                atts.AddForegroundAttribute (chunkStyle.Color, si, ei);
 
935
                                                var color = ColorStyle.GetForeground (chunkStyle);
 
936
                                                foreach (var marker in markers) {
 
937
                                                        var chunkMarker = marker as IChunkMarker;
 
938
                                                        if (chunkMarker == null)
 
939
                                                                continue;
 
940
                                                        chunkMarker.ChangeForeColor (textEditor, chunk, ref color);
 
941
                                                }
 
942
                                                atts.AddForegroundAttribute ((HslColor)color, si, ei);
907
943
                                                
908
 
                                                if (!chunkStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (chunkStyle.BackgroundColor)) {
909
 
                                                        wrapper.AddBackground (chunkStyle.CairoBackgroundColor, (int)si, (int)ei);
 
944
                                                if (!chunkStyle.TransparentBackground && GetPixel (ColorStyle.PlainText.Background) != GetPixel (chunkStyle.Background)) {
 
945
                                                        wrapper.AddBackground (chunkStyle.Background, (int)si, (int)ei);
910
946
                                                } else if (chunk.SpanStack != null && ColorStyle != null) {
911
947
                                                        foreach (var span in chunk.SpanStack) {
912
 
                                                                if (span == null)
 
948
                                                                if (span == null || string.IsNullOrEmpty (span.Color))
913
949
                                                                        continue;
914
950
                                                                var spanStyle = ColorStyle.GetChunkStyle (span.Color);
915
 
                                                                if (!spanStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (spanStyle.BackgroundColor)) {
916
 
                                                                        wrapper.AddBackground (spanStyle.CairoBackgroundColor, (int)si, (int)ei);
 
951
                                                                if (spanStyle != null && !spanStyle.TransparentBackground && GetPixel (ColorStyle.PlainText.Background) != GetPixel (spanStyle.Background)) {
 
952
                                                                        wrapper.AddBackground (spanStyle.Background, (int)si, (int)ei);
917
953
                                                                        break;
918
954
                                                                }
919
955
                                                        }
927
963
                                                }
928
964
                                                var si = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex);
929
965
                                                var ei = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex);
930
 
                                                atts.AddForegroundAttribute (SelectionColor.Color, si, ei);
 
966
                                                var color = !SelectionColor.TransparentForeground ? SelectionColor.Foreground : ColorStyle.GetForeground (chunkStyle);
 
967
                                                foreach (var marker in markers) {
 
968
                                                        var chunkMarker = marker as IChunkMarker;
 
969
                                                        if (chunkMarker == null)
 
970
                                                                continue;
 
971
                                                        chunkMarker.ChangeForeColor (textEditor, chunk, ref color);
 
972
                                                }
 
973
                                                atts.AddForegroundAttribute ((HslColor)color, si, ei);
931
974
                                                if (!wrapper.StartSet)
932
975
                                                        wrapper.SelectionStartIndex = (int)si;
933
976
                                                wrapper.SelectionEndIndex = (int)ei;
936
979
                                        var translatedStartIndex = TranslateToUTF8Index (lineChars, (uint)startIndex, ref curChunkIndex, ref byteChunkIndex);
937
980
                                        var translatedEndIndex = TranslateToUTF8Index (lineChars, (uint)endIndex, ref curChunkIndex, ref byteChunkIndex);
938
981
 
939
 
                                        if (chunkStyle.Bold)
940
 
                                                atts.AddWeightAttribute (Pango.Weight.Bold, translatedStartIndex, translatedEndIndex);
 
982
                                        if (chunkStyle.FontWeight != Xwt.Drawing.FontWeight.Normal)
 
983
                                                atts.AddWeightAttribute ((Pango.Weight)chunkStyle.FontWeight, translatedStartIndex, translatedEndIndex);
941
984
 
942
 
                                        if (chunkStyle.Italic)
943
 
                                                atts.AddStyleAttribute (Pango.Style.Italic, translatedStartIndex, translatedEndIndex);
 
985
                                        if (chunkStyle.FontStyle != Xwt.Drawing.FontStyle.Normal)
 
986
                                                atts.AddStyleAttribute ((Pango.Style)chunkStyle.FontStyle, translatedStartIndex, translatedEndIndex);
944
987
 
945
988
                                        if (chunkStyle.Underline)
946
989
                                                atts.AddUnderlineAttribute (Pango.Underline.Single, translatedStartIndex, translatedEndIndex);
953
996
                        }
954
997
                        wrapper.LineChars = lineChars;
955
998
                        wrapper.Layout.SetText (lineText);
 
999
                        wrapper.IndentSize = 0;
 
1000
                        for (int i = 0; i < lineChars.Length; i++) {
 
1001
                                char ch = lineChars [i];
 
1002
                                if (ch == ' ') {
 
1003
                                        wrapper.IndentSize ++;
 
1004
                                } else if (ch == '\t') {
 
1005
                                        wrapper.IndentSize = GetNextTabstop (textEditor.GetTextEditorData (), wrapper.IndentSize);
 
1006
                                } else {
 
1007
                                        break;
 
1008
                                }
 
1009
                        }
 
1010
 
956
1011
                        var nextLine = line.NextLine;
957
1012
                        wrapper.EolSpanStack = nextLine != null ? nextLine.StartSpan : null;
958
1013
                        atts.AssignTo (wrapper.Layout);
965
1020
                        selectionEnd = System.Math.Min (line.EndOffsetIncludingDelimiter + 1, selectionEnd);
966
1021
                        descriptor = new LayoutDescriptor (line, offset, length, wrapper, selectionStart, selectionEnd);
967
1022
                        if (!containsPreedit)
968
 
                                layoutDict[line] = descriptor;
 
1023
                                layoutDict [line] = descriptor;
 
1024
                        //textEditor.GetTextEditorData ().HeightTree.SetLineHeight (line.LineNumber, System.Math.Max (LineHeight, System.Math.Floor (h / Pango.Scale.PangoScale)));
969
1025
                        return wrapper;
970
1026
                }
971
1027
 
1006
1062
                                get;
1007
1063
                                private set;
1008
1064
                        }
 
1065
 
1009
1066
                        public ChunkDescriptor (DocumentLine line, int offset, int length, Chunk[] chunk) : base(line, offset, length)
1010
1067
                        {
1011
1068
                                this.Chunk = chunk;
1013
1070
                }
1014
1071
 
1015
1072
                Dictionary<DocumentLine, ChunkDescriptor> chunkDict = new Dictionary<DocumentLine, ChunkDescriptor> ();
 
1073
 
1016
1074
                IEnumerable<Chunk> GetCachedChunks (ISyntaxMode mode, TextDocument doc, Mono.TextEditor.Highlighting.ColorScheme style, DocumentLine line, int offset, int length)
1017
1075
                {
1018
1076
                        ChunkDescriptor descriptor;
1025
1083
 
1026
1084
                        Chunk[] chunks = mode.GetChunks (style, line, offset, length).ToArray ();
1027
1085
                        descriptor = new ChunkDescriptor (line, offset, length, chunks);
1028
 
                        chunkDict[line] = descriptor;
 
1086
                        chunkDict [line] = descriptor;
1029
1087
                        return chunks;
1030
1088
                }
1031
1089
 
1039
1097
                        }
1040
1098
                }
1041
1099
 
1042
 
                delegate void HandleSelectionDelegate (int start, int end);
 
1100
                delegate void HandleSelectionDelegate (int start,int end);
 
1101
 
1043
1102
                static void InternalHandleSelection (int selectionStart, int selectionEnd, int startOffset, int endOffset, HandleSelectionDelegate handleNotSelected, HandleSelectionDelegate handleSelected)
1044
1103
                {
1045
1104
                        if (startOffset >= selectionStart && endOffset <= selectionEnd) {
1103
1162
 
1104
1163
                public class LayoutWrapper : IDisposable
1105
1164
                {
 
1165
                        public int IndentSize {
 
1166
                                get;
 
1167
                                set;
 
1168
                        }
 
1169
 
1106
1170
                        public Pango.Layout Layout {
1107
1171
                                get;
1108
1172
                                private set;
1112
1176
                                get;
1113
1177
                                set;
1114
1178
                        }
 
1179
 
1115
1180
                        public bool StartSet {
1116
1181
                                get;
1117
1182
                                set;
1118
1183
                        }
1119
1184
 
 
1185
                        public IEnumerable<Chunk> Chunks {
 
1186
                                get;
 
1187
                                set;
 
1188
                        }
 
1189
 
1120
1190
                        public char[] LineChars {
1121
1191
                                get;
1122
1192
                                set;
1128
1198
                        }
1129
1199
 
1130
1200
                        int selectionStartIndex;
 
1201
 
1131
1202
                        public int SelectionStartIndex {
1132
1203
                                get {
1133
1204
                                        return selectionStartIndex;
1177
1248
                        }
1178
1249
 
1179
1250
                        List<BackgroundColor> backgroundColors = null;
 
1251
 
1180
1252
                        public List<BackgroundColor> BackgroundColors {
1181
1253
                                get {
1182
1254
                                        return backgroundColors ?? new List<BackgroundColor> ();
1191
1263
                        }
1192
1264
                }
1193
1265
 
 
1266
                ChunkStyle selectionColor;
1194
1267
                ChunkStyle SelectionColor {
1195
1268
                        get {
1196
 
                                return textEditor.HasFocus ? ColorStyle.Selection : ColorStyle.InactiveSelection;
 
1269
                                if (selectionColor == null)
 
1270
                                        selectionColor = textEditor.HasFocus ? ColorStyle.SelectedText : ColorStyle.SelectedInactiveText;
 
1271
                                return selectionColor;
 
1272
                        }
 
1273
                }
 
1274
 
 
1275
                AmbientColor currentLineColor;
 
1276
                AmbientColor CurrentLineColor {
 
1277
                        get {
 
1278
                                if (currentLineColor == null)
 
1279
                                        currentLineColor = textEditor.HasFocus ? ColorStyle.LineMarker : ColorStyle.LineMarkerInactive;
 
1280
                                return currentLineColor;
1197
1281
                        }
1198
1282
                }
1199
1283
 
1204
1288
 
1205
1289
                #endregion
1206
1290
 
1207
 
                public delegate void LineDecorator (Cairo.Context ctx, LayoutWrapper layout, int offset, int length, double xPos, double y, int selectionStart, int selectionEnd);
 
1291
                public delegate void LineDecorator (Cairo.Context ctx,LayoutWrapper layout,int offset,int length,double xPos,double y,int selectionStart,int selectionEnd);
 
1292
 
1208
1293
                public event LineDecorator DecorateLineBg;
1209
 
                public event LineDecorator DecorateLineFg;
1210
 
 
1211
 
                void DrawSpaceMarker (Cairo.Context cr, bool selected, double x, double y)
1212
 
                {
1213
 
                        cr.Save ();
1214
 
                        cr.Translate (x, y);
1215
 
                        cr.ShowLayout (spaceMarkerLayout);
1216
 
                        cr.Restore ();
1217
 
                }
1218
 
 
1219
 
                void DecorateSpaces (Cairo.Context ctx, LayoutWrapper layout, int offset, int length, double xPos, double y, int selectionStart, int selectionEnd)
1220
 
                {
1221
 
                        uint curIndex = 0, byteIndex = 0;
1222
 
                        bool first = true, oldSelected = false;
1223
 
                        int index, trailing;
1224
 
                        layout.Layout.XyToIndex ((int)textEditor.HAdjustment.Value, 0, out index, out trailing);
1225
 
 
1226
 
                        for (int i = index; i < layout.LineChars.Length; i++) {
1227
 
                                if (layout.LineChars [i] == ' ') {
1228
 
                                        bool selected = selectionStart <= offset + i && offset + i < selectionEnd;
1229
 
                                        if (first || oldSelected != selected) {
1230
 
                                                ctx.Color = selected ? SelectionColor.CairoColor : ColorStyle.WhitespaceMarker;
1231
 
                                                first = false;
1232
 
                                                oldSelected = selected;
1233
 
                                        }
1234
 
                                        Pango.Rectangle pos = layout.Layout.IndexToPos ((int)TranslateToUTF8Index (layout.LineChars, (uint)i, ref curIndex, ref byteIndex));
1235
 
                                        double xpos = xPos + pos.X / Pango.Scale.PangoScale;
1236
 
                                        if (xpos > textEditor.Allocation.Width)
1237
 
                                                break;
1238
 
                                        DrawSpaceMarker (ctx, selected, xpos, y);
1239
 
                                }
1240
 
                        }
1241
 
                }
1242
 
 
1243
 
                void DrawTabMarker (Cairo.Context cr, bool selected, double x, double y)
1244
 
                {
1245
 
                        cr.Save ();
1246
 
                        cr.Translate (x, y);
1247
 
                        cr.ShowLayout (tabMarkerLayout);
1248
 
                        cr.Restore ();
1249
 
                }
1250
 
                
1251
 
                void DecorateTabs (Cairo.Context ctx, LayoutWrapper layout, int offset, int length, double xPos, double y, int selectionStart, int selectionEnd)
1252
 
                {
1253
 
                        uint curIndex = 0, byteIndex = 0;
1254
 
                        bool first = true, oldSelected = false;
1255
 
                        int index, trailing;
1256
 
                        layout.Layout.XyToIndex ((int)textEditor.HAdjustment.Value, 0, out index, out trailing);
1257
 
 
1258
 
                        for (int i = index; i < layout.LineChars.Length; i++) {
1259
 
                                if (layout.LineChars[i] == '\t') {
1260
 
                                        bool selected = selectionStart <= offset + i && offset + i < selectionEnd;
1261
 
                                        if (first || oldSelected != selected) {
1262
 
                                                ctx.Color = selected ? SelectionColor.CairoColor : ColorStyle.WhitespaceMarker;
1263
 
                                                first = false;
1264
 
                                                oldSelected = selected;
1265
 
                                        }
1266
 
                                        Pango.Rectangle pos = layout.Layout.IndexToPos ((int)TranslateToUTF8Index (layout.LineChars, (uint)i, ref curIndex, ref byteIndex));
1267
 
                                        double xpos = xPos + pos.X / Pango.Scale.PangoScale;
1268
 
                                        if (xpos > textEditor.Allocation.Width)
1269
 
                                                break;
1270
 
                                        DrawTabMarker (ctx, selected, xpos, y);
1271
 
                                }
1272
 
                        }
1273
 
                }
 
1294
 
 
1295
                void DrawSpaceMarker (Cairo.Context cr, bool selected, double x, double x2, double y)
 
1296
                {
 
1297
                        var d = textEditor.Options.Zoom * 2;
 
1298
                        var py = (int)(y + (LineHeight - d) / 2);
 
1299
                        cr.Rectangle (x + (x2 - x - d) / 2, py, d, d);
 
1300
                        cr.Fill ();
 
1301
                }
 
1302
 
 
1303
                void DrawTabMarker (Cairo.Context cr, bool selected, double x, double x2, double y)
 
1304
                {
 
1305
                        var py = (int)(y + LineHeight / 2);
 
1306
                        cr.MoveTo (0.5 + x, 0.5 + py);
 
1307
                        cr.LineTo (0.5 + x2 - charWidth / 2, 0.5 + py);
 
1308
                        cr.Stroke ();
 
1309
                }
 
1310
 
 
1311
                const double whitespaceMarkerAlpha = 0.3;
1274
1312
 
1275
1313
                void DecorateTabsAndSpaces (Cairo.Context ctx, LayoutWrapper layout, int offset, int length, double xPos, double y, int selectionStart, int selectionEnd)
1276
1314
                {
1278
1316
                        bool first = true, oldSelected = false;
1279
1317
                        int index, trailing;
1280
1318
                        layout.Layout.XyToIndex ((int)textEditor.HAdjustment.Value, 0, out index, out trailing);
1281
 
 
 
1319
                        var curchunk = layout.Chunks != null ? layout.Chunks.FirstOrDefault () : null;
1282
1320
                        for (int i = index; i < layout.LineChars.Length; i++) {
1283
1321
                                char ch = layout.LineChars [i];
1284
1322
                                if (ch != ' ' && ch != '\t')
1285
1323
                                        continue;
 
1324
                                if (ch == ' ' && !textEditor.Options.IncludeWhitespaces.HasFlag (IncludeWhitespaces.Space))
 
1325
                                        continue;
 
1326
                                if (ch == '\t' && !textEditor.Options.IncludeWhitespaces.HasFlag (IncludeWhitespaces.Tab))
 
1327
                                        continue;
1286
1328
                                bool selected = selectionStart <= offset + i && offset + i < selectionEnd;
1287
1329
                                if (first || oldSelected != selected) {
1288
 
                                        ctx.Color = selected ? SelectionColor.CairoColor : ColorStyle.WhitespaceMarker;
1289
1330
                                        first = false;
1290
1331
                                        oldSelected = selected;
1291
1332
                                }
 
1333
                                if (!selected && textEditor.Options.ShowWhitespaces != ShowWhitespaces.Always)
 
1334
                                        continue;
1292
1335
                                Pango.Rectangle pos = layout.Layout.IndexToPos ((int)TranslateToUTF8Index (layout.LineChars, (uint)i, ref curIndex, ref byteIndex));
1293
1336
                                double xpos = xPos + pos.X / Pango.Scale.PangoScale;
1294
1337
                                if (xpos > textEditor.Allocation.Width)
1295
1338
                                        break;
 
1339
                                Pango.Rectangle pos2 = layout.Layout.IndexToPos ((int)TranslateToUTF8Index (layout.LineChars, (uint)i + 1, ref curIndex, ref byteIndex));
 
1340
                                double xpos2 = xPos + pos2.X / Pango.Scale.PangoScale;
 
1341
                                Cairo.Color col = new Cairo.Color (0, 0, 0);
 
1342
                                if (SelectionColor.TransparentForeground) {
 
1343
                                        while (curchunk != null && curchunk.EndOffset < offset + i)
 
1344
                                                curchunk = curchunk.Next;
 
1345
                                        if (curchunk != null && curchunk.SpanStack.Count > 0 && curchunk.SpanStack.Peek ().Color != "Plain Text") {
 
1346
                                                var chunkStyle = ColorStyle.GetChunkStyle (curchunk.SpanStack.Peek ().Color);
 
1347
                                                if (chunkStyle != null)
 
1348
                                                        col = ColorStyle.GetForeground (chunkStyle);
 
1349
                                        } else {
 
1350
                                                col = ColorStyle.PlainText.Foreground;
 
1351
                                        }
 
1352
                                } else {
 
1353
                                        col = selected ? SelectionColor.Foreground : col = ColorStyle.PlainText.Foreground;
 
1354
                                }
 
1355
                                ctx.Color = new Cairo.Color (col.R, col.G, col.B, whitespaceMarkerAlpha);
 
1356
 
1296
1357
                                if (ch == '\t') {
1297
 
                                        DrawTabMarker (ctx, selected, xpos, y);
 
1358
                                        DrawTabMarker (ctx, selected, xpos, xpos2, y);
1298
1359
                                } else {
1299
 
                                        DrawSpaceMarker (ctx, selected, xpos, y);
 
1360
                                        DrawSpaceMarker (ctx, selected, xpos, xpos2, y);
1300
1361
                                }
1301
1362
                        }
1302
1363
                }
1310
1371
                                
1311
1372
                                var bracketMatch = new Cairo.Rectangle (xPos + rect.X / Pango.Scale.PangoScale + 0.5, y + 0.5, (rect.Width / Pango.Scale.PangoScale) - 1, (rect.Height / Pango.Scale.PangoScale) - 1);
1312
1373
                                if (BackgroundRenderer == null) {
1313
 
                                        ctx.Color = this.ColorStyle.BracketHighlightRectangle.CairoBackgroundColor;
 
1374
                                        ctx.Color = this.ColorStyle.BraceMatchingRectangle.Color;
1314
1375
                                        ctx.Rectangle (bracketMatch);
1315
1376
                                        ctx.FillPreserve ();
1316
 
                                        ctx.Color = this.ColorStyle.BracketHighlightRectangle.CairoColor;
 
1377
                                        ctx.Color = this.ColorStyle.BraceMatchingRectangle.SecondColor;
1317
1378
                                        ctx.Stroke ();
1318
1379
                                }
1319
1380
                        }
1325
1386
                        return CreateLinePartLayout (mode, line, line.Offset, line.Length, -1, -1);
1326
1387
                }
1327
1388
 
1328
 
                public void DrawCaretLineMarker (Cairo.Context cr, double xPos, double y, double width)
 
1389
                public void DrawCaretLineMarker (Cairo.Context cr, double xPos, double y, double width, double lineHeight)
1329
1390
                {
1330
 
                        cr.Rectangle (xPos, y, width, LineHeight);
1331
 
                        var color = ColorStyle.LineMarker;
1332
 
                        cr.Color = new Cairo.Color (color.R, color.G, color.B, 0.5);
 
1391
                        if (BackgroundRenderer != null)
 
1392
                                return;
 
1393
                        xPos = System.Math.Floor (xPos);
 
1394
                        cr.Rectangle (xPos, y, width, lineHeight);
 
1395
                        var color = CurrentLineColor;
 
1396
                        cr.Color = color.Color;
1333
1397
                        cr.Fill ();
1334
1398
                        double halfLine = (cr.LineWidth / 2.0);
1335
1399
                        cr.MoveTo (xPos, y + halfLine);
1336
1400
                        cr.LineTo (xPos + width, y + halfLine);
1337
 
                        cr.MoveTo (xPos, y + LineHeight - halfLine);
1338
 
                        cr.LineTo (xPos + width, y + LineHeight - halfLine);
1339
 
                        cr.Color = color;
 
1401
                        cr.MoveTo (xPos, y + lineHeight - halfLine);
 
1402
                        cr.LineTo (xPos + width, y + lineHeight - halfLine);
 
1403
                        cr.Color = color.SecondColor;
1340
1404
                        cr.Stroke ();
1341
1405
                }
1342
1406
 
1343
 
                void DrawLinePart (Cairo.Context cr, DocumentLine line, int lineNumber, int logicalRulerColumn, int offset, int length, ref double pangoPosition, ref bool isSelectionDrawn, double y, double maxX)
 
1407
                void DrawIndent (Cairo.Context cr, LayoutWrapper layout, DocumentLine line, double xPos, double y)
 
1408
                {
 
1409
                        if (!textEditor.Options.DrawIndentationMarkers)
 
1410
                                return;
 
1411
                        if (line.Length == 0) {
 
1412
                                var nextLine = line.NextLine;
 
1413
                                while (nextLine != null && nextLine.Length == 0)
 
1414
                                        nextLine = nextLine.NextLine;
 
1415
                                if (nextLine != null)
 
1416
                                        layout = GetLayout (nextLine);
 
1417
                        }
 
1418
                        if (layout.IndentSize == 0)
 
1419
                                return;
 
1420
                        cr.Save ();
 
1421
                        var dotted = new [] { textEditor.Options.Zoom };
 
1422
                        cr.SetDash (dotted, (int)y + textEditor.VAdjustment.Value);
 
1423
                        var top = y;
 
1424
                        var bottom = y + LineHeight;
 
1425
                        if (Caret.Line == line.LineNumber && textEditor.Options.HighlightCaretLine) {
 
1426
                                top += textEditor.Options.Zoom;
 
1427
                                bottom -= textEditor.Options.Zoom;
 
1428
                        }
 
1429
                        for (int i = 0; i < layout.IndentSize; i += textEditor.Options.IndentationSize) {
 
1430
                                var x = System.Math.Floor (xPos + i * charWidth);
 
1431
                                cr.MoveTo (x + 0.5, top);
 
1432
                                cr.LineTo (x + 0.5, bottom);
 
1433
 
 
1434
                                cr.Color = ColorStyle.IndentationGuide.Color;
 
1435
                                cr.Stroke ();
 
1436
                        }
 
1437
                        cr.Restore ();
 
1438
                }
 
1439
 
 
1440
                void DrawLinePart (Cairo.Context cr, DocumentLine line, int lineNumber, int logicalRulerColumn, int offset, int length, ref double pangoPosition, ref bool isSelectionDrawn, double y, double maxX, double _lineHeight)
1344
1441
                {
1345
1442
                        ISyntaxMode mode = Document.SyntaxMode != null && textEditor.Options.EnableSyntaxHighlighting ? Document.SyntaxMode : new SyntaxMode (Document);
1346
1443
                        int selectionStart;
1357
1454
                        double width = layout.PangoWidth / Pango.Scale.PangoScale;
1358
1455
                        double xPos = pangoPosition / Pango.Scale.PangoScale;
1359
1456
 
 
1457
                        // The caret line marker must be drawn below the text markers otherwise the're invisible
 
1458
                        if ((HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNumber)
 
1459
                                DrawCaretLineMarker (cr, xPos, y, layout.PangoWidth / Pango.Scale.PangoScale, _lineHeight);
 
1460
 
1360
1461
                        //              if (!(HighlightCaretLine || textEditor.Options.HighlightCaretLine) || Document.GetLine(Caret.Line) != line) {
1361
 
                        foreach (var bg in layout.BackgroundColors) {
1362
 
                                int x1, x2;
1363
 
                                x1 = layout.Layout.IndexToPos (bg.FromIdx).X;
1364
 
                                x2 = layout.Layout.IndexToPos (bg.ToIdx).X;
1365
 
                                DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition,
1366
 
                                                new Cairo.Rectangle ((x1 + pangoPosition) / Pango.Scale.PangoScale, y, (x2 - x1) / Pango.Scale.PangoScale + 1, LineHeight),
 
1462
                        if (BackgroundRenderer == null) {
 
1463
                                foreach (var bg in layout.BackgroundColors) {
 
1464
                                        int x1, x2;
 
1465
                                        x1 = layout.Layout.IndexToPos (bg.FromIdx).X;
 
1466
                                        x2 = layout.Layout.IndexToPos (bg.ToIdx).X;
 
1467
                                        DrawRectangleWithRuler (
 
1468
                                                cr, xPos + textEditor.HAdjustment.Value - TextStartPosition,
 
1469
                                                new Cairo.Rectangle ((x1 + pangoPosition) / Pango.Scale.PangoScale, y, (x2 - x1) / Pango.Scale.PangoScale + 1, _lineHeight),
1367
1470
                                                bg.Color, true);
 
1471
                                }
1368
1472
                        }
1369
 
                        //              }
 
1473
 
1370
1474
 
1371
1475
                        bool drawBg = true;
1372
1476
                        bool drawText = true;
1373
 
                        foreach (TextMarker marker in line.Markers) {
 
1477
                        foreach (TextLineMarker marker in line.Markers) {
1374
1478
                                IBackgroundMarker bgMarker = marker as IBackgroundMarker;
1375
1479
                                if (bgMarker == null || !marker.IsVisible)
1376
1480
                                        continue;
1377
 
                                isSelectionDrawn |= (marker.Flags & TextMarkerFlags.DrawsSelection) == TextMarkerFlags.DrawsSelection;
 
1481
                                isSelectionDrawn |= (marker.Flags & TextLineMarkerFlags.DrawsSelection) == TextLineMarkerFlags.DrawsSelection;
1378
1482
                                drawText &= bgMarker.DrawBackground (textEditor, cr, layout, selectionStart, selectionEnd, offset, offset + length, y, xPos, xPos + width, ref drawBg);
1379
1483
                        }
1380
1484
 
1381
1485
                        if (DecorateLineBg != null)
1382
1486
                                DecorateLineBg (cr, layout, offset, length, xPos, y, selectionStart, selectionEnd);
1383
1487
                        
1384
 
                        if ((HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNumber)
1385
 
                                DrawCaretLineMarker (cr, xPos, y, layout.PangoWidth / Pango.Scale.PangoScale);
1386
1488
 
1387
 
                        if (!isSelectionDrawn && (layout.StartSet || selectionStart == offset + length)) {
 
1489
                        if (!isSelectionDrawn && (layout.StartSet || selectionStart == offset + length) && BackgroundRenderer == null) {
1388
1490
                                double startX;
1389
1491
                                double endX;
1390
1492
 
1391
1493
                                if (selectionStart != offset + length) {
1392
1494
                                        var start = layout.Layout.IndexToPos ((int)layout.SelectionStartIndex);
1393
 
                                        startX = start.X / Pango.Scale.PangoScale;
 
1495
                                        startX = System.Math.Floor (start.X / Pango.Scale.PangoScale);
1394
1496
                                        var end = layout.Layout.IndexToPos ((int)layout.SelectionEndIndex);
1395
 
                                        endX = end.X / Pango.Scale.PangoScale;
 
1497
                                        endX = System.Math.Ceiling (end.X / Pango.Scale.PangoScale);
1396
1498
                                } else {
1397
1499
                                        startX = width;
1398
1500
                                        endX = startX;
1401
1503
                                if (textEditor.MainSelection.SelectionMode == SelectionMode.Block && startX == endX) {
1402
1504
                                        endX = startX + 2;
1403
1505
                                }
1404
 
                                DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition, new Cairo.Rectangle (xPos + startX, y, endX - startX, LineHeight), this.SelectionColor.CairoBackgroundColor, true);
 
1506
                                DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition, new Cairo.Rectangle (xPos + startX, y, endX - startX, _lineHeight), this.SelectionColor.Background, true);
1405
1507
                        }
1406
1508
 
1407
1509
                        // highlight search results
1421
1523
                                                        int l, x1, x2;
1422
1524
                                                        layout.Layout.IndexToLineX ((int)startTranslated, false, out l, out x1);
1423
1525
                                                        layout.Layout.IndexToLineX ((int)endTranslated, false, out l, out x2);
1424
 
                                                        x1 += (int)x;
1425
 
                                                        x2 += (int)x;
1426
 
                                                        x1 /= (int)Pango.Scale.PangoScale;
1427
 
                                                        x2 /= (int)Pango.Scale.PangoScale;
1428
 
        
1429
 
                                                        cr.Color = MainSearchResult.IsInvalid || MainSearchResult.Offset != firstSearch.Offset ? ColorStyle.SearchTextBg : ColorStyle.SearchTextMainBg;
1430
 
                                                        FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, x1, y, System.Math.Min (10, width) * textEditor.Options.Zoom, x2 - x1, LineHeight);
 
1526
                                                        int w = (int) System.Math.Ceiling ((x2 - x1) / Pango.Scale.PangoScale);
 
1527
                                                        int s = (int) System.Math.Floor ((x1 + x) / Pango.Scale.PangoScale);
 
1528
                                                        double corner = System.Math.Min (4, width) * textEditor.Options.Zoom;
 
1529
 
 
1530
                                                        cr.Color = MainSearchResult.IsInvalid || MainSearchResult.Offset != firstSearch.Offset ? ColorStyle.SearchResult.Color : ColorStyle.SearchResultMain.Color;
 
1531
                                                        FoldingScreenbackgroundRenderer.DrawRoundRectangle (cr, true, true, s, y, corner, w + 1, LineHeight);
1431
1532
                                                        cr.Fill ();
1432
1533
                                                }
1433
1534
                                        }, null);
1440
1541
                        cr.Translate (xPos, y);
1441
1542
                        cr.ShowLayout (layout.Layout);
1442
1543
                        cr.Restore ();
1443
 
                        
1444
 
                        if (DecorateLineFg != null)
1445
 
                                DecorateLineFg (cr, layout, offset, length, xPos, y, selectionStart, selectionEnd);
 
1544
                        if (offset == line.Offset) {
 
1545
                                DrawIndent (cr, layout, line, xPos, y);
 
1546
                        }
 
1547
 
 
1548
                        if (textEditor.Options.ShowWhitespaces != ShowWhitespaces.Never && !(BackgroundRenderer != null && textEditor.Options.ShowWhitespaces == ShowWhitespaces.Selection))
 
1549
                                DecorateTabsAndSpaces (cr, layout, offset, length, xPos, y, selectionStart, selectionEnd);
1446
1550
 
1447
1551
                        if (lineNumber == Caret.Line) {
1448
1552
                                int caretOffset = Caret.Offset;
1468
1572
                                                SetVisibleCaretPosition (((pangoPosition + vx + layout.PangoWidth) / Pango.Scale.PangoScale), y);
1469
1573
                                                xPos = (pangoPosition + layout.PangoWidth) / Pango.Scale.PangoScale;
1470
1574
 
1471
 
                                                if (!isSelectionDrawn && (selectionEnd == lineOffset + line.Length)) {
 
1575
                                                if (!isSelectionDrawn && (selectionEnd == lineOffset + line.Length) && BackgroundRenderer == null) {
1472
1576
                                                        double startX;
1473
1577
                                                        double endX;
1474
1578
                                                        startX = xPos;
1475
1579
                                                        endX = (pangoPosition + vx + layout.PangoWidth) / Pango.Scale.PangoScale;
1476
 
                                                        DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition, new Cairo.Rectangle (startX, y, endX - startX, LineHeight), this.SelectionColor.CairoBackgroundColor, true);
 
1580
                                                        DrawRectangleWithRuler (cr, xPos + textEditor.HAdjustment.Value - TextStartPosition, new Cairo.Rectangle (startX, y, endX - startX, _lineHeight), this.SelectionColor.Background, true);
1477
1581
                                                }
1478
 
                                                if ((HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNumber)
1479
 
                                                        DrawCaretLineMarker (cr, pangoPosition / Pango.Scale.PangoScale, y, vx / Pango.Scale.PangoScale);
1480
1582
 
1481
1583
                                                // When drawing virtual space before the selection start paint it as unselected.
1482
1584
                                                var virtualSpaceMod = selectionStart < caretOffset ? 0 : virtualSpace.Length;
1483
1585
 
 
1586
                                                if ((!textEditor.IsSomethingSelected || (selectionStart >= offset && selectionStart != selectionEnd)) && (HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNumber)
 
1587
                                                        DrawCaretLineMarker (cr, pangoPosition / Pango.Scale.PangoScale, y, vx / Pango.Scale.PangoScale, _lineHeight);
 
1588
 
1484
1589
                                                if (DecorateLineBg != null)
1485
1590
                                                        DecorateLineBg (cr, wrapper, offset, length, xPos, y, selectionStart + virtualSpaceMod, selectionEnd + virtualSpace.Length);
1486
 
                                                if (DecorateLineFg != null)
1487
 
                                                        DecorateLineFg (cr, wrapper, offset, length, xPos, y, selectionStart + virtualSpaceMod, selectionEnd + virtualSpace.Length);
 
1591
 
 
1592
                                                switch (textEditor.Options.ShowWhitespaces) {
 
1593
                                                case ShowWhitespaces.Selection:
 
1594
                                                        if (textEditor.IsSomethingSelected && (selectionStart < offset || selectionStart == selectionEnd) && BackgroundRenderer == null)
 
1595
                                                                DecorateTabsAndSpaces (cr, wrapper, offset, length, xPos, y, selectionStart, selectionEnd + virtualSpace.Length);
 
1596
                                                        break;
 
1597
                                                case ShowWhitespaces.Always:
 
1598
                                                        DecorateTabsAndSpaces (cr, wrapper, offset, length, xPos, y, selectionStart, selectionEnd + virtualSpace.Length);
 
1599
                                                        break;
 
1600
                                                }
 
1601
 
1488
1602
                                                wrapper.Dispose ();
1489
1603
                                                pangoPosition += vx;
1490
1604
                                        } else if (index == length && textEditor.preeditString == null) {
1501
1615
                                                        utf8ByteIndex += preeditUtf8ByteIndex;
1502
1616
                                                }
1503
1617
                                                layout.Layout.GetCursorPos (utf8ByteIndex, out strong_pos, out weak_pos);
1504
 
                                                SetVisibleCaretPosition (xPos + (strong_pos.X / Pango.Scale.PangoScale), y);
 
1618
                                                SetVisibleCaretPosition (xPos + (strong_pos.X / Pango.Scale.PangoScale), y + (strong_pos.Y / Pango.Scale.PangoScale));
1505
1619
                                        }
1506
1620
                                }
1507
1621
                        }
1508
1622
 
1509
 
                        foreach (TextMarker marker in line.Markers.Where (m => m.IsVisible)) {
 
1623
                        foreach (TextLineMarker marker in line.Markers.Where (m => m.IsVisible)) {
 
1624
                                if (layout.Layout != null)
 
1625
                                        marker.Draw (textEditor, cr, layout.Layout, false, /*selected*/offset, offset + length, y, xPos, xPos + width);
 
1626
                        }
 
1627
 
 
1628
                        foreach (var marker in Document.GetTextSegmentMarkersAt (line).Where (m => m.IsVisible)) {
1510
1629
                                if (layout.Layout != null)
1511
1630
                                        marker.Draw (textEditor, cr, layout.Layout, false, /*selected*/offset, offset + length, y, xPos, xPos + width);
1512
1631
                        }
1513
1632
 
1514
1633
                        pangoPosition += layout.PangoWidth;
 
1634
                        int scaledDown = (int)(pangoPosition / Pango.Scale.PangoScale);
 
1635
                        pangoPosition = scaledDown * Pango.Scale.PangoScale;
 
1636
 
1515
1637
                        if (layout.IsUncached)
1516
1638
                                layout.Dispose ();
1517
1639
                }
1518
1640
 
1519
 
 
1520
1641
                TextSegment GetFirstSearchResult (int startOffset, int endOffset)
1521
1642
                {
1522
1643
                        if (startOffset < endOffset && this.selectedRegions.Count > 0) {
1549
1670
 
1550
1671
                void DrawEolMarker (Cairo.Context cr, DocumentLine line, bool selected, double x, double y)
1551
1672
                {
 
1673
                        if (!textEditor.Options.IncludeWhitespaces.HasFlag (IncludeWhitespaces.LineEndings))
 
1674
                                return;
 
1675
 
1552
1676
                        Pango.Layout layout;
 
1677
                        Pango.Rectangle rect;
1553
1678
                        switch (line.DelimiterLength) {
1554
1679
                        case 0:
1555
1680
                                // an emty line end should only happen at eof
1556
1681
                                layout = eofEolLayout;
 
1682
                                rect = eofEolLayoutRect;
1557
1683
                                break;
1558
1684
                        case 1:
1559
1685
                                if (Document.GetCharAt (line.Offset + line.Length) == '\n') {
1560
1686
                                        layout = unixEolLayout;
 
1687
                                        rect = unixEolLayoutRect;
1561
1688
                                } else {
1562
1689
                                        layout = macEolLayout;
 
1690
                                        rect = macEolLayoutRect;
1563
1691
                                }
1564
1692
                                break;
1565
1693
                        case 2:
1566
 
                                layout = windowEolLayout;
 
1694
                                layout = windowsEolLayout;
 
1695
                                rect = windowsEolLayoutRect;
1567
1696
                                break;
1568
1697
                        default:
1569
1698
                                throw new InvalidOperationException (); // other line endings are not known.
1570
1699
                        }
1571
1700
                        cr.Save ();
1572
 
                        cr.Translate (x, y);
1573
 
                        cr.Color = selected ? SelectionColor.CairoColor : ColorStyle.EolWhitespaceMarker;
 
1701
                        cr.Translate (x, y + System.Math.Max (0, LineHeight - rect.Height - 1));
 
1702
                        var col = ColorStyle.PlainText.Foreground;
 
1703
 
 
1704
                        if (selected && !SelectionColor.TransparentForeground) {
 
1705
                                col = SelectionColor.Foreground;
 
1706
                        } else {
 
1707
                                if (line != null && line.NextLine != null && line.NextLine.StartSpan != null && line.NextLine.StartSpan.Count > 0) {
 
1708
                                        var span = line.NextLine.StartSpan.Peek ();
 
1709
                                        var chunkStyle = ColorStyle.GetChunkStyle (span.Color);
 
1710
                                        if (chunkStyle != null)
 
1711
                                                col = ColorStyle.GetForeground (chunkStyle);
 
1712
                                }
 
1713
                        }
 
1714
 
 
1715
                        cr.Color = new Cairo.Color (col.R, col.G, col.B, whitespaceMarkerAlpha);
1574
1716
                        cr.ShowLayout (layout);
1575
1717
                        cr.Restore ();
1576
1718
                }
1577
 
                
1578
 
 
1579
 
                void DrawInvalidLineMarker (Cairo.Context cr, double x, double y)
1580
 
                {
1581
 
                        cr.Save ();
1582
 
                        cr.Translate (x, y);
1583
 
                        cr.Color = ColorStyle.InvalidLineMarker;
1584
 
                        cr.ShowLayout (invalidLineLayout);
1585
 
                        cr.Restore ();
1586
 
                }
1587
1719
 
1588
1720
                static internal ulong GetPixel (Color color)
1589
1721
                {
1590
1722
                        return (((ulong)color.Red) << 32) | (((ulong)color.Green) << 16) | ((ulong)color.Blue);
1591
1723
                }
1592
1724
 
1593
 
                public bool inSelectionDrag = false;
1594
 
                public bool inDrag = false;
1595
 
                public DocumentLocation clickLocation;
 
1725
                static internal ulong GetPixel (Cairo.Color color)
 
1726
                {
 
1727
                        return GetPixel ((Gdk.Color) ((HslColor)color));
 
1728
                }
 
1729
 
 
1730
                internal bool InSelectionDrag = false;
 
1731
                internal bool inDrag = false;
 
1732
                internal DocumentLocation clickLocation;
1596
1733
                int mouseWordStart, mouseWordEnd;
1597
1734
                enum MouseSelectionMode
1598
1735
                {
1602
1739
                }
1603
1740
                MouseSelectionMode mouseSelectionMode = MouseSelectionMode.SingleChar;
1604
1741
 
 
1742
                internal bool CalculateClickLocation (double x, double y, out DocumentLocation clickLocation)
 
1743
                {
 
1744
                        VisualLocationTranslator trans = new VisualLocationTranslator (this);
 
1745
 
 
1746
                        clickLocation = trans.PointToLocation (x, y);
 
1747
                        if (clickLocation.Line < DocumentLocation.MinLine || clickLocation.Column < DocumentLocation.MinColumn)
 
1748
                                return false;
 
1749
                        DocumentLine line = Document.GetLine (clickLocation.Line);
 
1750
                        if (line != null && clickLocation.Column >= line.Length + 1 && GetWidth (Document.GetTextAt (line.SegmentIncludingDelimiter) + "-") < x) {
 
1751
                                clickLocation = new DocumentLocation (clickLocation.Line, line.Length + 1);
 
1752
                                if (textEditor.GetTextEditorData ().HasIndentationTracker && textEditor.Options.IndentStyle == IndentStyle.Virtual && clickLocation.Column == 1) {
 
1753
                                        int indentationColumn = this.textEditor.GetTextEditorData ().GetVirtualIndentationColumn (clickLocation);
 
1754
                                        if (indentationColumn > clickLocation.Column)
 
1755
                                                clickLocation = new DocumentLocation (clickLocation.Line, indentationColumn);
 
1756
                                }
 
1757
                        }
 
1758
                        return true;
 
1759
                }
 
1760
 
1605
1761
                protected internal override void MousePressed (MarginMouseEventArgs args)
1606
1762
                {
1607
1763
                        base.MousePressed (args);
1609
1765
                        if (args.TriggersContextMenu ())
1610
1766
                                return;
1611
1767
                        
1612
 
                        inSelectionDrag = false;
 
1768
                        InSelectionDrag = false;
1613
1769
                        inDrag = false;
1614
1770
                        Selection selection = textEditor.MainSelection;
1615
 
                        int anchor = selection != null ? selection.GetAnchorOffset (this.textEditor.GetTextEditorData ()) : -1;
1616
1771
                        int oldOffset = textEditor.Caret.Offset;
1617
1772
 
1618
1773
                        string link = GetLink != null ? GetLink (args) : null;
1622
1777
                        }
1623
1778
 
1624
1779
                        if (args.Button == 1) {
1625
 
                                VisualLocationTranslator trans = new VisualLocationTranslator (this);
1626
 
                                clickLocation = trans.PointToLocation (args.X, args.Y);
1627
 
                                if (clickLocation.Line < DocumentLocation.MinLine || clickLocation.Column < DocumentLocation.MinColumn)
 
1780
                                if (!CalculateClickLocation (args.X, args.Y, out clickLocation))
1628
1781
                                        return;
 
1782
 
1629
1783
                                DocumentLine line = Document.GetLine (clickLocation.Line);
1630
1784
                                bool isHandled = false;
1631
1785
                                if (line != null) {
1632
 
                                        foreach (TextMarker marker in line.Markers) {
1633
 
                                                if (marker is IActionTextMarker) {
1634
 
                                                        isHandled |= ((IActionTextMarker)marker).MousePressed (this.textEditor, args);
 
1786
                                        foreach (TextLineMarker marker in line.Markers) {
 
1787
                                                if (marker is IActionTextLineMarker) {
 
1788
                                                        isHandled |= ((IActionTextLineMarker)marker).MousePressed (textEditor, args);
 
1789
                                                        if (isHandled)
 
1790
                                                                break;
 
1791
                                                }
 
1792
                                        }
 
1793
                                        foreach (var marker in Document.GetTextSegmentMarkersAt (line).Where (m => m.IsVisible)) {
 
1794
                                                if (marker is IActionTextLineMarker) {
 
1795
                                                        isHandled |= ((IActionTextLineMarker)marker).MousePressed (textEditor, args);
1635
1796
                                                        if (isHandled)
1636
1797
                                                                break;
1637
1798
                                                }
1639
1800
                                }
1640
1801
                                if (isHandled)
1641
1802
                                        return;
1642
 
                                if (line != null && clickLocation.Column >= line.Length + 1 && GetWidth (Document.GetTextAt (line.SegmentIncludingDelimiter) + "-") < args.X) {
1643
 
                                        clickLocation = new DocumentLocation (clickLocation.Line, line.Length + 1);
1644
 
                                        if (textEditor.GetTextEditorData ().HasIndentationTracker && textEditor.Options.IndentStyle == IndentStyle.Virtual) {
1645
 
                                                int indentationColumn = this.textEditor.GetTextEditorData ().GetVirtualIndentationColumn (clickLocation);
1646
 
                                                if (indentationColumn > clickLocation.Column)
1647
 
                                                        clickLocation = new DocumentLocation (clickLocation.Line, indentationColumn);
1648
 
                                        }
1649
 
                                }
1650
1803
 
1651
1804
                                int offset = Document.LocationToOffset (clickLocation);
1652
1805
                                if (offset < 0) {
1653
1806
                                        textEditor.RunAction (CaretMoveActions.ToDocumentEnd);
1654
1807
                                        return;
1655
1808
                                }
1656
 
                                if (args.Button == 2 && selection != null && selection.Contains (Document.OffsetToLocation (offset))) {
 
1809
                                if (args.Button == 2 && !selection.IsEmpty && selection.Contains (Document.OffsetToLocation (offset))) {
1657
1810
                                        textEditor.ClearSelection ();
1658
1811
                                        return;
1659
1812
                                }
1664
1817
                                        mouseWordEnd = data.FindCurrentWordEnd (offset);
1665
1818
                                        Caret.Offset = mouseWordEnd;
1666
1819
                                        textEditor.MainSelection = new Selection (textEditor.Document.OffsetToLocation (mouseWordStart), textEditor.Document.OffsetToLocation (mouseWordEnd));
1667
 
                                        inSelectionDrag = true;
 
1820
                                        InSelectionDrag = true;
1668
1821
                                        mouseSelectionMode = MouseSelectionMode.Word;
 
1822
 
 
1823
                                        // folding marker
 
1824
                                        int lineNr = args.LineNumber;
 
1825
                                        foreach (var shownFolding in GetFoldRectangles (lineNr)) {
 
1826
                                                if (shownFolding.Item1.Contains ((int)(args.X + this.XOffset), (int)args.Y)) {
 
1827
                                                        shownFolding.Item2.IsFolded = false;
 
1828
                                                        return;
 
1829
                                                }
 
1830
                                        }
1669
1831
                                        return;
1670
1832
                                } else if (args.Type == EventType.ThreeButtonPress) {
1671
1833
                                        int lineNr = Document.OffsetToLineNumber (offset);
1675
1837
                                        mouseWordStart = range.Offset;
1676
1838
                                        mouseWordEnd = range.EndOffset;
1677
1839
 
1678
 
                                        inSelectionDrag = true;
 
1840
                                        InSelectionDrag = true;
1679
1841
                                        mouseSelectionMode = MouseSelectionMode.WholeLine;
1680
1842
                                        return;
1681
1843
                                }
1685
1847
                                        inDrag = true;
1686
1848
                                } else {
1687
1849
                                        if ((args.ModifierState & Gdk.ModifierType.ShiftMask) == ModifierType.ShiftMask) {
1688
 
                                                inSelectionDrag = true;
 
1850
                                                InSelectionDrag = true;
1689
1851
                                                Caret.PreserveSelection = true;
1690
1852
                                                if (!textEditor.IsSomethingSelected) {
1691
1853
                                                        textEditor.MainSelection = new Selection (Caret.Location, clickLocation);
1696
1858
                                                }
1697
1859
                                                Caret.PreserveSelection = false;
1698
1860
                                        } else {
1699
 
                                                inSelectionDrag = false;
1700
1861
                                                textEditor.ClearSelection ();
1701
1862
                                                Caret.Location = clickLocation;
 
1863
                                                InSelectionDrag = true;
 
1864
                                                textEditor.SetSelection (clickLocation, clickLocation);
1702
1865
                                        }
1703
1866
                                        textEditor.RequestResetCaretBlink ();
1704
1867
                                }
1712
1875
                        if (!Platform.IsWindows && args.Button == 2 && this.textEditor.CanEdit (docLocation.Line)) {
1713
1876
                                TextSegment selectionRange = TextSegment.Invalid;
1714
1877
                                int offset = Document.LocationToOffset (docLocation);
1715
 
                                if (selection != null)
 
1878
                                if (!selection.IsEmpty)
1716
1879
                                        selectionRange = selection.GetSelectionRange (this.textEditor.GetTextEditorData ());
 
1880
                                var oldVersion = textEditor.Document.Version;
1717
1881
 
1718
1882
                                bool autoScroll = textEditor.Caret.AutoScrollToCaret;
1719
1883
                                textEditor.Caret.AutoScrollToCaret = false;
1720
 
                                if (selection != null && selectionRange.Contains (offset)) {
 
1884
                                if (!selection.IsEmpty && selectionRange.Contains (offset)) {
1721
1885
                                        textEditor.ClearSelection ();
1722
1886
                                        textEditor.Caret.Offset = selectionRange.EndOffset;
1723
1887
                                        return;
1724
1888
                                }
1725
1889
 
1726
 
                                int length = ClipboardActions.PasteFromPrimary (textEditor.GetTextEditorData (), offset);
 
1890
                                ClipboardActions.PasteFromPrimary (textEditor.GetTextEditorData (), offset);
1727
1891
                                textEditor.Caret.Offset = oldOffset;
1728
 
                                if (selection != null) {
1729
 
                                        if (offset < selectionRange.EndOffset) {
1730
 
                                                textEditor.SelectionRange = new TextSegment (selectionRange.Offset + length, selectionRange.Length);
1731
 
                                        }
1732
 
                                }
 
1892
                                if (!selectionRange.IsInvalid)
 
1893
                                        textEditor.SelectionRange = new TextSegment (oldVersion.MoveOffsetTo (Document.Version, selectionRange.Offset), selectionRange.Length);
1733
1894
 
1734
1895
                                if (autoScroll)
1735
1896
                                        textEditor.Caret.ActivateAutoScrollWithoutMove ();
1738
1899
 
1739
1900
                protected internal override void MouseReleased (MarginMouseEventArgs args)
1740
1901
                {
1741
 
                        if (args.Button != 2 && !inSelectionDrag)
 
1902
                        if (args.Button != 2 && !InSelectionDrag)
1742
1903
                                textEditor.ClearSelection ();
1743
 
                        inSelectionDrag = false;
 
1904
                        InSelectionDrag = false;
1744
1905
                        if (inDrag)
1745
1906
                                Caret.Location = clickLocation;
1746
1907
                        base.MouseReleased (args);
1747
1908
                }
1748
1909
 
1749
1910
                CodeSegmentPreviewWindow previewWindow = null;
 
1911
 
1750
1912
                public bool IsCodeSegmentPreviewWindowShown {
1751
1913
                        get {
1752
1914
                                return previewWindow != null;
1776
1938
                        CodeSegmentEditorWindow codeSegmentEditorWindow = new CodeSegmentEditorWindow (textEditor);
1777
1939
                        codeSegmentEditorWindow.Move (x, y);
1778
1940
                        codeSegmentEditorWindow.Resize (w, h);
1779
 
                        codeSegmentEditorWindow.SyntaxMode = Document.SyntaxMode;
1780
1941
                        int indentLength = SyntaxMode.GetIndentLength (Document, previewSegment.Offset, previewSegment.Length, false);
1781
1942
 
1782
1943
                        StringBuilder textBuilder = new StringBuilder ();
1799
1960
                }
1800
1961
 
1801
1962
                uint codeSegmentTooltipTimeoutId = 0;
 
1963
 
1802
1964
                void ShowTooltip (TextSegment segment, Rectangle hintRectangle)
1803
1965
                {
1804
1966
                        if (previewWindow != null && previewWindow.Segment == segment)
1808
1970
                        if (segment.IsInvalid || segment.Length == 0)
1809
1971
                                return;
1810
1972
                        codeSegmentTooltipTimeoutId = GLib.Timeout.Add (650, delegate {
1811
 
                                previewWindow = new CodeSegmentPreviewWindow (this.textEditor, false, segment);
 
1973
                                previewWindow = new CodeSegmentPreviewWindow (textEditor, false, segment);
1812
1974
                                if (previewWindow.IsEmptyText) {
1813
1975
                                        previewWindow.Destroy ();
1814
1976
                                        previewWindow = null;
1817
1979
                                        
1818
1980
                                int ox = 0, oy = 0;
1819
1981
                                this.textEditor.GdkWindow.GetOrigin (out ox, out oy);
 
1982
                                ox += textEditor.Allocation.X;
 
1983
                                oy += textEditor.Allocation.Y;
1820
1984
 
1821
 
                                int x = hintRectangle.X + hintRectangle.Width;
1822
 
                                int y = hintRectangle.Y + hintRectangle.Height;
 
1985
                                int x = hintRectangle.Right;
 
1986
                                int y = hintRectangle.Bottom;
1823
1987
                                previewWindow.CalculateSize ();
1824
 
                                int w = previewWindow.SizeRequest ().Width;
1825
 
                                int h = previewWindow.SizeRequest ().Height;
 
1988
                                var req = previewWindow.SizeRequest ();
 
1989
                                int w = req.Width;
 
1990
                                int h = req.Height;
1826
1991
 
1827
 
                                Gdk.Rectangle geometry = this.textEditor.Screen.GetUsableMonitorGeometry (this.textEditor.Screen.GetMonitorAtPoint (ox + x, oy + y));
 
1992
                                var geometry = this.textEditor.Screen.GetUsableMonitorGeometry (this.textEditor.Screen.GetMonitorAtPoint (ox + x, oy + y));
1828
1993
 
1829
1994
                                if (x + ox + w > geometry.X + geometry.Width)
1830
1995
                                        x = hintRectangle.Left - w;
1877
2042
                        get;
1878
2043
                        set;
1879
2044
                }
 
2045
 
1880
2046
                public event EventHandler<LineEventArgs> HoveredLineChanged;
 
2047
 
1881
2048
                protected virtual void OnHoveredLineChanged (LineEventArgs e)
1882
2049
                {
1883
2050
                        EventHandler<LineEventArgs> handler = this.HoveredLineChanged;
1885
2052
                                handler (this, e);
1886
2053
                }
1887
2054
 
1888
 
                List<IActionTextMarker> oldMarkers = new List<IActionTextMarker> ();
1889
 
                List<IActionTextMarker> newMarkers = new List<IActionTextMarker> ();
 
2055
                List<IActionTextLineMarker> oldMarkers = new List<IActionTextLineMarker> ();
 
2056
                List<IActionTextLineMarker> newMarkers = new List<IActionTextLineMarker> ();
1890
2057
                protected internal override void MouseHover (MarginMouseEventArgs args)
1891
2058
                {
1892
 
                        base.MouseHover (args);
1893
 
 
1894
2059
                        var loc = PointToLocation (args.X, args.Y);
1895
2060
                        if (loc.Line < DocumentLocation.MinLine || loc.Column < DocumentLocation.MinColumn)
1896
2061
                                return;
1899
2064
                        HoveredLine = line;
1900
2065
                        OnHoveredLineChanged (new LineEventArgs (oldHoveredLine));
1901
2066
 
1902
 
                        var hoverResult = new TextMarkerHoverResult ();
1903
 
                        oldMarkers.ForEach (m => m.MouseHover (this.textEditor, args, hoverResult));
 
2067
                        var hoverResult = new TextLineMarkerHoverResult ();
 
2068
                        oldMarkers.ForEach (m => m.MouseHover (textEditor, args, hoverResult));
1904
2069
 
1905
2070
                        if (line != null) {
1906
2071
                                newMarkers.Clear ();
1907
 
                                newMarkers.AddRange (line.Markers.Where (m => m is IActionTextMarker).Cast <IActionTextMarker> ());
1908
 
                                var extraMarker = Document.GetExtendingTextMarker (loc.Line) as IActionTextMarker;
 
2072
                                newMarkers.AddRange (line.Markers.Where (m => m is IActionTextLineMarker).Cast <IActionTextLineMarker> ());
 
2073
                                var extraMarker = Document.GetExtendingTextMarker (loc.Line) as IActionTextLineMarker;
1909
2074
                                if (extraMarker != null && !oldMarkers.Contains (extraMarker))
1910
2075
                                        newMarkers.Add (extraMarker);
1911
2076
                                foreach (var marker in newMarkers.Where (m => !oldMarkers.Contains (m))) {
1912
 
                                        marker.MouseHover (this.textEditor, args, hoverResult);
 
2077
                                        marker.MouseHover (textEditor, args, hoverResult);
1913
2078
                                }
1914
2079
                                oldMarkers.Clear ();
1915
2080
                                var tmp = oldMarkers;
1916
2081
                                oldMarkers = newMarkers;
1917
2082
                                newMarkers = tmp;
 
2083
                                foreach (var marker in Document.GetTextSegmentMarkersAt (line).Where (m => m.IsVisible)) {
 
2084
                                        if (marker is IActionTextLineMarker) {
 
2085
                                                ((IActionTextLineMarker)marker).MouseHover (textEditor, args, hoverResult);
 
2086
                                        }
 
2087
                                }
1918
2088
                        } else {
1919
2089
                                oldMarkers.Clear ();
1920
2090
                        }
1921
 
                        base.cursor = hoverResult.Cursor ?? xtermCursor;
 
2091
                        base.cursor = hoverResult.HasCursor ? hoverResult.Cursor : xtermCursor;
1922
2092
                        if (textEditor.TooltipMarkup != hoverResult.TooltipMarkup) {
1923
2093
                                textEditor.TooltipMarkup = null;
1924
2094
                                textEditor.TriggerTooltipQuery ();
1925
2095
                        }
1926
 
                        textEditor.TooltipMarkup = hoverResult.TooltipMarkup;
1927
 
 
 
2096
                        if (!textEditor.GetTextEditorData ().SuppressTooltips)
 
2097
                                textEditor.TooltipMarkup = hoverResult.TooltipMarkup;
1928
2098
                        if (args.Button != 1 && args.Y >= 0 && args.Y <= this.textEditor.Allocation.Height) {
1929
2099
                                // folding marker
1930
2100
                                int lineNr = args.LineNumber;
1931
 
                                foreach (KeyValuePair<Rectangle, FoldSegment> shownFolding in GetFoldRectangles (lineNr)) {
1932
 
                                        if (shownFolding.Key.Contains ((int)(args.X + this.XOffset), (int)args.Y)) {
1933
 
                                                ShowTooltip (shownFolding.Value.Segment, shownFolding.Key);
 
2101
                                foreach (var shownFolding in GetFoldRectangles (lineNr)) {
 
2102
                                        if (shownFolding.Item1.Contains ((int)(args.X + this.XOffset), (int)args.Y)) {
 
2103
                                                ShowTooltip (shownFolding.Item2.Segment, shownFolding.Item1);
1934
2104
                                                return;
1935
2105
                                        }
1936
2106
                                }
1941
2111
                                if (!String.IsNullOrEmpty (link)) {
1942
2112
                                        base.cursor = textLinkCursor;
1943
2113
                                } else {
1944
 
                                        base.cursor = hoverResult.Cursor ?? xtermCursor;
 
2114
                                        base.cursor = hoverResult.HasCursor ? hoverResult.Cursor : xtermCursor;
1945
2115
                                }
1946
2116
                                return;
1947
2117
                        }
1952
2122
 
1953
2123
                        switch (this.mouseSelectionMode) {
1954
2124
                        case MouseSelectionMode.SingleChar:
1955
 
                                if (!inSelectionDrag) {
 
2125
                                if (!InSelectionDrag) {
1956
2126
                                        textEditor.SetSelection (loc, loc);
1957
2127
                                } else {
1958
2128
                                        textEditor.ExtendSelectionTo (loc);
1973
2143
                                        end = data.FindCurrentWordEnd (offset);
1974
2144
                                        Caret.Offset = end;
1975
2145
                                }
1976
 
                                if (textEditor.MainSelection != null) {
1977
 
                                        textEditor.MainSelection.Lead = Caret.Location;
 
2146
                                if (!textEditor.MainSelection.IsEmpty) {
1978
2147
                                        if (Caret.Offset < mouseWordStart) {
1979
 
                                                textEditor.MainSelection.Anchor = Document.OffsetToLocation (mouseWordEnd);
 
2148
                                                textEditor.MainSelection = new Selection (Document.OffsetToLocation (mouseWordEnd), Caret.Location, textEditor.MainSelection.SelectionMode);
1980
2149
                                        } else {
1981
 
                                                textEditor.MainSelection.Anchor = Document.OffsetToLocation (mouseWordStart);
 
2150
                                                textEditor.MainSelection = new Selection (Document.OffsetToLocation (mouseWordStart), Caret.Location, textEditor.MainSelection.SelectionMode);
1982
2151
                                        }
1983
2152
                                }
1984
2153
                                break;
1988
2157
                                DocumentLine line2 = textEditor.Document.GetLineByOffset (textEditor.SelectionAnchor);
1989
2158
                                var o2 = line1.Offset < line2.Offset ? line1.Offset : line1.EndOffsetIncludingDelimiter;
1990
2159
                                Caret.Offset = o2;
1991
 
                                if (textEditor.MainSelection != null) {
1992
 
                                        textEditor.MainSelection.Lead = Caret.Location;
 
2160
                                if (!textEditor.MainSelection.IsEmpty) {
1993
2161
                                        if (mouseWordStart < o2) {
1994
 
                                                textEditor.MainSelection.Anchor = textEditor.OffsetToLocation (mouseWordStart);
 
2162
                                                textEditor.MainSelection = new Selection (textEditor.OffsetToLocation (mouseWordStart), Caret.Location, textEditor.MainSelection.SelectionMode);
1995
2163
                                        } else {
1996
 
                                                textEditor.MainSelection.Anchor = textEditor.OffsetToLocation (mouseWordEnd);
1997
 
 
 
2164
                                                textEditor.MainSelection = new Selection (textEditor.OffsetToLocation (mouseWordEnd), Caret.Location, textEditor.MainSelection.SelectionMode);
1998
2165
                                        }
1999
2166
                                }
2000
2167
 
2004
2171
 
2005
2172
                        //HACK: use cmd as Mac block select modifier because GTK currently makes it impossible to access alt/mod1
2006
2173
                        //NOTE: Mac cmd seems to be mapped as ControlMask from mouse events on older GTK, mod1 on newer
2007
 
                        var blockSelModifier = !Platform.IsMac? ModifierType.Mod1Mask
 
2174
                        var blockSelModifier = !Platform.IsMac ? ModifierType.Mod1Mask
2008
2175
                                : (ModifierType.ControlMask | ModifierType.Mod1Mask);
2009
2176
 
2010
2177
                        //NOTE: also allow super for block select on X11 because most window managers use the alt modifier already
2018
2185
                                        Document.CommitMultipleLineUpdate (textEditor.MainSelection.MinLine, textEditor.MainSelection.MaxLine);
2019
2186
                                textEditor.SelectionMode = SelectionMode.Normal;
2020
2187
                        }
2021
 
                        inSelectionDrag = true;
 
2188
                        InSelectionDrag = true;
 
2189
                        base.MouseHover (args);
 
2190
 
2022
2191
                }
2023
2192
 
2024
2193
                public static int GetNextTabstop (TextEditorData textEditor, int currentColumn)
2037
2206
                public int GetWidth (string text)
2038
2207
                {
2039
2208
                        text = text.Replace ("\t", new string (' ', textEditor.Options.TabSize));
2040
 
                        markerLayout.SetText (text);
 
2209
                        defaultLayout.SetText (text);
2041
2210
                        int width, height;
2042
 
                        markerLayout.GetPixelSize (out width, out height);
 
2211
                        defaultLayout.GetPixelSize (out width, out height);
2043
2212
                        return width;
2044
2213
                }
2045
2214
 
2050
2219
                                                      color.B * dimFactor);
2051
2220
                        return result;
2052
2221
                }
 
2222
 
2053
2223
                internal static Cairo.Color DimColor (Cairo.Color color)
2054
2224
                {
2055
2225
                        return DimColor (color, 0.95);
2061
2231
                        if (isDefaultColor && !drawDefaultBackground)
2062
2232
                                return;
2063
2233
                        cr.Color = color;
2064
 
                        double xp = /*System.Math.Floor*/ (area.X);
2065
 
                        
 
2234
                        var left = (int)(area.X);
 
2235
                        var width = (int)area.Width + 1;
2066
2236
                        if (textEditor.Options.ShowRuler) {
2067
 
                                double divider = System.Math.Max (area.X, System.Math.Min (x + TextStartPosition + rulerX, area.X + area.Width));
2068
 
                                if (divider < area.X + area.Width) {
2069
 
                                        cr.Rectangle (xp, area.Y, divider - area.X, area.Height);
2070
 
                                        cr.Fill ();
2071
 
                                        
2072
 
                                        cr.Rectangle (divider, area.Y, area.X + area.Width - divider, area.Height);
 
2237
                                var right = left + width;
 
2238
 
 
2239
                                var divider = (int) (System.Math.Max (left, System.Math.Min (x + TextStartPosition + rulerX, right)));
 
2240
                                if (divider < right) {
 
2241
                                        var beforeDividerWidth = divider - left;
 
2242
                                        if (beforeDividerWidth > 0) {
 
2243
                                                cr.Rectangle (left, area.Y, beforeDividerWidth, area.Height);
 
2244
                                                cr.Fill ();
 
2245
                                        }
 
2246
                                        cr.Rectangle (divider, area.Y, right - divider, area.Height);
2073
2247
                                        cr.Color = DimColor (color);
2074
2248
                                        cr.Fill ();
2075
 
                                        cr.DrawLine (ColorStyle.Ruler, divider, area.Y, divider, area.Y + area.Height);
 
2249
 
 
2250
                                        if (beforeDividerWidth > 0) {
 
2251
                                                cr.DrawLine (
 
2252
                                                        ColorStyle.Ruler.Color,
 
2253
                                                        divider + 0.5, area.Y,
 
2254
                                                        divider + 0.5, area.Y + area.Height);
 
2255
                                        }
2076
2256
                                        return;
2077
2257
                                }
2078
2258
                        }
2079
 
                        cr.Rectangle (xp, area.Y, area.Width, area.Height);
 
2259
 
 
2260
                        cr.Rectangle (left, area.Y, System.Math.Ceiling (area.Width), area.Height);
2080
2261
                        cr.Fill ();
2081
2262
                }
2082
2263
 
2083
 
                List<System.Collections.Generic.KeyValuePair<Gdk.Rectangle, FoldSegment>> GetFoldRectangles (int lineNr)
 
2264
                IEnumerable<Tuple<Gdk.Rectangle, FoldSegment>> GetFoldRectangles (int lineNr)
2084
2265
                {
2085
 
                        List<System.Collections.Generic.KeyValuePair<Gdk.Rectangle, FoldSegment>> result = new List<System.Collections.Generic.KeyValuePair<Gdk.Rectangle, FoldSegment>> ();
2086
2266
                        if (lineNr < 0)
2087
 
                                return result;
 
2267
                                yield break;
2088
2268
 
2089
 
                        DocumentLine line = lineNr <= Document.LineCount ? Document.GetLine (lineNr) : null;
 
2269
                        var line = lineNr <= Document.LineCount ? Document.GetLine (lineNr) : null;
2090
2270
                        //                      int xStart = XOffset;
2091
2271
                        int y = (int)(LineToY (lineNr) - textEditor.VAdjustment.Value);
2092
2272
                        //                      Gdk.Rectangle lineArea = new Gdk.Rectangle (XOffset, y, textEditor.Allocation.Width - XOffset, LineHeight);
2093
2273
                        int width, height;
2094
 
                        int xPos = (int)(XOffset - textEditor.HAdjustment.Value);
2095
 
 
2096
 
                        if (line == null) {
2097
 
                                return result;
2098
 
                        }
2099
 
 
2100
 
                        IEnumerable<FoldSegment> foldings = Document.GetStartFoldings (line);
 
2274
                        var xPos = this.XOffset + this.TextStartPosition - textEditor.HAdjustment.Value;
 
2275
 
 
2276
                        if (line == null)
 
2277
                                yield break;
 
2278
 
 
2279
                        var foldings = Document.GetStartFoldings (line);
2101
2280
                        int offset = line.Offset;
 
2281
                        double foldXMargin = foldMarkerXMargin * textEditor.Options.Zoom;
2102
2282
                        restart:
2103
 
                        //                      int caretOffset = Caret.Offset;
2104
 
                        foreach (FoldSegment folding in foldings) {
2105
 
                                int foldOffset = folding.StartLine.Offset + folding.Column - 1;
2106
 
                                if (foldOffset < offset)
2107
 
                                        continue;
2108
 
 
2109
 
                                if (folding.IsFolded) {
2110
 
                                        markerLayout.SetText (Document.GetTextAt (offset, System.Math.Max (0, System.Math.Min (foldOffset - offset, Document.TextLength - offset))).Replace ("\t", new string (' ', textEditor.Options.TabSize)));
2111
 
                                        markerLayout.GetPixelSize (out width, out height);
2112
 
                                        xPos += width;
2113
 
                                        offset = folding.EndLine.Offset + folding.EndColumn;
2114
 
 
2115
 
                                        markerLayout.SetText (folding.Description);
2116
 
                                        markerLayout.GetPixelSize (out width, out height);
2117
 
                                        Rectangle foldingRectangle = new Rectangle (xPos, y, width - 1, (int)this.LineHeight - 1);
2118
 
                                        result.Add (new KeyValuePair<Rectangle, FoldSegment> (foldingRectangle, folding));
2119
 
                                        xPos += width;
2120
 
                                        if (folding.EndLine != line) {
2121
 
                                                line = folding.EndLine;
2122
 
                                                foldings = Document.GetStartFoldings (line);
2123
 
                                                goto restart;
 
2283
                        using (var calcTextLayout = PangoUtil.CreateLayout (textEditor))
 
2284
                        using (var calcFoldingLayout = PangoUtil.CreateLayout (textEditor)) {
 
2285
                                calcTextLayout.FontDescription = textEditor.Options.Font;
 
2286
                                calcTextLayout.Tabs = this.tabArray;
 
2287
 
 
2288
                                calcFoldingLayout.FontDescription = markerLayout.FontDescription;
 
2289
                                calcFoldingLayout.Tabs = this.tabArray;
 
2290
                                foreach (var folding in foldings) {
 
2291
                                        int foldOffset = folding.StartLine.Offset + folding.Column - 1;
 
2292
                                        if (foldOffset < offset)
 
2293
                                                continue;
 
2294
 
 
2295
                                        if (folding.IsFolded) {
 
2296
                                                var txt = Document.GetTextAt (offset, System.Math.Max (0, System.Math.Min (foldOffset - offset, Document.TextLength - offset)));
 
2297
                                                calcTextLayout.SetText (txt);
 
2298
                                                calcTextLayout.GetSize (out width, out height);
 
2299
                                                xPos += width / Pango.Scale.PangoScale;
 
2300
                                                offset = folding.EndLine.Offset + folding.EndColumn;
 
2301
 
 
2302
                                                calcFoldingLayout.SetText (folding.Description);
 
2303
 
 
2304
                                                calcFoldingLayout.GetSize (out width, out height);
 
2305
 
 
2306
                                                var pixelWidth = width / Pango.Scale.PangoScale + foldXMargin * 2;
 
2307
 
 
2308
                                                var foldingRectangle = new Rectangle ((int)xPos, y, (int)pixelWidth, (int)LineHeight - 1);
 
2309
                                                yield return Tuple.Create (foldingRectangle, folding);
 
2310
                                                xPos += pixelWidth;
 
2311
                                                if (folding.EndLine != line) {
 
2312
                                                        line = folding.EndLine;
 
2313
                                                        foldings = Document.GetStartFoldings (line);
 
2314
                                                        goto restart;
 
2315
                                                }
2124
2316
                                        }
2125
2317
                                }
2126
2318
                        }
2127
 
                        return result;
2128
2319
                }
2129
2320
 
2130
2321
                List<TextSegment> selectedRegions = new List<TextSegment> ();
 
2322
 
2131
2323
                public int SearchResultMatchCount {
2132
2324
                        get {
2133
2325
                                return selectedRegions.Count;
2134
2326
                        }
2135
2327
                }
 
2328
 
2136
2329
                public IEnumerable<TextSegment> SearchResults {
2137
2330
                        get {
2138
2331
                                return selectedRegions;
2140
2333
                }
2141
2334
 
2142
2335
                TextSegment mainSearchResult;
 
2336
 
2143
2337
                public TextSegment MainSearchResult {
2144
2338
                        get {
2145
2339
                                return mainSearchResult;
2151
2345
                }
2152
2346
                
2153
2347
                public event EventHandler MainSearchResultChanged;
 
2348
 
2154
2349
                protected virtual void OnMainSearchResultChanged (EventArgs e)
2155
2350
                {
2156
2351
                        EventHandler handler = this.MainSearchResultChanged;
2166
2361
                        }
2167
2362
                }
2168
2363
 
 
2364
                [Flags]
 
2365
                public enum CairoCorners
 
2366
                {
 
2367
                        None = 0,
 
2368
                        TopLeft = 1,
 
2369
                        TopRight = 2,
 
2370
                        BottomLeft = 4,
 
2371
                        BottomRight = 8,
 
2372
                        All = 15
 
2373
                }
 
2374
 
 
2375
                public static void RoundedRectangle(Cairo.Context cr, double x, double y, double w, double h,
 
2376
                                                    double r, CairoCorners corners, bool topBottomFallsThrough)
 
2377
                {
 
2378
                        if(topBottomFallsThrough && corners == CairoCorners.None) {
 
2379
                                cr.MoveTo(x, y - r);
 
2380
                                cr.LineTo(x, y + h + r);
 
2381
                                cr.MoveTo(x + w, y - r);
 
2382
                                cr.LineTo(x + w, y + h + r);
 
2383
                                return;
 
2384
                        } else if(r < 0.0001 || corners == CairoCorners.None) {
 
2385
                                cr.Rectangle(x, y, w, h);
 
2386
                                return;
 
2387
                        }
 
2388
                        
 
2389
                        if((corners & (CairoCorners.TopLeft | CairoCorners.TopRight)) == 0 && topBottomFallsThrough) {
 
2390
                                y -= r;
 
2391
                                h += r;
 
2392
                                cr.MoveTo(x + w, y);
 
2393
                        } else {
 
2394
                                if((corners & CairoCorners.TopLeft) != 0) {
 
2395
                                        cr.MoveTo(x + r, y);
 
2396
                                } else {
 
2397
                                        cr.MoveTo(x, y);
 
2398
                                }
 
2399
                                if((corners & CairoCorners.TopRight) != 0) {
 
2400
                                        cr.Arc(x + w - r, y + r, r, System.Math.PI * 1.5, System.Math.PI * 2);
 
2401
                                } else {
 
2402
                                        cr.LineTo(x + w, y);
 
2403
                                }
 
2404
                        }
 
2405
                        
 
2406
                        if((corners & (CairoCorners.BottomLeft | CairoCorners.BottomRight)) == 0 && topBottomFallsThrough) {
 
2407
                                h += r;
 
2408
                                cr.LineTo(x + w, y + h);
 
2409
                                cr.MoveTo(x, y + h);
 
2410
                                cr.LineTo(x, y + r);
 
2411
                                cr.Arc(x + r, y + r, r, System.Math.PI, System.Math.PI * 1.5);
 
2412
                        } else {
 
2413
                                if((corners & CairoCorners.BottomRight) != 0) {
 
2414
                                        cr.Arc(x + w - r, y + h - r, r, 0, System.Math.PI * 0.5);
 
2415
                                } else {
 
2416
                                        cr.LineTo(x + w, y + h);
 
2417
                                }
 
2418
                                
 
2419
                                if((corners & CairoCorners.BottomLeft) != 0) {
 
2420
                                        cr.Arc(x + r, y + h - r, r, System.Math.PI * 0.5, System.Math.PI);
 
2421
                                } else {
 
2422
                                        cr.LineTo(x, y + h);
 
2423
                                }
 
2424
                                
 
2425
                                if((corners & CairoCorners.TopLeft) != 0) {
 
2426
                                        cr.Arc(x + r, y + r, r, System.Math.PI, System.Math.PI * 1.5);
 
2427
                                } else {
 
2428
                                        cr.LineTo(x, y);
 
2429
                                }
 
2430
                        }
 
2431
                }
 
2432
 
 
2433
                const double foldMarkerXMargin = 4.0;
 
2434
 
2169
2435
                protected internal override void Draw (Cairo.Context cr, Cairo.Rectangle area, DocumentLine line, int lineNr, double x, double y, double _lineHeight)
2170
2436
                {
2171
2437
//                      double xStart = System.Math.Max (area.X, XOffset);
2172
2438
//                      xStart = System.Math.Max (0, xStart);
2173
 
                        var lineArea = new Cairo.Rectangle (XOffset - 1, y, textEditor.Allocation.Width - XOffset + 1, _lineHeight);
 
2439
                        var correctedXOffset = System.Math.Floor (XOffset) - 1;
 
2440
                        var lineArea = new Cairo.Rectangle (correctedXOffset, y, textEditor.Allocation.Width - correctedXOffset, _lineHeight);
2174
2441
                        int width, height;
2175
2442
                        double pangoPosition = (x - textEditor.HAdjustment.Value + TextStartPosition) * Pango.Scale.PangoScale;
2176
2443
 
2177
 
                        defaultBgColor = Document.ReadOnly ? ColorStyle.ReadOnlyTextBg : ColorStyle.Default.CairoBackgroundColor;
 
2444
                        defaultBgColor = Document.ReadOnly ? ColorStyle.BackgroundReadOnly.Color : ColorStyle.PlainText.Background;
2178
2445
 
2179
2446
                        // Draw the default back color for the whole line. Colors other than the default
2180
2447
                        // background will be drawn when rendering the text chunks.
2181
 
                        DrawRectangleWithRuler (cr, x, lineArea, defaultBgColor, true);
 
2448
                        if (BackgroundRenderer == null)
 
2449
                                DrawRectangleWithRuler (cr, x, lineArea, defaultBgColor, true);
2182
2450
                        bool isSelectionDrawn = false;
2183
2451
 
2184
 
                        if (BackgroundRenderer != null)
2185
 
                                BackgroundRenderer.Draw (cr, area, line, x, y, _lineHeight);
2186
 
 
2187
2452
                        // Check if line is beyond the document length
2188
2453
                        if (line == null) {
2189
 
                                if (textEditor.Options.ShowInvalidLines)
2190
 
                                        DrawInvalidLineMarker (cr, pangoPosition / Pango.Scale.PangoScale, y);
2191
2454
                                var marker = Document.GetExtendingTextMarker (lineNr);
2192
2455
                                if (marker != null)
2193
2456
                                        marker.Draw (textEditor, cr, lineNr, lineArea);
2200
2463
                        bool isEolFolded = false;
2201
2464
                        restart:
2202
2465
                        int logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn);
2203
 
                        
 
2466
 
 
2467
                        if ((HighlightCaretLine || textEditor.Options.HighlightCaretLine) && Caret.Line == lineNr)
 
2468
                                DrawCaretLineMarker (cr, x, y, TextStartPosition, _lineHeight);
 
2469
 
2204
2470
                        foreach (FoldSegment folding in foldings) {
2205
2471
                                int foldOffset = folding.StartLine.Offset + folding.Column - 1;
2206
2472
                                if (foldOffset < offset)
2208
2474
 
2209
2475
                                if (folding.IsFolded) {
2210
2476
                                        
2211
 
                                        DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, foldOffset - offset, ref pangoPosition, ref isSelectionDrawn, y, area.X + area.Width);
 
2477
                                        DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, foldOffset - offset, ref pangoPosition, ref isSelectionDrawn, y, area.X + area.Width, _lineHeight);
2212
2478
                                        
2213
 
                                        offset = folding.EndLine.Offset + folding.EndColumn;
 
2479
                                        offset = folding.EndLine.Offset + folding.EndColumn - 1;
2214
2480
                                        markerLayout.SetText (folding.Description);
2215
2481
                                        markerLayout.GetSize (out width, out height);
2216
2482
                                        
2217
2483
                                        bool isFoldingSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (folding.Segment);
2218
 
                                        double pixelX = pangoPosition / Pango.Scale.PangoScale;
2219
 
                                        double pixelWidth = (pangoPosition + width) / Pango.Scale.PangoScale - pixelX;
2220
 
                                        var foldingRectangle = new Cairo.Rectangle (pixelX + 0.5, y + 0.5, pixelWidth - cr.LineWidth, this.LineHeight - cr.LineWidth);
2221
 
                                        if (BackgroundRenderer == null) {
2222
 
                                                cr.Color = isFoldingSelected ? SelectionColor.CairoBackgroundColor : defaultBgColor;
 
2484
                                        double pixelX = 0.5 + System.Math.Floor (pangoPosition / Pango.Scale.PangoScale);
 
2485
                                        double foldXMargin = foldMarkerXMargin * textEditor.Options.Zoom;
 
2486
                                        double pixelWidth = System.Math.Floor ((pangoPosition + width) / Pango.Scale.PangoScale - pixelX + foldXMargin * 2);
 
2487
                                        var foldingRectangle = new Cairo.Rectangle (
 
2488
                                                pixelX, 
 
2489
                                                y, 
 
2490
                                                pixelWidth, 
 
2491
                                                this.LineHeight);
 
2492
 
 
2493
                                        if (BackgroundRenderer == null && isFoldingSelected) {
 
2494
                                                cr.Color = SelectionColor.Background;
2223
2495
                                                cr.Rectangle (foldingRectangle);
2224
2496
                                                cr.Fill ();
2225
2497
                                        }
2226
 
                                        
2227
 
                                        cr.Color = isFoldingSelected ? SelectionColor.CairoColor : ColorStyle.FoldLine.CairoColor;
2228
 
                                        cr.Rectangle (foldingRectangle);
 
2498
 
 
2499
                                        if (isFoldingSelected && SelectionColor.TransparentForeground) {
 
2500
                                                cr.Color = ColorStyle.CollapsedText.Foreground;
 
2501
                                        } else {
 
2502
                                                cr.Color = isFoldingSelected ? SelectionColor.Foreground : ColorStyle.CollapsedText.Foreground;
 
2503
                                        }
 
2504
                                        var boundingRectangleHeight = foldingRectangle.Height - 1;
 
2505
                                        var boundingRectangleY = System.Math.Floor (foldingRectangle.Y + (foldingRectangle.Height - boundingRectangleHeight) / 2);
 
2506
                                        RoundedRectangle (cr,
 
2507
                                                         System.Math.Floor (foldingRectangle.X) + 0.5,
 
2508
                                                         boundingRectangleY + 0.5,
 
2509
                                                         System.Math.Floor (foldingRectangle.Width - cr.LineWidth),
 
2510
                                                         System.Math.Floor (boundingRectangleHeight - cr.LineWidth),
 
2511
                                                         LineHeight / 8, CairoCorners.All, false);
2229
2512
                                        cr.Stroke ();
2230
2513
                                        
2231
2514
                                        cr.Save ();
2232
 
                                        cr.Translate (pangoPosition / Pango.Scale.PangoScale, y);
2233
 
                                        cr.Color = isFoldingSelected ? SelectionColor.CairoColor : ColorStyle.FoldLine.CairoColor;
 
2515
                                        cr.Translate (
 
2516
                                                pangoPosition / Pango.Scale.PangoScale + foldXMargin,
 
2517
                                                System.Math.Floor (boundingRectangleY + (boundingRectangleHeight - System.Math.Floor (height / Pango.Scale.PangoScale)) / 2));
2234
2518
                                        cr.ShowLayout (markerLayout);
2235
2519
                                        cr.Restore ();
2236
 
                                        
2237
2520
 
2238
2521
                                        if (caretOffset == foldOffset && !string.IsNullOrEmpty (folding.Description))
2239
2522
                                                SetVisibleCaretPosition ((int)(pangoPosition / Pango.Scale.PangoScale), y);
2240
 
                                        pangoPosition += width;
 
2523
                                        pangoPosition += foldingRectangle.Width * Pango.Scale.PangoScale;
2241
2524
                                        if (caretOffset == foldOffset + folding.Length && !string.IsNullOrEmpty (folding.Description))
2242
2525
                                                SetVisibleCaretPosition ((int)(pangoPosition / Pango.Scale.PangoScale), y);
2243
2526
 
2254
2537
                        
2255
2538
                        // Draw remaining line - must be called for empty line parts as well because the caret may be at this positon
2256
2539
                        // and the caret position is calculated in DrawLinePart.
2257
 
                        if (line.EndOffsetIncludingDelimiter - offset >= 0)
2258
 
                                DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, line.Offset + line.Length - offset, ref pangoPosition, ref isSelectionDrawn, y, area.X + area.Width);
2259
 
                        
 
2540
                        if (line.EndOffsetIncludingDelimiter - offset >= 0) {
 
2541
                                DrawLinePart (cr, line, lineNr, logicalRulerColumn, offset, line.Offset + line.Length - offset, ref pangoPosition, ref isSelectionDrawn, y, area.X + area.Width, _lineHeight);
 
2542
                        }
 
2543
 
2260
2544
                        bool isEolSelected = !this.HideSelection && textEditor.IsSomethingSelected && textEditor.SelectionMode == SelectionMode.Normal && textEditor.SelectionRange.Contains (line.Offset + line.Length);
2261
 
                        lineArea = new Cairo.Rectangle (pangoPosition / Pango.Scale.PangoScale,
 
2545
                        var lx = (int)(pangoPosition / Pango.Scale.PangoScale);
 
2546
                        lineArea = new Cairo.Rectangle (lx,
2262
2547
                                lineArea.Y,
2263
 
                                textEditor.Allocation.Width - pangoPosition / Pango.Scale.PangoScale,
 
2548
                                textEditor.Allocation.Width - lx,
2264
2549
                                lineArea.Height);
2265
2550
 
2266
2551
                        if (textEditor.SelectionMode == SelectionMode.Block && textEditor.IsSomethingSelected && textEditor.SelectionRange.Contains (line.Offset + line.Length)) {
2276
2561
                                        x1 = x2;
2277
2562
                                        x2 = tmp;
2278
2563
                                }
2279
 
                                x1 += XOffset - textEditor.HAdjustment.Value;
2280
 
                                x2 += XOffset - textEditor.HAdjustment.Value;
 
2564
                                x1 += correctedXOffset - textEditor.HAdjustment.Value;
 
2565
                                x2 += correctedXOffset - textEditor.HAdjustment.Value;
2281
2566
 
2282
 
                                if (x2 > lineArea.X) {
 
2567
                                if (x2 > lineArea.X && BackgroundRenderer == null)  {
2283
2568
                                        if (x1 - lineArea.X > 0) {
2284
2569
                                                DrawRectangleWithRuler (cr, x, new Cairo.Rectangle (lineArea.X, lineArea.Y, x1 - lineArea.X, lineArea.Height), defaultBgColor, false);
2285
2570
                                                lineArea = new Cairo.Rectangle (x1, lineArea.Y, lineArea.Width, lineArea.Height);
2286
2571
                                        }
2287
 
                                        DrawRectangleWithRuler (cr, x, new Cairo.Rectangle (lineArea.X, lineArea.Y, x2 - lineArea.X, lineArea.Height), this.SelectionColor.CairoBackgroundColor, false);
 
2572
                                        DrawRectangleWithRuler (cr, x, new Cairo.Rectangle (lineArea.X, lineArea.Y, x2 - lineArea.X, lineArea.Height), this.SelectionColor.Background, false);
2288
2573
                                        lineArea = new Cairo.Rectangle (x2, lineArea.Y, textEditor.Allocation.Width - lineArea.X, lineArea.Height);
2289
2574
                                }
2290
2575
                        }
2291
2576
 
2292
 
                        if (!isSelectionDrawn) {
 
2577
                        if (!isSelectionDrawn && BackgroundRenderer == null) {
2293
2578
                                if (isEolSelected) {
2294
 
                                        if (!Platform.IsMac) {
2295
 
                                                // prevent "gaps" in the selection drawing ('fuzzy' lines problem)
2296
 
                                                lineArea = new Cairo.Rectangle (pangoPosition / Pango.Scale.PangoScale,
2297
 
                                                lineArea.Y,
2298
 
                                                textEditor.Allocation.Width - pangoPosition / Pango.Scale.PangoScale + 1,
2299
 
                                                lineArea.Height);
2300
 
                                        } else {
2301
 
                                                // prevent "gaps" in the selection drawing ('fuzzy' lines problem)
2302
 
                                                lineArea = new Cairo.Rectangle (System.Math.Max (pangoPosition / Pango.Scale.PangoScale - 1, XOffset + TextStartPosition),
2303
 
                                                lineArea.Y,
2304
 
                                                textEditor.Allocation.Width - pangoPosition / Pango.Scale.PangoScale + 1,
2305
 
                                                lineArea.Height);
2306
 
                                        }
2307
 
                                        
2308
 
                                        DrawRectangleWithRuler (cr, x, lineArea, this.SelectionColor.CairoBackgroundColor, false);
 
2579
                                        // prevent "gaps" in the selection drawing ('fuzzy' lines problem)
 
2580
                                        var eolStartX = System.Math.Floor (pangoPosition / Pango.Scale.PangoScale);
 
2581
                                        lineArea = new Cairo.Rectangle (
 
2582
                                                eolStartX,
 
2583
                                                lineArea.Y,
 
2584
                                                textEditor.Allocation.Width - eolStartX,
 
2585
                                                lineArea.Height);
 
2586
                                        DrawRectangleWithRuler (cr, x, lineArea, this.SelectionColor.Background, false);
 
2587
                                        if (line.Length == 0)
 
2588
                                                DrawIndent (cr, GetLayout (line), line, lx, y);
2309
2589
                                } else if (!(HighlightCaretLine || textEditor.Options.HighlightCaretLine) || Caret.Line != lineNr) {
2310
2590
                                        LayoutWrapper wrapper = GetLayout (line);
2311
2591
                                        if (wrapper.EolSpanStack != null) {
2312
2592
                                                foreach (var span in wrapper.EolSpanStack) {
2313
2593
                                                        var spanStyle = textEditor.ColorStyle.GetChunkStyle (span.Color);
2314
 
                                                        if (!spanStyle.TransparentBackround && GetPixel (ColorStyle.Default.BackgroundColor) != GetPixel (spanStyle.BackgroundColor)) {
2315
 
                                                                DrawRectangleWithRuler (cr, x, lineArea, spanStyle.CairoBackgroundColor, false);
 
2594
                                                        if (spanStyle == null)
 
2595
                                                                continue;
 
2596
                                                        if (!spanStyle.TransparentBackground && GetPixel (ColorStyle.PlainText.Background) != GetPixel (spanStyle.Background)) {
 
2597
                                                                DrawRectangleWithRuler (cr, x, lineArea, spanStyle.Background, false);
2316
2598
                                                                break;
2317
2599
                                                        }
2318
2600
                                                }
2319
2601
                                        }
2320
2602
                                } else {
2321
2603
                                        double xPos = pangoPosition / Pango.Scale.PangoScale;
2322
 
                                        DrawCaretLineMarker (cr, xPos, y, lineArea.X + lineArea.Width - xPos);
 
2604
                                        DrawCaretLineMarker (cr, xPos, y, lineArea.X + lineArea.Width - xPos, _lineHeight);
2323
2605
                                }
2324
2606
                        }
2325
 
                        
2326
 
                        if (!isEolFolded && textEditor.Options.ShowEolMarkers)
2327
 
                                DrawEolMarker (cr, line, isEolSelected, pangoPosition / Pango.Scale.PangoScale, y);
 
2607
 
 
2608
                        if (textEditor.Options.ShowWhitespaces != ShowWhitespaces.Never) {
 
2609
                                if (!isEolFolded && isEolSelected || textEditor.Options.ShowWhitespaces == ShowWhitespaces.Always)
 
2610
                                        if (!(BackgroundRenderer != null && textEditor.Options.ShowWhitespaces == ShowWhitespaces.Selection))
 
2611
                                                DrawEolMarker (cr, line, isEolSelected, pangoPosition / Pango.Scale.PangoScale, y);
 
2612
                        }
 
2613
 
2328
2614
                        var extendingMarker = Document.GetExtendingTextMarker (lineNr);
2329
2615
                        if (extendingMarker != null)
2330
2616
                                extendingMarker.Draw (textEditor, cr, lineNr, lineArea);
2331
2617
                        
2332
2618
                        lastLineRenderWidth = pangoPosition / Pango.Scale.PangoScale;
 
2619
                        if (textEditor.HAdjustment.Value > 0) {
 
2620
                                cr.LineWidth = textEditor.Options.Zoom;
 
2621
                                for (int i = 0; i < verticalShadowAlphaTable.Length; i++) {
 
2622
                                        cr.Color = new Cairo.Color (0, 0, 0, 1 - verticalShadowAlphaTable[i]);
 
2623
                                        cr.MoveTo (x + i * cr.LineWidth + 0.5, y);
 
2624
                                        cr.LineTo (x + i * cr.LineWidth + 0.5, y + 1 + _lineHeight);
 
2625
                                        cr.Stroke ();
 
2626
                                }
 
2627
                        }
2333
2628
                }
2334
2629
 
2335
 
                internal IBackgroundRenderer BackgroundRenderer {
2336
 
                        get;
2337
 
                        set;
2338
 
                }
 
2630
                static double[] verticalShadowAlphaTable = new [] { 0.71, 0.84, 0.95 };
2339
2631
 
2340
2632
                internal double lastLineRenderWidth = 0;
2341
2633
 
2365
2657
 
2366
2658
                        TextViewMargin.LayoutWrapper layoutWrapper;
2367
2659
                        int index;
 
2660
 
2368
2661
                        bool ConsumeLayout (int xp, int yp)
2369
2662
                        {
2370
2663
                                int trailing;
2385
2678
                                return false;
2386
2679
                        }
2387
2680
 
2388
 
                        public DocumentLocation PointToLocation (double xp, double yp)
 
2681
                        public DocumentLocation PointToLocation (double xp, double yp, bool endAtEol = false)
2389
2682
                        {
2390
2683
                                lineNumber = System.Math.Min (margin.YToLine (yp + margin.textEditor.VAdjustment.Value), margin.Document.LineCount);
2391
2684
                                line = lineNumber <= margin.Document.LineCount ? margin.Document.GetLine (lineNumber) : null;
2394
2687
                                
2395
2688
                                int offset = line.Offset;
2396
2689
                                
2397
 
                                yp = ((int)yp % margin.LineHeight);
2398
2690
                                xp -= margin.TextStartPosition;
2399
2691
                                xp += margin.textEditor.HAdjustment.Value;
2400
2692
                                xp *= Pango.Scale.PangoScale;
2401
 
                                yp *= Pango.Scale.PangoScale;
2402
 
                                yp = System.Math.Max (0, yp);
2403
2693
                                if (xp < 0)
2404
2694
                                        return new DocumentLocation (lineNumber, DocumentLocation.MinColumn);
2405
2695
                                int column = DocumentLocation.MinColumn;
2407
2697
                                IEnumerable<FoldSegment> foldings = margin.Document.GetStartFoldings (line);
2408
2698
                                bool done = false;
2409
2699
                                Pango.Layout measueLayout = null;
2410
 
                                restart:
2411
 
                                int logicalRulerColumn = line.GetLogicalColumn(margin.textEditor.GetTextEditorData(), margin.textEditor.Options.RulerColumn);
2412
 
                                foreach (FoldSegment folding in foldings.Where(f => f.IsFolded))
2413
 
                                {
2414
 
                                        int foldOffset = folding.StartLine.Offset + folding.Column - 1;
2415
 
                                        if (foldOffset < offset)
2416
 
                                                continue;
2417
 
                                        layoutWrapper = margin.CreateLinePartLayout(mode, line, logicalRulerColumn, line.Offset, foldOffset - offset, -1, -1);
2418
 
                                        done |= ConsumeLayout ((int)(xp - xPos), (int)yp);
2419
 
                                        if (done)
2420
 
                                                break;
2421
 
                                        int height, width;
2422
 
                                        layoutWrapper.Layout.GetPixelSize (out width, out height);
2423
 
                                        xPos += width * (int)Pango.Scale.PangoScale;
2424
 
                                        if (measueLayout == null) {
2425
 
                                                measueLayout = PangoUtil.CreateLayout (margin.textEditor, folding.Description);
2426
 
                                                measueLayout.FontDescription = margin.textEditor.Options.Font;
2427
 
                                        }
2428
 
 
2429
 
                                        int delta;
2430
 
                                        measueLayout.GetPixelSize (out delta, out height);
2431
 
                                        delta *= (int)Pango.Scale.PangoScale;
2432
 
                                        xPos += delta;
2433
 
                                        if (xPos - delta / 2 >= xp) {
2434
 
                                                index = foldOffset - offset;
2435
 
                                                done = true;
2436
 
                                                break;
2437
 
                                        }
2438
 
 
2439
 
                                        offset = folding.EndLine.Offset + folding.EndColumn;
2440
 
                                        DocumentLocation foldingEndLocation = margin.Document.OffsetToLocation(offset);
2441
 
                                        lineNumber = foldingEndLocation.Line;
2442
 
                                        column = foldingEndLocation.Column;
2443
 
                                        if (xPos >= xp) {
2444
 
                                                index = 0;
2445
 
                                                done = true;
2446
 
                                                break;
2447
 
                                        }
2448
 
 
2449
 
                                        if (folding.EndLine != line) {
2450
 
                                                line = folding.EndLine;
2451
 
                                                foldings = margin.Document.GetStartFoldings (line);
2452
 
                                                goto restart;
2453
 
                                        }
2454
 
                                }
2455
 
                                if (!done) {
2456
 
                                        layoutWrapper = margin.CreateLinePartLayout(mode, line, logicalRulerColumn, offset, line.Offset + line.Length - offset, -1, -1);
2457
 
                                        ConsumeLayout ((int)(xp - xPos), (int)yp);
2458
 
                                }
2459
 
                                if (measueLayout != null)
2460
 
                                        measueLayout.Dispose ();
 
2700
                                try {
 
2701
                                        restart:
 
2702
                                        int logicalRulerColumn = line.GetLogicalColumn (margin.textEditor.GetTextEditorData (), margin.textEditor.Options.RulerColumn);
 
2703
                                        foreach (FoldSegment folding in foldings.Where(f => f.IsFolded)) {
 
2704
                                                int foldOffset = folding.StartLine.Offset + folding.Column - 1;
 
2705
                                                if (foldOffset < offset)
 
2706
                                                        continue;
 
2707
                                                layoutWrapper = margin.CreateLinePartLayout (mode, line, logicalRulerColumn, line.Offset, foldOffset - offset, -1, -1);
 
2708
                                                done |= ConsumeLayout ((int)(xp - xPos), 0);
 
2709
                                                if (done)
 
2710
                                                        break;
 
2711
                                                int height, width;
 
2712
                                                layoutWrapper.Layout.GetPixelSize (out width, out height);
 
2713
                                                xPos += width * (int)Pango.Scale.PangoScale;
 
2714
                                                if (measueLayout == null) {
 
2715
                                                        measueLayout = PangoUtil.CreateLayout (margin.textEditor, folding.Description);
 
2716
                                                        measueLayout.FontDescription = margin.textEditor.Options.Font;
 
2717
                                                }
 
2718
 
 
2719
                                                int delta;
 
2720
                                                measueLayout.GetPixelSize (out delta, out height);
 
2721
                                                delta *= (int)Pango.Scale.PangoScale;
 
2722
                                                xPos += delta;
 
2723
                                                if (xPos - delta / 2 >= xp) {
 
2724
                                                        index = foldOffset - offset;
 
2725
                                                        done = true;
 
2726
                                                        break;
 
2727
                                                }
 
2728
 
 
2729
                                                offset = folding.EndLine.Offset + folding.EndColumn - 1;
 
2730
                                                DocumentLocation foldingEndLocation = margin.Document.OffsetToLocation (offset);
 
2731
                                                lineNumber = foldingEndLocation.Line;
 
2732
                                                column = foldingEndLocation.Column;
 
2733
                                                if (xPos >= xp) {
 
2734
                                                        index = 0;
 
2735
                                                        done = true;
 
2736
                                                        break;
 
2737
                                                }
 
2738
 
 
2739
                                                if (folding.EndLine != line) {
 
2740
                                                        line = folding.EndLine;
 
2741
                                                        foldings = margin.Document.GetStartFoldings (line);
 
2742
                                                        goto restart;
 
2743
                                                }
 
2744
                                        }
 
2745
                                        if (!done) {
 
2746
                                                layoutWrapper = margin.CreateLinePartLayout (mode, line, logicalRulerColumn, offset, line.Offset + line.Length - offset, -1, -1);
 
2747
                                                if (!ConsumeLayout ((int)(xp - xPos), 0)) {
 
2748
                                                        if (endAtEol)
 
2749
                                                                return DocumentLocation.Empty; 
 
2750
                                                }
 
2751
                                        }
 
2752
                                } finally {
 
2753
                                        if (measueLayout != null)
 
2754
                                                measueLayout.Dispose ();
 
2755
                                }
2461
2756
                                return new DocumentLocation (lineNumber, column + index);
2462
2757
                        }
2463
2758
                }
2464
2759
 
2465
 
                public DocumentLocation PointToLocation (double xp, double yp)
2466
 
                {
2467
 
                        return new VisualLocationTranslator (this).PointToLocation (xp, yp);
2468
 
                }
2469
 
                
2470
 
                public DocumentLocation PointToLocation (Cairo.Point p)
2471
 
                {
2472
 
                        return new VisualLocationTranslator (this).PointToLocation (p.X, p.Y);
2473
 
                }
2474
 
                
2475
 
                public DocumentLocation PointToLocation (Cairo.PointD p)
2476
 
                {
2477
 
                        return new VisualLocationTranslator (this).PointToLocation (p.X, p.Y);
 
2760
                public DocumentLocation PointToLocation (double xp, double yp, bool endAtEol = false)
 
2761
                {
 
2762
                        return new VisualLocationTranslator (this).PointToLocation (xp, yp, endAtEol);
 
2763
                }
 
2764
                
 
2765
                public DocumentLocation PointToLocation (Cairo.Point p, bool endAtEol = false)
 
2766
                {
 
2767
                        return new VisualLocationTranslator (this).PointToLocation (p.X, p.Y, endAtEol);
 
2768
                }
 
2769
                
 
2770
                public DocumentLocation PointToLocation (Cairo.PointD p, bool endAtEol = false)
 
2771
                {
 
2772
                        return new VisualLocationTranslator (this).PointToLocation (p.X, p.Y, endAtEol);
2478
2773
                }
2479
2774
                
2480
2775
                static bool IsNearX1 (int pos, int x1, int x2)
2510
2805
                public double ColumnToX (DocumentLine line, int column)
2511
2806
                {
2512
2807
                        column--;
 
2808
                        // calculate virtual indentation
 
2809
                        if (column > 0 && line.Length == 0 && textEditor.GetTextEditorData ().HasIndentationTracker) {
 
2810
                                using (var l = PangoUtil.CreateLayout (textEditor, textEditor.GetTextEditorData ().IndentationTracker.GetIndentationString (line.Offset))) {
 
2811
                                        l.Alignment = Pango.Alignment.Left;
 
2812
                                        l.FontDescription = textEditor.Options.Font;
 
2813
                                        l.Tabs = tabArray;
 
2814
 
 
2815
                                        Pango.Rectangle ink_rect, logical_rect;
 
2816
                                        l.GetExtents (out ink_rect, out logical_rect);
 
2817
                                        return (logical_rect.Width + Pango.Scale.PangoScale - 1) / Pango.Scale.PangoScale;
 
2818
                                }
 
2819
                        }
2513
2820
                        if (line == null || line.Length == 0 || column < 0)
2514
2821
                                return 0;
2515
2822
                        int logicalRulerColumn = line.GetLogicalColumn (textEditor.GetTextEditorData (), textEditor.Options.RulerColumn);
2551
2858
                        foreach (Chunk chunk in startChunk) {
2552
2859
                                ChunkStyle chunkStyle = chunk != null ? textEditor.ColorStyle.GetChunkStyle (chunk) : null;
2553
2860
 
2554
 
                                foreach (TextMarker marker in line.Markers)
 
2861
                                foreach (TextLineMarker marker in line.Markers)
2555
2862
                                        chunkStyle = marker.GetStyle (chunkStyle);
2556
2863
 
2557
2864
                                if (chunkStyle != null) {
2570
2877
                                        }
2571
2878
 
2572
2879
                                        HandleSelection (lineOffset, logicalRulerColumn, - 1, -1, chunk.Offset, chunk.EndOffset, delegate(int start, int end) {
2573
 
                                                Pango.AttrForeground foreGround = new Pango.AttrForeground (chunkStyle.Color.Red, chunkStyle.Color.Green, chunkStyle.Color.Blue);
 
2880
                                                var color = textEditor.ColorStyle.GetForeground (chunkStyle);
 
2881
                                                Pango.AttrForeground foreGround = new Pango.AttrForeground (
 
2882
                                                        (ushort)(color.R * ushort.MaxValue),
 
2883
                                                        (ushort)(color.G * ushort.MaxValue),
 
2884
                                                        (ushort)(color.B * ushort.MaxValue));
2574
2885
                                                foreGround.StartIndex = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex);
2575
2886
                                                foreGround.EndIndex = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex);
2576
2887
                                                attributes.Add (foreGround);
2577
 
                                                if (!chunkStyle.TransparentBackround) {
2578
 
                                                        var background = new Pango.AttrBackground (chunkStyle.BackgroundColor.Red, chunkStyle.BackgroundColor.Green, chunkStyle.BackgroundColor.Blue);
 
2888
                                                if (!chunkStyle.TransparentBackground) {
 
2889
                                                        color = chunkStyle.Background;
 
2890
                                                        var background = new Pango.AttrBackground (
 
2891
                                                                (ushort)(color.R * ushort.MaxValue),
 
2892
                                                                (ushort)(color.G * ushort.MaxValue),
 
2893
                                                                (ushort)(color.B * ushort.MaxValue));
2579
2894
                                                        background.StartIndex = foreGround.StartIndex;
2580
2895
                                                        background.EndIndex = foreGround.EndIndex;
2581
2896
                                                        attributes.Add (background);
2582
2897
                                                }
2583
2898
                                        }, delegate(int start, int end) {
2584
 
                                                Pango.AttrForeground selectedForeground = new Pango.AttrForeground (SelectionColor.Color.Red, SelectionColor.Color.Green, SelectionColor.Color.Blue);
 
2899
                                                Pango.AttrForeground selectedForeground;
 
2900
                                                if (!SelectionColor.TransparentForeground) {
 
2901
                                                        var color = SelectionColor.Foreground;
 
2902
                                                        selectedForeground = new Pango.AttrForeground (
 
2903
                                                                (ushort)(color.R * ushort.MaxValue),
 
2904
                                                                (ushort)(color.G * ushort.MaxValue),
 
2905
                                                                (ushort)(color.B * ushort.MaxValue));
 
2906
                                                } else {
 
2907
                                                        var color = ColorStyle.GetForeground (chunkStyle);
 
2908
                                                        selectedForeground = new Pango.AttrForeground (
 
2909
                                                                (ushort)(color.R * ushort.MaxValue),
 
2910
                                                                (ushort)(color.G * ushort.MaxValue),
 
2911
                                                                (ushort)(color.B * ushort.MaxValue));
 
2912
                                                } 
2585
2913
                                                selectedForeground.StartIndex = TranslateToUTF8Index (lineChars, (uint)(startIndex + start - chunk.Offset), ref curIndex, ref byteIndex);
2586
2914
                                                selectedForeground.EndIndex = TranslateToUTF8Index (lineChars, (uint)(startIndex + end - chunk.Offset), ref curIndex, ref byteIndex);
2587
2915
                                                attributes.Add (selectedForeground);
2590
2918
                                        var translatedStartIndex = TranslateToUTF8Index (lineChars, (uint)startIndex, ref curChunkIndex, ref byteChunkIndex);
2591
2919
                                        var translatedEndIndex = TranslateToUTF8Index (lineChars, (uint)endIndex, ref curChunkIndex, ref byteChunkIndex);
2592
2920
 
2593
 
                                        if (chunkStyle.Bold) {
2594
 
                                                Pango.AttrWeight attrWeight = new Pango.AttrWeight (Pango.Weight.Bold);
 
2921
                                        if (chunkStyle.FontWeight != Xwt.Drawing.FontWeight.Normal) {
 
2922
                                                Pango.AttrWeight attrWeight = new Pango.AttrWeight ((Pango.Weight)chunkStyle.FontWeight);
2595
2923
                                                attrWeight.StartIndex = translatedStartIndex;
2596
2924
                                                attrWeight.EndIndex = translatedEndIndex;
2597
2925
                                                attributes.Add (attrWeight);
2598
2926
                                        }
2599
2927
 
2600
 
                                        if (chunkStyle.Italic) {
2601
 
                                                Pango.AttrStyle attrStyle = new Pango.AttrStyle (Pango.Style.Italic);
 
2928
                                        if (chunkStyle.FontStyle != Xwt.Drawing.FontStyle.Normal) {
 
2929
                                                Pango.AttrStyle attrStyle = new Pango.AttrStyle ((Pango.Style)chunkStyle.FontStyle);
2602
2930
                                                attrStyle.StartIndex = translatedStartIndex;
2603
2931
                                                attrStyle.EndIndex = translatedEndIndex;
2604
2932
                                                attributes.Add (attrStyle);
2615
2943
                        Pango.AttrList attributeList = new Pango.AttrList ();
2616
2944
                        attributes.ForEach (attr => attributeList.Insert (attr));
2617
2945
                        layout.Attributes = attributeList;
2618
 
                        Pango.Rectangle ink_rect, logical_rect;
2619
 
                        layout.GetExtents (out ink_rect, out logical_rect);
 
2946
                        Pango.Rectangle inkrect, logicalrect;
 
2947
                        layout.GetExtents (out inkrect, out logicalrect);
2620
2948
                        attributes.ForEach (attr => attr.Dispose ());
2621
2949
                        attributeList.Dispose ();
2622
2950
                        layout.Dispose ();
2623
 
                        return (logical_rect.Width + Pango.Scale.PangoScale - 1) / Pango.Scale.PangoScale;
 
2951
                        return (logicalrect.Width + Pango.Scale.PangoScale - 1) / Pango.Scale.PangoScale;
2624
2952
                }
2625
2953
                
2626
2954
                public int YToLine (double yPos)
2655
2983
                        if (line == null)
2656
2984
                                return LineHeight;
2657
2985
                        foreach (var marker in line.Markers) {
2658
 
                                IExtendingTextMarker extendingTextMarker = marker as IExtendingTextMarker;
 
2986
                                IExtendingTextLineMarker extendingTextMarker = marker as IExtendingTextLineMarker;
2659
2987
                                if (extendingTextMarker == null)
2660
2988
                                        continue;
2661
2989
                                return extendingTextMarker.GetLineHeight (textEditor);