hehe
This commit is contained in:
parent
4c79d6772c
commit
53d4683bd1
42
box.go
42
box.go
@ -11,6 +11,7 @@ import "git.tebibyte.media/tomo/tomo/canvas"
|
||||
type box struct {
|
||||
backend *Backend
|
||||
parent parent
|
||||
outer anyBox
|
||||
|
||||
bounds image.Rectangle
|
||||
minSize image.Point
|
||||
@ -45,9 +46,12 @@ type box struct {
|
||||
}
|
||||
|
||||
func (backend *Backend) NewBox() tomo.Box {
|
||||
return &box {
|
||||
box := &box {
|
||||
backend: backend,
|
||||
}
|
||||
box.drawer = box
|
||||
box.outer = box
|
||||
return box
|
||||
}
|
||||
|
||||
func (this *box) Box () tomo.Box {
|
||||
@ -88,10 +92,14 @@ func (this *box) SetBorder (border ...tomo.Border) {
|
||||
}
|
||||
|
||||
func (this *box) SetMinimumSize (width, height int) {
|
||||
this.minSize = image.Pt(width, height)
|
||||
minSize := image.Pt(width, height)
|
||||
if this.minSize == minSize { return }
|
||||
this.minSize = minSize
|
||||
|
||||
if this.bounds.Dx() < width || this.bounds.Dy() < height {
|
||||
this.invalidateLayout()
|
||||
}
|
||||
// TODO: alert the parent
|
||||
}
|
||||
|
||||
func (this *box) SetPadding (padding tomo.Inset) {
|
||||
@ -112,7 +120,7 @@ func (this *box) SetFocused (focused bool) {
|
||||
if this.Focused () && !focused {
|
||||
this.parent.window().focus(nil)
|
||||
} else if !this.Focused() && focused {
|
||||
this.parent.window().focus(this)
|
||||
this.parent.window().focus(this.outer)
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +133,7 @@ func (this *box) SetFocusable (focusable bool) {
|
||||
}
|
||||
|
||||
func (this *box) Focused () bool {
|
||||
return this == this.parent.window().focused
|
||||
return this.outer == this.parent.window().focused
|
||||
}
|
||||
|
||||
func (this *box) Modifiers () input.Modifiers {
|
||||
@ -136,7 +144,7 @@ func (this *box) MousePosition () image.Point {
|
||||
return this.parent.window().mousePosition
|
||||
}
|
||||
|
||||
// ----- event handlers ----------------------------------------------------- //
|
||||
// ----- event handler setters ---------------------------------------------- //
|
||||
func (this *box) OnFocusEnter (callback func()) event.Cookie {
|
||||
return this.on.focusEnter.Connect(callback)
|
||||
}
|
||||
@ -179,8 +187,14 @@ func (this *box) OnKeyUp (callback func(key input.Key, numberPad bool)) event.Co
|
||||
// -------------------------------------------------------------------------- //
|
||||
|
||||
func (this *box) Draw (can canvas.Canvas) {
|
||||
this.drawBorders(can)
|
||||
pen := can.Pen()
|
||||
pen.Fill(this.color)
|
||||
pen.Rectangle(this.bounds)
|
||||
}
|
||||
|
||||
func (this *box) drawBorders (can canvas.Canvas) {
|
||||
pen := can.Pen()
|
||||
bounds := this.bounds
|
||||
for _, border := range this.border {
|
||||
pen.Fill(border.Color[tomo.SideTop])
|
||||
@ -210,15 +224,11 @@ func (this *box) Draw (can canvas.Canvas) {
|
||||
|
||||
bounds = border.Width.Apply(bounds)
|
||||
}
|
||||
pen.Fill(this.color)
|
||||
pen.Rectangle(bounds)
|
||||
}
|
||||
|
||||
func (this *box) doDraw () {
|
||||
if this.canvas == nil { return }
|
||||
if this.drawer == nil {
|
||||
this.Draw(this.canvas)
|
||||
} else {
|
||||
if this.drawer != nil {
|
||||
this.drawer.Draw(this.canvas)
|
||||
}
|
||||
}
|
||||
@ -236,12 +246,12 @@ func (this *box) recursiveRedo () {
|
||||
this.doDraw()
|
||||
}
|
||||
|
||||
func (this *box) invalidateDraw () {
|
||||
if this.parent == nil { return }
|
||||
this.parent.window().invalidateDraw(this)
|
||||
func (this *box) invalidateLayout () {
|
||||
if this.parent == nil || this.parent.window() == nil { return }
|
||||
this.parent.window().invalidateLayout(this.outer)
|
||||
}
|
||||
|
||||
func (this *box) invalidateLayout () {
|
||||
if this.parent == nil { return }
|
||||
this.parent.window().invalidateLayout(this)
|
||||
func (this *box) invalidateDraw () {
|
||||
if this.parent == nil || this.parent.window() == nil { return }
|
||||
this.parent.window().invalidateDraw(this.outer)
|
||||
}
|
||||
|
@ -8,9 +8,11 @@ type canvasBox struct {
|
||||
}
|
||||
|
||||
func (backend *Backend) NewCanvasBox () tomo.CanvasBox {
|
||||
return &canvasBox {
|
||||
box := &canvasBox {
|
||||
box: backend.NewBox().(*box),
|
||||
}
|
||||
box.outer = box
|
||||
return box
|
||||
}
|
||||
|
||||
func (this *canvasBox) Box () tomo.Box {
|
||||
|
172
containerbox.go
172
containerbox.go
@ -1,8 +1,176 @@
|
||||
package x
|
||||
|
||||
import "image"
|
||||
import "image/color"
|
||||
import "git.tebibyte.media/tomo/tomo"
|
||||
import "git.tebibyte.media/tomo/tomo/event"
|
||||
import "git.tebibyte.media/tomo/tomo/canvas"
|
||||
|
||||
type containerBox struct {
|
||||
*box
|
||||
|
||||
hOverflow, vOverflow bool
|
||||
contentBounds image.Rectangle
|
||||
scroll image.Point
|
||||
|
||||
gap tomo.Gap
|
||||
children []anyBox
|
||||
layout tomo.Layout
|
||||
|
||||
on struct {
|
||||
contentBoundsChange event.FuncBroadcaster
|
||||
}
|
||||
}
|
||||
|
||||
func (backend *Backend) NewContainerBox() tomo.ContainerBox {
|
||||
// TODO
|
||||
return nil
|
||||
box := &containerBox {
|
||||
box: backend.NewBox().(*box),
|
||||
}
|
||||
box.drawer = box
|
||||
box.outer = box
|
||||
return box
|
||||
}
|
||||
|
||||
func (this *containerBox) Box () tomo.Box {
|
||||
return this
|
||||
}
|
||||
|
||||
func (this *containerBox) SetOverflow (horizontal, vertical bool) {
|
||||
if this.hOverflow == horizontal && this.vOverflow == vertical { return }
|
||||
this.hOverflow = horizontal
|
||||
this.vOverflow = vertical
|
||||
this.invalidateLayout()
|
||||
}
|
||||
|
||||
func (this *containerBox) ContentBounds () image.Rectangle {
|
||||
return this.contentBounds
|
||||
}
|
||||
|
||||
func (this *containerBox) ScrollTo (point image.Point) {
|
||||
// TODO: constrain scroll
|
||||
this.scroll = point
|
||||
this.invalidateLayout()
|
||||
}
|
||||
|
||||
func (this *containerBox) OnContentBoundsChange (callback func()) event.Cookie {
|
||||
return this.on.contentBoundsChange.Connect(callback)
|
||||
}
|
||||
|
||||
func (this *containerBox) SetGap (gap tomo.Gap) {
|
||||
if this.gap == gap { return }
|
||||
this.gap = gap
|
||||
this.invalidateLayout()
|
||||
}
|
||||
|
||||
func (this *containerBox) Add (child tomo.Object) {
|
||||
box := assertAnyBox(child.Box())
|
||||
if indexOf(this.children, box) > -1 { return }
|
||||
|
||||
box.setParent(this)
|
||||
this.children = append(this.children, box)
|
||||
this.invalidateLayout()
|
||||
}
|
||||
|
||||
func (this *containerBox) Delete (child tomo.Object) {
|
||||
box := assertAnyBox(child.Box())
|
||||
index := indexOf(this.children, box)
|
||||
if index < 0 { return }
|
||||
|
||||
box.setParent(nil)
|
||||
this.children = remove(this.children, index)
|
||||
this.invalidateLayout()
|
||||
}
|
||||
|
||||
func (this *containerBox) Insert (child, before tomo.Object) {
|
||||
box := assertAnyBox(child.Box())
|
||||
if indexOf(this.children, box) > -1 { return }
|
||||
|
||||
beforeBox := assertAnyBox(before.Box())
|
||||
index := indexOf(this.children, beforeBox)
|
||||
if index < 0 { return }
|
||||
|
||||
box.setParent(this)
|
||||
this.children = insert(this.children, index, box)
|
||||
this.invalidateLayout()
|
||||
}
|
||||
|
||||
func (this *containerBox) Clear () {
|
||||
for _, box := range this.children {
|
||||
box.setParent(nil)
|
||||
}
|
||||
this.children = nil
|
||||
this.invalidateLayout()
|
||||
}
|
||||
|
||||
func (this *containerBox) Length () int {
|
||||
return len(this.children)
|
||||
}
|
||||
|
||||
func (this *containerBox) At (index int) tomo.Object {
|
||||
if index < 0 || index >= len(this.children) {
|
||||
return nil
|
||||
}
|
||||
return this.children[index]
|
||||
}
|
||||
|
||||
func (this *containerBox) SetLayout (layout tomo.Layout) {
|
||||
this.layout = layout
|
||||
this.invalidateLayout()
|
||||
}
|
||||
|
||||
func (this *containerBox) Draw (can canvas.Canvas) {
|
||||
this.drawBorders(can)
|
||||
pen := can.Pen()
|
||||
pen.Fill(this.color)
|
||||
|
||||
// TODO: do this in doLayout and save the result
|
||||
rocks := make([]image.Rectangle, len(this.children))
|
||||
for index, box := range this.children {
|
||||
rocks[index] = box.Bounds()
|
||||
}
|
||||
// TODO: use shatter algorithm here to optimize amount of pixels drawn
|
||||
// and not draw over child boxes
|
||||
for index, tile := range canvas.Shatter(this.bounds, rocks...) {
|
||||
pen.Fill(color.RGBA { R: uint8(32 * (index + 2)), A: 255 })
|
||||
pen.Rectangle(tile)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *containerBox) window () *window {
|
||||
if this.parent == nil { return nil }
|
||||
return this.parent.window()
|
||||
}
|
||||
|
||||
func (this *containerBox) canvas () canvas.Canvas {
|
||||
return this.box.canvas
|
||||
}
|
||||
|
||||
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 {
|
||||
// TODO maybe we should pass more information into Arrange such
|
||||
// as overflow information and scroll
|
||||
this.layout.Arrange (
|
||||
this.InnerBounds().Sub(this.scroll),
|
||||
this.gap,
|
||||
boxes)
|
||||
}
|
||||
if previousContentBounds != this.contentBounds {
|
||||
this.on.contentBoundsChange.Broadcast()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *containerBox) recursiveRedo () {
|
||||
this.doLayout()
|
||||
this.doDraw()
|
||||
for _, child := range this.children {
|
||||
child.recursiveRedo()
|
||||
}
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@ -4,7 +4,7 @@ go 1.20
|
||||
|
||||
require (
|
||||
git.tebibyte.media/tomo/ggfx v0.3.0
|
||||
git.tebibyte.media/tomo/tomo v0.7.3
|
||||
git.tebibyte.media/tomo/tomo v0.8.0
|
||||
git.tebibyte.media/tomo/xgbkb v1.0.1
|
||||
github.com/jezek/xgb v1.1.0
|
||||
github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0
|
||||
|
2
go.sum
2
go.sum
@ -21,6 +21,8 @@ git.tebibyte.media/tomo/tomo v0.7.2 h1:15dMJm4Sm339b23o9RZSq87u99SaF2q+b5CRB5P58
|
||||
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/xgbkb v1.0.1 h1:b3HDUopjdQp1MZrb5Vpil4bOtk3NnNXtfQW27Blw2kE=
|
||||
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=
|
||||
|
10
system.go
10
system.go
@ -44,6 +44,14 @@ type anyBox interface {
|
||||
recursiveRedo ()
|
||||
}
|
||||
|
||||
func assertAnyBox (unknown tomo.Box) anyBox {
|
||||
if box, ok := unknown.(anyBox); ok {
|
||||
return box
|
||||
} else {
|
||||
panic("foregin box implementation, i did not make this!")
|
||||
}
|
||||
}
|
||||
|
||||
func (window *window) SetRoot (root tomo.Object) {
|
||||
if window.root != nil {
|
||||
window.root.setParent(nil)
|
||||
@ -51,7 +59,7 @@ func (window *window) SetRoot (root tomo.Object) {
|
||||
if root == nil {
|
||||
window.root = nil
|
||||
} else {
|
||||
box := root.Box().(anyBox)
|
||||
box := assertAnyBox(root.Box())
|
||||
box.setParent(window)
|
||||
window.invalidateLayout(box)
|
||||
window.root = box
|
||||
|
20
util.go
Normal file
20
util.go
Normal file
@ -0,0 +1,20 @@
|
||||
package x
|
||||
|
||||
func indexOf[T comparable] (haystack []T, needle T) int {
|
||||
for index, test := range haystack {
|
||||
if test == needle {
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func remove[T any] (slice []T, index int) []T {
|
||||
return append(slice[:index], slice[index + 1:]...)
|
||||
}
|
||||
|
||||
func insert[T any] (slice []T, index int, element T) []T {
|
||||
slice = append(slice[:index + 1], slice[index:]...)
|
||||
slice[index] = element
|
||||
return slice
|
||||
}
|
Reference in New Issue
Block a user