コード例 #1
0
 /// <summary>
 /// Draws the margin at the given position.
 /// </summary>
 /// <param name="displayContext">The display context.</param>
 /// <param name="renderContext">The render context.</param>
 /// <param name="lineIndex">The line index being rendered.</param>
 /// <param name="point">The point of the specific line number.</param>
 /// <param name="height">The height of the rendered line.</param>
 /// <param name="lineBlockStyle">The line block style.</param>
 public abstract void Draw(
     IDisplayContext displayContext,
     IRenderContext renderContext,
     int lineIndex,
     PointD point,
     double height,
     LineBlockStyle lineBlockStyle);
        /// <summary>
        /// Draws the margins at the given position.
        /// </summary>
        /// <param name="displayContext">The display context.</param>
        /// <param name="renderContext">The render context.</param>
        /// <param name="lineIndex">The line index being rendered.</param>
        /// <param name="point">The point of the specific line number.</param>
        /// <param name="height">The height of the rendered line.</param>
        /// <param name="lineBlockStyle">The line block style.</param>
        public void Draw(
            IDisplayContext displayContext,
            IRenderContext renderContext,
            int lineIndex,
            PointD point,
            double height,
            LineBlockStyle lineBlockStyle)
        {
            // Go through the margins and draw each one so they don't overlap.
            double dx = point.X;

            foreach (MarginRenderer marginRenderer in this)
            {
                // If it isn't visible, then we do nothing.
                if (!marginRenderer.Visible)
                {
                    continue;
                }

                // Draw out the individual margin.
                marginRenderer.Draw(
                    displayContext,
                    renderContext,
                    lineIndex,
                    new PointD(dx, point.Y),
                    height,
                    lineBlockStyle);

                // Add to the x coordinate so we don't overlap the renders.
                dx += marginRenderer.Width;
            }
        }
コード例 #3
0
        public LineBlockStyle GetLineStyle(
            LinePosition linePosition,
            LineContexts lineContexts = LineContexts.None)
        {
            int            lineIndex = linePosition.GetLineIndex(LineBuffer);
            LineBlockStyle results   = GetLineStyle(lineIndex, lineContexts);

            return(results);
        }
コード例 #4
0
        /// <summary>
        /// Gets the line X coordinates from either the state if we have one
        /// or calculate it from the buffer position's X coordinate.
        /// </summary>
        /// <param name="controller">The action context.</param>
        /// <param name="wrappedLine">The wrapped line.</param>
        /// <param name="position">The position.</param>
        /// <returns></returns>
        private static int GetLineX(
            EditorViewController controller,
            LayoutLine wrappedLine,
            TextPosition position)
        {
            int lineX;
            var state = controller.States.Get <VerticalMovementActionState>();

            if (state == null)
            {
                // Calculate the line state from the caret position. The cursor
                // is always to the left of the character unless we're at the
                // end, and then it's considered trailing of the previous
                // character.
                LineBuffer lineBuffer     = controller.DisplayContext.LineBuffer;
                int        lineIndex      = position.LinePosition.GetLineIndex(lineBuffer.LineCount);
                string     lineText       = lineBuffer.GetLineText(lineIndex);
                int        characterIndex = position.CharacterPosition.GetCharacterIndex(lineText);
                bool       trailing       = false;

                if (characterIndex == lineText.Length &&
                    lineText.Length > 0)
                {
                    characterIndex--;
                    trailing = true;
                }

                // Because Pango works with UTF-8-based indexes, we need to
                // convert the C# character index into that index to properly
                // identify the character.
                characterIndex = NormalizeEmptyStrings(lineText, characterIndex);
                int unicodeIndex = PangoUtility.TranslateStringToPangoIndex(
                    lineText, characterIndex);
                lineX = wrappedLine.IndexToX(unicodeIndex, trailing);

                // We need the line's style since it may have left passing
                // which will change our columns.
                LineBlockStyle style =
                    controller.DisplayContext.Renderer.GetLineStyle(
                        lineIndex, LineContexts.CurrentLine);

                var pixelPadding = (int)style.Padding.Left.GetValueOrDefault(0);
                lineX += Units.FromPixels(pixelPadding);

                // Save a new state into the states.
                state = new VerticalMovementActionState(lineX);
                controller.States.Add(state);
            }
            else
            {
                // Get the line coordinate from the state.
                lineX = state.LayoutLineX;
            }

            return(lineX);
        }
