1package main
2
3// Rect is a position, width and height
4type Rect struct {
5	X int
6	Y int
7	W int
8	H int
9}
10
11// Box has one outer and one innner rectangle.
12// This is useful when having margins that surrounds content.
13type Box struct {
14	frame *Rect // The rectangle around the box, for placement
15	inner *Rect // The rectangle inside the box, for content
16}
17
18// Create a new Box / container.
19func NewBox() *Box {
20	return &Box{&Rect{0, 0, 0, 0}, &Rect{0, 0, 0, 0}}
21}
22
23// Place a Box at the center of the given container.
24func (b *Box) Center(container *Box) {
25	widthleftover := container.inner.W - b.frame.W
26	heightleftover := container.inner.H - b.frame.H
27	b.frame.X = container.inner.X + widthleftover/2
28	b.frame.Y = container.inner.Y + heightleftover/2
29}
30
31// Place a Box so that it fills the entire given container.
32func (b *Box) Fill(container *Box) {
33	b.frame.X = container.inner.X
34	b.frame.Y = container.inner.Y
35	b.frame.W = container.inner.W
36	b.frame.H = container.inner.H
37}
38
39// Place a Box inside a given container, with the given margins.
40// Margins are given in number of characters.
41func (b *Box) FillWithMargins(container *Box, margins int) {
42	b.Fill(container)
43	b.frame.X += margins
44	b.frame.Y += margins
45	b.frame.W -= margins * 2
46	b.frame.H -= margins * 2
47}
48
49// Place a Box inside a given container, using the given percentage wise ratios.
50// horizmarginp can for example be 0.1 for a 10% horizontal margin around
51// the inner box. vertmarginp works similarly, but for the vertical margins.
52func (b *Box) FillWithPercentageMargins(container *Box, horizmarginp float32, vertmarginp float32) {
53	horizmargin := int(float32(container.inner.W) * horizmarginp)
54	vertmargin := int(float32(container.inner.H) * vertmarginp)
55	b.Fill(container)
56	b.frame.X += horizmargin
57	b.frame.Y += vertmargin
58	b.frame.W -= horizmargin * 2
59	b.frame.H -= vertmargin * 2
60}
61
62// Retrieves the position of the inner rectangle.
63func (b *Box) GetContentPos() (int, int) {
64	return b.inner.X, b.inner.Y
65}
66
67// Set the size of the Box to 1/3 of the size of the inner rectangle
68// of the given container.
69func (b *Box) SetThirdSize(container *Box) {
70	b.frame.W = container.inner.W / 3
71	b.frame.H = container.inner.H / 3
72}
73
74// Set the position of the Box to 1/3 of the size of the inner rectangle
75// of the given container.
76func (b *Box) SetThirdPlace(container *Box) {
77	b.frame.X = container.inner.X + container.inner.W/3
78	b.frame.Y = container.inner.Y + container.inner.H/3
79}
80
81// Place a Box so that it either fills the given
82// container, or is placed 1/3 from the upper left edge,
83// depending on how much space is left.
84func (b *Box) SetNicePlacement(container *Box) {
85	b.frame.X = container.inner.X
86	b.frame.Y = container.inner.Y
87	leftoverwidth := container.inner.W - b.frame.W
88	leftoverheight := container.inner.H - b.frame.H
89	if leftoverwidth > b.frame.W {
90		b.frame.X += leftoverwidth / 3
91	}
92	if leftoverheight > b.frame.H {
93		b.frame.Y += leftoverheight / 3
94	}
95}
96
97// Place a Box within the given container.
98func (b *Box) Place(container *Box) {
99	b.frame.X = container.inner.X
100	b.frame.Y = container.inner.Y
101}
102
103// Place a box at the bottom center of a given container, but a bit to the left
104func (b *Box) BottomCenterLeft(container *Box) {
105	widthleftover := container.inner.W - b.frame.W
106	b.frame.X = container.inner.X + widthleftover/3
107	b.frame.Y = container.inner.Y + container.inner.H - 2
108}
109
110// Place a box at the bottom center of a given container, but a bit to the right
111func (b *Box) BottomCenterRight(container *Box) {
112	widthleftover := container.inner.W - b.frame.W
113	b.frame.X = container.inner.X + container.inner.W - (widthleftover / 2)
114	b.frame.Y = container.inner.Y + container.inner.H - 2
115}
116
117// Get the inner rectangle (content size + pos)
118func (b *Box) GetInner() *Rect {
119	return b.inner
120}
121
122// Get the outer frame (box size + pos)
123func (b *Box) GetFrame() *Rect {
124	return b.frame
125}
126
127// Set the inner rectangle (content size + pos)
128func (b *Box) SetInner(r *Rect) {
129	b.inner = r
130}
131
132// Set the outer frame (box size + pos)
133func (b *Box) SetFrame(r *Rect) {
134	b.frame = r
135}
136