diff options
Diffstat (limited to 'area.go')
| -rw-r--r-- | area.go | 67 |
1 files changed, 34 insertions, 33 deletions
@@ -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 |
