2 * Copyright (C) 2013 FooProject
3 * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
6 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
9 You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
12 using System.Collections.Generic;
15 using System.Windows.Controls;
16 using System.Windows.Media;
17 using System.Windows.Media.TextFormatting;
19 namespace FooEditEngine.WPF
21 sealed class WPFRender : IPrintableTextRender, IDisposable
24 double _FontSize, _LineHeight;
25 DrawingContext Context;
29 System.Windows.Media.Color ForegroundColor, BackgroundColor, HilightColor, Keyword1Color, Keyword2Color, LiteralColor, UrlColor, ControlCharColor, CommentColor, InsertCaretColor, OverwriteCaretColor, LineMarkerColor;
30 BrushStockes Brushes = new BrushStockes();
31 PenStockes Pens = new PenStockes();
35 public WPFRender(FontFamily font, double fontSize)
37 this.ChangedRenderResource += (s, e) => { };
38 this.ChangedRightToLeft += (s, e) => { };
39 this.FontFamily = font;
40 this.FontSize = fontSize;
43 public WPFRender(FooTextBox textbox, double width, double height,FrameworkElement image)
45 this.ChangedRenderResource += (s, e) => { };
46 this.ChangedRightToLeft += (s, e) => { };
48 this.FontFamily = textbox.FontFamily;
49 this.FontSize = textbox.FontSize;
50 this.ForegroundColor = textbox.Foreground;
51 this.BackgroundColor = textbox.Background;
52 this.ControlCharColor = textbox.ControlChar;
53 this.HilightColor = textbox.Hilight;
54 this.CommentColor = textbox.Comment;
55 this.UrlColor = textbox.URL;
56 this.Keyword1Color = textbox.Keyword1;
57 this.Keyword2Color = textbox.Keyword2;
58 this.LiteralColor = textbox.Literal;
59 this.InsertCaretColor = textbox.InsertCaret;
60 this.OverwriteCaretColor = textbox.OverwriteCaret;
61 this.LineMarkerColor = textbox.LineMarker;
63 this.host = (VisualHost)image;
66 public event EventHandler ChangedRightToLeft;
68 public TextAntialiasMode TextAntialiasMode
74 public bool ShowFullSpace
80 public bool ShowHalfSpace
92 public bool RightToLeft
94 get { return this._RightToLeft; }
97 this._RightToLeft = value;
98 this.ChangedRightToLeft(this, null);
102 public bool InsertMode
108 public Rectangle TextArea
114 public FontFamily FontFamily
123 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Font));
127 public double FontSize
131 return this._FontSize;
135 this._FontSize = value;
137 TextLayout layout = new TextLayout("0", this.FontFamily, this.FontSize, Brushes[this.Foreground], 0);
138 this.LineNemberWidth = layout.Lines[0].Width * EditView.LineNumberLength;
139 this._LineHeight = layout.Lines[0].Height;
140 this.emSize = new Size(layout.Lines[0].Width, layout.Lines[0].Height);
143 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Font));
147 public double LineNemberWidth
153 public double FoldingWidth
161 public int TabWidthChar
165 return this._TabWidthChar;
169 TextLayout layout = new TextLayout("a", this.FontFamily, this.FontSize, this.Brushes[this.ForegroundColor], 0);
170 double width = layout.Lines[0].WidthIncludingTrailingWhitespace;
172 this.TabWidth = width * value;
173 this._TabWidthChar = value;
183 public System.Windows.Media.Color Foreground
187 return this.ForegroundColor;
191 this.ForegroundColor = value;
192 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
196 public System.Windows.Media.Color Background
200 return this.BackgroundColor;
204 this.BackgroundColor = value;
205 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
209 public System.Windows.Media.Color InsertCaret
213 return this.InsertCaretColor;
217 this.InsertCaretColor = value;
221 public System.Windows.Media.Color OverwriteCaret
225 return this.OverwriteCaretColor;
229 this.OverwriteCaretColor = value;
233 public System.Windows.Media.Color LineMarker
237 return this.LineMarkerColor;
241 this.LineMarkerColor = value;
245 public System.Windows.Media.Color ControlChar
249 return this.ControlCharColor;
253 this.ControlCharColor = value;
254 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
258 public System.Windows.Media.Color Url
262 return this.UrlColor;
266 this.UrlColor = value;
267 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
271 public System.Windows.Media.Color Hilight
275 return this.HilightColor;
279 this.HilightColor = value;
280 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
284 public System.Windows.Media.Color Comment
288 return this.CommentColor;
292 this.CommentColor = value;
293 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
297 public System.Windows.Media.Color Literal
301 return this.LiteralColor;
305 this.LiteralColor = value;
306 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
310 public System.Windows.Media.Color Keyword1
314 return this.Keyword1Color;
318 this.Keyword1Color = value;
319 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
323 public System.Windows.Media.Color Keyword2
327 return this.Keyword2Color;
331 this.Keyword2Color = value;
332 this.ChangedRenderResource(this, new ChangedRenderRsourceEventArgs(ResourceType.Brush));
336 public float HeaderHeight
338 get { return (float)this._LineHeight; }
341 public float FooterHeight
343 get { return (float)this._LineHeight; }
352 public event ChangedRenderResourceEventHandler ChangedRenderResource;
354 public void DrawCachedBitmap(Rectangle rect)
359 public void CacheContent()
364 public bool IsVaildCache()
369 public void SetDrawingContext(DrawingContext dc)
374 public void BegineDraw()
376 this.visual = new DrawingVisual();
377 this.Context = this.visual.RenderOpen();
380 public void EndDraw()
382 this.Context.Close();
383 this.host.AddVisual(this.visual);
386 public bool Resize(double width, double height)
391 public void DrawString(string str, double x, double y, StringAlignment align, Size layoutRect)
393 TextAlignment TextAlign = TextAlignment.Left;
396 case StringAlignment.Left:
397 TextAlign = TextAlignment.Left;
399 case StringAlignment.Center:
400 TextAlign = TextAlignment.Center;
402 case StringAlignment.Right:
403 TextAlign = TextAlignment.Right;
406 TextLayout layout = new TextLayout(str, this.FontFamily, this.FontSize, this.Brushes[this.ForegroundColor], layoutRect.Width, TextAlign);
407 layout.FlowDirection = this.RightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
408 layout.Draw(this.Context, x, y);
412 public void FillRectangle(Rectangle rect,FillRectType type)
418 case FillRectType.OverwriteCaret:
419 this.Context.DrawRectangle(this.Brushes[this.OverwriteCaret], null, rect);
421 case FillRectType.InsertCaret:
422 this.Context.DrawRectangle(this.Brushes[this.InsertCaret], null, rect);
424 case FillRectType.InsertPoint:
426 case FillRectType.LineMarker:
427 this.Context.DrawRectangle(this.Brushes[this.LineMarker], null, rect);
432 public void DrawFoldingMark(bool expand, double x, double y)
434 string str = expand ? "-" : "+";
435 TextLayout layout = new TextLayout(str, this.FontFamily, this.FontSize, this.Brushes[this.ForegroundColor], this.FoldingWidth);
436 layout.Draw(this.Context, x, y);
439 public void DrawLine(Point from, Point to)
441 Brush brush = this.Brushes[this.ForegroundColor];
442 Pen pen = this.Pens.Get(brush,HilightType.Sold);
443 this.Context.DrawLine(pen, from, to);
446 public void FillBackground(Rectangle rect)
450 this.Context.DrawRectangle(this.Brushes[this.Background], null, rect);
453 public void DrawOneLine(LineToIndexTable lti, int row, double x, double y, IEnumerable<Selection> SelectRanges)
455 TextLayout layout = (TextLayout)lti.GetData(row).Layout;
456 LineToIndexTableData lineData = lti.GetData(row);
458 if (lineData.Length == 0)
461 if (this.Printing == false)
463 foreach (Selection sel in SelectRanges)
465 if (sel.length == 0 || sel.start == -1)
468 foreach (TextBounds bound in layout.GetTextBounds(sel.start, sel.length))
470 Rect rect = new Rect(x,y,bound.Rectangle.Width,bound.Rectangle.Height);
471 this.Context.DrawRectangle(this.Brushes[this.Hilight], null, rect);
476 layout.Draw(this.Context, x, y);
479 public List<LineToIndexTableData> BreakLine(Document doc, int startIndex, int endIndex, double wrapwidth)
481 List<LineToIndexTableData> output = new List<LineToIndexTableData>();
483 foreach (string str in doc.GetLines(startIndex, endIndex))
485 TextLayout layout = new TextLayout(str, this.FontFamily, this.FontSize, this.Brushes[this.Foreground], wrapwidth);
488 foreach (TextLine line in layout.Lines)
490 if (line.Length == 0 && line.NewlineLength == 0)
493 int length = line.Length;
495 IList<TextSpan<TextRun>> runs = line.GetTextRunSpans();
496 if (runs.Last().Value is TextEndOfParagraph)
499 bool lineend = false;
500 if (line.NewlineLength > 0)
503 output.Add(new LineToIndexTableData(i, length, lineend, null));
509 startIndex += str.Length;
512 if (output.Count > 0)
513 output.Last().LineEnd = true;
518 public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges)
520 TextLayout layout = new TextLayout(str,this.FontFamily,this.FontSize,Brushes[this.Foreground],this.TextArea.Width);
521 layout.TextWarpping = TextWrapping.NoWrap;
522 layout.FlowDirection = this.RightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
524 if (syntaxCollection != null)
526 foreach (SyntaxInfo s in syntaxCollection)
528 Brush brush = this.Brushes[this.Foreground];
531 case TokenType.Comment:
532 brush = this.Brushes[this.Comment];
534 case TokenType.Keyword1:
535 brush = this.Brushes[this.Keyword1];
537 case TokenType.Keyword2:
538 brush = this.Brushes[this.Keyword2];
540 case TokenType.Literal:
541 brush = this.Brushes[this.Literal];
544 TextEffect effect = new TextEffect(null, brush, null, s.index, s.length);
546 layout.SetTextEffect(effect);
550 if (MarkerRanges != null)
552 foreach (Marker m in MarkerRanges)
554 if (m.start == -1 || m.length == 0)
558 if (m.hilight == HilightType.Url)
560 brush = this.Brushes[this.Url];
561 TextEffect effect = new TextEffect(null, brush, null, m.start, m.length);
563 layout.SetTextEffect(effect);
567 System.Windows.Media.Color color = new System.Windows.Media.Color();
572 brush = this.Brushes[color];
575 Pen pen = this.Pens.Get(brush,m.hilight);
577 TextDecorationCollection collection = new TextDecorationCollection();
578 TextDecoration decoration = new TextDecoration();
579 decoration.Pen = pen;
580 decoration.Location = TextDecorationLocation.Underline;
582 collection.Add(decoration);
584 if (m.hilight == HilightType.Squiggle)
585 layout.SetSquilleLine(m.start, m.length, collection);
587 layout.SetTextDecoration(m.start, m.length, collection);
594 public void Dispose()
603 ResourceManager<System.Windows.Media.Color, Brush> collection = new ResourceManager<System.Windows.Media.Color, Brush>();
604 public Brush this[System.Windows.Media.Color c]
609 if (this.collection.TryGetValue(c, out brush))
611 brush = new SolidColorBrush(c);
613 this.collection.Add(c, brush);
621 ResourceManager<Brush, ResourceManager<HilightType, Pen>> cache = new ResourceManager<Brush, ResourceManager<HilightType, Pen>>();
622 public Pen Get(Brush brush, HilightType type)
624 ResourceManager<HilightType, Pen> hilights;
626 if (this.cache.TryGetValue(brush, out hilights))
628 if (hilights.TryGetValue(type, out effect))
630 effect = CreatePen(brush,type);
631 hilights.Add(type, effect);
634 effect = CreatePen(brush, type);
635 hilights = new ResourceManager<HilightType, Pen>();
636 hilights.Add(type, effect);
637 this.cache.Add(brush, hilights);
640 Pen CreatePen(Brush brush, HilightType type)
642 Pen pen = new Pen(brush, 1.0f);
645 case HilightType.Sold:
646 case HilightType.Url:
647 case HilightType.Squiggle:
648 pen.DashStyle = DashStyles.Solid;
650 case HilightType.Dash:
651 pen.DashStyle = DashStyles.Dash;
653 case HilightType.DashDot:
654 pen.DashStyle = DashStyles.DashDot;
656 case HilightType.DashDotDot:
657 pen.DashStyle = DashStyles.DashDotDot;
659 case HilightType.Dot:
660 pen.DashStyle = DashStyles.Dot;