Genie Cairo Example

uses 
        Gtk
        Cairo

class CairoSample : Gtk.Window 

        const private SIZE : int = 30

        construct ()
                self.title = "Cairo Genie Demo"
                self.destroy.connect (Gtk.main_quit)
                set_default_size (450, 550)
                create_widgets ()
        

        def private create_widgets () 
                var drawing_area = new DrawingArea ()
                drawing_area.draw.connect (on_draw)
                add (drawing_area)
        

        def private on_draw (da : Widget, ctx : Context) : bool
                ctx.set_source_rgb (0, 0, 0)

                ctx.set_line_width (SIZE / 4)
                ctx.set_tolerance (0.1)

                ctx.set_line_join (LineJoin.ROUND)
                dbl_arr : array of double = {SIZE / 4.0, SIZE / 4.0}
                ctx.set_dash ( dbl_arr, 0)
                stroke_shapes (ctx, 0, 0)

                ctx.set_dash (null, 0)
                stroke_shapes (ctx, 0, 3 * SIZE)

                ctx.set_line_join (LineJoin.BEVEL)
                stroke_shapes (ctx, 0, 6 * SIZE)

                ctx.set_line_join (LineJoin.MITER)
                stroke_shapes(ctx, 0, 9 * SIZE)

                fill_shapes (ctx, 0, 12 * SIZE)

                ctx.set_line_join (LineJoin.BEVEL)
                fill_shapes (ctx, 0, 15 * SIZE)
                ctx.set_source_rgb (1, 0, 0)
                stroke_shapes (ctx, 0, 15 * SIZE)

                return true
        

        def private stroke_shapes (ctx : Context, x : int, y : int) 
                self.draw_shapes (ctx, x, y, ctx.stroke)
        

        def private fill_shapes (ctx : Context, x : int, y : int) 
                self.draw_shapes (ctx, x, y, ctx.fill)
        

        delegate private DrawMethod ()

        def private draw_shapes (ctx : Context, x : int, y : int, draw_method : DrawMethod) 
                ctx.save ()

                ctx.new_path ()
                ctx.translate (x + SIZE, y + SIZE)
                bowtie (ctx)
                draw_method ()

                ctx.new_path ()
                ctx.translate (3 * SIZE, 0)
                square (ctx)
                draw_method ()

                ctx.new_path ()
                ctx.translate (3 * SIZE, 0)
                triangle (ctx)
                draw_method ()

                ctx.new_path ()
                ctx.translate (3 * SIZE, 0)
                inf (ctx)
                draw_method ()

                ctx.restore()
        

        def private triangle (ctx : Context) 
                ctx.move_to (SIZE, 0)
                ctx.rel_line_to (SIZE, 2 * SIZE)
                ctx.rel_line_to (-2 * SIZE, 0)
                ctx.close_path ()
        

        def private square (ctx : Context) 
                ctx.move_to (0, 0)
                ctx.rel_line_to (2 * SIZE, 0)
                ctx.rel_line_to (0, 2 * SIZE)
                ctx.rel_line_to (-2 * SIZE, 0)
                ctx.close_path ()
        

        def private bowtie (ctx : Context) 
                ctx.move_to (0, 0)
                ctx.rel_line_to (2 * SIZE, 2 * SIZE)
                ctx.rel_line_to (-2 * SIZE, 0)
                ctx.rel_line_to (2 * SIZE, -2 * SIZE)
                ctx.close_path ()
        

        def private inf (ctx : Context) 
                ctx.move_to (0, SIZE)
                ctx.rel_curve_to (0, SIZE, SIZE, SIZE, 2 * SIZE, 0)
                ctx.rel_curve_to (SIZE, -SIZE, 2 * SIZE, -SIZE, 2 * SIZE, 0)
                ctx.rel_curve_to (0, SIZE, -SIZE, SIZE, -2 * SIZE, 0)
                ctx.rel_curve_to (-SIZE, -SIZE, -2 * SIZE, -SIZE, -2 * SIZE, 0)
                ctx.close_path ()
        

init
        Gtk.init (ref args)

        var cairo_sample = new CairoSample ()
        cairo_sample.show_all ()

        Gtk.main ()

Compile and Run