コード例 #5
0
        /// <summary>
        /// Gets the buffer position from a given point.
        /// </summary>
        /// <param name="widgetPoint">The widget point.</param>
        /// <param name="displayContext">The display context.</param>
        /// <returns></returns>
        public static TextPosition GetTextPosition(
            PointD widgetPoint,
            EditorViewController controller)
        {
            IDisplayContext displayContext = controller.DisplayContext;
            double          y         = widgetPoint.Y + displayContext.BufferOffsetY;
            int             lineIndex = displayContext.Renderer.GetLineLayoutRange(y);
            Layout          layout    = displayContext.Renderer.GetLineLayout(
                lineIndex, LineContexts.None);

            // Shift the buffer-relative coordinates to layout-relative coordinates.
            double layoutY = y;

            if (lineIndex > 0)
            {
                layoutY -= displayContext.Renderer.GetLineLayoutHeight(0, lineIndex - 1);
            }

            int pangoLayoutY = Units.FromPixels((int)layoutY);

            // Shift the buffer-relative coordinates to handle padding.
            LineBlockStyle style = displayContext.Renderer.GetLineStyle(
                lineIndex, LineContexts.None);
            double layoutX = widgetPoint.X - style.Left;

            // Determines where in the layout is the point.
            int pangoLayoutX = Units.FromPixels((int)layoutX);
            int unicodeIndex;
            int trailing;

            layout.XyToIndex(pangoLayoutX, pangoLayoutY, out unicodeIndex, out trailing);

            // When dealing with UTF-8 characters, we have to convert the
            // Unicode index into a C# index.
            string lineText = displayContext.LineBuffer.GetLineText(lineIndex);

            unicodeIndex = NormalizeEmptyStrings(lineText, unicodeIndex);
            int characterIndex = PangoUtility.TranslatePangoToStringIndex(
                lineText, unicodeIndex);

            // If the source text is empty, then we disable the trailing.
            if (lineText.Length == 0)
            {
                trailing = 0;
            }

            // Return the buffer position.
            return(new TextPosition(lineIndex, characterIndex + trailing));
        }
コード例 #6
0
        /// <summary>
        /// Gets the height of a single line layout.
        /// </summary>
        /// <param name="lineIndex">The line.</param>
        /// <returns></returns>
        private int GetLineLayoutHeight(int lineIndex)
        {
            // Get the extents for the line while rendered.
            Layout lineLayout = GetLineLayout(lineIndex, LineContexts.None);
            int    lineWidth,
                   lineHeight;

            lineLayout.GetPixelSize(out lineWidth, out lineHeight);

            // Get the style to include the style's height.
            LineBlockStyle style = GetLineStyle(lineIndex, LineContexts.None);

            lineHeight += (int)Math.Ceiling(style.Height);

            // Return the resulting height.
            return(lineHeight);
        }
コード例 #7
0
        private static int GetLeftPaddingPixels(
            EditorViewController controller,
            int lineIndex)
        {
            // Get the style for the given line.
            LineBlockStyle style =
                controller.DisplayContext.Renderer.GetLineStyle(
                    lineIndex, LineContexts.CurrentLine);

            if (style == null)
            {
                return(0);
            }

            var pixelPadding = (int)style.Padding.Left.GetValueOrDefault(0);

            return(pixelPadding);
        }
コード例 #8
0
        /// <summary>
        /// Caches information about a line into the cached line.
        /// </summary>
        /// <param name="view">The view.</param>
        /// <param name="line">The line.</param>
        public void Cache(
            EditorViewRenderer view,
            int line)
        {
            // If we already have a layout, we don't need to do anything.
            if (Layout != null)
            {
                return;
            }

            // Cache various elements of the rendering. This is an expensive
            // operation, so we want to minimize it.
            Layout         layout = view.GetLineLayout(line, LineContexts.None);
            LineBlockStyle style  = view.GetLineStyle(line, LineContexts.None);

            Style  = style;
            Layout = layout;
            Height = (int)(layout.GetPixelHeight() + style.Height);
        }
