Search code examples
c++gtkgtkmm3

Gtkmm scroll_to() purpose


I'm wondering about this member-function's scroll_to(TextBuffer::iterator& iter, double within_margin = 0) parameter within_margin. The API says this:

The effective screen for purposes of this function is reduced by a margin of size within_margin.
...
Parameters
within_margin margin as a [0.0,0.5] fraction of screen size.

I just don't get it. What and when does this parameter modifies the behaviour? Every langugage-binding of Gtk includes the same description. I've written a small application, so you can change the passed argument to the parameter yourself.

#include <gtkmm.h>
#include <iostream>
#include <string>
using namespace std;

Gtk::TextView* text_view;
void on_add_button_clicked();
void on_scroll_button_clicked();

int main(int argc, char* argv[]) {
    Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
    Gtk::Window window;
    Glib::RefPtr<Gdk::Monitor> primary_monitor = window.get_screen()->get_display()->get_primary_monitor();
    Gdk::Rectangle monitor_size;
    primary_monitor->get_geometry(monitor_size);
    // half-size of primary-monitor
    int width = monitor_size.get_width() / 2;
    int height = monitor_size.get_height() / 2;

    window.set_default_size(width, height);
    window.set_title(__FILE__);

    Gtk::Grid grid;
    grid.set_row_spacing(5);
    grid.set_column_spacing(5);
    
    Gtk::ScrolledWindow scroll_window;
    text_view = new Gtk::TextView();
    text_view->set_editable(true);
    scroll_window.add(*text_view);
    scroll_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
    scroll_window.set_hexpand(true);
    scroll_window.set_vexpand(true);
    Glib::RefPtr<Gtk::TextBuffer> text_buffer = text_view->get_buffer();
    text_buffer->set_text("Hello!\n");
    text_view->set_buffer(text_buffer);
    grid.attach(scroll_window, 0, 0, 2, 2);
    

    Gtk::Button add_button("add text");
    add_button.signal_clicked().connect(sigc::ptr_fun(&on_add_button_clicked));
    grid.attach_next_to(add_button, scroll_window, Gtk::POS_BOTTOM, 1, 1);

    Gtk::Button scroll_button("scroll to somewhere");
    scroll_button.signal_clicked().connect(sigc::ptr_fun(&on_scroll_button_clicked));
    grid.attach_next_to(scroll_button, add_button, Gtk::POS_RIGHT, 1, 1);

    window.add(grid);
    window.show_all();

    return app->run(window);
}


void on_add_button_clicked() {
    Glib::RefPtr<Gtk::TextBuffer> text_buffer = text_view->get_buffer();
    for (int i = 0; i != 100; ++i) {
        text_buffer->insert_at_cursor("foobar\n");
    }
}

void on_scroll_button_clicked() {
    Glib::RefPtr<Gtk::TextBuffer> text_buffer = text_view->get_buffer();
    Gtk::TextBuffer::iterator it = text_buffer->end();
    text_view->scroll_to(it, 0.49);
}

You can compile the code with g++ -o scroll scroll.cpp -Wall -pedantic-errors `pkg-config gtkmm-3.0 --cflags --libs` .

Thank you


Solution

  • If margin is 0, then scroll_to() is free to put the target anywhere in the screen. If margin is 0.45, for example, then scroll_to() will put the target in the middle 10% of the screen, if possible.

    The reason you don't see this in your example, is because you are scrolling to the end iterator, and it's not possible to scroll view so that the end of the text is displayed in the middle of the screen. (Some text views include extra space after the text in order to make this possible; Gtk::TextView doesn't.)