[gnome-builder] ide-source-view: Fix issues with scrolling
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] ide-source-view: Fix issues with scrolling
- Date: Sun, 17 May 2015 01:08:36 +0000 (UTC)
commit 14eeedf6878797a27ddb8681228a898ac7625790
Author: Dimitris Zenios <dimitris zenios gmail com>
Date: Sun May 17 03:42:48 2015 +0300
ide-source-view: Fix issues with scrolling
https://bugzilla.gnome.org/show_bug.cgi?id=749343
libide/ide-source-view-movements.c | 2 +-
libide/ide-source-view.c | 240 +++++++++++++++++++++--------------
libide/ide-source-view.h | 5 +-
src/editor/gb-editor-frame.c | 5 +-
4 files changed, 153 insertions(+), 99 deletions(-)
---
diff --git a/libide/ide-source-view-movements.c b/libide/ide-source-view-movements.c
index 7f33cfc..777e2f5 100644
--- a/libide/ide-source-view-movements.c
+++ b/libide/ide-source-view-movements.c
@@ -1506,5 +1506,5 @@ _ide_source_view_apply_movement (IdeSourceView *self,
*target_offset = gtk_text_iter_get_line_offset (&mv.insert);
if (!mv.ignore_scroll_to_insert)
- ide_source_view_scroll_mark_onscreen (self, insert);
+ ide_source_view_scroll_mark_onscreen (self, insert, TRUE, 0.5, 0.5);
}
diff --git a/libide/ide-source-view.c b/libide/ide-source-view.c
index 2238b5f..0980278 100644
--- a/libide/ide-source-view.c
+++ b/libide/ide-source-view.c
@@ -20,7 +20,6 @@
#include <glib/gi18n.h>
#include <stdlib.h>
-
#include "egg-binding-set.h"
#include "egg-signal-group.h"
@@ -708,14 +707,12 @@ ide_source_view_scroll_to_insert (IdeSourceView *self)
{
GtkTextBuffer *buffer;
GtkTextMark *mark;
- GtkTextIter iter;
g_assert (IDE_IS_SOURCE_VIEW (self));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
mark = gtk_text_buffer_get_insert (buffer);
- gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
- gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (self), &iter, 0.0, FALSE, 0.0, 0.0);
+ ide_source_view_scroll_mark_onscreen (self, mark, 0.0, TRUE, 0.5, 0.5, TRUE);
}
static void
@@ -1095,7 +1092,7 @@ ide_source_view__search_settings_notify_search_text (IdeSourceView *se
&match_begin, &match_end))
{
gtk_text_buffer_move_mark (buffer, priv->rubberband_mark, &match_begin);
- ide_source_view_scroll_mark_onscreen (self, priv->rubberband_mark);
+ ide_source_view_scroll_mark_onscreen (self, priv->rubberband_mark, TRUE, 0.5, 0.5);
}
}
}
@@ -1336,7 +1333,7 @@ ide_source_view__buffer_loaded_cb (IdeSourceView *self,
}
insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (buffer));
- ide_source_view_scroll_to_mark (self, insert, 0.0, TRUE, 1.0, 0.5, TRUE);
+ ide_source_view_scroll_to_mark (self, insert, 0.0, TRUE, 0.5, 0.5, TRUE);
/*
* Store the line offset so movements are correct.
@@ -1411,7 +1408,7 @@ ide_source_view_bind_buffer (IdeSourceView *self,
ide_source_view_real_set_mode (self, NULL, IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT);
insert = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (buffer));
- gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (self), insert, 0.0, TRUE, 1.0, 0.5);
+ ide_source_view_scroll_mark_onscreen (self, insert, TRUE, 0.5, 0.5);
IDE_EXIT;
}
@@ -1821,7 +1818,7 @@ ide_source_view_do_indent (IdeSourceView *self,
/*
* Make sure we stay in the visible rect.
*/
- ide_source_view_scroll_mark_onscreen (self, insert);
+ ide_source_view_scroll_mark_onscreen (self, insert, FALSE, 0, 0);
/*
* Keep our selves pinned to the bottom of the document if that makes sense.
@@ -2212,7 +2209,7 @@ ide_source_view_key_press_event (GtkWidget *widget,
* Only scroll to the insert mark if we made a change.
*/
if (priv->change_sequence != change_sequence)
- ide_source_view_scroll_mark_onscreen (self, insert);
+ ide_source_view_scroll_mark_onscreen (self, insert, FALSE, 0, 0);
return ret;
}
@@ -2494,7 +2491,7 @@ ide_source_view_real_clear_selection (IdeSourceView *self)
insert = gtk_text_buffer_get_insert (buffer);
gtk_text_buffer_get_iter_at_mark (buffer, &iter, insert);
gtk_text_buffer_select_range (buffer, &iter, &iter);
- gtk_text_view_scroll_mark_onscreen (text_view, insert);
+ ide_source_view_scroll_mark_onscreen (self, insert, FALSE, 0, 0);
}
static void
@@ -2688,7 +2685,7 @@ ide_source_view_real_insert_at_cursor_and_indent (IdeSourceView *self,
gtk_text_buffer_end_user_action (buffer);
maybe_scroll:
- ide_source_view_scroll_mark_onscreen (self, gtk_text_buffer_get_insert (buffer));
+ ide_source_view_scroll_mark_onscreen (self, gtk_text_buffer_get_insert (buffer), FALSE, 0, 0);
if (at_bottom)
ide_source_view_scroll_to_bottom (self);
@@ -3157,7 +3154,7 @@ ide_source_view__search_forward_cb (GObject *object,
if (!gtk_widget_has_focus (GTK_WIDGET (mv->self)))
ide_source_view_real_save_insert_mark (mv->self);
- ide_source_view_scroll_mark_onscreen (mv->self, insert);
+ ide_source_view_scroll_mark_onscreen (mv->self, insert, TRUE, 0.5, 0.5);
}
static void
@@ -3225,7 +3222,7 @@ ide_source_view__search_backward_cb (GObject *object,
if (!gtk_widget_has_focus (GTK_WIDGET (mv->self)))
ide_source_view_real_save_insert_mark (mv->self);
- ide_source_view_scroll_mark_onscreen (mv->self, insert);
+ ide_source_view_scroll_mark_onscreen (mv->self, insert, TRUE, 0.5, 0.5);
}
static void
@@ -3357,7 +3354,7 @@ ide_source_view_real_move_error (IdeSourceView *self,
break;
gtk_text_buffer_select_range (buffer, &iter, &iter);
- ide_source_view_scroll_mark_onscreen (self, insert);
+ ide_source_view_scroll_mark_onscreen (self, insert, TRUE, 0.5, 0.5);
return;
}
@@ -3405,7 +3402,7 @@ ide_source_view_real_restore_insert_mark_full (IdeSourceView *self,
GtkTextMark *insert;
insert = gtk_text_buffer_get_insert (buffer);
- ide_source_view_scroll_mark_onscreen (self, insert);
+ ide_source_view_scroll_mark_onscreen (self, insert, FALSE, 0, 0);
}
}
@@ -3671,7 +3668,7 @@ ide_source_view_real_insert_at_cursor (GtkTextView *text_view,
GTK_TEXT_VIEW_CLASS (ide_source_view_parent_class)->insert_at_cursor (text_view, str);
buffer = gtk_text_view_get_buffer (text_view);
- ide_source_view_scroll_mark_onscreen (self, gtk_text_buffer_get_insert (buffer));
+ ide_source_view_scroll_mark_onscreen (self, gtk_text_buffer_get_insert (buffer), FALSE, 0, 0);
if (at_bottom)
ide_source_view_scroll_to_bottom (self);
@@ -4800,7 +4797,7 @@ ide_source_view_replay_scroll (gpointer data)
priv->delayed_scroll_replay = 0;
- ide_source_view_scroll_mark_onscreen (self, priv->scroll_mark);
+ ide_source_view_scroll_mark_onscreen (self, priv->scroll_mark, TRUE, 0.5, 0.5);
return G_SOURCE_REMOVE;
}
@@ -6490,7 +6487,10 @@ ide_source_view_get_visible_rect (IdeSourceView *self,
void
ide_source_view_scroll_mark_onscreen (IdeSourceView *self,
- GtkTextMark *mark)
+ GtkTextMark *mark,
+ gboolean use_align,
+ gdouble alignx,
+ gdouble aligny)
{
GtkTextView *text_view = (GtkTextView *)self;
GtkTextBuffer *buffer;
@@ -6509,7 +6509,7 @@ ide_source_view_scroll_mark_onscreen (IdeSourceView *self,
gtk_text_view_get_iter_location (text_view, &iter, &mark_rect);
if (!_GDK_RECTANGLE_CONTAINS (&visible_rect, &mark_rect))
- ide_source_view_scroll_to_mark (self, mark, 0.0, FALSE, 0.0, 0.0, TRUE);
+ ide_source_view_scroll_to_mark (self, mark, 0.0, use_align, alignx, aligny, TRUE);
IDE_EXIT;
}
@@ -6597,6 +6597,10 @@ ide_source_view__vadj_animation_completed (IdeSourceView *self)
IDE_EXIT;
}
+/*
+ * Many parts of this function were taken from gtk_text_view_scroll_to_iter ()
+ * https://developer.gnome.org/gtk3/stable/GtkTextView.html#gtk-text-view-scroll-to-iter
+ */
void
ide_source_view_scroll_to_iter (IdeSourceView *self,
const GtkTextIter *iter,
@@ -6609,112 +6613,156 @@ ide_source_view_scroll_to_iter (IdeSourceView *self,
IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
GtkTextView *text_view = (GtkTextView *)self;
GtkTextBuffer *buffer;
+ GdkRectangle rect;
+ GdkRectangle screen;
+ gint xvalue = 0;
+ gint yvalue = 0;
+ gint scroll_dest;
+ gint screen_bottom;
+ gint screen_right;
+ gint screen_xoffset;
+ gint screen_yoffset;
+ gint current_x_scroll;
+ gint current_y_scroll;
GtkAdjustment *hadj;
GtkAdjustment *vadj;
- GdkFrameClock *frame_clock;
- GdkRectangle real_visible_rect;
- GdkRectangle visible_rect;
- GdkRectangle iter_rect;
- gdouble yvalue;
- gdouble xvalue;
- gdouble orig_yalign;
- gint xoffset;
- gint yoffset;
IDE_ENTRY;
g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
- g_return_if_fail (iter);
- g_return_if_fail (xalign >= 0.0);
- g_return_if_fail (xalign <= 1.0);
- g_return_if_fail (yalign >= 0.0);
- g_return_if_fail (yalign <= 1.0);
+ g_return_if_fail (iter != NULL);
+ g_return_if_fail (within_margin >= 0.0 && within_margin <= 0.5);
+ g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
+ g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
if (!ide_source_view_can_animate (self))
animate_scroll = FALSE;
- buffer = gtk_text_view_get_buffer (text_view);
+ buffer = gtk_text_view_get_buffer (text_view);
gtk_text_buffer_move_mark (buffer, priv->scroll_mark, iter);
- gtk_text_view_get_visible_rect (text_view, &real_visible_rect);
- ide_source_view_get_visible_rect (self, &visible_rect);
-
hadj = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (self));
vadj = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (self));
- gtk_text_view_get_iter_location (text_view, iter, &iter_rect);
+ gtk_text_view_get_iter_location (text_view,
+ iter,
+ &rect);
- TRACE_RECTANGLE ("visible_rect", &visible_rect);
- TRACE_RECTANGLE ("iter_rect", &iter_rect);
+ gtk_text_view_get_visible_rect (text_view, &screen);
- /* leave a character of room to the right of the screen */
- visible_rect.width -= priv->cached_char_width;
+ current_x_scroll = screen.x;
+ current_y_scroll = screen.y;
- if (use_align == FALSE)
- {
- if (iter_rect.y < visible_rect.y)
- yalign = 0.0;
- else if (_GDK_RECTANGLE_Y2 (&iter_rect) > _GDK_RECTANGLE_Y2 (&visible_rect))
- yalign = 1.0;
- else
- yalign = (iter_rect.y - visible_rect.y) / (gdouble)visible_rect.height;
+ screen_xoffset = screen.width * within_margin;
+ screen_yoffset = screen.height * within_margin;
+
+ screen.x += screen_xoffset;
+ screen.y += screen_yoffset;
+ screen.width -= screen_xoffset * 2;
+ screen.height -= screen_yoffset * 2;
+
+
+ /* paranoia check */
+ if (screen.width < 1)
+ screen.width = 1;
+ if (screen.height < 1)
+ screen.height = 1;
- IDE_TRACE_MSG ("yalign = %lf", yalign);
+ /* The -1 here ensures that we leave enough space to draw the cursor
+ * when this function is used for horizontal scrolling.
+ */
+ screen_right = screen.x + screen.width - 1;
+ screen_bottom = screen.y + screen.height;
+
+
+ /* The alignment affects the point in the target character that we
+ * choose to align. If we're doing right/bottom alignment, we align
+ * the right/bottom edge of the character the mark is at; if we're
+ * doing left/top we align the left/top edge of the character; if
+ * we're doing center alignment we align the center of the
+ * character.
+ */
- if (iter_rect.x < visible_rect.x)
+ /* Vertical alignment */
+ scroll_dest = current_y_scroll;
+ if (use_align)
+ {
+ scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign);
+
+ /* if scroll_dest < screen.y, we move a negative increment (up),
+ * else a positive increment (down)
+ */
+ yvalue = scroll_dest - screen.y + screen_yoffset;
+ }
+ else
+ {
+ /* move minimum to get onscreen */
+ if (rect.y < screen.y)
{
- /* if we can get all the way to the line start, do so */
- if (_GDK_RECTANGLE_X2 (&iter_rect) < visible_rect.width)
- xalign = 1.0;
- else
- xalign = 0.0;
+ scroll_dest = rect.y;
+ yvalue = scroll_dest - screen.y - screen_yoffset;
+ }
+ else if ((rect.y + rect.height) > screen_bottom)
+ {
+ scroll_dest = rect.y + rect.height;
+ yvalue = scroll_dest - screen_bottom + screen_yoffset;
}
- else if (_GDK_RECTANGLE_X2 (&iter_rect) > _GDK_RECTANGLE_X2 (&visible_rect))
- xalign = 1.0;
- else
- xalign = (iter_rect.x - visible_rect.x) / (gdouble)visible_rect.width;
}
+ yvalue += current_y_scroll;
- g_assert (xalign >= 0.0);
- g_assert (yalign >= 0.0);
- g_assert (xalign <= 1.0);
- g_assert (yalign <= 1.0);
-
- /* get the screen coordinates within the real visible area */
- xoffset = (visible_rect.x - real_visible_rect.x) + (xalign * visible_rect.width);
- yoffset = (visible_rect.y - real_visible_rect.y) + (yalign * visible_rect.height);
+ /* Scroll offset adjustment */
+ if (priv->cached_char_height)
+ {
+ gint max_scroll_offset;
+ gint visible_lines;
+ gint scroll_offset;
+ gint scroll_offset_height;
- /*
- * now convert those back to alignments in the real visible area, but leave
- * enough space for an input character.
- */
- orig_yalign = yalign;
- xalign = xoffset / (gdouble)real_visible_rect.width;
- yalign = yoffset / (gdouble)(real_visible_rect.height + priv->cached_char_height);
+ visible_lines = screen.height / priv->cached_char_height;
+ max_scroll_offset = (visible_lines - 1) / 2;
+ scroll_offset = MIN (priv->scroll_offset, max_scroll_offset);
+ scroll_offset_height = priv->cached_char_height * scroll_offset;
- yvalue = iter_rect.y - (yalign * real_visible_rect.height);
- xvalue = iter_rect.x - (xalign * real_visible_rect.width);
+ if (scroll_offset_height > 0)
+ {
+ if (rect.y - scroll_offset_height < yvalue)
+ yvalue -= (scroll_offset_height - (rect.y - yvalue));
+ else if (_GDK_RECTANGLE_Y2 (&rect) + scroll_offset_height > yvalue + screen.height)
+ yvalue += (_GDK_RECTANGLE_Y2 (&rect) + scroll_offset_height) - (yvalue + screen.height);
+ }
+ }
- /*
- * FIXME:
- *
- * We need to understand better why this phenomina exists.
- *
- * 0.0 and 1.0 at visible boundaries creates some interesting artifacts.
- * This works around the phenomina at to ensure we are pinned inside the
- * visible area we care about. We probably need to take this into account
- * in the alignment calculations in a previous step.
- */
- if (orig_yalign == 1.0)
- yvalue += (priv->cached_char_height / 2);
- else if (orig_yalign == 0.0)
- yvalue -= (priv->cached_char_height / 2);
+ /* Horizontal alignment */
+ scroll_dest = current_x_scroll;
+ if (use_align)
+ {
+ scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign);
- frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (self));
+ /* if scroll_dest < screen.y, we move a negative increment (left),
+ * else a positive increment (right)
+ */
+ xvalue = scroll_dest - screen.x + screen_xoffset;
+ }
+ else
+ {
+ /* move minimum to get onscreen */
+ if (rect.x < screen.x)
+ {
+ scroll_dest = rect.x;
+ xvalue = scroll_dest - screen.x - screen_xoffset;
+ }
+ else if ((rect.x + rect.width) > screen_right)
+ {
+ scroll_dest = rect.x + rect.width;
+ xvalue = scroll_dest - screen_right + screen_xoffset;
+ }
+ }
+ xvalue += current_x_scroll;
if (animate_scroll)
{
+ GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (self));
guint duration_msec = LARGE_SCROLL_DURATION_MSEC;
gdouble difference;
gdouble page_size;
@@ -6748,7 +6796,7 @@ ide_source_view_scroll_to_iter (IdeSourceView *self,
IDE_ANIMATION_EASE_OUT_CUBIC,
duration_msec,
frame_clock,
- "value", xvalue,
+ "value", (double)xvalue,
NULL);
g_object_add_weak_pointer (G_OBJECT (priv->hadj_animation),
(gpointer *)&priv->hadj_animation);
@@ -6766,7 +6814,7 @@ ide_source_view_scroll_to_iter (IdeSourceView *self,
frame_clock,
(GDestroyNotify)ide_source_view__vadj_animation_completed,
self,
- "value", yvalue,
+ "value", (double)yvalue,
NULL);
g_object_add_weak_pointer (G_OBJECT (priv->vadj_animation),
(gpointer *)&priv->vadj_animation);
@@ -7177,7 +7225,7 @@ ide_source_view_rollback_search (IdeSourceView *self)
g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
- ide_source_view_scroll_mark_onscreen (self, priv->rubberband_mark);
+ ide_source_view_scroll_mark_onscreen (self, priv->rubberband_mark, TRUE, 0.5, 0.5);
}
GtkTextMark *
diff --git a/libide/ide-source-view.h b/libide/ide-source-view.h
index e3f4c5f..d9413bc 100644
--- a/libide/ide-source-view.h
+++ b/libide/ide-source-view.h
@@ -349,7 +349,10 @@ gboolean ide_source_view_move_mark_onscreen (IdeSource
gboolean ide_source_view_place_cursor_onscreen (IdeSourceView *self);
void ide_source_view_clear_search (IdeSourceView *self);
void ide_source_view_scroll_mark_onscreen (IdeSourceView *self,
- GtkTextMark *mark);
+ GtkTextMark *mark,
+ gboolean use_align,
+ gdouble alignx,
+ gdouble aligny);
void ide_source_view_scroll_to_mark (IdeSourceView *self,
GtkTextMark *mark,
gdouble
within_margin,
diff --git a/src/editor/gb-editor-frame.c b/src/editor/gb-editor-frame.c
index 59e07a0..874fd34 100644
--- a/src/editor/gb-editor-frame.c
+++ b/src/editor/gb-editor-frame.c
@@ -425,7 +425,10 @@ gb_editor_frame__search_key_press_event (GbEditorFrame *self,
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->source_view));
ide_source_view_set_rubberband_search (self->source_view, FALSE);
ide_source_view_scroll_mark_onscreen (self->source_view,
- gtk_text_buffer_get_insert (buffer));
+ gtk_text_buffer_get_insert (buffer),
+ TRUE,
+ 0.5,
+ 0.5);
/* finally we can focus the source view */
gtk_widget_grab_focus (GTK_WIDGET (self->source_view));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]