コード例 #9
0
        /// <summary>
        /// Gets the line layout for a given line.
        /// </summary>
        /// <param name="lineIndex">The line.</param>
        /// <param name="lineContexts">The line contexts.</param>
        /// <returns></returns>
        public virtual Layout GetLineLayout(
            int lineIndex,
            LineContexts lineContexts)
        {
            // Get the layout.
            var layout = new Layout(DisplayContext.PangoContext);

            // Assign the given style to the layout.
            LineBlockStyle style = GetLineStyle(lineIndex, lineContexts);

            DisplayContext.SetLayout(layout, style, DisplayContext.TextWidth);

            // Set the markup and return.
            string markup        = GetSelectionMarkup(lineIndex, lineContexts);
            string coloredMarkup = DrawingUtility.WrapColorMarkup(
                markup, style.GetForegroundColor());

            layout.SetMarkup(coloredMarkup);

            return(layout);
        }
コード例 #10
0
        /// <summary>
        /// Gets the region that the caret would be drawn in.
        /// </summary>
        /// <returns></returns>
        public Rectangle GetDrawRegion()
        {
            // Get the coordinates on the screen and the height of the current line.
            int    lineHeight;
            PointD point = Position.ToScreenCoordinates(displayContext, out lineHeight);
            double x     = point.X;
            double y     = point.Y;

            // Translate the buffer coordinates into the screen visible coordinates.
            y -= displayContext.BufferOffsetY;

            // Shift the contents to compenstate for the margins.
            LineBlockStyle style =
                displayContext.Renderer.GetLineStyle(Position.LinePosition);

            x += displayContext.TextX;
            x += style.Left;

            // Return the resulting rectangle.
            return(new Rectangle(x, y, 1, lineHeight));
        }
コード例 #11
0
        /// <summary>
        /// Configures the theme for all the elements used in the demo.
        /// </summary>
        private void SetupTheme()
        {
            // Grab the theme.
            Theme theme = editorView.Theme;

            // Set up the indicator styles.
            theme.IndicatorStyles["Error"] = new IndicatorStyle(
                "Error", 100, new Color(1, 0, 0));
            theme.IndicatorStyles["Warning"] = new IndicatorStyle(
                "Warning", 10, new Color(1, 165 / 255.0, 0));
            theme.IndicatorRenderStyle   = IndicatorRenderStyle.Ratio;
            theme.IndicatorPixelHeight   = 2;
            theme.IndicatorRatioPixelGap = 1;

            var indicatorBackgroundStyle = new RegionBlockStyle();

            indicatorBackgroundStyle.BackgroundColor = new Color(1, 0.9, 1);
            //indicatorBackgroundStyle.Borders.SetBorder(new Border(1, new Color(0.5, 0, 0)));
            theme.RegionStyles[IndicatorView.BackgroundRegionName] =
                indicatorBackgroundStyle;

            var indicatorVisibleStyle = new RegionBlockStyle();

            indicatorVisibleStyle.BackgroundColor = new Color(1, 1, 0.9);
            indicatorVisibleStyle.Borders.SetBorder(new Border(1, new Color(0, 0.5, 0)));
            theme.RegionStyles[IndicatorView.VisibleRegionName] = indicatorVisibleStyle;

            // Set up the editable text styles.
            for (var type = DemoLineStyleType.Default;
                 type <= DemoLineStyleType.Break;
                 type++)
            {
                // Create a line style for this type.
                var lineStyle = new LineBlockStyle(theme.TextLineStyle);

                theme.LineStyles[type.ToString()] = lineStyle;

                // Custom the style based on type.
                switch (type)
                {
                case DemoLineStyleType.Chapter:
                    lineStyle.FontDescription =
                        FontDescriptionCache.GetFontDescription("Serif Bold 24");
                    lineStyle.Borders.Bottom = new Border(2, new Color(0, 0, 0));
                    lineStyle.Margins.Top    = 6;
                    lineStyle.Margins.Bottom = 6;
                    break;

                case DemoLineStyleType.Heading:
                    lineStyle.FontDescription =
                        FontDescriptionCache.GetFontDescription("Sans Bold 18");
                    lineStyle.Padding.Left = 25;
                    break;

                case DemoLineStyleType.Borders:
                    lineStyle.Padding.Left   = 15;
                    lineStyle.Padding.Right  = 15;
                    lineStyle.Margins.Left   = 10;
                    lineStyle.Margins.Right  = 10;
                    lineStyle.Margins.Top    = 10;
                    lineStyle.Margins.Bottom = 10;
                    lineStyle.Borders.Bottom = new Border(5, new Color(1, 0, 0));
                    lineStyle.Borders.Top    = new Border(5, new Color(0, 1, 0));
                    lineStyle.Borders.Right  = new Border(5, new Color(0, 0, 1));
                    lineStyle.Borders.Left   = new Border(5, new Color(1, 0, 1));
                    break;

                case DemoLineStyleType.Default:
                    lineStyle.Padding.Left = 50;
                    break;

                case DemoLineStyleType.Break:
                    lineStyle.Padding.Left = 50;
                    lineStyle.Alignment    = Alignment.Center;
                    break;
                }
            }

            // Create the inactive header style.
            var inactiveHeadingStyle = new LineBlockStyle(theme.LineStyles["Heading"]);

            inactiveHeadingStyle.ForegroundColor = new Color(0.8, 0.8, 0.8);

            theme.LineStyles["Inactive Heading"] = inactiveHeadingStyle;
        }
