123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 |
- package widget
- import "fmt"
- import . "gitlab.com/beoran/ebsgo/zori/types"
- import "gitlab.com/beoran/ebsgo/zori/backend"
- import "gitlab.com/beoran/ebsgo/zori/state"
- import "gitlab.com/beoran/ebsgo/zori/style"
- import "gitlab.com/beoran/ebsgo/zori/event"
- import "gitlab.com/beoran/ebsgo/monolog"
- var LastID = 0
- type ActionCallback func (w Widget, data ... interface{}) event.Result
- type Basic struct {
- Be backend.Backend
- ID int
- MyRoot RootWidget
- Box
- Outer Box
- Inner Box
- Z int
- style.BasicTheme
- MyParent Widget
- MyChildren []Widget
- state.Flag
- Result interface{}
- ActionCallback
- }
- func (b * Basic) SetBounds(bounds * Box) {
- b.Box.X = bounds.X
- b.Box.Y = bounds.Y
- b.Box.W = bounds.W
- b.Box.H = bounds.H
- b.Outer = b.Box
- b.Inner = b.Box
- }
- func NewBasicWithTheme(parent Widget, bounds * Box, theme * style.Theme, cb ActionCallback) * Basic {
- b := &Basic{}
-
- LastID++
- b.ID = LastID
-
- if parent != nil {
- b.Be = parent.Backend()
- if parent.Theme() != nil {
- b.MyTheme = * parent.Theme()
- }
-
- if root, ok := parent.(RootWidget) ; ok {
- b.MyRoot = root
- } else {
- b.MyRoot = parent.Root()
- }
-
- b.MyParent = parent
- box := Bounds(parent.Top(), parent.Left(), parent.Width(), parent.Height())
- b.SetBounds(&box)
- }
-
- if bounds != nil {
- b.SetBounds(bounds)
- }
-
- if theme != nil {
- b.MyTheme = *theme
- }
-
- if cb != nil {
- b.ActionCallback = cb
- }
- return b;
- }
- func NewBasic(parent Widget, bounds * Box, cb ActionCallback) * Basic {
- return NewBasicWithTheme(parent, bounds, nil, cb)
- }
- func NewBasicWidgetWithTheme(parent Widget, bounds * Box, theme * style.Theme, cb ActionCallback) Widget {
- return Widget(NewBasicWidgetWithTheme(parent, bounds, theme, cb));
- }
- func NewBasicWidget(parent Widget, bounds * Box, cb ActionCallback) Widget {
- return Widget(NewBasicWidget(parent, bounds, cb));
- }
- func (b Basic) Backend() backend.Backend {
- return b.Be
- }
- func (b Basic) Parent() Widget {
- return b.MyParent
- }
- func (b Basic) Root() RootWidget {
- return b.MyRoot
- }
- func (b Basic) Children() []Widget {
- return b.MyChildren
- }
- func (b * Basic) AddChild(widget Widget) Widget {
- b.MyChildren = append(b.MyChildren, widget)
- return widget
- }
- func (bw *Basic) Action(ev event.Action) event.Result {
- monolog.Info("Action");
- if bw.ActionCallback != nil {
- return bw.ActionCallback(bw, ev.Data)
- }
- return event.Pass;
- }
-
- func (bw *Basic) Update(ev event.Update) event.Result { monolog.Info("Update"); return event.Pass; }
- func (bw *Basic) Draw(ev event.Draw) event.Result { monolog.Info("Draw"); return event.Pass; }
- func (bw *Basic) Resize(ev event.Resize) event.Result { monolog.Info("Resize"); return event.Pass; }
- func (bw *Basic) Destroy(ev event.Destroy) event.Result { monolog.Info("Destroy"); return event.Pass; }
- func (bw *Basic) Close(ev event.Close) event.Result { monolog.Info("Close"); return event.Pass; }
- func (bw *Basic) NewChild(ev event.NewChild) event.Result { monolog.Info("Child"); return event.Pass; }
- func (bw *Basic) JoystickButtonPress(ev event.Joystick) event.Result { monolog.Info("JBP"); return event.Pass; }
- func (bw *Basic) JoystickButtonRelease(ev event.Joystick) event.Result { monolog.Info("JBR"); return event.Pass; }
- func (bw *Basic) JoystickAxis(ev event.Joystick) event.Result { monolog.Info("JAX"); return event.Pass; }
- func (bw *Basic) KeyPress(ev event.Key) event.Result { monolog.Info("KEP"); return event.Pass; }
- func (bw *Basic) KeyRelease(ev event.Key) event.Result { monolog.Info("KER"); return event.Pass; }
- func (bw *Basic) MouseAxes(ev event.Mouse) event.Result { monolog.Info("MAX"); return event.Pass; }
- func (bw *Basic) MouseWarped(ev event.Mouse) event.Result { monolog.Info("MWA"); return event.Pass; }
- func (bw *Basic) MouseButtonPress(ev event.Mouse) event.Result { monolog.Info("MBP"); return event.Pass; }
- func (bw *Basic) MouseButtonRelease(ev event.Mouse) event.Result { monolog.Info("MBR"); return event.Pass; }
- func (bw *Basic) MouseEnterDisplay(ev event.Mouse) event.Result { monolog.Info("MED"); return event.Pass; }
- func (bw *Basic) MouseLeaveDisplay(ev event.Mouse) event.Result { monolog.Info("MLD"); return event.Pass; }
- func (bw *Basic) TouchBegin(ev event.Touch) event.Result { monolog.Info("TB"); return event.Pass; }
- func (bw *Basic) TouchEnd(ev event.Touch) event.Result { monolog.Info("TE"); return event.Pass; }
- func (bw *Basic) TouchMove(ev event.Touch) event.Result { monolog.Info("TM"); return event.Pass; }
- func (bw *Basic) TouchCancel(ev event.Touch) event.Result { monolog.Info("TC"); return event.Pass; }
- func (bw *Basic) Default(ev event.Event) event.Result {
- monolog.Warning("Warning using default event handler for type %d %s!", ev.Type(), event.String(ev));
- return event.Pass;
- }
- func (bw *Basic) KeyChar(kc event.Key) event.Result {
- monolog.Info("KeyChar of Basic")
- return event.Done
- }
- // Checks if the coordinates are inside the main rectange of the widget.
- func (bw *Basic) IsInside(x, y int) bool {
- return (x >= bw.X) && (x <= bw.X + bw.W) && (y >= bw.Y) && (y <= (bw.Y + bw.H))
- }
- func (bw * Basic) String() string {
- return fmt.Sprintf("widget %d", bw.ID)
- }
- func DispatchRecursive(bw Widget, ev event.Event) event.Result {
- res := event.Dispatch(ev, bw)
- dlev := "INFO"
- switch ev.(type) {
- case event.Draw: dlev = "DEBUG"
- case event.Update: dlev = "DEBUG"
- case event.Mouse: if ev.Type() == event.TypeMouseAxes { dlev = "DEBUG" ; }
- default: break
- }
- monolog.Log(dlev, "Parent dispatch: %s -> %s", event.String(ev), bw.String())
- if event.Done != res {
- one_ok := false
- for _ , child := range bw.Children() {
- monolog.Log(dlev, "Child dispatch: %v -> %s", child, event.String(ev))
- res := event.Dispatch(ev, child)
- if res == event.Done {
- one_ok = true
- }
- }
- if one_ok {
- return event.Done
- } else {
- return event.Pass
- }
- } else {
- return event.Done
- }
- }
- func (bw * Basic) Dispatch(ev event.Event) event.Result {
- return DispatchRecursive(bw, ev)
- }
- /** Returns whether or not a widget will even handle an event in the first place.
- * For example, a hidden widget won't draw, and a disabled widget won't
- * accept any system events, and a NULL widget doesn't accept events at all.. */
- func (bw * Basic) AcceptsEvent(ev event.Event) bool {
- switch ev.(type) {
- case event.Draw: return bw.Visible()
- default: return bw.Active()
- }
- }
- func (bw * Basic) Priority() int {
- return bw.Z
- }
- func (bw * Basic) Compare(w Widget) int {
- return (w.Priority() - bw.Priority())
- }
- /* Gets the theme to use for a marked widget. Looks up a root widget and then
- * looks for the cursor to determine this. */
- func (bw * Basic) MarkedTheme() style.Theme {
- return bw.Root().MarkedTheme()
- }
- /* Gets the style to use for a hovered widget. Looks up a screen widget and then
- * looks for the cursor t determine this. */
- func (bw * Basic) HoveredTheme() style.Theme {
- return bw.Root().HoveredTheme()
- }
- /* Sets the widget's margins */
- func (bw * Basic) SetMargins(left, top, right, bottom int) * Basic {
- bw.Outer = bw.Box
- bw.Outer.X -= left
- bw.Outer.Y -= top
- bw.Outer.W += (left+ right)
- bw.Outer.H += (top + bottom)
- return bw
- }
- /* Sets the widget's margins, all equal */
- func (bw * Basic) SetMargin(size int) * Basic {
- return bw.SetMargins(size, size, size, size)
- }
- /* Sets the widget's paddins */
- func (bw * Basic) SetPaddings(left, top, right, bottom int) * Basic {
- bw.Inner = bw.Box
- bw.Inner.X += left
- bw.Inner.Y += top
- bw.Inner.W -= (left+ right)
- bw.Inner.H -= (top + bottom)
- return bw
- }
- /* Sets the widget's paddings, all equal */
- func (bw * Basic) SetPadding(size int) * Basic {
- return bw.SetPaddings(size, size, size, size)
- }
- /* Draws a widget's frame based on it's style. If the background bitmap is set
- * then that is used, otherwise, the background color is used, including a border
- * if needed. */
- func (bw * Basic) DrawBackground() {
- be := bw.Backend()
- dx := bw.X
- dy := bw.Y
- dw := bw.W
- dh := bw.H
-
- theme := bw.MyTheme
-
- if bw.Hovered() {
- theme = bw.HoveredTheme()
- } else if bw.Marked() {
- theme = bw.MarkedTheme()
- }
-
- if theme.Background.Bitmap != nil {
- bmp := theme.Background.Bitmap
- sw := bmp.Width()
- sh := bmp.Height()
- // XXX should use draw9 algorithm here
- be.DrawScaledBitmap(0,0,sw,sh,dx,dy,dw,dh, bmp)
- } else {
- fillcol := theme.Background.Color
- bordcol := theme.Border.Color
- thick := theme.Border.Size
- rad := theme.Border.Radius
- be.DrawRoundedSlab(dx, dy, dw, dh, rad, rad, fillcol)
- be.DrawRoundedRectangle(dx, dy, dw, dh, rad, rad, bordcol, thick)
- }
- }
- func (bw * Basic) SetState(flag state.Flag, set bool) bool {
- if set {
- bw.Flag |= flag
- } else {
- bw.Flag &= (^flag)
- }
- return bw.IsState(flag)
- }
- func (bw * Basic) IsState(flag state.Flag) bool {
- return ((bw.Flag & flag) == flag)
- }
- func (bw * Basic) Visible() bool {
- return bw != nil && ((bw.Flag & state.HIDDEN) != state.HIDDEN)
- }
- func (bw * Basic) Active() bool {
- return bw != nil && ((bw.Flag & state.DISABLED) != state.DISABLED )
- }
- func (bw * Basic) Hovered() bool {
- return bw != nil && bw.IsState(state.HOVERED)
- }
- func (bw * Basic) Marked() bool {
- return bw != nil && bw.IsState(state.MARKED)
- }
- func (bw * Basic) SetHovered(set bool) bool {
- return bw.SetState(state.HOVERED, set)
- }
- func (bw * Basic) SetMarked(set bool) bool {
- return bw.SetState(state.MARKED, set)
- }
- func (bw * Basic) SetActive(set bool) bool {
- bw.SetState(state.DISABLED, !set)
- return bw.Active()
- }
- func (bw * Basic) SetVisible(set bool) bool {
- bw.SetState(state.HIDDEN, !set)
- return bw.Visible()
- }
- /** Get active and visible */
- func (bw * Basic) Live() bool {
- return bw.Active() && bw.Visible()
- }
- /** Set active and visible */
- func (bw * Basic) SetLive(live bool) {
- bw.SetActive(live)
- bw.SetVisible(live)
- }
- func (bw * Basic) FindParent(predicate func (wi Widget) bool) Widget {
- for parent := bw.Parent() ; parent != nil ; parent = parent.Parent() {
- if predicate(parent) {
- return parent
- }
- }
- return nil
- }
- func (bw * Basic) Mark() event.Result {
- root := bw.Root().(*Root)
- root.Cursors.Keyjoy.Point = bw.Box.Point
- return event.Done
- }
- /* Moves the widget by the offset (dx, dy). Does not move it's children. */
- func (bw * Basic) MoveSelfBy(dx, dy int) {
- bw.Box.X += dx
- bw.Box.Y += dy
- bw.Inner.X += dx
- bw.Inner.Y += dy
- bw.Outer.X += dx
- bw.Outer.Y += dy
- }
- /* Resizes the widget by the offset (dw, dh). Does not move it's children. */
- func (bw * Basic) ResizeSelfBy(dw, dh int) {
- bw.Box.W += dw
- bw.Box.H += dh
- bw.Inner.W += dw
- bw.Inner.H += dh
- bw.Outer.W += dw
- bw.Outer.H += dh
- }
- /* Moves the widget by the offset (dx, dy). It's children will be moved as well recursively
- * keeping the offset */
- func (bw * Basic) MoveBy(dx, dy int) {
- bw.MoveSelfBy(dx, dy)
- for _, child := range bw.MyChildren {
- child.MoveBy(dx, dy)
- }
- }
- /* Moves the widget to (x, y). It's children will be moved as well recursively
- * keeping the offset */
- func (bw * Basic) MoveTo(x, y int) {
- dx := bw.Box.X - x
- dy := bw.Box.Y - y
- bw.MoveBy(dx, dy)
- }
- /* Moves the widget to (x, y). Doesn't move children. */
- func (bw * Basic) MoveSelfTo(x, y int) {
- dx := bw.Box.X - x
- dy := bw.Box.Y - y
- bw.MoveSelfBy(dx, dy)
- }
- /* Resizes the widget to (w, h). Doesn't resize children. Margins and padding will be
- * resized accordingly. */
- func (bw * Basic) ResizeSelfTo(w, h int) {
- dx := bw.Box.W - w
- dy := bw.Box.H - h
- bw.ResizeSelfBy(dx, dy)
- }
-
-
- /* Makes the widget fit itself to all direct children.
- * Does not resize nor move the children.
- */
- func (bw * Basic) FitToChildren(w, h int) {
- min_x := 640
- min_y := 480
- min_w := 0
- min_h := 0
- be := bw.Backend()
-
- if be.Display() != nil {
- min_x = be.Display().Width()
- min_y = be.Display().Height()
- }
-
- for _,child := range bw.MyChildren {
- if child.Left() < min_x {
- min_x = child.Left()
- }
- if child.Top() < min_y {
- min_y = child.Top()
- }
- if child.Width() > min_w {
- min_w = child.Width()
- }
- if child.Height() > min_h {
- min_w = child.Height()
- }
- }
-
- bw.MoveSelfTo(min_x, min_y)
- bw.ResizeSelfTo(min_w, min_h)
- }
- /* Style getters for ease of use. */
- func (bw * Basic) TextFont() Font {
- theme := bw.MyTheme
- if (theme.Text.Font != nil) {
- return theme.Text.Font
- }
-
- if bw.MyParent != nil {
- return bw.Root().Theme().Text.Font
- }
- return nil
- }
- func (bw * Basic) TextColor() Color {
- theme := bw.MyTheme
- return theme.Text.Color
- }
- func (bw * Basic) BackgroundColor() Color {
- theme := bw.MyTheme
- return theme.Background.Color
- }
|