summaryrefslogtreecommitdiff
path: root/area.go
diff options
context:
space:
mode:
Diffstat (limited to 'area.go')
-rw-r--r--area.go67
1 files changed, 34 insertions, 33 deletions
diff --git a/area.go b/area.go
index 27706cc..983c547 100644
--- a/area.go
+++ b/area.go
@@ -10,42 +10,40 @@ import (
// Area represents a blank canvas upon which programs may draw anything and receive arbitrary events from the user.
// An Area has an explicit size, represented in pixels, that may be different from the size shown in its Window; scrollbars are placed automatically should they be needed.
// The coordinate system of an Area always has an origin of (0,0) which maps to the top-left corner; all image.Points and image.Rectangles sent across Area's channels conform to this.
+//
+// To handle events to the Area, an Area must be paired with an AreaHandler.
+// See AreaHandler for details.
+//
// To facilitate development and debugging, for the time being, Areas have a fixed size of 320x240 and only work on GTK+.
type Area struct {
- // Paint is signaled when the Area needs to be redrawn.
- // You MUST handle Paint signals; failure to do so will result in the UI task hanging.
- // See the documentation of PaintRequest for details.
- Paint chan PaintRequest
-
- // Mouse is signaled when the Area receives a mouse event.
- // See MouseEvent for details.
- Mouse chan MouseEvent
-
lock sync.Mutex
created bool
sysData *sysData
+ handler AreaHandler
}
-// PaintRequest contains the information needed to redraw an Area.
-// On each Paint event, an Area will receive a full request on its Paint channel.
-// It must send something back on Out in order to complete the painting.
-// Example:
-// imgFromFile, _, err := image.Decode(file)
-// if err != nil { panic(err) }
-// img := image.NewNRGBA(imgFromFile.Rect)
-// draw.Draw(img, img.Rect, imgFromFile, image.ZP, draw.Over)
-// for req := range area.Paint {
-// req.Out <- img.SubImage(req.Rect).(*image.NRGBA)
-// }
-type PaintRequest struct {
- // Rect is the clip rectangle of the whole Area that needs to be redrawn.
- // The image sent on Out must have the same size as Rect (but does not have to have the same Rect.Min/Rect.Max points).
- Rect image.Rectangle
+// AreaHandler represents the events that an Area should respond to.
+// You are responsible for the thread safety of any members of the actual type that implements ths interface.
+// (Having to use this interface does not strike me as being particularly Go-like, but the nature of Paint makes channel-based event handling a non-option; in practice, deadlocks occur.)
+type AreaHandler interface {
+ // Paint is called when the Area needs to be redrawn.
+ // You MUST handle this event, and you MUST return a valid image, otherwise deadlocks and panicking will occur.
+ // The image returned must have the same size as rect (but does not have to have the same origin points).
+ // Example:
+ // imgFromFile, _, err := image.Decode(file)
+ // if err != nil { panic(err) }
+ // img := image.NewNRGBA(imgFromFile.Rect)
+ // draw.Draw(img, img.Rect, imgFromFile, image.ZP, draw.Over)
+ // // ...
+ // func (h *myAreaHandler) Paint(rect image.Rectangle) *image.NRGBA {
+ // return img.SubImage(rect).(*image.NRGBA)
+ // }
+ Paint(rect image.Rectangle) *image.NRGBA
- // Out is where you send the image to draw.
- // Only one image per PaintRequest may be sent; you must send an image.
- // Do not close Out; the package will do this itself.
- Out chan<- *image.NRGBA
+ // Mouse is called when the Area receives a mouse event.
+ // You are allowed to do nothing in this handler (to ignore mouse events).
+ // See MouseEvent for details.
+ Mouse(e MouseEvent)
}
// MouseEvent contains all the information for a mous event sent by Area.Mouse.
@@ -63,6 +61,7 @@ type MouseEvent struct {
// If the event was generated by a mouse button being released, Up contains the ID of that button.
// Otherwise, Up contains 0.
// If both Down and Up are 0, the event represents mouse movement (with optional held buttons; see below).
+ // Down and Up shall not both be nonzero.
Up uint
// If Down is nonzero, Count indicates the number of clicks: 1 for single-click, 2 for double-click.
@@ -98,11 +97,14 @@ const (
)
// NewArea creates a new Area.
-func NewArea() *Area {
+// It panics if handler is nil.
+func NewArea(handler AreaHandler) *Area {
+ if handler == nil {
+ panic("handler passed to NewArea() must not be nil")
+ }
return &Area{
sysData: mksysdata(c_area),
- Paint: make(chan PaintRequest),
- Mouse: make(chan MouseEvent),
+ handler: handler,
}
}
@@ -110,8 +112,7 @@ func (a *Area) make(window *sysData) error {
a.lock.Lock()
defer a.lock.Unlock()
- a.sysData.paint = a.Paint
- a.sysData.mouse = a.Mouse
+ a.sysData.handler = a.handler
err := a.sysData.make("", window)
if err != nil {
return err