[gitg] Improved staging/unstaging
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg] Improved staging/unstaging
- Date: Sun, 30 May 2010 14:58:40 +0000 (UTC)
commit 3ac8587189b6ac5698939e17ac3dd59619c7c523
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Sun May 30 10:50:36 2010 +0200
Improved staging/unstaging
Per-line staging/unstaging is now possible.
data/gitgstyle.xml | 1 +
gitg/gitg-cell-renderer-path.c | 2 +-
gitg/gitg-commit-view.c | 596 +++++++++++++++++++++++++++++++++++-----
gitg/gitg-diff-line-renderer.c | 195 ++++++++++++-
gitg/gitg-diff-view.c | 438 +++++++++++++++++++++++++++---
gitg/gitg-diff-view.h | 19 ++
gitg/gitg-label-renderer.c | 25 +--
gitg/gitg-utils.c | 76 +++++
gitg/gitg-utils.h | 4 +
9 files changed, 1227 insertions(+), 129 deletions(-)
---
diff --git a/data/gitgstyle.xml b/data/gitgstyle.xml
index 74dd877..3c750e7 100644
--- a/data/gitgstyle.xml
+++ b/data/gitgstyle.xml
@@ -60,6 +60,7 @@
<!-- Default -->
<style name="gitgdiff:text" foreground="skyblue3" background="aluminium1"/>
<style name="text" use-style="gitgdiff:text"/>
+ <style name="current-line" line-background="aluminium4" foreground="aluminium1"/>
<!-- Right Margin -->
<style name="right-margin" foreground="aluminium5" background="aluminium4"/>
diff --git a/gitg/gitg-cell-renderer-path.c b/gitg/gitg-cell-renderer-path.c
index 449a936..3baf088 100644
--- a/gitg/gitg-cell-renderer-path.c
+++ b/gitg/gitg-cell-renderer-path.c
@@ -325,7 +325,7 @@ renderer_render(GtkCellRenderer *renderer, GdkDrawable *window, GtkWidget *widge
cairo_t *cr = gdk_cairo_create(window);
- cairo_rectangle(cr, area->x, area->y, area->width, area->height);
+ gdk_cairo_rectangle (cr, area);
cairo_clip(cr);
draw_paths(self, cr, area);
diff --git a/gitg/gitg-commit-view.c b/gitg/gitg-commit-view.c
index 173f694..06e819f 100644
--- a/gitg/gitg-commit-view.c
+++ b/gitg/gitg-commit-view.c
@@ -90,6 +90,8 @@ struct _GitgCommitViewPrivate
GtkTextIter context_iter;
GtkActionGroup *group_context;
+ GtkTextMark *highlight_mark;
+ GtkTextTag *highlight_tag;
};
static void gitg_commit_view_buildable_iface_init(GtkBuildableIface *iface);
@@ -129,20 +131,22 @@ static void on_edit_file(GtkAction *action, GitgCommitView *view);
static void on_check_button_amend_toggled (GtkToggleButton *button, GitgCommitView *view);
static void
-gitg_commit_view_finalize(GObject *object)
+gitg_commit_view_finalize (GObject *object)
{
- GitgCommitView *view = GITG_COMMIT_VIEW(object);
+ GitgCommitView *view = GITG_COMMIT_VIEW (object);
if (view->priv->update_id)
- g_signal_handler_disconnect(view->priv->runner, view->priv->update_id);
+ {
+ g_signal_handler_disconnect (view->priv->runner, view->priv->update_id);
+ }
- gitg_runner_cancel(view->priv->runner);
- g_object_unref(view->priv->runner);
- g_object_unref(view->priv->ui_manager);
+ gitg_runner_cancel (view->priv->runner);
+ g_object_unref (view->priv->runner);
+ g_object_unref (view->priv->ui_manager);
- gdk_cursor_unref(view->priv->hand);
+ gdk_cursor_unref (view->priv->hand);
- G_OBJECT_CLASS(gitg_commit_view_parent_class)->finalize(object);
+ G_OBJECT_CLASS (gitg_commit_view_parent_class)->finalize (object);
}
static void
@@ -672,28 +676,217 @@ get_hunk_patch(GitgCommitView *view, GtkTextIter *iter)
return g_strconcat(header, contents, NULL);
}
+static gchar *
+line_patch_contents (GitgCommitView *view,
+ GtkTextIter const *iter,
+ GitgDiffLineType old_type,
+ GitgDiffLineType new_type)
+{
+ GtkTextIter start;
+ GtkTextIter end;
+ GtkTextIter patch_iter = *iter;
+ GitgDiffView *diff_view = GITG_DIFF_VIEW (view->priv->changes_view);
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (diff_view));
+ GitgDiffIter diff_iter;
+
+ gtk_text_iter_set_line_offset (&patch_iter, 0);
+
+ if (!gitg_diff_view_get_hunk_at_iter (diff_view, &patch_iter, &diff_iter))
+ {
+ return NULL;
+ }
+
+ gitg_diff_iter_get_bounds (&diff_iter, &start, &end);
+ GtkTextIter begin = start;
+
+ GString *patch = g_string_new ("");
+ gchar *header = NULL;
+ gint count_old = 0;
+ gint count_new = 0;
+
+ while (gtk_text_iter_compare (&start, &end) < 0)
+ {
+ GitgDiffLineType line_type;
+ gboolean is_patch_line;
+
+ line_type = gitg_diff_view_get_line_type (diff_view, &start);
+
+ is_patch_line = gtk_text_iter_equal (&start, &patch_iter);
+
+ gchar *text;
+ GtkTextIter line_end = start;
+ gtk_text_iter_forward_to_line_end (&line_end);
+
+ if (gtk_text_iter_equal (&start, &begin))
+ {
+ header = gtk_text_buffer_get_text (buffer, &start, &line_end, TRUE);
+ }
+ else
+ {
+ if (line_type == old_type && !is_patch_line)
+ {
+ /* Take over like it was context */
+ g_string_append_c (patch, ' ');
+
+ if (!gtk_text_iter_ends_line (&start))
+ {
+ gtk_text_iter_forward_char (&start);
+ }
+ }
+
+ if (line_type == GITG_DIFF_LINE_TYPE_NONE ||
+ line_type == old_type || is_patch_line)
+ {
+ /* copy context */
+ text = gtk_text_buffer_get_text (buffer, &start, &line_end, TRUE);
+
+ g_string_append (patch, text);
+ g_string_append_c (patch, '\n');
+
+ if (!is_patch_line || line_type == GITG_DIFF_LINE_TYPE_REMOVE)
+ {
+ ++count_old;
+ }
+
+ if (!is_patch_line || line_type == GITG_DIFF_LINE_TYPE_ADD)
+ {
+ ++count_new;
+ }
+
+ g_free (text);
+ }
+ }
+
+ if (!gtk_text_iter_forward_line (&start))
+ {
+ break;
+ }
+ }
+
+ gchar *head = gitg_utils_rewrite_hunk_counters (header, count_old, count_new);
+ g_free (header);
+ gchar *ret = NULL;
+
+ if (head)
+ {
+ gchar *contents = g_string_free (patch, FALSE);
+ ret = g_strconcat (head, "\n", contents, NULL);
+
+ g_free (contents);
+ g_free (head);
+ }
+
+ return ret;
+}
+
+static gboolean
+stage_unstage_hunk (GitgCommitView *view, gchar const *hunk, GError **error)
+{
+ gboolean ret;
+ gboolean unstage = view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED;
+
+ if (unstage)
+ {
+ ret = gitg_commit_stage (view->priv->commit, view->priv->current_file, hunk, error);
+ }
+ else
+ {
+ ret = gitg_commit_unstage (view->priv->commit, view->priv->current_file, hunk, error);
+ }
+
+ return ret;
+}
+
+static gboolean
+handle_stage_unstage_line (GitgCommitView *view, GtkTextIter const *iter)
+{
+ GitgDiffView *diff_view = GITG_DIFF_VIEW (view->priv->changes_view);
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->priv->changes_view));
+ gchar *header = get_patch_header (view, buffer, iter);
+ GitgDiffLineType old_type;
+ GitgDiffLineType new_type;
+
+ if (!header)
+ {
+ return FALSE;
+ }
+
+ GitgDiffIter diff_iter;
+
+ if (!gitg_diff_view_get_header_at_iter (diff_view, iter, &diff_iter))
+ {
+ g_free (header);
+ return FALSE;
+ }
+
+ if (view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED)
+ {
+ old_type = GITG_DIFF_LINE_TYPE_REMOVE;
+ new_type = GITG_DIFF_LINE_TYPE_ADD;
+ }
+ else
+ {
+ old_type = GITG_DIFF_LINE_TYPE_ADD;
+ new_type = GITG_DIFF_LINE_TYPE_REMOVE;
+ }
+
+ gchar *contents = line_patch_contents (view, iter, old_type, new_type);
+
+ if (!contents)
+ {
+ g_free (header);
+ return FALSE;
+ }
+
+ gboolean ret;
+ GitgChangedFile *file = g_object_ref (view->priv->current_file);
+ GError *error = NULL;
+ gchar *hunk = g_strconcat (header, contents, NULL);
+
+ g_free (contents);
+ g_free (header);
+
+ ret = stage_unstage_hunk (view, hunk, &error);
+
+ if (ret && file == view->priv->current_file)
+ {
+ gitg_diff_view_clear_line (GITG_DIFF_VIEW (view->priv->changes_view),
+ iter,
+ old_type,
+ new_type);
+ }
+ else if (!ret)
+ {
+ g_warning ("Could not stage/unstage: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_free (hunk);
+ g_object_unref (file);
+
+ return ret;
+}
+
static gboolean
handle_stage_unstage(GitgCommitView *view, GtkTextIter *iter)
{
- gchar *hunk = get_hunk_patch(view, iter);
+ gchar *hunk = get_hunk_patch (view, iter);
if (!hunk)
+ {
return FALSE;
+ }
gboolean ret;
- GitgChangedFile *file = g_object_ref(view->priv->current_file);
- gboolean unstage = view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED;
+ GitgChangedFile *file = g_object_ref (view->priv->current_file);
GError *error = NULL;
- if (unstage)
- ret = gitg_commit_stage(view->priv->commit, view->priv->current_file, hunk, &error);
- else
- ret = gitg_commit_unstage(view->priv->commit, view->priv->current_file, hunk, &error);
+ ret = stage_unstage_hunk (view, hunk, &error);
if (ret && file == view->priv->current_file)
{
/* remove hunk from text view */
- gitg_diff_view_remove_hunk(GITG_DIFF_VIEW(view->priv->changes_view), iter);
+ gitg_diff_view_remove_hunk (GITG_DIFF_VIEW (view->priv->changes_view), iter);
}
else if (!ret)
{
@@ -701,76 +894,273 @@ handle_stage_unstage(GitgCommitView *view, GtkTextIter *iter)
g_error_free (error);
}
- g_object_unref(file);
- g_free(hunk);
+ g_object_unref (file);
+ g_free (hunk);
return ret;
}
static gboolean
-get_hunk_at_pointer(GitgCommitView *view, GtkTextIter *iter, gchar **hunk)
+get_info_at_pointer (GitgCommitView *view,
+ GtkTextIter *iter,
+ gboolean *is_hunk,
+ gchar **hunk,
+ GitgDiffLineType *line_type)
{
- GtkTextView *textview = GTK_TEXT_VIEW(view->priv->changes_view);
+ GtkTextView *textview = GTK_TEXT_VIEW (view->priv->changes_view);
gint x;
gint y;
+ gint width;
+ gint height;
gint buf_x;
gint buf_y;
/* Get where the pointer really is. */
- GdkWindow *win = gtk_text_view_get_window(textview, GTK_TEXT_WINDOW_TEXT);
- gdk_window_get_pointer(win, &x, &y, NULL);
+ GdkWindow *win = gtk_text_view_get_window (textview, GTK_TEXT_WINDOW_TEXT);
+
+ gdk_window_get_pointer (win, &x, &y, NULL);
+ gdk_drawable_get_size (GDK_DRAWABLE (win), &width, &height);
+
+ if (x < 0 || y < 0 || x > width || y > height)
+ {
+ return FALSE;
+ }
/* Get the iter where the cursor is at */
- gtk_text_view_window_to_buffer_coords(textview, GTK_TEXT_WINDOW_TEXT, x, y, &buf_x, &buf_y);
- gtk_text_view_get_iter_at_location(textview, iter, buf_x, buf_y);
+ gtk_text_view_window_to_buffer_coords (textview, GTK_TEXT_WINDOW_TEXT, x, y, &buf_x, &buf_y);
+ gtk_text_view_get_iter_at_location (textview, iter, buf_x, buf_y);
- if (gtk_text_iter_backward_line(iter))
- gtk_text_iter_forward_line(iter);
+ gtk_text_iter_set_line_offset (iter, 0);
- GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(textview));
+ GtkSourceBuffer *buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (textview));
- if (!has_hunk_mark(buffer, iter))
- return FALSE;
+ if (is_hunk)
+ {
+ *is_hunk = has_hunk_mark (buffer, iter);
+
+ if (*is_hunk && hunk)
+ {
+ *hunk = get_hunk_patch (view, iter);
+ }
+ }
- if (hunk)
- *hunk = get_hunk_patch(view, iter);
+ if (line_type)
+ {
+ *line_type = gitg_diff_view_get_line_type (GITG_DIFF_VIEW (view->priv->changes_view),
+ iter);
+ }
return TRUE;
}
-static gboolean
-view_event(GtkWidget *widget, GdkEventAny *event, GitgCommitView *view)
+static void
+unset_highlight (GitgCommitView *view)
{
- GtkTextWindowType type;
+ if (!view->priv->highlight_mark)
+ {
+ return;
+ }
+
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->priv->changes_view));
+ GtkTextIter start;
+ GtkTextIter end;
+
+ gtk_text_buffer_get_iter_at_mark (buffer, &start, view->priv->highlight_mark);
+ end = start;
+
+ gtk_text_iter_forward_to_line_end (&end);
+
+ gtk_text_buffer_remove_tag (buffer, view->priv->highlight_tag, &start, &end);
+
+ gtk_text_buffer_delete_mark (buffer, view->priv->highlight_mark);
+ view->priv->highlight_mark = NULL;
+}
+
+static void
+set_highlight (GitgCommitView *view, GtkTextIter *iter)
+{
+ if (!view->priv->highlight_tag)
+ {
+ return;
+ }
+
+ GtkTextIter start = *iter;
+ GtkTextBuffer *buffer = gtk_text_iter_get_buffer (iter);
+
+ gtk_text_iter_set_line_offset (&start, 0);
+
+ if (view->priv->highlight_mark != NULL)
+ {
+ GtkTextIter mark_iter;
+ gtk_text_buffer_get_iter_at_mark (buffer,
+ &mark_iter,
+ view->priv->highlight_mark);
+
+ if (gtk_text_iter_equal (&start, &mark_iter))
+ {
+ return;
+ }
+
+ unset_highlight (view);
+ }
+
+ view->priv->highlight_mark = gtk_text_buffer_create_mark (buffer,
+ NULL,
+ &start,
+ TRUE);
+
+ GtkTextIter end = start;
+ gtk_text_iter_forward_to_line_end (&end);
+
+ gtk_text_buffer_apply_tag (buffer,
+ view->priv->highlight_tag,
+ &start,
+ &end);
+}
+
+static void
+update_cursor_view (GitgCommitView *view)
+{
+ gboolean is_hunk = FALSE;
GtkTextIter iter;
+ GitgDiffLineType line_type = GITG_DIFF_LINE_TYPE_NONE;
+ GdkWindow *window;
- type = gtk_text_view_get_window_type(GTK_TEXT_VIEW(widget), event->window);
+ window = gtk_text_view_get_window (GTK_TEXT_VIEW (view->priv->changes_view), GTK_TEXT_WINDOW_TEXT);
- if (type != GTK_TEXT_WINDOW_TEXT)
- return FALSE;
+ if (!get_info_at_pointer (view, &iter, &is_hunk, NULL, &line_type))
+ {
+ unset_highlight (view);
+ gdk_window_set_cursor (window, NULL);
+ return;
+ }
- if (event->type != GDK_MOTION_NOTIFY && event->type != GDK_BUTTON_PRESS)
+ if (is_hunk ||
+ line_type == GITG_DIFF_LINE_TYPE_ADD ||
+ line_type == GITG_DIFF_LINE_TYPE_REMOVE)
+ {
+ gdk_window_set_cursor (window, view->priv->hand);
+ set_highlight (view, &iter);
+ }
+ else
+ {
+ gdk_window_set_cursor (window, NULL);
+ unset_highlight (view);
+ }
+}
+
+static gboolean
+view_event (GtkWidget *widget, GdkEventAny *event, GitgCommitView *view)
+{
+ GtkTextWindowType type;
+ GtkTextBuffer *buffer;
+
+ type = gtk_text_view_get_window_type (GTK_TEXT_VIEW (widget), event->window);
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widget));
+
+ if (type == GTK_TEXT_WINDOW_TEXT && event->type == GDK_LEAVE_NOTIFY)
+ {
+ unset_highlight (view);
+ gdk_window_set_cursor (event->window, NULL);
return FALSE;
+ }
- gboolean is_hunk = get_hunk_at_pointer(view, &iter, NULL);
+ if (event->type == GDK_LEAVE_NOTIFY ||
+ event->type == GDK_MOTION_NOTIFY ||
+ event->type == GDK_BUTTON_PRESS ||
+ event->type == GDK_BUTTON_RELEASE ||
+ event->type == GDK_ENTER_NOTIFY)
+ {
+ update_cursor_view (view);
+ }
- if (event->type == GDK_MOTION_NOTIFY)
+ if (type == GTK_TEXT_WINDOW_TEXT && event->type == GDK_BUTTON_RELEASE &&
+ ((GdkEventButton *)event)->button == 1 &&
+ !gtk_text_buffer_get_has_selection (buffer))
{
+ GtkTextIter iter;
+ gboolean is_hunk = FALSE;
+ GitgDiffLineType line_type = GITG_DIFF_LINE_TYPE_NONE;
+
+ get_info_at_pointer (view, &iter, &is_hunk, NULL, &line_type);
+
if (is_hunk)
{
- gdk_window_set_cursor(event->window, view->priv->hand);
- }
- else
+ if (handle_stage_unstage (view, &iter))
+ {
+ unset_highlight (view);
+ update_cursor_view (view);
+ }
+ }
+ else if (line_type == GITG_DIFF_LINE_TYPE_ADD ||
+ line_type == GITG_DIFF_LINE_TYPE_REMOVE)
{
- gdk_window_set_cursor(event->window, NULL);
+ if (handle_stage_unstage_line (view, &iter))
+ {
+ unset_highlight (view);
+ update_cursor_view (view);
+ }
}
}
- else if (is_hunk && ((GdkEventButton *)event)->button == 1)
+
+ return FALSE;
+}
+
+static gchar *
+stage_unstage_label_func (GitgDiffView *diff_view,
+ gint line,
+ GitgCommitView *view)
+{
+ static gchar const *format = "<small><b>%s</b></small>";
+
+ if (line == -1)
{
- handle_stage_unstage(view, &iter);
+ static gchar const *longest_label = NULL;
+
+ gchar const *stage = _("stage");
+ gchar const *unstage = _("unstage");
+
+ if (!longest_label)
+ {
+ if (g_utf8_strlen (stage, -1) > g_utf8_strlen (unstage, -1))
+ {
+ longest_label = stage;
+ }
+ else
+ {
+ longest_label = unstage;
+ }
+ }
+
+ return g_markup_printf_escaped (format, _("stage"));
}
+ else if (view->priv->highlight_mark)
+ {
+ GtkTextBuffer *buffer;
+ GtkTextIter iter;
+ GtkTextIter hl_iter;
- return FALSE;
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (diff_view));
+ gtk_text_buffer_get_iter_at_line (buffer, &iter, line);
+
+ gtk_text_buffer_get_iter_at_mark (buffer,
+ &hl_iter,
+ view->priv->highlight_mark);
+
+ if (gtk_text_iter_equal (&iter, &hl_iter))
+ {
+ if (view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_UNSTAGED)
+ {
+ return g_markup_printf_escaped (format, _("stage"));
+ }
+ else
+ {
+ return g_markup_printf_escaped (format, _("unstage"));
+ }
+ }
+ }
+
+ return NULL;
}
static GtkTextBuffer *
@@ -922,6 +1312,15 @@ initialize_dnd_unstaged(GitgCommitView *view)
}
static void
+on_tag_added (GtkTextTagTable *table,
+ GtkTextTag *tag,
+ GitgCommitView *view)
+{
+ gtk_text_tag_set_priority (view->priv->highlight_tag,
+ gtk_text_tag_table_get_size (table) - 1);
+}
+
+static void
gitg_commit_view_parser_finished(GtkBuildable *buildable, GtkBuilder *builder)
{
if (parent_iface.parser_finished)
@@ -953,6 +1352,15 @@ gitg_commit_view_parser_finished(GtkBuildable *buildable, GtkBuilder *builder)
set_sort_func(self->priv->store_staged);
self->priv->changes_view = GTK_SOURCE_VIEW(gtk_builder_get_object(builder, "source_view_changes"));
+
+ gtk_widget_add_events (GTK_WIDGET (self->priv->changes_view),
+ GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK);
+
+ gitg_diff_view_set_label_func (GITG_DIFF_VIEW (self->priv->changes_view),
+ (GitgDiffViewLabelFunc)stage_unstage_label_func,
+ self,
+ NULL);
+
self->priv->comment_view = GTK_TEXT_VIEW(gtk_builder_get_object(builder, "text_view_comment"));
self->priv->check_button_signed_off_by = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "check_button_signed_off_by"));
self->priv->check_button_amend = GTK_CHECK_BUTTON(gtk_builder_get_object(builder, "check_button_amend"));
@@ -1000,6 +1408,63 @@ gitg_commit_view_parser_finished(GtkBuildable *buildable, GtkBuilder *builder)
set_icon_data_func(self, self->priv->tree_view_unstaged, GTK_CELL_RENDERER(gtk_builder_get_object(builder, "unstaged_cell_renderer_icon")));
set_icon_data_func(self, self->priv->tree_view_staged, GTK_CELL_RENDERER(gtk_builder_get_object(builder, "staged_cell_renderer_icon")));
+ GtkSourceStyleScheme *scheme;
+ GtkSourceStyle *style;
+
+ scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (buffer));
+ style = gtk_source_style_scheme_get_style (scheme, "current-line");
+
+ gchar *background = NULL;
+ gboolean background_set = FALSE;
+
+ gchar *foreground = NULL;
+ gboolean foreground_set = FALSE;
+
+ if (style)
+ {
+ g_object_get (style,
+ "line-background",
+ &background,
+ "line-background-set",
+ &background_set,
+ "foreground",
+ &foreground,
+ "foreground-set",
+ &foreground_set,
+ NULL);
+
+ if (!background_set)
+ {
+ g_object_get (style,
+ "background",
+ &background,
+ "background-set",
+ &background_set,
+ NULL);
+ }
+ }
+
+ if (background_set)
+ {
+ self->priv->highlight_tag = gtk_text_buffer_create_tag (buffer,
+ NULL,
+ "paragraph-background",
+ background,
+ "foreground",
+ foreground,
+ "foreground-set",
+ foreground_set,
+ NULL);
+
+ gtk_text_tag_set_priority (self->priv->highlight_tag,
+ gtk_text_tag_table_get_size (gtk_text_buffer_get_tag_table (buffer)) - 1);
+
+ g_signal_connect (gtk_text_buffer_get_tag_table (buffer),
+ "tag-added",
+ G_CALLBACK (on_tag_added),
+ self);
+ }
+
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection(self->priv->tree_view_unstaged);
@@ -1169,12 +1634,12 @@ gitg_commit_view_class_init(GitgCommitViewClass *klass)
}
static void
-gitg_commit_view_init(GitgCommitView *self)
+gitg_commit_view_init (GitgCommitView *self)
{
- self->priv = GITG_COMMIT_VIEW_GET_PRIVATE(self);
+ self->priv = GITG_COMMIT_VIEW_GET_PRIVATE (self);
- self->priv->runner = gitg_runner_new(10000);
- self->priv->hand = gdk_cursor_new(GDK_HAND1);
+ self->priv->runner = gitg_runner_new (10000);
+ self->priv->hand = gdk_cursor_new (GDK_HAND1);
}
void
@@ -1800,31 +2265,36 @@ create_context_menu_item (GitgCommitView *view, gchar const *action)
}
static void
-on_changes_view_popup_menu(GtkTextView *textview, GtkMenu *menu, GitgCommitView *view)
+on_changes_view_popup_menu (GtkTextView *textview, GtkMenu *menu, GitgCommitView *view)
{
- /* check the hunk */
- if (!get_hunk_at_pointer(view, &view->priv->context_iter, NULL))
+ gboolean is_hunk;
+
+ get_info_at_pointer (view, &view->priv->context_iter, &is_hunk, NULL, NULL);
+
+ if (!is_hunk)
+ {
return;
+ }
- GtkWidget *separator = gtk_separator_menu_item_new();
- gtk_widget_show(separator);
+ GtkWidget *separator = gtk_separator_menu_item_new ();
+ gtk_widget_show (separator);
view->priv->context_type = CONTEXT_TYPE_HUNK;
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), separator);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), separator);
if (view->priv->current_changes & GITG_CHANGED_FILE_CHANGES_CACHED)
{
- GtkWidget *unstage = create_context_menu_item(view, "UnstageChangesAction");
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), unstage);
+ GtkWidget *unstage = create_context_menu_item (view, "UnstageChangesAction");
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), unstage);
}
else
{
- GtkWidget *stage = create_context_menu_item(view, "StageChangesAction");
- GtkWidget *revert = create_context_menu_item(view, "RevertChangesAction");
+ GtkWidget *stage = create_context_menu_item (view, "StageChangesAction");
+ GtkWidget *revert = create_context_menu_item (view, "RevertChangesAction");
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), stage);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), revert);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), stage);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), revert);
}
}
diff --git a/gitg/gitg-diff-line-renderer.c b/gitg/gitg-diff-line-renderer.c
index 567ef27..29561dc 100644
--- a/gitg/gitg-diff-line-renderer.c
+++ b/gitg/gitg-diff-line-renderer.c
@@ -21,6 +21,7 @@
*/
#include "gitg-diff-line-renderer.h"
+#include "gitg-utils.h"
#define GITG_DIFF_LINE_RENDERER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GITG_TYPE_DIFF_LINE_RENDERER, GitgDiffLineRendererPrivate))
@@ -37,13 +38,15 @@ enum
{
PROP_0,
PROP_LINE_OLD,
- PROP_LINE_NEW
+ PROP_LINE_NEW,
+ PROP_LABEL
};
struct _GitgDiffLineRendererPrivate
{
gint line_old;
gint line_new;
+ gchar *label;
};
G_DEFINE_TYPE (GitgDiffLineRenderer, gitg_diff_line_renderer, GTK_TYPE_CELL_RENDERER)
@@ -70,6 +73,10 @@ gitg_diff_line_renderer_set_property (GObject *object,
case PROP_LINE_NEW:
self->priv->line_new = g_value_get_int (value);
break;
+ case PROP_LABEL:
+ g_free (self->priv->label);
+ self->priv->label = g_value_dup_string (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -92,6 +99,9 @@ gitg_diff_line_renderer_get_property (GObject *object,
case PROP_LINE_NEW:
g_value_set_int (value, self->priv->line_new);
break;
+ case PROP_LABEL:
+ g_value_set_string (value, self->priv->label);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -99,16 +109,109 @@ gitg_diff_line_renderer_get_property (GObject *object,
}
static void
-gitg_diff_line_renderer_render_impl (GtkCellRenderer *cell,
- GdkDrawable *window,
- GtkWidget *widget,
- GdkRectangle *background_area,
- GdkRectangle *cell_area,
- GdkRectangle *expose_area,
- GtkCellRendererState flags)
+darken_or_lighten (cairo_t *ctx,
+ GdkColor const *color)
{
- GitgDiffLineRenderer *lr = GITG_DIFF_LINE_RENDERER (cell);
+ float r, g, b;
+
+ r = color->red / 65535.0;
+ g = color->green / 65535.0;
+ b = color->blue / 65535.0;
+
+ if ((r + g + b) / 3 > 0.5)
+ {
+ cairo_set_source_rgb (ctx,
+ r * 0.5,
+ g * 0.5,
+ b * 0.5);
+ }
+ else
+ {
+ cairo_set_source_rgb (ctx,
+ r * 1.5,
+ g * 1.5,
+ b * 1.5);
+ }
+}
+
+static void
+render_label (GitgDiffLineRenderer *lr,
+ GdkDrawable *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags)
+{
+ PangoLayout *layout;
+ GtkStyle *style;
+ GtkStateType state;
+ gint pixel_height;
+
+ layout = gtk_widget_create_pango_layout (widget, "");
+
+ pango_layout_set_markup (layout, lr->priv->label, -1);
+ pango_layout_set_width (layout, cell_area->width);
+
+ pango_layout_get_pixel_size (layout, NULL, &pixel_height);
+
+ pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
+
+ style = gtk_widget_get_style (widget);
+ state = gtk_widget_get_state (widget);
+
+ cairo_t *ctx = gdk_cairo_create (window);
+
+ gdk_cairo_rectangle (ctx, expose_area);
+ cairo_clip (ctx);
+
+ gdk_cairo_set_source_color (ctx, &(style->fg[state]));
+
+ gitg_utils_rounded_rectangle (ctx,
+ cell_area->x + 0.5,
+ cell_area->y + 0.5,
+ cell_area->width - 1,
+ cell_area->height - 1,
+ 5);
+
+ cairo_fill_preserve (ctx);
+
+ darken_or_lighten (ctx, &(style->fg[state]));
+
+ cairo_set_line_width (ctx, 1);
+ cairo_stroke (ctx);
+
+ gdk_cairo_set_source_color (ctx, &(style->base[state]));
+
+ cairo_move_to (ctx,
+ cell_area->x + cell_area->width / 2,
+ cell_area->y + (cell_area->height - pixel_height) / 2);
+
+ pango_cairo_show_layout (ctx, layout);
+
+ cairo_destroy (ctx);
+ /*gtk_paint_layout (style,
+ window,
+ state,
+ FALSE,
+ NULL,
+ widget,
+ NULL,
+ cell_area->x + cell_area->width / 2,
+ cell_area->y,
+ layout);*/
+}
+
+static void
+render_lines (GitgDiffLineRenderer *lr,
+ GdkDrawable *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags)
+{
/* Render new/old in the cell area */
gchar old_str[16];
gchar new_str[16];
@@ -138,7 +241,7 @@ gitg_diff_line_renderer_render_impl (GtkCellRenderer *cell,
*new_str = '\0';
}
- g_object_get (cell, "xpad", &xpad, "ypad", &ypad, NULL);
+ g_object_get (lr, "xpad", &xpad, "ypad", &ypad, NULL);
pango_layout_set_text (layout, old_str, -1);
gtk_paint_layout (widget->style,
@@ -178,6 +281,39 @@ gitg_diff_line_renderer_render_impl (GtkCellRenderer *cell,
}
static void
+gitg_diff_line_renderer_render_impl (GtkCellRenderer *cell,
+ GdkDrawable *window,
+ GtkWidget *widget,
+ GdkRectangle *background_area,
+ GdkRectangle *cell_area,
+ GdkRectangle *expose_area,
+ GtkCellRendererState flags)
+{
+ GitgDiffLineRenderer *lr = GITG_DIFF_LINE_RENDERER (cell);
+
+ if (lr->priv->label)
+ {
+ render_label (lr,
+ window,
+ widget,
+ background_area,
+ cell_area,
+ expose_area,
+ flags);
+ }
+ else
+ {
+ render_lines (lr,
+ window,
+ widget,
+ background_area,
+ cell_area,
+ expose_area,
+ flags);
+ }
+}
+
+static void
gitg_diff_line_renderer_get_size_impl (GtkCellRenderer *cell,
GtkWidget *widget,
GdkRectangle *cell_area,
@@ -201,8 +337,35 @@ gitg_diff_line_renderer_get_size_impl (GtkCellRenderer *cell,
pango_layout_get_pixel_size(layout, &pixel_width, &pixel_height);
g_object_get (cell, "xpad", &xpad, "ypad", &ypad, NULL);
+ pixel_width += pixel_width + xpad * 2 + 3;
- pixel_width = pixel_width * 2 + xpad * 4 + 3;
+ if (lr->priv->label)
+ {
+ PangoLayout *lbl_layout;
+ gint lbl_pixel_width;
+ gint lbl_pixel_height;
+
+ lbl_layout = gtk_widget_create_pango_layout (widget,
+ "");
+
+ pango_layout_set_markup (lbl_layout, lr->priv->label, -1);
+
+ pango_layout_get_pixel_size (lbl_layout,
+ &lbl_pixel_width,
+ &lbl_pixel_height);
+
+ if (lbl_pixel_width > pixel_width)
+ {
+ pixel_width = lbl_pixel_width;
+ }
+
+ if (lbl_pixel_height > pixel_height)
+ {
+ pixel_height = lbl_pixel_height;
+ }
+ }
+
+ pixel_width += xpad * 2;
pixel_height += ypad * 2;
if (width)
@@ -261,7 +424,15 @@ gitg_diff_line_renderer_class_init (GitgDiffLineRendererClass *klass)
-1,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
- g_type_class_add_private (object_class, sizeof(GitgDiffLineRendererPrivate));
+ g_object_class_install_property (object_class,
+ PROP_LABEL,
+ g_param_spec_string ("label",
+ "Label",
+ "Label",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ g_type_class_add_private (object_class, sizeof (GitgDiffLineRendererPrivate));
}
static void
diff --git a/gitg/gitg-diff-view.c b/gitg/gitg-diff-view.c
index ed363a5..db97dc3 100644
--- a/gitg/gitg-diff-view.c
+++ b/gitg/gitg-diff-view.c
@@ -23,6 +23,7 @@
#include "gitg-diff-view.h"
#include "gitg-types.h"
#include "gitg-diff-line-renderer.h"
+#include "gitg-utils.h"
#include <string.h>
#include <stdlib.h>
@@ -39,11 +40,11 @@
#define IDLE_SCAN_COUNT 30
-#define GITG_DIFF_ITER_GET_VIEW(iter) ((GitgDiffView *)iter->userdata)
-#define GITG_DIFF_ITER_GET_REGION(iter) ((Region *)iter->userdata2)
+#define GITG_DIFF_ITER_GET_VIEW(iter) ((GitgDiffView *)((iter)->userdata))
+#define GITG_DIFF_ITER_GET_REGION(iter) ((Region *)((iter)->userdata2))
-#define GITG_DIFF_ITER_SET_REGION(iter, region) (iter->userdata2 = region)
-#define GITG_DIFF_ITER_SET_VIEW(iter, view) (iter->userdata = view)
+#define GITG_DIFF_ITER_SET_REGION(iter, region) ((iter)->userdata2 = region)
+#define GITG_DIFF_ITER_SET_VIEW(iter, view) ((iter)->userdata = view)
static void on_buffer_insert_text(GtkTextBuffer *buffer, GtkTextIter *iter, gchar const *text, gint len, GitgDiffView *view);
static void on_buffer_delete_range(GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, GitgDiffView *view);
@@ -124,6 +125,12 @@ struct _GitgDiffViewPrivate
Region *lines_current_region;
gint lines_previous_line;
guint lines_counters[2];
+
+ gboolean ignore_changes;
+
+ GitgDiffViewLabelFunc label_func;
+ gpointer label_func_user_data;
+ GDestroyNotify label_func_destroy_notify;
};
G_DEFINE_TYPE(GitgDiffView, gitg_diff_view, GTK_TYPE_SOURCE_VIEW)
@@ -186,6 +193,12 @@ gitg_diff_view_finalize (GObject *object)
regions_free (view, TRUE);
g_sequence_free (view->priv->regions_index);
+ if (view->priv->label_func &&
+ view->priv->label_func_destroy_notify)
+ {
+ view->priv->label_func_destroy_notify (view->priv->label_func_user_data);
+ }
+
G_OBJECT_CLASS (gitg_diff_view_parent_class)->finalize (object);
}
@@ -395,7 +408,7 @@ region_to_iter (GitgDiffView *view, Region *region, GitgDiffIter *iter)
}
static void
-add_region(GitgDiffView *view, Region *region)
+add_region (GitgDiffView *view, Region *region)
{
if (view->priv->last_region)
{
@@ -404,7 +417,7 @@ add_region(GitgDiffView *view, Region *region)
if (view->priv->last_region->type == GITG_DIFF_ITER_TYPE_HUNK)
{
- ensure_max_line(view, (Hunk *)view->priv->last_region);
+ ensure_max_line (view, (Hunk *)view->priv->last_region);
}
}
else
@@ -622,6 +635,16 @@ line_renderer_size_func (GtkSourceGutter *gutter,
"line_old", view->priv->max_line_count,
"line_new", view->priv->max_line_count,
NULL);
+
+ if (view->priv->label_func)
+ {
+ gchar *label = view->priv->label_func (view,
+ -1,
+ view->priv->label_func_user_data);
+
+ g_object_set (cell, "label", label, NULL);
+ g_free (label);
+ }
}
static void
@@ -676,6 +699,16 @@ line_renderer_data_func (GtkSourceGutter *gutter,
view->priv->lines_counters[0] = view->priv->lines_counters[1] = 0;
*current = (*current)->next->visible ? (*current)->next : NULL;
}
+
+ if (view->priv->label_func)
+ {
+ gchar *label = view->priv->label_func (view,
+ line_number,
+ view->priv->label_func_user_data);
+
+ g_object_set (cell, "label", label, NULL);
+ g_free (label);
+ }
}
static gint
@@ -710,44 +743,176 @@ gitg_diff_view_set_diff_enabled(GitgDiffView *view, gboolean enabled)
g_object_notify(G_OBJECT(view), "diff-enabled");
}
-void
-gitg_diff_view_remove_hunk(GitgDiffView *view, GtkTextIter *iter)
+static void
+offset_regions (Region *region,
+ gint offset)
{
- g_return_if_fail(GITG_IS_DIFF_VIEW(view));
+ while (region)
+ {
+ region->line += offset;
+ region = region->next;
+ }
+}
- /* removes hunk at iter and if it was the last hunk of a file, also removes
- the file header */
- Region *region = find_current_region(view, gtk_text_iter_get_line(iter));
+static gint
+compare_regions (Region *first,
+ Region *second,
+ gpointer user_data)
+{
+ return first->line < second->line ? -1 : (first->line > second->line ? 1 : 0);
+}
- if (!region)
- return;
+static GSequenceIter *
+region_get_iter (GitgDiffView *view, Region *region)
+{
+ GSequenceIter *iter;
+ iter = g_sequence_search (view->priv->regions_index,
+ region,
+ (GCompareDataFunc)compare_regions,
+ NULL);
+
+ if (g_sequence_iter_is_end (iter))
+ {
+ return g_sequence_iter_prev (iter);
+ }
+ else
+ {
+ Region *reg = g_sequence_get (iter);
+
+ if (reg->line != region->line)
+ {
+ return g_sequence_iter_prev (iter);
+ }
+ else
+ {
+ return iter;
+ }
+ }
+}
+
+static void
+remove_regions_sequence (GitgDiffView *view,
+ Region *from,
+ Region *to)
+{
+ GSequenceIter *start;
+ GSequenceIter *end;
+
+ start = region_get_iter (view, from);
+
+ if (to)
+ {
+ end = g_sequence_iter_prev (region_get_iter (view, to));
+ }
+ else
+ {
+ end = g_sequence_get_end_iter (view->priv->regions_index);
+ }
+
+ g_sequence_remove_range (start, end);
+}
+
+static void
+remove_regions (GitgDiffView *view, Region *from, Region *to)
+{
+ GtkTextBuffer *buffer;
GtkTextIter start;
GtkTextIter end;
+ gint offset;
- gtk_text_buffer_get_iter_at_line(view->priv->current_buffer, &start, region->line);
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
- if (region->next)
+ if (from->prev)
{
- gtk_text_buffer_get_iter_at_line(view->priv->current_buffer, &end, region->next->line - 1);
- gtk_text_iter_forward_line(&end);
+ if (to)
+ {
+ from->prev->next = to;
+ to->prev = from->prev;
+ }
+ else
+ {
+ from->prev->next = NULL;
+ }
}
else
{
- gtk_text_buffer_get_end_iter(view->priv->current_buffer, &end);
+ if (to)
+ {
+ view->priv->regions = to;
+ to->prev = NULL;
+ }
+ else
+ {
+ view->priv->regions = NULL;
+ }
+ }
+
+ if (!to)
+ {
+ view->priv->last_region = from->prev;
}
- Region *prev = find_current_region(view, region->line - 1);
+ remove_regions_sequence (view, from, to);
+
+ gtk_text_buffer_get_iter_at_line (buffer, &start, from->line);
- if ((!region->next || region->next->type == GITG_DIFF_ITER_TYPE_HEADER) && (!prev || prev->type == GITG_DIFF_ITER_TYPE_HEADER))
+ if (to)
{
- if (!prev)
- gtk_text_buffer_get_start_iter(view->priv->current_buffer, &start);
- else
- gtk_text_buffer_get_iter_at_line(view->priv->current_buffer, &start, region->line);
+ gtk_text_buffer_get_iter_at_line (buffer, &end, to->line);
+ }
+ else
+ {
+ gtk_text_buffer_get_end_iter (buffer, &end);
+ }
+
+ /* Remove and free from sequence */
+ while (from && from != to)
+ {
+ Region *next = from->next;
+
+ //region_free (from);
+ from = next;
}
- gtk_text_buffer_delete(view->priv->current_buffer, &start, &end);
+ offset = gtk_text_iter_get_line (&start) - gtk_text_iter_get_line (&end);
+
+ offset_regions (to, offset);
+
+ view->priv->ignore_changes = TRUE;
+ gtk_text_buffer_begin_user_action (buffer);
+ gtk_text_buffer_delete (buffer, &start, &end);
+ gtk_text_buffer_end_user_action (buffer);
+ view->priv->ignore_changes = FALSE;
+}
+
+void
+gitg_diff_view_remove_hunk (GitgDiffView *view, GtkTextIter *iter)
+{
+ g_return_if_fail (GITG_IS_DIFF_VIEW (view));
+ g_return_if_fail (iter != NULL);
+
+ /* removes hunk at iter and if it was the last hunk of a file, also removes
+ the file header */
+ Region *region = find_current_region (view,
+ gtk_text_iter_get_line (iter));
+
+ if (!region)
+ {
+ return;
+ }
+
+ Region *from = region;
+ Region *to = region->next;
+
+ if (region->prev && region->prev->type == GITG_DIFF_ITER_TYPE_HEADER &&
+ (!to || to->type == GITG_DIFF_ITER_TYPE_HEADER))
+ {
+ /* also remove the header in this case */
+ from = region->prev;
+ }
+
+ remove_regions (view, from, to);
}
gboolean
@@ -1014,6 +1179,11 @@ try_scan(GitgDiffView *view)
static void
on_buffer_delete_range(GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *end, GitgDiffView *view)
{
+ if (view->priv->ignore_changes)
+ {
+ return;
+ }
+
regions_free(view, FALSE);
if (iter_in_view(view, start) || iter_in_view(view, end))
@@ -1026,6 +1196,11 @@ on_buffer_delete_range(GtkTextBuffer *buffer, GtkTextIter *start, GtkTextIter *e
static void
on_buffer_insert_text(GtkTextBuffer *buffer, GtkTextIter *iter, gchar const *text, gint len, GitgDiffView *view)
{
+ if (view->priv->ignore_changes)
+ {
+ return;
+ }
+
/* if region is in current view and not scanned, issue scan now */
if (iter_in_view(view, iter))
try_scan(view);
@@ -1088,6 +1263,29 @@ gitg_diff_view_get_hunk_at_iter (GitgDiffView *view,
return TRUE;
}
+static void
+region_get_bounds (GitgDiffView *view,
+ Region *region,
+ GtkTextIter *start,
+ GtkTextIter *end)
+{
+ gtk_text_buffer_get_iter_at_line (view->priv->current_buffer,
+ start,
+ region->line);
+
+ if (region->next != NULL)
+ {
+ gtk_text_buffer_get_iter_at_line (view->priv->current_buffer,
+ end,
+ region->next->line);
+ }
+ else
+ {
+ gtk_text_buffer_get_end_iter (view->priv->current_buffer,
+ end);
+ }
+}
+
void
gitg_diff_iter_get_bounds (GitgDiffIter const *iter,
GtkTextIter *start,
@@ -1102,20 +1300,190 @@ gitg_diff_iter_get_bounds (GitgDiffIter const *iter,
GitgDiffView *view = GITG_DIFF_ITER_GET_VIEW (iter);
Region *region = GITG_DIFF_ITER_GET_REGION (iter);
- gtk_text_buffer_get_iter_at_line (view->priv->current_buffer,
- start,
- region->line);
+ region_get_bounds (view, region, start, end);
+}
- if (region->next != NULL)
+GitgDiffLineType
+gitg_diff_view_get_line_type (GitgDiffView *view, GtkTextIter const *iter)
+{
+ g_return_val_if_fail (GITG_IS_DIFF_VIEW (view), GITG_DIFF_LINE_TYPE_NONE);
+ g_return_val_if_fail (iter != NULL, GITG_DIFF_LINE_TYPE_NONE);
+
+ GitgDiffIter diff_iter;
+
+ if (!gitg_diff_view_get_hunk_at_iter (view, iter, &diff_iter))
{
- gtk_text_buffer_get_iter_at_line (view->priv->current_buffer,
- end,
- region->next->line);
+ return GITG_DIFF_LINE_TYPE_NONE;
+ }
+
+ GtkTextIter start = *iter;
+ gtk_text_iter_set_line_offset (&start, 0);
+
+ gunichar ch = gtk_text_iter_get_char (&start);
+
+ switch (ch)
+ {
+ case '+':
+ return GITG_DIFF_LINE_TYPE_ADD;
+ case '-':
+ return GITG_DIFF_LINE_TYPE_REMOVE;
+ default:
+ return GITG_DIFF_LINE_TYPE_NONE;
+ }
+}
+
+static void
+calculate_hunk_header_counters (GitgDiffView *view,
+ Region *region)
+{
+ GtkTextIter start;
+ GtkTextIter end;
+ GtkTextIter begin;
+
+ GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ region_get_bounds (view, region, &start, &end);
+
+ begin = start;
+
+ guint new_count = 0;
+ guint old_count = 0;
+
+ gboolean isempty = TRUE;
+
+ if (gtk_text_iter_forward_line (&start))
+ {
+ while (gtk_text_iter_compare (&start, &end) < 0)
+ {
+ GitgDiffLineType line_type;
+ GtkTextIter line_end = start;
+
+ gtk_text_iter_forward_to_line_end (&line_end);
+
+ line_type = gitg_diff_view_get_line_type (view, &start);
+
+ if (line_type == GITG_DIFF_LINE_TYPE_NONE ||
+ line_type == GITG_DIFF_LINE_TYPE_ADD)
+ {
+ ++new_count;
+ }
+
+ if (line_type == GITG_DIFF_LINE_TYPE_NONE ||
+ line_type == GITG_DIFF_LINE_TYPE_REMOVE)
+ {
+ ++old_count;
+ }
+
+ if (line_type != GITG_DIFF_LINE_TYPE_NONE)
+ {
+ isempty = FALSE;
+ }
+
+ if (!gtk_text_iter_forward_line (&start))
+ {
+ break;
+ }
+ }
+ }
+
+ if (isempty)
+ {
+ gitg_diff_view_remove_hunk (view, &begin);
}
else
{
- gtk_text_buffer_get_end_iter (view->priv->current_buffer,
- end);
+ end = begin;
+ gtk_text_iter_forward_to_line_end (&end);
+
+ gchar *header = gtk_text_buffer_get_text (buffer, &begin, &end, TRUE);
+ gchar *ret;
+
+ ret = gitg_utils_rewrite_hunk_counters (header, old_count, new_count);
+ g_free (header);
+
+ gtk_text_buffer_delete (buffer, &begin, &end);
+ gtk_text_buffer_insert (buffer, &begin, ret, -1);
+
+ g_free (ret);
+ }
+}
+
+void
+gitg_diff_view_clear_line (GitgDiffView *view,
+ GtkTextIter const *iter,
+ GitgDiffLineType old_type,
+ GitgDiffLineType new_type)
+{
+ g_return_if_fail (GITG_IS_DIFF_VIEW (view));
+ g_return_if_fail (iter != NULL);
+
+ GitgDiffLineType line_type;
+ GitgDiffIter diff_iter;
+
+ line_type = gitg_diff_view_get_line_type (view, iter);
+
+ if (line_type == GITG_DIFF_LINE_TYPE_NONE)
+ {
+ return;
+ }
+
+ gitg_diff_view_get_hunk_at_iter (view, iter, &diff_iter);
+
+ GtkTextIter start = *iter;
+ GtkTextIter end;
+ GtkTextBuffer *buffer;
+ Region *region;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+ gtk_text_iter_set_line_offset (&start, 0);
+ end = start;
+
+ gtk_text_buffer_begin_user_action (buffer);
+ view->priv->ignore_changes = TRUE;
+
+ region = GITG_DIFF_ITER_GET_REGION (&diff_iter);
+
+ if (line_type == new_type)
+ {
+ /* means the line now just becomes context */
+ gtk_text_iter_forward_char (&end);
+ gtk_text_buffer_delete (buffer, &start, &end);
+ gtk_text_buffer_insert (buffer, &start, " ", 1);
}
+ else
+ {
+ /* means the line should be removed */
+ if (!gtk_text_iter_forward_line (&end))
+ {
+ gtk_text_iter_forward_to_line_end (&end);
+ }
+
+ gtk_text_buffer_delete (buffer, &start, &end);
+ offset_regions (region->next, -1);
+ }
+
+ calculate_hunk_header_counters (view, region);
+
+ view->priv->ignore_changes = FALSE;
+ gtk_text_buffer_end_user_action (buffer);
}
+void
+gitg_diff_view_set_label_func (GitgDiffView *view,
+ GitgDiffViewLabelFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy_notify)
+{
+ g_return_if_fail (GITG_IS_DIFF_VIEW (view));
+
+ if (view->priv->label_func &&
+ view->priv->label_func_destroy_notify)
+ {
+ view->priv->label_func_destroy_notify (view->priv->label_func_user_data);
+ }
+
+ view->priv->label_func = func;
+ view->priv->label_func_user_data = user_data;
+ view->priv->label_func_destroy_notify = destroy_notify;
+}
diff --git a/gitg/gitg-diff-view.h b/gitg/gitg-diff-view.h
index d7b7946..4aa294e 100644
--- a/gitg/gitg-diff-view.h
+++ b/gitg/gitg-diff-view.h
@@ -54,6 +54,13 @@ typedef enum
GITG_DIFF_ITER_TYPE_HUNK
} GitgDiffIterType;
+typedef enum
+{
+ GITG_DIFF_LINE_TYPE_NONE,
+ GITG_DIFF_LINE_TYPE_ADD,
+ GITG_DIFF_LINE_TYPE_REMOVE,
+} GitgDiffLineType;
+
struct _GitgDiffView
{
GtkSourceView parent;
@@ -69,6 +76,10 @@ struct _GitgDiffViewClass
void (*hunk_added)(GitgDiffView *view, GitgDiffIter *iter);
};
+typedef gchar *(*GitgDiffViewLabelFunc) (GitgDiffView *view,
+ gint line,
+ gpointer user_data);
+
GType gitg_diff_view_get_type(void) G_GNUC_CONST;
GitgDiffView *gitg_diff_view_new(void);
@@ -91,6 +102,14 @@ gboolean gitg_diff_view_get_hunk_at_iter (GitgDiffView *view, GtkTextIter const
void gitg_diff_iter_get_bounds (GitgDiffIter const *iter, GtkTextIter *start, GtkTextIter *end);
+GitgDiffLineType gitg_diff_view_get_line_type (GitgDiffView *view, GtkTextIter const *iter);
+void gitg_diff_view_clear_line (GitgDiffView *view, GtkTextIter const *iter, GitgDiffLineType old_type, GitgDiffLineType new_type);
+
+void gitg_diff_view_set_label_func (GitgDiffView *view,
+ GitgDiffViewLabelFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy_notify);
+
G_END_DECLS
#endif /* __GITG_DIFF_VIEW_H__ */
diff --git a/gitg/gitg-label-renderer.c b/gitg/gitg-label-renderer.c
index 442304f..bd5f3b2 100644
--- a/gitg/gitg-label-renderer.c
+++ b/gitg/gitg-label-renderer.c
@@ -22,6 +22,8 @@
#include "gitg-label-renderer.h"
#include "gitg-ref.h"
+#include "gitg-utils.h"
+
#include <math.h>
#define PADDING 4
@@ -67,23 +69,6 @@ gitg_label_renderer_width(GtkWidget *widget, PangoFontDescription *description,
}
static void
-rounded_rectangle(cairo_t *ctx, float x, float y, float width, float height, float radius)
-{
- cairo_move_to(ctx, x + radius, y);
- cairo_rel_line_to(ctx, width - 2 * radius, 0);
- cairo_arc(ctx, x + width - radius, y + radius, radius, 1.5 * M_PI, 0.0);
-
- cairo_rel_line_to(ctx, 0, height - 2 * radius);
- cairo_arc(ctx, x + width - radius, y + height - radius, radius, 0.0, 0.5 * M_PI);
-
- cairo_rel_line_to(ctx, -(width - radius * 2), 0);
- cairo_arc(ctx, x + radius, y + height - radius, radius, 0.5 * M_PI, M_PI);
-
- cairo_rel_line_to(ctx, 0, -(height - radius * 2));
- cairo_arc(ctx, x + radius, y + radius, radius, M_PI, 1.5 * M_PI);
-}
-
-static void
get_type_color (GitgRefType type, gdouble *r, gdouble *g, gdouble *b)
{
switch (type)
@@ -177,7 +162,11 @@ render_label (cairo_t *context, PangoLayout *layout, GitgRef *ref, gint x, gint
pango_layout_get_pixel_size(layout, &w, &h);
// draw rounded rectangle
- rounded_rectangle(context, x + 0.5, y + MARGIN + 0.5, w + PADDING * 2, height - MARGIN * 2, 5);
+ gitg_utils_rounded_rectangle (context, x + 0.5,
+ y + MARGIN + 0.5,
+ w + PADDING * 2,
+ height - MARGIN * 2,
+ 5);
set_source_for_ref_type(context, ref, use_state);
cairo_fill_preserve(context);
diff --git a/gitg/gitg-utils.c b/gitg/gitg-utils.c
index c66c908..705d19b 100644
--- a/gitg/gitg-utils.c
+++ b/gitg/gitg-utils.c
@@ -24,6 +24,7 @@
#include <glib.h>
#include <stdlib.h>
#include <gconf/gconf-client.h>
+#include <math.h>
#include "gitg-utils.h"
#include "gitg-dirs.h"
@@ -596,3 +597,78 @@ gitg_utils_restore_pane_position (GtkPaned *paned, gint position, gboolean rever
(GClosureNotify)free_paned_restore_info,
G_CONNECT_AFTER);
}
+
+gchar *
+gitg_utils_rewrite_hunk_counters (gchar const *header,
+ guint old_count,
+ guint new_count)
+{
+ if (!header)
+ {
+ return NULL;
+ }
+
+ gchar *copy = g_strdup (header);
+ gchar *ptr1 = g_utf8_strchr (copy, -1, ',');
+
+ if (!ptr1)
+ {
+ g_free (copy);
+ return NULL;
+ }
+
+ gchar *ptrs1 = g_utf8_strchr (ptr1 + 1, -1, ' ');
+
+ if (!ptrs1)
+ {
+ g_free (copy);
+ return NULL;
+ }
+
+ gchar *ptr2 = g_utf8_strchr (ptrs1 + 1, -1, ',');
+
+ if (!ptr2)
+ {
+ g_free (copy);
+ return NULL;
+ }
+
+ gchar *ptrs2 = g_utf8_strchr (ptr2 + 1, -1, ' ');
+
+ if (!ptrs2)
+ {
+ g_free (copy);
+ return NULL;
+ }
+
+ *ptr1 = *ptr2 = '\0';
+
+ gchar *ret;
+
+ ret = g_strdup_printf ("%s,%d%s,%d%s",
+ copy,
+ old_count,
+ ptrs1,
+ new_count,
+ ptrs2);
+
+ g_free (copy);
+ return ret;
+}
+
+void
+gitg_utils_rounded_rectangle(cairo_t *ctx, gdouble x, gdouble y, gdouble width, gdouble height, gdouble radius)
+{
+ cairo_move_to (ctx, x + radius, y);
+ cairo_rel_line_to (ctx, width - 2 * radius, 0);
+ cairo_arc (ctx, x + width - radius, y + radius, radius, 1.5 * M_PI, 0.0);
+
+ cairo_rel_line_to (ctx, 0, height - 2 * radius);
+ cairo_arc (ctx, x + width - radius, y + height - radius, radius, 0.0, 0.5 * M_PI);
+
+ cairo_rel_line_to (ctx, -(width - radius * 2), 0);
+ cairo_arc (ctx, x + radius, y + height - radius, radius, 0.5 * M_PI, M_PI);
+
+ cairo_rel_line_to (ctx, 0, -(height - radius * 2));
+ cairo_arc (ctx, x + radius, y + radius, radius, M_PI, 1.5 * M_PI);
+}
diff --git a/gitg/gitg-utils.h b/gitg/gitg-utils.h
index 1ae8d3c..fe3008b 100644
--- a/gitg/gitg-utils.h
+++ b/gitg/gitg-utils.h
@@ -71,4 +71,8 @@ GtkCellRenderer *gitg_utils_find_cell_at_pos (GtkTreeView *tree_view, GtkTreeVie
void gitg_utils_restore_pane_position (GtkPaned *paned, gint position, gboolean reversed);
+gchar *gitg_utils_rewrite_hunk_counters (gchar const *hunk, guint old_count, guint new_count);
+void gitg_utils_rounded_rectangle (cairo_t *ctx, gdouble x, gdouble y, gdouble width, gdouble height, gdouble radius);
+
+
#endif /* __GITG_UTILS_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]