Drawing with Cairo

In this part of the Visual Basic GTK# tutorial, we will do some painting with the Cairo library.

Cairo is a library for creating 2D vector graphics. We can use it to draw our own widgets, charts or various effects or animations.

Colors

In the first example, we will work with colors. A color is an object representing a combination of Red, Green, and Blue (RGB) intensity values. Cairo valid RGB values are in the range 0 to 1.

' ZetCode Mono Visual Basic GTK# tutorial
'
' This program draws three rectangles.
' The interiors are filled with
' different colors.
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com


Imports Gtk
 
Public Class GtkVBApp
    Inherits Window
       
    Public Sub New
        
        MyBase.New("Colors")
        
        Me.InitUI

        Me.SetDefaultSize(360, 100)
        Me.SetPosition(WindowPosition.Center)
        AddHandler Me.DeleteEvent, AddressOf Me.OnDelete

        Me.ShowAll 
        
    End Sub
    
    Private Sub InitUI
        
        Dim darea As New DrawingArea
        AddHandler darea.ExposeEvent, AddressOf Me.OnExpose
        Me.Add(darea)

    End Sub
    
    Private Sub OnExpose(ByVal sender As Object, ByVal args As ExposeEventArgs)
    
        Dim cc As Cairo.Context = Gdk.CairoHelper.Create(sender.GdkWindow)
                
        Me.DrawColors(cc)
    
        Dim disposeTarget As IDisposable = CType(cc.Target, IDisposable)
        disposeTarget.Dispose
        
        Dim disposeContext As IDisposable = CType(cc, IDisposable)
        disposeContext.Dispose

    End Sub
    
    Private Sub DrawColors(ByVal cc As Cairo.Context)
    
        cc.SetSourceRGB(0.2, 0.23, 0.9)
        cc.Rectangle(10, 15, 90, 60)
        cc.Fill
         
        cc.SetSourceRGB(0.9, 0.1, 0.1)
        cc.Rectangle(130, 15, 90, 60)
        cc.Fill

        cc.SetSourceRGB(0.4, 0.9, 0.4)
        cc.Rectangle(250, 15, 90, 60)
        cc.Fill    
    
    End Sub
    
    
    Private Sub OnDelete(ByVal sender As Object, _
            ByVal args As DeleteEventArgs)
        Application.Quit
    End Sub

    Public Shared Sub Main
    
        Application.Init
        Dim app As New GtkVBApp
        Application.Run
        
    End Sub
 
End Class

In our example, we will draw three rectangles and fill them with three different colors.

vbnc -r:/usr/lib/mono/gtk-sharp-2.0/gtk-sharp.dll 
 -r:/usr/lib/mono/gtk-sharp-2.0/gdk-sharp.dll
 -r:/usr/lib/mono/2.0/Mono.Cairo.dll colors.vb

Here is how we compile the example.

Dim darea As New DrawingArea

We will be doing our drawing operations on the DrawingArea widget.

AddHandler darea.ExposeEvent, AddressOf Me.OnExpose

All drawing is done in a method that we plug into the ExposeEvent.

Dim cc As Cairo.Context = Gdk.CairoHelper.Create(sender.GdkWindow)

We create the Cairo.Context object from the GdkWindow of the drawing area. The context is an object onto which we do all our drawings.

Me.DrawColors(cc)

The actual drawing is delegated to the DrawColors method.

Dim disposeTarget As IDisposable = CType(cc.Target, IDisposable)
disposeTarget.Dispose

Dim disposeContext As IDisposable = CType(cc, IDisposable)
disposeContext.Dispose

Here we dispose the resources that were used during the drawing process.

cc.SetSourceRGB(0.2, 0.23, 0.9)

The SetSourceRGB method sets a color for the cairo context. The three parameters of the method are the color intensity values.

cc.Rectangle(10, 15, 90, 60)

We draw a rectangle. The first two parameters are the x, y coordinates of the top left corner of the rectangle. The last two parameters are the width and height of the rectangle.

cc.Fill

We fill the inside of the rectangle with the current color.

Colors
Figure: Colors

Basic shapes

The next example draws some basic shapes onto the window.

' ZetCode Mono Visual Basic GTK# tutorial
'
' This program draws basic shapes
' available in Cairo
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com


Imports Gtk
 
