LiveCode
  • Why LiveCode?
  • Customers
  • Resources
  • Education
  • Consulting
  • Pricing
  • Blog
  • Login
  • Try LiveCode
Back to
  • slides
  • tutorial
Resources

The OnPaint Handler

Topic Progress:
← Back to Lesson

The OnPaint handler

The OnPaint handler draws the widget.

The Pie Chart is a fairly complex widget so drawing the widget consists of a number of steps.

  1. Get the width and  the height of the widget.
  2. Check if the labels are to be shown
    1. If the labels are not to be shown
      1. Work out the diameter of the chart – the minimum of the width and height of the widget.
      2. Work out the rect of the chart – this will be the rect of the widget.
    2. If the labels are to be shown
      1. Work out the area required to show the labels.
      2. Work out the diameter of the chart, allowing enough space for the labels.
      3. Work out the rect of  the chart and the rect of the label area, depending on the orientation of the widget.
    3. Work out the radius of the chart – required to draw each sector.
    4. Work out the origin of the chart – the center of the chart rect.
    5. Calculate the sum of all the values.
    6. Calculate the percentage of the chart for each sector, based on the sector value.
    7. Calculate the start and end angle for each sector, these are used to draw each sector of the card in the correct position.
    8. Draw the pie chart.
    9. If labels are to be shown draw the labels.

We’ll implement each step on OnPaint in turn, testing the widget as we go.

Define OnPaint

Start by adding the OnPaint definition and definitions for the first of the required variables.

  • tWidth – the width of the widget
  • tHeight – the height of the widget
  • tDiameter – the diameter of the pie chart
  • tChartRect – the pie chart area
  • tLabelRect – the labels area
  • tLabelLineHeight – the height of a single label
public handler OnPaint()
   variable tWidth as Number
   variable tHeight as Number
   variable tDiameter as Number

   variable tChartRect as Rectangle
   variable tLabelRect as Rectangle
   variable tLabelLineHeight as Number
end handler

The width and height

Get the width and height of the widget and assign the values to the variables tWidth and tHeight.

public handler OnPaint()
   variable tWidth as Number
   variable tHeight as Number
   variable tDiameter as Number
   variable tChartRect as Rectangle
   variable tLabelRect as Rectangle

   put my width into tWidth
   put my height into tHeight

end handler

The chart rectangle

To work out the rectangle of the pie chart area

  • Check the showLabels property
  • If labels are not to be shown the chart rectangle is the full widget rectangle
    • Calculate the diameter
    • Allow for some padding between the chart and the edges of the widget
    • Assign the rectangle to the tChartRect variable
public handler OnPaint()
   … previous code

   if mShowLabels is false then
      put the minimum of tHeight and tWidth into tDiameter
      subtract kPadding*2 from tDiameter
      put rectangle [0,0,tWidth,tHeight] into tChartRect
   else
      … code continues on next slide
   end if
end handler

If the labels are to be shown

  • Declare variables
  • Work out how much space the labels require
    • Iterate over each label
    • Measure the label text on the canvas, this returns the rectangle required to draw the text using the current text size, style and font.
    • If the required label width > the current maximum label width update tLabelWidth.

If the required label height> the current maximum label height update tLabelHeight.

public handler OnPaint()
   … previous code
   if mShowLabels is false then
       … previous code
    else
      variable tLabelText as String
      variable tLabelBounds as Rectangle
      variable tLabelWidth as Number
      variable tLabelHeight as Number

      repeat for each element tLabelText in mLabels
         measure tLabelText on this canvas
         put the result into tLabelBounds

         if the width of tLabelBounds > tLabelWidth then
            put the width of tLabelBounds into tLabelWidth
         end if

         if the height of tLabelBounds > tLabelHeight then
            put the height of tLabelBounds into tLabelHeight
         end if
      end repeat 
      … code continues on next slide 
   end if
