SimpleJavaEngine/src/main/java/speiger/src/coreengine/rendering/gui/base/GuiScreenBase.java

512 lines
13 KiB
Java

package speiger.src.coreengine.rendering.gui.base;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.IntToLongFunction;
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectLinkedOpenHashMap;
import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectOrderedMap;
import speiger.src.collections.ints.sets.IntSet;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.maps.impl.hash.Object2BooleanLinkedOpenHashMap;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
import speiger.src.collections.objects.maps.interfaces.Object2BooleanOrderedMap;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.sets.ObjectLinkedOpenHashSet;
import speiger.src.collections.objects.sets.ObjectOrderedSet;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.coreengine.math.MathUtils;
import speiger.src.coreengine.math.misc.ColorUtils;
import speiger.src.coreengine.rendering.gui.GuiBase;
import speiger.src.coreengine.rendering.gui.GuiComponent;
import speiger.src.coreengine.rendering.gui.components.TooltipPanel;
import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.gui.renderer.UIRenderer;
import speiger.src.coreengine.utils.collections.iterators.IterableWrapper;
public class GuiScreenBase extends GuiBase
{
Int2ObjectMap<GuiComponent> getters = new Int2ObjectOpenHashMap<>();
Set<GuiComponent> components = new ObjectLinkedOpenHashSet<>();
Set<IKeyComponent> keyOrder = new ObjectLinkedOpenHashSet<>();
ObjectOrderedSet<GuiComponent> renderOrder = new ObjectLinkedOpenHashSet<>();
Object2BooleanOrderedMap<IButtonComponent> buttonOrder = new Object2BooleanLinkedOpenHashMap<>();
Int2ObjectOrderedMap<IButtonComponent> selectedButtons = new Int2ObjectLinkedOpenHashMap<>();
Set<IButtonComponent> draggingButtons = new ObjectLinkedOpenHashSet<>();
TooltipPanel tooltips = new TooltipPanel();
int lastMouseX = -1;
int lastMouseY = -1;
long lastTooltipCheck = 0;
boolean drawsTooltip = false;
long delay = 200L;
@Override
public void onInit()
{
super.onInit();
addComponent(tooltips);
}
public void setDelay(long delay, TimeUnit unit)
{
this.delay = Math.max(0, unit.toMillis(delay));
}
@Override
public <T extends GuiComponent> T addComponent(T comp, Constrains contrains)
{
components.add(comp);
renderOrder.addAndMoveToLast(comp);
addConstrains(comp, contrains);
comp.setOwner(this);
if(comp instanceof IButtonComponent)
{
buttonOrder.put((IButtonComponent)comp, true);
addButtonListener((IButtonComponent)comp);
}
if(comp instanceof IKeyComponent)
{
addKeyListener((IKeyComponent)comp);
}
return comp;
}
@Override
public <T extends GuiComponent> T addComponent(int id, T comp, Constrains contrains)
{
getters.put(id, comp);
return addComponent(comp, contrains);
}
@Override
public void addButtonListener(IButtonComponent listener)
{
buttonOrder.putAndMoveToFirst(listener, false);
}
@Override
public void addKeyListener(IKeyComponent listener)
{
keyOrder.add(listener);
}
@Override
public GuiComponent getComponent(int id)
{
return getters.get(id);
}
@Override
public void removeComponent(GuiComponent comp)
{
if(comp != null)
{
comp.onClosed();
}
components.remove(comp);
renderOrder.remove(comp);
getters.values().remove(comp);
if(comp instanceof IButtonComponent)
{
removeButtonListener((IButtonComponent)comp);
}
if(comp instanceof IKeyComponent)
{
removeKeyListener((IKeyComponent)comp);
}
}
@Override
public void removeButtonListener(IButtonComponent listener)
{
buttonOrder.rem(listener);
}
@Override
public void removeKeyListener(IKeyComponent listener)
{
keyOrder.remove(listener);
}
@Override
public void onClosed()
{
super.onClosed();
for(GuiComponent entry : components)
{
entry.onClosed();
}
getters.clear();
renderOrder.clear();
buttonOrder.clear();
}
@Override
public void onScreenChanged()
{
super.onScreenChanged();
for(GuiComponent entry : components)
{
entry.onChanged(true);
}
}
@Override
public void onFixedUpdate()
{
for(GuiComponent entry : renderOrder)
{
if(entry.isVisible())
{
entry.fixedUpdate();
}
}
}
@Override
protected void update(int mouseX, int mouseY, float particalTicks)
{
for(GuiComponent entry : renderOrder)
{
if(entry.isVisible())
{
entry.update(mouseX, mouseY, particalTicks);
}
}
}
@Override
protected void render(int mouseX, int mouseY, float particalTicks)
{
layers = (1 + getBaseLayer());
UIRenderer render = getRenderer();
float biggestZ = 0.0F;
float extra = 1.0F;
Object2ObjectMap<UUID, GuiComponent> components = hasFocus() ? new Object2ObjectLinkedOpenHashMap<>() : Object2ObjectMaps.empty();
for(GuiComponent base : renderOrder)
{
if(base.isVisible() && !base.isManualRender())
{
float z = base.getZOffset();
boolean layer = base.usesRenderOrder();
render.translate(0.0F, 0.0F, layers + z + (layer ? extra : 0.0F));
base.render(mouseX, mouseY, particalTicks);
render.resetTransform();
biggestZ = Math.max(biggestZ, z);
if(layer)
{
extra += 1.0F;
}
}
if(hasFocus())
{
base.collectTooltips(mouseX, mouseY, particalTicks, components);
}
}
layers += MathUtils.floor(biggestZ + extra);
if(hasFocus())
{
if(!drawsTooltip && (lastMouseX != mouseX || lastMouseY != mouseY) || components.isEmpty())
{
lastTooltipCheck = System.currentTimeMillis();
lastMouseX = mouseX;
lastMouseY = mouseY;
if(components.isEmpty())
{
tooltips.updateTooltips(components);
drawsTooltip = false;
}
}
else if(System.currentTimeMillis() - lastTooltipCheck >= delay)
{
drawsTooltip = true;
tooltips.updateTooltips(components);
tooltips.set(mouseX+tooltips.isOutsideScreen(mouseX, width), mouseY);
render.translate(0.0F, 0.0F, layers + 50F);
tooltips.render(mouseX, mouseY, particalTicks);
render.resetTransform();
}
}
render.resetEffects();
}
public void drawBox(GuiComponent comp)
{
if(!getUIManager().isRenderUIBoxes()) return;
UIRenderer render = getRenderer();
render.translate(0F, 0F, 100F);
render.drawFrame(comp.getBox(), ColorUtils.RED);
render.translate(0F, 0F, -100F);
}
@Override
public boolean isAllowingMovement()
{
for(IKeyComponent comp : findKeyPopups())
{
if(comp.isAcceptingInput() && comp.isBlockingMovement())
{
return false;
}
}
return true;
}
@Override
public boolean onKeyTyped(char letter, int codepoint)
{
for(IKeyComponent comp : findKeyPopups())
{
if(comp.isAcceptingInput() && comp.onKeyTyped(letter, codepoint))
{
return true;
}
}
return false;
}
@Override
public boolean onKeyPressed(int key)
{
for(IKeyComponent comp : findKeyPopups())
{
if(comp.isAcceptingInput() && comp.onKeyPressed(key))
{
return true;
}
}
return false;
}
@Override
public boolean onMousePressed(int button, int mouseX, int mouseY)
{
if(buttonOrder.isEmpty()) return false;
List<IButtonComponent> components = new ObjectArrayList<>();
for(Iterator<IButtonComponent> iter = findPopups();iter.hasNext();)
{
IButtonComponent base = iter.next();
if(!base.isValidButton(button)) continue;
if(!base.isComponentColliding(mouseX, mouseY))
{
components.add(base);
continue;
}
if(!base.onClick(button, mouseX, mouseY)) continue;
buttonOrder.getAndMoveToFirst(base);
selectedButtons.put(button, base);
draggingButtons.add(base);
GuiComponent top = getTopComponent(base);
if(base.canMoveIntoForground())
{
if(buttonOrder.getAndMoveToFirst(base) && base instanceof GuiComponent)
{
requestComponentFocus(((GuiComponent)base).getTopComponent());
}
else
{
requestComponentFocus(top);
}
}
else if(top instanceof IButtonComponent && ((IButtonComponent)top).canMoveIntoForground())
{
requestComponentFocus(top);
}
for(int i = 0,m=components.size();i<m;i++)
{
components.get(i).onFocusLost();
}
while(iter.hasNext())
{
IButtonComponent com = iter.next();
if(com == null || com == base)
{
continue;
}
com.onFocusLost();
}
return true;
}
for(int i = 0,m=components.size();i<m;i++)
{
components.get(i).onFocusLost();
}
return false;
}
@Override
public boolean onMouseDragged(IntSet activeButtons, int mouseX, int mouseY, IntToLongFunction timeMap)
{
boolean result = false;
for(IButtonComponent button : draggingButtons)
{
result |= button.onDrag(mouseX, mouseY);
}
return result;
}
@Override
public boolean onMouseReleased(int button, int mouseX, int mouseY)
{
IButtonComponent buttonObj = selectedButtons.remove(button);
if(buttonObj != null)
{
if(buttonObj.isComponentColliding(mouseX, mouseY))
{
buttonObj.onRelease(button, mouseX, mouseY);
draggingButtons.retainAll(selectedButtons.values());
return true;
}
buttonObj.onFocusLost();
}
return false;
}
@Override
public boolean onMouseScroll(int mouseX, int mouseY, int scrollX)
{
if(buttonOrder.isEmpty())
{
return false;
}
for(IButtonComponent base : IterableWrapper.wrap(findPopups()))
{
if(!base.isComponentColliding(mouseX, mouseY))
{
continue;
}
if(base.onScroll(scrollX, mouseX, mouseY))
{
return true;
}
}
return false;
}
public Iterator<IButtonComponent> findPopups()
{
List<IButtonComponent> popups = new ObjectArrayList<IButtonComponent>();
for(IButtonComponent button : buttonOrder.keySet())
{
if(button.isPopup() && !button.hasChildPopups())
{
popups.add(button);
continue;
}
GuiComponent comp = getTopComponent(button);
if(comp instanceof IButtonComponent && ((IButtonComponent)comp).isPopup() && !((IButtonComponent)comp).hasChildPopups())
{
popups.add(button);
}
}
return sortByHeight(popups.isEmpty() ? new ObjectArrayList<IButtonComponent>(buttonOrder.keySet()) : popups);
}
protected Iterator<IButtonComponent> sortByHeight(List<IButtonComponent> comp)
{
comp.sort(ButtonSorter.SORTER);
return comp.iterator();
}
protected Set<IKeyComponent> findKeyPopups()
{
Set<IKeyComponent> components = new ObjectLinkedOpenHashSet<IKeyComponent>();
for(IKeyComponent key : keyOrder)
{
if(key.isPopup() && !key.hasChildPopups())
{
components.add(key);
continue;
}
GuiComponent comp = getTopComponent(key);
if((comp instanceof IKeyComponent && ((IKeyComponent)comp).isPopup() && !((IKeyComponent)comp).hasChildPopups()) || (comp instanceof IButtonComponent && ((IButtonComponent)comp).isPopup()) && !((IButtonComponent)comp).hasChildPopups())
{
components.add(key);
}
}
return components.isEmpty() ? keyOrder : components;
}
protected GuiComponent getTopComponent(IKeyComponent button)
{
return button instanceof GuiComponent ? ((GuiComponent)button).getTopComponent() : null;
}
protected GuiComponent getTopComponent(IButtonComponent button)
{
return button instanceof GuiComponent ? ((GuiComponent)button).getTopComponent() : null;
}
@Override
public void requestComponentFocus(GuiComponent comp)
{
if(!comp.hasPopups())
{
renderOrder.moveToLast(comp);
}
}
@Override
public boolean hasComponentInTheWay(GuiComponent comp, int mouseX, int mouseY)
{
for(GuiComponent other : renderOrder)
{
if(other == comp) break;
if(other.usesRenderOrder() && other.isHovered(mouseX, mouseY)) return true;
}
return false;
}
@Override
public boolean isComponentInWay(GuiComponent comp, int mouseX, int mouseY)
{
for(IButtonComponent entry : buttonOrder.keySet())
{
if(entry != comp && entry instanceof GuiComponent && ((GuiComponent)entry).isHovered(mouseX, mouseY))
{
return true;
}
}
return false;
}
@Override
public boolean isComponentFocused(GuiComponent comp)
{
return hasFocus() && buttonOrder.size() > 0 && ((buttonOrder.size() == 1 && buttonOrder.containsKey(comp)) || buttonOrder.firstKey() == comp);
}
@Override
public boolean isComponentInFront(GuiComponent comp)
{
if(!hasFocus() || renderOrder.last() == comp || (renderOrder.last() instanceof IButtonComponent && ((IButtonComponent)renderOrder.last()).isPopup()))
{
return true;
}
return false;
}
@Override
public boolean hasComponentPressed(int mouseButton)
{
return selectedButtons.containsKey(mouseButton);
}
static final class ButtonSorter implements Comparator<IButtonComponent>
{
public static final ButtonSorter SORTER = new ButtonSorter();
@Override
public int compare(IButtonComponent o1, IButtonComponent o2)
{
return Float.compare(o2.getComponentZ(), o1.getComponentZ());
}
}
}