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.ComponentConstrains; import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; import speiger.src.coreengine.utils.collections.iterators.IterableWrapper; public class GuiScreenBase extends GuiBase { Int2ObjectMap getters = new Int2ObjectOpenHashMap<>(); Set components = new ObjectLinkedOpenHashSet<>(); Set keyOrder = new ObjectLinkedOpenHashSet<>(); ObjectOrderedSet renderOrder = new ObjectLinkedOpenHashSet<>(); Object2BooleanOrderedMap buttonOrder = new Object2BooleanLinkedOpenHashMap<>(); Int2ObjectOrderedMap selectedButtons = new Int2ObjectLinkedOpenHashMap<>(); Set 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 addComponent(T comp, ComponentConstrains 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 addComponent(int id, T comp, ComponentConstrains 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 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 components = new ObjectArrayList<>(); for(Iterator 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 findPopups() { List popups = new ObjectArrayList(); 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(buttonOrder.keySet()) : popups); } protected Iterator sortByHeight(List comp) { comp.sort(ButtonSorter.SORTER); return comp.iterator(); } protected Set findKeyPopups() { Set components = new ObjectLinkedOpenHashSet(); 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 { public static final ButtonSorter SORTER = new ButtonSorter(); @Override public int compare(IButtonComponent o1, IButtonComponent o2) { return Float.compare(o2.getComponentZ(), o1.getComponentZ()); } } }