コード例 #12
0
 /// <summary>
 /// Resets the cached line.
 /// </summary>
 public void Reset()
 {
     Height = 0;
     Style  = null;
     Layout = null;
 }
コード例 #13
0
        /// <summary>
        /// Sets up the theme elements.
        /// </summary>
        /// <param name="theme"></param>
        public static void SetupTheme(Theme theme)
        {
            // Set up the indicator elements.
            SetupThemeIndicators(theme);

            // Use slightly more muted colors for the current line.
            theme.RegionStyles["EditorViewCurrentLine"].BackgroundColor = new Color(
                1, 1, 1);
            theme.RegionStyles["EditorViewCurrentWrappedLine"].BackgroundColor =
                new Color(245 / 255.0, 245 / 255.0, 220 / 255.0);

            // Set up the paragraph style.
            var paragraphyStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro 16"),
                Margins =
                {
                    Top    = 8,
                    Bottom = 8
                }
            };

            // Set up the chapter style.
            var chapterStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro Bold 32"),
                Margins =
                {
                    Bottom = 5
                },
                Borders =
                {
                    Bottom = new Border(2, new Color(0, 0, 0))
                }
            };

            // Set up the scene style.
            var sceneStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro Italic 24"),
                ForegroundColor = new Color(.5, .5, .5)
            };

            // Set up the epigraph style.
            var epigraphStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro 12"),
                Padding =
                {
                    Left = 20
                }
            };

            // Set up the epigraph attributation style.
            var epigraphAttributationStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro Italic 12"),
                Padding =
                {
                    Left = 20
                }
            };

            // Add all the styles into the theme.
            theme.LineStyles[BlockTypeSupervisor.ParagraphName]           = paragraphyStyle;
            theme.LineStyles[BlockTypeSupervisor.ChapterName]             = chapterStyle;
            theme.LineStyles[BlockTypeSupervisor.SceneName]               = sceneStyle;
            theme.LineStyles[BlockTypeSupervisor.EpigraphName]            = epigraphStyle;
            theme.LineStyles[BlockTypeSupervisor.EpigraphAttributionName] =
                epigraphAttributationStyle;
        }
