Skip to content

Commit b4df42f

Browse files
committed
feat: added Position class
1 parent faca7af commit b4df42f

5 files changed

Lines changed: 196 additions & 28 deletions

File tree

twinkle-screen/src/main/java/org/codejive/twinkle/screen/BufferStack.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import java.util.Set;
77
import org.codejive.twinkle.ansi.Style;
88
import org.codejive.twinkle.ansi.util.Printable;
9+
import org.codejive.twinkle.text.Position;
910
import org.codejive.twinkle.text.Size;
1011
import org.jspecify.annotations.NonNull;
1112

@@ -16,16 +17,14 @@ public class BufferStack implements Printable {
1617

1718
public static class BufferElement {
1819
public Buffer buffer;
19-
public int xPos;
20-
public int yPos;
20+
public Position pos;
2121
public int zIndex;
2222
public boolean visible;
2323
public String transparancy;
2424

25-
public BufferElement(Buffer buffer, int xPos, int yPos, int zIndex) {
25+
public BufferElement(Buffer buffer, Position pos, int zIndex) {
2626
this.buffer = buffer;
27-
this.xPos = xPos;
28-
this.yPos = yPos;
27+
this.pos = pos;
2928
this.zIndex = zIndex;
3029
this.visible = true;
3130
this.transparancy = "\0";
@@ -73,7 +72,7 @@ public void primary(Buffer primary) {
7372

7473
public List<BufferElement> list() {
7574
List<BufferElement> elems = list_();
76-
elems.add(0, new BufferElement(primary, 0, 0, Integer.MIN_VALUE));
75+
elems.add(0, new BufferElement(primary, Position.ZERO, Integer.MIN_VALUE));
7776
return elems;
7877
}
7978

@@ -85,13 +84,19 @@ private List<BufferElement> list_() {
8584
}
8685

8786
public BufferElement add(Buffer buffer) {
88-
BufferElement element = new BufferElement(buffer, 0, 0, bufferStack.size());
87+
BufferElement element = new BufferElement(buffer, Position.ZERO, bufferStack.size());
88+
bufferStack.add(element);
89+
return element;
90+
}
91+
92+
public BufferElement add(Buffer buffer, Position pos, int zIndex) {
93+
BufferElement element = new BufferElement(buffer, pos, zIndex);
8994
bufferStack.add(element);
9095
return element;
9196
}
9297

9398
public BufferElement add(Buffer buffer, int xPos, int yPos, int zIndex) {
94-
BufferElement element = new BufferElement(buffer, xPos, yPos, zIndex);
99+
BufferElement element = new BufferElement(buffer, Position.of(xPos, yPos), zIndex);
95100
bufferStack.add(element);
96101
return element;
97102
}
@@ -121,7 +126,7 @@ public Buffer combined() {
121126
for (BufferElement element : list_()) {
122127
if (element.visible) {
123128
element.buffer.overlayOn(
124-
combined, element.xPos, element.yPos, element.transparancy);
129+
combined, element.pos.x(), element.pos.y(), element.transparancy);
125130
}
126131
}
127132
return combined;

twinkle-screen/src/main/java/org/codejive/twinkle/screen/util/Rect.java

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package org.codejive.twinkle.screen.util;
22

3+
import org.codejive.twinkle.text.Position;
34
import org.codejive.twinkle.text.Size;
45
import org.jspecify.annotations.NonNull;
56

67
public class Rect implements Sized {
7-
private final int left, top;
8-
private final Size size;
8+
private final @NonNull Position pos;
9+
private final @NonNull Size size;
910

1011
public static @NonNull Rect of(int width, int height) {
1112
return of(0, 0, width, height);
@@ -16,33 +17,44 @@ public class Rect implements Sized {
1617
}
1718

1819
public static @NonNull Rect of(int left, int top, int width, int height) {
19-
return new Rect(left, top, Size.of(width, height));
20+
return new Rect(Position.of(left, top), Size.of(width, height));
2021
}
2122

2223
public static @NonNull Rect of(int left, int top, @NonNull Size size) {
23-
return new Rect(left, top, size);
24+
return new Rect(Position.of(left, top), size);
2425
}
2526

26-
public Rect(int left, int top, @NonNull Size size) {
27-
this.left = left;
28-
this.top = top;
27+
public static @NonNull Rect of(@NonNull Position pos, @NonNull Size size) {
28+
return new Rect(pos, size);
29+
}
30+
31+
public Rect(@NonNull Position pos, @NonNull Size size) {
32+
this.pos = pos;
2933
this.size = size;
3034
}
3135

36+
public int x() {
37+
return pos.x();
38+
}
39+
40+
public int y() {
41+
return pos.y();
42+
}
43+
3244
public int left() {
33-
return left;
45+
return pos.x();
3446
}
3547

3648
public int right() {
37-
return left + width() - 1;
49+
return left() + width() - 1;
3850
}
3951

4052
public int top() {
41-
return top;
53+
return pos.y();
4254
}
4355

4456
public int bottom() {
45-
return top + height() - 1;
57+
return top() + height() - 1;
4658
}
4759

4860
public int width() {
@@ -53,6 +65,10 @@ public int height() {
5365
return size.height();
5466
}
5567

68+
public @NonNull Position position() {
69+
return pos;
70+
}
71+
5672
@Override
5773
public @NonNull Size size() {
5874
return size;
@@ -78,31 +94,31 @@ public boolean overlap(@NonNull Rect other) {
7894

7995
public Rect grow(int leftAmount, int topAmount, int rightAmount, int bottomAmount) {
8096
return Rect.of(
81-
left - leftAmount,
82-
top - topAmount,
97+
left() - leftAmount,
98+
top() - topAmount,
8399
Math.max(width() + leftAmount + rightAmount, 0),
84100
Math.max(height() + topAmount + bottomAmount, 0));
85101
}
86102

87103
public Rect limited(@NonNull Rect availableRect) {
88-
int l = Math.max(left, availableRect.left());
89-
int t = Math.max(top, availableRect.top());
104+
int l = Math.max(left(), availableRect.left());
105+
int t = Math.max(top(), availableRect.top());
90106
int r = Math.min(right(), availableRect.right());
91107
int b = Math.min(bottom(), availableRect.bottom());
92108
return Rect.of(l, t, r - l + 1, b - t + 1);
93109
}
94110

95111
public Rect appliedTo(@NonNull Rect rect) {
96-
return of(rect.left() + left, rect.top() + top, size);
112+
return of(rect.left() + left(), rect.top() + top(), size);
97113
}
98114

99115
@Override
100116
public String toString() {
101117
return "Rect{"
102118
+ "left="
103-
+ left
119+
+ left()
104120
+ ", top="
105-
+ top
121+
+ top()
106122
+ ", width="
107123
+ width()
108124
+ ", height="

twinkle-text/src/main/java/org/codejive/twinkle/fluent/commands/CursorCommands.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.codejive.twinkle.fluent.commands;
22

33
import org.codejive.twinkle.fluent.Fluent;
4+
import org.codejive.twinkle.text.Position;
45

56
public interface CursorCommands {
67
/**
@@ -10,6 +11,17 @@ public interface CursorCommands {
1011
*/
1112
Fluent home();
1213

14+
/**
15+
* Positions the cursor at the specified column (x) and row (y). Coordinates are 0-based (the
16+
* top-left corner is 0,0).
17+
*
18+
* @param pos the position (0-based)
19+
* @return this Fluent instance for chaining
20+
*/
21+
default Fluent at(Position pos) {
22+
return at(pos.x(), pos.y());
23+
}
24+
1325
/**
1426
* Positions the cursor at the specified column (x) and row (y). Coordinates are 0-based (the
1527
* top-left corner is 0,0).
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.codejive.twinkle.text;
2+
3+
import java.util.Objects;
4+
import org.jspecify.annotations.NonNull;
5+
6+
public class Position {
7+
private final int x;
8+
private final int y;
9+
10+
public static Position ZERO = new Position(0, 0);
11+
public static Position MAX = new Position(Integer.MAX_VALUE, Integer.MAX_VALUE);
12+
13+
public static @NonNull Position of(int x, int y) {
14+
if (x == 0 && y == 0) {
15+
return ZERO;
16+
}
17+
if (x == Integer.MAX_VALUE && y == Integer.MAX_VALUE) {
18+
return MAX;
19+
}
20+
return new Position(x, y);
21+
}
22+
23+
protected Position(int x, int y) {
24+
this.x = x;
25+
this.y = y;
26+
}
27+
28+
public int x() {
29+
return x;
30+
}
31+
32+
public int y() {
33+
return y;
34+
}
35+
36+
/**
37+
* Returns a new position moved by the given amounts in x and y direction.
38+
*
39+
* @param dx the distance to move in the X direction
40+
* @param dy the distance to move in the Y direction
41+
* @return a new position with the updated coordinates
42+
*/
43+
public Position move(int dx, int dy) {
44+
return of(x + dx, y + dy);
45+
}
46+
47+
@Override
48+
public boolean equals(Object o) {
49+
if (o == null || getClass() != o.getClass()) return false;
50+
Position pos = (Position) o;
51+
return x == pos.x && y == pos.y;
52+
}
53+
54+
@Override
55+
public int hashCode() {
56+
return Objects.hash(x, y);
57+
}
58+
59+
@Override
60+
public String toString() {
61+
return "(" + x + "," + y + ")";
62+
}
63+
}

twinkle-text/src/main/java/org/codejive/twinkle/text/Size.java

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,20 @@ public class Size {
77
private final int width;
88
private final int height;
99

10+
public static Size EMPTY = new Size(0, 0);
11+
public static Size MAX = new Size(Integer.MAX_VALUE, Integer.MAX_VALUE);
12+
1013
public static @NonNull Size of(int width, int height) {
14+
if (width == 0 && height == 0) {
15+
return EMPTY;
16+
}
17+
if (width == Integer.MAX_VALUE && height == Integer.MAX_VALUE) {
18+
return MAX;
19+
}
1120
return new Size(width, height);
1221
}
1322

14-
public Size(int width, int height) {
23+
protected Size(int width, int height) {
1524
assert width >= 0;
1625
assert height >= 0;
1726
this.width = width;
@@ -26,10 +35,73 @@ public int height() {
2635
return height;
2736
}
2837

38+
/**
39+
* Grows the size by the given size, returning a new Size instance with the updated dimensions.
40+
*
41+
* @param growSize the amount to grow the width
42+
* @return a new size with the updated dimensions
43+
*/
44+
public Size grow(Size growSize) {
45+
return grow(growSize.width(), growSize.height());
46+
}
47+
48+
/**
49+
* Grows the size by the given amounts in width and height, returning a new Size instance with
50+
* the updated dimensions.
51+
*
52+
* @param dw the amount to grow the width
53+
* @param dh the amount to grow the height
54+
* @return a new size with the updated dimensions
55+
*/
2956
public Size grow(int dw, int dh) {
3057
return of(width + dw, height + dh);
3158
}
3259

60+
/**
61+
* Shrinks the size by the given size, returning a new Size instance with the updated
62+
* dimensions.
63+
*
64+
* @param shrinkSize the amount to shrink the width
65+
* @return a new size with the updated dimensions
66+
*/
67+
public Size shrink(Size shrinkSize) {
68+
return shrink(shrinkSize.width(), shrinkSize.height());
69+
}
70+
71+
/**
72+
* Shrinks the size by the given amounts in width and height, returning a new Size instance with
73+
* the updated dimensions.
74+
*
75+
* @param dw the amount to shrink the width
76+
* @param dh the amount to shrink the height
77+
* @return a new size with the updated dimensions
78+
*/
79+
public Size shrink(int dw, int dh) {
80+
return of(width - dw, height - dh);
81+
}
82+
83+
/**
84+
* Returns the center position of an area of this size
85+
*
86+
* @return the center position
87+
*/
88+
public Position center() {
89+
return new Position(width / 2, height / 2);
90+
}
91+
92+
/**
93+
* Returns the position where the other size would be centered, both horizontally as vertically,
94+
* within this size.
95+
*
96+
* @param otherSize the other size to center
97+
* @return the position where the other size would be centered within this size
98+
*/
99+
public Position center(Size otherSize) {
100+
int posX = (width - otherSize.width) / 2;
101+
int posY = (height - otherSize.height) / 2;
102+
return new Position(posX, posY);
103+
}
104+
33105
@Override
34106
public boolean equals(Object o) {
35107
if (o == null || getClass() != o.getClass()) return false;

0 commit comments

Comments
 (0)