184 lines
5.2 KiB
Go
184 lines
5.2 KiB
Go
package layouts
|
|
|
|
import (
|
|
"image"
|
|
|
|
"git.milar.in/milarin/gui"
|
|
)
|
|
|
|
// BorderLayout ia a gui.Layout which places its children onto a given gui.Side
|
|
type BorderLayout struct {
|
|
gui.ViewTmpl
|
|
views map[Slot]gui.View
|
|
horizontalLayout *LayoutResult
|
|
verticalLayout *LayoutResult
|
|
|
|
viewDims map[Slot]gui.Dimension
|
|
}
|
|
|
|
var _ gui.Layout = &BorderLayout{}
|
|
|
|
func NewBorderLayout() *BorderLayout {
|
|
return &BorderLayout{
|
|
views: map[Slot]gui.View{},
|
|
viewDims: map[Slot]gui.Dimension{},
|
|
}
|
|
}
|
|
|
|
func (g *BorderLayout) Views() []gui.View {
|
|
s := make([]gui.View, 0, len(g.views))
|
|
for _, view := range g.views {
|
|
s = append(s, view)
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (g *BorderLayout) SetView(v gui.View, slot Slot) {
|
|
g.views[slot] = v
|
|
}
|
|
|
|
func (g *BorderLayout) View(slot Slot) gui.View {
|
|
return g.views[slot]
|
|
}
|
|
|
|
func (g *BorderLayout) Draw(img *gui.Image, ctx gui.AppContext) {
|
|
g.ViewTmpl.Draw(img, ctx)
|
|
|
|
if g.verticalLayout == nil {
|
|
g.Layout(ctx)
|
|
}
|
|
verticalLayout := g.verticalLayout
|
|
|
|
if g.horizontalLayout == nil {
|
|
g.Layout(ctx)
|
|
}
|
|
horizontalLayout := g.horizontalLayout
|
|
|
|
remainingVerticalSpacePerView := (img.Bounds().Dy() - verticalLayout.Sum.Height)
|
|
if verticalLayout.VerticalNegativeCount > 0 {
|
|
remainingVerticalSpacePerView /= verticalLayout.VerticalNegativeCount
|
|
}
|
|
|
|
remainingHorizontalSpacePerView := (img.Bounds().Dx() - horizontalLayout.Sum.Width)
|
|
if horizontalLayout.HorizontalNegativeCount > 0 {
|
|
remainingHorizontalSpacePerView /= horizontalLayout.HorizontalNegativeCount
|
|
}
|
|
|
|
fitsVertically := img.Bounds().Dy() >= verticalLayout.Sum.Height
|
|
fitsHorizontally := img.Bounds().Dx() >= horizontalLayout.Sum.Width
|
|
|
|
var topHeight int
|
|
var bottomHeight int
|
|
var leftWidth int
|
|
var rightWidth int
|
|
|
|
if view, ok := g.views[Top]; ok {
|
|
_, topHeight = view.Layout(ctx)
|
|
|
|
if fitsVertically {
|
|
topHeight = iff(topHeight < 0, remainingVerticalSpacePerView, topHeight)
|
|
} else {
|
|
topHeight = int(float64(img.Bounds().Dy()) * float64(topHeight) / float64(verticalLayout.Sum.Height))
|
|
}
|
|
|
|
g.viewDims[Top] = gui.D(0, 0, img.Bounds().Dx(), topHeight)
|
|
view.Draw(img.SubImage(image.Rect(0, 0, img.Bounds().Dx(), topHeight)).(*gui.Image), ctx)
|
|
}
|
|
|
|
if view, ok := g.views[Bottom]; ok {
|
|
_, bottomHeight = view.Layout(ctx)
|
|
|
|
if fitsVertically {
|
|
bottomHeight = iff(bottomHeight < 0, remainingVerticalSpacePerView, bottomHeight)
|
|
} else {
|
|
bottomHeight = int(float64(img.Bounds().Dy()) * float64(bottomHeight) / float64(verticalLayout.Sum.Height))
|
|
}
|
|
|
|
g.viewDims[Bottom] = gui.D(0, img.Bounds().Dy()-bottomHeight, img.Bounds().Dx(), bottomHeight)
|
|
view.Draw(img.SubImage(image.Rect(0, img.Bounds().Dy()-bottomHeight, img.Bounds().Dx(), img.Bounds().Dy())).(*gui.Image), ctx)
|
|
}
|
|
|
|
if view, ok := g.views[Left]; ok {
|
|
leftWidth, _ = view.Layout(ctx)
|
|
|
|
if fitsHorizontally {
|
|
leftWidth = iff(leftWidth < 0, remainingHorizontalSpacePerView, leftWidth)
|
|
} else {
|
|
leftWidth = int(float64(img.Bounds().Dx()) * float64(leftWidth) / float64(horizontalLayout.Sum.Width))
|
|
}
|
|
|
|
g.viewDims[Left] = gui.D(0, topHeight, leftWidth, img.Bounds().Dy()-topHeight-bottomHeight)
|
|
view.Draw(img.SubImage(image.Rect(0, topHeight, leftWidth, img.Bounds().Dy()-bottomHeight)).(*gui.Image), ctx)
|
|
}
|
|
|
|
if view, ok := g.views[Right]; ok {
|
|
rightWidth, _ = view.Layout(ctx)
|
|
|
|
if fitsHorizontally {
|
|
rightWidth = iff(rightWidth < 0, remainingHorizontalSpacePerView, rightWidth)
|
|
} else {
|
|
rightWidth = int(float64(img.Bounds().Dx()) * float64(rightWidth) / float64(horizontalLayout.Sum.Width))
|
|
}
|
|
|
|
g.viewDims[Right] = gui.D(img.Bounds().Dx()-rightWidth, topHeight, rightWidth, img.Bounds().Dy()-topHeight-bottomHeight)
|
|
view.Draw(img.SubImage(image.Rect(img.Bounds().Dx()-rightWidth, topHeight, img.Bounds().Dx(), img.Bounds().Dy()-bottomHeight)).(*gui.Image), ctx)
|
|
}
|
|
|
|
if view, ok := g.views[Center]; ok {
|
|
g.viewDims[Center] = gui.D(leftWidth, topHeight, img.Bounds().Dx()-leftWidth-rightWidth, img.Bounds().Dy()-topHeight-bottomHeight)
|
|
view.Draw(img.SubImage(image.Rect(leftWidth, topHeight, img.Bounds().Dx()-rightWidth, img.Bounds().Dy()-bottomHeight)).(*gui.Image), ctx)
|
|
}
|
|
|
|
g.verticalLayout = nil
|
|
g.horizontalLayout = nil
|
|
}
|
|
|
|
func (g *BorderLayout) Layout(ctx gui.AppContext) (prefWidth, prefHeight int) {
|
|
g.verticalLayout = CalculateLayoutResult(ctx, []gui.View{g.View(Top), g.View(Center), g.View(Bottom)})
|
|
g.horizontalLayout = CalculateLayoutResult(ctx, []gui.View{g.View(Left), g.View(Center), g.View(Right)})
|
|
return -1, -1
|
|
}
|
|
|
|
func (g *BorderLayout) OnMouseClick(event gui.MouseEvent) (consumed bool) {
|
|
for slot, dim := range g.viewDims {
|
|
if event.Position.In(dim) {
|
|
if g.views[slot].OnMouseClick(event.SubtractPos(dim.Point)) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (g *BorderLayout) OnMouseMove(event gui.MouseEvent) (consumed bool) {
|
|
for slot, dim := range g.viewDims {
|
|
if event.Position.In(dim) {
|
|
if g.views[slot].OnMouseMove(event.SubtractPos(dim.Point)) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (g *BorderLayout) OnMouseScroll(event gui.MouseEvent) (consumed bool) {
|
|
for slot, dim := range g.viewDims {
|
|
if event.Position.In(dim) {
|
|
if g.views[slot].OnMouseScroll(event.SubtractPos(dim.Point)) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
type Slot string
|
|
|
|
const (
|
|
Top Slot = "top"
|
|
Bottom Slot = "bottom"
|
|
Left Slot = "left"
|
|
Right Slot = "right"
|
|
Center Slot = "center"
|
|
)
|