private void DrawLines(Graphics g, RenderParameter param) { RenderProfile prof = GetRenderProfile(); //Rendering Core if (param.LineFrom <= _document.LastLineNumber) { IntPtr hdc = g.GetHdc(); IntPtr gdipgraphics = IntPtr.Zero; try { if (prof.UseClearType) { Win32.GdipCreateFromHDC(hdc, ref gdipgraphics); Win32.GdipSetTextRenderingHint(gdipgraphics, 5); //5はTextRenderingHintClearTypeGridFit } float y = (prof.Pitch.Height + prof.LineSpacing) * param.LineFrom + BORDER; for (int i = 0; i < _transientLines.Count; i++) { GLine line = _transientLines[i]; line.Render(hdc, prof, BORDER, (int)y); y += prof.Pitch.Height + prof.LineSpacing; } } finally { if (gdipgraphics != IntPtr.Zero) { Win32.GdipDeleteGraphics(gdipgraphics); } g.ReleaseHdc(hdc); } } }
private void DrawLines(Graphics g, RenderParameter param, Color baseBackColor) { RenderProfile prof = GetRenderProfile(); Caret caret = _caret; //Rendering Core if (param.LineFrom <= _document.LastLineNumber) { IntPtr hdc = g.GetHdc(); try { float y = (prof.Pitch.Height + prof.LineSpacing) * param.LineFrom + BORDER; for (int i = 0; i < _transientLines.Count; i++) { GLine line = _transientLines[i]; line.Render(hdc, prof, caret, baseBackColor, BORDER, (int)y); if (line.IsPeriodicRedrawRequired()) { _requiresPeriodicRedraw = true; } y += prof.Pitch.Height + prof.LineSpacing; } } finally { g.ReleaseHdc(hdc); } } }
private void DrawBoldUnderlineCaret(Graphics g, RenderParameter param, int x, int y) { RenderProfile profile = GetRenderProfile(); float xchar = BORDER + profile.Pitch.Width * x; float ychar = BORDER + (profile.Pitch.Height + profile.LineSpacing) * y; this.DrawCaret_Box(g, xchar, ychar + profile.Pitch.Height - 3, profile.Pitch.Width, 3.0f); }
private void DrawBarCaret(Graphics g, RenderParameter param, int x, int y) { RenderProfile profile = GetRenderProfile(); float xchar = BORDER + profile.Pitch.Width * x; float ychar = BORDER + (profile.Pitch.Height + profile.LineSpacing) * y; //this.DrawCaret_Box(g,xchar,ychar+2,2.0f,profile.Pitch.Height-1); this.DrawCaret_Box(g, xchar, ychar + 1, 2.0f, profile.Pitch.Height - 1); }
private void DrawUnderLineCaret(Graphics g, RenderParameter param, int x, int y) { RenderProfile profile = GetRenderProfile(); PointF pt1 = new PointF(profile.Pitch.Width * x + BORDER + 2, (profile.Pitch.Height + profile.LineSpacing) * y + BORDER + profile.Pitch.Height); PointF pt2 = new PointF(pt1.X + profile.Pitch.Width - 2, pt1.Y); Pen p = _caret.ToPen(profile); g.DrawLine(p, pt1, pt2); pt1.Y += 1; pt2.Y += 1; g.DrawLine(p, pt1, pt2); }
private void BuildTransientDocument(PaintEventArgs e, RenderParameter param) { Rectangle clip = e.ClipRectangle; RenderProfile profile = GetRenderProfile(); _transientLines.Clear(); //Win32.SystemMetrics sm = GEnv.SystemMetrics; //param.TargetRect = new Rectangle(sm.ControlBorderWidth+1, sm.ControlBorderHeight, // this.Width - _VScrollBar.Width - sm.ControlBorderWidth + 8, //この8がない値が正当だが、.NETの文字サイズ丸め問題のため行の最終文字が表示されないことがある。これを回避するためにちょっと増やす // this.Height - sm.ControlBorderHeight); param.TargetRect = this.ClientRectangle; int offset1 = (int)Math.Floor((clip.Top - BORDER) / (profile.Pitch.Height + profile.LineSpacing)); if (offset1 < 0) { offset1 = 0; } param.LineFrom = offset1; int offset2 = (int)Math.Floor((clip.Bottom - BORDER) / (profile.Pitch.Height + profile.LineSpacing)); if (offset2 < 0) { offset2 = 0; } param.LineCount = offset2 - offset1 + 1; //Debug.WriteLine(String.Format("{0} {1} ", param.LineFrom, param.LineCount)); int topline_id = GetTopLine().ID; GLine l = _document.FindLineOrNull(topline_id + param.LineFrom); if (l != null) { for (int i = param.LineFrom; i < param.LineFrom + param.LineCount; i++) { _transientLines.Add(l.Clone()); //TODO クローンはきついよなあ だが描画の方が時間かかるので、その間ロックをしないためには仕方ない点もある l = l.NextLine; if (l == null) { break; } } } //以下、_transientLinesにはparam.LineFromから示される値が入っていることに注意 //選択領域の描画 if (!_textSelection.IsEmpty) { TextSelection.TextPoint from = _textSelection.HeadPoint; TextSelection.TextPoint to = _textSelection.TailPoint; l = _document.FindLineOrNull(from.Line); GLine t = _document.FindLineOrNull(to.Line); if (l != null && t != null) //本当はlがnullではいけないはずだが、それを示唆するバグレポートがあったので念のため { t = t.NextLine; int pos = from.Column; //たとえば左端を越えてドラッグしたときの選択範囲は前行末になるので pos==TerminalWidthとなるケースがある。 do { int index = l.ID - (topline_id + param.LineFrom); if (pos >= 0 && pos < l.DisplayLength && index >= 0 && index < _transientLines.Count) { GLine r = null; if (l.ID == to.Line) { if (pos != to.Column) { r = _transientLines[index].CreateInvertedClone(pos, to.Column); } } else { r = _transientLines[index].CreateInvertedClone(pos, l.DisplayLength); } if (r != null) { _transientLines[index] = r; } } pos = 0; //2行目からの選択は行頭から l = l.NextLine; } while (l != t); } } AdjustCaret(_caret); _caret.Enabled = _caret.Enabled && (param.LineFrom <= _caret.Y && _caret.Y < param.LineFrom + param.LineCount); //Caret画面外にあるなら処理はしなくてよい。2番目の条件は、Attach-ResizeTerminalの流れの中でこのOnPaintを実行した場合にTerminalHeight>lines.Countになるケースがあるのを防止するため if (_caret.Enabled) { //ヒクヒク問題のため、キャレットを表示しないときでもこの操作は省けない if (_caret.Style == CaretType.Box) { int y = _caret.Y - param.LineFrom; if (y >= 0 && y < _transientLines.Count) { _transientLines[y].InvertCharacter(_caret.X, _caret.IsActiveTick, _caret.Color); } } } }
//描画の本体 protected override sealed void OnPaint(PaintEventArgs e) { #if ONPAINT_TIME_MEASUREMENT Stopwatch onPaintSw = (_onPaintTimeObserver != null) ? Stopwatch.StartNew() : null; #endif base.OnPaint(e); try { if (_document != null) { ShowVScrollBar(); } else { HideVScrollBar(); } if (_enabled && !this.DesignMode) { Rectangle clip = e.ClipRectangle; Graphics g = e.Graphics; RenderProfile profile = GetRenderProfile(); int paneheight = GetHeightInLines(); // determine background color of the view Color backColor; if (_document.IsApplicationMode) { backColor = _document.ApplicationModeBackColor; if (backColor.IsEmpty) { backColor = profile.BackColor; } } else { backColor = profile.BackColor; } if (this.BackColor != backColor) { this.BackColor = backColor; // set background color of the view } // draw background image if it is required. if (!_document.IsApplicationMode) { Image img = profile.GetImage(); if (img != null) { DrawBackgroundImage(g, img, profile.ImageStyle, clip); } } //描画用にテンポラリのGLineを作り、描画中にdocumentをロックしないようにする //!!ここは実行頻度が高いのでnewを毎回するのは避けたいところだ RenderParameter param = new RenderParameter(); _caret.Enabled = _caret.Enabled && this.Focused; //TODO さらにIME起動中はキャレットを表示しないように. TerminalControlだったらAdjustCaretでIMEをみてるので問題はない lock (_document) { CommitTransientScrollBar(); BuildTransientDocument(e, param); } DrawLines(g, param, backColor); if (_caret.Enabled && (!_caret.Blink || _caret.IsActiveTick)) //点滅しなければEnabledによってのみ決まる { if (_caret.Style == CaretType.Line) { DrawBarCaret(g, param, _caret.X, _caret.Y); } else if (_caret.Style == CaretType.Underline) { DrawUnderLineCaret(g, param, _caret.X, _caret.Y); } } } //マークの描画 _splitMark.OnPaint(e); } catch (Exception ex) { if (!_errorRaisedInDrawing) //この中で一度例外が発生すると繰り返し起こってしまうことがままある。なので初回のみ表示してとりあえず切り抜ける { _errorRaisedInDrawing = true; RuntimeUtil.ReportException(ex); } } #if ONPAINT_TIME_MEASUREMENT if (onPaintSw != null) { onPaintSw.Stop(); if (_onPaintTimeObserver != null) { _onPaintTimeObserver(onPaintSw); } } #endif }
private void DrawLines(Graphics g, RenderParameter param, Color baseBackColor) { RenderProfile prof = GetRenderProfile(); //Rendering Core if (param.LineFrom <= _document.LastLineNumber) { IntPtr hdc = g.GetHdc(); try { float y = (prof.Pitch.Height + prof.LineSpacing) * param.LineFrom + BORDER; for (int i = 0; i < _transientLines.Count; i++) { GLine line = _transientLines[i]; line.Render(hdc, prof, baseBackColor, BORDER, (int)y); y += prof.Pitch.Height + prof.LineSpacing; } } finally { g.ReleaseHdc(hdc); } } }
private void BuildTransientDocument(PaintEventArgs e, RenderParameter param) { Rectangle clip = e.ClipRectangle; RenderProfile profile = GetRenderProfile(); _transientLines.Clear(); //Win32.SystemMetrics sm = GEnv.SystemMetrics; //param.TargetRect = new Rectangle(sm.ControlBorderWidth+1, sm.ControlBorderHeight, // this.Width - _VScrollBar.Width - sm.ControlBorderWidth + 8, //この8がない値が正当だが、.NETの文字サイズ丸め問題のため行の最終文字が表示されないことがある。これを回避するためにちょっと増やす // this.Height - sm.ControlBorderHeight); param.TargetRect = this.ClientRectangle; int offset1 = (int)Math.Floor((clip.Top - BORDER) / (profile.Pitch.Height + profile.LineSpacing)); if (offset1 < 0) offset1 = 0; param.LineFrom = offset1; int offset2 = (int)Math.Floor((clip.Bottom - BORDER) / (profile.Pitch.Height + profile.LineSpacing)); if (offset2 < 0) offset2 = 0; param.LineCount = offset2 - offset1 + 1; //Debug.WriteLine(String.Format("{0} {1} ", param.LineFrom, param.LineCount)); int topline_id = GetTopLine().ID; GLine l = _document.FindLineOrNull(topline_id + param.LineFrom); if (l != null) { for (int i = param.LineFrom; i < param.LineFrom + param.LineCount; i++) { _transientLines.Add(l.Clone()); //TODO クローンはきついよなあ だが描画の方が時間かかるので、その間ロックをしないためには仕方ない点もある l = l.NextLine; if (l == null) break; } } //以下、_transientLinesにはparam.LineFromから示される値が入っていることに注意 //選択領域の描画 if (!_textSelection.IsEmpty) { TextSelection.TextPoint from = _textSelection.HeadPoint; TextSelection.TextPoint to = _textSelection.TailPoint; l = _document.FindLineOrNull(from.Line); GLine t = _document.FindLineOrNull(to.Line); if (l != null && t != null) { //本当はlがnullではいけないはずだが、それを示唆するバグレポートがあったので念のため t = t.NextLine; int pos = from.Column; //たとえば左端を越えてドラッグしたときの選択範囲は前行末になるので pos==TerminalWidthとなるケースがある。 do { int index = l.ID - (topline_id + param.LineFrom); if (pos >= 0 && pos < l.DisplayLength && index >= 0 && index < _transientLines.Count) { GLine r = null; if (l.ID == to.Line) { if (pos != to.Column) r = _transientLines[index].CreateInvertedClone(pos, to.Column); } else r = _transientLines[index].CreateInvertedClone(pos, l.DisplayLength); if (r != null) { _transientLines[index] = r; } } pos = 0; //2行目からの選択は行頭から l = l.NextLine; } while (l != t); } } AdjustCaret(_caret); _caret.Enabled = _caret.Enabled && (param.LineFrom <= _caret.Y && _caret.Y < param.LineFrom + param.LineCount); //Caret画面外にあるなら処理はしなくてよい。2番目の条件は、Attach-ResizeTerminalの流れの中でこのOnPaintを実行した場合にTerminalHeight>lines.Countになるケースがあるのを防止するため if (_caret.Enabled) { //ヒクヒク問題のため、キャレットを表示しないときでもこの操作は省けない if (_caret.Style == CaretType.Box) { int y = _caret.Y - param.LineFrom; if (y >= 0 && y < _transientLines.Count) _transientLines[y].InvertCharacter(_caret.X, _caret.IsActiveTick, _caret.Color); } } }
//描画の本体 protected override sealed void OnPaint(PaintEventArgs e) { #if ONPAINT_TIME_MEASUREMENT Stopwatch onPaintSw = (_onPaintTimeObserver != null) ? Stopwatch.StartNew() : null; #endif base.OnPaint(e); try { if (_document != null) ShowVScrollBar(); else HideVScrollBar(); if (_enabled && !this.DesignMode) { Rectangle clip = e.ClipRectangle; Graphics g = e.Graphics; RenderProfile profile = GetRenderProfile(); int paneheight = GetHeightInLines(); // determine background color of the view Color backColor; if (_document.IsApplicationMode) { backColor = _document.ApplicationModeBackColor; if (backColor.IsEmpty) backColor = profile.BackColor; } else { backColor = profile.BackColor; } if (this.BackColor != backColor) this.BackColor = backColor; // set background color of the view // draw background image if it is required. if (!_document.IsApplicationMode) { Image img = profile.GetImage(); if (img != null) { DrawBackgroundImage(g, img, profile.ImageStyle, clip); } } //描画用にテンポラリのGLineを作り、描画中にdocumentをロックしないようにする //!!ここは実行頻度が高いのでnewを毎回するのは避けたいところだ RenderParameter param = new RenderParameter(); _caret.Enabled = _caret.Enabled && this.Focused; //TODO さらにIME起動中はキャレットを表示しないように. TerminalControlだったらAdjustCaretでIMEをみてるので問題はない lock (_document) { CommitTransientScrollBar(); BuildTransientDocument(e, param); } DrawLines(g, param, backColor); if (_caret.Enabled && (!_caret.Blink || _caret.IsActiveTick)) { //点滅しなければEnabledによってのみ決まる if (_caret.Style == CaretType.Line) DrawBarCaret(g, param, _caret.X, _caret.Y); else if (_caret.Style == CaretType.Underline) DrawUnderLineCaret(g, param, _caret.X, _caret.Y); } } //マークの描画 _splitMark.OnPaint(e); } catch (Exception ex) { if (!_errorRaisedInDrawing) { //この中で一度例外が発生すると繰り返し起こってしまうことがままある。なので初回のみ表示してとりあえず切り抜ける _errorRaisedInDrawing = true; RuntimeUtil.ReportException(ex); } } #if ONPAINT_TIME_MEASUREMENT if (onPaintSw != null) { onPaintSw.Stop(); if (_onPaintTimeObserver != null) { _onPaintTimeObserver(onPaintSw); } } #endif }
//描画の本体 protected override sealed void OnPaint(PaintEventArgs e) { base.OnPaint(e); try { if (_document != null) { ShowVScrollBar(); } else { HideVScrollBar(); } if (_enabled && !this.DesignMode) { Rectangle clip = e.ClipRectangle; Graphics g = e.Graphics; RenderProfile profile = GetRenderProfile(); int paneheight = GetHeightInLines(); if (_document.BackColor != profile.BackColor) { if (_document.IsApplicationMode) { if (this.BackColor != _document.BackColor) { this.BackColor = _document.BackColor; _drawbgImage = false; } } else { this.BackColor = profile.BackColor; _document.BackColor = profile.BackColor; _drawbgImage = true; } } if (_drawbgImage) { Image img = profile.GetImage(); if (img != null) { DrawBackgroundImage(g, img, profile.ImageStyle, clip); } } //描画用にテンポラリのGLineを作り、描画中にdocumentをロックしないようにする //!!ここは実行頻度が高いのでnewを毎回するのは避けたいところだ RenderParameter param = new RenderParameter(); _caret.Enabled = _caret.Enabled && this.Focused; //TODO さらにIME起動中はキャレットを表示しないように. TerminalControlだったらAdjustCaretでIMEをみてるので問題はない lock (_document) { CommitTransientScrollBar(); BuildTransientDocument(e, param); } DrawLines(g, param); if (_caret.Enabled && (!_caret.Blink || _caret.IsActiveTick)) //点滅しなければEnabledによってのみ決まる { if (_caret.Style == CaretType.Line) { DrawBarCaret(g, param, _caret.X, _caret.Y); } else if (_caret.Style == CaretType.Underline) { DrawUnderLineCaret(g, param, _caret.X, _caret.Y); } else if (_caret.Style == CaretType.BoldUnderline) { DrawBoldUnderlineCaret(g, param, _caret.X, _caret.Y); } } } //マークの描画 _splitMark.OnPaint(e); } catch (Exception ex) { if (!_errorRaisedInDrawing) //この中で一度例外が発生すると繰り返し起こってしまうことがままある。なので初回のみ表示してとりあえず切り抜ける { _errorRaisedInDrawing = true; RuntimeUtil.ReportException(ex); } } }