Browse Source

Working on Engine and GUI.

Beoran 6 years ago
parent
commit
8609fe749b

+ 25 - 5
engine/global/state.go

@@ -122,16 +122,15 @@ func (ms * State) OpenDisplay(w, h int, title string, fullscreen bool) * al.Disp
     ms.Fullscreen = fullscreen
     ms.W          = w
     ms.H          = h
-    flags := 0
+    flags        := 0
     // Use full screen mode if needed.
     if fullscreen {
         flags = al.FULLSCREEN // | GENERATE_EXPOSE_EVENTS
-    } else {
-        al.SetNewDisplayFlags(flags)
     }
+    al.SetNewDisplayFlags(flags)
     // Create a window to display things on: 640x480 pixels.
     display := al.CreateDisplay(w, h)
-    display.Resize(w, h)
+    // display.Resize(w, h)
     if !(fullscreen) {
         display.SetWindowTitle(title)
     }
@@ -146,6 +145,8 @@ func (ms * State) OpenDisplay(w, h int, title string, fullscreen bool) * al.Disp
     ms.Camera.W = ms.Display.Widthf()
     ms.Camera.H = ms.Display.Heightf()
     
+    tile.InitBlendMasks();
+    
     return display
 }
 
@@ -217,11 +218,29 @@ func (ms * State) Draw() {
 }
 
 func (ms * State) Load() {
-    ms.LoadMap("map/map_0001_tiled11.tmx")
+    ms.LoadMap("map/map_0001_tiled115.tmx")
+}
+
+func (ms * State) Close() {
+    if ms.Map != nil {
+        ms.Map.Close()
+        ms.Map = nil
+    }
+    
+    if ms.Queue != nil {
+        ms.Queue.Destroy()
+        ms.Queue = nil
+    }
+    
+    if ms.Display != nil {
+        ms.Display.Destroy()
+        ms.Display = nil
+    }
 }
 
 func (ms * State) Run() {
     ms.Load()
+    defer ms.Close()
     
     for !ms.Done {
         ms.Draw()
@@ -231,6 +250,7 @@ func (ms * State) Run() {
 }
 
 
+
 func (ms * State) HandleEvents() {
     for event, ok := ms.Queue.GetNextEvent() ; ok ; event, ok = ms.Queue.GetNextEvent() {
         ms.HandleEvent(event.Event())

+ 5 - 0
engine/tile/io.go

@@ -395,6 +395,11 @@ func LoadPane(xml_pane * etree.Element, index int, tm * Map) (* Pane, error) {
             }
         }
     }
+    
+    monolog.Log("TILEIO", "Loaded pane, initializing blends")
+    pane.InitBlend(index)
+    
+    
     return pane, nil
 }
 

+ 20 - 1
engine/tile/map.go

@@ -121,7 +121,7 @@ func (tm * Map) Draw(camera * physics.Camera) {
         if pane != nil {
             pane.DrawTiles(camera)
             if ( i % 2 ) == 0 {
-                // pane.DrawBlends(camera)
+                pane.DrawBlends(camera)
                 // floor =  pane
             } else if (i % 2) == 1 {
                 // pane.DrawShadowsOn(floor, camera)
@@ -140,6 +140,25 @@ func (tm * Map) Update(dt float64) {
     }
 }    
 
+/** Closes the map after use. Loaded bitmaps are unloaded immediately. */
+func (tm * Map) Close() {
+    for i := 0 ; i < len(tm.Panes) ; i ++ {
+        pane := tm.Panes[i]
+        if pane != nil {
+            pane.Close()
+        }
+        tm.Panes[i] = nil
+    }
+    for i := 0 ; i < len(tm.Sets) ; i ++ {
+        pane := tm.Sets[i]
+        if pane != nil {
+            pane.Close()
+        }
+        tm.Sets[i] = nil
+    }
+}
+
+
 
 /** Sets up the camera so it will stay locked in to the 
 given layer of the tile map */

+ 31 - 12
engine/tile/pane.go

@@ -6,6 +6,7 @@ import "gitlab.com/beoran/al5go/al"
 // import "gitlab.com/beoran/ebsgo/engine/geometry/point"
 import "gitlab.com/beoran/ebsgo/engine/physics"
 import "gitlab.com/beoran/ebsgo/engine/fifi"
+import "gitlab.com/beoran/ebsgo/monolog"
 
 
 
@@ -36,7 +37,7 @@ const (
     BLEND_GRADUAL              = 1
     BLEND_FUZZY                = 2
     BLEND_FUZZY_GRADUAL        = 3
-    BLEND_TYPE_MAX             = 4
+    BLEND_TYPE_MAX             = 3 // XXX data for type FUZZY_GRADUAL is missing...
 )
 
 const BLEND_BITMAPS_MAX = 255 
@@ -592,11 +593,8 @@ var BlendOffsets [8]BlendOffset = [8]BlendOffset{
 }
 
 func (pane * Pane) InitBlendTile(index, tx, ty int, tile * Tile) bool {
-    blend := pane.Blend(tx, ty)
-    if blend != nil {
-        blend.Destroy()
-        pane.SetBlend(tx, ty, nil)
-    }
+    // SetBlend calls Destoy() on the bitmap automagically
+    pane.SetBlend(tx, ty, nil)
     
     target          := al.TargetBitmap()
     tile_prio       := tile.Blend
@@ -631,7 +629,7 @@ const (
     MASK_H          = 8
 )
 
-func (pane * Pane) InitMasks() {
+func InitBlendMasks() {
     // load the masks into the pane
     for blend_type := 0; blend_type < BLEND_TYPE_MAX ; blend_type++ {
         fin1 := fmt.Sprintf("/image/masks/corner_mask_%d.png", blend_type)
@@ -641,25 +639,46 @@ func (pane * Pane) InitMasks() {
         bmp2 := fifi.LoadBitmap(fin2)
         BlendMasks[blend_type][BLEND_CORNER]    = bmp1
         BlendMasks[blend_type][BLEND_SIDE]      = bmp2
+        if bmp1 == nil {
+            monolog.Error("Could not load blend mask %d %d", blend_type, BLEND_CORNER)
+        }
+        if bmp2 == nil {
+            monolog.Error("Could not load blend mask %d %d", blend_type, BLEND_SIDE)
+        }
     }
 }
 
 func (pane * Pane) InitBlend(index int) bool {
     if pane == nil        { return false }
     if pane.Blends == nil { return false }
-    if index > 4          { return false }
-    tx := 0
-    ty := 0
     w  := pane.GridW
     h  := pane.GridH
-    for ty = 0 ; ty < h; ty++ { 
-        for tx = 0; tx < w; tx++ {
+    for ty := 0 ; ty < h; ty++ { 
+        for tx := 0; tx < w; tx++ {
             tile := pane.Tile(tx, ty)
             if tile == nil { continue; }
             if tile.Blend < 1 { continue; }
+            monolog.Info("Will it blend? %d %d %d", tx, ty, tile.Blend)
             pane.InitBlendTile(index, tx, ty, tile)
         }
     }
     return true
 }
 
+func (pane * Pane) Close() {
+    // No need to close tile set, the map will close them.
+    w  := pane.GridW
+    h  := pane.GridH
+    for ty := 0 ; ty < h; ty++ { 
+        for tx := 0; tx < w; tx++ {
+            pane.SetBlend(tx, ty, nil)
+        }
+    }
+    
+    if pane.Blends != nil {
+        pane.Blends.Destroy()
+        pane.Blends = nil
+    }
+}
+
+

+ 23 - 18
engine/tile/tile.go

@@ -1,5 +1,6 @@
 package tile
 
+import "fmt"
 import "gitlab.com/beoran/ebsgo/monolog"
 // import "os"
 // import "math"
@@ -72,7 +73,7 @@ type Tile struct {
   /* Automatic shadow mask number. */
   ShadowMask    int
   /* Tiled-style animation frames. */
-  Frames        []Frame
+  Frames        []*Frame
   /* Active frame for TMX-style animations. */
   ActiveFrame   int
 };
@@ -103,6 +104,13 @@ func NewSet(sheet * al.Bitmap, tile_w, tile_h, firstgid int) * Set {
     return set
 }
 
+func (set * Set) Close() {
+    if set.Sheet != nil {
+        set.Sheet.Destroy()
+        set.Sheet = nil
+    }
+}
+
 func (tile * Tile) Init(set * Set, index int) {
     tile.Tileset    = set
     tile.Index      = index
@@ -202,6 +210,9 @@ func (frame * Frame) Init(index int, duration float64) {
     frame.Duration  = duration
 }
 
+func (frame Frame) String() string {
+    return fmt.Sprintf("frame: %d", frame.Index)
+}
 
 /** Gets the nth frame of Tiled style animations for this tile 
  * or NULL if no such animation frame. */
@@ -209,13 +220,13 @@ func (tile Tile) Frame(index int)  * Frame {
     if nil == tile.Frames{ 
        return nil
     } else { 
-        return &tile.Frames[index]
+        return tile.Frames[index]
     }
 } 
 
 /** Gets the amount of Tiled style animations for this tile, or 0 if none. */
 func (tile Tile) FrameCount() int {
-  if nil == tile.Frames { 
+    if nil == tile.Frames { 
        return 0
     } else { 
         return len(tile.Frames)
@@ -224,14 +235,8 @@ func (tile Tile) FrameCount() int {
 
 /** Adds a Tiled-style animation frame to the tile. */
 func (tile * Tile) AddAnimationFrame(index int, duration float64) (frame * Frame) {
-    if (nil == tile.Frames) {
-        tile.Frames = make([]Frame, 1)
-        frame       = &tile.Frames[0] 
-    } else {
-        frame       = &Frame{}
-        tile.Frames = append(tile.Frames, *frame)
-    }
-    
+    frame       = &Frame{}
+    tile.Frames = append(tile.Frames, frame)
     frame.Init(index, duration)
     return frame
 }
@@ -254,18 +259,18 @@ func (tile * Tile) UpdateAnimation(dt float64) {
   if nil == frame { /* Animation overshot itself */
     tile.ActiveFrame = 0
     frame = tile.Frame(tile.ActiveFrame)
-    if nil == frame {
+    if nil == frame { /* Tile has no frames at all. */
          return
     }
   }
   
-  monolog.Log("TILE", "Animation for tile: %d %d %f %f\n", 
-    tile.ActiveFrame, frame.Index, frame.Duration, tile.Time)
+  /* monolog.Log("TILE", "Animation for tile: %d %d %f %f\n", 
+    tile.ActiveFrame, frame.Index, frame.Duration, tile.Time) */
 
   
   tile.Time += dt // advance animation time of tile. 
   // Don't animate if not enough time has passed
-  if tile.Time < frame.Duration {
+  if tile.Time < (frame.Duration * 10.0) {
       return
   }
   // advance the animation frame, loop it around if needed. 
@@ -282,8 +287,8 @@ func (tile * Tile) UpdateAnimation(dt float64) {
        return
   }
   
-  monolog.Log("TILE", "Animation for tile: %d %d %f %f %b\n", 
-    tile.ActiveFrame, frame.Index, frame.Duration, tile.Time)
+  monolog.Log("TILE", "Animation for tile: %d %d %d %d %v\n", 
+    tile.ActiveFrame, frame.Index, frame.Duration, tile.Time, tile.Frames)
 
   // Get the active tile to use from the animation frame
   active   = frame.Index
@@ -296,7 +301,7 @@ func (tile * Tile) UpdateAnimation(dt float64) {
   tile.Active = active
   // Finally recalculate tile position.
   tile.Recalculate()
-  monolog.Log("TILE", "Updated animation for tile: %d\n", tile.Active)
+  monolog.Log("TILE", "Updated animation for tile: %d %d\n", tile.Active, frame.Index)
 }
 
 /* Animates the tile. Animates the tile if it has animation frames. */

+ 33 - 0
zori/backend/backend.go

@@ -0,0 +1,33 @@
+package backend
+
+import . "gitlab.com/beoran/ebsgo/zori/types"
+import "gitlab.com/beoran/ebsgo/zori/event"
+
+
+type Loader interface {
+    Bitmap(name string) (Bitmap, error)
+    Font(name string) (Bitmap, error)
+}
+
+type Drawer interface {
+    Bitmap(x, y int, bitmap Bitmap)
+    ScaledBitmap(x, y, dw, dh int, bitmap Bitmap)
+    Rectangle(x, y, w, h int, color Color)
+    Slab(x, y, w, h int, color Color)
+    RoundedRectangle(x, y, w, h, rx, ry int, color Color)
+    RoundedSlab(x, y, w, h, rx, ry int, color Color)
+}
+
+
+type Poller interface {
+    Empty() bool
+    Poll() event.Event
+}
+
+type Backend interface {
+    Display()   Display
+    Load()      Loader
+    Draw()      Drawer
+    Queue()     Poller
+    Close()
+}

+ 285 - 0
zori/event/event.go

@@ -0,0 +1,285 @@
+/* event handler and events for the Zori module. */
+
+package event
+
+import . "gitlab.com/beoran/ebsgo/zori/types"
+
+
+type Basic struct {
+    Stamp  float64
+    // Widget Widget
+    Data   interface{}
+}
+
+func (be Basic) Timestamp() float64 {
+    return be.Stamp
+}
+
+/* Update event, when UI has to update (animations, etc). */
+type Update struct {
+    Basic
+    TimePassed float64
+}
+
+/* Resize event, when the parent of an element has resized. */
+type Resize struct {
+    Basic
+    NewSize Box
+}
+
+/* Draw event when the UI has to draw itself. */
+type Draw struct {
+    Basic
+}
+
+/* Cleanup event. */
+type Destroy struct {
+    Basic
+}
+
+/* Action event. */
+type Action struct {
+    Basic
+}
+
+/* Close event. */
+type Close struct {
+    Basic
+    // Parent Widget
+}
+
+/* Close event. */
+type NewChild struct {
+    Basic
+    // Child Widget
+}
+
+type Event interface {
+    Timestamp() float64
+}
+
+type JoyButtonPress interface {
+    ID() int
+    Button() int
+    IsJoyButtonPress()
+}
+
+type JoyButtonRelease interface {
+    ID() int
+    Button() int
+    IsJoyButtonRelease()
+}
+
+type JoyAxis interface {
+    Event
+    ID() int
+    Stick() int
+    Axis() int
+    Pos() float32
+    IsJoyAxis()
+}
+
+type KeyPress interface {
+    Event
+    KeyCode() int
+    Display() Display
+    IsKeyPress()
+}
+
+type KeyRelease interface {
+    Event
+    KeyCode() int
+    Display() Display
+    IsKeyRelease()
+}
+
+type KeyChar interface {
+    Event
+    KeyCode() int
+    Display() Display
+    Unichar() rune
+    Modifiers() int
+    Repeat() bool
+    IsKeyChar()
+}
+
+type MouseAxes interface {
+    Event
+    Display() Display
+    X() int
+    Y() int
+    Z() int
+    W() int
+    DX() int
+    DY() int
+    DZ() int
+    DW() int
+    Pressure() float32
+}
+
+type MouseWarped interface {
+    Event
+    Display() Display
+    X() int
+    Y() int
+    Z() int
+    W() int
+    DX() int
+    DY() int
+    DZ() int
+    DW() int
+    Pressure() float32
+}
+
+type MouseButtonPress interface {
+    Event
+    Display() Display
+    X() int
+    Y() int
+    Z() int
+    W() int
+    Button() int
+    Pressure() float32
+}
+
+type MouseButtonRelease interface {
+    Event
+    Display() Display
+    X() int
+    Y() int
+    Z() int
+    W() int
+    Button() int
+    Pressure() float32
+}
+
+type MouseEnterDisplay interface {
+    Event
+    Display() Display
+    X() int
+    Y() int
+    Z() int
+    W() int
+}
+
+type MouseLeaveDisplay interface {
+    Event
+    Display() Display
+    X() int
+    Y() int
+    Z() int
+    W() int
+}
+
+
+type Touch interface {
+    Event
+    Display() Display
+    X() int
+    Y() int
+    DX() int
+    DY() int
+    ID() int
+    Primary() bool
+}
+
+type TouchBegin interface {
+    Touch
+}
+
+
+type TouchEnd interface {
+    Touch
+}
+
+type TouchMove interface {
+    Touch
+}
+
+type TouchCancel interface {
+    Touch
+}
+
+
+type Result bool
+
+type UIHandler interface {
+    Update(ev Update) Result
+    Resize(ev Resize) Result
+    Draw(ev Draw) Result    
+    Destroy(ev Destroy) Result
+    Action(ev Action) Result
+    Close(ev Close) Result
+    NewChild(ev NewChild) Result
+}
+
+type JoyHandler interface {
+    JoyButtonPress(ev JoyButtonPress) Result
+    JoyButtonRelease(ev JoyButtonRelease) Result
+    JoyAxis(ev JoyAxis) Result
+}
+
+type KeyHandler interface {
+    KeyPress(ev KeyPress) Result
+    KeyRelease(ev KeyRelease) Result
+    KeyChar(ev KeyChar) Result
+}
+
+type MouseHandler interface {
+    MouseAxes(ev MouseAxes) Result
+    MouseWarped(ev MouseWarped) Result
+    MouseButtonPress(ev MouseButtonPress) Result
+    MouseButtonRelease(ev MouseButtonRelease) Result
+    MouseEnterDisplay(ev MouseEnterDisplay) Result
+    MouseLeaveDisplay(ev MouseLeaveDisplay) Result
+}
+
+type TouchHandler interface {
+    TouchBegin(ev TouchBegin) Result
+    TouchEnd(ev TouchEnd) Result
+    TouchMove(ev TouchMove) Result
+    TouchCancel(ev TouchCancel) Result    
+}
+
+
+/* Handler is an interface for a type that can handle all 
+ * of Zori's events. */
+type Handler interface {
+    UIHandler
+    JoyHandler
+    KeyHandler
+    MouseHandler
+    TouchHandler
+    Default(ev Event) Result
+}
+
+
+func Dispatch(event Event, handler Handler) Result {
+    switch de := event.(type) {
+    case Update:             return handler.Update(de)
+    case Draw:               return handler.Draw(de)
+    case Destroy:            return handler.Destroy(de)
+    case Action:             return handler.Action(de)
+    case Close:              return handler.Close(de)
+    case NewChild:           return handler.NewChild(de)
+    case JoyButtonPress:     return handler.JoyButtonPress(de)
+    case JoyButtonRelease:   return handler.JoyButtonRelease(de)
+    case JoyAxis:            return handler.JoyAxis(de)
+    case KeyPress:           return handler.KeyPress(de)
+    case KeyRelease:         return handler.KeyRelease(de)
+    case KeyChar:            return handler.KeyChar(de)
+    case MouseAxes:          return handler.MouseAxes(de)
+    case MouseWarped:        return handler.MouseWarped(de)
+    case MouseButtonPress:   return handler.MouseButtonPress(de)
+    case MouseButtonRelease: return handler.MouseButtonRelease(de)
+    case MouseEnterDisplay:  return handler.MouseEnterDisplay(de)
+    case MouseLeaveDisplay:  return handler.MouseLeaveDisplay(de)
+    case TouchBegin:         return handler.TouchBegin(de)
+    case TouchEnd:           return handler.TouchEnd(de)
+    case TouchMove:          return handler.TouchMove(de)
+    case TouchCancel:        return handler.TouchCancel(de)            
+    default:                 return handler.Default(event)
+    }
+}
+
+

+ 14 - 0
zori/state/state.go

@@ -0,0 +1,14 @@
+package state
+
+type Flag int
+
+/* Generic state flags for several zori structs. */
+const (
+    HIDDEN      = Flag(1 << iota)
+    DISABLED    = Flag(1 << iota)
+    HOVERED     = Flag(1 << iota)
+    MARKED      = Flag(1 << iota)
+    READY       = Flag(1 << iota)
+    DEACTIVATED = DISABLED | HIDDEN
+)
+

+ 133 - 0
zori/style/style.go

@@ -0,0 +1,133 @@
+package style
+
+import . "gitlab.com/beoran/ebsgo/zori/types"
+
+type Flag int
+
+const (
+    BORDER  = Flag(1)
+    FILL    = Flag(2)
+    DEFAULT = Flag(3)
+)
+
+/**
+ * For style: not all combinations make sense. How to improve this?
+ *
+ * What is available in CSS 1:
+ *
+ * font : font of the text (with many sub details in CCS not relevant here).
+ * color: text color of an element
+ * background-color: background color of an element.
+ * background-image: background image of an element.
+ * background-repeat: determines how/if the image is repeated.
+ * background-attachment: fixed with regard to the canvas.
+ * background-position: initial position of the background image.
+ * word-spacing: text spacing
+ * letter-spacing: text spacing
+ * text-decoration: text decoration (underline, overline, etc)
+ * vertical-align: vertical alignment, top, center, bottom based on the parent.
+ * text-transform:
+ * text-align: text alignment, left, right, centered.
+ * text-indent: Text indentation.
+ * line-height: Height of a line of text.
+ * margin: sizes of the margin
+ * padding: sizes of the padding
+ * border-width: sizes of the border
+ * border-color: color of the border
+ * border-style: style of the border (per side)
+ * border: border style, general of per side
+ * width: width of the box
+ * height: height of the box
+ * float: floating
+ * clear: float control
+ * display: display type (visual, block, hiden, none, etc)
+ * white-space: white space display.
+ * list-style: list styling with type, image and position of the image.
+ *
+ * Squeezing it down to the essential, we retain:
+ *
+ * text.font    : Font for texts.
+ * text.color   : Color for texts.
+ * text.flags   : Style flags, merges horizontal alignment, decoration, etc.
+ *
+ * back.color   : Background color.
+ * back.image   : Background image.
+ * back.flags   : Style flags, solid background, no background, etc.
+ * back.radius  : Size of corner for image_scale9 algorithm.
+ *
+ * border.color : Border color.
+ * border.size  : Border size (thickness).
+ * border.flags : Border style flags.
+ * border.radius: Rounded corners radius.
+ *
+ * cursor.color   : Text cursor color.
+ *
+ * mouse.back     : Mouse cursor background information.
+ * mouse.border   : Mouse cursor border.
+ * keyjoy.back    : Keyjoy cursor background information.
+ * keyjoy.border  : Keyjoy cursor border.
+ *
+ *
+ * width, height, margins and padding are not considered style but positioning.
+ * The keyjoy and mouse cursor and a border are only available
+ * per-screen.
+ *
+ * The text cursor has a color only.
+ *
+ * 1. Text can have a font, a color and font flags (centered, etc)
+ * 2. A rectangle / container / widget can have a background image combined
+ * with a background color it can have draw flags for the background image and
+ * for the color (fill or not). Furthermore it can have a border color.
+ * Possibly (through not suupported now) would be a background
+ *
+ *
+ */
+
+type Basic struct {
+    Color
+    Bitmap
+    Flag
+    Radius int
+}
+
+/* The style of the background of a widget. */
+type Background struct {
+    Basic
+}
+
+/* The style of the border of a widget.  */
+type Border struct {
+    Basic
+    Size int
+}
+
+/* A text style has all elements needed to style a piece of text.
+ * It consists of the text color, font and font flags flags applied to a part of the GUI.
+ */
+type Text struct {
+    Color
+    Font
+}
+
+/* A theme is a set of style elements for a widget or cursor. */
+type Theme struct {
+    Background
+    Border
+    Text
+}
+
+type Themed interface {
+    Theme() Theme
+}
+
+
+type BasicThemed struct {
+    Looks Theme
+}
+
+func (bs BasicThemed) Theme() * Theme {
+    return & bs.Looks
+}
+
+
+

+ 59 - 0
zori/types/types.go

@@ -0,0 +1,59 @@
+package types
+
+type Sized interface {
+    Width() int
+    Height() int
+}
+
+type Positioned interface {
+    Top() int
+    Left() int
+}
+
+type Color interface {
+}
+
+type Point struct {
+    X int
+    Y int
+}
+
+func (p Point) Left() int {
+    return p.X
+}
+
+func (p Point) Top() int {
+    return p.Y
+}
+
+type Box struct {
+    Point
+    W int
+    H int
+}
+
+func (re Box) Width() int {
+    return re.W
+}
+
+func (re Box) Height() int {
+    return re.W
+}
+
+type Bitmap interface {
+    Sized
+    Close()
+}
+
+type Font interface {
+    Width(string) int
+    Height(string) int
+    Draw(x, y int, color Color, text string)
+    Close()
+}
+
+type Display interface {
+    Sized
+}
+
+

+ 66 - 0
zori/widget/basic.go

@@ -0,0 +1,66 @@
+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"
+
+
+type Basic struct {
+    ID    int
+    Root  Widget
+    Box
+    Outer Box
+    Inner Box
+    Z     int
+    style.BasicThemed
+    Parent   Widget
+    Children []Widget
+    state.Flag
+    Result  interface{}
+}
+                                                                        
+func (bw *Basic) Update(ev event.Update) event.Result                         { fmt.Println("Update"); return event.Result(false); }
+func (bw *Basic) Draw(ev event.Draw) event.Result                             { fmt.Println("Draw"); return event.Result(false); }
+func (bw *Basic) Resize(ev event.Resize) event.Result                             { fmt.Println("Resize"); return event.Result(false); }
+func (bw *Basic) Destroy(ev event.Destroy) event.Result                       { fmt.Println("Destroy"); return event.Result(false); }
+func (bw *Basic) Action(ev event.Action) event.Result                         { fmt.Println("Action"); return event.Result(false); }
+func (bw *Basic) Close(ev event.Close) event.Result                           { fmt.Println("Close"); return event.Result(false); }
+func (bw *Basic) NewChild(ev event.NewChild) event.Result                     { fmt.Println("Child"); return event.Result(false); }
+func (bw *Basic) JoyButtonPress(ev event.JoyButtonPress) event.Result         { fmt.Println("JBP"); return event.Result(false); }
+func (bw *Basic) JoyButtonRelease(ev event.JoyButtonRelease) event.Result     { fmt.Println("JBR"); return event.Result(false); }
+func (bw *Basic) JoyAxis(ev event.JoyAxis) event.Result                       { fmt.Println("JAX"); return event.Result(false); }
+func (bw *Basic) KeyPress(ev event.KeyPress) event.Result                     { fmt.Println("KEP"); return event.Result(false); }
+func (bw *Basic) KeyRelease(ev event.KeyRelease) event.Result                 { fmt.Println("KER"); return event.Result(false); }
+func (bw *Basic) MouseAxes(ev event.MouseAxes) event.Result                   { fmt.Println("MAX"); return event.Result(false); }
+func (bw *Basic) MouseWarped(ev event.MouseWarped) event.Result               { fmt.Println("MWA"); return event.Result(false); }
+func (bw *Basic) MouseButtonPress(ev event.MouseButtonPress) event.Result     { fmt.Println("MBP"); return event.Result(false); }
+func (bw *Basic) MouseButtonRelease(ev event.MouseButtonRelease) event.Result { fmt.Println("MBR"); return event.Result(false); }
+func (bw *Basic) MouseEnterDisplay(ev event.MouseEnterDisplay) event.Result   { fmt.Println("MED"); return event.Result(false); }
+func (bw *Basic) MouseLeaveDisplay(ev event.MouseLeaveDisplay) event.Result   { fmt.Println("MLD"); return event.Result(false); }
+func (bw *Basic) TouchBegin(ev event.TouchBegin) event.Result                 { fmt.Println("TB"); return event.Result(false); }
+func (bw *Basic) TouchEnd(ev event.TouchEnd) event.Result                     { fmt.Println("TE"); return event.Result(false); }
+func (bw *Basic) TouchMove(ev event.TouchMove) event.Result                   { fmt.Println("TM"); return event.Result(false); }
+func (bw *Basic) TouchCancel(ev event.TouchCancel) event.Result               { fmt.Println("TC"); return event.Result(false); }
+
+func (bw *Basic) Default(ev event.Event) event.Result { 
+    fmt.Println("Warning using default event handler!"); 
+    return event.Result(false); 
+}
+
+func (bw *Basic) KeyChar(kc event.KeyChar) event.Result {
+    fmt.Println("KeyChar of Basic")
+    return event.Result(true)
+}
+
+// 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) Dispatch(ev event.Event) event.Result {
+    return event.Dispatch(ev, bw)
+}
+

+ 14 - 0
zori/widget/button.go

@@ -0,0 +1,14 @@
+package widget
+
+// 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"
+
+
+
+type Button struct {
+    Basic
+}
+
+

+ 21 - 0
zori/widget/caption.go

@@ -0,0 +1,21 @@
+package widget
+
+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"
+
+
+/* Caption helper struct for use by widgets that have captions. */
+type Caption struct {
+    Label string
+    style.Theme
+    Box
+}
+
+/* Widget with a caption. */
+type Captioned struct {
+    Basic
+    Caption
+}
+

+ 30 - 0
zori/widget/console.go

@@ -0,0 +1,30 @@
+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"
+
+
+type Console struct {
+    Basic
+    Lines  []string
+    Input  string
+    Cursor int
+}
+
+
+func (cw * Console) Dispatch(ev event.Event) event.Result {
+    return event.Dispatch(ev, cw)
+}
+
+
+func (cw *Console) KeyChar(kc event.KeyChar) event.Result {
+    cw.Basic.KeyChar(kc)
+    fmt.Println("KeyChar of ConsoleWidget")
+    return event.Result(true)
+}
+

+ 65 - 0
zori/widget/dragger.go

@@ -0,0 +1,65 @@
+package widget
+
+import "gitlab.com/beoran/ebsgo/zori/event"
+// 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"
+
+
+type Draggable interface {
+    event.MouseHandler
+    Drag(x, y, start_w, start_y int)
+    Drop(x, y, start_w, start_y int)
+    CanDrag() bool
+    IsInside(x, y int) bool
+}
+
+type Dragger struct {    
+    Draggable
+    Dragging bool
+    StartX int
+    StartY int
+}
+
+
+func (dr Dragger) MouseAxes(ev event.MouseAxes) event.Result {
+    if dr.Draggable != nil {
+        dr.Draggable.MouseAxes(ev)
+        if dr.Draggable.CanDrag() && dr.Dragging {
+            dr.Draggable.Drag(ev.X(), ev.Y(), dr.StartX, dr.StartY)
+        }
+    }
+    return event.Result(false)
+}
+
+
+func (dr Dragger) MouseButtonPress(ev event.MouseButtonPress) event.Result {
+    if dr.Draggable != nil {
+        dr.Draggable.MouseButtonPress(ev)
+        if (!dr.Draggable.IsInside(ev.X(), ev.Y()) || !dr.Draggable.CanDrag()) {
+            return event.Result(false)
+        }
+        dr.Dragging = true
+        dr.StartX   = ev.X()
+        dr.StartY   = ev.Y()
+        return event.Result(true)
+    } else {
+        return event.Result(false)
+    }
+}
+
+func (dr Dragger) MouseButtonRelease(ev event.MouseButtonRelease) event.Result {
+    if dr.Draggable != nil {
+        dr.Draggable.MouseButtonRelease(ev)
+        if (!dr.Dragging) {
+            return event.Result(false)
+        }
+        dr.Dragging = false
+        dr.Draggable.Drop(ev.X(), ev.Y(), dr.StartX, dr.StartY)
+        return event.Result(true)
+    } else {
+        return event.Result(false)
+    }
+}
+

+ 14 - 0
zori/widget/label.go

@@ -0,0 +1,14 @@
+package widget
+
+// import "gitlab.com/beoran/ebsgo/zori/event"
+// 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"
+
+
+/* Label widget. */
+type Label struct {
+    Captioned
+}
+

+ 57 - 0
zori/widget/longtext.go

@@ -0,0 +1,57 @@
+package widget
+
+// import "gitlab.com/beoran/ebsgo/zori/event"
+// 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"
+
+
+/* A descriptor for the current state of the longtext */
+type LongtextState struct {
+    /* Time waited between display of characters */
+    wait float64
+    /* Virtual text page we are currently on. */
+    page int
+    /* Line of text we are currently on. */
+    line int
+    /* Currently paused or not. */
+    paused bool
+    /* Total amount of lines to display for this text. */
+    total int
+    /* Current position in current line. */
+    position int
+    /* Animation timer. */
+    animationTimer float64
+}
+
+type LongtextFlags int
+
+const (
+    /* Disable animation of pause marker. */
+    LONGTEXT_FLAG_STATIC_MARKER = LongtextFlags(1 << 0)
+    /*- Show letters one by one in stead of space separated words.  */
+    LONGTEXT_FLAG_SHOW_LETTERS = LongtextFlags(1 << 1)
+)
+
+/* A descriptor for the configurable size settings of a
+ * longtext. */
+type LongtextSettings struct {
+    /* Amount of lines to display in one virtual page of text. */
+    Lines int
+    /* Vertcal spacing between lines.  */
+    Spacing int
+    /* Delay between display of the individual characters. */
+    Delay float64
+    /* Several flags that modify the behavior of the box. */
+    LongtextFlags
+}
+
+type Longtext struct {
+    Captioned
+    Text string
+    LongtextSettings
+    LongtextState
+}
+
+

+ 15 - 0
zori/widget/page.go

@@ -0,0 +1,15 @@
+package widget
+
+// 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"
+
+
+/* In Zori, the GUI is paginated. This means that on any
+ * screen, only a single GUI page can be active. The intent is to
+ * support different GUI modes such as startup screen, status view,
+ * settings, HUD, and so on between which can be switched easily. */
+type PageWidget struct {
+    Basic
+}

+ 23 - 0
zori/widget/root.go

@@ -0,0 +1,23 @@
+package widget
+
+
+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"
+
+
+/*
+ * Root level widget, my spread out over several displays.
+ * In Zori, there can only be a single root level widget active.
+ * It's ID is always 0;
+ */
+type Root struct {
+    Basic
+    Icons map[string]Bitmap
+    Display
+    Console
+    UITheme style.Theme
+    Cursors
+    Active *PageWidget
+}

+ 31 - 0
zori/widget/widget.go

@@ -0,0 +1,31 @@
+package widget
+
+
+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"
+
+
+/* Mouse or keyboard/joystick cursor. */
+type Cursor struct {
+    Point
+    Hover Widget
+    Focus Widget
+    Bitmap
+    state.Flag
+    style.Basic
+    TargetStyle style.Theme
+}
+
+/* Support multiple cursors...  */
+type Cursors struct {
+    Mouse  Cursor
+    Keyjoy Cursor
+}
+
+type Widget interface {
+    Sized
+    Positioned
+    style.Themed
+}

+ 30 - 0
zori/zori.go

@@ -0,0 +1,30 @@
+package zori
+
+// import "fmt"
+
+// import "gitlab.com/beoran/ebsgo/monolog"
+import _ "gitlab.com/beoran/ebsgo/zori/event"
+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/widget"
+
+
+
+
+
+
+type MenuWidget struct {
+    widget.Captioned
+    Selected int
+}
+
+
+
+
+
+
+ 
+
+

+ 61 - 0
zori/zori_test.go

@@ -0,0 +1,61 @@
+// zori_test.go
+package zori
+
+import (
+    //    "strings"
+    "testing"
+    "gitlab.com/beoran/ebsgo/zori/event"
+    . "gitlab.com/beoran/ebsgo/zori/types"
+    _ "gitlab.com/beoran/ebsgo/zori/backend"
+
+    // _ "gitlab.com/beoran/woe/monolog"
+    // "gitlab.com/beoran/woe/tree"
+)
+
+func Assert(test *testing.T, ok bool, text string) bool {
+    if !ok {
+        test.Error(text)
+    }
+    return ok
+}
+
+type TestKeyboardEvent struct {
+    event.Basic
+    stamp   float64
+    unichar rune
+}
+
+func (ke TestKeyboardEvent) IsKeyChar() {
+}
+
+
+func (ke TestKeyboardEvent) KeyCode() int {
+    return int(ke.unichar)
+}
+
+func (ke TestKeyboardEvent) Unichar() rune {
+    return ke.unichar
+}
+
+func (ke TestKeyboardEvent) Modifiers() int {
+    return 0
+}
+
+func (ke TestKeyboardEvent) Repeat() bool {
+    return false
+}
+
+func (ke TestKeyboardEvent) Display() Display {
+    return nil
+}
+
+func TestDispatch(test *testing.T) {
+    bw := &BasicWidget{}
+    cw := &ConsoleWidget{}
+    ev := &TestKeyboardEvent{}
+    Assert(test, bool(event.Dispatch(ev, bw)),  "Dispatch bw failed")
+    Assert(test, bool(event.Dispatch(ev, cw)),  "Dispatch cw failed")
+    Assert(test, bool(bw.Dispatch(ev)),   "Dispatch bw failed")
+    Assert(test, bool(cw.Dispatch(ev)),   "Dispatch cw failed")
+
+}