Compare commits
18 Commits
v0.22.0
...
df2e8f1b07
| Author | SHA1 | Date | |
|---|---|---|---|
| df2e8f1b07 | |||
| 0c4e098680 | |||
| fc51e7ab9f | |||
| 4e8823ef9f | |||
| 8de08a9bdc | |||
| 04f44cea86 | |||
| c889838c9c | |||
| 7bcb4cf823 | |||
| 02516bdcce | |||
| 8432cc70da | |||
| 8469962c90 | |||
| 0ccdb609ef | |||
| d1f0786043 | |||
| 73731c6201 | |||
| 7c42b7ad37 | |||
| 0fe4979483 | |||
| 155752ba78 | |||
| f4a3cb3c00 |
60
button.go
60
button.go
@@ -5,13 +5,15 @@ import "git.tebibyte.media/tomo/tomo/input"
|
||||
import "git.tebibyte.media/tomo/tomo/event"
|
||||
import "git.tebibyte.media/tomo/objects/layouts"
|
||||
|
||||
var _ tomo.Object = new(Button)
|
||||
|
||||
var buttonLayout = layouts.Row { true }
|
||||
var iconButtonLayout = layouts.Row { true }
|
||||
var bothButtonLayout = layouts.Row { false, true }
|
||||
|
||||
// Button is a clickable button.
|
||||
type Button struct {
|
||||
tomo.ContainerBox
|
||||
box tomo.ContainerBox
|
||||
|
||||
label *Label
|
||||
icon *Icon
|
||||
@@ -24,33 +26,45 @@ type Button struct {
|
||||
|
||||
// NewButton creates a new button with the specified text.
|
||||
func NewButton (text string) *Button {
|
||||
box := &Button {
|
||||
ContainerBox: tomo.NewContainerBox(),
|
||||
button := &Button {
|
||||
box: tomo.NewContainerBox(),
|
||||
label: NewLabel(text),
|
||||
}
|
||||
box.SetRole(tomo.R("objects", "Button"))
|
||||
box.label.SetAttr(tomo.AAlign(tomo.AlignMiddle, tomo.AlignMiddle))
|
||||
box.SetAttr(tomo.ALayout(buttonLayout))
|
||||
box.SetText(text)
|
||||
button.box.SetRole(tomo.R("objects", "Button"))
|
||||
button.label.SetAttr(tomo.AAlign(tomo.AlignMiddle, tomo.AlignMiddle))
|
||||
button.box.SetAttr(tomo.ALayout(buttonLayout))
|
||||
button.SetText(text)
|
||||
|
||||
box.SetInputMask(true)
|
||||
box.OnButtonDown(box.handleButtonDown)
|
||||
box.OnButtonUp(box.handleButtonUp)
|
||||
box.OnKeyDown(box.handleKeyDown)
|
||||
box.OnKeyUp(box.handleKeyUp)
|
||||
box.SetFocusable(true)
|
||||
return box
|
||||
button.box.SetInputMask(true)
|
||||
button.box.OnButtonDown(button.handleButtonDown)
|
||||
button.box.OnButtonUp(button.handleButtonUp)
|
||||
button.box.OnKeyDown(button.handleKeyDown)
|
||||
button.box.OnKeyUp(button.handleKeyUp)
|
||||
button.box.SetFocusable(true)
|
||||
return button
|
||||
}
|
||||
|
||||
// GetBox returns the underlying box.
|
||||
func (this *Button) GetBox () tomo.Box {
|
||||
return this.box
|
||||
}
|
||||
|
||||
// SetFocused sets whether or not this button has keyboard focus. If set to
|
||||
// true, this method will steal focus away from whichever object currently has
|
||||
// focus.
|
||||
func (this *Button) SetFocused (focused bool) {
|
||||
this.box.SetFocused(focused)
|
||||
}
|
||||
|
||||
// SetText sets the text of the button's label.
|
||||
func (this *Button) SetText (text string) {
|
||||
this.label.SetText(text)
|
||||
if this.labelActive && text == "" {
|
||||
this.Remove(this.label)
|
||||
this.box.Remove(this.label)
|
||||
this.labelActive = false
|
||||
}
|
||||
if !this.labelActive && text != "" {
|
||||
this.Add(this.label)
|
||||
this.box.Add(this.label)
|
||||
this.labelActive = true
|
||||
}
|
||||
this.applyLayout()
|
||||
@@ -59,7 +73,7 @@ func (this *Button) SetText (text string) {
|
||||
// SetIcon sets an icon for this button. Setting the icon to IconUnknown will
|
||||
// remove it.
|
||||
func (this *Button) SetIcon (id tomo.Icon) {
|
||||
if this.icon != nil { this.Remove(this.icon) }
|
||||
if this.icon != nil { this.box.Remove(this.icon) }
|
||||
|
||||
var icon *Icon; if id != tomo.IconUnknown {
|
||||
icon = NewIcon(id, tomo.IconSizeSmall)
|
||||
@@ -67,9 +81,9 @@ func (this *Button) SetIcon (id tomo.Icon) {
|
||||
this.icon = icon
|
||||
|
||||
if this.icon != nil {
|
||||
this.Insert(this.icon, this.label)
|
||||
this.box.Insert(this.icon, this.label)
|
||||
}
|
||||
this.SetTag("icon", this.icon != nil)
|
||||
this.box.SetTag("icon", this.icon != nil)
|
||||
this.applyLayout()
|
||||
}
|
||||
|
||||
@@ -80,11 +94,11 @@ func (this *Button) OnClick (callback func ()) event.Cookie {
|
||||
|
||||
func (this *Button) applyLayout () {
|
||||
if this.labelActive && this.icon == nil {
|
||||
this.SetAttr(tomo.ALayout(buttonLayout))
|
||||
this.box.SetAttr(tomo.ALayout(buttonLayout))
|
||||
} else if !this.labelActive && this.icon != nil {
|
||||
this.SetAttr(tomo.ALayout(iconButtonLayout))
|
||||
this.box.SetAttr(tomo.ALayout(iconButtonLayout))
|
||||
} else {
|
||||
this.SetAttr(tomo.ALayout(bothButtonLayout))
|
||||
this.box.SetAttr(tomo.ALayout(bothButtonLayout))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +120,7 @@ func (this *Button) handleButtonDown (button input.Button) bool {
|
||||
|
||||
func (this *Button) handleButtonUp (button input.Button) bool {
|
||||
if !isClickingButton(button) { return false }
|
||||
if this.Window().MousePosition().In(this.Bounds()) {
|
||||
if this.box.Window().MousePosition().In(this.box.Bounds()) {
|
||||
this.on.click.Broadcast()
|
||||
}
|
||||
return true
|
||||
|
||||
21
calendar.go
21
calendar.go
@@ -6,10 +6,12 @@ import "git.tebibyte.media/tomo/tomo"
|
||||
import "git.tebibyte.media/tomo/tomo/event"
|
||||
import "git.tebibyte.media/tomo/objects/layouts"
|
||||
|
||||
var _ tomo.Object = new(Calendar)
|
||||
|
||||
// Calendar is an object that can display a date and allow the user to change
|
||||
// it. It can display one month at a time.
|
||||
type Calendar struct {
|
||||
tomo.ContainerBox
|
||||
box tomo.ContainerBox
|
||||
|
||||
grid tomo.ContainerBox
|
||||
time time.Time
|
||||
@@ -23,11 +25,11 @@ type Calendar struct {
|
||||
// NewCalendar creates a new calendar with the specified date.
|
||||
func NewCalendar (tm time.Time) *Calendar {
|
||||
calendar := &Calendar {
|
||||
ContainerBox: tomo.NewContainerBox(),
|
||||
box: tomo.NewContainerBox(),
|
||||
time: tm,
|
||||
}
|
||||
calendar.SetRole(tomo.R("objects", "Calendar"))
|
||||
calendar.SetAttr(tomo.ALayout(layouts.ContractVertical))
|
||||
calendar.box.SetRole(tomo.R("objects", "Calendar"))
|
||||
calendar.box.SetAttr(tomo.ALayout(layouts.ContractVertical))
|
||||
|
||||
prevButton := NewButton("")
|
||||
prevButton.SetIcon(tomo.IconGoPrevious)
|
||||
@@ -48,17 +50,22 @@ func NewCalendar (tm time.Time) *Calendar {
|
||||
calendar.grid.SetRole(tomo.R("objects", "CalendarGrid"))
|
||||
calendar.grid.SetAttr(tomo.ALayout(layouts.NewGrid (
|
||||
true, true, true, true, true, true, true)()))
|
||||
calendar.Add(NewInnerContainer (
|
||||
calendar.box.Add(NewInnerContainer (
|
||||
layouts.Row { false, true, false },
|
||||
prevButton, calendar.monthLabel, nextButton))
|
||||
calendar.Add(calendar.grid)
|
||||
calendar.box.Add(calendar.grid)
|
||||
|
||||
calendar.OnScroll(calendar.handleScroll)
|
||||
calendar.box.OnScroll(calendar.handleScroll)
|
||||
|
||||
calendar.refresh()
|
||||
return calendar
|
||||
}
|
||||
|
||||
// GetBox returns the underlying box.
|
||||
func (this *Calendar) GetBox () tomo.Box {
|
||||
return this.box
|
||||
}
|
||||
|
||||
// Value returns the time this calendar is displaying.
|
||||
func (this *Calendar) Value () time.Time {
|
||||
return this.time
|
||||
|
||||
42
checkbox.go
42
checkbox.go
@@ -4,9 +4,11 @@ import "git.tebibyte.media/tomo/tomo"
|
||||
import "git.tebibyte.media/tomo/tomo/input"
|
||||
import "git.tebibyte.media/tomo/tomo/event"
|
||||
|
||||
var _ tomo.Object = new(Checkbox)
|
||||
|
||||
// Checkbox is a control that can be toggled.
|
||||
type Checkbox struct {
|
||||
tomo.Box
|
||||
box tomo.Box
|
||||
value bool
|
||||
on struct {
|
||||
valueChange event.FuncBroadcaster
|
||||
@@ -15,18 +17,30 @@ type Checkbox struct {
|
||||
|
||||
// NewCheckbox creates a new checkbox with the specified value.
|
||||
func NewCheckbox (value bool) *Checkbox {
|
||||
box := &Checkbox {
|
||||
Box: tomo.NewBox(),
|
||||
checkbox := &Checkbox {
|
||||
box: tomo.NewBox(),
|
||||
}
|
||||
box.SetRole(tomo.R("objects", "Checkbox"))
|
||||
box.SetValue(value)
|
||||
checkbox.box.SetRole(tomo.R("objects", "Checkbox"))
|
||||
checkbox.SetValue(value)
|
||||
|
||||
box.OnButtonDown(box.handleButtonDown)
|
||||
box.OnButtonUp(box.handleButtonUp)
|
||||
box.OnKeyDown(box.handleKeyDown)
|
||||
box.OnKeyUp(box.handleKeyUp)
|
||||
box.SetFocusable(true)
|
||||
return box
|
||||
checkbox.box.OnButtonDown(checkbox.handleButtonDown)
|
||||
checkbox.box.OnButtonUp(checkbox.handleButtonUp)
|
||||
checkbox.box.OnKeyDown(checkbox.handleKeyDown)
|
||||
checkbox.box.OnKeyUp(checkbox.handleKeyUp)
|
||||
checkbox.box.SetFocusable(true)
|
||||
return checkbox
|
||||
}
|
||||
|
||||
// GetBox returns the underlying box.
|
||||
func (this *Checkbox) GetBox () tomo.Box {
|
||||
return this.box
|
||||
}
|
||||
|
||||
// SetFocused sets whether or not this checkbox has keyboard focus. If set to
|
||||
// true, this method will steal focus away from whichever object currently has
|
||||
// focus.
|
||||
func (this *Checkbox) SetFocused (focused bool) {
|
||||
this.box.SetFocused(focused)
|
||||
}
|
||||
|
||||
// Value returns the value of the checkbox.
|
||||
@@ -38,8 +52,8 @@ func (this *Checkbox) Value () bool {
|
||||
func (this *Checkbox) SetValue (value bool) {
|
||||
this.value = value
|
||||
// the theme shall decide what checked and unchecked states look like
|
||||
this.SetTag("checked", value)
|
||||
this.SetTag("unchecked", !value)
|
||||
this.box.SetTag("checked", value)
|
||||
this.box.SetTag("unchecked", !value)
|
||||
}
|
||||
|
||||
// Toggle toggles the value of the checkbox between true and false.
|
||||
@@ -71,7 +85,7 @@ func (this *Checkbox) handleButtonDown (button input.Button) bool {
|
||||
|
||||
func (this *Checkbox) handleButtonUp (button input.Button) bool {
|
||||
if !isClickingButton(button) { return false }
|
||||
if this.Window().MousePosition().In(this.Bounds()) {
|
||||
if this.box.Window().MousePosition().In(this.box.Bounds()) {
|
||||
this.Toggle()
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -8,10 +8,12 @@ import "git.tebibyte.media/tomo/tomo/canvas"
|
||||
import "git.tebibyte.media/tomo/objects/layouts"
|
||||
import "git.tebibyte.media/tomo/objects/internal"
|
||||
|
||||
var _ tomo.Object = new(HSVAColorPicker)
|
||||
|
||||
// HSVAColorPicker allows the user to pick a color by controlling its HSVA
|
||||
// parameters.
|
||||
type HSVAColorPicker struct {
|
||||
tomo.ContainerBox
|
||||
box tomo.ContainerBox
|
||||
value internal.HSVA
|
||||
|
||||
pickerMap *hsvaColorPickerMap
|
||||
@@ -26,15 +28,15 @@ type HSVAColorPicker struct {
|
||||
// NewHSVAColorPicker creates a new color picker with the specified color.
|
||||
func NewHSVAColorPicker (value color.Color) *HSVAColorPicker {
|
||||
picker := &HSVAColorPicker {
|
||||
ContainerBox: tomo.NewContainerBox(),
|
||||
box: tomo.NewContainerBox(),
|
||||
}
|
||||
picker.SetRole(tomo.R("objects", "ColorPicker"))
|
||||
picker.SetAttr(tomo.ALayout(layouts.Row { true, false, false }))
|
||||
picker.box.SetRole(tomo.R("objects", "ColorPicker"))
|
||||
picker.box.SetAttr(tomo.ALayout(layouts.Row { true, false, false }))
|
||||
picker.pickerMap = newHsvaColorPickerMap(picker)
|
||||
picker.Add(picker.pickerMap)
|
||||
picker.box.Add(picker.pickerMap)
|
||||
|
||||
picker.hueSlider = NewVerticalSlider(0.0)
|
||||
picker.Add(picker.hueSlider)
|
||||
picker.box.Add(picker.hueSlider)
|
||||
picker.hueSlider.OnValueChange(func () {
|
||||
picker.value.H = picker.hueSlider.Value()
|
||||
picker.on.valueChange.Broadcast()
|
||||
@@ -42,7 +44,7 @@ func NewHSVAColorPicker (value color.Color) *HSVAColorPicker {
|
||||
})
|
||||
|
||||
picker.alphaSlider = NewVerticalSlider(0.0)
|
||||
picker.Add(picker.alphaSlider)
|
||||
picker.box.Add(picker.alphaSlider)
|
||||
picker.alphaSlider.OnValueChange(func () {
|
||||
picker.value.A = uint16(picker.alphaSlider.Value() * 0xFFFF)
|
||||
picker.on.valueChange.Broadcast()
|
||||
@@ -54,6 +56,18 @@ func NewHSVAColorPicker (value color.Color) *HSVAColorPicker {
|
||||
return picker
|
||||
}
|
||||
|
||||
// GetBox returns the underlying box.
|
||||
func (this *HSVAColorPicker) GetBox () tomo.Box {
|
||||
return this.box
|
||||
}
|
||||
|
||||
// SetFocused sets whether or not this color picker has keyboard focus. If set
|
||||
// to true, this method will steal focus away from whichever object currently
|
||||
// has focus.
|
||||
func (this *HSVAColorPicker) SetFocused (focused bool) {
|
||||
this.box.SetFocused(focused)
|
||||
}
|
||||
|
||||
// Value returns the color of the picker.
|
||||
func (this *HSVAColorPicker) Value () color.Color {
|
||||
return this.value
|
||||
|
||||
93
container.go
93
container.go
@@ -1,6 +1,10 @@
|
||||
package objects
|
||||
|
||||
import "image"
|
||||
import "git.tebibyte.media/tomo/tomo"
|
||||
import "git.tebibyte.media/tomo/tomo/event"
|
||||
|
||||
var _ tomo.ContentObject = new(Container)
|
||||
|
||||
// Container is an object that can contain other objects. It can be used as a
|
||||
// primitive for building more complex layouts. It has two variants: an outer
|
||||
@@ -8,14 +12,14 @@ import "git.tebibyte.media/tomo/tomo"
|
||||
// its edges, whereas the inner container does not. The container will have a
|
||||
// corresponding object role variation of either "outer" or "inner".
|
||||
type Container struct {
|
||||
tomo.ContainerBox
|
||||
box tomo.ContainerBox
|
||||
}
|
||||
|
||||
func newContainer (layout tomo.Layout, children ...tomo.Object) *Container {
|
||||
this := &Container {
|
||||
ContainerBox: tomo.NewContainerBox(),
|
||||
box: tomo.NewContainerBox(),
|
||||
}
|
||||
this.SetAttr(tomo.ALayout(layout))
|
||||
this.box.SetAttr(tomo.ALayout(layout))
|
||||
for _, child := range children {
|
||||
this.Add(child)
|
||||
}
|
||||
@@ -27,8 +31,8 @@ func newContainer (layout tomo.Layout, children ...tomo.Object) *Container {
|
||||
// window, tab pane, etc.
|
||||
func NewOuterContainer (layout tomo.Layout, children ...tomo.Object) *Container {
|
||||
this := newContainer(layout, children...)
|
||||
this.SetRole(tomo.R("objects", "Container"))
|
||||
this.SetTag("outer", true)
|
||||
this.box.SetRole(tomo.R("objects", "Container"))
|
||||
this.box.SetTag("outer", true)
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -36,16 +40,87 @@ func NewOuterContainer (layout tomo.Layout, children ...tomo.Object) *Container
|
||||
// around it. It is meant to be used as a root container for a ScrollContainer.
|
||||
func NewSunkenContainer (layout tomo.Layout, children ...tomo.Object) *Container {
|
||||
this := newContainer(layout, children...)
|
||||
this.SetRole(tomo.R("objects", "Container"))
|
||||
this.SetTag("sunken", true)
|
||||
this.box.SetRole(tomo.R("objects", "Container"))
|
||||
this.box.SetTag("sunken", true)
|
||||
return this
|
||||
}
|
||||
|
||||
// NewInnerContainer creates a new container that has no padding around it.
|
||||
func NewInnerContainer (layout tomo.Layout, children ...tomo.Object) *Container {
|
||||
this := newContainer(layout, children...)
|
||||
this.SetRole(tomo.R("objects", "Container"))
|
||||
this.SetTag("inner", true)
|
||||
this.box.SetRole(tomo.R("objects", "Container"))
|
||||
this.box.SetTag("inner", true)
|
||||
return this
|
||||
}
|
||||
|
||||
// GetBox returns the underlying box.
|
||||
func (this *Container) GetBox () tomo.Box {
|
||||
return this.box
|
||||
}
|
||||
|
||||
// ContentBounds returns the bounds of the inner content of the container
|
||||
// relative to the container's InnerBounds.
|
||||
func (this *Container) ContentBounds () image.Rectangle {
|
||||
return this.box.ContentBounds()
|
||||
}
|
||||
|
||||
// ScrollTo shifts the origin of the container's content to the origin of the
|
||||
// container's InnerBounds, offset by the given point.
|
||||
func (this *Container) ScrollTo (position image.Point) {
|
||||
this.box.ScrollTo(position)
|
||||
}
|
||||
|
||||
// OnContentBoundsChange specifies a function to be called when the container's
|
||||
// ContentBounds or InnerBounds changes.
|
||||
func (this *Container) OnContentBoundsChange (callback func ()) event.Cookie {
|
||||
return this.box.OnContentBoundsChange(callback)
|
||||
}
|
||||
|
||||
// SetLayout sets the layout of the container.
|
||||
func (this *Container) SetLayout (layout tomo.Layout) {
|
||||
this.box.SetAttr(tomo.ALayout(layout))
|
||||
}
|
||||
|
||||
// SetAlign sets the X and Y alignment of the container.
|
||||
func (this *Container) SetAlign (x, y tomo.Align) {
|
||||
this.box.SetAttr(tomo.AAlign(x, y))
|
||||
}
|
||||
|
||||
// SetOverflow sets the X and Y overflow of the container.
|
||||
func (this *Container) SetOverflow (x, y bool) {
|
||||
this.box.SetAttr(tomo.AOverflow(x, y))
|
||||
}
|
||||
|
||||
// Add appends a child object. If the object is already a child of another
|
||||
// object, it will be removed from that object first.
|
||||
func (this *Container) Add (object tomo.Object) {
|
||||
this.box.Add(object)
|
||||
}
|
||||
|
||||
// Remove removes a child object, if it is a child of this container.
|
||||
func (this *Container) Remove (object tomo.Object) {
|
||||
this.box.Remove(object)
|
||||
}
|
||||
|
||||
// Insert inserts a child object before a specified object. If the before object
|
||||
// is nil or is not contained within this container, the inserted object is
|
||||
// appended. If the inserted object is already a child of another object, it
|
||||
// will be removed from that object first.
|
||||
func (this *Container) Insert (child tomo.Object, before tomo.Object) {
|
||||
this.box.Insert(child, before)
|
||||
}
|
||||
|
||||
// Clear removes all child objects.
|
||||
func (this *Container) Clear () {
|
||||
this.box.Clear()
|
||||
}
|
||||
|
||||
// Len returns hte amount of child objects.
|
||||
func (this *Container) Len () int {
|
||||
return this.box.Len()
|
||||
}
|
||||
|
||||
// At returns the child object at the specified index.
|
||||
func (this *Container) At (index int) tomo.Object {
|
||||
return this.box.At(index)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ type DialogKind int; const (
|
||||
// Dialog is a modal dialog window.
|
||||
type Dialog struct {
|
||||
tomo.Window
|
||||
controlRow tomo.ContainerBox
|
||||
controlRow *Container
|
||||
}
|
||||
|
||||
type clickable interface {
|
||||
@@ -53,6 +53,7 @@ func NewDialog (kind DialogKind, parent tomo.Window, title, message string, opti
|
||||
case DialogError: iconId = tomo.IconDialogError
|
||||
}
|
||||
dialog.SetTitle(title)
|
||||
dialog.SetIcon(iconId)
|
||||
icon := NewIcon(iconId, tomo.IconSizeLarge)
|
||||
messageText := NewLabel(message)
|
||||
messageText.SetAttr(tomo.AAlign(tomo.AlignStart, tomo.AlignMiddle))
|
||||
@@ -63,7 +64,7 @@ func NewDialog (kind DialogKind, parent tomo.Window, title, message string, opti
|
||||
}
|
||||
}
|
||||
dialog.controlRow = NewInnerContainer(layouts.ContractHorizontal, options...)
|
||||
dialog.controlRow.SetAttr(tomo.AAlign(tomo.AlignEnd, tomo.AlignEnd))
|
||||
dialog.controlRow.SetAlign(tomo.AlignEnd, tomo.AlignEnd)
|
||||
|
||||
dialog.SetRoot(NewOuterContainer (
|
||||
layouts.Column { true, false },
|
||||
|
||||
40
dropdown.go
40
dropdown.go
@@ -6,10 +6,12 @@ import "git.tebibyte.media/tomo/tomo/input"
|
||||
import "git.tebibyte.media/tomo/tomo/event"
|
||||
import "git.tebibyte.media/tomo/objects/layouts"
|
||||
|
||||
var _ tomo.Object = new(Dropdown)
|
||||
|
||||
// Dropdown is a non-editable text input that allows the user to pick a value
|
||||
// from a list.
|
||||
type Dropdown struct {
|
||||
tomo.ContainerBox
|
||||
box tomo.ContainerBox
|
||||
label *Label
|
||||
|
||||
value string
|
||||
@@ -24,28 +26,40 @@ type Dropdown struct {
|
||||
// NewDropdown creates a new dropdown input with the specified items
|
||||
func NewDropdown (items ...string) *Dropdown {
|
||||
dropdown := &Dropdown {
|
||||
ContainerBox: tomo.NewContainerBox(),
|
||||
box: tomo.NewContainerBox(),
|
||||
label: NewLabel(""),
|
||||
}
|
||||
dropdown.SetRole(tomo.R("objects", "Dropdown"))
|
||||
dropdown.SetAttr(tomo.ALayout(layouts.Row { true, false }))
|
||||
dropdown.Add(dropdown.label)
|
||||
dropdown.Add(NewIcon(tomo.IconListChoose, tomo.IconSizeSmall))
|
||||
dropdown.box.SetRole(tomo.R("objects", "Dropdown"))
|
||||
dropdown.box.SetAttr(tomo.ALayout(layouts.Row { true, false }))
|
||||
dropdown.box.Add(dropdown.label)
|
||||
dropdown.box.Add(NewIcon(tomo.IconListChoose, tomo.IconSizeSmall))
|
||||
|
||||
dropdown.SetItems(items...)
|
||||
if len(items) > 0 {
|
||||
dropdown.SetValue(items[0])
|
||||
}
|
||||
|
||||
dropdown.SetInputMask(true)
|
||||
dropdown.OnButtonDown(dropdown.handleButtonDown)
|
||||
dropdown.OnButtonUp(dropdown.handleButtonUp)
|
||||
dropdown.OnKeyDown(dropdown.handleKeyDown)
|
||||
dropdown.OnKeyUp(dropdown.handleKeyUp)
|
||||
dropdown.SetFocusable(true)
|
||||
dropdown.box.SetInputMask(true)
|
||||
dropdown.box.OnButtonDown(dropdown.handleButtonDown)
|
||||
dropdown.box.OnButtonUp(dropdown.handleButtonUp)
|
||||
dropdown.box.OnKeyDown(dropdown.handleKeyDown)
|
||||
dropdown.box.OnKeyUp(dropdown.handleKeyUp)
|
||||
dropdown.box.SetFocusable(true)
|
||||
return dropdown
|
||||
}
|
||||
|
||||
// GetBox returns the underlying box.
|
||||
func (this *Dropdown) GetBox () tomo.Box {
|
||||
return this.box
|
||||
}
|
||||
|
||||
// SetFocused sets whether or not this dropdown has keyboard focus. If set to
|
||||
// true, this method will steal focus away from whichever object currently has
|
||||
// focus.
|
||||
func (this *Dropdown) SetFocused (focused bool) {
|
||||
this.box.SetFocused(focused)
|
||||
}
|
||||
|
||||
// Value returns the value of the dropdown. This does not necissarily have to be
|
||||
// in the list of items.
|
||||
func (this *Dropdown) Value () string {
|
||||
@@ -107,7 +121,7 @@ func (this *Dropdown) handleButtonDown (button input.Button) bool {
|
||||
|
||||
func (this *Dropdown) handleButtonUp (button input.Button) bool {
|
||||
if !isClickingButton(button) { return false }
|
||||
if this.Window().MousePosition().In(this.Bounds()) {
|
||||
if this.box.Window().MousePosition().In(this.box.Bounds()) {
|
||||
this.Choose()
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -24,6 +24,8 @@ func NewLabelSwatch (value color.Color, text string) *LabelSwatch {
|
||||
box.SetRole(tomo.R("objects", "LabelSwatch"))
|
||||
box.swatch.label = text
|
||||
box.label.SetAttr(tomo.AAlign(tomo.AlignStart, tomo.AlignMiddle))
|
||||
box.label.SetSelectable(false)
|
||||
box.label.SetFocusable(false)
|
||||
box.Add(box.swatch)
|
||||
box.Add(box.label)
|
||||
box.SetAttr(tomo.ALayout(layouts.Row { false, true }))
|
||||
@@ -61,12 +63,12 @@ func (this *LabelSwatch) OnConfirm (callback func ()) event.Cookie {
|
||||
}
|
||||
|
||||
func (this *LabelSwatch) handleButtonDown (button input.Button) bool {
|
||||
if button != input.ButtonLeft { return true }
|
||||
if !isClickingButton(button) { return true }
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *LabelSwatch) handleButtonUp (button input.Button) bool {
|
||||
if button != input.ButtonLeft { return true }
|
||||
if !isClickingButton(button) { return true }
|
||||
if this.Window().MousePosition().In(this.Bounds()) {
|
||||
this.swatch.SetFocused(true)
|
||||
this.swatch.Choose()
|
||||
|
||||
15
menu.go
15
menu.go
@@ -72,6 +72,7 @@ func (this *Menu) TearOff () {
|
||||
this.torn = true
|
||||
|
||||
window, err := this.parent.NewChild(this.bounds)
|
||||
window.SetIcon(tomo.IconListChoose)
|
||||
if err != nil { return }
|
||||
|
||||
visible := this.Window.Visible()
|
||||
@@ -90,21 +91,27 @@ func (this *Menu) newTearLine () tomo.Object {
|
||||
tearLine := tomo.NewBox()
|
||||
tearLine.SetRole(tomo.R("objects", "TearLine"))
|
||||
tearLine.SetFocusable(true)
|
||||
tearLine.OnMouseEnter(func () {
|
||||
tearLine.SetFocused(true)
|
||||
})
|
||||
tearLine.OnMouseLeave(func () {
|
||||
tearLine.SetFocused(false)
|
||||
})
|
||||
tearLine.OnKeyDown(func (key input.Key, numberPad bool) bool {
|
||||
if key != input.KeyEnter && key != input.Key(' ') { return false }
|
||||
if !isClickingKey(key) { return false }
|
||||
return true
|
||||
})
|
||||
tearLine.OnKeyUp(func (key input.Key, numberPad bool) bool {
|
||||
if key != input.KeyEnter && key != input.Key(' ') { return false }
|
||||
if !isClickingKey(key) { return false }
|
||||
this.TearOff()
|
||||
return true
|
||||
})
|
||||
tearLine.OnButtonDown(func (button input.Button) bool {
|
||||
if button != input.ButtonLeft { return false }
|
||||
if !isClickingButton(button) { return false }
|
||||
return true
|
||||
})
|
||||
tearLine.OnButtonUp(func (button input.Button) bool {
|
||||
if button != input.ButtonLeft { return false }
|
||||
if !isClickingButton(button) { return false }
|
||||
if tearLine.Window().MousePosition().In(tearLine.Bounds()) {
|
||||
this.TearOff()
|
||||
}
|
||||
|
||||
10
menuitem.go
10
menuitem.go
@@ -38,6 +38,8 @@ func NewIconMenuItem (icon tomo.Icon, text string) *MenuItem {
|
||||
box.Add(box.label)
|
||||
|
||||
box.SetInputMask(true)
|
||||
box.OnMouseEnter(box.handleMouseEnter)
|
||||
box.OnMouseLeave(box.handleMouseLeave)
|
||||
box.OnButtonDown(box.handleButtonDown)
|
||||
box.OnButtonUp(box.handleButtonUp)
|
||||
box.OnKeyDown(box.handleKeyDown)
|
||||
@@ -62,6 +64,14 @@ func (this *MenuItem) OnClick (callback func ()) event.Cookie {
|
||||
return this.on.click.Connect(callback)
|
||||
}
|
||||
|
||||
func (this *MenuItem) handleMouseEnter () {
|
||||
this.SetFocused(true)
|
||||
}
|
||||
|
||||
func (this *MenuItem) handleMouseLeave () {
|
||||
this.SetFocused(false)
|
||||
}
|
||||
|
||||
func (this *MenuItem) handleKeyDown (key input.Key, numberPad bool) bool {
|
||||
if key != input.KeyEnter && key != input.Key(' ') { return false }
|
||||
return true
|
||||
|
||||
@@ -9,7 +9,7 @@ import "git.tebibyte.media/tomo/tomo/event"
|
||||
// overflowing ContainerBox.
|
||||
type Scrollbar struct {
|
||||
tomo.ContainerBox
|
||||
handle *SliderHandle
|
||||
handle *sliderHandle
|
||||
layout scrollbarLayout
|
||||
dragging bool
|
||||
dragOffset image.Point
|
||||
@@ -24,7 +24,7 @@ type Scrollbar struct {
|
||||
func newScrollbar (orient string) *Scrollbar {
|
||||
this := &Scrollbar {
|
||||
ContainerBox: tomo.NewContainerBox(),
|
||||
handle: &SliderHandle {
|
||||
handle: &sliderHandle {
|
||||
Box: tomo.NewBox(),
|
||||
},
|
||||
layout: scrollbarLayout {
|
||||
@@ -43,9 +43,9 @@ func newScrollbar (orient string) *Scrollbar {
|
||||
this.OnMouseMove(this.handleMouseMove)
|
||||
this.OnScroll(this.handleScroll)
|
||||
|
||||
this.handle.SetRole(tomo.R("objects", "SliderHandle"))
|
||||
this.handle.SetRole(tomo.R("objects", "ScrollbarHandle"))
|
||||
this.handle.SetTag(orient, true)
|
||||
this.SetRole(tomo.R("objects", "Slider"))
|
||||
this.SetRole(tomo.R("objects", "Scrollbar"))
|
||||
this.SetTag(orient, true)
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import "git.tebibyte.media/tomo/tomo/event"
|
||||
// Slider is a control that selects a numeric value between 0 and 1.
|
||||
type Slider struct {
|
||||
tomo.ContainerBox
|
||||
handle *SliderHandle
|
||||
handle *sliderHandle
|
||||
layout sliderLayout
|
||||
dragging bool
|
||||
dragOffset image.Point
|
||||
@@ -21,16 +21,14 @@ type Slider struct {
|
||||
}
|
||||
}
|
||||
|
||||
// SliderHandle is a simple object that serves as a handle for sliders and
|
||||
// scrollbars. It is completely inert.
|
||||
type SliderHandle struct {
|
||||
type sliderHandle struct {
|
||||
tomo.Box
|
||||
}
|
||||
|
||||
func newSlider (orient string, value float64) *Slider {
|
||||
this := &Slider {
|
||||
ContainerBox: tomo.NewContainerBox(),
|
||||
handle: &SliderHandle {
|
||||
handle: &sliderHandle {
|
||||
Box: tomo.NewBox(),
|
||||
},
|
||||
layout: sliderLayout {
|
||||
|
||||
@@ -129,7 +129,7 @@ func (this *Swatch) Choose () {
|
||||
layouts.ContractHorizontal,
|
||||
cancelButton,
|
||||
okButton)
|
||||
controlRow.SetAttr(tomo.AAlign(tomo.AlignEnd, tomo.AlignMiddle))
|
||||
controlRow.SetAlign(tomo.AlignEnd, tomo.AlignMiddle)
|
||||
window.SetRoot(NewOuterContainer (
|
||||
layouts.Column { true, false },
|
||||
colorPicker,
|
||||
|
||||
Reference in New Issue
Block a user