Merge branch 'main' of git.tebibyte.media:sashakoshka/tomo
This commit is contained in:
commit
14d1836209
@ -3,11 +3,11 @@ package artist
|
|||||||
import "math"
|
import "math"
|
||||||
import "image"
|
import "image"
|
||||||
import "image/color"
|
import "image/color"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
|
|
||||||
// FillEllipse draws a filled ellipse with the specified pattern.
|
// FillEllipse draws a filled ellipse with the specified pattern.
|
||||||
func FillEllipse (
|
func FillEllipse (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
source Pattern,
|
source Pattern,
|
||||||
bounds image.Rectangle,
|
bounds image.Rectangle,
|
||||||
) (
|
) (
|
||||||
@ -36,7 +36,7 @@ func FillEllipse (
|
|||||||
// StrokeEllipse draws the outline of an ellipse with the specified line weight
|
// StrokeEllipse draws the outline of an ellipse with the specified line weight
|
||||||
// and pattern.
|
// and pattern.
|
||||||
func StrokeEllipse (
|
func StrokeEllipse (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
source Pattern,
|
source Pattern,
|
||||||
weight int,
|
weight int,
|
||||||
bounds image.Rectangle,
|
bounds image.Rectangle,
|
||||||
|
@ -2,14 +2,14 @@ package artist
|
|||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "image/color"
|
import "image/color"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
|
|
||||||
// TODO: draw thick lines more efficiently
|
// TODO: draw thick lines more efficiently
|
||||||
|
|
||||||
// Line draws a line from one point to another with the specified weight and
|
// Line draws a line from one point to another with the specified weight and
|
||||||
// pattern.
|
// pattern.
|
||||||
func Line (
|
func Line (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
source Pattern,
|
source Pattern,
|
||||||
weight int,
|
weight int,
|
||||||
min image.Point,
|
min image.Point,
|
||||||
@ -46,7 +46,7 @@ func Line (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func lineLow (
|
func lineLow (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
source Pattern,
|
source Pattern,
|
||||||
weight int,
|
weight int,
|
||||||
min image.Point,
|
min image.Point,
|
||||||
@ -82,7 +82,7 @@ func lineLow (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func lineHigh (
|
func lineHigh (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
source Pattern,
|
source Pattern,
|
||||||
weight int,
|
weight int,
|
||||||
min image.Point,
|
min image.Point,
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package artist
|
package artist
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
|
|
||||||
// Paste transfers one canvas onto another, offset by the specified point.
|
// Paste transfers one canvas onto another, offset by the specified point.
|
||||||
func Paste (
|
func Paste (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
source tomo.Canvas,
|
source canvas.Canvas,
|
||||||
offset image.Point,
|
offset image.Point,
|
||||||
) (
|
) (
|
||||||
updatedRegion image.Rectangle,
|
updatedRegion image.Rectangle,
|
||||||
@ -31,7 +31,7 @@ func Paste (
|
|||||||
|
|
||||||
// FillRectangle draws a filled rectangle with the specified pattern.
|
// FillRectangle draws a filled rectangle with the specified pattern.
|
||||||
func FillRectangle (
|
func FillRectangle (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
source Pattern,
|
source Pattern,
|
||||||
bounds image.Rectangle,
|
bounds image.Rectangle,
|
||||||
) (
|
) (
|
||||||
@ -61,7 +61,7 @@ func FillRectangle (
|
|||||||
// StrokeRectangle draws the outline of a rectangle with the specified line
|
// StrokeRectangle draws the outline of a rectangle with the specified line
|
||||||
// weight and pattern.
|
// weight and pattern.
|
||||||
func StrokeRectangle (
|
func StrokeRectangle (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
source Pattern,
|
source Pattern,
|
||||||
weight int,
|
weight int,
|
||||||
bounds image.Rectangle,
|
bounds image.Rectangle,
|
||||||
|
@ -6,7 +6,7 @@ import "unicode"
|
|||||||
import "image/draw"
|
import "image/draw"
|
||||||
import "golang.org/x/image/font"
|
import "golang.org/x/image/font"
|
||||||
import "golang.org/x/image/math/fixed"
|
import "golang.org/x/image/math/fixed"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
|
|
||||||
type characterLayout struct {
|
type characterLayout struct {
|
||||||
x int
|
x int
|
||||||
@ -95,7 +95,7 @@ func (drawer *TextDrawer) SetAlignment (align Align) {
|
|||||||
|
|
||||||
// Draw draws the drawer's text onto the specified canvas at the given offset.
|
// Draw draws the drawer's text onto the specified canvas at the given offset.
|
||||||
func (drawer *TextDrawer) Draw (
|
func (drawer *TextDrawer) Draw (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
source Pattern,
|
source Pattern,
|
||||||
offset image.Point,
|
offset image.Point,
|
||||||
) (
|
) (
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package tomo
|
package tomo
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/data"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||||
|
|
||||||
// Backend represents a connection to a display server, or something similar.
|
// Backend represents a connection to a display server, or something similar.
|
||||||
// It is capable of managing an event loop, and creating windows.
|
// It is capable of managing an event loop, and creating windows.
|
||||||
@ -19,13 +21,13 @@ type Backend interface {
|
|||||||
// NewWindow creates a new window with the specified width and height,
|
// NewWindow creates a new window with the specified width and height,
|
||||||
// and returns a struct representing it that fulfills the Window
|
// and returns a struct representing it that fulfills the Window
|
||||||
// interface.
|
// interface.
|
||||||
NewWindow (width, height int) (window Window, err error)
|
NewWindow (width, height int) (window elements.Window, err error)
|
||||||
|
|
||||||
// Copy puts data into the clipboard.
|
// Copy puts data into the clipboard.
|
||||||
Copy (Data)
|
Copy (data.Data)
|
||||||
|
|
||||||
// Paste returns the data currently in the clipboard.
|
// Paste returns the data currently in the clipboard.
|
||||||
Paste (accept []Mime) (Data)
|
Paste (accept []data.Mime) (data.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BackendFactory represents a function capable of constructing a backend
|
// BackendFactory represents a function capable of constructing a backend
|
||||||
|
@ -3,64 +3,64 @@ package x
|
|||||||
import "unicode"
|
import "unicode"
|
||||||
import "github.com/jezek/xgb/xproto"
|
import "github.com/jezek/xgb/xproto"
|
||||||
import "github.com/jezek/xgbutil/keybind"
|
import "github.com/jezek/xgbutil/keybind"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
|
|
||||||
// when making changes to this file, look at keysymdef.h and
|
// when making changes to this file, look at keysymdef.h and
|
||||||
// https://tronche.com/gui/x/xlib/input/keyboard-encoding.html
|
// https://tronche.com/gui/x/xlib/input/keyboard-encoding.html
|
||||||
|
|
||||||
var buttonCodeTable = map[xproto.Keysym] tomo.Key {
|
var buttonCodeTable = map[xproto.Keysym] input.Key {
|
||||||
0xFFFFFF: tomo.KeyNone,
|
0xFFFFFF: input.KeyNone,
|
||||||
|
|
||||||
0xFF63: tomo.KeyInsert,
|
0xFF63: input.KeyInsert,
|
||||||
0xFF67: tomo.KeyMenu,
|
0xFF67: input.KeyMenu,
|
||||||
0xFF61: tomo.KeyPrintScreen,
|
0xFF61: input.KeyPrintScreen,
|
||||||
0xFF6B: tomo.KeyPause,
|
0xFF6B: input.KeyPause,
|
||||||
0xFFE5: tomo.KeyCapsLock,
|
0xFFE5: input.KeyCapsLock,
|
||||||
0xFF14: tomo.KeyScrollLock,
|
0xFF14: input.KeyScrollLock,
|
||||||
0xFF7F: tomo.KeyNumLock,
|
0xFF7F: input.KeyNumLock,
|
||||||
0xFF08: tomo.KeyBackspace,
|
0xFF08: input.KeyBackspace,
|
||||||
0xFF09: tomo.KeyTab,
|
0xFF09: input.KeyTab,
|
||||||
0xFE20: tomo.KeyTab,
|
0xFE20: input.KeyTab,
|
||||||
0xFF0D: tomo.KeyEnter,
|
0xFF0D: input.KeyEnter,
|
||||||
0xFF1B: tomo.KeyEscape,
|
0xFF1B: input.KeyEscape,
|
||||||
|
|
||||||
0xFF52: tomo.KeyUp,
|
0xFF52: input.KeyUp,
|
||||||
0xFF54: tomo.KeyDown,
|
0xFF54: input.KeyDown,
|
||||||
0xFF51: tomo.KeyLeft,
|
0xFF51: input.KeyLeft,
|
||||||
0xFF53: tomo.KeyRight,
|
0xFF53: input.KeyRight,
|
||||||
0xFF55: tomo.KeyPageUp,
|
0xFF55: input.KeyPageUp,
|
||||||
0xFF56: tomo.KeyPageDown,
|
0xFF56: input.KeyPageDown,
|
||||||
0xFF50: tomo.KeyHome,
|
0xFF50: input.KeyHome,
|
||||||
0xFF57: tomo.KeyEnd,
|
0xFF57: input.KeyEnd,
|
||||||
|
|
||||||
0xFFE1: tomo.KeyLeftShift,
|
0xFFE1: input.KeyLeftShift,
|
||||||
0xFFE2: tomo.KeyRightShift,
|
0xFFE2: input.KeyRightShift,
|
||||||
0xFFE3: tomo.KeyLeftControl,
|
0xFFE3: input.KeyLeftControl,
|
||||||
0xFFE4: tomo.KeyRightControl,
|
0xFFE4: input.KeyRightControl,
|
||||||
|
|
||||||
0xFFE7: tomo.KeyLeftMeta,
|
0xFFE7: input.KeyLeftMeta,
|
||||||
0xFFE8: tomo.KeyRightMeta,
|
0xFFE8: input.KeyRightMeta,
|
||||||
0xFFE9: tomo.KeyLeftAlt,
|
0xFFE9: input.KeyLeftAlt,
|
||||||
0xFFEA: tomo.KeyRightAlt,
|
0xFFEA: input.KeyRightAlt,
|
||||||
0xFFEB: tomo.KeyLeftSuper,
|
0xFFEB: input.KeyLeftSuper,
|
||||||
0xFFEC: tomo.KeyRightSuper,
|
0xFFEC: input.KeyRightSuper,
|
||||||
0xFFED: tomo.KeyLeftHyper,
|
0xFFED: input.KeyLeftHyper,
|
||||||
0xFFEE: tomo.KeyRightHyper,
|
0xFFEE: input.KeyRightHyper,
|
||||||
|
|
||||||
0xFFFF: tomo.KeyDelete,
|
0xFFFF: input.KeyDelete,
|
||||||
|
|
||||||
0xFFBE: tomo.KeyF1,
|
0xFFBE: input.KeyF1,
|
||||||
0xFFBF: tomo.KeyF2,
|
0xFFBF: input.KeyF2,
|
||||||
0xFFC0: tomo.KeyF3,
|
0xFFC0: input.KeyF3,
|
||||||
0xFFC1: tomo.KeyF4,
|
0xFFC1: input.KeyF4,
|
||||||
0xFFC2: tomo.KeyF5,
|
0xFFC2: input.KeyF5,
|
||||||
0xFFC3: tomo.KeyF6,
|
0xFFC3: input.KeyF6,
|
||||||
0xFFC4: tomo.KeyF7,
|
0xFFC4: input.KeyF7,
|
||||||
0xFFC5: tomo.KeyF8,
|
0xFFC5: input.KeyF8,
|
||||||
0xFFC6: tomo.KeyF9,
|
0xFFC6: input.KeyF9,
|
||||||
0xFFC7: tomo.KeyF10,
|
0xFFC7: input.KeyF10,
|
||||||
0xFFC8: tomo.KeyF11,
|
0xFFC8: input.KeyF11,
|
||||||
0xFFC9: tomo.KeyF12,
|
0xFFC9: input.KeyF12,
|
||||||
|
|
||||||
// TODO: send this whenever a compose key, dead key, etc is pressed,
|
// TODO: send this whenever a compose key, dead key, etc is pressed,
|
||||||
// and then send the resulting character while witholding the key
|
// and then send the resulting character while witholding the key
|
||||||
@ -68,46 +68,46 @@ var buttonCodeTable = map[xproto.Keysym] tomo.Key {
|
|||||||
// concerned, a magical key with the final character was pressed and the
|
// concerned, a magical key with the final character was pressed and the
|
||||||
// KeyDead key is just so that the program might provide some visual
|
// KeyDead key is just so that the program might provide some visual
|
||||||
// feedback to the user while input is being waited for.
|
// feedback to the user while input is being waited for.
|
||||||
0xFF20: tomo.KeyDead,
|
0xFF20: input.KeyDead,
|
||||||
}
|
}
|
||||||
|
|
||||||
var keypadCodeTable = map[xproto.Keysym] tomo.Key {
|
var keypadCodeTable = map[xproto.Keysym] input.Key {
|
||||||
0xff80: tomo.Key(' '),
|
0xff80: input.Key(' '),
|
||||||
0xff89: tomo.KeyTab,
|
0xff89: input.KeyTab,
|
||||||
0xff8d: tomo.KeyEnter,
|
0xff8d: input.KeyEnter,
|
||||||
0xff91: tomo.KeyF1,
|
0xff91: input.KeyF1,
|
||||||
0xff92: tomo.KeyF2,
|
0xff92: input.KeyF2,
|
||||||
0xff93: tomo.KeyF3,
|
0xff93: input.KeyF3,
|
||||||
0xff94: tomo.KeyF4,
|
0xff94: input.KeyF4,
|
||||||
0xff95: tomo.KeyHome,
|
0xff95: input.KeyHome,
|
||||||
0xff96: tomo.KeyLeft,
|
0xff96: input.KeyLeft,
|
||||||
0xff97: tomo.KeyUp,
|
0xff97: input.KeyUp,
|
||||||
0xff98: tomo.KeyRight,
|
0xff98: input.KeyRight,
|
||||||
0xff99: tomo.KeyDown,
|
0xff99: input.KeyDown,
|
||||||
0xff9a: tomo.KeyPageUp,
|
0xff9a: input.KeyPageUp,
|
||||||
0xff9b: tomo.KeyPageDown,
|
0xff9b: input.KeyPageDown,
|
||||||
0xff9c: tomo.KeyEnd,
|
0xff9c: input.KeyEnd,
|
||||||
0xff9d: tomo.KeyHome,
|
0xff9d: input.KeyHome,
|
||||||
0xff9e: tomo.KeyInsert,
|
0xff9e: input.KeyInsert,
|
||||||
0xff9f: tomo.KeyDelete,
|
0xff9f: input.KeyDelete,
|
||||||
0xffbd: tomo.Key('='),
|
0xffbd: input.Key('='),
|
||||||
0xffaa: tomo.Key('*'),
|
0xffaa: input.Key('*'),
|
||||||
0xffab: tomo.Key('+'),
|
0xffab: input.Key('+'),
|
||||||
0xffac: tomo.Key(','),
|
0xffac: input.Key(','),
|
||||||
0xffad: tomo.Key('-'),
|
0xffad: input.Key('-'),
|
||||||
0xffae: tomo.Key('.'),
|
0xffae: input.Key('.'),
|
||||||
0xffaf: tomo.Key('/'),
|
0xffaf: input.Key('/'),
|
||||||
|
|
||||||
0xffb0: tomo.Key('0'),
|
0xffb0: input.Key('0'),
|
||||||
0xffb1: tomo.Key('1'),
|
0xffb1: input.Key('1'),
|
||||||
0xffb2: tomo.Key('2'),
|
0xffb2: input.Key('2'),
|
||||||
0xffb3: tomo.Key('3'),
|
0xffb3: input.Key('3'),
|
||||||
0xffb4: tomo.Key('4'),
|
0xffb4: input.Key('4'),
|
||||||
0xffb5: tomo.Key('5'),
|
0xffb5: input.Key('5'),
|
||||||
0xffb6: tomo.Key('6'),
|
0xffb6: input.Key('6'),
|
||||||
0xffb7: tomo.Key('7'),
|
0xffb7: input.Key('7'),
|
||||||
0xffb8: tomo.Key('8'),
|
0xffb8: input.Key('8'),
|
||||||
0xffb9: tomo.Key('9'),
|
0xffb9: input.Key('9'),
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeKeymapInformation grabs keyboard mapping information from the X
|
// initializeKeymapInformation grabs keyboard mapping information from the X
|
||||||
@ -168,7 +168,7 @@ func (backend *Backend) keycodeToKey (
|
|||||||
keycode xproto.Keycode,
|
keycode xproto.Keycode,
|
||||||
state uint16,
|
state uint16,
|
||||||
) (
|
) (
|
||||||
button tomo.Key,
|
button input.Key,
|
||||||
numberPad bool,
|
numberPad bool,
|
||||||
) {
|
) {
|
||||||
// PARAGRAPH 3
|
// PARAGRAPH 3
|
||||||
@ -359,7 +359,7 @@ func (backend *Backend) keycodeToKey (
|
|||||||
if numberPad { return }
|
if numberPad { return }
|
||||||
|
|
||||||
// otherwise, use the rune
|
// otherwise, use the rune
|
||||||
button = tomo.Key(selectedRune)
|
button = input.Key(selectedRune)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package x
|
package x
|
||||||
|
|
||||||
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/xgbutil"
|
||||||
import "github.com/jezek/xgb/xproto"
|
import "github.com/jezek/xgb/xproto"
|
||||||
@ -98,9 +99,9 @@ func (window *Window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (fo
|
|||||||
func (window *Window) modifiersFromState (
|
func (window *Window) modifiersFromState (
|
||||||
state uint16,
|
state uint16,
|
||||||
) (
|
) (
|
||||||
modifiers tomo.Modifiers,
|
modifiers input.Modifiers,
|
||||||
) {
|
) {
|
||||||
return tomo.Modifiers {
|
return input.Modifiers {
|
||||||
Shift:
|
Shift:
|
||||||
(state & xproto.ModMaskShift) > 0 ||
|
(state & xproto.ModMaskShift) > 0 ||
|
||||||
(state & window.backend.modifierMasks.shiftLock) > 0,
|
(state & window.backend.modifierMasks.shiftLock) > 0,
|
||||||
@ -123,18 +124,18 @@ func (window *Window) handleKeyPress (
|
|||||||
modifiers := window.modifiersFromState(keyEvent.State)
|
modifiers := window.modifiersFromState(keyEvent.State)
|
||||||
modifiers.NumberPad = numberPad
|
modifiers.NumberPad = numberPad
|
||||||
|
|
||||||
if key == tomo.KeyTab && modifiers.Alt {
|
if key == input.KeyTab && modifiers.Alt {
|
||||||
if child, ok := window.child.(tomo.Focusable); ok {
|
if child, ok := window.child.(elements.Focusable); ok {
|
||||||
direction := tomo.KeynavDirectionForward
|
direction := input.KeynavDirectionForward
|
||||||
if modifiers.Shift {
|
if modifiers.Shift {
|
||||||
direction = tomo.KeynavDirectionBackward
|
direction = input.KeynavDirectionBackward
|
||||||
}
|
}
|
||||||
|
|
||||||
if !child.HandleFocus(direction) {
|
if !child.HandleFocus(direction) {
|
||||||
child.HandleUnfocus()
|
child.HandleUnfocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if child, ok := window.child.(tomo.KeyboardTarget); ok {
|
} else if child, ok := window.child.(elements.KeyboardTarget); ok {
|
||||||
child.HandleKeyDown(key, modifiers)
|
child.HandleKeyDown(key, modifiers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,7 +169,7 @@ func (window *Window) handleKeyRelease (
|
|||||||
modifiers := window.modifiersFromState(keyEvent.State)
|
modifiers := window.modifiersFromState(keyEvent.State)
|
||||||
modifiers.NumberPad = numberPad
|
modifiers.NumberPad = numberPad
|
||||||
|
|
||||||
if child, ok := window.child.(tomo.KeyboardTarget); ok {
|
if child, ok := window.child.(elements.KeyboardTarget); ok {
|
||||||
child.HandleKeyUp(key, modifiers)
|
child.HandleKeyUp(key, modifiers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,7 +180,7 @@ func (window *Window) handleButtonPress (
|
|||||||
) {
|
) {
|
||||||
if window.child == nil { return }
|
if window.child == nil { return }
|
||||||
|
|
||||||
if child, ok := window.child.(tomo.MouseTarget); ok {
|
if child, ok := window.child.(elements.MouseTarget); ok {
|
||||||
buttonEvent := *event.ButtonPressEvent
|
buttonEvent := *event.ButtonPressEvent
|
||||||
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 {
|
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 {
|
||||||
sum := scrollSum { }
|
sum := scrollSum { }
|
||||||
@ -193,7 +194,7 @@ func (window *Window) handleButtonPress (
|
|||||||
child.HandleMouseDown (
|
child.HandleMouseDown (
|
||||||
int(buttonEvent.EventX),
|
int(buttonEvent.EventX),
|
||||||
int(buttonEvent.EventY),
|
int(buttonEvent.EventY),
|
||||||
tomo.Button(buttonEvent.Detail))
|
input.Button(buttonEvent.Detail))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,13 +206,13 @@ func (window *Window) handleButtonRelease (
|
|||||||
) {
|
) {
|
||||||
if window.child == nil { return }
|
if window.child == nil { return }
|
||||||
|
|
||||||
if child, ok := window.child.(tomo.MouseTarget); ok {
|
if child, ok := window.child.(elements.MouseTarget); ok {
|
||||||
buttonEvent := *event.ButtonReleaseEvent
|
buttonEvent := *event.ButtonReleaseEvent
|
||||||
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return }
|
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return }
|
||||||
child.HandleMouseUp (
|
child.HandleMouseUp (
|
||||||
int(buttonEvent.EventX),
|
int(buttonEvent.EventX),
|
||||||
int(buttonEvent.EventY),
|
int(buttonEvent.EventY),
|
||||||
tomo.Button(buttonEvent.Detail))
|
input.Button(buttonEvent.Detail))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +222,7 @@ func (window *Window) handleMotionNotify (
|
|||||||
) {
|
) {
|
||||||
if window.child == nil { return }
|
if window.child == nil { return }
|
||||||
|
|
||||||
if child, ok := window.child.(tomo.MouseTarget); ok {
|
if child, ok := window.child.(elements.MouseTarget); ok {
|
||||||
motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
|
motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
|
||||||
child.HandleMouseMove (
|
child.HandleMouseMove (
|
||||||
int(motionEvent.EventX),
|
int(motionEvent.EventX),
|
||||||
|
@ -7,14 +7,16 @@ import "github.com/jezek/xgbutil/icccm"
|
|||||||
import "github.com/jezek/xgbutil/xevent"
|
import "github.com/jezek/xgbutil/xevent"
|
||||||
import "github.com/jezek/xgbutil/xwindow"
|
import "github.com/jezek/xgbutil/xwindow"
|
||||||
import "github.com/jezek/xgbutil/xgraphics"
|
import "github.com/jezek/xgbutil/xgraphics"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||||
|
|
||||||
type Window struct {
|
type Window struct {
|
||||||
backend *Backend
|
backend *Backend
|
||||||
xWindow *xwindow.Window
|
xWindow *xwindow.Window
|
||||||
xCanvas *xgraphics.Image
|
xCanvas *xgraphics.Image
|
||||||
canvas tomo.BasicCanvas
|
canvas canvas.BasicCanvas
|
||||||
child tomo.Element
|
child elements.Element
|
||||||
onClose func ()
|
onClose func ()
|
||||||
skipChildDrawCallback bool
|
skipChildDrawCallback bool
|
||||||
|
|
||||||
@ -27,7 +29,7 @@ type Window struct {
|
|||||||
func (backend *Backend) NewWindow (
|
func (backend *Backend) NewWindow (
|
||||||
width, height int,
|
width, height int,
|
||||||
) (
|
) (
|
||||||
output tomo.Window,
|
output elements.Window,
|
||||||
err error,
|
err error,
|
||||||
) {
|
) {
|
||||||
if backend == nil { panic("nil backend") }
|
if backend == nil { panic("nil backend") }
|
||||||
@ -79,16 +81,16 @@ func (backend *Backend) NewWindow (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *Window) Adopt (child tomo.Element) {
|
func (window *Window) Adopt (child elements.Element) {
|
||||||
// disown previous child
|
// disown previous child
|
||||||
if window.child != nil {
|
if window.child != nil {
|
||||||
window.child.OnDamage(nil)
|
window.child.OnDamage(nil)
|
||||||
window.child.OnMinimumSizeChange(nil)
|
window.child.OnMinimumSizeChange(nil)
|
||||||
}
|
}
|
||||||
if previousChild, ok := window.child.(tomo.Flexible); ok {
|
if previousChild, ok := window.child.(elements.Flexible); ok {
|
||||||
previousChild.OnFlexibleHeightChange(nil)
|
previousChild.OnFlexibleHeightChange(nil)
|
||||||
}
|
}
|
||||||
if previousChild, ok := window.child.(tomo.Focusable); ok {
|
if previousChild, ok := window.child.(elements.Focusable); ok {
|
||||||
previousChild.OnFocusRequest(nil)
|
previousChild.OnFocusRequest(nil)
|
||||||
previousChild.OnFocusMotionRequest(nil)
|
previousChild.OnFocusMotionRequest(nil)
|
||||||
if previousChild.Focused() {
|
if previousChild.Focused() {
|
||||||
@ -98,10 +100,10 @@ func (window *Window) Adopt (child tomo.Element) {
|
|||||||
|
|
||||||
// adopt new child
|
// adopt new child
|
||||||
window.child = child
|
window.child = child
|
||||||
if newChild, ok := child.(tomo.Flexible); ok {
|
if newChild, ok := child.(elements.Flexible); ok {
|
||||||
newChild.OnFlexibleHeightChange(window.resizeChildToFit)
|
newChild.OnFlexibleHeightChange(window.resizeChildToFit)
|
||||||
}
|
}
|
||||||
if newChild, ok := child.(tomo.Focusable); ok {
|
if newChild, ok := child.(elements.Focusable); ok {
|
||||||
newChild.OnFocusRequest(window.childSelectionRequestCallback)
|
newChild.OnFocusRequest(window.childSelectionRequestCallback)
|
||||||
}
|
}
|
||||||
if child != nil {
|
if child != nil {
|
||||||
@ -116,7 +118,7 @@ func (window *Window) Adopt (child tomo.Element) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *Window) Child () (child tomo.Element) {
|
func (window *Window) Child () (child elements.Element) {
|
||||||
child = window.child
|
child = window.child
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -229,7 +231,7 @@ func (window *Window) redrawChildEntirely () {
|
|||||||
|
|
||||||
func (window *Window) resizeChildToFit () {
|
func (window *Window) resizeChildToFit () {
|
||||||
window.skipChildDrawCallback = true
|
window.skipChildDrawCallback = true
|
||||||
if child, ok := window.child.(tomo.Flexible); ok {
|
if child, ok := window.child.(elements.Flexible); ok {
|
||||||
minimumHeight := child.FlexibleHeightFor(window.metrics.width)
|
minimumHeight := child.FlexibleHeightFor(window.metrics.width)
|
||||||
minimumWidth, _ := child.MinimumSize()
|
minimumWidth, _ := child.MinimumSize()
|
||||||
|
|
||||||
@ -252,12 +254,12 @@ func (window *Window) resizeChildToFit () {
|
|||||||
window.skipChildDrawCallback = false
|
window.skipChildDrawCallback = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *Window) childDrawCallback (region tomo.Canvas) {
|
func (window *Window) childDrawCallback (region canvas.Canvas) {
|
||||||
if window.skipChildDrawCallback { return }
|
if window.skipChildDrawCallback { return }
|
||||||
window.pushRegion(window.paste(region))
|
window.pushRegion(window.paste(region))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *Window) paste (canvas tomo.Canvas) (updatedRegion image.Rectangle) {
|
func (window *Window) paste (canvas canvas.Canvas) (updatedRegion image.Rectangle) {
|
||||||
data, stride := canvas.Buffer()
|
data, stride := canvas.Buffer()
|
||||||
bounds := canvas.Bounds().Intersect(window.xCanvas.Bounds())
|
bounds := canvas.Bounds().Intersect(window.xCanvas.Bounds())
|
||||||
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
|
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
|
||||||
@ -293,18 +295,18 @@ func (window *Window) childMinimumSizeChangeCallback (width, height int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (window *Window) childSelectionRequestCallback () (granted bool) {
|
func (window *Window) childSelectionRequestCallback () (granted bool) {
|
||||||
if child, ok := window.child.(tomo.Focusable); ok {
|
if child, ok := window.child.(elements.Focusable); ok {
|
||||||
child.HandleFocus(tomo.KeynavDirectionNeutral)
|
child.HandleFocus(input.KeynavDirectionNeutral)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *Window) childSelectionMotionRequestCallback (
|
func (window *Window) childSelectionMotionRequestCallback (
|
||||||
direction tomo.KeynavDirection,
|
direction input.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
granted bool,
|
granted bool,
|
||||||
) {
|
) {
|
||||||
if child, ok := window.child.(tomo.Focusable); ok {
|
if child, ok := window.child.(elements.Focusable); ok {
|
||||||
if !child.HandleFocus(direction) {
|
if !child.HandleFocus(direction) {
|
||||||
child.HandleUnfocus()
|
child.HandleUnfocus()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package x
|
package x
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/data"
|
||||||
|
|
||||||
import "github.com/jezek/xgbutil"
|
import "github.com/jezek/xgbutil"
|
||||||
import "github.com/jezek/xgb/xproto"
|
import "github.com/jezek/xgb/xproto"
|
||||||
@ -81,14 +82,14 @@ func (backend *Backend) Do (callback func ()) {
|
|||||||
|
|
||||||
// Copy puts data into the clipboard. This method is not yet implemented and
|
// Copy puts data into the clipboard. This method is not yet implemented and
|
||||||
// will do nothing!
|
// will do nothing!
|
||||||
func (backend *Backend) Copy (data tomo.Data) {
|
func (backend *Backend) Copy (data data.Data) {
|
||||||
backend.assert()
|
backend.assert()
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paste returns the data currently in the clipboard. This method may
|
// Paste returns the data currently in the clipboard. This method may
|
||||||
// return nil. This method is not yet implemented and will do nothing!
|
// return nil. This method is not yet implemented and will do nothing!
|
||||||
func (backend *Backend) Paste (accept []tomo.Mime) (data tomo.Data) {
|
func (backend *Backend) Paste (accept []data.Mime) (data data.Data) {
|
||||||
backend.assert()
|
backend.assert()
|
||||||
// TODO
|
// TODO
|
||||||
return
|
return
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package tomo
|
package canvas
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "image/draw"
|
import "image/draw"
|
22
config/config.go
Normal file
22
config/config.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
// Padding returns the amount of internal padding elements should have. An
|
||||||
|
// element's inner content (such as text) should be inset by this amount,
|
||||||
|
// in addition to the inset returned by the pattern of its background. When
|
||||||
|
// using the aforementioned inset values to calculate the element's minimum size
|
||||||
|
// or the position and alignment of its content, all parameters in the
|
||||||
|
// PatternState should be unset except for Case.
|
||||||
|
func Padding () int {
|
||||||
|
return 7
|
||||||
|
}
|
||||||
|
|
||||||
|
// Margin returns how much space should be put in between elements.
|
||||||
|
func Margin () int {
|
||||||
|
return 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandleWidth returns how large grab handles should typically be. This is
|
||||||
|
// important for accessibility reasons.
|
||||||
|
func HandleWidth () int {
|
||||||
|
return 16
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package tomo
|
package data
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "image"
|
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/theme"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||||
@ -38,10 +38,10 @@ func NewButton (text string) (element *Button) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Button) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *Button) HandleMouseDown (x, y int, button input.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
if !element.Focused() { element.Focus() }
|
if !element.Focused() { element.Focus() }
|
||||||
if button != tomo.ButtonLeft { return }
|
if button != input.ButtonLeft { return }
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
element.draw()
|
element.draw()
|
||||||
@ -49,8 +49,8 @@ func (element *Button) HandleMouseDown (x, y int, button tomo.Button) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Button) HandleMouseUp (x, y int, button tomo.Button) {
|
func (element *Button) HandleMouseUp (x, y int, button input.Button) {
|
||||||
if button != tomo.ButtonLeft { return }
|
if button != input.ButtonLeft { return }
|
||||||
element.pressed = false
|
element.pressed = false
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
element.draw()
|
element.draw()
|
||||||
@ -69,9 +69,9 @@ func (element *Button) HandleMouseUp (x, y int, button tomo.Button) {
|
|||||||
func (element *Button) HandleMouseMove (x, y int) { }
|
func (element *Button) HandleMouseMove (x, y int) { }
|
||||||
func (element *Button) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
func (element *Button) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
||||||
|
|
||||||
func (element *Button) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Button) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
if key == tomo.KeyEnter {
|
if key == input.KeyEnter {
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
element.draw()
|
element.draw()
|
||||||
@ -80,8 +80,8 @@ func (element *Button) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Button) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Button) HandleKeyUp(key input.Key, modifiers input.Modifiers) {
|
||||||
if key == tomo.KeyEnter && element.pressed {
|
if key == input.KeyEnter && element.pressed {
|
||||||
element.pressed = false
|
element.pressed = false
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
element.draw()
|
element.draw()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "image"
|
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/theme"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||||
@ -39,7 +39,7 @@ func NewCheckbox (text string, checked bool) (element *Checkbox) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Checkbox) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *Checkbox) HandleMouseDown (x, y int, button input.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
element.Focus()
|
element.Focus()
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
@ -49,8 +49,8 @@ func (element *Checkbox) HandleMouseDown (x, y int, button tomo.Button) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Checkbox) HandleMouseUp (x, y int, button tomo.Button) {
|
func (element *Checkbox) HandleMouseUp (x, y int, button input.Button) {
|
||||||
if button != tomo.ButtonLeft || !element.pressed { return }
|
if button != input.ButtonLeft || !element.pressed { return }
|
||||||
|
|
||||||
element.pressed = false
|
element.pressed = false
|
||||||
within := image.Point { x, y }.
|
within := image.Point { x, y }.
|
||||||
@ -71,8 +71,8 @@ func (element *Checkbox) HandleMouseUp (x, y int, button tomo.Button) {
|
|||||||
func (element *Checkbox) HandleMouseMove (x, y int) { }
|
func (element *Checkbox) HandleMouseMove (x, y int) { }
|
||||||
func (element *Checkbox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
func (element *Checkbox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
||||||
|
|
||||||
func (element *Checkbox) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Checkbox) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||||
if key == tomo.KeyEnter {
|
if key == input.KeyEnter {
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
element.draw()
|
element.draw()
|
||||||
@ -81,8 +81,8 @@ func (element *Checkbox) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Checkbox) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Checkbox) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
|
||||||
if key == tomo.KeyEnter && element.pressed {
|
if key == input.KeyEnter && element.pressed {
|
||||||
element.pressed = false
|
element.pressed = false
|
||||||
element.checked = !element.checked
|
element.checked = !element.checked
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "image"
|
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/theme"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
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"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||||
|
|
||||||
var containerCase = theme.C("basic", "container")
|
var containerCase = theme.C("basic", "container")
|
||||||
@ -14,21 +17,21 @@ type Container struct {
|
|||||||
*core.Core
|
*core.Core
|
||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
|
|
||||||
layout tomo.Layout
|
layout layouts.Layout
|
||||||
children []tomo.LayoutEntry
|
children []layouts.LayoutEntry
|
||||||
drags [10]tomo.MouseTarget
|
drags [10]elements.MouseTarget
|
||||||
warping bool
|
warping bool
|
||||||
focused bool
|
focused bool
|
||||||
focusable bool
|
focusable bool
|
||||||
flexible bool
|
flexible bool
|
||||||
|
|
||||||
onFocusRequest func () (granted bool)
|
onFocusRequest func () (granted bool)
|
||||||
onFocusMotionRequest func (tomo.KeynavDirection) (granted bool)
|
onFocusMotionRequest func (input.KeynavDirection) (granted bool)
|
||||||
onFlexibleHeightChange func ()
|
onFlexibleHeightChange func ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContainer creates a new container.
|
// NewContainer creates a new container.
|
||||||
func NewContainer (layout tomo.Layout) (element *Container) {
|
func NewContainer (layout layouts.Layout) (element *Container) {
|
||||||
element = &Container { }
|
element = &Container { }
|
||||||
element.Core, element.core = core.NewCore(element.redoAll)
|
element.Core, element.core = core.NewCore(element.redoAll)
|
||||||
element.SetLayout(layout)
|
element.SetLayout(layout)
|
||||||
@ -36,7 +39,7 @@ func NewContainer (layout tomo.Layout) (element *Container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetLayout sets the layout of this container.
|
// SetLayout sets the layout of this container.
|
||||||
func (element *Container) SetLayout (layout tomo.Layout) {
|
func (element *Container) SetLayout (layout layouts.Layout) {
|
||||||
element.layout = layout
|
element.layout = layout
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
element.redoAll()
|
element.redoAll()
|
||||||
@ -47,28 +50,28 @@ func (element *Container) SetLayout (layout tomo.Layout) {
|
|||||||
// Adopt adds a new child element to the container. If expand is set to true,
|
// 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
|
// the element will expand (instead of contract to its minimum size), in
|
||||||
// whatever way is defined by the current layout.
|
// whatever way is defined by the current layout.
|
||||||
func (element *Container) Adopt (child tomo.Element, expand bool) {
|
func (element *Container) Adopt (child elements.Element, expand bool) {
|
||||||
// set event handlers
|
// set event handlers
|
||||||
child.OnDamage (func (region tomo.Canvas) {
|
child.OnDamage (func (region canvas.Canvas) {
|
||||||
element.core.DamageRegion(region.Bounds())
|
element.core.DamageRegion(region.Bounds())
|
||||||
})
|
})
|
||||||
child.OnMinimumSizeChange(element.updateMinimumSize)
|
child.OnMinimumSizeChange(element.updateMinimumSize)
|
||||||
if child0, ok := child.(tomo.Flexible); ok {
|
if child0, ok := child.(elements.Flexible); ok {
|
||||||
child0.OnFlexibleHeightChange(element.updateMinimumSize)
|
child0.OnFlexibleHeightChange(element.updateMinimumSize)
|
||||||
}
|
}
|
||||||
if child0, ok := child.(tomo.Focusable); ok {
|
if child0, ok := child.(elements.Focusable); ok {
|
||||||
child0.OnFocusRequest (func () (granted bool) {
|
child0.OnFocusRequest (func () (granted bool) {
|
||||||
return element.childFocusRequestCallback(child0)
|
return element.childFocusRequestCallback(child0)
|
||||||
})
|
})
|
||||||
child0.OnFocusMotionRequest (
|
child0.OnFocusMotionRequest (
|
||||||
func (direction tomo.KeynavDirection) (granted bool) {
|
func (direction input.KeynavDirection) (granted bool) {
|
||||||
if element.onFocusMotionRequest == nil { return }
|
if element.onFocusMotionRequest == nil { return }
|
||||||
return element.onFocusMotionRequest(direction)
|
return element.onFocusMotionRequest(direction)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// add child
|
// add child
|
||||||
element.children = append (element.children, tomo.LayoutEntry {
|
element.children = append (element.children, layouts.LayoutEntry {
|
||||||
Element: child,
|
Element: child,
|
||||||
Expand: expand,
|
Expand: expand,
|
||||||
})
|
})
|
||||||
@ -106,7 +109,7 @@ func (element *Container) Warp (callback func ()) {
|
|||||||
|
|
||||||
// Disown removes the given child from the container if it is contained within
|
// Disown removes the given child from the container if it is contained within
|
||||||
// it.
|
// it.
|
||||||
func (element *Container) Disown (child tomo.Element) {
|
func (element *Container) Disown (child elements.Element) {
|
||||||
for index, entry := range element.children {
|
for index, entry := range element.children {
|
||||||
if entry.Element == child {
|
if entry.Element == child {
|
||||||
element.clearChildEventHandlers(entry.Element)
|
element.clearChildEventHandlers(entry.Element)
|
||||||
@ -125,18 +128,18 @@ func (element *Container) Disown (child tomo.Element) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) clearChildEventHandlers (child tomo.Element) {
|
func (element *Container) clearChildEventHandlers (child elements.Element) {
|
||||||
child.DrawTo(nil)
|
child.DrawTo(nil)
|
||||||
child.OnDamage(nil)
|
child.OnDamage(nil)
|
||||||
child.OnMinimumSizeChange(nil)
|
child.OnMinimumSizeChange(nil)
|
||||||
if child0, ok := child.(tomo.Focusable); ok {
|
if child0, ok := child.(elements.Focusable); ok {
|
||||||
child0.OnFocusRequest(nil)
|
child0.OnFocusRequest(nil)
|
||||||
child0.OnFocusMotionRequest(nil)
|
child0.OnFocusMotionRequest(nil)
|
||||||
if child0.Focused() {
|
if child0.Focused() {
|
||||||
child0.HandleUnfocus()
|
child0.HandleUnfocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if child0, ok := child.(tomo.Flexible); ok {
|
if child0, ok := child.(elements.Flexible); ok {
|
||||||
child0.OnFlexibleHeightChange(nil)
|
child0.OnFlexibleHeightChange(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,8 +157,8 @@ func (element *Container) DisownAll () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Children returns a slice containing this element's children.
|
// Children returns a slice containing this element's children.
|
||||||
func (element *Container) Children () (children []tomo.Element) {
|
func (element *Container) Children () (children []elements.Element) {
|
||||||
children = make([]tomo.Element, len(element.children))
|
children = make([]elements.Element, len(element.children))
|
||||||
for index, entry := range element.children {
|
for index, entry := range element.children {
|
||||||
children[index] = entry.Element
|
children[index] = entry.Element
|
||||||
}
|
}
|
||||||
@ -169,14 +172,14 @@ func (element *Container) CountChildren () (count int) {
|
|||||||
|
|
||||||
// Child returns the child at the specified index. If the index is out of
|
// Child returns the child at the specified index. If the index is out of
|
||||||
// bounds, this method will return nil.
|
// bounds, this method will return nil.
|
||||||
func (element *Container) Child (index int) (child tomo.Element) {
|
func (element *Container) Child (index int) (child elements.Element) {
|
||||||
if index < 0 || index > len(element.children) { return }
|
if index < 0 || index > len(element.children) { return }
|
||||||
return element.children[index].Element
|
return element.children[index].Element
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChildAt returns the child that contains the specified x and y coordinates. If
|
// 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.
|
// there are no children at the coordinates, this method will return nil.
|
||||||
func (element *Container) ChildAt (point image.Point) (child tomo.Element) {
|
func (element *Container) ChildAt (point image.Point) (child elements.Element) {
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
if point.In(entry.Bounds) {
|
if point.In(entry.Bounds) {
|
||||||
child = entry.Element
|
child = entry.Element
|
||||||
@ -185,7 +188,7 @@ func (element *Container) ChildAt (point image.Point) (child tomo.Element) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) childPosition (child tomo.Element) (position image.Point) {
|
func (element *Container) childPosition (child elements.Element) (position image.Point) {
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
if entry.Element == child {
|
if entry.Element == child {
|
||||||
position = entry.Bounds.Min
|
position = entry.Bounds.Min
|
||||||
@ -209,18 +212,18 @@ func (element *Container) redoAll () {
|
|||||||
|
|
||||||
// cut our canvas up and give peices to child elements
|
// cut our canvas up and give peices to child elements
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
entry.DrawTo(tomo.Cut(element, entry.Bounds))
|
entry.DrawTo(canvas.Cut(element, entry.Bounds))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *Container) HandleMouseDown (x, y int, button input.Button) {
|
||||||
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(tomo.MouseTarget)
|
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget)
|
||||||
if !handlesMouse { return }
|
if !handlesMouse { return }
|
||||||
element.drags[button] = child
|
element.drags[button] = child
|
||||||
child.HandleMouseDown(x, y, button)
|
child.HandleMouseDown(x, y, button)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleMouseUp (x, y int, button tomo.Button) {
|
func (element *Container) HandleMouseUp (x, y int, button input.Button) {
|
||||||
child := element.drags[button]
|
child := element.drags[button]
|
||||||
if child == nil { return }
|
if child == nil { return }
|
||||||
element.drags[button] = nil
|
element.drags[button] = nil
|
||||||
@ -235,14 +238,14 @@ func (element *Container) HandleMouseMove (x, y int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleMouseScroll (x, y int, deltaX, deltaY float64) {
|
func (element *Container) HandleMouseScroll (x, y int, deltaX, deltaY float64) {
|
||||||
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(tomo.MouseTarget)
|
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(elements.MouseTarget)
|
||||||
if !handlesMouse { return }
|
if !handlesMouse { return }
|
||||||
child.HandleMouseScroll(x, y, deltaX, deltaY)
|
child.HandleMouseScroll(x, y, deltaX, deltaY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Container) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||||
element.forFocused (func (child tomo.Focusable) bool {
|
element.forFocused (func (child elements.Focusable) bool {
|
||||||
child0, handlesKeyboard := child.(tomo.KeyboardTarget)
|
child0, handlesKeyboard := child.(elements.KeyboardTarget)
|
||||||
if handlesKeyboard {
|
if handlesKeyboard {
|
||||||
child0.HandleKeyDown(key, modifiers)
|
child0.HandleKeyDown(key, modifiers)
|
||||||
}
|
}
|
||||||
@ -250,9 +253,9 @@ func (element *Container) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Container) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
|
||||||
element.forFocused (func (child tomo.Focusable) bool {
|
element.forFocused (func (child elements.Focusable) bool {
|
||||||
child0, handlesKeyboard := child.(tomo.KeyboardTarget)
|
child0, handlesKeyboard := child.(elements.KeyboardTarget)
|
||||||
if handlesKeyboard {
|
if handlesKeyboard {
|
||||||
child0.HandleKeyUp(key, modifiers)
|
child0.HandleKeyUp(key, modifiers)
|
||||||
}
|
}
|
||||||
@ -261,7 +264,9 @@ func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) FlexibleHeightFor (width int) (height int) {
|
func (element *Container) FlexibleHeightFor (width int) (height int) {
|
||||||
return element.layout.FlexibleHeightFor(element.children, width)
|
return element.layout.FlexibleHeightFor (
|
||||||
|
element.children,
|
||||||
|
theme.Margin(), width)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) OnFlexibleHeightChange (callback func ()) {
|
func (element *Container) OnFlexibleHeightChange (callback func ()) {
|
||||||
@ -278,7 +283,7 @@ func (element *Container) Focus () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool) {
|
func (element *Container) HandleFocus (direction input.KeynavDirection) (ok bool) {
|
||||||
if !element.focusable { return false }
|
if !element.focusable { return false }
|
||||||
direction = direction.Canon()
|
direction = direction.Canon()
|
||||||
|
|
||||||
@ -288,12 +293,12 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool)
|
|||||||
// the first or last focusable element depending on the
|
// the first or last focusable element depending on the
|
||||||
// direction.
|
// direction.
|
||||||
switch direction {
|
switch direction {
|
||||||
case tomo.KeynavDirectionNeutral, tomo.KeynavDirectionForward:
|
case input.KeynavDirectionNeutral, input.KeynavDirectionForward:
|
||||||
// if we recieve a neutral or forward direction, focus
|
// if we recieve a neutral or forward direction, focus
|
||||||
// the first focusable element.
|
// the first focusable element.
|
||||||
return element.focusFirstFocusableElement(direction)
|
return element.focusFirstFocusableElement(direction)
|
||||||
|
|
||||||
case tomo.KeynavDirectionBackward:
|
case input.KeynavDirectionBackward:
|
||||||
// if we recieve a backward direction, focus the last
|
// if we recieve a backward direction, focus the last
|
||||||
// focusable element.
|
// focusable element.
|
||||||
return element.focusLastFocusableElement(direction)
|
return element.focusLastFocusableElement(direction)
|
||||||
@ -302,7 +307,7 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool)
|
|||||||
// an element is currently focused, so we need to move the
|
// an element is currently focused, so we need to move the
|
||||||
// focus in the specified direction
|
// focus in the specified direction
|
||||||
firstFocusedChild :=
|
firstFocusedChild :=
|
||||||
element.children[firstFocused].Element.(tomo.Focusable)
|
element.children[firstFocused].Element.(elements.Focusable)
|
||||||
|
|
||||||
// before we move the focus, the currently focused child
|
// before we move the focus, the currently focused child
|
||||||
// may also be able to move its focus. if the child is able
|
// may also be able to move its focus. if the child is able
|
||||||
@ -319,7 +324,7 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool)
|
|||||||
|
|
||||||
child, focusable :=
|
child, focusable :=
|
||||||
element.children[index].
|
element.children[index].
|
||||||
Element.(tomo.Focusable)
|
Element.(elements.Focusable)
|
||||||
if focusable && child.HandleFocus(direction) {
|
if focusable && child.HandleFocus(direction) {
|
||||||
// we have found one, so we now actually move
|
// we have found one, so we now actually move
|
||||||
// the focus.
|
// the focus.
|
||||||
@ -334,11 +339,11 @@ func (element *Container) HandleFocus (direction tomo.KeynavDirection) (ok bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) focusFirstFocusableElement (
|
func (element *Container) focusFirstFocusableElement (
|
||||||
direction tomo.KeynavDirection,
|
direction input.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
ok bool,
|
ok bool,
|
||||||
) {
|
) {
|
||||||
element.forFocusable (func (child tomo.Focusable) bool {
|
element.forFocusable (func (child elements.Focusable) bool {
|
||||||
if child.HandleFocus(direction) {
|
if child.HandleFocus(direction) {
|
||||||
element.focused = true
|
element.focused = true
|
||||||
ok = true
|
ok = true
|
||||||
@ -350,11 +355,11 @@ func (element *Container) focusFirstFocusableElement (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) focusLastFocusableElement (
|
func (element *Container) focusLastFocusableElement (
|
||||||
direction tomo.KeynavDirection,
|
direction input.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
ok bool,
|
ok bool,
|
||||||
) {
|
) {
|
||||||
element.forFocusableBackward (func (child tomo.Focusable) bool {
|
element.forFocusableBackward (func (child elements.Focusable) bool {
|
||||||
if child.HandleFocus(direction) {
|
if child.HandleFocus(direction) {
|
||||||
element.focused = true
|
element.focused = true
|
||||||
ok = true
|
ok = true
|
||||||
@ -367,7 +372,7 @@ func (element *Container) focusLastFocusableElement (
|
|||||||
|
|
||||||
func (element *Container) HandleUnfocus () {
|
func (element *Container) HandleUnfocus () {
|
||||||
element.focused = false
|
element.focused = false
|
||||||
element.forFocused (func (child tomo.Focusable) bool {
|
element.forFocused (func (child elements.Focusable) bool {
|
||||||
child.HandleUnfocus()
|
child.HandleUnfocus()
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -378,41 +383,41 @@ func (element *Container) OnFocusRequest (callback func () (granted bool)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) OnFocusMotionRequest (
|
func (element *Container) OnFocusMotionRequest (
|
||||||
callback func (direction tomo.KeynavDirection) (granted bool),
|
callback func (direction input.KeynavDirection) (granted bool),
|
||||||
) {
|
) {
|
||||||
element.onFocusMotionRequest = callback
|
element.onFocusMotionRequest = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) forFocused (callback func (child tomo.Focusable) bool) {
|
func (element *Container) forFocused (callback func (child elements.Focusable) bool) {
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
child, focusable := entry.Element.(tomo.Focusable)
|
child, focusable := entry.Element.(elements.Focusable)
|
||||||
if focusable && child.Focused() {
|
if focusable && child.Focused() {
|
||||||
if !callback(child) { break }
|
if !callback(child) { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) forFocusable (callback func (child tomo.Focusable) bool) {
|
func (element *Container) forFocusable (callback func (child elements.Focusable) bool) {
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
child, focusable := entry.Element.(tomo.Focusable)
|
child, focusable := entry.Element.(elements.Focusable)
|
||||||
if focusable {
|
if focusable {
|
||||||
if !callback(child) { break }
|
if !callback(child) { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) forFlexible (callback func (child tomo.Flexible) bool) {
|
func (element *Container) forFlexible (callback func (child elements.Flexible) bool) {
|
||||||
for _, entry := range element.children {
|
for _, entry := range element.children {
|
||||||
child, flexible := entry.Element.(tomo.Flexible)
|
child, flexible := entry.Element.(elements.Flexible)
|
||||||
if flexible {
|
if flexible {
|
||||||
if !callback(child) { break }
|
if !callback(child) { break }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) forFocusableBackward (callback func (child tomo.Focusable) bool) {
|
func (element *Container) forFocusableBackward (callback func (child elements.Focusable) bool) {
|
||||||
for index := len(element.children) - 1; index >= 0; index -- {
|
for index := len(element.children) - 1; index >= 0; index -- {
|
||||||
child, focusable := element.children[index].Element.(tomo.Focusable)
|
child, focusable := element.children[index].Element.(elements.Focusable)
|
||||||
if focusable {
|
if focusable {
|
||||||
if !callback(child) { break }
|
if !callback(child) { break }
|
||||||
}
|
}
|
||||||
@ -421,7 +426,7 @@ func (element *Container) forFocusableBackward (callback func (child tomo.Focusa
|
|||||||
|
|
||||||
func (element *Container) firstFocused () (index int) {
|
func (element *Container) firstFocused () (index int) {
|
||||||
for currentIndex, entry := range element.children {
|
for currentIndex, entry := range element.children {
|
||||||
child, focusable := entry.Element.(tomo.Focusable)
|
child, focusable := entry.Element.(elements.Focusable)
|
||||||
if focusable && child.Focused() {
|
if focusable && child.Focused() {
|
||||||
return currentIndex
|
return currentIndex
|
||||||
}
|
}
|
||||||
@ -431,12 +436,12 @@ func (element *Container) firstFocused () (index int) {
|
|||||||
|
|
||||||
func (element *Container) reflectChildProperties () {
|
func (element *Container) reflectChildProperties () {
|
||||||
element.focusable = false
|
element.focusable = false
|
||||||
element.forFocusable (func (tomo.Focusable) bool {
|
element.forFocusable (func (elements.Focusable) bool {
|
||||||
element.focusable = true
|
element.focusable = true
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
element.flexible = false
|
element.flexible = false
|
||||||
element.forFlexible (func (tomo.Flexible) bool {
|
element.forFlexible (func (elements.Flexible) bool {
|
||||||
element.flexible = true
|
element.flexible = true
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
@ -446,16 +451,16 @@ func (element *Container) reflectChildProperties () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) childFocusRequestCallback (
|
func (element *Container) childFocusRequestCallback (
|
||||||
child tomo.Focusable,
|
child elements.Focusable,
|
||||||
) (
|
) (
|
||||||
granted bool,
|
granted bool,
|
||||||
) {
|
) {
|
||||||
if element.onFocusRequest != nil && element.onFocusRequest() {
|
if element.onFocusRequest != nil && element.onFocusRequest() {
|
||||||
element.forFocused (func (child tomo.Focusable) bool {
|
element.forFocused (func (child elements.Focusable) bool {
|
||||||
child.HandleUnfocus()
|
child.HandleUnfocus()
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
child.HandleFocus(tomo.KeynavDirectionNeutral)
|
child.HandleFocus(input.KeynavDirectionNeutral)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -463,13 +468,16 @@ func (element *Container) childFocusRequestCallback (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) updateMinimumSize () {
|
func (element *Container) updateMinimumSize () {
|
||||||
width, height := element.layout.MinimumSize(element.children)
|
width, height := element.layout.MinimumSize (
|
||||||
|
element.children, theme.Margin())
|
||||||
if element.flexible {
|
if element.flexible {
|
||||||
height = element.layout.FlexibleHeightFor(element.children, width)
|
height = element.layout.FlexibleHeightFor (
|
||||||
|
element.children, theme.Margin(), width)
|
||||||
}
|
}
|
||||||
element.core.SetMinimumSize(width, height)
|
element.core.SetMinimumSize(width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Container) recalculate () {
|
func (element *Container) recalculate () {
|
||||||
element.layout.Arrange(element.children, element.Bounds())
|
element.layout.Arrange (
|
||||||
|
element.children, theme.Margin(), element.Bounds())
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "image"
|
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/theme"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||||
|
|
||||||
@ -73,10 +74,10 @@ func (element *List) Collapse (width, height int) {
|
|||||||
element.updateMinimumSize()
|
element.updateMinimumSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *List) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *List) HandleMouseDown (x, y int, button input.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
if !element.Focused() { element.Focus() }
|
if !element.Focused() { element.Focus() }
|
||||||
if button != tomo.ButtonLeft { return }
|
if button != input.ButtonLeft { return }
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
if element.selectUnderMouse(x, y) && element.core.HasImage() {
|
if element.selectUnderMouse(x, y) && element.core.HasImage() {
|
||||||
element.draw()
|
element.draw()
|
||||||
@ -84,8 +85,8 @@ func (element *List) HandleMouseDown (x, y int, button tomo.Button) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *List) HandleMouseUp (x, y int, button tomo.Button) {
|
func (element *List) HandleMouseUp (x, y int, button input.Button) {
|
||||||
if button != tomo.ButtonLeft { return }
|
if button != input.ButtonLeft { return }
|
||||||
element.pressed = false
|
element.pressed = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,18 +101,18 @@ func (element *List) HandleMouseMove (x, y int) {
|
|||||||
|
|
||||||
func (element *List) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
func (element *List) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
||||||
|
|
||||||
func (element *List) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *List) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
|
|
||||||
altered := false
|
altered := false
|
||||||
switch key {
|
switch key {
|
||||||
case tomo.KeyLeft, tomo.KeyUp:
|
case input.KeyLeft, input.KeyUp:
|
||||||
altered = element.changeSelectionBy(-1)
|
altered = element.changeSelectionBy(-1)
|
||||||
|
|
||||||
case tomo.KeyRight, tomo.KeyDown:
|
case input.KeyRight, input.KeyDown:
|
||||||
altered = element.changeSelectionBy(1)
|
altered = element.changeSelectionBy(1)
|
||||||
|
|
||||||
case tomo.KeyEscape:
|
case input.KeyEscape:
|
||||||
altered = element.selectEntry(-1)
|
altered = element.selectEntry(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +122,7 @@ func (element *List) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *List) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) { }
|
func (element *List) HandleKeyUp(key input.Key, modifiers input.Modifiers) { }
|
||||||
|
|
||||||
// ScrollContentBounds returns the full content size of the element.
|
// ScrollContentBounds returns the full content size of the element.
|
||||||
func (element *List) ScrollContentBounds () (bounds image.Rectangle) {
|
func (element *List) ScrollContentBounds () (bounds image.Rectangle) {
|
||||||
@ -383,7 +384,7 @@ func (element *List) draw () {
|
|||||||
bounds.Min.X,
|
bounds.Min.X,
|
||||||
bounds.Min.Y - element.scroll,
|
bounds.Min.Y - element.scroll,
|
||||||
}
|
}
|
||||||
innerCanvas := tomo.Cut(element, bounds)
|
innerCanvas := canvas.Cut(element, bounds)
|
||||||
for index, entry := range element.entries {
|
for index, entry := range element.entries {
|
||||||
entryPosition := dot
|
entryPosition := dot
|
||||||
dot.Y += entry.Bounds().Dy()
|
dot.Y += entry.Bounds().Dy()
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
|
||||||
var listEntryCase = theme.C("basic", "listEntry")
|
var listEntryCase = theme.C("basic", "listEntry")
|
||||||
@ -53,7 +53,7 @@ func (entry *ListEntry) updateBounds () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (entry *ListEntry) Draw (
|
func (entry *ListEntry) Draw (
|
||||||
destination tomo.Canvas,
|
destination canvas.Canvas,
|
||||||
offset image.Point,
|
offset image.Point,
|
||||||
focused bool,
|
focused bool,
|
||||||
on bool,
|
on bool,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "image"
|
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/theme"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||||
|
|
||||||
var scrollContainerCase = theme.C("basic", "scrollContainer")
|
var scrollContainerCase = theme.C("basic", "scrollContainer")
|
||||||
@ -17,7 +19,7 @@ type ScrollContainer struct {
|
|||||||
core core.CoreControl
|
core core.CoreControl
|
||||||
focused bool
|
focused bool
|
||||||
|
|
||||||
child tomo.Scrollable
|
child elements.Scrollable
|
||||||
childWidth, childHeight int
|
childWidth, childHeight int
|
||||||
|
|
||||||
horizontal struct {
|
horizontal struct {
|
||||||
@ -41,7 +43,7 @@ type ScrollContainer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onFocusRequest func () (granted bool)
|
onFocusRequest func () (granted bool)
|
||||||
onFocusMotionRequest func (tomo.KeynavDirection) (granted bool)
|
onFocusMotionRequest func (input.KeynavDirection) (granted bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewScrollContainer creates a new scroll container with the specified scroll
|
// NewScrollContainer creates a new scroll container with the specified scroll
|
||||||
@ -64,7 +66,7 @@ func (element *ScrollContainer) handleResize () {
|
|||||||
// Adopt adds a scrollable element to the scroll container. The container can
|
// 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
|
// only contain one scrollable element at a time, and when a new one is adopted
|
||||||
// it replaces the last one.
|
// it replaces the last one.
|
||||||
func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
|
func (element *ScrollContainer) Adopt (child elements.Scrollable) {
|
||||||
// disown previous child if it exists
|
// disown previous child if it exists
|
||||||
if element.child != nil {
|
if element.child != nil {
|
||||||
element.clearChildEventHandlers(child)
|
element.clearChildEventHandlers(child)
|
||||||
@ -76,7 +78,7 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
|
|||||||
child.OnDamage(element.childDamageCallback)
|
child.OnDamage(element.childDamageCallback)
|
||||||
child.OnMinimumSizeChange(element.updateMinimumSize)
|
child.OnMinimumSizeChange(element.updateMinimumSize)
|
||||||
child.OnScrollBoundsChange(element.childScrollBoundsChangeCallback)
|
child.OnScrollBoundsChange(element.childScrollBoundsChangeCallback)
|
||||||
if newChild, ok := child.(tomo.Focusable); ok {
|
if newChild, ok := child.(elements.Focusable); ok {
|
||||||
newChild.OnFocusRequest (
|
newChild.OnFocusRequest (
|
||||||
element.childFocusRequestCallback)
|
element.childFocusRequestCallback)
|
||||||
newChild.OnFocusMotionRequest (
|
newChild.OnFocusMotionRequest (
|
||||||
@ -96,19 +98,19 @@ func (element *ScrollContainer) Adopt (child tomo.Scrollable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *ScrollContainer) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||||
if child, ok := element.child.(tomo.KeyboardTarget); ok {
|
if child, ok := element.child.(elements.KeyboardTarget); ok {
|
||||||
child.HandleKeyDown(key, modifiers)
|
child.HandleKeyDown(key, modifiers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *ScrollContainer) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
|
||||||
if child, ok := element.child.(tomo.KeyboardTarget); ok {
|
if child, ok := element.child.(elements.KeyboardTarget); ok {
|
||||||
child.HandleKeyUp(key, modifiers)
|
child.HandleKeyUp(key, modifiers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *ScrollContainer) HandleMouseDown (x, y int, button input.Button) {
|
||||||
point := image.Pt(x, y)
|
point := image.Pt(x, y)
|
||||||
if point.In(element.horizontal.bar) {
|
if point.In(element.horizontal.bar) {
|
||||||
element.horizontal.dragging = true
|
element.horizontal.dragging = true
|
||||||
@ -140,12 +142,12 @@ func (element *ScrollContainer) HandleMouseDown (x, y int, button tomo.Button) {
|
|||||||
element.scrollChildBy(0, -16)
|
element.scrollChildBy(0, -16)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if child, ok := element.child.(tomo.MouseTarget); ok {
|
} else if child, ok := element.child.(elements.MouseTarget); ok {
|
||||||
child.HandleMouseDown(x, y, button)
|
child.HandleMouseDown(x, y, button)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) HandleMouseUp (x, y int, button tomo.Button) {
|
func (element *ScrollContainer) HandleMouseUp (x, y int, button input.Button) {
|
||||||
if element.horizontal.dragging {
|
if element.horizontal.dragging {
|
||||||
element.horizontal.dragging = false
|
element.horizontal.dragging = false
|
||||||
element.drawHorizontalBar()
|
element.drawHorizontalBar()
|
||||||
@ -156,7 +158,7 @@ func (element *ScrollContainer) HandleMouseUp (x, y int, button tomo.Button) {
|
|||||||
element.drawVerticalBar()
|
element.drawVerticalBar()
|
||||||
element.core.DamageRegion(element.vertical.bar)
|
element.core.DamageRegion(element.vertical.bar)
|
||||||
|
|
||||||
} else if child, ok := element.child.(tomo.MouseTarget); ok {
|
} else if child, ok := element.child.(elements.MouseTarget); ok {
|
||||||
child.HandleMouseUp(x, y, button)
|
child.HandleMouseUp(x, y, button)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,7 +170,7 @@ func (element *ScrollContainer) HandleMouseMove (x, y int) {
|
|||||||
} else if element.vertical.dragging {
|
} else if element.vertical.dragging {
|
||||||
element.dragVerticalBar(image.Pt(x, y))
|
element.dragVerticalBar(image.Pt(x, y))
|
||||||
|
|
||||||
} else if child, ok := element.child.(tomo.MouseTarget); ok {
|
} else if child, ok := element.child.(elements.MouseTarget); ok {
|
||||||
child.HandleMouseMove(x, y)
|
child.HandleMouseMove(x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,11 +201,11 @@ func (element *ScrollContainer) Focus () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) HandleFocus (
|
func (element *ScrollContainer) HandleFocus (
|
||||||
direction tomo.KeynavDirection,
|
direction input.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
accepted bool,
|
accepted bool,
|
||||||
) {
|
) {
|
||||||
if child, ok := element.child.(tomo.Focusable); ok {
|
if child, ok := element.child.(elements.Focusable); ok {
|
||||||
element.focused = true
|
element.focused = true
|
||||||
return child.HandleFocus(direction)
|
return child.HandleFocus(direction)
|
||||||
} else {
|
} else {
|
||||||
@ -213,7 +215,7 @@ func (element *ScrollContainer) HandleFocus (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) HandleUnfocus () {
|
func (element *ScrollContainer) HandleUnfocus () {
|
||||||
if child, ok := element.child.(tomo.Focusable); ok {
|
if child, ok := element.child.(elements.Focusable); ok {
|
||||||
child.HandleUnfocus()
|
child.HandleUnfocus()
|
||||||
}
|
}
|
||||||
element.focused = false
|
element.focused = false
|
||||||
@ -224,20 +226,20 @@ func (element *ScrollContainer) OnFocusRequest (callback func () (granted bool))
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) OnFocusMotionRequest (
|
func (element *ScrollContainer) OnFocusMotionRequest (
|
||||||
callback func (direction tomo.KeynavDirection) (granted bool),
|
callback func (direction input.KeynavDirection) (granted bool),
|
||||||
) {
|
) {
|
||||||
element.onFocusMotionRequest = callback
|
element.onFocusMotionRequest = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) childDamageCallback (region tomo.Canvas) {
|
func (element *ScrollContainer) childDamageCallback (region canvas.Canvas) {
|
||||||
element.core.DamageRegion(artist.Paste(element, region, image.Point { }))
|
element.core.DamageRegion(artist.Paste(element, region, image.Point { }))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) childFocusRequestCallback () (granted bool) {
|
func (element *ScrollContainer) childFocusRequestCallback () (granted bool) {
|
||||||
child, ok := element.child.(tomo.Focusable)
|
child, ok := element.child.(elements.Focusable)
|
||||||
if !ok { return false }
|
if !ok { return false }
|
||||||
if element.onFocusRequest != nil && element.onFocusRequest() {
|
if element.onFocusRequest != nil && element.onFocusRequest() {
|
||||||
child.HandleFocus(tomo.KeynavDirectionNeutral)
|
child.HandleFocus(input.KeynavDirectionNeutral)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -245,7 +247,7 @@ func (element *ScrollContainer) childFocusRequestCallback () (granted bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) childFocusMotionRequestCallback (
|
func (element *ScrollContainer) childFocusMotionRequestCallback (
|
||||||
direction tomo.KeynavDirection,
|
direction input.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
granted bool,
|
granted bool,
|
||||||
) {
|
) {
|
||||||
@ -253,19 +255,19 @@ func (element *ScrollContainer) childFocusMotionRequestCallback (
|
|||||||
return element.onFocusMotionRequest(direction)
|
return element.onFocusMotionRequest(direction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) clearChildEventHandlers (child tomo.Scrollable) {
|
func (element *ScrollContainer) clearChildEventHandlers (child elements.Scrollable) {
|
||||||
child.DrawTo(nil)
|
child.DrawTo(nil)
|
||||||
child.OnDamage(nil)
|
child.OnDamage(nil)
|
||||||
child.OnMinimumSizeChange(nil)
|
child.OnMinimumSizeChange(nil)
|
||||||
child.OnScrollBoundsChange(nil)
|
child.OnScrollBoundsChange(nil)
|
||||||
if child0, ok := child.(tomo.Focusable); ok {
|
if child0, ok := child.(elements.Focusable); ok {
|
||||||
child0.OnFocusRequest(nil)
|
child0.OnFocusRequest(nil)
|
||||||
child0.OnFocusMotionRequest(nil)
|
child0.OnFocusMotionRequest(nil)
|
||||||
if child0.Focused() {
|
if child0.Focused() {
|
||||||
child0.HandleUnfocus()
|
child0.HandleUnfocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if child0, ok := child.(tomo.Flexible); ok {
|
if child0, ok := child.(elements.Flexible); ok {
|
||||||
child0.OnFlexibleHeightChange(nil)
|
child0.OnFlexibleHeightChange(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,7 +277,7 @@ func (element *ScrollContainer) resizeChildToFit () {
|
|||||||
0, 0,
|
0, 0,
|
||||||
element.childWidth,
|
element.childWidth,
|
||||||
element.childHeight).Add(element.Bounds().Min)
|
element.childHeight).Add(element.Bounds().Min)
|
||||||
element.child.DrawTo(tomo.Cut(element, childBounds))
|
element.child.DrawTo(canvas.Cut(element, childBounds))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *ScrollContainer) recalculate () {
|
func (element *ScrollContainer) recalculate () {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "image"
|
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/theme"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||||
@ -41,7 +41,7 @@ func NewSwitch (text string, on bool) (element *Switch) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Switch) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *Switch) HandleMouseDown (x, y int, button input.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
element.Focus()
|
element.Focus()
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
@ -51,8 +51,8 @@ func (element *Switch) HandleMouseDown (x, y int, button tomo.Button) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Switch) HandleMouseUp (x, y int, button tomo.Button) {
|
func (element *Switch) HandleMouseUp (x, y int, button input.Button) {
|
||||||
if button != tomo.ButtonLeft || !element.pressed { return }
|
if button != input.ButtonLeft || !element.pressed { return }
|
||||||
|
|
||||||
element.pressed = false
|
element.pressed = false
|
||||||
within := image.Point { x, y }.
|
within := image.Point { x, y }.
|
||||||
@ -73,8 +73,8 @@ func (element *Switch) HandleMouseUp (x, y int, button tomo.Button) {
|
|||||||
func (element *Switch) HandleMouseMove (x, y int) { }
|
func (element *Switch) HandleMouseMove (x, y int) { }
|
||||||
func (element *Switch) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
func (element *Switch) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
||||||
|
|
||||||
func (element *Switch) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Switch) HandleKeyDown (key input.Key, modifiers input.Modifiers) {
|
||||||
if key == tomo.KeyEnter {
|
if key == input.KeyEnter {
|
||||||
element.pressed = true
|
element.pressed = true
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
element.draw()
|
element.draw()
|
||||||
@ -83,8 +83,8 @@ func (element *Switch) HandleKeyDown (key tomo.Key, modifiers tomo.Modifiers) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Switch) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *Switch) HandleKeyUp (key input.Key, modifiers input.Modifiers) {
|
||||||
if key == tomo.KeyEnter && element.pressed {
|
if key == input.KeyEnter && element.pressed {
|
||||||
element.pressed = false
|
element.pressed = false
|
||||||
element.checked = !element.checked
|
element.checked = !element.checked
|
||||||
if element.core.HasImage() {
|
if element.core.HasImage() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package basic
|
package basicElements
|
||||||
|
|
||||||
import "image"
|
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/theme"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/textmanip"
|
import "git.tebibyte.media/sashakoshka/tomo/textmanip"
|
||||||
@ -24,7 +24,7 @@ type TextBox struct {
|
|||||||
placeholderDrawer artist.TextDrawer
|
placeholderDrawer artist.TextDrawer
|
||||||
valueDrawer artist.TextDrawer
|
valueDrawer artist.TextDrawer
|
||||||
|
|
||||||
onKeyDown func (key tomo.Key, modifiers tomo.Modifiers) (handled bool)
|
onKeyDown func (key input.Key, modifiers input.Modifiers) (handled bool)
|
||||||
onChange func ()
|
onChange func ()
|
||||||
onScrollBoundsChange func ()
|
onScrollBoundsChange func ()
|
||||||
}
|
}
|
||||||
@ -59,16 +59,16 @@ func (element *TextBox) handleResize () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *TextBox) HandleMouseDown (x, y int, button input.Button) {
|
||||||
if !element.Enabled() { return }
|
if !element.Enabled() { return }
|
||||||
if !element.Focused() { element.Focus() }
|
if !element.Focused() { element.Focus() }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) HandleMouseUp (x, y int, button tomo.Button) { }
|
func (element *TextBox) HandleMouseUp (x, y int, button input.Button) { }
|
||||||
func (element *TextBox) HandleMouseMove (x, y int) { }
|
func (element *TextBox) HandleMouseMove (x, y int) { }
|
||||||
func (element *TextBox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
func (element *TextBox) HandleMouseScroll (x, y int, deltaX, deltaY float64) { }
|
||||||
|
|
||||||
func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
|
func (element *TextBox) HandleKeyDown(key input.Key, modifiers input.Modifiers) {
|
||||||
if element.onKeyDown != nil && element.onKeyDown(key, modifiers) {
|
if element.onKeyDown != nil && element.onKeyDown(key, modifiers) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -77,7 +77,7 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
|
|||||||
altered := true
|
altered := true
|
||||||
textChanged := false
|
textChanged := false
|
||||||
switch {
|
switch {
|
||||||
case key == tomo.KeyBackspace:
|
case key == input.KeyBackspace:
|
||||||
if len(element.text) < 1 { break }
|
if len(element.text) < 1 { break }
|
||||||
element.text, element.cursor = textmanip.Backspace (
|
element.text, element.cursor = textmanip.Backspace (
|
||||||
element.text,
|
element.text,
|
||||||
@ -85,7 +85,7 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
|
|||||||
modifiers.Control)
|
modifiers.Control)
|
||||||
textChanged = true
|
textChanged = true
|
||||||
|
|
||||||
case key == tomo.KeyDelete:
|
case key == input.KeyDelete:
|
||||||
if len(element.text) < 1 { break }
|
if len(element.text) < 1 { break }
|
||||||
element.text, element.cursor = textmanip.Delete (
|
element.text, element.cursor = textmanip.Delete (
|
||||||
element.text,
|
element.text,
|
||||||
@ -93,13 +93,13 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
|
|||||||
modifiers.Control)
|
modifiers.Control)
|
||||||
textChanged = true
|
textChanged = true
|
||||||
|
|
||||||
case key == tomo.KeyLeft:
|
case key == input.KeyLeft:
|
||||||
element.cursor = textmanip.MoveLeft (
|
element.cursor = textmanip.MoveLeft (
|
||||||
element.text,
|
element.text,
|
||||||
element.cursor,
|
element.cursor,
|
||||||
modifiers.Control)
|
modifiers.Control)
|
||||||
|
|
||||||
case key == tomo.KeyRight:
|
case key == input.KeyRight:
|
||||||
element.cursor = textmanip.MoveRight (
|
element.cursor = textmanip.MoveRight (
|
||||||
element.text,
|
element.text,
|
||||||
element.cursor,
|
element.cursor,
|
||||||
@ -136,7 +136,7 @@ func (element *TextBox) HandleKeyDown(key tomo.Key, modifiers tomo.Modifiers) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) { }
|
func (element *TextBox) HandleKeyUp(key input.Key, modifiers input.Modifiers) { }
|
||||||
|
|
||||||
func (element *TextBox) SetPlaceholder (placeholder string) {
|
func (element *TextBox) SetPlaceholder (placeholder string) {
|
||||||
if element.placeholder == placeholder { return }
|
if element.placeholder == placeholder { return }
|
||||||
@ -177,7 +177,7 @@ func (element *TextBox) Filled () (filled bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (element *TextBox) OnKeyDown (
|
func (element *TextBox) OnKeyDown (
|
||||||
callback func (key tomo.Key, modifiers tomo.Modifiers) (handled bool),
|
callback func (key input.Key, modifiers input.Modifiers) (handled bool),
|
||||||
) {
|
) {
|
||||||
element.onKeyDown = callback
|
element.onKeyDown = callback
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@ package core
|
|||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "image/color"
|
import "image/color"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
|
|
||||||
// Core is a struct that implements some core functionality common to most
|
// Core is a struct that implements some core functionality common to most
|
||||||
// widgets. It is meant to be embedded directly into a struct.
|
// widgets. It is meant to be embedded directly into a struct.
|
||||||
type Core struct {
|
type Core struct {
|
||||||
canvas tomo.Canvas
|
canvas canvas.Canvas
|
||||||
|
|
||||||
metrics struct {
|
metrics struct {
|
||||||
minimumWidth int
|
minimumWidth int
|
||||||
@ -16,7 +16,7 @@ type Core struct {
|
|||||||
|
|
||||||
drawSizeChange func ()
|
drawSizeChange func ()
|
||||||
onMinimumSizeChange func ()
|
onMinimumSizeChange func ()
|
||||||
onDamage func (region tomo.Canvas)
|
onDamage func (region canvas.Canvas)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCore creates a new element core and its corresponding control.
|
// NewCore creates a new element core and its corresponding control.
|
||||||
@ -49,7 +49,7 @@ func (core *Core) Set (x, y int, c color.Color) () {
|
|||||||
core.canvas.Set(x, y, c)
|
core.canvas.Set(x, y, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer fulfills the tomo.Canvas interface.
|
// Buffer fulfills the canvas.Canvas interface.
|
||||||
func (core *Core) Buffer () (data []color.RGBA, stride int) {
|
func (core *Core) Buffer () (data []color.RGBA, stride int) {
|
||||||
if core.canvas == nil { return }
|
if core.canvas == nil { return }
|
||||||
return core.canvas.Buffer()
|
return core.canvas.Buffer()
|
||||||
@ -63,7 +63,7 @@ func (core *Core) MinimumSize () (width, height int) {
|
|||||||
|
|
||||||
// DrawTo fulfills the tomo.Element interface. This should not need to be
|
// DrawTo fulfills the tomo.Element interface. This should not need to be
|
||||||
// overridden.
|
// overridden.
|
||||||
func (core *Core) DrawTo (canvas tomo.Canvas) {
|
func (core *Core) DrawTo (canvas canvas.Canvas) {
|
||||||
core.canvas = canvas
|
core.canvas = canvas
|
||||||
if core.drawSizeChange != nil {
|
if core.drawSizeChange != nil {
|
||||||
core.drawSizeChange()
|
core.drawSizeChange()
|
||||||
@ -72,7 +72,7 @@ func (core *Core) DrawTo (canvas tomo.Canvas) {
|
|||||||
|
|
||||||
// OnDamage fulfils the tomo.Element interface. This should not need to be
|
// OnDamage fulfils the tomo.Element interface. This should not need to be
|
||||||
// overridden.
|
// overridden.
|
||||||
func (core *Core) OnDamage (callback func (region tomo.Canvas)) {
|
func (core *Core) OnDamage (callback func (region canvas.Canvas)) {
|
||||||
core.onDamage = callback
|
core.onDamage = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ func (control CoreControl) HasImage () (has bool) {
|
|||||||
// does not need to be called when responding to a resize event.
|
// does not need to be called when responding to a resize event.
|
||||||
func (control CoreControl) DamageRegion (bounds image.Rectangle) {
|
func (control CoreControl) DamageRegion (bounds image.Rectangle) {
|
||||||
if control.core.onDamage != nil {
|
if control.core.onDamage != nil {
|
||||||
control.core.onDamage(tomo.Cut(control.core, bounds))
|
control.core.onDamage(canvas.Cut(control.core, bounds))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
|
|
||||||
// FocusableCore is a struct that can be embedded into objects to make them
|
// FocusableCore is a struct that can be embedded into objects to make them
|
||||||
// focusable, giving them the default keynav behavior.
|
// focusable, giving them the default keynav behavior.
|
||||||
@ -9,7 +9,7 @@ type FocusableCore struct {
|
|||||||
enabled bool
|
enabled bool
|
||||||
drawFocusChange func ()
|
drawFocusChange func ()
|
||||||
onFocusRequest func () (granted bool)
|
onFocusRequest func () (granted bool)
|
||||||
onFocusMotionRequest func(tomo.KeynavDirection) (granted bool)
|
onFocusMotionRequest func(input.KeynavDirection) (granted bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFocusableCore creates a new focusability core and its corresponding
|
// NewFocusableCore creates a new focusability core and its corresponding
|
||||||
@ -46,13 +46,13 @@ func (core *FocusableCore) Focus () {
|
|||||||
// HandleFocus causes this element to mark itself as focused, if it can
|
// HandleFocus causes this element to mark itself as focused, if it can
|
||||||
// currently be. Otherwise, it will return false and do nothing.
|
// currently be. Otherwise, it will return false and do nothing.
|
||||||
func (core *FocusableCore) HandleFocus (
|
func (core *FocusableCore) HandleFocus (
|
||||||
direction tomo.KeynavDirection,
|
direction input.KeynavDirection,
|
||||||
) (
|
) (
|
||||||
accepted bool,
|
accepted bool,
|
||||||
) {
|
) {
|
||||||
direction = direction.Canon()
|
direction = direction.Canon()
|
||||||
if !core.enabled { return false }
|
if !core.enabled { return false }
|
||||||
if core.focused && direction != tomo.KeynavDirectionNeutral {
|
if core.focused && direction != input.KeynavDirectionNeutral {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ func (core *FocusableCore) OnFocusRequest (callback func () (granted bool)) {
|
|||||||
// should return true if the request was granted, and false if it was
|
// should return true if the request was granted, and false if it was
|
||||||
// not.
|
// not.
|
||||||
func (core *FocusableCore) OnFocusMotionRequest (
|
func (core *FocusableCore) OnFocusMotionRequest (
|
||||||
callback func (direction tomo.KeynavDirection) (granted bool),
|
callback func (direction input.KeynavDirection) (granted bool),
|
||||||
) {
|
) {
|
||||||
core.onFocusMotionRequest = callback
|
core.onFocusMotionRequest = callback
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package tomo
|
package elements
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
|
|
||||||
// Element represents a basic on-screen object.
|
// Element represents a basic on-screen object.
|
||||||
type Element interface {
|
type Element interface {
|
||||||
// Element must implement the Canvas interface. Elements should start
|
// Element must implement the Canvas interface. Elements should start
|
||||||
// out with a completely blank buffer, and only allocate memory and draw
|
// out with a completely blank buffer, and only allocate memory and draw
|
||||||
// on it for the first time when sent an EventResize event.
|
// on it for the first time when sent an EventResize event.
|
||||||
Canvas
|
canvas.Canvas
|
||||||
|
|
||||||
// MinimumSize specifies the minimum amount of pixels this element's
|
// MinimumSize specifies the minimum amount of pixels this element's
|
||||||
// width and height may be set to. If the element is given a resize
|
// width and height may be set to. If the element is given a resize
|
||||||
@ -18,37 +20,17 @@ type Element interface {
|
|||||||
// DrawTo sets this element's canvas. This should only be called by the
|
// DrawTo sets this element's canvas. This should only be called by the
|
||||||
// parent element. This is typically a region of the parent element's
|
// parent element. This is typically a region of the parent element's
|
||||||
// canvas.
|
// canvas.
|
||||||
DrawTo (canvas Canvas)
|
DrawTo (canvas canvas.Canvas)
|
||||||
|
|
||||||
// OnDamage sets a function to be called when an area of the element is
|
// OnDamage sets a function to be called when an area of the element is
|
||||||
// drawn on and should be pushed to the screen.
|
// drawn on and should be pushed to the screen.
|
||||||
OnDamage (callback func (region Canvas))
|
OnDamage (callback func (region canvas.Canvas))
|
||||||
|
|
||||||
// OnMinimumSizeChange sets a function to be called when the element's
|
// OnMinimumSizeChange sets a function to be called when the element's
|
||||||
// minimum size is changed.
|
// minimum size is changed.
|
||||||
OnMinimumSizeChange (callback func ())
|
OnMinimumSizeChange (callback func ())
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeynavDirection represents a keyboard navigation direction.
|
|
||||||
type KeynavDirection int
|
|
||||||
|
|
||||||
const (
|
|
||||||
KeynavDirectionNeutral KeynavDirection = 0
|
|
||||||
KeynavDirectionBackward KeynavDirection = -1
|
|
||||||
KeynavDirectionForward KeynavDirection = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// Canon returns a well-formed direction.
|
|
||||||
func (direction KeynavDirection) Canon () (canon KeynavDirection) {
|
|
||||||
if direction > 0 {
|
|
||||||
return KeynavDirectionForward
|
|
||||||
} else if direction == 0 {
|
|
||||||
return KeynavDirectionNeutral
|
|
||||||
} else {
|
|
||||||
return KeynavDirectionBackward
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Focusable represents an element that has keyboard navigation support. This
|
// Focusable represents an element that has keyboard navigation support. This
|
||||||
// includes inputs, buttons, sliders, etc. as well as any elements that have
|
// includes inputs, buttons, sliders, etc. as well as any elements that have
|
||||||
// children (so keyboard navigation events can be propagated downward).
|
// children (so keyboard navigation events can be propagated downward).
|
||||||
@ -67,7 +49,7 @@ type Focusable interface {
|
|||||||
// selectable children in the given direction, it should return false
|
// selectable children in the given direction, it should return false
|
||||||
// and do nothing. Otherwise, it should select itself and any children
|
// and do nothing. Otherwise, it should select itself and any children
|
||||||
// (if applicable) and return true.
|
// (if applicable) and return true.
|
||||||
HandleFocus (direction KeynavDirection) (accepted bool)
|
HandleFocus (direction input.KeynavDirection) (accepted bool)
|
||||||
|
|
||||||
// HandleDeselection causes this element to mark itself and all of its
|
// HandleDeselection causes this element to mark itself and all of its
|
||||||
// children as unfocused.
|
// children as unfocused.
|
||||||
@ -83,7 +65,7 @@ type Focusable interface {
|
|||||||
// front of it, depending on the specified direction. Parent elements
|
// front of it, depending on the specified direction. Parent elements
|
||||||
// should return true if the request was granted, and false if it was
|
// should return true if the request was granted, and false if it was
|
||||||
// not.
|
// not.
|
||||||
OnFocusMotionRequest (func (direction KeynavDirection) (granted bool))
|
OnFocusMotionRequest (func (direction input.KeynavDirection) (granted bool))
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyboardTarget represents an element that can receive keyboard input.
|
// KeyboardTarget represents an element that can receive keyboard input.
|
||||||
@ -95,11 +77,11 @@ type KeyboardTarget interface {
|
|||||||
// every key down event is guaranteed to be paired with exactly one key
|
// every key down event is guaranteed to be paired with exactly one key
|
||||||
// up event. This is the reason a list of modifier keys held down at the
|
// up event. This is the reason a list of modifier keys held down at the
|
||||||
// time of the key press is given.
|
// time of the key press is given.
|
||||||
HandleKeyDown (key Key, modifiers Modifiers)
|
HandleKeyDown (key input.Key, modifiers input.Modifiers)
|
||||||
|
|
||||||
// HandleKeyUp is called when a key is released while this element has
|
// HandleKeyUp is called when a key is released while this element has
|
||||||
// keyboard focus.
|
// keyboard focus.
|
||||||
HandleKeyUp (key Key, modifiers Modifiers)
|
HandleKeyUp (key input.Key, modifiers input.Modifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MouseTarget represents an element that can receive mouse events.
|
// MouseTarget represents an element that can receive mouse events.
|
||||||
@ -111,11 +93,11 @@ type MouseTarget interface {
|
|||||||
|
|
||||||
// HandleMouseDown is called when a mouse button is pressed down on this
|
// HandleMouseDown is called when a mouse button is pressed down on this
|
||||||
// element.
|
// element.
|
||||||
HandleMouseDown (x, y int, button Button)
|
HandleMouseDown (x, y int, button input.Button)
|
||||||
|
|
||||||
// HandleMouseUp is called when a mouse button is released that was
|
// HandleMouseUp is called when a mouse button is released that was
|
||||||
// originally pressed down on this element.
|
// originally pressed down on this element.
|
||||||
HandleMouseUp (x, y int, button Button)
|
HandleMouseUp (x, y int, button input.Button)
|
||||||
|
|
||||||
// HandleMouseMove is called when the mouse is moved over this element,
|
// HandleMouseMove is called when the mouse is moved over this element,
|
||||||
// or the mouse is moving while being held down and originally pressed
|
// or the mouse is moving while being held down and originally pressed
|
@ -2,7 +2,7 @@ package testing
|
|||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "image/color"
|
import "image/color"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/core"
|
||||||
@ -44,12 +44,12 @@ func (element *Mouse) draw () {
|
|||||||
bounds.Min.Add(image.Pt(bounds.Dx() - 2, 1)))
|
bounds.Min.Add(image.Pt(bounds.Dx() - 2, 1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Mouse) HandleMouseDown (x, y int, button tomo.Button) {
|
func (element *Mouse) HandleMouseDown (x, y int, button input.Button) {
|
||||||
element.drawing = true
|
element.drawing = true
|
||||||
element.lastMousePos = image.Pt(x, y)
|
element.lastMousePos = image.Pt(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Mouse) HandleMouseUp (x, y int, button tomo.Button) {
|
func (element *Mouse) HandleMouseUp (x, y int, button input.Button) {
|
||||||
element.drawing = false
|
element.drawing = false
|
||||||
mousePos := image.Pt(x, y)
|
mousePos := image.Pt(x, y)
|
||||||
element.core.DamageRegion (artist.Line (
|
element.core.DamageRegion (artist.Line (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package tomo
|
package elements
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
|
|
@ -11,7 +11,7 @@ func main () {
|
|||||||
func run () {
|
func run () {
|
||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("example button")
|
window.SetTitle("example button")
|
||||||
button := basic.NewButton("hello tomo!")
|
button := basicElements.NewButton("hello tomo!")
|
||||||
button.OnClick (func () {
|
button.OnClick (func () {
|
||||||
// when we set the button's text to something longer, the window
|
// when we set the button's text to something longer, the window
|
||||||
// will automatically resize to accomodate it.
|
// will automatically resize to accomodate it.
|
||||||
|
@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/popups"
|
import "git.tebibyte.media/sashakoshka/tomo/popups"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -14,22 +14,22 @@ func run () {
|
|||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("Checkboxes")
|
window.SetTitle("Checkboxes")
|
||||||
|
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
container.Adopt (basic.NewLabel (
|
container.Adopt (basicElements.NewLabel (
|
||||||
"We advise you to not read thPlease listen to me. I am " +
|
"We advise you to not read thPlease listen to me. I am " +
|
||||||
"trapped inside the example code. This is the only way for " +
|
"trapped inside the example code. This is the only way for " +
|
||||||
"me to communicate.", true), true)
|
"me to communicate.", true), true)
|
||||||
container.Adopt(basic.NewSpacer(true), false)
|
container.Adopt(basicElements.NewSpacer(true), false)
|
||||||
container.Adopt(basic.NewCheckbox("Oh god", false), false)
|
container.Adopt(basicElements.NewCheckbox("Oh god", false), false)
|
||||||
container.Adopt(basic.NewCheckbox("Can you hear them", true), false)
|
container.Adopt(basicElements.NewCheckbox("Can you hear them", true), false)
|
||||||
container.Adopt(basic.NewCheckbox("They are in the walls", false), false)
|
container.Adopt(basicElements.NewCheckbox("They are in the walls", false), false)
|
||||||
container.Adopt(basic.NewCheckbox("They are coming for us", false), false)
|
container.Adopt(basicElements.NewCheckbox("They are coming for us", false), false)
|
||||||
disabledCheckbox := basic.NewCheckbox("We are but their helpless prey", false)
|
disabledCheckbox := basicElements.NewCheckbox("We are but their helpless prey", false)
|
||||||
disabledCheckbox.SetEnabled(false)
|
disabledCheckbox.SetEnabled(false)
|
||||||
container.Adopt(disabledCheckbox, false)
|
container.Adopt(disabledCheckbox, false)
|
||||||
vsync := basic.NewCheckbox("Enable vsync", false)
|
vsync := basicElements.NewCheckbox("Enable vsync", false)
|
||||||
vsync.OnToggle (func () {
|
vsync.OnToggle (func () {
|
||||||
if vsync.Value() {
|
if vsync.Value() {
|
||||||
popups.NewDialog (
|
popups.NewDialog (
|
||||||
@ -39,7 +39,7 @@ func run () {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
container.Adopt(vsync, false)
|
container.Adopt(vsync, false)
|
||||||
button := basic.NewButton("What")
|
button := basicElements.NewButton("What")
|
||||||
button.OnClick(tomo.Stop)
|
button.OnClick(tomo.Stop)
|
||||||
container.Adopt(button, false)
|
container.Adopt(button, false)
|
||||||
button.Focus()
|
button.Focus()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -13,14 +13,14 @@ func run () {
|
|||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("dialog")
|
window.SetTitle("dialog")
|
||||||
|
|
||||||
container := basic.NewContainer(layouts.Dialog { true, true })
|
container := basicElements.NewContainer(basicLayouts.Dialog { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
container.Adopt(basic.NewLabel("you will explode", true), true)
|
container.Adopt(basicElements.NewLabel("you will explode", true), true)
|
||||||
cancel := basic.NewButton("Cancel")
|
cancel := basicElements.NewButton("Cancel")
|
||||||
cancel.SetEnabled(false)
|
cancel.SetEnabled(false)
|
||||||
container.Adopt(cancel, false)
|
container.Adopt(cancel, false)
|
||||||
okButton := basic.NewButton("OK")
|
okButton := basicElements.NewButton("OK")
|
||||||
container.Adopt(okButton, false)
|
container.Adopt(okButton, false)
|
||||||
okButton.Focus()
|
okButton.Focus()
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/flow"
|
import "git.tebibyte.media/sashakoshka/tomo/flow"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -13,21 +13,21 @@ func main () {
|
|||||||
func run () {
|
func run () {
|
||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("adventure")
|
window.SetTitle("adventure")
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
var world flow.Flow
|
var world flow.Flow
|
||||||
world.Transition = container.DisownAll
|
world.Transition = container.DisownAll
|
||||||
world.Stages = map [string] func () {
|
world.Stages = map [string] func () {
|
||||||
"start": func () {
|
"start": func () {
|
||||||
label := basic.NewLabel (
|
label := basicElements.NewLabel (
|
||||||
"you are standing next to a river.", true)
|
"you are standing next to a river.", true)
|
||||||
|
|
||||||
button0 := basic.NewButton("go in the river")
|
button0 := basicElements.NewButton("go in the river")
|
||||||
button0.OnClick(world.SwitchFunc("wet"))
|
button0.OnClick(world.SwitchFunc("wet"))
|
||||||
button1 := basic.NewButton("walk along the river")
|
button1 := basicElements.NewButton("walk along the river")
|
||||||
button1.OnClick(world.SwitchFunc("house"))
|
button1.OnClick(world.SwitchFunc("house"))
|
||||||
button2 := basic.NewButton("turn around")
|
button2 := basicElements.NewButton("turn around")
|
||||||
button2.OnClick(world.SwitchFunc("bear"))
|
button2.OnClick(world.SwitchFunc("bear"))
|
||||||
|
|
||||||
container.Warp ( func () {
|
container.Warp ( func () {
|
||||||
@ -39,13 +39,13 @@ func run () {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
"wet": func () {
|
"wet": func () {
|
||||||
label := basic.NewLabel (
|
label := basicElements.NewLabel (
|
||||||
"you get completely soaked.\n" +
|
"you get completely soaked.\n" +
|
||||||
"you die of hypothermia.", true)
|
"you die of hypothermia.", true)
|
||||||
|
|
||||||
button0 := basic.NewButton("try again")
|
button0 := basicElements.NewButton("try again")
|
||||||
button0.OnClick(world.SwitchFunc("start"))
|
button0.OnClick(world.SwitchFunc("start"))
|
||||||
button1 := basic.NewButton("exit")
|
button1 := basicElements.NewButton("exit")
|
||||||
button1.OnClick(tomo.Stop)
|
button1.OnClick(tomo.Stop)
|
||||||
|
|
||||||
container.Warp (func () {
|
container.Warp (func () {
|
||||||
@ -56,13 +56,13 @@ func run () {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
"house": func () {
|
"house": func () {
|
||||||
label := basic.NewLabel (
|
label := basicElements.NewLabel (
|
||||||
"you are standing in front of a delapidated " +
|
"you are standing in front of a delapidated " +
|
||||||
"house.", true)
|
"house.", true)
|
||||||
|
|
||||||
button1 := basic.NewButton("go inside")
|
button1 := basicElements.NewButton("go inside")
|
||||||
button1.OnClick(world.SwitchFunc("inside"))
|
button1.OnClick(world.SwitchFunc("inside"))
|
||||||
button0 := basic.NewButton("turn back")
|
button0 := basicElements.NewButton("turn back")
|
||||||
button0.OnClick(world.SwitchFunc("start"))
|
button0.OnClick(world.SwitchFunc("start"))
|
||||||
|
|
||||||
container.Warp (func () {
|
container.Warp (func () {
|
||||||
@ -73,14 +73,14 @@ func run () {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
"inside": func () {
|
"inside": func () {
|
||||||
label := basic.NewLabel (
|
label := basicElements.NewLabel (
|
||||||
"you are standing inside of the house.\n" +
|
"you are standing inside of the house.\n" +
|
||||||
"it is dark, but rays of light stream " +
|
"it is dark, but rays of light stream " +
|
||||||
"through the window.\n" +
|
"through the window.\n" +
|
||||||
"there is nothing particularly interesting " +
|
"there is nothing particularly interesting " +
|
||||||
"here.", true)
|
"here.", true)
|
||||||
|
|
||||||
button0 := basic.NewButton("go back outside")
|
button0 := basicElements.NewButton("go back outside")
|
||||||
button0.OnClick(world.SwitchFunc("house"))
|
button0.OnClick(world.SwitchFunc("house"))
|
||||||
|
|
||||||
container.Warp (func () {
|
container.Warp (func () {
|
||||||
@ -90,13 +90,13 @@ func run () {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
"bear": func () {
|
"bear": func () {
|
||||||
label := basic.NewLabel (
|
label := basicElements.NewLabel (
|
||||||
"you come face to face with a bear.\n" +
|
"you come face to face with a bear.\n" +
|
||||||
"it eats you (it was hungry).", true)
|
"it eats you (it was hungry).", true)
|
||||||
|
|
||||||
button0 := basic.NewButton("try again")
|
button0 := basicElements.NewButton("try again")
|
||||||
button0.OnClick(world.SwitchFunc("start"))
|
button0.OnClick(world.SwitchFunc("start"))
|
||||||
button1 := basic.NewButton("exit")
|
button1 := basicElements.NewButton("exit")
|
||||||
button1.OnClick(tomo.Stop)
|
button1.OnClick(tomo.Stop)
|
||||||
|
|
||||||
container.Warp (func () {
|
container.Warp (func () {
|
||||||
|
@ -3,7 +3,7 @@ package main
|
|||||||
import "os"
|
import "os"
|
||||||
import "time"
|
import "time"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/fun"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/fun"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
@ -16,12 +16,12 @@ func main () {
|
|||||||
func run () {
|
func run () {
|
||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("clock")
|
window.SetTitle("clock")
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
clock := fun.NewAnalogClock(time.Now())
|
clock := fun.NewAnalogClock(time.Now())
|
||||||
container.Adopt(clock, true)
|
container.Adopt(clock, true)
|
||||||
label := basic.NewLabel(formatTime(), false)
|
label := basicElements.NewLabel(formatTime(), false)
|
||||||
container.Adopt(label, false)
|
container.Adopt(label, false)
|
||||||
|
|
||||||
window.OnClose(tomo.Stop)
|
window.OnClose(tomo.Stop)
|
||||||
@ -33,7 +33,7 @@ func formatTime () (timeString string) {
|
|||||||
return time.Now().Format("2006-01-02 15:04:05")
|
return time.Now().Format("2006-01-02 15:04:05")
|
||||||
}
|
}
|
||||||
|
|
||||||
func tick (label *basic.Label, clock *fun.AnalogClock) {
|
func tick (label *basicElements.Label, clock *fun.AnalogClock) {
|
||||||
for {
|
for {
|
||||||
tomo.Do (func () {
|
tomo.Do (func () {
|
||||||
label.SetText(formatTime())
|
label.SetText(formatTime())
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -13,12 +13,12 @@ func run () {
|
|||||||
window, _ := tomo.NewWindow(360, 2)
|
window, _ := tomo.NewWindow(360, 2)
|
||||||
window.SetTitle("horizontal stack")
|
window.SetTitle("horizontal stack")
|
||||||
|
|
||||||
container := basic.NewContainer(layouts.Horizontal { true, true })
|
container := basicElements.NewContainer(basicLayouts.Horizontal { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
container.Adopt(basic.NewLabel("this is sample text", true), true)
|
container.Adopt(basicElements.NewLabel("this is sample text", true), true)
|
||||||
container.Adopt(basic.NewLabel("this is sample text", true), true)
|
container.Adopt(basicElements.NewLabel("this is sample text", true), true)
|
||||||
container.Adopt(basic.NewLabel("this is sample text", true), true)
|
container.Adopt(basicElements.NewLabel("this is sample text", true), true)
|
||||||
|
|
||||||
window.OnClose(tomo.Stop)
|
window.OnClose(tomo.Stop)
|
||||||
window.Show()
|
window.Show()
|
||||||
|
@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/popups"
|
import "git.tebibyte.media/sashakoshka/tomo/popups"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -13,14 +13,14 @@ func main () {
|
|||||||
func run () {
|
func run () {
|
||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("Enter Details")
|
window.SetTitle("Enter Details")
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
// create inputs
|
// create inputs
|
||||||
firstName := basic.NewTextBox("First name", "")
|
firstName := basicElements.NewTextBox("First name", "")
|
||||||
lastName := basic.NewTextBox("Last name", "")
|
lastName := basicElements.NewTextBox("Last name", "")
|
||||||
fingerLength := basic.NewTextBox("Length of fingers", "")
|
fingerLength := basicElements.NewTextBox("Length of fingers", "")
|
||||||
button := basic.NewButton("Ok")
|
button := basicElements.NewButton("Ok")
|
||||||
|
|
||||||
button.SetEnabled(false)
|
button.SetEnabled(false)
|
||||||
button.OnClick (func () {
|
button.OnClick (func () {
|
||||||
@ -45,11 +45,11 @@ func run () {
|
|||||||
fingerLength.OnChange(check)
|
fingerLength.OnChange(check)
|
||||||
|
|
||||||
// add elements to container
|
// add elements to container
|
||||||
container.Adopt(basic.NewLabel("Choose your words carefully.", false), true)
|
container.Adopt(basicElements.NewLabel("Choose your words carefully.", false), true)
|
||||||
container.Adopt(firstName, false)
|
container.Adopt(firstName, false)
|
||||||
container.Adopt(lastName, false)
|
container.Adopt(lastName, false)
|
||||||
container.Adopt(fingerLength, false)
|
container.Adopt(fingerLength, false)
|
||||||
container.Adopt(basic.NewSpacer(true), false)
|
container.Adopt(basicElements.NewSpacer(true), false)
|
||||||
container.Adopt(button, false)
|
container.Adopt(button, false)
|
||||||
|
|
||||||
window.OnClose(tomo.Stop)
|
window.OnClose(tomo.Stop)
|
||||||
|
@ -11,7 +11,7 @@ func main () {
|
|||||||
func run () {
|
func run () {
|
||||||
window, _ := tomo.NewWindow(480, 2)
|
window, _ := tomo.NewWindow(480, 2)
|
||||||
window.SetTitle("example label")
|
window.SetTitle("example label")
|
||||||
window.Adopt(basic.NewLabel(text, true))
|
window.Adopt(basicElements.NewLabel(text, true))
|
||||||
window.OnClose(tomo.Stop)
|
window.OnClose(tomo.Stop)
|
||||||
window.Show()
|
window.Show()
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ package main
|
|||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/popups"
|
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/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/testing"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/testing"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
@ -15,11 +16,11 @@ func run () {
|
|||||||
window, _ := tomo.NewWindow(300, 2)
|
window, _ := tomo.NewWindow(300, 2)
|
||||||
window.SetTitle("List Sidebar")
|
window.SetTitle("List Sidebar")
|
||||||
|
|
||||||
container := basic.NewContainer(layouts.Horizontal { true, true })
|
container := basicElements.NewContainer(basicLayouts.Horizontal { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
var currentPage tomo.Element
|
var currentPage elements.Element
|
||||||
turnPage := func (newPage tomo.Element) {
|
turnPage := func (newPage elements.Element) {
|
||||||
container.Warp (func () {
|
container.Warp (func () {
|
||||||
if currentPage != nil {
|
if currentPage != nil {
|
||||||
container.Disown(currentPage)
|
container.Disown(currentPage)
|
||||||
@ -29,27 +30,27 @@ func run () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
intro := basic.NewLabel (
|
intro := basicElements.NewLabel (
|
||||||
"The List element can be easily used as a sidebar. " +
|
"The List element can be easily used as a sidebar. " +
|
||||||
"Click on entries to flip pages!", true)
|
"Click on entries to flip pages!", true)
|
||||||
button := basic.NewButton("I do nothing!")
|
button := basicElements.NewButton("I do nothing!")
|
||||||
button.OnClick (func () {
|
button.OnClick (func () {
|
||||||
popups.NewDialog(popups.DialogKindInfo, "", "Sike!")
|
popups.NewDialog(popups.DialogKindInfo, "", "Sike!")
|
||||||
})
|
})
|
||||||
mouse := testing.NewMouse()
|
mouse := testing.NewMouse()
|
||||||
input := basic.NewTextBox("Write some text", "")
|
input := basicElements.NewTextBox("Write some text", "")
|
||||||
form := basic.NewContainer(layouts.Vertical { true, false})
|
form := basicElements.NewContainer(basicLayouts.Vertical { true, false})
|
||||||
form.Adopt(basic.NewLabel("I have:", false), false)
|
form.Adopt(basicElements.NewLabel("I have:", false), false)
|
||||||
form.Adopt(basic.NewSpacer(true), false)
|
form.Adopt(basicElements.NewSpacer(true), false)
|
||||||
form.Adopt(basic.NewCheckbox("Skin", true), false)
|
form.Adopt(basicElements.NewCheckbox("Skin", true), false)
|
||||||
form.Adopt(basic.NewCheckbox("Blood", false), false)
|
form.Adopt(basicElements.NewCheckbox("Blood", false), false)
|
||||||
form.Adopt(basic.NewCheckbox("Bone", false), false)
|
form.Adopt(basicElements.NewCheckbox("Bone", false), false)
|
||||||
|
|
||||||
list := basic.NewList (
|
list := basicElements.NewList (
|
||||||
basic.NewListEntry("button", func () { turnPage(button) }),
|
basicElements.NewListEntry("button", func () { turnPage(button) }),
|
||||||
basic.NewListEntry("mouse", func () { turnPage(mouse) }),
|
basicElements.NewListEntry("mouse", func () { turnPage(mouse) }),
|
||||||
basic.NewListEntry("input", func () { turnPage(input) }),
|
basicElements.NewListEntry("input", func () { turnPage(input) }),
|
||||||
basic.NewListEntry("form", func () { turnPage(form) }))
|
basicElements.NewListEntry("form", func () { turnPage(form) }))
|
||||||
list.OnNoEntrySelected(func () { turnPage (intro) })
|
list.OnNoEntrySelected(func () { turnPage (intro) })
|
||||||
list.Collapse(96, 0)
|
list.Collapse(96, 0)
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ package main
|
|||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/popups"
|
import "git.tebibyte.media/sashakoshka/tomo/popups"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -14,12 +14,12 @@ func run () {
|
|||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("Dialog Boxes")
|
window.SetTitle("Dialog Boxes")
|
||||||
|
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
container.Adopt(basic.NewLabel("Try out different dialogs:", false), true)
|
container.Adopt(basicElements.NewLabel("Try out different dialogs:", false), true)
|
||||||
|
|
||||||
infoButton := basic.NewButton("popups.DialogKindInfo")
|
infoButton := basicElements.NewButton("popups.DialogKindInfo")
|
||||||
infoButton.OnClick (func () {
|
infoButton.OnClick (func () {
|
||||||
popups.NewDialog (
|
popups.NewDialog (
|
||||||
popups.DialogKindInfo,
|
popups.DialogKindInfo,
|
||||||
@ -29,7 +29,7 @@ func run () {
|
|||||||
container.Adopt(infoButton, false)
|
container.Adopt(infoButton, false)
|
||||||
infoButton.Focus()
|
infoButton.Focus()
|
||||||
|
|
||||||
questionButton := basic.NewButton("popups.DialogKindQuestion")
|
questionButton := basicElements.NewButton("popups.DialogKindQuestion")
|
||||||
questionButton.OnClick (func () {
|
questionButton.OnClick (func () {
|
||||||
popups.NewDialog (
|
popups.NewDialog (
|
||||||
popups.DialogKindQuestion,
|
popups.DialogKindQuestion,
|
||||||
@ -41,7 +41,7 @@ func run () {
|
|||||||
})
|
})
|
||||||
container.Adopt(questionButton, false)
|
container.Adopt(questionButton, false)
|
||||||
|
|
||||||
warningButton := basic.NewButton("popups.DialogKindWarning")
|
warningButton := basicElements.NewButton("popups.DialogKindWarning")
|
||||||
warningButton.OnClick (func () {
|
warningButton.OnClick (func () {
|
||||||
popups.NewDialog (
|
popups.NewDialog (
|
||||||
popups.DialogKindQuestion,
|
popups.DialogKindQuestion,
|
||||||
@ -50,7 +50,7 @@ func run () {
|
|||||||
})
|
})
|
||||||
container.Adopt(warningButton, false)
|
container.Adopt(warningButton, false)
|
||||||
|
|
||||||
errorButton := basic.NewButton("popups.DialogKindError")
|
errorButton := basicElements.NewButton("popups.DialogKindError")
|
||||||
errorButton.OnClick (func () {
|
errorButton.OnClick (func () {
|
||||||
popups.NewDialog (
|
popups.NewDialog (
|
||||||
popups.DialogKindQuestion,
|
popups.DialogKindQuestion,
|
||||||
@ -59,7 +59,7 @@ func run () {
|
|||||||
})
|
})
|
||||||
container.Adopt(errorButton, false)
|
container.Adopt(errorButton, false)
|
||||||
|
|
||||||
cancelButton := basic.NewButton("No thank you.")
|
cancelButton := basicElements.NewButton("No thank you.")
|
||||||
cancelButton.OnClick(tomo.Stop)
|
cancelButton.OnClick(tomo.Stop)
|
||||||
container.Adopt(cancelButton, false)
|
container.Adopt(cancelButton, false)
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ package main
|
|||||||
import "time"
|
import "time"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/popups"
|
import "git.tebibyte.media/sashakoshka/tomo/popups"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -14,14 +14,14 @@ func main () {
|
|||||||
func run () {
|
func run () {
|
||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("Approaching")
|
window.SetTitle("Approaching")
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
container.Adopt (basic.NewLabel (
|
container.Adopt (basicElements.NewLabel (
|
||||||
"Rapidly approaching your location...", false), false)
|
"Rapidly approaching your location...", false), false)
|
||||||
bar := basic.NewProgressBar(0)
|
bar := basicElements.NewProgressBar(0)
|
||||||
container.Adopt(bar, false)
|
container.Adopt(bar, false)
|
||||||
button := basic.NewButton("Stop")
|
button := basicElements.NewButton("Stop")
|
||||||
button.SetEnabled(false)
|
button.SetEnabled(false)
|
||||||
container.Adopt(button, false)
|
container.Adopt(button, false)
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ func run () {
|
|||||||
go fill(bar)
|
go fill(bar)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fill (bar *basic.ProgressBar) {
|
func fill (bar *basicElements.ProgressBar) {
|
||||||
for progress := 0.0; progress < 1.0; progress += 0.01 {
|
for progress := 0.0; progress < 1.0; progress += 0.01 {
|
||||||
time.Sleep(time.Second / 24)
|
time.Sleep(time.Second / 24)
|
||||||
tomo.Do (func () {
|
tomo.Do (func () {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -12,13 +12,13 @@ func main () {
|
|||||||
func run () {
|
func run () {
|
||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("Scroll")
|
window.SetTitle("Scroll")
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
container.Adopt(basic.NewLabel("look at this non sense", false), false)
|
container.Adopt(basicElements.NewLabel("look at this non sense", false), false)
|
||||||
|
|
||||||
textBox := basic.NewTextBox("", "sample text sample text")
|
textBox := basicElements.NewTextBox("", "sample text sample text")
|
||||||
scrollContainer := basic.NewScrollContainer(true, false)
|
scrollContainer := basicElements.NewScrollContainer(true, false)
|
||||||
scrollContainer.Adopt(textBox)
|
scrollContainer.Adopt(textBox)
|
||||||
container.Adopt(scrollContainer, true)
|
container.Adopt(scrollContainer, true)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -13,14 +13,14 @@ func run () {
|
|||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("Spaced Out")
|
window.SetTitle("Spaced Out")
|
||||||
|
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
container.Adopt (basic.NewLabel("This is at the top", false), false)
|
container.Adopt (basicElements.NewLabel("This is at the top", false), false)
|
||||||
container.Adopt (basic.NewSpacer(true), false)
|
container.Adopt (basicElements.NewSpacer(true), false)
|
||||||
container.Adopt (basic.NewLabel("This is in the middle", false), false)
|
container.Adopt (basicElements.NewLabel("This is in the middle", false), false)
|
||||||
container.Adopt (basic.NewSpacer(false), true)
|
container.Adopt (basicElements.NewSpacer(false), true)
|
||||||
container.Adopt (basic.NewLabel("This is at the bottom", false), false)
|
container.Adopt (basicElements.NewLabel("This is at the bottom", false), false)
|
||||||
|
|
||||||
window.OnClose(tomo.Stop)
|
window.OnClose(tomo.Stop)
|
||||||
window.Show()
|
window.Show()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
|
|
||||||
@ -13,12 +13,12 @@ func run () {
|
|||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("Switches")
|
window.SetTitle("Switches")
|
||||||
|
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
container.Adopt(basic.NewSwitch("hahahah", false), false)
|
container.Adopt(basicElements.NewSwitch("hahahah", false), false)
|
||||||
container.Adopt(basic.NewSwitch("hehehehheheh", false), false)
|
container.Adopt(basicElements.NewSwitch("hehehehheheh", false), false)
|
||||||
container.Adopt(basic.NewSwitch("you can flick da swicth", false), false)
|
container.Adopt(basicElements.NewSwitch("you can flick da swicth", false), false)
|
||||||
|
|
||||||
window.OnClose(tomo.Stop)
|
window.OnClose(tomo.Stop)
|
||||||
window.Show()
|
window.Show()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/basic"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/elements/testing"
|
import "git.tebibyte.media/sashakoshka/tomo/elements/testing"
|
||||||
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
import _ "git.tebibyte.media/sashakoshka/tomo/backends/x"
|
||||||
@ -14,15 +14,15 @@ func run () {
|
|||||||
window, _ := tomo.NewWindow(2, 2)
|
window, _ := tomo.NewWindow(2, 2)
|
||||||
window.SetTitle("vertical stack")
|
window.SetTitle("vertical stack")
|
||||||
|
|
||||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
container := basicElements.NewContainer(basicLayouts.Vertical { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
label := basic.NewLabel("it is a label hehe", true)
|
label := basicElements.NewLabel("it is a label hehe", true)
|
||||||
button := basic.NewButton("drawing pad")
|
button := basicElements.NewButton("drawing pad")
|
||||||
okButton := basic.NewButton("OK")
|
okButton := basicElements.NewButton("OK")
|
||||||
button.OnClick (func () {
|
button.OnClick (func () {
|
||||||
container.DisownAll()
|
container.DisownAll()
|
||||||
container.Adopt(basic.NewLabel("Draw here:", false), false)
|
container.Adopt(basicElements.NewLabel("Draw here:", false), false)
|
||||||
container.Adopt(testing.NewMouse(), true)
|
container.Adopt(testing.NewMouse(), true)
|
||||||
container.Adopt(okButton, false)
|
container.Adopt(okButton, false)
|
||||||
okButton.Focus()
|
okButton.Focus()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package tomo
|
package input
|
||||||
|
|
||||||
import "unicode"
|
import "unicode"
|
||||||
|
|
||||||
@ -110,3 +110,22 @@ type Modifiers struct {
|
|||||||
NumberPad bool
|
NumberPad bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KeynavDirection represents a keyboard navigation direction.
|
||||||
|
type KeynavDirection int
|
||||||
|
|
||||||
|
const (
|
||||||
|
KeynavDirectionNeutral KeynavDirection = 0
|
||||||
|
KeynavDirectionBackward KeynavDirection = -1
|
||||||
|
KeynavDirectionForward KeynavDirection = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Canon returns a well-formed direction.
|
||||||
|
func (direction KeynavDirection) Canon () (canon KeynavDirection) {
|
||||||
|
if direction > 0 {
|
||||||
|
return KeynavDirectionForward
|
||||||
|
} else if direction == 0 {
|
||||||
|
return KeynavDirectionNeutral
|
||||||
|
} else {
|
||||||
|
return KeynavDirectionBackward
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
package layouts
|
package basicLayouts
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||||
|
|
||||||
// Dialog arranges elements in the form of a dialog box. The first element is
|
// 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
|
// positioned above as the main focus of the dialog, and is set to expand
|
||||||
@ -19,13 +19,18 @@ type Dialog struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Arrange arranges a list of entries into a dialog.
|
// Arrange arranges a list of entries into a dialog.
|
||||||
func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle) {
|
func (layout Dialog) Arrange (
|
||||||
if layout.Pad { bounds = bounds.Inset(theme.Margin()) }
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
|
bounds image.Rectangle,
|
||||||
|
) {
|
||||||
|
if layout.Pad { bounds = bounds.Inset(margin) }
|
||||||
|
|
||||||
controlRowWidth, controlRowHeight := 0, 0
|
controlRowWidth, controlRowHeight := 0, 0
|
||||||
if len(entries) > 1 {
|
if len(entries) > 1 {
|
||||||
controlRowWidth,
|
controlRowWidth,
|
||||||
controlRowHeight = layout.minimumSizeOfControlRow(entries[1:])
|
controlRowHeight = layout.minimumSizeOfControlRow (
|
||||||
|
entries[1:], margin)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(entries) > 0 {
|
if len(entries) > 0 {
|
||||||
@ -33,7 +38,7 @@ func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle
|
|||||||
main.Bounds.Min = bounds.Min
|
main.Bounds.Min = bounds.Min
|
||||||
mainHeight := bounds.Dy() - controlRowHeight
|
mainHeight := bounds.Dy() - controlRowHeight
|
||||||
if layout.Gap {
|
if layout.Gap {
|
||||||
mainHeight -= theme.Margin()
|
mainHeight -= margin
|
||||||
}
|
}
|
||||||
main.Bounds.Max = main.Bounds.Min.Add(image.Pt(bounds.Dx(), mainHeight))
|
main.Bounds.Max = main.Bounds.Min.Add(image.Pt(bounds.Dx(), mainHeight))
|
||||||
entries[0] = main
|
entries[0] = main
|
||||||
@ -53,7 +58,7 @@ func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle
|
|||||||
freeSpace -= entryMinWidth
|
freeSpace -= entryMinWidth
|
||||||
}
|
}
|
||||||
if index > 0 && layout.Gap {
|
if index > 0 && layout.Gap {
|
||||||
freeSpace -= theme.Margin()
|
freeSpace -= margin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expandingElementWidth := 0
|
expandingElementWidth := 0
|
||||||
@ -69,7 +74,7 @@ func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle
|
|||||||
|
|
||||||
// set the size and position of each element in the control row
|
// set the size and position of each element in the control row
|
||||||
for index, entry := range entries[1:] {
|
for index, entry := range entries[1:] {
|
||||||
if index > 0 && layout.Gap { dot.X += theme.Margin() }
|
if index > 0 && layout.Gap { dot.X += margin }
|
||||||
|
|
||||||
entry.Bounds.Min = dot
|
entry.Bounds.Min = dot
|
||||||
entryWidth := 0
|
entryWidth := 0
|
||||||
@ -95,7 +100,8 @@ func (layout Dialog) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle
|
|||||||
// MinimumSize returns the minimum width and height that will be needed to
|
// MinimumSize returns the minimum width and height that will be needed to
|
||||||
// arrange the given list of entries.
|
// arrange the given list of entries.
|
||||||
func (layout Dialog) MinimumSize (
|
func (layout Dialog) MinimumSize (
|
||||||
entries []tomo.LayoutEntry,
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
) (
|
) (
|
||||||
width, height int,
|
width, height int,
|
||||||
) {
|
) {
|
||||||
@ -106,9 +112,10 @@ func (layout Dialog) MinimumSize (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(entries) > 1 {
|
if len(entries) > 1 {
|
||||||
if layout.Gap { height += theme.Margin() }
|
if layout.Gap { height += margin }
|
||||||
additionalWidth,
|
additionalWidth,
|
||||||
additionalHeight := layout.minimumSizeOfControlRow(entries[1:])
|
additionalHeight := layout.minimumSizeOfControlRow (
|
||||||
|
entries[1:], margin)
|
||||||
height += additionalHeight
|
height += additionalHeight
|
||||||
if additionalWidth > width {
|
if additionalWidth > width {
|
||||||
width = additionalWidth
|
width = additionalWidth
|
||||||
@ -116,8 +123,8 @@ func (layout Dialog) MinimumSize (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if layout.Pad {
|
if layout.Pad {
|
||||||
width += theme.Margin() * 2
|
width += margin * 2
|
||||||
height += theme.Margin() * 2
|
height += margin * 2
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -125,18 +132,19 @@ func (layout Dialog) MinimumSize (
|
|||||||
// FlexibleHeightFor Returns the minimum height the layout needs to lay out the
|
// FlexibleHeightFor Returns the minimum height the layout needs to lay out the
|
||||||
// specified elements at the given width, taking into account flexible elements.
|
// specified elements at the given width, taking into account flexible elements.
|
||||||
func (layout Dialog) FlexibleHeightFor (
|
func (layout Dialog) FlexibleHeightFor (
|
||||||
entries []tomo.LayoutEntry,
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
width int,
|
width int,
|
||||||
) (
|
) (
|
||||||
height int,
|
height int,
|
||||||
) {
|
) {
|
||||||
if layout.Pad {
|
if layout.Pad {
|
||||||
width -= theme.Margin() * 2
|
width -= margin * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(entries) > 0 {
|
if len(entries) > 0 {
|
||||||
mainChildHeight := 0
|
mainChildHeight := 0
|
||||||
if child, flexible := entries[0].Element.(tomo.Flexible); flexible {
|
if child, flexible := entries[0].Element.(elements.Flexible); flexible {
|
||||||
mainChildHeight = child.FlexibleHeightFor(width)
|
mainChildHeight = child.FlexibleHeightFor(width)
|
||||||
} else {
|
} else {
|
||||||
_, mainChildHeight = entries[0].MinimumSize()
|
_, mainChildHeight = entries[0].MinimumSize()
|
||||||
@ -145,13 +153,14 @@ func (layout Dialog) FlexibleHeightFor (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(entries) > 1 {
|
if len(entries) > 1 {
|
||||||
if layout.Gap { height += theme.Margin() }
|
if layout.Gap { height += margin }
|
||||||
_, additionalHeight := layout.minimumSizeOfControlRow(entries[1:])
|
_, additionalHeight := layout.minimumSizeOfControlRow (
|
||||||
|
entries[1:], margin)
|
||||||
height += additionalHeight
|
height += additionalHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.Pad {
|
if layout.Pad {
|
||||||
height += theme.Margin() * 2
|
height += margin * 2
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -159,7 +168,8 @@ func (layout Dialog) FlexibleHeightFor (
|
|||||||
// TODO: possibly flatten this method to account for flexible elements within
|
// TODO: possibly flatten this method to account for flexible elements within
|
||||||
// the control row.
|
// the control row.
|
||||||
func (layout Dialog) minimumSizeOfControlRow (
|
func (layout Dialog) minimumSizeOfControlRow (
|
||||||
entries []tomo.LayoutEntry,
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
) (
|
) (
|
||||||
width, height int,
|
width, height int,
|
||||||
) {
|
) {
|
||||||
@ -170,7 +180,7 @@ func (layout Dialog) minimumSizeOfControlRow (
|
|||||||
}
|
}
|
||||||
width += entryWidth
|
width += entryWidth
|
||||||
if layout.Gap && index > 0 {
|
if layout.Gap && index > 0 {
|
||||||
width += theme.Margin()
|
width += margin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
@ -1,8 +1,8 @@
|
|||||||
package layouts
|
package basicLayouts
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||||
|
|
||||||
// Horizontal arranges elements horizontally. Elements at the start of the entry
|
// Horizontal arranges elements horizontally. Elements at the start of the entry
|
||||||
// list will be positioned on the left, and elements at the end of the entry
|
// list will be positioned on the left, and elements at the end of the entry
|
||||||
@ -17,16 +17,21 @@ type Horizontal struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Arrange arranges a list of entries horizontally.
|
// Arrange arranges a list of entries horizontally.
|
||||||
func (layout Horizontal) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle) {
|
func (layout Horizontal) Arrange (
|
||||||
if layout.Pad { bounds = bounds.Inset(theme.Margin()) }
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
|
bounds image.Rectangle,
|
||||||
|
) {
|
||||||
|
if layout.Pad { bounds = bounds.Inset(margin) }
|
||||||
|
|
||||||
// get width of expanding elements
|
// get width of expanding elements
|
||||||
expandingElementWidth := layout.expandingElementWidth(entries, bounds.Dx())
|
expandingElementWidth := layout.expandingElementWidth (
|
||||||
|
entries, margin, bounds.Dx())
|
||||||
|
|
||||||
// set the size and position of each element
|
// set the size and position of each element
|
||||||
dot := bounds.Min
|
dot := bounds.Min
|
||||||
for index, entry := range entries {
|
for index, entry := range entries {
|
||||||
if index > 0 && layout.Gap { dot.X += theme.Margin() }
|
if index > 0 && layout.Gap { dot.X += margin }
|
||||||
|
|
||||||
entry.Bounds.Min = dot
|
entry.Bounds.Min = dot
|
||||||
entryWidth := 0
|
entryWidth := 0
|
||||||
@ -45,7 +50,8 @@ func (layout Horizontal) Arrange (entries []tomo.LayoutEntry, bounds image.Recta
|
|||||||
// MinimumSize returns the minimum width and height that will be needed to
|
// MinimumSize returns the minimum width and height that will be needed to
|
||||||
// arrange the given list of entries.
|
// arrange the given list of entries.
|
||||||
func (layout Horizontal) MinimumSize (
|
func (layout Horizontal) MinimumSize (
|
||||||
entries []tomo.LayoutEntry,
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
) (
|
) (
|
||||||
width, height int,
|
width, height int,
|
||||||
) {
|
) {
|
||||||
@ -56,13 +62,13 @@ func (layout Horizontal) MinimumSize (
|
|||||||
}
|
}
|
||||||
width += entryWidth
|
width += entryWidth
|
||||||
if layout.Gap && index > 0 {
|
if layout.Gap && index > 0 {
|
||||||
width += theme.Margin()
|
width += margin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.Pad {
|
if layout.Pad {
|
||||||
width += theme.Margin() * 2
|
width += margin * 2
|
||||||
height += theme.Margin() * 2
|
height += margin * 2
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -70,21 +76,22 @@ func (layout Horizontal) MinimumSize (
|
|||||||
// FlexibleHeightFor Returns the minimum height the layout needs to lay out the
|
// FlexibleHeightFor Returns the minimum height the layout needs to lay out the
|
||||||
// specified elements at the given width, taking into account flexible elements.
|
// specified elements at the given width, taking into account flexible elements.
|
||||||
func (layout Horizontal) FlexibleHeightFor (
|
func (layout Horizontal) FlexibleHeightFor (
|
||||||
entries []tomo.LayoutEntry,
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
width int,
|
width int,
|
||||||
) (
|
) (
|
||||||
height int,
|
height int,
|
||||||
) {
|
) {
|
||||||
if layout.Pad {
|
if layout.Pad { width -= margin * 2 }
|
||||||
width -= theme.Margin() * 2
|
|
||||||
}
|
|
||||||
// get width of expanding elements
|
// get width of expanding elements
|
||||||
expandingElementWidth := layout.expandingElementWidth(entries, width)
|
expandingElementWidth := layout.expandingElementWidth (
|
||||||
|
entries, margin, width)
|
||||||
|
|
||||||
x, y := 0, 0
|
x, y := 0, 0
|
||||||
if layout.Pad {
|
if layout.Pad {
|
||||||
x += theme.Margin()
|
x += margin
|
||||||
y += theme.Margin()
|
y += margin
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the size and position of each element
|
// set the size and position of each element
|
||||||
@ -93,23 +100,24 @@ func (layout Horizontal) FlexibleHeightFor (
|
|||||||
if entry.Expand {
|
if entry.Expand {
|
||||||
entryWidth = expandingElementWidth
|
entryWidth = expandingElementWidth
|
||||||
}
|
}
|
||||||
if child, flexible := entry.Element.(tomo.Flexible); flexible {
|
if child, flexible := entry.Element.(elements.Flexible); flexible {
|
||||||
entryHeight = child.FlexibleHeightFor(entryWidth)
|
entryHeight = child.FlexibleHeightFor(entryWidth)
|
||||||
}
|
}
|
||||||
if entryHeight > height { height = entryHeight }
|
if entryHeight > height { height = entryHeight }
|
||||||
|
|
||||||
x += entryWidth
|
x += entryWidth
|
||||||
if index > 0 && layout.Gap { x += theme.Margin() }
|
if index > 0 && layout.Gap { x += margin }
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.Pad {
|
if layout.Pad {
|
||||||
height += theme.Margin() * 2
|
height += margin * 2
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (layout Horizontal) expandingElementWidth (
|
func (layout Horizontal) expandingElementWidth (
|
||||||
entries []tomo.LayoutEntry,
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
freeSpace int,
|
freeSpace int,
|
||||||
) (
|
) (
|
||||||
width int,
|
width int,
|
||||||
@ -126,7 +134,7 @@ func (layout Horizontal) expandingElementWidth (
|
|||||||
freeSpace -= entryMinWidth
|
freeSpace -= entryMinWidth
|
||||||
}
|
}
|
||||||
if index > 0 && layout.Gap {
|
if index > 0 && layout.Gap {
|
||||||
freeSpace -= theme.Margin()
|
freeSpace -= margin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
|||||||
package layouts
|
package basicLayouts
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo/layouts"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||||
|
|
||||||
// Vertical arranges elements vertically. Elements at the start of the entry
|
// Vertical arranges elements vertically. Elements at the start of the entry
|
||||||
// list will be positioned at the top, and elements at the end of the entry list
|
// list will be positioned at the top, and elements at the end of the entry list
|
||||||
@ -17,8 +17,12 @@ type Vertical struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Arrange arranges a list of entries vertically.
|
// Arrange arranges a list of entries vertically.
|
||||||
func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectangle) {
|
func (layout Vertical) Arrange (
|
||||||
if layout.Pad { bounds = bounds.Inset(theme.Margin()) }
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
|
bounds image.Rectangle,
|
||||||
|
) {
|
||||||
|
if layout.Pad { bounds = bounds.Inset(margin) }
|
||||||
|
|
||||||
// count the number of expanding elements and the amount of free space
|
// count the number of expanding elements and the amount of free space
|
||||||
// for them to collectively occupy, while gathering minimum heights.
|
// for them to collectively occupy, while gathering minimum heights.
|
||||||
@ -28,7 +32,7 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectang
|
|||||||
for index, entry := range entries {
|
for index, entry := range entries {
|
||||||
var entryMinHeight int
|
var entryMinHeight int
|
||||||
|
|
||||||
if child, flexible := entry.Element.(tomo.Flexible); flexible {
|
if child, flexible := entry.Element.(elements.Flexible); flexible {
|
||||||
entryMinHeight = child.FlexibleHeightFor(bounds.Dx())
|
entryMinHeight = child.FlexibleHeightFor(bounds.Dx())
|
||||||
} else {
|
} else {
|
||||||
_, entryMinHeight = entry.MinimumSize()
|
_, entryMinHeight = entry.MinimumSize()
|
||||||
@ -41,7 +45,7 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectang
|
|||||||
freeSpace -= entryMinHeight
|
freeSpace -= entryMinHeight
|
||||||
}
|
}
|
||||||
if index > 0 && layout.Gap {
|
if index > 0 && layout.Gap {
|
||||||
freeSpace -= theme.Margin()
|
freeSpace -= margin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +57,7 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectang
|
|||||||
// set the size and position of each element
|
// set the size and position of each element
|
||||||
dot := bounds.Min
|
dot := bounds.Min
|
||||||
for index, entry := range entries {
|
for index, entry := range entries {
|
||||||
if index > 0 && layout.Gap { dot.Y += theme.Margin() }
|
if index > 0 && layout.Gap { dot.Y += margin }
|
||||||
|
|
||||||
entry.Bounds.Min = dot
|
entry.Bounds.Min = dot
|
||||||
entryHeight := 0
|
entryHeight := 0
|
||||||
@ -72,7 +76,8 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, bounds image.Rectang
|
|||||||
// MinimumSize returns the minimum width and height that will be needed to
|
// MinimumSize returns the minimum width and height that will be needed to
|
||||||
// arrange the given list of entries.
|
// arrange the given list of entries.
|
||||||
func (layout Vertical) MinimumSize (
|
func (layout Vertical) MinimumSize (
|
||||||
entries []tomo.LayoutEntry,
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
) (
|
) (
|
||||||
width, height int,
|
width, height int,
|
||||||
) {
|
) {
|
||||||
@ -83,13 +88,13 @@ func (layout Vertical) MinimumSize (
|
|||||||
}
|
}
|
||||||
height += entryHeight
|
height += entryHeight
|
||||||
if layout.Gap && index > 0 {
|
if layout.Gap && index > 0 {
|
||||||
height += theme.Margin()
|
height += margin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.Pad {
|
if layout.Pad {
|
||||||
width += theme.Margin() * 2
|
width += margin * 2
|
||||||
height += theme.Margin() * 2
|
height += margin * 2
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -97,18 +102,19 @@ func (layout Vertical) MinimumSize (
|
|||||||
// FlexibleHeightFor Returns the minimum height the layout needs to lay out the
|
// FlexibleHeightFor Returns the minimum height the layout needs to lay out the
|
||||||
// specified elements at the given width, taking into account flexible elements.
|
// specified elements at the given width, taking into account flexible elements.
|
||||||
func (layout Vertical) FlexibleHeightFor (
|
func (layout Vertical) FlexibleHeightFor (
|
||||||
entries []tomo.LayoutEntry,
|
entries []layouts.LayoutEntry,
|
||||||
|
margin int,
|
||||||
width int,
|
width int,
|
||||||
) (
|
) (
|
||||||
height int,
|
height int,
|
||||||
) {
|
) {
|
||||||
if layout.Pad {
|
if layout.Pad {
|
||||||
width -= theme.Margin() * 2
|
width -= margin * 2
|
||||||
height += theme.Margin() * 2
|
height += margin * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
for index, entry := range entries {
|
for index, entry := range entries {
|
||||||
child, flexible := entry.Element.(tomo.Flexible)
|
child, flexible := entry.Element.(elements.Flexible)
|
||||||
if flexible {
|
if flexible {
|
||||||
height += child.FlexibleHeightFor(width)
|
height += child.FlexibleHeightFor(width)
|
||||||
} else {
|
} else {
|
||||||
@ -117,7 +123,7 @@ func (layout Vertical) FlexibleHeightFor (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if layout.Gap && index > 0 {
|
if layout.Gap && index > 0 {
|
||||||
height += theme.Margin()
|
height += margin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
@ -1,11 +1,12 @@
|
|||||||
package tomo
|
package layouts
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||||
|
|
||||||
// LayoutEntry associates an element with layout and positioning information so
|
// LayoutEntry associates an element with layout and positioning information so
|
||||||
// it can be arranged by a Layout.
|
// it can be arranged by a Layout.
|
||||||
type LayoutEntry struct {
|
type LayoutEntry struct {
|
||||||
Element
|
elements.Element
|
||||||
Bounds image.Rectangle
|
Bounds image.Rectangle
|
||||||
Expand bool
|
Expand bool
|
||||||
}
|
}
|
||||||
@ -17,14 +18,20 @@ type Layout interface {
|
|||||||
// and changes the position of the entiries in the slice so that they
|
// and changes the position of the entiries in the slice so that they
|
||||||
// are properly laid out. The given width and height should not be less
|
// are properly laid out. The given width and height should not be less
|
||||||
// than what is returned by MinimumSize.
|
// than what is returned by MinimumSize.
|
||||||
Arrange (entries []LayoutEntry, bounds image.Rectangle)
|
Arrange (entries []LayoutEntry, margin int, bounds image.Rectangle)
|
||||||
|
|
||||||
// MinimumSize returns the minimum width and height that the layout
|
// MinimumSize returns the minimum width and height that the layout
|
||||||
// needs to properly arrange the given slice of layout entries.
|
// needs to properly arrange the given slice of layout entries.
|
||||||
MinimumSize (entries []LayoutEntry) (width, height int)
|
MinimumSize (entries []LayoutEntry, margin int) (width, height int)
|
||||||
|
|
||||||
// FlexibleHeightFor Returns the minimum height the layout needs to lay
|
// FlexibleHeightFor Returns the minimum height the layout needs to lay
|
||||||
// out the specified elements at the given width, taking into account
|
// out the specified elements at the given width, taking into account
|
||||||
// flexible elements.
|
// flexible elements.
|
||||||
FlexibleHeightFor (entries []LayoutEntry, squeeze int) (height int)
|
FlexibleHeightFor (
|
||||||
|
entries []LayoutEntry,
|
||||||
|
margin int,
|
||||||
|
squeeze int,
|
||||||
|
) (
|
||||||
|
height int,
|
||||||
|
)
|
||||||
}
|
}
|
@ -1,7 +1,8 @@
|
|||||||
package popups
|
package popups
|
||||||
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
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/elements/basic"
|
||||||
|
|
||||||
// DialogKind defines the semantic role of a dialog window.
|
// DialogKind defines the semantic role of a dialog window.
|
||||||
@ -30,24 +31,24 @@ func NewDialog (
|
|||||||
title, message string,
|
title, message string,
|
||||||
buttons ...Button,
|
buttons ...Button,
|
||||||
) (
|
) (
|
||||||
window tomo.Window,
|
window elements.Window,
|
||||||
) {
|
) {
|
||||||
window, _ = tomo.NewWindow(2, 2)
|
window, _ = tomo.NewWindow(2, 2)
|
||||||
window.SetTitle(title)
|
window.SetTitle(title)
|
||||||
|
|
||||||
container := basic.NewContainer(layouts.Dialog { true, true })
|
container := basicElements.NewContainer(basicLayouts.Dialog { true, true })
|
||||||
window.Adopt(container)
|
window.Adopt(container)
|
||||||
|
|
||||||
container.Adopt(basic.NewLabel(message, false), true)
|
container.Adopt(basicElements.NewLabel(message, false), true)
|
||||||
if len(buttons) == 0 {
|
if len(buttons) == 0 {
|
||||||
button := basic.NewButton("OK")
|
button := basicElements.NewButton("OK")
|
||||||
button.OnClick(window.Close)
|
button.OnClick(window.Close)
|
||||||
container.Adopt(button, false)
|
container.Adopt(button, false)
|
||||||
button.Focus()
|
button.Focus()
|
||||||
} else {
|
} else {
|
||||||
var button *basic.Button
|
var button *basicElements.Button
|
||||||
for _, buttonDescriptor := range buttons {
|
for _, buttonDescriptor := range buttons {
|
||||||
button = basic.NewButton(buttonDescriptor.Name)
|
button = basicElements.NewButton(buttonDescriptor.Name)
|
||||||
button.SetEnabled(buttonDescriptor.OnPress != nil)
|
button.SetEnabled(buttonDescriptor.OnPress != nil)
|
||||||
button.OnClick (func () {
|
button.OnClick (func () {
|
||||||
buttonDescriptor.OnPress()
|
buttonDescriptor.OnPress()
|
||||||
|
@ -111,24 +111,3 @@ func FontFaceItalic () font.Face {
|
|||||||
func FontFaceBoldItalic () font.Face {
|
func FontFaceBoldItalic () font.Face {
|
||||||
return defaultfont.FaceBoldItalic
|
return defaultfont.FaceBoldItalic
|
||||||
}
|
}
|
||||||
|
|
||||||
// Padding returns the amount of internal padding elements should have. An
|
|
||||||
// element's inner content (such as text) should be inset by this amount,
|
|
||||||
// in addition to the inset returned by the pattern of its background. When
|
|
||||||
// using the aforementioned inset values to calculate the element's minimum size
|
|
||||||
// or the position and alignment of its content, all parameters in the
|
|
||||||
// PatternState should be unset except for Case.
|
|
||||||
func Padding () int {
|
|
||||||
return 7
|
|
||||||
}
|
|
||||||
|
|
||||||
// Margin returns how much space should be put in between elements.
|
|
||||||
func Margin () int {
|
|
||||||
return 8
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleWidth returns how large grab handles should typically be. This is
|
|
||||||
// important for accessibility reasons.
|
|
||||||
func HandleWidth () int {
|
|
||||||
return 16
|
|
||||||
}
|
|
||||||
|
8
tomo.go
8
tomo.go
@ -1,6 +1,8 @@
|
|||||||
package tomo
|
package tomo
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/data"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||||
|
|
||||||
var backend Backend
|
var backend Backend
|
||||||
|
|
||||||
@ -32,7 +34,7 @@ func Do (callback func ()) {
|
|||||||
// Window. If the window could not be created, an error is returned explaining
|
// Window. If the window could not be created, an error is returned explaining
|
||||||
// why. If this function is called without a running backend, an error is
|
// why. If this function is called without a running backend, an error is
|
||||||
// returned as well.
|
// returned as well.
|
||||||
func NewWindow (width, height int) (window Window, err error) {
|
func NewWindow (width, height int) (window elements.Window, err error) {
|
||||||
if backend == nil {
|
if backend == nil {
|
||||||
err = errors.New("no backend is running.")
|
err = errors.New("no backend is running.")
|
||||||
return
|
return
|
||||||
@ -41,14 +43,14 @@ func NewWindow (width, height int) (window Window, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy puts data into the clipboard.
|
// Copy puts data into the clipboard.
|
||||||
func Copy (data Data) {
|
func Copy (data data.Data) {
|
||||||
if backend == nil { panic("no backend is running") }
|
if backend == nil { panic("no backend is running") }
|
||||||
backend.Copy(data)
|
backend.Copy(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paste returns the data currently in the clipboard. This method may
|
// Paste returns the data currently in the clipboard. This method may
|
||||||
// return nil.
|
// return nil.
|
||||||
func Paste (accept []Mime) (Data) {
|
func Paste (accept []data.Mime) (data.Data) {
|
||||||
if backend == nil { panic("no backend is running") }
|
if backend == nil { panic("no backend is running") }
|
||||||
return backend.Paste(accept)
|
return backend.Paste(accept)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user