end handler
  • Assign the line height required for each individual label to tLabelLineHeight
  • Calculate the height required to show all the labels.
  • Allow space for the color indicator. The indicator is a square width dimensions â…” label line height with some padding so add tLabelLineHeight to tLabelWidth.
public handler OnPaint()
   … previous code
   if mShowLabels is false then
       … previous code
    else
      … previous code
      put tLabelHeight into tLabelLineHeight
      put tLabelHeight * (the number of elements in mLabels) into tLabelHeight       add tLabelLineHeight to tLabelWidth  
      … code continues
   end if
end handler

The chart and label rectangles

The widget is laid out differently depending on whether is is ‘landscape’ or ‘portrait’.

rects1rects2

  • Check the orientation of the widget
  • Landscape
    • Calculate the chart diameter: the minimum of (widget width – label width) and widget height.
    • Allow for padding around the chart
    • Calculate tChartRect: 0,0,widget width – label width, widget height
    • Calculate tLabelRect: – widget width – label width,0, widget width, widget height
  • Portrait
    • Calculate the chart diameter: the minimum of widget width and (widget height-label height).
    • Allow for padding around the chart
    • Calculate tChartRect: 0,0,widget width,widget height-label height
    • Calculate tLabelRect: 0,widget height-label height,widget width, widget height
public handler OnPaint()
   … previous code
   if mShowLabels is false then
       … previous code
   else
       … previous code
      if tWidth > tHeight then
         put the minimum of tHeight and (tWidth - tLabelWidth) into tDiameter          subtract kPadding*2 from tDiameter

         put rectangle [0,0,tWidth-tLabelWidth,tHeight] into tChartRect          put rectangle [tWidth-tLabelWidth,0,tWidth,tHeight] into tLabelRect      else
         put the minimum of tWidth and (tHeight - tLabelHeight) into tDiameter          subtract kPadding*2 from tDiameter
         put rectangle [0,0,tWidth,tHeight-tLabelHeight] into tChartRect          put rectangle [0,tHeight-tLabelHeight,tWidth,tHeight] into tLabelRect      end if
     … code continues on next slide
   end if

Testing the widget

This is a good point to test the widget to make sure we don’t have any errors.

At this point we are not actually drawing anything to the canvas so to check the chart and label rectangles are in the place add a couple of temporary lines to draw the rectangles to the canvas.

Note: in this example we don’t explicitly address the possibility that the label width or height will be greater than that of the widget. In that case the widget will still render but the content will overlap or be outside the widget area.

public handler OnPaint()
   … previous code
   if mShowLabels is false then
       … previous code
   else
       … previous code
      stroke rectangle path of tChartRect on this canvas
      stroke rectangle path of tLabelRect on this canvas
   end if
end handler

To test the widget

  1. Open the Extension Builder from the Tools menu.
  2. Load in the ‘pieChart.lcb’ file.
  3. Click Test.
  4. Open the Property Inspector to check the widget properties.
  5. Select the widget and resize it to check the chart and label areas change size.

test1

test2

test3

Drawing the Pie Chart

The next step is to draw the pie chart.

  • Calculate the sum of all the values
  • Work out what percentage of the pie chart each sector should take up
  • Calculate the size of the angle of each sector
  • Draw the filled sector. The color of the sector comes from the list if colors that was initialised earlier.
Label Value % Angle
Jan 1 3.125 11.25
Feb 2 6.25 22.5
Mar 3 9.375 33.75
Apr 5 15.625 56.25
May 8 25 90
Jun 13 40.625 146.25

pie6

At this stage we will remove the temporary stroke commands that drew the rectangles around the chart and label areas.

To draw the chart

  • Declare the tTotal and tElement  variables
  • Calculate the sum of all the values. Remember to convert the value from a string to a number.
public handler OnPaint()
   … previous code

if mShowLabels is false then
       … previous code
    else
        … previous code
      stroke rectangle path of tChartRect on this canvas
      stroke rectangle path of tLabelRect on this canvas
   end if
   variable tTotal as Number
   variable tElement as String

   repeat for each element tElement in mValues
        add tElement parsed as number to tTotal
   end repeat
   … code continues
