Пример #1
0
        void DrawBlockBg(Cairo.Context ctx, double x, int width, BlockInfo block)
        {
            if (!IsChangeBlock(block.Type))
            {
                return;
            }

            x += 0.5;
            Gdk.Color color  = block.Type == BlockType.Added ? baseAddColor : baseRemoveColor;
            double    y      = block.YStart + 0.5;
            int       height = block.YEnd - block.YStart;

            double markerx = x + LeftPaddingBlock - 0.5;
            double rd      = RoundedSectionRadius;

            if (block.SectionStart)
            {
                ctx.Arc(x + rd, y + rd, rd, 180 * (Math.PI / 180), 270 * (Math.PI / 180));
                ctx.LineTo(markerx, y);
            }
            else
            {
                ctx.MoveTo(markerx, y);
            }

            ctx.LineTo(markerx, y + height);

            if (block.SectionEnd)
            {
                ctx.LineTo(x + rd, y + height);
                ctx.Arc(x + rd, y + height - rd, rd, 90 * (Math.PI / 180), 180 * (Math.PI / 180));
            }
            else
            {
                ctx.LineTo(x, y + height);
            }
            if (block.SectionStart)
            {
                ctx.LineTo(x, y + rd);
            }
            else
            {
                ctx.LineTo(x, y);
            }
            ctx.Color = color.AddLight(0.1).ToCairoColor();
            ctx.Fill();

            ctx.Rectangle(markerx, y, width - markerx, height);
            using (Cairo.Gradient pat = new Cairo.LinearGradient(x, y, x + width, y)) {
                pat.AddColorStop(0, color.AddLight(0.21).ToCairoColor());
                pat.AddColorStop(1, color.AddLight(0.3).ToCairoColor());
                ctx.Pattern = pat;
                ctx.Fill();
            }
        }
Пример #2
0
        void DrawChangeSymbol(Cairo.Context ctx, double x, int width, BlockInfo block)
        {
            if (!IsChangeBlock(block.Type))
            {
                return;
            }

            Gdk.Color color = block.Type == BlockType.Added ? baseAddColor : baseRemoveColor;

            int ssize   = 8;
            int barSize = 3;

            if (ssize - 2 > lineHeight)
            {
                ssize = lineHeight - 2;
            }
            if (ssize <= 0)
            {
                return;
            }

            double inSize = (ssize / 2) - (barSize / 2);
            double py     = block.YStart + ((block.YEnd - block.YStart) / 2 - ssize / 2) + 0.5;
            double px     = x + (LeftPaddingBlock / 2) - (ssize / 2) + 0.5;

            if (block.Type == BlockType.Added)
            {
                ctx.MoveTo(px + inSize, py);
                ctx.RelLineTo(barSize, 0);
                ctx.RelLineTo(0, inSize);
                ctx.RelLineTo(inSize, 0);
                ctx.RelLineTo(0, barSize);
                ctx.RelLineTo(-inSize, 0);
                ctx.RelLineTo(0, inSize);
                ctx.RelLineTo(-barSize, 0);
                ctx.RelLineTo(0, -inSize);
                ctx.RelLineTo(-inSize, 0);
                ctx.RelLineTo(0, -barSize);
                ctx.RelLineTo(inSize, 0);
                ctx.RelLineTo(0, -inSize);
                ctx.ClosePath();
            }
            else
            {
                ctx.MoveTo(px, py + inSize);
                ctx.RelLineTo(ssize, 0);
                ctx.RelLineTo(0, barSize);
                ctx.RelLineTo(-ssize, 0);
                ctx.RelLineTo(0, -barSize);
                ctx.ClosePath();
            }

            ctx.Color = color.ToCairoColor();
            ctx.FillPreserve();
            ctx.Color     = color.AddLight(-0.2).ToCairoColor();;
            ctx.LineWidth = 1;
            ctx.Stroke();
        }
