Document works now
This commit is contained in:
		
							parent
							
								
									7d4ddaf387
								
							
						
					
					
						commit
						a7de6c7f3b
					
				@ -7,8 +7,9 @@ import "git.tebibyte.media/sashakoshka/tomo/shatter"
 | 
			
		||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
 | 
			
		||||
 | 
			
		||||
type scratchEntry struct {
 | 
			
		||||
	expand  bool
 | 
			
		||||
	minimum float64
 | 
			
		||||
	expand     bool
 | 
			
		||||
	minSize    float64
 | 
			
		||||
	minBreadth float64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 {
 | 
			
		||||
			size = expandingElementSize
 | 
			
		||||
		} else {
 | 
			
		||||
			size = entry.minimum
 | 
			
		||||
			size = entry.minSize
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var childBounds image.Rectangle; if element.vertical {
 | 
			
		||||
@ -170,7 +171,7 @@ func (element *Box) freeSpace () (space float64, nExpanding float64) {
 | 
			
		||||
		if entry.expand {
 | 
			
		||||
			nExpanding ++;
 | 
			
		||||
		} else {
 | 
			
		||||
			space -= float64(entry.minimum)
 | 
			
		||||
			space -= float64(entry.minSize)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -204,7 +205,7 @@ func (element *Box) updateMinimumSize () {
 | 
			
		||||
		
 | 
			
		||||
		key   := element.entity.Child(index)
 | 
			
		||||
		entry := element.scratch[key]
 | 
			
		||||
		entry.minimum = float64(childSize)
 | 
			
		||||
		entry.minSize = float64(childSize)
 | 
			
		||||
		element.scratch[key] = entry
 | 
			
		||||
		
 | 
			
		||||
		if childBreadth > breadth {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										235
									
								
								elements/containers/document.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								elements/containers/document.go
									
									
									
									
									
										Normal 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())
 | 
			
		||||
}
 | 
			
		||||
@ -11,11 +11,11 @@ func main () {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func run () {
 | 
			
		||||
	window, _ := tomo.NewWindow(tomo.Bounds(0, 0, 0, 0))
 | 
			
		||||
	window, _ := tomo.NewWindow(tomo.Bounds(0, 0, 256, 256))
 | 
			
		||||
	window.SetTitle("Text alignment")
 | 
			
		||||
 | 
			
		||||
	container := containers.NewDocumentContainer()
 | 
			
		||||
	scrollContainer := containers.NewScrollContainer(false, true)
 | 
			
		||||
	container := containers.NewDocument()
 | 
			
		||||
	scrollContainer := containers.NewScroll(false, true)
 | 
			
		||||
	scrollContainer.Adopt(container)
 | 
			
		||||
	window.Adopt(scrollContainer)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,8 +22,8 @@ func run () {
 | 
			
		||||
	file.Close()
 | 
			
		||||
	if err != nil { panic(err.Error()); return  }
 | 
			
		||||
 | 
			
		||||
	scrollContainer := containers.NewScrollContainer(false, true)
 | 
			
		||||
	document := containers.NewDocumentContainer()
 | 
			
		||||
	scrollContainer := containers.NewScroll(false, true)
 | 
			
		||||
	document := containers.NewDocument()
 | 
			
		||||
 | 
			
		||||
	document.Adopt (elements.NewLabel (
 | 
			
		||||
		"A document container is a vertically stacked container " +
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user