diff --git a/box.go b/box.go index e163827..039975a 100644 --- a/box.go +++ b/box.go @@ -74,12 +74,19 @@ func (this *box) MinimumSize () image.Point { return this.minSize } -func (this *box) innerClippingBounds () image.Rectangle { - innerBounds := this.bounds +func (this *box) borderSum () tomo.Inset { + sum := tomo.Inset { } for _, border := range this.border { - innerBounds = border.Width.Apply(innerBounds) + sum[0] += border.Width[0] + sum[1] += border.Width[1] + sum[2] += border.Width[2] + sum[3] += border.Width[3] } - return innerBounds + return sum +} + +func (this *box) innerClippingBounds () image.Rectangle { + return this.borderSum().Apply(this.bounds) } func (this *box) SetBounds (bounds image.Rectangle) { @@ -97,6 +104,7 @@ func (this *box) SetColor (c color.Color) { func (this *box) SetBorder (border ...tomo.Border) { this.border = border this.invalidateLayout() + this.recalculateMinimumSize() } func (this *box) SetMinimumSize (size image.Point) { @@ -112,6 +120,7 @@ func (this *box) SetPadding (padding tomo.Inset) { if this.padding == padding { return } this.padding = padding this.invalidateLayout() + this.recalculateMinimumSize() } func (this *box) SetDNDData (dat data.Data) { @@ -263,3 +272,9 @@ func (this *box) invalidateDraw () { if this.parent == nil || this.parent.window() == nil { return } this.parent.window().invalidateDraw(this.outer) } + +func (this *box) recalculateMinimumSize () { + if this.outer != this { + this.outer.recalculateMinimumSize() + } +} diff --git a/containerbox.go b/containerbox.go index c581c70..c2fcc39 100644 --- a/containerbox.go +++ b/containerbox.go @@ -9,6 +9,7 @@ type containerBox struct { *box hOverflow, vOverflow bool + hAlign, vAlign tomo.Align contentBounds image.Rectangle scroll image.Point @@ -41,6 +42,13 @@ func (this *containerBox) SetOverflow (horizontal, vertical bool) { this.invalidateLayout() } +func (this *containerBox) SetAlign (x, y tomo.Align) { + if this.hAlign == x && this.vAlign == y { return } + this.hAlign = x + this.vAlign = y + this.invalidateLayout() +} + func (this *containerBox) ContentBounds () image.Rectangle { return this.contentBounds } @@ -176,6 +184,9 @@ func (this *containerBox) recalculateMinimumSize () { minimum := this.layout.MinimumSize(this.layoutHints(), this.children) minimum.X += this.padding.Horizontal() minimum.Y += this.padding.Vertical() + borderSum := this.borderSum() + minimum.X += borderSum.Horizontal() + minimum.Y += borderSum.Vertical() this.SetMinimumSize(minimum) } diff --git a/go.mod b/go.mod index 6d53af8..2790075 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( git.tebibyte.media/tomo/ggfx v0.4.0 - git.tebibyte.media/tomo/tomo v0.12.0 + git.tebibyte.media/tomo/tomo v0.14.0 git.tebibyte.media/tomo/typeset v0.3.0 git.tebibyte.media/tomo/xgbkb v1.0.1 github.com/jezek/xgb v1.1.0 diff --git a/go.sum b/go.sum index dc19c62..16d7e74 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,10 @@ git.tebibyte.media/tomo/tomo v0.11.0 h1:Gh9c/6rDqvhxt/DaNQHYNUfdRmSQTuz9T3F+pb5W 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/tomo v0.13.0 h1:xQvEia1vDUfq3QkpU3De72z53ON+y8I6HMP8TDtcS2k= +git.tebibyte.media/tomo/tomo v0.13.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY= +git.tebibyte.media/tomo/tomo v0.14.0 h1:cMCOLjBEH9OtF+CODn0XFWa9liE0keMnLWs3t66I+Zw= +git.tebibyte.media/tomo/tomo v0.14.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= diff --git a/system.go b/system.go index 79a0bc3..7c34052 100644 --- a/system.go +++ b/system.go @@ -43,6 +43,7 @@ type anyBox interface { doLayout () setParent (parent) recursiveRedo () + recalculateMinimumSize () } func assertAnyBox (unknown tomo.Box) anyBox { diff --git a/textbox.go b/textbox.go index 3b6a20e..d02af74 100644 --- a/textbox.go +++ b/textbox.go @@ -18,6 +18,7 @@ type textBox struct { text string textColor color.Color face font.Face + wrap bool hAlign tomo.Align drawer typeset.Drawer @@ -31,8 +32,6 @@ 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 @@ -82,11 +81,18 @@ func (this *textBox) SetFace (face font.Face) { this.invalidateLayout() } -func (this *textBox) SetHAlign (align tomo.Align) { - if this.hAlign == align { return } - this.hAlign = align +func (this *textBox) SetWrap (wrap bool) { + if this.wrap == wrap { return } + this.wrap = wrap + this.recalculateMinimumSize() + this.invalidateLayout() +} - switch align { +func (this *textBox) SetAlign (x, y tomo.Align) { + if this.hAlign == x { return } + this.hAlign = x + + switch x { case tomo.AlignStart: this.drawer.SetAlign(typeset.AlignLeft) case tomo.AlignMiddle: this.drawer.SetAlign(typeset.AlignCenter) case tomo.AlignEnd: this.drawer.SetAlign(typeset.AlignRight) @@ -96,10 +102,6 @@ func (this *textBox) SetHAlign (align tomo.Align) { this.invalidateDraw() } -func (this *textBox) SetVAlign (align tomo.Align) { - // TODO -} - func (this *textBox) Draw (can canvas.Canvas) { if can == nil { return } this.drawBorders(can) @@ -114,8 +116,30 @@ func (this *textBox) Draw (can canvas.Canvas) { this.drawer.Draw(can, this.textColor, offset) } +func (this *textBox) normalizedLayoutBoundsSpace () image.Rectangle { + bounds := this.drawer.LayoutBoundsSpace() + return bounds.Sub(bounds.Min) +} + func (this *textBox) recalculateMinimumSize () { - // TODO calculate minimum size and use SetMinimumSize + minimum := image.Pt ( + this.drawer.Em().Round(), + this.drawer.LineHeight().Round()) + + textSize := this.normalizedLayoutBoundsSpace() + if !this.hOverflow && !this.wrap { + minimum.X = textSize.Dx() + } + if !this.vOverflow { + minimum.Y = textSize.Dy() + } + + minimum.X += this.padding.Horizontal() + minimum.Y += this.padding.Vertical() + borderSum := this.borderSum() + minimum.X += borderSum.Horizontal() + minimum.Y += borderSum.Vertical() + this.SetMinimumSize(minimum) } func (this *textBox) doLayout () { @@ -123,7 +147,7 @@ func (this *textBox) doLayout () { previousContentBounds := this.contentBounds innerBounds := this.InnerBounds() - if this.hOverflow { + if this.hOverflow && !this.wrap { this.drawer.SetMaxWidth(0) } else { this.drawer.SetMaxWidth(innerBounds.Dx()) @@ -134,9 +158,7 @@ func (this *textBox) doLayout () { 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) + this.contentBounds = this.normalizedLayoutBoundsSpace().Sub(this.scroll) if previousContentBounds != this.contentBounds { this.on.contentBoundsChange.Broadcast()