2014-03-14 15:43:46 -05:00
// 14 march 2014
package ui
import (
"sync"
"image"
)
// 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.
2014-03-15 16:27:42 -05:00
// 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.
2014-03-14 15:43:46 -05:00
// 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
2014-03-15 20:36:10 -05:00
// Mouse is signaled when the Area receives a mouse event.
// See MouseEvent for details.
Mouse chan MouseEvent
2014-03-14 15:43:46 -05:00
lock sync . Mutex
created bool
sysData * sysData
}
// 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
// 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
}
2014-03-15 20:36:10 -05:00
// MouseEvent contains all the information for a mous event sent by Area.Mouse.
// Mouse button IDs start at 1, with 1 being the left mouse button, 2 being the middle mouse button, and 3 being the right mouse button.
// (TODO "If additional buttons are supported, they will be returned with 4 being the first additional button (XBUTTON1 on Windows), 5 being the second (XBUTTON2 on Windows), and so on."?) (TODO get the user-facing name for XBUTTON1/2; find out if there's a way to query available button count)
type MouseEvent struct {
// Pos is the position of the mouse in the Area at the time of the event.
2014-03-15 21:29:47 -05:00
// TODO rename to Pt or Point?
2014-03-15 20:36:10 -05:00
Pos image . Point
// If the event was generated by a mouse button being pressed, Down contains the ID of that button.
// Otherwise, Down contains 0.
Down uint
// If the event was generated by a mouse button being released, Up contains the ID of that button.
// Otherwise, Up contains 0.
Up uint
// If Down is nonzero, Count indicates the number of clicks: 1 for single-click, 2 for double-click.
// If Count == 2, AT LEAST one event with Count == 1 will have been sent prior.
// (This is a platform-specific issue: some platforms send one, some send two.)
Count uint
// Modifiers is a bit mask indicating the modifier keys being held during the event.
Modifiers Modifiers
// Held is a slice of button IDs that indicate which mouse buttons are being held during the event.
// (TODO "There is no guarantee that Held is sorted."?)
// (TODO will this include or exclude Down and Up?)
Held [ ] uint
}
// HeldBits returns Held as a bit mask.
// Bit 0 maps to button 1, bit 1 maps to button 2, etc.
func ( e MouseEvent ) HeldBits ( ) ( h uintptr ) {
for _ , x := range e . Held {
h |= uintptr ( 1 ) << ( x - 1 )
}
return h
}
// Modifiers indicates modifier keys being held during a mouse event.
// There is no way to differentiate between left and right modifier keys.
type Modifiers uintptr
const (
Ctrl Modifiers = 1 << iota // the canonical Ctrl keys ([TODO] on Mac OS X, Control on others)
Alt // the canonical Alt keys ([TODO] on Mac OS X, Meta on Unix systems, Alt on others)
Shift // the Shift keys
)
2014-03-14 15:43:46 -05:00
// NewArea creates a new Area.
func NewArea ( ) * Area {
return & Area {
sysData : mksysdata ( c_area ) ,
Paint : make ( chan PaintRequest ) ,
2014-03-15 20:36:10 -05:00
Mouse : make ( chan MouseEvent ) ,
2014-03-14 15:43:46 -05:00
}
}
func ( a * Area ) make ( window * sysData ) error {
a . lock . Lock ( )
defer a . lock . Unlock ( )
a . sysData . paint = a . Paint
2014-03-15 20:36:10 -05:00
a . sysData . mouse = a . Mouse
2014-03-14 15:43:46 -05:00
err := a . sysData . make ( "" , window )
if err != nil {
return err
}
a . created = true
return nil
}
func ( a * Area ) setRect ( x int , y int , width int , height int , winheight int ) error {
a . lock . Lock ( )
defer a . lock . Unlock ( )
return a . sysData . setRect ( x , y , width , height , winheight )
}
func ( a * Area ) preferredSize ( ) ( width int , height int ) {
a . lock . Lock ( )
defer a . lock . Unlock ( )
return a . sysData . preferredSize ( )
}