Improvements to TextBox and ContainerBox
This commit is contained in:
parent
069b8898f3
commit
34ca98f865
15
box.go
15
box.go
@ -70,6 +70,10 @@ func (this *box) InnerBounds () image.Rectangle {
|
||||
return this.padding.Apply(this.innerClippingBounds())
|
||||
}
|
||||
|
||||
func (this *box) MinimumSize () image.Point {
|
||||
return this.minSize
|
||||
}
|
||||
|
||||
func (this *box) innerClippingBounds () image.Rectangle {
|
||||
innerBounds := this.bounds
|
||||
for _, border := range this.border {
|
||||
@ -95,13 +99,12 @@ func (this *box) SetBorder (border ...tomo.Border) {
|
||||
this.invalidateLayout()
|
||||
}
|
||||
|
||||
func (this *box) SetMinimumSize (width, height int) {
|
||||
minSize := image.Pt(width, height)
|
||||
if this.minSize == minSize { return }
|
||||
this.minSize = minSize
|
||||
func (this *box) SetMinimumSize (size image.Point) {
|
||||
if this.minSize == size { return }
|
||||
this.minSize = size
|
||||
|
||||
if this.bounds.Dx() < width || this.bounds.Dy() < height {
|
||||
// TODO: alert the parent
|
||||
if this.parent != nil {
|
||||
this.parent.notifyMinimumSizeChange(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ type containerBox struct {
|
||||
scroll image.Point
|
||||
|
||||
gap image.Point
|
||||
children []anyBox
|
||||
children []tomo.Box
|
||||
layout tomo.Layout
|
||||
|
||||
on struct {
|
||||
@ -64,7 +64,7 @@ func (this *containerBox) SetGap (gap image.Point) {
|
||||
|
||||
func (this *containerBox) Add (child tomo.Object) {
|
||||
box := assertAnyBox(child.Box())
|
||||
if indexOf(this.children, box) > -1 { return }
|
||||
if indexOf(this.children, tomo.Box(box)) > -1 { return }
|
||||
|
||||
box.setParent(this)
|
||||
this.children = append(this.children, box)
|
||||
@ -74,7 +74,7 @@ func (this *containerBox) Add (child tomo.Object) {
|
||||
|
||||
func (this *containerBox) Delete (child tomo.Object) {
|
||||
box := assertAnyBox(child.Box())
|
||||
index := indexOf(this.children, box)
|
||||
index := indexOf(this.children, tomo.Box(box))
|
||||
if index < 0 { return }
|
||||
|
||||
box.setParent(nil)
|
||||
@ -85,21 +85,21 @@ func (this *containerBox) Delete (child tomo.Object) {
|
||||
|
||||
func (this *containerBox) Insert (child, before tomo.Object) {
|
||||
box := assertAnyBox(child.Box())
|
||||
if indexOf(this.children, box) > -1 { return }
|
||||
if indexOf(this.children, tomo.Box(box)) > -1 { return }
|
||||
|
||||
beforeBox := assertAnyBox(before.Box())
|
||||
index := indexOf(this.children, beforeBox)
|
||||
index := indexOf(this.children, tomo.Box(beforeBox))
|
||||
if index < 0 { return }
|
||||
|
||||
box.setParent(this)
|
||||
this.children = insert(this.children, index, box)
|
||||
this.children = insert(this.children, index, tomo.Box(box))
|
||||
this.invalidateLayout()
|
||||
this.recalculateMinimumSize()
|
||||
}
|
||||
|
||||
func (this *containerBox) Clear () {
|
||||
for _, box := range this.children {
|
||||
box.setParent(nil)
|
||||
box.(anyBox).setParent(nil)
|
||||
}
|
||||
this.children = nil
|
||||
this.invalidateLayout()
|
||||
@ -148,6 +148,16 @@ func (this *containerBox) canvas () canvas.Canvas {
|
||||
return this.box.canvas
|
||||
}
|
||||
|
||||
func (this *containerBox) notifyMinimumSizeChange (child anyBox) {
|
||||
this.recalculateMinimumSize()
|
||||
|
||||
size := child.MinimumSize()
|
||||
bounds := child.Bounds()
|
||||
if bounds.Dx() < size.X || bounds.Dy() < size.Y {
|
||||
this.invalidateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *containerBox) layoutHints () tomo.LayoutHints {
|
||||
innerBounds := this.InnerBounds().Sub(this.scroll)
|
||||
return tomo.LayoutHints {
|
||||
@ -159,20 +169,21 @@ func (this *containerBox) layoutHints () tomo.LayoutHints {
|
||||
}
|
||||
|
||||
func (this *containerBox) recalculateMinimumSize () {
|
||||
// TODO calculate minimum size and use SetMinimumSize
|
||||
if this.layout == nil {
|
||||
this.SetMinimumSize(image.Point { })
|
||||
return
|
||||
}
|
||||
minimum := this.layout.MinimumSize(this.layoutHints(), this.children)
|
||||
minimum.X += this.padding.Horizontal()
|
||||
minimum.Y += this.padding.Vertical()
|
||||
this.SetMinimumSize(minimum)
|
||||
}
|
||||
|
||||
func (this *containerBox) doLayout () {
|
||||
this.box.doLayout()
|
||||
// TODO: possibly store all children as tomo.Box-es and don't allocate a
|
||||
// slice here
|
||||
previousContentBounds := this.contentBounds
|
||||
boxes := make([]tomo.Box, len(this.children))
|
||||
for index, box := range this.children {
|
||||
boxes[index] = box
|
||||
}
|
||||
if this.layout != nil {
|
||||
this.layout.Arrange(this.layoutHints(), boxes)
|
||||
this.layout.Arrange(this.layoutHints(), this.children)
|
||||
}
|
||||
if previousContentBounds != this.contentBounds {
|
||||
this.on.contentBoundsChange.Broadcast()
|
||||
@ -183,6 +194,6 @@ func (this *containerBox) recursiveRedo () {
|
||||
this.doLayout()
|
||||
this.doDraw()
|
||||
for _, child := range this.children {
|
||||
child.recursiveRedo()
|
||||
child.(anyBox).recursiveRedo()
|
||||
}
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -4,7 +4,7 @@ go 1.20
|
||||
|
||||
require (
|
||||
git.tebibyte.media/tomo/ggfx v0.4.0
|
||||
git.tebibyte.media/tomo/tomo v0.11.0
|
||||
git.tebibyte.media/tomo/tomo v0.12.0
|
||||
git.tebibyte.media/tomo/typeset v0.3.0
|
||||
git.tebibyte.media/tomo/xgbkb v1.0.1
|
||||
github.com/jezek/xgb v1.1.0
|
||||
|
2
go.sum
2
go.sum
@ -3,6 +3,8 @@ git.tebibyte.media/tomo/ggfx v0.4.0 h1:3aUHeGS/yYWRV/zCDubBsXnik5ygkMnj/VgrM5Z75
|
||||
git.tebibyte.media/tomo/ggfx v0.4.0/go.mod h1:zPoz8BdVQyG2KhEmeGFQBK66V71i6Kj8oVFbrZaCwRA=
|
||||
git.tebibyte.media/tomo/tomo v0.11.0 h1:Gh9c/6rDqvhxt/DaNQHYNUfdRmSQTuz9T3F+pb5W6BI=
|
||||
git.tebibyte.media/tomo/tomo v0.11.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
||||
git.tebibyte.media/tomo/tomo v0.12.0 h1:MwcudNzo7hSeiEWGSLt6lxJGK3itxTSgdggaZoHZLJo=
|
||||
git.tebibyte.media/tomo/tomo v0.12.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
||||
git.tebibyte.media/tomo/typeset v0.1.0 h1:ZLwQzy51vUskjg1nB4Emjag8VXn3ki2jEkE19kwVQ4c=
|
||||
git.tebibyte.media/tomo/typeset v0.1.0/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
|
||||
git.tebibyte.media/tomo/typeset v0.2.0 h1:7DcnB0sW12eL+MxkEMv99eVG2IQxsZHDDK6pz6VE1O8=
|
||||
|
@ -34,6 +34,7 @@ func (set *boxSet) Pop () anyBox {
|
||||
type parent interface {
|
||||
window () *window
|
||||
canvas () canvas.Canvas
|
||||
notifyMinimumSizeChange (anyBox)
|
||||
}
|
||||
|
||||
type anyBox interface {
|
||||
@ -64,6 +65,7 @@ func (window *window) SetRoot (root tomo.Object) {
|
||||
window.invalidateLayout(box)
|
||||
window.root = box
|
||||
}
|
||||
window.recalculateMinimumSize()
|
||||
}
|
||||
|
||||
func (window *window) window () *window {
|
||||
@ -74,6 +76,10 @@ func (window *window) canvas () canvas.Canvas {
|
||||
return window.xCanvas
|
||||
}
|
||||
|
||||
func (window *window) notifyMinimumSizeChange (anyBox) {
|
||||
window.recalculateMinimumSize()
|
||||
}
|
||||
|
||||
func (window *window) invalidateDraw (box anyBox) {
|
||||
window.needDraw.Add(box)
|
||||
}
|
||||
|
14
textbox.go
14
textbox.go
@ -31,6 +31,8 @@ func (backend *Backend) NewTextBox() tomo.TextBox {
|
||||
box := &textBox {
|
||||
box: backend.NewBox().(*box),
|
||||
textColor: color.Black,
|
||||
hOverflow: false,
|
||||
vOverflow: false,
|
||||
}
|
||||
box.box.drawer = box
|
||||
box.outer = box
|
||||
@ -120,6 +122,18 @@ func (this *textBox) doLayout () {
|
||||
this.box.doLayout()
|
||||
previousContentBounds := this.contentBounds
|
||||
|
||||
innerBounds := this.InnerBounds()
|
||||
if this.hOverflow {
|
||||
this.drawer.SetMaxWidth(0)
|
||||
} else {
|
||||
this.drawer.SetMaxWidth(innerBounds.Dx())
|
||||
}
|
||||
if this.vOverflow {
|
||||
this.drawer.SetMaxHeight(0)
|
||||
} else {
|
||||
this.drawer.SetMaxHeight(innerBounds.Dy())
|
||||
}
|
||||
|
||||
this.contentBounds = this.drawer.LayoutBoundsSpace()
|
||||
this.contentBounds = this.contentBounds.Sub(this.contentBounds.Min)
|
||||
this.contentBounds = this.contentBounds.Sub(this.scroll)
|
||||
|
24
window.go
24
window.go
@ -128,7 +128,7 @@ func (backend *Backend) newWindow (
|
||||
// Connect(backend.x, window.xWindow.Id)
|
||||
|
||||
window.metrics.bounds = bounds
|
||||
window.setMinimumSize(8, 8)
|
||||
window.setMinimumSize(image.Pt(8, 8))
|
||||
|
||||
backend.windows[window.xWindow.Id] = window
|
||||
|
||||
@ -351,21 +351,29 @@ func (window *window) pushRegion (region image.Rectangle) {
|
||||
subCanvas.(*xcanvas.Canvas).Push(window.xWindow.Id)
|
||||
}
|
||||
|
||||
func (window *window) setMinimumSize (width, height int) {
|
||||
if width < 8 { width = 8 }
|
||||
if height < 8 { height = 8 }
|
||||
func (window *window) recalculateMinimumSize () {
|
||||
rootMinimum := image.Point { }
|
||||
if window.root != nil {
|
||||
rootMinimum = window.root.MinimumSize()
|
||||
}
|
||||
window.setMinimumSize(rootMinimum)
|
||||
}
|
||||
|
||||
func (window *window) setMinimumSize (size image.Point) {
|
||||
if size.X < 8 { size.X = 8 }
|
||||
if size.Y < 8 { size.Y = 8 }
|
||||
icccm.WmNormalHintsSet (
|
||||
window.backend.x,
|
||||
window.xWindow.Id,
|
||||
&icccm.NormalHints {
|
||||
Flags: icccm.SizeHintPMinSize,
|
||||
MinWidth: uint(width),
|
||||
MinHeight: uint(height),
|
||||
MinWidth: uint(size.X),
|
||||
MinHeight: uint(size.Y),
|
||||
})
|
||||
newWidth := window.metrics.bounds.Dx()
|
||||
newHeight := window.metrics.bounds.Dy()
|
||||
if newWidth < width { newWidth = width }
|
||||
if newHeight < height { newHeight = height }
|
||||
if newWidth < size.X { newWidth = size.X }
|
||||
if newHeight < size.Y { newHeight = size.Y }
|
||||
if newWidth != window.metrics.bounds.Dx() ||
|
||||
newHeight != window.metrics.bounds.Dy() {
|
||||
window.xWindow.Resize(newWidth, newHeight)
|
||||
|
Reference in New Issue
Block a user