diff --git a/backends/x/selection.go b/backends/x/selection.go index 886dc2c..befe208 100644 --- a/backends/x/selection.go +++ b/backends/x/selection.go @@ -97,11 +97,13 @@ func (request *selectionRequest) convertSelection ( func (request *selectionRequest) die (err error) { request.callback(nil, err) + request.window.system.afterEvent() request.state = selReqStateClosed } func (request *selectionRequest) finalize (data data.Data) { request.callback(data, nil) + request.window.system.afterEvent() request.state = selReqStateClosed } diff --git a/backends/x/system.go b/backends/x/system.go index 50b598f..84ffa23 100644 --- a/backends/x/system.go +++ b/backends/x/system.go @@ -141,11 +141,13 @@ func (system *system) afterEvent () { } func (system *system) layout (entity *entity, force bool) { - if entity == nil || !entity.isContainer { return } + if entity == nil { return } if entity.layoutInvalid == true || force { - entity.element.(tomo.Container).Layout() - entity.layoutInvalid = false - force = true + if element, ok := entity.element.(tomo.Layoutable); ok { + element.Layout() + entity.layoutInvalid = false + force = true + } } for _, child := range entity.children { diff --git a/element.go b/element.go index e91f57f..0b99b04 100644 --- a/element.go +++ b/element.go @@ -15,12 +15,19 @@ type Element interface { Entity () Entity } -// Container is an element capable of containing child elements. +// Layoutable represents an element that needs to perform layout calculations +// before it can draw itself. +type Layoutable interface { + Element + + // Layout causes this element to perform a layout operation. + Layout () +} + +// Container represents an element capable of containing child elements. type Container interface { Element - - // Layout causes this element to arrange its children. - Layout () + Layoutable // DrawBackground causes the element to draw its background pattern to // the specified canvas. The bounds of this canvas specify the area that diff --git a/elements/containers/box.go b/elements/containers/box.go index 516e9ed..9e67f65 100644 --- a/elements/containers/box.go +++ b/elements/containers/box.go @@ -98,7 +98,6 @@ func (element *Box) Layout () { if element.margin { x += marginSize } } } - } func (element *Box) Adopt (child tomo.Element, expand bool) { diff --git a/elements/containers/notdone/scroll.go b/elements/containers/notdone/scroll.go deleted file mode 100644 index f523d4b..0000000 --- a/elements/containers/notdone/scroll.go +++ /dev/null @@ -1,332 +0,0 @@ -package containers - -import "image" -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" -import "git.tebibyte.media/sashakoshka/tomo/elements/core" -import "git.tebibyte.media/sashakoshka/tomo/default/theme" -import "git.tebibyte.media/sashakoshka/tomo/default/config" - -// ScrollContainer is a container that is capable of holding a scrollable -// element. -type ScrollContainer struct { - *core.Core - *core.Propagator - core core.CoreControl - - child tomo.Scrollable - horizontal *elements.ScrollBar - vertical *elements.ScrollBar - - config config.Wrapped - theme theme.Wrapped - - onFocusRequest func () (granted bool) - onFocusMotionRequest func (input.KeynavDirection) (granted bool) -} - -// NewScrollContainer creates a new scroll container with the specified scroll -// bars. -func NewScrollContainer (horizontal, vertical bool) (element *ScrollContainer) { - element = &ScrollContainer { } - element.theme.Case = tomo.C("tomo", "scrollContainer") - element.Core, element.core = core.NewCore(element, element.redoAll) - element.Propagator = core.NewPropagator(element, element.core) - - if horizontal { - element.horizontal = elements.NewScrollBar(false) - element.setUpChild(element.horizontal) - element.horizontal.OnScroll (func (viewport image.Point) { - if element.child != nil { - element.child.ScrollTo(viewport) - } - if element.vertical != nil { - element.vertical.SetBounds ( - element.child.ScrollContentBounds(), - element.child.ScrollViewportBounds()) - } - }) - } - if vertical { - element.vertical = elements.NewScrollBar(true) - element.setUpChild(element.vertical) - element.vertical.OnScroll (func (viewport image.Point) { - if element.child != nil { - element.child.ScrollTo(viewport) - } - if element.horizontal != nil { - element.horizontal.SetBounds ( - element.child.ScrollContentBounds(), - element.child.ScrollViewportBounds()) - } - }) - } - return -} - - -// Adopt adds a scrollable element to the scroll container. The container can -// only contain one scrollable element at a time, and when a new one is adopted -// it replaces the last one. -func (element *ScrollContainer) Adopt (child tomo.Scrollable) { - // disown previous child if it exists - if element.child != nil { - element.disownChild(child) - } - - // adopt new child - element.child = child - if child != nil { - element.setUpChild(child) - } - - element.updateEnabled() - element.updateMinimumSize() - if element.core.HasImage() { - element.redoAll() - element.core.DamageAll() - } -} - -func (element *ScrollContainer) setUpChild (child tomo.Element) { - child.SetParent(element) - if child, ok := child.(tomo.Themeable); ok { - child.SetTheme(element.theme.Theme) - } - if child, ok := child.(tomo.Configurable); ok { - child.SetConfig(element.config.Config) - } -} - -func (element *ScrollContainer) disownChild (child tomo.Scrollable) { - child.DrawTo(nil, image.Rectangle { }, nil) - child.SetParent(nil) - if child, ok := child.(tomo.Focusable); ok { - if child.Focused() { - child.HandleUnfocus() - } - } -} - -func (element *ScrollContainer) Window () tomo.Window { - return element.core.Window() -} - -// NotifyMinimumSizeChange notifies the container that the minimum size of a -// child element has changed. -func (element *ScrollContainer) NotifyMinimumSizeChange (child tomo.Element) { - element.redoAll() - element.core.DamageAll() -} - -// NotifyScrollBoundsChange notifies the container that the scroll bounds or -// axes of a child have changed. -func (element *ScrollContainer) NotifyScrollBoundsChange (child tomo.Scrollable) { - element.updateEnabled() - viewportBounds := element.child.ScrollViewportBounds() - contentBounds := element.child.ScrollContentBounds() - if element.horizontal != nil { - element.horizontal.SetBounds(contentBounds, viewportBounds) - } - if element.vertical != nil { - element.vertical.SetBounds(contentBounds, viewportBounds) - } -} - -// DrawBackground draws a portion of the container's background pattern within -// the specified bounds. The container will not push these changes. -func (element *ScrollContainer) DrawBackground (bounds image.Rectangle) { - element.core.DrawBackgroundBounds ( - element.theme.Pattern(tomo.PatternBackground, tomo.State { }), - bounds) -} - -// SetTheme sets the element's theme. -func (element *ScrollContainer) SetTheme (new tomo.Theme) { - if new == element.theme.Theme { return } - element.theme.Theme = new - element.Propagator.SetTheme(new) - element.updateMinimumSize() - element.redoAll() -} - -// SetConfig sets the element's configuration. -func (element *ScrollContainer) SetConfig (new tomo.Config) { - if new == element.config.Config { return } - element.Propagator.SetConfig(new) - element.updateMinimumSize() - element.redoAll() -} - -func (element *ScrollContainer) HandleScroll ( - x, y int, - deltaX, deltaY float64, -) { - horizontal, vertical := element.child.ScrollAxes() - if !horizontal { deltaX = 0 } - if !vertical { deltaY = 0 } - element.scrollChildBy(int(deltaX), int(deltaY)) -} - -// HandleKeyDown is called when a key is pressed down or repeated while -// this element has keyboard focus. It is important to note that not -// 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 -// time of the key press is given. -func (element *ScrollContainer) HandleKeyDown (key input.Key, modifiers input.Modifiers) { - switch key { - case input.KeyPageUp: - viewport := element.child.ScrollViewportBounds() - element.HandleScroll(0, 0, 0, float64(-viewport.Dy())) - case input.KeyPageDown: - viewport := element.child.ScrollViewportBounds() - element.HandleScroll(0, 0, 0, float64(viewport.Dy())) - default: - element.Propagator.HandleKeyDown(key, modifiers) - } -} - -// HandleKeyUp is called when a key is released while this element has -// keyboard focus. -func (element *ScrollContainer) HandleKeyUp (key input.Key, modifiers input.Modifiers) { } - -// CountChildren returns the amount of children contained within this element. -func (element *ScrollContainer) CountChildren () (count int) { - return 3 -} - -// Child returns the child at the specified index. If the index is out of -// bounds, this method will return nil. -func (element *ScrollContainer) Child (index int) (child tomo.Element) { - switch index { - case 0: return element.child - case 1: - if element.horizontal == nil { - return nil - } else { - return element.horizontal - } - case 2: - if element.vertical == nil { - return nil - } else { - return element.vertical - } - default: return nil - } -} - -func (element *ScrollContainer) redoAll () { - if !element.core.HasImage() { return } - - zr := image.Rectangle { } - if element.child != nil { element.child.DrawTo(nil, zr, nil) } - if element.horizontal != nil { element.horizontal.DrawTo(nil, zr, nil) } - if element.vertical != nil { element.vertical.DrawTo(nil, zr, nil) } - - childBounds, horizontalBounds, verticalBounds := element.layout() - if element.child != nil { - element.child.DrawTo ( - canvas.Cut(element.core, childBounds), - childBounds, element.childDamageCallback) - } - if element.horizontal != nil { - element.horizontal.DrawTo ( - canvas.Cut(element.core, horizontalBounds), - horizontalBounds, element.childDamageCallback) - } - if element.vertical != nil { - element.vertical.DrawTo ( - canvas.Cut(element.core, verticalBounds), - verticalBounds, element.childDamageCallback) - } - element.draw() -} - -func (element *ScrollContainer) scrollChildBy (x, y int) { - if element.child == nil { return } - scrollPoint := - element.child.ScrollViewportBounds().Min. - Add(image.Pt(x, y)) - element.child.ScrollTo(scrollPoint) -} - -func (element *ScrollContainer) childDamageCallback (region image.Rectangle) { - element.core.DamageRegion(region) -} - -func (element *ScrollContainer) layout () ( - child image.Rectangle, - horizontal image.Rectangle, - vertical image.Rectangle, -) { - bounds := element.Bounds() - child = bounds - - if element.horizontal != nil { - _, hMinHeight := element.horizontal.MinimumSize() - child.Max.Y -= hMinHeight - } - if element.vertical != nil { - vMinWidth, _ := element.vertical.MinimumSize() - child.Max.X -= vMinWidth - } - - vertical.Min.X = child.Max.X - vertical.Max.X = bounds.Max.X - vertical.Min.Y = bounds.Min.Y - vertical.Max.Y = child.Max.Y - - horizontal.Min.X = bounds.Min.X - horizontal.Max.X = child.Max.X - horizontal.Min.Y = child.Max.Y - horizontal.Max.Y = bounds.Max.Y - return -} - -func (element *ScrollContainer) draw () { - if element.horizontal != nil && element.vertical != nil { - bounds := element.Bounds() - bounds.Min = image.Pt ( - bounds.Max.X - element.vertical.Bounds().Dx(), - bounds.Max.Y - element.horizontal.Bounds().Dy()) - state := tomo.State { } - deadArea := element.theme.Pattern(tomo.PatternDead, state) - deadArea.Draw(canvas.Cut(element.core, bounds), bounds) - } -} - -func (element *ScrollContainer) updateMinimumSize () { - var width, height int - - if element.child != nil { - width, height = element.child.MinimumSize() - } - if element.horizontal != nil { - hMinWidth, hMinHeight := element.horizontal.MinimumSize() - height += hMinHeight - if hMinWidth > width { - width = hMinWidth - } - } - if element.vertical != nil { - vMinWidth, vMinHeight := element.vertical.MinimumSize() - width += vMinWidth - if vMinHeight > height { - height = vMinHeight - } - } - element.core.SetMinimumSize(width, height) -} - -func (element *ScrollContainer) updateEnabled () { - horizontal, vertical := element.child.ScrollAxes() - if element.horizontal != nil { - element.horizontal.SetEnabled(horizontal) - } - if element.vertical != nil { - element.vertical.SetEnabled(vertical) - } -} diff --git a/elements/containers/scroll.go b/elements/containers/scroll.go new file mode 100644 index 0000000..5c420c4 --- /dev/null +++ b/elements/containers/scroll.go @@ -0,0 +1,197 @@ +package containers + +import "image" +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" +import "git.tebibyte.media/sashakoshka/tomo/default/theme" +import "git.tebibyte.media/sashakoshka/tomo/default/config" + +type Scroll struct { + entity tomo.ContainerEntity + + child tomo.Scrollable + horizontal *elements.ScrollBar + vertical *elements.ScrollBar + + config config.Wrapped + theme theme.Wrapped +} + +func NewScroll (horizontal, vertical bool) (element *Scroll) { + element = &Scroll { } + element.theme.Case = tomo.C("tomo", "scroll") + element.entity = tomo.NewEntity(element).(tomo.ContainerEntity) + + if horizontal { + element.horizontal = elements.NewScrollBar(false) + element.horizontal.OnScroll (func (viewport image.Point) { + if element.child != nil { + element.child.ScrollTo(viewport) + } + if element.vertical != nil { + element.vertical.SetBounds ( + element.child.ScrollContentBounds(), + element.child.ScrollViewportBounds()) + } + }) + element.entity.Adopt(element.horizontal) + } + if vertical { + element.vertical = elements.NewScrollBar(true) + element.vertical.OnScroll (func (viewport image.Point) { + if element.child != nil { + element.child.ScrollTo(viewport) + } + if element.horizontal != nil { + element.horizontal.SetBounds ( + element.child.ScrollContentBounds(), + element.child.ScrollViewportBounds()) + } + }) + element.entity.Adopt(element.vertical) + } + return +} + +func (element *Scroll) Entity () tomo.Entity { + return element.entity +} + +func (element *Scroll) Draw (destination canvas.Canvas) { + if element.horizontal != nil && element.vertical != nil { + bounds := element.entity.Bounds() + bounds.Min = image.Pt ( + bounds.Max.X - element.vertical.Entity().Bounds().Dx(), + bounds.Max.Y - element.horizontal.Entity().Bounds().Dy()) + state := tomo.State { } + deadArea := element.theme.Pattern(tomo.PatternDead, state) + deadArea.Draw(canvas.Cut(destination, bounds), bounds) + } +} + +func (element *Scroll) Layout () { + bounds := element.entity.Bounds() + child := bounds + + iHorizontal := element.entity.IndexOf(element.horizontal) + iVertical := element.entity.IndexOf(element.vertical) + iChild := element.entity.IndexOf(element.child) + + var horizontal, vertical image.Rectangle + + if element.horizontal != nil { + _, hMinHeight := element.entity.ChildMinimumSize(iHorizontal) + child.Max.Y -= hMinHeight + } + if element.vertical != nil { + vMinWidth, _ := element.entity.ChildMinimumSize(iVertical) + child.Max.X -= vMinWidth + } + + horizontal.Min.X = bounds.Min.X + horizontal.Max.X = child.Max.X + horizontal.Min.Y = child.Max.Y + horizontal.Max.Y = bounds.Max.Y + + vertical.Min.X = child.Max.X + vertical.Max.X = bounds.Max.X + vertical.Min.Y = bounds.Min.Y + vertical.Max.Y = child.Max.Y + + if element.horizontal != nil { + element.entity.PlaceChild (iHorizontal, horizontal) + } + if element.vertical != nil { + element.entity.PlaceChild(iVertical, vertical) + } + if element.child != nil { + element.entity.PlaceChild(iChild, child) + } +} + +func (element *Scroll) DrawBackground (destination canvas.Canvas) { + element.entity.DrawBackground(destination) +} + +func (element *Scroll) Adopt (child tomo.Scrollable) { + if element.child != nil { + element.entity.Disown(element.entity.IndexOf(element.child)) + } + if child != nil { + element.entity.Adopt(child) + } + element.child = child + + element.updateEnabled() + element.updateMinimumSize() + element.entity.Invalidate() + element.entity.InvalidateLayout() +} + +func (element *Scroll) HandleChildMinimumSizeChange (tomo.Element) { + element.updateMinimumSize() + element.entity.Invalidate() + element.entity.InvalidateLayout() +} + +func (element *Scroll) HandleChildScrollBoundsChange (tomo.Scrollable) { + element.updateEnabled() + viewportBounds := element.child.ScrollViewportBounds() + contentBounds := element.child.ScrollContentBounds() + if element.horizontal != nil { + element.horizontal.SetBounds(contentBounds, viewportBounds) + } + if element.vertical != nil { + element.vertical.SetBounds(contentBounds, viewportBounds) + } +} + +func (element *Scroll) SetTheme (theme tomo.Theme) { + if theme == element.theme.Theme { return } + element.theme.Theme = theme + element.updateMinimumSize() + element.entity.Invalidate() + element.entity.InvalidateLayout() +} + +func (element *Scroll) SetConfig (config tomo.Config) { + element.config.Config = config +} + +func (element *Scroll) updateMinimumSize () { + var width, height int + + if element.child != nil { + width, height = element.entity.ChildMinimumSize ( + element.entity.IndexOf(element.child)) + } + if element.horizontal != nil { + hMinWidth, hMinHeight := element.entity.ChildMinimumSize ( + element.entity.IndexOf(element.horizontal)) + height += hMinHeight + if hMinWidth > width { + width = hMinWidth + } + } + if element.vertical != nil { + vMinWidth, vMinHeight := element.entity.ChildMinimumSize ( + element.entity.IndexOf(element.vertical)) + width += vMinWidth + if vMinHeight > height { + height = vMinHeight + } + } + element.entity.SetMinimumSize(width, height) +} + +func (element *Scroll) updateEnabled () { + horizontal, vertical := element.child.ScrollAxes() + if element.horizontal != nil { + element.horizontal.SetEnabled(horizontal) + } + if element.vertical != nil { + element.vertical.SetEnabled(vertical) + } +} diff --git a/elements/textbox.go b/elements/textbox.go index f4c0106..5f1ce2f 100644 --- a/elements/textbox.go +++ b/elements/textbox.go @@ -18,6 +18,7 @@ import "git.tebibyte.media/sashakoshka/tomo/default/config" type textBoxEntity interface { tomo.FocusableEntity tomo.ScrollableEntity + tomo.LayoutEntity } // TextBox is a single-line text input. @@ -72,7 +73,6 @@ func (element *TextBox) Entity () tomo.Entity { // Draw causes the element to draw to the specified destination canvas. func (element *TextBox) Draw (destination canvas.Canvas) { bounds := element.entity.Bounds() - element.scrollToCursor() state := element.state() pattern := element.theme.Pattern(tomo.PatternInput, state) @@ -134,6 +134,11 @@ func (element *TextBox) Draw (destination canvas.Canvas) { } } +// Layout causes the element to perform a layout operation. +func (element *TextBox) Layout () { + element.scrollToCursor() +} + func (element *TextBox) HandleFocusChange () { element.entity.Invalidate() } @@ -497,8 +502,8 @@ func (element *TextBox) scrollToCursor () { } else if cursorPosition.X < minX { element.scroll -= minX - cursorPosition.X if element.scroll < 0 { element.scroll = 0 } - element.entity.Invalidate() element.entity.NotifyScrollBoundsChange() + element.entity.Invalidate() } } diff --git a/entity.go b/entity.go index 4bda6d9..dfdede7 100644 --- a/entity.go +++ b/entity.go @@ -31,14 +31,20 @@ type Entity interface { DrawBackground (canvas.Canvas) } +// LayoutEntity is given to elements that support the Layoutable interface. +type LayoutEntity interface { + Entity + + // InvalidateLayout marks the element's layout as invalid. At the end of + // every event, the backend will ask all invalid elements to recalculate + // their layouts. + InvalidateLayout () +} + // ContainerEntity is given to elements that support the Container interface. type ContainerEntity interface { Entity - - // InvalidateLayout marks the element's layout as invalid. At the end of - // every event, the backend will ask all invalid containers to - // recalculate their layouts. - InvalidateLayout () + LayoutEntity // Adopt adds an element as a child. Adopt (child Element) diff --git a/examples/scroll/main.go b/examples/scroll/main.go index 2436bd9..b01a887 100644 --- a/examples/scroll/main.go +++ b/examples/scroll/main.go @@ -1,8 +1,7 @@ package main -import "image" +// import "image" 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/backends/all" import "git.tebibyte.media/sashakoshka/tomo/elements/containers" @@ -14,58 +13,56 @@ func main () { func run () { window, _ := tomo.NewWindow(tomo.Bounds(0, 0, 360, 240)) window.SetTitle("Scroll") - container := containers.NewContainer(layouts.Vertical { true, true }) + container := containers.NewVBox(true, true) window.Adopt(container) textBox := elements.NewTextBox("", copypasta) - scrollContainer := containers.NewScrollContainer(true, false) + scrollContainer := containers.NewScroll(true, false) - disconnectedContainer := containers.NewContainer (layouts.Horizontal { - Gap: true, - }) - list := elements.NewList ( - elements.NewListEntry("This is list item 0", nil), - elements.NewListEntry("This is list item 1", nil), - elements.NewListEntry("This is list item 2", nil), - elements.NewListEntry("This is list item 3", nil), - elements.NewListEntry("This is list item 4", nil), - elements.NewListEntry("This is list item 5", nil), - elements.NewListEntry("This is list item 6", nil), - elements.NewListEntry("This is list item 7", nil), - elements.NewListEntry("This is list item 8", nil), - elements.NewListEntry("This is list item 9", nil), - elements.NewListEntry("This is list item 10", nil), - elements.NewListEntry("This is list item 11", nil), - elements.NewListEntry("This is list item 12", nil), - elements.NewListEntry("This is list item 13", nil), - elements.NewListEntry("This is list item 14", nil), - elements.NewListEntry("This is list item 15", nil), - elements.NewListEntry("This is list item 16", nil), - elements.NewListEntry("This is list item 17", nil), - elements.NewListEntry("This is list item 18", nil), - elements.NewListEntry("This is list item 19", nil), - elements.NewListEntry("This is list item 20", nil)) - list.Collapse(0, 32) - scrollBar := elements.NewScrollBar(true) - list.OnScrollBoundsChange (func () { - scrollBar.SetBounds ( - list.ScrollContentBounds(), - list.ScrollViewportBounds()) - }) - scrollBar.OnScroll (func (viewport image.Point) { - list.ScrollTo(viewport) - }) + disconnectedContainer := containers.NewHBox(false, true) + // list := elements.NewList ( + // elements.NewListEntry("This is list item 0", nil), + // elements.NewListEntry("This is list item 1", nil), + // elements.NewListEntry("This is list item 2", nil), + // elements.NewListEntry("This is list item 3", nil), + // elements.NewListEntry("This is list item 4", nil), + // elements.NewListEntry("This is list item 5", nil), + // elements.NewListEntry("This is list item 6", nil), + // elements.NewListEntry("This is list item 7", nil), + // elements.NewListEntry("This is list item 8", nil), + // elements.NewListEntry("This is list item 9", nil), + // elements.NewListEntry("This is list item 10", nil), + // elements.NewListEntry("This is list item 11", nil), + // elements.NewListEntry("This is list item 12", nil), + // elements.NewListEntry("This is list item 13", nil), + // elements.NewListEntry("This is list item 14", nil), + // elements.NewListEntry("This is list item 15", nil), + // elements.NewListEntry("This is list item 16", nil), + // elements.NewListEntry("This is list item 17", nil), + // elements.NewListEntry("This is list item 18", nil), + // elements.NewListEntry("This is list item 19", nil), + // elements.NewListEntry("This is list item 20", nil)) + // list.Collapse(0, 32) + // scrollBar := elements.NewScrollBar(true) + // list.OnScrollBoundsChange (func () { + // scrollBar.SetBounds ( + // list.ScrollContentBounds(), + // list.ScrollViewportBounds()) + // }) + // scrollBar.OnScroll (func (viewport image.Point) { + // list.ScrollTo(viewport) + // }) scrollContainer.Adopt(textBox) container.Adopt(elements.NewLabel("A ScrollContainer:", false), false) container.Adopt(scrollContainer, false) - disconnectedContainer.Adopt(list, false) + // disconnectedContainer.Adopt(list, false) disconnectedContainer.Adopt (elements.NewLabel ( "Notice how the scroll bar to the right can be used to " + "control the list, despite not even touching it. It is " + "indeed a thing you can do. It is also terrible UI design so " + "don't do it.", true), true) - disconnectedContainer.Adopt(scrollBar, false) + // disconnectedContainer.Adopt(scrollBar, false) container.Adopt(disconnectedContainer, true) window.OnClose(tomo.Stop)