コード例 #14
0
        /// <summary>
        /// Converts the given line and character coordinates into pixel coordinates
        /// on the display.
        /// </summary>
        /// <param name="bufferPosition">The buffer position.</param>
        /// <param name="displayContext">The display context.</param>
        /// <param name="lineHeight">Will contains the height of the current line.</param>
        /// <returns></returns>
        public static PointD ToScreenCoordinates(
            this TextPosition bufferPosition,
            IDisplayContext displayContext,
            out int lineHeight)
        {
            // Get the line index, which needs to be a number in range.
            EditorViewRenderer buffer = displayContext.Renderer;
            int lineIndex             =
                bufferPosition.LinePosition.GetLineIndex(displayContext.LineBuffer);

            // Pull out some of the common things we'll be using in this method.
            int    bufferLineIndex = buffer.LineBuffer.NormalizeLineIndex(lineIndex);
            Layout layout          = buffer.GetLineLayout(
                bufferLineIndex, LineContexts.Unformatted);
            LineBlockStyle style = buffer.GetLineStyle(
                bufferLineIndex, LineContexts.Unformatted);

            // Figure out the top of the current line in relation to the entire
            // buffer and view. For lines beyond the first, we use
            // GetLineLayoutHeight because it also takes into account the line
            // spacing and borders which we would have to calculate otherwise.
            double y = bufferLineIndex == 0
                                ? 0
                                : buffer.GetLineLayoutHeight(0, bufferLineIndex - 1);

            // Add the style offset for the top-padding.
            y += style.Top;

            // The cursor position code uses Unicode instead of C# character
            // positions. This means we have to advance more than just one
            // value to calculate it. This actually uses UTF-8 encoding to
            // calculate the indexes.
            string lineText       = displayContext.LineBuffer.GetLineText(lineIndex);
            int    characterIndex =
                bufferPosition.GetCharacterIndex(displayContext.LineBuffer);
            int unicodeCharacter = PangoUtility.TranslateStringToPangoIndex(
                lineText, characterIndex);

            // We need to figure out the relative position. If the position equals
            // the length of the string, we want to put the caret at the end of the
            // character. Otherwise, we put it on the front of the character to
            // indicate insert point.
            bool trailing   = false;
            int  lineLength = buffer.LineBuffer.GetLineLength(
                bufferLineIndex, LineContexts.Unformatted);

            if (unicodeCharacter == lineLength)
            {
                // Shift back one character to calculate the position and put
                // the cursor at the end of the character.
                unicodeCharacter--;
                trailing = true;
            }

            // Figure out which wrapped line we are actually on and the position
            // inside that line. If the character equals the length of the string,
            // then we want to move to the end of it.
            int wrappedLineIndex;
            int layoutX;

            layout.IndexToLineX(
                unicodeCharacter, trailing, out wrappedLineIndex, out layoutX);

            // Get the relative offset into the wrapped lines.
            Rectangle layoutPoint = layout.IndexToPos(unicodeCharacter);

            y += Units.ToPixels(layoutPoint.Y);

            // Get the height of the wrapped line.
            Rectangle ink     = Rectangle.Zero;
            Rectangle logical = Rectangle.Zero;

            layout.Lines[wrappedLineIndex].GetPixelExtents(ref ink, ref logical);
            lineHeight = logical.Height;

            // Return the results.
            return(new PointD(Units.ToPixels(layoutX), y));
        }
        /// <summary>
        /// Draws the margin at the given position.
        /// </summary>
        /// <param name="displayContext">The display context.</param>
        /// <param name="renderContext">The render context.</param>
        /// <param name="lineIndex">The line index being rendered.</param>
        /// <param name="point">The point of the specific line number.</param>
        /// <param name="height">The height of the rendered line.</param>
        /// <param name="lineBlockStyle"></param>
        public override void Draw(
            IDisplayContext displayContext,
            IRenderContext renderContext,
            int lineIndex,
            PointD point,
            double height,
            LineBlockStyle lineBlockStyle)
        {
            // Figure out the style we need to use.
            MarginBlockStyle style =
                lineBlockStyle.MarginStyles.Get(Theme.LineNumberStyle);

            // Create a layout object if we don't have one.
            if (layout == null)
            {
                layout = new Layout(displayContext.PangoContext);
                displayContext.SetLayout(layout, style, Width);
            }

            // Figure out the line number.
            string lineNumber = displayContext.LineBuffer.GetLineNumber(lineIndex);

            if (string.IsNullOrEmpty(lineNumber))
            {
                lineNumber = String.Empty;
            }

            // Wrap the text in a markup that includes the foreground color.
            string markup = DrawingUtility.WrapColorMarkup(
                lineNumber, style.GetForegroundColor());

            layout.SetMarkup(markup);

            // Figure out if the current width of the margin is wider than what
            // we've already calculated.
            if (lineNumber.Length > maximumCharactersRendered)
            {
                // Get the new width as if we don't have line-wrapping.
                int layoutWidth,
                    layoutHeight;

                layout.Width = Int32.MaxValue;
                layout.GetSize(out layoutWidth, out layoutHeight);

                // Set the layout width so we don't have to redo the entire
                // layout and update our margin width (including style).
                layout.Width = layoutWidth;
                SetWidth((int)(Units.ToPixels(layoutWidth) + style.Width));

                // Since we are looking at a large length of line number, update
                // it so we don't continually calculate the line width.
                maximumCharactersRendered = lineNumber.Length;

                // Request a full redraw since this will change even the lines
                // we already drew. We draw the line anyways to avoid seeing a
                // white block.
                displayContext.RequestScrollToCaret();
                displayContext.RequestRedraw();
            }

            // Use the common drawing routine to handle the borders and padding.
            DrawingUtility.DrawLayout(
                displayContext,
                renderContext,
                new Rectangle(point.X, point.Y, Width, height),
                layout,
                style);
        }
