internal D2dBitmap(D2dGraphics owner, SharpDX.Direct2D1.Bitmap bmp) { m_nativeBitmap = bmp; m_owner = owner; m_bitmap = null; m_owner.RecreateResources += RecreateResources; m_rtNumber = owner.RenderTargetNumber; }
internal D2dBitmap(D2dGraphics owner, System.Drawing.Bitmap bmp) { if (bmp.PixelFormat != GdiPixelFormat.Format32bppPArgb) throw new System.ArgumentException("pixel format must be GdiPixelFormat.Format32bppPArgb"); m_owner = owner; m_bitmap = bmp; Create(); m_owner.RecreateResources += RecreateResources; m_rtNumber = owner.RenderTargetNumber; }
internal D2dRadialGradientBrush(D2dGraphics owner, PointF center, PointF gradientOriginOffset, float radiusX, float radiusY, params D2dGradientStop[] gradientStops) : base(owner) { m_center = center; m_gradientOriginOffset = gradientOriginOffset; m_radiusX = radiusX; m_radiusY = radiusY; m_gradientStops = new D2dGradientStop[gradientStops.Length]; Array.Copy(gradientStops, m_gradientStops, m_gradientStops.Length); Create();//to-do: it's dangerous to call a virtual method in a constructor; derived class may not be properly initialized! }
/// <summary> /// Initializes class with graphics object</summary> /// <param name="graphics">Graphics object for drawing</param> public override void Init(D2dGraphics graphics) { base.Init(graphics); SelectedBrush = graphics.CreateSolidBrush(Color.Tomato);//should have width of 3 CollapsedBrush = graphics.CreateSolidBrush(Color.LightGray); InvalidBrush = graphics.CreateSolidBrush(Color.DimGray); GroupBrush = graphics.CreateLinearGradientBrush( new D2dGradientStop(Color.LightGoldenrodYellow, 0), new D2dGradientStop(Color.Khaki, 1)); GhostGroupBrush = graphics.CreateSolidBrush(Color.FromArgb(128, Color.Gray)); TrackBrush = graphics.CreateSolidBrush(Color.LightGray); GhostTrackBrush = graphics.CreateSolidBrush(Color.FromArgb(128, Color.Gray)); TextBrush = graphics.CreateSolidBrush(SystemColors.WindowText); }
internal D2dLinearGradientBrush(D2dGraphics owner, PointF pt1, PointF pt2, D2dGradientStop[] gradientStops, D2dExtendMode extendMode, D2dGamma gamma) : base(owner) { m_start = pt1; m_end = pt2; m_gradientStops = new D2dGradientStop[gradientStops.Length]; Array.Copy(gradientStops, m_gradientStops, m_gradientStops.Length); m_gamma = gamma; m_extendMode = extendMode; Create();//to-do: it's dangerous to call a virtual method in a constructor; derived class may not be properly initialized! }
/// <summary> /// Initializes this class with a graphics object. Must be called before using this class to render.</summary> /// <param name="graphics">The graphics object that this TimelineRenderer will permanently use</param> public virtual void Init(D2dGraphics graphics) { if (m_graphics != null) throw new InvalidOperationException("Only call Init() once"); m_graphics = graphics; m_gridPen = m_graphics.CreateSolidBrush(Color.FromArgb(128, 128, 128, 128)); m_headerBrush = m_graphics.CreateSolidBrush(SystemColors.Control); m_headerLineBrush = m_graphics.CreateSolidBrush(SystemColors.ControlDark); m_scaleLineBrush = m_graphics.CreateSolidBrush(SystemColors.ControlDark); m_expanderBrush = m_graphics.CreateSolidBrush(Color.DimGray); m_nameBrush = m_graphics.CreateSolidBrush(SystemColors.WindowText); m_scaleTextBrush = m_graphics.CreateSolidBrush(SystemColors.WindowText); m_generalSolidColorBrush = m_graphics.CreateSolidBrush(Color.Empty); m_trackTextFormat = D2dFactory.CreateTextFormat(Font); m_trackTextFormat.ParagraphAlignment = D2dParagraphAlignment.Far; m_trackTextFormat.TextAlignment = D2dTextAlignment.Trailing; }
/// <summary> /// Draws horizontal grid using Direct2D</summary> /// <param name="transform">Transform from graph (world) to Window's client (screen) transform</param> /// <param name="graphRect">Graph rectangle</param> /// <param name="step">Grid step in canvas coordinates</param> /// <param name="color">Grid line color</param> /// <param name="g">Graphics Direct2D drawing surface</param> public static void DrawHorizontalGrid( Matrix transform, RectangleF graphRect, double step, Color color, D2dGraphics g) { double yScale = transform.Elements[3]; RectangleF clientRect = GdiUtil.Transform(transform, graphRect); double screenStep = Math.Abs(yScale * step); int a = ComputeOpacity(screenStep); color = Color.FromArgb(a, color); double start = graphRect.Top - MathUtil.Remainder(graphRect.Top, step) + step; for (double y = start; y < graphRect.Bottom; y += step) { double cy = (y - graphRect.Top) * yScale + clientRect.Top; g.DrawLine(clientRect.Left, (float)cy, clientRect.Right, (float)cy, color); } }
/// <summary> /// Draws the scrubber manipulator and calculates the bounding rectangle on the handle</summary> /// <param name="g">The graphics object to draw with</param> /// <param name="handleRect">The handle's bounding rectangle for pick tests, in view /// coordinates</param> protected virtual void DrawManipulator(D2dGraphics g, out RectangleF handleRect) { Matrix worldToView = Owner.Transform; float viewX = Sce.Atf.GdiUtil.Transform(worldToView, Position); Rectangle clipRectangle = Owner.VisibleClientRectangle; // allow only the arrow portion to be selected handleRect = new RectangleF( viewX - 5, clipRectangle.Top, 10, 7); g.DrawLine(viewX, clipRectangle.Top, viewX, clipRectangle.Bottom, s_color, 1.0f, null); Color handle_color = m_isMoving ? Color.Tomato : s_color; float pos_x = viewX; float pos_y = clipRectangle.Top + 5; s_arrow[0] = new PointF(pos_x - 4, pos_y - 5); s_arrow[1] = new PointF(pos_x - 4, pos_y); s_arrow[2] = new PointF(pos_x - 5, pos_y + 1); s_arrow[3] = new PointF(pos_x - 5, pos_y + 2); s_arrow[4] = new PointF(pos_x, pos_y + 7); s_arrow[5] = new PointF(pos_x + 5, pos_y + 2); s_arrow[6] = new PointF(pos_x + 5, pos_y + 1); s_arrow[7] = new PointF(pos_x + 4, pos_y); s_arrow[8] = new PointF(pos_x + 4, pos_y - 5); //g.FillPolygon(s_arrow, handle_color); // Fill arrow // Draw arrow border with same gray Photoshop uses //g.DrawLines(s_arrow, Color.FromArgb(116, 114, 106), 3.0f); g.DrawLines(s_arrow, handle_color, 2.0f); string label = Position.ToString(CultureInfo.CurrentCulture); g.DrawText(label, Owner.Renderer.TextFormat, new PointF(pos_x + 6, clipRectangle.Top), SystemColors.WindowText); }
internal D2dBitmap(D2dGraphics owner, int width, int height) { if (width < 1 || height < 1) throw new ArgumentOutOfRangeException("Width and height must be greater than zero"); m_owner = owner; var props = new SharpDX.Direct2D1.BitmapProperties(); props.DpiX = m_owner.DotsPerInch.Width; props.DpiY = m_owner.DotsPerInch.Height; props.PixelFormat = new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied); m_nativeBitmap = new SharpDX.Direct2D1.Bitmap(m_owner.D2dRenderTarget, new Size2(width, height), props); m_owner.RecreateResources += RecreateResources; m_rtNumber = owner.RenderTargetNumber; }
/// <summary> /// Constructor</summary> /// <param name="renderer">Timeline renderer</param> /// <param name="transform">Transform, taking timeline coordinates to display</param> /// <param name="clientRectangle">Bounds of displayed area of timeline, in screen space</param> /// <param name="g">Graphics object</param> public Context( D2dTimelineRenderer renderer, Matrix transform, RectangleF clientRectangle, D2dGraphics g) { Graphics = g; Transform = transform; ClientRectangle = clientRectangle; Bounds = GdiUtil.InverseTransform(transform, clientRectangle); TextFormat = renderer.m_textFormat; FontHeight = renderer.m_textFormat.FontHeight; PixelSize = new SizeF(1 / transform.Elements[0], 1 / transform.Elements[3]); }
private void DrawAnnotation(IAnnotation annotation, DiagramDrawingStyle style, D2dGraphics g, bool drawText, RectangleF graphBound) { // fill background Rectangle bounds = annotation.Bounds; Color backColor = m_coloringContext == null ? SystemColors.Info : (Color) m_coloringContext.GetColor(ColoringTypes.BackColor, annotation); // keep the width of border in 1 pixel after transformation to avoid D2d antialiasing away the line float borderThickness = 1.0f/m_scaleX; g.FillRectangle(bounds, backColor); g.DrawRectangle(bounds, ControlPaint.Dark(backColor), borderThickness, null); // draw titlebar if (style == DiagramDrawingStyle.LastSelected || style == DiagramDrawingStyle.Selected) { var titleBarRect = new RectangleF(bounds.X, bounds.Y, bounds.Width, Margin.Top - 1); g.FillRectangle(titleBarRect, ControlPaint.Dark(backColor)); } // line seperate titlebar from text content g.DrawLine(bounds.X, bounds.Y + Margin.Top-1, bounds.X + bounds.Width, bounds.Y + Margin.Top-1, ControlPaint.Dark(backColor), borderThickness); // draw content if (drawText) { var contentBounds = new RectangleF(bounds.X + Margin.Left, bounds.Y + Margin.Top, bounds.Width - Margin.Size.Width, bounds.Height - Margin.Size.Height); contentBounds.Width = Math.Max(contentBounds.Width, MinimumWidth); contentBounds.Height = Math.Max(contentBounds.Height, MinimumHeight); var textBounds = contentBounds; int topLine = 0; D2dTextLayout textLayout = null; if (m_annotationEditors.ContainsKey(annotation)) { var annotationEditor = m_annotationEditors[annotation]; if (annotationEditor.TextLayout.Text != annotation.Text) // text content changed, for example, undo,redo { annotationEditor.ResetText(annotation.Text); } topLine = annotationEditor.TopLine; textLayout = m_annotationEditors[annotation].TextLayout; annotationEditor.VerticalScrollBarVisibe = textLayout.Height > textLayout.LayoutHeight; if (m_annotationEditors[annotation].VerticalScrollBarVisibe) textBounds.Width -= ScrollBarWidth + 2 * ScrollBarMargin; textLayout.LayoutWidth = textBounds.Width; textLayout.LayoutHeight = textBounds.Height; } if (textLayout == null) { // first assume no v-scroll bar needed textLayout = D2dFactory.CreateTextLayout(annotation.Text, m_theme.TextFormat, contentBounds.Width, contentBounds.Height); if (m_theme.TextFormat.Underlined) textLayout.SetUnderline(true, 0, annotation.Text.Length); if (m_theme.TextFormat.Strikeout) textLayout.SetStrikethrough(true, 0, annotation.Text.Length); if (textLayout.Height > textLayout.LayoutHeight) // need v-scroll bar { textLayout.LayoutWidth = contentBounds.Width - ScrollBarWidth - 2*ScrollBarMargin; } m_annotationEditors.Add(annotation, new TextEditor() { TextLayout = textLayout, TextFormat = m_theme.TextFormat, TopLine = topLine, VerticalScrollBarVisibe = textLayout.Height > textLayout.LayoutHeight }); } var annotationData = m_annotationEditors[annotation]; PointF origin = new PointF(contentBounds.Location.X, contentBounds.Location.Y - topLine * m_theme.TextFormat.FontHeight); g.PushAxisAlignedClip(contentBounds); // draw the selection range behind the text. if (annotationData.SelectionLength > 0) { var hitTestMetrics = textLayout.HitTestTextRange(annotationData.SelectionStart, annotationData.SelectionLength, 0, 0); for (int i = 0; i < hitTestMetrics.Length; ++i) { var highlightRect = new RectangleF(hitTestMetrics[i].Point.X, hitTestMetrics[i].Point.Y, hitTestMetrics[i].Width, hitTestMetrics[i].Height); highlightRect.Offset(origin); g.FillRectangle(highlightRect, m_theme.TextHighlightBrush); } } // draw caret if ( style == DiagramDrawingStyle.Selected || style == DiagramDrawingStyle.LastSelected) { textLayout = annotationData.TextLayout; var caretRect = m_annotationEditors[annotation].GetCaretRect(); caretRect.Offset(origin); //g.FillRectangle(caretRect, m_theme.HotBrush); // set Windows caret position if (m_editingText && contentBounds.IntersectsWith(caretRect) && graphBound.IntersectsWith(caretRect) && AdaptedControl.Focused) { var caretClientRect = GdiUtil.Transform(m_transformAdapter.Transform, caretRect); float ratio = m_scaleX*m_theme.TextFormat.FontHeight/CaretHeight; if (ratio > 1.1f || ratio < 0.9f) // adjust caret height { CaretHeight = (int)(m_scaleX*m_theme.TextFormat.FontHeight); User32.DestroyCaret(); User32.CreateCaret(AdaptedControl.Handle, IntPtr.Zero, CaretWidth, CaretHeight); } // align bottom User32.SetCaretPos((int) caretClientRect.X, (int)(caretClientRect.Y + caretClientRect.Height - CaretHeight)); if (!m_rmbPressed) AdaptedControl.HasKeyboardFocus = true; } else HideCaret(); } // draw text g.DrawTextLayout(origin, textLayout, m_theme.TextBrush); g.PopAxisAlignedClip(); // draw v-scroll bar if (contentBounds.Height < textLayout.Height) { float visibleLines = contentBounds.Height / m_theme.TextFormat.FontHeight; float vMin = topLine * textLayout.LayoutHeight / textLayout.LineCount; float vMax = (topLine + visibleLines-1) * textLayout.LayoutHeight / textLayout.LineCount; if (m_scrolling) { var trackBounds = new RectangleF(contentBounds.Right - ScrollBarMargin - ScrollBarWidth, contentBounds.Y, ScrollBarWidth, contentBounds.Height); g.FillRectangle(trackBounds, Color.Gainsboro); } var thumbBounds = new RectangleF(contentBounds.Right - ScrollBarMargin - ScrollBarWidth, contentBounds.Y + vMin, ScrollBarWidth, vMax - vMin); g.FillRectangle(thumbBounds, Color.DimGray); } } else HideCaret(); }
internal D2dBitmapBrush(D2dGraphics owner, D2dBitmap bitmap) : base(owner) { m_bitmap = bitmap; m_extendModeX = D2dExtendMode.Clamp; m_extendModeY = D2dExtendMode.Clamp; m_location = new PointF(1, 1); m_interpolationMode = D2dBitmapInterpolationMode.Linear; Create();//to-do: it's dangerous to call a virtual method in a constructor; derived class may not be properly initialized! }
internal D2dSolidColorBrush(D2dGraphics owner, Color color) : base(owner) { m_color = color; Create();//to-do: it's dangerous to call a virtual method in a constructor; derived class may not be properly initialized! }
/// <summary> /// Draws a pin button, which looks like a square with /// a dash (expanded) or a cross (unexpanded).</summary> /// <param name="x">X coordinate of pin top left corner</param> /// <param name="y">Y coordinate of pin top left corner</param> /// <param name="pinned">Whether or not pin should appear "pinned"</param> /// <param name="toLeft">Whether pin points left or right</param> /// <param name="pen">Pen, should be 1 pixel wide</param> /// <param name="g">Graphics object</param> public static void DrawPin(int x, int y, bool pinned, bool toLeft, D2dBrush pen, D2dGraphics g) { if (toLeft) DrawLeftPin(x, y, ThumbtackSize, pen, pinned, g); else DrawRightPin(x, y, ThumbtackSize, pen, pinned, g); }
internal D2dBrush(D2dGraphics owner) { m_owner = owner; m_owner.RecreateResources += RecreateResources; m_rtNumber = owner.RenderTargetNumber; }
internal D2dBitmapGraphics(D2dGraphics owner,BitmapRenderTarget renderTarget) : base(renderTarget) { m_owner = owner; }
/// <summary> /// Draws vertical grid lines using Direct2D</summary> /// <param name="transform">Transform from graph (world) to Window's client (screen) transform</param> /// <param name="graphRect">Graph rectangle</param> /// <param name="step">Grid step in canvas coordinates</param> /// <param name="color">Grid line color</param> /// <param name="g">Graphics Direct2D drawing surface</param> public static void DrawVerticalGrid( Matrix transform, RectangleF graphRect, double step, Color color, D2dGraphics g) { double xScale = transform.Elements[0]; RectangleF clientRect = GdiUtil.Transform(transform, graphRect); double screenStep = Math.Abs(xScale * step); int a = ComputeOpacity(screenStep); color = Color.FromArgb(a, color); double start = graphRect.Left - MathUtil.Remainder(graphRect.Left, step) + step; for (double x = start; x < graphRect.Right; x += step) { double cx = (x - graphRect.Left) * xScale + clientRect.Left; g.DrawLine((float)cx, clientRect.Top, (float)cx, clientRect.Bottom, color); } }
/// <summary> /// Draws a tree-control style expander, which looks like a square with /// a dash (expanded) or a cross (unexpanded).</summary> /// <param name="x">X coordinate of expander top right corner</param> /// <param name="y">Y coordinate of expander top right corner</param> /// <param name="pen">Pen, should be 1 pixel wide</param> /// <param name="size">Size of pin, in pixels</param> /// <param name="pinned">Whether or not expander should appear "expanded"</param> /// <param name="g">Graphics object</param> public static void DrawRightPin(int x, int y, int size, D2dBrush pen, bool pinned, D2dGraphics g) { //g.DrawRectangle(pen, x - size, y, size, size); int rectWidth = size / 4; int rectHeight = 2 * size / 3; int center = size / 2; if (pinned) { g.DrawLine(x + center - size, y + rectHeight, x + center - size, y + size, pen); //lower center-vertical line g.DrawLine(x - size, y + rectHeight, x, y + rectHeight, pen); // middle-horizontal line g.DrawRectangle(new RectangleF(x + rectWidth - size, y, 2 * rectWidth, rectHeight), pen); //g.DrawLine(pen, x + 3 * rectWidth - 1, y, x + 3 * rectWidth - 1, y + rectHeight); // a vertial line next to the right side of the rect g.DrawLine(x + 3 * rectWidth - 1 - size, y, x + 3 * rectWidth - 1 - size, y + rectHeight, pen); // a vertial line next to the right side of the rect } else { g.DrawLine(x, y + center, x - size + rectHeight, y + center, pen); //left center-horizontal line g.DrawLine(x - size + rectHeight, y, x - size + rectHeight, y + size, pen); // middle-vertical line g.DrawRectangle(new RectangleF(x - size, y + (size - rectWidth) / 2 - 1, rectHeight, 2 * rectWidth), pen); g.DrawLine(x - size + rectHeight, y + (size - rectWidth) / 2 + 2 * rectWidth - 2, x - size, y + (size - rectWidth) / 2 + 2 * rectWidth - 2, pen); // a horizontal line next to the bottom side of the rect } }
private void DrawAnnotation(IAnnotation annotation, DiagramDrawingStyle style, D2dGraphics g, bool drawText, RectangleF graphBound) { // fill background Rectangle bounds = annotation.Bounds; Color backColor = m_coloringContext == null ? SystemColors.Info : m_coloringContext.GetColor(ColoringTypes.BackColor, annotation); Color foreColor = m_coloringContext == null ? SystemColors.WindowText : m_coloringContext.GetColor(ColoringTypes.ForeColor, annotation); // keep the width of border in 2 pixel after transformation to avoid D2d antialiasing away the line float borderThickness = 2.0f/m_scaleX; g.FillRectangle(bounds, backColor); g.DrawRectangle(bounds, m_theme.GetOutLineBrush(style), borderThickness); //// draw titlebar //if (style == DiagramDrawingStyle.LastSelected || style == DiagramDrawingStyle.Selected) //{ // var titleBarRect = new RectangleF(bounds.X, bounds.Y, bounds.Width, Margin.Top - 1); // g.FillRectangle(titleBarRect, ControlPaint.Dark(backColor)); //} //// line seperate titlebar from text content //g.DrawLine(bounds.X, bounds.Y + Margin.Top-1, bounds.X + bounds.Width, bounds.Y + Margin.Top-1, ControlPaint.Dark(backColor), borderThickness); // draw content if (drawText) { var contentBounds = new RectangleF(bounds.X + Margin.Left, bounds.Y + Margin.Top, bounds.Width - Margin.Size.Width, bounds.Height - Margin.Size.Height); contentBounds.Width = Math.Max(contentBounds.Width, MinimumWidth); contentBounds.Height = Math.Max(contentBounds.Height, MinimumHeight); var textBounds = contentBounds; TextEditor textEditor; if (!m_annotationEditors.TryGetValue(annotation,out textEditor)) { // first assume no v-scroll bar needed var textLayout = D2dFactory.CreateTextLayout(annotation.Text, m_theme.TextFormat, contentBounds.Width, contentBounds.Height); if (m_theme.TextFormat.Underlined) textLayout.SetUnderline(true, 0, annotation.Text.Length); if (m_theme.TextFormat.Strikeout) textLayout.SetStrikethrough(true, 0, annotation.Text.Length); if (textLayout.Height > textLayout.LayoutHeight) // need v-scroll bar { textLayout.LayoutWidth = contentBounds.Width - ScrollBarWidth - 2 * ScrollBarMargin; } textEditor = new TextEditor { TextLayout = textLayout, TextFormat = m_theme.TextFormat, TopLine = 0, VerticalScrollBarVisibe = textLayout.Height > textLayout.LayoutHeight }; m_annotationEditors.Add(annotation, textEditor); } else if (textEditor.TextLayout.Text != annotation.Text) // text content changed, for example, undo,redo { textEditor.ResetText(annotation.Text); } int topLine = textEditor.TopLine; textEditor.VerticalScrollBarVisibe = textEditor.TextLayout.Height > textEditor.TextLayout.LayoutHeight; if (textEditor.VerticalScrollBarVisibe) textBounds.Width -= ScrollBarWidth + 2 * ScrollBarMargin; if (Math.Abs(textEditor.TextLayout.LayoutWidth - textBounds.Width) + Math.Abs(textEditor.TextLayout.LayoutHeight - textBounds.Height) > 1.0) { textEditor.TextLayout.LayoutWidth = textBounds.Width; // layout width and height can be updated textEditor.TextLayout.LayoutHeight = textBounds.Height; textEditor.Validate(); } float yOffset = textEditor.GetLineYOffset(topLine); PointF origin = new PointF(contentBounds.Location.X, contentBounds.Location.Y - yOffset); g.PushAxisAlignedClip(contentBounds); // adjust caret. // pull out this code to the caller. if ( annotation == m_editingAnnotation && m_caretCreated) { var caretRect = textEditor.GetCaretRect(); caretRect.Offset(origin); // set Windows caret position if (contentBounds.IntersectsWith(caretRect) && AdaptedControl.Focused) { Matrix3x2F xform = m_transformAdapter != null ? m_transformAdapter.Transform : g.Transform; var caretClientRect = Matrix3x2F.Transform(xform, caretRect); float ratio = m_scaleX*m_theme.TextFormat.FontHeight/CaretHeight; if (ratio > 1.1f || ratio < 0.9f) // adjust caret height { CaretHeight = (int)(m_scaleX*m_theme.TextFormat.FontHeight); User32.DestroyCaret(); User32.CreateCaret(AdaptedControl.Handle, IntPtr.Zero, CaretWidth, CaretHeight); } // align bottom User32.SetCaretPos((int) caretClientRect.X, (int)(caretClientRect.Y + caretClientRect.Height - CaretHeight)); if (!m_rmbPressed) AdaptedControl.HasKeyboardFocus = true; } else HideCaret(); } // draw the selection range above the text. if (textEditor.SelectionLength > 0) { D2dBrush hibrush = AdaptedControl.Focused ? m_theme.TextHighlightBrush : m_solidBrush; var hitTestMetrics = textEditor.TextLayout.HitTestTextRange(textEditor.SelectionStart, textEditor.SelectionLength, 0, 0); for (int i = 0; i < hitTestMetrics.Length; ++i) { var highlightRect = new RectangleF(hitTestMetrics[i].Point.X, hitTestMetrics[i].Point.Y, hitTestMetrics[i].Width, hitTestMetrics[i].Height); highlightRect.Offset(origin); g.FillRectangle(highlightRect, hibrush); } } // draw text g.DrawTextLayout(origin, textEditor.TextLayout, foreColor); g.PopAxisAlignedClip(); // draw v-scroll bar // if (contentBounds.Height < textEditor.TextLayout.Height) if(textEditor.VerticalScrollBarVisibe) { float visibleLines = textEditor.GetVisibleLines(); float vMin = topLine * contentBounds.Height / textEditor.TextLayout.LineCount; float vMax = (topLine + visibleLines - 1) * contentBounds.Height / textEditor.TextLayout.LineCount; // if (m_scrolling) // { var trackBounds = new RectangleF(contentBounds.Right - ScrollBarMargin - ScrollBarWidth, contentBounds.Y, ScrollBarWidth, contentBounds.Height); g.FillRectangle(trackBounds, Color.Gainsboro); // } var thumbBounds = new RectangleF(contentBounds.Right - ScrollBarMargin - ScrollBarWidth, contentBounds.Y + vMin, ScrollBarWidth, vMax - vMin); g.FillRectangle(thumbBounds, Color.DimGray); } } }