$ valac --pkg gtk+-3.0 cairosample.gs 
$ ./cairosample 

cairo-demo.png

Shaped Window Example

uses
        Gtk
        Cairo

/**
 * This example creates a clock with the following features:
 * Shaped window -- Window is unbordered and transparent outside the clock
 * Events are only registered for the window on the hour dots or on the center
 * dot. When the mouse is "in" the window (on one of the dots) it will turn
 * green.
 * This helps you understand where the events are actually being registered
 * Clicking allows you to drag the clock.
 * There is currently no code in place to close the window, you must kill the
 * process manually. A Composited environment is required. The python code I
 * copied this from includes checks for this. In my laziness I left them out.
 */
class CairoShaped : Gtk.Window 

        // Are we inside the window?
        inside : bool = false

        /**
         * Just creating the window, setting things up
         */
         
        construct ()
                self.title = "Cairo Vala Demo"
                set_default_size (200, 200)

                // 'skip_taskbar_hint' determines whether the window gets an icon in
                // the taskbar / dock
                this.skip_taskbar_hint = true

                // Turn off the border decoration
                this.decorated = false
                this.app_paintable = true

                // Need to get the RGBA colormap or transparency doesn't work.
                set_colormap (this.screen.get_rgba_colormap ())

                // We need to register which events we are interested in
                add_events (Gdk.EventMask.BUTTON_PRESS_MASK)
                add_events (Gdk.EventMask.ENTER_NOTIFY_MASK)
                add_events (Gdk.EventMask.LEAVE_NOTIFY_MASK)

                // Connecting some events, 'queue_draw()' redraws the window.
                // 'begin_move_drag()' sets up the window drag
                self.enter_notify_event.connect( enter_event )
                self.leave_notify_event.connect ( leave_event )
                self.button_press_event.connect ( handle_btn_press )
                

                // The expose event is what is called when we need to draw the window
                this.expose_event.connect (on_expose)

                this.destroy.connect (Gtk.main_quit)
        
        def handle_btn_press( e : Gdk.EventButton ) : bool
                begin_move_drag ((int) e.button, (int) e.x_root, (int) e.y_root, e.time)
                return true
                
        def leave_event() : bool
                self.inside = false
                self.queue_draw () 
                return true
        
        def enter_event() : bool
                self.inside = true
                self.queue_draw () 
                return true

        /**
         * Actual drawing takes place within this method
         */
        def private on_expose (da : Widget, event : Gdk.EventExpose) : bool
                // Get a cairo context for our window
                var ctx = Gdk.cairo_create (da.window)

                // This makes the current color transparent (a = 0.0)
                ctx.set_source_rgba (1.0, 1.0, 1.0, 0.0)

                // Paint the entire window transparent to start with.
                ctx.set_operator (Cairo.Operator.SOURCE)
                ctx.paint ()

                // If we wanted to allow scaling we could do some calculation here
                radius : float = 100

                // This creates a radial gradient. c() is just a helper method to
                // convert from 0 - 255 scale to 0.0 - 1.0 scale.
                var p = new Cairo.Pattern.radial (100, 100, 0, 100, 100, 100)
                if inside 
                        p.add_color_stop_rgba (0.0, c (10), c (190), c (10), 1.0)
                        p.add_color_stop_rgba (0.8, c (10), c (190), c (10), 0.7)
                        p.add_color_stop_rgba (1.0, c (10), c (190), c (10), 0.5)
                 else 
                        p.add_color_stop_rgba (0.0, c (10), c (10), c (190), 1.0)
                        p.add_color_stop_rgba (0.8, c (10), c (10), c (190), 0.7)
                        p.add_color_stop_rgba (1.0, c (10), c (10), c (190), 0.5)
                

                // Set the gradient as our source and paint a circle.
                ctx.set_source (p)
                ctx.arc (100, 100, radius, 0, 2.0 * 3.14)
                ctx.fill ()
                ctx.stroke ()

                // This chooses the color for the hour dots
                if inside
                        ctx.set_source_rgba (0.0, 0.2, 0.6, 0.8)
                 else 
                        ctx.set_source_rgba (c (226), c (119), c (214), 0.8)
                

                // Draw the 12 hour dots.
                for var i = 0 to 12 
                        ctx.arc (100 + 90.0 * Math.cos (2.0 * 3.14 * (i / 12.0)),
                                         100 + 90.0 * Math.sin (2.0 * 3.14 * (i / 12.0)),
                                         5, 0, 2.0 * 3.14)
                        ctx.fill ()
                        ctx.stroke ()
                

                // This is the math to draw the hands.
                // Nothing overly useful in this section
                ctx.move_to (100, 100)
                ctx.set_source_rgba (0, 0, 0, 0.8)

                var t = Time.local (time_t ())
                hour : int = t.hour
                minutes : int = t.minute
                seconds :int = t.second
                per_hour : double = (2 * 3.14) / 12
                dh : double = (hour * per_hour) + ((per_hour / 60) * minutes)
                dh += 2 * 3.14 / 4
                ctx.set_line_width (0.05 * radius)
                ctx.rel_line_to (-0.5 * radius * Math.cos (dh), -0.5 * radius * Math.sin (dh))
                ctx.move_to (100, 100)
                per_minute : double  = (2 * 3.14) / 60
                dm : double = minutes * per_minute
                dm += 2 * 3.14 / 4
                ctx.rel_line_to (-0.9 * radius * Math.cos (dm), -0.9 * radius * Math.sin (dm))
                ctx.move_to (100, 100)
                per_second :double = (2 * 3.14) / 60
                ds :double = seconds * per_second
                ds += 2 * 3.14 / 4
                ctx.rel_line_to (-0.9 * radius * Math.cos (ds), -0.9 * radius * Math.sin (ds))
                ctx.stroke ()

                // Drawing the center dot
                ctx.set_source_rgba (c (124), c (32), c (113), 0.7)

                ctx.arc (100, 100, 0.1 * radius, 0, 2.0 * 3.14)
                ctx.fill ()
                ctx.stroke ()

                // This is possibly the most important bit.
                // Here is where we create the mask to shape the window
                // And decide what areas will receive events and which areas
                // Will let events pass through to the windows below.

                // First create a pixmap the size of the window
                var px = new Gdk.Pixmap (null, 200, 200, 1)
                // Get a context for it
                var pmcr = Gdk.cairo_create (px)

                // Initially we want to blank out everything in transparent as we
                // Did initially on the ctx context
                pmcr.set_source_rgba (1.0, 1.0, 1.0, 0.0)
                pmcr.set_operator (Cairo.Operator.SOURCE)
                pmcr.paint ()

                // Now the areas that should receive events need to be made opaque
                pmcr.set_source_rgba (0, 0, 0, 1)

                // Here we copy the motions to draw the middle dots and the hour dots.
                // This is mostly to demonstrate that you can make this any shape you
                // want.
                pmcr.arc (100, 100, 10, 0, 2.0 * 3.14)
                pmcr.fill ()
                pmcr.stroke ()
                for var i = 0 to 12             // ATTENTION -> divide by zero ?
                        pmcr.arc (100 + 90.0 * Math.cos (2.0 * 3.14 * (i / 12.0)),
                                          100 + 90.0 * Math.sin (2.0 * 3.14 * (i / 12.0)),
                                          5, 0, 2.0 * 3.14)
                        pmcr.fill ()
                        pmcr.stroke ()
                

                // This sets the mask. Note that we have to cast to a Gdk.Bitmap*,
                // it won't compile without that bit.
                input_shape_combine_mask ((Gdk.Bitmap*) px, 0, 0)
                return true
        

        def private c (val : int) : double
                return val / 255.0
        
        def updatedraw() : bool
                self.queue_draw()
                return true

init
        Gtk.init (ref args)

        var cairo_sample = new CairoShaped ()
        cairo_sample.show_all ()

        // Just a timeout to update once a second.
        Timeout.add_seconds (1, cairo_sample.updatedraw )

        Gtk.main ()

Compile and Run

$ valac --pkg gtk+-2.0 --pkg cairo --pkg gdk-2.0 cairo-shaped.gs
$ ./cairo-shaped


More Genie Examples

Projects/Genie/CairoSample (last edited 2014-03-17 21:53:56 by AlThomas)