# GAMBAS BOOK 3.19.1

### Site Tools

k23:k23.3:k23.3.3:start

## 23.3.3.1 Drawing areas

To draw with Paint in Gambas, you need an artboard and a pen or brush - just like in the real world. The following drawing areas (devices) are available to you:

• DrawingArea,
• ScrollArea as a specialised DrawingArea,
• Picture,
• Image and SVGImage or
• Printer.

## 23.3.3.2 Geometric shapes

You can draw these geometric shapes (lines or areas or text) in six categories on the drawing area:

• Point
• Line - distance as the shortest connection between two points
• Polygon (n-corner)
• Rectangle (special case square)
• Ellipse (special case circle)
• Ellipse arc - ellipse sector
• Circle arc - circle sector
• 3rd degree Bézier curves as curvilinear connection of two points
• Text

Yes, text is also drawn, whereby you must specify the font, the font colour and the (start) point at which the font is inserted into the drawing area after calling special methods.

## 23.3.3.3 Paint coordinate system

All artboards have a (non-visible) coordinate system to which all coordinate specifications in the properties or in the arguments of the methods of the Paint class refer. Please observe these notes:

• The coordinate origin O(0|0) of the Paint coordinate system is in the top left-hand corner of the Paint canvas.
• The positive x-axis points to the right.
• The positive y-axis points downwards - in contrast to the usual Cartesian coordinate system used in maths!
• Coordinates in Paint are always of the float data type.
• Each point on the drawing area is defined by a coordinate pair P(x|y).

Figure 23.3.3.3.1: Paint coordinate system with shifted coordinate origin

In order to draw the names of the two axes and the values legibly if required, the coordinate origin of the coordinate system can be permanently shifted using the Translate method of the Paint class.

```Paint.Begin(hPicture)
Paint.Translate(40, 45) ' Verschiebung um +40.0 in x-Richtung und um +45.0 in y-Richtung
...
Paint.End```

The shift does not change the direction of the two coordinate axes!

You could also omit the display of the coordinate system in the following illustration, as it has no influence on the effect of the image:

Figure 23.3.3.3.2: Paint image

The next figure shows the correct image of a function in a shifted paint coordinate system with clearly legible designations:

Figure 23.3.3.3.3: Image of a function y = f(x)

You will certainly recognise that the function has no zeros in the specified interval and also has a local high point in addition to the local minimum in the vicinity of 2. To realise the usual view, you can scale the coordinate system so that the positive y-axis points upwards. A translation of the coordinate origin O(0|0), combined with a mirroring of the y-axis at the abscissa - realised by using the scale method - can be implemented in this way:

```Paint.Begin(hPicture)
Paint.Translate(40, 45) 	'-- Shift by +40.0 in the x-direction and by +45.0 in the y-direction
Paint.Scale(1, -1)	      	'-- The -1 causes the direction of the y-axis to be inverted → +y ▲
...
Paint.End```

Figure 23.3.3.3.4: Image of a function y = f(x)

## 23.3.3.4 Drawing with methods of the Paint class

Admittedly, the concept of drawing geometric shapes with Paint takes some getting used to, as a geometric shape is always drawn in three steps on the drawing area used:

1. First you assign suitable properties to the brush (Paint.Brush), such as fill colour or line colour, by calling Paint.Color, Paint.Image, Paint.LinearGradient or Paint.RadialGradient. You can define the line width separately if required.
2. Then define the so-called drawing path, which is described by a start point and the specification of a geometric shape. You can define a start point using the Paint.MoveTo(..) method or use the end point of a completed drawing action. You define the shape using selected drawing methods such as Paint.LineTo(..), Paint.Rectangle(..) or Paint.Arc(..) with specific arguments.
3. Finally, trace the drawing path with the defined brush on the drawing area (device), using the Paint.Stroke(A) method for a defined line and the Paint.Fill(A) method for an area. Normally, the last drawing path used is deleted after tracing (once). If you set the optional argument A to the value True, the drawing path is retained and can continue to be used.

The following example takes up the last step with the reference to the optional argument A. A circle with a red border and yellow circle area is to be drawn on a picture (object) as a drawing area (device).

```Public hPicture As Picture

Public Sub Form_Open()
daCanvas.Cached = False '-- Standard for a DrawingArea
hPicture = New Picture(daCanvas.Width, daCanvas.Height, True)
hPicture.Fill(&HC3DDFF)
PaintScriptCircle()
End

Public Sub PaintScriptCircle()
Paint.Begin(hPicture)
Paint.Translate(30, 300) 		     '-- Shifting the coordinate system
Paint.Scale(1, -1)		             '-- Inversion of the direction of the y-axis → +y ▲
Paint.Brush = Paint.Color(Color.Red)     '-- Colour arc
Paint.LineWidth = 5                      '-- Thickness of the circular arc
Paint.Arc(200, 150, 70)		     '-- Centre of circle M(200|150), radius 70
Paint.Stroke(True)		             '-- (Re)draw arc → path is retained!
Paint.Brush = Paint.Color(Color.Yellow)  '-- Colour circular area
Paint.Fill()			     '-- Fill circular area with colour → Path is deleted
Paint.End()
End```

