Updated everything else to match

This commit is contained in:
Sasha Koshka 2023-02-02 01:48:16 -05:00
parent 99942466f8
commit 892c74a9da
40 changed files with 304 additions and 759 deletions

View File

@ -3,11 +3,11 @@ package artist
import "math"
import "image"
import "image/color"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
// FillEllipse draws a filled ellipse with the specified pattern.
func FillEllipse (
destination tomo.Canvas,
destination canvas.Canvas,
source Pattern,
bounds image.Rectangle,
) (
@ -36,7 +36,7 @@ func FillEllipse (
// StrokeEllipse draws the outline of an ellipse with the specified line weight
// and pattern.
func StrokeEllipse (
destination tomo.Canvas,
destination canvas.Canvas,
source Pattern,
weight int,
bounds image.Rectangle,

View File

@ -2,14 +2,14 @@ package artist
import "image"
import "image/color"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
// TODO: draw thick lines more efficiently
// Line draws a line from one point to another with the specified weight and
// pattern.
func Line (
destination tomo.Canvas,
destination canvas.Canvas,
source Pattern,
weight int,
min image.Point,
@ -46,7 +46,7 @@ func Line (
}
func lineLow (
destination tomo.Canvas,
destination canvas.Canvas,
source Pattern,
weight int,
min image.Point,
@ -82,7 +82,7 @@ func lineLow (
}
func lineHigh (
destination tomo.Canvas,
destination canvas.Canvas,
source Pattern,
weight int,
min image.Point,

View File

@ -1,12 +1,12 @@
package artist
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
// Paste transfers one canvas onto another, offset by the specified point.
func Paste (
destination tomo.Canvas,
source tomo.Canvas,
destination canvas.Canvas,
source canvas.Canvas,
offset image.Point,
) (
updatedRegion image.Rectangle,
@ -31,7 +31,7 @@ func Paste (
// FillRectangle draws a filled rectangle with the specified pattern.
func FillRectangle (
destination tomo.Canvas,
destination canvas.Canvas,
source Pattern,
bounds image.Rectangle,
) (
@ -61,7 +61,7 @@ func FillRectangle (
// StrokeRectangle draws the outline of a rectangle with the specified line
// weight and pattern.
func StrokeRectangle (
destination tomo.Canvas,
destination canvas.Canvas,
source Pattern,
weight int,
bounds image.Rectangle,

View File

@ -6,7 +6,7 @@ import "unicode"
import "image/draw"
import "golang.org/x/image/font"
import "golang.org/x/image/math/fixed"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
type characterLayout struct {
x int
@ -95,7 +95,7 @@ func (drawer *TextDrawer) SetAlignment (align Align) {
// Draw draws the drawer's text onto the specified canvas at the given offset.
func (drawer *TextDrawer) Draw (
destination tomo.Canvas,
destination canvas.Canvas,
source Pattern,
offset image.Point,
) (

View File

@ -1,90 +0,0 @@
package tomo
import "image"
import "image/draw"
import "image/color"
// Canvas is like draw.Image but is also able to return a raw pixel buffer for
// more efficient drawing. This interface can be easily satisfied using a
// BasicCanvas struct.
type Canvas interface {
draw.Image
Buffer () (data []color.RGBA, stride int)
}
// BasicCanvas is a general purpose implementation of tomo.Canvas.
type BasicCanvas struct {
pix []color.RGBA
stride int
rect image.Rectangle
}
// NewBasicCanvas creates a new basic canvas with the specified width and
// height, allocating a buffer for it.
func NewBasicCanvas (width, height int) (canvas BasicCanvas) {
canvas.pix = make([]color.RGBA, height * width)
canvas.stride = width
canvas.rect = image.Rect(0, 0, width, height)
return
}
// you know what it do
func (canvas BasicCanvas) Bounds () (bounds image.Rectangle) {
return canvas.rect
}
// you know what it do
func (canvas BasicCanvas) At (x, y int) (color.Color) {
if !image.Pt(x, y).In(canvas.rect) { return nil }
return canvas.pix[x + y * canvas.stride]
}
// you know what it do
func (canvas BasicCanvas) ColorModel () (model color.Model) {
return color.RGBAModel
}
// you know what it do
func (canvas BasicCanvas) Set (x, y int, c color.Color) {
if !image.Pt(x, y).In(canvas.rect) { return }
r, g, b, a := c.RGBA()
canvas.pix[x + y * canvas.stride] = color.RGBA {
R: uint8(r >> 8),
G: uint8(g >> 8),
B: uint8(b >> 8),
A: uint8(a >> 8),
}
}
// you know what it do
func (canvas BasicCanvas) Buffer () (data []color.RGBA, stride int) {
return canvas.pix, canvas.stride
}
// Reallocate efficiently reallocates the canvas. The data within will be
// garbage. This method will do nothing if this is a cut image.
func (canvas *BasicCanvas) Reallocate (width, height int) {
if canvas.rect.Min != (image.Point { }) { return }
previousLen := len(canvas.pix)
newLen := width * height
bigger := newLen > previousLen
smaller := newLen < previousLen / 2
if bigger || smaller {
canvas.pix = make (
[]color.RGBA,
((height * width) / 4096) * 4096 + 4096)
}
canvas.stride = width
canvas.rect = image.Rect(0, 0, width, height)
}
// Cut returns a sub-canvas of a given canvas.
func Cut (canvas Canvas, bounds image.Rectangle) (reduced BasicCanvas) {
// println(canvas.Bounds().String(), bounds.String())
bounds = bounds.Intersect(canvas.Bounds())
if bounds.Empty() { return }
reduced.rect = bounds
reduced.pix, reduced.stride = canvas.Buffer()
return
}

20
data.go
View File

@ -1,20 +0,0 @@
package tomo
import "io"
// Data represents arbitrary polymorphic data that can be used for data transfer
// between applications.
type Data map[Mime] io.ReadCloser
// Mime represents a MIME type.
type Mime struct {
// Type is the first half of the MIME type, and Subtype is the second
// half. The separating slash is not included in either. For example,
// text/html becomes:
// Mime { Type: "text", Subtype: "html" }
Type, Subtype string
}
var MimePlain = Mime { "text", "plain" }
var MimeFile = Mime { "text", "uri-list" }

View File

@ -1,177 +0,0 @@
package tomo
import "image"
// Element represents a basic on-screen object.
type Element interface {
// Element must implement the Canvas interface. Elements should start
// out with a completely blank buffer, and only allocate memory and draw
// on it for the first time when sent an EventResize event.
Canvas
// MinimumSize specifies the minimum amount of pixels this element's
// width and height may be set to. If the element is given a resize
// event with dimensions smaller than this, it will use its minimum
// instead of the offending dimension(s).
MinimumSize () (width, height int)
// DrawTo sets this element's canvas. This should only be called by the
// parent element. This is typically a region of the parent element's
// canvas.
DrawTo (canvas Canvas)
// OnDamage sets a function to be called when an area of the element is
// drawn on and should be pushed to the screen.
OnDamage (callback func (region Canvas))
// OnMinimumSizeChange sets a function to be called when the element's
// minimum size is changed.
OnMinimumSizeChange (callback func ())
}
// KeynavDirection represents a keyboard navigation direction.
type KeynavDirection int
const (
KeynavDirectionNeutral KeynavDirection = 0
KeynavDirectionBackward KeynavDirection = -1
KeynavDirectionForward KeynavDirection = 1
)
// Canon returns a well-formed direction.
func (direction KeynavDirection) Canon () (canon KeynavDirection) {
if direction > 0 {
return KeynavDirectionForward
} else if direction == 0 {
return KeynavDirectionNeutral
} else {
return KeynavDirectionBackward
}
}
// Focusable represents an element that has keyboard navigation support. This
// includes inputs, buttons, sliders, etc. as well as any elements that have
// children (so keyboard navigation events can be propagated downward).
type Focusable interface {
Element
// Focused returns whether or not this element is currently focused.
Focused () (selected bool)
// Focus focuses this element, if its parent element grants the
// request.
Focus ()
// HandleFocus causes this element to mark itself as focused. If the
// element does not have children, it is disabled, or there are no more
// selectable children in the given direction, it should return false
// and do nothing. Otherwise, it should select itself and any children
// (if applicable) and return true.
HandleFocus (direction KeynavDirection) (accepted bool)
// HandleDeselection causes this element to mark itself and all of its
// children as unfocused.
HandleUnfocus ()
// OnFocusRequest sets a function to be called when this element wants
// its parent element to focus it. Parent elements should return true if
// the request was granted, and false if it was not.
OnFocusRequest (func () (granted bool))
// OnFocusMotionRequest sets a function to be called when this
// element wants its parent element to focus the element behind or in
// front of it, depending on the specified direction. Parent elements
// should return true if the request was granted, and false if it was
// not.
OnFocusMotionRequest (func (direction KeynavDirection) (granted bool))
}
// KeyboardTarget represents an element that can receive keyboard input.
type KeyboardTarget interface {
Element
// HandleKeyDown is called when a key is pressed down or repeated while
// this element has keyboard focus. It is important to note that not
// every key down event is guaranteed to be paired with exactly one key
// up event. This is the reason a list of modifier keys held down at the
// time of the key press is given.
HandleKeyDown (key Key, modifiers Modifiers)
// HandleKeyUp is called when a key is released while this element has
// keyboard focus.
HandleKeyUp (key Key, modifiers Modifiers)
}
// MouseTarget represents an element that can receive mouse events.
type MouseTarget interface {
Element
// Each of these handler methods is passed the position of the mouse
// cursor at the time of the event as x, y.
// HandleMouseDown is called when a mouse button is pressed down on this
// element.
HandleMouseDown (x, y int, button Button)
// HandleMouseUp is called when a mouse button is released that was
// originally pressed down on this element.
HandleMouseUp (x, y int, button Button)
// HandleMouseMove is called when the mouse is moved over this element,
// or the mouse is moving while being held down and originally pressed
// down on this element.
HandleMouseMove (x, y int)
// HandleScroll is called when the mouse is scrolled. The X and Y
// direction of the scroll event are passed as deltaX and deltaY.
HandleMouseScroll (x, y int, deltaX, deltaY float64)
}
// Flexible represents an element who's preferred minimum height can change in
// response to its width.
type Flexible interface {
Element
// FlexibleHeightFor returns what the element's minimum height would be
// if resized to a specified width. This does not actually alter the
// state of the element in any way, but it may perform significant work,
// so it should be called sparingly.
//
// It is reccomended that parent containers check for this interface and
// take this method's value into account in order to support things like
// flow layouts and text wrapping, but it is not absolutely necessary.
// The element's MinimumSize method will still return the absolute
// minimum size that the element may be resized to.
//
// It is important to note that if a parent container checks for
// flexible chilren, it itself will likely need to be flexible.
FlexibleHeightFor (width int) (height int)
// OnFlexibleHeightChange sets a function to be called when the
// parameters affecting this element's flexible height are changed.
OnFlexibleHeightChange (callback func ())
}
// Scrollable represents an element that can be scrolled. It acts as a viewport
// through which its contents can be observed.
type Scrollable interface {
Element
// ScrollContentBounds returns the full content size of the element.
ScrollContentBounds () (bounds image.Rectangle)
// ScrollViewportBounds returns the size and position of the element's
// viewport relative to ScrollBounds.
ScrollViewportBounds () (bounds image.Rectangle)
// ScrollTo scrolls the viewport to the specified point relative to
// ScrollBounds.
ScrollTo (position image.Point)
// ScrollAxes returns the supported axes for scrolling.
ScrollAxes () (horizontal, vertical bool)
// OnScrollBoundsChange sets a function to be called when the element's
// ScrollContentBounds, ScrollViewportBounds, or ScrollAxes are changed.
OnScrollBoundsChange (callback func ())
}

View File

@ -1,7 +1,7 @@
package basic
package basicElements
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
@ -38,10 +38,10 @@ func NewButton (text string) (element *Button) {
return
}
func (element *Button) HandleMouseDown (x, y int, button tomo.Button) {
func (element *Button) HandleMouseDown (x, y int, button input.Button) {
if !element.Enabled() { return }
if !element.Focused() { element.Focus() }
if button != tomo.ButtonLeft { return }
if button != input.ButtonLeft { return }
element.pressed = true
if element.core.HasImage() {
element.draw()
@ -49,8 +49,8 @@ func (element *Button) HandleMouseDown (x, y int, button tomo.Button) {
}
}
func (element *Button) HandleMouseUp (x, y int, button tomo.Button) {
if button != tomo.ButtonLeft { return }
func (element *Button) HandleMouseUp (x, y int, button input.Button) {
if button != input.ButtonLeft { return }
element.pressed = false
if element.core.HasImage() {
element.draw()
@ -69,9 +69,9 @@ func (element *Button) HandleMouseUp (x, y int, button tomo.Button) {
func (element *Button) HandleMouseMove (x, y int) { }
func (element *Button) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
func (element *Button) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
func (element *Button) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
if !element.Enabled() { return }
if key == tomo.KeyEnter {
if key == input.KeyEnter {
element.pressed = true
if element.core.HasImage() {
element.draw()
@ -80,8 +80,8 @@ func (element *Button) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
}
}
func (element *Button) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) {
if key == tomo.KeyEnter && element.pressed {
func (element *Button) HandleKeyUp(key input.Key, modifiers input.Modifiers) {
if key == input.KeyEnter && element.pressed {
element.pressed = false
if element.core.HasImage() {
element.draw()

View File

@ -1,7 +1,7 @@
package basic
package basicElements
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
@ -39,7 +39,7 @@ func NewCheckbox (text string, checked bool) (element *Checkbox) {
return
}
func (element *Checkbox) HandleMouseDown (x, y int, button tomo.Button) {
func (element *Checkbox) HandleMouseDown (x, y int, button input.Button) {
if !element.Enabled() { return }
element.Focus()
element.pressed = true
@ -49,8 +49,8 @@ func (element *Checkbox) HandleMouseDown (x, y int, button tomo.Button) {
}
}
func (element *Checkbox) HandleMouseUp (x, y int, button tomo.Button) {
if button != tomo.ButtonLeft || !element.pressed { return }
func (element *Checkbox) HandleMouseUp (x, y int, button input.Button) {
if button != input.ButtonLeft || !element.pressed { return }
element.pressed = false
within := image.Point { x, y }.
@ -71,8 +71,8 @@ func (element *Checkbox) HandleMouseUp (x, y int, button tomo.Button) {
func (element *Checkbox) HandleMouseMove (x, y int) { }
func (element *Checkbox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
func (element *Checkbox) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
if key == tomo.KeyEnter {
func (element *Checkbox) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
if key == input.KeyEnter {
element.pressed = true
if element.core.HasImage() {
element.draw()
@ -81,8 +81,8 @@ func (element *Checkbox) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers)
}
}
func (element *Checkbox) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
if key == tomo.KeyEnter && element.pressed {
func (element *Checkbox) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
if key == input.KeyEnter && element.pressed {
element.pressed = false
element.checked = !element.checked
if element.core.HasImage() {

View File

@ -1,9 +1,12 @@
package basic
package basicElements
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
var containerCase = theme.C("basic", "container")
@ -14,21 +17,21 @@ type Container struct {
*core.Core
core core.CoreControl
layout tomo.Layout
children []tomo.LayoutEntry
drags [10]tomo.MouseTarget
layout layouts.Layout
children []layouts.LayoutEntry
drags [10]elements.MouseTarget
warping bool
focused bool
focusable bool
flexible bool
onFocusRequest func () (granted bool)
onFocusMotionRequest func (tomo.KeynavDirection) (granted bool)
onFocusMotionRequest func (input.KeynavDirection) (granted bool)
onFlexibleHeightChange func ()
}
// NewContainer creates a new container.
func NewContainer (layout tomo.Layout) (element *Container) {
func NewContainer (layout layouts.Layout) (element *Container) {
element = &Container { }
element.Core, element.core = core.NewCore(element.redoAll)
element.SetLayout(layout)
@ -36,7 +39,7 @@ func NewContainer (layout tomo.Layout) (element *Container) {
}
// SetLayout sets the layout of this container.
func (element *Container) SetLayout (layout tomo.Layout) {
func (element *Container) SetLayout (layout layouts.Layout) {
element.layout = layout
if element.core.HasImage() {
element.redoAll()
@ -47,28 +50,28 @@ func (element *Container) SetLayout (layout tomo.Layout) {
// Adopt adds a new child element to the container. If expand is set to true,
// the element will expand (instead of contract to its minimum size), in
// whatever way is defined by the current layout.
func (element *Container) Adopt (child tomo.Element, expand bool) {
func (element *Container) Adopt (child elements.Element, expand bool) {
// set event handlers
child.OnDamage (func (region tomo.Canvas) {
child.OnDamage (func (region canvas.Canvas) {
element.core.DamageRegion(region.Bounds())
})
child.OnMinimumSizeChange(element.updateMinimumSize)
if child0, ok := child.(tomo.Flexible); ok {
if child0, ok := child.(elements.Flexible); ok {
child0.OnFlexibleHeightChange(element.updateMinimumSize)
}
if child0, ok := child.(tomo.Focusable); ok {
if child0, ok := child.(elements.Focusable); ok {
child0.OnFocusRequest (func () (granted bool) {
return element.childFocusRequestCallback(child0)
})
child0.OnFocusMotionRequest (
func (direction tomo.KeynavDirection) (granted bool) {
func (direction input.KeynavDirection) (granted bool) {
if element.onFocusMotionRequest == nil { return }
return element.onFocusMotionRequest(direction)
})
}
// add child
element.children = append (element.children, tomo.LayoutEntry {
element.children = append (element.children, layouts.LayoutEntry {
Element: child,
Expand: expand,
})
@ -106,7 +109,7 @@ func (element *Container) Warp (callback func ()) {
// Disown removes the given child from the container if it is contained within
// it.
func (element *Container) Disown (child tomo.Element) {
func (element *Container) Disown (child elements.Element) {
for index, entry := range element.children {
if entry.Element == child {
element.clearChildEventHandlers(entry.Element)
@ -125,18 +128,18 @@ func (element *Container) Disown (child tomo.Element) {
}
}
func (element *Container) clearChildEventHandlers (child tomo.Element) {
func (element *Container) clearChildEventHandlers (child elements.Element) {
child.DrawTo(nil)
child.OnDamage(nil)
child.OnMinimumSizeChange(nil)
if child0, ok := child.(tomo.Focusable); ok {
if child0, ok := child.(elements.Focusable); ok {
child0.OnFocusRequest(nil)
child0.OnFocusMotionRequest(nil)
if child0.Focused() {
child0.HandleUnfocus()
}
}
if child0, ok := child.(tomo.Flexible); ok {
if child0, ok := child.(elements.Flexible); ok {
child0.OnFlexibleHeightChange(nil)
}
}
@ -154,8 +157,8 @@ func (element *Container) DisownAll () {
}
// Children returns a slice containing this element's children.
func (element *Container) Children () (children []tomo.Element) {
children = make([]tomo.Element, len(element.children))
func (element *Container) Children () (children []elements.Element) {
children = make([]elements.Element, len(element.children))
for index, entry := range element.children {
children[index] = entry.Element
}
@ -169,14 +172,14 @@ func (element *Container) CountChildren () (count int) {
// Child returns the child at the specified index. If the index is out of
// bounds, this method will return nil.
func (element *Container) Child (index int) (child tomo.Element) {
func (element *Container) Child (index int) (child elements.Element) {
if index < 0 || index > len(element.children) { return }
return element.children[index].Element
}
// ChildAt returns the child that contains the specified x and y coordinates. If
// there are no children at the coordinates, this method will return nil.
func (element *Container) ChildAt (point image.Point) (child tomo.Element) {
func (element *Container) ChildAt (point image.Point) (child elements.Element) {
for _, entry := range element.children {
if point.In(entry.Bounds) {
child = entry.Element
@ -185,7 +188,7 @@ func (element *Container) ChildAt (point image.Point) (child tomo.Element) {
return
}
func (element *Container) childPosition (child tomo.Element) (position image.Point) {
func (element *Container) childPosition (child elements.Element) (position image.Point) {
for _, entry := range element.children {
if entry.Element == child {
position = entry.Bounds.Min
@ -209,18 +212,18 @@ func (element *Container) redoAll () {
// cut our canvas up and give peices to child elements
for _, entry := range element.children {
entry.DrawTo(tomo.Cut(element, entry.Bounds))
entry.DrawTo(canvas.Cut(element, entry.Bounds))
}
}
func (element *Container) HandleMouseDown (x, y int, button tomo.Button) {
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(tomo.MouseTarget)
func (element *Container) HandleMouseDown (x, y int, button input.Button) {
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget)
if !handlesMouse { return }
element.drags[button] = child
child.HandleMouseDown(x, y, button)
}
func (element *Container) HandleMouseUp (x, y int, button tomo.Button) {
func (element *Container) HandleMouseUp (x, y int, button input.Button) {
child := element.drags[button]
if child == nil { return }
element.drags[button] = nil
@ -235,14 +238,14 @@ func (element *Container) HandleMouseMove (x, y int) {
}
func (element *Container) HandleMouseScroll (x, y int, deltaX, deltaY float64) {
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(tomo.MouseTarget)
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget)
if !handlesMouse { return }
child.HandleMouseScroll(x, y, deltaX, deltaY)
}
func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
element.forFocused (func (child tomo.Focusable) bool {
child0, handlesKeyboard := child.(tomo.KeyboardTarget)
func (element *Container) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
element.forFocused (func (child elements.Focusable) bool {
child0, handlesKeyboard := child.(elements.KeyboardTarget)
if handlesKeyboard {
child0.HandleKeyDown(key, modifiers)
}
@ -250,9 +253,9 @@ func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers)
})
}
func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
element.forFocused (func (child tomo.Focusable) bool {
child0, handlesKeyboard := child.(tomo.KeyboardTarget)
func (element *Container) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
element.forFocused (func (child elements.Focusable) bool {
child0, handlesKeyboard := child.(elements.KeyboardTarget)
if handlesKeyboard {
child0.HandleKeyUp(key, modifiers)
}
@ -261,7 +264,9 @@ func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
}
func (element *Container) FlexibleHeightFor (width int) (height int) {
return element.layout.FlexibleHeightFor(element.children, width)
return element.layout.FlexibleHeightFor (
element.children,
theme.Margin(), width)
}
func (element *Container) OnFlexibleHeightChange (callback func ()) {
@ -278,7 +283,7 @@ func (element *Container) Focus () {
}
}
func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool) {
func (element *Container) HandleFocus (direction input.KeynavDirection) (ok bool) {
if !element.focusable { return false }
direction = direction.Canon()
@ -288,12 +293,12 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool)
// the first or last focusable element depending on the
// direction.
switch direction {
case tomo.KeynavDirectionNeutral, tomo.KeynavDirectionForward:
case input.KeynavDirectionNeutral, input.KeynavDirectionForward:
// if we recieve a neutral or forward direction, focus
// the first focusable element.
return element.focusFirstFocusableElement(direction)
case tomo.KeynavDirectionBackward:
case input.KeynavDirectionBackward:
// if we recieve a backward direction, focus the last
// focusable element.
return element.focusLastFocusableElement(direction)
@ -302,7 +307,7 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool)
// an element is currently focused, so we need to move the
// focus in the specified direction
firstFocusedChild :=
element.children[firstFocused].Element.(tomo.Focusable)
element.children[firstFocused].Element.(elements.Focusable)
// before we move the focus, the currently focused child
// may also be able to move its focus. if the child is able
@ -319,7 +324,7 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool)
child, focusable :=
element.children[index].
Element.(tomo.Focusable)
Element.(elements.Focusable)
if focusable && child.HandleFocus(direction) {
// we have found one, so we now actually move
// the focus.
@ -334,11 +339,11 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool)
}
func (element *Container) focusFirstFocusableElement (
direction tomo.KeynavDirection,
direction input.KeynavDirection,
) (
ok bool,
) {
element.forFocusable (func (child tomo.Focusable) bool {
element.forFocusable (func (child elements.Focusable) bool {
if child.HandleFocus(direction) {
element.focused = true
ok = true
@ -350,11 +355,11 @@ func (element *Container) focusFirstFocusableElement (
}
func (element *Container) focusLastFocusableElement (
direction tomo.KeynavDirection,
direction input.KeynavDirection,
) (
ok bool,
) {
element.forFocusableBackward (func (child tomo.Focusable) bool {
element.forFocusableBackward (func (child elements.Focusable) bool {
if child.HandleFocus(direction) {
element.focused = true
ok = true
@ -367,7 +372,7 @@ func (element *Container) focusLastFocusableElement (
func (element *Container) HandleUnfocus () {
element.focused = false
element.forFocused (func (child tomo.Focusable) bool {
element.forFocused (func (child elements.Focusable) bool {
child.HandleUnfocus()
return true
})
@ -378,41 +383,41 @@ func (element *Container) OnFocusRequest (callback func () (granted bool)) {
}
func (element *Container) OnFocusMotionRequest (
callback func (direction tomo.KeynavDirection) (granted bool),
callback func (direction input.KeynavDirection) (granted bool),
) {
element.onFocusMotionRequest = callback
}
func (element *Container) forFocused (callback func (child tomo.Focusable) bool) {
func (element *Container) forFocused (callback func (child elements.Focusable) bool) {
for _, entry := range element.children {
child, focusable := entry.Element.(tomo.Focusable)
child, focusable := entry.Element.(elements.Focusable)
if focusable && child.Focused() {
if !callback(child) { break }
}
}
}
func (element *Container) forFocusable (callback func (child tomo.Focusable) bool) {
func (element *Container) forFocusable (callback func (child elements.Focusable) bool) {
for _, entry := range element.children {
child, focusable := entry.Element.(tomo.Focusable)
child, focusable := entry.Element.(elements.Focusable)
if focusable {
if !callback(child) { break }
}
}
}
func (element *Container) forFlexible (callback func (child tomo.Flexible) bool) {
func (element *Container) forFlexible (callback func (child elements.Flexible) bool) {
for _, entry := range element.children {
child, flexible := entry.Element.(tomo.Flexible)
child, flexible := entry.Element.(elements.Flexible)
if flexible {
if !callback(child) { break }
}
}
}
func (element *Container) forFocusableBackward (callback func (child tomo.Focusable) bool) {
func (element *Container) forFocusableBackward (callback func (child elements.Focusable) bool) {
for index := len(element.children) - 1; index >= 0; index -- {
child, focusable := element.children[index].Element.(tomo.Focusable)
child, focusable := element.children[index].Element.(elements.Focusable)
if focusable {
if !callback(child) { break }
}
@ -421,7 +426,7 @@ func (element *Container) forFocusableBackward (callback func (child tomo.Focusa
func (element *Container) firstFocused () (index int) {
for currentIndex, entry := range element.children {
child, focusable := entry.Element.(tomo.Focusable)
child, focusable := entry.Element.(elements.Focusable)
if focusable && child.Focused() {
return currentIndex
}
@ -431,12 +436,12 @@ func (element *Container) firstFocused () (index int) {
func (element *Container) reflectChildProperties () {
element.focusable = false
element.forFocusable (func (tomo.Focusable) bool {
element.forFocusable (func (elements.Focusable) bool {
element.focusable = true
return false
})
element.flexible = false
element.forFlexible (func (tomo.Flexible) bool {
element.forFlexible (func (elements.Flexible) bool {
element.flexible = true
return false
})
@ -446,16 +451,16 @@ func (element *Container) reflectChildProperties () {
}
func (element *Container) childFocusRequestCallback (
child tomo.Focusable,
child elements.Focusable,
) (
granted bool,
) {
if element.onFocusRequest != nil && element.onFocusRequest() {
element.forFocused (func (child tomo.Focusable) bool {
element.forFocused (func (child elements.Focusable) bool {
child.HandleUnfocus()
return true
})
child.HandleFocus(tomo.KeynavDirectionNeutral)
child.HandleFocus(input.KeynavDirectionNeutral)
return true
} else {
return false
@ -463,13 +468,16 @@ func (element *Container) childFocusRequestCallback (
}
func (element *Container) updateMinimumSize () {
width, height := element.layout.MinimumSize(element.children)
width, height := element.layout.MinimumSize (
element.children, theme.Margin())
if element.flexible {
height = element.layout.FlexibleHeightFor(element.children, width)
height = element.layout.FlexibleHeightFor (
element.children, theme.Margin(), width)
}
element.core.SetMinimumSize(width, height)
}
func (element *Container) recalculate () {
element.layout.Arrange(element.children, element.Bounds())
element.layout.Arrange (
element.children, theme.Margin(), element.Bounds())
}

View File

@ -1,4 +1,4 @@
package basic
package basicElements
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist"

View File

@ -1,9 +1,10 @@
package basic
package basicElements
import "fmt"
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
@ -73,10 +74,10 @@ func (element *List) Collapse (width, height int) {
element.updateMinimumSize()
}
func (element *List) HandleMouseDown (x, y int, button tomo.Button) {
func (element *List) HandleMouseDown (x, y int, button input.Button) {
if !element.Enabled() { return }
if !element.Focused() { element.Focus() }
if button != tomo.ButtonLeft { return }
if button != input.ButtonLeft { return }
element.pressed = true
if element.selectUnderMouse(x, y) && element.core.HasImage() {
element.draw()
@ -84,8 +85,8 @@ func (element *List) HandleMouseDown (x, y int, button tomo.Button) {
}
}
func (element *List) HandleMouseUp (x, y int, button tomo.Button) {
if button != tomo.ButtonLeft { return }
func (element *List) HandleMouseUp (x, y int, button input.Button) {
if button != input.ButtonLeft { return }
element.pressed = false
}
@ -100,18 +101,18 @@ func (element *List) HandleMouseMove (x, y int) {
func (element *List) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
func (element *List) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
func (element *List) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
if !element.Enabled() { return }
altered := false
switch key {
case tomo.KeyLeft, tomo.KeyUp:
case input.KeyLeft, input.KeyUp:
altered = element.changeSelectionBy(-1)
case tomo.KeyRight, tomo.KeyDown:
case input.KeyRight, input.KeyDown:
altered = element.changeSelectionBy(1)
case tomo.KeyEscape:
case input.KeyEscape:
altered = element.selectEntry(-1)
}
@ -121,7 +122,7 @@ func (element *List) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
}
}
func (element *List) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) { }
func (element *List) HandleKeyUp(key input.Key, modifiers input.Modifiers) { }
// ScrollContentBounds returns the full content size of the element.
func (element *List) ScrollContentBounds () (bounds image.Rectangle) {
@ -383,7 +384,7 @@ func (element *List) draw () {
bounds.Min.X,
bounds.Min.Y - element.scroll,
}
innerCanvas := tomo.Cut(element, bounds)
innerCanvas := canvas.Cut(element, bounds)
for index, entry := range element.entries {
entryPosition := dot
dot.Y += entry.Bounds().Dy()

View File

@ -1,8 +1,8 @@
package basic
package basicElements
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/artist"
var listEntryCase = theme.C("basic", "listEntry")
@ -53,7 +53,7 @@ func (entry *ListEntry) updateBounds () {
}
func (entry *ListEntry) Draw (
destination tomo.Canvas,
destination canvas.Canvas,
offset image.Point,
focused bool,
on bool,

View File

@ -1,4 +1,4 @@
package basic
package basicElements
import "image"
import "git.tebibyte.media/sashakoshka/tomo/theme"

View File

@ -1,9 +1,11 @@
package basic
package basicElements
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
var scrollContainerCase = theme.C("basic", "scrollContainer")
@ -17,7 +19,7 @@ type ScrollContainer struct {
core core.CoreControl
focused bool
child tomo.Scrollable
child elements.Scrollable
childWidth, childHeight int
horizontal struct {
@ -41,7 +43,7 @@ type ScrollContainer struct {
}
onFocusRequest func () (granted bool)
onFocusMotionRequest func (tomo.KeynavDirection) (granted bool)
onFocusMotionRequest func (input.KeynavDirection) (granted bool)
}
// NewScrollContainer creates a new scroll container with the specified scroll
@ -64,7 +66,7 @@ func (element *ScrollContainer) handleResize () {
// Adopt adds a scrollable element to the scroll container. The container can
// only contain one scrollable element at a time, and when a new one is adopted
// it replaces the last one.
func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
func (element *ScrollContainer) Adopt (child elements.Scrollable) {
// disown previous child if it exists
if element.child != nil {
element.clearChildEventHandlers(child)
@ -76,7 +78,7 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
child.OnDamage(element.childDamageCallback)
child.OnMinimumSizeChange(element.updateMinimumSize)
child.OnScrollBoundsChange(element.childScrollBoundsChangeCallback)
if newChild, ok := child.(tomo.Focusable); ok {
if newChild, ok := child.(elements.Focusable); ok {
newChild.OnFocusRequest (
element.childFocusRequestCallback)
newChild.OnFocusMotionRequest (
@ -96,19 +98,19 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
}
}
func (element *ScrollContainer) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
if child, ok := element.child.(tomo.KeyboardTarget); ok {
func (element *ScrollContainer) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
if child, ok := element.child.(elements.KeyboardTarget); ok {
child.HandleKeyDown(key, modifiers)
}
}
func (element *ScrollContainer) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
if child, ok := element.child.(tomo.KeyboardTarget); ok {
func (element *ScrollContainer) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
if child, ok := element.child.(elements.KeyboardTarget); ok {
child.HandleKeyUp(key, modifiers)
}
}
func (element *ScrollContainer) HandleMouseDown (x, y int, button tomo.Button) {
func (element *ScrollContainer) HandleMouseDown (x, y int, button input.Button) {
point := image.Pt(x, y)
if point.In(element.horizontal.bar) {
element.horizontal.dragging = true
@ -140,12 +142,12 @@ func (element *ScrollContainer) HandleMouseDown (x, y int, button tomo.Button) {
element.scrollChildBy(0, -16)
}
} else if child, ok := element.child.(tomo.MouseTarget); ok {
} else if child, ok := element.child.(elements.MouseTarget); ok {
child.HandleMouseDown(x, y, button)
}
}
func (element *ScrollContainer) HandleMouseUp (x, y int, button tomo.Button) {
func (element *ScrollContainer) HandleMouseUp (x, y int, button input.Button) {
if element.horizontal.dragging {
element.horizontal.dragging = false
element.drawHorizontalBar()
@ -156,7 +158,7 @@ func (element *ScrollContainer) HandleMouseUp (x, y int, button tomo.Button) {
element.drawVerticalBar()
element.core.DamageRegion(element.vertical.bar)
} else if child, ok := element.child.(tomo.MouseTarget); ok {
} else if child, ok := element.child.(elements.MouseTarget); ok {
child.HandleMouseUp(x, y, button)
}
}
@ -168,7 +170,7 @@ func (element *ScrollContainer) HandleMouseMove (x, y int) {
} else if element.vertical.dragging {
element.dragVerticalBar(image.Pt(x, y))
} else if child, ok := element.child.(tomo.MouseTarget); ok {
} else if child, ok := element.child.(elements.MouseTarget); ok {
child.HandleMouseMove(x, y)
}
}
@ -199,11 +201,11 @@ func (element *ScrollContainer) Focus () {
}
func (element *ScrollContainer) HandleFocus (
direction tomo.KeynavDirection,
direction input.KeynavDirection,
) (
accepted bool,
) {
if child, ok := element.child.(tomo.Focusable); ok {
if child, ok := element.child.(elements.Focusable); ok {
element.focused = true
return child.HandleFocus(direction)
} else {
@ -213,7 +215,7 @@ func (element *ScrollContainer) HandleFocus (
}
func (element *ScrollContainer) HandleUnfocus () {
if child, ok := element.child.(tomo.Focusable); ok {
if child, ok := element.child.(elements.Focusable); ok {
child.HandleUnfocus()
}
element.focused = false
@ -224,20 +226,20 @@ func (element *ScrollContainer) OnFocusRequest (callback func () (granted bool))
}
func (element *ScrollContainer) OnFocusMotionRequest (
callback func (direction tomo.KeynavDirection) (granted bool),
callback func (direction input.KeynavDirection) (granted bool),
) {
element.onFocusMotionRequest = callback
}
func (element *ScrollContainer) childDamageCallback (region tomo.Canvas) {
func (element *ScrollContainer) childDamageCallback (region canvas.Canvas) {
element.core.DamageRegion(artist.Paste(element, region, image.Point { }))
}
func (element *ScrollContainer) childFocusRequestCallback () (granted bool) {
child, ok := element.child.(tomo.Focusable)
child, ok := element.child.(elements.Focusable)
if !ok { return false }
if element.onFocusRequest != nil && element.onFocusRequest() {
child.HandleFocus(tomo.KeynavDirectionNeutral)
child.HandleFocus(input.KeynavDirectionNeutral)
return true
} else {
return false
@ -245,7 +247,7 @@ func (element *ScrollContainer) childFocusRequestCallback () (granted bool) {
}
func (element *ScrollContainer) childFocusMotionRequestCallback (
direction tomo.KeynavDirection,
direction input.KeynavDirection,
) (
granted bool,
) {
@ -253,19 +255,19 @@ func (element *ScrollContainer) childFocusMotionRequestCallback (
return element.onFocusMotionRequest(direction)
}
func (element *ScrollContainer) clearChildEventHandlers (child tomo.Scrollable) {
func (element *ScrollContainer) clearChildEventHandlers (child elements.Scrollable) {
child.DrawTo(nil)
child.OnDamage(nil)
child.OnMinimumSizeChange(nil)
child.OnScrollBoundsChange(nil)
if child0, ok := child.(tomo.Focusable); ok {
if child0, ok := child.(elements.Focusable); ok {
child0.OnFocusRequest(nil)
child0.OnFocusMotionRequest(nil)
if child0.Focused() {
child0.HandleUnfocus()
}
}
if child0, ok := child.(tomo.Flexible); ok {
if child0, ok := child.(elements.Flexible); ok {
child0.OnFlexibleHeightChange(nil)
}
}
@ -275,7 +277,7 @@ func (element *ScrollContainer) resizeChildToFit () {
0, 0,
element.childWidth,
element.childHeight).Add(element.Bounds().Min)
element.child.DrawTo(tomo.Cut(element, childBounds))
element.child.DrawTo(canvas.Cut(element, childBounds))
}
func (element *ScrollContainer) recalculate () {

View File

@ -1,4 +1,4 @@
package basic
package basicElements
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist"

View File

@ -1,7 +1,7 @@
package basic
package basicElements
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
@ -41,7 +41,7 @@ func NewSwitch (text string, on bool) (element *Switch) {
return
}
func (element *Switch) HandleMouseDown (x, y int, button tomo.Button) {
func (element *Switch) HandleMouseDown (x, y int, button input.Button) {
if !element.Enabled() { return }
element.Focus()
element.pressed = true
@ -51,8 +51,8 @@ func (element *Switch) HandleMouseDown (x, y int, button tomo.Button) {
}
}
func (element *Switch) HandleMouseUp (x, y int, button tomo.Button) {
if button != tomo.ButtonLeft || !element.pressed { return }
func (element *Switch) HandleMouseUp (x, y int, button input.Button) {
if button != input.ButtonLeft || !element.pressed { return }
element.pressed = false
within := image.Point { x, y }.
@ -73,8 +73,8 @@ func (element *Switch) HandleMouseUp (x, y int, button tomo.Button) {
func (element *Switch) HandleMouseMove (x, y int) { }
func (element *Switch) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
func (element *Switch) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
if key == tomo.KeyEnter {
func (element *Switch) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
if key == input.KeyEnter {
element.pressed = true
if element.core.HasImage() {
element.draw()
@ -83,8 +83,8 @@ func (element *Switch) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
}
}
func (element *Switch) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
if key == tomo.KeyEnter && element.pressed {
func (element *Switch) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
if key == input.KeyEnter && element.pressed {
element.pressed = false
element.checked = !element.checked
if element.core.HasImage() {

View File

@ -1,7 +1,7 @@
package basic
package basicElements
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/textmanip"
@ -24,7 +24,7 @@ type TextBox struct {
placeholderDrawer artist.TextDrawer
valueDrawer artist.TextDrawer
onKeyDown func (key tomo.Key, modifiers tomo.Modifiers) (handled bool)
onKeyDown func (key input.Key, modifiers input.Modifiers) (handled bool)
onChange func ()
onScrollBoundsChange func ()
}
@ -59,16 +59,16 @@ func (element *TextBox) handleResize () {
}
}
func (element *TextBox) HandleMouseDown (x, y int, button tomo.Button) {
func (element *TextBox) HandleMouseDown (x, y int, button input.Button) {
if !element.Enabled() { return }
if !element.Focused() { element.Focus() }
}
func (element *TextBox) HandleMouseUp (x, y int, button tomo.Button) { }
func (element *TextBox) HandleMouseUp (x, y int, button input.Button) { }
func (element *TextBox) HandleMouseMove (x, y int) { }
func (element *TextBox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
func (element *TextBox) HandleKeyDown(key input.Key, modifiers input.Modifiers) {
if element.onKeyDown != nil && element.onKeyDown(key, modifiers) {
return
}
@ -77,7 +77,7 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
altered := true
textChanged := false
switch {
case key == tomo.KeyBackspace:
case key == input.KeyBackspace:
if len(element.text) < 1 { break }
element.text, element.cursor = textmanip.Backspace (
element.text,
@ -85,7 +85,7 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
modifiers.Control)
textChanged = true
case key == tomo.KeyDelete:
case key == input.KeyDelete:
if len(element.text) < 1 { break }
element.text, element.cursor = textmanip.Delete (
element.text,
@ -93,13 +93,13 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
modifiers.Control)
textChanged = true
case key == tomo.KeyLeft:
case key == input.KeyLeft:
element.cursor = textmanip.MoveLeft (
element.text,
element.cursor,
modifiers.Control)
case key == tomo.KeyRight:
case key == input.KeyRight:
element.cursor = textmanip.MoveRight (
element.text,
element.cursor,
@ -136,7 +136,7 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
}
}
func (element *TextBox) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) { }
func (element *TextBox) HandleKeyUp(key input.Key, modifiers input.Modifiers) { }
func (element *TextBox) SetPlaceholder (placeholder string) {
if element.placeholder == placeholder { return }
@ -177,7 +177,7 @@ func (element *TextBox) Filled () (filled bool) {
}
func (element *TextBox) OnKeyDown (
callback func (key tomo.Key, modifiers tomo.Modifiers) (handled bool),
callback func (key input.Key, modifiers input.Modifiers) (handled bool),
) {
element.onKeyDown = callback
}

View File

@ -2,12 +2,12 @@ package core
import "image"
import "image/color"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
// Core is a struct that implements some core functionality common to most
// widgets. It is meant to be embedded directly into a struct.
type Core struct {
canvas tomo.Canvas
canvas canvas.Canvas
metrics struct {
minimumWidth int
@ -16,7 +16,7 @@ type Core struct {
drawSizeChange func ()
onMinimumSizeChange func ()
onDamage func (region tomo.Canvas)
onDamage func (region canvas.Canvas)
}
// NewCore creates a new element core and its corresponding control.
@ -49,7 +49,7 @@ func (core *Core) Set (x, y int, c color.Color) () {
core.canvas.Set(x, y, c)
}
// Buffer fulfills the tomo.Canvas interface.
// Buffer fulfills the canvas.Canvas interface.
func (core *Core) Buffer () (data []color.RGBA, stride int) {
if core.canvas == nil { return }
return core.canvas.Buffer()
@ -63,7 +63,7 @@ func (core *Core) MinimumSize () (width, height int) {
// DrawTo fulfills the tomo.Element interface. This should not need to be
// overridden.
func (core *Core) DrawTo (canvas tomo.Canvas) {
func (core *Core) DrawTo (canvas canvas.Canvas) {
core.canvas = canvas
if core.drawSizeChange != nil {
core.drawSizeChange()
@ -72,7 +72,7 @@ func (core *Core) DrawTo (canvas tomo.Canvas) {
// OnDamage fulfils the tomo.Element interface. This should not need to be
// overridden.
func (core *Core) OnDamage (callback func (region tomo.Canvas)) {
func (core *Core) OnDamage (callback func (region canvas.Canvas)) {
core.onDamage = callback
}
@ -100,7 +100,7 @@ func (control CoreControl) HasImage () (has bool) {
// does not need to be called when responding to a resize event.
func (control CoreControl) DamageRegion (bounds image.Rectangle) {
if control.core.onDamage != nil {
control.core.onDamage(tomo.Cut(control.core, bounds))
control.core.onDamage(canvas.Cut(control.core, bounds))
}
}

View File

@ -1,6 +1,6 @@
package core
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
// FocusableCore is a struct that can be embedded into objects to make them
// focusable, giving them the default keynav behavior.
@ -9,7 +9,7 @@ type FocusableCore struct {
enabled bool
drawFocusChange func ()
onFocusRequest func () (granted bool)
onFocusMotionRequest func(tomo.KeynavDirection) (granted bool)
onFocusMotionRequest func(input.KeynavDirection) (granted bool)
}
// NewFocusableCore creates a new focusability core and its corresponding
@ -46,13 +46,13 @@ func (core *FocusableCore) Focus () {
// HandleFocus causes this element to mark itself as focused, if it can
// currently be. Otherwise, it will return false and do nothing.
func (core *FocusableCore) HandleFocus (
direction tomo.KeynavDirection,
direction input.KeynavDirection,
) (
accepted bool,
) {
direction = direction.Canon()
if !core.enabled { return false }
if core.focused && direction != tomo.KeynavDirectionNeutral {
if core.focused && direction != input.KeynavDirectionNeutral {
return false
}
@ -80,7 +80,7 @@ func (core *FocusableCore) OnFocusRequest (callback func () (granted bool)) {
// should return true if the request was granted, and false if it was
// not.
func (core *FocusableCore) OnFocusMotionRequest (
callback func (direction tomo.KeynavDirection) (granted bool),
callback func (direction input.KeynavDirection) (granted bool),
) {
core.onFocusMotionRequest = callback
}

View File

@ -2,7 +2,7 @@ package testing
import "image"
import "image/color"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
@ -44,12 +44,12 @@ func (element *Mouse) draw () {
bounds.Min.Add(image.Pt(bounds.Dx() - 2, 1)))
}
func (element *Mouse) HandleMouseDown (x, y int, button tomo.Button) {
func (element *Mouse) HandleMouseDown (x, y int, button input.Button) {
element.drawing = true
element.lastMousePos = image.Pt(x, y)
}
func (element *Mouse) HandleMouseUp (x, y int, button tomo.Button) {
func (element *Mouse) HandleMouseUp (x, y int, button input.Button) {
element.drawing = false
mousePos := image.Pt(x, y)
element.core.DamageRegion (artist.Line (

View File

@ -11,7 +11,7 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("example button")
button := basic.NewButton("hello tomo!")
button := basicElements.NewButton("hello tomo!")
button.OnClick (func () {
// when we set the button's text to something longer, the window
// will automatically resize to accomodate it.

View File

@ -2,7 +2,7 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -14,22 +14,22 @@ func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Checkboxes")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
container.Adopt (basic.NewLabel (
container.Adopt (basicElements.NewLabel (
"We advise you to not read thPlease listen to me. I am " +
"trapped inside the example code. This is the only way for " +
"me to communicate.", true), true)
container.Adopt(basic.NewSpacer(true), false)
container.Adopt(basic.NewCheckbox("Oh god", false), false)
container.Adopt(basic.NewCheckbox("Can you hear them", true), false)
container.Adopt(basic.NewCheckbox("They are in the walls", false), false)
container.Adopt(basic.NewCheckbox("They are coming for us", false), false)
disabledCheckbox := basic.NewCheckbox("We are but their helpless prey", false)
container.Adopt(basicElements.NewSpacer(true), false)
container.Adopt(basicElements.NewCheckbox("Oh god", false), false)
container.Adopt(basicElements.NewCheckbox("Can you hear them", true), false)
container.Adopt(basicElements.NewCheckbox("They are in the walls", false), false)
container.Adopt(basicElements.NewCheckbox("They are coming for us", false), false)
disabledCheckbox := basicElements.NewCheckbox("We are but their helpless prey", false)
disabledCheckbox.SetEnabled(false)
container.Adopt(disabledCheckbox, false)
vsync := basic.NewCheckbox("Enable vsync", false)
vsync := basicElements.NewCheckbox("Enable vsync", false)
vsync.OnToggle (func () {
if vsync.Value() {
popups.NewDialog (
@ -39,7 +39,7 @@ func run () {
}
})
container.Adopt(vsync, false)
button := basic.NewButton("What")
button := basicElements.NewButton("What")
button.OnClick(tomo.Stop)
container.Adopt(button, false)
button.Focus()

View File

@ -1,7 +1,7 @@
package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -13,14 +13,14 @@ func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("dialog")
container := basic.NewContainer(layouts.Dialog { true, true })
container := basicElements.NewContainer(basicLayouts.Dialog { true, true })
window.Adopt(container)
container.Adopt(basic.NewLabel("you will explode", true), true)
cancel := basic.NewButton("Cancel")
container.Adopt(basicElements.NewLabel("you will explode", true), true)
cancel := basicElements.NewButton("Cancel")
cancel.SetEnabled(false)
container.Adopt(cancel, false)
okButton := basic.NewButton("OK")
okButton := basicElements.NewButton("OK")
container.Adopt(okButton, false)
okButton.Focus()

View File

@ -2,7 +2,7 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/flow"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -13,21 +13,21 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("adventure")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
var world flow.Flow
world.Transition = container.DisownAll
world.Stages = map [string] func () {
"start": func () {
label := basic.NewLabel (
label := basicElements.NewLabel (
"you are standing next to a river.", true)
button0 := basic.NewButton("go in the river")
button0 := basicElements.NewButton("go in the river")
button0.OnClick(world.SwitchFunc("wet"))
button1 := basic.NewButton("walk along the river")
button1 := basicElements.NewButton("walk along the river")
button1.OnClick(world.SwitchFunc("house"))
button2 := basic.NewButton("turn around")
button2 := basicElements.NewButton("turn around")
button2.OnClick(world.SwitchFunc("bear"))
container.Warp ( func () {
@ -39,13 +39,13 @@ func run () {
})
},
"wet": func () {
label := basic.NewLabel (
label := basicElements.NewLabel (
"you get completely soaked.\n" +
"you die of hypothermia.", true)
button0 := basic.NewButton("try again")
button0 := basicElements.NewButton("try again")
button0.OnClick(world.SwitchFunc("start"))
button1 := basic.NewButton("exit")
button1 := basicElements.NewButton("exit")
button1.OnClick(tomo.Stop)
container.Warp (func () {
@ -56,13 +56,13 @@ func run () {
})
},
"house": func () {
label := basic.NewLabel (
label := basicElements.NewLabel (
"you are standing in front of a delapidated " +
"house.", true)
button1 := basic.NewButton("go inside")
button1 := basicElements.NewButton("go inside")
button1.OnClick(world.SwitchFunc("inside"))
button0 := basic.NewButton("turn back")
button0 := basicElements.NewButton("turn back")
button0.OnClick(world.SwitchFunc("start"))
container.Warp (func () {
@ -73,14 +73,14 @@ func run () {
})
},
"inside": func () {
label := basic.NewLabel (
label := basicElements.NewLabel (
"you are standing inside of the house.\n" +
"it is dark, but rays of light stream " +
"through the window.\n" +
"there is nothing particularly interesting " +
"here.", true)
button0 := basic.NewButton("go back outside")
button0 := basicElements.NewButton("go back outside")
button0.OnClick(world.SwitchFunc("house"))
container.Warp (func () {
@ -90,13 +90,13 @@ func run () {
})
},
"bear": func () {
label := basic.NewLabel (
label := basicElements.NewLabel (
"you come face to face with a bear.\n" +
"it eats you (it was hungry).", true)
button0 := basic.NewButton("try again")
button0 := basicElements.NewButton("try again")
button0.OnClick(world.SwitchFunc("start"))
button1 := basic.NewButton("exit")
button1 := basicElements.NewButton("exit")
button1.OnClick(tomo.Stop)
container.Warp (func () {

View File

@ -3,7 +3,7 @@ package main
import "os"
import "time"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/fun"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -16,12 +16,12 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("clock")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
clock := fun.NewAnalogClock(time.Now())
container.Adopt(clock, true)
label := basic.NewLabel(formatTime(), false)
label := basicElements.NewLabel(formatTime(), false)
container.Adopt(label, false)
window.OnClose(tomo.Stop)
@ -33,7 +33,7 @@ func formatTime () (timeString string) {
return time.Now().Format("2006-01-02 15:04:05")
}
func tick (label *basic.Label, clock *fun.AnalogClock) {
func tick (label *basicElements.Label, clock *fun.AnalogClock) {
for {
tomo.Do (func () {
label.SetText(formatTime())

View File

@ -1,7 +1,7 @@
package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -13,12 +13,12 @@ func run () {
window, _ := tomo.NewWindow(360, 2)
window.SetTitle("horizontal stack")
container := basic.NewContainer(layouts.Horizontal { true, true })
container := basicElements.NewContainer(basicLayouts.Horizontal { true, true })
window.Adopt(container)
container.Adopt(basic.NewLabel("this is sample text", true), true)
container.Adopt(basic.NewLabel("this is sample text", true), true)
container.Adopt(basic.NewLabel("this is sample text", true), true)
container.Adopt(basicElements.NewLabel("this is sample text", true), true)
container.Adopt(basicElements.NewLabel("this is sample text", true), true)
container.Adopt(basicElements.NewLabel("this is sample text", true), true)
window.OnClose(tomo.Stop)
window.Show()

View File

@ -2,7 +2,7 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -13,14 +13,14 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Enter Details")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
// create inputs
firstName := basic.NewTextBox("First name", "")
lastName := basic.NewTextBox("Last name", "")
fingerLength := basic.NewTextBox("Length of fingers", "")
button := basic.NewButton("Ok")
firstName := basicElements.NewTextBox("First name", "")
lastName := basicElements.NewTextBox("Last name", "")
fingerLength := basicElements.NewTextBox("Length of fingers", "")
button := basicElements.NewButton("Ok")
button.SetEnabled(false)
button.OnClick (func () {
@ -45,11 +45,11 @@ func run () {
fingerLength.OnChange(check)
// add elements to container
container.Adopt(basic.NewLabel("Choose your words carefully.", false), true)
container.Adopt(basicElements.NewLabel("Choose your words carefully.", false), true)
container.Adopt(firstName, false)
container.Adopt(lastName, false)
container.Adopt(fingerLength, false)
container.Adopt(basic.NewSpacer(true), false)
container.Adopt(basicElements.NewSpacer(true), false)
container.Adopt(button, false)
window.OnClose(tomo.Stop)

View File

@ -11,7 +11,7 @@ func main () {
func run () {
window, _ := tomo.NewWindow(480, 2)
window.SetTitle("example label")
window.Adopt(basic.NewLabel(text, true))
window.Adopt(basicElements.NewLabel(text, true))
window.OnClose(tomo.Stop)
window.Show()
}

View File

@ -2,7 +2,8 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/testing"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -15,11 +16,11 @@ func run () {
window, _ := tomo.NewWindow(300, 2)
window.SetTitle("List Sidebar")
container := basic.NewContainer(layouts.Horizontal { true, true })
container := basicElements.NewContainer(basicLayouts.Horizontal { true, true })
window.Adopt(container)
var currentPage tomo.Element
turnPage := func (newPage tomo.Element) {
var currentPage elements.Element
turnPage := func (newPage elements.Element) {
container.Warp (func () {
if currentPage != nil {
container.Disown(currentPage)
@ -29,27 +30,27 @@ func run () {
})
}
intro := basic.NewLabel (
intro := basicElements.NewLabel (
"The List element can be easily used as a sidebar. " +
"Click on entries to flip pages!", true)
button := basic.NewButton("I do nothing!")
button := basicElements.NewButton("I do nothing!")
button.OnClick (func () {
popups.NewDialog(popups.DialogKindInfo, "", "Sike!")
})
mouse := testing.NewMouse()
input := basic.NewTextBox("Write some text", "")
form := basic.NewContainer(layouts.Vertical { true, false})
form.Adopt(basic.NewLabel("I have:", false), false)
form.Adopt(basic.NewSpacer(true), false)
form.Adopt(basic.NewCheckbox("Skin", true), false)
form.Adopt(basic.NewCheckbox("Blood", false), false)
form.Adopt(basic.NewCheckbox("Bone", false), false)
input := basicElements.NewTextBox("Write some text", "")
form := basicElements.NewContainer(basicLayouts.Vertical { true, false})
form.Adopt(basicElements.NewLabel("I have:", false), false)
form.Adopt(basicElements.NewSpacer(true), false)
form.Adopt(basicElements.NewCheckbox("Skin", true), false)
form.Adopt(basicElements.NewCheckbox("Blood", false), false)
form.Adopt(basicElements.NewCheckbox("Bone", false), false)
list := basic.NewList (
basic.NewListEntry("button", func () { turnPage(button) }),
basic.NewListEntry("mouse", func () { turnPage(mouse) }),
basic.NewListEntry("input", func () { turnPage(input) }),
basic.NewListEntry("form", func () { turnPage(form) }))
list := basicElements.NewList (
basicElements.NewListEntry("button", func () { turnPage(button) }),
basicElements.NewListEntry("mouse", func () { turnPage(mouse) }),
basicElements.NewListEntry("input", func () { turnPage(input) }),
basicElements.NewListEntry("form", func () { turnPage(form) }))
list.OnNoEntrySelected(func () { turnPage (intro) })
list.Collapse(96, 0)

View File

@ -2,7 +2,7 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -14,12 +14,12 @@ func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Dialog Boxes")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
container.Adopt(basic.NewLabel("Try out different dialogs:", false), true)
container.Adopt(basicElements.NewLabel("Try out different dialogs:", false), true)
infoButton := basic.NewButton("popups.DialogKindInfo")
infoButton := basicElements.NewButton("popups.DialogKindInfo")
infoButton.OnClick (func () {
popups.NewDialog (
popups.DialogKindInfo,
@ -29,7 +29,7 @@ func run () {
container.Adopt(infoButton, false)
infoButton.Focus()
questionButton := basic.NewButton("popups.DialogKindQuestion")
questionButton := basicElements.NewButton("popups.DialogKindQuestion")
questionButton.OnClick (func () {
popups.NewDialog (
popups.DialogKindQuestion,
@ -41,7 +41,7 @@ func run () {
})
container.Adopt(questionButton, false)
warningButton := basic.NewButton("popups.DialogKindWarning")
warningButton := basicElements.NewButton("popups.DialogKindWarning")
warningButton.OnClick (func () {
popups.NewDialog (
popups.DialogKindQuestion,
@ -50,7 +50,7 @@ func run () {
})
container.Adopt(warningButton, false)
errorButton := basic.NewButton("popups.DialogKindError")
errorButton := basicElements.NewButton("popups.DialogKindError")
errorButton.OnClick (func () {
popups.NewDialog (
popups.DialogKindQuestion,
@ -59,7 +59,7 @@ func run () {
})
container.Adopt(errorButton, false)
cancelButton := basic.NewButton("No thank you.")
cancelButton := basicElements.NewButton("No thank you.")
cancelButton.OnClick(tomo.Stop)
container.Adopt(cancelButton, false)

View File

@ -3,7 +3,7 @@ package main
import "time"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -14,14 +14,14 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Approaching")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
container.Adopt (basic.NewLabel (
container.Adopt (basicElements.NewLabel (
"Rapidly approaching your location...", false), false)
bar := basic.NewProgressBar(0)
bar := basicElements.NewProgressBar(0)
container.Adopt(bar, false)
button := basic.NewButton("Stop")
button := basicElements.NewButton("Stop")
button.SetEnabled(false)
container.Adopt(button, false)
@ -30,7 +30,7 @@ func run () {
go fill(bar)
}
func fill (bar *basic.ProgressBar) {
func fill (bar *basicElements.ProgressBar) {
for progress := 0.0; progress < 1.0; progress += 0.01 {
time.Sleep(time.Second / 24)
tomo.Do (func () {

View File

@ -1,7 +1,7 @@
package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -12,13 +12,13 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Scroll")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
container.Adopt(basic.NewLabel("look at this non sense", false), false)
container.Adopt(basicElements.NewLabel("look at this non sense", false), false)
textBox := basic.NewTextBox("", "sample text sample text")
scrollContainer := basic.NewScrollContainer(true, false)
textBox := basicElements.NewTextBox("", "sample text sample text")
scrollContainer := basicElements.NewScrollContainer(true, false)
scrollContainer.Adopt(textBox)
container.Adopt(scrollContainer, true)

View File

@ -1,7 +1,7 @@
package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -13,14 +13,14 @@ func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Spaced Out")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
container.Adopt (basic.NewLabel("This is at the top", false), false)
container.Adopt (basic.NewSpacer(true), false)
container.Adopt (basic.NewLabel("This is in the middle", false), false)
container.Adopt (basic.NewSpacer(false), true)
container.Adopt (basic.NewLabel("This is at the bottom", false), false)
container.Adopt (basicElements.NewLabel("This is at the top", false), false)
container.Adopt (basicElements.NewSpacer(true), false)
container.Adopt (basicElements.NewLabel("This is in the middle", false), false)
container.Adopt (basicElements.NewSpacer(false), true)
container.Adopt (basicElements.NewLabel("This is at the bottom", false), false)
window.OnClose(tomo.Stop)
window.Show()

View File

@ -1,7 +1,7 @@
package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -13,12 +13,12 @@ func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Switches")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
container.Adopt(basic.NewSwitch("hahahah", false), false)
container.Adopt(basic.NewSwitch("hehehehheheh", false), false)
container.Adopt(basic.NewSwitch("you can flick da swicth", false), false)
container.Adopt(basicElements.NewSwitch("hahahah", false), false)
container.Adopt(basicElements.NewSwitch("hehehehheheh", false), false)
container.Adopt(basicElements.NewSwitch("you can flick da swicth", false), false)
window.OnClose(tomo.Stop)
window.Show()

View File

@ -1,7 +1,7 @@
package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/testing"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
@ -14,15 +14,15 @@ func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("vertical stack")
container := basic.NewContainer(layouts.Vertical { true, true })
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
window.Adopt(container)
label := basic.NewLabel("it is a label hehe", true)
button := basic.NewButton("drawing pad")
okButton := basic.NewButton("OK")
label := basicElements.NewLabel("it is a label hehe", true)
button := basicElements.NewButton("drawing pad")
okButton := basicElements.NewButton("OK")
button.OnClick (func () {
container.DisownAll()
container.Adopt(basic.NewLabel("Draw here:", false), false)
container.Adopt(basicElements.NewLabel("Draw here:", false), false)
container.Adopt(testing.NewMouse(), true)
container.Adopt(okButton, false)
okButton.Focus()

112
input.go
View File

@ -1,112 +0,0 @@
package tomo
import "unicode"
// Key represents a keyboard key.
type Key int
const (
KeyNone Key = 0
KeyInsert Key = 1
KeyMenu Key = 2
KeyPrintScreen Key = 3
KeyPause Key = 4
KeyCapsLock Key = 5
KeyScrollLock Key = 6
KeyNumLock Key = 7
KeyBackspace Key = 8
KeyTab Key = 9
KeyEnter Key = 10
KeyEscape Key = 11
KeyUp Key = 12
KeyDown Key = 13
KeyLeft Key = 14
KeyRight Key = 15
KeyPageUp Key = 16
KeyPageDown Key = 17
KeyHome Key = 18
KeyEnd Key = 19
KeyLeftShift Key = 20
KeyRightShift Key = 21
KeyLeftControl Key = 22
KeyRightControl Key = 23
KeyLeftAlt Key = 24
KeyRightAlt Key = 25
KeyLeftMeta Key = 26
KeyRightMeta Key = 27
KeyLeftSuper Key = 28
KeyRightSuper Key = 29
KeyLeftHyper Key = 30
KeyRightHyper Key = 31
KeyDelete Key = 127
KeyDead Key = 128
KeyF1 Key = 129
KeyF2 Key = 130
KeyF3 Key = 131
KeyF4 Key = 132
KeyF5 Key = 133
KeyF6 Key = 134
KeyF7 Key = 135
KeyF8 Key = 136
KeyF9 Key = 137
KeyF10 Key = 138
KeyF11 Key = 139
KeyF12 Key = 140
)
// Button represents a mouse button.
type Button int
const (
ButtonNone Button = iota
Button1
Button2
Button3
Button4
Button5
Button6
Button7
Button8
Button9
ButtonLeft Button = Button1
ButtonMiddle Button = Button2
ButtonRight Button = Button3
ButtonBack Button = Button8
ButtonForward Button = Button9
)
// Printable returns whether or not the key's character could show up on screen.
// If this function returns true, the key can be cast to a rune and used as
// such.
func (key Key) Printable () (printable bool) {
printable = unicode.IsPrint(rune(key))
return
}
// Modifiers lists what modifier keys are being pressed. This is used in
// conjunction with a Key code in a Key press event. These should be used
// instead of attempting to track the state of the modifier keys, because there
// is no guarantee that one press event will be coupled with one release event.
type Modifiers struct {
Shift bool
Control bool
Alt bool
Meta bool
Super bool
Hyper bool
// NumberPad does not represent a key, but it behaves like one. If it is
// set to true, the Key was pressed on the number pad. It is treated
// as a modifier key because if you don't care whether a key was pressed
// on the number pad or not, you can just ignore this value.
NumberPad bool
}

View File

@ -1,30 +0,0 @@
package tomo
import "image"
// LayoutEntry associates an element with layout and positioning information so
// it can be arranged by a Layout.
type LayoutEntry struct {
Element
Bounds image.Rectangle
Expand bool
}
// Layout is capable of arranging elements within a container. It is also able
// to determine the minimum amount of room it needs to do so.
type Layout interface {
// Arrange takes in a slice of entries and a bounding width and height,
// and changes the position of the entiries in the slice so that they
// are properly laid out. The given width and height should not be less
// than what is returned by MinimumSize.
Arrange (entries []LayoutEntry, bounds image.Rectangle)
// MinimumSize returns the minimum width and height that the layout
// needs to properly arrange the given slice of layout entries.
MinimumSize (entries []LayoutEntry) (width, height int)
// FlexibleHeightFor Returns the minimum height the layout needs to lay
// out the specified elements at the given width, taking into account
// flexible elements.
FlexibleHeightFor (entries []LayoutEntry, squeeze int) (height int)
}

View File

@ -1,7 +1,8 @@
package popups
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
// DialogKind defines the semantic role of a dialog window.
@ -30,24 +31,24 @@ func NewDialog (
title, message string,
buttons ...Button,
) (
window tomo.Window,
window elements.Window,
) {
window, _ = tomo.NewWindow(2, 2)
window.SetTitle(title)
container := basic.NewContainer(layouts.Dialog { true, true })
container := basicElements.NewContainer(basicLayouts.Dialog { true, true })
window.Adopt(container)
container.Adopt(basic.NewLabel(message, false), true)
container.Adopt(basicElements.NewLabel(message, false), true)
if len(buttons) == 0 {
button := basic.NewButton("OK")
button := basicElements.NewButton("OK")
button.OnClick(window.Close)
container.Adopt(button, false)
button.Focus()
} else {
var button *basic.Button
var button *basicElements.Button
for _, buttonDescriptor := range buttons {
button = basic.NewButton(buttonDescriptor.Name)
button = basicElements.NewButton(buttonDescriptor.Name)
button.SetEnabled(buttonDescriptor.OnPress != nil)
button.OnClick (func () {
buttonDescriptor.OnPress()

View File

@ -1,39 +0,0 @@
package tomo
import "image"
// Window represents a top-level container generated by the currently running
// backend. It can contain a single element. It is hidden by default, and must
// be explicitly shown with the Show() method. If it contains no element, it
// displays a black (or transprent) background.
type Window interface {
// Adopt sets the root element of the window. There can only be one of
// these at one time.
Adopt (child Element)
// Child returns the root element of the window.
Child () (child Element)
// SetTitle sets the title that appears on the window's title bar. This
// method might have no effect with some backends.
SetTitle (title string)
// SetIcon taks in a list different sizes of the same icon and selects
// the best one to display on the window title bar, dock, or whatever is
// applicable for the given backend. This method might have no effect
// for some backends.
SetIcon (sizes []image.Image)
// Show shows the window. The window starts off hidden, so this must be
// called after initial setup to make sure it is visible.
Show ()
// Hide hides the window.
Hide ()
// Close closes the window.
Close ()
// OnClose specifies a function to be called when the window is closed.
OnClose (func ())
}