Re-organized module structure

This commit is contained in:
Sasha Koshka 2023-03-30 23:19:04 -04:00
parent 719b7b99ac
commit 53bfc8df68
62 changed files with 458 additions and 532 deletions

View File

@ -3,7 +3,6 @@ package tomo
import "errors"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/config"
import "git.tebibyte.media/sashakoshka/tomo/elements"
// Backend represents a connection to a display server, or something similar.
// It is capable of managing an event loop, and creating windows.
@ -22,7 +21,7 @@ type Backend interface {
// NewWindow creates a new window with the specified width and height,
// and returns a struct representing it that fulfills the MainWindow
// interface.
NewWindow (width, height int) (window elements.MainWindow, err error)
NewWindow (width, height int) (window MainWindow, err error)
// SetTheme sets the theme of all open windows.
SetTheme (theme.Theme)

View File

@ -1,8 +1,8 @@
package x
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "github.com/jezek/xgbutil"
import "github.com/jezek/xgb/xproto"
@ -127,7 +127,7 @@ func (window *window) handleKeyPress (
modifiers.NumberPad = numberPad
if key == input.KeyTab && modifiers.Alt {
if child, ok := window.child.(elements.Focusable); ok {
if child, ok := window.child.(tomo.Focusable); ok {
direction := input.KeynavDirectionForward
if modifiers.Shift {
direction = input.KeynavDirectionBackward
@ -137,7 +137,7 @@ func (window *window) handleKeyPress (
child.HandleUnfocus()
}
}
} else if child, ok := window.child.(elements.KeyboardTarget); ok {
} else if child, ok := window.child.(tomo.KeyboardTarget); ok {
child.HandleKeyDown(key, modifiers)
}
}
@ -171,7 +171,7 @@ func (window *window) handleKeyRelease (
modifiers := window.modifiersFromState(keyEvent.State)
modifiers.NumberPad = numberPad
if child, ok := window.child.(elements.KeyboardTarget); ok {
if child, ok := window.child.(tomo.KeyboardTarget); ok {
child.HandleKeyUp(key, modifiers)
}
}
@ -185,7 +185,7 @@ func (window *window) handleButtonPress (
buttonEvent := *event.ButtonPressEvent
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 {
if child, ok := window.child.(elements.ScrollTarget); ok {
if child, ok := window.child.(tomo.ScrollTarget); ok {
sum := scrollSum { }
sum.add(buttonEvent.Detail, window, buttonEvent.State)
window.compressScrollSum(buttonEvent, &sum)
@ -195,7 +195,7 @@ func (window *window) handleButtonPress (
float64(sum.x), float64(sum.y))
}
} else {
if child, ok := window.child.(elements.MouseTarget); ok {
if child, ok := window.child.(tomo.MouseTarget); ok {
child.HandleMouseDown (
int(buttonEvent.EventX),
int(buttonEvent.EventY),
@ -211,7 +211,7 @@ func (window *window) handleButtonRelease (
) {
if window.child == nil { return }
if child, ok := window.child.(elements.MouseTarget); ok {
if child, ok := window.child.(tomo.MouseTarget); ok {
buttonEvent := *event.ButtonReleaseEvent
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return }
child.HandleMouseUp (
@ -227,7 +227,7 @@ func (window *window) handleMotionNotify (
) {
if window.child == nil { return }
if child, ok := window.child.(elements.MotionTarget); ok {
if child, ok := window.child.(tomo.MotionTarget); ok {
motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
child.HandleMotion (
int(motionEvent.EventX),

View File

@ -9,12 +9,12 @@ import "github.com/jezek/xgbutil/xprop"
import "github.com/jezek/xgbutil/xevent"
import "github.com/jezek/xgbutil/xwindow"
import "github.com/jezek/xgbutil/xgraphics"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/data"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/config"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/elements"
// import "runtime/debug"
type mainWindow struct { *window }
@ -23,7 +23,7 @@ type window struct {
xWindow *xwindow.Window
xCanvas *xgraphics.Image
canvas canvas.BasicCanvas
child elements.Element
child tomo.Element
onClose func ()
skipChildDrawCallback bool
@ -45,7 +45,7 @@ type window struct {
func (backend *Backend) NewWindow (
width, height int,
) (
output elements.MainWindow,
output tomo.MainWindow,
err error,
) {
if backend == nil { panic("nil backend") }
@ -120,35 +120,35 @@ func (backend *Backend) newWindow (
return
}
func (window *window) NotifyMinimumSizeChange (child elements.Element) {
func (window *window) NotifyMinimumSizeChange (child tomo.Element) {
window.childMinimumSizeChangeCallback(child.MinimumSize())
}
func (window *window) RequestFocus (
child elements.Focusable,
child tomo.Focusable,
) (
granted bool,
) {
return true
}
func (window *window) RequestFocusNext (child elements.Focusable) {
if child, ok := window.child.(elements.Focusable); ok {
func (window *window) RequestFocusNext (child tomo.Focusable) {
if child, ok := window.child.(tomo.Focusable); ok {
if !child.HandleFocus(input.KeynavDirectionForward) {
child.HandleUnfocus()
}
}
}
func (window *window) RequestFocusPrevious (child elements.Focusable) {
if child, ok := window.child.(elements.Focusable); ok {
func (window *window) RequestFocusPrevious (child tomo.Focusable) {
if child, ok := window.child.(tomo.Focusable); ok {
if !child.HandleFocus(input.KeynavDirectionBackward) {
child.HandleUnfocus()
}
}
}
func (window *window) Adopt (child elements.Element) {
func (window *window) Adopt (child tomo.Element) {
// disown previous child
if window.child != nil {
window.child.SetParent(nil)
@ -159,10 +159,10 @@ func (window *window) Adopt (child elements.Element) {
// adopt new child
window.child = child
child.SetParent(window)
if newChild, ok := child.(elements.Themeable); ok {
if newChild, ok := child.(tomo.Themeable); ok {
newChild.SetTheme(window.theme)
}
if newChild, ok := child.(elements.Configurable); ok {
if newChild, ok := child.(tomo.Configurable); ok {
newChild.SetConfig(window.config)
}
if child != nil {
@ -174,7 +174,7 @@ func (window *window) Adopt (child elements.Element) {
}
}
func (window *window) Child () (child elements.Element) {
func (window *window) Child () (child tomo.Element) {
child = window.child
return
}
@ -225,7 +225,7 @@ func (window *window) SetIcon (sizes []image.Image) {
wmIcons)
}
func (window *window) NewModal (width, height int) (elements.Window, error) {
func (window *window) NewModal (width, height int) (tomo.Window, error) {
modal, err := window.backend.newWindow(width, height)
icccm.WmTransientForSet (
window.backend.connection,
@ -240,7 +240,7 @@ func (window *window) NewModal (width, height int) (elements.Window, error) {
return modal, err
}
func (window mainWindow) NewPanel (width, height int) (elements.Window, error) {
func (window mainWindow) NewPanel (width, height int) (tomo.Window, error) {
panel, err := window.backend.newWindow(width, height)
if err != nil { return nil, err }
panel.setClientLeader(window.window)
@ -336,14 +336,14 @@ func (window *window) OnClose (callback func ()) {
func (window *window) SetTheme (theme theme.Theme) {
window.theme = theme
if child, ok := window.child.(elements.Themeable); ok {
if child, ok := window.child.(tomo.Themeable); ok {
child.SetTheme(theme)
}
}
func (window *window) SetConfig (config config.Config) {
window.config = config
if child, ok := window.child.(elements.Configurable); ok {
if child, ok := window.child.(tomo.Configurable); ok {
child.SetConfig(config)
}
}

View File

@ -1,4 +1,4 @@
package elements
package tomo
import "image"
import "git.tebibyte.media/sashakoshka/tomo/input"

View File

@ -1,3 +0,0 @@
// Package basicElements provides standard elements that are commonly used in
// GUI applications.
package basicElements

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "image"
// import "runtime/debug"
@ -34,7 +34,7 @@ type Button struct {
// NewButton creates a new button with the specified label text.
func NewButton (text string) (element *Button) {
element = &Button { showText: true }
element.theme.Case = theme.C("basic", "button")
element.theme.Case = theme.C("tomo", "button")
element.Core, element.core = core.NewCore(element, element.drawAll)
element.FocusableCore,
element.focusableControl = core.NewFocusableCore(element.core, element.drawAndPush)

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "image"
import "git.tebibyte.media/sashakoshka/tomo/input"
@ -28,7 +28,7 @@ type Checkbox struct {
// NewCheckbox creates a new cbeckbox with the specified label text.
func NewCheckbox (text string, checked bool) (element *Checkbox) {
element = &Checkbox { checked: checked }
element.theme.Case = theme.C("basic", "checkbox")
element.theme.Case = theme.C("tomo", "checkbox")
element.Core, element.core = core.NewCore(element, element.draw)
element.FocusableCore,
element.focusableControl = core.NewFocusableCore(element.core, element.redo)

View File

@ -1,13 +1,12 @@
package containers
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/config"
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"
// Container is an element capable of containg other elements, and arranging
@ -17,8 +16,8 @@ type Container struct {
*core.Propagator
core core.CoreControl
layout layouts.Layout
children []layouts.LayoutEntry
layout tomo.Layout
children []tomo.LayoutEntry
warping bool
config config.Wrapped
@ -29,9 +28,9 @@ type Container struct {
}
// NewContainer creates a new container.
func NewContainer (layout layouts.Layout) (element *Container) {
func NewContainer (layout tomo.Layout) (element *Container) {
element = &Container { }
element.theme.Case = theme.C("containers", "container")
element.theme.Case = theme.C("tomo", "container")
element.Core, element.core = core.NewCore(element, element.redoAll)
element.Propagator = core.NewPropagator(element, element.core)
element.SetLayout(layout)
@ -39,7 +38,7 @@ func NewContainer (layout layouts.Layout) (element *Container) {
}
// SetLayout sets the layout of this container.
func (element *Container) SetLayout (layout layouts.Layout) {
func (element *Container) SetLayout (layout tomo.Layout) {
element.layout = layout
element.updateMinimumSize()
if element.core.HasImage() {
@ -51,17 +50,17 @@ func (element *Container) SetLayout (layout layouts.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 elements.Element, expand bool) {
if child0, ok := child.(elements.Themeable); ok {
func (element *Container) Adopt (child tomo.Element, expand bool) {
if child0, ok := child.(tomo.Themeable); ok {
child0.SetTheme(element.theme.Theme)
}
if child0, ok := child.(elements.Configurable); ok {
if child0, ok := child.(tomo.Configurable); ok {
child0.SetConfig(element.config.Config)
}
child.SetParent(element)
// add child
element.children = append (element.children, layouts.LayoutEntry {
element.children = append (element.children, tomo.LayoutEntry {
Element: child,
Expand: expand,
})
@ -98,7 +97,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 elements.Element) {
func (element *Container) Disown (child tomo.Element) {
for index, entry := range element.children {
if entry.Element == child {
element.clearChildEventHandlers(entry.Element)
@ -116,11 +115,11 @@ func (element *Container) Disown (child elements.Element) {
}
}
func (element *Container) clearChildEventHandlers (child elements.Element) {
func (element *Container) clearChildEventHandlers (child tomo.Element) {
child.DrawTo(nil, image.Rectangle { }, nil)
child.SetParent(nil)
if child, ok := child.(elements.Focusable); ok {
if child, ok := child.(tomo.Focusable); ok {
if child.Focused() {
child.HandleUnfocus()
}
@ -142,8 +141,8 @@ func (element *Container) DisownAll () {
}
// Children returns a slice containing this element's children.
func (element *Container) Children () (children []elements.Element) {
children = make([]elements.Element, len(element.children))
func (element *Container) Children () (children []tomo.Element) {
children = make([]tomo.Element, len(element.children))
for index, entry := range element.children {
children[index] = entry.Element
}
@ -157,14 +156,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 elements.Element) {
func (element *Container) Child (index int) (child tomo.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 elements.Element) {
func (element *Container) ChildAt (point image.Point) (child tomo.Element) {
for _, entry := range element.children {
if point.In(entry.Bounds) {
child = entry.Element
@ -207,7 +206,7 @@ func (element *Container) redoAll () {
// NotifyMinimumSizeChange notifies the container that the minimum size of a
// child element has changed.
func (element *Container) NotifyMinimumSizeChange (child elements.Element) {
func (element *Container) NotifyMinimumSizeChange (child tomo.Element) {
element.updateMinimumSize()
element.redoAll()
element.core.DamageAll()

View File

@ -1,12 +1,11 @@
package containers
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/config"
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"
type DocumentContainer struct {
@ -14,7 +13,7 @@ type DocumentContainer struct {
*core.Propagator
core core.CoreControl
children []layouts.LayoutEntry
children []tomo.LayoutEntry
scroll image.Point
warping bool
contentBounds image.Rectangle
@ -28,24 +27,24 @@ type DocumentContainer struct {
// NewDocumentContainer creates a new document container.
func NewDocumentContainer () (element *DocumentContainer) {
element = &DocumentContainer { }
element.theme.Case = theme.C("containers", "documentContainer")
element.theme.Case = theme.C("tomo", "documentContainer")
element.Core, element.core = core.NewCore(element, element.redoAll)
element.Propagator = core.NewPropagator(element, element.core)
return
}
// Adopt adds a new child element to the container.
func (element *DocumentContainer) Adopt (child elements.Element) {
func (element *DocumentContainer) Adopt (child tomo.Element) {
// set event handlers
if child0, ok := child.(elements.Themeable); ok {
if child0, ok := child.(tomo.Themeable); ok {
child0.SetTheme(element.theme.Theme)
}
if child0, ok := child.(elements.Configurable); ok {
if child0, ok := child.(tomo.Configurable); ok {
child0.SetConfig(element.config.Config)
}
// add child
element.children = append (element.children, layouts.LayoutEntry {
element.children = append (element.children, tomo.LayoutEntry {
Element: child,
})
@ -80,7 +79,7 @@ func (element *DocumentContainer) Warp (callback func ()) {
// Disown removes the given child from the container if it is contained within
// it.
func (element *DocumentContainer) Disown (child elements.Element) {
func (element *DocumentContainer) Disown (child tomo.Element) {
for index, entry := range element.children {
if entry.Element == child {
element.clearChildEventHandlers(entry.Element)
@ -98,11 +97,11 @@ func (element *DocumentContainer) Disown (child elements.Element) {
}
}
func (element *DocumentContainer) clearChildEventHandlers (child elements.Element) {
func (element *DocumentContainer) clearChildEventHandlers (child tomo.Element) {
child.DrawTo(nil, image.Rectangle { }, nil)
child.SetParent(nil)
if child, ok := child.(elements.Focusable); ok {
if child, ok := child.(tomo.Focusable); ok {
if child.Focused() {
child.HandleUnfocus()
}
@ -124,8 +123,8 @@ func (element *DocumentContainer) DisownAll () {
}
// Children returns a slice containing this element's children.
func (element *DocumentContainer) Children () (children []elements.Element) {
children = make([]elements.Element, len(element.children))
func (element *DocumentContainer) Children () (children []tomo.Element) {
children = make([]tomo.Element, len(element.children))
for index, entry := range element.children {
children[index] = entry.Element
}
@ -139,14 +138,14 @@ func (element *DocumentContainer) 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 *DocumentContainer) Child (index int) (child elements.Element) {
func (element *DocumentContainer) Child (index int) (child tomo.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 *DocumentContainer) ChildAt (point image.Point) (child elements.Element) {
func (element *DocumentContainer) ChildAt (point image.Point) (child tomo.Element) {
for _, entry := range element.children {
if point.In(entry.Bounds) {
child = entry.Element
@ -178,7 +177,7 @@ func (element *DocumentContainer) redoAll () {
artist.DrawShatter(element.core, pattern, element.Bounds(), rocks...)
element.partition()
if parent, ok := element.core.Parent().(elements.ScrollableParent); ok {
if parent, ok := element.core.Parent().(tomo.ScrollableParent); ok {
parent.NotifyScrollBoundsChange(element)
}
if element.onScrollBoundsChange != nil {
@ -205,7 +204,7 @@ func (element *DocumentContainer) partition () {
// NotifyMinimumSizeChange notifies the container that the minimum size of a
// child element has changed.
func (element *DocumentContainer) NotifyMinimumSizeChange (child elements.Element) {
func (element *DocumentContainer) NotifyMinimumSizeChange (child tomo.Element) {
element.redoAll()
element.core.DamageAll()
}
@ -214,7 +213,7 @@ func (element *DocumentContainer) NotifyMinimumSizeChange (child elements.Elemen
// affecting a child's flexible height have changed. This method is
// expected to be called by flexible child element when their content
// changes.
func (element *DocumentContainer) NotifyFlexibleHeightChange (child elements.Flexible) {
func (element *DocumentContainer) NotifyFlexibleHeightChange (child tomo.Flexible) {
element.redoAll()
element.core.DamageAll()
}
@ -300,7 +299,7 @@ func (element *DocumentContainer) doLayout () {
if width < bounds.Dx() {
width = bounds.Dx()
}
if typedChild, ok := entry.Element.(elements.Flexible); ok {
if typedChild, ok := entry.Element.(tomo.Flexible); ok {
height = typedChild.FlexibleHeightFor(width)
}

View File

@ -1,13 +1,13 @@
package containers
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/config"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
// ScrollContainer is a container that is capable of holding a scrollable
// element.
@ -16,9 +16,9 @@ type ScrollContainer struct {
*core.Propagator
core core.CoreControl
child elements.Scrollable
horizontal *basicElements.ScrollBar
vertical *basicElements.ScrollBar
child tomo.Scrollable
horizontal *elements.ScrollBar
vertical *elements.ScrollBar
config config.Wrapped
theme theme.Wrapped
@ -31,12 +31,12 @@ type ScrollContainer struct {
// bars.
func NewScrollContainer (horizontal, vertical bool) (element *ScrollContainer) {
element = &ScrollContainer { }
element.theme.Case = theme.C("containers", "scrollContainer")
element.theme.Case = theme.C("tomo", "scrollContainer")
element.Core, element.core = core.NewCore(element, element.redoAll)
element.Propagator = core.NewPropagator(element, element.core)
if horizontal {
element.horizontal = basicElements.NewScrollBar(false)
element.horizontal = elements.NewScrollBar(false)
element.setUpChild(element.horizontal)
element.horizontal.OnScroll (func (viewport image.Point) {
if element.child != nil {
@ -50,7 +50,7 @@ func NewScrollContainer (horizontal, vertical bool) (element *ScrollContainer) {
})
}
if vertical {
element.vertical = basicElements.NewScrollBar(true)
element.vertical = elements.NewScrollBar(true)
element.setUpChild(element.vertical)
element.vertical.OnScroll (func (viewport image.Point) {
if element.child != nil {
@ -70,7 +70,7 @@ func NewScrollContainer (horizontal, vertical bool) (element *ScrollContainer) {
// 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 elements.Scrollable) {
func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
// disown previous child if it exists
if element.child != nil {
element.disownChild(child)
@ -90,20 +90,20 @@ func (element *ScrollContainer) Adopt (child elements.Scrollable) {
}
}
func (element *ScrollContainer) setUpChild (child elements.Element) {
func (element *ScrollContainer) setUpChild (child tomo.Element) {
child.SetParent(element)
if child, ok := child.(elements.Themeable); ok {
if child, ok := child.(tomo.Themeable); ok {
child.SetTheme(element.theme.Theme)
}
if child, ok := child.(elements.Configurable); ok {
if child, ok := child.(tomo.Configurable); ok {
child.SetConfig(element.config.Config)
}
}
func (element *ScrollContainer) disownChild (child elements.Scrollable) {
func (element *ScrollContainer) disownChild (child tomo.Scrollable) {
child.DrawTo(nil, image.Rectangle { }, nil)
child.SetParent(nil)
if child, ok := child.(elements.Focusable); ok {
if child, ok := child.(tomo.Focusable); ok {
if child.Focused() {
child.HandleUnfocus()
}
@ -112,14 +112,14 @@ func (element *ScrollContainer) disownChild (child elements.Scrollable) {
// NotifyMinimumSizeChange notifies the container that the minimum size of a
// child element has changed.
func (element *ScrollContainer) NotifyMinimumSizeChange (child elements.Element) {
func (element *ScrollContainer) NotifyMinimumSizeChange (child tomo.Element) {
element.redoAll()
element.core.DamageAll()
}
// NotifyScrollBoundsChange notifies the container that the scroll bounds or
// axes of a child have changed.
func (element *ScrollContainer) NotifyScrollBoundsChange (child elements.Scrollable) {
func (element *ScrollContainer) NotifyScrollBoundsChange (child tomo.Scrollable) {
element.updateEnabled()
viewportBounds := element.child.ScrollViewportBounds()
contentBounds := element.child.ScrollContentBounds()
@ -165,7 +165,7 @@ func (element *ScrollContainer) 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 *ScrollContainer) Child (index int) (child elements.Element) {
func (element *ScrollContainer) Child (index int) (child tomo.Element) {
switch index {
case 0: return element.child
case 1:

View File

@ -2,16 +2,16 @@ package core
import "image"
import "image/color"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/elements"
// 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 canvas.Canvas
bounds image.Rectangle
parent elements.Parent
outer elements.Element
parent tomo.Parent
outer tomo.Element
metrics struct {
minimumWidth int
@ -26,7 +26,7 @@ type Core struct {
// element that it will be a part of. If outer is nil, this function will return
// nil.
func NewCore (
outer elements.Element,
outer tomo.Element,
drawSizeChange func (),
) (
core *Core,
@ -57,7 +57,7 @@ func (core *Core) MinimumSize () (width, height int) {
// MinimumSize fulfils the tomo.Element interface. This should not need to be
// overridden, unless you want to detect when the element is parented or
// unparented.
func (core *Core) SetParent (parent elements.Parent) {
func (core *Core) SetParent (parent tomo.Parent) {
if parent != nil && core.parent != nil {
panic("core.SetParent: element already has a parent")
}
@ -118,12 +118,12 @@ func (control CoreControl) Buffer () (data []color.RGBA, stride int) {
}
// Parent returns the element's parent.
func (control CoreControl) Parent () elements.Parent {
func (control CoreControl) Parent () tomo.Parent {
return control.core.parent
}
// Outer returns the outer element given when the control was constructed.
func (control CoreControl) Outer () elements.Element {
func (control CoreControl) Outer () tomo.Element {
return control.core.outer
}

View File

@ -1,8 +1,8 @@
package core
// import "runtime/debug"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/elements"
// FocusableCore is a struct that can be embedded into objects to make them
// focusable, giving them the default keynav behavior.
@ -42,9 +42,9 @@ func (core *FocusableCore) Focused () (focused bool) {
func (core *FocusableCore) Focus () {
if !core.enabled || core.focused { return }
parent := core.core.Parent()
if parent, ok := parent.(elements.FocusableParent); ok {
if parent, ok := parent.(tomo.FocusableParent); ok {
core.focused = parent.RequestFocus (
core.core.Outer().(elements.Focusable))
core.core.Outer().(tomo.Focusable))
}
}

View File

@ -1,15 +1,15 @@
package core
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/config"
import "git.tebibyte.media/sashakoshka/tomo/elements"
// Container represents an object that can provide access to a list of child
// elements.
type Container interface {
Child (index int) elements.Element
Child (index int) tomo.Element
CountChildren () int
}
@ -20,7 +20,7 @@ type Container interface {
type Propagator struct {
core CoreControl
container Container
drags [10]elements.MouseTarget
drags [10]tomo.MouseTarget
focused bool
}
@ -49,9 +49,9 @@ func (propagator *Propagator) Focused () (focused bool) {
func (propagator *Propagator) Focus () {
if propagator.focused == true { return }
parent := propagator.core.Parent()
if parent, ok := parent.(elements.FocusableParent); ok && parent != nil {
if parent, ok := parent.(tomo.FocusableParent); ok && parent != nil {
propagator.focused = parent.RequestFocus (
propagator.core.Outer().(elements.Focusable))
propagator.core.Outer().(tomo.Focusable))
}
}
@ -90,7 +90,7 @@ func (propagator *Propagator) HandleFocus (direction input.KeynavDirection) (acc
// focus in the specified direction
firstFocusedChild :=
propagator.container.Child(firstFocused).
(elements.Focusable)
(tomo.Focusable)
// before we move the focus, the currently focused child
// may also be able to move its focus. if the child is able
@ -107,7 +107,7 @@ func (propagator *Propagator) HandleFocus (direction input.KeynavDirection) (acc
child, focusable :=
propagator.container.Child(index).
(elements.Focusable)
(tomo.Focusable)
if focusable && child.HandleFocus(direction) {
// we have found one, so we now actually move
// the focus.
@ -126,12 +126,12 @@ func (propagator *Propagator) HandleFocus (direction input.KeynavDirection) (acc
// return true and the child element should behave as if a HandleFocus
// call was made.
func (propagator *Propagator) RequestFocus (
child elements.Focusable,
child tomo.Focusable,
) (
granted bool,
) {
if parent, ok := propagator.core.Parent().(elements.FocusableParent); ok {
if parent.RequestFocus(propagator.core.Outer().(elements.Focusable)) {
if parent, ok := propagator.core.Parent().(tomo.FocusableParent); ok {
if parent.RequestFocus(propagator.core.Outer().(tomo.Focusable)) {
propagator.HandleUnfocus()
propagator.focused = true
granted = true
@ -142,26 +142,26 @@ func (propagator *Propagator) RequestFocus (
// RequestFocusMotion notifies the parent that a child element wants the
// focus to be moved to the next focusable element.
func (propagator *Propagator) RequestFocusNext (child elements.Focusable) {
func (propagator *Propagator) RequestFocusNext (child tomo.Focusable) {
if !propagator.focused { return }
if parent, ok := propagator.core.Parent().(elements.FocusableParent); ok {
parent.RequestFocusNext(propagator.core.Outer().(elements.Focusable))
if parent, ok := propagator.core.Parent().(tomo.FocusableParent); ok {
parent.RequestFocusNext(propagator.core.Outer().(tomo.Focusable))
}
}
// RequestFocusMotion notifies the parent that a child element wants the
// focus to be moved to the previous focusable element.
func (propagator *Propagator) RequestFocusPrevious (child elements.Focusable) {
func (propagator *Propagator) RequestFocusPrevious (child tomo.Focusable) {
if !propagator.focused { return }
if parent, ok := propagator.core.Parent().(elements.FocusableParent); ok {
parent.RequestFocusPrevious(propagator.core.Outer().(elements.Focusable))
if parent, ok := propagator.core.Parent().(tomo.FocusableParent); ok {
parent.RequestFocusPrevious(propagator.core.Outer().(tomo.Focusable))
}
}
// HandleDeselection causes this element to mark itself and all of its children
// as unfocused.
func (propagator *Propagator) HandleUnfocus () {
propagator.forFocusable (func (child elements.Focusable) bool {
propagator.forFocusable (func (child tomo.Focusable) bool {
child.HandleUnfocus()
return true
})
@ -170,8 +170,8 @@ func (propagator *Propagator) HandleUnfocus () {
// HandleKeyDown propogates the keyboard event to the currently selected child.
func (propagator *Propagator) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
propagator.forFocused (func (child elements.Focusable) bool {
typedChild, handlesKeyboard := child.(elements.KeyboardTarget)
propagator.forFocused (func (child tomo.Focusable) bool {
typedChild, handlesKeyboard := child.(tomo.KeyboardTarget)
if handlesKeyboard {
typedChild.HandleKeyDown(key, modifiers)
}
@ -181,8 +181,8 @@ func (propagator *Propagator) HandleKeyDown (key input.Key, modifiers input.Modi
// HandleKeyUp propogates the keyboard event to the currently selected child.
func (propagator *Propagator) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
propagator.forFocused (func (child elements.Focusable) bool {
typedChild, handlesKeyboard := child.(elements.KeyboardTarget)
propagator.forFocused (func (child tomo.Focusable) bool {
typedChild, handlesKeyboard := child.(tomo.KeyboardTarget)
if handlesKeyboard {
typedChild.HandleKeyUp(key, modifiers)
}
@ -195,7 +195,7 @@ func (propagator *Propagator) HandleKeyUp (key input.Key, modifiers input.Modifi
func (propagator *Propagator) HandleMouseDown (x, y int, button input.Button) {
child, handlesMouse :=
propagator.childAt(image.Pt(x, y)).
(elements.MouseTarget)
(tomo.MouseTarget)
if handlesMouse {
propagator.drags[button] = child
child.HandleMouseDown(x, y, button)
@ -218,7 +218,7 @@ func (propagator *Propagator) HandleMouseUp (x, y int, button input.Button) {
func (propagator *Propagator) HandleMotion (x, y int) {
handled := false
for _, child := range propagator.drags {
if child, ok := child.(elements.MotionTarget); ok {
if child, ok := child.(tomo.MotionTarget); ok {
child.HandleMotion(x, y)
handled = true
}
@ -226,7 +226,7 @@ func (propagator *Propagator) HandleMotion (x, y int) {
if !handled {
child := propagator.childAt(image.Pt(x, y))
if child, ok := child.(elements.MotionTarget); ok {
if child, ok := child.(tomo.MotionTarget); ok {
child.HandleMotion(x, y)
}
}
@ -236,15 +236,15 @@ func (propagator *Propagator) HandleMotion (x, y int) {
// pointer.
func (propagator *Propagator) HandleScroll (x, y int, deltaX, deltaY float64) {
child := propagator.childAt(image.Pt(x, y))
if child, ok := child.(elements.ScrollTarget); ok {
if child, ok := child.(tomo.ScrollTarget); ok {
child.HandleScroll(x, y, deltaX, deltaY)
}
}
// SetTheme sets the theme of all children to the specified theme.
func (propagator *Propagator) SetTheme (theme theme.Theme) {
propagator.forChildren (func (child elements.Element) bool {
typedChild, themeable := child.(elements.Themeable)
propagator.forChildren (func (child tomo.Element) bool {
typedChild, themeable := child.(tomo.Themeable)
if themeable {
typedChild.SetTheme(theme)
}
@ -254,8 +254,8 @@ func (propagator *Propagator) SetTheme (theme theme.Theme) {
// SetConfig sets the theme of all children to the specified config.
func (propagator *Propagator) SetConfig (config config.Config) {
propagator.forChildren (func (child elements.Element) bool {
typedChild, configurable := child.(elements.Configurable)
propagator.forChildren (func (child tomo.Element) bool {
typedChild, configurable := child.(tomo.Configurable)
if configurable {
typedChild.SetConfig(config)
}
@ -270,7 +270,7 @@ func (propagator *Propagator) focusFirstFocusableElement (
) (
ok bool,
) {
propagator.forFocusable (func (child elements.Focusable) bool {
propagator.forFocusable (func (child tomo.Focusable) bool {
if child.HandleFocus(direction) {
propagator.focused = true
ok = true
@ -286,8 +286,8 @@ func (propagator *Propagator) focusLastFocusableElement (
) (
ok bool,
) {
propagator.forChildrenReverse (func (child elements.Element) bool {
typedChild, focusable := child.(elements.Focusable)
propagator.forChildrenReverse (func (child tomo.Element) bool {
typedChild, focusable := child.(tomo.Focusable)
if focusable && typedChild.HandleFocus(direction) {
propagator.focused = true
ok = true
@ -300,7 +300,7 @@ func (propagator *Propagator) focusLastFocusableElement (
// ----------- Iterator utilities ----------- //
func (propagator *Propagator) forChildren (callback func (child elements.Element) bool) {
func (propagator *Propagator) forChildren (callback func (child tomo.Element) bool) {
for index := 0; index < propagator.container.CountChildren(); index ++ {
child := propagator.container.Child(index)
if child == nil { continue }
@ -308,7 +308,7 @@ func (propagator *Propagator) forChildren (callback func (child elements.Element
}
}
func (propagator *Propagator) forChildrenReverse (callback func (child elements.Element) bool) {
func (propagator *Propagator) forChildrenReverse (callback func (child tomo.Element) bool) {
for index := propagator.container.CountChildren() - 1; index > 0; index -- {
child := propagator.container.Child(index)
if child == nil { continue }
@ -316,8 +316,8 @@ func (propagator *Propagator) forChildrenReverse (callback func (child elements.
}
}
func (propagator *Propagator) childAt (position image.Point) (child elements.Element) {
propagator.forChildren (func (current elements.Element) bool {
func (propagator *Propagator) childAt (position image.Point) (child tomo.Element) {
propagator.forChildren (func (current tomo.Element) bool {
if position.In(current.Bounds()) {
child = current
}
@ -326,9 +326,9 @@ func (propagator *Propagator) childAt (position image.Point) (child elements.Ele
return
}
func (propagator *Propagator) forFocused (callback func (child elements.Focusable) bool) {
propagator.forChildren (func (child elements.Element) bool {
typedChild, focusable := child.(elements.Focusable)
func (propagator *Propagator) forFocused (callback func (child tomo.Focusable) bool) {
propagator.forChildren (func (child tomo.Element) bool {
typedChild, focusable := child.(tomo.Focusable)
if focusable && typedChild.Focused() {
if !callback(typedChild) { return false }
}
@ -336,9 +336,9 @@ func (propagator *Propagator) forFocused (callback func (child elements.Focusabl
})
}
func (propagator *Propagator) forFocusable (callback func (child elements.Focusable) bool) {
propagator.forChildren (func (child elements.Element) bool {
typedChild, focusable := child.(elements.Focusable)
func (propagator *Propagator) forFocusable (callback func (child tomo.Focusable) bool) {
propagator.forChildren (func (child tomo.Element) bool {
typedChild, focusable := child.(tomo.Focusable)
if focusable {
if !callback(typedChild) { return false }
}
@ -348,7 +348,7 @@ func (propagator *Propagator) forFocusable (callback func (child elements.Focusa
func (propagator *Propagator) firstFocused () int {
for index := 0; index < propagator.container.CountChildren(); index ++ {
child, focusable := propagator.container.Child(index).(elements.Focusable)
child, focusable := propagator.container.Child(index).(tomo.Focusable)
if focusable && child.Focused() {
return index
}

View File

@ -1,6 +1,3 @@
// Package elements provides several standard interfaces that elements can
// fulfill in order to inform other elements of their capabilities and what
// events they are able to process. Sub-packages of this package provide
// pre-made standard elements, as well as tools that can be used to easily
// create more.
// Package elements provides standard elements that are commonly used in GUI
// applications.
package elements

View File

@ -22,7 +22,7 @@ type AnalogClock struct {
// NewAnalogClock creates a new analog clock that displays the specified time.
func NewAnalogClock (newTime time.Time) (element *AnalogClock) {
element = &AnalogClock { }
element.theme.Case = theme.C("fun", "clock")
element.theme.Case = theme.C("tomo", "clock")
element.Core, element.core = core.NewCore(element, element.draw)
element.core.SetMinimumSize(64, 64)
return

View File

@ -52,7 +52,7 @@ func NewPiano (low, high music.Octave) (element *Piano) {
keynavPressed: make(map[music.Note] bool),
}
element.theme.Case = theme.C("fun", "piano")
element.theme.Case = theme.C("tomo", "piano")
element.Core, element.core = core.NewCore (element, func () {
element.recalculate()
element.draw()

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "image"
import "git.tebibyte.media/sashakoshka/tomo/theme"
@ -18,7 +18,7 @@ func NewIcon (id theme.Icon, size theme.IconSize) (element *Icon) {
id: id,
size: size,
}
element.theme.Case = theme.C("basic", "icon")
element.theme.Case = theme.C("tomo", "icon")
element.Core, element.core = core.NewCore(element, element.draw)
element.updateMinimumSize()
return

View File

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

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "golang.org/x/image/math/fixed"
import "git.tebibyte.media/sashakoshka/tomo/theme"
@ -29,7 +29,7 @@ type Label struct {
// wrapped.
func NewLabel (text string, wrap bool) (element *Label) {
element = &Label { }
element.theme.Case = theme.C("basic", "label")
element.theme.Case = theme.C("tomo", "label")
element.Core, element.core = core.NewCore(element, element.handleResize)
element.SetWrap(wrap)
element.SetText(text)

View File

@ -1,4 +1,4 @@
package basicElements
package elements
// Numeric is a type constraint representing a number.
type Numeric interface {

View File

@ -1,13 +1,13 @@
package basicElements
package elements
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/config"
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"
// List is an element that contains several objects that a user can select.
@ -37,7 +37,7 @@ type List struct {
// NewList creates a new list element with the specified entries.
func NewList (entries ...ListEntry) (element *List) {
element = &List { selectedEntry: -1 }
element.theme.Case = theme.C("basic", "list")
element.theme.Case = theme.C("tomo", "list")
element.Core, element.core = core.NewCore(element, element.handleResize)
element.FocusableCore,
element.focusableControl = core.NewFocusableCore (element.core, func () {
@ -435,7 +435,7 @@ func (element *List) updateMinimumSize () {
}
func (element *List) scrollBoundsChange () {
if parent, ok := element.core.Parent().(elements.ScrollableParent); ok {
if parent, ok := element.core.Parent().(tomo.ScrollableParent); ok {
parent.NotifyScrollBoundsChange(element)
}
if element.onScrollBoundsChange != nil {

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "image"
import "git.tebibyte.media/sashakoshka/tomo/theme"
@ -26,7 +26,7 @@ func NewListEntry (text string, onSelect func ()) (entry ListEntry) {
text: text,
onSelect: onSelect,
}
entry.theme.Case = theme.C("basic", "listEntry")
entry.theme.Case = theme.C("tomo", "listEntry")
entry.drawer.SetText([]rune(text))
entry.updateBounds()
return

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "image"
import "git.tebibyte.media/sashakoshka/tomo/theme"
@ -19,7 +19,7 @@ type ProgressBar struct {
// level.
func NewProgressBar (progress float64) (element *ProgressBar) {
element = &ProgressBar { progress: progress }
element.theme.Case = theme.C("basic", "progressBar")
element.theme.Case = theme.C("tomo", "progressBar")
element.Core, element.core = core.NewCore(element, element.draw)
return
}

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "image"
import "git.tebibyte.media/sashakoshka/tomo/input"
@ -45,9 +45,9 @@ func NewScrollBar (vertical bool) (element *ScrollBar) {
enabled: true,
}
if vertical {
element.theme.Case = theme.C("basic", "scrollBarHorizontal")
element.theme.Case = theme.C("tomo", "scrollBarHorizontal")
} else {
element.theme.Case = theme.C("basic", "scrollBarVertical")
element.theme.Case = theme.C("tomo", "scrollBarVertical")
}
element.Core, element.core = core.NewCore(element, element.handleResize)
element.updateMinimumSize()

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "image"
import "git.tebibyte.media/sashakoshka/tomo/input"
@ -35,9 +35,9 @@ func NewSlider (value float64, vertical bool) (element *Slider) {
vertical: vertical,
}
if vertical {
element.theme.Case = theme.C("basic", "sliderVertical")
element.theme.Case = theme.C("tomo", "sliderVertical")
} else {
element.theme.Case = theme.C("basic", "sliderHorizontal")
element.theme.Case = theme.C("tomo", "sliderHorizontal")
}
element.Core, element.core = core.NewCore(element, element.draw)
element.FocusableCore,

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/config"
@ -19,7 +19,7 @@ type Spacer struct {
// will appear as a line.
func NewSpacer (line bool) (element *Spacer) {
element = &Spacer { line: line }
element.theme.Case = theme.C("basic", "spacer")
element.theme.Case = theme.C("tomo", "spacer")
element.Core, element.core = core.NewCore(element, element.draw)
element.updateMinimumSize()
return

View File

@ -1,4 +1,4 @@
package basicElements
package elements
import "image"
import "git.tebibyte.media/sashakoshka/tomo/input"
@ -32,7 +32,7 @@ func NewSwitch (text string, on bool) (element *Switch) {
checked: on,
text: text,
}
element.theme.Case = theme.C("basic", "switch")
element.theme.Case = theme.C("tomo", "switch")
element.Core, element.core = core.NewCore(element, element.draw)
element.FocusableCore,
element.focusableControl = core.NewFocusableCore(element.core, element.redo)

View File

@ -23,7 +23,7 @@ type Mouse struct {
// NewMouse creates a new mouse test element.
func NewMouse () (element *Mouse) {
element = &Mouse { c: theme.C("testing", "mouse") }
element = &Mouse { c: theme.C("tomo", "mouse") }
element.Core, element.core = core.NewCore(element, element.draw)
element.core.SetMinimumSize(32, 32)
return

View File

@ -1,12 +1,12 @@
package basicElements
package elements
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/config"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
import "git.tebibyte.media/sashakoshka/tomo/textmanip"
import "git.tebibyte.media/sashakoshka/tomo/fixedutil"
@ -43,7 +43,7 @@ type TextBox struct {
// text.
func NewTextBox (placeholder, value string) (element *TextBox) {
element = &TextBox { }
element.theme.Case = theme.C("basic", "textBox")
element.theme.Case = theme.C("tomo", "textBox")
element.Core, element.core = core.NewCore(element, element.handleResize)
element.FocusableCore,
element.focusableControl = core.NewFocusableCore (element.core, func () {
@ -62,7 +62,7 @@ func NewTextBox (placeholder, value string) (element *TextBox) {
func (element *TextBox) handleResize () {
element.scrollToCursor()
element.draw()
if parent, ok := element.core.Parent().(elements.ScrollableParent); ok {
if parent, ok := element.core.Parent().(tomo.ScrollableParent); ok {
parent.NotifyScrollBoundsChange(element)
}
}
@ -197,7 +197,7 @@ func (element *TextBox) HandleKeyDown(key input.Key, modifiers input.Modifiers)
}
if (textChanged || scrollMemory != element.scroll) {
if parent, ok := element.core.Parent().(elements.ScrollableParent); ok {
if parent, ok := element.core.Parent().(tomo.ScrollableParent); ok {
parent.NotifyScrollBoundsChange(element)
}
}
@ -294,7 +294,7 @@ func (element *TextBox) ScrollTo (position image.Point) {
if element.scroll > maxPosition { element.scroll = maxPosition }
element.redo()
if parent, ok := element.core.Parent().(elements.ScrollableParent); ok {
if parent, ok := element.core.Parent().(tomo.ScrollableParent); ok {
parent.NotifyScrollBoundsChange(element)
}
}

View File

@ -2,7 +2,7 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/textdraw"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -19,10 +19,10 @@ func run () {
scrollContainer.Adopt(container)
window.Adopt(scrollContainer)
left := basicElements.NewLabel(text, true)
center := basicElements.NewLabel(text, true)
right := basicElements.NewLabel(text, true)
justify := basicElements.NewLabel(text, true)
left := elements.NewLabel(text, true)
center := elements.NewLabel(text, true)
right := elements.NewLabel(text, true)
justify := elements.NewLabel(text, true)
left.SetAlign(textdraw.AlignLeft)
center.SetAlign(textdraw.AlignCenter)

View File

@ -1,7 +1,7 @@
package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/ezprof/ez"
@ -12,7 +12,7 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("example button")
button := basicElements.NewButton("hello tomo!")
button := elements.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,8 +2,8 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
@ -15,34 +15,35 @@ func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Checkboxes")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
container := containers.NewContainer(layouts.Vertical { true, true })
window.Adopt(container)
introText := basicElements.NewLabel (
introText := elements.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)
introText.EmCollapse(0, 5)
container.Adopt(introText, true)
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)
container.Adopt(elements.NewSpacer(true), false)
container.Adopt(elements.NewCheckbox("Oh god", false), false)
container.Adopt(elements.NewCheckbox("Can you hear them", true), false)
container.Adopt(elements.NewCheckbox("They are in the walls", false), false)
container.Adopt(elements.NewCheckbox("They are coming for us", false), false)
disabledCheckbox := elements.NewCheckbox("We are but their helpless prey", false)
disabledCheckbox.SetEnabled(false)
container.Adopt(disabledCheckbox, false)
vsync := basicElements.NewCheckbox("Enable vsync", false)
vsync := elements.NewCheckbox("Enable vsync", false)
vsync.OnToggle (func () {
if vsync.Value() {
popups.NewDialog (
popups.DialogKindInfo,
window,
"Ha!",
"That doesn't do anything.")
}
})
container.Adopt(vsync, false)
button := basicElements.NewButton("What")
button := elements.NewButton("What")
button.OnClick(tomo.Stop)
container.Adopt(button, false)
button.Focus()

View File

@ -9,8 +9,8 @@ import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/data"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -28,14 +28,14 @@ func run () {
window, _ := tomo.NewWindow(256, 2)
window.SetTitle("Clipboard")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
textInput := basicElements.NewTextBox("", "")
controlRow := containers.NewContainer(basicLayouts.Horizontal { true, false })
copyButton := basicElements.NewButton("Copy")
container := containers.NewContainer(layouts.Vertical { true, true })
textInput := elements.NewTextBox("", "")
controlRow := containers.NewContainer(layouts.Horizontal { true, false })
copyButton := elements.NewButton("Copy")
copyButton.SetIcon(theme.IconCopy)
pasteButton := basicElements.NewButton("Paste")
pasteButton := elements.NewButton("Paste")
pasteButton.SetIcon(theme.IconPaste)
pasteImageButton := basicElements.NewButton("Image")
pasteImageButton := elements.NewButton("Image")
pasteImageButton.SetIcon(theme.IconPictures)
imageClipboardCallback := func (clipboard data.Data, err error) {
@ -124,12 +124,12 @@ func run () {
func imageWindow (image image.Image) {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Clipboard Image")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
closeButton := basicElements.NewButton("Ok")
container := containers.NewContainer(layouts.Vertical { true, true })
closeButton := elements.NewButton("Ok")
closeButton.SetIcon(theme.IconYes)
closeButton.OnClick(window.Close)
container.Adopt(basicElements.NewImage(image), true)
container.Adopt(elements.NewImage(image), true)
container.Adopt(closeButton, false)
window.Adopt(container)
window.Show()

View File

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

View File

@ -4,8 +4,8 @@ import "os"
import "image"
import _ "image/png"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -26,34 +26,34 @@ func run () {
scrollContainer := containers.NewScrollContainer(false, true)
document := containers.NewDocumentContainer()
document.Adopt (basicElements.NewLabel (
document.Adopt (elements.NewLabel (
"A document container is a vertically stacked container " +
"capable of properly laying out flexible elements such as " +
"text-wrapped labels. You can also include normal elements " +
"like:", true))
document.Adopt (basicElements.NewButton (
document.Adopt (elements.NewButton (
"Buttons,"))
document.Adopt (basicElements.NewCheckbox (
document.Adopt (elements.NewCheckbox (
"Checkboxes,", true))
document.Adopt(basicElements.NewTextBox("", "And text boxes."))
document.Adopt (basicElements.NewSpacer(true))
document.Adopt (basicElements.NewLabel (
document.Adopt(elements.NewTextBox("", "And text boxes."))
document.Adopt (elements.NewSpacer(true))
document.Adopt (elements.NewLabel (
"Document containers are meant to be placed inside of a " +
"ScrollContainer, like this one.", true))
document.Adopt (basicElements.NewLabel (
document.Adopt (elements.NewLabel (
"You could use document containers to do things like display various " +
"forms of hypertext (like HTML, gemtext, markdown, etc.), " +
"lay out a settings menu with descriptive label text between " +
"control groups like in iOS, or list comment or chat histories.", true))
document.Adopt(basicElements.NewImage(logo))
document.Adopt (basicElements.NewLabel (
document.Adopt(elements.NewImage(logo))
document.Adopt (elements.NewLabel (
"Oh, you're a switch? Then name all of these switches:", true))
for i := 0; i < 3; i ++ {
switchContainer := containers.NewContainer (basicLayouts.Horizontal {
switchContainer := containers.NewContainer (layouts.Horizontal {
Gap: true,
})
for i := 0; i < 10; i ++ {
switchContainer.Adopt(basicElements.NewSwitch("", false), true)
switchContainer.Adopt(elements.NewSwitch("", false), true)
}
document.Adopt(switchContainer)
}

View File

@ -4,9 +4,9 @@ import "os"
import "path/filepath"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/elements/file"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"

View File

@ -2,8 +2,8 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/flow"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -14,21 +14,21 @@ func main () {
func run () {
window, _ := tomo.NewWindow(192, 192)
window.SetTitle("adventure")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
container := containers.NewContainer(layouts.Vertical { true, true })
window.Adopt(container)
var world flow.Flow
world.Transition = container.DisownAll
world.Stages = map [string] func () {
"start": func () {
label := basicElements.NewLabel (
label := elements.NewLabel (
"you are standing next to a river.", true)
button0 := basicElements.NewButton("go in the river")
button0 := elements.NewButton("go in the river")
button0.OnClick(world.SwitchFunc("wet"))
button1 := basicElements.NewButton("walk along the river")
button1 := elements.NewButton("walk along the river")
button1.OnClick(world.SwitchFunc("house"))
button2 := basicElements.NewButton("turn around")
button2 := elements.NewButton("turn around")
button2.OnClick(world.SwitchFunc("bear"))
container.Warp ( func () {
@ -40,13 +40,13 @@ func run () {
})
},
"wet": func () {
label := basicElements.NewLabel (
label := elements.NewLabel (
"you get completely soaked.\n" +
"you die of hypothermia.", true)
button0 := basicElements.NewButton("try again")
button0 := elements.NewButton("try again")
button0.OnClick(world.SwitchFunc("start"))
button1 := basicElements.NewButton("exit")
button1 := elements.NewButton("exit")
button1.OnClick(tomo.Stop)
container.Warp (func () {
@ -57,13 +57,13 @@ func run () {
})
},
"house": func () {
label := basicElements.NewLabel (
label := elements.NewLabel (
"you are standing in front of a delapidated " +
"house.", true)
button1 := basicElements.NewButton("go inside")
button1 := elements.NewButton("go inside")
button1.OnClick(world.SwitchFunc("inside"))
button0 := basicElements.NewButton("turn back")
button0 := elements.NewButton("turn back")
button0.OnClick(world.SwitchFunc("start"))
container.Warp (func () {
@ -74,14 +74,14 @@ func run () {
})
},
"inside": func () {
label := basicElements.NewLabel (
label := elements.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 := basicElements.NewButton("go back outside")
button0 := elements.NewButton("go back outside")
button0.OnClick(world.SwitchFunc("house"))
container.Warp (func () {
@ -91,13 +91,13 @@ func run () {
})
},
"bear": func () {
label := basicElements.NewLabel (
label := elements.NewLabel (
"you come face to face with a bear.\n" +
"it eats you (it was hungry).", true)
button0 := basicElements.NewButton("try again")
button0 := elements.NewButton("try again")
button0.OnClick(world.SwitchFunc("start"))
button1 := basicElements.NewButton("exit")
button1 := elements.NewButton("exit")
button1.OnClick(tomo.Stop)
container.Warp (func () {

View File

@ -3,9 +3,9 @@ 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/elements"
import "git.tebibyte.media/sashakoshka/tomo/elements/fun"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -17,12 +17,12 @@ func main () {
func run () {
window, _ := tomo.NewWindow(200, 216)
window.SetTitle("Clock")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
container := containers.NewContainer(layouts.Vertical { true, true })
window.Adopt(container)
clock := fun.NewAnalogClock(time.Now())
container.Adopt(clock, true)
label := basicElements.NewLabel(formatTime(), false)
label := elements.NewLabel(formatTime(), false)
container.Adopt(label, false)
window.OnClose(tomo.Stop)
@ -34,7 +34,7 @@ func formatTime () (timeString string) {
return time.Now().Format("2006-01-02 15:04:05")
}
func tick (label *basicElements.Label, clock *fun.AnalogClock) {
func tick (label *elements.Label, clock *fun.AnalogClock) {
for {
tomo.Do (func () {
label.SetText(formatTime())

View File

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

View File

@ -2,8 +2,8 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -15,16 +15,16 @@ func run () {
window, _ := tomo.NewWindow(360, 2)
window.SetTitle("Icons")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
container := containers.NewContainer(layouts.Vertical { true, true })
window.Adopt(container)
container.Adopt(basicElements.NewLabel("Just some of the wonderful icons we have:", false), false)
container.Adopt(basicElements.NewSpacer(true), false)
container.Adopt(elements.NewLabel("Just some of the wonderful icons we have:", false), false)
container.Adopt(elements.NewSpacer(true), false)
container.Adopt(icons(theme.IconHome, theme.IconRepositories), true)
container.Adopt(icons(theme.IconFile, theme.IconCD), true)
container.Adopt(icons(theme.IconOpen, theme.IconRemoveBookmark), true)
closeButton := basicElements.NewButton("Ok")
closeButton := elements.NewButton("Ok")
closeButton.SetIcon(theme.IconYes)
closeButton.ShowText(false)
closeButton.OnClick(tomo.Stop)
@ -35,9 +35,9 @@ func run () {
}
func icons (min, max theme.Icon) (container *containers.Container) {
container = containers.NewContainer(basicLayouts.Horizontal { true, false })
container = containers.NewContainer(layouts.Horizontal { true, false })
for index := min; index <= max; index ++ {
container.Adopt(basicElements.NewIcon(index, theme.IconSizeSmall), true)
container.Adopt(elements.NewIcon(index, theme.IconSizeSmall), true)
}
return
}

View File

@ -7,8 +7,8 @@ import _ "image/png"
import "github.com/jezek/xgbutil/gopher"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -21,20 +21,20 @@ func run () {
window.SetTitle("Tomo Logo")
file, err := os.Open("assets/banner.png")
if err != nil { fatalError(err); return }
if err != nil { fatalError(window, err); return }
logo, _, err := image.Decode(file)
file.Close()
if err != nil { fatalError(err); return }
if err != nil { fatalError(window, err); return }
container := containers.NewContainer(basicLayouts.Vertical { true, true })
logoImage := basicElements.NewImage(logo)
button := basicElements.NewButton("Show me a gopher instead")
container := containers.NewContainer(layouts.Vertical { true, true })
logoImage := elements.NewImage(logo)
button := elements.NewButton("Show me a gopher instead")
button.OnClick (func () { container.Warp (func () {
container.DisownAll()
gopher, _, err :=
image.Decode(bytes.NewReader(gopher.GopherPng()))
if err != nil { fatalError(err); return }
container.Adopt(basicElements.NewImage(gopher),true)
if err != nil { fatalError(window, err); return }
container.Adopt(elements.NewImage(gopher),true)
}) })
container.Adopt(logoImage, true)
@ -47,9 +47,10 @@ func run () {
window.Show()
}
func fatalError (err error) {
func fatalError (window tomo.Window, err error) {
popups.NewDialog (
popups.DialogKindError,
window,
"Error",
err.Error(),
popups.Button {
@ -57,3 +58,4 @@ func fatalError (err error) {
OnPress: tomo.Stop,
})
}

View File

@ -2,8 +2,8 @@ package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -14,20 +14,21 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Enter Details")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
container := containers.NewContainer(layouts.Vertical { true, true })
window.Adopt(container)
// create inputs
firstName := basicElements.NewTextBox("First name", "")
lastName := basicElements.NewTextBox("Last name", "")
fingerLength := basicElements.NewTextBox("Length of fingers", "")
button := basicElements.NewButton("Ok")
firstName := elements.NewTextBox("First name", "")
lastName := elements.NewTextBox("Last name", "")
fingerLength := elements.NewTextBox("Length of fingers", "")
button := elements.NewButton("Ok")
button.SetEnabled(false)
button.OnClick (func () {
// create a dialog displaying the results
popups.NewDialog (
popups.DialogKindInfo,
window,
"Profile",
firstName.Value() + " " + lastName.Value() +
"'s fingers\nmeasure in at " + fingerLength.Value() +
@ -46,11 +47,11 @@ func run () {
fingerLength.OnChange(check)
// add elements to container
container.Adopt(basicElements.NewLabel("Choose your words carefully.", false), true)
container.Adopt(elements.NewLabel("Choose your words carefully.", false), true)
container.Adopt(firstName, false)
container.Adopt(lastName, false)
container.Adopt(fingerLength, false)
container.Adopt(basicElements.NewSpacer(true), false)
container.Adopt(elements.NewSpacer(true), false)
container.Adopt(button, false)
window.OnClose(tomo.Stop)

View File

@ -1,7 +1,7 @@
package main
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
func main () {
@ -11,7 +11,7 @@ func main () {
func run () {
window, _ := tomo.NewWindow(480, 360)
window.SetTitle("example label")
window.Adopt(basicElements.NewLabel(text, true))
window.Adopt(elements.NewLabel(text, true))
window.OnClose(tomo.Stop)
window.Show()
}

View File

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

View File

@ -2,9 +2,8 @@ package main
import "fmt"
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"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -16,8 +15,8 @@ func run () {
window, _ := tomo.NewWindow(256, 256)
window.SetTitle("Main")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
container.Adopt(basicElements.NewLabel("Main window", false), true)
container := containers.NewContainer(layouts.Vertical { true, true })
container.Adopt(elements.NewLabel("Main window", false), true)
window.Adopt(container)
window.OnClose(tomo.Stop)
@ -29,12 +28,12 @@ func run () {
createPanel(window, 3)
}
func createPanel (parent elements.MainWindow, id int) {
func createPanel (parent tomo.MainWindow, id int) {
window, _ := parent.NewPanel(2, 2)
title := fmt.Sprint("Panel #", id)
window.SetTitle(title)
container := containers.NewContainer(basicLayouts.Vertical { true, true })
container.Adopt(basicElements.NewLabel(title, false), true)
container := containers.NewContainer(layouts.Vertical { true, true })
container.Adopt(elements.NewLabel(title, false), true)
window.Adopt(container)
window.Show()
}

View File

@ -6,9 +6,9 @@ import "errors"
import "github.com/faiface/beep"
import "github.com/faiface/beep/speaker"
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/elements/fun"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/fun/music"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
@ -34,27 +34,27 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Piano")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
controlBar := containers.NewContainer(basicLayouts.Horizontal { true, false })
container := containers.NewContainer(layouts.Vertical { true, true })
controlBar := containers.NewContainer(layouts.Horizontal { true, false })
waveformColumn := containers.NewContainer(basicLayouts.Vertical { true, false })
waveformList := basicElements.NewList (
basicElements.NewListEntry("Sine", func(){ waveform = 0 }),
basicElements.NewListEntry("Triangle", func(){ waveform = 3 }),
basicElements.NewListEntry("Square", func(){ waveform = 1 }),
basicElements.NewListEntry("Saw", func(){ waveform = 2 }),
basicElements.NewListEntry("Supersaw", func(){ waveform = 4 }),
waveformColumn := containers.NewContainer(layouts.Vertical { true, false })
waveformList := elements.NewList (
elements.NewListEntry("Sine", func(){ waveform = 0 }),
elements.NewListEntry("Triangle", func(){ waveform = 3 }),
elements.NewListEntry("Square", func(){ waveform = 1 }),
elements.NewListEntry("Saw", func(){ waveform = 2 }),
elements.NewListEntry("Supersaw", func(){ waveform = 4 }),
)
waveformList.OnNoEntrySelected (func(){waveformList.Select(0)})
waveformList.Select(0)
adsrColumn := containers.NewContainer(basicLayouts.Vertical { true, false })
adsrGroup := containers.NewContainer(basicLayouts.Horizontal { true, false })
attackSlider := basicElements.NewLerpSlider(0, 3 * time.Second, adsr.Attack, true)
decaySlider := basicElements.NewLerpSlider(0, 3 * time.Second, adsr.Decay, true)
sustainSlider := basicElements.NewSlider(adsr.Sustain, true)
releaseSlider := basicElements.NewLerpSlider(0, 3 * time.Second, adsr.Release, true)
gainSlider := basicElements.NewSlider(math.Sqrt(gain), false)
adsrColumn := containers.NewContainer(layouts.Vertical { true, false })
adsrGroup := containers.NewContainer(layouts.Horizontal { true, false })
attackSlider := elements.NewLerpSlider(0, 3 * time.Second, adsr.Attack, true)
decaySlider := elements.NewLerpSlider(0, 3 * time.Second, adsr.Decay, true)
sustainSlider := elements.NewSlider(adsr.Sustain, true)
releaseSlider := elements.NewLerpSlider(0, 3 * time.Second, adsr.Release, true)
gainSlider := elements.NewSlider(math.Sqrt(gain), false)
attackSlider.OnRelease (func () {
adsr.Attack = attackSlider.Value()
@ -72,7 +72,7 @@ func run () {
gain = math.Pow(gainSlider.Value(), 2)
})
patchColumn := containers.NewContainer(basicLayouts.Vertical { true, false })
patchColumn := containers.NewContainer(layouts.Vertical { true, false })
patch := func (w int, a, d time.Duration, s float64, r time.Duration) func () {
return func () {
waveform = w
@ -89,22 +89,22 @@ func run () {
releaseSlider.SetValue(adsr.Release)
}
}
patchList := basicElements.NewList (
basicElements.NewListEntry ("Bones", patch (
patchList := elements.NewList (
elements.NewListEntry ("Bones", patch (
0, 0, 100, 0.0, 0)),
basicElements.NewListEntry ("Staccato", patch (
elements.NewListEntry ("Staccato", patch (
4, 70, 500, 0, 0)),
basicElements.NewListEntry ("Sustain", patch (
elements.NewListEntry ("Sustain", patch (
4, 70, 200, 0.8, 500)),
basicElements.NewListEntry ("Upright", patch (
elements.NewListEntry ("Upright", patch (
1, 0, 500, 0.4, 70)),
basicElements.NewListEntry ("Space Pad", patch (
elements.NewListEntry ("Space Pad", patch (
4, 1500, 0, 1.0, 3000)),
basicElements.NewListEntry ("Popcorn", patch (
elements.NewListEntry ("Popcorn", patch (
2, 0, 40, 0.0, 0)),
basicElements.NewListEntry ("Racer", patch (
elements.NewListEntry ("Racer", patch (
3, 70, 0, 0.7, 400)),
basicElements.NewListEntry ("Reverse", patch (
elements.NewListEntry ("Reverse", patch (
2, 3000, 60, 0, 0)),
)
patchList.Collapse(0, 32)
@ -121,19 +121,19 @@ func run () {
window.Adopt(container)
controlBar.Adopt(patchColumn, true)
patchColumn.Adopt(basicElements.NewLabel("Presets", false), false)
patchColumn.Adopt(elements.NewLabel("Presets", false), false)
patchColumn.Adopt(patchScrollBox, true)
patchScrollBox.Adopt(patchList)
controlBar.Adopt(basicElements.NewSpacer(true), false)
controlBar.Adopt(elements.NewSpacer(true), false)
controlBar.Adopt(waveformColumn, false)
waveformColumn.Adopt(basicElements.NewLabel("Waveform", false), false)
waveformColumn.Adopt(elements.NewLabel("Waveform", false), false)
waveformColumn.Adopt(waveformList, true)
controlBar.Adopt(basicElements.NewSpacer(true), false)
controlBar.Adopt(elements.NewSpacer(true), false)
adsrColumn.Adopt(basicElements.NewLabel("ADSR", false), false)
adsrColumn.Adopt(elements.NewLabel("ADSR", false), false)
adsrGroup.Adopt(attackSlider, false)
adsrGroup.Adopt(decaySlider, false)
adsrGroup.Adopt(sustainSlider, false)

View File

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

View File

@ -3,8 +3,8 @@ package main
import "time"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
@ -15,23 +15,23 @@ func main () {
func run () {
window, _ := tomo.NewWindow(2, 2)
window.SetTitle("Approaching")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
container := containers.NewContainer(layouts.Vertical { true, true })
window.Adopt(container)
container.Adopt (basicElements.NewLabel (
container.Adopt (elements.NewLabel (
"Rapidly approaching your location...", false), false)
bar := basicElements.NewProgressBar(0)
bar := elements.NewProgressBar(0)
container.Adopt(bar, false)
button := basicElements.NewButton("Stop")
button := elements.NewButton("Stop")
button.SetEnabled(false)
container.Adopt(button, false)
window.OnClose(tomo.Stop)
window.Show()
go fill(bar)
go fill(window, bar)
}
func fill (bar *basicElements.ProgressBar) {
func fill (window tomo.Window, bar *elements.ProgressBar) {
for progress := 0.0; progress < 1.0; progress += 0.01 {
time.Sleep(time.Second / 24)
tomo.Do (func () {
@ -41,6 +41,7 @@ func fill (bar *basicElements.ProgressBar) {
tomo.Do (func () {
popups.NewDialog (
popups.DialogKindInfo,
window,
"I am here",
"Don't look outside your window.")
})

View File

@ -5,8 +5,8 @@ import _ "embed"
import _ "image/png"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/popups"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -21,7 +21,7 @@ func run () {
window, _ := tomo.NewWindow(640, 480)
window.SetTitle("Raycaster")
container := containers.NewContainer(basicLayouts.Vertical { false, false })
container := containers.NewContainer(layouts.Vertical { false, false })
window.Adopt(container)
wallTexture, _ := TextureFrom(bytes.NewReader(wallTextureBytes))
@ -48,13 +48,13 @@ func run () {
wallTexture,
})
topBar := containers.NewContainer(basicLayouts.Horizontal { true, true })
staminaBar := basicElements.NewProgressBar(game.Stamina())
healthBar := basicElements.NewProgressBar(game.Health())
topBar := containers.NewContainer(layouts.Horizontal { true, true })
staminaBar := elements.NewProgressBar(game.Stamina())
healthBar := elements.NewProgressBar(game.Health())
topBar.Adopt(basicElements.NewLabel("Stamina:", false), false)
topBar.Adopt(elements.NewLabel("Stamina:", false), false)
topBar.Adopt(staminaBar, true)
topBar.Adopt(basicElements.NewLabel("Health:", false), false)
topBar.Adopt(elements.NewLabel("Health:", false), false)
topBar.Adopt(healthBar, true)
container.Adopt(topBar, false)
container.Adopt(game, true)
@ -69,6 +69,7 @@ func run () {
popups.NewDialog (
popups.DialogKindInfo,
window,
"Welcome to the backrooms",
"You've no-clipped into the backrooms!\n" +
"Move with WASD, and look with the arrow keys.\n" +

View File

@ -2,8 +2,8 @@ package main
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/elements"
import _ "git.tebibyte.media/sashakoshka/tomo/backends/all"
import "git.tebibyte.media/sashakoshka/tomo/elements/containers"
@ -14,39 +14,39 @@ func main () {
func run () {
window, _ := tomo.NewWindow(360, 240)
window.SetTitle("Scroll")
container := containers.NewContainer(basicLayouts.Vertical { true, true })
container := containers.NewContainer(layouts.Vertical { true, true })
window.Adopt(container)
textBox := basicElements.NewTextBox("", copypasta)
textBox := elements.NewTextBox("", copypasta)
scrollContainer := containers.NewScrollContainer(true, false)
disconnectedContainer := containers.NewContainer (basicLayouts.Horizontal {
disconnectedContainer := containers.NewContainer (layouts.Horizontal {
Gap: true,
})
list := basicElements.NewList (
basicElements.NewListEntry("This is list item 0", nil),
basicElements.NewListEntry("This is list item 1", nil),
basicElements.NewListEntry("This is list item 2", nil),
basicElements.NewListEntry("This is list item 3", nil),
basicElements.NewListEntry("This is list item 4", nil),
basicElements.NewListEntry("This is list item 5", nil),
basicElements.NewListEntry("This is list item 6", nil),
basicElements.NewListEntry("This is list item 7", nil),
basicElements.NewListEntry("This is list item 8", nil),
basicElements.NewListEntry("This is list item 9", nil),
basicElements.NewListEntry("This is list item 10", nil),
basicElements.NewListEntry("This is list item 11", nil),
basicElements.NewListEntry("This is list item 12", nil),
basicElements.NewListEntry("This is list item 13", nil),
basicElements.NewListEntry("This is list item 14", nil),
basicElements.NewListEntry("This is list item 15", nil),
basicElements.NewListEntry("This is list item 16", nil),
basicElements.NewListEntry("This is list item 17", nil),
basicElements.NewListEntry("This is list item 18", nil),
basicElements.NewListEntry("This is list item 19", nil),
basicElements.NewListEntry("This is list item 20", nil))
list := elements.NewList (
elements.NewListEntry("This is list item 0", nil),
elements.NewListEntry("This is list item 1", nil),
elements.NewListEntry("This is list item 2", nil),
elements.NewListEntry("This is list item 3", nil),
elements.NewListEntry("This is list item 4", nil),
elements.NewListEntry("This is list item 5", nil),
elements.NewListEntry("This is list item 6", nil),
elements.NewListEntry("This is list item 7", nil),
elements.NewListEntry("This is list item 8", nil),
elements.NewListEntry("This is list item 9", nil),
elements.NewListEntry("This is list item 10", nil),
elements.NewListEntry("This is list item 11", nil),
elements.NewListEntry("This is list item 12", nil),
elements.NewListEntry("This is list item 13", nil),
elements.NewListEntry("This is list item 14", nil),
elements.NewListEntry("This is list item 15", nil),
elements.NewListEntry("This is list item 16", nil),
elements.NewListEntry("This is list item 17", nil),
elements.NewListEntry("This is list item 18", nil),
elements.NewListEntry("This is list item 19", nil),
elements.NewListEntry("This is list item 20", nil))
list.Collapse(0, 32)
scrollBar := basicElements.NewScrollBar(true)
scrollBar := elements.NewScrollBar(true)
list.OnScrollBoundsChange (func () {
scrollBar.SetBounds (
list.ScrollContentBounds(),
@ -57,10 +57,10 @@ func run () {
})
scrollContainer.Adopt(textBox)
container.Adopt(basicElements.NewLabel("A ScrollContainer:", false), false)
container.Adopt(elements.NewLabel("A ScrollContainer:", false), false)
container.Adopt(scrollContainer, false)
disconnectedContainer.Adopt(list, false)
disconnectedContainer.Adopt (basicElements.NewLabel (
disconnectedContainer.Adopt (elements.NewLabel (
"Notice how the scroll bar to the right can be used to " +
"control the list, despite not even touching it. It is " +
"indeed a thing you can do. It is also terrible UI design so " +

View File

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

View File

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

View File

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

View File

@ -1,18 +1,12 @@
// Package layouts defines a layout interface which a container element can
// accept to have its child elements automatically arranged by any layout that
// satisfies it.
//
// Sub-packages of layouts contain several pre-made ones.
package layouts
package tomo
import "image"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/elements"
// LayoutEntry associates an element with layout and positioning information so
// it can be arranged by a Layout.
type LayoutEntry struct {
elements.Element
Element
Bounds image.Rectangle
Expand bool
}

View File

@ -1,8 +1,8 @@
package basicLayouts
package layouts
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
// Dialog arranges elements in the form of a dialog box. The first element is
// positioned above as the main focus of the dialog, and is set to expand
@ -20,7 +20,7 @@ type Dialog struct {
// Arrange arranges a list of entries into a dialog.
func (layout Dialog) Arrange (
entries []layouts.LayoutEntry,
entries []tomo.LayoutEntry,
margin image.Point,
padding artist.Inset,
bounds image.Rectangle,
@ -101,7 +101,7 @@ func (layout Dialog) Arrange (
// MinimumSize returns the minimum width and height that will be needed to
// arrange the given list of entries.
func (layout Dialog) MinimumSize (
entries []layouts.LayoutEntry,
entries []tomo.LayoutEntry,
margin image.Point,
padding artist.Inset,
) (
@ -132,7 +132,7 @@ func (layout Dialog) MinimumSize (
}
func (layout Dialog) minimumSizeOfControlRow (
entries []layouts.LayoutEntry,
entries []tomo.LayoutEntry,
margin image.Point,
padding artist.Inset,
) (

View File

@ -1,9 +1,9 @@
package basicLayouts
package layouts
import "image"
import "golang.org/x/image/math/fixed"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/fixedutil"
// Horizontal arranges elements horizontally. Elements at the start of the entry
@ -20,7 +20,7 @@ type Horizontal struct {
// Arrange arranges a list of entries horizontally.
func (layout Horizontal) Arrange (
entries []layouts.LayoutEntry,
entries []tomo.LayoutEntry,
margin image.Point,
padding artist.Inset,
bounds image.Rectangle,
@ -55,7 +55,7 @@ func (layout Horizontal) Arrange (
// MinimumSize returns the minimum width and height that will be needed to
// arrange the given list of entries.
func (layout Horizontal) MinimumSize (
entries []layouts.LayoutEntry,
entries []tomo.LayoutEntry,
margin image.Point,
padding artist.Inset,
) (
@ -80,7 +80,7 @@ func (layout Horizontal) MinimumSize (
}
func (layout Horizontal) expandingElementWidth (
entries []layouts.LayoutEntry,
entries []tomo.LayoutEntry,
margin image.Point,
padding artist.Inset,
freeSpace int,

View File

@ -1,9 +1,9 @@
package basicLayouts
package layouts
import "image"
import "golang.org/x/image/math/fixed"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/artist"
import "git.tebibyte.media/sashakoshka/tomo/layouts"
import "git.tebibyte.media/sashakoshka/tomo/fixedutil"
// Vertical arranges elements vertically. Elements at the start of the entry
@ -20,7 +20,7 @@ type Vertical struct {
// Arrange arranges a list of entries vertically.
func (layout Vertical) Arrange (
entries []layouts.LayoutEntry,
entries []tomo.LayoutEntry,
margin image.Point,
padding artist.Inset,
bounds image.Rectangle,
@ -55,7 +55,7 @@ func (layout Vertical) Arrange (
// MinimumSize returns the minimum width and height that will be needed to
// arrange the given list of entries.
func (layout Vertical) MinimumSize (
entries []layouts.LayoutEntry,
entries []tomo.LayoutEntry,
margin image.Point,
padding artist.Inset,
) (
@ -80,7 +80,7 @@ func (layout Vertical) MinimumSize (
}
func (layout Vertical) expandingElementHeight (
entries []layouts.LayoutEntry,
entries []tomo.LayoutEntry,
margin image.Point,
padding artist.Inset,
freeSpace int,

View File

@ -1,4 +1,4 @@
package elements
package tomo
// Parent represents a type capable of containing child elements.
type Parent interface {

View File

@ -2,9 +2,8 @@ package popups
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/theme"
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/containers"
// DialogKind defines the semantic role of a dialog window.
@ -31,11 +30,11 @@ type Button struct {
// the dialog will just be a normal window
func NewDialog (
kind DialogKind,
parent elements.Window,
parent tomo.Window,
title, message string,
buttons ...Button,
) (
window elements.Window,
window tomo.Window,
) {
if parent == nil {
window, _ = tomo.NewWindow(2, 2)
@ -44,10 +43,10 @@ func NewDialog (
}
window.SetTitle(title)
container := containers.NewContainer(basicLayouts.Dialog { true, true })
container := containers.NewContainer(layouts.Dialog { true, true })
window.Adopt(container)
messageContainer := containers.NewContainer(basicLayouts.Horizontal { true, false })
messageContainer := containers.NewContainer(layouts.Horizontal { true, false })
iconId := theme.IconInformation
switch kind {
case DialogKindInfo: iconId = theme.IconInformation
@ -56,20 +55,20 @@ func NewDialog (
case DialogKindError: iconId = theme.IconError
}
messageContainer.Adopt(basicElements.NewIcon(iconId, theme.IconSizeLarge), false)
messageContainer.Adopt(basicElements.NewLabel(message, false), true)
messageContainer.Adopt(elements.NewIcon(iconId, theme.IconSizeLarge), false)
messageContainer.Adopt(elements.NewLabel(message, false), true)
container.Adopt(messageContainer, true)
if len(buttons) == 0 {
button := basicElements.NewButton("OK")
button := elements.NewButton("OK")
button.SetIcon(theme.IconYes)
button.OnClick(window.Close)
container.Adopt(button, false)
button.Focus()
} else {
var button *basicElements.Button
var button *elements.Button
for _, buttonDescriptor := range buttons {
button = basicElements.NewButton(buttonDescriptor.Name)
button = elements.NewButton(buttonDescriptor.Name)
button.SetEnabled(buttonDescriptor.OnPress != nil)
button.OnClick (func () {
buttonDescriptor.OnPress()

View File

@ -210,7 +210,7 @@ func (Default) Pattern (id Pattern, state State, c Case) artist.Pattern {
case PatternBackground: return patterns.Uhex(0xaaaaaaFF)
case PatternDead: return defaultTextures[0][offset]
case PatternRaised:
if c.Match("basic", "listEntry", "") {
if c.Match("tomo", "listEntry", "") {
return defaultTextures[10][offset]
} else {
return defaultTextures[1][offset]
@ -219,11 +219,11 @@ func (Default) Pattern (id Pattern, state State, c Case) artist.Pattern {
case PatternPinboard: return defaultTextures[3][offset]
case PatternButton:
switch {
case c.Match("basic", "checkbox", ""):
case c.Match("tomo", "checkbox", ""):
return defaultTextures[9][offset]
case c.Match("fun", "piano", "flatKey"):
case c.Match("tomo", "piano", "flatKey"):
return defaultTextures[11][offset]
case c.Match("fun", "piano", "sharpKey"):
case c.Match("tomo", "piano", "sharpKey"):
return defaultTextures[12][offset]
default:
return defaultTextures[4][offset]
@ -253,13 +253,13 @@ func (Default) Color (id Color, state State, c Case) color.RGBA {
func (Default) Padding (id Pattern, c Case) artist.Inset {
switch id {
case PatternRaised:
if c.Match("basic", "listEntry", "") {
if c.Match("tomo", "listEntry", "") {
return artist.I(4, 8)
} else {
return artist.I(8)
}
case PatternSunken:
if c.Match("basic", "list", "") {
if c.Match("tomo", "list", "") {
return artist.I(4, 0, 3)
} else if c.Match("basic", "progressBar", "") {
return artist.I(2, 1, 1, 2)
@ -267,7 +267,7 @@ func (Default) Padding (id Pattern, c Case) artist.Inset {
return artist.I(8)
}
case PatternPinboard:
if c.Match("fun", "piano", "") {
if c.Match("tomo", "piano", "") {
return artist.I(2)
} else {
return artist.I(8)

64
tomo.go
View File

@ -1,12 +1,7 @@
package tomo
import "os"
import "io"
import "path/filepath"
import "git.tebibyte.media/sashakoshka/tomo/dirs"
import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/config"
import "git.tebibyte.media/sashakoshka/tomo/elements"
var backend Backend
@ -16,9 +11,6 @@ var backend Backend
func Run (callback func ()) (err error) {
backend, err = instantiateBackend()
if err != nil { return }
config := parseConfig()
backend.SetConfig(config)
backend.SetTheme(parseTheme(config.ThemePath()))
if callback != nil { callback() }
err = backend.Run()
backend = nil
@ -41,7 +33,7 @@ func Do (callback func ()) {
// NewWindow creates a new window using the current backend, and returns it as a
// MainWindow. If the window could not be created, an error is returned
// explaining why.
func NewWindow (width, height int) (window elements.MainWindow, err error) {
func NewWindow (width, height int) (window MainWindow, err error) {
assertBackend()
return backend.NewWindow(width, height)
}
@ -56,60 +48,6 @@ func SetConfig (config config.Config) {
backend.SetConfig(config)
}
func parseConfig () (config.Config) {
return parseMany [config.Config] (
dirs.ConfigDirs("tomo/tomo.conf"),
config.Parse,
config.Default { })
}
func parseTheme (path string) (theme.Theme) {
if path == "" { return theme.Default { } }
path = filepath.Join(path, "tomo")
// find all tomo pattern graph files in the directory
directory, err := os.Open(path)
if err != nil { return theme.Default { } }
names, _ := directory.Readdirnames(0)
paths := []string { }
for _, name := range names {
if filepath.Ext(name) == ".tpg" {
paths = append(paths, filepath.Join(path, name))
}
}
// parse them
return parseMany [theme.Theme] (
paths,
theme.Parse,
theme.Default { })
}
func parseMany [OBJECT any] (
paths []string,
parser func (...io.Reader) OBJECT,
fallback OBJECT,
) (
object OBJECT,
) {
// convert all paths into readers
sources := []io.Reader { }
for _, path := range paths {
file, err := os.Open(path)
if err != nil { continue }
sources = append(sources, file)
defer file.Close()
}
if sources == nil {
// if there are no readers, return the fallback object
return fallback
} else {
// if there are readers, parse them
return parser(sources...)
}
}
func assertBackend () {
if backend == nil { panic("no backend is running") }
}

View File

@ -1,4 +1,4 @@
package elements
package tomo
import "image"
import "git.tebibyte.media/sashakoshka/tomo/data"