Using librsvg library and cairo graphics with vala

Recently, I was doing some research regarding possibilities of chess pieces drawing on a gtk+ widget. Taking out the most of the ideas from the glchess source code I have written a little application with vala, which shows a preview of chess pieces, found on wikipedia’s chess piece site or here on wikimedia and I would like to memorize it for me and share it with you. Especially, I liked the Maurizio Monge chess piece set.

So, in the following code snippet is demonstrated how to:

  • draw something in gtk+-3.0 within a widget named DrawingArea
  • access and read svg vector graphic files with a librsvg library and to render them afterwards with cairo
  • proceed mouse wheel and mouse click events using gdk and gtk+ respectively
  • transfer a svg file to a temporary created surface in memory for a later accelerated rendering on the widget

So, there are snapshots:



And the code below:

class PiecePreviewWindow : Gtk.Window
{
	public PiecePreviewWindow( ) {
		set_title( "Piece Preview" );
		add( new PieceView( ) );
		show_all( );
	}

	public override void destroy( ) {
		Gtk.main_quit( );
	}

	public static int main( string[] args ) {
		Gtk.init( ref args );
		new PiecePreviewWindow( );
		Gtk.main( );

		return 0;
	}
}

class PieceView : Gtk.DrawingArea
{
	public PieceView( ) {
		set_size_request( 400, 400 );
		add_events( Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.SCROLL_MASK );

		temp_surface = new Cairo.ImageSurface( Cairo.Format.ARGB32, 12 * square_size, square_size );

		string format = "./pieces/Maurizio Monge/Chess_Maurizio_Monge_Fantasy_%s%s.svg";
		string[] color = { "b", "w" };
		string[] piece = { "p", "r", "n", "b", "q", "k" };

		for( int c = 0; c < 2; c ++ ) {
			for(int p = 0; p < 6; p ++ ) {
				render_piece( format.printf( color[c], piece[p] ), 6 * c + p );
			}
		}
	}

	public override bool draw( Cairo.Context cr ) {
		cr.set_source_rgb( 0.5, 0.5, 0.5 );
		cr.rectangle( 0.0, 0.0, 400.0, 400.0 );
		cr.fill( );

		cr.scale( 400.0 / square_size, 400.0 / square_size );
		cr.set_source_surface( temp_surface, -offset * square_size, 0 );
		cr.rectangle( 0, 0, square_size, square_size );
		cr.clip( );
		cr.paint( );

		return false;
	}

	void render_piece( string file_name, int offset ) {
		Rsvg.Handle handle;
		try {
			handle = new Rsvg.Handle.from_file( file_name );
		} catch( Error e ) {
			stderr.printf( "can not open svg file\n" );
			return;
		}

		temp_cr = new Cairo.Context( temp_surface );
		temp_cr.save( );
		temp_cr.translate( square_size * offset, 0 );
		temp_cr.scale( (double) square_size / handle.width, (double) square_size / handle.height );
		handle.render_cairo( temp_cr );
		temp_cr.restore( );
	}

	public override bool button_press_event( Gdk.EventButton event ) {
		if( event.button  == 1 ) {
		 	change_piece( true );
		} else if( event.button == 3 ) {
			change_piece( false );
		} else
			return false;

		return true;
	}

	public override bool scroll_event( Gdk.EventScroll event ) {
		if( event.direction == Gdk.ScrollDirection.UP ) {
			change_piece( true );
		} else if( event.direction == Gdk.ScrollDirection.DOWN ) {
			change_piece( false );
		} else
			return false;
		return true;
	}

	private void change_piece( bool forward ) {
		if( forward ) offset ++;
		else offset --;

		if( offset < 0 ) offset = 11; 		if( offset > 11) offset = 0;

		queue_draw( );
	}

	private Cairo.ImageSurface temp_surface;
	private Cairo.Context temp_cr;
	private int square_size = 500;
	private int offset;
}

All this can be compiled with

# valac gtk-svg.vala --pkg librsvg-2.0 --pkg gtk+-3.0
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s