Add partial support for text boxes
This commit is contained in:
parent
42ee8f3bf4
commit
069b8898f3
15
box.go
15
box.go
@ -67,7 +67,11 @@ func (this *box) Bounds () image.Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *box) InnerBounds () image.Rectangle {
|
func (this *box) InnerBounds () image.Rectangle {
|
||||||
innerBounds := this.padding.Apply(this.bounds)
|
return this.padding.Apply(this.innerClippingBounds())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *box) innerClippingBounds () image.Rectangle {
|
||||||
|
innerBounds := this.bounds
|
||||||
for _, border := range this.border {
|
for _, border := range this.border {
|
||||||
innerBounds = border.Width.Apply(innerBounds)
|
innerBounds = border.Width.Apply(innerBounds)
|
||||||
}
|
}
|
||||||
@ -97,9 +101,8 @@ func (this *box) SetMinimumSize (width, height int) {
|
|||||||
this.minSize = minSize
|
this.minSize = minSize
|
||||||
|
|
||||||
if this.bounds.Dx() < width || this.bounds.Dy() < height {
|
if this.bounds.Dx() < width || this.bounds.Dy() < height {
|
||||||
this.invalidateLayout()
|
|
||||||
}
|
|
||||||
// TODO: alert the parent
|
// TODO: alert the parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *box) SetPadding (padding tomo.Inset) {
|
func (this *box) SetPadding (padding tomo.Inset) {
|
||||||
@ -187,13 +190,14 @@ func (this *box) OnKeyUp (callback func(key input.Key, numberPad bool)) event.Co
|
|||||||
// -------------------------------------------------------------------------- //
|
// -------------------------------------------------------------------------- //
|
||||||
|
|
||||||
func (this *box) Draw (can canvas.Canvas) {
|
func (this *box) Draw (can canvas.Canvas) {
|
||||||
this.drawBorders(can)
|
if can == nil { return }
|
||||||
pen := can.Pen()
|
pen := can.Pen()
|
||||||
pen.Fill(this.color)
|
pen.Fill(this.color)
|
||||||
pen.Rectangle(this.bounds)
|
pen.Rectangle(this.bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *box) drawBorders (can canvas.Canvas) {
|
func (this *box) drawBorders (can canvas.Canvas) {
|
||||||
|
if can == nil { return }
|
||||||
pen := can.Pen()
|
pen := can.Pen()
|
||||||
bounds := this.bounds
|
bounds := this.bounds
|
||||||
for _, border := range this.border {
|
for _, border := range this.border {
|
||||||
@ -229,7 +233,8 @@ func (this *box) drawBorders (can canvas.Canvas) {
|
|||||||
func (this *box) doDraw () {
|
func (this *box) doDraw () {
|
||||||
if this.canvas == nil { return }
|
if this.canvas == nil { return }
|
||||||
if this.drawer != nil {
|
if this.drawer != nil {
|
||||||
this.drawer.Draw(this.canvas)
|
this.drawBorders(this.canvas)
|
||||||
|
this.drawer.Draw(this.canvas.Clip(this.innerClippingBounds()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ func (this *containerBox) SetGap (gap image.Point) {
|
|||||||
if this.gap == gap { return }
|
if this.gap == gap { return }
|
||||||
this.gap = gap
|
this.gap = gap
|
||||||
this.invalidateLayout()
|
this.invalidateLayout()
|
||||||
|
this.recalculateMinimumSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *containerBox) Add (child tomo.Object) {
|
func (this *containerBox) Add (child tomo.Object) {
|
||||||
@ -68,6 +69,7 @@ func (this *containerBox) Add (child tomo.Object) {
|
|||||||
box.setParent(this)
|
box.setParent(this)
|
||||||
this.children = append(this.children, box)
|
this.children = append(this.children, box)
|
||||||
this.invalidateLayout()
|
this.invalidateLayout()
|
||||||
|
this.recalculateMinimumSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *containerBox) Delete (child tomo.Object) {
|
func (this *containerBox) Delete (child tomo.Object) {
|
||||||
@ -78,6 +80,7 @@ func (this *containerBox) Delete (child tomo.Object) {
|
|||||||
box.setParent(nil)
|
box.setParent(nil)
|
||||||
this.children = remove(this.children, index)
|
this.children = remove(this.children, index)
|
||||||
this.invalidateLayout()
|
this.invalidateLayout()
|
||||||
|
this.recalculateMinimumSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *containerBox) Insert (child, before tomo.Object) {
|
func (this *containerBox) Insert (child, before tomo.Object) {
|
||||||
@ -91,6 +94,7 @@ func (this *containerBox) Insert (child, before tomo.Object) {
|
|||||||
box.setParent(this)
|
box.setParent(this)
|
||||||
this.children = insert(this.children, index, box)
|
this.children = insert(this.children, index, box)
|
||||||
this.invalidateLayout()
|
this.invalidateLayout()
|
||||||
|
this.recalculateMinimumSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *containerBox) Clear () {
|
func (this *containerBox) Clear () {
|
||||||
@ -99,6 +103,7 @@ func (this *containerBox) Clear () {
|
|||||||
}
|
}
|
||||||
this.children = nil
|
this.children = nil
|
||||||
this.invalidateLayout()
|
this.invalidateLayout()
|
||||||
|
this.recalculateMinimumSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *containerBox) Length () int {
|
func (this *containerBox) Length () int {
|
||||||
@ -115,9 +120,11 @@ func (this *containerBox) At (index int) tomo.Object {
|
|||||||
func (this *containerBox) SetLayout (layout tomo.Layout) {
|
func (this *containerBox) SetLayout (layout tomo.Layout) {
|
||||||
this.layout = layout
|
this.layout = layout
|
||||||
this.invalidateLayout()
|
this.invalidateLayout()
|
||||||
|
this.recalculateMinimumSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *containerBox) Draw (can canvas.Canvas) {
|
func (this *containerBox) Draw (can canvas.Canvas) {
|
||||||
|
if can == nil { return }
|
||||||
this.drawBorders(can)
|
this.drawBorders(can)
|
||||||
pen := can.Pen()
|
pen := can.Pen()
|
||||||
pen.Fill(this.color)
|
pen.Fill(this.color)
|
||||||
@ -127,8 +134,6 @@ func (this *containerBox) Draw (can canvas.Canvas) {
|
|||||||
for index, box := range this.children {
|
for index, box := range this.children {
|
||||||
rocks[index] = box.Bounds()
|
rocks[index] = box.Bounds()
|
||||||
}
|
}
|
||||||
// TODO: use shatter algorithm here to optimize amount of pixels drawn
|
|
||||||
// and not draw over child boxes
|
|
||||||
for _, tile := range canvas.Shatter(this.bounds, rocks...) {
|
for _, tile := range canvas.Shatter(this.bounds, rocks...) {
|
||||||
pen.Rectangle(tile)
|
pen.Rectangle(tile)
|
||||||
}
|
}
|
||||||
@ -153,6 +158,10 @@ func (this *containerBox) layoutHints () tomo.LayoutHints {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *containerBox) recalculateMinimumSize () {
|
||||||
|
// TODO calculate minimum size and use SetMinimumSize
|
||||||
|
}
|
||||||
|
|
||||||
func (this *containerBox) doLayout () {
|
func (this *containerBox) doLayout () {
|
||||||
this.box.doLayout()
|
this.box.doLayout()
|
||||||
// TODO: possibly store all children as tomo.Box-es and don't allocate a
|
// TODO: possibly store all children as tomo.Box-es and don't allocate a
|
||||||
@ -163,8 +172,6 @@ func (this *containerBox) doLayout () {
|
|||||||
boxes[index] = box
|
boxes[index] = box
|
||||||
}
|
}
|
||||||
if this.layout != nil {
|
if this.layout != nil {
|
||||||
// TODO maybe we should pass more information into Arrange such
|
|
||||||
// as overflow information and scroll
|
|
||||||
this.layout.Arrange(this.layoutHints(), boxes)
|
this.layout.Arrange(this.layoutHints(), boxes)
|
||||||
}
|
}
|
||||||
if previousContentBounds != this.contentBounds {
|
if previousContentBounds != this.contentBounds {
|
||||||
|
3
go.mod
3
go.mod
@ -4,7 +4,8 @@ go 1.20
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
git.tebibyte.media/tomo/ggfx v0.4.0
|
git.tebibyte.media/tomo/ggfx v0.4.0
|
||||||
git.tebibyte.media/tomo/tomo v0.10.0
|
git.tebibyte.media/tomo/tomo v0.11.0
|
||||||
|
git.tebibyte.media/tomo/typeset v0.3.0
|
||||||
git.tebibyte.media/tomo/xgbkb v1.0.1
|
git.tebibyte.media/tomo/xgbkb v1.0.1
|
||||||
github.com/jezek/xgb v1.1.0
|
github.com/jezek/xgb v1.1.0
|
||||||
github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0
|
github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0
|
||||||
|
39
go.sum
39
go.sum
@ -1,34 +1,14 @@
|
|||||||
git.tebibyte.media/sashakoshka/xgbkb v1.0.0/go.mod h1:pNcE6TRO93vHd6q42SdwLSTTj25L0Yzggz7yLe0JV6Q=
|
git.tebibyte.media/sashakoshka/xgbkb v1.0.0/go.mod h1:pNcE6TRO93vHd6q42SdwLSTTj25L0Yzggz7yLe0JV6Q=
|
||||||
git.tebibyte.media/tomo/ggfx v0.2.0 h1:TSWfNQgnnHewwHiGC3VPFssdOIYCfgqCcOiPX4Sgv00=
|
|
||||||
git.tebibyte.media/tomo/ggfx v0.2.0/go.mod h1:zPoz8BdVQyG2KhEmeGFQBK66V71i6Kj8oVFbrZaCwRA=
|
|
||||||
git.tebibyte.media/tomo/ggfx v0.3.0 h1:h+RfairZTt4jT76KwmJN8OcdU7Ew0vFRqMZFqz3iHaE=
|
|
||||||
git.tebibyte.media/tomo/ggfx v0.3.0/go.mod h1:zPoz8BdVQyG2KhEmeGFQBK66V71i6Kj8oVFbrZaCwRA=
|
|
||||||
git.tebibyte.media/tomo/ggfx v0.4.0 h1:3aUHeGS/yYWRV/zCDubBsXnik5ygkMnj/VgrM5Z75A4=
|
git.tebibyte.media/tomo/ggfx v0.4.0 h1:3aUHeGS/yYWRV/zCDubBsXnik5ygkMnj/VgrM5Z75A4=
|
||||||
git.tebibyte.media/tomo/ggfx v0.4.0/go.mod h1:zPoz8BdVQyG2KhEmeGFQBK66V71i6Kj8oVFbrZaCwRA=
|
git.tebibyte.media/tomo/ggfx v0.4.0/go.mod h1:zPoz8BdVQyG2KhEmeGFQBK66V71i6Kj8oVFbrZaCwRA=
|
||||||
git.tebibyte.media/tomo/tomo v0.4.0 h1:nraUtsmYLSe8BZOolmeBuD+aaMk4duSxI84RqnzflCs=
|
git.tebibyte.media/tomo/tomo v0.11.0 h1:Gh9c/6rDqvhxt/DaNQHYNUfdRmSQTuz9T3F+pb5W6BI=
|
||||||
git.tebibyte.media/tomo/tomo v0.4.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
git.tebibyte.media/tomo/tomo v0.11.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
||||||
git.tebibyte.media/tomo/tomo v0.5.0 h1:bfHNExPewlt+n7nq8LvNiAbemqSllrCY/tAI08r8sAo=
|
git.tebibyte.media/tomo/typeset v0.1.0 h1:ZLwQzy51vUskjg1nB4Emjag8VXn3ki2jEkE19kwVQ4c=
|
||||||
git.tebibyte.media/tomo/tomo v0.5.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
git.tebibyte.media/tomo/typeset v0.1.0/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
|
||||||
git.tebibyte.media/tomo/tomo v0.5.1 h1:APOTY+YSV8JJwNmJsKFYzBYLPUy3DqNr49rrSspOKZ8=
|
git.tebibyte.media/tomo/typeset v0.2.0 h1:7DcnB0sW12eL+MxkEMv99eVG2IQxsZHDDK6pz6VE1O8=
|
||||||
git.tebibyte.media/tomo/tomo v0.5.1/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
git.tebibyte.media/tomo/typeset v0.2.0/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
|
||||||
git.tebibyte.media/tomo/tomo v0.6.0 h1:/gjY6neXEqyKQ2Ye05mZi3yIOvsRVyIKSddvCySGN2Y=
|
git.tebibyte.media/tomo/typeset v0.3.0 h1:9koJzy0bguBHjlesrHpXK8odIVEMmQRBIFIRXDhv7Bk=
|
||||||
git.tebibyte.media/tomo/tomo v0.6.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
git.tebibyte.media/tomo/typeset v0.3.0/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
|
||||||
git.tebibyte.media/tomo/tomo v0.6.1 h1:XdtHfF2xhz9pZXqyrwSsPaore/8PHVqFrnT4NwlBOhY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.6.1/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.7.0 h1:dUYBB/gZzmkiKR8Cq/nmEQGwMqVE01CnQFtvjmInif0=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.7.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.7.1 h1:CHOBGel7Acp88cVW+5SEIx41cRdwuuP/niSSp9/CRRg=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.7.1/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.7.2 h1:15dMJm4Sm339b23o9RZSq87u99SaF2q+b5CRB5P58fA=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.7.2/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.7.3 h1:eHwuYKe+0nLWoEfPZid8njirxmWY3dFmdY+PsPp1RN0=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.7.3/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.8.0 h1:Sqvos2Huf0mSHFZ0FJrBZiH8Ro/gmQPHCvK6Qr29SBo=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.8.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.9.0 h1:Ow7LaOwPTNogkREDVbxsx827XcyHKzXq3dFSM0TttC4=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.9.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.10.0 h1:SFX4JQt1KgWeX9RnYoUQRj7MyFyb1ld8uDPHFTU2IKU=
|
|
||||||
git.tebibyte.media/tomo/tomo v0.10.0/go.mod h1:lTwjpiHbP4UN/kFw+6FwhG600B+PMKVtMOr7wpd5IUY=
|
|
||||||
git.tebibyte.media/tomo/xgbkb v1.0.1 h1:b3HDUopjdQp1MZrb5Vpil4bOtk3NnNXtfQW27Blw2kE=
|
git.tebibyte.media/tomo/xgbkb v1.0.1 h1:b3HDUopjdQp1MZrb5Vpil4bOtk3NnNXtfQW27Blw2kE=
|
||||||
git.tebibyte.media/tomo/xgbkb v1.0.1/go.mod h1:P5Du0yo5hUsojchW08t+Mds0XPIJXwMi733ZfklzjRw=
|
git.tebibyte.media/tomo/xgbkb v1.0.1/go.mod h1:P5Du0yo5hUsojchW08t+Mds0XPIJXwMi733ZfklzjRw=
|
||||||
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJXZHsaM8b6OLVo6muQUQd4CwkH/D3fnnbHXA=
|
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJXZHsaM8b6OLVo6muQUQd4CwkH/D3fnnbHXA=
|
||||||
@ -42,8 +22,6 @@ github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0/go.mod h1:AHecLyFNy6
|
|||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/image v0.8.0 h1:agUcRXV/+w6L9ryntYYsF2x9fQTMd4T8fiiYXAVW6Jg=
|
|
||||||
golang.org/x/image v0.8.0/go.mod h1:PwLxp3opCYg4WR2WO9P0L6ESnsD6bLTWcw8zanLMVFM=
|
|
||||||
golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
|
golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
|
||||||
golang.org/x/image v0.9.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
|
golang.org/x/image v0.9.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
@ -68,7 +46,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
126
textbox.go
126
textbox.go
@ -1,8 +1,130 @@
|
|||||||
package x
|
package x
|
||||||
|
|
||||||
|
import "image"
|
||||||
|
import "image/color"
|
||||||
|
import "golang.org/x/image/font"
|
||||||
import "git.tebibyte.media/tomo/tomo"
|
import "git.tebibyte.media/tomo/tomo"
|
||||||
|
import "git.tebibyte.media/tomo/typeset"
|
||||||
|
import "git.tebibyte.media/tomo/tomo/event"
|
||||||
|
import "git.tebibyte.media/tomo/tomo/canvas"
|
||||||
|
|
||||||
|
type textBox struct {
|
||||||
|
*box
|
||||||
|
|
||||||
|
hOverflow, vOverflow bool
|
||||||
|
contentBounds image.Rectangle
|
||||||
|
scroll image.Point
|
||||||
|
|
||||||
|
text string
|
||||||
|
textColor color.Color
|
||||||
|
face font.Face
|
||||||
|
hAlign tomo.Align
|
||||||
|
|
||||||
|
drawer typeset.Drawer
|
||||||
|
|
||||||
|
on struct {
|
||||||
|
contentBoundsChange event.FuncBroadcaster
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (backend *Backend) NewTextBox() tomo.TextBox {
|
func (backend *Backend) NewTextBox() tomo.TextBox {
|
||||||
// TODO
|
box := &textBox {
|
||||||
return nil
|
box: backend.NewBox().(*box),
|
||||||
|
textColor: color.Black,
|
||||||
|
}
|
||||||
|
box.box.drawer = box
|
||||||
|
box.outer = box
|
||||||
|
return box
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) SetOverflow (horizontal, vertical bool) {
|
||||||
|
if this.hOverflow == horizontal && this.vOverflow == vertical { return }
|
||||||
|
this.hOverflow = horizontal
|
||||||
|
this.vOverflow = vertical
|
||||||
|
this.invalidateLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) ContentBounds () image.Rectangle {
|
||||||
|
return this.contentBounds
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) ScrollTo (point image.Point) {
|
||||||
|
// TODO: constrain scroll
|
||||||
|
this.scroll = point
|
||||||
|
this.invalidateLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) OnContentBoundsChange (callback func()) event.Cookie {
|
||||||
|
return this.on.contentBoundsChange.Connect(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) SetText (text string) {
|
||||||
|
if this.text == text { return }
|
||||||
|
this.text = text
|
||||||
|
this.drawer.SetText([]rune(text))
|
||||||
|
this.recalculateMinimumSize()
|
||||||
|
this.invalidateLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) SetTextColor (c color.Color) {
|
||||||
|
if this.textColor == c { return }
|
||||||
|
this.textColor = c
|
||||||
|
this.invalidateDraw()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) SetFace (face font.Face) {
|
||||||
|
if this.face == face { return }
|
||||||
|
this.face = face
|
||||||
|
this.drawer.SetFace(face)
|
||||||
|
this.recalculateMinimumSize()
|
||||||
|
this.invalidateLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) SetHAlign (align tomo.Align) {
|
||||||
|
if this.hAlign == align { return }
|
||||||
|
this.hAlign = align
|
||||||
|
|
||||||
|
switch align {
|
||||||
|
case tomo.AlignStart: this.drawer.SetAlign(typeset.AlignLeft)
|
||||||
|
case tomo.AlignMiddle: this.drawer.SetAlign(typeset.AlignCenter)
|
||||||
|
case tomo.AlignEnd: this.drawer.SetAlign(typeset.AlignRight)
|
||||||
|
case tomo.AlignEven: this.drawer.SetAlign(typeset.AlignJustify)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.invalidateDraw()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) SetVAlign (align tomo.Align) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) Draw (can canvas.Canvas) {
|
||||||
|
if can == nil { return }
|
||||||
|
this.drawBorders(can)
|
||||||
|
pen := can.Pen()
|
||||||
|
pen.Fill(this.color)
|
||||||
|
pen.Rectangle(can.Bounds())
|
||||||
|
|
||||||
|
if this.face == nil { return }
|
||||||
|
offset := this.InnerBounds().Min.
|
||||||
|
Sub(this.scroll).
|
||||||
|
Sub(this.drawer.LayoutBoundsSpace().Min)
|
||||||
|
this.drawer.Draw(can, this.textColor, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) recalculateMinimumSize () {
|
||||||
|
// TODO calculate minimum size and use SetMinimumSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *textBox) doLayout () {
|
||||||
|
this.box.doLayout()
|
||||||
|
previousContentBounds := this.contentBounds
|
||||||
|
|
||||||
|
this.contentBounds = this.drawer.LayoutBoundsSpace()
|
||||||
|
this.contentBounds = this.contentBounds.Sub(this.contentBounds.Min)
|
||||||
|
this.contentBounds = this.contentBounds.Sub(this.scroll)
|
||||||
|
|
||||||
|
if previousContentBounds != this.contentBounds {
|
||||||
|
this.on.contentBoundsChange.Broadcast()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user