18 Commits

Author SHA1 Message Date
df2e8f1b07 Dropdown no longer embeds tomo.ContainerBox 2024-08-24 19:33:16 -04:00
0c4e098680 HSVAColorPicker no longer embeds tomo.ContainerBox 2024-08-24 19:28:48 -04:00
fc51e7ab9f Checkbox no longer embeds tomo.ContainerBox 2024-08-24 15:41:47 -04:00
4e8823ef9f Calendar no longer embeds tomo.ContainerBox 2024-08-24 15:20:09 -04:00
8de08a9bdc Button no longer embeds tomo.ContainerBox 2024-08-24 15:11:57 -04:00
04f44cea86 Ensure Container satisfies tomo.ContentObject 2024-08-24 15:04:44 -04:00
c889838c9c Container no longer embeds tomo.ContainerBox
Progress on #7
2024-08-24 15:02:17 -04:00
7bcb4cf823 Add SetLayout to Container 2024-08-24 14:45:31 -04:00
02516bdcce Same as last commit but for TearLine 2024-08-24 14:42:08 -04:00
8432cc70da MenuItem focuses on hover
Styles should remove MenuItem[hover] styling
2024-08-24 14:37:44 -04:00
8469962c90 Use key/button functions for menu 2024-08-24 14:32:19 -04:00
0ccdb609ef Tear off menu windows now have an icon 2024-08-24 01:00:34 -04:00
d1f0786043 Dialog boxes have icons now 2024-08-23 21:39:39 -04:00
73731c6201 Scrollbar has Scrollbar role 2024-08-16 18:36:49 -04:00
7c42b7ad37 Scrollbar has ScrollbarHandle instead of SliderHandle 2024-08-16 18:36:20 -04:00
0fe4979483 Un-export SliderHandle
Closes #8
2024-08-16 18:35:19 -04:00
155752ba78 LabelSwatch uses the new button functions 2024-08-16 18:32:07 -04:00
f4a3cb3c00 LabelSwatch's label is not selectable, to match LabelCheckbox 2024-08-16 18:26:13 -04:00
13 changed files with 249 additions and 93 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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 },

View File

@@ -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

View File

@@ -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
View File

@@ -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()
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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,