[gtkmm] ScrolledWindow doesn't scroll a DrawingArea



I can't seem to find a sufficiently complicated example of
ScrolledWindow to help me with this problem.  I'm trying to create a
ScrolledWindow that is initially centered on a DrawingArea of unknown
size (i.e. may be larger or smaller than the ScrolledWindow).  However,
the scrollbars won't allow me to scroll, despite the fact that the
accessors for the associated Adjustments seem to indicate that their
entire range is not currently visible within one page size.

If I set the ScrolledWindow policy to POLICY_AUTOMATIC, the scrollbars
do not appear, despite the fact that the entire Pixbuf is clearly not
visible at once.

I'm new to GUI design, so most of this code is borrowed from examples
and mailing lists.  In fact, I found a gtk+ example that does precisely
what I want, and converted it to gtkmm, but the scrollbars still fail.

Thank you in advance for your consideration.

-- 
Nik A. Melchior              Washington University

GPG Key Fingerprint (see http://www.gnupg.org/):
F824 BB7F 5424 04D0 0EBF  2AE7 7BB9 533C 380A 0462
//FIXME: copyright notice

// $Id$

#ifndef LOCALIZE_VIEWER_H
#define LOCALIZE_VIEWER_H

#define UPDATE_DELAY 50

#include <gtkmm.h>

class LocalizeViewer : public Gtk::Window {
public:
	LocalizeViewer (void);
	virtual ~LocalizeViewer (void);

private:
	// Load the map file and create an image of the map,
	// and set map_buf_{width,height}.
	// Returns true if it succeeds.
	bool create_map_pixbuf (void);

	void adjust_scrollbars (void);
	
	// signal handlers
	void on_close_clicked (void);
	bool on_drawing_area_expose (GdkEventExpose *event);
	bool on_timeout (void);

	Gtk::HBox           top_hbox;

	Gtk::ScrolledWindow       scroll_pane;
	Gtk::DrawingArea          drawing_area;
	Glib::RefPtr<Gdk::Pixbuf> pixbuf_ref, map_pixbuf_ref;
	guint                     map_buf_width, map_buf_height;
	SigC::Connection          timeout_connection;

	Gtk::Alignment      close_button_aligned;
	Gtk::Button         close_button;
};

#endif //header guard
//FIXME: copyright notice

// $Id$

#include <gdkmm.h>
#include <iostream>

#include "localize_viewer.h"

LocalizeViewer::LocalizeViewer (void) :
	map_buf_width(0),
	map_buf_height(0),
	close_button_aligned(Gtk::ALIGN_CENTER, Gtk::ALIGN_BOTTOM, 0.0, 0.0),
	close_button(Gtk::Stock::QUIT)
{
	set_title("SMRT LocalizeViewer");
	set_border_width(10);

	//FIXME: check returns of following 2 lines
	create_map_pixbuf();
	pixbuf_ref = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB,
									 FALSE,               // has_alpha
									 8,                   // bits/pixel
									 map_buf_width, map_buf_height);
	
	// policy can also be POLICY_AUTOMATIC; first horizontal, then vertical
	scroll_pane.set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS);
	scroll_pane.set_border_width(10);
	scroll_pane.set_size_request(200, 200);

	// register callbacks
	drawing_area.signal_expose_event().connect(
		                slot(*this, &LocalizeViewer::on_drawing_area_expose));
	timeout_connection = Glib::signal_timeout().connect(
						slot(*this, &LocalizeViewer::on_timeout), UPDATE_DELAY);
	close_button.signal_clicked().connect(
						slot(*this, &LocalizeViewer::on_close_clicked));

	// place all the widgets
	scroll_pane.add(drawing_area);   // creates viewport for me
	adjust_scrollbars();
	top_hbox.pack_start(scroll_pane);
	close_button_aligned.add(close_button);
	top_hbox.pack_end(close_button_aligned);
	add(top_hbox);
	show_all_children();

	set_size_request(300, 300);
}

