package speiger.src.coreengine.rendering.gui; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.function.Consumer; import org.lwjgl.glfw.GLFW; import speiger.src.collections.objects.lists.ObjectArrayList; import speiger.src.collections.objects.sets.ObjectLinkedOpenHashSet; import speiger.src.coreengine.assets.AssetLocation; import speiger.src.coreengine.math.collision2d.Plane; import speiger.src.coreengine.math.vector.doubles.Vec2d; import speiger.src.coreengine.rendering.gui.base.GuiScreenBase; import speiger.src.coreengine.rendering.gui.base.IButtonComponent; import speiger.src.coreengine.rendering.gui.base.IKeyComponent; import speiger.src.coreengine.rendering.gui.components.TextComponent; import speiger.src.coreengine.rendering.gui.helper.Align; import speiger.src.coreengine.rendering.gui.helper.animations.Animator; import speiger.src.coreengine.rendering.gui.helper.box.GuiBox; import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; import speiger.src.coreengine.rendering.gui.helper.constrains.ComponentConstrains; import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain; import speiger.src.coreengine.rendering.gui.renderer.IComponentRenderer; import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; import speiger.src.coreengine.rendering.input.Keyboard; import speiger.src.coreengine.rendering.input.bindings.utils.BindingType; import speiger.src.coreengine.rendering.input.bindings.utils.ModType; import speiger.src.coreengine.rendering.input.window.Window; import speiger.src.coreengine.rendering.utils.Cursor; import speiger.src.coreengine.rendering.utils.GLUtils; import speiger.src.coreengine.utils.collections.CollectionUtils; import speiger.src.coreengine.utils.collections.FlagHolder; public abstract class GuiComponent extends FlagHolder { public static final int FLAG_VISIBLE = 1; public static final int FLAG_ENABLED = 2; public static final int FLAG_IGNORE_PARENT_BOUNDS = 4; public static final int FLAG_ALWAYS_CLICKABLE = 8; public static final int FLAG_RENDER_ORDER = 16; public static final int FLAG_MANUAL_RENDER = 32; public static final int FLAG_MASS_CHANGE = 64; public static final int FLAG_SUPPORT_BINDING = 128; public static final int FLAG_TEST_SCISSORS = 256; static final int FLAG_CLOSING = 512; public static final int LAST_FLAG = 1 << 19;// This is the last flag and then // anything behind this is custom // flags for components public static final int LISTENER_USER_ACTION = 0; public static final int LISTENER_ON_CHANGE = 1; public static final int LISTENER_CLOSED = 2; final IGuiBox box; GuiBase owner; GuiComponent parent; ComponentConstrains constraints = null; Animator animation = null; KeyBindAction binding = null; IComponentRenderer customRenderer; Set>[] listeners = CollectionUtils.createSets(3, true); Set children = new ObjectLinkedOpenHashSet<>(); Set popupChildren = new ObjectLinkedOpenHashSet<>(); Tooltips tooltips = new Tooltips(); UUID tooltipId; float zLevel = 0F; float totalZ = 0F; float visiblity = 1F; float totalVisibility = 1F; float brightness = 1F; boolean changed = false; boolean massRepaint = false; public GuiComponent(float x, float y, float width, float height) { this(new GuiBox(x, y, width, height)); } public GuiComponent(IGuiBox box) { super(FLAG_VISIBLE | FLAG_ENABLED); this.box = box; } public IGuiBox getBox() { return box; } public GuiBase getGui() { return owner; } public void calculateActualBounds(float[] area, boolean start) { if(start) { area[0] = Float.MAX_VALUE; area[1] = Float.MAX_VALUE; area[2] = Float.MIN_VALUE; area[3] = Float.MIN_VALUE; } area[0] = Math.min(area[0], box.getMinX()); area[1] = Math.min(area[1], box.getMinY()); area[2] = Math.max(area[2], box.getMaxX()); area[3] = Math.max(area[3], box.getMaxY()); for(GuiComponent comp : children) { if(comp.isVisible()) comp.calculateActualBounds(area, false); } } public boolean isMouseOver(int mouseX, int mouseY) { return (parent == null || isFlagSet(FLAG_IGNORE_PARENT_BOUNDS) || parent.isMouseOver(mouseX, mouseY)) && isOverBox(mouseX, mouseY); } protected boolean isOverBox(int mouseX, int mouseY) { return box.isColiding(mouseX, mouseY); } public boolean isHovered(int mouseX, int mouseY) { return isParentVisible() && isAnyFlagSet(FLAG_ALWAYS_CLICKABLE | FLAG_ENABLED) && isMouseOver(mouseX, mouseY); } public boolean isTopHovered(int mouseX, int mouseY) { if(!isHovered(mouseX, mouseY)) { return false; } GuiComponent top = getTopComponent(); return !getGui().hasComponentInTheWay(top, mouseX, mouseY) && top.isChildAtTop(this, mouseX, mouseY); } public boolean isChildAtTop(GuiComponent component, int mouseX, int mouseY) { float sourceHeight = component.calculateZLevel(); if(children.isEmpty()) { return true; } for(GuiComponent comp : children) { if(comp != component && comp.isOverChild(mouseX, mouseY) && (comp.calculateZLevel() > sourceHeight || !comp.isChildAtTop(component, mouseX, mouseY))) { return false; } } return true; } public boolean isOverChild(int mouseX, int mouseY) { if(children.isEmpty()) { return false; } for(GuiComponent comp : children) { if(comp.isOverChild(mouseX, mouseY) || (comp instanceof IButtonComponent && ((IButtonComponent)comp).isComponentColliding(mouseX, mouseY))) { return true; } } return false; } public boolean hasFocus() { return getGui().isComponentFocused(getTopComponent()); } public final boolean hasPopups() { return popupChildren.size() > 0; } public final void setOwner(GuiBase gui) { owner = gui; for(GuiComponent comp : children) { comp.setOwner(gui); if(comp instanceof IButtonComponent) { getGui().addButtonListener((IButtonComponent)comp); } if(comp instanceof IKeyComponent) { getGui().addKeyListener((IKeyComponent)comp); } } init(); onComponentChanged(true); if(binding != null) { gui.addKeyListener(binding); } } public abstract void init(); public void onClosed() { if(!setFlag(FLAG_CLOSING, true)) { return; } for(GuiComponent comp : children) { comp.onClosed(); if(comp instanceof IButtonComponent) { getGui().removeButtonListener((IButtonComponent)comp); } if(comp instanceof IKeyComponent) { getGui().removeKeyListener((IKeyComponent)comp); } } children.clear(); popupChildren.clear(); box.clearChildren(); if(binding != null) { owner.removeKeyListener(binding); } notifyListeners(LISTENER_CLOSED); clearFlag(FLAG_CLOSING); } public final float getZOffset() { return zLevel; } public final float calculateZLevel() { return totalZ; } public final float getVisibility() { return visiblity; } public final float getTotalVisibility() { return totalVisibility; } public final float getBrightness() { return brightness; } public final boolean hasConstraints() { return constraints != null; } public final boolean isEnabled() { return isFlagSet(FLAG_ENABLED); } public final boolean isVisible() { return isFlagSet(FLAG_VISIBLE); } public final boolean usesRenderOrder() { return isFlagSet(FLAG_RENDER_ORDER); } public final boolean isManualRender() { return isFlagSet(FLAG_MANUAL_RENDER); } public boolean isTestingScissors() { return isFlagSet(FLAG_TEST_SCISSORS); } public final boolean isParentVisible() { return isVisible() && (parent == null || parent.isVisible()); } public final void setMassChanging() { setFlag(FLAG_MASS_CHANGE); } public final T setMassChanging(Class clz) { setFlag(FLAG_MASS_CHANGE); return (T)this; } public final GuiComponent finishMassChanging() { return finishMassChanging(false); } public final GuiComponent finishMassChanging(boolean quiet) { if(isFlagSet(FLAG_MASS_CHANGE)) { clearFlag(FLAG_MASS_CHANGE); if(changed && !quiet) { onComponentChanged(massRepaint); } } return this; } public final GuiComponent setEnabled(boolean value) { if(!setFlag(FLAG_ENABLED, value)) return this; for(GuiComponent comp : children) { comp.setEnabled(value); } return this; } public final GuiComponent setVisible(boolean value) { if(!setFlag(FLAG_VISIBLE, value)) return this; for(GuiComponent comp : children) { comp.setVisible(value); } return this; } public final GuiComponent setManualRenderer(boolean value) { setFlag(FLAG_MANUAL_RENDER, value); return this; } public GuiComponent setIgnoreBounds(boolean value) { setFlag(FLAG_IGNORE_PARENT_BOUNDS, value); return this; } public GuiComponent setScissorsTest(boolean value) { setFlag(FLAG_TEST_SCISSORS, value); return this; } public final GuiComponent setScale(float value) { if(getBox().getBaseScale() != value) { getBox().setScale(value); onComponentChanged(true); } return this; } public final GuiComponent setZOffset(float value) { zLevel = value; return this; } public final GuiComponent setVisibilty(float value) { if(visiblity == value) return this; visiblity = value; updateVisibility(); return this; } public final GuiComponent setBrightness(float value) { brightness = value; return this; } public final GuiComponent changeVisibility(float value) { return value == 1F ? this : setVisibilty(visiblity * value); } protected void updateVisibility() { totalVisibility = (parent != null ? parent.totalVisibility : 1F) * visiblity; for(GuiComponent comp : children) { comp.updateVisibility(); } } public GuiComponent setUserKey(int keyBind){return setUserKey(keyBind, ModType.IGNORE, false);} public GuiComponent setUserKey(int keyBind, boolean block){return setUserKey(keyBind, ModType.IGNORE, block);} public GuiComponent setUserKey(int keyBind, int mod){return setUserKey(keyBind, mod, false);} public GuiComponent setUserKey(int keyBind, int mod, boolean block) { if(isFlagNotSet(FLAG_SUPPORT_BINDING)) return this; if(owner != null) { if(binding != null) { owner.removeKeyListener(binding); tooltips.removeTooltip(binding.getTooltip()); } binding = new KeyBindAction(keyBind, mod, block); owner.addKeyListener(binding); addBindingTooltip(); return this; } binding = new KeyBindAction(keyBind, mod, block); addBindingTooltip(); return this; } public GuiComponent setCustomRenderer(IComponentRenderer renderer) { customRenderer = (IComponentRenderer)renderer; return this; } private void addBindingTooltip() { tooltips.addComponent(binding.getTooltip(), new TextComponent(0F, 0F, 200F, 0F, "Key: "+ModType.getMods(binding.mod)+BindingType.KEYBOARD.getName(binding.key)).setLimitedHeight(false).setAlignment(Align.LEFT_TOP, Align.LEFT_TOP).setScale(0.5F)); } protected boolean onUserKey() { return false; } public T setRelativeTo(T component) { return setRelativeTo(component, Align.CENTER, Align.CENTER); } public T setRelativeTo(T component, Align horizontal, Align vertical) { return component.setComponentPosition(box.getMinX() + horizontal.align(box.getWidth(), component.getBox().getWidth()), box.getMinY() + vertical.align(box.getHeight(), component.getBox().getHeight())).cast(); } public T centerComponent(T component) { return getGui().centerComponent(component); } public T addChild(T comp) { return addChild(comp, null); } public T addChild(T comp, Constrain xPos, Constrain yPos, Constrain width, Constrain height) { return addChild(comp, new ComponentConstrains(xPos, yPos, width, height)); } public T addChild(T comp, ComponentConstrains constrains) { comp.constraints = constrains; comp.parent = this; children.add(comp); box.addChild(comp.getBox()); if(constrains != null) { constrains.setOwner(comp, this); constrains.onComponentChanged(); } if(owner != null) { comp.setOwner(owner); if(comp instanceof IButtonComponent) { owner.addButtonListener((IButtonComponent)comp); } if(comp instanceof IKeyComponent) { owner.addKeyListener((IKeyComponent)comp); } } return comp; } public T addPopup(T popup) { popupChildren.add(popup.addCloseListener(popupChildren::remove)); getGui().addComponent(popup); return popup; } protected void addConstrains(GuiComponent comp, ComponentConstrains constrains) { comp.constraints = constrains; if(constrains != null) { constrains.setOwner(comp, this); constrains.onComponentChanged(); } } public final UUID getTooltipId() { return tooltipId; } public Tooltips getTooltips() { return tooltips; } public GuiComponent addTooltip(String s, float width) { return addTooltip(s, width, 0F); } public GuiComponent addTooltip(String s, float width, float height) { return addTooltip(s, width, height, 0.5F); } public GuiComponent addTooltip(String s, float width, float height, float scale) { tooltips.addComponent(new TextComponent(0F, 0F, width, height, s).setLimitedHeight(height != 0F).setAlignment(Align.LEFT_TOP, Align.LEFT_TOP).setScale(scale)); return this; } public GuiComponent addTooltip(GuiComponent comp) { tooltips.addComponent(comp); return this; } public GuiComponent addTooltip(UUID id, GuiComponent comp) { tooltips.addComponent(id, comp); return this; } public boolean containsTooltip(UUID id) { return tooltips.contains(id); } public boolean isTooltip() { return tooltipId != null; } public GuiComponent removeTooltip(GuiComponent comp) { return removeTooltip(comp.getTooltipId()); } public GuiComponent removeTooltip(UUID id) { return tooltips.removeTooltip(id); } public List getChildren() { return new ObjectArrayList(children); } public GuiComponent getParent() { return parent; } public GuiComponent removeChild(GuiComponent comp) { comp.onClosed(); children.remove(comp); box.removeChild(comp.getBox()); if(comp instanceof IButtonComponent) { owner.removeButtonListener((IButtonComponent)comp); } if(comp instanceof IKeyComponent) { owner.removeKeyListener((IKeyComponent)comp); } return this; } public GuiComponent removeChildren() { for(GuiComponent comp : children) { comp.onClosed(); if(comp instanceof IButtonComponent) { owner.removeButtonListener((IButtonComponent)comp); } if(comp instanceof IKeyComponent) { owner.removeKeyListener((IKeyComponent)comp); } } children.clear(); box.clearChildren(); return this; } public IGuiBox addBox(IGuiBox box) { this.box.addChild(box); return box; } public GuiComponent removeBox(IGuiBox box) { this.box.removeChild(box); return this; } public final GuiComponent addUserActionListener(Consumer listener) { return addListener(listener, GuiComponent.LISTENER_USER_ACTION); } public final GuiComponent addUserActionListener(Runnable listener) { return addListener(listener, GuiComponent.LISTENER_USER_ACTION); } public final GuiComponent addChangeListener(Consumer listener) { return addListener(listener, GuiComponent.LISTENER_ON_CHANGE); } public final GuiComponent addChangeListener(Runnable listener) { return addListener(listener, GuiComponent.LISTENER_ON_CHANGE); } public final GuiComponent addCloseListener(Consumer listener) { return addListener(listener, GuiComponent.LISTENER_CLOSED); } public final GuiComponent addCloseListener(Runnable listener) { return addListener(listener, GuiComponent.LISTENER_CLOSED); } public final GuiComponent addListener(Runnable runnable, int index) { listeners[index].add(T -> runnable.run()); return this; } public final GuiComponent addListener(Consumer listener, int index) { listeners[index].add(listener); return this; } protected final void notifyListeners(int index) { if(listeners[index].size() > 0) { for(Consumer comp : listeners[index]) { comp.accept(this); } } } public final GuiComponent removeUserActionListener(Consumer listener) { return removeListener(listener, GuiComponent.LISTENER_USER_ACTION); } public final GuiComponent removeChangeListener(Consumer listener) { return removeListener(listener, GuiComponent.LISTENER_ON_CHANGE); } public final GuiComponent removeCloseListener(Consumer listener) { return removeListener(listener, GuiComponent.LISTENER_CLOSED); } public final GuiComponent removeListener(Consumer listener, int index) { listeners[index].remove(listener); return this; } public GuiComponent moveComponent(float x, float y) { if(x == 0F && y == 0F || constraints != null) return this; box.move(x, y); onComponentChanged(false); return this; } public GuiComponent setComponentPosition(float x, float y) { if(box.getBaseX() == x && box.getBaseY() == y || constraints != null) return this; box.setXY(x, y); onComponentChanged(false); return this; } public GuiComponent resizeComponent(float moveX, float moveY) { if(moveX == 0F && moveY == 0F || constraints != null) return this; box.grow(moveX, moveY); onComponentChanged(true); return this; } public GuiComponent setComponentBounds(float width, float height) { if(box.getBaseWidth() == width && box.getBaseHeight() == height || constraints != null) return this; box.setBounds(width, height); onComponentChanged(true); return this; } public final void onComponentChanged(boolean repaint) { if(owner == null) return; if(isFlagSet(FLAG_MASS_CHANGE)) { changed = true; massRepaint |= repaint; return; } massRepaint = false; changed = false; if(constraints != null) { constraints.onComponentChanged(); if(animation != null) animation.applyValues(false); } box.onChanged(); totalZ = 0F; GuiComponent zComp = this; while(zComp != null) { totalZ += 0.01F + zComp.getZOffset(); zComp = zComp.parent; } notifyListeners(LISTENER_ON_CHANGE); updateState(); if(repaint) repaint(); if(children.isEmpty()) return; for(GuiComponent comp : children) { comp.onComponentChanged(repaint); } } protected void updateState() { } protected void repaint() { } public final void onFixedUpdate() { if(fixedUpdateSelf()) fixedUpdateChildren(); } public final void onUpdate(int mouseX, int mouseY, float particalTicks) { if(animation != null) animation.update(particalTicks); if(updateSelf(mouseX, mouseY, particalTicks)) updateChildren(mouseX, mouseY, particalTicks); } protected void onPreRender() { } public final void onRender(int mouseX, int mouseY, float particalTicks) { if(customRenderer != null) { customRenderer.onPreRender(this); getRenderer().setVisibility(totalVisibility).setBrightness(brightness); if(customRenderer.render(this)) renderChildren(mouseX, mouseY, particalTicks); customRenderer.onPostRender(this); getRenderer().resetEffects(); } else { onPreRender(); getRenderer().setVisibility(totalVisibility).setBrightness(brightness); if(renderSelf(mouseX, mouseY, particalTicks)) renderChildren(mouseX, mouseY, particalTicks); onPostRender(); getRenderer().resetEffects(); } if(getGui() instanceof GuiScreenBase) { ((GuiScreenBase)getGui()).drawBox(this); } } protected void onPostRender() { } protected boolean fixedUpdateSelf() { return true; } protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) { return true; } protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) { return true; } public void collectTooltips(int mouseX, int mouseY, float particalTicks, Map collector) { if(isParentVisible()) { if(isHovered(mouseX, mouseY)) { tooltips.merge(collector); } if(children.size() > 0) { for(GuiComponent entry : children) { entry.collectTooltips(mouseX, mouseY, particalTicks, collector); } } } } public void fixedUpdateChildren() { for(GuiComponent entry : children) { if(entry.isVisible()) { entry.onFixedUpdate(); } } } public void updateChildren(int mouseX, int mouseY, float particalTicks) { for(GuiComponent entry : children) { if(entry.isVisible()) { entry.onUpdate(mouseX, mouseY, particalTicks); } } } public void renderChildren(int mouseX, int mouseY, float particalTicks) { for(GuiComponent entry : children) { if(!entry.isManualRender() && entry.isVisible() && (!isTestingScissors() || isInScissors(entry.getBox()))) { float zOffset = entry.getZOffset() + 0.01F; getRenderer().push(); getRenderer().translate(0F, 0F, zOffset); entry.onPreRender(); entry.onRender(mouseX, mouseY, particalTicks); entry.onPostRender(); getRenderer().translate(0F, 0F, -zOffset); getRenderer().pop(); } } } public Animator getAnimator() { if(animation == null) { animation = new Animator(this); } return animation; } public T cast() { return (T)this; } public T cast(Class clz) { return (T)this; } public T tryCast(Class clz) { return clz.isInstance(this) ? (T)this : null; } public GuiComponent getTopComponent() { GuiComponent top = this; while(top.parent != null) { top = top.parent; } return top; } protected void requestFocus() { getGui().requestComponentFocus(this); } protected boolean isFocused() { return getGui().isComponentFocused(this); } protected boolean isFocusedOrChilds() { return isFocused() || isChildFocused(); } protected boolean isChildFocused() { for(GuiComponent comp : children) { if(comp.isFocusedOrChilds()) { return true; } } return false; } protected UIRenderer getRenderer() { return owner.getRenderer(); } protected Window getWindow() { return owner.getWindow(); } protected boolean isSelect(int keyCode) { return keyCode == GLFW.GLFW_KEY_A && Keyboard.isCtrlDown() && !Keyboard.isShiftDown() && !Keyboard.isAltDown(); } protected boolean isCopy(int keyCode) { return keyCode == GLFW.GLFW_KEY_C && Keyboard.isCtrlDown() && !Keyboard.isShiftDown() && !Keyboard.isAltDown(); } protected boolean isPaste(int keyCode) { return keyCode == GLFW.GLFW_KEY_V && Keyboard.isCtrlDown() && !Keyboard.isShiftDown() && !Keyboard.isAltDown(); } protected boolean isCut(int keyCode) { return keyCode == GLFW.GLFW_KEY_X && Keyboard.isCtrlDown() && !Keyboard.isShiftDown() && !Keyboard.isAltDown(); } protected final float getBrightness(int mouseX, int mouseY) { return isEnabled() ? (isHovered(mouseX, mouseY) ? 0.7F : 1F) : 0.5F; } public final float getActiveBrightness() { return isEnabled() ? 1F : 0.5F; } public long getGlobalClock() { return getGui().getGlobalClock(); } protected final void bindCursor(AssetLocation location) { Cursor.INSTANCE.bindCursor(location, getWindow()); } protected final void clearCursor() { Cursor.INSTANCE.clearCursor(getWindow()); } protected final void enableScissors(Plane box) { enableScissors(box.getMinX(), box.getMinY(), box.getWidth(), box.getHeight()); } protected final void enableScissors(IGuiBox box) { enableScissors((int)box.getMinX(), (int)box.getMinY(), (int)box.getWidth(), (int)box.getHeight()); } protected final void enableScissorsBox(float minX, float minY, float maxX, float maxY) { enableScissors((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY)); } protected final void enableScissors(float x, float y, float width, float height) { enableScissors((int)x, (int)y, (int)width, (int)height); } protected final void enableScissors(int x, int y, int width, int height) { getRenderer().flush(); int bottom = y + height; Window window = owner.getWindow(); Vec2d vec = owner.getUIManager().res.getScaleVec(); GLUtils.TESTER.enableScissors((int)(x * vec.getX()), (int)(window.getHeight() - bottom * vec.getY()), (int)(width * vec.getX()), (int)(height * vec.getY())); } protected final boolean isInScissors(Plane box) { return isInScissors(box.getMinX(), box.getMinY(), box.getWidth(), box.getHeight()); } protected final boolean isInScissors(IGuiBox box) { return isInScissors((int)box.getMinX(), (int)box.getMinY(), (int)box.getWidth(), (int)box.getHeight()); } protected final boolean isInScissors(float minX, float minY, float maxX, float maxY) { return isInScissors((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY)); } protected final boolean isInScissors(int x, int y, int width, int height) { int bottom = y + height; Window window = owner.getWindow(); Vec2d vec = owner.getUIManager().res.getScaleVec(); return GLUtils.TESTER.isInScissors((int)(x * vec.getX()), (int)(window.getHeight() - bottom * vec.getY()), (int)(width * vec.getX()), (int)(height * vec.getY())); } public final void disableScissors() { getRenderer().flush(); GLUtils.TESTER.disableScissors(); } class KeyBindAction implements IKeyComponent { int key; int mod; boolean block; UUID tooltip = UUID.randomUUID(); public KeyBindAction(int key, int mod, boolean block) { this.key = key; this.mod = mod; this.block = block; } public UUID getTooltip() { return tooltip; } @Override public boolean isAcceptingInput() { return isAnyFlagSet(FLAG_ALWAYS_CLICKABLE | FLAG_ENABLED); } @Override public boolean isBlockingMovement() { return block; } @Override public boolean isPopup() { return isPopupButton(GuiComponent.this) || isPopupButton(getTopComponent()); } @Override public boolean hasChildPopups() { return hasPopups(); } private boolean isPopupButton(GuiComponent comp) { return comp instanceof IButtonComponent ? ((IButtonComponent)comp).isPopup() : false; } @Override public boolean onKeyPressed(int key) { if(key == this.key && ModType.isActive(mod)) { return onUserKey(); } return false; } } }