コード例 #16
0
        /// <summary>
        /// Sets up the theme elements.
        /// </summary>
        /// <param name="theme"></param>
        public static void SetupTheme(Theme theme)
        {
            // Set up the indicator elements.
            SetupThemeIndicators(theme);

            // Use slightly more muted colors for the current line.
            theme.RegionStyles["EditorViewCurrentLine"].BackgroundColor = new Color(
                1, 1, 1);
            theme.RegionStyles["EditorViewCurrentWrappedLine"].BackgroundColor =
                new Color(245 / 255.0, 245 / 255.0, 220 / 255.0);

            // Set up the paragraph style.
            var paragraphyStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro 16"),
                Margins =
                {
                    Top = 8,
                    Bottom = 8
                }
            };

            // Set up the chapter style.
            var chapterStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro Bold 32"),
                Margins =
                {
                    Bottom = 5
                },
                Borders =
                {
                    Bottom = new Border(2, new Color(0, 0, 0))
                }
            };

            // Set up the scene style.
            var sceneStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro Italic 24"),
                ForegroundColor = new Color(.5, .5, .5)
            };

            // Set up the epigraph style.
            var epigraphStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro 12"),
                Padding =
                {
                    Left = 20
                }
            };

            // Set up the epigraph attributation style.
            var epigraphAttributationStyle = new LineBlockStyle(theme.TextLineStyle)
            {
                FontDescription =
                    FontDescriptionCache.GetFontDescription("Source Code Pro Italic 12"),
                Padding =
                {
                    Left = 20
                }
            };

            // Add all the styles into the theme.
            theme.LineStyles[BlockTypeSupervisor.ParagraphName] = paragraphyStyle;
            theme.LineStyles[BlockTypeSupervisor.ChapterName] = chapterStyle;
            theme.LineStyles[BlockTypeSupervisor.SceneName] = sceneStyle;
            theme.LineStyles[BlockTypeSupervisor.EpigraphName] = epigraphStyle;
            theme.LineStyles[BlockTypeSupervisor.EpigraphAttributionName] =
                epigraphAttributationStyle;
        }
