Compare commits
No commits in common. "1596d54834fed9020a4a068c7a67dbbe630d00aa" and "6a8aaca18de3bd83dd6a3c771413a843491c4abd" have entirely different histories.
1596d54834
...
6a8aaca18d
@ -28,6 +28,7 @@ func newContainer (layout tomo.Layout, children ...tomo.Object) *Container {
|
||||
func NewOuterContainer (layout tomo.Layout, children ...tomo.Object) *Container {
|
||||
this := newContainer(layout, children...)
|
||||
this.SetRole(tomo.R("objects", "Container", "outer"))
|
||||
tomo.Apply(this)
|
||||
return this
|
||||
}
|
||||
|
||||
@ -36,6 +37,7 @@ func NewOuterContainer (layout tomo.Layout, children ...tomo.Object) *Container
|
||||
func NewSunkenContainer (layout tomo.Layout, children ...tomo.Object) *Container {
|
||||
this := newContainer(layout, children...)
|
||||
this.SetRole(tomo.R("objects", "Container", "sunken"))
|
||||
tomo.Apply(this)
|
||||
return this
|
||||
}
|
||||
|
||||
@ -43,6 +45,7 @@ func NewSunkenContainer (layout tomo.Layout, children ...tomo.Object) *Container
|
||||
func NewInnerContainer (layout tomo.Layout, children ...tomo.Object) *Container {
|
||||
this := newContainer(layout, children...)
|
||||
this.SetRole(tomo.R("objects", "Container", "inner"))
|
||||
tomo.Apply(this)
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,6 @@ package layouts
|
||||
import "image"
|
||||
import "git.tebibyte.media/tomo/tomo"
|
||||
|
||||
var _ tomo.Layout = ContractVertical
|
||||
|
||||
// Contract is a layout that arranges boxes in a simple row or column according
|
||||
// to their minimum sizes.
|
||||
type Contract bool
|
||||
@ -42,7 +40,6 @@ func (contract Contract) MinimumSize (hints tomo.LayoutHints, boxes []tomo.Box)
|
||||
}
|
||||
|
||||
func (contract Contract) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) {
|
||||
// TODO if we overflow in a direction, respect the reccomended size
|
||||
if contract.v() {
|
||||
dot := hints.Bounds.Min
|
||||
for index, box := range boxes {
|
||||
@ -94,15 +91,5 @@ func (contract Contract) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) {
|
||||
}
|
||||
}
|
||||
|
||||
func (contract Contract) RecommendedHeight (hints tomo.LayoutHints, boxes []tomo.Box, width int) int {
|
||||
// TODO
|
||||
return 0
|
||||
}
|
||||
|
||||
func (contract Contract) RecommendedWidth (hints tomo.LayoutHints, boxes []tomo.Box, height int) int {
|
||||
// TODO
|
||||
return 0
|
||||
}
|
||||
|
||||
func (contract Contract) v () bool { return contract == ContractVertical }
|
||||
func (contract Contract) h () bool { return contract == ContractHorizontal }
|
||||
|
173
layouts/cut.go
Normal file
173
layouts/cut.go
Normal file
@ -0,0 +1,173 @@
|
||||
package layouts
|
||||
|
||||
import "image"
|
||||
import "git.tebibyte.media/tomo/tomo"
|
||||
|
||||
// Cut is a layout that can be divided into smaller and smaller sections.
|
||||
type Cut struct {
|
||||
branches []*Cut
|
||||
expand []bool
|
||||
vertical bool
|
||||
}
|
||||
|
||||
// NewCut creates and returns a new Cut layout.
|
||||
func NewCut () *Cut {
|
||||
return new(Cut)
|
||||
}
|
||||
|
||||
// Vertical divides the layout vertically. Sections are specified using
|
||||
// booleans. If a section is true, it will expand. If false, it will contract.
|
||||
func (this *Cut) Vertical (expand ...bool) {
|
||||
this.expand = expand
|
||||
this.vertical = true
|
||||
this.fill()
|
||||
}
|
||||
|
||||
// Horizontal divides the layout horizontally. Sections are specified using
|
||||
// booleans. If a section is true, it will expand. If false, it will contract.
|
||||
func (this *Cut) Horizontal (expand ...bool) {
|
||||
this.expand = expand
|
||||
this.vertical = false
|
||||
this.fill()
|
||||
}
|
||||
|
||||
// At returns the section of this layout at the specified index.
|
||||
func (this *Cut) At (index int) *Cut {
|
||||
return this.branches[index]
|
||||
}
|
||||
|
||||
func (this *Cut) real () bool {
|
||||
return this != nil && this.branches != nil
|
||||
}
|
||||
|
||||
func (this *Cut) fill () {
|
||||
this.branches = make([]*Cut, len(this.expand))
|
||||
for index := range this.branches {
|
||||
this.branches[index] = new(Cut)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Cut) MinimumSize (hints tomo.LayoutHints, boxes []tomo.Box) image.Point {
|
||||
size, _ := this.minimumSize(hints, boxes)
|
||||
return size
|
||||
}
|
||||
|
||||
func (this *Cut) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) {
|
||||
this.arrange(hints, boxes)
|
||||
}
|
||||
|
||||
func (this *Cut) minimumSize (hints tomo.LayoutHints, boxes []tomo.Box) (image.Point, []tomo.Box) {
|
||||
size := image.Point { }
|
||||
|
||||
for index, branch := range this.branches {
|
||||
if len(boxes) == 0 { break }
|
||||
|
||||
var point image.Point
|
||||
if branch.real() {
|
||||
point, boxes = branch.minimumSize(hints, boxes)
|
||||
} else {
|
||||
point = boxes[0].MinimumSize()
|
||||
boxes = boxes[1:]
|
||||
}
|
||||
|
||||
if this.vertical {
|
||||
if point.X > size.X { size.X = point.X }
|
||||
if index > 0 { size.Y += hints.Gap.Y }
|
||||
size.Y += point.Y
|
||||
} else {
|
||||
if point.Y > size.Y { size.Y = point.Y }
|
||||
if index > 0 { size.X += hints.Gap.X }
|
||||
size.X += point.X
|
||||
}
|
||||
}
|
||||
|
||||
return size, boxes
|
||||
}
|
||||
|
||||
func (this *Cut) arrange (hints tomo.LayoutHints, boxes []tomo.Box) []tomo.Box {
|
||||
nChildren := len(this.branches)
|
||||
|
||||
// collect minimum sizes and physical endpoints
|
||||
var minimums = make([]image.Point, nChildren)
|
||||
var leaves = make([]tomo.Box, nChildren)
|
||||
var nBranches int
|
||||
remaining := boxes
|
||||
for index, branch := range this.branches {
|
||||
if branch.real() {
|
||||
minimums[index], remaining = branch.minimumSize(hints, remaining)
|
||||
} else {
|
||||
if len(remaining) == 0 { break }
|
||||
leaves[index] = remaining[0]
|
||||
minimums[index] = remaining[0].MinimumSize()
|
||||
remaining = remaining[1:]
|
||||
}
|
||||
nBranches ++
|
||||
}
|
||||
|
||||
// determine the amount of space to divide among expanding branches
|
||||
gaps := nBranches - 1
|
||||
var freeSpace float64; if this.vertical {
|
||||
freeSpace = float64(hints.Bounds.Dy() - hints.Gap.Y * gaps)
|
||||
} else {
|
||||
freeSpace = float64(hints.Bounds.Dx() - hints.Gap.X * gaps)
|
||||
}
|
||||
var nExpanding float64
|
||||
for index, minimum := range minimums {
|
||||
if this.expand[index] {
|
||||
nExpanding ++
|
||||
} else if this.vertical {
|
||||
freeSpace -= float64(minimum.Y)
|
||||
} else {
|
||||
freeSpace -= float64(minimum.X)
|
||||
}
|
||||
}
|
||||
expandingSize := freeSpace / nExpanding
|
||||
|
||||
// calculate the size and position of branches
|
||||
var bounds = make([]image.Rectangle, nChildren)
|
||||
x := float64(hints.Bounds.Min.X)
|
||||
y := float64(hints.Bounds.Min.Y)
|
||||
for index, minimum := range minimums {
|
||||
// get size along significant axis
|
||||
var size float64; if this.expand[index] {
|
||||
size = expandingSize
|
||||
} else if this.vertical {
|
||||
size = float64(minimum.Y)
|
||||
} else {
|
||||
size = float64(minimum.X)
|
||||
}
|
||||
|
||||
// figure out bounds from size
|
||||
if this.vertical {
|
||||
bounds[index].Max = image.Pt (
|
||||
int(hints.Bounds.Dx()),
|
||||
int(size))
|
||||
} else {
|
||||
bounds[index].Max = image.Pt (
|
||||
int(size),
|
||||
int(hints.Bounds.Dy()))
|
||||
}
|
||||
bounds[index] = bounds[index].Add(image.Pt(int(x), int(y)))
|
||||
|
||||
// move along
|
||||
if this.vertical {
|
||||
y += float64(hints.Gap.Y) + size
|
||||
} else {
|
||||
x += float64(hints.Gap.X) + size
|
||||
}
|
||||
}
|
||||
|
||||
// apply the size and position
|
||||
for index, bound := range bounds {
|
||||
if leaves[index] != nil {
|
||||
leaves[index].SetBounds(bound)
|
||||
boxes = boxes[1:]
|
||||
} else if this.branches[index] != nil {
|
||||
newHints := hints
|
||||
newHints.Bounds = bound
|
||||
boxes = this.branches[index].arrange(newHints, boxes)
|
||||
}
|
||||
}
|
||||
|
||||
return boxes
|
||||
}
|
@ -3,8 +3,6 @@ package layouts
|
||||
import "image"
|
||||
import "git.tebibyte.media/tomo/tomo"
|
||||
|
||||
var _ tomo.Layout = FlowVertical
|
||||
|
||||
// Flow is a grid layout where the number of rows and columns changes depending
|
||||
// on the size of the container. It is designed to be used with an overflowing
|
||||
// container. If the container does not overflow in the correct direction, the
|
||||
@ -123,13 +121,3 @@ func (flow Flow) deltaMinor (rectangle image.Rectangle) int {
|
||||
func (flow Flow) fallback () tomo.Layout {
|
||||
return Contract(flow)
|
||||
}
|
||||
|
||||
func (flow Flow) RecommendedHeight (hints tomo.LayoutHints, boxes []tomo.Box, width int) int {
|
||||
// TODO
|
||||
return 0
|
||||
}
|
||||
|
||||
func (flow Flow) RecommendedWidth (hints tomo.LayoutHints, boxes []tomo.Box, height int) int {
|
||||
// TODO
|
||||
return 0
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ import "math"
|
||||
import "image"
|
||||
import "git.tebibyte.media/tomo/tomo"
|
||||
|
||||
var _ tomo.Layout = new(Grid)
|
||||
|
||||
// Grid is a layout that arranges boxes in a grid formation with distinct rows
|
||||
// and columns. It is great for creating forms.
|
||||
type Grid struct {
|
||||
@ -108,13 +106,3 @@ func expand (hints tomo.LayoutHints, sizes []int, space int, expands func (int)
|
||||
func ceilDiv (x, y int) int {
|
||||
return int(math.Ceil(float64(x) / float64(y)))
|
||||
}
|
||||
|
||||
func (this *Grid) RecommendedHeight (hints tomo.LayoutHints, boxes []tomo.Box, width int) int {
|
||||
// TODO
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *Grid) RecommendedWidth (hints tomo.LayoutHints, boxes []tomo.Box, height int) int {
|
||||
// TODO
|
||||
return 0
|
||||
}
|
||||
|
@ -335,14 +335,6 @@ func (this scrollbarLayout) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) {
|
||||
|
||||
}
|
||||
|
||||
func (this scrollbarLayout) RecommendedHeight (tomo.LayoutHints, []tomo.Box, int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this scrollbarLayout) RecommendedWidth (tomo.LayoutHints, []tomo.Box, int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this scrollbarLayout) viewportContentRatio () float64 {
|
||||
if this.linked == nil { return 0 }
|
||||
return this.viewportLength() / this.contentLength()
|
||||
|
@ -133,7 +133,6 @@ func (this *ScrollContainer) handleScroll (x, y float64) {
|
||||
Sub(image.Pt(int(x), int(y))))
|
||||
}
|
||||
|
||||
// TODO: remove this and replace it with something from the layouts package
|
||||
type scrollContainerLayout struct {
|
||||
root tomo.ContentObject
|
||||
horizontal *Scrollbar
|
||||
@ -184,14 +183,6 @@ func (this *scrollContainerLayout) Arrange (hints tomo.LayoutHints, boxes []tomo
|
||||
}
|
||||
}
|
||||
|
||||
func (this *scrollContainerLayout) RecommendedHeight (tomo.LayoutHints, []tomo.Box, int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *scrollContainerLayout) RecommendedWidth (tomo.LayoutHints, []tomo.Box, int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func max (x, y int) int {
|
||||
if x > y { return x }
|
||||
return y
|
||||
|
@ -238,11 +238,3 @@ func (this sliderLayout) Arrange (hints tomo.LayoutHints, boxes []tomo.Box) {
|
||||
Add(gutter.Min))
|
||||
}
|
||||
}
|
||||
|
||||
func (this sliderLayout) RecommendedHeight (tomo.LayoutHints, []tomo.Box, int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this sliderLayout) RecommendedWidth (tomo.LayoutHints, []tomo.Box, int) int {
|
||||
return 0
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user