|
|
|
@@ -0,0 +1,225 @@
|
|
|
|
|
package speiger.src.coreengine.ui.gui.screen;
|
|
|
|
|
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
import speiger.src.collections.ints.sets.IntOpenHashSet;
|
|
|
|
|
import speiger.src.collections.ints.sets.IntSet;
|
|
|
|
|
import speiger.src.collections.objects.lists.ObjectArrayList;
|
|
|
|
|
import speiger.src.collections.objects.maps.abstracts.AbstractObject2BooleanMap.BasicEntry;
|
|
|
|
|
import speiger.src.collections.objects.maps.interfaces.Object2BooleanMap;
|
|
|
|
|
import speiger.src.collections.objects.maps.interfaces.Object2BooleanMap.Entry;
|
|
|
|
|
import speiger.src.collections.utils.Stack;
|
|
|
|
|
import speiger.src.coreengine.platform.input.window.Window;
|
|
|
|
|
import speiger.src.coreengine.ui.gui.component.base.GuiComponent;
|
|
|
|
|
import speiger.src.coreengine.ui.gui.component.base.IComponentScreen;
|
|
|
|
|
import speiger.src.coreengine.ui.gui.interaction.IInteractable;
|
|
|
|
|
import speiger.src.coreengine.ui.gui.interaction.IInteractableContainer;
|
|
|
|
|
import speiger.src.coreengine.ui.gui.layout.box.IGuiBox;
|
|
|
|
|
import speiger.src.coreengine.ui.gui.layout.constraint.ConstraintContainer;
|
|
|
|
|
import speiger.src.coreengine.ui.gui.renderer.IUIRenderer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class GuiContainer implements IComponentScreen, IInteractableContainer {
|
|
|
|
|
LayeredContainer container = new LayeredContainer();
|
|
|
|
|
IntSet activeButtons = new IntOpenHashSet();
|
|
|
|
|
IInteractable focused;
|
|
|
|
|
IGuiBox box = IGuiBox.of(0F, 0F, 0F, 0F);
|
|
|
|
|
long tick;
|
|
|
|
|
|
|
|
|
|
public void setScreen(Window window) {
|
|
|
|
|
box = IGuiBox.of(0, 0, window.width(), window.height());
|
|
|
|
|
init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void init() {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public IGuiBox getBox() { return box; }
|
|
|
|
|
@Override
|
|
|
|
|
public long clock() { return tick; }
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isFocused() { return focused != null; }
|
|
|
|
|
@Override
|
|
|
|
|
public void setFocused(boolean value) { if(!value) setFocusedChild(null); }
|
|
|
|
|
@Override
|
|
|
|
|
public List<? extends IInteractable> getChildren() { return container.interactables(); }
|
|
|
|
|
@Override
|
|
|
|
|
public void setFocusedChild(IInteractable child) {
|
|
|
|
|
if(focused != null) focused.setFocused(false);
|
|
|
|
|
this.focused = child;
|
|
|
|
|
if(focused != null) focused.setFocused(true);
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
public IInteractable getFocusedChild() { return focused; }
|
|
|
|
|
@Override
|
|
|
|
|
public IntSet getActiveButtons() { return activeButtons; }
|
|
|
|
|
@Override
|
|
|
|
|
public void pushLayer() { container.pushLayer(); }
|
|
|
|
|
@Override
|
|
|
|
|
public void popLayer() { container.popLayer(); }
|
|
|
|
|
@Override
|
|
|
|
|
public GuiComponent addComponent(GuiComponent component, ConstraintContainer constraints) {
|
|
|
|
|
if(component.screen() != null) throw new IllegalArgumentException("A Child can not have multiple Screens");
|
|
|
|
|
container.add(component);
|
|
|
|
|
component.withConstraints(constraints);
|
|
|
|
|
component.setScreen(this);
|
|
|
|
|
component.init();
|
|
|
|
|
component.onChanged(true);
|
|
|
|
|
return component;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean hasComponent(GuiComponent component) {
|
|
|
|
|
return component.screen() == this && container.contains(component);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isAtTop(GuiComponent component) {
|
|
|
|
|
return component.screen() == this && container.children().contains(component);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean moveToTop(GuiComponent component) {
|
|
|
|
|
return component.screen() == this && container.moveToTop(component);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean removeComponent(GuiComponent component) {
|
|
|
|
|
if(component.screen() == this && container.remove(component)) {
|
|
|
|
|
component.close();
|
|
|
|
|
component.setScreen(null);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void render(IUIRenderer renderer, int mouseX, int mouseY, float partialTicks) {
|
|
|
|
|
for(Object2BooleanMap.Entry<GuiComponent> entry : container) {
|
|
|
|
|
boolean keepMouse = entry.getBooleanValue();
|
|
|
|
|
GuiComponent.renderComponent(entry.getKey(), renderer, keepMouse ? mouseX : -1, keepMouse ? mouseY : -1, partialTicks);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void tick() {
|
|
|
|
|
tick++;
|
|
|
|
|
for(Object2BooleanMap.Entry<GuiComponent> entry : container) {
|
|
|
|
|
GuiComponent.tickComponent(entry.getKey());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class LayeredContainer implements Iterable<Object2BooleanMap.Entry<GuiComponent>> {
|
|
|
|
|
Stack<Layer> layers = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
|
|
public LayeredContainer() { pushLayer(); }
|
|
|
|
|
|
|
|
|
|
public void pushLayer() {
|
|
|
|
|
layers.push(new Layer());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void popLayer() {
|
|
|
|
|
if(layers.size() == 1) return;
|
|
|
|
|
layers.pop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void add(GuiComponent component) {
|
|
|
|
|
layers.top().add(component);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean moveToTop(GuiComponent component) {
|
|
|
|
|
if(layers.top().contains(component)) return true;
|
|
|
|
|
for(int i = 1,m=layers.size();i<m;i++) {
|
|
|
|
|
Layer layer = layers.peek(i);
|
|
|
|
|
if(layer.remove(component)) {
|
|
|
|
|
layers.top().add(component);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean contains(GuiComponent component) {
|
|
|
|
|
for(int i = 0,m=layers.size();i<m;i++) {
|
|
|
|
|
if(layers.peek(i).contains(component)) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean remove(GuiComponent component) {
|
|
|
|
|
for(int i = 0,m=layers.size();i<m;i++) {
|
|
|
|
|
if(layers.peek(i).remove(component)) {
|
|
|
|
|
clearEmptyLayers();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void clearEmptyLayers() {
|
|
|
|
|
while(layers.top().isEmpty() && layers.size() > 0) {
|
|
|
|
|
popLayer();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Iterator<Object2BooleanMap.Entry<GuiComponent>> iterator() {
|
|
|
|
|
return new Iterator<>() {
|
|
|
|
|
BasicEntry<GuiComponent> entry = new BasicEntry<>();
|
|
|
|
|
int myLayer = layers.size()-1;
|
|
|
|
|
Iterator<GuiComponent> childIterator = layers.peek(myLayer).components.iterator();
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean hasNext() {
|
|
|
|
|
return childIterator.hasNext();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Entry<GuiComponent> next() {
|
|
|
|
|
if(!hasNext()) throw new IllegalStateException("Out of Elements to poll");
|
|
|
|
|
entry.set(childIterator.next(), myLayer == 0);
|
|
|
|
|
if(!childIterator.hasNext() && myLayer > 0) {
|
|
|
|
|
childIterator = layers.peek(--myLayer).components.iterator();
|
|
|
|
|
}
|
|
|
|
|
return entry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<GuiComponent> children() {
|
|
|
|
|
return layers.top().components;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<IInteractable> interactables() {
|
|
|
|
|
return layers.top().interactables;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class Layer {
|
|
|
|
|
List<GuiComponent> components = new ObjectArrayList<>();
|
|
|
|
|
List<IInteractable> interactables = new ObjectArrayList<>();
|
|
|
|
|
|
|
|
|
|
public void add(GuiComponent component) {
|
|
|
|
|
components.add(component);
|
|
|
|
|
interactables.add(component.interactContainer());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean contains(GuiComponent component) {
|
|
|
|
|
return components.contains(component);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean remove(GuiComponent component) {
|
|
|
|
|
if(components.remove(component)) {
|
|
|
|
|
interactables.remove(component.interactContainer());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isEmpty() {
|
|
|
|
|
return components.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|