Document works now

This commit is contained in:
Sasha Koshka 2023-04-16 16:48:32 -04:00
parent 7d4ddaf387
commit a7de6c7f3b
4 changed files with 246 additions and 10 deletions

View File

@ -7,8 +7,9 @@ import "git.tebibyte.media/sashakoshka/tomo/shatter"
import "git.tebibyte.media/sashakoshka/tomo/default/theme" import "git.tebibyte.media/sashakoshka/tomo/default/theme"
type scratchEntry struct { type scratchEntry struct {
expand bool expand bool
minimum float64 minSize float64
minBreadth float64
} }
// Box is a container that lays out its children horizontally or vertically. // Box is a container that lays out its children horizontally or vertically.
@ -80,7 +81,7 @@ func (element *Box) Layout () {
var size float64; if entry.expand { var size float64; if entry.expand {
size = expandingElementSize size = expandingElementSize
} else { } else {
size = entry.minimum size = entry.minSize
} }
var childBounds image.Rectangle; if element.vertical { var childBounds image.Rectangle; if element.vertical {
@ -170,7 +171,7 @@ func (element *Box) freeSpace () (space float64, nExpanding float64) {
if entry.expand { if entry.expand {
nExpanding ++; nExpanding ++;
} else { } else {
space -= float64(entry.minimum) space -= float64(entry.minSize)
} }
} }
@ -204,7 +205,7 @@ func (element *Box) updateMinimumSize () {
key := element.entity.Child(index) key := element.entity.Child(index)
entry := element.scratch[key] entry := element.scratch[key]
entry.minimum = float64(childSize) entry.minSize = float64(childSize)
element.scratch[key] = entry element.scratch[key] = entry
if childBreadth > breadth { if childBreadth > breadth {

View File

@ -0,0 +1,235 @@
package containers
import "image"
import "git.tebibyte.media/sashakoshka/tomo"
import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/shatter"
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
type documentEntity interface {
tomo.ContainerEntity
tomo.ScrollableEntity
}
type Document struct {
entity documentEntity
scratch map[tomo.Element] scratchEntry
scroll image.Point
contentBounds image.Rectangle
theme theme.Wrapped
onScrollBoundsChange func ()
}
func NewDocument () (element *Document) {
element = &Document { }
element.scratch = make(map[tomo.Element] scratchEntry)
element.theme.Case = tomo.C("tomo", "document")
element.entity = tomo.NewEntity(element).(documentEntity)
return
}
func (element *Document) Entity () tomo.Entity {
return element.entity
}
func (element *Document) Draw (destination canvas.Canvas) {
rocks := make([]image.Rectangle, element.entity.CountChildren())
for index := 0; index < element.entity.CountChildren(); index ++ {
rocks[index] = element.entity.Child(index).Entity().Bounds()
}
tiles := shatter.Shatter(element.entity.Bounds(), rocks...)
for _, tile := range tiles {
element.entity.DrawBackground(canvas.Cut(destination, tile))
}
}
func (element *Document) Layout () {
margin := element.theme.Margin(tomo.PatternBackground)
padding := element.theme.Padding(tomo.PatternBackground)
bounds := padding.Apply(element.entity.Bounds())
element.contentBounds = image.Rectangle { }
dot := bounds.Min.Sub(element.scroll)
xStart := dot.X
rowHeight := 0
nextLine := func () {
dot.X = xStart
dot.Y += margin.Y
dot.Y += rowHeight
rowHeight = 0
}
for index := 0; index < element.entity.CountChildren(); index ++ {
child := element.entity.Child(index)
entry := element.scratch[child]
if dot.X > xStart && entry.expand {
nextLine()
}
width := int(entry.minBreadth)
height := int(entry.minSize)
if width + dot.X > bounds.Dx() && !entry.expand {
nextLine()
}
if width < bounds.Dx() && entry.expand {
width = bounds.Dx()
}
if typedChild, ok := child.(tomo.Flexible); ok {
height = typedChild.FlexibleHeightFor(width)
}
if rowHeight < height {
rowHeight = height
}
childBounds := tomo.Bounds (
dot.X, dot.Y,
width, height)
element.entity.PlaceChild(index, childBounds)
element.contentBounds = element.contentBounds.Union(childBounds)
if entry.expand {
nextLine()
} else {
dot.X += width + margin.X
}
}
element.contentBounds =
element.contentBounds.Sub(element.contentBounds.Min)
element.entity.NotifyScrollBoundsChange()
if element.onScrollBoundsChange != nil {
element.onScrollBoundsChange()
}
}
func (element *Document) Adopt (child tomo.Element, expand bool) {
element.entity.Adopt(child)
element.scratch[child] = scratchEntry { expand: expand }
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *Document) Disown (child tomo.Element) {
index := element.entity.IndexOf(child)
if index < 0 { return }
element.entity.Disown(index)
delete(element.scratch, child)
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *Document) DisownAll () {
func () {
for index := 0; index < element.entity.CountChildren(); index ++ {
index := index
defer element.entity.Disown(index)
}
} ()
element.scratch = make(map[tomo.Element] scratchEntry)
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *Document) HandleChildMinimumSizeChange (child tomo.Element) {
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *Document) HandleChildFlexibleHeightChange (child tomo.Flexible) {
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
func (element *Document) DrawBackground (destination canvas.Canvas) {
element.entity.DrawBackground(destination)
}
// SetTheme sets the element's theme.
func (element *Document) SetTheme (theme tomo.Theme) {
if theme == element.theme.Theme { return }
element.theme.Theme = theme
element.updateMinimumSize()
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
// ScrollContentBounds returns the full content size of the element.
func (element *Document) ScrollContentBounds () image.Rectangle {
return element.contentBounds
}
// ScrollViewportBounds returns the size and position of the element's
// viewport relative to ScrollBounds.
func (element *Document) ScrollViewportBounds () image.Rectangle {
padding := element.theme.Padding(tomo.PatternBackground)
bounds := padding.Apply(element.entity.Bounds())
bounds = bounds.Sub(bounds.Min).Add(element.scroll)
return bounds
}
// ScrollTo scrolls the viewport to the specified point relative to
// ScrollBounds.
func (element *Document) ScrollTo (position image.Point) {
if position.Y < 0 {
position.Y = 0
}
maxScrollHeight := element.maxScrollHeight()
if position.Y > maxScrollHeight {
position.Y = maxScrollHeight
}
element.scroll = position
element.entity.Invalidate()
element.entity.InvalidateLayout()
}
// OnScrollBoundsChange sets a function to be called when the element's viewport
// bounds, content bounds, or scroll axes change.
func (element *Document) OnScrollBoundsChange (callback func ()) {
element.onScrollBoundsChange = callback
}
// ScrollAxes returns the supported axes for scrolling.
func (element *Document) ScrollAxes () (horizontal, vertical bool) {
return false, true
}
func (element *Document) maxScrollHeight () (height int) {
padding := element.theme.Padding(tomo.PatternSunken)
viewportHeight := element.entity.Bounds().Dy() - padding.Vertical()
height = element.contentBounds.Dy() - viewportHeight
if height < 0 { height = 0 }
return
}
func (element *Document) updateMinimumSize () {
padding := element.theme.Padding(tomo.PatternBackground)
minimumWidth := 0
for index := 0; index < element.entity.CountChildren(); index ++ {
width, height := element.entity.ChildMinimumSize(index)
if width > minimumWidth {
minimumWidth = width
}
key := element.entity.Child(index)
entry := element.scratch[key]
entry.minSize = float64(height)
entry.minBreadth = float64(width)
element.scratch[key] = entry
}
element.entity.SetMinimumSize (
minimumWidth + padding.Horizontal(),
padding.Vertical())
}

View File

@ -11,11 +11,11 @@ func main () {
} }
func run () { func run () {
window, _ := tomo.NewWindow(tomo.Bounds(0, 0, 0, 0)) window, _ := tomo.NewWindow(tomo.Bounds(0, 0, 256, 256))
window.SetTitle("Text alignment") window.SetTitle("Text alignment")
container := containers.NewDocumentContainer() container := containers.NewDocument()
scrollContainer := containers.NewScrollContainer(false, true) scrollContainer := containers.NewScroll(false, true)
scrollContainer.Adopt(container) scrollContainer.Adopt(container)
window.Adopt(scrollContainer) window.Adopt(scrollContainer)

View File

@ -22,8 +22,8 @@ func run () {
file.Close() file.Close()
if err != nil { panic(err.Error()); return } if err != nil { panic(err.Error()); return }
scrollContainer := containers.NewScrollContainer(false, true) scrollContainer := containers.NewScroll(false, true)
document := containers.NewDocumentContainer() document := containers.NewDocument()
document.Adopt (elements.NewLabel ( document.Adopt (elements.NewLabel (
"A document container is a vertically stacked container " + "A document container is a vertically stacked container " +