To see the result of the drawing, the picture - which is currently only in memory - is drawn in a DrawingArea (daCanvas) and thus becomes visible:

```Public Sub daCanvas_Draw()
Paint.Begin(daCanvas)
If hPicture Then Paint.DrawPicture(hPicture, 0, 0)
Paint.End
End```

This flexible way of drawing has proved its worth. If you want to print the picture, the following additional lines are sufficient to draw the picture on the printer (myPrinter):

```Public Sub myPrinter_Draw()
Paint.Begin(myPrinter)
If hPicture Then Paint.DrawPicture(hPicture, 0, 0)
Paint.End
End```

Start the printout of the picture after a printer dialogue with 'myPrinter.Print'.

If, on the other hand, you want to save the image and process it further, for example to present figures as data in a text, save the picture as an image file:

```Public Sub btnSaveCurPicture_Click()
Dim sPictureFileName As String

sPictureFileName = Lower(cmbPictures.Text & ".png")
hPicture.Save(sPicturePath &/ sPictureFileName)
End```

Figure 23.3.3.4.1: Pie chart with 12 values

In chapter → 23.3.4.1 Projects1, 11 further examples are presented in a project and commented on in detail.

If you are drawing with Gambas for the first time, please follow these instructions:

• Coordinates in Paint are always of the float data type.
• The coordinate origin O(0|0) is in the top left-hand corner of the Paint drawing area.
• The positive y-axis points downwards - in contrast to the usual Cartesian coordinate system used in mathematics!
• Each point on the drawing area is defined by a coordinate pair P(x|y).
• Always differentiate between the border (line shape) and the area within the border.

## 23.3.3.5 Default values

For drawing with Paint, there are fixed (default) start values that you can set:

• The line or fill colour or the font colour is opaque black - without an alpha channel in the colour. If the paint device is a DrawingArea, this is its background colour.
• The line width is 1.
• Edge smoothing (AntiAlias) is switched on.
• The default font in Gambas is the system font. You can change the default font in the Gambas settings (Interface → Fonts).

A test results in these values:

```Print Paint.Background	     '-- 0 → black
Print Paint.LineWidth	     '-- 1
Print Paint.AntiAlias	     '-- TRUE
Print Paint.Font.ToString()  '-- Ubuntu, 11```

## 23.3.3.6 Notes on the DrawingArea as a drawing area

The DrawingArea provides a drawing area that can be drawn on from the application in two modes. The key to drawing on a DrawingArea is understanding the relationship between the value of the DrawingArea.Cached property and the use of the DrawingArea_Draw() event.

• If DrawingArea.Cached = True, then the DrawingArea is switched to a 'canvas' mode: Everything that is drawn remains visible on the DrawingArea - as long as the drawing is not deleted using the DrawingArea.Clear method.
• However, if the DrawingArea.Cached property is set to False, the drawing only remains visible as long as the DrawingArea has not been covered or hidden by another window because the (volatile) image memory has been cleared. The image must be redrawn in order to be visible again. The draw event is triggered automatically at precisely these moments.

Conclusion: The Draw event is used or not used depending on the value of the DrawingArea.Cached property.

As the Draw class has been considered obsolete since Gambas version 3.4, you should only use the Paint class in future. This is why the DrawingArea.Painted property no longer exists in the Paint class!

It is interesting to take a look at the module Draw.module, which you will find in the Gambas source files. It reveals that the Draw class is redefined via the Paint class. This ensures that your existing drawing projects can still be used with the Draw class.

Figure 23.3.3.6.1: Start project

In the download area you will find a project that implements the above principle approaches 1:1. The view of the complete source code is particularly advantageous for those who are drawing with methods of the Paint class for the first time.

Source code:

