diff --git a/block.go b/block.go index ac35505..210131f 100644 --- a/block.go +++ b/block.go @@ -120,6 +120,7 @@ type Block struct { PaddingLeft int PaddingRight int id string + Float Align } // NewBlock returns a *Block which inherits styles from current theme. @@ -139,6 +140,7 @@ func NewBlock() *Block { b.Width = 2 b.Height = 2 b.id = GenId() + b.Float = AlignNone return &b } @@ -148,13 +150,19 @@ func (b Block) Id() string { // Align computes box model func (b *Block) Align() { - b.area.Min.X = b.X - b.area.Min.Y = b.Y - b.area.Max.X = b.X + b.Width - b.area.Max.Y = b.Y + b.Height + // outer + b.area.Min.X = 0 + b.area.Min.Y = 0 + b.area.Max.X = b.Width + b.area.Max.Y = b.Height - b.innerArea.Min.X = b.X + b.PaddingLeft - b.innerArea.Min.Y = b.Y + b.PaddingTop + // float + b.area = AlignArea(TermRect(), b.area, b.Float) + b.area = MoveArea(b.area, b.X, b.Y) + + // inner + b.innerArea.Min.X = b.area.Min.X + b.PaddingLeft + b.innerArea.Min.Y = b.area.Min.Y + b.PaddingTop b.innerArea.Max.X = b.area.Max.X - b.PaddingRight b.innerArea.Max.Y = b.area.Max.Y - b.PaddingBottom diff --git a/block_test.go b/block_test.go index 0b97c3e..9be8aa7 100644 --- a/block_test.go +++ b/block_test.go @@ -1,8 +1,25 @@ package termui -import "testing" +import ( + "testing" +) + +func TestBlockFloat(t *testing.T) { + Init() + defer Close() + + b := NewBlock() + b.X = 10 + b.Y = 20 + + b.Float = AlignCenter + b.Align() +} + +func TestBlockInnerBounds(t *testing.T) { + Init() + defer Close() -func TestBlock_InnerBounds(t *testing.T) { b := NewBlock() b.X = 10 b.Y = 11 @@ -16,11 +33,12 @@ func TestBlock_InnerBounds(t *testing.T) { cy := area.Min.Y cw := area.Dx() ch := area.Dy() + if cx != x { t.Errorf("expected x to be %d but got %d", x, cx) } if cy != y { - t.Errorf("expected y to be %d but got %d", y, cy) + t.Errorf("expected y to be %d but got %d\n%+v", y, cy, area) } if cw != w { t.Errorf("expected width to be %d but got %d", w, cw) diff --git a/gauge.go b/gauge.go index 5816d05..05ec775 100644 --- a/gauge.go +++ b/gauge.go @@ -21,16 +21,6 @@ import ( g.PercentColor = termui.ColorBlue */ -// Align is the position of the gauge's label. -type Align int - -// All supported positions. -const ( - AlignLeft Align = iota - AlignCenter - AlignRight -) - type Gauge struct { Block Percent int diff --git a/pos.go b/pos.go new file mode 100644 index 0000000..b26fd11 --- /dev/null +++ b/pos.go @@ -0,0 +1,71 @@ +package termui + +import "image" + +// Align is the position of the gauge's label. +type Align uint + +// All supported positions. +const ( + AlignNone Align = 0 + AlignLeft Align = 1 << iota + AlignRight + AlignBottom + AlignTop + AlignCenterVertical + AlignCenterHorizontal + AlignCenter = AlignCenterVertical | AlignCenterHorizontal +) + +func AlignArea(parent, child image.Rectangle, a Align) image.Rectangle { + w, h := child.Dx(), child.Dy() + + // parent center + pcx, pcy := parent.Min.X+parent.Dx()/2, parent.Min.Y+parent.Dy()/2 + // child center + ccx, ccy := child.Min.X+child.Dx()/2, child.Min.Y+child.Dy()/2 + + if a&AlignLeft == AlignLeft { + child.Min.X = parent.Min.X + child.Max.X = child.Min.X + w + } + + if a&AlignRight == AlignRight { + child.Max.X = parent.Max.X + child.Min.X = child.Max.X - w + } + + if a&AlignBottom == AlignBottom { + child.Max.Y = parent.Max.Y + child.Min.Y = child.Max.Y - h + } + + if a&AlignTop == AlignRight { + child.Min.Y = parent.Min.Y + child.Max.Y = child.Min.Y + h + } + + if a&AlignCenterHorizontal == AlignCenterHorizontal { + child.Min.X += pcx - ccx + child.Max.X = child.Min.X + w + } + + if a&AlignCenterVertical == AlignCenterVertical { + child.Min.Y += pcy - ccy + child.Max.Y = child.Min.Y + h + } + + return child +} + +func MoveArea(a image.Rectangle, dx, dy int) image.Rectangle { + a.Min.X += dx + a.Max.X += dx + a.Min.Y += dy + a.Max.Y += dy + return a +} + +func TermRect() image.Rectangle { + return image.Rect(0, 0, TermWidth(), TermHeight()) +} diff --git a/pos_test.go b/pos_test.go new file mode 100644 index 0000000..0454345 --- /dev/null +++ b/pos_test.go @@ -0,0 +1,34 @@ +package termui + +import ( + "image" + "testing" +) + +func TestAlignArea(t *testing.T) { + p := image.Rect(0, 0, 100, 100) + c := image.Rect(10, 10, 20, 20) + + nc := AlignArea(p, c, AlignLeft) + if nc.Min.X != 0 || nc.Max.Y != 20 { + t.Errorf("AlignLeft failed:\n%+v", nc) + } + + nc = AlignArea(p, c, AlignCenter) + if nc.Min.X != 45 || nc.Max.Y != 55 { + t.Error("AlignCenter failed") + } + + nc = AlignArea(p, c, AlignBottom|AlignRight) + if nc.Min.X != 90 || nc.Max.Y != 100 { + t.Errorf("AlignBottom|AlignRight failed\n%+v", nc) + } +} + +func TestMoveArea(t *testing.T) { + a := image.Rect(10, 10, 20, 20) + a = MoveArea(a, 5, 10) + if a.Min.X != 15 || a.Min.Y != 20 || a.Max.X != 25 || a.Max.Y != 30 { + t.Error("MoveArea failed") + } +} diff --git a/test/runtest.go b/test/runtest.go index feaf43a..422a1ad 100644 --- a/test/runtest.go +++ b/test/runtest.go @@ -26,10 +26,11 @@ func main() { //termui.UseTheme("helloworld") b := termui.NewBlock() b.Width = 20 - b.Height = 30 + b.Height = 20 + b.Float = termui.AlignCenter b.BorderLabel = "[HELLO](fg-red,bg-white) [WORLD](fg-blue,bg-green)" - termui.SendBufferToRender(b) + termui.Render(b) termui.Handle("/sys", func(e termui.Event) { k, ok := e.Data.(termui.EvtKbd) @@ -48,7 +49,7 @@ func main() { b.BorderLabel = "[HELLO](fg-blue,bg-white) [WORLD](fg-red,bg-green)" } - termui.SendBufferToRender(b) + termui.Render(b) }) termui.Loop()