end handler

To draw the chart

  • Declare the tRadius, tChartOrigin, tStartAngle, tAngle, tPath and tSectorNumber variables.
  • Calculate the radius

Work out the origin of the chart as a Point. The origin is the centre of the chart rectangle.

public handler OnPaint()
    … previous code
   variable tRadius as Number
   variable tChartOrigin as Point
   variable tStartAngle as Number
   variable tAngle as Number
   variable tPath as Path
   variable tSectorNumber as Number

   put tDiameter / 2 into tRadius
   put point [the width of tChartRect/2,the height of tChartRect/2] into tChartOrigin
   … code continues
end handler

Drawing the Pie Chart

  • Iterate across each value in mValues.
  • Calculate the sector number
  • Work out the sector angle as a fraction of the circle.
  • Empty the tPath variable
  • Get the sector path of the sector using the chart origin, radius, start and end angle.
  • Set the paint of the canvas to the corresponding color in the mColors list.
  • Fill the path to draw the sector.
  • Add the angle to tStartAngle to be used  in the next iteration.
public handler OnPaint()
    … previous code
   repeat for each element tElement in mValues
      add 1 to tSectorNumber
      put (tElement parsed as number/tTotal) * 360 into tAngle
      put the empty path into tPath
      put sector path centered at tChartOrigin with radii [tRadius,tRadius] from tStartAngle to (tStartAngle + tAngle) into tPath

      set the paint of this canvas to solid paint with element tSectorNumber of mColors
      fill tPath on this canvas
      add tAngle to tStartAngle
   end repeat
   … code continues
end handler

Testing the widget

To test the widget

  1. Open the Extension Builder from the Tools menu.
  2. Load in the ‘pieChart.lcb’ file.
  3. Click Test.
  4. Select the widget and resize it.
  5. Open  the Property Inspector. Add another value to the Values property: 1,2,3,5,8,13,21.

pie7

pie8

pie9

Showing the labels

If the Show labels(mShowLabels) property is true we want to show the labels in the tLabelRect area. LiveCode Builder cannot currently draw multi-line text so we draw each label individually.

  • Declare variables
  • Check if labels are to be shown.
  • Calculate the dimension and padding of the color indicator
  • Assign values to the tLineTop and tSectorNumber variables
public handler OnPaint()
   … previous code
   variable tLineTop as Number
   variable tLineRect as Rectangle
   variable tColorIndicatorDimension as Number
   variable tColorIndicatorPadding as Number
   variable tColorIndicatorPath as Path

   if mShowLabels is true then
      put (tLabelLineHeight/3) * 2 into tColorIndicatorDimension
      put tLabelLineHeight/6 into tColorIndicatorPadding

      put the top of tLabelRect into tLineTop
      put 0 into tSectorNumber
           … code continues

end handler
  • Iterate over each label
    • Update the sector number
    • Calculate the rectangle of the color indicator
    • Set the color of the canvas to the sector color
    • Draw the color indicator
    • Calculate the rectangle of the label
    • Set the color of the canvas to black
    • Draw the text from the top left of the label rectangle
    • Calculate the top of the next label ready for use in the next iteration
public handler OnPaint()
    … previous code   
   if mShowLabels is true then
     … previous code  
     repeat for each element tElement in mLabels
          add 1 to tSectorNumber
          put rectangle path of rectangle [the left of tLabelRect + tColorIndicatorPadding, tLineTop + tColorIndicatorPadding, the left of tLabelRect + tColorIndicatorDimension + tColorIndicatorPadding,tLineTop + tColorIndicatorDimension + tColorIndicatorPadding] into tColorIndicatorPath
          set the paint of this canvas to solid paint with element tSectorNumber of mColors         
          fill tColorIndicatorPath on this canvas
          put rectangle [the left of tLabelRect + tLabelLineHeight,tLineTop,tWidth,tLineTop + tLabelLineHeight] into tLineRect           set the paint of this canvas to solid paint with color [0,0,0,1]           fill text tElement at top left of tLineRect on this canvas
          add tLabelLineHeight to tLineTop
      end repeat
  end if