コード例 #17
0
        /// <summary>
        /// Called when the widget is exposed or drawn.
        /// </summary>
        /// <param name="e">The e.</param>
        /// <returns></returns>
        protected override bool OnExposeEvent(EventExpose e)
        {
            // Figure out the area we are rendering into.
            Gdk.Rectangle area      = e.Region.Clipbox;
            var           cairoArea = new Rectangle(area.X, area.Y, area.Width, area.Height);

            using (Context cairoContext = CairoHelper.Create(e.Window))
            {
                // Create a render context.
                var renderContext = new RenderContext(cairoContext);
                renderContext.RenderRegion = cairoArea;

                // If we don't have a buffer at this point, don't render anything.
                if (Renderer == null ||
                    LineBuffer == null)
                {
                    return(true);
                }

                // Paint the background color of the window.
                RegionBlockStyle backgroundStyle =
                    Theme.RegionStyles[Theme.BackgroundRegionStyleName];
                DrawingUtility.DrawLayout(this, renderContext, cairoArea, backgroundStyle);

                // Reset the layout and its properties.
                Renderer.Width = area.Width - margins.Width;

                // Figure out the viewport area we'll be drawing.
                int offsetY = 0;

                if (verticalAdjustment != null)
                {
                    offsetY += (int)verticalAdjustment.Value;
                }

                var viewArea = new Rectangle(
                    area.X, area.Y + offsetY, area.Width, area.Height);

                // Determine the line range visible in the given area.
                int startLine,
                    endLine;
                Renderer.GetLineLayoutRange(viewArea, out startLine, out endLine);

                // Determine where the first line actually starts.
                int startLineY = 0;

                if (startLine > 0)
                {
                    startLineY = Renderer.GetLineLayoutHeight(0, startLine - 1);
                }

                // Go through the lines and draw each one in the correct position.
                double currentY = startLineY - offsetY;

                for (int lineIndex = startLine;
                     lineIndex <= endLine;
                     lineIndex++)
                {
                    // Figure out if we are on the current line.
                    var  lineContexts = LineContexts.None;
                    bool currentLine  = false;

                    if (lineIndex == caret.Position.LinePosition)
                    {
                        // Add the curent line to the context.
                        lineContexts |= LineContexts.CurrentLine;
                        currentLine   = true;
                    }

                    // Pull out the layout and style since we'll use it.
                    Layout         layout = Renderer.GetLineLayout(lineIndex, lineContexts);
                    LineBlockStyle style  = Renderer.GetLineStyle(lineIndex, lineContexts);

                    // Get the extents for that line.
                    int layoutWidth,
                        layoutHeight;
                    layout.GetPixelSize(out layoutWidth, out layoutHeight);

                    // Figure out the height of the line including padding.
                    double height = layoutHeight + style.Height;

                    if (currentLine)
                    {
                        // If we have a full-line background color, display it.
                        RegionBlockStyle currentLineStyle =
                            Theme.RegionStyles[Theme.CurrentLineRegionStyleName];

                        if (currentLineStyle != null)
                        {
                            var lineArea = new Rectangle(TextX, currentY, TextWidth, height);

                            DrawingUtility.DrawLayout(
                                this, renderContext, lineArea, currentLineStyle);
                        }

                        // If we have a wrapped line background color, draw it.
                        RegionBlockStyle currentWrappedLineStyle =
                            Theme.RegionStyles[Theme.CurrentWrappedLineRegionStyleName];

                        if (currentWrappedLineStyle != null)
                        {
                            // Get the wrapped line for the caret's position.
                            LayoutLine      wrappedLine = caret.Position.GetWrappedLine(this);
                            Pango.Rectangle wrappedLineExtents;

                            wrappedLine.GetPixelExtents(out wrappedLineExtents);

                            // Draw the current wrapped line index.
                            var wrappedLineArea = new Rectangle(
                                TextX,
                                currentY + wrappedLineExtents.Y + style.Top,
                                TextWidth,
                                wrappedLineExtents.Height);

                            DrawingUtility.DrawLayout(
                                this, renderContext, wrappedLineArea, currentWrappedLineStyle);
                        }
                    }

                    // Draw the current line along with wrapping and padding.
                    DrawingUtility.DrawLayout(
                        this,
                        renderContext,
                        new Rectangle(TextX, currentY, TextWidth, height),
                        layout,
                        style);

                    // Render out the margin renderers.
                    margins.Draw(
                        this, renderContext, lineIndex, new PointD(0, currentY), height, style);

                    // Move down a line.
                    currentY += height;
                }

                // Draw the caret on the screen, but only if we have focus.
                if (IsFocus)
                {
                    caret.Draw(renderContext);
                }

                // Show the scroll region, if requested.
                if (editorViewSettings.ShowScrollPadding)
                {
                    cairoContext.Color = new Color(1, 0.5, 0.5);
                    cairoContext.Rectangle(scrollPaddingRegion);
                    cairoContext.Stroke();
                }
            }

            return(true);
        }