Skip to content

Commit ffc0d4d

Browse files
committed
feat: added List widget and demo
1 parent 0650608 commit ffc0d4d

7 files changed

Lines changed: 208 additions & 0 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.codejive.twinkle.core.widget;
2+
3+
import org.codejive.twinkle.core.text.Canvas;
4+
import org.codejive.twinkle.util.StyledIterator;
5+
6+
public interface StringWidget extends Widget {
7+
8+
CharSequence render();
9+
10+
default void render(Canvas canvas) {
11+
StyledIterator iter = StyledIterator.of(render());
12+
int y = 0;
13+
while (iter.hasNext()) {
14+
canvas.putStringAt(0, y++, iter);
15+
}
16+
}
17+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.codejive.twinkle.widgets.list;
2+
3+
import org.codejive.twinkle.core.util.Size;
4+
import org.codejive.twinkle.core.widget.StringWidget;
5+
import org.codejive.twinkle.util.Printable;
6+
import org.jspecify.annotations.NonNull;
7+
8+
public class List implements StringWidget {
9+
private @NonNull ListModel list;
10+
private @NonNull ListRenderer renderer;
11+
12+
protected List(@NonNull ListModel list, @NonNull ListRenderer renderer) {
13+
this.list = list;
14+
this.renderer = renderer;
15+
}
16+
17+
@Override
18+
public @NonNull Size size() {
19+
return null;
20+
}
21+
22+
@Override
23+
public CharSequence render() {
24+
return renderer.render(list, 0, list.items().size());
25+
}
26+
27+
public static @NonNull List create() {
28+
return new List(ListModel.ofStrings(), ListRenderer.create());
29+
}
30+
31+
public static @NonNull List ofStrings(String... texts) {
32+
return new List(ListModel.ofStrings(texts), ListRenderer.create());
33+
}
34+
35+
public static @NonNull List ofPrintables(Printable... texts) {
36+
return new List(ListModel.ofPrintables(texts), ListRenderer.create());
37+
}
38+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.codejive.twinkle.widgets.list;
2+
3+
import org.codejive.twinkle.ansi.Color;
4+
import org.codejive.twinkle.ansi.Style;
5+
import org.jspecify.annotations.NonNull;
6+
7+
public class ListConfig {
8+
public @NonNull Color listbackgroundColor = Color.DEFAULT;
9+
public @NonNull Style itemStyle = Style.DEFAULT;
10+
public @NonNull Style selectedItemStyle = Style.INVERSE;
11+
public @NonNull Style highlightedItemStyle = Style.FAINT;
12+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.codejive.twinkle.widgets.list;
2+
3+
import org.codejive.twinkle.util.Printable;
4+
5+
public class ListItem {
6+
public Printable content;
7+
public boolean selected;
8+
public boolean highlighted;
9+
10+
protected ListItem(Printable content, boolean selected, boolean highlighted) {
11+
this.content = content;
12+
this.selected = selected;
13+
this.highlighted = highlighted;
14+
}
15+
16+
public static ListItem of(Printable content) {
17+
return new ListItem(content, false, false);
18+
}
19+
20+
public static ListItem of(Printable content, boolean selected, boolean highlighted) {
21+
return new ListItem(content, selected, highlighted);
22+
}
23+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.codejive.twinkle.widgets.list;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
import org.codejive.twinkle.core.text.Line;
7+
import org.codejive.twinkle.util.Printable;
8+
9+
public class ListModel {
10+
private final List<ListItem> items;
11+
12+
public ListModel() {
13+
this.items = new ArrayList<>();
14+
}
15+
16+
public List<ListItem> items() {
17+
return items;
18+
}
19+
20+
public ListModel add(String text) {
21+
items.add(ListItem.of(Line.of(text)));
22+
return this;
23+
}
24+
25+
public ListModel add(Printable text) {
26+
items.add(ListItem.of(text));
27+
return this;
28+
}
29+
30+
public static ListModel ofStrings(String... texts) {
31+
return ofStrings(Arrays.asList(texts));
32+
}
33+
34+
public static ListModel ofStrings(List<String> texts) {
35+
ListModel model = new ListModel();
36+
for (String text : texts) {
37+
model.add(text);
38+
}
39+
return model;
40+
}
41+
42+
public static ListModel ofPrintables(Printable... texts) {
43+
return ofPrintables(Arrays.asList(texts));
44+
}
45+
46+
public static ListModel ofPrintables(List<Printable> texts) {
47+
ListModel model = new ListModel();
48+
for (Printable text : texts) {
49+
model.add(text);
50+
}
51+
return model;
52+
}
53+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.codejive.twinkle.widgets.list;
2+
3+
import java.util.stream.Collectors;
4+
import org.codejive.twinkle.ansi.Ansi;
5+
import org.jspecify.annotations.NonNull;
6+
7+
public class ListRenderer {
8+
private final @NonNull ListConfig config;
9+
10+
protected ListRenderer(@NonNull ListConfig config) {
11+
this.config = config;
12+
}
13+
14+
public CharSequence render(@NonNull ListModel list, int startIndex, int count) {
15+
int endIndex = Math.min(startIndex + count, list.items().size());
16+
return list.items().subList(startIndex, endIndex).stream()
17+
.map(this::renderItem)
18+
.collect(Collectors.joining("\n"));
19+
}
20+
21+
public CharSequence renderItem(@NonNull ListItem item) {
22+
String content =
23+
Ansi.STYLE_RESET
24+
+ config.listbackgroundColor.toAnsiBg()
25+
+ config.itemStyle.toAnsiString();
26+
if (item.selected) {
27+
content += config.selectedItemStyle.toAnsiString();
28+
}
29+
if (item.highlighted) {
30+
content += config.highlightedItemStyle.toAnsiString();
31+
}
32+
content += item.content.toAnsiString();
33+
return content;
34+
}
35+
36+
public static @NonNull ListRenderer create() {
37+
return new ListRenderer(new ListConfig());
38+
}
39+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// java
2+
package examples;
3+
4+
import org.codejive.twinkle.ansi.Ansi;
5+
import org.codejive.twinkle.core.text.Buffer;
6+
import org.codejive.twinkle.core.text.Line;
7+
import org.codejive.twinkle.widgets.Framed;
8+
import org.codejive.twinkle.widgets.list.List;
9+
10+
public class ListDemo {
11+
public static void main(String[] args) throws InterruptedException {
12+
List l =
13+
List.ofStrings(
14+
"First Item", "Second Item", "Third Item", "Fourth Item", "Fifth Item");
15+
Framed f = Framed.of(l).title(Line.of(" Simple List "));
16+
Buffer buf = Buffer.of(42, 22);
17+
18+
System.out.print(Ansi.hideCursor());
19+
try {
20+
f.render(buf);
21+
System.out.println(buf.toAnsiString());
22+
} finally {
23+
System.out.print(Ansi.showCursor());
24+
}
25+
}
26+
}

0 commit comments

Comments
 (0)