/*
* This file is part of gitg
*
* Copyright (C) 2012 - Jesse van den Kieboom
*
* gitg is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* gitg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gitg. If not, see .
*/
namespace GitgGtk
{
class CellRendererLanes : Gtk.CellRendererText
{
public Gitg.Commit? commit { get; set; }
public Gitg.Commit? next_commit { get; set; }
public uint lane_width { get; set; default = 16; }
public uint dot_width { get; set; default = 10; }
public unowned SList labels { get; set; }
private int d_last_height;
private uint num_lanes
{
get { return commit.get_lanes().length(); }
}
private uint total_width(Gtk.Widget widget)
{
return num_lanes * lane_width +
LabelRenderer.width(widget, font_desc, labels);
}
public override void get_size(Gtk.Widget widget,
Gdk.Rectangle? area,
out int xoffset,
out int yoffset,
out int width,
out int height)
{
xoffset = 0;
yoffset = 0;
width = (int)total_width(widget);
height = area != null ? area.height : 1;
}
private void draw_arrow(Cairo.Context context,
Gdk.Rectangle area,
uint laneidx,
bool top)
{
double cw = lane_width;
double xpos = area.x + laneidx * cw + cw / 2.0;
double df = (top ? -1 : 1) * 0.25 * area.height;
double ypos = area.y + area.height / 2.0 + df;
double q = cw / 4.0;
context.move_to(xpos - q, ypos + (top ? q : -q));
context.line_to(xpos, ypos);
context.line_to(xpos + q, ypos + (top ? q : -q));
context.stroke();
context.move_to(xpos, ypos);
context.line_to(xpos, ypos - df);
context.stroke();
}
private void draw_arrows(Cairo.Context context,
Gdk.Rectangle area)
{
uint to = 0;
foreach (var lane in commit.get_lanes())
{
var color = lane.color;
context.set_source_rgb(color.r, color.g, color.b);
if (lane.tag == Gitg.LaneTag.START)
{
draw_arrow(context, area, to, true);
}
else if (lane.tag == Gitg.LaneTag.END)
{
draw_arrow(context, area, to, false);
}
++to;
}
}
private void draw_paths_real(Cairo.Context context,
Gdk.Rectangle area,
Gitg.Commit? commit,
double yoffset)
{
if (commit == null)
{
return;
}
int to = 0;
double cw = lane_width;
double ch = area.height / 2.0;
foreach (var lane in commit.get_lanes())
{
var color = lane.color;
context.set_source_rgb(color.r, color.g, color.b);
foreach (var from in lane.from)
{
double x1 = area.x + from * cw + cw / 2.0;
double x2 = area.x + to * cw + cw / 2.0;
double y1 = area.y + yoffset * ch;
double y2 = area.y + (yoffset + 1) * ch;
double y3 = area.y + (yoffset + 2) * ch;
context.move_to(x1, y1);
context.curve_to(x1, y2, x2, y2, x2, y3);
context.stroke();
}
++to;
}
}
private void draw_top_paths(Cairo.Context context,
Gdk.Rectangle area)
{
draw_paths_real(context, area, commit, -1);
}
private void draw_bottom_paths(Cairo.Context context,
Gdk.Rectangle area)
{
draw_paths_real(context, area, next_commit, 1);
}
private void draw_paths(Cairo.Context context,
Gdk.Rectangle area)
{
context.set_line_width(2.0);
context.set_line_cap(Cairo.LineCap.ROUND);
draw_top_paths(context, area);
draw_bottom_paths(context, area);
draw_arrows(context, area);
}
private void draw_indicator(Cairo.Context context,
Gdk.Rectangle area)
{
double offset;
double radius;
offset = commit.mylane * lane_width + (lane_width - dot_width) / 2.0;
radius = dot_width / 2.0;
context.set_line_width(2.0);
context.arc(area.x + offset + radius,
area.y + area.height / 2.0,
radius,
0,
2 * Math.PI);
context.set_source_rgb(0, 0, 0);
context.stroke_preserve();
if (commit.lane != null)
{
var color = commit.lane.color;
context.set_source_rgb(color.r, color.g, color.b);
}
context.fill();
}
private void draw_labels(Cairo.Context context,
Gdk.Rectangle area,
Gtk.Widget widget)
{
uint offset;
offset = num_lanes * lane_width;
context.translate(offset, 0);
LabelRenderer.draw(widget, font_desc, context, labels, area);
}
public override void render(Cairo.Context context,
Gtk.Widget widget,
Gdk.Rectangle area,
Gdk.Rectangle cell_area,
Gtk.CellRendererState flags)
{
var ncell_area = cell_area;
var narea = area;
d_last_height = area.height;
if (commit != null)
{
context.save();
Gdk.cairo_rectangle(context, area);
context.clip();
draw_paths(context, area);
draw_indicator(context, area);
draw_labels(context, area, widget);
var tw = total_width(widget);
narea.x += (int)tw;
ncell_area.x += (int)tw;
context.restore();
}
base.render(context, widget, narea, ncell_area, flags);
}
}
}
// vi:ts=4