Public Class GtkVBApp
    Inherits Window
       
    Public Sub New
        
        MyBase.New("Basic Shapes")
        
        Me.InitUI

        Me.SetDefaultSize(400, 250)
        Me.SetPosition(WindowPosition.Center)
        AddHandler Me.DeleteEvent, AddressOf Me.OnDelete

        Me.ShowAll
        
    End Sub
    
    Private Sub InitUI
        
        Dim darea As New DrawingArea
        AddHandler darea.ExposeEvent, AddressOf Me.OnExpose
        Me.Add(darea)

    End Sub
    
    Private Sub OnExpose(ByVal sender As Object, ByVal args As ExposeEventArgs)
    
        Dim cc As Cairo.Context = Gdk.CairoHelper.Create(sender.GdkWindow)
                
        Me.DrawShapes(cc)
    
        Dim disposeTarget As IDisposable = CType(cc.Target, IDisposable)
        disposeTarget.Dispose
        
        Dim disposeContext As IDisposable = CType(cc, IDisposable)
        disposeContext.Dispose

    End Sub
    
    Private Sub DrawShapes(ByVal cc As Cairo.Context)
        
        cc.SetSourceRGB(0.5, 0.5, 0.5)

        cc.Rectangle(20, 20, 120, 80)
        cc.Rectangle(180, 20, 80, 80)
        cc.Fill

        cc.Arc(330, 60, 40, 0, 2*Math.PI)
        cc.Fill
        
        cc.Arc(90, 160, 40, Math.PI/4, Math.PI)
        cc.ClosePath
        cc.Fill

        cc.Translate(220, 180)
        cc.Scale(1, 0.7)
        cc.Arc(0, 0, 50, 0, 2*Math.PI)
        cc.Fill
    
    End Sub
    
    
    Private Sub OnDelete(ByVal sender As Object, _
            ByVal args As DeleteEventArgs)
        Application.Quit
    End Sub

    Public Shared Sub Main
    
        Application.Init
        Dim app As New GtkVBApp
        Application.Run
        
    End Sub
 
End Class

In this example, we will create a rectangle, a square, a circle, an arc and an ellipse.

cc.Rectangle(20, 20, 120, 80)
cc.Rectangle(180, 20, 80, 80)
cc.Fill

These lines draw a rectangle and a square.

cc.Arc(330, 60, 40, 0, 2*Math.PI)
cc.Fill

Here the Arc method draws a full circle.

cc.Translate(220, 180)
cc.Scale(1, 0.7)
cc.Arc(0, 0, 50, 0, 2*Math.PI)
cc.Fill

The Translate method moves the object to a specific point. If we want to draw an oval, we do some scaling first. Here the Scale method shrinks the y axis.

Basic shapes
Figure: Basic shapes

Transparent rectangles

Transparency is the quality of being able to see through a material. The easiest way to understand transparency is to imagine a piece of glass or water. Technically, the rays of light can go through the glass and this way we can see objects behind the glass.

In computer graphics, we can achieve transparency effects using alpha compositing. Alpha compositing is the process of combining an image with a background to create the appearance of partial transparency. The composition process uses an alpha channel. (wikipedia.org, answers.com)

' ZetCode Mono Visual Basic GTK# tutorial
'
' This program draws ten
' rectangles with different
' levels of transparency
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com


Imports Gtk
 
Public Class GtkVBApp
    Inherits Window
       
    Public Sub New
        
        MyBase.New("Transparent rectangles")
        
        Me.InitUI

        Me.SetDefaultSize(590, 90)
        Me.SetPosition(WindowPosition.Center)
        AddHandler Me.DeleteEvent, AddressOf Me.OnDelete

        Me.ShowAll
        
    End Sub
    
    Private Sub InitUI
        
        Dim darea As New DrawingArea
        AddHandler darea.ExposeEvent, AddressOf Me.OnExpose
        Me.Add(darea)

    End Sub
    
    Private Sub OnExpose(ByVal sender As Object, ByVal args As ExposeEventArgs)
    
        Dim cc As Cairo.Context = Gdk.CairoHelper.Create(sender.GdkWindow)
                
        Me.DrawRectangles(cc)
 
        Dim disposeTarget As IDisposable = CType(cc.Target, IDisposable)
        disposeTarget.Dispose()
        
        Dim disposeContext As IDisposable = CType(cc, IDisposable)
        disposeContext.Dispose()

    End Sub
    
    Private Sub DrawRectangles(ByVal cc As Cairo.Context)
    
        For i As Integer = 1 To 10        
            cc.SetSourceRGBA(0, 0, 1, i*0.1)
            cc.Rectangle(50*i, 20, 40, 40)
            cc.Fill  
        Next
    
    End Sub
    
    
    Private Sub OnDelete(ByVal sender As Object, _
            ByVal args As DeleteEventArgs)
        Application.Quit
    End Sub

    Public Shared Sub Main
    
        Application.Init
        Dim app As New GtkVBApp
        Application.Run
        
    End Sub
 
End Class

In the example we will draw ten rectangles with different levels of transparency.

cc.SetSourceRGBA(0, 0, 1, i*0.1)

The last parameter of the SetSourceRGBA method is the alpha transparency.

Transparent rectangles
Figure: Transparent rectangles

Donut

In the following example we create n complex shape by rotating a bunch of ellipses.

' ZetCode Mono Visual Basic GTK# tutorial
'
' This program draws basic shapes
' available in Cairo
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com


Imports Gtk
 
