Area and drawing

The ui.Area widget presents a canvas-like control—a surface that can be drawn on using Path and other drawing primitives. At the time of writing, these APIs are all part of the ui package, but it may soon move to ui/draw in an effort to separate them from the main controls API. An area can either be the size of the space it occupies or it can be larger, in which case it will be embedded in a scrollable control. The desired behavior is chosen based on whether ui.NewArea(handler) or ui.NewScrollingArea(handler, width, height) is called (where width and height are the desired content size).

The logic behind an area is ui.AreaHandler, the first parameter to either of the area constructor functions. Its Draw(*ui.Area, *ui.AreaDrawParams) function is invoked by the toolkit whenever the area needs to be redrawn, the first parameter being the area it's registered on and the second providing context, such as the clipping rectangle to be filled. As well as drawing the content of an area, the handler is responsible for handling the mouse and key events, with MouseEvent(*ui.Area, *ui.AreaMouseEvent) being called whenever a mouse event occurs and KeyEvent(*ui.Area, *ui.AreaKeyEvent) for any keyboard events.

To look more closely at the drawing capabilities, let's run a little code. In this example, we are creating a new ui.AreaHandler type (named areaHandler) that implements all the required functions from the interface. The only method of interest is the Draw() call, which is included here:

func (areaHandler) Draw(a *ui.Area, dp *ui.AreaDrawParams) {
p := ui.NewPath(ui.Winding)
p.NewFigure(10, 10)
p.LineTo(dp.ClipWidth - 10, 10)
p.LineTo(dp.ClipWidth - 10, dp.ClipHeight - 10)
p.LineTo(10, dp.ClipHeight - 10)
p.CloseFigure()
p.End()

dp.Context.Fill(p, &ui.Brush{Type:ui.Solid, R:.75, G:.25, B:0, A:1})
dp.Context.Stroke(p, &ui.Brush{Type:ui.Solid, R:.25, G:.25, B:.75, A:.5},
&ui.StrokeParams{Thickness: 4, Dashes: []float64{10, 6}, Cap:ui.RoundCap})
p.Free()
}

This code is split into two parts: first we set up a ui.Path and then we use the path to draw. The path (named p) is set to be 10 pixels inside the clip area that is being drawn—this is done so the canvas background is demonstrated (the drawing area is cleared before every Draw() call). Next, we use this path to Fill() and Stroke() within the draw context (dp.Context). The call to Fill() specifies a Brush that is a solid orange color of full opacity (A in the preceding code stands for alpha). Then, we call Stroke() using the same path (this will draw a line around the filled box). We are asking for a four-pixel-wide dashed line with round caps—this time with a semi-transparent blue color.

To draw this to screen, we need to configure a window to have a ui.Area control that expands to fill the window, as follows:

func main() {
err := ui.Main(func() {
window := ui.NewWindow("Draw", 200, 150, false)
window.SetMargined(false)
window.OnClosing(func(*ui.Window) bool {
ui.Quit()
return true
})

handler := new(areaHandler)
box := ui.NewVerticalBox()
box.Append(ui.NewArea(handler), true)

window.SetChild(box)
window.Show()
})
if err != nil {
panic(err)
}
}

If you put all this together (or run the chapter5/draw example), you should see something like the following screenshot:

 
Andlabs UI draw functions

Notice how the transparent blue is outlining the orange—filled rectangle, and also displaying the rectangle and the background from beneath. If we reversed the order of the Fill() and Stroke() calls, the orange rectangle would completely cover half of the dashed outline.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.58.194