```' Gambas class file

Private hPicture As Picture
Private iPrinterDPI As Integer
Private fDesktopresolutionProInch As Float = (Desktop.Resolution / 25.4)
Private bPainted As Boolean = False

Public Sub Form_Open()
FMain.Center
FMain.Resizable = False
pboxPreView.Stretch = True
daCanvas.Cached = True '-- `daCanvas` is a DrawingArea
End ' Form_Open()

Public Sub PaintScriptCircle()
Try hPicture = New Picture(daCanvas.Width, daCanvas.Height, True) '-- A new Picture object is created
hPicture.Fill(&HC3DDFF)                                           '-- The picture gets a light blue background colour

Paint.Begin(hPicture) 		        '-- The picture is now drawn on ...
Paint.Translate(30, 200)                    '-- Shifting the coordinate system
Paint.Scale(1, -1)                          '-- Inversion of the direction of the y-axis → +y ▼
Paint.Brush = Paint.Color(Color.Red)        '-- Colour arc → red
Paint.LineWidth = 5                         '-- Thickness of the circular arc
Paint.Arc(270, 100, 70)                     '-- Centre of circle M(270|100), radius 70
Paint.Stroke(True)                          '-- (Re)draw arc → path is retained!
Paint.Brush = Paint.Color(Color.Yellow)     '-- Colour circular area → yellow
Paint.Fill()                                '-- Fill circular area with colour → Path is deleted
Paint.End

End

Public Sub daCanvas_Draw()
Paint.Begin(daCanvas)
If hPicture Then Paint.DrawPicture(hPicture, 0, 0) '-- The picture is drawn in the DrawingArea
Paint.End
End

Public Sub myPrinter_Draw()
Dim iDruckBreite, iDruckHoehe, iDruckrandLinks, iDruckrandOben As Integer
Dim imgToPrint As Image

iDruckrandLinks = 25 '-- Millimetre - tested value
iDruckrandOben = 20  '-- Millimetre - tested value

If Not hPicture Then
Return
Else
'-- The hPicture converted into an image is assigned to the imgToPrint image
imgToPrint = hPicture.Image
Endif

'-- Automatic changeover from landscape to portrait format when Picture.W > Picture.H
If imgToPrint.Width > imgToPrint.Height Then imgToPrint = imgToPrint.Rotate(Pi(0.5))
'-- Conversion from DA point unit to millimetre unit
Paint.Scale(Paint.Width / myPrinter.PaperWidth, Paint.Height / myPrinter.PaperHeight)

'-- The values used, 170 (width) and 260 (height), have been tested for A4
If PixelToMillimeter(imgToPrint.W) > 170 Then
iDruckBreite = 170
iDruckHoehe = CInt(iDruckBreite * (imgToPrint.Height / imgToPrint.Width))
If iDruckHoehe > 260 Then
iDruckHoehe = 260
iDruckBreite = CInt(iDruckHoehe / (imgToPrint.Height / imgToPrint.Width))
Endif
Return
Endif

If PixelToMillimeter(imgToPrint.H) > 260 Then
iDruckHoehe = 260
iDruckBreite = CInt(iDruckHoehe / (imgToPrint.Height / imgToPrint.Width))
If iDruckBreite > 170 Then
iDruckBreite = 170
iDruckHoehe = CInt(iDruckBreite / (imgToPrint.Height / imgToPrint.Width))
Endif

Return

Endif

iDruckBreite = PixelToMillimeter(imgToPrint.W)
iDruckHoehe = CInt(iDruckBreite * (imgToPrint.Height / imgToPrint.Width))

'-- The image to be printed - now as Image imgToPrint - is printed in the printer

End ' myPrinter_Draw()

Public Sub btnDrawPicture_Click()
PaintScriptCircle() '-- The picture - circle with red border and yellow area - is drawn on the Picture
bPainted = True
pboxPreView.Picture = hPicture '-- Mini preview image, as the hPicture object only exists in memory!
End

Public Sub btnShowPicture_Click()
If bPainted Then
daCanvas_Draw() '-- The picture is drawn in the DrawingArea
Endif
End

Public Sub btnSavePicture_Click()
Dim sPictureFileName As String

sPictureFileName = Lower("startfrei.png")
If Exist(Application.Path &/ sPictureFileName) Then Kill Application.Path &/ sPictureFileName
Wait
If bPainted Then
hPicture.Save(Application.Path &/ sPictureFileName) ' Das Picture wird als Bild-Datei gespeichert
Wait
Endif
pboxPreView.Enabled = False
Wait 0.3
pboxPreView.Enabled = True

End

Public Sub btnPrintPicture_Click()
If bPainted Then
If myPrinter.Configure() Then Return '-- Printer dialogue
Me.Enabled = False          '-- The form is deactivated
Inc Application.Busy     '-- The programme no longer accepts any input ...
myPrinter.Print      '-- The printout is started
Dec Application.Busy     '-- The programme is accepting entries again...
Me.Enabled = True           '-- The form is activated
Endif
End

Public Sub btnClearPicture_Click()
hPicture = Null '-- The Picture object is deleted
daCanvas.Clear()
pboxPreView.Picture = hPicture
bPainted = False
End

' ---------------------------------------------------------------------------------------------------------

Private Function PixelToMillimeter(iPixel As Integer) As Float
Return iPixel / fDesktopresolutionProInch
End```