end handler

Testing the widget

To test the widget

  1. Open the Extension Builder from the Tools menu.
  2. Load in the ‘pieChart.lcb’ file.
  3. Click Test.
  4. Open the Property Inspector
  5. Try changing some properties
    1. Add another value
    2. Add another label
    3. Switch Show labels off

pie10

pie11

pie12

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

← Previous Topic

← Previous Topic Next Topic →
  •  
  •  
  • (0)
  •  

Expand All | Collapse All
Lessons Status
1 - Hello World Library
  • Introduction
  • Installing a Text Editor
  • Creating an LCB library
  • LCB library definition
  • LCB handler definitions
  • Compiling and testing a library in LiveCode
  • LCB metadata
  • Installing an LCB Library
  • Packaging and sharing an LCB library
  • Including an LCB library in a standalone
  • Conclusion
2 - Extended Hello World Library
  • Introduction
  • Explicit Types
  • LCB Lists and Arrays
  • Type Conversion between LCB and LiveCode Script
  • Using Explicit Typing in the Library
  • Passing Parameters to the Library
  • Using Lists in the Library
  • Documenting the Library
  • Browsing the Documentation
  • Conclusion
3 - Rotated Text Widget
  • Introduction
  • Defining a Widget
  • LCB Module Level Variables
  • Widget Properties
  • Widget Handlers
  • LCB Canvas Operations
  • Compiling and Testing the Widget
  • Installing the Widget and adding it to a Stack
  • Including the Widget in a Standalone
  • Conclusion
4 - Extended Rotated Text Widget
  • Introduction
  • Integrating Properties
  • Accessing LiveCode Control Properties
  • Handling Mouse Events
  • Saving and Loading Widgets
  • Read Only Properties
  • Documenting the Widget
  • Conclusion
5 - Pie Chart Widget
  • Introduction
  • Planning the Widget
  • Widget Properties
  • The OnCreate Handler
  • The OnPaint Handler
  • Responding to Mouse Events
  • Saving and Loading the Widget
  • Installing and Including the Widget in a Standalone
  • Documenting the Widget
  • Conclusion
6 - Modifying the Line Graph Widget
  • Introduction
  • Duplicating the Line Graph Widget
  • Additional Color Properties
  • Filling the area below the line
  • Adding graph marker mouse events
  • Conclusion
7 - Additional Resources
  • Extending LiveCode Guide
  • LiveCode Builder Language Reference
  • LiveCode Builder Style Guide
  • LiveCode Documentation Format
 

LCB Source

LCB Source
 

Login

LiveCode

  • Why LiveCode?
  • Pricing
  • Customer Stories
  • Extensions
  • LiveCode in Education
  • LiveCode in Business

Looking for LiveCode FileMaker?

LiveCode for FM

Resources

  • Docs
  • API (Language Dictionary)
  • Lessons
  • Sample Stacks
  • Forums
  • Stackoverflow
  • User Groups
  • Support
  • Directory
  • LiveCode Services

About

  • About
  • Meet The Team
  • Careers at LiveCode
  • Contact us

Recent Posts

  • LiveCode Classic 10.0.1 Stable and 10.0.2-rc-1 Released
  • Create Progress – the Three D’s
  • LiveCode Create: Closing out the year with big steps forward
  • Create dp-5: Unified Engines and Shared Extensions
  • 3 Great New LiveCode Releases
Sitemap
Terms Privacy Policy EULA
Brought to you by LiveCode Ltd, Registered in Scotland, No. SC200728
We use cookies to ensure that we give you the best experience on our website. If you continue to use this site we will assume that you are happy with it.Ok