Half-working container flexibility propagation
This commit is contained in:
parent
76d50bb01a
commit
e94e170a04
@ -89,7 +89,7 @@ func (window *Window) Adopt (child tomo.Element) {
|
||||
child.SetParentHooks (tomo.ParentHooks {
|
||||
Draw: window.childDrawCallback,
|
||||
MinimumSizeChange: window.childMinimumSizeChangeCallback,
|
||||
ExpandingHeightChange: window.resizeChildToFit,
|
||||
FlexibleHeightChange: window.resizeChildToFit,
|
||||
SelectionRequest: window.childSelectionRequestCallback,
|
||||
})
|
||||
|
||||
|
12
element.go
12
element.go
@ -16,9 +16,9 @@ type ParentHooks struct {
|
||||
// event.
|
||||
MinimumSizeChange func (width, height int)
|
||||
|
||||
// ExpandingHeightChange is called when the parameters affecting the
|
||||
// FlexibleHeightChange is called when the parameters affecting the
|
||||
// element's expanding height have changed.
|
||||
ExpandingHeightChange func ()
|
||||
FlexibleHeightChange func ()
|
||||
|
||||
// SelectionRequest is called when the child element element wants
|
||||
// itself to be selected. If the parent element chooses to grant the
|
||||
@ -46,11 +46,11 @@ func (hooks ParentHooks) RunMinimumSizeChange (width, height int) {
|
||||
}
|
||||
}
|
||||
|
||||
// RunExpandingHeightChange runs the ExpandingHeightChange hook if it is not
|
||||
// RunFlexibleHeightChange runs the ExpandingHeightChange hook if it is not
|
||||
// nil. If it is nil, it does nothing.
|
||||
func (hooks ParentHooks) RunExpandingHeightChange () {
|
||||
if hooks.ExpandingHeightChange != nil {
|
||||
hooks.ExpandingHeightChange()
|
||||
func (hooks ParentHooks) RunFlexibleHeightChange () {
|
||||
if hooks.FlexibleHeightChange != nil {
|
||||
hooks.FlexibleHeightChange()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ type Container struct {
|
||||
warping bool
|
||||
selected bool
|
||||
selectable bool
|
||||
flexible bool
|
||||
}
|
||||
|
||||
// NewContainer creates a new container.
|
||||
@ -49,6 +50,7 @@ func (element *Container) Adopt (child tomo.Element, expand bool) {
|
||||
MinimumSizeChange: func (int, int) {
|
||||
element.updateMinimumSize()
|
||||
},
|
||||
FlexibleHeightChange: element.updateMinimumSize,
|
||||
SelectionRequest: func () (granted bool) {
|
||||
child, selectable := child.(tomo.Selectable)
|
||||
if !selectable { return }
|
||||
@ -68,7 +70,7 @@ func (element *Container) Adopt (child tomo.Element, expand bool) {
|
||||
})
|
||||
|
||||
element.updateMinimumSize()
|
||||
element.updateSelectable()
|
||||
element.reflectChildProperties()
|
||||
if element.core.HasImage() && !element.warping {
|
||||
element.recalculate()
|
||||
element.draw()
|
||||
@ -113,7 +115,7 @@ func (element *Container) Disown (child tomo.Element) {
|
||||
}
|
||||
|
||||
element.updateMinimumSize()
|
||||
element.updateSelectable()
|
||||
element.reflectChildProperties()
|
||||
if element.core.HasImage() && !element.warping {
|
||||
element.recalculate()
|
||||
element.draw()
|
||||
@ -126,7 +128,7 @@ func (element *Container) DisownAll () {
|
||||
element.children = nil
|
||||
|
||||
element.updateMinimumSize()
|
||||
element.updateSelectable()
|
||||
element.reflectChildProperties()
|
||||
if element.core.HasImage() && !element.warping {
|
||||
element.recalculate()
|
||||
element.draw()
|
||||
@ -183,8 +185,6 @@ func (element *Container) Resize (width, height int) {
|
||||
element.draw()
|
||||
}
|
||||
|
||||
// TODO: implement KeyboardTarget
|
||||
|
||||
func (element *Container) HandleMouseDown (x, y int, button tomo.Button) {
|
||||
child, handlesMouse := element.ChildAt(image.Pt(x, y)).(tomo.MouseTarget)
|
||||
if !handlesMouse { return }
|
||||
@ -230,7 +230,7 @@ func (element *Container) HandleKeyDown (
|
||||
})
|
||||
}
|
||||
|
||||
func (element *Container) HandleKeyUp(key tomo.Key, modifiers tomo.Modifiers) {
|
||||
func (element *Container) HandleKeyUp (key tomo.Key, modifiers tomo.Modifiers) {
|
||||
element.forSelected (func (child tomo.Selectable) bool {
|
||||
child0, handlesKeyboard := child.(tomo.KeyboardTarget)
|
||||
if handlesKeyboard {
|
||||
@ -300,6 +300,11 @@ func (element *Container) HandleSelection (direction tomo.SelectionDirection) (o
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO: fix this!
|
||||
// func (element *Container) MinimumHeightFor (width int) (height int) {
|
||||
// return element.layout.MinimumHeightFor(element.children, width)
|
||||
// }
|
||||
|
||||
func (element *Container) HandleDeselection () {
|
||||
element.selected = false
|
||||
element.forSelected (func (child tomo.Selectable) bool {
|
||||
@ -326,6 +331,15 @@ func (element *Container) forSelectable (callback func (child tomo.Selectable) b
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Container) forFlexible (callback func (child tomo.Flexible) bool) {
|
||||
for _, entry := range element.children {
|
||||
child, selectable := entry.Element.(tomo.Flexible)
|
||||
if selectable {
|
||||
if !callback(child) { break }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (element *Container) forSelectableBackward (callback func (child tomo.Selectable) bool) {
|
||||
for index := len(element.children) - 1; index >= 0; index -- {
|
||||
child, selectable := element.children[index].Element.(tomo.Selectable)
|
||||
@ -345,12 +359,17 @@ func (element *Container) firstSelected () (index int) {
|
||||
return -1
|
||||
}
|
||||
|
||||
func (element *Container) updateSelectable () {
|
||||
func (element *Container) reflectChildProperties () {
|
||||
element.selectable = false
|
||||
element.forSelectable (func (tomo.Selectable) bool {
|
||||
element.selectable = true
|
||||
return false
|
||||
})
|
||||
element.flexible = false
|
||||
element.forFlexible (func (tomo.Flexible) bool {
|
||||
element.flexible = true
|
||||
return false
|
||||
})
|
||||
if !element.selectable {
|
||||
element.selected = false
|
||||
}
|
||||
@ -374,8 +393,11 @@ func (element *Container) childSelectionRequestCallback (
|
||||
}
|
||||
|
||||
func (element *Container) updateMinimumSize () {
|
||||
element.core.SetMinimumSize (
|
||||
element.layout.MinimumSize(element.children, 1e9))
|
||||
width, height := element.layout.MinimumSize(element.children)
|
||||
if element.flexible {
|
||||
height = element.layout.MinimumHeightFor(element.children, width)
|
||||
}
|
||||
element.core.SetMinimumSize(width, height)
|
||||
}
|
||||
|
||||
func (element *Container) recalculate () {
|
||||
|
@ -88,7 +88,7 @@ func (element *Label) updateMinimumSize () {
|
||||
if em < 1 { em = theme.Padding() }
|
||||
element.core.SetMinimumSize (
|
||||
em, element.drawer.LineHeight().Round())
|
||||
element.core.NotifyExpandingHeightChange()
|
||||
element.core.NotifyFlexibleHeightChange()
|
||||
} else {
|
||||
bounds := element.drawer.LayoutBounds()
|
||||
element.core.SetMinimumSize(bounds.Dx(), bounds.Dy())
|
||||
|
@ -144,10 +144,10 @@ func (control CoreControl) SetMinimumSize (width, height int) {
|
||||
}
|
||||
}
|
||||
|
||||
// NotifyExpandingHeightChange notifies the parent element that this element's
|
||||
// expanding height has changed.
|
||||
func (control CoreControl) NotifyExpandingHeightChange () {
|
||||
control.core.hooks.RunExpandingHeightChange()
|
||||
// NotifyFlexibleHeightChange notifies the parent element that this element's
|
||||
// flexible height has changed.
|
||||
func (control CoreControl) NotifyFlexibleHeightChange () {
|
||||
control.core.hooks.RunFlexibleHeightChange()
|
||||
}
|
||||
|
||||
// ConstrainSize contstrains the specified width and height to the minimum width
|
||||
|
@ -17,7 +17,7 @@ func run () {
|
||||
container := basic.NewContainer(layouts.Vertical { true, true })
|
||||
window.Adopt(container)
|
||||
|
||||
label := basic.NewLabel("it is a label hehe", false)
|
||||
label := basic.NewLabel("it is a label hehe", true)
|
||||
button := basic.NewButton("drawing pad")
|
||||
okButton := basic.NewButton("OK")
|
||||
button.OnClick (func () {
|
||||
|
11
layout.go
11
layout.go
@ -20,8 +20,11 @@ type Layout interface {
|
||||
Arrange (entries []LayoutEntry, width, height int)
|
||||
|
||||
// MinimumSize returns the minimum width and height that the layout
|
||||
// needs to properly arrange the given slice of layout entries, given a
|
||||
// "suqeeze" width so that the height can be determined for elements
|
||||
// fulfilling the Expanding interface.
|
||||
MinimumSize (entries []LayoutEntry, squeeze int) (width, height int)
|
||||
// needs to properly arrange the given slice of layout entries.
|
||||
MinimumSize (entries []LayoutEntry) (width, height int)
|
||||
|
||||
// MinimumHeightFor Returns the minimum height the layout needs to lay
|
||||
// out the specified elements at the given width, taking into account
|
||||
// flexible elements.
|
||||
MinimumHeightFor (entries []LayoutEntry, squeeze int) (height int)
|
||||
}
|
||||
|
@ -25,17 +25,22 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, width, height int) {
|
||||
freeSpace := height
|
||||
expandingElements := 0
|
||||
|
||||
// TODO: find the width first, then store the minumum height of
|
||||
// everything in a list, then arrange everything.
|
||||
// minimumHeights := make([]int, len(entries))
|
||||
|
||||
// count the number of expanding elements and the amount of free space
|
||||
// for them to collectively occupy
|
||||
// for them to collectively occupy, while gathering minimum heights.
|
||||
minimumHeights := make([]int, len(entries))
|
||||
for index, entry := range entries {
|
||||
var entryMinHeight int
|
||||
|
||||
if child, flexible := entry.Element.(tomo.Flexible); flexible {
|
||||
entryMinHeight = child.MinimumHeightFor(width)
|
||||
} else {
|
||||
_, entryMinHeight = entry.MinimumSize()
|
||||
}
|
||||
minimumHeights[index] = entryMinHeight
|
||||
|
||||
if entry.Expand {
|
||||
expandingElements ++
|
||||
} else {
|
||||
_, entryMinHeight := entry.MinimumSize()
|
||||
freeSpace -= entryMinHeight
|
||||
}
|
||||
if index > 0 && layout.Gap {
|
||||
@ -62,7 +67,7 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, width, height int) {
|
||||
if entry.Expand {
|
||||
entryHeight = expandingElementHeight
|
||||
} else {
|
||||
_, entryHeight = entry.MinimumSize()
|
||||
entryHeight = minimumHeights[index]
|
||||
}
|
||||
y += entryHeight
|
||||
entryBounds := entry.Bounds()
|
||||
@ -76,7 +81,6 @@ func (layout Vertical) Arrange (entries []tomo.LayoutEntry, width, height int) {
|
||||
// arrange the given list of entries.
|
||||
func (layout Vertical) MinimumSize (
|
||||
entries []tomo.LayoutEntry,
|
||||
squeeze int,
|
||||
) (
|
||||
width, height int,
|
||||
) {
|
||||
@ -97,3 +101,31 @@ func (layout Vertical) MinimumSize (
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MinimumHeightFor Returns the minimum height the layout needs to lay out the
|
||||
// specified elements at the given width, taking into account flexible elements.
|
||||
func (layout Vertical) MinimumHeightFor (
|
||||
entries []tomo.LayoutEntry,
|
||||
squeeze int,
|
||||
) (
|
||||
height int,
|
||||
) {
|
||||
for index, entry := range entries {
|
||||
child, flexible := entry.Element.(tomo.Flexible)
|
||||
if flexible {
|
||||
height += child.MinimumHeightFor(squeeze)
|
||||
} else {
|
||||
_, entryHeight := entry.MinimumSize()
|
||||
height += entryHeight
|
||||
}
|
||||
|
||||
if layout.Gap && index > 0 {
|
||||
height += theme.Padding()
|
||||
}
|
||||
}
|
||||
|
||||
if layout.Pad {
|
||||
height += theme.Padding() * 2
|
||||
}
|
||||
return
|
||||
}
|
||||
|
Reference in New Issue
Block a user