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 bool ShowLineBreak
358 public event ChangedRenderResourceEventHandler ChangedRenderResource;
360 public void DrawCachedBitmap(Rectangle rect)
365 public void CacheContent()
370 public bool IsVaildCache()
375 public void SetDrawingContext(DrawingContext dc)
380 public void BegineDraw()
382 this.visual = new DrawingVisual();
383 this.Context = this.visual.RenderOpen();
386 public void EndDraw()
388 this.Context.Close();
389 this.host.AddVisual(this.visual);
392 public bool Resize(double width, double height)
397 public void DrawString(string str, double x, double y, StringAlignment align, Size layoutRect, StringColorType colorType = StringColorType.Forground)
399 TextAlignment TextAlign = TextAlignment.Left;
402 case StringAlignment.Left:
403 TextAlign = TextAlignment.Left;
405 case StringAlignment.Center:
406 TextAlign = TextAlignment.Center;
408 case StringAlignment.Right:
409 TextAlign = TextAlignment.Right;
412 TextLayout layout = new TextLayout(str, this.FontFamily, this.FontSize, this.Brushes[this.ForegroundColor], layoutRect.Width, TextAlign);
413 layout.FlowDirection = this.RightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
414 layout.Draw(this.Context, x, y);
418 public void FillRectangle(Rectangle rect,FillRectType type)
424 case FillRectType.OverwriteCaret:
425 this.Context.DrawRectangle(this.Brushes[this.OverwriteCaret], null, rect);
427 case FillRectType.InsertCaret:
428 this.Context.DrawRectangle(this.Brushes[this.InsertCaret], null, rect);
430 case FillRectType.InsertPoint:
432 case FillRectType.LineMarker:
433 this.Context.DrawRectangle(this.Brushes[this.LineMarker], null, rect);
438 public void DrawFoldingMark(bool expand, double x, double y)
440 string str = expand ? "-" : "+";
441 TextLayout layout = new TextLayout(str, this.FontFamily, this.FontSize, this.Brushes[this.ForegroundColor], this.FoldingWidth);
442 layout.Draw(this.Context, x, y);
445 public void DrawLine(Point from, Point to)
447 Brush brush = this.Brushes[this.ForegroundColor];
448 Pen pen = this.Pens.Get(brush,HilightType.Sold);
449 this.Context.DrawLine(pen, from, to);
452 public void FillBackground(Rectangle rect)
456 this.Context.DrawRectangle(this.Brushes[this.Background], null, rect);
459 public void DrawOneLine(Document doc, LineToIndexTable lti, int row, double x, double y)
461 TextLayout layout = (TextLayout)lti.GetLayout(row);
463 if (lti.GetLengthFromLineNumber(row) == 0)
466 if (this.Printing == false)
468 int lineIndex = lti.GetIndexFromLineNumber(row);
469 int lineLength = lti.GetLengthFromLineNumber(row);
470 var SelectRanges = from s in doc.Selections.Get(lineIndex, lineLength)
471 let n = Util.ConvertAbsIndexToRelIndex(s, lineIndex, lineLength)
474 foreach (Selection sel in SelectRanges)
476 if (sel.length == 0 || sel.start == -1)
479 foreach (TextBounds bound in layout.GetTextBounds(sel.start, sel.length))
481 Rect rect = new Rect(x, y, bound.Rectangle.Width, bound.Rectangle.Height);
482 this.Context.DrawRectangle(this.Brushes[this.Hilight], null, rect);
487 layout.Draw(this.Context, x, y);
490 public void BeginClipRect(Rectangle rect)
494 public void EndClipRect()
498 public List<LineToIndexTableData> BreakLine(Document doc, LineToIndexTable layoutLineCollection, int startIndex, int endIndex, double wrapwidth)
500 List<LineToIndexTableData> output = new List<LineToIndexTableData>();
502 foreach (string str in doc.GetLines(startIndex, endIndex))
504 TextLayout layout = new TextLayout(str, this.FontFamily, this.FontSize, this.Brushes[this.Foreground], wrapwidth);
507 foreach (TextLine line in layout.Lines)
509 if (line.Length == 0 && line.NewlineLength == 0)
512 int length = line.Length;
514 IList<TextSpan<TextRun>> runs = line.GetTextRunSpans();
515 if (runs.Last().Value is TextEndOfParagraph)
518 bool lineend = false;
519 if (line.NewlineLength > 0)
522 output.Add(layoutLineCollection.CreateLineToIndexTableData(i, length, lineend, null));
528 startIndex += str.Length;
531 if (output.Count > 0)
532 output.Last().LineEnd = true;
537 public ITextLayout CreateLaytout(string str, SyntaxInfo[] syntaxCollection, IEnumerable<Marker> MarkerRanges, IEnumerable<Selection> SelectRanges)
539 TextLayout layout = new TextLayout(str,this.FontFamily,this.FontSize,Brushes[this.Foreground],this.TextArea.Width);
540 layout.TextWarpping = TextWrapping.NoWrap;
541 layout.FlowDirection = this.RightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
543 if (syntaxCollection != null)
545 foreach (SyntaxInfo s in syntaxCollection)
547 Brush brush = this.Brushes[this.Foreground];
550 case TokenType.Comment:
551 brush = this.Brushes[this.Comment];
553 case TokenType.Keyword1:
554 brush = this.Brushes[this.Keyword1];
556 case TokenType.Keyword2:
557 brush = this.Brushes[this.Keyword2];
559 case TokenType.Literal:
560 brush = this.Brushes[this.Literal];
563 TextEffect effect = new TextEffect(null, brush, null, s.index, s.length);
565 layout.SetTextEffect(effect);
569 if (MarkerRanges != null)
571 foreach (Marker m in MarkerRanges)
573 if (m.start == -1 || m.length == 0)
577 if (m.hilight == HilightType.Url)
579 brush = this.Brushes[this.Url];
580 TextEffect effect = new TextEffect(null, brush, null, m.start, m.length);
582 layout.SetTextEffect(effect);
586 System.Windows.Media.Color color = new System.Windows.Media.Color();
591 brush = this.Brushes[color];
594 Pen pen = this.Pens.Get(brush,m.hilight);
596 TextDecorationCollection collection = new TextDecorationCollection();
597 TextDecoration decoration = new TextDecoration();
598 decoration.Pen = pen;
599 decoration.Location = TextDecorationLocation.Underline;
601 collection.Add(decoration);
603 if (m.hilight == HilightType.Squiggle)
604 layout.SetSquilleLine(m.start, m.length, collection);
606 layout.SetTextDecoration(m.start, m.length, collection);
613 public void DrawGripper(Point p, double radius)
615 //タッチには対応していないので実装する必要はない
616 throw new NotImplementedException();
619 public void Dispose()
628 ResourceManager<System.Windows.Media.Color, Brush> collection = new ResourceManager<System.Windows.Media.Color, Brush>();
629 public Brush this[System.Windows.Media.Color c]
634 if (this.collection.TryGetValue(c, out brush))
636 brush = new SolidColorBrush(c);
638 this.collection.Add(c, brush);
646 ResourceManager<Brush, ResourceManager<HilightType, Pen>> cache = new ResourceManager<Brush, ResourceManager<HilightType, Pen>>();
647 public Pen Get(Brush brush, HilightType type)
649 ResourceManager<HilightType, Pen> hilights;
651 if (this.cache.TryGetValue(brush, out hilights))
653 if (hilights.TryGetValue(type, out effect))
655 effect = CreatePen(brush,type);
656 hilights.Add(type, effect);
659 effect = CreatePen(brush, type);
660 hilights = new ResourceManager<HilightType, Pen>();
661 hilights.Add(type, effect);
662 this.cache.Add(brush, hilights);
665 Pen CreatePen(Brush brush, HilightType type)
667 Pen pen = new Pen(brush, 1.0f);
670 case HilightType.Sold:
671 case HilightType.Url:
672 case HilightType.Squiggle:
673 pen.DashStyle = DashStyles.Solid;
675 case HilightType.Dash:
676 pen.DashStyle = DashStyles.Dash;
678 case HilightType.DashDot:
679 pen.DashStyle = DashStyles.DashDot;
681 case HilightType.DashDotDot:
682 pen.DashStyle = DashStyles.DashDotDot;
684 case HilightType.Dot:
685 pen.DashStyle = DashStyles.Dot;