Created
August 11, 2023 04:48
-
-
Save audinue/a0ac7df9d5e2464c29f376068fd696e8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package sketch; | |
import java.awt.Rectangle; | |
import java.util.HashMap; | |
public class Ui { | |
//////////////////////////////////// STATE ///////////////////////////////////// | |
private static class State { | |
State parent; | |
HashMap<Object, State> children = new HashMap<Object, State>(); | |
Object value; | |
int key; | |
} | |
private static State state = new State(); | |
private static State nextChildState(Object initialValue, Object key) { | |
if (initialValue == null) { | |
throw new IllegalArgumentException("Initial value must not be null."); | |
} | |
if (key == null) { | |
key = ++state.key; | |
} | |
State child = state.children.get(key); | |
if (child == null) { | |
child = new State(); | |
child.parent = state; | |
child.value = initialValue; | |
state.children.put(key, child); | |
} else { | |
if (child.value.getClass() != initialValue.getClass()) { | |
child.value = initialValue; | |
} | |
} | |
return child; | |
} | |
public static <T> T nextState(T initialValue, Object key) { | |
return (T) nextChildState(initialValue, key).value; | |
} | |
public static <T> T nextState(T initialValue) { | |
return nextState(initialValue, null); | |
} | |
public static <T> T pushState(T initialValue, Object key) { | |
return (T) (state = nextChildState(initialValue, key)).value; | |
} | |
public static <T> T pushState(T initialValue) { | |
return pushState(initialValue, null); | |
} | |
public static void popState() { | |
if (state.parent == null) { | |
throw new IllegalStateException("Too many `popState()`."); | |
} | |
state = state.parent; | |
} | |
private static void resetState(State state) { | |
state.key = 0; | |
for (State child : state.children.values()) { | |
resetState(child); | |
} | |
} | |
static void resetState() { | |
assert (state.parent == null); // This must be root state. | |
resetState(state); | |
} | |
/////////////////////////////////// LAYOUT ///////////////////////////////////// | |
private static class Layout { | |
Layout previous; | |
Layout next; | |
Rectangle bounds; | |
int spacing; | |
int padding; | |
int[] columnWidths; | |
int rowHeight; | |
int x; | |
int y; | |
int column; | |
int row; | |
} | |
private static Layout layout = new Layout(); | |
public static void setBounds(Rectangle bounds) { | |
layout.bounds = bounds; | |
} | |
public static void setPadding(int padding) { | |
layout.padding = padding; | |
} | |
public static void setSpacing(int spacing) { | |
layout.spacing = spacing; | |
} | |
public static void setColumnWidths(int[] columnWidths) { | |
layout.columnWidths = columnWidths; | |
} | |
public static void setRowHeight(int rowHeight) { | |
layout.rowHeight = rowHeight; | |
} | |
public static Rectangle nextLayout() { | |
if (layout.column == 0 && layout.row == 0) { | |
layout.x = layout.bounds.x + layout.padding; | |
layout.y = layout.bounds.y + layout.padding; | |
} | |
int width = layout.columnWidths[layout.column]; | |
int height = layout.rowHeight; | |
if (width == -1) { | |
width = layout.bounds.width - layout.padding * 2; | |
} else if (width < 0) { | |
width = layout.bounds.width - layout.padding * 2 + width; | |
} | |
if (height == -1) { | |
height = layout.bounds.height - layout.padding * 2; | |
} else if (height < 0) { | |
height = layout.bounds.height - layout.padding * 2 + height; | |
} | |
Rectangle next = new Rectangle(layout.x, layout.y, width, height); | |
layout.x = layout.x + width + layout.spacing; | |
layout.column++; | |
if (layout.column >= layout.columnWidths.length) { | |
layout.x = layout.bounds.x + layout.padding; | |
layout.y = layout.y + height + layout.spacing; | |
layout.column = 0; | |
layout.row++; | |
} | |
return next; | |
} | |
public static Rectangle pushLayout() { | |
Rectangle bounds = nextLayout(); | |
if (layout.next == null) { | |
layout.next = new Layout(); | |
layout.next.previous = layout; | |
} | |
layout = layout.next; | |
layout.bounds = bounds; | |
layout.column = 0; | |
layout.row = 0; | |
return bounds; | |
} | |
public static void popLayout() { | |
if (layout.previous == null) { | |
throw new IllegalStateException("Too many `popLayout()`."); | |
} | |
layout = layout.previous; | |
} | |
static void resetLayout() { | |
assert (layout.previous == null); | |
layout.column = 0; | |
layout.row = 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment