[gtkmm] writing a custom cellrenderer



Hello all,

I spend the bigger part of yesterday evening trying to write a custom 
cellrenderer for Gtk::TreeView but I didn't get it to work. I'm porting 
an application from plain C Gtk to C++ with gtkmm. In the original 
application I used the code from 
http://scentric.net/tutorial/sec-custom-cell-renderers.html, which was 
luckily exactly what I needed (in C). I thought that for a C++ version 
all I'd have to is derive my own class from Gtk::CellRenderer, override 
a few methods (that would have been declare pure virtual so that the 
compiler would point me to them) and that would be it. Turns out I was 
wrong.
I started by looking at 
http://www.gtkmm.org/docs/gtkmm-2.4/docs/reference/html/classGtk_1_1CellRend
erer.html. 
I didn't see anything there that indicated what functions I had to 
override to make my own so I just write a small class, overriding 
get_size(), _property_renderable() and render() and copied the code from 
my original C renderer to the corresponding functions. I had to massage 
it a bit to get it into C++ format and then it compiled. I used the 
add_column() method that takes a custom renderer and when all of that 
compiled I thought it'd work, but all I saw was a blank cell. So I 
looked at the implementation of the CellRendererText and -Pixbut in the 
gtkmm source and to my horror I found all the structs from the C version 
in there - the init thing and a sort of virtual vtable and all the 
things I hoped I would never have to bother with again when I switched 
to gtkmm. I'm still hoping that this is only because they wrap the C 
version and that it is possible to write one in pure C++.
Ok so sorry if this sounds frustrated (it's because I am), but here are 
a few questions that I have:

- What functions do I have to override and what do I have to implement 
to get a custom cellrenderer, a complete new one and not one that just 
wraps a C version? I think I'm missing two things: first, registering a 
custom property ('progress' in my case), and secondly registring the 
cellrenderer itself somewhere.
- All properties (like property_xalign()) have comments like "You rarely 
need to use properties because there are get_ and set_ methods for 
almost all of them.". But are there really? Where are they declared? How 
should I use those properties?
- What are the protected methods in CellRenderer (like get_size_vfunc() 
) used for? Should I override them?
- Why are there two versions of get_size? Is there an easy way to 
implement the one in terms of the other or should I write full 
implementations for both?

I've attached the code that I have so far. Some of it is commented out, 
that's what I was trying after I got everything to compile but when it 
didn't work. It's mostly copied from CellRendererText, but that one 
wraps the C version so it's not quite the same as what I try to do.
Thanks in advance.


cheers,

roel



#include <gtkmm.h>

#define FIXED_WIDTH   100
#define FIXED_HEIGHT  10

class CellRendererProgress : public Gtk::CellRenderer
{
	/*class CellRendererProgress_Class
	{
	public:
		const Glib::Class& init()
		{
			if (!gtype) {
				class_init_func_ = &CellRendererProgress_Class::class_init_functions;
				CppClassParent::CppObjectType::get_type();
			}
			return *this;
		}
		void class_init_function(void* g_class, void* class_data)
		{
			BaseClassType* const klass = static_cast<BaseClassType*>(g_class);
			CppClassParent::class_init_function(klass, class_data);
			klass->edited = &edited_callback;
		}
	};
	typedef CellRendererProgress_Class CppClassType;
	static CppClassType cellrendererprogress_class_;

	GType GetType()
	{
		cellrendererprogress_class_.init().get_type();
	}*/

	void render(const Glib::RefPtr<Gdk::Window>& window
			, Gtk::Widget& widget, const Gdk::Rectangle& background_area
			, const Gdk::Rectangle& cell_area
			, const Gdk::Rectangle& expose_area, Gtk::CellRendererState flags)
	{
		std::cout << "In render" << std::endl;
		//CellRendererProgress* cellprogress = CUSTOM_CELL_RENDERER_PROGRESS (cell);
		Gtk::StateType state;
		gint width, height;
		gint x_offset, y_offset;
		Glib::RefPtr<Gtk::Style> style = Gtk::RC::get_style(widget);

		get_size(widget, cell_area, x_offset, y_offset, width, height);

		if (widget.has_focus()) {
			state = Gtk::STATE_ACTIVE;
		} else {
			state = Gtk::STATE_NORMAL;
		}

		width  -= this->property_xpad() * 2;
		height -= this->property_ypad() * 2;

		style->paint_box(window,
			Gtk::STATE_NORMAL, Gtk::SHADOW_IN,
			cell_area, widget, "trough",
			cell_area.get_x() + x_offset + this->property_xpad(),
			cell_area.get_y() + y_offset + this->property_ypad(),
			width - 1, height - 1);
		
		if ( (int)(width * this->property_progress() ) > 0) {
			style->paint_box (window,
				state, Gtk::SHADOW_OUT,
				cell_area, widget, "bar",
				cell_area.get_x() + x_offset + this->property_xpad(),
				cell_area.get_y() + y_offset + this->property_ypad(),
				width * this->property_progress(),
				height - 1);
		}
	}

	void get_size(Gtk::Widget& widget, int& x_offset, int& y_offset
		, int& width, int& height) const
	{
		//get_size(widget, Gdk::Rec);
		gint calc_width;
		gint calc_height;
		
		calc_width  = (gint) const_cast<ProgressCellRenderer*>(this)->property_xpad() * 2 + FIXED_WIDTH;
		calc_height = (gint) const_cast<ProgressCellRenderer*>(this)->property_ypad() * 2 + FIXED_HEIGHT;
		
		if (width) {
			width = calc_width;
		}
		
		if (height) {
			height = calc_height;
		}
	}
	
	 void get_size(Gtk::Widget& widget, const Gdk::Rectangle& cell_area, int& x_offset, int& y_offset
	 		, int& width, int& height) const
	 {
		get_size(widget, x_offset, y_offset, width, height);
		
		gint calc_width;
		gint calc_height;
		
		calc_width  = (gint) const_cast<ProgressCellRenderer*>(this)->property_xpad() * 2 + FIXED_WIDTH;
		calc_height = (gint) const_cast<ProgressCellRenderer*>(this)->property_ypad() * 2 + FIXED_HEIGHT;

		if (x_offset) {
			x_offset = (int)const_cast<ProgressCellRenderer*>(this)->property_xalign() * (cell_area.get_width() - calc_width);
			x_offset = std::max(x_offset, 0);
		}
	
		if (y_offset) {
			y_offset = const_cast<ProgressCellRenderer*>(this)->property_yalign() * (cell_area.get_height() - calc_height);
			y_offset = std::max(y_offset, 0);
		}
	}
	
	virtual Glib::PropertyProxy_Base _property_renderable()
	{
		return property_progress();
	}
	
	Glib::PropertyProxy<int> property_progress()
	{
		return Glib::PropertyProxy<int>(this, "progress");
	}
};



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