demonstrate automatic scrolling

This commit is contained in:
Matthias Clasen
2006-08-26 01:17:17 +00:00
parent 4ab827e20a
commit 72e4e08602
5 changed files with 223 additions and 8 deletions

View File

@ -1,5 +1,9 @@
2006-08-25 Matthias Clasen <mclasen@redhat.com> 2006-08-25 Matthias Clasen <mclasen@redhat.com>
* demos/gtk-demo/Makefile.am:
* demos/gtk-demo/textscroll.c: Add an example of automatic
scrolling, thanks to Yevgen Muntyan. (#351206)
* gtk/gtkmodules.c (find_module): Use local binding when * gtk/gtkmodules.c (find_module): Use local binding when
loading modules. (#351868) loading modules. (#351868)

View File

@ -31,6 +31,7 @@ demos = \
sizegroup.c \ sizegroup.c \
stock_browser.c \ stock_browser.c \
textview.c \ textview.c \
textscroll.c \
tree_store.c \ tree_store.c \
ui_manager.c ui_manager.c

202
demos/gtk-demo/textscroll.c Normal file
View File

@ -0,0 +1,202 @@
/* Text Widget/Automatic scrolling
*
* This example demonstrates how to use the gravity of
* GtkTextMarks to keep a text view scrolled to the bottom
* while appending text.
*/
#include <gtk/gtk.h>
#include "demo-common.h"
/* Scroll to the end of the buffer.
*/
static gboolean
scroll_to_end (GtkTextView *textview)
{
GtkTextBuffer *buffer;
GtkTextIter iter;
GtkTextMark *mark;
char *spaces;
static int count;
buffer = gtk_text_view_get_buffer (textview);
/* Get "end" mark. It's located at the end of buffer because
* of right gravity
*/
mark = gtk_text_buffer_get_mark (buffer, "end");
gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
/* and insert some text at its position, the iter will be
* revalidated after insertion to point to the end of inserted text
*/
spaces = g_strnfill (count++, ' ');
gtk_text_buffer_insert (buffer, &iter, "\n", -1);
gtk_text_buffer_insert (buffer, &iter, spaces, -1);
gtk_text_buffer_insert (buffer, &iter,
"Scroll to end scroll to end scroll "
"to end scroll to end ",
-1);
g_free (spaces);
/* Now scroll the end mark onscreen.
*/
gtk_text_view_scroll_mark_onscreen (textview, mark);
/* Emulate typewriter behavior, shift to the left if we
* are far enough to the right.
*/
if (count > 150)
count = 0;
return TRUE;
}
/* Scroll to the bottom of the buffer.
*/
static gboolean
scroll_to_bottom (GtkTextView *textview)
{
GtkTextBuffer *buffer;
GtkTextIter iter;
GtkTextMark *mark;
char *spaces;
static int count;
buffer = gtk_text_view_get_buffer (textview);
/* Get end iterator */
gtk_text_buffer_get_end_iter (buffer, &iter);
/* and insert some text at it, the iter will be revalidated
* after insertion to point to the end of inserted text
*/
spaces = g_strnfill (count++, ' ');
gtk_text_buffer_insert (buffer, &iter, "\n", -1);
gtk_text_buffer_insert (buffer, &iter, spaces, -1);
gtk_text_buffer_insert (buffer, &iter,
"Scroll to bottom scroll to bottom scroll "
"to bottom scroll to bottom",
-1);
g_free (spaces);
/* Move the iterator to the beginning of line, so we don't scroll
* in horizontal direction
*/
gtk_text_iter_set_line_offset (&iter, 0);
/* and place the mark at iter. the mark will stay there after we
* insert some text at the end because it has right gravity.
*/
mark = gtk_text_buffer_get_mark (buffer, "scroll");
gtk_text_buffer_move_mark (buffer, mark, &iter);
/* Scroll the mark onscreen.
*/
gtk_text_view_scroll_mark_onscreen (textview, mark);
/* Shift text back if we got enough to the right.
*/
if (count > 40)
count = 0;
return TRUE;
}
static guint
setup_scroll (GtkTextView *textview,
gboolean to_end)
{
GtkTextBuffer *buffer;
GtkTextIter iter;
GtkTextMark *mark;
buffer = gtk_text_view_get_buffer (textview);
gtk_text_buffer_get_end_iter (buffer, &iter);
if (to_end)
{
/* If we want to scroll to the end, including horizontal scrolling,
* then we just create a mark with right gravity at the end of the
* buffer. It will stay at the end unless explicitely moved with
* gtk_text_buffer_move_mark.
*/
gtk_text_buffer_create_mark (buffer, "end", &iter, FALSE);
/* Add scrolling timeout. */
return g_timeout_add (50, (GSourceFunc) scroll_to_end, textview);
}
else
{
/* If we want to scroll to the bottom, but not scroll horizontally,
* then an end mark won't do the job. Just create a mark so we can
* use it with gtk_text_view_scroll_mark_onscreen, we'll position it
* explicitely when needed. Use left gravity so the mark stays where
* we put it after inserting new text.
*/
gtk_text_buffer_create_mark (buffer, "scroll", &iter, TRUE);
/* Add scrolling timeout. */
return g_timeout_add (100, (GSourceFunc) scroll_to_bottom, textview);
}
}
static void
remove_timeout (GtkWidget *window,
gpointer timeout)
{
g_source_remove (GPOINTER_TO_UINT (timeout));
}
static void
create_text_view (GtkWidget *hbox,
gboolean to_end)
{
GtkWidget *swindow;
GtkWidget *textview;
guint timeout;
swindow = gtk_scrolled_window_new (NULL, NULL);
gtk_box_pack_start_defaults (GTK_BOX (hbox), swindow);
textview = gtk_text_view_new ();
gtk_container_add (GTK_CONTAINER (swindow), textview);
timeout = setup_scroll (GTK_TEXT_VIEW (textview), to_end);
/* Remove the timeout in destroy handler, so we don't try to
* scroll destroyed widget.
*/
g_signal_connect (textview, "destroy",
G_CALLBACK (remove_timeout),
GUINT_TO_POINTER (timeout));
}
GtkWidget *
do_textscroll (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *hbox;
GtkWidget *swindow;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
hbox = gtk_hbox_new (TRUE, 6);
gtk_container_add (GTK_CONTAINER (window), hbox);
create_text_view (hbox, TRUE);
create_text_view (hbox, FALSE);
}
if (!GTK_WIDGET_VISIBLE (window))
gtk_widget_show_all (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@ -1,3 +1,8 @@
2006-08-25 Matthias Clasen <mclasen@redhat.com>
* gtk/question_index.sgml: Rewrite the answer for
automatic scrolling.
2006-08-17 Matthias Clasen <mclasen@redhat.com> 2006-08-17 Matthias Clasen <mclasen@redhat.com>
* === Released 2.10.2 === * === Released 2.10.2 ===

View File

@ -757,18 +757,21 @@ How do I make a text view scroll to the end of the buffer automatically ?
<answer> <answer>
<para> <para>
The "insert" <link linkend="GtkTextMark">mark</link> marks the insertion point A good way to keep a text buffer scrolled to the end is to place a
where gtk_text_buffer_insert() inserts new text into the buffer. The text is inserted <link linkend="GtkTextMark">mark</link> at the end of the buffer, and
<emphasis>before</emphasis> the "insert" mark, so that it generally stays give it right gravity. The gravity has the effect that text inserted
at the end of the buffer. If it gets explicitly moved to some other position, at the mark gets inserted <emphasis>before</emphasis>, keeping the mark
e.g. when the user selects some text, use gtk_text_buffer_move_mark() to set it to at the end.
the desired location before inserting more text. The "insert" mark of a buffer can be
obtained with gtk_text_buffer_get_insert().
</para> </para>
<para> <para>
To ensure that the end of the buffer remains visible, use To ensure that the end of the buffer remains visible, use
gtk_text_view_scroll_to_mark() to scroll to the "insert" mark after inserting new text. gtk_text_view_scroll_to_mark() to scroll to the mark after
inserting new text.
</para>
<para>
The gtk-demo application contains an example of this technique.
</para> </para>
</answer> </answer>
</qandaentry> </qandaentry>