Пример #3
0
        protected override void Render(Drawable window, Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gdk.Rectangle expose_area, CellRendererState flags)
        {
            if (isDisposed)
            {
                return;
            }
            if (diffMode)
            {
                if (path.Equals(selctedPath))
                {
                    selectedLine = -1;
                    selctedPath  = null;
                }

                int w, maxy;
                window.GetSize(out w, out maxy);
                if (DrawLeft)
                {
                    cell_area.Width += cell_area.X - leftSpace;
                    cell_area.X      = leftSpace;
                }
                var treeview = widget as FileTreeView;
                var p        = treeview != null? treeview.CursorLocation : null;

                cell_area.Width -= RightPadding;

                window.DrawRectangle(widget.Style.BaseGC(Gtk.StateType.Normal), true, cell_area.X, cell_area.Y, cell_area.Width - 1, cell_area.Height);

                Gdk.GC normalGC  = widget.Style.TextGC(StateType.Normal);
                Gdk.GC removedGC = new Gdk.GC(window);
                removedGC.Copy(normalGC);
                removedGC.RgbFgColor = baseRemoveColor.AddLight(-0.3);
                Gdk.GC addedGC = new Gdk.GC(window);
                addedGC.Copy(normalGC);
                addedGC.RgbFgColor = baseAddColor.AddLight(-0.3);
                Gdk.GC infoGC = new Gdk.GC(window);
                infoGC.Copy(normalGC);
                infoGC.RgbFgColor = widget.Style.Text(StateType.Normal).AddLight(0.2);

                Cairo.Context ctx = CairoHelper.Create(window);

                // Rendering is done in two steps:
                // 1) Get a list of blocks to render
                // 2) render the blocks

                int y = cell_area.Y + 2;

                // cline keeps track of the current source code line (the one to jump to when double clicking)
                int       cline        = 1;
                bool      inHeader     = true;
                BlockInfo currentBlock = null;

                List <BlockInfo> blocks = new List <BlockInfo> ();

                for (int n = 0; n < lines.Length; n++, y += lineHeight)
                {
                    string line = lines [n];
                    if (line.Length == 0)
                    {
                        currentBlock = null;
                        y           -= lineHeight;
                        continue;
                    }

                    char tag = line [0];

                    if (line.StartsWith("---") || line.StartsWith("+++"))
                    {
                        // Ignore this part of the header.
                        currentBlock = null;
                        y           -= lineHeight;
                        continue;
                    }
                    if (tag == '@')
                    {
                        int l = ParseCurrentLine(line);
                        if (l != -1)
                        {
                            cline = l - 1;
                        }
                        inHeader = false;
                    }
                    else if (tag != '-' && !inHeader)
                    {
                        cline++;
                    }

                    BlockType type;
                    switch (tag)
                    {
                    case '-': type = BlockType.Removed; break;

                    case '+': type = BlockType.Added; break;

                    case '@': type = BlockType.Info; break;

                    default: type = BlockType.Unchanged; break;
                    }

                    if (currentBlock == null || type != currentBlock.Type)
                    {
                        if (y > maxy)
                        {
                            break;
                        }

                        // Starting a new block. Mark section ends between a change block and a normal code block
                        if (currentBlock != null && IsChangeBlock(currentBlock.Type) && !IsChangeBlock(type))
                        {
                            currentBlock.SectionEnd = true;
                        }

                        currentBlock = new BlockInfo()
                        {
                            YStart          = y,
                            FirstLine       = n,
                            Type            = type,
                            SourceLineStart = cline,
                            SectionStart    = (blocks.Count == 0 || !IsChangeBlock(blocks[blocks.Count - 1].Type)) && IsChangeBlock(type)
                        };
                        blocks.Add(currentBlock);
                    }
                    // Include the line in the current block
                    currentBlock.YEnd     = y + lineHeight;
                    currentBlock.LastLine = n;
                }

                // Now render the blocks

                // The y position of the highlighted line
                int selectedLineRowTop = -1;

                BlockInfo lastCodeSegmentStart = null;
                BlockInfo lastCodeSegmentEnd   = null;

                foreach (BlockInfo block in blocks)
                {
                    if (block.Type == BlockType.Info)
                    {
                        // Finished drawing the content of a code segment. Now draw the segment border and label.
                        if (lastCodeSegmentStart != null)
                        {
                            DrawCodeSegmentBorder(infoGC, ctx, cell_area.X, cell_area.Width, lastCodeSegmentStart, lastCodeSegmentEnd, lines, widget, window);
                        }
                        lastCodeSegmentStart = block;
                    }

                    lastCodeSegmentEnd = block;

                    if (block.YEnd < 0)
                    {
                        continue;
                    }

                    // Draw the block background
                    DrawBlockBg(ctx, cell_area.X + 1, cell_area.Width - 2, block);

                    // Get all text for the current block
                    StringBuilder sb = new StringBuilder();
                    for (int n = block.FirstLine; n <= block.LastLine; n++)
                    {
                        string s = ProcessLine(lines [n]);
                        if (n > block.FirstLine)
                        {
                            sb.Append('\n');
                        }
                        if (block.Type != BlockType.Info && s.Length > 0)
                        {
                            sb.Append(s, 1, s.Length - 1);
                        }
                        else
                        {
                            sb.Append(s);
                        }
                    }

                    // Draw a special background for the selected line

                    if (block.Type != BlockType.Info && p.HasValue && p.Value.X >= cell_area.X && p.Value.X <= cell_area.Right && p.Value.Y >= block.YStart && p.Value.Y <= block.YEnd)
                    {
                        int    row  = (p.Value.Y - block.YStart) / lineHeight;
                        double yrow = block.YStart + lineHeight * row + 0.5;
                        double xrow = cell_area.X + LeftPaddingBlock + 0.5;
                        int    wrow = cell_area.Width - 1 - LeftPaddingBlock;
                        if (block.Type == BlockType.Added)
                        {
                            ctx.Color = baseAddColor.AddLight(0.1).ToCairoColor();
                        }
                        else if (block.Type == BlockType.Removed)
                        {
                            ctx.Color = baseRemoveColor.AddLight(0.1).ToCairoColor();
                        }
                        else
                        {
                            ctx.Color = widget.Style.Base(Gtk.StateType.Prelight).AddLight(0.1).ToCairoColor();
                            xrow     -= LeftPaddingBlock;
                            wrow     += LeftPaddingBlock;
                        }
                        ctx.Rectangle(xrow, yrow, wrow, lineHeight);
                        ctx.Fill();
                        selectedLine       = block.SourceLineStart + row;
                        selctedPath        = path;
                        selectedLineRowTop = (int)yrow;
                    }

                    // Draw the line text. Ignore header blocks, since they are drawn as labels in DrawCodeSegmentBorder

                    if (block.Type != BlockType.Info)
                    {
                        layout.SetMarkup("");
                        layout.SetText(sb.ToString());
                        Gdk.GC gc;
                        switch (block.Type)
                        {
                        case BlockType.Removed: gc = removedGC; break;

                        case BlockType.Added: gc = addedGC; break;

                        case BlockType.Info: gc = infoGC; break;

                        default: gc = normalGC; break;
                        }
                        window.DrawLayout(gc, cell_area.X + 2 + LeftPaddingBlock, block.YStart, layout);
                    }

                    // Finally draw the change symbol at the left margin

                    DrawChangeSymbol(ctx, cell_area.X + 1, cell_area.Width - 2, block);
                }

                // Finish the drawing of the code segment
                if (lastCodeSegmentStart != null)
                {
                    DrawCodeSegmentBorder(infoGC, ctx, cell_area.X, cell_area.Width, lastCodeSegmentStart, lastCodeSegmentEnd, lines, widget, window);
                }

                // Draw the source line number at the current selected line. It must be done at the end because it must
                // be drawn over the source code text and segment borders.
                if (selectedLineRowTop != -1)
                {
                    DrawLineBox(normalGC, ctx, ((Gtk.TreeView)widget).VisibleRect.Right - 4, selectedLineRowTop, selectedLine, widget, window);
                }

                ((IDisposable)ctx).Dispose();
                removedGC.Dispose();
                addedGC.Dispose();
                infoGC.Dispose();
            }
            else
            {
                // Rendering a normal text row
                int y = cell_area.Y + (cell_area.Height - height) / 2;
                window.DrawLayout(widget.Style.TextGC(GetState(flags)), cell_area.X, y, layout);
            }
        }