Use GSList for lanes, prepare for lane inactivity work

Changed generating lanes to easier design
This commit is contained in:
Jesse van den Kieboom 2008-10-02 21:47:58 +02:00
parent 1b911a24f8
commit 19d3917fe5
7 changed files with 199 additions and 116 deletions

View file

@ -23,8 +23,8 @@ enum
struct _GitgCellRendererPathPrivate
{
gint8 lane;
GitgLane **lanes;
GitgLane **next_lanes;
GSList *lanes;
GSList *next_lanes;
guint lane_width;
guint dot_width;
};
@ -36,7 +36,7 @@ G_DEFINE_TYPE(GitgCellRendererPath, gitg_cell_renderer_path, GTK_TYPE_CELL_RENDE
static gint
num_lanes(GitgCellRendererPath *self)
{
return gitg_utils_null_length((gconstpointer *)self->priv->lanes);
return g_slist_length (self->priv->lanes);
}
inline static gint
@ -70,7 +70,30 @@ renderer_get_size(GtkCellRenderer *renderer, GtkWidget *widget, GdkRectangle *ar
}
static void
draw_paths_real(GitgCellRendererPath *self, cairo_t *cr, GdkRectangle *area, GitgLane **lanes, gboolean top, gdouble yoffset)
draw_arrow(GitgCellRendererPath *self, cairo_t *cr, GdkRectangle *area, gint8 laneidx, gboolean top)
{
gdouble cw = self->priv->lane_width;
gdouble xpos = area->x + laneidx * cw + cw / 2.0;
gdouble df = (top ? -1 : 1) * 0.25 * area->height;
gdouble ypos = area->y + area->height / 2.0 + df;
gdouble q = cw / 4.0;
cairo_move_to(cr, xpos - q, ypos + (top ? q : -q));
cairo_line_to(cr, xpos, ypos);
cairo_line_to(cr, xpos + q, ypos + (top ? q : -q));
cairo_stroke(cr);
cairo_move_to(cr, xpos, ypos);
cairo_line_to(cr, xpos, ypos - df);
cairo_stroke(cr);
//cairo_move_to(cr, xpos, ypos);
//cairo_line_to(cr, xpos, ypos + (top ? 1 : -1) * area->height / 2.0);
//cairo_stroke(cr);
}
static void
draw_paths_real(GitgCellRendererPath *self, cairo_t *cr, GdkRectangle *area, GSList *lanes, gboolean top, gdouble yoffset)
{
if (!lanes)
return;
@ -79,10 +102,13 @@ draw_paths_real(GitgCellRendererPath *self, cairo_t *cr, GdkRectangle *area, Git
gdouble cw = self->priv->lane_width;
gdouble ch = area->height / 2.0;
GitgLane *lane;
while ((lane = *lanes++))
while (lanes)
{
GSList *item;
lane = (GitgLane *)(lanes->data);
gitg_color_set_cairo_source(lane->color, cr);
for (item = lane->from; item; item = item->next)
{
@ -92,13 +118,13 @@ draw_paths_real(GitgCellRendererPath *self, cairo_t *cr, GdkRectangle *area, Git
if (from != to)
xf = 0.5 * (to - from);
gitg_color_set_cairo_source(lane->color, cr);
cairo_move_to(cr, area->x + (from + (top ? xf : 0)) * cw + cw / 2.0, area->y + yoffset * ch);
cairo_line_to(cr, area->x + (to - (top ? 0 : xf)) * cw + cw / 2.0, area->y + (yoffset + 1) * ch);
cairo_stroke(cr);
}
++to;
lanes = lanes->next;
}
}
@ -114,14 +140,36 @@ draw_bottom_paths(GitgCellRendererPath *self, cairo_t *cr, GdkRectangle *area)
draw_paths_real(self, cr, area, self->priv->next_lanes, FALSE, 1);
}
static void
draw_arrows(GitgCellRendererPath *self, cairo_t *cr, GdkRectangle *area)
{
GSList *item;
gint8 to = 0;
for (item = self->priv->lanes; item; item = item->next)
{
GitgLane *lane = (GitgLane *)item->data;
gitg_color_set_cairo_source(lane->color, cr);
if (lane->type == GITG_LANE_TYPE_START)
draw_arrow(self, cr, area, to, TRUE);
else if (lane->type == GITG_LANE_TYPE_END)
draw_arrow(self, cr, area, to, FALSE);
++to;
}
}
static void
draw_paths(GitgCellRendererPath *self, cairo_t *cr, GdkRectangle *area)
{
cairo_set_line_width(cr, 2);
//cairo_set_source_rgb(cr, 0.45, 0.6, 0.74);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
draw_top_paths(self, cr, area);
draw_bottom_paths(self, cr, area);
draw_arrows(self, cr, area);
}
static void
@ -141,7 +189,7 @@ renderer_render(GtkCellRenderer *renderer, GdkDrawable *window, GtkWidget *widge
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke_preserve(cr);
gitg_color_set_cairo_source(self->priv->lanes[self->priv->lane]->color, cr);
gitg_color_set_cairo_source(((GitgLane *)g_slist_nth_data(self->priv->lanes, self->priv->lane))->color, cr);
cairo_fill(cr);
@ -193,10 +241,10 @@ gitg_cell_renderer_path_set_property(GObject *object, guint prop_id, const GValu
self->priv->lane = g_value_get_int(value);
break;
case PROP_LANES:
self->priv->lanes = (GitgLane **)g_value_get_pointer(value);
self->priv->lanes = (GSList *)g_value_get_pointer(value);
break;
case PROP_NEXT_LANES:
self->priv->next_lanes = (GitgLane **)g_value_get_pointer(value);
self->priv->next_lanes = (GSList *)g_value_get_pointer(value);
break;
case PROP_LANE_WIDTH:
self->priv->lane_width = g_value_get_uint(value);

View file

@ -3,15 +3,34 @@
#define GITG_LANES_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_LANES, GitgLanesPrivate))
typedef struct _LaneContainer
//#define MAX_INACTIVE 6
typedef struct
{
GitgLane *lane;
//gint8 inactive;
gchar const *hash;
} LaneContainer;
/*typedef struct
{
GitgColor *color;
gint8 index;
} InactiveLane;*/
struct _GitgLanesPrivate
{
/* list of last N GitgRevisions used to backtrack in case of lane
collapse/reactivation */
//GSList *previous;
/* list of LaneContainer resembling the current lanes state for the
next revision */
GSList *lanes;
/* hash table of rev hash -> InactiveLane where rev hash is the hash
to be expected on the lane */
//GHashTable *inactive;
};
G_DEFINE_TYPE(GitgLanes, gitg_lanes, G_TYPE_OBJECT)
@ -19,20 +38,25 @@ G_DEFINE_TYPE(GitgLanes, gitg_lanes, G_TYPE_OBJECT)
static void
lane_container_free(LaneContainer *container)
{
gitg_lane_free(container->lane);
//gitg_lane_free(container->lane);
g_free(container);
}
/*static void
inactive_container_free(InactiveContainer *container)
{
gitg_color_unref(container->color);
g_free(container);
}*/
static void
free_lanes(GitgLanes *lanes)
{
GSList *item;
for (item = lanes->priv->lanes; item; item = item->next)
lane_container_free((LaneContainer *)item->data);
g_slist_foreach(lanes->priv->lanes, (GFunc)lane_container_free, NULL);
g_slist_free(lanes->priv->lanes);
lanes->priv->lanes = NULL;
}
static LaneContainer *
@ -68,7 +92,7 @@ gitg_lanes_finalize(GObject *object)
{
GitgLanes *self = GITG_LANES(object);
free_lanes(self);
gitg_lanes_reset(self);
G_OBJECT_CLASS(gitg_lanes_parent_class)->finalize(object);
}
@ -87,6 +111,7 @@ static void
gitg_lanes_init(GitgLanes *self)
{
self->priv = GITG_LANES_GET_PRIVATE(self);
//self->priv->inactive = g_hash_table_new_full(gitg_utils_hash_hash, gitg_utils_hash_equal, NULL, (GDestroyNotify)inactive_container_free);
}
GitgLanes *
@ -101,37 +126,50 @@ lane_container_new(gchar const *hash)
LaneContainer *ret = g_new(LaneContainer, 1);
ret->hash = hash;
ret->lane = gitg_lane_new();
//ret->inactive = 0;
return ret;
}
static GitgLane **
flatten_lanes(GitgLanes *lanes)
GSList *
lanes_list(GitgLanes *lanes)
{
gint len = g_slist_length(lanes->priv->lanes);
GitgLane **res = g_new(GitgLane *, len + 1);
GSList *item = lanes->priv->lanes;
int i;
for (i = 0; i < len; ++i)
{
res[i] = gitg_lane_copy(((LaneContainer *)(item->data))->lane);
item = item->next;
}
GSList *lns = NULL;
GSList *item;
res[len] = NULL;
return res;
for (item = lanes->priv->lanes; item; item = item->next)
lns = g_slist_prepend(lns, gitg_lane_copy(((LaneContainer*)item->data)->lane));
return g_slist_reverse(lns);
}
GitgLane **
gitg_lanes_reset(GitgLanes *lanes, gchar const *hash)
void
gitg_lanes_reset(GitgLanes *lanes)
{
free_lanes(lanes);
gitg_color_reset();
lanes->priv->lanes = g_slist_prepend(NULL, lane_container_new(hash));
return flatten_lanes(lanes);
//g_slist_foreach(lanes->priv->previous, (GFunc)g_object_unref);
//g_slist_free(lanes->priv->previous);
//lanes->priv->previous = NULL;
//g_hash_table_destroy(self->priv->inactive);
}
static void
lane_container_next(LaneContainer *container, gint index)
{
GitgLane *lane = gitg_lane_copy(container->lane);
lane->type = GITG_LANE_TYPE_NONE;
g_slist_free(lane->from);
gitg_lane_free(container->lane);
container->lane = lane;
container->lane->from = g_slist_prepend(NULL, GINT_TO_POINTER((gint)(index)));
//if (container->inactive < MAX_INACTIVE)
// ++container->inactive;
}
static void
@ -139,59 +177,39 @@ init_next_layer(GitgLanes *lanes)
{
GSList *item;
gint8 index = 0;
// Initialize new set of lanes based on 'lanes'. It copies the lane (refs
// the color) and adds the lane index as a merge (so it basicly represents
// a passthrough)
for (item = lanes->priv->lanes; item; item = item->next)
{
LaneContainer *container = (LaneContainer *)(item->data);
GitgLane *lane = gitg_lane_copy(container->lane);
g_slist_free(lane->from);
gitg_lane_free(container->lane);
container->lane = lane;
container->lane->from = g_slist_prepend(NULL, GINT_TO_POINTER((gint)(index++)));
++lanes;
}
lane_container_next((LaneContainer *)(item->data), index++);
}
GitgLane **
gitg_lanes_next(GitgLanes *lanes, GitgRevision *previous, GitgRevision *current, gint8 *currentpos)
static void
prepare_lanes(GitgLanes *lanes, GitgRevision *next, gint8 pos)
{
init_next_layer(lanes);
gint8 mypos;
LaneContainer *mylane = find_lane_by_hash(lanes, gitg_revision_get_hash(previous), &mypos);
if (mylane)
{
GitgColor *nc = gitg_color_copy(mylane->lane->color);
gitg_color_unref(mylane->lane->color);
mylane->lane->color = nc;
mylane->hash = NULL;
}
LaneContainer *mylane;
guint num;
Hash *parents = gitg_revision_get_parents_hash(previous, &num);
int i;
Hash *parents = gitg_revision_get_parents_hash(next, &num);
guint i;
/* prepare the next layer */
init_next_layer(lanes);
mylane = (LaneContainer *)g_slist_nth_data(lanes->priv->lanes, pos);
// Iterate over all parents and find them a lane
for (i = 0; i < num; ++i)
{
gint8 lnpos;
LaneContainer *lane = find_lane_by_hash(lanes, parents[i], &lnpos);
if (lane)
LaneContainer *container = find_lane_by_hash(lanes, parents[i], &lnpos);
if (container)
{
// There already is a lane for this parent. This means that we add
// mypos as a merge for the lane, also this means the color of
// this lane incluis the merge should change to one color
lane->lane->from = g_slist_append(lane->lane->from, GINT_TO_POINTER((gint)mypos));
gitg_color_next_index(lane->lane->color);
container->lane->from = g_slist_append(container->lane->from, GINT_TO_POINTER((gint)pos));
gitg_color_next_index(container->lane->color);
continue;
}
@ -200,41 +218,65 @@ gitg_lanes_next(GitgLanes *lanes, GitgRevision *previous, GitgRevision *current,
// There is no parent yet which can proceed on the current
// revision lane, so set it now
mylane->hash = (gchar const *)parents[i];
// If there is more than one parent, then also change the color
// since this revision is actually a merge
// since this revision is a merge
if (num > 1)
{
gitg_color_unref(mylane->lane->color);
mylane->lane->color = gitg_color_next();
}
else
{
GitgColor *nc = gitg_color_copy(mylane->lane->color);
gitg_color_unref(mylane->lane->color);
mylane->lane->color = nc;
}
}
else
{
// Generate a new lane for this parent
LaneContainer *newlane = lane_container_new(parents[i]);
newlane->lane->from = g_slist_prepend(NULL, GINT_TO_POINTER((gint)mypos));
newlane->lane->from = g_slist_prepend(NULL, GINT_TO_POINTER((gint)pos));
lanes->priv->lanes = g_slist_append(lanes->priv->lanes, newlane);
if (!mylane)
mylane = newlane;
}
}
// Remove the current lane if it is no longer needed
if (mylane && mylane->hash == NULL)
lanes->priv->lanes = g_slist_remove(lanes->priv->lanes, mylane);
// Determine the lane of the current revision
LaneContainer *lane = find_lane_by_hash(lanes, gitg_revision_get_hash(current), currentpos);
if (!lane)
{
// No lane for this revision reserved, we therefore add a new one
lanes->priv->lanes = g_slist_append(lanes->priv->lanes, lane_container_new(gitg_revision_get_hash(current)));
*currentpos = g_slist_length(lanes->priv->lanes) - 1;
}
return flatten_lanes(lanes);
//while (g_slist_length(lanes->priv->previous) >= MAX_INACTIVE)
// lanes->priv->previous = g_slist_remove(lanes->priv->previous, g_slist_last(lanes->priv->previous)->data);
//lanes->priv->previous = g_slist_prepend(lanes->priv->previous, next);
}
GSList *
gitg_lanes_next(GitgLanes *lanes, GitgRevision *next, gint8 *nextpos)
{
LaneContainer *mylane = find_lane_by_hash(lanes, gitg_revision_get_hash(next), nextpos);
GSList *res;
if (!mylane)
{
/* apparently, there is no lane reserved for this revision, we
add a new one */
lanes->priv->lanes = g_slist_append(lanes->priv->lanes, lane_container_new(NULL));
*nextpos = g_slist_length(lanes->priv->lanes) - 1;
}
else
{
/* copy the color here because this represents a new stop */
GitgColor *nc = gitg_color_copy(mylane->lane->color);
gitg_color_unref(mylane->lane->color);
mylane->lane->color = nc;
mylane->hash = NULL;
}
res = lanes_list(lanes);
prepare_lanes(lanes, next, *nextpos);
return res;
}

View file

@ -32,8 +32,8 @@ struct _GitgLanesClass {
GType gitg_lanes_get_type (void) G_GNUC_CONST;
GitgLanes *gitg_lanes_new(void);
GitgLane **gitg_lanes_reset(GitgLanes *lanes, gchar const *hash);
GitgLane **gitg_lanes_next(GitgLanes *lanes, GitgRevision *previous, GitgRevision *current, gint8 *mylane);
void gitg_lanes_reset(GitgLanes *lanes);
GSList *gitg_lanes_next(GitgLanes *lanes, GitgRevision *next, gint8 *mylane);
G_END_DECLS

View file

@ -396,14 +396,14 @@ on_loader_update(GitgRunner *object, gchar **buffer, GitgRepository *self)
gint64 timestamp = g_ascii_strtoll(components[4], NULL, 0);
GitgRevision *rv = gitg_revision_new(components[0], components[1], components[2], components[3], timestamp);
GitgLane **lanes = NULL;
GSList *lanes;
gint8 mylane = 0;
if (self->priv->size == 0)
lanes = gitg_lanes_reset(self->priv->lanes, gitg_revision_get_hash(rv));
else
lanes = gitg_lanes_next(self->priv->lanes, self->priv->storage[self->priv->size - 1], rv, &mylane);
gitg_lanes_reset(self->priv->lanes);
lanes = gitg_lanes_next(self->priv->lanes, rv, &mylane);
gitg_revision_set_lanes(rv, lanes);
gitg_revision_set_mylane(rv, mylane);

View file

@ -11,7 +11,7 @@ struct _GitgRevisionPrivate
Hash *parents;
guint num_parents;
GitgLane **lanes;
GSList *lanes;
gint8 mylane;
gint64 timestamp;
@ -22,16 +22,9 @@ G_DEFINE_TYPE(GitgRevision, gitg_revision, G_TYPE_OBJECT)
static void
free_lanes(GitgRevision *rv)
{
if (!rv->priv->lanes)
return;
GitgLane **lanes = rv->priv->lanes;
GitgLane *lane;
while ((lane = *lanes++))
gitg_lane_free(lane);
g_free(rv->priv->lanes);
g_slist_foreach(rv->priv->lanes, (GFunc)gitg_lane_free, NULL);
g_slist_free(rv->priv->lanes);
rv->priv->lanes = NULL;
}
static void
@ -162,15 +155,15 @@ gitg_revision_get_parents(GitgRevision *revision)
return ret;
}
GitgLane **
GSList *
gitg_revision_get_lanes(GitgRevision *revision)
{
g_return_val_if_fail(GITG_IS_REVISION(revision), NULL);
return revision->priv->lanes;
return g_slist_copy(revision->priv->lanes);
}
void
gitg_revision_set_lanes(GitgRevision *revision, GitgLane **lanes)
gitg_revision_set_lanes(GitgRevision *revision, GSList *lanes)
{
g_return_if_fail(GITG_IS_REVISION(revision));

View file

@ -44,8 +44,8 @@ inline Hash *gitg_revision_get_parents_hash(GitgRevision *revision, guint *num_p
gchar *gitg_revision_get_sha1(GitgRevision *revision);
gchar **gitg_revision_get_parents(GitgRevision *revision);
GitgLane **gitg_revision_get_lanes(GitgRevision *revision);
void gitg_revision_set_lanes(GitgRevision *revision, GitgLane **lanes);
GSList *gitg_revision_get_lanes(GitgRevision *revision);
void gitg_revision_set_lanes(GitgRevision *revision, GSList *lanes);
gint8 gitg_revision_get_mylane(GitgRevision *revision);
void gitg_revision_set_mylane(GitgRevision *revision, gint8 mylane);

View file

@ -214,7 +214,7 @@ on_renderer_path(GtkTreeViewColumn *column, GitgCellRendererPath *renderer, GtkT
gtk_tree_model_get(model, iter, 0, &rv, -1);
GtkTreeIter iter1 = *iter;
GitgLane **next_lanes = NULL;
GSList *next_lanes = NULL;
if (gtk_tree_model_iter_next(model, &iter1))
{