LocalizeViewer::~LocalizeViewer (void)
{
	// should probably happen anyway
	timeout_connection.disconnect();
}

bool
LocalizeViewer::create_map_pixbuf (void)
{
	if (map_pixbuf_ref)
		map_pixbuf_ref->unreference();

	map_pixbuf_ref = Gdk::Pixbuf::create_from_file("background.jpg");
	/* FIXME: eventually, something like this:
	 * create_from_data((guint8 *)map_rgb_data,
	 *                  Gdk::COLORSPACE_RGB,
	 *                  FALSE,                  // has_alpha
	 *                  8,                      // bits per pixel
	 *                  map_width,
	 *                  map_height,
	 *                  rowstride,              // distance in bytes b/w rows
	 *                  destroy_slot);          // used to free data when
	 *                                    // pixbuf's refcount drops to 0
	 */
	map_buf_width = map_pixbuf_ref->get_width();
	map_buf_height = map_pixbuf_ref->get_height();
	std::cout << "map_buf size: (" << map_buf_width << ", " << map_buf_height
	          << ")." << std::endl;
	
	return true;
}

void
LocalizeViewer::on_close_clicked (void)
{
	hide();
}

bool
LocalizeViewer::on_drawing_area_expose (GdkEventExpose *event)
{
	gint rowstride = pixbuf_ref->get_rowstride();
	const guchar * pixels = pixbuf_ref->get_pixels()
		                    + (rowstride * event->area.y) + (event->area.x * 3);
	Glib::RefPtr<Gdk::Window> window_ref = drawing_area.get_window();
	Glib::RefPtr<Gdk::GC> gc_ref = drawing_area.get_style()->get_black_gc();

	window_ref->draw_rgb_image(gc_ref,
							   0, 0,
							   map_buf_width, map_buf_height,
							   Gdk::RGB_DITHER_NORMAL,
							   pixels,
							   rowstride);

	return true;
}

void
LocalizeViewer::adjust_scrollbars (void)
{
	Gtk::Adjustment *h_adj = scroll_pane.get_hadjustment();
	Gtk::Adjustment *v_adj = scroll_pane.get_vadjustment();
	int start_x = (int) (((float)scroll_pane.get_width() - map_buf_width)
						 / -2.0);
	int start_y = (int) (((float)scroll_pane.get_height() - map_buf_height)
						 / -2.0);

	h_adj->set_lower(MIN(start_x, 0));
	h_adj->set_upper(MAX(map_buf_width, map_buf_width - start_x));
	h_adj->set_page_size(scroll_pane.get_width());
	h_adj->changed();
	h_adj->set_value((h_adj->get_upper() - h_adj->get_lower()
					 - scroll_pane.get_width()) / 2 + h_adj->get_lower());
	h_adj->value_changed();

	v_adj->set_lower(MIN(start_y, 0));
	v_adj->set_upper(MAX(map_buf_height, map_buf_height - start_y));
	v_adj->set_page_size(scroll_pane.get_height());
	v_adj->changed();
	v_adj->set_value((v_adj->get_upper() - v_adj->get_lower()
					 - scroll_pane.get_height()) / 2 + v_adj->get_lower());
	v_adj->value_changed();

	std::cout << "Start pos: (" << start_x << ", " << start_y << ").  ";
	std::cout << "Scrollbar pos: (" << h_adj->get_value() << ", "
	          << v_adj->get_value() << ") of (" << h_adj->get_lower()
			  << ", " << v_adj->get_lower() << ") to ("
			  << h_adj->get_upper() << ", " << v_adj->get_upper()
			  << ")." << std::endl;
}

bool
LocalizeViewer::on_timeout()
{
	// This copies an unaltered version of the map
	// into the pixbuf_ref, which is the one actually displayed.
	map_pixbuf_ref->copy_area(0, 0, map_buf_width, map_buf_height,
							  pixbuf_ref, 0, 0);

	drawing_area.queue_draw();
	return true;
}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]