Public Class GtkVBApp
    Inherits Window
       
    Public Sub New
        
        MyBase.New("Donut")
        
        Me.InitUI

        Me.SetDefaultSize(400, 250)
        Me.SetPosition(WindowPosition.Center)
        AddHandler Me.DeleteEvent, AddressOf Me.OnDelete

        Me.ShowAll
        
    End Sub
    
    Private Sub InitUI
        
        Dim darea As New DrawingArea
        AddHandler darea.ExposeEvent, AddressOf Me.OnExpose
        Me.Add(darea)

    End Sub
    
    Private Sub OnExpose(ByVal sender As Object, ByVal args As ExposeEventArgs)
    
        Dim cc As Cairo.Context = Gdk.CairoHelper.Create(sender.GdkWindow)
                
        Me.DrawDonut(cc)
    
        Dim disposeTarget As IDisposable = CType(cc.Target, IDisposable)
        disposeTarget.Dispose
        
        Dim disposeContext As IDisposable = CType(cc, IDisposable)
        disposeContext.Dispose

    End Sub
    
    Private Sub DrawDonut(ByVal cc As Cairo.Context)
        
        cc.LineWidth = 0.5

        Dim width, height As Integer
        width = Allocation.Width
        height = Allocation.Height
       
        cc.Translate(width/2, height/2)
        cc.Arc(0, 0, 120, 0, 2*Math.PI)
        cc.Stroke
         
        cc.Save

        For i As Integer = 0 To 35
            cc.Rotate( i*Math.PI/36)
            cc.Scale(0.3, 1)
            cc.Arc(0, 0, 120, 0, 2*Math.PI)
            cc.Restore
            cc.Stroke
            cc.Save
        Next
    
    End Sub
    
    
    Private Sub OnDelete(ByVal sender As Object, _
            ByVal args As DeleteEventArgs)
        Application.Quit
    End Sub

    Public Shared Sub Main
    
        Application.Init
        Dim app As New GtkVBApp
        Application.Run
        
    End Sub
 
End Class

In this example, we create a donut. The shape resembles a cookie, hence the name donut.

cc.Translate(width/2, height/2)
cc.Arc(0, 0, 120, 0, 2*Math.PI)
cc.Stroke

In the beginning there is an ellipse.

For i As Integer = 0 To 35
    cc.Rotate( i*Math.PI/36)
    cc.Scale(0.3, 1)
    cc.Arc(0, 0, 120, 0, 2*Math.PI)
    cc.Restore
    cc.Stroke
    cc.Save
Next

After several rotations, there is a donut.

Donut
Figure: Donut

Drawing text

In the next example, we draw some text on the window.

' ZetCode Mono Visual Basic GTK# tutorial
'
' This program draws text
' on the window
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com


Imports Gtk
 
Public Class GtkVBApp
    Inherits Window
       
    Public Sub New
        
        MyBase.New("Soulmate")
        
        Me.InitUI

        Me.SetDefaultSize(400, 250)
        Me.SetPosition(WindowPosition.Center)
        AddHandler Me.DeleteEvent, AddressOf Me.OnDelete

        Me.ShowAll    
        
    End Sub
    
    Private Sub InitUI
        
        Dim darea As New DrawingArea
        AddHandler darea.ExposeEvent, AddressOf Me.OnExpose
        Me.Add(darea)

    End Sub
    
    Private Sub OnExpose(ByVal sender As Object, ByVal args As ExposeEventArgs)
    
        Dim cc As Cairo.Context = Gdk.CairoHelper.Create(sender.GdkWindow)
                
        Me.DrawLyrics(cc)
    
        Dim disposeTarget As IDisposable = CType(cc.Target, IDisposable)
        disposeTarget.Dispose
        
        Dim disposeContext As IDisposable = CType(cc, IDisposable)
        disposeContext.Dispose

    End Sub
    
    Private Sub DrawLyrics(ByVal cc As Cairo.Context)
        
        cc.SetSourceRGB(0.1, 0.1, 0.1)
         
        cc.SelectFontFace("Purisa", Cairo.FontSlant.Normal, Cairo.FontWeight.Bold)
        cc.SetFontSize(13)
       
        cc.MoveTo(20, 30)
        cc.ShowText("Most relationships seem so transitory")
        cc.MoveTo(20, 60)
        cc.ShowText("They're all good but not the permanent one")
        cc.MoveTo(20, 120)
        cc.ShowText("Who doesn't long for someone to hold")
        cc.MoveTo(20, 150)
        cc.ShowText("Who knows how to love without being told")
        cc.MoveTo(20, 180)
        cc.ShowText("Somebody tell me why I'm on my own")
        cc.MoveTo(20, 210)
        cc.ShowText("If there's a soulmate for everyone")

    End Sub
    
    
    Private Sub OnDelete(ByVal sender As Object, _
            ByVal args As DeleteEventArgs)
        Application.Quit
    End Sub

    Public Shared Sub Main
    
        Application.Init
        Dim app As New GtkVBApp
        Application.Run
        
    End Sub
 
End Class

We display part of the lyrics from the Natasha Bedingfields Soulmate song.

cc.SelectFontFace("Purisa", Cairo.FontSlant.Normal, Cairo.FontWeight.Bold)

Here we specify the font that we use. Purisa bold.

cc.SetFontSize(13)

We specify the size of the font.

cc.MoveTo(20, 30)

We move to the point, where we will draw the text.

cc.ShowText("Most relationships seem so transitory")

The ShowText method draws text onto the window.

Soulmate
Figure: Soulmate

In this chapter of the Visual Basic GTK# tutorial, we were painting with Cairo library.