From b42e680b8a2c5eaf0b489071a37ecc2fc5de4549 Mon Sep 17 00:00:00 2001 From: Speiger Date: Fri, 19 May 2023 21:26:57 +0200 Subject: [PATCH] Latest Sync --- build.gradle | 137 +- .../application/ApplicationExecutor.java | 286 +- .../rendering/gui/GuiComponent.java | 2309 +++++++++-------- .../coreengine/rendering/gui/GuiManager.java | 556 ++-- .../rendering/gui/base/GuiScreenBase.java | 1022 ++++---- .../gui/components/ButtonComponent.java | 136 +- .../gui/components/CheckBoxComponent.java | 244 +- .../gui/components/LabelComponent.java | 112 +- .../gui/components/ListComponent.java | 1372 +++++----- .../gui/components/PanelComponent.java | 68 +- .../gui/components/PieComponent.java | 346 +-- .../gui/components/ProgressBarComponent.java | 281 +- .../gui/components/ScrollBarComponent.java | 486 ++-- .../gui/components/ScrollPanelComponent.java | 192 +- .../gui/components/ScrollWindowComponent.java | 218 +- .../gui/components/SelectionComponent.java | 726 +++--- .../components/SingleTabPanelComponent.java | 334 +++ .../gui/components/SliderComponent.java | 415 +-- .../gui/components/TabbedPanelComponent.java | 339 +++ .../gui/components/TabbedWindowComponent.java | 61 - .../gui/components/TextComponent.java | 874 +++---- .../gui/components/TextFieldComponent.java | 1456 +++++------ .../gui/components/TextPanelComponent.java | 1386 +++++----- .../gui/components/TreeComponent.java | 1394 +++++----- .../gui/components/WindowComponent.java | 720 ++--- .../components/layouts/VerticalLayout.java | 168 +- .../gui/components/menu/MenuBarComponent.java | 204 +- .../menu/MenuCheckBoxComponent.java | 252 +- .../gui/components/menu/MenuComponent.java | 636 ++--- .../gui/components/misc/CheckBoxGroup.java | 236 +- .../gui/components/misc/ICheckBox.java | 20 +- .../components/special/ConsoleComponent.java | 444 ++-- .../components/tree/ProfilerTreeEntry.java | 258 +- .../color/ColorPickerWindowComponent.java | 306 +-- ...wComponent.java => PieProfilerWindow.java} | 630 ++--- .../window/debug/TreeProfilerWindow.java | 216 ++ .../debug/TreeProfilerWindowComponent.java | 184 -- .../window/misc/ChoiceComponent.java | 120 +- .../window/misc/MessageComponent.java | 148 +- .../window/misc/TextInputComponent.java | 132 +- .../helper/animations/AnimationInstance.java | 104 +- .../gui/helper/constrains/Constrains.java | 256 +- .../rendering/gui/renderer/UIRenderer.java | 1414 +++++----- .../gui/renderer/buffer/RenderBuffer.java | 160 +- .../rendering/gui/renderer/lexer/Line.java | 284 +- .../gui/renderer/lexer/TextMetadata.java | 316 +-- .../rendering/input/window/Window.java | 1207 ++++----- .../rendering/shader/ShaderEntry.java | 46 +- .../rendering/tesselation/Tesselator.java | 552 ++-- .../rendering/tesselation/VertexList.java | 140 +- .../rendering/tesselation/VertexType.java | 70 +- .../coreengine/rendering/utils/GLUtils.java | 270 +- .../rendering/utils/ScreenshotHandler.java | 496 ++-- .../rendering/utils/states/BlendState.java | 81 +- .../rendering/utils/states/CullState.java | 73 +- .../rendering/utils/states/FloatState.java | 117 +- .../rendering/utils/states/GLState.java | 137 +- .../rendering/utils/states/IGLState.java | 13 +- .../utils/collections/pools/ThreadPool.java | 156 +- .../utils/profiler/GPUProfilerEntry.java | 302 +-- .../coreengine/utils/profiler/IProfiler.java | 324 ++- .../utils/profiler/ProfilerEntry.java | 304 +-- .../utils/tasks/MainThreadTaskProcessor.java | 292 +-- 63 files changed, 13681 insertions(+), 12857 deletions(-) create mode 100644 src/main/java/speiger/src/coreengine/rendering/gui/components/SingleTabPanelComponent.java create mode 100644 src/main/java/speiger/src/coreengine/rendering/gui/components/TabbedPanelComponent.java delete mode 100644 src/main/java/speiger/src/coreengine/rendering/gui/components/TabbedWindowComponent.java rename src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/{PieProfilerWindowComponent.java => PieProfilerWindow.java} (59%) create mode 100644 src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/TreeProfilerWindow.java delete mode 100644 src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/TreeProfilerWindowComponent.java diff --git a/build.gradle b/build.gradle index ce57f6a..7482966 100644 --- a/build.gradle +++ b/build.gradle @@ -1,70 +1,69 @@ -apply plugin: 'java' -apply plugin: 'eclipse' - -tasks.withType(JavaCompile) { - options.encoding = 'UTF-8' - options.compilerArgs << "-Xlint:deprecation" -} - -eclipse { - classpath { - downloadJavadoc = true - downloadSources = true - } -} -sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' -repositories { - mavenCentral() - maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } - maven { - url = "https://maven.speiger.com/repository/main" - } -} - -task srcJar(type: Jar) { - from sourceSets.main.allSource - classifier = 'sources' - from { - configurations.compile.collect { - it.isDirectory() ? it : zipTree(it) - } - } -} - -artifacts { - archives srcJar -} - -jar{ - from { - configurations.compile.collect { - it.isDirectory() ? it : zipTree(it) - } - } -} - -dependencies { - //LWJGL 3 - compile platform("org.lwjgl:lwjgl-bom:$lwjglVersion") - - compile "org.lwjgl:lwjgl" - compile "org.lwjgl:lwjgl-glfw" - compile "org.lwjgl:lwjgl-jemalloc" - compile "org.lwjgl:lwjgl-openal" - compile "org.lwjgl:lwjgl-opengl" - compile "org.lwjgl:lwjgl-stb" - compile "org.lwjgl:lwjgl-nfd" - compile "org.lwjgl:lwjgl::$lwjglNatives" - compile "org.lwjgl:lwjgl-glfw::$lwjglNatives" - compile "org.lwjgl:lwjgl-jemalloc::$lwjglNatives" - compile "org.lwjgl:lwjgl-openal::$lwjglNatives" - compile "org.lwjgl:lwjgl-opengl::$lwjglNatives" - compile "org.lwjgl:lwjgl-stb::$lwjglNatives" - compile "org.lwjgl:lwjgl-nfd::$lwjglNatives" - - //Gson - compile 'com.google.code.gson:gson:2.8.6' - - //Primitive Collections - compile 'de.speiger:Primitive-Collections:0.6.1' +apply plugin: 'java' +apply plugin: 'eclipse' + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +eclipse { + classpath { + downloadJavadoc = true + downloadSources = true + } +} +sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' +repositories { + mavenCentral() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } + maven { + url = "https://maven.speiger.com/repository/main" + } +} + +task srcJar(type: Jar) { + from sourceSets.main.allSource + classifier = 'sources' + from { + configurations.compile.collect { + it.isDirectory() ? it : zipTree(it) + } + } +} + +artifacts { + archives srcJar +} + +jar{ + from { + configurations.compile.collect { + it.isDirectory() ? it : zipTree(it) + } + } +} + +dependencies { + //LWJGL 3 + compile platform("org.lwjgl:lwjgl-bom:$lwjglVersion") + + compile "org.lwjgl:lwjgl" + compile "org.lwjgl:lwjgl-glfw" + compile "org.lwjgl:lwjgl-jemalloc" + compile "org.lwjgl:lwjgl-openal" + compile "org.lwjgl:lwjgl-opengl" + compile "org.lwjgl:lwjgl-stb" + compile "org.lwjgl:lwjgl-nfd" + compile "org.lwjgl:lwjgl::$lwjglNatives" + compile "org.lwjgl:lwjgl-glfw::$lwjglNatives" + compile "org.lwjgl:lwjgl-jemalloc::$lwjglNatives" + compile "org.lwjgl:lwjgl-openal::$lwjglNatives" + compile "org.lwjgl:lwjgl-opengl::$lwjglNatives" + compile "org.lwjgl:lwjgl-stb::$lwjglNatives" + compile "org.lwjgl:lwjgl-nfd::$lwjglNatives" + + //Gson + compile 'com.google.code.gson:gson:2.8.6' + + //Primitive Collections + compile 'de.speiger:Primitive-Collections:0.7.0' } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/application/ApplicationExecutor.java b/src/main/java/speiger/src/coreengine/application/ApplicationExecutor.java index d430402..a1ce37c 100644 --- a/src/main/java/speiger/src/coreengine/application/ApplicationExecutor.java +++ b/src/main/java/speiger/src/coreengine/application/ApplicationExecutor.java @@ -1,143 +1,143 @@ -package speiger.src.coreengine.application; - -import java.text.DecimalFormat; - -import org.lwjgl.opengl.GL11; - -import speiger.src.collections.objects.queues.ObjectArrayFIFOQueue; -import speiger.src.collections.objects.queues.ObjectPriorityQueue; -import speiger.src.coreengine.rendering.input.window.Window; -import speiger.src.coreengine.rendering.utils.AllocationTracker; -import speiger.src.coreengine.rendering.utils.GLStamper; -import speiger.src.coreengine.rendering.utils.GLStamper.GLStamp; -import speiger.src.coreengine.rendering.utils.GLUtils; -import speiger.src.coreengine.utils.counters.averager.TimeAverager; -import speiger.src.coreengine.utils.counters.timers.FPSTimer; -import speiger.src.coreengine.utils.counters.timers.FrameSyncer; -import speiger.src.coreengine.utils.counters.timers.TimerTarget; -import speiger.src.coreengine.utils.helpers.FileUtils; -import speiger.src.coreengine.utils.helpers.TextUtil; -import speiger.src.coreengine.utils.io.GameLog; -import speiger.src.coreengine.utils.io.GameLog.LogLevel; -import speiger.src.coreengine.utils.profiler.IProfiler; - -public class ApplicationExecutor -{ - public static final DecimalFormat FORMATTER = new DecimalFormat("###"); - FPSTimer timer = new FPSTimer(); - TimerTarget fps = timer.getFPS(); - TimerTarget ups = timer.getUPS(); - FrameSyncer sync = new FrameSyncer(); - - TimeAverager gpuTime = new TimeAverager(); - ObjectPriorityQueue stamps = new ObjectArrayFIFOQueue<>(); - StringBuilder builder = new StringBuilder(); - - long frame = 0L; - - Application owner; - - public ApplicationExecutor(Application owner) - { - this.owner = owner; - owner.timer = timer; - } - - private IProfiler gpu() - { - return owner.gpuProfiler; - } - - public void start(Window window) - { - createTimeHacker(); - timer.init(); - try - { - while(window.shouldRun()) loop(window); - } - catch(Exception e) - { - GameLog.error("Client Has Crashed", e, LogLevel.ERROR); - } - } - - private void loop(Window window) - { - GLStamp stamp = GLStamper.INSTANCE.createStamp("MainStamp").start(); - stamps.enqueue(stamp); - gpu().start("Client").start("Update"); - window.update(); - for(long f = timer.getDelta();f >= ups.getTargetNS();f = timer.consumeDelta()) - { - ups.tick(); - owner.updateInternal(); - builder.setLength(0); - builder.append(owner.getMainWindowName()); - if(owner.showProfilingInfo) addDebugInfo(builder); - window.setTitle(builder.toString()); - } - gpu().next("Render"); - render(timer.getParticalTime()); - gpu().next("Trackers"); - boolean end = timer.update(); - stamp.stop(); - AllocationTracker.INSTANCE.update(); - GLUtils.onFrameEnded(); - gpu().next("Window").start("V-Sync"); - window.finishFrame(); - if(window.isCPULimited()) sync.sync(fps.getTargetTicks()); - gpu().next("Input"); - window.gatherInputs(); - gpu().stop().stop().stop().onFrameEnded(end); - while(!stamps.isEmpty() && stamps.first().isFinished()) - { - stamp = stamps.dequeue(); - gpuTime.addEntry(stamp.getResult()); - stamp.release(); - } - frame++; - } - - private void render(float particalTicks) - { - gpu().start("Prep"); - fps.tick(); - GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); - gpu().stop(); - owner.renderInternal(particalTicks); - } - - public void createTimeHacker() - { - Thread thread = new Thread(() -> { - while (true){ - try {Thread.sleep(2147483647L);} - catch (InterruptedException e){} - } - }, "Time Fixer Thread"); - thread.setDaemon(true); - thread.start(); - } - - protected void addDebugInfo(StringBuilder builder) - { - builder.append("("); - builder.append(fps.getTicks()).append(":").append(ups.getTicks()); - owner.addExtraTickRates(T -> builder.append(":").append(T)); - builder.append(",").append(getMemoryUsage()); - builder.append(",").append("CPU-A: "+FileUtils.convertBytes(AllocationTracker.INSTANCE.getCPUAllocatedBytes())); - builder.append(",").append("GPU-A: "+FileUtils.convertBytes(AllocationTracker.INSTANCE.getGPUAllocatedBytes())); - builder.append(",").append(TextUtil.convertTime(timer.getUsage(), "Client:", FORMATTER)); - builder.append(",").append(TextUtil.convertTime(gpuTime.getAverage(), "GPU:", FORMATTER)); - owner.addExtraTimers((N, T) -> builder.append(",").append(TextUtil.convertTime(T, N, FORMATTER))); - builder.append(")"); - } - - private String getMemoryUsage() - { - Runtime time = Runtime.getRuntime(); - long aviable = time.totalMemory(); - return "Memory:"+((aviable - time.freeMemory()) >> 20)+"MB/"+(aviable >> 20)+"MB"; - } -} +package speiger.src.coreengine.application; + +import java.text.DecimalFormat; + +import org.lwjgl.opengl.GL11; + +import speiger.src.collections.objects.queues.ObjectArrayFIFOQueue; +import speiger.src.collections.objects.queues.ObjectPriorityQueue; +import speiger.src.coreengine.rendering.input.window.Window; +import speiger.src.coreengine.rendering.utils.AllocationTracker; +import speiger.src.coreengine.rendering.utils.GLStamper; +import speiger.src.coreengine.rendering.utils.GLStamper.GLStamp; +import speiger.src.coreengine.rendering.utils.GLUtils; +import speiger.src.coreengine.utils.counters.averager.TimeAverager; +import speiger.src.coreengine.utils.counters.timers.FPSTimer; +import speiger.src.coreengine.utils.counters.timers.FrameSyncer; +import speiger.src.coreengine.utils.counters.timers.TimerTarget; +import speiger.src.coreengine.utils.helpers.FileUtils; +import speiger.src.coreengine.utils.helpers.TextUtil; +import speiger.src.coreengine.utils.io.GameLog; +import speiger.src.coreengine.utils.io.GameLog.LogLevel; +import speiger.src.coreengine.utils.profiler.IProfiler; + +public class ApplicationExecutor +{ + public static final DecimalFormat FORMATTER = new DecimalFormat("###"); + FPSTimer timer = new FPSTimer(); + TimerTarget fps = timer.getFPS(); + TimerTarget ups = timer.getUPS(); + FrameSyncer sync = new FrameSyncer(); + + TimeAverager gpuTime = new TimeAverager(); + ObjectPriorityQueue stamps = new ObjectArrayFIFOQueue<>(); + StringBuilder builder = new StringBuilder(); + + long frame = 0L; + + Application owner; + + public ApplicationExecutor(Application owner) + { + this.owner = owner; + owner.timer = timer; + } + + private IProfiler gpu() + { + return owner.gpuProfiler; + } + + public void start(Window window) + { + createTimeHacker(); + timer.init(); + try + { + while(window.shouldRun()) loop(window); + } + catch(Exception e) + { + GameLog.error("Client Has Crashed", e, LogLevel.ERROR); + } + } + + private void loop(Window window) + { + GLStamp stamp = GLStamper.INSTANCE.createStamp("MainStamp").start(); + stamps.enqueue(stamp); + gpu().start("Client").start("Update"); + window.update(); + for(long f = timer.getDelta();f >= ups.getTargetNS();f = timer.consumeDelta()) + { + ups.tick(); + owner.updateInternal(); + builder.setLength(0); + builder.append(owner.getMainWindowName()); + if(owner.showProfilingInfo) addDebugInfo(builder); + window.setTitle(builder.toString()); + } + gpu().next("Render"); + render(timer.getParticalTime()); + gpu().next("Trackers"); + boolean end = timer.update(); + stamp.stop(); + AllocationTracker.INSTANCE.update(); + GLUtils.onFrameEnded(); + gpu().next("Window").start("V-Sync"); + window.finishFrame(); + if(window.isCPULimited()) sync.sync(fps.getTargetTicks()); + gpu().next("Input"); + window.gatherInputs(); + gpu().stop().stop().stop().onFrameEnded(end); + while(!stamps.isEmpty() && stamps.first().isFinished()) + { + stamp = stamps.dequeue(); + gpuTime.addEntry(stamp.getResult()); + stamp.release(); + } + frame++; + } + + private void render(float particalTicks) + { + gpu().start("Prep"); + fps.tick(); + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); + gpu().stop(); + owner.renderInternal(particalTicks); + } + + public void createTimeHacker() + { + Thread thread = new Thread(() -> { + while (true){ + try {Thread.sleep(2147483647L);} + catch (InterruptedException e){} + } + }, "Time Fixer Thread"); + thread.setDaemon(true); + thread.start(); + } + + protected void addDebugInfo(StringBuilder builder) + { + builder.append("("); + builder.append(fps.getTicks()).append(":").append(ups.getTicks()); + owner.addExtraTickRates(T -> builder.append(":").append(T)); + builder.append(",").append(getMemoryUsage()); + builder.append(",").append("CPU-A: "+FileUtils.convertBytes(AllocationTracker.INSTANCE.getCPUAllocatedBytes())); + builder.append(",").append("GPU-A: "+FileUtils.convertBytes(AllocationTracker.INSTANCE.getGPUAllocatedBytes())); + builder.append(",").append(TextUtil.convertTime(timer.getUsage(), "Client:", FORMATTER)); + builder.append(",").append(TextUtil.convertTime(gpuTime.getAverage(), "GPU:", FORMATTER)); + owner.addExtraTimers((N, T) -> builder.append(",").append(TextUtil.convertTime(T, N, FORMATTER))); + builder.append(")"); + } + + private String getMemoryUsage() + { + Runtime time = Runtime.getRuntime(); + long aviable = time.totalMemory(); + return "Memory:"+((aviable - time.freeMemory()) >> 20)+"MB/"+(aviable >> 20)+"MB"; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/GuiComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/GuiComponent.java index d7e5751..9d91cb1 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/GuiComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/GuiComponent.java @@ -1,1145 +1,1164 @@ -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.Constrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.renderer.FontRenderer; -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; - Constrains 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 FontRenderer getFont() - { - return owner.getFont(); - } - - 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(); - onChanged(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 GuiComponent setMassChanging() - { - setFlag(FLAG_MASS_CHANGE); - return this; - } - - 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) - { - onChanged(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 final GuiComponent setScissorsTest(boolean value) - { - setFlag(FLAG_TEST_SCISSORS, value); - return this; - } - - public final GuiComponent setScale(float value) - { - if(getBox().getBaseScale() != value) - { - getBox().setScale(value); - onChanged(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)).limitHeight(false).align(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.set(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 center() - { - return getGui().centerComponent(this).cast(); - } - - 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 Constrains(xPos, yPos, width, height)); - } - - public T addChild(T comp, Constrains 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, Constrains 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).limitHeight(height != 0F).align(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 move(float x, float y) - { - if(x == 0F && y == 0F || constraints != null) return this; - box.move(x, y); - onChanged(false); - return this; - } - - public GuiComponent set(float x, float y) - { - if(box.getBaseX() == x && box.getBaseY() == y || constraints != null) return this; - box.setXY(x, y); - onChanged(false); - return this; - } - - public GuiComponent resize(float moveX, float moveY) - { - if(moveX == 0F && moveY == 0F || constraints != null) return this; - box.grow(moveX, moveY); - onChanged(true); - return this; - } - - public GuiComponent bounds(float width, float height) - { - if(box.getBaseWidth() == width && box.getBaseHeight() == height || constraints != null) return this; - box.setBounds(width, height); - onChanged(true); - return this; - } - - public final void onChanged(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.onChanged(repaint); - } - } - - protected void updateState() - { - - } - - protected void repaint() - { - - } - - public final void fixedUpdate() - { - if(fixedUpdateSelf()) fixedUpdateChildren(); - } - - public final void update(int mouseX, int mouseY, float particalTicks) - { - if(animation != null) animation.update(particalTicks); - if(updateSelf(mouseX, mouseY, particalTicks)) updateChildren(mouseX, mouseY, particalTicks); - } - - protected void preRender() - { - - } - - public final void render(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 - { - preRender(); - getRenderer().setVisibility(totalVisibility).setBrightness(brightness); - if(renderSelf(mouseX, mouseY, particalTicks)) renderChildren(mouseX, mouseY, particalTicks); - postRender(); - getRenderer().resetEffects(); - } - if(getGui() instanceof GuiScreenBase) - { - ((GuiScreenBase)getGui()).drawBox(this); - } - } - - protected void postRender() - { - - } - - 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.fixedUpdate(); - } - } - } - - public void updateChildren(int mouseX, int mouseY, float particalTicks) - { - for(GuiComponent entry : children) - { - if(entry.isVisible()) - { - entry.update(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.preRender(); - entry.render(mouseX, mouseY, particalTicks); - entry.postRender(); - 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; - } - } -} +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.Constrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.renderer.FontRenderer; +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 FLAG_RENDER_BOUNDS = 1024; + + 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; + Constrains 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 FontRenderer getFont() + { + return owner.getFont(); + } + + 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(); + onChanged(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 GuiComponent setMassChanging() + { + setFlag(FLAG_MASS_CHANGE); + return this; + } + + @SuppressWarnings("unchecked") + public final T setMassChanging(Class clz) + { + setMassChanging(); + 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) + { + onChanged(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 setRenderBounds() + { + setFlag(FLAG_RENDER_BOUNDS); + 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 final GuiComponent setScissorsTest(boolean value) + { + setFlag(FLAG_TEST_SCISSORS, value); + return this; + } + + public final GuiComponent setScale(float value) + { + if(getBox().getBaseScale() != value) + { + getBox().setScale(value); + onChanged(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; + } + + @SuppressWarnings("unchecked") + 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)).limitHeight(false).align(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.set(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 center() + { + return getGui().centerComponent(this).cast(); + } + + 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 Constrains(xPos, yPos, width, height)); + } + + public T addChild(T comp, Constrains 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.onClose(popupChildren::remove)); + getGui().addComponent(popup); + return popup; + } + + protected void addConstrains(GuiComponent comp, Constrains constrains) + { + comp.constraints = constrains; + if(constrains != null) + { + constrains.setOwner(comp, this); + constrains.onComponentChanged(); + } + } + + protected void updateConstrains(GuiComponent comp, Constrains constrains) + { + comp.constraints = constrains; + if(constrains != null) + { + constrains.setOwner(comp, comp.parent); + 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).limitHeight(height != 0F).align(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 onAction(Consumer listener) + { + return addListener(listener, GuiComponent.LISTENER_USER_ACTION); + } + + public final GuiComponent onAction(Runnable listener) + { + return addListener(listener, GuiComponent.LISTENER_USER_ACTION); + } + + public final GuiComponent onChange(Consumer listener) + { + return addListener(listener, GuiComponent.LISTENER_ON_CHANGE); + } + + public final GuiComponent onChange(Runnable listener) + { + return addListener(listener, GuiComponent.LISTENER_ON_CHANGE); + } + + public final GuiComponent onClose(Consumer listener) + { + return addListener(listener, GuiComponent.LISTENER_CLOSED); + } + + public final GuiComponent onClose(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 move(float x, float y) + { + if(x == 0F && y == 0F || constraints != null) return this; + box.move(x, y); + onChanged(false); + return this; + } + + public GuiComponent set(float x, float y) + { + if(box.getBaseX() == x && box.getBaseY() == y || constraints != null) return this; + box.setXY(x, y); + onChanged(false); + return this; + } + + public GuiComponent resize(float moveX, float moveY) + { + if(moveX == 0F && moveY == 0F || constraints != null) return this; + box.grow(moveX, moveY); + onChanged(true); + return this; + } + + public GuiComponent bounds(float width, float height) + { + if(box.getBaseWidth() == width && box.getBaseHeight() == height || constraints != null) return this; + box.setBounds(width, height); + onChanged(true); + return this; + } + + public final void onChanged(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.onChanged(repaint); + } + } + + protected void updateState() + { + + } + + protected void repaint() + { + + } + + public final void fixedUpdate() + { + if(fixedUpdateSelf()) fixedUpdateChildren(); + } + + public final void update(int mouseX, int mouseY, float particalTicks) + { + if(animation != null) animation.update(particalTicks); + if(updateSelf(mouseX, mouseY, particalTicks)) updateChildren(mouseX, mouseY, particalTicks); + } + + protected void preRender() + { + + } + + public final void render(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 + { + preRender(); + getRenderer().setVisibility(totalVisibility).setBrightness(brightness); + if(renderSelf(mouseX, mouseY, particalTicks)) renderChildren(mouseX, mouseY, particalTicks); + postRender(); + getRenderer().resetEffects(); + } + if(getGui() instanceof GuiScreenBase) + { + ((GuiScreenBase)getGui()).drawBox(this); + } + } + + protected void postRender() + { + + } + + 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.fixedUpdate(); + } + } + } + + public void updateChildren(int mouseX, int mouseY, float particalTicks) + { + for(GuiComponent entry : children) + { + if(entry.isVisible()) + { + entry.update(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.preRender(); + entry.render(mouseX, mouseY, particalTicks); + entry.postRender(); + getRenderer().translate(0F, 0F, -zOffset); + getRenderer().pop(); + } + } + } + + public Animator getAnimator() + { + if(animation == null) + { + animation = new Animator(this); + } + return animation; + } + + @SuppressWarnings("unchecked") + public T cast() + { + return (T)this; + } + + @SuppressWarnings("unchecked") + public T cast(Class clz) + { + return (T)this; + } + + @SuppressWarnings("unchecked") + 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; + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/GuiManager.java b/src/main/java/speiger/src/coreengine/rendering/gui/GuiManager.java index 1b262df..2d71301 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/GuiManager.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/GuiManager.java @@ -1,278 +1,278 @@ -package speiger.src.coreengine.rendering.gui; - -import org.lwjgl.opengl.GL11; - -import speiger.src.coreengine.assets.AssetLocation; -import speiger.src.coreengine.math.vector.ints.Vec2i; -import speiger.src.coreengine.rendering.gui.base.DebugOverlay; -import speiger.src.coreengine.rendering.gui.renderer.FontRenderer; -import speiger.src.coreengine.rendering.gui.renderer.GuiShader; -import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; -import speiger.src.coreengine.rendering.gui.renderer.provider.FontManager; -import speiger.src.coreengine.rendering.input.events.KeyEvent.CharTypeEvent; -import speiger.src.coreengine.rendering.input.events.KeyEvent.KeyPressEvent; -import speiger.src.coreengine.rendering.input.events.MouseEvent; -import speiger.src.coreengine.rendering.input.window.IWindowListener; -import speiger.src.coreengine.rendering.input.window.ScaledResolution; -import speiger.src.coreengine.rendering.input.window.Window; -import speiger.src.coreengine.rendering.models.UniformBuffer; -import speiger.src.coreengine.rendering.shader.ShaderTracker; -import speiger.src.coreengine.rendering.utils.Cursor; -import speiger.src.coreengine.rendering.utils.GLUtils; -import speiger.src.coreengine.utils.eventbus.EventBus; -import speiger.src.coreengine.utils.profiler.IProfiler; - -public abstract class GuiManager implements IWindowListener -{ - protected GuiBase[] activeGuis = new GuiBase[2]; - protected GuiBase gui; - protected DebugOverlay debug; - protected UIRenderer renderer = new UIRenderer(this); - protected Window window; - protected ScaledResolution res; - protected long globalClock = 0L; - protected boolean isReloading = false; - protected FontRenderer font; - protected GuiShader shader = ShaderTracker.INSTANCE.register(GuiShader::create, T -> shader = T); - - public GuiManager(Window window, EventBus bus, FontManager manager) - { - this.window = window; - font = manager.loadFont(AssetLocation.of("font/roboto.json"), 18.5F); - bus.register(MouseEvent.class, this::onMouseEvent); - bus.register(KeyPressEvent.class, (T) -> T.setCanceled(onKeyPressed(T.key))); - bus.register(CharTypeEvent.class, (T) -> T.setCanceled(onCharTyped(T.character, T.codePoint))); - window.addListener(this, false); - debug = createOverlay(); - activeGuis[1] = debug; - res = window.getUIFrame(); - debug.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); - debug.onInit(); - } - - public abstract IProfiler getGPUProfiler(); - public abstract IProfiler getCPUProfiler(); - public abstract IProfiler getServerProfiler(); - public abstract UniformBuffer getOrthoMatrixBuffer(); - public abstract DebugOverlay createOverlay(); - - public void showGui(GuiBase base, boolean allowBack) - { - if(allowBack) - { - base.setLastGui(gui); - } - closeGui(); - gui = base; - if(gui != null) - { - gui.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); - gui.onInit(); - if(activeGuis[0] != null) - { - activeGuis[1] = activeGuis[0]; - } - activeGuis[0] = base; - } - if(activeGuis[0] != null) - { - activeGuis[0].focus = true; - } - if(activeGuis[1] != null) - { - activeGuis[1].focus = false; - } - } - - public void closeGui() - { - if(gui != null) - { - if(gui == activeGuis[0]) - { - activeGuis[0] = null; - } - if(gui == activeGuis[1]) - { - activeGuis[1] = null; - } - gui.onClosed(); - gui = null; - } - } - - @Override - public void onWindowChanged(Window window) - { - if(gui != null) - { - gui.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); - gui.onScreenChanged(); - } - debug.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); - debug.onScreenChanged(); - } - - public void onFixedUpdate() - { - globalClock++; - for(int i = 0;i < 2;i++) - { - if(activeGuis[i] != null) - { - activeGuis[i].onFixedUpdate(); - } - } - } - - public void render(float particalTicks) - { - Vec2i offsetMouse = start(); - if(debug.isUpdating() || isReloading) - { - isReloading = false; - debug.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); - debug.onScreenChanged(); - if(gui != null) - { - gui.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); - gui.onScreenChanged(); - } - } - if(activeGuis[0] != null) - { - activeGuis[0].baseLayer = activeGuis[1] != null ? activeGuis[1].layers : 0; - } - for(int i = 1;i >= 0;i--) - { - if(activeGuis[i] != null && (activeGuis[i] instanceof DebugOverlay || debug.isRendering())) - { - activeGuis[i].draw(offsetMouse.getX(), offsetMouse.getY(), particalTicks); - } - } - stop(); - Cursor.INSTANCE.clearCursor(window); - } - - protected Vec2i start() - { - GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT); - GLUtils.DEBTH_TEST.push(false); - GLUtils.CULL_FACE.push(false); - GLUtils.BLEND.setFunction(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA).push(true); - renderer.beginFrame(); - return res.getScaledMouse(); - } - - protected void stop() - { - GLUtils.DEBTH_TEST.pop(); - GLUtils.DEBTH_TEST.push(true); - renderer.endFrame(); - GLUtils.BLEND.pop(); - GLUtils.CULL_FACE.pop(); - ShaderTracker.INSTANCE.stopShader(); - } - - public boolean onCharTyped(char character, int codePoint) - { - for(int i = 0;i < 2;i++) - { - if(activeGuis[i] != null && debug.shouldAcceptInputs(activeGuis[i]) && activeGuis[i].onKeyTyped(character, codePoint)) - { - return true; - } - } - return false; - } - - public boolean onKeyPressed(int key) - { - for(int i = 0;i < 2;i++) - { - if(activeGuis[i] != null && debug.shouldAcceptInputs(activeGuis[i]) && activeGuis[i].onKeyPressed(key)) - { - return true; - } - } - return false; - } - - public void onMouseEvent(MouseEvent event) - { - if(!onMouseEventInternal(event)) - { - return; - } - if(activeGuis[0] != null && !event.isCanceled() && debug.shouldAcceptInputs(activeGuis[0])) - { - activeGuis[0].onMouseEvent(event); - } - if(activeGuis[1] != null && !event.isCanceled() && debug.shouldAcceptInputs(activeGuis[1])) - { - activeGuis[1].onMouseEvent(event); - if(event.isCanceled()) - { - GuiBase base = activeGuis[0]; - activeGuis[0] = activeGuis[1]; - activeGuis[1] = base; - if(base != null) - { - base.onFocusLost(); - base.baseLayer = 0; - base.layers = 0; - } - if(activeGuis[0] != null) - { - activeGuis[0].focus = true; - } - if(activeGuis[1] != null) - { - activeGuis[1].focus = false; - } - } - } - event.convertToOrigin(); - } - - protected boolean onMouseEventInternal(MouseEvent event) - { - event.convertToScreenCoords(res); - return true; - } - - public boolean isAllowingMovement() - { - return gui == null || gui.isAllowingMovement(); - } - - public DebugOverlay getDebug() - { - return debug; - } - - public boolean isRenderUIBoxes() - { - return false; - } - - public GuiShader getShader() - { - return shader; - } - - public UIRenderer getRenderer() - { - return renderer; - } - - public FontRenderer getFont() - { - return font; - } - - public ScaledResolution getRes() - { - return res; - } -} +package speiger.src.coreengine.rendering.gui; + +import org.lwjgl.opengl.GL11; + +import speiger.src.coreengine.assets.AssetLocation; +import speiger.src.coreengine.math.vector.ints.Vec2i; +import speiger.src.coreengine.rendering.gui.base.DebugOverlay; +import speiger.src.coreengine.rendering.gui.renderer.FontRenderer; +import speiger.src.coreengine.rendering.gui.renderer.GuiShader; +import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; +import speiger.src.coreengine.rendering.gui.renderer.provider.FontManager; +import speiger.src.coreengine.rendering.input.events.KeyEvent.CharTypeEvent; +import speiger.src.coreengine.rendering.input.events.KeyEvent.KeyPressEvent; +import speiger.src.coreengine.rendering.input.events.MouseEvent; +import speiger.src.coreengine.rendering.input.window.IWindowListener; +import speiger.src.coreengine.rendering.input.window.ScaledResolution; +import speiger.src.coreengine.rendering.input.window.Window; +import speiger.src.coreengine.rendering.models.UniformBuffer; +import speiger.src.coreengine.rendering.shader.ShaderTracker; +import speiger.src.coreengine.rendering.utils.Cursor; +import speiger.src.coreengine.rendering.utils.GLUtils; +import speiger.src.coreengine.utils.eventbus.EventBus; +import speiger.src.coreengine.utils.profiler.IProfiler; + +public abstract class GuiManager implements IWindowListener +{ + protected GuiBase[] activeGuis = new GuiBase[2]; + protected GuiBase gui; + protected DebugOverlay debug; + protected UIRenderer renderer = new UIRenderer(this); + protected Window window; + protected ScaledResolution res; + protected long globalClock = 0L; + protected boolean isReloading = false; + protected FontRenderer font; + protected GuiShader shader = ShaderTracker.INSTANCE.register(GuiShader::create, T -> shader = T); + + public GuiManager(Window window, EventBus bus, FontManager manager) + { + this.window = window; + font = manager.loadFont(AssetLocation.of("font/roboto.json"), 18.5F); + bus.register(MouseEvent.class, this::onMouseEvent); + bus.register(KeyPressEvent.class, (T) -> T.setCanceled(onKeyPressed(T.key))); + bus.register(CharTypeEvent.class, (T) -> T.setCanceled(onCharTyped(T.character, T.codePoint))); + window.addListener(this, false); + debug = createOverlay(); + activeGuis[1] = debug; + res = window.getUIFrame(); + debug.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); + debug.onInit(); + } + + public abstract IProfiler getGPUProfiler(); + public abstract IProfiler getCPUProfiler(); + public abstract IProfiler getServerProfiler(); + public abstract UniformBuffer getOrthoMatrixBuffer(); + public abstract DebugOverlay createOverlay(); + + public void showGui(GuiBase base, boolean allowBack) + { + if(allowBack) + { + base.setLastGui(gui); + } + closeGui(); + gui = base; + if(gui != null) + { + gui.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); + gui.onInit(); + if(activeGuis[0] != null) + { + activeGuis[1] = activeGuis[0]; + } + activeGuis[0] = base; + } + if(activeGuis[0] != null) + { + activeGuis[0].focus = true; + } + if(activeGuis[1] != null) + { + activeGuis[1].focus = false; + } + } + + public void closeGui() + { + if(gui != null) + { + if(gui == activeGuis[0]) + { + activeGuis[0] = null; + } + if(gui == activeGuis[1]) + { + activeGuis[1] = null; + } + gui.onClosed(); + gui = null; + } + } + + @Override + public void onWindowChanged(Window window) + { + if(gui != null) + { + gui.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); + gui.onScreenChanged(); + } + debug.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); + debug.onScreenChanged(); + } + + public void onFixedUpdate() + { + globalClock++; + for(int i = 0;i < 2;i++) + { + if(activeGuis[i] != null) + { + activeGuis[i].onFixedUpdate(); + } + } + } + + public void render(float particalTicks) + { + Vec2i offsetMouse = start(); + if(debug.isUpdating() || isReloading) + { + isReloading = false; + debug.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); + debug.onScreenChanged(); + if(gui != null) + { + gui.setGuiBounds(this, res.getScaledWidth(), res.getScaledHeight()); + gui.onScreenChanged(); + } + } + if(activeGuis[0] != null) + { + activeGuis[0].baseLayer = activeGuis[1] != null ? activeGuis[1].layers : 0; + } + for(int i = 1;i >= 0;i--) + { + if(activeGuis[i] != null && (activeGuis[i] instanceof DebugOverlay || debug.isRendering())) + { + activeGuis[i].draw(offsetMouse.getX(), offsetMouse.getY(), particalTicks); + } + } + stop(); + Cursor.INSTANCE.clearCursor(window); + } + + protected Vec2i start() + { + GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT); + GLUtils.DEBTH_TEST.push(false); + GLUtils.CULL_FACE.push(false); + GLUtils.BLEND.setFunction(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA).push(true); + renderer.beginFrame(); + return res.getScaledMouse(); + } + + protected void stop() + { + GLUtils.DEBTH_TEST.pop(); + GLUtils.DEBTH_TEST.push(true); + renderer.endFrame(); + GLUtils.BLEND.pop(); + GLUtils.CULL_FACE.pop(); + ShaderTracker.INSTANCE.stopShader(); + } + + public boolean onCharTyped(char character, int codePoint) + { + for(int i = 0;i < 2;i++) + { + if(activeGuis[i] != null && debug.shouldAcceptInputs(activeGuis[i]) && activeGuis[i].onKeyTyped(character, codePoint)) + { + return true; + } + } + return false; + } + + public boolean onKeyPressed(int key) + { + for(int i = 0;i < 2;i++) + { + if(activeGuis[i] != null && debug.shouldAcceptInputs(activeGuis[i]) && activeGuis[i].onKeyPressed(key)) + { + return true; + } + } + return false; + } + + public void onMouseEvent(MouseEvent event) + { + if(!onMouseEventInternal(event)) + { + return; + } + if(activeGuis[0] != null && !event.isCanceled() && debug.shouldAcceptInputs(activeGuis[0])) + { + activeGuis[0].onMouseEvent(event); + } + if(activeGuis[1] != null && !event.isCanceled() && debug.shouldAcceptInputs(activeGuis[1])) + { + activeGuis[1].onMouseEvent(event); + if(event.isCanceled()) + { + GuiBase base = activeGuis[0]; + activeGuis[0] = activeGuis[1]; + activeGuis[1] = base; + if(base != null) + { + base.onFocusLost(); + base.baseLayer = 0; + base.layers = 0; + } + if(activeGuis[0] != null) + { + activeGuis[0].focus = true; + } + if(activeGuis[1] != null) + { + activeGuis[1].focus = false; + } + } + } + event.convertToOrigin(); + } + + protected boolean onMouseEventInternal(MouseEvent event) + { + event.convertToScreenCoords(res); + return true; + } + + public boolean isAllowingMovement() + { + return gui == null || gui.isAllowingMovement(); + } + + public DebugOverlay getDebug() + { + return debug; + } + + public boolean isRenderUIBoxes() + { + return false; + } + + public GuiShader getShader() + { + return shader; + } + + public UIRenderer getRenderer() + { + return renderer; + } + + public FontRenderer getFont() + { + return font; + } + + public ScaledResolution getRes() + { + return res; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/base/GuiScreenBase.java b/src/main/java/speiger/src/coreengine/rendering/gui/base/GuiScreenBase.java index f2462cd..f285e87 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/base/GuiScreenBase.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/base/GuiScreenBase.java @@ -1,511 +1,511 @@ -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 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, 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 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 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()); - } - - } -} +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 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, 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 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 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() && comp.isFlagNotSet(GuiComponent.FLAG_RENDER_BOUNDS)) 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()); + } + + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/ButtonComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/ButtonComponent.java index d5bf0df..4136d34 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/ButtonComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/ButtonComponent.java @@ -1,63 +1,73 @@ -package speiger.src.coreengine.rendering.gui.components; - -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IButtonComponent; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; - -public class ButtonComponent extends GuiComponent implements IButtonComponent -{ - TextComponent text = new TextComponent(); - int color; - - public ButtonComponent(String text, int color) - { - this(0F, 0F, 0F, 0F, text, color); - } - - public ButtonComponent(float x, float y, float width, float height, String text, int color) - { - super(x, y, width, height); - this.text.setText(text); - this.color = color; - setFlag(FLAG_SUPPORT_BINDING); - } - - @Override - public void init() - { - addChild(text, Constrains.parent()); - } - - public TextComponent getText() - { - return text; - } - - public ButtonComponent setColor(int color) - { - this.color = color; - return this; - } - - @Override - public boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float brigthness = getBrightness(mouseX, mouseY); - getRenderer().setBrightness(brigthness).drawQuad(getBox(), color); - text.setBrightness(brigthness); - return true; - } - - @Override - public void onRelease(int button, int mouseX, int mouseY) - { - notifyListeners(LISTENER_USER_ACTION); - } - - @Override - protected boolean onUserKey() - { - notifyListeners(LISTENER_USER_ACTION); - return true; - } -} +package speiger.src.coreengine.rendering.gui.components; + +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.base.IButtonComponent; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; + +public class ButtonComponent extends GuiComponent implements IButtonComponent +{ + TextComponent text = new TextComponent(); + int color; + + public ButtonComponent(String text, int color) + { + this(0F, 0F, 0F, 0F, text, color, 1F); + } + + public ButtonComponent(String text, int color, float textScale) + { + this(0F, 0F, 0F, 0F, text, color, textScale); + } + + public ButtonComponent(float x, float y, float width, float height, String text, int color) + { + this(x, y, width, height, text, color, 1F); + } + + public ButtonComponent(float x, float y, float width, float height, String text, int color, float textScale) + { + super(x, y, width, height); + this.text.setText(text).setTextScale(textScale); + this.color = color; + setFlag(FLAG_SUPPORT_BINDING); + } + + @Override + public void init() + { + addChild(text, Constrains.parent()); + } + + public TextComponent getText() + { + return text; + } + + public ButtonComponent setColor(int color) + { + this.color = color; + return this; + } + + @Override + public boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float brigthness = getBrightness(mouseX, mouseY); + getRenderer().setBrightness(brigthness).drawQuad(getBox(), color); + text.setBrightness(brigthness); + return true; + } + + @Override + public void onRelease(int button, int mouseX, int mouseY) + { + notifyListeners(LISTENER_USER_ACTION); + } + + @Override + protected boolean onUserKey() + { + notifyListeners(LISTENER_USER_ACTION); + return true; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/CheckBoxComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/CheckBoxComponent.java index dd2da28..d405fe5 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/CheckBoxComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/CheckBoxComponent.java @@ -1,122 +1,122 @@ -package speiger.src.coreengine.rendering.gui.components; - -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IButtonComponent; -import speiger.src.coreengine.rendering.gui.components.misc.ICheckBox; -import speiger.src.coreengine.rendering.gui.helper.UIShapes; -import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; - -public class CheckBoxComponent extends GuiComponent implements IButtonComponent, ICheckBox -{ - boolean isChecked = false; - int color; - RenderBuffer buffer; - - public CheckBoxComponent(int color) - { - super(0F, 0F, 0F, 0F); - setFlag(FLAG_SUPPORT_BINDING); - this.color = color; - } - - public CheckBoxComponent(int color, boolean checked) - { - super(0F, 0F, 0F, 0F); - setFlag(FLAG_SUPPORT_BINDING); - this.color = color; - } - - public CheckBoxComponent(float x, float y, float width, float height, int color) - { - super(x, y, width, height); - setFlag(FLAG_SUPPORT_BINDING); - this.color = color; - } - - public CheckBoxComponent(float x, float y, float width, float height, int color, boolean checked) - { - super(x, y, width, height); - setFlag(FLAG_SUPPORT_BINDING); - this.color = color; - isChecked = checked; - } - - @Override - public void init() - { - addCloseListener(buffer = getRenderer().createBuffer()); - } - - @Override - public final CheckBoxComponent setChecked(boolean isChecked) - { - this.isChecked = isChecked; - return this; - } - - public final CheckBoxComponent setColor(int color) - { - if(this.color != color) - { - this.color = color; - onChanged(true); - } - return this; - } - - @Override - public boolean isChecked() - { - return isChecked; - } - - @Override - protected void repaint() - { - float width = getBox().getWidth(); - float height = getBox().getHeight(); - buffer.clear(); - UIShapes.createCross(buffer, width, height, (width / 3.3F), (height / 5F), color); - UIShapes.createCross(buffer, width, height, (width / 5F), (height / 10F), color); - } - - @Override - public boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float brightness = getActiveBrightness(); - float centerX = getBox().getCenterX(); - float centerY = getBox().getCenterY(); - getRenderer().setBrightness(brightness).drawQuad(getBox(), color).setBrightness(brightness * 0.8F).drawFrame(getBox(), color).translate(centerX, centerY); - if(isChecked()) - { - getRenderer().setBrightness(brightness * 0.7F).translate(0, 0, 0.001F).drawBuffers(buffer.selectionIterator(1), getBox().getWidth(), getBox().getHeight()).translate(0, 0, -0.001F); - } - if(isTopHovered(mouseX, mouseY)) - { - getRenderer().setBrightness(brightness * 1.3F).translate(0, 0, 0.002F).drawBuffers(buffer.selectionIterator(0), getBox().getWidth(), getBox().getHeight()).translate(0, 0, -0.002F); - } - getRenderer().setBrightness(1F).translate(-centerX, -centerY); - return true; - } - - @Override - public boolean onClick(int button, int mouseX, int mouseY) - { - return true; - } - - @Override - public void onRelease(int button, int mouseX, int mouseY) - { - isChecked = !isChecked; - notifyListeners(LISTENER_USER_ACTION); - } - - @Override - protected boolean onUserKey() - { - isChecked = !isChecked; - notifyListeners(LISTENER_USER_ACTION); - return true; - } -} +package speiger.src.coreengine.rendering.gui.components; + +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.base.IButtonComponent; +import speiger.src.coreengine.rendering.gui.components.misc.ICheckBox; +import speiger.src.coreengine.rendering.gui.helper.UIShapes; +import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; + +public class CheckBoxComponent extends GuiComponent implements IButtonComponent, ICheckBox +{ + boolean isChecked = false; + int color; + RenderBuffer buffer; + + public CheckBoxComponent(int color) + { + super(0F, 0F, 0F, 0F); + setFlag(FLAG_SUPPORT_BINDING); + this.color = color; + } + + public CheckBoxComponent(int color, boolean checked) + { + super(0F, 0F, 0F, 0F); + setFlag(FLAG_SUPPORT_BINDING); + this.color = color; + } + + public CheckBoxComponent(float x, float y, float width, float height, int color) + { + super(x, y, width, height); + setFlag(FLAG_SUPPORT_BINDING); + this.color = color; + } + + public CheckBoxComponent(float x, float y, float width, float height, int color, boolean checked) + { + super(x, y, width, height); + setFlag(FLAG_SUPPORT_BINDING); + this.color = color; + isChecked = checked; + } + + @Override + public void init() + { + onClose(buffer = getRenderer().createBuffer()); + } + + @Override + public final CheckBoxComponent setChecked(boolean isChecked) + { + this.isChecked = isChecked; + return this; + } + + public final CheckBoxComponent setColor(int color) + { + if(this.color != color) + { + this.color = color; + onChanged(true); + } + return this; + } + + @Override + public boolean isChecked() + { + return isChecked; + } + + @Override + protected void repaint() + { + float width = getBox().getWidth(); + float height = getBox().getHeight(); + buffer.clear(); + UIShapes.createCross(buffer, width, height, (width / 3.3F), (height / 5F), color); + UIShapes.createCross(buffer, width, height, (width / 5F), (height / 10F), color); + } + + @Override + public boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float brightness = getActiveBrightness(); + float centerX = getBox().getCenterX(); + float centerY = getBox().getCenterY(); + getRenderer().setBrightness(brightness).drawQuad(getBox(), color).setBrightness(brightness * 0.8F).drawFrame(getBox(), color).translate(centerX, centerY); + if(isChecked()) + { + getRenderer().setBrightness(brightness * 0.7F).translate(0, 0, 0.001F).drawBuffers(buffer.selectionIterator(1), getBox().getWidth(), getBox().getHeight()).translate(0, 0, -0.001F); + } + if(isTopHovered(mouseX, mouseY)) + { + getRenderer().setBrightness(brightness * 1.3F).translate(0, 0, 0.002F).drawBuffers(buffer.selectionIterator(0), getBox().getWidth(), getBox().getHeight()).translate(0, 0, -0.002F); + } + getRenderer().setBrightness(1F).translate(-centerX, -centerY); + return true; + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + return true; + } + + @Override + public void onRelease(int button, int mouseX, int mouseY) + { + isChecked = !isChecked; + notifyListeners(LISTENER_USER_ACTION); + } + + @Override + protected boolean onUserKey() + { + isChecked = !isChecked; + notifyListeners(LISTENER_USER_ACTION); + return true; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/LabelComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/LabelComponent.java index 456d776..14dbca7 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/LabelComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/LabelComponent.java @@ -1,51 +1,61 @@ -package speiger.src.coreengine.rendering.gui.components; - -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; - -public class LabelComponent extends GuiComponent -{ - TextComponent text = new TextComponent(); - int color; - - public LabelComponent(String text, int color) - { - this(0F, 0F, 0F, 0F, text, color); - } - - public LabelComponent(float x, float y, float width, float height, String text, int color) - { - super(x, y, width, height); - this.text.setText(text); - this.color = color; - } - - public TextComponent getText() - { - return text; - } - - public LabelComponent setColor(int color) - { - this.color = color; - return this; - } - - public int getColor() - { - return color; - } - - @Override - public void init() - { - addChild(text, Constrains.parent()); - } - - @Override - public boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - getRenderer().drawQuad(getBox(), color); - return true; - } -} +package speiger.src.coreengine.rendering.gui.components; + +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; + +public class LabelComponent extends GuiComponent +{ + TextComponent text = new TextComponent(); + int color; + + public LabelComponent(String text, int color) + { + this(0F, 0F, 0F, 0F, text, color); + } + + public LabelComponent(String text, int color, float textScale) + { + this(0F, 0F, 0F, 0F, text, color, textScale); + } + + public LabelComponent(float x, float y, float width, float height, String text, int color) + { + this(x, y, width, height, text, color, 1F); + } + + public LabelComponent(float x, float y, float width, float height, String text, int color, float textScale) + { + super(x, y, width, height); + this.text.setText(text).setTextScale(textScale); + this.color = color; + } + + public TextComponent getText() + { + return text; + } + + public LabelComponent setColor(int color) + { + this.color = color; + return this; + } + + public int getColor() + { + return color; + } + + @Override + public void init() + { + addChild(text, Constrains.parent()); + } + + @Override + public boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + getRenderer().drawQuad(getBox(), color); + return true; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/ListComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/ListComponent.java index d5e9276..8f99914 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/ListComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/ListComponent.java @@ -1,686 +1,686 @@ -package speiger.src.coreengine.rendering.gui.components; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.function.Function; -import java.util.function.Predicate; - -import speiger.src.collections.ints.collections.IntCollection; -import speiger.src.collections.ints.lists.IntArrayList; -import speiger.src.collections.ints.lists.IntList; -import speiger.src.collections.ints.sets.IntLinkedOpenHashSet; -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.collections.objects.lists.ObjectList; -import speiger.src.collections.objects.utils.ObjectIterators; -import speiger.src.coreengine.math.MathUtils; -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.math.vector.ints.Vec2i; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IButtonComponent; -import speiger.src.coreengine.rendering.gui.components.list.IListEntry; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; -import speiger.src.coreengine.rendering.input.Keyboard; - -public class ListComponent extends GuiComponent - implements Iterable, IButtonComponent -{ - public static final int SELECTION_MODE_DISABLE = 0; - public static final int SELECTION_MODE_SINGLE = 1; - public static final int SELECTION_MODE_MULTI = 2; - public static final int SELECTION_MODE_INTERACT = 3; - - public static final int UPDATE_MODE_DISABLED = 0; - public static final int UPDATE_MODE_VISIBLE = 1; - public static final int UPDATE_MODE_ALL = 2; - - public static final int FLAG_DISABLE_BACKGROUND = 1024; - public static final int FLAG_START_AT_BOTTOM = 2048; - - protected int color; - protected int hoverColor = ColorUtils.LIGHT_GRAY; - protected int hoverIndex = -1; - protected int dragIndex = -1; - protected int movement = 0; - protected IButtonComponent customButton; - protected IntLinkedOpenHashSet selectedIndexes = new IntLinkedOpenHashSet(); - protected ObjectList entries = new ObjectArrayList(); - protected int selectionMode = 1; - protected int updateMode = 1; - protected float entryHeight; - protected float cachedWidth = 0F; - protected ScrollBarComponent verticalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY); - protected ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY).setHorizontal(true); - protected Vec2i lastMouse = Vec2i.mutable(); - - public ListComponent() - { - super(0F, 0F, 0F, 0F); - } - - public ListComponent(int color, float entryHeight) - { - super(0F, 0F, 0F, 0F); - this.color = color; - this.entryHeight = entryHeight; - } - - public ListComponent(float x, float y, float width, float height, int color, float entryHeight) - { - super(x, y, width, height); - this.color = color; - this.entryHeight = entryHeight; - } - - @Override - public void init() - { - addChild(horizontalBar, Constrains.scrollBar(verticalBar::isInUse, true, 5F)); - addChild(verticalBar, Constrains.scrollBar(horizontalBar::isInUse, false, 5F)); - for(int i = 0, m = entries.size();i < m;i++) - { - entries.get(i).init(this, getGui()); - } - updateScrollBar(); - } - - @Override - public void onClosed() - { - for(int i = 0,m=entries.size();i disableBackground() - { - setFlag(FLAG_DISABLE_BACKGROUND); - return this; - } - - public ListComponent setStartAtBottom(boolean value) - { - setFlag(FLAG_START_AT_BOTTOM, value); - return this; - } - - public boolean isStartAtBottom() - { - return isFlagSet(FLAG_START_AT_BOTTOM); - } - - public ListComponent setColor(int color) - { - this.color = color; - return this; - } - - public ListComponent setHoverColor(int color) - { - hoverColor = color; - return this; - } - - public ListComponent setEntryHeight(float entryHeight) - { - if(this.entryHeight != entryHeight) - { - this.entryHeight = entryHeight; - onChanged(true); - } - return this; - } - - public ListComponent setSelectionMode(int mode) - { - if(mode < 0 || mode > 3) - { - throw new IllegalStateException("Unknown Mode"); - } - this.selectionMode = mode; - selectedIndexes.clear(); - return this; - } - - public ListComponent setUpdateMode(int mode) - { - if(mode < 0 || mode > 2) - { - throw new IllegalStateException("Unknown Mode"); - } - updateMode = mode; - return this; - } - - public ListComponent setSelectedIndex(int index) - { - switch(selectionMode) - { - case 0: - throw new IllegalStateException("Selection is not allowed"); - case 1: - selectedIndexes.clear(); - case 2: - if(index >= 0 && index < entries.size()) - { - if(selectionMode == SELECTION_MODE_MULTI && Keyboard.isShiftDown()) - { - for(int i = selectedIndexes.lastInt();iindex;i--) - { - selectedIndexes.add(i); - } - } - selectedIndexes.add(index); - } - break; - } - return this; - } - - public boolean isSelected(int index) - { - return selectedIndexes.contains(index); - } - - public T removeSelectedIndex(int index) - { - return selectedIndexes.remove(index) ? entries.get(index) : null; - } - - public boolean hasSelected() - { - return !selectedIndexes.isEmpty(); - } - - public int getSelectedIndex() - { - return selectedIndexes.isEmpty() ? -1 : selectedIndexes.iterator().nextInt(); - } - - public T getSelectedValue() - { - return selectedIndexes.isEmpty() ? null : entries.get(selectedIndexes.iterator().nextInt()); - } - - public void clearSelection() - { - selectedIndexes.clear(); - } - - public IntList getSelection() - { - return new IntArrayList(selectedIndexes); - } - - public List getSelectedValues() - { - List entries = new ObjectArrayList(); - for(int index : selectedIndexes) - { - entries.add(this.entries.get(index)); - } - return entries; - } - - public ListComponent add(T entry) - { - entries.add(entry); - if(getGui() != null) - { - entry.init(this, getGui()); - updateScrollBar(); - } - return this; - } - - public ListComponent addAll(Collection entries) - { - this.entries.addAll(entries); - if(getGui() != null) - { - for(T entry : entries) - { - entry.init(this, getGui()); - } - updateScrollBar(); - } - return this; - } - - public int size() - { - return entries.size(); - } - - public T get(int index) - { - return entries.get(index); - } - - public boolean removeIf(Predicate filter) - { - if(entries.isEmpty()) return false; - selectedIndexes.clear(); - return entries.removeIf(K -> { - if(filter.test(K)) { - K.onClosed(); - return true; - } - return false; - }); - } - - public List map(Function mapper) - { - List list = new ObjectArrayList<>(entries.size()); - for(int i = 0,m=entries.size();i 0) - { - entries.add(index - 1, entries.remove(index)); - if(isSelected(index)) - { - removeSelectedIndex(index); - setSelectedIndex(index-1); - } - } - } - - public void moveDown(int index) - { - if(index + 1 < entries.size()) - { - entries.add(index + 1, entries.remove(index)); - if(isSelected(index)) - { - removeSelectedIndex(index); - setSelectedIndex(index+1); - } - } - } - - public void move(int fromIndex, int toIndex) - { - entries.add(toIndex, entries.remove(fromIndex)); - } - - public int indexOf(T value) - { - return entries.indexOf(value); - } - - public T remove(int index) - { - if(index < 0 || index >= entries.size()) - { - return null; - } - T value = entries.remove(index); - if(value != null) - { - value.onClosed(); - selectedIndexes.remove(index); - } - return value; - } - - public boolean removeAll(IntCollection values) - { - List result = new ObjectArrayList(); - for(int index : values) - { - if(index < 0 || index >= entries.size()) - { - continue; - } - selectedIndexes.remove(index); - T entry = entries.get(index); - entry.onClosed(); - result.add(entry); - } - if(result.size() > 0) - { - entries.removeAll(result); - return true; - } - return false; - } - - public boolean remove(T value) - { - return remove(indexOf(value)) != null; - } - - public void clear() - { - for(int i = 0,m=entries.size();i iterator() - { - return ObjectIterators.unmodifiable(entries.iterator()); - } - - protected Iterator rangeIterator(int start, int end) - { - return new Iterator() { - int index = start; - - @Override - public boolean hasNext() - { - return index < end && entries.size() > index; - } - - @Override - public T next() - { - return entries.get(index++); - } - }; - } - - public Iterator visibleIterator() - { - int start = getStartIndex(); - return rangeIterator(start, MathUtils.clamp(0, entries.size() - 1, start + getIndexWidth())); - } - - public float getCachedWidth() - { - return cachedWidth; - } - - @Override - protected void repaint() - { - float scale = getBox().getScale(); - for(int i = 0,m=entries.size();i= entries.size() ? -1 : index; - return true; - } - - @Override - public boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float brightness = getActiveBrightness(); - UIRenderer render = getRenderer(); - int start = getStartIndex(); - int end = MathUtils.clamp(0, entries.size(), start + getIndexWidth()); - IGuiBox box = getBox(); - float scale = box.getScale(); - float pixelSize = scale * entryHeight; - render.setBrightness(brightness); - if(isFlagNotSet(FLAG_DISABLE_BACKGROUND)) - { - render.drawQuad(box, color); - } - render.push(); - render.translate(box.getMinX(-horizontalBar.getScroll()), box.getMinY(-verticalBar.getScroll())); - float minX = horizontalBar.getScroll() * scale; - float maxX = box.getWidth() - verticalBar.getRequiredSpace() + (horizontalBar.getScroll() * scale); - enableScissorsBox(box.getMinX(), box.getMinY(), box.getMaxX()-verticalBar.getRequiredSpace(), box.getMaxY()-horizontalBar.getRequiredSpace()); - boolean bottom = !verticalBar.isInUse() && isStartAtBottom(); - if(hoverIndex != -1 && selectionMode != SELECTION_MODE_INTERACT && hoverIndex >= start && hoverIndex < end) - { - float offset = bottom ? box.getHeight()-(end-hoverIndex) * pixelSize : hoverIndex * pixelSize; - render.drawQuad(minX, offset, maxX, offset + pixelSize, 0.01F, hoverColor); - } - if(selectedIndexes.size() > 0) - { - render.setBrightness(0.75F * brightness); - for(int index : selectedIndexes) - { - if(index >= start && index < end) - { - float offset = bottom ? box.getHeight()-(end-index) * pixelSize : index * pixelSize; - render.drawQuad(minX, offset, maxX, offset + pixelSize, 0.011F, color); - } - } - } - mouseX -= box.getMinX(); - mouseY -= box.getMinY(); - for(int i = start;i collector) - { - super.collectTooltips(mouseX, mouseY, particalTicks, collector); - int start = getStartIndex(); - int end = MathUtils.clamp(0, entries.size(), start + getIndexWidth()); - IGuiBox box = getBox(); - float scale = box.getScale(); - float pixelSize = scale * entryHeight; - mouseX -= box.getMinX(); - mouseY -= box.getMinY(); - boolean bottom = !verticalBar.isInUse() && isStartAtBottom(); - for(int i = start;i extends GuiComponent + implements Iterable, IButtonComponent +{ + public static final int SELECTION_MODE_DISABLE = 0; + public static final int SELECTION_MODE_SINGLE = 1; + public static final int SELECTION_MODE_MULTI = 2; + public static final int SELECTION_MODE_INTERACT = 3; + + public static final int UPDATE_MODE_DISABLED = 0; + public static final int UPDATE_MODE_VISIBLE = 1; + public static final int UPDATE_MODE_ALL = 2; + + public static final int FLAG_DISABLE_BACKGROUND = 1 << 20; + public static final int FLAG_START_AT_BOTTOM = 1 << 21; + + protected int color; + protected int hoverColor = ColorUtils.LIGHT_GRAY; + protected int hoverIndex = -1; + protected int dragIndex = -1; + protected int movement = 0; + protected IButtonComponent customButton; + protected IntLinkedOpenHashSet selectedIndexes = new IntLinkedOpenHashSet(); + protected ObjectList entries = new ObjectArrayList(); + protected int selectionMode = 1; + protected int updateMode = 1; + protected float entryHeight; + protected float cachedWidth = 0F; + protected ScrollBarComponent verticalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY); + protected ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY).setHorizontal(true); + protected Vec2i lastMouse = Vec2i.mutable(); + + public ListComponent() + { + super(0F, 0F, 0F, 0F); + } + + public ListComponent(int color, float entryHeight) + { + super(0F, 0F, 0F, 0F); + this.color = color; + this.entryHeight = entryHeight; + } + + public ListComponent(float x, float y, float width, float height, int color, float entryHeight) + { + super(x, y, width, height); + this.color = color; + this.entryHeight = entryHeight; + } + + @Override + public void init() + { + addChild(horizontalBar, Constrains.scrollBar(verticalBar::isInUse, true, 5F)); + addChild(verticalBar, Constrains.scrollBar(horizontalBar::isInUse, false, 5F)); + for(int i = 0, m = entries.size();i < m;i++) + { + entries.get(i).init(this, getGui()); + } + updateScrollBar(); + } + + @Override + public void onClosed() + { + for(int i = 0,m=entries.size();i disableBackground() + { + setFlag(FLAG_DISABLE_BACKGROUND); + return this; + } + + public ListComponent setStartAtBottom(boolean value) + { + setFlag(FLAG_START_AT_BOTTOM, value); + return this; + } + + public boolean isStartAtBottom() + { + return isFlagSet(FLAG_START_AT_BOTTOM); + } + + public ListComponent setColor(int color) + { + this.color = color; + return this; + } + + public ListComponent setHoverColor(int color) + { + hoverColor = color; + return this; + } + + public ListComponent setEntryHeight(float entryHeight) + { + if(this.entryHeight != entryHeight) + { + this.entryHeight = entryHeight; + onChanged(true); + } + return this; + } + + public ListComponent setSelectionMode(int mode) + { + if(mode < 0 || mode > 3) + { + throw new IllegalStateException("Unknown Mode"); + } + this.selectionMode = mode; + selectedIndexes.clear(); + return this; + } + + public ListComponent setUpdateMode(int mode) + { + if(mode < 0 || mode > 2) + { + throw new IllegalStateException("Unknown Mode"); + } + updateMode = mode; + return this; + } + + public ListComponent setSelectedIndex(int index) + { + switch(selectionMode) + { + case 0: + throw new IllegalStateException("Selection is not allowed"); + case 1: + selectedIndexes.clear(); + case 2: + if(index >= 0 && index < entries.size()) + { + if(selectionMode == SELECTION_MODE_MULTI && Keyboard.isShiftDown()) + { + for(int i = selectedIndexes.lastInt();iindex;i--) + { + selectedIndexes.add(i); + } + } + selectedIndexes.add(index); + } + break; + } + return this; + } + + public boolean isSelected(int index) + { + return selectedIndexes.contains(index); + } + + public T removeSelectedIndex(int index) + { + return selectedIndexes.remove(index) ? entries.get(index) : null; + } + + public boolean hasSelected() + { + return !selectedIndexes.isEmpty(); + } + + public int getSelectedIndex() + { + return selectedIndexes.isEmpty() ? -1 : selectedIndexes.iterator().nextInt(); + } + + public T getSelectedValue() + { + return selectedIndexes.isEmpty() ? null : entries.get(selectedIndexes.iterator().nextInt()); + } + + public void clearSelection() + { + selectedIndexes.clear(); + } + + public IntList getSelection() + { + return new IntArrayList(selectedIndexes); + } + + public List getSelectedValues() + { + List entries = new ObjectArrayList(); + for(int index : selectedIndexes) + { + entries.add(this.entries.get(index)); + } + return entries; + } + + public ListComponent add(T entry) + { + entries.add(entry); + if(getGui() != null) + { + entry.init(this, getGui()); + updateScrollBar(); + } + return this; + } + + public ListComponent addAll(Collection entries) + { + this.entries.addAll(entries); + if(getGui() != null) + { + for(T entry : entries) + { + entry.init(this, getGui()); + } + updateScrollBar(); + } + return this; + } + + public int size() + { + return entries.size(); + } + + public T get(int index) + { + return entries.get(index); + } + + public boolean removeIf(Predicate filter) + { + if(entries.isEmpty()) return false; + selectedIndexes.clear(); + return entries.removeIf(K -> { + if(filter.test(K)) { + K.onClosed(); + return true; + } + return false; + }); + } + + public List map(Function mapper) + { + List list = new ObjectArrayList<>(entries.size()); + for(int i = 0,m=entries.size();i 0) + { + entries.add(index - 1, entries.remove(index)); + if(isSelected(index)) + { + removeSelectedIndex(index); + setSelectedIndex(index-1); + } + } + } + + public void moveDown(int index) + { + if(index + 1 < entries.size()) + { + entries.add(index + 1, entries.remove(index)); + if(isSelected(index)) + { + removeSelectedIndex(index); + setSelectedIndex(index+1); + } + } + } + + public void move(int fromIndex, int toIndex) + { + entries.add(toIndex, entries.remove(fromIndex)); + } + + public int indexOf(T value) + { + return entries.indexOf(value); + } + + public T remove(int index) + { + if(index < 0 || index >= entries.size()) + { + return null; + } + T value = entries.remove(index); + if(value != null) + { + value.onClosed(); + selectedIndexes.remove(index); + } + return value; + } + + public boolean removeAll(IntCollection values) + { + List result = new ObjectArrayList(); + for(int index : values) + { + if(index < 0 || index >= entries.size()) + { + continue; + } + selectedIndexes.remove(index); + T entry = entries.get(index); + entry.onClosed(); + result.add(entry); + } + if(result.size() > 0) + { + entries.removeAll(result); + return true; + } + return false; + } + + public boolean remove(T value) + { + return remove(indexOf(value)) != null; + } + + public void clear() + { + for(int i = 0,m=entries.size();i iterator() + { + return ObjectIterators.unmodifiable(entries.iterator()); + } + + protected Iterator rangeIterator(int start, int end) + { + return new Iterator() { + int index = start; + + @Override + public boolean hasNext() + { + return index < end && entries.size() > index; + } + + @Override + public T next() + { + return entries.get(index++); + } + }; + } + + public Iterator visibleIterator() + { + int start = getStartIndex(); + return rangeIterator(start, MathUtils.clamp(0, entries.size() - 1, start + getIndexWidth())); + } + + public float getCachedWidth() + { + return cachedWidth; + } + + @Override + protected void repaint() + { + float scale = getBox().getScale(); + for(int i = 0,m=entries.size();i= entries.size() ? -1 : index; + return true; + } + + @Override + public boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float brightness = getActiveBrightness(); + UIRenderer render = getRenderer(); + int start = getStartIndex(); + int end = MathUtils.clamp(0, entries.size(), start + getIndexWidth()); + IGuiBox box = getBox(); + float scale = box.getScale(); + float pixelSize = scale * entryHeight; + render.setBrightness(brightness); + if(isFlagNotSet(FLAG_DISABLE_BACKGROUND)) + { + render.drawQuad(box, color); + } + render.push(); + render.translate(box.getMinX(-horizontalBar.getScroll()), box.getMinY(-verticalBar.getScroll())); + float minX = horizontalBar.getScroll() * scale; + float maxX = box.getWidth() - verticalBar.getRequiredSpace() + (horizontalBar.getScroll() * scale); + enableScissorsBox(box.getMinX(), box.getMinY(), box.getMaxX()-verticalBar.getRequiredSpace(), box.getMaxY()-horizontalBar.getRequiredSpace()); + boolean bottom = !verticalBar.isInUse() && isStartAtBottom(); + if(hoverIndex != -1 && selectionMode != SELECTION_MODE_INTERACT && hoverIndex >= start && hoverIndex < end) + { + float offset = bottom ? box.getHeight()-(end-hoverIndex) * pixelSize : hoverIndex * pixelSize; + render.drawQuad(minX, offset, maxX, offset + pixelSize, 0.01F, hoverColor); + } + if(selectedIndexes.size() > 0) + { + render.setBrightness(0.75F * brightness); + for(int index : selectedIndexes) + { + if(index >= start && index < end) + { + float offset = bottom ? box.getHeight()-(end-index) * pixelSize : index * pixelSize; + render.drawQuad(minX, offset, maxX, offset + pixelSize, 0.011F, color); + } + } + } + mouseX -= box.getMinX(); + mouseY -= box.getMinY(); + for(int i = start;i collector) + { + super.collectTooltips(mouseX, mouseY, particalTicks, collector); + int start = getStartIndex(); + int end = MathUtils.clamp(0, entries.size(), start + getIndexWidth()); + IGuiBox box = getBox(); + float scale = box.getScale(); + float pixelSize = scale * entryHeight; + mouseX -= box.getMinX(); + mouseY -= box.getMinY(); + boolean bottom = !verticalBar.isInUse() && isStartAtBottom(); + for(int i = start;i> parts; - int maxSteps; - - public PieComponent(int maxSteps, Supplier> parts) - { - super(0F, 0F, 0F, 0F); - this.maxSteps = maxSteps; - this.parts = parts; - } - - public PieComponent(float x, float y, float width, float height, int maxSteps, Supplier> parts) - { - super(x, y, width, height); - this.maxSteps = maxSteps; - this.parts = parts; - } - - @Override - public void init() - { - addCloseListener(buffer = getRenderer().createBuffer()); - } - - public final PieComponent setAutoUpdate(boolean value) - { - setFlag(FLAG_AUTO_UPDATE, value); - return this; - } - - public final boolean isAutoUpdating() - { - return isFlagSet(FLAG_AUTO_UPDATE); - } - - public int getMaxSteps() - { - return maxSteps; - } - - @Override - protected boolean fixedUpdateSelf() - { - if(isAutoUpdating()) - { - createPie(); - } - return true; - } - - @Override - protected void repaint() - { - createPie(); - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float centerX = getBox().getCenterX(); - float centerY = getBox().getCenterY(); - getRenderer().setBrightness(getActiveBrightness()).translate(centerX, centerY).flush(); - GLUtils.DEBTH_TEST.push(true); - getRenderer().drawBuffers(buffer, 0F, 0F).flush(); - GLUtils.DEBTH_TEST.pop(); - getRenderer().translate(-centerX, -centerY).setBrightness(1F); - return true; - } - - protected void createPie() - { - buffer.clear(); - if(parts == null) - { - return; - } - float xSize = getBox().getWidth() / 2F; - float ySize = getBox().getHeight() / 2F; - float extra = getBox().getHeight() / 10F; - float value = -3.17F; - float spaceScale = 0.0495F * (127.0F / maxSteps); - List indexes = parts.get(); - int stepsDone = 0; - Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI); - for(int j = indexes.size()-1;j>=0;j--) - { - IPieIndex pieIndex = indexes.get(j); - int steps = j == 0 ? maxSteps - stepsDone : pieIndex.getSteps(); - int color = pieIndex.getColor(); - int darker = ColorUtils.darker(color); - tes.offset(0F, 0F, 0.01F); - for(int i = 0;i> parts; + int maxSteps; + + public PieComponent(int maxSteps, Supplier> parts) + { + super(0F, 0F, 0F, 0F); + this.maxSteps = maxSteps; + this.parts = parts; + } + + public PieComponent(float x, float y, float width, float height, int maxSteps, Supplier> parts) + { + super(x, y, width, height); + this.maxSteps = maxSteps; + this.parts = parts; + } + + @Override + public void init() + { + onClose(buffer = getRenderer().createBuffer()); + } + + public final PieComponent setAutoUpdate(boolean value) + { + setFlag(FLAG_AUTO_UPDATE, value); + return this; + } + + public final boolean isAutoUpdating() + { + return isFlagSet(FLAG_AUTO_UPDATE); + } + + public int getMaxSteps() + { + return maxSteps; + } + + @Override + protected boolean fixedUpdateSelf() + { + if(isAutoUpdating()) + { + createPie(); + } + return true; + } + + @Override + protected void repaint() + { + createPie(); + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float centerX = getBox().getCenterX(); + float centerY = getBox().getCenterY(); + getRenderer().setBrightness(getActiveBrightness()).translate(centerX, centerY).flush(); + GLUtils.DEBTH_TEST.push(true); + getRenderer().drawBuffers(buffer, 0F, 0F).flush(); + GLUtils.DEBTH_TEST.pop(); + getRenderer().translate(-centerX, -centerY).setBrightness(1F); + return true; + } + + protected void createPie() + { + buffer.clear(); + if(parts == null) + { + return; + } + float xSize = getBox().getWidth() / 2F; + float ySize = getBox().getHeight() / 2F; + float extra = getBox().getHeight() / 10F; + float value = -3.14F; + float spaceScale = 0.0495F * (127.0F / maxSteps); + List indexes = parts.get(); + int stepsDone = 0; + Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI); + for(int j = indexes.size()-1;j>=0;j--) + { + IPieIndex pieIndex = indexes.get(j); + int steps = j == 0 ? maxSteps - stepsDone : pieIndex.getSteps(); + int color = pieIndex.getColor(); + int darker = ColorUtils.darker(color); + tes.offset(0F, 0F, 0.01F); + for(int i = 0;i name; - IntSupplier valueGenerator; - - public ProgressBarComponent(int color, int value, int max) - { - this(color, value, max, null); - } - - public ProgressBarComponent(int color, int value, int max, IntFunction name) - { - this(0F, 0F, 0F, 0F, color, value, max, name); - } - - public ProgressBarComponent(float x, float y, float width, float height, int color, int value, int max) - { - this(x, y, width, height, color, value, max, null); - } - - public ProgressBarComponent(float x, float y, float width, float height, int color, int value, int max, IntFunction name) - { - super(x, y, width, height); - this.name = name; - setColor(color); - setMax(max); - setValue(value); - } - - @Override - public void init() - { - addBox(inner); - text.setZOffset(0.1F); - text.setText(stringify()); - addChild(text, Constrains.parent()); - } - - public TextComponent getText() - { - return text; - } - - public ProgressBarComponent setColor(int color) - { - this.color = color; - return this; - } - - public ProgressBarComponent setValueGenerator(IntSupplier valueGenerator) - { - this.valueGenerator = valueGenerator; - return this; - } - - public ProgressBarComponent setValue(int newValue) - { - if(value != newValue) - { - value = newValue; - text.setText(stringify()); - } - return this; - } - - public ProgressBarComponent setMax(int newMax) - { - if(max != newMax) - { - max = newMax; - if(value > max) setValue(max); - } - return this; - } - - protected String stringify() - { - if(name != null) return name.apply(value); - else if(max == 0) return "0%"; - return Integer.toString((int)(((float)value / (float)max) * 100F))+"%"; - } - - protected float getProgress() - { - return max == 0 ? 0F : (float)value / (float)max; - } - - @Override - protected boolean fixedUpdateSelf() - { - if(valueGenerator != null) setValue(valueGenerator.getAsInt()); - return true; - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float extra = (inner.getMaxX() - inner.getMinX()) * getProgress(); - UIRenderer render = getRenderer(); - render.setBrightness(getActiveBrightness() * 0.75F).drawQuad(getBox(), color); - render.setBrightness(getActiveBrightness()).drawQuad(inner, 0.01F, color); - render.setBrightness(getActiveBrightness() * 1.25F).drawQuad(inner.getMinX(), inner.getMinY(), inner.getMinX() + extra, inner.getMaxY(), 0.02F, color); - text.setBrightness(getActiveBrightness()); - return true; - } -} +package speiger.src.coreengine.rendering.gui.components; + +import java.util.function.IntFunction; +import java.util.function.IntSupplier; + +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; +import speiger.src.coreengine.rendering.gui.helper.box.ParentBox; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; + +public class ProgressBarComponent extends GuiComponent +{ + IGuiBox inner = new ParentBox(1F); + TextComponent text = new TextComponent(); + int color; + int value; + int max; + IntFunction name; + IntSupplier valueGenerator; + + public ProgressBarComponent(int color, int value, int max) + { + this(color, value, max, null); + } + + public ProgressBarComponent(int color, float textScale, int value, int max) + { + this(color, textScale, value, max, null); + } + + public ProgressBarComponent(int color, int value, int max, IntFunction name) + { + this(0F, 0F, 0F, 0F, color, value, max, name); + } + + public ProgressBarComponent(int color, float textScale, int value, int max, IntFunction name) + { + this(0F, 0F, 0F, 0F, color, textScale, value, max, name); + } + + public ProgressBarComponent(float x, float y, float width, float height, int color, int value, int max) + { + this(x, y, width, height, color, value, max, null); + } + + public ProgressBarComponent(float x, float y, float width, float height, int color, float textScale, int value, int max) + { + this(x, y, width, height, color, textScale, value, max, null); + } + + public ProgressBarComponent(float x, float y, float width, float height, int color, int value, int max, IntFunction name) + { + this(x, y, width, height, color, 1F, value, max, name); + } + + public ProgressBarComponent(float x, float y, float width, float height, int color, float textScale, int value, int max, IntFunction name) + { + super(x, y, width, height); + this.name = name; + text.setTextScale(textScale); + setColor(color); + setMax(max); + setValue(value); + } + + @Override + public void init() + { + addBox(inner); + text.setZOffset(0.1F); + text.setText(stringify()); + addChild(text, Constrains.parent()); + } + + public TextComponent getText() + { + return text; + } + + public ProgressBarComponent setColor(int color) + { + this.color = color; + return this; + } + + public ProgressBarComponent setValueGenerator(IntSupplier valueGenerator) + { + this.valueGenerator = valueGenerator; + return this; + } + + public ProgressBarComponent setTextGenerator(IntFunction name) + { + this.name = name; + return this; + } + + public ProgressBarComponent setValue(int newValue) + { + if(value != newValue) + { + value = newValue; + text.setText(stringify()); + } + return this; + } + + public ProgressBarComponent setMax(int newMax) + { + if(max != newMax) + { + max = newMax; + if(value > max) setValue(max); + } + return this; + } + + protected String stringify() + { + if(name != null) return name.apply(value); + else if(max == 0) return "0%"; + return Integer.toString((int)(((float)value / (float)max) * 100F))+"%"; + } + + protected float getProgress() + { + return max == 0 ? 0F : (float)value / (float)max; + } + + public int getValue() + { + return value; + } + + public int getMax() + { + return max; + } + + @Override + protected boolean fixedUpdateSelf() + { + if(valueGenerator != null) setValue(valueGenerator.getAsInt()); + return true; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float extra = (inner.getMaxX() - inner.getMinX()) * getProgress(); + UIRenderer render = getRenderer(); + render.setBrightness(getActiveBrightness() * 0.75F).drawQuad(getBox(), color); + render.setBrightness(getActiveBrightness()).drawQuad(inner, 0.01F, color); + render.setBrightness(getActiveBrightness() * 1.25F).drawQuad(inner.getMinX(), inner.getMinY(), inner.getMinX() + extra, inner.getMaxY(), 0.02F, color); + text.setBrightness(getActiveBrightness()); + return true; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollBarComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollBarComponent.java index 8f6706a..5f29fdb 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollBarComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollBarComponent.java @@ -1,243 +1,243 @@ -package speiger.src.coreengine.rendering.gui.components; - -import speiger.src.coreengine.math.MathUtils; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IButtonComponent; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; - -public class ScrollBarComponent extends GuiComponent implements IButtonComponent -{ - public static final int FLAG_HORIZONTAL = 1024; - public static final int FLAG_INVERTED = 2048; - int color; - float lastMouse = -1; - int current; - int max; - - public ScrollBarComponent(int color) - { - super(0F, 0F, 0F, 0F); - this.color = color; - } - - public ScrollBarComponent(int color, int max) - { - super(0F, 0F, 0F, 0F); - this.color = color; - this.max = max; - } - - public ScrollBarComponent(int color, int max, int current) - { - super(0F, 0F, 0F, 0F); - this.color = color; - this.max = max; - this.current = current; - } - - public ScrollBarComponent(float x, float y, float width, float height, int color) - { - super(x, y, width, height); - this.color = color; - } - - public ScrollBarComponent(float x, float y, float width, float height, int color, int max) - { - super(x, y, width, height); - this.color = color; - this.max = max; - } - - public ScrollBarComponent(float x, float y, float width, float height, int color, int max, int current) - { - super(x, y, width, height); - this.color = color; - this.max = max; - this.current = current; - } - - @Override - public void init() - { - - } - - public ScrollBarComponent setColor(int color) - { - this.color = color; - return this; - } - - public ScrollBarComponent setScrollMax(int max) - { - this.max = max; - return addScroll(0); - } - - public ScrollBarComponent addScroll(int add) - { - return setScrollCurrent(current + add); - } - - public ScrollBarComponent setScrollEnd() - { - return setScrollCurrent(max); - } - - public ScrollBarComponent setScrollStart() - { - return setScrollCurrent(0); - } - - public ScrollBarComponent setScrollCurrent(int current) - { - this.current = (int)MathUtils.clamp(0F, Math.max(0, max - getBaseRange()), current); - return this; - } - - protected int getCurrent() - { - return current; - } - - protected void setCurrent(int value) - { - current = value; - } - - public ScrollBarComponent setHorizontal(boolean value) - { - setFlag(FLAG_HORIZONTAL, value); - return this; - } - - public ScrollBarComponent setInverted(boolean value) - { - setFlag(FLAG_INVERTED, value); - return this; - } - - public boolean isHorizontal() - { - return isFlagSet(FLAG_HORIZONTAL); - } - - public int getScroll() - { - return current; - } - - public boolean isAtEnd() - { - return (max - getBaseRange()) <= current; - } - - public boolean isInUse() - { - return (max - getBaseRange()) > 0F; - } - - public float getRequiredSpace() - { - return (max - getBaseRange()) > 0F ? (isHorizontal() ? getBox().getHeight() : getBox().getWidth()) : 0F; - } - - @Override - public boolean isComponentColliding(int mouseX, int mouseY) - { - return isInUse() && isHovered(mouseX, mouseY); - } - - @Override - public boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float baseRange = getBaseRange(); - float extra = max - baseRange; - if(extra <= 0) - { - return true; - } - IGuiBox box = getBox(); - float range = getRange(); - float min = getCurrent() * (baseRange - range) / extra; - float brightness = getActiveBrightness(); - getRenderer().setBrightness(brightness * 0.5F).drawQuad(box, color); - if(isHorizontal()) getRenderer().setBrightness(brightness * 1F).drawQuad(box.getMinX(min), box.getMinY(), box.getMinX(min + range), box.getMaxY(), 0.01F, color); - else getRenderer().setBrightness(brightness * 1F).drawQuad(box.getMinX(), box.getMinY(min), box.getMaxX(), box.getMinY(min + range), 0.01F, color); - getRenderer().setBrightness(1F); - return true; - } - - @Override - public boolean onClick(int button, int mouseX, int mouseY) - { - float baseRange = getBaseRange(); - float extra = max - baseRange; - if(extra <= 0F) - { - return false; - } - float range = getRange(); - float pos = (baseRange - range) / extra; - float start = Math.max(0F, getCurrent() * pos); - IGuiBox box = getBox(); - float currentPos = (isHorizontal() ? box.getMinX(start) : box.getMinY(start)) + ((range * box.getScale()) / 2F); - float mouse = isHorizontal() ? mouseX : mouseY; - if(mouse < currentPos) - { - setCurrent((int)Math.max(0F, getCurrent() - (((currentPos - mouse) / pos) / box.getScale()))); - } - else if(mouse > currentPos) - { - setCurrent((int)Math.min(extra, getCurrent() + (((mouse - currentPos) / pos) / box.getScale()))); - } - lastMouse = mouse; - return true; - } - - @Override - public boolean onDrag(int mouseX, int mouseY) - { - if(lastMouse != -1F) - { - float range = getRange(); - IGuiBox box = getBox(); - float mouse = (isHorizontal() ? mouseX - box.getMinX() : mouseY - box.getMinY()) - ((range * box.getScale()) / 2F); - float baseRange = getBaseRange(); - float extra = max - baseRange; - setCurrent((int)MathUtils.clamp(0F, Math.max(0F, extra), (mouse / ((baseRange - range) / extra)) / box.getScale())); - return true; - } - return false; - } - - @Override - public void onRelease(int button, int mouseX, int mouseY) - { - lastMouse = -1F; - } - - @Override - public boolean onScroll(int scroll, int mouseX, int mouseY) - { - float extra = max - getBaseRange(); - if(extra > 0F) - { - setCurrent((int)MathUtils.clamp(0, extra, current - (scroll * (extra / 10F)))); - return true; - } - return false; - } - - protected float getBaseRange() - { - return isHorizontal() ? getBox().getBaseWidth() : getBox().getBaseHeight(); - } - - protected float getRange() - { - float value = getBaseRange(); - return MathUtils.clamp(10F, value, ((value * value) / max)); - } - -} +package speiger.src.coreengine.rendering.gui.components; + +import speiger.src.coreengine.math.MathUtils; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.base.IButtonComponent; +import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; + +public class ScrollBarComponent extends GuiComponent implements IButtonComponent +{ + public static final int FLAG_HORIZONTAL = 1 << 20; + public static final int FLAG_INVERTED = 1 << 21; + int color; + float lastMouse = -1; + int current; + int max; + + public ScrollBarComponent(int color) + { + super(0F, 0F, 0F, 0F); + this.color = color; + } + + public ScrollBarComponent(int color, int max) + { + super(0F, 0F, 0F, 0F); + this.color = color; + this.max = max; + } + + public ScrollBarComponent(int color, int max, int current) + { + super(0F, 0F, 0F, 0F); + this.color = color; + this.max = max; + this.current = current; + } + + public ScrollBarComponent(float x, float y, float width, float height, int color) + { + super(x, y, width, height); + this.color = color; + } + + public ScrollBarComponent(float x, float y, float width, float height, int color, int max) + { + super(x, y, width, height); + this.color = color; + this.max = max; + } + + public ScrollBarComponent(float x, float y, float width, float height, int color, int max, int current) + { + super(x, y, width, height); + this.color = color; + this.max = max; + this.current = current; + } + + @Override + public void init() + { + + } + + public ScrollBarComponent setColor(int color) + { + this.color = color; + return this; + } + + public ScrollBarComponent setScrollMax(int max) + { + this.max = max; + return addScroll(0); + } + + public ScrollBarComponent addScroll(int add) + { + return setScrollCurrent(current + add); + } + + public ScrollBarComponent setScrollEnd() + { + return setScrollCurrent(max); + } + + public ScrollBarComponent setScrollStart() + { + return setScrollCurrent(0); + } + + public ScrollBarComponent setScrollCurrent(int current) + { + this.current = (int)MathUtils.clamp(0F, Math.max(0, max - getBaseRange()), current); + return this; + } + + protected int getCurrent() + { + return current; + } + + protected void setCurrent(int value) + { + current = value; + } + + public ScrollBarComponent setHorizontal(boolean value) + { + setFlag(FLAG_HORIZONTAL, value); + return this; + } + + public ScrollBarComponent setInverted(boolean value) + { + setFlag(FLAG_INVERTED, value); + return this; + } + + public boolean isHorizontal() + { + return isFlagSet(FLAG_HORIZONTAL); + } + + public int getScroll() + { + return current; + } + + public boolean isAtEnd() + { + return (max - getBaseRange()) <= current; + } + + public boolean isInUse() + { + return (max - getBaseRange()) > 0F; + } + + public float getRequiredSpace() + { + return (max - getBaseRange()) > 0F ? (isHorizontal() ? getBox().getHeight() : getBox().getWidth()) : 0F; + } + + @Override + public boolean isComponentColliding(int mouseX, int mouseY) + { + return isInUse() && isHovered(mouseX, mouseY); + } + + @Override + public boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float baseRange = getBaseRange(); + float extra = max - baseRange; + if(extra <= 0) + { + return true; + } + IGuiBox box = getBox(); + float range = getRange(); + float min = getCurrent() * (baseRange - range) / extra; + float brightness = getActiveBrightness(); + getRenderer().setBrightness(brightness * 0.5F).drawQuad(box, color); + if(isHorizontal()) getRenderer().setBrightness(brightness * 1F).drawQuad(box.getMinX(min), box.getMinY(), box.getMinX(min + range), box.getMaxY(), 0.01F, color); + else getRenderer().setBrightness(brightness * 1F).drawQuad(box.getMinX(), box.getMinY(min), box.getMaxX(), box.getMinY(min + range), 0.01F, color); + getRenderer().setBrightness(1F); + return true; + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + float baseRange = getBaseRange(); + float extra = max - baseRange; + if(extra <= 0F) + { + return false; + } + float range = getRange(); + float pos = (baseRange - range) / extra; + float start = Math.max(0F, getCurrent() * pos); + IGuiBox box = getBox(); + float currentPos = (isHorizontal() ? box.getMinX(start) : box.getMinY(start)) + ((range * box.getScale()) / 2F); + float mouse = isHorizontal() ? mouseX : mouseY; + if(mouse < currentPos) + { + setCurrent((int)Math.max(0F, getCurrent() - (((currentPos - mouse) / pos) / box.getScale()))); + } + else if(mouse > currentPos) + { + setCurrent((int)Math.min(extra, getCurrent() + (((mouse - currentPos) / pos) / box.getScale()))); + } + lastMouse = mouse; + return true; + } + + @Override + public boolean onDrag(int mouseX, int mouseY) + { + if(lastMouse != -1F) + { + float range = getRange(); + IGuiBox box = getBox(); + float mouse = (isHorizontal() ? mouseX - box.getMinX() : mouseY - box.getMinY()) - ((range * box.getScale()) / 2F); + float baseRange = getBaseRange(); + float extra = max - baseRange; + setCurrent((int)MathUtils.clamp(0F, Math.max(0F, extra), (mouse / ((baseRange - range) / extra)) / box.getScale())); + return true; + } + return false; + } + + @Override + public void onRelease(int button, int mouseX, int mouseY) + { + lastMouse = -1F; + } + + @Override + public boolean onScroll(int scroll, int mouseX, int mouseY) + { + float extra = max - getBaseRange(); + if(extra > 0F) + { + setCurrent((int)MathUtils.clamp(0, extra, current - (scroll * (extra / 10F)))); + return true; + } + return false; + } + + protected float getBaseRange() + { + return isHorizontal() ? getBox().getBaseWidth() : getBox().getBaseHeight(); + } + + protected float getRange() + { + float value = getBaseRange(); + return MathUtils.clamp(10F, value, ((value * value) / max)); + } + +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollPanelComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollPanelComponent.java index fdfcd37..31bbd50 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollPanelComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollPanelComponent.java @@ -1,96 +1,96 @@ -package speiger.src.coreengine.rendering.gui.components; - -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; -import speiger.src.coreengine.rendering.gui.helper.constrains.ConditionalConstraint; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; - -public class ScrollPanelComponent extends GuiComponent -{ - public static final int FLAG_CORNER = 1 << 20; - - ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY).setHorizontal(true); - ScrollBarComponent verticalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY); - protected PanelComponent container = new PanelComponent().setManualRenderer(true).setScissorsTest(true).cast(); - PanelComponent viewPort = new PanelComponent().setManualRenderer(true).cast(); - - public ScrollPanelComponent() - { - super(0F, 0F, 0F, 0F); - } - - public ScrollPanelComponent(float x, float y, float width, float height) - { - super(x, y, width, height); - } - - @Override - public void init() - { - addChild(horizontalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : verticalBar::isInUse, true, 5F)); - addChild(verticalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : horizontalBar::isInUse, false, 5F)); - viewPort.addChild(container); - container.addChangeListener(this::recalculateSize); - addChild(viewPort, Constrains.width(ConditionalConstraint.parent(verticalBar::isInUse, 0F, 5F)).height(ConditionalConstraint.parent(horizontalBar::isInUse, 0F, 5F)).build()); - } - - public ScrollPanelComponent setForcedCorner(boolean value) - { - if(setFlag(FLAG_CORNER, value) && getGui() != null) - { - addConstrains(horizontalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : verticalBar::isInUse, true, 5F)); - addConstrains(verticalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : horizontalBar::isInUse, false, 5F)); - onChanged(false); - } - return this; - } - - public PanelComponent getContainer() - { - return container; - } - - public PanelComponent getViewPort() - { - return viewPort; - } - - protected void recalculateSize(GuiComponent owner) - { - float maxX = 0F; - float maxY = 0F; - for(GuiComponent component : container.getChildren()) - { - IGuiBox box = component.getBox(); - maxX = Math.max(maxX, box.getBaseX() + box.getBaseWidth()); - maxY = Math.max(maxY, box.getBaseY() + box.getBaseHeight()); - } - horizontalBar.setScrollMax((int)maxX); - verticalBar.setScrollMax((int)maxY); - owner.bounds(maxX, maxY).set(-horizontalBar.getScroll(), -verticalBar.getScroll()); - } - - @Override - protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) - { - super.updateSelf(mouseX, mouseY, particalTicks); - container.set(-horizontalBar.getScroll(), -verticalBar.getScroll()); - return true; - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - renderChildren(mouseX, mouseY, particalTicks); - if(container.isVisible()) - { - enableScissors(viewPort.getBox()); - getRenderer().translate(0F, 0F, 0.1F); - container.render(mouseX, mouseY, particalTicks); - getRenderer().translate(0F, 0F, -0.1F); - disableScissors(); - } - return false; - } -} +package speiger.src.coreengine.rendering.gui.components; + +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; +import speiger.src.coreengine.rendering.gui.helper.constrains.ConditionalConstraint; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; + +public class ScrollPanelComponent extends GuiComponent +{ + public static final int FLAG_CORNER = 1 << 20; + + ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY).setHorizontal(true); + ScrollBarComponent verticalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY); + protected PanelComponent container = new PanelComponent().setManualRenderer(true).setScissorsTest(true).cast(); + PanelComponent viewPort = new PanelComponent().setManualRenderer(true).cast(); + + public ScrollPanelComponent() + { + super(0F, 0F, 0F, 0F); + } + + public ScrollPanelComponent(float x, float y, float width, float height) + { + super(x, y, width, height); + } + + @Override + public void init() + { + addChild(horizontalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : verticalBar::isInUse, true, 5F)); + addChild(verticalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : horizontalBar::isInUse, false, 5F)); + viewPort.addChild(container); + container.onChange(this::recalculateSize); + addChild(viewPort, Constrains.width(ConditionalConstraint.parent(verticalBar::isInUse, 0F, 5F)).height(ConditionalConstraint.parent(horizontalBar::isInUse, 0F, 5F)).build()); + } + + public ScrollPanelComponent setForcedCorner(boolean value) + { + if(setFlag(FLAG_CORNER, value) && getGui() != null) + { + addConstrains(horizontalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : verticalBar::isInUse, true, 5F)); + addConstrains(verticalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : horizontalBar::isInUse, false, 5F)); + onChanged(false); + } + return this; + } + + public PanelComponent getContainer() + { + return container; + } + + public PanelComponent getViewPort() + { + return viewPort; + } + + protected void recalculateSize(GuiComponent owner) + { + float maxX = 0F; + float maxY = 0F; + for(GuiComponent component : container.getChildren()) + { + IGuiBox box = component.getBox(); + maxX = Math.max(maxX, box.getBaseX() + box.getBaseWidth()); + maxY = Math.max(maxY, box.getBaseY() + box.getBaseHeight()); + } + horizontalBar.setScrollMax((int)maxX); + verticalBar.setScrollMax((int)maxY); + owner.bounds(maxX, maxY).set(-horizontalBar.getScroll(), -verticalBar.getScroll()); + } + + @Override + protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) + { + super.updateSelf(mouseX, mouseY, particalTicks); + container.set(-horizontalBar.getScroll(), -verticalBar.getScroll()); + return true; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + renderChildren(mouseX, mouseY, particalTicks); + if(container.isVisible()) + { + enableScissors(viewPort.getBox()); + getRenderer().translate(0F, 0F, 0.1F); + container.render(mouseX, mouseY, particalTicks); + getRenderer().translate(0F, 0F, -0.1F); + disableScissors(); + } + return false; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollWindowComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollWindowComponent.java index 5c68dd3..3903495 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollWindowComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/ScrollWindowComponent.java @@ -1,109 +1,109 @@ -package speiger.src.coreengine.rendering.gui.components; - -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; -import speiger.src.coreengine.rendering.gui.helper.constrains.ConditionalConstraint; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; - -public class ScrollWindowComponent extends WindowComponent -{ - public static final int FLAG_CORNER = 1 << 26; - ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY).setHorizontal(true); - ScrollBarComponent verticalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY); - protected PanelComponent container = new PanelComponent().setManualRenderer(true).cast(); - PanelComponent viewPort = new PanelComponent().setManualRenderer(true).cast(); - - public ScrollWindowComponent(int flags, String name) - { - super(0F, 0F, 0F, 0F, flags, name); - } - - public ScrollWindowComponent(float x, float y, float width, float height, int flags, String name) - { - super(x, y, width, height, flags, name); - } - - @Override - public void init() - { - super.init(); - addChild(horizontalBar.addChangeListener(minimizedListener), Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : verticalBar::isInUse, true, 5F)); - addChild(verticalBar.addChangeListener(minimizedListener), Constrains.verticalScrollBar(isFlagSet(FLAG_CORNER) ? () -> true : horizontalBar::isInUse, 7.5F, 5F)); - viewPort.addChild(container); - container.addChangeListener(this::recalculateSize).addChangeListener(minimizedListener); - addChild(viewPort.set(0F, 7.5F), Constrains.width(ConditionalConstraint.parent(verticalBar::isInUse, 0F, 5F)).height(ConditionalConstraint.parent(horizontalBar::isInUse, 0F, 5F)).build()); - } - - public T addComponent(T comp) - { - return container.addChild(comp); - } - - public T addComponent(T comp, Constrains constraints) - { - return container.addChild(comp, constraints); - } - - public PanelComponent getContainer() - { - return container; - } - - public PanelComponent getViewPort() - { - return viewPort; - } - - public ScrollWindowComponent setForcedCorner(boolean value) - { - if(setFlag(FLAG_CORNER, value) && getGui() != null) - { - addConstrains(horizontalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : verticalBar::isInUse, true, 5F)); - addConstrains(verticalBar, Constrains.verticalScrollBar(isFlagSet(FLAG_CORNER) ? () -> true : horizontalBar::isInUse, 7.5F, 5F)); - onChanged(false); - } - return this; - } - - protected void recalculateSize(GuiComponent owner) - { - float maxX = 0F; - float maxY = 0F; - for(GuiComponent component : container.getChildren()) - { - IGuiBox box = component.getBox(); - maxX = Math.max(maxX, box.getBaseX() + box.getBaseWidth()); - maxY = Math.max(maxY, box.getBaseY() + box.getBaseHeight()); - } - horizontalBar.setScrollMax((int)maxX); - verticalBar.setScrollMax((int)maxY); - horizontalBar.onChanged(true); - verticalBar.onChanged(true); - owner.bounds(maxX, maxY).set(-horizontalBar.getScroll(), -verticalBar.getScroll()); - } - - @Override - protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) - { - super.updateSelf(mouseX, mouseY, particalTicks); - container.set(-horizontalBar.getScroll(), -verticalBar.getScroll()); - return true; - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - super.renderSelf(mouseX, mouseY, particalTicks); - renderChildren(mouseX, mouseY, particalTicks); - if(container.isVisible()) - { - enableScissors(viewPort.getBox()); - getRenderer().translate(0F, 0F, 0.1F); - container.render(mouseX, mouseY, particalTicks); - getRenderer().translate(0F, 0F, -0.1F); - disableScissors(); - } - return false; - } -} +package speiger.src.coreengine.rendering.gui.components; + +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; +import speiger.src.coreengine.rendering.gui.helper.constrains.ConditionalConstraint; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; + +public class ScrollWindowComponent extends WindowComponent +{ + public static final int FLAG_CORNER = 1 << 26; + ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY).setHorizontal(true); + ScrollBarComponent verticalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY); + protected PanelComponent container = new PanelComponent().setManualRenderer(true).cast(); + PanelComponent viewPort = new PanelComponent().setManualRenderer(true).cast(); + + public ScrollWindowComponent(int flags, String name) + { + super(0F, 0F, 0F, 0F, flags, name); + } + + public ScrollWindowComponent(float x, float y, float width, float height, int flags, String name) + { + super(x, y, width, height, flags, name); + } + + @Override + public void init() + { + super.init(); + addChild(horizontalBar.onChange(minimizedListener), Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : verticalBar::isInUse, true, 5F)); + addChild(verticalBar.onChange(minimizedListener), Constrains.verticalScrollBar(isFlagSet(FLAG_CORNER) ? () -> true : horizontalBar::isInUse, 7.5F, 5F)); + viewPort.addChild(container); + container.onChange(this::recalculateSize).onChange(minimizedListener); + addChild(viewPort.set(0F, 7.5F), Constrains.width(ConditionalConstraint.parent(verticalBar::isInUse, 0F, 5F)).height(ConditionalConstraint.parent(horizontalBar::isInUse, 0F, 5F)).build()); + } + + public T addComponent(T comp) + { + return container.addChild(comp); + } + + public T addComponent(T comp, Constrains constraints) + { + return container.addChild(comp, constraints); + } + + public PanelComponent getContainer() + { + return container; + } + + public PanelComponent getViewPort() + { + return viewPort; + } + + public ScrollWindowComponent setForcedCorner(boolean value) + { + if(setFlag(FLAG_CORNER, value) && getGui() != null) + { + addConstrains(horizontalBar, Constrains.scrollBar(isFlagSet(FLAG_CORNER) ? () -> true : verticalBar::isInUse, true, 5F)); + addConstrains(verticalBar, Constrains.verticalScrollBar(isFlagSet(FLAG_CORNER) ? () -> true : horizontalBar::isInUse, 7.5F, 5F)); + onChanged(false); + } + return this; + } + + protected void recalculateSize(GuiComponent owner) + { + float maxX = 0F; + float maxY = 0F; + for(GuiComponent component : container.getChildren()) + { + IGuiBox box = component.getBox(); + maxX = Math.max(maxX, box.getBaseX() + box.getBaseWidth()); + maxY = Math.max(maxY, box.getBaseY() + box.getBaseHeight()); + } + horizontalBar.setScrollMax((int)maxX); + verticalBar.setScrollMax((int)maxY); + horizontalBar.onChanged(true); + verticalBar.onChanged(true); + owner.bounds(maxX, maxY).set(-horizontalBar.getScroll(), -verticalBar.getScroll()); + } + + @Override + protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) + { + super.updateSelf(mouseX, mouseY, particalTicks); + container.set(-horizontalBar.getScroll(), -verticalBar.getScroll()); + return true; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + super.renderSelf(mouseX, mouseY, particalTicks); + renderChildren(mouseX, mouseY, particalTicks); + if(container.isVisible()) + { + enableScissors(viewPort.getBox()); + getRenderer().translate(0F, 0F, 0.1F); + container.render(mouseX, mouseY, particalTicks); + getRenderer().translate(0F, 0F, -0.1F); + disableScissors(); + } + return false; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/SelectionComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/SelectionComponent.java index dbe0ee7..795dff6 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/SelectionComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/SelectionComponent.java @@ -1,363 +1,363 @@ -package speiger.src.coreengine.rendering.gui.components; - -import java.util.Collection; -import java.util.function.Consumer; - -import org.lwjgl.opengl.GL11; - -import speiger.src.collections.ints.collections.IntCollection; -import speiger.src.coreengine.math.value.IValue; -import speiger.src.coreengine.math.value.LiniarValue; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IButtonComponent; -import speiger.src.coreengine.rendering.gui.components.list.SelectionEntry; -import speiger.src.coreengine.rendering.gui.helper.Align; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain.Target; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; -import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; -import speiger.src.coreengine.rendering.tesselation.Tesselator; -import speiger.src.coreengine.rendering.tesselation.VertexType; - -public class SelectionComponent extends GuiComponent implements IButtonComponent, Consumer -{ - public static final int FLAG_ANIMATE = 1 << 20; - ListComponent list = new ListComponent().bounds(0F, 120F).setManualRenderer(true).setIgnoreBounds(true).cast(); - TextComponent text = new TextComponent().align(Align.LEFT_TOP, Align.CENTER).setTextScale(0.85F).setManualRenderer(true).cast(); - RenderBuffer buffer; - int color; - boolean isOpen = false; - int selectedIndex = -1; - int defaultIndex = -1; - IValue animation = null; - - public SelectionComponent(int color) - { - super(0F, 0F, 0F, 0F); - this.color = color; - text.setText("Select Index"); - list.setColor(color); - } - - public SelectionComponent(int color, Collection collection) - { - super(0F, 0F, 0F, 0F); - this.color = color; - text.setText("Select Index"); - list.setColor(color); - addEntries(collection); - } - - public SelectionComponent(float x, float y, float width, float height, int color) - { - super(x, y, width, height); - this.color = color; - text.setText("Select Index"); - list.setColor(color); - } - - public SelectionComponent(float x, float y, float width, float height, int color, Collection collection) - { - super(x, y, width, height); - this.color = color; - text.setText("Select Index"); - list.setColor(color); - addEntries(collection); - } - - @Override - public void init() - { - list.setEntryHeight(getGui().getFont().height()).addUserActionListener(this); - addChild(text, Constrains.parent(21F, 0F, 10.5F, 0F)); - addChild(list, Constrains.parent(Target.X).invParent(Target.Y).parent(Target.WIDTH).build()); - addCloseListener(buffer = getRenderer().createBuffer()); - createArrow(); - } - - public final SelectionComponent setAnimating(boolean value) - { - setFlag(FLAG_ANIMATE, value); - return this; - } - - public final boolean isAnimating() - { - return isFlagSet(FLAG_ANIMATE); - } - - @Override - protected void updateState() - { - list.setVisible(isOpen); - } - - public TextComponent getText() - { - return text; - } - - public ListComponent getList() - { - return list; - } - - public SelectionComponent addEntry(String s) - { - list.add(new SelectionEntry(s)); - return this; - } - - public SelectionComponent addEntries(Collection collection) - { - for(String s : collection) - { - list.add(new SelectionEntry(s)); - } - return this; - } - - public SelectionComponent updateEntry(int index, String newName) - { - list.get(index).setText(newName); - if(index == selectedIndex) - { - updateSelection(); - } - return this; - } - - public SelectionComponent removeEntry(String s) - { - for(int i = 0,m=list.size();i +{ + public static final int FLAG_ANIMATE = 1 << 20; + ListComponent list = new ListComponent().bounds(0F, 120F).setManualRenderer(true).setIgnoreBounds(true).cast(); + TextComponent text = new TextComponent().align(Align.LEFT_TOP, Align.CENTER).setTextScale(0.85F).setManualRenderer(true).cast(); + RenderBuffer buffer; + int color; + boolean isOpen = false; + int selectedIndex = -1; + int defaultIndex = -1; + IValue animation = null; + + public SelectionComponent(int color) + { + super(0F, 0F, 0F, 0F); + this.color = color; + text.setText("Select Index"); + list.setColor(color); + } + + public SelectionComponent(int color, Collection collection) + { + super(0F, 0F, 0F, 0F); + this.color = color; + text.setText("Select Index"); + list.setColor(color); + addEntries(collection); + } + + public SelectionComponent(float x, float y, float width, float height, int color) + { + super(x, y, width, height); + this.color = color; + text.setText("Select Index"); + list.setColor(color); + } + + public SelectionComponent(float x, float y, float width, float height, int color, Collection collection) + { + super(x, y, width, height); + this.color = color; + text.setText("Select Index"); + list.setColor(color); + addEntries(collection); + } + + @Override + public void init() + { + list.setEntryHeight(getGui().getFont().height()).onAction(this); + addChild(text, Constrains.parent(21F, 0F, 10.5F, 0F)); + addChild(list, Constrains.parent(Target.X).invParent(Target.Y).parent(Target.WIDTH).build()); + onClose(buffer = getRenderer().createBuffer()); + createArrow(); + } + + public final SelectionComponent setAnimating(boolean value) + { + setFlag(FLAG_ANIMATE, value); + return this; + } + + public final boolean isAnimating() + { + return isFlagSet(FLAG_ANIMATE); + } + + @Override + protected void updateState() + { + list.setVisible(isOpen); + } + + public TextComponent getText() + { + return text; + } + + public ListComponent getList() + { + return list; + } + + public SelectionComponent addEntry(String s) + { + list.add(new SelectionEntry(s)); + return this; + } + + public SelectionComponent addEntries(Collection collection) + { + for(String s : collection) + { + list.add(new SelectionEntry(s)); + } + return this; + } + + public SelectionComponent updateEntry(int index, String newName) + { + list.get(index).setText(newName); + if(index == selectedIndex) + { + updateSelection(); + } + return this; + } + + public SelectionComponent removeEntry(String s) + { + for(int i = 0,m=list.size();i tabs = new ObjectArrayList<>(); + int selectedTab = -1; + float tabScale = 1F; + + Facing facing; + int backgroundColor = ColorUtils.GRAY; + int unselectedColor = ColorUtils.GRAY; + int selectedColor = ColorUtils.DARK_GRAY; + float padding = 30F; + + public SingleTabPanelComponent() + { + this(Facing.NORTH); + } + + public SingleTabPanelComponent(Facing facing) + { + this(0F, 0F, 0F, 0F, facing); + } + + public SingleTabPanelComponent(float x, float y, float width, float height) + { + this(x, y, width, height, Facing.NORTH); + } + + public SingleTabPanelComponent(float x, float y, float width, float height, Facing facing) + { + super(x, y, width, height); + this.facing = facing; + } + + public SingleTabPanelComponent setFacing(Facing facing) + { + this.facing = facing; + updateConstrains(selection, createView()); + for(Tab tab : tabs) + { + updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab)); + } + updateConstrains(panel, createPanel()); + onChanged(true); + return this; + } + + public SingleTabPanelComponent setPadding(float padding) + { + this.padding = padding; + for(Tab tab : tabs) + { + tab.updatePadding(); + } + onChanged(true); + return this; + } + + public SingleTabPanelComponent addTab(String name) + { + Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)); + tabs.add(newTab); + if(selectedTab == -1) { + selectedTab = tabs.size()-1; + } + newTab.onAction(() -> selectTab(newTab)); + selection.addChild(newTab, createConstraint(newTab)); + onChanged(true); + return this; + } + + public Facing getFacing() + { + return facing; + } + + public int findTab(String name) + { + for(int i = 0,m=tabs.size();i= tabs.size()) return false; + if(selectedTab == index) return false; + selectedTab = index; + onChanged(true); + return true; + } + + protected float getOffset(Tab tab) + { + int index = tabs.indexOf(tab); + float offset = 0F; + for(int i = 0;i function; + + public DynamicTab(Tab tab, Object2FloatFunction function) + { + this.tab = tab; + this.function = function; + } + + @Override + public float getAsFloat() + { + return function.getFloat(tab); + } + } + + private class Tab extends GuiComponent implements IButtonComponent + { + String name; + float width = -1F; + TextComponent comp; + + public Tab(String name) + { + super(0F, 0F, 100F, 7.5F); + this.name = name; + comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP); + setFlag(FLAG_SUPPORT_BINDING); + } + + public Tab align(Align align) + { + comp.horizontal(align); + return this; + } + + public void updatePadding() + { + if(getGui() != null) width = getFont().width(name)+padding; + } + + @Override + public void init() + { + addChild(comp, Constrains.parent()); + updatePadding(); + } + + public float getWidth() + { + return width; + } + + public float getTextScale() + { + return comp.getTextScale(); + } + + @Override + protected void repaint() + { + String s = name; + float scale = comp.getTextScale(); + float width = (this.width-padding)*scale; + float desiredWidth = getBox().getBaseWidth(); + if(width > desiredWidth) { + while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) { + s = s.substring(0, s.length()-1); + } + comp.setText(s+"..."); + return; + } + comp.setText(s); + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + boolean notSelected = tabs.indexOf(this) != selectedTab; + getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor); + if(notSelected) getRenderer().drawFrame(getBox(), selectedColor); + return true; + } + + @Override + public void onRelease(int button, int mouseX, int mouseY) + { + notifyListeners(LISTENER_USER_ACTION); + } + + @Override + protected boolean onUserKey() + { + notifyListeners(LISTENER_USER_ACTION); + return true; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/SliderComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/SliderComponent.java index 193c3dd..04ea236 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/SliderComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/SliderComponent.java @@ -1,202 +1,213 @@ -package speiger.src.coreengine.rendering.gui.components; - -import java.util.function.IntFunction; - -import speiger.src.coreengine.math.MathUtils; -import speiger.src.coreengine.math.misc.Facing; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IButtonComponent; -import speiger.src.coreengine.rendering.gui.helper.UIShapes; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; - -public class SliderComponent extends GuiComponent implements IButtonComponent -{ - TextComponent text = new TextComponent(); - protected int color; - protected boolean vertical = false; - - protected int min; - protected int max; - protected int value; - int scrollEffect; - IntFunction textBuilder; - protected RenderBuffer buffer; - - public SliderComponent(int min, int max, int value, int color, IntFunction textBuilder) - { - this(0F, 0F, 0F, 0F, min, max, value, color, textBuilder); - } - - public SliderComponent(float x, float y, float width, float height, int min, int max, int value, int color, IntFunction textBuilder) - { - super(x, y, width, height); - this.min = min; - this.max = max; - this.value = MathUtils.clamp(min, max, value); - this.color = color; - this.textBuilder = textBuilder; - updateText(false); - } - - @Override - public void init() - { - text.setTextScale(0.35F); - addChild(text, Constrains.parent()); - createArrow(); - } - - protected void createArrow() - { - if(getGui() == null) - { - return; - } - if(buffer == null) - { - addCloseListener(buffer = getRenderer().createBuffer()); - } - buffer.clear(); - UIShapes.createArrow(buffer, 12F, 12F, color, vertical ? Facing.EAST : Facing.SOUTH); - } - - public TextComponent getText() - { - return text; - } - - public SliderComponent updateText(boolean notifyListeners) - { - if(textBuilder != null) - { - text.setText(textBuilder.apply(value)); - } - if(notifyListeners) - { - notifyListeners(LISTENER_USER_ACTION); - } - return this; - } - - public SliderComponent setColor(int color) - { - if(this.color != color) - { - this.color = color; - createArrow(); - } - return this; - } - - public SliderComponent setValue(int value) - { - int lastValue = this.value; - this.value = MathUtils.clamp(min, max, value); - if(lastValue != value) - { - updateText(true); - } - return this; - } - - public SliderComponent addValue(int value) - { - return setValue(this.value + value); - } - - public SliderComponent setScrollEffect(int scrollEffect) - { - this.scrollEffect = scrollEffect; - return this; - } - - public SliderComponent setVertical(boolean vertical) - { - if(this.vertical != vertical) - { - this.vertical = vertical; - createArrow(); - } - return this; - } - - public int getValue() - { - return value; - } - - public float getPercentalValue() - { - return ((float)(value - min) / (float)(max - min)); - } - - @Override - public boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float brightness = getActiveBrightness(); - float minX = getBox().getMinX(5F); - float minY = getBox().getMinY(2F); - float maxX = getBox().getMaxX(-5F); - float maxY = getBox().getMaxY(-2F); - float scale = 0.6F * getBox().getScale(); - if(vertical) - { - float extra = (((float)(value - min) / (float)(max - min)) * (getBox().getMaxY(-3F) - getBox().getMinY(3F))) + getBox().getMinY(3F); - float left = getBox().getMinX(2F); - getRenderer().setBrightness(brightness).drawQuad(minX, minY, maxX, maxY, color).setBrightness(brightness * 0.7F).drawFrame(minX, minY, maxX, maxY, 0.001F, color); - getRenderer().setBrightness(brightness * 0.5F).translate(left, extra, 0.002F).scale(scale).drawBuffers(buffer, maxX - minX, maxX - minX).setBrightness(brightness).unscale(scale).translate(-left, -extra, -0.002F); - } - else - { - float extra = (((float)(value - min) / (float)(max - min)) * (getBox().getMaxX(-6F) - getBox().getMinX(6F))) + getBox().getMinX(6F); - float top = getBox().getMinY(); - getRenderer().setBrightness(brightness).drawQuad(minX, minY, maxX, maxY, color).setBrightness(brightness * 0.7F).drawFrame(minX, minY, maxX, maxY, 0.001F, color); - getRenderer().setBrightness(brightness * 0.5F).translate(extra, top, 0.002F).scale(scale).drawBuffers(buffer, maxX - minX, maxX - minX).setBrightness(brightness).unscale(scale).translate(-extra, -top, -0.002F); - } - getRenderer().setBrightness(getBrightness(mouseX, mouseY)); - renderChildren(mouseX, mouseY, particalTicks); - getRenderer().setBrightness(1F); - return false; - } - - @Override - public boolean onClick(int button, int mouseX, int mouseY) - { - updateScroll(mouseX, mouseY); - return true; - } - - @Override - public boolean onDrag(int mouseX, int mouseY) - { - updateScroll(mouseX, mouseY); - return true; - } - - @Override - public boolean onScroll(int scroll, int mouseX, int mouseY) - { - if(scrollEffect != 0) - { - int newValue = MathUtils.clamp(min, max, value + (scroll * scrollEffect)); - if(newValue != value) - { - value = newValue; - updateText(true); - } - } - return scrollEffect != 0; - } - - public void updateScroll(int mouseX, int mouseY) - { - float pos = vertical ? (mouseY - getBox().getMinY(2F)) / getBox().getHeight(-5F) : (mouseX - getBox().getMinX(5F)) / getBox().getWidth(-11F); - int newValue = min + (int)(MathUtils.clamp(0F, 1F, pos) * (max - min)); - if(newValue != value) - { - value = newValue; - updateText(true); - } - } -} +package speiger.src.coreengine.rendering.gui.components; + +import java.util.function.IntFunction; + +import speiger.src.coreengine.math.MathUtils; +import speiger.src.coreengine.math.misc.Facing; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.base.IButtonComponent; +import speiger.src.coreengine.rendering.gui.helper.UIShapes; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; + +public class SliderComponent extends GuiComponent implements IButtonComponent +{ + TextComponent text = new TextComponent(); + protected int color; + protected boolean vertical = false; + + protected int min; + protected int max; + protected int value; + int scrollEffect; + IntFunction textBuilder; + protected RenderBuffer buffer; + + public SliderComponent(int min, int max, int value, int color, IntFunction textBuilder) + { + this(0F, 0F, 0F, 0F, min, max, value, color, 1F, textBuilder); + } + + public SliderComponent(int min, int max, int value, int color, float textScale, IntFunction textBuilder) + { + this(0F, 0F, 0F, 0F, min, max, value, color, textScale, textBuilder); + } + + public SliderComponent(float x, float y, float width, float height, int min, int max, int value, int color, IntFunction textBuilder) + { + this(x, y, width, height, min, max, value, color, 1F, textBuilder); + } + + public SliderComponent(float x, float y, float width, float height, int min, int max, int value, int color, float textScale, IntFunction textBuilder) + { + super(x, y, width, height); + this.min = min; + this.max = max; + this.value = MathUtils.clamp(min, max, value); + this.color = color; + text.setTextScale(textScale); + this.textBuilder = textBuilder; + updateText(false); + } + + @Override + public void init() + { + text.setTextScale(0.35F); + addChild(text, Constrains.parent()); + createArrow(); + } + + protected void createArrow() + { + if(getGui() == null) + { + return; + } + if(buffer == null) + { + onClose(buffer = getRenderer().createBuffer()); + } + buffer.clear(); + UIShapes.createArrow(buffer, 12F, 12F, color, vertical ? Facing.EAST : Facing.SOUTH); + } + + public TextComponent getText() + { + return text; + } + + public SliderComponent updateText(boolean notifyListeners) + { + if(textBuilder != null) + { + text.setText(textBuilder.apply(value)); + } + if(notifyListeners) + { + notifyListeners(LISTENER_USER_ACTION); + } + return this; + } + + public SliderComponent setColor(int color) + { + if(this.color != color) + { + this.color = color; + createArrow(); + } + return this; + } + + public SliderComponent setValue(int value) + { + int lastValue = this.value; + this.value = MathUtils.clamp(min, max, value); + if(lastValue != value) + { + updateText(true); + } + return this; + } + + public SliderComponent addValue(int value) + { + return setValue(this.value + value); + } + + public SliderComponent setScrollEffect(int scrollEffect) + { + this.scrollEffect = scrollEffect; + return this; + } + + public SliderComponent setVertical(boolean vertical) + { + if(this.vertical != vertical) + { + this.vertical = vertical; + createArrow(); + } + return this; + } + + public int getValue() + { + return value; + } + + public float getPercentalValue() + { + return ((float)(value - min) / (float)(max - min)); + } + + @Override + public boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float brightness = getActiveBrightness(); + float minX = getBox().getMinX(5F); + float minY = getBox().getMinY(2F); + float maxX = getBox().getMaxX(-5F); + float maxY = getBox().getMaxY(-2F); + float scale = 0.6F * getBox().getScale(); + if(vertical) + { + float extra = (((float)(value - min) / (float)(max - min)) * (getBox().getMaxY(-3F) - getBox().getMinY(3F))) + getBox().getMinY(3F); + float left = getBox().getMinX(2F); + getRenderer().setBrightness(brightness).drawQuad(minX, minY, maxX, maxY, color).setBrightness(brightness * 0.7F).drawFrame(minX, minY, maxX, maxY, 0.001F, color); + getRenderer().setBrightness(brightness * 0.5F).translate(left, extra, 0.002F).scale(scale).drawBuffers(buffer, maxX - minX, maxX - minX).setBrightness(brightness).unscale(scale).translate(-left, -extra, -0.002F); + } + else + { + float extra = (((float)(value - min) / (float)(max - min)) * (getBox().getMaxX(-6F) - getBox().getMinX(6F))) + getBox().getMinX(6F); + float top = getBox().getMinY(); + getRenderer().setBrightness(brightness).drawQuad(minX, minY, maxX, maxY, color).setBrightness(brightness * 0.7F).drawFrame(minX, minY, maxX, maxY, 0.001F, color); + getRenderer().setBrightness(brightness * 0.5F).translate(extra, top, 0.002F).scale(scale).drawBuffers(buffer, maxX - minX, maxX - minX).setBrightness(brightness).unscale(scale).translate(-extra, -top, -0.002F); + } + getRenderer().setBrightness(getBrightness(mouseX, mouseY)); + renderChildren(mouseX, mouseY, particalTicks); + getRenderer().setBrightness(1F); + return false; + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + updateScroll(mouseX, mouseY); + return true; + } + + @Override + public boolean onDrag(int mouseX, int mouseY) + { + updateScroll(mouseX, mouseY); + return true; + } + + @Override + public boolean onScroll(int scroll, int mouseX, int mouseY) + { + if(scrollEffect != 0) + { + int newValue = MathUtils.clamp(min, max, value + (scroll * scrollEffect)); + if(newValue != value) + { + value = newValue; + updateText(true); + } + } + return scrollEffect != 0; + } + + public void updateScroll(int mouseX, int mouseY) + { + float pos = vertical ? (mouseY - getBox().getMinY(2F)) / getBox().getHeight(-5F) : (mouseX - getBox().getMinX(5F)) / getBox().getWidth(-11F); + int newValue = min + (int)(MathUtils.clamp(0F, 1F, pos) * (max - min)); + if(newValue != value) + { + value = newValue; + updateText(true); + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/TabbedPanelComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/TabbedPanelComponent.java new file mode 100644 index 0000000..acd09ff --- /dev/null +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/TabbedPanelComponent.java @@ -0,0 +1,339 @@ +package speiger.src.coreengine.rendering.gui.components; + +import speiger.src.collections.objects.functions.function.Object2FloatFunction; +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.collections.objects.lists.ObjectList; +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.math.misc.Facing; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.base.IButtonComponent; +import speiger.src.coreengine.rendering.gui.helper.Align; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain.Target; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.helper.constrains.DynamicConstrain; +import speiger.src.coreengine.utils.functions.FloatSupplier; + +public class TabbedPanelComponent extends PanelComponent +{ + PanelComponent selection = new PanelComponent(); + ObjectList tabs = new ObjectArrayList<>(); + int selectedTab = -1; + float tabScale = 1F; + + Facing facing; + int backgroundColor = ColorUtils.GRAY; + int unselectedColor = ColorUtils.GRAY; + int selectedColor = ColorUtils.DARK_GRAY; + float padding = 30F; + + public TabbedPanelComponent() + { + this(Facing.NORTH); + } + + public TabbedPanelComponent(Facing facing) + { + this(0F, 0F, 0F, 0F, facing); + } + + public TabbedPanelComponent(float x, float y, float width, float height) + { + this(x, y, width, height, Facing.NORTH); + } + + public TabbedPanelComponent(float x, float y, float width, float height, Facing facing) + { + super(x, y, width, height); + this.facing = facing; + } + + public TabbedPanelComponent setFacing(Facing facing) + { + this.facing = facing; + updateConstrains(selection, createView()); + for(Tab tab : tabs) + { + updateConstrains(tab.align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)), createConstraint(tab)); + updateConstrains(tab.getPanel(), createPanel()); + } + onChanged(true); + return this; + } + + public TabbedPanelComponent setPadding(float padding) + { + this.padding = padding; + for(Tab tab : tabs) + { + tab.updatePadding(); + } + onChanged(true); + return this; + } + + public Facing getFacing() + { + return facing; + } + + public PanelComponent addTab(String name) + { + Tab newTab = new Tab(name).align(facing.isZAxis() ? Align.CENTER : (facing == Facing.WEST ? Align.LEFT_TOP : Align.RIGHT_BOTTOM)); + tabs.add(newTab); + if(selectedTab == -1) { + selectedTab = tabs.size()-1; + newTab.getPanel().setVisible(true); + } + newTab.onAction(() -> selectTab(newTab)); + selection.addChild(newTab, createConstraint(newTab)); + addChild(newTab.getPanel(), createPanel()); + onChanged(true); + return newTab.getPanel(); + } + + public int findTab(String name) + { + for(int i = 0,m=tabs.size();i= tabs.size()) return false; + if(selectedTab == index) return false; + if(selectedTab != -1) tabs.get(selectedTab).getPanel().setVisible(false); + selectedTab = index; + tabs.get(selectedTab).getPanel().setVisible(true); + onChanged(true); + return true; + } + + protected float getOffset(Tab tab) + { + int index = tabs.indexOf(tab); + float offset = 0F; + for(int i = 0;i function; + + public DynamicTab(Tab tab, Object2FloatFunction function) + { + this.tab = tab; + this.function = function; + } + + @Override + public float getAsFloat() + { + return function.getFloat(tab); + } + } + + private class Tab extends GuiComponent implements IButtonComponent + { + String name; + float width = -1F; + TextComponent comp; + PanelComponent panel = new PanelComponent().setScissors(true).setVisible(false).cast(); + + public Tab(String name) + { + super(0F, 0F, 100F, 7.5F); + this.name = name; + comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP); + setFlag(FLAG_SUPPORT_BINDING); + } + + public Tab align(Align align) + { + comp.horizontal(align); + return this; + } + + public void updatePadding() + { + if(getGui() != null) width = getFont().width(name)+padding; + } + + @Override + public void init() + { + addChild(comp, Constrains.parent()); + updatePadding(); + } + + public float getWidth() + { + return width; + } + + public float getTextScale() + { + return comp.getTextScale(); + } + + @Override + protected void repaint() + { + String s = name; + float scale = comp.getTextScale(); + float width = (this.width-padding)*scale; + float desiredWidth = getBox().getBaseWidth(); + if(width > desiredWidth) { + while(s.length() >= 1 && getFont().width(s+"...") * scale > desiredWidth) { + s = s.substring(0, s.length()-1); + } + comp.setText(s+"..."); + return; + } + comp.setText(s); + } + + public PanelComponent getPanel() + { + return panel; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + boolean notSelected = tabs.indexOf(this) != selectedTab; + getRenderer().drawQuad(getBox(), notSelected ? unselectedColor : selectedColor); + if(notSelected) getRenderer().drawFrame(getBox(), selectedColor); + return true; + } + + @Override + public void onRelease(int button, int mouseX, int mouseY) + { + notifyListeners(LISTENER_USER_ACTION); + } + + @Override + protected boolean onUserKey() + { + notifyListeners(LISTENER_USER_ACTION); + return true; + } + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/TabbedWindowComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/TabbedWindowComponent.java deleted file mode 100644 index e326f04..0000000 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/TabbedWindowComponent.java +++ /dev/null @@ -1,61 +0,0 @@ -package speiger.src.coreengine.rendering.gui.components; - -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.helper.Align; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; - -public class TabbedWindowComponent extends WindowComponent -{ - - public TabbedWindowComponent(float x, float y, float width, float height) - { - super(x, y, width, height, DEFAULT_FLAGS, "Test"); - } - - @Override - public void init() - { - super.init(); - addChild(new Tab("Testing My theory with the full lenght text"), null, null, new ParentConstrain(), null); - } - - public static class Tab extends GuiComponent - { - String name; - float width = -1F; - boolean closeable; - TextComponent comp; - - public Tab(String name) - { - super(0F, 7F, 100F, 10F); - this.name = name; - comp = new TextComponent(name).setTextScale(0.4F).singleLine(true).horizontal(Align.LEFT_TOP); - } - - @Override - public void init() - { - width = getFont().width(name); - addChild(comp, Constrains.parent()); - } - - @Override - protected void repaint() - { - String s = name; - float scale = comp.getTextScale(); - float width = getFont().width(s)*scale; - float desiredWidth = getBox().getBaseWidth(); - if(width > desiredWidth) { - while(getFont().width(s+"...") * scale > desiredWidth) { - s = s.substring(0, s.length()-1); - } - comp.setText(s+"..."); - return; - } - comp.setText(s); - } - } -} \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/TextComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/TextComponent.java index 25031ef..f7d8e72 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/TextComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/TextComponent.java @@ -1,437 +1,437 @@ -package speiger.src.coreengine.rendering.gui.components; - -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.helper.Align; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; -import speiger.src.coreengine.rendering.gui.renderer.FontRenderer; -import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; -import speiger.src.coreengine.rendering.gui.renderer.lexer.TextMetadata; - -public class TextComponent extends GuiComponent -{ - public static final int FLAG_STRIKE_THROUGH = 1 << 20; - public static final int FLAG_UNDERLINE = 1 << 21; - public static final int FLAG_BOLD = 1 << 22; - public static final int FLAG_FORMATTING = 1 << 23; - public static final int FLAG_FLIPPED = 1 << 24; - public static final int FLAG_LIMITED_WIDTH = 1 << 25; - public static final int FLAG_LIMITED_HEIGHT = 1 << 26; - public static final int FLAG_AUTO_SCALE = 1 << 27; - public static final int FLAG_SINGLE_LINE = 1 << 28; - - FontRenderer font; - String text = ""; - Align vertical = Align.CENTER; - Align horizontal = Align.CENTER; - int textColor = ColorUtils.WHITE; - Integer backGroundColor = null; - float italic = 0F; - float textScale = 1F; - RenderBuffer buffer; - float initialSize; - TextMetadata metadata = new TextMetadata(this); - - public TextComponent() - { - super(0F, 0F, 0F, 0F); - setFlag(FLAG_FORMATTING | FLAG_LIMITED_WIDTH | FLAG_LIMITED_HEIGHT); - } - - public TextComponent(String text) - { - this(0F, 0F, 0F, 0F, text); - } - - public TextComponent(float x, float y, float width, float height) - { - super(x, y, width, height); - setFlag(FLAG_FORMATTING | FLAG_LIMITED_WIDTH | FLAG_LIMITED_HEIGHT); - } - - public TextComponent(float x, float y, float width, float height, String text) - { - super(x, y, width, height); - setFlag(FLAG_FORMATTING | FLAG_LIMITED_WIDTH | FLAG_LIMITED_HEIGHT); - setText(text); - } - - @Override - public void init() - { - addCloseListener(buffer = getRenderer().createBuffer()); - if(font == null) - { - setFont(getGui().getFont()); - } - initialSize = getBox().getWidth(); - } - - @Override - public boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - if(text.isEmpty()) - { - return true; - } - float minX = getBox().getMinX(); - float minY = getBox().getMinY(); - getRenderer().translate(minX, minY).setActiveTexture(font.getTexture()).drawBuffers(buffer, getBox().getWidth(), getBox().getHeight()).translate(-minX, -minY); - return true; - } - - @Override - 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; - } - IGuiBox box = getBox(); - area[0] = Math.min(area[0], box.getMinX() - metadata.getStartX()); - area[1] = Math.min(area[1], box.getMinY() - metadata.getStartY()); - area[2] = Math.max(area[2], (box.getMinX() - metadata.getStartX()) + metadata.getMaxWidth()); - area[3] = Math.max(area[3], (box.getMinY() - metadata.getStartY()) + metadata.getMaxHeight()); - for(GuiComponent comp : getChildren()) - { - if(comp.isVisible()) comp.calculateActualBounds(area, false); - } - } - - public RenderBuffer getBuffer() - { - return buffer; - } - - @Override - protected void repaint() - { - metadata.clear(); - if(font == null) - { - return; - } - font.updateText(this); - } - - public TextComponent setTextScale(float textScale) - { - if(this.textScale != textScale) - { - this.textScale = textScale; - onChanged(true); - } - return this; - } - - public TextMetadata getMetadata() - { - return metadata; - } - - public final float getTextScale() - { - return textScale * getBox().getScale() * (isAutoScaling() ? getBox().getWidth() / initialSize : 1F); - } - - public final float getRawTextScale() - { - return textScale * (isAutoScaling() ? getBox().getWidth() / initialSize : 1F); - } - - public final float getWidth() - { - return getBox().getWidth() / getTextScale(); - } - - public final float getItalic() - { - return italic; - } - - public final boolean isBold() - { - return isFlagSet(FLAG_BOLD); - } - - public final boolean isStrikeThrough() - { - return isFlagSet(FLAG_STRIKE_THROUGH); - } - - public final boolean isUnderlined() - { - return isFlagSet(FLAG_UNDERLINE); - } - - public final boolean isFlipped() - { - return isFlagSet(FLAG_FLIPPED); - } - - public final boolean isRenderingSpecial() - { - return isFlagSet(FLAG_FORMATTING); - } - - public final boolean isWidthLimited() - { - return isFlagSet(FLAG_LIMITED_WIDTH); - } - - public final boolean isHeightLimited() - { - return isFlagSet(FLAG_LIMITED_HEIGHT); - } - - public final boolean isLimitedText() - { - return isFlagSet(FLAG_LIMITED_WIDTH | FLAG_LIMITED_HEIGHT); - } - - public final boolean isAutoScaling() - { - return isFlagSet(FLAG_AUTO_SCALE); - } - - public final boolean isForcedSingleLine() - { - return isFlagSet(FLAG_SINGLE_LINE); - } - - public final int getTextColor() - { - return textColor; - } - - public final Integer getBackgroundColor() - { - return backGroundColor; - } - - @Override - public FontRenderer getFont() - { - return font; - } - - public String getText() - { - return text; - } - - public String getText(int min) - { - return text.substring(min); - } - - public String getText(int min, int max) - { - return text.substring(min, max); - } - - public int length() - { - return text.length(); - } - - public Align getVertical() - { - return vertical; - } - - public Align getHorizontal() - { - return horizontal; - } - - public final TextComponent bold(boolean value) - { - if(setFlag(FLAG_BOLD, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent strikethrough(boolean value) - { - if(!setFlag(FLAG_STRIKE_THROUGH, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent underline(boolean value) - { - if(!setFlag(FLAG_UNDERLINE, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent flipped(boolean value) - { - if(!setFlag(FLAG_FLIPPED, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent special(boolean value) - { - if(!setFlag(FLAG_FORMATTING, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent limit(boolean value) - { - if(!setFlag(FLAG_LIMITED_HEIGHT | FLAG_LIMITED_WIDTH, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent limitWidth(boolean value) - { - if(!setFlag(FLAG_LIMITED_WIDTH, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent limitHeight(boolean value) - { - if(!setFlag(FLAG_LIMITED_HEIGHT, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent autoScale(boolean value) - { - if(!setFlag(FLAG_AUTO_SCALE, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent singleLine(boolean value) - { - if(!setFlag(FLAG_SINGLE_LINE, value)) - { - return this; - } - onChanged(true); - return this; - } - - public final TextComponent italic(boolean value) - { - return italic(value ? 3F : 0F); - } - - public final TextComponent italic(float value) - { - if(italic != value) - { - italic = value; - onChanged(true); - } - return this; - } - - public TextComponent align(Align horizontal, Align vertical) - { - if(this.horizontal != horizontal || this.vertical != vertical) - { - this.horizontal = horizontal; - this.vertical = vertical; - onChanged(true); - } - return this; - } - - public TextComponent horizontal(Align horizontal) - { - if(this.horizontal != horizontal) - { - this.horizontal = horizontal; - onChanged(true); - } - return this; - } - - public TextComponent vertical(Align vertical) - { - if(this.vertical != vertical) - { - this.vertical = vertical; - onChanged(true); - } - return this; - } - - public TextComponent setText(String text) - { - if(text == null) text = "null"; - if(!this.text.equals(text)) - { - this.text = text; - onChanged(true); - } - return this; - } - - public TextComponent textColor(int color) - { - if(textColor != color) - { - textColor = color; - onChanged(true); - } - return this; - } - - public TextComponent backgroundColor(int color) - { - if(backGroundColor != color) - { - backGroundColor = color; - onChanged(true); - } - return this; - } - - public TextComponent setFont(FontRenderer font) - { - if(this.font != font) - { - this.font = font; - onChanged(true); - } - return this; - } -} +package speiger.src.coreengine.rendering.gui.components; + +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.helper.Align; +import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; +import speiger.src.coreengine.rendering.gui.renderer.FontRenderer; +import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; +import speiger.src.coreengine.rendering.gui.renderer.lexer.TextMetadata; + +public class TextComponent extends GuiComponent +{ + public static final int FLAG_STRIKE_THROUGH = 1 << 20; + public static final int FLAG_UNDERLINE = 1 << 21; + public static final int FLAG_BOLD = 1 << 22; + public static final int FLAG_FORMATTING = 1 << 23; + public static final int FLAG_FLIPPED = 1 << 24; + public static final int FLAG_LIMITED_WIDTH = 1 << 25; + public static final int FLAG_LIMITED_HEIGHT = 1 << 26; + public static final int FLAG_AUTO_SCALE = 1 << 27; + public static final int FLAG_SINGLE_LINE = 1 << 28; + + FontRenderer font; + String text = ""; + Align vertical = Align.CENTER; + Align horizontal = Align.CENTER; + int textColor = ColorUtils.WHITE; + Integer backGroundColor = null; + float italic = 0F; + float textScale = 1F; + RenderBuffer buffer; + float initialSize; + TextMetadata metadata = new TextMetadata(this); + + public TextComponent() + { + super(0F, 0F, 0F, 0F); + setFlag(FLAG_FORMATTING | FLAG_LIMITED_WIDTH | FLAG_LIMITED_HEIGHT); + } + + public TextComponent(String text) + { + this(0F, 0F, 0F, 0F, text); + } + + public TextComponent(float x, float y, float width, float height) + { + super(x, y, width, height); + setFlag(FLAG_FORMATTING | FLAG_LIMITED_WIDTH | FLAG_LIMITED_HEIGHT); + } + + public TextComponent(float x, float y, float width, float height, String text) + { + super(x, y, width, height); + setFlag(FLAG_FORMATTING | FLAG_LIMITED_WIDTH | FLAG_LIMITED_HEIGHT); + setText(text); + } + + @Override + public void init() + { + onClose(buffer = getRenderer().createBuffer()); + if(font == null) + { + setFont(getGui().getFont()); + } + initialSize = getBox().getWidth(); + } + + @Override + public boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + if(text.isEmpty()) + { + return true; + } + float minX = getBox().getMinX(); + float minY = getBox().getMinY(); + getRenderer().translate(minX, minY).setActiveTexture(font.getTexture()).drawBuffers(buffer, getBox().getWidth(), getBox().getHeight()).translate(-minX, -minY); + return true; + } + + @Override + 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; + } + IGuiBox box = getBox(); + area[0] = Math.min(area[0], box.getMinX() - metadata.getStartX()); + area[1] = Math.min(area[1], box.getMinY() - metadata.getStartY()); + area[2] = Math.max(area[2], (box.getMinX() - metadata.getStartX()) + metadata.getMaxWidth()); + area[3] = Math.max(area[3], (box.getMinY() - metadata.getStartY()) + metadata.getMaxHeight()); + for(GuiComponent comp : getChildren()) + { + if(comp.isVisible()) comp.calculateActualBounds(area, false); + } + } + + public RenderBuffer getBuffer() + { + return buffer; + } + + @Override + protected void repaint() + { + metadata.clear(); + if(font == null) + { + return; + } + font.updateText(this); + } + + public TextComponent setTextScale(float textScale) + { + if(this.textScale != textScale) + { + this.textScale = textScale; + onChanged(true); + } + return this; + } + + public TextMetadata getMetadata() + { + return metadata; + } + + public final float getTextScale() + { + return textScale * getBox().getScale() * (isAutoScaling() ? getBox().getWidth() / initialSize : 1F); + } + + public final float getRawTextScale() + { + return textScale * (isAutoScaling() ? getBox().getWidth() / initialSize : 1F); + } + + public final float getWidth() + { + return getBox().getWidth() / getTextScale(); + } + + public final float getItalic() + { + return italic; + } + + public final boolean isBold() + { + return isFlagSet(FLAG_BOLD); + } + + public final boolean isStrikeThrough() + { + return isFlagSet(FLAG_STRIKE_THROUGH); + } + + public final boolean isUnderlined() + { + return isFlagSet(FLAG_UNDERLINE); + } + + public final boolean isFlipped() + { + return isFlagSet(FLAG_FLIPPED); + } + + public final boolean isRenderingSpecial() + { + return isFlagSet(FLAG_FORMATTING); + } + + public final boolean isWidthLimited() + { + return isFlagSet(FLAG_LIMITED_WIDTH); + } + + public final boolean isHeightLimited() + { + return isFlagSet(FLAG_LIMITED_HEIGHT); + } + + public final boolean isLimitedText() + { + return isFlagSet(FLAG_LIMITED_WIDTH | FLAG_LIMITED_HEIGHT); + } + + public final boolean isAutoScaling() + { + return isFlagSet(FLAG_AUTO_SCALE); + } + + public final boolean isForcedSingleLine() + { + return isFlagSet(FLAG_SINGLE_LINE); + } + + public final int getTextColor() + { + return textColor; + } + + public final Integer getBackgroundColor() + { + return backGroundColor; + } + + @Override + public FontRenderer getFont() + { + return font; + } + + public String getText() + { + return text; + } + + public String getText(int min) + { + return text.substring(min); + } + + public String getText(int min, int max) + { + return text.substring(min, max); + } + + public int length() + { + return text.length(); + } + + public Align getVertical() + { + return vertical; + } + + public Align getHorizontal() + { + return horizontal; + } + + public final TextComponent bold(boolean value) + { + if(setFlag(FLAG_BOLD, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent strikethrough(boolean value) + { + if(!setFlag(FLAG_STRIKE_THROUGH, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent underline(boolean value) + { + if(!setFlag(FLAG_UNDERLINE, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent flipped(boolean value) + { + if(!setFlag(FLAG_FLIPPED, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent special(boolean value) + { + if(!setFlag(FLAG_FORMATTING, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent limit(boolean value) + { + if(!setFlag(FLAG_LIMITED_HEIGHT | FLAG_LIMITED_WIDTH, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent limitWidth(boolean value) + { + if(!setFlag(FLAG_LIMITED_WIDTH, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent limitHeight(boolean value) + { + if(!setFlag(FLAG_LIMITED_HEIGHT, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent autoScale(boolean value) + { + if(!setFlag(FLAG_AUTO_SCALE, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent singleLine(boolean value) + { + if(!setFlag(FLAG_SINGLE_LINE, value)) + { + return this; + } + onChanged(true); + return this; + } + + public final TextComponent italic(boolean value) + { + return italic(value ? 3F : 0F); + } + + public final TextComponent italic(float value) + { + if(italic != value) + { + italic = value; + onChanged(true); + } + return this; + } + + public TextComponent align(Align horizontal, Align vertical) + { + if(this.horizontal != horizontal || this.vertical != vertical) + { + this.horizontal = horizontal; + this.vertical = vertical; + onChanged(true); + } + return this; + } + + public TextComponent horizontal(Align horizontal) + { + if(this.horizontal != horizontal) + { + this.horizontal = horizontal; + onChanged(true); + } + return this; + } + + public TextComponent vertical(Align vertical) + { + if(this.vertical != vertical) + { + this.vertical = vertical; + onChanged(true); + } + return this; + } + + public TextComponent setText(String text) + { + if(text == null) text = "null"; + if(!this.text.equals(text)) + { + this.text = text; + onChanged(true); + } + return this; + } + + public TextComponent textColor(int color) + { + if(textColor != color) + { + textColor = color; + onChanged(true); + } + return this; + } + + public TextComponent backgroundColor(int color) + { + if(backGroundColor != color) + { + backGroundColor = color; + onChanged(true); + } + return this; + } + + public TextComponent setFont(FontRenderer font) + { + if(this.font != font) + { + this.font = font; + onChanged(true); + } + return this; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/TextFieldComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/TextFieldComponent.java index 5d8a2be..67ba324 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/TextFieldComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/TextFieldComponent.java @@ -1,723 +1,733 @@ -package speiger.src.coreengine.rendering.gui.components; - -import java.util.function.Predicate; - -import org.lwjgl.glfw.GLFW; - -import speiger.src.coreengine.math.MathUtils; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IButtonComponent; -import speiger.src.coreengine.rendering.gui.base.IKeyComponent; -import speiger.src.coreengine.rendering.gui.helper.Align; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; -import speiger.src.coreengine.rendering.gui.helper.box.ParentBox; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain.Target; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; -import speiger.src.coreengine.rendering.gui.renderer.lexer.TextMetadata; -import speiger.src.coreengine.rendering.gui.renderer.lexer.Word; -import speiger.src.coreengine.rendering.gui.renderer.lexer.WordType; -import speiger.src.coreengine.rendering.input.Keyboard; -import speiger.src.coreengine.rendering.utils.Cursor; -import speiger.src.coreengine.utils.functions.Functions; - -public class TextFieldComponent extends GuiComponent - implements IButtonComponent, IKeyComponent -{ - public static final int FLAG_FOCUS = 1 << 20; - public static final int FLAG_CAN_LOSE_FOCUS = 1 << 21; - public static final int FLAG_DOUBLE_CLICK = 1 << 22; - public static final int FLAG_INFINITE_WIDTH = 1 << 23; - public static final int FLAG_AUTO_VALIDATE = 1 << 24; - - TextComponent text = new TextComponent().horizontal(Align.LEFT_TOP).singleLine(true).special(false).cast(); - int color; - int curserPosition = 0; - int selectionPosition = 0; - long lastClickTime = 0; - int maxTextLength = 32; - Predicate validator = Functions.getAlwaysTrue(); - int lineOffset = 0; - boolean direction = false; - int largestPos = 0; - IGuiBox viewPort = new ParentBox(1F); - - public TextFieldComponent(int color) - { - super(0F, 0F, 0F, 0F); - setFlag(FLAG_CAN_LOSE_FOCUS); - this.color = color; - } - - public TextFieldComponent(float x, float y, float width, float height, int color) - { - super(x, y, width, height); - setFlag(FLAG_CAN_LOSE_FOCUS); - this.color = color; - } - - @Override - public void init() - { - addBox(viewPort); - addChild(text, createConstraints()); - if(text.getText().length() > 0 && isFlagNotSet(FLAG_INFINITE_WIDTH)) - { - String s = text.getText(); - float scale = text.getTextScale(); - float width = text.getBox().getWidth(); - while(text.getFont().width(s) * scale > width && s.length() > 0) - { - s = s.substring(0, s.length() - 1); - } - text.setText(s); - } - } - - private Constrains createConstraints() - { - return isFlagNotSet(FLAG_INFINITE_WIDTH) ? Constrains.parent(1F) : Constrains.dynamic(this::getOffset, Target.X).parent(1F, Target.Y).parent(1F, Target.WIDTH).parent(1F, Target.HEIGHT).build(); - } - - public TextFieldComponent setValidator(Predicate validator) - { - this.validator = validator; - return this; - } - - public TextFieldComponent setMaxTextLength(int charLimit) - { - maxTextLength = charLimit; - return this; - } - - public TextFieldComponent setCanLoseFocus(boolean value) - { - setFlag(FLAG_CAN_LOSE_FOCUS, value); - return this; - } - - public TextFieldComponent setFocused(boolean value) - { - setFlag(FLAG_FOCUS, value); - return this; - } - - public TextFieldComponent setAutoUpdating(boolean value) - { - setFlag(FLAG_AUTO_VALIDATE, value); - return this; - } - - public TextFieldComponent setColor(int color) - { - this.color = color; - return this; - } - - public final TextFieldComponent setInfiniteText(boolean value) - { - if(setFlag(FLAG_INFINITE_WIDTH, value)) - { - text.limit(!value); - if(getGui() != null) - { - addConstrains(text, createConstraints()); - } - } - return this; - } - - public TextComponent getRawText() - { - return text; - } - - public String getText() - { - return text.getText(); - } - - public String getSelectedText() - { - return text.getText(Math.min(getCurserPosition(), getSelectionPosition()), Math.max(getCurserPosition(), getSelectionPosition())); - } - - public TextFieldComponent setText(String s) - { - if(s == null) - { - return this; - } - if(validator.test(s)) - { - if(s.length() > maxTextLength) - { - s = s.substring(0, maxTextLength); - } - if(isFlagNotSet(FLAG_INFINITE_WIDTH) && getGui() != null) - { - float scale = text.getTextScale(); - float width = text.getBox().getWidth(); - while(text.getFont().width(s) * scale > width) - { - s = s.substring(0, s.length() - 1); - } - } - text.setText(s); - } - return this; - } - - @Override - protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) - { - if(text.isTopHovered(mouseX, mouseY)) - { - bindCursor(Cursor.CURSOR_IBEAM); - } - return true; - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float brightness = getActiveBrightness(); - UIRenderer render = getRenderer(); - render.setBrightness(brightness * 0.7F).drawQuad(getBox(), color).setBrightness(brightness); - IGuiBox box = text.getBox(); - render.drawQuad(viewPort, 0.001F, color); - if(isFlagSet(FLAG_INFINITE_WIDTH)) - { - enableScissorsBox(getBox().getMinX(1F), getBox().getMinY(1F), getBox().getMaxX(-1F), getBox().getMaxY(-1F)); - } - if(isFlagSet(FLAG_FOCUS) && (getGlobalClock() / 15) % 2L == 0) - { - TextMetadata data = text.getMetadata(); - if(hasSelectedText()) - { - float extra = text.getHorizontal().align(box.getWidth(), data.getMaxWidth()); - render.drawQuad(box.getMinX() + extra + data.getWidth(Math.min(getCurserPosition(), getSelectionPosition())), box.getMinY(), box.getMinX() + extra + data.getWidth(Math.max(getCurserPosition(), getSelectionPosition())), box.getMaxY(), 0.02F, text.getTextColor()); - } - else - { - float width = data.getWidth(curserPosition) + text.getHorizontal().align(box.getWidth(), data.getMaxWidth()); - render.drawQuad(box.getMinX() + width, box.getMinY(), box.getMinX() + width + text.getTextScale(), box.getMaxY(), 0.02F, text.getTextColor()); - } - } - if(isFlagSet(FLAG_INFINITE_WIDTH)) - { - renderChildren(mouseX, mouseY, particalTicks); - disableScissors(); - return false; - } - return true; - } - - @Override - public boolean onClick(int button, int mouseX, int mouseY) - { - setFocused(true); - if(hasSelectedText() && isFlagNotSet(FLAG_DOUBLE_CLICK)) - { - setSelectionPosition(-1); - setCurserPosition(getMousePosition(mouseX)); - return true; - } - int pos = getMousePosition(mouseX); - if(pos == getCurserPosition() || isFlagSet(FLAG_DOUBLE_CLICK)) - { - if(System.currentTimeMillis() - lastClickTime < 500L) - { - if(isFlagSet(FLAG_DOUBLE_CLICK)) - { - clearFlag(FLAG_DOUBLE_CLICK); - setSelectionPosition(0); - setCurserPosition(text.length()); - } - else - { - setFlag(FLAG_DOUBLE_CLICK); - handleDoubleClick(pos); - } - } - else - { - clearFlag(FLAG_DOUBLE_CLICK); - } - lastClickTime = System.currentTimeMillis(); - return true; - } - clearFlag(FLAG_DOUBLE_CLICK); - setCurserPosition(pos); - lastClickTime = System.currentTimeMillis(); - return true; - } - - @Override - public boolean onDrag(int mouseX, int mouseY) - { - if(!hasSelectedText()) - { - setSelectionPosition(getCurserPosition()); - } - setCurserPosition(getMousePosition(mouseX)); - return true; - } - - @Override - public boolean isAcceptingInput() - { - return isFlagSet(FLAG_FOCUS); - } - - @Override - public boolean isBlockingMovement() - { - return true; - } - - @Override - public boolean onKeyPressed(int key) - { - if(isFlagNotSet(FLAG_FOCUS)) - { - return false; - } - if(key == GLFW.GLFW_KEY_ENTER) - { - notifyListeners(LISTENER_USER_ACTION); - if(isFlagSet(FLAG_CAN_LOSE_FOCUS)) - { - setFocused(false); - return true; - } - } - if(key == GLFW.GLFW_KEY_BACKSPACE) - { - if(Keyboard.isCtrlDown()) - { - Word word = text.getMetadata().getWord(getCurserPosition()); - if(word == null) - { - return true; - } - if(getCurserPosition() == word.getStartIndex()) - { - if(word.getPrev() != null) - { - deleteAtCurser(word.getPrev().getStartIndex() - word.getStartIndex()); - } - } - else - { - setCurserPosition(word.getStartIndex()); - deleteAtCurser(word.getEndIndex() - word.getStartIndex()); - } - return true; - } - else if(deleteAtCurser(-1)) - { - return true; - } - } - else if(key == GLFW.GLFW_KEY_DELETE) - { - if(Keyboard.isCtrlDown()) - { - Word word = text.getMetadata().getWord(getCurserPosition()); - if(word == null) - { - return true; - } - if(getCurserPosition() == word.getEndIndex()) - { - if(word.getNext() != null) - { - deleteAtCurser(word.getNext().getEndIndex() - word.getEndIndex()); - } - } - else - { - setCurserPosition(word.getStartIndex()); - deleteAtCurser(word.getEndIndex() - word.getStartIndex()); - } - return true; - } - else if(deleteAtCurser(1)) - { - return true; - } - } - else if(key == GLFW.GLFW_KEY_LEFT) - { - if(getCurserPosition() >= 0) - { - if(Keyboard.isShiftDown() && getSelectionPosition() == -1) - { - setSelectionPosition(getCurserPosition()); - } - else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1) - { - setSelectionPosition(-1); - } - if(Keyboard.isCtrlDown()) - { - Word word = text.getMetadata().getWord(getCurserPosition()); - if(word.getStartIndex() == getCurserPosition()) - { - if(word.getPrev() != null) - { - setCurserPosition(word.getPrev().getStartIndex()); - } - } - else - { - setCurserPosition(word.getStartIndex()); - } - } - else - { - setCurserPosition(getCurserPosition() - 1); - } - return true; - } - } - else if(key == GLFW.GLFW_KEY_RIGHT) - { - if(getCurserPosition() < text.length()) - { - if(Keyboard.isShiftDown() && getSelectionPosition() == -1) - { - setSelectionPosition(getCurserPosition()); - } - else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1) - { - setSelectionPosition(-1); - } - if(Keyboard.isCtrlDown()) - { - Word word = text.getMetadata().getWord(getCurserPosition()); - if(word.getEndIndex() == getCurserPosition()) - { - if(word.getNext() != null) - { - setCurserPosition(word.getNext().getEndIndex()); - } - } - else - { - setCurserPosition(word.getEndIndex()); - } - } - else - { - setCurserPosition(getCurserPosition() + 1); - } - return true; - } - else - { - if(!Keyboard.isShiftDown() && hasSelectedText()) - { - setSelectionPosition(-1); - } - return true; - } - } - else if(key == GLFW.GLFW_KEY_END) - { - if(Keyboard.isShiftDown()) - { - if(!hasSelectedText()) - { - setSelectionPosition(getCurserPosition()); - } - } - else - { - setSelectionPosition(-1); - } - setCurserToEnd(); - return true; - } - else if(key == GLFW.GLFW_KEY_HOME) - { - if(Keyboard.isShiftDown()) - { - if(getSelectionPosition() == -1) - { - setSelectionPosition(getCurserPosition()); - } - } - else - { - setSelectionPosition(-1); - } - setCurserPosition(0); - return true; - } - else if(key == GLFW.GLFW_KEY_TAB) - { - writeText(Character.toString('\t')); - return true; - } - else if(isSelect(key)) - { - setSelectionPosition(0); - setCurserToEnd(); - return true; - } - else if(isCopy(key)) - { - if(hasSelectedText()) - { - getWindow().setClipboardString(getSelectedText()); - } - return true; - } - else if(isPaste(key)) - { - String text = getWindow().getClipboardString(); - if(text != null) - { - writeText(text); - } - return true; - } - else if(isCut(key)) - { - if(hasSelectedText()) - { - getWindow().setClipboardString(getSelectedText()); - writeText(""); - } - return true; - } - else if(Keyboard.isPrintableKey(key)) - { - return true; - } - return false; - } - - @Override - public boolean onKeyTyped(char letter, int codepoint) - { - return isFlagSet(FLAG_FOCUS) && text.getFont().isCharValid(codepoint) && writeText(new String(Character.toChars(codepoint))); - } - - public boolean deleteAtCurser(int amount) - { - if(text.length() > 0) - { - if(hasSelectedText()) - { - int startPos = Math.min(getCurserPosition(), getSelectionPosition()); - writeText(""); - setCurserPosition(startPos); - } - else - { - int startPos = Math.min(getCurserPosition(), getCurserPosition() + amount); - int endPos = Math.max(getCurserPosition(), getCurserPosition() + amount); - StringBuilder builder = new StringBuilder(); - if(startPos >= 0) - { - builder.append(text.getText(0, startPos)); - } - if(endPos < text.length()) - { - builder.append(text.getText(endPos)); - } - String s = builder.toString(); - if(validator.test(s)) - { - setText(s); - setCurserPosition(Math.min(startPos, text.length())); - if(isFlagSet(FLAG_AUTO_VALIDATE)) notifyListeners(LISTENER_USER_ACTION); - } - } - return true; - } - return false; - } - - public boolean writeText(String toWrite) - { - toWrite = text.getFont().clearInvalidLetters(toWrite); - StringBuilder builder = new StringBuilder(); - int startPos = hasSelectedText() ? Math.min(getSelectionPosition(), getCurserPosition()) : getCurserPosition(); - int endPos = hasSelectedText() ? Math.max(getSelectionPosition(), getCurserPosition()) : getCurserPosition(); - int room = maxTextLength - text.length() - (startPos - endPos); - if(text.length() > 0) builder.append(text.getText(0, startPos)); - int moved = 0; - if(room < toWrite.length()) - { - builder.append(toWrite.substring(0, room)); - moved = room; - } - else - { - builder.append(toWrite); - moved = toWrite.length(); - } - if(text.length() > 0 && endPos < text.length()) builder.append(text.getText(endPos)); - String s = builder.toString(); - if(validator.test(s)) - { - setText(s); - setCurserPosition(Math.min(endPos + moved, text.length())); - setSelectionPosition(-1); - if(isFlagSet(FLAG_AUTO_VALIDATE)) notifyListeners(LISTENER_USER_ACTION); - return true; - } - return false; - } - - @Override - public void onFocusLost() - { - if(isFlagSet(FLAG_CAN_LOSE_FOCUS)) - { - if(isFlagSet(FLAG_FOCUS)) - { - notifyListeners(LISTENER_USER_ACTION); - } - setFocused(false); - } - } - - protected void handleDoubleClick(int position) - { - Word word = text.getMetadata().getWord(position); - if(word == null) - { - return; - } - if(!word.isSpecial()) - { - setSelectionPosition(word.getStartIndex()); - setCurserPosition(word.getEndIndex()); - return; - } - WordType type = word.getType(); - if(type.isStartWord()) - { - Word other = type.findEndWord(word); - if(other != null) - { - setSelectionPosition(word.getStartIndex()); - setCurserPosition(other.getEndIndex()); - } - } - else if(type.isEndWord()) - { - Word other = type.findStartWord(word); - if(other != null) - { - setSelectionPosition(other.getStartIndex()); - setCurserPosition(word.getEndIndex()); - } - } - else if(type.isDualWord()) - { - if(word.getStartIndex() == position && word.getPrev() != null) - { - Word other = type.findStartWord(word); - if(other != null) - { - setSelectionPosition(other.getStartIndex()); - setCurserPosition(word.getEndIndex()); - } - } - else - { - Word other = type.findEndWord(word); - if(other != null) - { - setSelectionPosition(word.getStartIndex()); - setCurserPosition(other.getEndIndex()); - } - } - } - else - { - setSelectionPosition(word.getStartIndex()); - setCurserPosition(word.getEndIndex()); - } - } - - protected int getMousePosition(int mouseX) - { - return text.getMetadata().getIndex(mouseX - (text.getBox().getMinX()+text.getHorizontal().align(text.getBox().getWidth(), text.getMetadata().getMaxWidth()))); - } - - public void setCurserToEnd() - { - setCurserPosition(text.length()); - } - - public void setCurserPosition(int curserPosition) - { - this.curserPosition = Math.max(0, curserPosition); - if(isFlagSet(FLAG_INFINITE_WIDTH) && text.getFont() != null) - { - int lastLine = lineOffset; - if(lineOffset > text.length()) - { - lineOffset = text.length(); - } - - String s = text.getFont().trimToWidth(text.getText(lineOffset), text.getWidth()); - int k = s.length() + lineOffset; - if(curserPosition > k) - { - lineOffset += curserPosition - k; - direction = true; - largestPos = curserPosition; - } - else if(curserPosition < largestPos) - { - int diff = largestPos - curserPosition; - lineOffset -= diff; - largestPos -= diff; - if(lineOffset <= 0) direction = false; - } - lineOffset = MathUtils.clamp(0, text.length(), lineOffset); - if(lastLine != lineOffset) - { - text.onChanged(false); - } - } - } - - public int getCurserPosition() - { - return curserPosition; - } - - public void setSelectionPosition(int selectionPosition) - { - this.selectionPosition = selectionPosition; - } - - public int getSelectionPosition() - { - return selectionPosition; - } - - public boolean hasSelectedText() - { - return selectionPosition != -1; - } - - protected float getOffset() - { - if(direction && text.getFont() != null) - { - return -(text.getMetadata().getWidth(largestPos)) + text.getBox().getWidth() - 1F; - } - return 1F - (text.getMetadata().getWidth(lineOffset)); - } -} +package speiger.src.coreengine.rendering.gui.components; + +import java.util.function.Predicate; + +import org.lwjgl.glfw.GLFW; + +import speiger.src.coreengine.math.MathUtils; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.base.IButtonComponent; +import speiger.src.coreengine.rendering.gui.base.IKeyComponent; +import speiger.src.coreengine.rendering.gui.helper.Align; +import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; +import speiger.src.coreengine.rendering.gui.helper.box.ParentBox; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain.Target; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; +import speiger.src.coreengine.rendering.gui.renderer.lexer.TextMetadata; +import speiger.src.coreengine.rendering.gui.renderer.lexer.Word; +import speiger.src.coreengine.rendering.gui.renderer.lexer.WordType; +import speiger.src.coreengine.rendering.input.Keyboard; +import speiger.src.coreengine.rendering.utils.Cursor; +import speiger.src.coreengine.utils.functions.Functions; + +public class TextFieldComponent extends GuiComponent + implements IButtonComponent, IKeyComponent +{ + public static final int FLAG_FOCUS = 1 << 20; + public static final int FLAG_CAN_LOSE_FOCUS = 1 << 21; + public static final int FLAG_DOUBLE_CLICK = 1 << 22; + public static final int FLAG_INFINITE_WIDTH = 1 << 23; + public static final int FLAG_AUTO_VALIDATE = 1 << 24; + + TextComponent text = new TextComponent().horizontal(Align.LEFT_TOP).singleLine(true).special(false).cast(); + int color; + int curserPosition = 0; + int selectionPosition = 0; + long lastClickTime = 0; + int maxTextLength = 32; + Predicate validator = Functions.getAlwaysTrue(); + int lineOffset = 0; + boolean direction = false; + int largestPos = 0; + IGuiBox viewPort = new ParentBox(1F); + + public TextFieldComponent(int color) + { + this(color, 1F); + } + + public TextFieldComponent(int color, float textScale) + { + super(0F, 0F, 0F, 0F); + setFlag(FLAG_CAN_LOSE_FOCUS); + this.color = color; + } + + public TextFieldComponent(float x, float y, float width, float height, int color) + { + this(x, y, width, height, color, 1F); + } + + public TextFieldComponent(float x, float y, float width, float height, int color, float textScale) + { + super(x, y, width, height); + setFlag(FLAG_CAN_LOSE_FOCUS); + this.color = color; + } + + @Override + public void init() + { + addBox(viewPort); + addChild(text, createConstraints()); + if(text.getText().length() > 0 && isFlagNotSet(FLAG_INFINITE_WIDTH)) + { + String s = text.getText(); + float scale = text.getTextScale(); + float width = text.getBox().getWidth(); + while(text.getFont().width(s) * scale > width && s.length() > 0) + { + s = s.substring(0, s.length() - 1); + } + text.setText(s); + } + } + + private Constrains createConstraints() + { + return isFlagNotSet(FLAG_INFINITE_WIDTH) ? Constrains.parent(1F) : Constrains.dynamic(this::getOffset, Target.X).parent(1F, Target.Y).parent(1F, Target.WIDTH).parent(1F, Target.HEIGHT).build(); + } + + public TextFieldComponent setValidator(Predicate validator) + { + this.validator = validator; + return this; + } + + public TextFieldComponent setMaxTextLength(int charLimit) + { + maxTextLength = charLimit; + return this; + } + + public TextFieldComponent setCanLoseFocus(boolean value) + { + setFlag(FLAG_CAN_LOSE_FOCUS, value); + return this; + } + + public TextFieldComponent setFocused(boolean value) + { + setFlag(FLAG_FOCUS, value); + return this; + } + + public TextFieldComponent setAutoUpdating(boolean value) + { + setFlag(FLAG_AUTO_VALIDATE, value); + return this; + } + + public TextFieldComponent setColor(int color) + { + this.color = color; + return this; + } + + public final TextFieldComponent setInfiniteText(boolean value) + { + if(setFlag(FLAG_INFINITE_WIDTH, value)) + { + text.limit(!value); + if(getGui() != null) + { + addConstrains(text, createConstraints()); + } + } + return this; + } + + public TextComponent getRawText() + { + return text; + } + + public String getText() + { + return text.getText(); + } + + public String getSelectedText() + { + return text.getText(Math.min(getCurserPosition(), getSelectionPosition()), Math.max(getCurserPosition(), getSelectionPosition())); + } + + public TextFieldComponent setText(String s) + { + if(s == null) + { + return this; + } + if(validator.test(s)) + { + if(s.length() > maxTextLength) + { + s = s.substring(0, maxTextLength); + } + if(isFlagNotSet(FLAG_INFINITE_WIDTH) && getGui() != null) + { + float scale = text.getTextScale(); + float width = text.getBox().getWidth(); + while(text.getFont().width(s) * scale > width) + { + s = s.substring(0, s.length() - 1); + } + } + text.setText(s); + } + return this; + } + + @Override + protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) + { + if(text.isTopHovered(mouseX, mouseY)) + { + bindCursor(Cursor.CURSOR_IBEAM); + } + return true; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float brightness = getActiveBrightness(); + UIRenderer render = getRenderer(); + render.setBrightness(brightness * 0.7F).drawQuad(getBox(), color).setBrightness(brightness); + IGuiBox box = text.getBox(); + render.drawQuad(viewPort, 0.001F, color); + if(isFlagSet(FLAG_INFINITE_WIDTH)) + { + enableScissorsBox(getBox().getMinX(1F), getBox().getMinY(1F), getBox().getMaxX(-1F), getBox().getMaxY(-1F)); + } + if(isFlagSet(FLAG_FOCUS) && (getGlobalClock() / 15) % 2L == 0) + { + TextMetadata data = text.getMetadata(); + if(hasSelectedText()) + { + float extra = text.getHorizontal().align(box.getWidth(), data.getMaxWidth()); + render.drawQuad(box.getMinX() + extra + data.getWidth(Math.min(getCurserPosition(), getSelectionPosition())), box.getMinY(), box.getMinX() + extra + data.getWidth(Math.max(getCurserPosition(), getSelectionPosition())), box.getMaxY(), 0.02F, text.getTextColor()); + } + else + { + float width = data.getWidth(curserPosition) + text.getHorizontal().align(box.getWidth(), data.getMaxWidth()); + render.drawQuad(box.getMinX() + width, box.getMinY(), box.getMinX() + width + text.getTextScale(), box.getMaxY(), 0.02F, text.getTextColor()); + } + } + if(isFlagSet(FLAG_INFINITE_WIDTH)) + { + renderChildren(mouseX, mouseY, particalTicks); + disableScissors(); + return false; + } + return true; + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + setFocused(true); + if(hasSelectedText() && isFlagNotSet(FLAG_DOUBLE_CLICK)) + { + setSelectionPosition(-1); + setCurserPosition(getMousePosition(mouseX)); + return true; + } + int pos = getMousePosition(mouseX); + if(pos == getCurserPosition() || isFlagSet(FLAG_DOUBLE_CLICK)) + { + if(System.currentTimeMillis() - lastClickTime < 500L) + { + if(isFlagSet(FLAG_DOUBLE_CLICK)) + { + clearFlag(FLAG_DOUBLE_CLICK); + setSelectionPosition(0); + setCurserPosition(text.length()); + } + else + { + setFlag(FLAG_DOUBLE_CLICK); + handleDoubleClick(pos); + } + } + else + { + clearFlag(FLAG_DOUBLE_CLICK); + } + lastClickTime = System.currentTimeMillis(); + return true; + } + clearFlag(FLAG_DOUBLE_CLICK); + setCurserPosition(pos); + lastClickTime = System.currentTimeMillis(); + return true; + } + + @Override + public boolean onDrag(int mouseX, int mouseY) + { + if(!hasSelectedText()) + { + setSelectionPosition(getCurserPosition()); + } + setCurserPosition(getMousePosition(mouseX)); + return true; + } + + @Override + public boolean isAcceptingInput() + { + return isFlagSet(FLAG_FOCUS); + } + + @Override + public boolean isBlockingMovement() + { + return true; + } + + @Override + public boolean onKeyPressed(int key) + { + if(isFlagNotSet(FLAG_FOCUS)) + { + return false; + } + if(key == GLFW.GLFW_KEY_ENTER) + { + notifyListeners(LISTENER_USER_ACTION); + if(isFlagSet(FLAG_CAN_LOSE_FOCUS)) + { + setFocused(false); + return true; + } + } + if(key == GLFW.GLFW_KEY_BACKSPACE) + { + if(Keyboard.isCtrlDown()) + { + Word word = text.getMetadata().getWord(getCurserPosition()); + if(word == null) + { + return true; + } + if(getCurserPosition() == word.getStartIndex()) + { + if(word.getPrev() != null) + { + deleteAtCurser(word.getPrev().getStartIndex() - word.getStartIndex()); + } + } + else + { + setCurserPosition(word.getStartIndex()); + deleteAtCurser(word.getEndIndex() - word.getStartIndex()); + } + return true; + } + else if(deleteAtCurser(-1)) + { + return true; + } + } + else if(key == GLFW.GLFW_KEY_DELETE) + { + if(Keyboard.isCtrlDown()) + { + Word word = text.getMetadata().getWord(getCurserPosition()); + if(word == null) + { + return true; + } + if(getCurserPosition() == word.getEndIndex()) + { + if(word.getNext() != null) + { + deleteAtCurser(word.getNext().getEndIndex() - word.getEndIndex()); + } + } + else + { + setCurserPosition(word.getStartIndex()); + deleteAtCurser(word.getEndIndex() - word.getStartIndex()); + } + return true; + } + else if(deleteAtCurser(1)) + { + return true; + } + } + else if(key == GLFW.GLFW_KEY_LEFT) + { + if(getCurserPosition() >= 0) + { + if(Keyboard.isShiftDown() && getSelectionPosition() == -1) + { + setSelectionPosition(getCurserPosition()); + } + else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1) + { + setSelectionPosition(-1); + } + if(Keyboard.isCtrlDown()) + { + Word word = text.getMetadata().getWord(getCurserPosition()); + if(word.getStartIndex() == getCurserPosition()) + { + if(word.getPrev() != null) + { + setCurserPosition(word.getPrev().getStartIndex()); + } + } + else + { + setCurserPosition(word.getStartIndex()); + } + } + else + { + setCurserPosition(getCurserPosition() - 1); + } + return true; + } + } + else if(key == GLFW.GLFW_KEY_RIGHT) + { + if(getCurserPosition() < text.length()) + { + if(Keyboard.isShiftDown() && getSelectionPosition() == -1) + { + setSelectionPosition(getCurserPosition()); + } + else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1) + { + setSelectionPosition(-1); + } + if(Keyboard.isCtrlDown()) + { + Word word = text.getMetadata().getWord(getCurserPosition()); + if(word.getEndIndex() == getCurserPosition()) + { + if(word.getNext() != null) + { + setCurserPosition(word.getNext().getEndIndex()); + } + } + else + { + setCurserPosition(word.getEndIndex()); + } + } + else + { + setCurserPosition(getCurserPosition() + 1); + } + return true; + } + else + { + if(!Keyboard.isShiftDown() && hasSelectedText()) + { + setSelectionPosition(-1); + } + return true; + } + } + else if(key == GLFW.GLFW_KEY_END) + { + if(Keyboard.isShiftDown()) + { + if(!hasSelectedText()) + { + setSelectionPosition(getCurserPosition()); + } + } + else + { + setSelectionPosition(-1); + } + setCurserToEnd(); + return true; + } + else if(key == GLFW.GLFW_KEY_HOME) + { + if(Keyboard.isShiftDown()) + { + if(getSelectionPosition() == -1) + { + setSelectionPosition(getCurserPosition()); + } + } + else + { + setSelectionPosition(-1); + } + setCurserPosition(0); + return true; + } + else if(key == GLFW.GLFW_KEY_TAB) + { + writeText(Character.toString('\t')); + return true; + } + else if(isSelect(key)) + { + setSelectionPosition(0); + setCurserToEnd(); + return true; + } + else if(isCopy(key)) + { + if(hasSelectedText()) + { + getWindow().setClipboardString(getSelectedText()); + } + return true; + } + else if(isPaste(key)) + { + String text = getWindow().getClipboardString(); + if(text != null) + { + writeText(text); + } + return true; + } + else if(isCut(key)) + { + if(hasSelectedText()) + { + getWindow().setClipboardString(getSelectedText()); + writeText(""); + } + return true; + } + else if(Keyboard.isPrintableKey(key)) + { + return true; + } + return false; + } + + @Override + public boolean onKeyTyped(char letter, int codepoint) + { + return isFlagSet(FLAG_FOCUS) && text.getFont().isCharValid(codepoint) && writeText(new String(Character.toChars(codepoint))); + } + + public boolean deleteAtCurser(int amount) + { + if(text.length() > 0) + { + if(hasSelectedText()) + { + int startPos = Math.min(getCurserPosition(), getSelectionPosition()); + writeText(""); + setCurserPosition(startPos); + } + else + { + int startPos = Math.min(getCurserPosition(), getCurserPosition() + amount); + int endPos = Math.max(getCurserPosition(), getCurserPosition() + amount); + StringBuilder builder = new StringBuilder(); + if(startPos >= 0) + { + builder.append(text.getText(0, startPos)); + } + if(endPos < text.length()) + { + builder.append(text.getText(endPos)); + } + String s = builder.toString(); + if(validator.test(s)) + { + setText(s); + setCurserPosition(Math.min(startPos, text.length())); + if(isFlagSet(FLAG_AUTO_VALIDATE)) notifyListeners(LISTENER_USER_ACTION); + } + } + return true; + } + return false; + } + + public boolean writeText(String toWrite) + { + toWrite = text.getFont().clearInvalidLetters(toWrite); + StringBuilder builder = new StringBuilder(); + int startPos = hasSelectedText() ? Math.min(getSelectionPosition(), getCurserPosition()) : getCurserPosition(); + int endPos = hasSelectedText() ? Math.max(getSelectionPosition(), getCurserPosition()) : getCurserPosition(); + int room = maxTextLength - text.length() - (startPos - endPos); + if(text.length() > 0) builder.append(text.getText(0, startPos)); + int moved = 0; + if(room < toWrite.length()) + { + builder.append(toWrite.substring(0, room)); + moved = room; + } + else + { + builder.append(toWrite); + moved = toWrite.length(); + } + if(text.length() > 0 && endPos < text.length()) builder.append(text.getText(endPos)); + String s = builder.toString(); + if(validator.test(s)) + { + setText(s); + setCurserPosition(Math.min(endPos + moved, text.length())); + setSelectionPosition(-1); + if(isFlagSet(FLAG_AUTO_VALIDATE)) notifyListeners(LISTENER_USER_ACTION); + return true; + } + return false; + } + + @Override + public void onFocusLost() + { + if(isFlagSet(FLAG_CAN_LOSE_FOCUS)) + { + if(isFlagSet(FLAG_FOCUS)) + { + notifyListeners(LISTENER_USER_ACTION); + } + setFocused(false); + } + } + + protected void handleDoubleClick(int position) + { + Word word = text.getMetadata().getWord(position); + if(word == null) + { + return; + } + if(!word.isSpecial()) + { + setSelectionPosition(word.getStartIndex()); + setCurserPosition(word.getEndIndex()); + return; + } + WordType type = word.getType(); + if(type.isStartWord()) + { + Word other = type.findEndWord(word); + if(other != null) + { + setSelectionPosition(word.getStartIndex()); + setCurserPosition(other.getEndIndex()); + } + } + else if(type.isEndWord()) + { + Word other = type.findStartWord(word); + if(other != null) + { + setSelectionPosition(other.getStartIndex()); + setCurserPosition(word.getEndIndex()); + } + } + else if(type.isDualWord()) + { + if(word.getStartIndex() == position && word.getPrev() != null) + { + Word other = type.findStartWord(word); + if(other != null) + { + setSelectionPosition(other.getStartIndex()); + setCurserPosition(word.getEndIndex()); + } + } + else + { + Word other = type.findEndWord(word); + if(other != null) + { + setSelectionPosition(word.getStartIndex()); + setCurserPosition(other.getEndIndex()); + } + } + } + else + { + setSelectionPosition(word.getStartIndex()); + setCurserPosition(word.getEndIndex()); + } + } + + protected int getMousePosition(int mouseX) + { + return text.getMetadata().getIndex(mouseX - (text.getBox().getMinX()+text.getHorizontal().align(text.getBox().getWidth(), text.getMetadata().getMaxWidth()))); + } + + public void setCurserToEnd() + { + setCurserPosition(text.length()); + } + + public void setCurserPosition(int curserPosition) + { + this.curserPosition = Math.max(0, curserPosition); + if(isFlagSet(FLAG_INFINITE_WIDTH) && text.getFont() != null) + { + int lastLine = lineOffset; + if(lineOffset > text.length()) + { + lineOffset = text.length(); + } + + String s = text.getFont().trimToWidth(text.getText(lineOffset), text.getWidth()); + int k = s.length() + lineOffset; + if(curserPosition > k) + { + lineOffset += curserPosition - k; + direction = true; + largestPos = curserPosition; + } + else if(curserPosition < largestPos) + { + int diff = largestPos - curserPosition; + lineOffset -= diff; + largestPos -= diff; + if(lineOffset <= 0) direction = false; + } + lineOffset = MathUtils.clamp(0, text.length(), lineOffset); + if(lastLine != lineOffset) + { + text.onChanged(false); + } + } + } + + public int getCurserPosition() + { + return curserPosition; + } + + public void setSelectionPosition(int selectionPosition) + { + this.selectionPosition = selectionPosition; + } + + public int getSelectionPosition() + { + return selectionPosition; + } + + public boolean hasSelectedText() + { + return selectionPosition != -1; + } + + protected float getOffset() + { + if(direction && text.getFont() != null) + { + return -(text.getMetadata().getWidth(largestPos)) + text.getBox().getWidth() - 1F; + } + return 1F - (text.getMetadata().getWidth(lineOffset)); + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/TextPanelComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/TextPanelComponent.java index e58269e..08dbd03 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/TextPanelComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/TextPanelComponent.java @@ -1,687 +1,699 @@ -package speiger.src.coreengine.rendering.gui.components; - -import java.util.function.Predicate; - -import org.lwjgl.glfw.GLFW; - -import speiger.src.coreengine.math.vector.ints.Vec2i; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IButtonComponent; -import speiger.src.coreengine.rendering.gui.base.IKeyComponent; -import speiger.src.coreengine.rendering.gui.helper.Align; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; -import speiger.src.coreengine.rendering.gui.renderer.lexer.Line; -import speiger.src.coreengine.rendering.gui.renderer.lexer.TextMetadata; -import speiger.src.coreengine.rendering.gui.renderer.lexer.Word; -import speiger.src.coreengine.rendering.gui.renderer.lexer.WordType; -import speiger.src.coreengine.rendering.input.Keyboard; -import speiger.src.coreengine.rendering.utils.Cursor; -import speiger.src.coreengine.utils.functions.Functions; - -public class TextPanelComponent extends GuiComponent implements IButtonComponent, IKeyComponent -{ - public static final int FLAG_FOCUS = 1024; - public static final int FLAG_CAN_LOSE_FOCUS = 2048; - - TextComponent text = new TextComponent().align(Align.LEFT_TOP, Align.LEFT_TOP).singleLine(true).special(false).cast(); - int color; - int curserPosition = 0; - Vec2i curserPos = Vec2i.mutable(); - int selectionPosition = 0; - Vec2i selectionPos = Vec2i.mutable(); - long lastClickTime = 0; - int maxTextLength = 64; - int clickCount = 0; - Predicate validator = Functions.getAlwaysTrue(); - - public TextPanelComponent(int color) - { - super(0F, 0F, 0F, 0F); - this.color = color; - } - - public TextPanelComponent(float x, float y, float width, float height, int color) - { - super(x, y, width, height); - this.color = color; - } - - @Override - public void init() - { - addChild(text, Constrains.parent(1F)); - } - - public TextPanelComponent setValidator(Predicate validator) - { - this.validator = validator; - return this; - } - - public TextPanelComponent setMaxTextLength(int charLimit) - { - maxTextLength = charLimit; - return this; - } - - public TextPanelComponent setColor(int color) - { - this.color = color; - return this; - } - - public TextComponent getRawText() - { - return text; - } - - public String getText() - { - return text.getText(); - } - - public String getSelectedText() - { - return text.getText(Math.min(getCurserPosition(), getSelectionPosition()), Math.max(getCurserPosition(), getSelectionPosition())); - } - - public TextPanelComponent setText(String s) - { - if(s == null) - { - return this; - } - if(validator.test(s)) - { - if(s.length() > maxTextLength) - { - s = s.substring(0, maxTextLength); - } - float height = text.getBox().getHeight(); - float scale = text.getTextScale(); - while(s.length() > 0 && text.getFont().height(s) * scale > height) - { - s = s.substring(0, s.length() - 1); - } - text.setText(s); - } - return this; - } - - @Override - protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) - { - if(text.isMouseOver(mouseX, mouseY) && !text.isOverChild(mouseX, mouseY)) - { - bindCursor(Cursor.CURSOR_IBEAM); - } - return true; - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float brightness = getActiveBrightness(); - UIRenderer render = getRenderer(); - render.setBrightness(brightness * 0.7F).drawQuad(getBox(), color).setBrightness(brightness); - IGuiBox box = text.getBox(); - render.drawQuad(box, 0.001F, color); - if(isFlagSet(FLAG_FOCUS) && (getGlobalClock() / 15) % 2L == 0) - { - TextMetadata data = text.getMetadata(); - float height = text.getFont().height() * text.getTextScale(); - if(hasSelectedText()) - { - if(selectionPos.getY() == curserPos.getY()) - { - render.drawQuad(box.getMinX() + data.getWidth(Math.min(curserPos.getX(), selectionPos.getX()), curserPos.getY()), box.getMinY() + (height * curserPos.getY()), box.getMinX() + data.getWidth(Math.max(curserPos.getX(), selectionPos.getX()), curserPos.getY()), box.getMinY() + (height * (curserPos.getY()+1)), 0.02F, text.getTextColor()); - } - else - { - Vec2i min = selectionPos.getY() < curserPos.getY() ? selectionPos : curserPos; - Vec2i max = selectionPos.getY() > curserPos.getY() ? selectionPos : curserPos; - for(int i = min.getY(),m=max.getY();i<=m;i++) - { - if(i == min.getY()) - { - render.drawQuad(box.getMinX() + data.getWidth(min.getX()), box.getMinY() + (height * i), box.getMinX() + data.getLineWidth(i), box.getMinY() + (height * (i+1)), 0.02F, text.getTextColor()); - } - else if(i == max.getY()) - { - render.drawQuad(box.getMinX(), box.getMinY() + (height * i), box.getMinX() + data.getWidth(max.getX()), box.getMinY() + (height * (i+1)), 0.02F, text.getTextColor()); - } - else - { - render.drawQuad(box.getMinX(), box.getMinY() + (height * i), box.getMinX() + data.getLineWidth(i), box.getMinY() + (height * (i+1)), 0.02F, text.getTextColor()); - } - } - } - return true; - } - float width = data.getWidth(curserPos.getX(), curserPos.getY()); - render.drawQuad(box.getMinX()+width, box.getMinY() + (height * curserPos.getY()), box.getMinX()+width+text.getTextScale(), box.getMinY() + (height * (curserPos.getY()+1)), 0.02F, text.getTextColor()); - } - return true; - } - - @Override - public boolean onClick(int button, int mouseX, int mouseY) - { - setFlag(FLAG_FOCUS); - if(hasSelectedText() && clickCount <= 0) - { - setSelectionPosition(-1); - setCurserPosition(getMousePosition(mouseX, mouseY)); - return true; - } - int pos = getMousePosition(mouseX, mouseY); - if(pos == getCurserPosition()) - { - if(System.currentTimeMillis() - lastClickTime < 500L) - { - if(clickCount == 1) - { - Line line = text.getMetadata().getLine(curserPos.getY()); - setSelectionPosition(line.getStart()); - setCurserPosition(line.getEnd()); - clickCount = 2; - } - else if(clickCount == 2) - { - clickCount = 3; - setSelectionPosition(0); - setCurserToEnd(); - } - else - { - clickCount = 1; - handleDoubleClick(pos); - } - } - else - { - clickCount = 0; - } - lastClickTime = System.currentTimeMillis(); - return true; - } - lastClickTime = System.currentTimeMillis(); - setCurserPosition(pos); - setSelectionPosition(-1); - clickCount = 0; - return false; - } - - @Override - public boolean onDrag(int mouseX, int mouseY) - { - if(!hasSelectedText()) - { - setSelectionPosition(getCurserPosition()); - } - setCurserPosition(getMousePosition(mouseX, mouseY)); - return true; - } - - @Override - public void onFocusLost() - { - clearFlag(FLAG_FOCUS); - } - - @Override - public boolean isAcceptingInput() - { - return isFlagSet(FLAG_FOCUS); - } - - @Override - public boolean isBlockingMovement() - { - return true; - } - - @Override - public boolean onKeyPressed(int key) - { - if(isFlagNotSet(FLAG_FOCUS)) - { - return false; - } - if(key == GLFW.GLFW_KEY_BACKSPACE) - { - if(Keyboard.isCtrlDown()) - { - Word word = text.getMetadata().getWord(getCurserPosition()); - if(word == null) - { - return true; - } - if(getCurserPosition() == word.getStartIndex()) - { - if(word.getPrev() != null) - { - deleteAtCurser(word.getPrev().getStartIndex() - word.getStartIndex()); - } - } - else - { - setCurserPosition(word.getStartIndex()); - deleteAtCurser(word.getEndIndex() - word.getStartIndex()); - } - return true; - } - else if(deleteAtCurser(-1)) - { - return true; - } - } - else if(key == GLFW.GLFW_KEY_DELETE) - { - if(Keyboard.isCtrlDown()) - { - Word word = text.getMetadata().getWord(getCurserPosition()); - if(word == null) - { - return true; - } - if(getCurserPosition() == word.getEndIndex()) - { - if(word.getNext() != null) - { - deleteAtCurser(word.getNext().getEndIndex() - word.getEndIndex()); - } - } - else - { - setCurserPosition(word.getStartIndex()); - deleteAtCurser(word.getEndIndex() - word.getStartIndex()); - } - return true; - } - else if(deleteAtCurser(1)) - { - return true; - } - } - else if(key == GLFW.GLFW_KEY_LEFT) - { - if(getCurserPosition() >= 0) - { - if(Keyboard.isShiftDown() && getSelectionPosition() == -1) - { - setSelectionPosition(getCurserPosition()); - } - else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1) - { - setSelectionPosition(-1); - } - if(Keyboard.isCtrlDown()) - { - Word word = text.getMetadata().getWord(getCurserPosition()); - if(word == null) - { - return true; - } - if(word.getStartIndex() == getCurserPosition()) - { - if(word.getPrev() != null) - { - setCurserPosition(word.getPrev().getStartIndex()); - } - } - else - { - setCurserPosition(word.getStartIndex()); - } - } - else - { - setCurserPosition(getCurserPosition()-1); - } - return true; - } - } - else if(key == GLFW.GLFW_KEY_RIGHT) - { - if(getCurserPosition() < text.length()) - { - if(Keyboard.isShiftDown() && getSelectionPosition() == -1) - { - setSelectionPosition(getCurserPosition()); - } - else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1) - { - setSelectionPosition(-1); - } - if(Keyboard.isCtrlDown()) - { - Word word = text.getMetadata().getWord(getCurserPosition()); - if(word == null) - { - return true; - } - if(word.getEndIndex() == getCurserPosition()) - { - if(word.getNext() != null) - { - setCurserPosition(word.getNext().getEndIndex()); - } - } - else - { - setCurserPosition(word.getEndIndex()); - } - } - else - { - setCurserPosition(getCurserPosition()+1); - } - return true; - } - else - { - if(!Keyboard.isShiftDown() && hasSelectedText()) - { - setSelectionPosition(-1); - } - return true; - } - } - else if(key == GLFW.GLFW_KEY_UP) - { - if(Keyboard.isShiftDown() && !hasSelectedText()) - { - setSelectionPosition(getCurserPosition()); - } - else if(!Keyboard.isShiftDown() && hasSelectedText()) - { - setSelectionPosition(-1); - } - setCurserPosition(text.getMetadata().moveDown(curserPos)); - } - else if(key == GLFW.GLFW_KEY_DOWN) - { - if(Keyboard.isShiftDown() && !hasSelectedText()) - { - setSelectionPosition(getCurserPosition()); - } - else if(!Keyboard.isShiftDown() && hasSelectedText()) - { - setSelectionPosition(-1); - } - setCurserPosition(text.getMetadata().moveUp(curserPos)); - } - else if(key == GLFW.GLFW_KEY_END) - { - if(Keyboard.isShiftDown()) - { - if(!hasSelectedText()) - { - setSelectionPosition(getCurserPosition()); - } - } - else - { - setSelectionPosition(-1); - } - setCurserToEnd(); - return true; - } - else if(key == GLFW.GLFW_KEY_HOME) - { - if(Keyboard.isShiftDown()) - { - if(getSelectionPosition() == -1) - { - setSelectionPosition(getCurserPosition()); - } - } - else - { - setSelectionPosition(-1); - } - setCurserPosition(0); - return true; - } - else if(key == GLFW.GLFW_KEY_TAB) - { - writeText(Character.toString('\t')); - return true; - } - else if(key == GLFW.GLFW_KEY_ENTER) - { - writeText(Character.toString('\n')); - return true; - } - else if(isSelect(key)) - { - setSelectionPosition(0); - setCurserToEnd(); - return true; - } - else if(isCopy(key)) - { - if(hasSelectedText()) - { - getWindow().setClipboardString(getSelectedText()); - } - return true; - } - else if(isPaste(key)) - { - String text = getWindow().getClipboardString(); - if(text != null) - { - writeText(text); - } - return true; - } - else if(isCut(key)) - { - if(hasSelectedText()) - { - getWindow().setClipboardString(getSelectedText()); - writeText(""); - } - return true; - } - else if(Keyboard.isPrintableKey(key)) - { - return true; - } - return false; - } - - @Override - public boolean onKeyTyped(char letter, int codepoint) - { - return isFlagSet(FLAG_FOCUS) && text.getFont().isCharValid(codepoint) && writeText(new String(Character.toChars(codepoint))); - } - - public boolean deleteAtCurser(int amount) - { - if(text.length() > 0) - { - if(hasSelectedText()) - { - int startPos = Math.min(getCurserPosition(), getSelectionPosition()); - writeText(""); - setCurserPosition(startPos); - } - else - { - int startPos = Math.min(getCurserPosition(), getCurserPosition() + amount); - int endPos = Math.max(getCurserPosition(), getCurserPosition() + amount); - StringBuilder builder = new StringBuilder(); - if(startPos >= 0) - { - builder.append(text.getText(0, startPos)); - } - if(endPos < text.length()) - { - builder.append(text.getText(endPos)); - } - String s = builder.toString(); - if (validator.test(s)) - { - setText(s); - setCurserPosition(Math.min(startPos, text.length())); - notifyListeners(LISTENER_USER_ACTION); - } - } - return true; - } - return false; - } - - public boolean writeText(String toWrite) - { - toWrite = text.getFont().clearInvalidLetters(toWrite); - StringBuilder builder = new StringBuilder(); - int startPos = hasSelectedText() ? Math.min(getSelectionPosition(), getCurserPosition()) : getCurserPosition(); - int endPos = hasSelectedText() ? Math.max(getSelectionPosition(), getCurserPosition()) : getCurserPosition(); - int room = maxTextLength - text.length() - (startPos - endPos); - if(text.length() > 0) - { - builder.append(text.getText(0, startPos)); - } - int moved = 0; - if(room < toWrite.length()) - { - builder.append(toWrite.substring(0, room)); - moved = room; - } - else - { - builder.append(toWrite); - moved = toWrite.length(); - } - if(text.length() > 0 && endPos < text.length()) - { - builder.append(text.getText(endPos)); - } - String s = builder.toString(); - if(validator.test(s)) - { - setText(s); - setCurserPosition(Math.min(endPos + moved, text.length())); - setSelectionPosition(-1); - notifyListeners(LISTENER_USER_ACTION); - return true; - } - return false; - } - - protected void handleDoubleClick(int position) - { - Word word = text.getMetadata().getWord(position); - if(word == null) - { - return; - } - if(!word.isSpecial()) - { - setSelectionPosition(word.getStartIndex()); - setCurserPosition(word.getEndIndex()); - return; - } - WordType type = word.getType(); - if(type.isStartWord()) - { - Word other = type.findEndWord(word); - if(other != null) - { - setSelectionPosition(word.getStartIndex()); - setCurserPosition(other.getEndIndex()); - } - } - else if(type.isEndWord()) - { - Word other = type.findStartWord(word); - if(other != null) - { - setSelectionPosition(other.getStartIndex()); - setCurserPosition(word.getEndIndex()); - } - } - else if(type.isDualWord()) - { - if(word.getStartIndex() == position && word.getPrev() != null) - { - Word other = type.findStartWord(word); - if(other != null) - { - setSelectionPosition(other.getStartIndex()); - setCurserPosition(word.getEndIndex()); - } - } - else - { - Word other = type.findEndWord(word); - if(other != null) - { - setSelectionPosition(word.getStartIndex()); - setCurserPosition(other.getEndIndex()); - } - } - } - else - { - setSelectionPosition(word.getStartIndex()); - setCurserPosition(word.getEndIndex()); - } - } - - public int getMousePosition(int mouseX, int mouseY) - { - return text.getMetadata().getIndex(mouseX - text.getBox().getMinX(), mouseY - text.getBox().getMinY()); - } - - public void setCurserToEnd() - { - setCurserPosition(curserPosition); - } - - public void setCurserPosition(int curserPosition) - { - if(this.curserPosition == curserPosition) - { - return; - } - this.curserPosition = curserPosition; - text.getMetadata().convert(curserPosition, curserPos); - } - - public int getCurserPosition() - { - return curserPosition; - } - - public void setSelectionPosition(int selectionPosition) - { - if(this.selectionPosition == selectionPosition) - { - return; - } - this.selectionPosition = selectionPosition; - if(selectionPosition == -1) - { - selectionPos.set(Vec2i.MINUS_ONE); - return; - } - text.getMetadata().convert(selectionPosition, selectionPos); - } - - public int getSelectionPosition() - { - return selectionPosition; - } - - public boolean hasSelectedText() - { - return selectionPosition != -1; - } -} +package speiger.src.coreengine.rendering.gui.components; + +import java.util.function.Predicate; + +import org.lwjgl.glfw.GLFW; + +import speiger.src.coreengine.math.vector.ints.Vec2i; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.base.IButtonComponent; +import speiger.src.coreengine.rendering.gui.base.IKeyComponent; +import speiger.src.coreengine.rendering.gui.helper.Align; +import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; +import speiger.src.coreengine.rendering.gui.renderer.lexer.Line; +import speiger.src.coreengine.rendering.gui.renderer.lexer.TextMetadata; +import speiger.src.coreengine.rendering.gui.renderer.lexer.Word; +import speiger.src.coreengine.rendering.gui.renderer.lexer.WordType; +import speiger.src.coreengine.rendering.input.Keyboard; +import speiger.src.coreengine.rendering.utils.Cursor; +import speiger.src.coreengine.utils.functions.Functions; + +public class TextPanelComponent extends GuiComponent implements IButtonComponent, IKeyComponent +{ + public static final int FLAG_FOCUS = 1 << 20; + public static final int FLAG_CAN_LOSE_FOCUS = 1 << 21; + + TextComponent text = new TextComponent().align(Align.LEFT_TOP, Align.LEFT_TOP).singleLine(true).special(false).cast(); + int color; + int curserPosition = 0; + Vec2i curserPos = Vec2i.mutable(); + int selectionPosition = 0; + Vec2i selectionPos = Vec2i.mutable(); + long lastClickTime = 0; + int maxTextLength = 64; + int clickCount = 0; + Predicate validator = Functions.getAlwaysTrue(); + + public TextPanelComponent(int color) + { + this(color, 1F); + } + + public TextPanelComponent(int color, float textScale) + { + super(0F, 0F, 0F, 0F); + this.color = color; + text.setTextScale(textScale); + } + + public TextPanelComponent(float x, float y, float width, float height, int color) + { + this(x, y, width, height, color, 1F); + } + + public TextPanelComponent(float x, float y, float width, float height, int color, float textScale) + { + super(x, y, width, height); + this.color = color; + text.setTextScale(textScale); + } + + @Override + public void init() + { + addChild(text, Constrains.parent(1F)); + } + + public TextPanelComponent setValidator(Predicate validator) + { + this.validator = validator; + return this; + } + + public TextPanelComponent setMaxTextLength(int charLimit) + { + maxTextLength = charLimit; + return this; + } + + public TextPanelComponent setColor(int color) + { + this.color = color; + return this; + } + + public TextComponent getRawText() + { + return text; + } + + public String getText() + { + return text.getText(); + } + + public String getSelectedText() + { + return text.getText(Math.min(getCurserPosition(), getSelectionPosition()), Math.max(getCurserPosition(), getSelectionPosition())); + } + + public TextPanelComponent setText(String s) + { + if(s == null) + { + return this; + } + if(validator.test(s)) + { + if(s.length() > maxTextLength) + { + s = s.substring(0, maxTextLength); + } + float height = text.getBox().getHeight(); + float scale = text.getTextScale(); + while(s.length() > 0 && text.getFont().height(s) * scale > height) + { + s = s.substring(0, s.length() - 1); + } + text.setText(s); + } + return this; + } + + @Override + protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) + { + if(text.isMouseOver(mouseX, mouseY) && !text.isOverChild(mouseX, mouseY)) + { + bindCursor(Cursor.CURSOR_IBEAM); + } + return true; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float brightness = getActiveBrightness(); + UIRenderer render = getRenderer(); + render.setBrightness(brightness * 0.7F).drawQuad(getBox(), color).setBrightness(brightness); + IGuiBox box = text.getBox(); + render.drawQuad(box, 0.001F, color); + if(isFlagSet(FLAG_FOCUS) && (getGlobalClock() / 15) % 2L == 0) + { + TextMetadata data = text.getMetadata(); + float height = text.getFont().height() * text.getTextScale(); + if(hasSelectedText()) + { + if(selectionPos.getY() == curserPos.getY()) + { + render.drawQuad(box.getMinX() + data.getWidth(Math.min(curserPos.getX(), selectionPos.getX()), curserPos.getY()), box.getMinY() + (height * curserPos.getY()), box.getMinX() + data.getWidth(Math.max(curserPos.getX(), selectionPos.getX()), curserPos.getY()), box.getMinY() + (height * (curserPos.getY()+1)), 0.02F, text.getTextColor()); + } + else + { + Vec2i min = selectionPos.getY() < curserPos.getY() ? selectionPos : curserPos; + Vec2i max = selectionPos.getY() > curserPos.getY() ? selectionPos : curserPos; + for(int i = min.getY(),m=max.getY();i<=m;i++) + { + if(i == min.getY()) + { + render.drawQuad(box.getMinX() + data.getWidth(min.getX()), box.getMinY() + (height * i), box.getMinX() + data.getLineWidth(i), box.getMinY() + (height * (i+1)), 0.02F, text.getTextColor()); + } + else if(i == max.getY()) + { + render.drawQuad(box.getMinX(), box.getMinY() + (height * i), box.getMinX() + data.getWidth(max.getX()), box.getMinY() + (height * (i+1)), 0.02F, text.getTextColor()); + } + else + { + render.drawQuad(box.getMinX(), box.getMinY() + (height * i), box.getMinX() + data.getLineWidth(i), box.getMinY() + (height * (i+1)), 0.02F, text.getTextColor()); + } + } + } + return true; + } + float width = data.getWidth(curserPos.getX(), curserPos.getY()); + render.drawQuad(box.getMinX()+width, box.getMinY() + (height * curserPos.getY()), box.getMinX()+width+text.getTextScale(), box.getMinY() + (height * (curserPos.getY()+1)), 0.02F, text.getTextColor()); + } + return true; + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + setFlag(FLAG_FOCUS); + if(hasSelectedText() && clickCount <= 0) + { + setSelectionPosition(-1); + setCurserPosition(getMousePosition(mouseX, mouseY)); + return true; + } + int pos = getMousePosition(mouseX, mouseY); + if(pos == getCurserPosition()) + { + if(System.currentTimeMillis() - lastClickTime < 500L) + { + if(clickCount == 1) + { + Line line = text.getMetadata().getLine(curserPos.getY()); + setSelectionPosition(line.getStart()); + setCurserPosition(line.getEnd()); + clickCount = 2; + } + else if(clickCount == 2) + { + clickCount = 3; + setSelectionPosition(0); + setCurserToEnd(); + } + else + { + clickCount = 1; + handleDoubleClick(pos); + } + } + else + { + clickCount = 0; + } + lastClickTime = System.currentTimeMillis(); + return true; + } + lastClickTime = System.currentTimeMillis(); + setCurserPosition(pos); + setSelectionPosition(-1); + clickCount = 0; + return false; + } + + @Override + public boolean onDrag(int mouseX, int mouseY) + { + if(!hasSelectedText()) + { + setSelectionPosition(getCurserPosition()); + } + setCurserPosition(getMousePosition(mouseX, mouseY)); + return true; + } + + @Override + public void onFocusLost() + { + clearFlag(FLAG_FOCUS); + } + + @Override + public boolean isAcceptingInput() + { + return isFlagSet(FLAG_FOCUS); + } + + @Override + public boolean isBlockingMovement() + { + return true; + } + + @Override + public boolean onKeyPressed(int key) + { + if(isFlagNotSet(FLAG_FOCUS)) + { + return false; + } + if(key == GLFW.GLFW_KEY_BACKSPACE) + { + if(Keyboard.isCtrlDown()) + { + Word word = text.getMetadata().getWord(getCurserPosition()); + if(word == null) + { + return true; + } + if(getCurserPosition() == word.getStartIndex()) + { + if(word.getPrev() != null) + { + deleteAtCurser(word.getPrev().getStartIndex() - word.getStartIndex()); + } + } + else + { + setCurserPosition(word.getStartIndex()); + deleteAtCurser(word.getEndIndex() - word.getStartIndex()); + } + return true; + } + else if(deleteAtCurser(-1)) + { + return true; + } + } + else if(key == GLFW.GLFW_KEY_DELETE) + { + if(Keyboard.isCtrlDown()) + { + Word word = text.getMetadata().getWord(getCurserPosition()); + if(word == null) + { + return true; + } + if(getCurserPosition() == word.getEndIndex()) + { + if(word.getNext() != null) + { + deleteAtCurser(word.getNext().getEndIndex() - word.getEndIndex()); + } + } + else + { + setCurserPosition(word.getStartIndex()); + deleteAtCurser(word.getEndIndex() - word.getStartIndex()); + } + return true; + } + else if(deleteAtCurser(1)) + { + return true; + } + } + else if(key == GLFW.GLFW_KEY_LEFT) + { + if(getCurserPosition() >= 0) + { + if(Keyboard.isShiftDown() && getSelectionPosition() == -1) + { + setSelectionPosition(getCurserPosition()); + } + else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1) + { + setSelectionPosition(-1); + } + if(Keyboard.isCtrlDown()) + { + Word word = text.getMetadata().getWord(getCurserPosition()); + if(word == null) + { + return true; + } + if(word.getStartIndex() == getCurserPosition()) + { + if(word.getPrev() != null) + { + setCurserPosition(word.getPrev().getStartIndex()); + } + } + else + { + setCurserPosition(word.getStartIndex()); + } + } + else + { + setCurserPosition(getCurserPosition()-1); + } + return true; + } + } + else if(key == GLFW.GLFW_KEY_RIGHT) + { + if(getCurserPosition() < text.length()) + { + if(Keyboard.isShiftDown() && getSelectionPosition() == -1) + { + setSelectionPosition(getCurserPosition()); + } + else if(!Keyboard.isShiftDown() && getSelectionPosition() != -1) + { + setSelectionPosition(-1); + } + if(Keyboard.isCtrlDown()) + { + Word word = text.getMetadata().getWord(getCurserPosition()); + if(word == null) + { + return true; + } + if(word.getEndIndex() == getCurserPosition()) + { + if(word.getNext() != null) + { + setCurserPosition(word.getNext().getEndIndex()); + } + } + else + { + setCurserPosition(word.getEndIndex()); + } + } + else + { + setCurserPosition(getCurserPosition()+1); + } + return true; + } + else + { + if(!Keyboard.isShiftDown() && hasSelectedText()) + { + setSelectionPosition(-1); + } + return true; + } + } + else if(key == GLFW.GLFW_KEY_UP) + { + if(Keyboard.isShiftDown() && !hasSelectedText()) + { + setSelectionPosition(getCurserPosition()); + } + else if(!Keyboard.isShiftDown() && hasSelectedText()) + { + setSelectionPosition(-1); + } + setCurserPosition(text.getMetadata().moveDown(curserPos)); + } + else if(key == GLFW.GLFW_KEY_DOWN) + { + if(Keyboard.isShiftDown() && !hasSelectedText()) + { + setSelectionPosition(getCurserPosition()); + } + else if(!Keyboard.isShiftDown() && hasSelectedText()) + { + setSelectionPosition(-1); + } + setCurserPosition(text.getMetadata().moveUp(curserPos)); + } + else if(key == GLFW.GLFW_KEY_END) + { + if(Keyboard.isShiftDown()) + { + if(!hasSelectedText()) + { + setSelectionPosition(getCurserPosition()); + } + } + else + { + setSelectionPosition(-1); + } + setCurserToEnd(); + return true; + } + else if(key == GLFW.GLFW_KEY_HOME) + { + if(Keyboard.isShiftDown()) + { + if(getSelectionPosition() == -1) + { + setSelectionPosition(getCurserPosition()); + } + } + else + { + setSelectionPosition(-1); + } + setCurserPosition(0); + return true; + } + else if(key == GLFW.GLFW_KEY_TAB) + { + writeText(Character.toString('\t')); + return true; + } + else if(key == GLFW.GLFW_KEY_ENTER) + { + writeText(Character.toString('\n')); + return true; + } + else if(isSelect(key)) + { + setSelectionPosition(0); + setCurserToEnd(); + return true; + } + else if(isCopy(key)) + { + if(hasSelectedText()) + { + getWindow().setClipboardString(getSelectedText()); + } + return true; + } + else if(isPaste(key)) + { + String text = getWindow().getClipboardString(); + if(text != null) + { + writeText(text); + } + return true; + } + else if(isCut(key)) + { + if(hasSelectedText()) + { + getWindow().setClipboardString(getSelectedText()); + writeText(""); + } + return true; + } + else if(Keyboard.isPrintableKey(key)) + { + return true; + } + return false; + } + + @Override + public boolean onKeyTyped(char letter, int codepoint) + { + return isFlagSet(FLAG_FOCUS) && text.getFont().isCharValid(codepoint) && writeText(new String(Character.toChars(codepoint))); + } + + public boolean deleteAtCurser(int amount) + { + if(text.length() > 0) + { + if(hasSelectedText()) + { + int startPos = Math.min(getCurserPosition(), getSelectionPosition()); + writeText(""); + setCurserPosition(startPos); + } + else + { + int startPos = Math.min(getCurserPosition(), getCurserPosition() + amount); + int endPos = Math.max(getCurserPosition(), getCurserPosition() + amount); + StringBuilder builder = new StringBuilder(); + if(startPos >= 0) + { + builder.append(text.getText(0, startPos)); + } + if(endPos < text.length()) + { + builder.append(text.getText(endPos)); + } + String s = builder.toString(); + if (validator.test(s)) + { + setText(s); + setCurserPosition(Math.min(startPos, text.length())); + notifyListeners(LISTENER_USER_ACTION); + } + } + return true; + } + return false; + } + + public boolean writeText(String toWrite) + { + toWrite = text.getFont().clearInvalidLetters(toWrite); + StringBuilder builder = new StringBuilder(); + int startPos = hasSelectedText() ? Math.min(getSelectionPosition(), getCurserPosition()) : getCurserPosition(); + int endPos = hasSelectedText() ? Math.max(getSelectionPosition(), getCurserPosition()) : getCurserPosition(); + int room = maxTextLength - text.length() - (startPos - endPos); + if(text.length() > 0) + { + builder.append(text.getText(0, startPos)); + } + int moved = 0; + if(room < toWrite.length()) + { + builder.append(toWrite.substring(0, room)); + moved = room; + } + else + { + builder.append(toWrite); + moved = toWrite.length(); + } + if(text.length() > 0 && endPos < text.length()) + { + builder.append(text.getText(endPos)); + } + String s = builder.toString(); + if(validator.test(s)) + { + setText(s); + setCurserPosition(Math.min(endPos + moved, text.length())); + setSelectionPosition(-1); + notifyListeners(LISTENER_USER_ACTION); + return true; + } + return false; + } + + protected void handleDoubleClick(int position) + { + Word word = text.getMetadata().getWord(position); + if(word == null) + { + return; + } + if(!word.isSpecial()) + { + setSelectionPosition(word.getStartIndex()); + setCurserPosition(word.getEndIndex()); + return; + } + WordType type = word.getType(); + if(type.isStartWord()) + { + Word other = type.findEndWord(word); + if(other != null) + { + setSelectionPosition(word.getStartIndex()); + setCurserPosition(other.getEndIndex()); + } + } + else if(type.isEndWord()) + { + Word other = type.findStartWord(word); + if(other != null) + { + setSelectionPosition(other.getStartIndex()); + setCurserPosition(word.getEndIndex()); + } + } + else if(type.isDualWord()) + { + if(word.getStartIndex() == position && word.getPrev() != null) + { + Word other = type.findStartWord(word); + if(other != null) + { + setSelectionPosition(other.getStartIndex()); + setCurserPosition(word.getEndIndex()); + } + } + else + { + Word other = type.findEndWord(word); + if(other != null) + { + setSelectionPosition(word.getStartIndex()); + setCurserPosition(other.getEndIndex()); + } + } + } + else + { + setSelectionPosition(word.getStartIndex()); + setCurserPosition(word.getEndIndex()); + } + } + + public int getMousePosition(int mouseX, int mouseY) + { + return text.getMetadata().getIndex(mouseX - text.getBox().getMinX(), mouseY - text.getBox().getMinY()); + } + + public void setCurserToEnd() + { + setCurserPosition(curserPosition); + } + + public void setCurserPosition(int curserPosition) + { + if(this.curserPosition == curserPosition) + { + return; + } + this.curserPosition = curserPosition; + text.getMetadata().convert(curserPosition, curserPos); + } + + public int getCurserPosition() + { + return curserPosition; + } + + public void setSelectionPosition(int selectionPosition) + { + if(this.selectionPosition == selectionPosition) + { + return; + } + this.selectionPosition = selectionPosition; + if(selectionPosition == -1) + { + selectionPos.set(Vec2i.MINUS_ONE); + return; + } + text.getMetadata().convert(selectionPosition, selectionPos); + } + + public int getSelectionPosition() + { + return selectionPosition; + } + + public boolean hasSelectedText() + { + return selectionPosition != -1; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/TreeComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/TreeComponent.java index 95b320f..f36b62c 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/TreeComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/TreeComponent.java @@ -1,697 +1,697 @@ -package speiger.src.coreengine.rendering.gui.components; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.collections.objects.sets.ObjectOpenHashSet; -import speiger.src.collections.objects.sets.ObjectSet; -import speiger.src.coreengine.math.MathUtils; -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.math.misc.Facing; -import speiger.src.coreengine.math.vector.ints.Vec2i; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IButtonComponent; -import speiger.src.coreengine.rendering.gui.components.tree.ITreeEntry; -import speiger.src.coreengine.rendering.gui.helper.UIShapes; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.renderer.UIRenderer; -import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; -import speiger.src.coreengine.rendering.input.Keyboard; - -public class TreeComponent extends GuiComponent implements IButtonComponent -{ - public static final int SELECTION_MODE_DISABLE = 0; - public static final int SELECTION_MODE_SINGLE = 1; - public static final int SELECTION_MODE_MULTI = 2; - public static final int SELECTION_MODE_INTERACT = 3; - - public static final int UPDATE_MODE_DISABLED = 0; - public static final int UPDATE_MODE_VISIBLE = 1; - public static final int UPDATE_MODE_OPEN = 2; - public static final int UPDATE_MODE_ALL = 3; - - public static final int FLAG_NO_BACKGROUND = 1 << 20; - - ScrollBarComponent verticalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY); - ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY).setHorizontal(true); - - int color; - int selectedColor; - int hoverColor = ColorUtils.LIGHT_GRAY; - int hoverIndex = -1; - int dragIndex = -1; - int movement; - Vec2i lastMouse = Vec2i.mutable(); - IButtonComponent customButton; - protected ObjectSet openNodes = new ObjectOpenHashSet<>(); - protected ObjectSet selectedNodes = new ObjectOpenHashSet<>(); - protected int selectionMode = 1; - protected int updateMode = 1; - T node; - float entryHeight; - - boolean listChange = true; - List visibleNodes = new ObjectArrayList(); - RenderBuffer buffer; - - public TreeComponent(int color, float entryHeight) - { - super(0F, 0F, 0F, 0F); - this.entryHeight = entryHeight; - this.color = color; - this.selectedColor = color; - } - - public TreeComponent(int color, float entryHeight, T entry) - { - super(0F, 0F, 0F, 0F); - this.entryHeight = entryHeight; - getNodes(entry, openNodes, false); - this.color = color; - this.selectedColor = color; - node = entry; - if(entry != null) - { - entry.calculateDebth(); - } - } - - public TreeComponent(float x, float y, float width, float height, int color, float entryHeight, T entry) - { - super(x, y, width, height); - this.entryHeight = entryHeight; - getNodes(entry, openNodes, false); - this.color = color; - node = entry; - if(entry != null) - { - entry.calculateDebth(); - } - } - - @Override - public void init() - { - addCloseListener(buffer = getRenderer().createBuffer()); - addChild(horizontalBar, Constrains.scrollBar(verticalBar::isInUse, true, 5F)); - addChild(verticalBar, Constrains.scrollBar(horizontalBar::isInUse, false, 5F)); - List entries = new ObjectArrayList(); - getNodes(node, entries, false); - for(int i = 0, m = entries.size();i < m;i++) - { - entries.get(i).init(this, getGui()); - } - updateScrollBar(); - createArrow(); - } - - public TreeComponent setColor(int color) - { - if(this.color != color) - { - this.color = color; - onChanged(true); - } - return this; - } - - public TreeComponent setHoverColor(int color) - { - hoverColor = color; - return this; - } - - public TreeComponent setSelectionColor(int color) - { - selectedColor = color; - return this; - } - - public TreeComponent setEntryHeight(float entryHeight) - { - if(this.entryHeight != entryHeight) - { - this.entryHeight = entryHeight; - onChanged(true); - } - return this; - } - - public TreeComponent setSelectionMode(int mode) - { - if(mode < 0 || mode > 3) - { - throw new IllegalStateException("Unknown Mode"); - } - this.selectionMode = mode; - selectedNodes.clear(); - return this; - } - - public TreeComponent setUpdateMode(int mode) - { - if(mode < 0 || mode > 3) - { - throw new IllegalStateException("Unknown Mode"); - } - updateMode = mode; - return this; - } - - public TreeComponent disableBackground(boolean value) - { - setFlag(FLAG_NO_BACKGROUND, value); - return this; - } - - @Override - protected void repaint() - { - float scale = getBox().getScale(); - List entries = new ObjectArrayList(); - getNodes(node, entries, false); - for(int i = 0,m=entries.size();i setTree(T entry) - { - if(node == entry) - { - return this; - } - node = entry; - if(entry != null) - { - entry.calculateDebth(); - if(getGui() != null) - { - List entries = new ObjectArrayList(); - getNodes(entry, entries, false); - for(int i = 0,m=entries.size();i entries = new ObjectArrayList(); - getNodes(node, entries, false); - for(int i = 0,m=entries.size();i 0; - } - - public T getSelectedNode() - { - return selectedNodes.isEmpty() ? null : selectedNodes.iterator().next(); - } - - public List getSelectedNodes() - { - return new ObjectArrayList(this.selectedNodes); - } - - public List getOpenNodes() - { - return new ObjectArrayList(this.visibleNodes); - } - - public List getAllNodes() - { - List list = new ObjectArrayList(); - getNodes(node, list, false); - return list; - } - - public void openAll() - { - if(node != null) - { - openNode(node, true); - } - } - - public void closeAll() - { - if(node != null) - { - closeNode(node, true); - } - } - - public void openNode(T entry, boolean childrenIncluded) - { - openNode(entry, childrenIncluded, Integer.MAX_VALUE); - } - - public void openNode(T entry, boolean childrenIncluded, int maxLayers) - { - openNodes.add(entry); - if(childrenIncluded) - { - getNodes(entry, openNodes, false, maxLayers); - } - listChange = true; - updateScrollBar(); - } - - public void toggleNode(T entry, boolean childrenIncluded) - { - if(isOpen(entry)) - { - closeNode(entry, childrenIncluded); - return; - } - openNode(entry, childrenIncluded); - } - - public boolean isOpen(T entry) - { - return openNodes.contains(entry); - } - - public void closeNode(T entry, boolean childrenIncluded) - { - openNodes.remove(entry); - if(childrenIncluded) - { - Set entries = new ObjectOpenHashSet(); - getNodes(entry, entries, false); - openNodes.removeAll(entries); - } - listChange = true; - updateScrollBar(); - } - - protected void createArrow() - { - float pixelSize = (entryHeight * 0.5F); - UIShapes.createArrow(buffer, pixelSize, pixelSize, color, Facing.EAST); - UIShapes.createArrow(buffer, pixelSize, pixelSize, color, Facing.SOUTH); - } - - protected void updateScrollBar() - { - if(listChange) - { - listChange = false; - visibleNodes.clear(); - getNodes(node, visibleNodes, true); - customButton = null; - } - float width = 0F; - float pixelSize = getBox().getScale() * entryHeight; - for(int i = 0,m=visibleNodes.size();i entries = new ObjectArrayList(); - getNodes(node, entries, false); - for(int i = 0,m=entries.size();i= visibleNodes.size() ? -1 : index; - return true; - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float brightness = getActiveBrightness(); - UIRenderer render = getRenderer(); - int start = getStartIndex(); - int end = MathUtils.clamp(0, visibleNodes.size(), start + getIndexWidth()); - IGuiBox box = getBox(); - float scale = box.getScale(); - float minX = horizontalBar.getScroll() * scale; - float minY = verticalBar.getScroll() * scale; - float maxX = box.getWidth() - verticalBar.getRequiredSpace() + (horizontalBar.getScroll() * scale); - float pixelSize = scale * entryHeight; - float offsetSize = pixelSize * 0.8F; - if(isFlagNotSet(FLAG_NO_BACKGROUND)) - { - render.setBrightness(brightness).drawQuad(box, color); - } - render.push(); - render.translate(box.getMinX(-horizontalBar.getScroll()), box.getMinY(-verticalBar.getScroll())); - enableScissorsBox(box.getMinX(), box.getMinY(), box.getMaxX()-verticalBar.getRequiredSpace(), box.getMaxY()-horizontalBar.getRequiredSpace()); - boolean skip = false; - if(hoverIndex != -1 && hoverIndex >= start && hoverIndex < end) - { - T node = visibleNodes.get(hoverIndex); - float xOffset = (offsetSize + (node.getDebth() * offsetSize * 0.6F)) * 0.8F; - if(!node.isLeaf() && mouseX - box.getMinX() >= xOffset - (pixelSize * 0.6F) && mouseX - box.getMinX() <= xOffset) - { - skip = true; - } - if(!skip) - { - int extraX = (int)(minX - getBox().getMinX() - xOffset); - int extraY = (int)(minY - hoverIndex * pixelSize - getBox().getMinY()); - if(node instanceof IButtonComponent && ((IButtonComponent)node).isComponentColliding(mouseX + extraX, mouseY + extraY)) - { - skip = true; - } - } - float otherMax = node.getHighlightWidth() >= 0F ? xOffset + node.getHighlightWidth() : maxX; - if(mouseX - box.getMinX() >= otherMax) skip = true; - if(!skip && selectionMode != SELECTION_MODE_INTERACT) - { - float offset = pixelSize * hoverIndex; - render.drawQuad(minX, offset, Math.min(otherMax, maxX), offset + pixelSize, 0.01F, hoverColor); - } - } - mouseX -= box.getMinX(); - mouseY -= box.getMinY(); - if(selectedNodes.size() > 0) - { - render.setBrightness(0.75F * brightness); - for(int i = start;i collector) - { - super.collectTooltips(mouseX, mouseY, particalTicks, collector); - int start = getStartIndex(); - int end = MathUtils.clamp(0, visibleNodes.size(), start + getIndexWidth()); - mouseX -= getBox().getMinX(); - mouseY -= getBox().getMinY(); - float scale = getBox().getScale(); - float minX = horizontalBar.getScroll() * scale; - float minY = verticalBar.getScroll() * scale; - float pixelSize = scale * entryHeight; - float offsetSize = pixelSize * 0.8F; - for(int i = start;i= offsetX - (entryHeight * scale * 0.6F) && mouseX - getBox().getMinX() <= offsetX) - { - toggleNode(visibleNodes.get(hoverIndex), Keyboard.isShiftDown()); - return true; - } - if(visibleNodes.get(hoverIndex) instanceof IButtonComponent) - { - IButtonComponent comp = (IButtonComponent)visibleNodes.get(hoverIndex); - int extraX = (int)((horizontalBar.getScroll() * scale - getBox().getMinX()) - offsetX); - int extraY = (int)(verticalBar.getScroll() * scale - (hoverIndex * scale * entryHeight) - getBox().getMinY()); - if(comp.isComponentColliding(mouseX + extraX, mouseY + extraY) && comp.onClick(button, mouseX + extraX, mouseY + extraY)) - { - customButton = comp; - return true; - } - } - } - dragIndex = hoverIndex; - if(selectionMode == SELECTION_MODE_INTERACT) - { - dragIndex = -1; - } - lastMouse.set(mouseX, mouseY); - return true; - } - - @Override - public boolean onDrag(int mouseX, int mouseY) - { - if(horizontalBar.onDrag(mouseX, mouseY) || verticalBar.onDrag(mouseX, mouseY)) - { - return true; - } - if(customButton != null) - { - float scale = getBox().getScale(); - float offsetSize = entryHeight * scale * 0.8F; - int extraX = (int)((horizontalBar.getScroll() * scale - getBox().getMinX()) - ((offsetSize + (visibleNodes.get(hoverIndex).getDebth() * offsetSize * 0.6F)) * 0.8F)); - int extraY = (int)(verticalBar.getScroll() * scale - (hoverIndex * scale * entryHeight) - getBox().getMinY()); - return customButton.onDrag(mouseX + extraX, mouseY + extraY); - } - horizontalBar.addScroll(lastMouse.getX() - mouseX); - verticalBar.addScroll(lastMouse.getY() - mouseY); - movement += Math.abs(lastMouse.getX() - mouseX) + Math.abs(lastMouse.getY() - mouseY); - lastMouse.set(mouseX, mouseY); - return true; - } - - @Override - public void onRelease(int button, int mouseX, int mouseY) - { - horizontalBar.onRelease(button, mouseX, mouseY); - verticalBar.onRelease(button, mouseX, mouseY); - if(customButton != null && (hoverIndex >= 0 && hoverIndex < visibleNodes.size() && customButton == visibleNodes.get(hoverIndex))) - { - float scale = getBox().getScale(); - float offsetSize = entryHeight * scale * 0.8F; - int extraX = (int)((horizontalBar.getScroll() * scale - getBox().getMinX()) - ((offsetSize + (visibleNodes.get(hoverIndex).getDebth() * offsetSize * 0.6F)) * 0.8F)); - int extraY = (int)(verticalBar.getScroll() * scale - (hoverIndex * scale * entryHeight) - getBox().getMinY()); - customButton.onRelease(button, mouseX + extraX, mouseY + extraY); - customButton = null; - } - else if(dragIndex != -1 && dragIndex == hoverIndex && movement < 2) - { - if(isNodeSelected(visibleNodes.get(hoverIndex))) - { - removeSelectedNode(visibleNodes.get(hoverIndex)); - } - else - { - addSelectedNode(visibleNodes.get(hoverIndex)); - } - notifyListeners(LISTENER_USER_ACTION); - dragIndex = -1; - } - movement = 0; - } - - @Override - public boolean onScroll(int scroll, int mouseX, int mouseY) - { - if((horizontalBar.isComponentColliding(mouseX, mouseY) && horizontalBar.onScroll(scroll, mouseX, mouseY)) || (verticalBar.isComponentColliding(mouseX, mouseY) && verticalBar.onScroll(scroll, mouseX, mouseY))) - { - movement = 100; - return true; - } - if(hoverIndex != -1 && visibleNodes.get(hoverIndex) instanceof IButtonComponent) - { - IButtonComponent comp = (IButtonComponent)visibleNodes.get(hoverIndex); - float scale = getBox().getScale(); - float offsetSize = entryHeight * scale * 0.8F; - int extraX = (int)((horizontalBar.getScroll() * scale - getBox().getMinX()) - ((offsetSize + (visibleNodes.get(hoverIndex).getDebth() * offsetSize * 0.6F)) * 0.8F)); - int extraY = (int)(verticalBar.getScroll() - (hoverIndex * getBox().getScale() * entryHeight) - getBox().getMinY()); - if(comp.isComponentColliding(mouseX + extraX, mouseY + extraY) && comp.onScroll(scroll, mouseX + extraX, mouseY + extraY)) - { - return true; - } - } - if(verticalBar.isInUse()) - { - verticalBar.addScroll(-(int)(scroll * 5F * getBox().getScale())); - return true; - } - return false; - } - - public int getStartIndex() - { - return MathUtils.clamp(0, visibleNodes.size(), MathUtils.floor(verticalBar.getScroll() / entryHeight)); - } - - public int getIndexWidth() - { - return MathUtils.clamp(0, visibleNodes.size(), MathUtils.ceil((getBox().getBaseHeight() - (horizontalBar.getRequiredSpace() / getBox().getScale())) / entryHeight) + 1); - } - - protected void getNodes(T entry, Collection collection, boolean openOnly, int layers) - { - if(entry != null && layers >= 0) - { - collection.add(entry); - if(!entry.isLeaf() && (!openOnly || openNodes.contains(entry))) - { - for(int i = 0,m=entry.getChildCount();i collection, boolean openOnly) - { - if(entry != null) - { - collection.add(entry); - if(!entry.isLeaf() && (!openOnly || openNodes.contains(entry))) - { - for(int i = 0,m=entry.getChildCount();i extends GuiComponent implements IButtonComponent +{ + public static final int SELECTION_MODE_DISABLE = 0; + public static final int SELECTION_MODE_SINGLE = 1; + public static final int SELECTION_MODE_MULTI = 2; + public static final int SELECTION_MODE_INTERACT = 3; + + public static final int UPDATE_MODE_DISABLED = 0; + public static final int UPDATE_MODE_VISIBLE = 1; + public static final int UPDATE_MODE_OPEN = 2; + public static final int UPDATE_MODE_ALL = 3; + + public static final int FLAG_NO_BACKGROUND = 1 << 20; + + ScrollBarComponent verticalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY); + ScrollBarComponent horizontalBar = new ScrollBarComponent(ColorUtils.LIGHT_GRAY).setHorizontal(true); + + int color; + int selectedColor; + int hoverColor = ColorUtils.LIGHT_GRAY; + int hoverIndex = -1; + int dragIndex = -1; + int movement; + Vec2i lastMouse = Vec2i.mutable(); + IButtonComponent customButton; + protected ObjectSet openNodes = new ObjectOpenHashSet<>(); + protected ObjectSet selectedNodes = new ObjectOpenHashSet<>(); + protected int selectionMode = 1; + protected int updateMode = 1; + T node; + float entryHeight; + + boolean listChange = true; + List visibleNodes = new ObjectArrayList(); + RenderBuffer buffer; + + public TreeComponent(int color, float entryHeight) + { + super(0F, 0F, 0F, 0F); + this.entryHeight = entryHeight; + this.color = color; + this.selectedColor = color; + } + + public TreeComponent(int color, float entryHeight, T entry) + { + super(0F, 0F, 0F, 0F); + this.entryHeight = entryHeight; + getNodes(entry, openNodes, false); + this.color = color; + this.selectedColor = color; + node = entry; + if(entry != null) + { + entry.calculateDebth(); + } + } + + public TreeComponent(float x, float y, float width, float height, int color, float entryHeight, T entry) + { + super(x, y, width, height); + this.entryHeight = entryHeight; + getNodes(entry, openNodes, false); + this.color = color; + node = entry; + if(entry != null) + { + entry.calculateDebth(); + } + } + + @Override + public void init() + { + onClose(buffer = getRenderer().createBuffer()); + addChild(horizontalBar, Constrains.scrollBar(verticalBar::isInUse, true, 5F)); + addChild(verticalBar, Constrains.scrollBar(horizontalBar::isInUse, false, 5F)); + List entries = new ObjectArrayList(); + getNodes(node, entries, false); + for(int i = 0, m = entries.size();i < m;i++) + { + entries.get(i).init(this, getGui()); + } + updateScrollBar(); + createArrow(); + } + + public TreeComponent setColor(int color) + { + if(this.color != color) + { + this.color = color; + onChanged(true); + } + return this; + } + + public TreeComponent setHoverColor(int color) + { + hoverColor = color; + return this; + } + + public TreeComponent setSelectionColor(int color) + { + selectedColor = color; + return this; + } + + public TreeComponent setEntryHeight(float entryHeight) + { + if(this.entryHeight != entryHeight) + { + this.entryHeight = entryHeight; + onChanged(true); + } + return this; + } + + public TreeComponent setSelectionMode(int mode) + { + if(mode < 0 || mode > 3) + { + throw new IllegalStateException("Unknown Mode"); + } + this.selectionMode = mode; + selectedNodes.clear(); + return this; + } + + public TreeComponent setUpdateMode(int mode) + { + if(mode < 0 || mode > 3) + { + throw new IllegalStateException("Unknown Mode"); + } + updateMode = mode; + return this; + } + + public TreeComponent disableBackground(boolean value) + { + setFlag(FLAG_NO_BACKGROUND, value); + return this; + } + + @Override + protected void repaint() + { + float scale = getBox().getScale(); + List entries = new ObjectArrayList(); + getNodes(node, entries, false); + for(int i = 0,m=entries.size();i setTree(T entry) + { + if(node == entry) + { + return this; + } + node = entry; + if(entry != null) + { + entry.calculateDebth(); + if(getGui() != null) + { + List entries = new ObjectArrayList(); + getNodes(entry, entries, false); + for(int i = 0,m=entries.size();i entries = new ObjectArrayList(); + getNodes(node, entries, false); + for(int i = 0,m=entries.size();i 0; + } + + public T getSelectedNode() + { + return selectedNodes.isEmpty() ? null : selectedNodes.iterator().next(); + } + + public List getSelectedNodes() + { + return new ObjectArrayList(this.selectedNodes); + } + + public List getOpenNodes() + { + return new ObjectArrayList(this.visibleNodes); + } + + public List getAllNodes() + { + List list = new ObjectArrayList(); + getNodes(node, list, false); + return list; + } + + public void openAll() + { + if(node != null) + { + openNode(node, true); + } + } + + public void closeAll() + { + if(node != null) + { + closeNode(node, true); + } + } + + public void openNode(T entry, boolean childrenIncluded) + { + openNode(entry, childrenIncluded, Integer.MAX_VALUE); + } + + public void openNode(T entry, boolean childrenIncluded, int maxLayers) + { + openNodes.add(entry); + if(childrenIncluded) + { + getNodes(entry, openNodes, false, maxLayers); + } + listChange = true; + updateScrollBar(); + } + + public void toggleNode(T entry, boolean childrenIncluded) + { + if(isOpen(entry)) + { + closeNode(entry, childrenIncluded); + return; + } + openNode(entry, childrenIncluded); + } + + public boolean isOpen(T entry) + { + return openNodes.contains(entry); + } + + public void closeNode(T entry, boolean childrenIncluded) + { + openNodes.remove(entry); + if(childrenIncluded) + { + Set entries = new ObjectOpenHashSet(); + getNodes(entry, entries, false); + openNodes.removeAll(entries); + } + listChange = true; + updateScrollBar(); + } + + protected void createArrow() + { + float pixelSize = (entryHeight * 0.5F); + UIShapes.createArrow(buffer, pixelSize, pixelSize, color, Facing.EAST); + UIShapes.createArrow(buffer, pixelSize, pixelSize, color, Facing.SOUTH); + } + + protected void updateScrollBar() + { + if(listChange) + { + listChange = false; + visibleNodes.clear(); + getNodes(node, visibleNodes, true); + customButton = null; + } + float width = 0F; + float pixelSize = getBox().getScale() * entryHeight; + for(int i = 0,m=visibleNodes.size();i entries = new ObjectArrayList(); + getNodes(node, entries, false); + for(int i = 0,m=entries.size();i= visibleNodes.size() ? -1 : index; + return true; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float brightness = getActiveBrightness(); + UIRenderer render = getRenderer(); + int start = getStartIndex(); + int end = MathUtils.clamp(0, visibleNodes.size(), start + getIndexWidth()); + IGuiBox box = getBox(); + float scale = box.getScale(); + float minX = horizontalBar.getScroll() * scale; + float minY = verticalBar.getScroll() * scale; + float maxX = box.getWidth() - verticalBar.getRequiredSpace() + (horizontalBar.getScroll() * scale); + float pixelSize = scale * entryHeight; + float offsetSize = pixelSize * 0.8F; + if(isFlagNotSet(FLAG_NO_BACKGROUND)) + { + render.setBrightness(brightness).drawQuad(box, color); + } + render.push(); + render.translate(box.getMinX(-horizontalBar.getScroll()), box.getMinY(-verticalBar.getScroll())); + enableScissorsBox(box.getMinX(), box.getMinY(), box.getMaxX()-verticalBar.getRequiredSpace(), box.getMaxY()-horizontalBar.getRequiredSpace()); + boolean skip = false; + if(hoverIndex != -1 && hoverIndex >= start && hoverIndex < end) + { + T node = visibleNodes.get(hoverIndex); + float xOffset = (offsetSize + (node.getDebth() * offsetSize * 0.6F)) * 0.8F; + if(!node.isLeaf() && mouseX - box.getMinX() >= xOffset - (pixelSize * 0.6F) && mouseX - box.getMinX() <= xOffset) + { + skip = true; + } + if(!skip) + { + int extraX = (int)(minX - getBox().getMinX() - xOffset); + int extraY = (int)(minY - hoverIndex * pixelSize - getBox().getMinY()); + if(node instanceof IButtonComponent && ((IButtonComponent)node).isComponentColliding(mouseX + extraX, mouseY + extraY)) + { + skip = true; + } + } + float otherMax = node.getHighlightWidth() >= 0F ? xOffset + node.getHighlightWidth() : maxX; + if(mouseX - box.getMinX() >= otherMax) skip = true; + if(!skip && selectionMode != SELECTION_MODE_INTERACT) + { + float offset = pixelSize * hoverIndex; + render.drawQuad(minX, offset, Math.min(otherMax, maxX), offset + pixelSize, 0.01F, hoverColor); + } + } + mouseX -= box.getMinX(); + mouseY -= box.getMinY(); + if(selectedNodes.size() > 0) + { + render.setBrightness(0.75F * brightness); + for(int i = start;i collector) + { + super.collectTooltips(mouseX, mouseY, particalTicks, collector); + int start = getStartIndex(); + int end = MathUtils.clamp(0, visibleNodes.size(), start + getIndexWidth()); + mouseX -= getBox().getMinX(); + mouseY -= getBox().getMinY(); + float scale = getBox().getScale(); + float minX = horizontalBar.getScroll() * scale; + float minY = verticalBar.getScroll() * scale; + float pixelSize = scale * entryHeight; + float offsetSize = pixelSize * 0.8F; + for(int i = start;i= offsetX - (entryHeight * scale * 0.6F) && mouseX - getBox().getMinX() <= offsetX) + { + toggleNode(visibleNodes.get(hoverIndex), Keyboard.isShiftDown()); + return true; + } + if(visibleNodes.get(hoverIndex) instanceof IButtonComponent) + { + IButtonComponent comp = (IButtonComponent)visibleNodes.get(hoverIndex); + int extraX = (int)((horizontalBar.getScroll() * scale - getBox().getMinX()) - offsetX); + int extraY = (int)(verticalBar.getScroll() * scale - (hoverIndex * scale * entryHeight) - getBox().getMinY()); + if(comp.isComponentColliding(mouseX + extraX, mouseY + extraY) && comp.onClick(button, mouseX + extraX, mouseY + extraY)) + { + customButton = comp; + return true; + } + } + } + dragIndex = hoverIndex; + if(selectionMode == SELECTION_MODE_INTERACT) + { + dragIndex = -1; + } + lastMouse.set(mouseX, mouseY); + return true; + } + + @Override + public boolean onDrag(int mouseX, int mouseY) + { + if(horizontalBar.onDrag(mouseX, mouseY) || verticalBar.onDrag(mouseX, mouseY)) + { + return true; + } + if(customButton != null) + { + float scale = getBox().getScale(); + float offsetSize = entryHeight * scale * 0.8F; + int extraX = (int)((horizontalBar.getScroll() * scale - getBox().getMinX()) - ((offsetSize + (visibleNodes.get(hoverIndex).getDebth() * offsetSize * 0.6F)) * 0.8F)); + int extraY = (int)(verticalBar.getScroll() * scale - (hoverIndex * scale * entryHeight) - getBox().getMinY()); + return customButton.onDrag(mouseX + extraX, mouseY + extraY); + } + horizontalBar.addScroll(lastMouse.getX() - mouseX); + verticalBar.addScroll(lastMouse.getY() - mouseY); + movement += Math.abs(lastMouse.getX() - mouseX) + Math.abs(lastMouse.getY() - mouseY); + lastMouse.set(mouseX, mouseY); + return true; + } + + @Override + public void onRelease(int button, int mouseX, int mouseY) + { + horizontalBar.onRelease(button, mouseX, mouseY); + verticalBar.onRelease(button, mouseX, mouseY); + if(customButton != null && (hoverIndex >= 0 && hoverIndex < visibleNodes.size() && customButton == visibleNodes.get(hoverIndex))) + { + float scale = getBox().getScale(); + float offsetSize = entryHeight * scale * 0.8F; + int extraX = (int)((horizontalBar.getScroll() * scale - getBox().getMinX()) - ((offsetSize + (visibleNodes.get(hoverIndex).getDebth() * offsetSize * 0.6F)) * 0.8F)); + int extraY = (int)(verticalBar.getScroll() * scale - (hoverIndex * scale * entryHeight) - getBox().getMinY()); + customButton.onRelease(button, mouseX + extraX, mouseY + extraY); + customButton = null; + } + else if(dragIndex != -1 && dragIndex == hoverIndex && movement < 2) + { + if(isNodeSelected(visibleNodes.get(hoverIndex))) + { + removeSelectedNode(visibleNodes.get(hoverIndex)); + } + else + { + addSelectedNode(visibleNodes.get(hoverIndex)); + } + notifyListeners(LISTENER_USER_ACTION); + dragIndex = -1; + } + movement = 0; + } + + @Override + public boolean onScroll(int scroll, int mouseX, int mouseY) + { + if((horizontalBar.isComponentColliding(mouseX, mouseY) && horizontalBar.onScroll(scroll, mouseX, mouseY)) || (verticalBar.isComponentColliding(mouseX, mouseY) && verticalBar.onScroll(scroll, mouseX, mouseY))) + { + movement = 100; + return true; + } + if(hoverIndex != -1 && visibleNodes.get(hoverIndex) instanceof IButtonComponent) + { + IButtonComponent comp = (IButtonComponent)visibleNodes.get(hoverIndex); + float scale = getBox().getScale(); + float offsetSize = entryHeight * scale * 0.8F; + int extraX = (int)((horizontalBar.getScroll() * scale - getBox().getMinX()) - ((offsetSize + (visibleNodes.get(hoverIndex).getDebth() * offsetSize * 0.6F)) * 0.8F)); + int extraY = (int)(verticalBar.getScroll() - (hoverIndex * getBox().getScale() * entryHeight) - getBox().getMinY()); + if(comp.isComponentColliding(mouseX + extraX, mouseY + extraY) && comp.onScroll(scroll, mouseX + extraX, mouseY + extraY)) + { + return true; + } + } + if(verticalBar.isInUse()) + { + verticalBar.addScroll(-(int)(scroll * 5F * getBox().getScale())); + return true; + } + return false; + } + + public int getStartIndex() + { + return MathUtils.clamp(0, visibleNodes.size(), MathUtils.floor(verticalBar.getScroll() / entryHeight)); + } + + public int getIndexWidth() + { + return MathUtils.clamp(0, visibleNodes.size(), MathUtils.ceil((getBox().getBaseHeight() - (horizontalBar.getRequiredSpace() / getBox().getScale())) / entryHeight) + 1); + } + + protected void getNodes(T entry, Collection collection, boolean openOnly, int layers) + { + if(entry != null && layers >= 0) + { + collection.add(entry); + if(!entry.isLeaf() && (!openOnly || openNodes.contains(entry))) + { + for(int i = 0,m=entry.getChildCount();i collection, boolean openOnly) + { + if(entry != null) + { + collection.add(entry); + if(!entry.isLeaf() && (!openOnly || openNodes.contains(entry))) + { + for(int i = 0,m=entry.getChildCount();i -{ - public static final Vec2f DEFAULT_MINIMUM_BOUNDS = Vec2f.of(75F, 7.5F); - public static final int FLAG_MINIMIZED = 1 << 20; - public static final int FLAG_RESIZEABLE = 1 << 21; - public static final int FLAG_MOVEABLE = 1 << 22; - public static final int FLAG_RESIZEABLE_HORIZONTAL = 1 << 23; - public static final int FLAG_RESIZEABLE_VERTICAL = 1 << 24; - public static final int FLAG_RESIZE_INVERT = 1 << 25; - - public static final int WINDOW_FLAG_CLOSEABLE = 1; - public static final int WINDOW_FLAG_MINIMIZEABLE = 2; - - public static final int WINDOW_FLAGS = WINDOW_FLAG_CLOSEABLE | WINDOW_FLAG_MINIMIZEABLE; - - public static final int DEFAULT_FLAGS = WINDOW_FLAGS | FLAG_RESIZEABLE | FLAG_MOVEABLE; - public static final int FIXED_SIZE_WINDOW = WINDOW_FLAGS | FLAG_MOVEABLE; - public static final int FIXED_SIZE_POPUP = WINDOW_FLAG_CLOSEABLE | FLAG_MOVEABLE; - public static final int DYNAMIC_POPUP = FIXED_SIZE_POPUP | FLAG_RESIZEABLE; - public static final int UNCLOSEABLE_WINDOW = WINDOW_FLAG_MINIMIZEABLE | FLAG_RESIZEABLE | FLAG_MOVEABLE; - public static final int SUB_WINDOW = WINDOW_FLAG_MINIMIZEABLE | FLAG_RESIZEABLE | FLAG_RESIZE_INVERT; - - final int flags; - FacingList facing = null; - String name; - int color = ColorUtils.WINDOW_DEFAULT_BACKGROUND; - Vec2f lastSize = Vec2f.mutable(); - Vec2i lastClick = Vec2i.mutable(); - IValue animation = null; - protected final Consumer closeListener = new ConsumerConverter(0, this); - protected final Consumer minimizedListener = new ConsumerConverter(2, this); - - public WindowComponent(float x, float y, float width, float height, int flags, String name) - { - super(x, y, width, height); - this.name = name; - this.flags = flags & WINDOW_FLAGS; - setFlag(flags &= ~(WINDOW_FLAGS)); - setFlag(FLAG_RESIZEABLE_HORIZONTAL | FLAG_RESIZEABLE_VERTICAL); - lastSize.set(getBox().getBaseWidth(), getBox().getBaseHeight()); - } - - @Override - public void init() - { - super.init(); - LabelComponent label = new LabelComponent(name, ColorUtils.DARK_GRAY); - label.getText().setTextScale(0.4F).horizontal(Align.LEFT_TOP).singleLine(true); - addChild(label, new Constrains(null, null, new ParentConstrain(), new PixelConstrain(7.5F))); - float offset = 9F; - if((flags & WINDOW_FLAG_CLOSEABLE) != 0) - { - addChild(new IconButtonComponent(0F, 0F, 7.5F, 7.5F, ColorUtils.RED, new CrossIcon(ColorUtils.WHITE).setPadding(2.5F, 2F)).addUserActionListener(new ConsumerConverter<>(0, this)).setZOffset(0.001F), new Constrains(new PixelConstrain(offset).setInverted(), null, null, null)); - offset += 7.5F; - } - if((flags & WINDOW_FLAG_MINIMIZEABLE) != 0) - { - addChild(new IconButtonComponent(0F, 0F, 7.5F, 7.5F, ColorUtils.GRAY, new LineIcon(ColorUtils.WHITE, 0.7F, 0.25F)).addUserActionListener(new ConsumerConverter<>(1, this)).setZOffset(0.001F), new Constrains(new PixelConstrain(offset).setInverted(), null, null, null)); - } - if(canMoveIntoForground()) - { - setFlag(FLAG_RENDER_ORDER); - } - } - - protected void updateMinizedState(boolean value) - { - if(setFlag(FLAG_MINIMIZED, value)) - { - onChanged(false); - } - } - - public final WindowComponent setMinimized(boolean value) - { - if((flags & WINDOW_FLAG_MINIMIZEABLE) != 0 && setFlag(FLAG_MINIMIZED, value)) - { - if(value) - { - Vec2f last = InternalThreadPools.VEC2F.get().set(lastSize); - bounds(last.getX(), isFlagSet(FLAG_MINIMIZED) ? getMinimizedY() : last.getY()); - lastSize.set(last); - InternalThreadPools.VEC2F.accept(last.negate()); - } - else bounds(lastSize.getX(), lastSize.getY()); - onChanged(false); - } - return this; - } - - public final boolean isMinimized() - { - return isFlagSet(FLAG_MINIMIZED); - } - - public Vec2f getMinimumBounds() - { - return DEFAULT_MINIMUM_BOUNDS; - } - - public float getMinimizedY() - { - return 7.5F; - } - - public WindowComponent setColor(int color) - { - this.color = color; - return this; - } - - @Override - public void calculateActualBounds(float[] area, boolean start) - { - if(animation != null) - { - float scale = getBox().getScale(); - area[0] = Math.min(area[0], getBox().getMinX()); - area[1] = Math.min(area[1], getBox().getMinY()); - area[2] = Math.max(area[2], lastSize.getX() * scale); - area[3] = Math.max(area[3], animation.get(getMinimizedY(), lastSize.getY()) * scale); - return; - } - super.calculateActualBounds(area, start); - } - - @Override - protected void updateState() - { - if(animation == null) - { - if(isFlagSet(FLAG_MINIMIZED)) - { - lastSize.setX(getBox().getBaseWidth()); - return; - } - lastSize.set(getBox().getBaseWidth(), getBox().getBaseHeight()); - } - } - - @Override - protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) - { - if(animation != null) - { - animation.update(particalTicks); - if(animation.isDone()) - { - if(animation.get() < 0.1F) - { - updateMinizedState(true); - } - Vec2f last = InternalThreadPools.VEC2F.get().set(lastSize); - bounds(last.getX(), isFlagSet(FLAG_MINIMIZED) ? getMinimizedY() : last.getY()); - lastSize.set(last); - InternalThreadPools.VEC2F.accept(last.negate()); - animation = null; - } - notifyListeners(LISTENER_ON_CHANGE); - } - else if(isFlagSet(FLAG_RESIZEABLE) && !isOverChild(mouseX, mouseY) && !getGui().hasComponentInTheWay(getTopComponent(), mouseX, mouseY)) - { - FacingList list = getBox().isColiding(mouseX, mouseY) ? getBox().getColidingBorder(mouseX, mouseY, 2F) : null; - if(list != null) - { - if(isFlagNotSet(FLAG_RESIZEABLE_HORIZONTAL)) list = list.remove(FacingList.HORIZONTAL); - if(isFlagNotSet(FLAG_RESIZEABLE_VERTICAL)) list = list.remove(FacingList.VERTICAL); - bindCursor(list.containsAny(FacingList.VERTICAL) && isFlagNotSet(FLAG_MINIMIZED) ? Cursor.CURSOR_VRESIZE : (list.containsAny(FacingList.HORIZONTAL) ? Cursor.CURSOR_HRESIZE : null)); - } - } - if(isPopup() && !hasChildPopups() && !getGui().isComponentInFront(this)) - { - requestFocus(); - } - return true; - } - - @Override - protected void preRender() - { - if(animation != null) - { - float scale = getBox().getScale(); - enableScissors(getBox().getMinX(), getBox().getMinY(), lastSize.getX() * scale, animation.get(getMinimizedY(), lastSize.getY()) * scale); - } - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - getRenderer().drawQuad(getBox(), color); - return true; - } - - @Override - protected void postRender() - { - if(animation != null) - { - disableScissors(); - } - } - - @Override - public void accept(GuiComponent value, int index) - { - switch(index) - { - case 0: - getGui().removeComponent(this); - break; - case 1: - if(animation != null || (flags & WINDOW_FLAG_MINIMIZEABLE) == 0) - { - break; - } - animation = (isMinimized() ? new LiniarValue(1F, 0F, 1F) : new LiniarValue(1F, 1F, 0F)).setSmooth(); - if(isMinimized()) - { - bounds(lastSize.getX(), lastSize.getY()); - } - updateMinizedState(false); - break; - case 2: - value.setVisible(!isMinimized()); - break; - } - } - - @Override - public boolean onClick(int button, int mouseX, int mouseY) - { - if(isOverChild(mouseX, mouseY) || getGui().hasComponentInTheWay(getTopComponent(), mouseX, mouseY)) - { - return false; - } - facing = getBox().getColidingBorder(mouseX, mouseY, 2F); - lastClick.set(mouseX, mouseY); - if(facing != null) - { - if(isFlagNotSet(FLAG_RESIZEABLE_HORIZONTAL)) facing = facing.remove(FacingList.HORIZONTAL); - if(isFlagNotSet(FLAG_RESIZEABLE_VERTICAL)) facing = facing.remove(FacingList.VERTICAL); - } - return true; - } - - @Override - public boolean onDrag(int mouseX, int mouseY) - { - if(facing != null) - { - if(facing.isEmpty() && isFlagSet(FLAG_MOVEABLE)) - { - move(mouseX - lastClick.getX(), mouseY - lastClick.getY()); - } - else if(!facing.isEmpty() && isFlagSet(FLAG_RESIZEABLE)) - { - float scale = getBox().getScale(); - float xChange = (mouseX - lastClick.getX()) * (facing.containsAny(FacingList.HORIZONTAL) ? 1F : 0F); - float yChange = (mouseY - lastClick.getY()) * (facing.containsAny(FacingList.VERTICAL) ? 1F : 0F); - if(isFlagSet(FLAG_RESIZE_INVERT)) - { - xChange *= -1F; - yChange *= -1F; - } - setMassChanging(); - if(facing.contains(Facing.NORTH) && isFlagNotSet(FLAG_MINIMIZED)) - { - resize(0F, -(yChange / scale)); - move(0F, yChange); - } - else if(facing.contains(Facing.SOUTH) && isFlagNotSet(FLAG_MINIMIZED)) - { - resize(0F, yChange / scale); - } - if(facing.contains(Facing.WEST)) - { - resize(-(xChange / scale) - 1F, 0F); - move(xChange, 0F); - } - else if(facing.contains(Facing.EAST)) - { - resize(xChange / scale, 0F); - } - ensureMinimumBounds(); - finishMassChanging(); - if(xChange > 0F || yChange > 0F) - { - onChanged(true); - } - } - lastClick.set(mouseX, mouseY); - return true; - } - return false; - } - - @Override - public void onRelease(int button, int mouseX, int mouseY) - { - facing = null; - } - - @Override - public boolean canMoveIntoForground() - { - return true; - } - - @Override - public void onFocusLost() - { - facing = null; - } - - protected void ensureMinimumBounds() - { - IGuiBox box = getBox(); - Vec2f bounds = getMinimumBounds(); - if(box.getBaseWidth() < bounds.getX()) - { - box.setWidth(bounds.getX()); - onChanged(true); - } - if(box.getBaseHeight() < bounds.getY()) - { - box.setHeight(bounds.getY()); - onChanged(true); - } - } -} +package speiger.src.coreengine.rendering.gui.components; + +import java.util.function.Consumer; +import java.util.function.ObjIntConsumer; + +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.math.misc.Facing; +import speiger.src.coreengine.math.misc.FacingList; +import speiger.src.coreengine.math.value.IValue; +import speiger.src.coreengine.math.value.LiniarValue; +import speiger.src.coreengine.math.vector.floats.Vec2f; +import speiger.src.coreengine.math.vector.ints.Vec2i; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.base.IButtonComponent; +import speiger.src.coreengine.rendering.gui.components.icon.CrossIcon; +import speiger.src.coreengine.rendering.gui.components.icon.LineIcon; +import speiger.src.coreengine.rendering.gui.helper.Align; +import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; +import speiger.src.coreengine.rendering.utils.Cursor; +import speiger.src.coreengine.utils.functions.ConsumerConverter; +import speiger.src.coreengine.utils.helpers.InternalThreadPools; +import speiger.src.coreengine.utils.io.GameLog; + +public class WindowComponent extends PanelComponent implements IButtonComponent, ObjIntConsumer +{ + public static final Vec2f DEFAULT_MINIMUM_BOUNDS = Vec2f.of(75F, 7.5F); + public static final int FLAG_MINIMIZED = 1 << 20; + public static final int FLAG_RESIZEABLE = 1 << 21; + public static final int FLAG_MOVEABLE = 1 << 22; + public static final int FLAG_RESIZEABLE_HORIZONTAL = 1 << 23; + public static final int FLAG_RESIZEABLE_VERTICAL = 1 << 24; + public static final int FLAG_RESIZE_INVERT = 1 << 25; + + public static final int WINDOW_FLAG_CLOSEABLE = 1; + public static final int WINDOW_FLAG_MINIMIZEABLE = 2; + + public static final int WINDOW_FLAGS = WINDOW_FLAG_CLOSEABLE | WINDOW_FLAG_MINIMIZEABLE; + + public static final int DEFAULT_FLAGS = WINDOW_FLAGS | FLAG_RESIZEABLE | FLAG_MOVEABLE; + public static final int FIXED_SIZE_WINDOW = WINDOW_FLAGS | FLAG_MOVEABLE; + public static final int FIXED_SIZE_POPUP = WINDOW_FLAG_CLOSEABLE | FLAG_MOVEABLE; + public static final int DYNAMIC_POPUP = FIXED_SIZE_POPUP | FLAG_RESIZEABLE; + public static final int UNCLOSEABLE_WINDOW = WINDOW_FLAG_MINIMIZEABLE | FLAG_RESIZEABLE | FLAG_MOVEABLE; + public static final int SUB_WINDOW = WINDOW_FLAG_MINIMIZEABLE | FLAG_RESIZEABLE | FLAG_RESIZE_INVERT; + + final int flags; + FacingList facing = null; + String name; + int color = ColorUtils.WINDOW_DEFAULT_BACKGROUND; + Vec2f lastSize = Vec2f.mutable(); + Vec2i lastClick = Vec2i.mutable(); + IValue animation = null; + protected final Consumer closeListener = new ConsumerConverter(0, this); + protected final Consumer minimizedListener = new ConsumerConverter(2, this); + + public WindowComponent(float x, float y, float width, float height, int flags, String name) + { + super(x, y, width, height); + this.name = name; + this.flags = flags & WINDOW_FLAGS; + setFlag(flags &= ~(WINDOW_FLAGS)); + setFlag(FLAG_RESIZEABLE_HORIZONTAL | FLAG_RESIZEABLE_VERTICAL); + lastSize.set(getBox().getBaseWidth(), getBox().getBaseHeight()); + } + + @Override + public void init() + { + super.init(); + LabelComponent label = new LabelComponent(name, ColorUtils.DARK_GRAY); + label.getText().setTextScale(0.4F).horizontal(Align.LEFT_TOP).singleLine(true); + addChild(label, new Constrains(null, null, new ParentConstrain(), new PixelConstrain(7.5F))); + float offset = 9F; + if((flags & WINDOW_FLAG_CLOSEABLE) != 0) + { + addChild(new IconButtonComponent(0F, 0F, 7.5F, 7.5F, ColorUtils.RED, new CrossIcon(ColorUtils.WHITE).setPadding(2.5F, 2F)).onAction(new ConsumerConverter<>(0, this)).setZOffset(0.001F), new Constrains(new PixelConstrain(offset).setInverted(), null, null, null)); + offset += 7.5F; + } + if((flags & WINDOW_FLAG_MINIMIZEABLE) != 0) + { + addChild(new IconButtonComponent(0F, 0F, 7.5F, 7.5F, ColorUtils.GRAY, new LineIcon(ColorUtils.WHITE, 0.7F, 0.25F)).onAction(new ConsumerConverter<>(1, this)).setZOffset(0.001F), new Constrains(new PixelConstrain(offset).setInverted(), null, null, null)); + } + if(canMoveIntoForground()) + { + setFlag(FLAG_RENDER_ORDER); + } + } + + protected void updateMinizedState(boolean value) + { + if(setFlag(FLAG_MINIMIZED, value)) + { + onChanged(false); + } + } + + public final WindowComponent setMinimized(boolean value) + { + if((flags & WINDOW_FLAG_MINIMIZEABLE) != 0 && setFlag(FLAG_MINIMIZED, value)) + { + if(value) + { + Vec2f last = InternalThreadPools.VEC2F.get().set(lastSize); + bounds(last.getX(), isFlagSet(FLAG_MINIMIZED) ? getMinimizedY() : last.getY()); + lastSize.set(last); + InternalThreadPools.VEC2F.accept(last.negate()); + } + else bounds(lastSize.getX(), lastSize.getY()); + onChanged(false); + } + return this; + } + + public final boolean isMinimized() + { + return isFlagSet(FLAG_MINIMIZED); + } + + public Vec2f getMinimumBounds() + { + return DEFAULT_MINIMUM_BOUNDS; + } + + public float getMinimizedY() + { + return 7.5F; + } + + public WindowComponent setColor(int color) + { + this.color = color; + return this; + } + + @Override + public void calculateActualBounds(float[] area, boolean start) + { + if(animation != null) + { + float scale = getBox().getScale(); + area[0] = Math.min(area[0], getBox().getMinX()); + area[1] = Math.min(area[1], getBox().getMinY()); + area[2] = Math.max(area[2], lastSize.getX() * scale); + area[3] = Math.max(area[3], animation.get(getMinimizedY(), lastSize.getY()) * scale); + return; + } + super.calculateActualBounds(area, start); + } + + @Override + protected void updateState() + { + if(animation == null) + { + if(isFlagSet(FLAG_MINIMIZED)) + { + lastSize.setX(getBox().getBaseWidth()); + return; + } + lastSize.set(getBox().getBaseWidth(), getBox().getBaseHeight()); + } + } + + @Override + protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) + { + if(animation != null) + { + animation.update(particalTicks); + if(animation.isDone()) + { + if(animation.get() < 0.1F) + { + updateMinizedState(true); + } + Vec2f last = InternalThreadPools.VEC2F.get().set(lastSize); + bounds(last.getX(), isFlagSet(FLAG_MINIMIZED) ? getMinimizedY() : last.getY()); + lastSize.set(last); + InternalThreadPools.VEC2F.accept(last.negate()); + animation = null; + } + notifyListeners(LISTENER_ON_CHANGE); + } + else if(isFlagSet(FLAG_RESIZEABLE) && !isOverChild(mouseX, mouseY) && !getGui().hasComponentInTheWay(getTopComponent(), mouseX, mouseY)) + { + FacingList list = getBox().isColiding(mouseX, mouseY) ? getBox().getColidingBorder(mouseX, mouseY, 2F) : null; + if(list != null) + { + if(isFlagNotSet(FLAG_RESIZEABLE_HORIZONTAL)) list = list.remove(FacingList.HORIZONTAL); + if(isFlagNotSet(FLAG_RESIZEABLE_VERTICAL)) list = list.remove(FacingList.VERTICAL); + bindCursor(list.containsAny(FacingList.VERTICAL) && isFlagNotSet(FLAG_MINIMIZED) ? Cursor.CURSOR_VRESIZE : (list.containsAny(FacingList.HORIZONTAL) ? Cursor.CURSOR_HRESIZE : null)); + } + } + if(isPopup() && !hasChildPopups() && !getGui().isComponentInFront(this)) + { + requestFocus(); + } + return true; + } + + @Override + protected void preRender() + { + if(animation != null) + { + float scale = getBox().getScale(); + enableScissors(getBox().getMinX(), getBox().getMinY(), lastSize.getX() * scale, animation.get(getMinimizedY(), lastSize.getY()) * scale); + } + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + getRenderer().drawQuad(getBox(), color); + return true; + } + + @Override + protected void postRender() + { + if(animation != null) + { + disableScissors(); + } + } + + @Override + public void accept(GuiComponent value, int index) + { + switch(index) + { + case 0: + getGui().removeComponent(this); + break; + case 1: + if(animation != null || (flags & WINDOW_FLAG_MINIMIZEABLE) == 0) + { + break; + } + animation = (isMinimized() ? new LiniarValue(1F, 0F, 1F) : new LiniarValue(1F, 1F, 0F)).setSmooth(); + if(isMinimized()) + { + bounds(lastSize.getX(), lastSize.getY()); + } + updateMinizedState(false); + break; + case 2: + value.setVisible(!isMinimized()); + break; + } + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + if(getGui().hasComponentInTheWay(getTopComponent(), mouseX, mouseY)) + { + return false; + } + facing = getBox().getColidingBorder(mouseX, mouseY, 2F); + lastClick.set(mouseX, mouseY); + if(facing != null) + { + GameLog.info("Testing: "+facing.getCode()); + if(isFlagNotSet(FLAG_RESIZEABLE_HORIZONTAL)) facing = facing.remove(FacingList.HORIZONTAL); + if(isFlagNotSet(FLAG_RESIZEABLE_VERTICAL)) facing = facing.remove(FacingList.VERTICAL); + if(isOverChild(mouseX, mouseY) && facing.isEmpty()) + { + facing = null; + return false; + } + return true; + } + return false; + } + + @Override + public boolean onDrag(int mouseX, int mouseY) + { + if(facing != null) + { + if(facing.isEmpty() && isFlagSet(FLAG_MOVEABLE)) + { + move(mouseX - lastClick.getX(), mouseY - lastClick.getY()); + } + else if(!facing.isEmpty() && isFlagSet(FLAG_RESIZEABLE)) + { + float scale = getBox().getScale(); + float xChange = (mouseX - lastClick.getX()) * (facing.containsAny(FacingList.HORIZONTAL) ? 1F : 0F); + float yChange = (mouseY - lastClick.getY()) * (facing.containsAny(FacingList.VERTICAL) ? 1F : 0F); + if(isFlagSet(FLAG_RESIZE_INVERT)) + { + xChange *= -1F; + yChange *= -1F; + } + setMassChanging(); + if(facing.contains(Facing.NORTH) && isFlagNotSet(FLAG_MINIMIZED)) + { + resize(0F, -(yChange / scale)); + move(0F, yChange); + } + else if(facing.contains(Facing.SOUTH) && isFlagNotSet(FLAG_MINIMIZED)) + { + resize(0F, yChange / scale); + } + if(facing.contains(Facing.WEST)) + { + resize(-(xChange / scale) - 1F, 0F); + move(xChange, 0F); + } + else if(facing.contains(Facing.EAST)) + { + resize(xChange / scale, 0F); + } + ensureMinimumBounds(); + finishMassChanging(); + if(xChange > 0F || yChange > 0F) + { + onChanged(true); + } + } + lastClick.set(mouseX, mouseY); + return true; + } + return false; + } + + @Override + public void onRelease(int button, int mouseX, int mouseY) + { + facing = null; + } + + @Override + public boolean canMoveIntoForground() + { + return true; + } + + @Override + public void onFocusLost() + { + facing = null; + } + + protected void ensureMinimumBounds() + { + IGuiBox box = getBox(); + Vec2f bounds = getMinimumBounds(); + if(box.getBaseWidth() < bounds.getX()) + { + box.setWidth(bounds.getX()); + onChanged(true); + } + if(box.getBaseHeight() < bounds.getY()) + { + box.setHeight(bounds.getY()); + onChanged(true); + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/layouts/VerticalLayout.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/layouts/VerticalLayout.java index 27a2cc9..545e1e9 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/layouts/VerticalLayout.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/layouts/VerticalLayout.java @@ -1,84 +1,84 @@ -package speiger.src.coreengine.rendering.gui.components.layouts; - -import java.util.List; -import java.util.function.Consumer; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; - -public class VerticalLayout implements Consumer -{ - GuiComponent parent; - List components = new ObjectArrayList<>(); - IGuiBox box; - float padding; - boolean changing = false; - - public VerticalLayout(List components, IGuiBox box, float padding) - { - this.components.addAll(components); - for(int i = 0;i T addComponent(T gui) - { - components.add(gui); - gui.addChangeListener(this); - gui.addCloseListener(this::removeComponent); - accept(null); - return gui; - } - - public void removeComponent(GuiComponent gui) - { - if(components.remove(gui)) - { - gui.removeChangeListener(this); - gui.removeCloseListener(this::removeComponent); - accept(null); - } - } - - @Override - public void accept(GuiComponent t) - { - if(changing) return; - changing = true; - float minX = box.getBaseX(); - float minY = box.getBaseY(); - float currentY = 0F; - for(int i = 0;i +{ + GuiComponent parent; + List components = new ObjectArrayList<>(); + IGuiBox box; + float padding; + boolean changing = false; + + public VerticalLayout(List components, IGuiBox box, float padding) + { + this.components.addAll(components); + for(int i = 0;i T addComponent(T gui) + { + components.add(gui); + gui.onChange(this); + gui.onClose(this::removeComponent); + accept(null); + return gui; + } + + public void removeComponent(GuiComponent gui) + { + if(components.remove(gui)) + { + gui.removeChangeListener(this); + gui.removeCloseListener(this::removeComponent); + accept(null); + } + } + + @Override + public void accept(GuiComponent t) + { + if(changing) return; + changing = true; + float minX = box.getBaseX(); + float minY = box.getBaseY(); + float currentY = 0F; + for(int i = 0;i menuItems = new ObjectArrayList(); - float scale = 1F; - - public MenuBarComponent(int color) - { - super(0F, 0F, 0F, 0F); - this.color = color; - } - - public MenuBarComponent(float x, float y, float width, float height, int color) - { - super(x, y, width, height); - this.color = color; - } - - @Override - public void init() - { - } - - public MenuBarComponent setTextScale(float scale) - { - if(this.scale != scale) - { - this.scale = scale; - for(int i = 0,m=menuItems.size();i(menuItems), new PixelConstrain(), item.createWidthConstriain(), new ParentConstrain())); - item.setZOffset(0.3F); - item.setTextScale(scale); - item.onChanged(false); - return item; - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - getRenderer().drawQuad(getBox(), color); - return true; - } - - protected void closeMenus(GuiComponent owner) - { - for(int i = 0,m=menuItems.size();i menuItems = new ObjectArrayList(); + float scale = 1F; + + public MenuBarComponent(int color) + { + super(0F, 0F, 0F, 0F); + this.color = color; + } + + public MenuBarComponent(float x, float y, float width, float height, int color) + { + super(x, y, width, height); + this.color = color; + } + + @Override + public void init() + { + } + + public MenuBarComponent setTextScale(float scale) + { + if(this.scale != scale) + { + this.scale = scale; + for(int i = 0,m=menuItems.size();i(menuItems), new PixelConstrain(), item.createWidthConstriain(), new ParentConstrain())); + item.setZOffset(0.3F); + item.setTextScale(scale); + item.onChanged(false); + return item; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + getRenderer().drawQuad(getBox(), color); + return true; + } + + protected void closeMenus(GuiComponent owner) + { + for(int i = 0,m=menuItems.size();i -{ - public static final int FLAG_CHECKED = 1 << 21; - RenderBuffer buffer; - - public MenuCheckBoxComponent(String name) - { - super(name); - setFlag(FLAG_KEEP_MENU_OPEN | FLAG_SUPPORT_BINDING); - } - - public MenuCheckBoxComponent(String name, boolean checked) - { - super(name); - setFlag(FLAG_CHECKED, checked); - setFlag(FLAG_KEEP_MENU_OPEN | FLAG_SUPPORT_BINDING); - } - - public MenuCheckBoxComponent(float x, float y, float width, float height, String name) - { - super(x, y, width, height, name); - setFlag(FLAG_KEEP_MENU_OPEN | FLAG_SUPPORT_BINDING); - } - - public MenuCheckBoxComponent(float x, float y, float width, float height, String name, boolean checked) - { - super(x, y, width, height, name); - setFlag(FLAG_CHECKED, checked); - setFlag(FLAG_KEEP_MENU_OPEN | FLAG_SUPPORT_BINDING); - } - - @Override - public void init() - { - addChild(text, new Constrains(new PixelConstrain(getBox().getHeight() + 1F), new ParentConstrain(), new DynamicConstrain(() -> text.getMetadata().getMaxWidth() + 0.5F), new ParentConstrain())); - addCloseListener(buffer = getRenderer().createBuffer()); - } - - @Override - protected void repaint() - { - float width = getBox().getHeight(); - float height = getBox().getHeight(); - buffer.clear(); - UIShapes.createCross(buffer, width, height, (width / 3.3F), (height / 5F), color); - UIShapes.createCross(buffer, width, height, (width / 5F), (height / 10F), color); - } - - @Override - protected Constrain createWidthConstriain() - { - return new DynamicConstrain(() -> text.getMetadata().getMaxWidth() + getBox().getHeight() + 3F); - } - - @Override - public final boolean isChecked() - { - return isFlagSet(FLAG_CHECKED); - } - - @Override - public final MenuCheckBoxComponent setChecked(boolean value) - { - setFlag(FLAG_CHECKED, value); - return this; - } - - @Override - public boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float brightness = getActiveBrightness(); - float height = getBox().getHeight(); - float centerX = getBox().getMinX(height * 0.5F); - float centerY = getBox().getMinY(height * 0.5F); - getRenderer().setBrightness(brightness * 0.85F).drawQuad(getBox().getMinX(0.2F), getBox().getMinY(), getBox().getMinX(height + 0.2F), getBox().getMinY(height), color).setBrightness(brightness * 0.75F).drawFrame(getBox().getMinX(0.2F), getBox().getMinY(), getBox().getMinX(height + 0.2F), getBox().getMinY(height), color).translate(centerX, centerY); - if(isChecked()) - { - getRenderer().setBrightness(brightness * 0.7F).translate(0, 0, 0.001F).drawBuffers(buffer.selectionIterator(1), getBox().getWidth(), getBox().getHeight()).translate(0, 0, -0.001F); - } - if(isHovered(mouseX, mouseY)) - { - getRenderer().setBrightness(brightness * 1.3F).translate(0, 0, 0.002F).drawBuffers(buffer.selectionIterator(0), getBox().getWidth(), getBox().getHeight()).translate(0, 0, -0.002F); - } - float maxX = Math.min(boxWidth, getBox().getMaxX()); - getRenderer().setBrightness(1F).translate(-centerX, -centerY).drawQuad(getBox().getMinX(height), getBox().getMinY(), getBox().getMinX(maxX), getBox().getMaxY(), color).setBrightness(brightness * 0.75F).drawFrame(getBox().getMinX(height), getBox().getMinY(), getBox().getMinX(maxX), getBox().getMaxY(), color); - return true; - } - - protected boolean isCheckBoxHovered(int mouseX, int mouseY) - { - float height = getBox().getHeight(); - return getBox().getMinX() <= mouseX && getBox().getMinX(height) >= mouseX && getBox().getMinY() <= mouseY && getBox().getMinY(height) >= mouseY && getGui().hasComponentInTheWay(this, mouseX, mouseY); - } - - @Override - public boolean onClick(int button, int mouseX, int mouseY) - { - return true; - } - - @Override - public void onRelease(int button, int mouseX, int mouseY) - { - setFlag(FLAG_CHECKED, !isFlagSet(FLAG_CHECKED)); - notifyListeners(LISTENER_USER_ACTION); - } - - @Override - protected boolean onUserKey() - { - setFlag(FLAG_CHECKED, !isFlagSet(FLAG_CHECKED)); - notifyListeners(LISTENER_USER_ACTION); - return true; - } -} +package speiger.src.coreengine.rendering.gui.components.menu; + +import speiger.src.coreengine.rendering.gui.components.misc.ICheckBox; +import speiger.src.coreengine.rendering.gui.helper.UIShapes; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.DynamicConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; +import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; + +public class MenuCheckBoxComponent extends MenuItemComponent implements ICheckBox +{ + public static final int FLAG_CHECKED = 1 << 21; + RenderBuffer buffer; + + public MenuCheckBoxComponent(String name) + { + super(name); + setFlag(FLAG_KEEP_MENU_OPEN | FLAG_SUPPORT_BINDING); + } + + public MenuCheckBoxComponent(String name, boolean checked) + { + super(name); + setFlag(FLAG_CHECKED, checked); + setFlag(FLAG_KEEP_MENU_OPEN | FLAG_SUPPORT_BINDING); + } + + public MenuCheckBoxComponent(float x, float y, float width, float height, String name) + { + super(x, y, width, height, name); + setFlag(FLAG_KEEP_MENU_OPEN | FLAG_SUPPORT_BINDING); + } + + public MenuCheckBoxComponent(float x, float y, float width, float height, String name, boolean checked) + { + super(x, y, width, height, name); + setFlag(FLAG_CHECKED, checked); + setFlag(FLAG_KEEP_MENU_OPEN | FLAG_SUPPORT_BINDING); + } + + @Override + public void init() + { + addChild(text, new Constrains(new PixelConstrain(getBox().getHeight() + 1F), new ParentConstrain(), new DynamicConstrain(() -> text.getMetadata().getMaxWidth() + 0.5F), new ParentConstrain())); + onClose(buffer = getRenderer().createBuffer()); + } + + @Override + protected void repaint() + { + float width = getBox().getHeight(); + float height = getBox().getHeight(); + buffer.clear(); + UIShapes.createCross(buffer, width, height, (width / 3.3F), (height / 5F), color); + UIShapes.createCross(buffer, width, height, (width / 5F), (height / 10F), color); + } + + @Override + protected Constrain createWidthConstriain() + { + return new DynamicConstrain(() -> text.getMetadata().getMaxWidth() + getBox().getHeight() + 3F); + } + + @Override + public final boolean isChecked() + { + return isFlagSet(FLAG_CHECKED); + } + + @Override + public final MenuCheckBoxComponent setChecked(boolean value) + { + setFlag(FLAG_CHECKED, value); + return this; + } + + @Override + public boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float brightness = getActiveBrightness(); + float height = getBox().getHeight(); + float centerX = getBox().getMinX(height * 0.5F); + float centerY = getBox().getMinY(height * 0.5F); + getRenderer().setBrightness(brightness * 0.85F).drawQuad(getBox().getMinX(0.2F), getBox().getMinY(), getBox().getMinX(height + 0.2F), getBox().getMinY(height), color).setBrightness(brightness * 0.75F).drawFrame(getBox().getMinX(0.2F), getBox().getMinY(), getBox().getMinX(height + 0.2F), getBox().getMinY(height), color).translate(centerX, centerY); + if(isChecked()) + { + getRenderer().setBrightness(brightness * 0.7F).translate(0, 0, 0.001F).drawBuffers(buffer.selectionIterator(1), getBox().getWidth(), getBox().getHeight()).translate(0, 0, -0.001F); + } + if(isHovered(mouseX, mouseY)) + { + getRenderer().setBrightness(brightness * 1.3F).translate(0, 0, 0.002F).drawBuffers(buffer.selectionIterator(0), getBox().getWidth(), getBox().getHeight()).translate(0, 0, -0.002F); + } + float maxX = Math.min(boxWidth, getBox().getMaxX()); + getRenderer().setBrightness(1F).translate(-centerX, -centerY).drawQuad(getBox().getMinX(height), getBox().getMinY(), getBox().getMinX(maxX), getBox().getMaxY(), color).setBrightness(brightness * 0.75F).drawFrame(getBox().getMinX(height), getBox().getMinY(), getBox().getMinX(maxX), getBox().getMaxY(), color); + return true; + } + + protected boolean isCheckBoxHovered(int mouseX, int mouseY) + { + float height = getBox().getHeight(); + return getBox().getMinX() <= mouseX && getBox().getMinX(height) >= mouseX && getBox().getMinY() <= mouseY && getBox().getMinY(height) >= mouseY && getGui().hasComponentInTheWay(this, mouseX, mouseY); + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + return true; + } + + @Override + public void onRelease(int button, int mouseX, int mouseY) + { + setFlag(FLAG_CHECKED, !isFlagSet(FLAG_CHECKED)); + notifyListeners(LISTENER_USER_ACTION); + } + + @Override + protected boolean onUserKey() + { + setFlag(FLAG_CHECKED, !isFlagSet(FLAG_CHECKED)); + notifyListeners(LISTENER_USER_ACTION); + return true; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/menu/MenuComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/menu/MenuComponent.java index 2d8dcec..bae1731 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/menu/MenuComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/menu/MenuComponent.java @@ -1,318 +1,318 @@ -package speiger.src.coreengine.rendering.gui.components.menu; - -import java.util.List; -import java.util.function.Consumer; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.DynamicConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.MenuConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; - -public class MenuComponent extends MenuItemComponent implements Consumer -{ - static final int FLAG_OPEN = 1 << 21; - static final int FLAG_SUB_MENU = 1 << 22; - List components = new ObjectArrayList(); - float defaultScale = 1F; - float width = 0F; - float entryHeight = 10F; - float textScale = 1F; - long timeNotHovered = -1; - MenuComponent ownerMenu; - - public MenuComponent(String name) - { - super(name); - clearFlag(FLAG_SUPPORT_BINDING); - } - - public MenuComponent(float x, float y, float width, float height, String name) - { - super(x, y, width, height, name); - clearFlag(FLAG_SUPPORT_BINDING); - } - - @Override - public boolean canMoveIntoForground() - { - return true; - } - - public MenuComponent setHeight(float height) - { - entryHeight = height; - return this; - } - - protected MenuComponent setParent(MenuComponent owner) - { - ownerMenu = owner; - return this; - } - - @Override - protected void setMenuColor(int color) - { - super.setMenuColor(color); - for(int i = 0,m=components.size();i").setIsSubMenu(true).setParent(this)).cast(); - } - - public MenuItemComponent addText(String name) - { - return addMenuItem(new MenuTextComponent(name)).cast(); - } - - public MenuItemComponent addMenuItem(String name) - { - return addMenuItem(new MenuItemComponent(name)); - } - - public MenuCheckBoxComponent addCheckBox(String name) - { - return addMenuItem(new MenuCheckBoxComponent(name)).cast(); - } - - public MenuCheckBoxComponent addCheckBox(String name, boolean value) - { - return addMenuItem(new MenuCheckBoxComponent(name, value)).cast(); - } - - public MenuItemComponent addMenuItem(MenuItemComponent comp) - { - components.add(comp); - comp.setScale(defaultScale); - comp.setMenuColor(color); - addChild(comp.setIgnoreBounds(true).addUserActionListener(this), createConstrains(comp)).onChanged(false); - comp.setVisible(isFlagSet(FLAG_OPEN)); - comp.setTextScale(textScale); - return comp; - } - - protected Constrains createConstrains(MenuItemComponent comp) - { - Constrain constraint = isFlagSet(FLAG_SUB_MENU) ? new DynamicConstrain(() -> Math.max(getBox().getBaseWidth(), boxWidth / getBox().getScale())) : new PixelConstrain(); - return new Constrains(constraint, new MenuConstrain(components, isFlagSet(FLAG_SUB_MENU) ? MenuConstrain.DEFAULT : () -> getBox().getBaseHeight() + 0.1F).setPadding(0.01F), comp.createWidthConstriain(), new PixelConstrain(entryHeight)); - } - - @Override - public GuiComponent removeChild(GuiComponent comp) - { - super.removeChild(comp); - if(components.remove(comp)) - { - onChanged(false); - } - return this; - } - - @Override - public GuiComponent removeChildren() - { - components.clear(); - return super.removeChildren(); - } - - public void removeElements() - { - for(MenuItemComponent comp : components) - { - super.removeChild(comp); - } - components.clear(); - } - - @Override - protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) - { - if(isSubMenu() && isVisible()) - { - if(isFlagSet(FLAG_OPEN)) - { - if(isMouseOver(mouseX, mouseY) || isOverChild(mouseX, mouseY)) - { - timeNotHovered = -1; - return true; - } - if(timeNotHovered == -1) - { - timeNotHovered = getGlobalClock(); - } - if(getGlobalClock() - timeNotHovered > 10) - { - setOpen(false); - } - return true; - } - timeNotHovered = -1; - if(isMouseOver(mouseX, mouseY) && !ownerMenu.hasOtherMenuOpen(this)) - { - setOpen(true); - } - } - return true; - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - float brigthness = isFlagSet(FLAG_OPEN) ? 0.7F : getBrightness(mouseX, mouseY); - float minX = getBox().getMinX(0.2F); - float minY = getBox().getMinY(0.2F); - float maxX = Math.max(getBox().getMaxX(), minX + boxWidth); - float maxY = getBox().getMaxY(-0.2F); - getRenderer().setBrightness(brigthness).drawQuad(minX, minY, maxX, maxY, color).setBrightness(brigthness * 0.5F).drawFrame(minX, minY, maxX, maxY, color); - text.setBrightness(brigthness); - return true; - } - - @Override - public boolean onClick(int button, int mouseX, int mouseY) - { - if(!isSubMenu()) - { - setOpen(!isFlagSet(FLAG_OPEN)).notifyListeners(LISTENER_USER_ACTION); - } - return true; - } - - protected MenuComponent setIsSubMenu(boolean value) - { - if(setFlag(FLAG_SUB_MENU, value)) - { - setFlag(FLAG_KEEP_MENU_OPEN, value); - for(int i = 0,m=components.size();i +{ + static final int FLAG_OPEN = 1 << 21; + static final int FLAG_SUB_MENU = 1 << 22; + List components = new ObjectArrayList<>(); + float defaultScale = 1F; + float width = 0F; + float entryHeight = 10F; + float textScale = 1F; + long timeNotHovered = -1; + MenuComponent ownerMenu; + + public MenuComponent(String name) + { + super(name); + clearFlag(FLAG_SUPPORT_BINDING); + } + + public MenuComponent(float x, float y, float width, float height, String name) + { + super(x, y, width, height, name); + clearFlag(FLAG_SUPPORT_BINDING); + } + + @Override + public boolean canMoveIntoForground() + { + return true; + } + + public MenuComponent setHeight(float height) + { + entryHeight = height; + return this; + } + + protected MenuComponent setParent(MenuComponent owner) + { + ownerMenu = owner; + return this; + } + + @Override + protected void setMenuColor(int color) + { + super.setMenuColor(color); + for(int i = 0,m=components.size();i").setIsSubMenu(true).setParent(this)).cast(); + } + + public MenuItemComponent addText(String name) + { + return addMenuItem(new MenuTextComponent(name)).cast(); + } + + public MenuItemComponent addMenuItem(String name) + { + return addMenuItem(new MenuItemComponent(name)); + } + + public MenuCheckBoxComponent addCheckBox(String name) + { + return addMenuItem(new MenuCheckBoxComponent(name)).cast(); + } + + public MenuCheckBoxComponent addCheckBox(String name, boolean value) + { + return addMenuItem(new MenuCheckBoxComponent(name, value)).cast(); + } + + public MenuItemComponent addMenuItem(MenuItemComponent comp) + { + components.add(comp); + comp.setScale(defaultScale); + comp.setMenuColor(color); + addChild(comp.setIgnoreBounds(true).onAction(this), createConstrains(comp)).onChanged(false); + comp.setVisible(isFlagSet(FLAG_OPEN)); + comp.setTextScale(textScale); + return comp; + } + + protected Constrains createConstrains(MenuItemComponent comp) + { + Constrain constraint = isFlagSet(FLAG_SUB_MENU) ? new DynamicConstrain(() -> Math.max(getBox().getBaseWidth(), boxWidth / getBox().getScale())) : new PixelConstrain(); + return new Constrains(constraint, new MenuConstrain(components, isFlagSet(FLAG_SUB_MENU) ? MenuConstrain.DEFAULT : () -> getBox().getBaseHeight() + 0.1F).setPadding(0.01F), comp.createWidthConstriain(), new PixelConstrain(entryHeight)); + } + + @Override + public GuiComponent removeChild(GuiComponent comp) + { + super.removeChild(comp); + if(components.remove(comp)) + { + onChanged(false); + } + return this; + } + + @Override + public GuiComponent removeChildren() + { + components.clear(); + return super.removeChildren(); + } + + public void removeElements() + { + for(MenuItemComponent comp : components) + { + super.removeChild(comp); + } + components.clear(); + } + + @Override + protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) + { + if(isSubMenu() && isVisible()) + { + if(isFlagSet(FLAG_OPEN)) + { + if(isMouseOver(mouseX, mouseY) || isOverChild(mouseX, mouseY)) + { + timeNotHovered = -1; + return true; + } + if(timeNotHovered == -1) + { + timeNotHovered = getGlobalClock(); + } + if(getGlobalClock() - timeNotHovered > 10) + { + setOpen(false); + } + return true; + } + timeNotHovered = -1; + if(isMouseOver(mouseX, mouseY) && !ownerMenu.hasOtherMenuOpen(this)) + { + setOpen(true); + } + } + return true; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + float brigthness = isFlagSet(FLAG_OPEN) ? 0.7F : getBrightness(mouseX, mouseY); + float minX = getBox().getMinX(0.2F); + float minY = getBox().getMinY(0.2F); + float maxX = Math.max(getBox().getMaxX(), minX + boxWidth); + float maxY = getBox().getMaxY(-0.2F); + getRenderer().setBrightness(brigthness).drawQuad(minX, minY, maxX, maxY, color).setBrightness(brigthness * 0.5F).drawFrame(minX, minY, maxX, maxY, color); + text.setBrightness(brigthness); + return true; + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + if(!isSubMenu()) + { + setOpen(!isFlagSet(FLAG_OPEN)).notifyListeners(LISTENER_USER_ACTION); + } + return true; + } + + protected MenuComponent setIsSubMenu(boolean value) + { + if(setFlag(FLAG_SUB_MENU, value)) + { + setFlag(FLAG_KEEP_MENU_OPEN, value); + for(int i = 0,m=components.size();i> implements Consumer -{ - ObjectList checkboxes = new ObjectArrayList(); - int selectedIndex = -1; - Runnable listener; - - public CheckBoxGroup setListener(Runnable listener) - { - this.listener = listener; - return this; - } - - public T add(T box) - { - checkboxes.add(box); - if(box.isChecked()) - { - if(selectedIndex == -1) - { - selectedIndex = checkboxes.indexOf(box); - } - else - { - box.setChecked(false); - } - } - box.addUserActionListener(this); - return box; - } - - public boolean remove(T box) - { - boolean result = checkboxes.remove(box); - if(result) - { - if(box.isChecked()) - { - selectedIndex = -1; - } - box.removeChangeListener(this); - } - return result; - } - - public T getSelected() - { - return selectedIndex == -1 ? null : checkboxes.get(selectedIndex); - } - - public boolean hasSelected() - { - return selectedIndex != -1; - } - - public int getSelectedIndex() - { - return selectedIndex; - } - - public List getCheckBoxes() - { - return ObjectLists.unmodifiable(checkboxes); - } - - public void setChecked(int selected) - { - if(selectedIndex != -1) - { - checkboxes.get(selectedIndex).setChecked(false); - } - selectedIndex = selected; - if(selectedIndex != -1) - { - checkboxes.get(selectedIndex).setChecked(true); - } - } - - @Override - public void accept(GuiComponent t) - { - ICheckBox box = t.tryCast(ICheckBox.class); - if(box == null) - { - return; - } - int index = checkboxes.indexOf(t); - if(index == -1) - { - return; - } - if(box.isChecked()) - { - if(selectedIndex != -1) - { - checkboxes.get(selectedIndex).setChecked(false); - } - selectedIndex = index; - } - else - { - selectedIndex = -1; - } - if(listener != null) - { - listener.run(); - } - } -} +package speiger.src.coreengine.rendering.gui.components.misc; + +import java.util.List; +import java.util.function.Consumer; + +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.collections.objects.lists.ObjectList; +import speiger.src.collections.objects.utils.ObjectLists; +import speiger.src.coreengine.rendering.gui.GuiComponent; + +public class CheckBoxGroup> implements Consumer +{ + ObjectList checkboxes = new ObjectArrayList(); + int selectedIndex = -1; + Runnable listener; + + public CheckBoxGroup setListener(Runnable listener) + { + this.listener = listener; + return this; + } + + public T add(T box) + { + checkboxes.add(box); + if(box.isChecked()) + { + if(selectedIndex == -1) + { + selectedIndex = checkboxes.indexOf(box); + } + else + { + box.setChecked(false); + } + } + box.onAction(this); + return box; + } + + public boolean remove(T box) + { + boolean result = checkboxes.remove(box); + if(result) + { + if(box.isChecked()) + { + selectedIndex = -1; + } + box.removeChangeListener(this); + } + return result; + } + + public T getSelected() + { + return selectedIndex == -1 ? null : checkboxes.get(selectedIndex); + } + + public boolean hasSelected() + { + return selectedIndex != -1; + } + + public int getSelectedIndex() + { + return selectedIndex; + } + + public List getCheckBoxes() + { + return ObjectLists.unmodifiable(checkboxes); + } + + public void setChecked(int selected) + { + if(selectedIndex != -1) + { + checkboxes.get(selectedIndex).setChecked(false); + } + selectedIndex = selected; + if(selectedIndex != -1) + { + checkboxes.get(selectedIndex).setChecked(true); + } + } + + @Override + public void accept(GuiComponent t) + { + ICheckBox box = t.tryCast(ICheckBox.class); + if(box == null) + { + return; + } + int index = checkboxes.indexOf(t); + if(index == -1) + { + return; + } + if(box.isChecked()) + { + if(selectedIndex != -1) + { + checkboxes.get(selectedIndex).setChecked(false); + } + selectedIndex = index; + } + else + { + selectedIndex = -1; + } + if(listener != null) + { + listener.run(); + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/misc/ICheckBox.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/misc/ICheckBox.java index 4b8cf84..81cbc9e 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/misc/ICheckBox.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/misc/ICheckBox.java @@ -1,10 +1,10 @@ -package speiger.src.coreengine.rendering.gui.components.misc; - -import speiger.src.coreengine.rendering.gui.GuiComponent; - -public interface ICheckBox -{ - public boolean isChecked(); - - public T setChecked(boolean value); -} +package speiger.src.coreengine.rendering.gui.components.misc; + +import speiger.src.coreengine.rendering.gui.GuiComponent; + +public interface ICheckBox +{ + public boolean isChecked(); + + public T setChecked(boolean value); +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/special/ConsoleComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/special/ConsoleComponent.java index 10204e2..0f80268 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/special/ConsoleComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/special/ConsoleComponent.java @@ -1,223 +1,223 @@ -package speiger.src.coreengine.rendering.gui.components.special; - -import java.util.List; -import java.util.function.Consumer; - -import org.lwjgl.glfw.GLFW; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.base.IKeyComponent; -import speiger.src.coreengine.rendering.gui.components.ListComponent; -import speiger.src.coreengine.rendering.gui.components.ScrollBarComponent; -import speiger.src.coreengine.rendering.gui.components.TextFieldComponent; -import speiger.src.coreengine.rendering.gui.components.list.TextListEntry; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; -import speiger.src.coreengine.rendering.gui.renderer.IFontRenderer; - -public class ConsoleComponent extends GuiComponent implements IKeyComponent -{ - TextFieldComponent chat = new TextFieldComponent(ColorUtils.DARK_GRAY).setCanLoseFocus(false).setInfiniteText(true).setMaxTextLength(Integer.MAX_VALUE).setFocused(true); - ListComponent list = new ListComponent<>(ColorUtils.setA(ColorUtils.DARK_GRAY, 120), 8F); - float lastWidth = 0F; - List messages = new ObjectArrayList<>(); - Consumer listener; - int messageIterator = 0; - boolean started = false; - - public ConsoleComponent() - { - this(0F, 0F, 0F, 0F); - } - - public ConsoleComponent(float x, float y, float width, float height) - { - super(x, y, width, height); - } - - public ConsoleComponent setListener(Consumer listener) - { - this.listener = listener; - return this; - } - - @Override - public void init() - { - chat.getRawText().setTextScale(0.45F); - chat.addUserActionListener(this::onEnter); - list.setSelectionMode(ListComponent.SELECTION_MODE_DISABLE); - list.setStartAtBottom(true); - addChild(chat, new Constrains(new ParentConstrain(), new ParentConstrain(12F).invert(), new ParentConstrain(), new PixelConstrain(12F))); - addChild(list, new Constrains(new ParentConstrain(), new ParentConstrain(100).invert(), new RelativeConstrain(0.8F), new PixelConstrain(88))); - } - - @Override - protected void updateState() - { - float width = list.getBox().getWidth(); - if(lastWidth != width) - { - lastWidth = width; - updateMessages(); - } - } - - protected void updateMessages() - { - list.clear(); - for(int i = 0,m=messages.size();i 0) - { - messageIterator--; - chat.setText(messages.get((messages.size()-1 - messageIterator)).getMessage()).setCurserToEnd(); - } - else if(started) - { - chat.setText("").setCurserToEnd(); - started = false; - } - return true; - } - return false; - } - - public void addMessage(String text) - { - addMessage(text, 0); - } - - public void addMessage(String text, int messageId) - { - addMessage(text, messageId, true); - } - - private void addMessage(String text, int messageId, boolean add) - { - if(listener != null && text.startsWith("/")) - { - listener.accept(text.substring(1)); - return; - } - ScrollBarComponent scroll = list.getVerticalBar(); - boolean atEnd = scroll.isAtEnd(); - float width = (list.getBox().getWidth() -5F) / 0.45F; - for(String s : getGui().getFont().split(text, width, IFontRenderer.SPECIAL)) - { - list.add(new MessageEntry(s, messageId)); - } - if(atEnd) scroll.setScrollEnd(); - if(add) - { - messages.add(new ConsoleMessage(messageId, text)); - messageIterator = 0; - } - } - - public void clearMessages() - { - messages.clear(); - list.clear(); - messageIterator = 0; - } - - public void removeMessage(int messageId) - { - messages.removeIf(T -> T.getMessageId() == messageId); - list.removeIf(T -> T.getMessageId() == messageId); - } - - private static class ConsoleMessage - { - int messageId; - String message; - - public ConsoleMessage(int messageId, String message) - { - this.messageId = messageId; - this.message = message; - } - - public String getMessage() - { - return message; - } - - public int getMessageId() - { - return messageId; - } - } - - private static class MessageEntry extends TextListEntry - { - int messageId; - - public MessageEntry(String s, int messageId) - { - super(s); - this.messageId = messageId; - setScale(0.45F); - } - - public int getMessageId() - { - return messageId; - } - } +package speiger.src.coreengine.rendering.gui.components.special; + +import java.util.List; +import java.util.function.Consumer; + +import org.lwjgl.glfw.GLFW; + +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.base.IKeyComponent; +import speiger.src.coreengine.rendering.gui.components.ListComponent; +import speiger.src.coreengine.rendering.gui.components.ScrollBarComponent; +import speiger.src.coreengine.rendering.gui.components.TextFieldComponent; +import speiger.src.coreengine.rendering.gui.components.list.TextListEntry; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; +import speiger.src.coreengine.rendering.gui.renderer.IFontRenderer; + +public class ConsoleComponent extends GuiComponent implements IKeyComponent +{ + TextFieldComponent chat = new TextFieldComponent(ColorUtils.DARK_GRAY).setCanLoseFocus(false).setInfiniteText(true).setMaxTextLength(Integer.MAX_VALUE).setFocused(true); + ListComponent list = new ListComponent<>(ColorUtils.setA(ColorUtils.DARK_GRAY, 120), 8F); + float lastWidth = 0F; + List messages = new ObjectArrayList<>(); + Consumer listener; + int messageIterator = 0; + boolean started = false; + + public ConsoleComponent() + { + this(0F, 0F, 0F, 0F); + } + + public ConsoleComponent(float x, float y, float width, float height) + { + super(x, y, width, height); + } + + public ConsoleComponent setListener(Consumer listener) + { + this.listener = listener; + return this; + } + + @Override + public void init() + { + chat.getRawText().setTextScale(0.45F); + chat.onAction(this::onEnter); + list.setSelectionMode(ListComponent.SELECTION_MODE_DISABLE); + list.setStartAtBottom(true); + addChild(chat, new Constrains(new ParentConstrain(), new ParentConstrain(12F).invert(), new ParentConstrain(), new PixelConstrain(12F))); + addChild(list, new Constrains(new ParentConstrain(), new ParentConstrain(100).invert(), new RelativeConstrain(0.8F), new PixelConstrain(88))); + } + + @Override + protected void updateState() + { + float width = list.getBox().getWidth(); + if(lastWidth != width) + { + lastWidth = width; + updateMessages(); + } + } + + protected void updateMessages() + { + list.clear(); + for(int i = 0,m=messages.size();i 0) + { + messageIterator--; + chat.setText(messages.get((messages.size()-1 - messageIterator)).getMessage()).setCurserToEnd(); + } + else if(started) + { + chat.setText("").setCurserToEnd(); + started = false; + } + return true; + } + return false; + } + + public void addMessage(String text) + { + addMessage(text, 0); + } + + public void addMessage(String text, int messageId) + { + addMessage(text, messageId, true); + } + + private void addMessage(String text, int messageId, boolean add) + { + if(listener != null && text.startsWith("/")) + { + listener.accept(text.substring(1)); + return; + } + ScrollBarComponent scroll = list.getVerticalBar(); + boolean atEnd = scroll.isAtEnd(); + float width = (list.getBox().getWidth() -5F) / 0.45F; + for(String s : getGui().getFont().split(text, width, IFontRenderer.SPECIAL)) + { + list.add(new MessageEntry(s, messageId)); + } + if(atEnd) scroll.setScrollEnd(); + if(add) + { + messages.add(new ConsoleMessage(messageId, text)); + messageIterator = 0; + } + } + + public void clearMessages() + { + messages.clear(); + list.clear(); + messageIterator = 0; + } + + public void removeMessage(int messageId) + { + messages.removeIf(T -> T.getMessageId() == messageId); + list.removeIf(T -> T.getMessageId() == messageId); + } + + private static class ConsoleMessage + { + int messageId; + String message; + + public ConsoleMessage(int messageId, String message) + { + this.messageId = messageId; + this.message = message; + } + + public String getMessage() + { + return message; + } + + public int getMessageId() + { + return messageId; + } + } + + private static class MessageEntry extends TextListEntry + { + int messageId; + + public MessageEntry(String s, int messageId) + { + super(s); + this.messageId = messageId; + setScale(0.45F); + } + + public int getMessageId() + { + return messageId; + } + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/tree/ProfilerTreeEntry.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/tree/ProfilerTreeEntry.java index 7c73336..480cfa8 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/tree/ProfilerTreeEntry.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/tree/ProfilerTreeEntry.java @@ -1,129 +1,129 @@ -package speiger.src.coreengine.rendering.gui.components.tree; - -import java.util.Map; -import java.util.UUID; - -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.TextComponent; -import speiger.src.coreengine.rendering.gui.components.window.debug.PieProfilerWindowComponent; -import speiger.src.coreengine.rendering.gui.helper.Align; -import speiger.src.coreengine.rendering.input.Keyboard; -import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry; - -public class ProfilerTreeEntry extends BaseTreeEntry -{ - TextComponent text = new TextComponent().limit(false).align(Align.LEFT_TOP, Align.LEFT_TOP).special(true).setTextScale(0.4F).set(0F, 1F).cast(); - IProfilerEntry entry; - - public ProfilerTreeEntry(IProfilerEntry entry) - { - this.entry = entry; - } - - @Override - public float getWidth() - { - return text.getMetadata().getMaxWidth(); - } - - @Override - public void init(GuiComponent comp, GuiBase owner) - { - super.init(comp, owner); - text.setOwner(owner); - } - - @Override - public void updateState(GuiComponent comp, float scale) - { - text.setScale(scale); - } - - @Override - public void onClosed() - { - text.onClosed(); - } - - @Override - public void onFixedUpdate() - { - if(text.length() > 0 && (Keyboard.isAltDown() || text.getGui().getGlobalClock() % 2 != 0)) - { - return; - } - StringBuilder builder = new StringBuilder(); - builder.append(entry.getName()).append(": "); - builder.append(getColor(entry.getMinTime())).append(getTime(entry.getMinTime())).append("§").append(" / "); - builder.append(getColor(entry.getNanoTime())).append(getTime(entry.getNanoTime())).append("§").append(" / "); - builder.append(getColor(entry.getMaxTime())).append(getTime(entry.getMaxTime())).append("§"); - text.setText(builder.toString()); - } - - @Override - public void onRender(GuiComponent comp, boolean enabled, int mouseX, int mouseY, float particalTicks) - { - text.setEnabled(enabled).render(mouseX, mouseY, particalTicks); - } - - @Override - public void collectTooltips(GuiComponent comp, int mouseX, int mouseY, float particalTicks, Map collector) - { - - } - - @Override - public int hashCode() - { - return entry.getPathName().hashCode(); - } - - @Override - public boolean equals(Object obj) - { - if(obj instanceof ProfilerTreeEntry) - { - return ((ProfilerTreeEntry)obj).entry == entry; - } - return false; - } - - public String getTime(long time) - { - if(time >= 2000000L) - { - return PieProfilerWindowComponent.PERCENT_FORMAT.format(time / 1000000.0D) + "ms"; - } - if(time >= 2000L) - { - return PieProfilerWindowComponent.PERCENT_FORMAT.format(time / 1000.0D) + "µs"; - } - return PieProfilerWindowComponent.PERCENT_FORMAT.format(time) + "ns"; - } - - public String getColor(long time) - { - time /= 1000000L; - if(time < 1) - { - return "§"; - } - if(time >= 12) - { - return "§"; - } - if(time >= 5) - { - return "§"; - } - return "§"; - } - - @Override - public String toString() - { - return entry.getPathName(); - } -} +package speiger.src.coreengine.rendering.gui.components.tree; + +import java.util.Map; +import java.util.UUID; + +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.TextComponent; +import speiger.src.coreengine.rendering.gui.components.window.debug.PieProfilerWindow; +import speiger.src.coreengine.rendering.gui.helper.Align; +import speiger.src.coreengine.rendering.input.Keyboard; +import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry; + +public class ProfilerTreeEntry extends BaseTreeEntry +{ + TextComponent text = new TextComponent().limit(false).align(Align.LEFT_TOP, Align.LEFT_TOP).special(true).setTextScale(0.4F).set(0F, 1F).cast(); + IProfilerEntry entry; + + public ProfilerTreeEntry(IProfilerEntry entry) + { + this.entry = entry; + } + + @Override + public float getWidth() + { + return text.getMetadata().getMaxWidth(); + } + + @Override + public void init(GuiComponent comp, GuiBase owner) + { + super.init(comp, owner); + text.setOwner(owner); + } + + @Override + public void updateState(GuiComponent comp, float scale) + { + text.setScale(scale); + } + + @Override + public void onClosed() + { + text.onClosed(); + } + + @Override + public void onFixedUpdate() + { + if(text.length() > 0 && (Keyboard.isAltDown() || text.getGui().getGlobalClock() % 2 != 0)) + { + return; + } + StringBuilder builder = new StringBuilder(); + builder.append(entry.getName()).append(": "); + builder.append(getColor(entry.getMinTime())).append(getTime(entry.getMinTime())).append("§").append(" / "); + builder.append(getColor(entry.getNanoTime())).append(getTime(entry.getNanoTime())).append("§").append(" / "); + builder.append(getColor(entry.getMaxTime())).append(getTime(entry.getMaxTime())).append("§"); + text.setText(builder.toString()); + } + + @Override + public void onRender(GuiComponent comp, boolean enabled, int mouseX, int mouseY, float particalTicks) + { + text.setEnabled(enabled).render(mouseX, mouseY, particalTicks); + } + + @Override + public void collectTooltips(GuiComponent comp, int mouseX, int mouseY, float particalTicks, Map collector) + { + + } + + @Override + public int hashCode() + { + return entry.getPathName().hashCode(); + } + + @Override + public boolean equals(Object obj) + { + if(obj instanceof ProfilerTreeEntry) + { + return ((ProfilerTreeEntry)obj).entry == entry; + } + return false; + } + + public String getTime(long time) + { + if(time >= 2000000L) + { + return PieProfilerWindow.PERCENT_FORMAT.format(time / 1000000.0D) + "ms"; + } + if(time >= 2000L) + { + return PieProfilerWindow.PERCENT_FORMAT.format(time / 1000.0D) + "µs"; + } + return PieProfilerWindow.PERCENT_FORMAT.format(time) + "ns"; + } + + public String getColor(long time) + { + time /= 1000000L; + if(time < 1) + { + return "§"; + } + if(time >= 12) + { + return "§"; + } + if(time >= 5) + { + return "§"; + } + return "§"; + } + + @Override + public String toString() + { + return entry.getPathName(); + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/color/ColorPickerWindowComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/color/ColorPickerWindowComponent.java index 8307037..8317a39 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/color/ColorPickerWindowComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/color/ColorPickerWindowComponent.java @@ -1,153 +1,153 @@ -package speiger.src.coreengine.rendering.gui.components.window.color; - -import java.awt.Color; -import java.util.function.IntConsumer; - -import speiger.src.coreengine.math.MathUtils; -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.math.misc.Facing; -import speiger.src.coreengine.math.vector.floats.Vec2f; -import speiger.src.coreengine.rendering.gui.UITextures; -import speiger.src.coreengine.rendering.gui.components.ButtonComponent; -import speiger.src.coreengine.rendering.gui.components.GradientSliderComponent; -import speiger.src.coreengine.rendering.gui.components.SliderComponent; -import speiger.src.coreengine.rendering.gui.components.TextFieldComponent; -import speiger.src.coreengine.rendering.gui.components.WindowComponent; -import speiger.src.coreengine.rendering.gui.components.icon.IIcon; -import speiger.src.coreengine.rendering.gui.components.icon.TexturedIcon; -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.Constrains; -import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; -import speiger.src.coreengine.utils.functions.Functions; -import speiger.src.coreengine.utils.helpers.InternalThreadPools; - -public class ColorPickerWindowComponent extends WindowComponent -{ - IntConsumer listener; - IIcon wheelIcon = new TexturedIcon(UITextures.COLOR_WHEEL); - IGuiBox wheelBox = new GuiBox(15, 10, 70, 70); - IGuiBox selectedBox = new GuiBox(5F, 94F, 50F, 10F); - int[] colors = new int[]{ColorUtils.rgb(0), ColorUtils.rgb(0), ColorUtils.rgb(0), ColorUtils.rgb(0), ColorUtils.rgb(0)}; - SliderComponent brightness = new GradientSliderComponent(95, 13, 17, 76, 0, 100, 0, ColorUtils.GRAY, colors[2], colors[3], Facing.NORTH, null).setScrollEffect(-1).setVertical(true); - SliderComponent saturation = new GradientSliderComponent(110, 13, 17, 76, 0, 100, 0, ColorUtils.GRAY, colors[0], colors[1], Facing.NORTH, null).setScrollEffect(-1).setVertical(true); - TextFieldComponent code = new TextFieldComponent(60, 94, 104, 20, ColorUtils.DARK_GRAY).setValidator(Functions.NUMBERS_ONLY).setMaxTextLength(8); - float[] hsv = new float[3]; - IGuiBox[] colorBoxes; - ColorPool pool; - - public ColorPickerWindowComponent(float x, float y, ColorPool pool, int defaultColor, IntConsumer listener, String name) - { - super(x, y, 125, 140, FIXED_SIZE_POPUP, name); - this.pool = pool; - this.listener = listener; - hsv = ColorUtils.toHue(defaultColor); - colorBoxes = new IGuiBox[Math.min(18, pool.size())]; - for(int i = 0,m=colorBoxes.length;i= 9 ? 12 : 0), 10, 10)); - } - } - - @Override - public void init() - { - super.init(); - addBox(wheelBox); - addBox(selectedBox); - addChild(brightness.addChangeListener(minimizedListener).addUserActionListener(T -> setColor(hsv[0], hsv[1], T.cast(SliderComponent.class).getValue() * 0.01F))); - addChild(saturation.addChangeListener(minimizedListener).addUserActionListener(T -> setColor(hsv[0], T.cast(SliderComponent.class).getValue() * 0.01F, hsv[2]))); - addChild(code.setScale(0.5F).addChangeListener(minimizedListener).addUserActionListener(T -> onTyped())); - addChild(new ButtonComponent(0F, 0F, 0F, 20F, "Select", ColorUtils.GREEN).setScale(0.4F).addUserActionListener(T -> apply()), new Constrains(null, new ParentConstrain(8F).invert(), new RelativeConstrain(0.5F / 0.4F), null)); - addChild(new ButtonComponent(0F, 0F, 0F, 20F, "Cancel", ColorUtils.RED).setScale(0.4F).addUserActionListener(T -> T.getGui().removeComponent(this)), new Constrains(new RelativeConstrain(0.5F), new ParentConstrain(8F).invert(), new RelativeConstrain(0.5F / 0.4F), null)); - setColor(hsv[0], hsv[1], hsv[2]); - } - - @Override - public boolean isPopup() - { - return true; - } - - @Override - protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) - { - super.renderSelf(mouseX, mouseY, particalTicks); - wheelIcon.render(getRenderer().translate(0F, 0F, 0.01F).setBrightness(hsv[1]), wheelBox); - getRenderer().setBrightness(1F); - for(int i = 0,m=colorBoxes.length;i> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, new float[3]); - setColor(hsv[0], hsv[1], hsv[2]); - } - catch(Exception e){} - } - - public void apply() - { - pool.addColor(colors[4]); - listener.accept(colors[4]); - getGui().removeComponent(this); - } - - @Override - public boolean onClick(int button, int mouseX, int mouseY) - { - return wheelBox.isColiding(mouseX, mouseY) ? onChanged(mouseX, mouseY) : super.onClick(button, mouseX, mouseY); - } - - @Override - public boolean onDrag(int mouseX, int mouseY) - { - return super.onDrag(mouseX, mouseY) || (wheelBox.isColiding(mouseX, mouseY) ? onChanged(mouseX, mouseY) : false); - } - - private boolean onChanged(int mouseX, int mouseY) - { - Vec2f pos = InternalThreadPools.VEC2F.get().set(mouseX, mouseY); - float radius = (float)pos.distanceTo(wheelBox.getCenterX(), wheelBox.getCenterY()); - if(radius > 38) - { - InternalThreadPools.VEC2F.accept(pos); - return false; - } - float hue = (pos.directionAngle(wheelBox.getCenterX(), wheelBox.getCenterY()) + 180F) % 360F; - setColor(hue / 360F, hsv[1], radius / 33F); - InternalThreadPools.VEC2F.accept(pos); - return true; - } - - protected void setColor(float hue, float saturation, float brightness) - { - hsv[0] = MathUtils.clamp(0F, 1F, hue); - hsv[1] = MathUtils.clamp(0F, 1F, saturation); - hsv[2] = MathUtils.clamp(0F, 1F, brightness); - colors[0] = ColorUtils.toRGB(hsv[0], 0F, 1F); - colors[1] = ColorUtils.toRGB(hsv[0], 1F, 1F); - colors[2] = ColorUtils.toRGB(hsv[0], 1F, 0F); - colors[3] = ColorUtils.toRGB(hsv[0], 1F, 1F); - colors[4] = ColorUtils.toRGB(hsv[0], hsv[1], hsv[2]); - code.setText(ColorUtils.getHTMLCode(colors[4], false)); - this.brightness.setValue((int)(hsv[2] * 100F)); - this.saturation.setValue((int)(hsv[1] * 100F)); - } -} +package speiger.src.coreengine.rendering.gui.components.window.color; + +import java.awt.Color; +import java.util.function.IntConsumer; + +import speiger.src.coreengine.math.MathUtils; +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.math.misc.Facing; +import speiger.src.coreengine.math.vector.floats.Vec2f; +import speiger.src.coreengine.rendering.gui.UITextures; +import speiger.src.coreengine.rendering.gui.components.ButtonComponent; +import speiger.src.coreengine.rendering.gui.components.GradientSliderComponent; +import speiger.src.coreengine.rendering.gui.components.SliderComponent; +import speiger.src.coreengine.rendering.gui.components.TextFieldComponent; +import speiger.src.coreengine.rendering.gui.components.WindowComponent; +import speiger.src.coreengine.rendering.gui.components.icon.IIcon; +import speiger.src.coreengine.rendering.gui.components.icon.TexturedIcon; +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.Constrains; +import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; +import speiger.src.coreengine.utils.functions.Functions; +import speiger.src.coreengine.utils.helpers.InternalThreadPools; + +public class ColorPickerWindowComponent extends WindowComponent +{ + IntConsumer listener; + IIcon wheelIcon = new TexturedIcon(UITextures.COLOR_WHEEL); + IGuiBox wheelBox = new GuiBox(15, 10, 70, 70); + IGuiBox selectedBox = new GuiBox(5F, 94F, 50F, 10F); + int[] colors = new int[]{ColorUtils.rgb(0), ColorUtils.rgb(0), ColorUtils.rgb(0), ColorUtils.rgb(0), ColorUtils.rgb(0)}; + SliderComponent brightness = new GradientSliderComponent(95, 13, 17, 76, 0, 100, 0, ColorUtils.GRAY, colors[2], colors[3], Facing.NORTH, null).setScrollEffect(-1).setVertical(true); + SliderComponent saturation = new GradientSliderComponent(110, 13, 17, 76, 0, 100, 0, ColorUtils.GRAY, colors[0], colors[1], Facing.NORTH, null).setScrollEffect(-1).setVertical(true); + TextFieldComponent code = new TextFieldComponent(60, 94, 104, 20, ColorUtils.DARK_GRAY).setValidator(Functions.NUMBERS_ONLY).setMaxTextLength(8); + float[] hsv = new float[3]; + IGuiBox[] colorBoxes; + ColorPool pool; + + public ColorPickerWindowComponent(float x, float y, ColorPool pool, int defaultColor, IntConsumer listener, String name) + { + super(x, y, 125, 140, FIXED_SIZE_POPUP, name); + this.pool = pool; + this.listener = listener; + hsv = ColorUtils.toHue(defaultColor); + colorBoxes = new IGuiBox[Math.min(18, pool.size())]; + for(int i = 0,m=colorBoxes.length;i= 9 ? 12 : 0), 10, 10)); + } + } + + @Override + public void init() + { + super.init(); + addBox(wheelBox); + addBox(selectedBox); + addChild(brightness.onChange(minimizedListener).onAction(T -> setColor(hsv[0], hsv[1], T.cast(SliderComponent.class).getValue() * 0.01F))); + addChild(saturation.onChange(minimizedListener).onAction(T -> setColor(hsv[0], T.cast(SliderComponent.class).getValue() * 0.01F, hsv[2]))); + addChild(code.setScale(0.5F).onChange(minimizedListener).onAction(T -> onTyped())); + addChild(new ButtonComponent(0F, 0F, 0F, 20F, "Select", ColorUtils.GREEN).setScale(0.4F).onAction(T -> apply()), new Constrains(null, new ParentConstrain(8F).invert(), new RelativeConstrain(0.5F / 0.4F), null)); + addChild(new ButtonComponent(0F, 0F, 0F, 20F, "Cancel", ColorUtils.RED).setScale(0.4F).onAction(T -> T.getGui().removeComponent(this)), new Constrains(new RelativeConstrain(0.5F), new ParentConstrain(8F).invert(), new RelativeConstrain(0.5F / 0.4F), null)); + setColor(hsv[0], hsv[1], hsv[2]); + } + + @Override + public boolean isPopup() + { + return true; + } + + @Override + protected boolean renderSelf(int mouseX, int mouseY, float particalTicks) + { + super.renderSelf(mouseX, mouseY, particalTicks); + wheelIcon.render(getRenderer().translate(0F, 0F, 0.01F).setBrightness(hsv[1]), wheelBox); + getRenderer().setBrightness(1F); + for(int i = 0,m=colorBoxes.length;i> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, new float[3]); + setColor(hsv[0], hsv[1], hsv[2]); + } + catch(Exception e){} + } + + public void apply() + { + pool.addColor(colors[4]); + listener.accept(colors[4]); + getGui().removeComponent(this); + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + return wheelBox.isColiding(mouseX, mouseY) ? onChanged(mouseX, mouseY) : super.onClick(button, mouseX, mouseY); + } + + @Override + public boolean onDrag(int mouseX, int mouseY) + { + return super.onDrag(mouseX, mouseY) || (wheelBox.isColiding(mouseX, mouseY) ? onChanged(mouseX, mouseY) : false); + } + + private boolean onChanged(int mouseX, int mouseY) + { + Vec2f pos = InternalThreadPools.VEC2F.get().set(mouseX, mouseY); + float radius = (float)pos.distanceTo(wheelBox.getCenterX(), wheelBox.getCenterY()); + if(radius > 38) + { + InternalThreadPools.VEC2F.accept(pos); + return false; + } + float hue = (pos.directionAngle(wheelBox.getCenterX(), wheelBox.getCenterY()) + 180F) % 360F; + setColor(hue / 360F, hsv[1], radius / 33F); + InternalThreadPools.VEC2F.accept(pos); + return true; + } + + protected void setColor(float hue, float saturation, float brightness) + { + hsv[0] = MathUtils.clamp(0F, 1F, hue); + hsv[1] = MathUtils.clamp(0F, 1F, saturation); + hsv[2] = MathUtils.clamp(0F, 1F, brightness); + colors[0] = ColorUtils.toRGB(hsv[0], 0F, 1F); + colors[1] = ColorUtils.toRGB(hsv[0], 1F, 1F); + colors[2] = ColorUtils.toRGB(hsv[0], 1F, 0F); + colors[3] = ColorUtils.toRGB(hsv[0], 1F, 1F); + colors[4] = ColorUtils.toRGB(hsv[0], hsv[1], hsv[2]); + code.setText(ColorUtils.getHTMLCode(colors[4], false)); + this.brightness.setValue((int)(hsv[2] * 100F)); + this.saturation.setValue((int)(hsv[1] * 100F)); + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/PieProfilerWindowComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/PieProfilerWindow.java similarity index 59% rename from src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/PieProfilerWindowComponent.java rename to src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/PieProfilerWindow.java index a81caf4..3da08fb 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/PieProfilerWindowComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/PieProfilerWindow.java @@ -1,306 +1,324 @@ -package speiger.src.coreengine.rendering.gui.components.window.debug; - -import java.text.DecimalFormat; -import java.util.List; -import java.util.function.Supplier; - -import org.lwjgl.glfw.GLFW; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.collections.objects.utils.ObjectLists; -import speiger.src.coreengine.math.MathUtils; -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.math.vector.floats.Vec2f; -import speiger.src.coreengine.rendering.gui.GuiManager; -import speiger.src.coreengine.rendering.gui.base.IKeyComponent; -import speiger.src.coreengine.rendering.gui.components.ButtonComponent; -import speiger.src.coreengine.rendering.gui.components.PieComponent; -import speiger.src.coreengine.rendering.gui.components.PieComponent.IPieIndex; -import speiger.src.coreengine.rendering.gui.components.PieComponent.PieIndex; -import speiger.src.coreengine.rendering.gui.components.TextComponent; -import speiger.src.coreengine.rendering.gui.components.WindowComponent; -import speiger.src.coreengine.rendering.gui.helper.Align; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.DynamicConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; -import speiger.src.coreengine.rendering.input.Keyboard; -import speiger.src.coreengine.utils.profiler.IProfiler; -import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry; -import speiger.src.coreengine.utils.profiler.IProfiler.ProfilerData; - -public class PieProfilerWindowComponent extends WindowComponent - implements Supplier>, IKeyComponent -{ - public static final DecimalFormat PERCENT_FORMAT = new DecimalFormat("##0.00"); - - PieComponent pie = new PieComponent(127, this); - ButtonComponent[] buttons = new ButtonComponent[3]; - TextComponent[] extraFeatures = new TextComponent[3]; - List entries = new ObjectArrayList(); - int textInUse = 0; - IProfiler profiler; - IProfilerEntry currentEntry; - String entryName; - List lastValues = null; - - public PieProfilerWindowComponent(float x, float y, float width, float height, String name) - { - super(x, y, width, height, DEFAULT_FLAGS, name); - } - - @Override - public boolean canMoveIntoForground() - { - return true; - } - - @Override - public void init() - { - super.init(); - addChild(pie.setAutoUpdate(true).set(0F, 5F).addChangeListener(minimizedListener), new Constrains(null, null, new ParentConstrain(), new DynamicConstrain(this::calculatePieHeight))); - buttons[0] = createButton(0, "Client"); - buttons[1] = createButton(1, "GPU"); - buttons[2] = createButton(2, "Server"); - extraFeatures[0] = new TextComponent(0F, 0F, 18F, 5.5F).setTextScale(0.3F).setText("[0] Back").align(Align.LEFT_TOP, Align.CENTER); - extraFeatures[0].addChangeListener(T -> T.setVisible(!isMinimized() && currentEntry != null && currentEntry.getParent() != null)); - addChild(extraFeatures[0], new Constrains(null, new DynamicConstrain(() -> pie.getBox().getBaseHeight() + (-5.5F)), new PixelConstrain(38).setInverted(), null)); - - extraFeatures[1] = new TextComponent(0F, 0F, 0F, 7F).setTextScale(0.4F).setText("Client Thread"); - addChild(extraFeatures[1].addChangeListener(minimizedListener), new Constrains(null, new PixelConstrain(8F), new ParentConstrain(), null)); - extraFeatures[2] = new TextComponent(0F, 0F, 0F, 6F).setTextScale(0.33F).setText("Client"); - addChild(extraFeatures[2].addChangeListener(minimizedListener), new Constrains(null, new PixelConstrain(15F), new ParentConstrain(), null)); - - } - - @Override - public void onClosed() - { - super.onClosed(); - if(profiler != null) - { - profiler.disable(); - profiler = null; - } - } - - public PieProfilerWindowComponent setProfiler(IProfiler profiler, String root) - { - if(this.profiler != null) - { - buttons[getProfilerIndex(this.profiler)].setEnabled(true); - this.profiler.disable(); - } - this.profiler = profiler; - if(profiler != null) - { - profiler.enable(); - setCurrentEntry(root); - buttons[getProfilerIndex(this.profiler)].setEnabled(false); - extraFeatures[1].setText(profiler.getName()); - } - return this; - } - - public PieProfilerWindowComponent setCurrentEntry(String name) - { - entryName = name; - currentEntry = profiler.getEntry(name); - lastValues = null; - extraFeatures[2].setText(currentEntry == null ? "Unknown" : currentEntry.getName()); - return this; - } - - @Override - protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) - { - for(int i = 0,m=entries.size();i= GLFW.GLFW_KEY_1 && key <= GLFW.GLFW_KEY_9) - { - key -= GLFW.GLFW_KEY_1; - if(key < textInUse) - { - String s = entries.get(key)[0].getText(); - s = s.substring(s.indexOf("] ")+2); - if(!s.equalsIgnoreCase("Nameless")) - { - setCurrentEntry(currentEntry.getPathName() + "/" + s); - return true; - } - } - return false; - } - return false; - } - - @Override - public Vec2f getMinimumBounds() - { - return Vec2f.of(80F, 80F + (textInUse * 5.5F)); - } - - @Override - public List get() - { - if(lastValues != null) - { - List entries = new ObjectArrayList(); - for(int i = 0, m = lastValues.size();i < m;i++) - { - entries.add(new PieIndex(MathUtils.floor(lastValues.get(i).getEffect() * 1.28D), lastValues.get(i).getColor())); - } - return entries; - } - return ObjectLists.singleton(new PieIndex(pie.getMaxSteps(), ColorUtils.LIGHT_BLUE)); - } - - protected float calculatePieHeight() - { - return getBox().getBaseHeight() - ((textInUse * 5.5F) + 9F); - } - - public IProfiler getProfiler(int index) - { - GuiManager manager = getGui().getUIManager(); - switch(index) - { - case 1: - return manager.getGPUProfiler(); - case 2: - return manager.getServerProfiler(); - default: - return manager.getCPUProfiler(); - } - } - - public int getProfilerIndex(IProfiler prof) - { - GuiManager manager = getGui().getUIManager(); - return manager.getGPUProfiler() == prof ? 1 : manager.getServerProfiler() == prof ? 2 : 0; - } - - public static String getRoot(int index) - { - return index < 2 ? "Client" : "Server"; - } - - protected TextComponent createComponent(int column) - { - final int index = entries.size(); - String text = column == 0 ? "[" + (entries.size() + 1) + "] Unknown" : PERCENT_FORMAT.format(0D) + "%"; - TextComponent comp = new TextComponent(0F, 0F, 18F, 5.5F).setTextScale(0.3F).setText(text).align(column == 0 ? Align.LEFT_TOP : Align.RIGHT_BOTTOM, Align.CENTER); - comp.addChangeListener(T -> T.setVisible(!isMinimized() && index < textInUse)); - Constrain xPos = column == 0 ? null : (column == 1 ? new PixelConstrain(38F).setInverted() : new PixelConstrain(19F).setInverted()); - addChild(comp, new Constrains(xPos, new DynamicConstrain(() -> pie.getBox().getBaseHeight() + (index * 5.5F)), column == 0 ? new PixelConstrain(38).setInverted() : null, null)); - return comp; - } - - protected ButtonComponent createButton(int index, String name) - { - ButtonComponent button = new ButtonComponent(name, ColorUtils.GRAY); - button.getText().setTextScale(0.3F); - button.addChangeListener(minimizedListener).addUserActionListener(T -> setProfiler(getProfiler(index), getRoot(index))); - addChild(button, new Constrains(new RelativeConstrain(index * 0.3333F), new PixelConstrain(8F).setInverted(), new RelativeConstrain(0.3333F), new PixelConstrain(7F))); - return button; - } -} +package speiger.src.coreengine.rendering.gui.components.window.debug; + +import java.text.DecimalFormat; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.lwjgl.glfw.GLFW; + +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.collections.objects.utils.ObjectLists; +import speiger.src.coreengine.math.MathUtils; +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.math.misc.Facing; +import speiger.src.coreengine.math.vector.floats.Vec2f; +import speiger.src.coreengine.rendering.gui.base.IKeyComponent; +import speiger.src.coreengine.rendering.gui.components.PieComponent; +import speiger.src.coreengine.rendering.gui.components.PieComponent.IPieIndex; +import speiger.src.coreengine.rendering.gui.components.PieComponent.PieIndex; +import speiger.src.coreengine.rendering.gui.components.SingleTabPanelComponent; +import speiger.src.coreengine.rendering.gui.components.TextComponent; +import speiger.src.coreengine.rendering.gui.components.WindowComponent; +import speiger.src.coreengine.rendering.gui.helper.Align; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain.Target; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.helper.constrains.DynamicConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; +import speiger.src.coreengine.rendering.input.Keyboard; +import speiger.src.coreengine.utils.profiler.IProfiler; +import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry; +import speiger.src.coreengine.utils.profiler.IProfiler.ProfilerData; + +public class PieProfilerWindow extends WindowComponent implements Supplier>, IKeyComponent +{ + public static final DecimalFormat PERCENT_FORMAT = new DecimalFormat("##0.00"); + + SingleTabPanelComponent panel = new SingleTabPanelComponent(Facing.SOUTH).onAction(this::onProfilerChanged).cast(); + PieComponent pie = panel.getPanel().addChild(new PieComponent(127, this).setAutoUpdate(true), Constrains.parent(Target.WIDTH).dynamic(this::calculatePieHeight, Target.HEIGHT).build()); + TextComponent[] extraFeatures = new TextComponent[] { + new TextComponent(0F, 0F, 18F, 7F), + new TextComponent(0F, 0F, 0F, 8F), + new TextComponent(0F, 8F, 0F, 7F) + }; + List entries = new ObjectArrayList<>(); + List tabs = new ObjectArrayList<>(); + int previouseTab = -1; + int textInUse = 0; + IProfilerEntry currentEntry; + String entryName; + List lastValues = null; + + public PieProfilerWindow(float x, float y, float width, float height, String name) + { + super(x, y, width, height, DEFAULT_FLAGS, name); + } + + @Override + public boolean canMoveIntoForground() + { + return true; + } + + @Override + public void init() + { + super.init(); + addChild(panel.set(0F, 7.5F).onChange(minimizedListener), Constrains.parent(0.25F, Target.WIDTH).parent(4F, Target.HEIGHT).build()); + extraFeatures[0].setTextScale(0.3F).setText("[0] Back").horizontal(Align.LEFT_TOP); + extraFeatures[0].onChange(T -> T.setVisible(currentEntry != null && currentEntry.getParent() != null)); + panel.getPanel().addChild(extraFeatures[0], Constrains.dynamic(() -> pie.getBox().getBaseHeight() - 7F, Target.Y).invPixel(38F, Target.WIDTH).build()); + + panel.getPanel().addChild(extraFeatures[1].setTextScale(0.4F), Constrains.parent(0F, Target.Y).parent(Target.WIDTH).build()); + panel.getPanel().addChild(extraFeatures[2].setTextScale(0.33F), Constrains.pixel(8F, Target.Y).parent(Target.WIDTH).build()); + } + + public PieProfilerWindow addProfiler(IProfiler profiler, String root) + { + String name = profiler.getName(); + panel.addTab(name); + tabs.add(new ProfilerTab(name, profiler, root)); + if(tabs.size() == 1) + { + onProfilerChanged(); + } + return this; + } + + protected IProfiler getActive() + { + return tabs.get(panel.getActiveIndex()).getProfiler(); + } + + protected void applyProfiler(boolean prev, Consumer action) + { + int index = prev ? previouseTab : panel.getActiveIndex(); + if(index >= 0) action.accept(tabs.get(index).getProfiler()); + } + + @Override + public void onClosed() + { + super.onClosed(); + applyProfiler(false, IProfiler::disable); + } + + protected void onProfilerChanged() + { + if(previouseTab == panel.getActiveIndex()) return; + applyProfiler(true, IProfiler::disable); + applyProfiler(false, IProfiler::enable); + previouseTab = panel.getActiveIndex(); + ProfilerTab tab = tabs.get(previouseTab); + extraFeatures[1].setText(tab.getName()); + setCurrentEntry(tab.getRoot()); + } + + public SingleTabPanelComponent getTab() + { + return panel; + } + + public PieProfilerWindow setCurrentEntry(String name) + { + entryName = name; + currentEntry = getActive().getEntry(name); + lastValues = null; + extraFeatures[2].setText(currentEntry == null ? "Unknown" : currentEntry.getName()); + return this; + } + + @Override + protected boolean updateSelf(int mouseX, int mouseY, float particalTicks) + { + for(int i = 0,m=entries.size();i 0) { + resize(0F, diff); + } + onChanged(true); + } + else if(lastEmpty) + { + onChanged(true); + } + return true; + } + + @Override + public boolean onClick(int button, int mouseX, int mouseY) + { + if(super.onClick(button, mouseX, mouseY)) + { + return true; + } + if(currentEntry != null && currentEntry.getParent() != null && extraFeatures[0].isHovered(mouseX, mouseY)) + { + setCurrentEntry(currentEntry.getParent().getPathName()); + } + if(lastValues != null) + { + for(int i = 0;i= GLFW.GLFW_KEY_1 && key <= GLFW.GLFW_KEY_9) + { + key -= GLFW.GLFW_KEY_1; + if(key < textInUse) + { + String s = entries.get(key)[0].getText(); + s = s.substring(s.indexOf("] ")+2); + if(!s.equalsIgnoreCase("Nameless")) + { + setCurrentEntry(currentEntry.getPathName() + "/" + s); + return true; + } + } + return false; + } + return false; + } + + @Override + public Vec2f getMinimumBounds() + { + return Vec2f.of(80F, 80F + (textInUse * 7F)); + } + + @Override + public List get() + { + if(lastValues != null) + { + List entries = new ObjectArrayList<>(); + for(int i = 0, m = lastValues.size();i < m;i++) + { + entries.add(new PieIndex(MathUtils.floor(lastValues.get(i).getEffect() * 1.28D), lastValues.get(i).getColor())); + } + return entries; + } + return ObjectLists.singleton(new PieIndex(pie.getMaxSteps(), ColorUtils.LIGHT_BLUE)); + } + + protected float calculatePieHeight() + { + return getBox().getBaseHeight() - ((textInUse * 7) + 17F); + } + + protected TextComponent createComponent(int column) + { + final int index = entries.size(); + String text = column == 0 ? "[" + (entries.size() + 1) + "] Unknown" : PERCENT_FORMAT.format(0D) + "%"; + TextComponent comp = new TextComponent(0F, 0F, 18F, 7F).setTextScale(0.33F).setText(text).align(column == 0 ? Align.LEFT_TOP : Align.RIGHT_BOTTOM, Align.CENTER); + comp.onChange(T -> T.setVisible(index < textInUse)); + Constrain xPos = column == 0 ? null : (column == 1 ? new PixelConstrain(38F).setInverted() : new PixelConstrain(19F).setInverted()); + panel.getPanel().addChild(comp, new Constrains(xPos, new DynamicConstrain(() -> pie.getBox().getBaseHeight() + (index * 7F)), column == 0 ? new PixelConstrain(38).setInverted() : null, null)); + return comp; + } + + private static class ProfilerTab + { + String name; + IProfiler profiler; + String root; + + public ProfilerTab(String name, IProfiler profiler, String root) + { + this.name = name; + this.profiler = profiler; + this.root = root; + } + + public String getName() + { + return name; + } + + public IProfiler getProfiler() + { + return profiler; + } + + public String getRoot() + { + return root; + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/TreeProfilerWindow.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/TreeProfilerWindow.java new file mode 100644 index 0000000..dd6068c --- /dev/null +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/TreeProfilerWindow.java @@ -0,0 +1,216 @@ +package speiger.src.coreengine.rendering.gui.components.window.debug; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.ObjIntConsumer; + +import speiger.src.collections.ints.queues.IntArrayFIFOQueue; +import speiger.src.collections.ints.queues.IntPriorityQueue; +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.math.misc.Facing; +import speiger.src.coreengine.math.vector.floats.Vec2f; +import speiger.src.coreengine.rendering.gui.components.SingleTabPanelComponent; +import speiger.src.coreengine.rendering.gui.components.TreeComponent; +import speiger.src.coreengine.rendering.gui.components.WindowComponent; +import speiger.src.coreengine.rendering.gui.components.tree.ProfilerTreeEntry; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain.Target; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.utils.profiler.IProfiler; +import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry; + +public class TreeProfilerWindow extends WindowComponent +{ + IntPriorityQueue todoList = new IntArrayFIFOQueue().synchronizeQueue(); + ObjIntConsumer listener = (T, V) -> todoList.enqueue(V); + SingleTabPanelComponent panel = new SingleTabPanelComponent(Facing.SOUTH).onAction(this::onProfilerChanged).cast(); + TreeComponent tree = panel.addChild(new TreeComponent<>(ColorUtils.GRAY, 9F).disableBackground(true).setSelectionMode(TreeComponent.SELECTION_MODE_INTERACT).cast(), Constrains.parent(Target.WIDTH).parent(4, Target.HEIGHT).build()); + List tabs = new ObjectArrayList<>(); + int previouseTab = -1; + + + public TreeProfilerWindow(float x, float y, float width, float height, String name) + { + super(x, y, width, height, DEFAULT_FLAGS, name); + } + + public TreeProfilerWindow addProfiler(IProfiler profiler, String root) + { + panel.addTab(profiler.getName()); + tabs.add(new ProfilerTab(profiler, root)); + if(tabs.size() == 1) + { + onProfilerChanged(); + } + return this; + } + + @Override + public boolean canMoveIntoForground() + { + return true; + } + + @Override + public Vec2f getMinimumBounds() + { + return Vec2f.of(100F, 50F); + } + + @Override + public void init() + { + super.init(); + addChild(panel.set(0F, 7.5F).onChange(minimizedListener), Constrains.parent(0.25F, Target.WIDTH).parent(4F, Target.HEIGHT).build()); + } + + @Override + public void onClosed() + { + super.onClosed(); + applyProfiler(false, this::disable); + } + + @Override + protected boolean fixedUpdateSelf() + { + ProfilerTab entry = getActiveTab(); + if(entry == null) + { + todoList.clear(); + return true; + } + while(!todoList.isEmpty()) + { + int index = todoList.dequeue(); + switch(index) + { + case 0: + addEntries(entry.getRootEntry()); + break; + case 1: + tree.setTree(null); + break; + case 2: + if(tree.getTree() == null) + { + addEntries(entry.getRootEntry()); + break; + } + updateChildren(entry.getRootEntry(), tree.getTree()); + tree.onTreeChanged(); + break; + } + } + return true; + } + + protected void onProfilerChanged() + { + if(previouseTab == panel.getActiveIndex()) return; + applyProfiler(true, this::disable); + applyProfiler(false, this::enable); + previouseTab = panel.getActiveIndex(); + ProfilerTab tab = tabs.get(previouseTab); + setCurrentEntry(tab.getRoot()); + } + + protected void enable(IProfiler profiler) + { + profiler.enable(); + profiler.addListener(listener); + } + + protected void disable(IProfiler profiler) + { + profiler.removeListener(listener); + profiler.disable(); + } + + protected void addEntries(IProfilerEntry entry) + { + if(entry == null) return; + ProfilerTreeEntry child = new ProfilerTreeEntry(entry); + for(int i = 0,m=entry.getChildCount();i= tabs.size() ? null : tabs.get(index); + } + + protected void applyProfiler(boolean prev, Consumer action) + { + int index = prev ? previouseTab : panel.getActiveIndex(); + if(index >= 0) action.accept(tabs.get(index).getProfiler()); + } + + private static class ProfilerTab + { + IProfiler profiler; + String root; + + public ProfilerTab(IProfiler profiler, String root) + { + this.profiler = profiler; + this.root = root; + } + + public IProfiler getProfiler() + { + return profiler; + } + + public String getRoot() + { + return root; + } + + public IProfilerEntry getRootEntry() + { + return profiler.getEntry(root); + } + + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/TreeProfilerWindowComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/TreeProfilerWindowComponent.java deleted file mode 100644 index 6d90ebd..0000000 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/debug/TreeProfilerWindowComponent.java +++ /dev/null @@ -1,184 +0,0 @@ -package speiger.src.coreengine.rendering.gui.components.window.debug; - -import java.util.function.ObjIntConsumer; - -import speiger.src.collections.ints.queues.IntArrayFIFOQueue; -import speiger.src.collections.ints.queues.IntPriorityQueue; -import speiger.src.collections.ints.utils.IntPriorityQueues; -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.math.vector.floats.Vec2f; -import speiger.src.coreengine.rendering.gui.GuiManager; -import speiger.src.coreengine.rendering.gui.components.ButtonComponent; -import speiger.src.coreengine.rendering.gui.components.TreeComponent; -import speiger.src.coreengine.rendering.gui.components.WindowComponent; -import speiger.src.coreengine.rendering.gui.components.tree.ProfilerTreeEntry; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; -import speiger.src.coreengine.utils.profiler.IProfiler; -import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry; - -public class TreeProfilerWindowComponent extends WindowComponent -{ - IntPriorityQueue todoList = IntPriorityQueues.synchronize(new IntArrayFIFOQueue()); - TreeComponent tree = new TreeComponent(ColorUtils.GRAY, 9F).disableBackground(true).setSelectionMode(TreeComponent.SELECTION_MODE_INTERACT); - ButtonComponent[] buttons = new ButtonComponent[3]; - ObjIntConsumer listener = (T, V) -> todoList.enqueue(V); - IProfiler profiler; - String root; - - public TreeProfilerWindowComponent(float x, float y, float width, float height, String name) - { - super(x, y, width, height, DEFAULT_FLAGS, name); - } - - @Override - public boolean canMoveIntoForground() - { - return true; - } - - @Override - public void init() - { - super.init(); - addChild(tree.addChangeListener(minimizedListener), new Constrains(new PixelConstrain(2F), new PixelConstrain(getMinimizedY()), new ParentConstrain(1.5F), new PixelConstrain(getMinimizedY() + 8.5F).setInverted())); - buttons[0] = createButton(0, "Client"); - buttons[1] = createButton(1, "GPU"); - buttons[2] = createButton(2, "Server"); - } - - @Override - protected boolean fixedUpdateSelf() - { - while(!todoList.isEmpty()) - { - int index = todoList.dequeue(); - switch(index) - { - case 0: - addEntries(profiler.getEntry(root)); - break; - case 1: - tree.setTree(null); - break; - case 2: - if(tree.getTree() == null) - { - addEntries(profiler.getEntry(root)); - break; - } - updateChildren(profiler.getEntry(root), tree.getTree()); - tree.onTreeChanged(); - break; - } - } - return true; - } - - public TreeProfilerWindowComponent setProfiler(IProfiler profiler, String root) - { - if(this.profiler != null) - { - buttons[getProfilerIndex(this.profiler)].setEnabled(true); - this.profiler.removeListener(listener); - this.profiler.disable(); - tree.setTree(null); - } - this.profiler = profiler; - this.root = root; - if(this.profiler != null) - { - buttons[getProfilerIndex(this.profiler)].setEnabled(false); - this.profiler.enable(); - this.profiler.addListener(listener); - addEntries(this.profiler.getEntry(this.root)); - } - return this; - } - - protected void addEntries(IProfilerEntry entry) - { - if(entry == null) - { - return; - } - ProfilerTreeEntry child = new ProfilerTreeEntry(entry); - for(int i = 0,m=entry.getChildCount();i setProfiler(getProfiler(index), PieProfilerWindowComponent.getRoot(index))); - addChild(button, new Constrains(new RelativeConstrain(index * 0.3333F), new PixelConstrain(8F).setInverted(), new RelativeConstrain(0.3333F), new PixelConstrain(7F))); - return button; - } - - @Override - public Vec2f getMinimumBounds() - { - return Vec2f.of(100F, 50F); - } -} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/ChoiceComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/ChoiceComponent.java index 62e744f..014cefd 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/ChoiceComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/ChoiceComponent.java @@ -1,60 +1,60 @@ -package speiger.src.coreengine.rendering.gui.components.window.misc; - -import speiger.src.collections.booleans.functions.BooleanConsumer; -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.rendering.gui.components.ButtonComponent; -import speiger.src.coreengine.rendering.gui.components.TextComponent; -import speiger.src.coreengine.rendering.gui.components.WindowComponent; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.TextConstrain; - -public class ChoiceComponent extends WindowComponent -{ - TextComponent message = new TextComponent().limitHeight(false).setTextScale(0.5F); - ButtonComponent yesButton = new ButtonComponent("Yes", ColorUtils.GRAY); - ButtonComponent noButton = new ButtonComponent("No", ColorUtils.GRAY); - BooleanConsumer listener; - - public ChoiceComponent(float width, String windowTitle, String message, BooleanConsumer listener) - { - this(0F, 0F, width, windowTitle, message, listener); - } - - public ChoiceComponent(float x, float y, float width, String windowTitle, String message, BooleanConsumer listener) - { - super(x, y, width, 25F, FIXED_SIZE_POPUP, windowTitle); - this.message.setText(message); - this.listener = listener; - } - - public static ChoiceComponent createChoice(float width, String windowTitle, String message, BooleanConsumer listener) - { - return new ChoiceComponent(width, windowTitle, message, listener); - } - - public static ChoiceComponent createChoice(String windowTitle, String message, BooleanConsumer listener) - { - return new ChoiceComponent(150, windowTitle, message, listener); - } - - @Override - public void init() - { - super.init(); - yesButton.getText().setTextScale(0.5F); - noButton.getText().setTextScale(0.5F); - addChild(yesButton.addChangeListener(minimizedListener).addUserActionListener(closeListener).addUserActionListener(T -> listener.accept(true)), new Constrains(new RelativeConstrain(0F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F))); - addChild(noButton.addChangeListener(minimizedListener).addUserActionListener(closeListener).addUserActionListener(T -> listener.accept(false)), new Constrains(new RelativeConstrain(0.5F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F))); - addChild(message, new Constrains(new PixelConstrain(10F), new PixelConstrain(11F), new ParentConstrain(10F), TextConstrain.height(message))); - getBox().setHeight(25F + message.getMetadata().getMaxHeight()); - } - - @Override - public boolean isPopup() - { - return true; - } -} +package speiger.src.coreengine.rendering.gui.components.window.misc; + +import speiger.src.collections.booleans.functions.BooleanConsumer; +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.rendering.gui.components.ButtonComponent; +import speiger.src.coreengine.rendering.gui.components.TextComponent; +import speiger.src.coreengine.rendering.gui.components.WindowComponent; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.TextConstrain; + +public class ChoiceComponent extends WindowComponent +{ + TextComponent message = new TextComponent().limitHeight(false).setTextScale(0.5F); + ButtonComponent yesButton = new ButtonComponent("Yes", ColorUtils.GRAY); + ButtonComponent noButton = new ButtonComponent("No", ColorUtils.GRAY); + BooleanConsumer listener; + + public ChoiceComponent(float width, String windowTitle, String message, BooleanConsumer listener) + { + this(0F, 0F, width, windowTitle, message, listener); + } + + public ChoiceComponent(float x, float y, float width, String windowTitle, String message, BooleanConsumer listener) + { + super(x, y, width, 25F, FIXED_SIZE_POPUP, windowTitle); + this.message.setText(message); + this.listener = listener; + } + + public static ChoiceComponent createChoice(float width, String windowTitle, String message, BooleanConsumer listener) + { + return new ChoiceComponent(width, windowTitle, message, listener); + } + + public static ChoiceComponent createChoice(String windowTitle, String message, BooleanConsumer listener) + { + return new ChoiceComponent(150, windowTitle, message, listener); + } + + @Override + public void init() + { + super.init(); + yesButton.getText().setTextScale(0.5F); + noButton.getText().setTextScale(0.5F); + addChild(yesButton.onChange(minimizedListener).onAction(closeListener).onAction(T -> listener.accept(true)), new Constrains(new RelativeConstrain(0F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F))); + addChild(noButton.onChange(minimizedListener).onAction(closeListener).onAction(T -> listener.accept(false)), new Constrains(new RelativeConstrain(0.5F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F))); + addChild(message, new Constrains(new PixelConstrain(10F), new PixelConstrain(11F), new ParentConstrain(10F), TextConstrain.height(message))); + getBox().setHeight(25F + message.getMetadata().getMaxHeight()); + } + + @Override + public boolean isPopup() + { + return true; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/MessageComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/MessageComponent.java index 63a79ab..b8f2c7c 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/MessageComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/MessageComponent.java @@ -1,74 +1,74 @@ -package speiger.src.coreengine.rendering.gui.components.window.misc; - -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.rendering.gui.components.ButtonComponent; -import speiger.src.coreengine.rendering.gui.components.TextComponent; -import speiger.src.coreengine.rendering.gui.components.WindowComponent; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; -import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.TextConstrain; - -public class MessageComponent extends WindowComponent -{ - TextComponent message = new TextComponent().limitHeight(false).setTextScale(0.5F); - ButtonComponent resultButton = new ButtonComponent("", ColorUtils.GRAY); - - public MessageComponent(float width, String windowTitle, String confirmButton, String message) - { - this(0F, 0F, width, windowTitle, confirmButton, message); - } - - public MessageComponent(float x, float y, float width, String windowTitle, String confirmButton, String message) - { - super(x, y, width, 25F, FIXED_SIZE_POPUP, windowTitle); - resultButton.getText().setText(confirmButton); - this.message.setText(message); - } - - public static MessageComponent createInfo(String message) - { - return new MessageComponent(150, "Info", "Ok", message); - } - - public static MessageComponent createInfo(float width, String message) - { - return new MessageComponent(width, "Info", "Ok", message); - } - - public static MessageComponent createWarn(String message) - { - return new MessageComponent(150, "Warn", "Ok", message); - } - - public static MessageComponent createWarn(float width, String message) - { - return new MessageComponent(width, "Warn", "Ok", message); - } - - public static MessageComponent createError(String message) - { - return new MessageComponent(150, "Error!", "Ok", message); - } - - public static MessageComponent createError(float width, String message) - { - return new MessageComponent(width, "Error!", "Ok", message); - } - - @Override - public void init() - { - super.init(); - resultButton.getText().setTextScale(0.5F); - addChild(resultButton.addChangeListener(minimizedListener).addUserActionListener(closeListener), new Constrains(new ParentConstrain(), new ParentConstrain(10F).invert(), new ParentConstrain(), new PixelConstrain(10F))); - addChild(message, new Constrains(new PixelConstrain(10F), new PixelConstrain(11F), new ParentConstrain(10F), TextConstrain.height(message))); - getBox().setHeight(25F + message.getMetadata().getMaxHeight()); - } - - @Override - public boolean isPopup() - { - return true; - } -} +package speiger.src.coreengine.rendering.gui.components.window.misc; + +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.rendering.gui.components.ButtonComponent; +import speiger.src.coreengine.rendering.gui.components.TextComponent; +import speiger.src.coreengine.rendering.gui.components.WindowComponent; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrains; +import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.TextConstrain; + +public class MessageComponent extends WindowComponent +{ + TextComponent message = new TextComponent().limitHeight(false).setTextScale(0.5F); + ButtonComponent resultButton = new ButtonComponent("", ColorUtils.GRAY); + + public MessageComponent(float width, String windowTitle, String confirmButton, String message) + { + this(0F, 0F, width, windowTitle, confirmButton, message); + } + + public MessageComponent(float x, float y, float width, String windowTitle, String confirmButton, String message) + { + super(x, y, width, 25F, FIXED_SIZE_POPUP, windowTitle); + resultButton.getText().setText(confirmButton); + this.message.setText(message); + } + + public static MessageComponent createInfo(String message) + { + return new MessageComponent(150, "Info", "Ok", message); + } + + public static MessageComponent createInfo(float width, String message) + { + return new MessageComponent(width, "Info", "Ok", message); + } + + public static MessageComponent createWarn(String message) + { + return new MessageComponent(150, "Warn", "Ok", message); + } + + public static MessageComponent createWarn(float width, String message) + { + return new MessageComponent(width, "Warn", "Ok", message); + } + + public static MessageComponent createError(String message) + { + return new MessageComponent(150, "Error!", "Ok", message); + } + + public static MessageComponent createError(float width, String message) + { + return new MessageComponent(width, "Error!", "Ok", message); + } + + @Override + public void init() + { + super.init(); + resultButton.getText().setTextScale(0.5F); + addChild(resultButton.onChange(minimizedListener).onAction(closeListener), new Constrains(new ParentConstrain(), new ParentConstrain(10F).invert(), new ParentConstrain(), new PixelConstrain(10F))); + addChild(message, new Constrains(new PixelConstrain(10F), new PixelConstrain(11F), new ParentConstrain(10F), TextConstrain.height(message))); + getBox().setHeight(25F + message.getMetadata().getMaxHeight()); + } + + @Override + public boolean isPopup() + { + return true; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/TextInputComponent.java b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/TextInputComponent.java index f188942..1ce8254 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/TextInputComponent.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/components/window/misc/TextInputComponent.java @@ -1,66 +1,66 @@ -package speiger.src.coreengine.rendering.gui.components.window.misc; - -import speiger.src.coreengine.math.misc.ColorUtils; -import speiger.src.coreengine.rendering.gui.components.ButtonComponent; -import speiger.src.coreengine.rendering.gui.components.TextComponent; -import speiger.src.coreengine.rendering.gui.components.TextFieldComponent; -import speiger.src.coreengine.rendering.gui.components.WindowComponent; -import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; -import speiger.src.coreengine.rendering.gui.helper.constrains.TextConstrain; - -public class TextInputComponent extends WindowComponent -{ - TextComponent message = new TextComponent().limitHeight(false).setTextScale(0.5F); - TextFieldComponent input = new TextFieldComponent(ColorUtils.GRAY).setCanLoseFocus(false).setInfiniteText(true).setMaxTextLength(Integer.MAX_VALUE).setFocused(true); - ButtonComponent confirm = new ButtonComponent("Confirm", ColorUtils.DARK_GREEN); - ButtonComponent cancel = new ButtonComponent("Cancel", ColorUtils.RED); - - public TextInputComponent(float width, String name, String message) - { - this(0F, 0F, width, name, message); - } - - public TextInputComponent(float x, float y, float width, String name, String message) - { - super(x, y, width, 35F, FIXED_SIZE_POPUP, name); - this.message.setText(message); - } - - public TextFieldComponent getInput() - { - return input; - } - - public String getText() - { - return input.getText(); - } - - @Override - public void init() - { - super.init(); - confirm.getText().setTextScale(0.5F); - cancel.getText().setTextScale(0.5F); - input.getRawText().setTextScale(0.5F); - addChild(confirm.addChangeListener(minimizedListener).addUserActionListener(this::onListen), new RelativeConstrain(0F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F)); - addChild(cancel.addChangeListener(minimizedListener).addUserActionListener(closeListener), new RelativeConstrain(0.5F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F)); - addChild(message.addChangeListener(minimizedListener), new PixelConstrain(10F), new PixelConstrain(11F), new ParentConstrain(10F), TextConstrain.height(message)); - addChild(input.addChangeListener(minimizedListener).addUserActionListener(this::onListen), new PixelConstrain(10F), TextConstrain.height(message).setPadding(15F), new ParentConstrain(10F), new PixelConstrain(12F)); - getBox().setHeight(45F + message.getMetadata().getMaxHeight()); - } - - private void onListen() - { - notifyListeners(LISTENER_USER_ACTION); - closeListener.accept(this); - } - - @Override - public boolean isPopup() - { - return true; - } -} +package speiger.src.coreengine.rendering.gui.components.window.misc; + +import speiger.src.coreengine.math.misc.ColorUtils; +import speiger.src.coreengine.rendering.gui.components.ButtonComponent; +import speiger.src.coreengine.rendering.gui.components.TextComponent; +import speiger.src.coreengine.rendering.gui.components.TextFieldComponent; +import speiger.src.coreengine.rendering.gui.components.WindowComponent; +import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain; +import speiger.src.coreengine.rendering.gui.helper.constrains.TextConstrain; + +public class TextInputComponent extends WindowComponent +{ + TextComponent message = new TextComponent().limitHeight(false).setTextScale(0.5F); + TextFieldComponent input = new TextFieldComponent(ColorUtils.GRAY).setCanLoseFocus(false).setInfiniteText(true).setMaxTextLength(Integer.MAX_VALUE).setFocused(true); + ButtonComponent confirm = new ButtonComponent("Confirm", ColorUtils.DARK_GREEN); + ButtonComponent cancel = new ButtonComponent("Cancel", ColorUtils.RED); + + public TextInputComponent(float width, String name, String message) + { + this(0F, 0F, width, name, message); + } + + public TextInputComponent(float x, float y, float width, String name, String message) + { + super(x, y, width, 35F, FIXED_SIZE_POPUP, name); + this.message.setText(message); + } + + public TextFieldComponent getInput() + { + return input; + } + + public String getText() + { + return input.getText(); + } + + @Override + public void init() + { + super.init(); + confirm.getText().setTextScale(0.5F); + cancel.getText().setTextScale(0.5F); + input.getRawText().setTextScale(0.5F); + addChild(confirm.onChange(minimizedListener).onAction(this::onListen), new RelativeConstrain(0F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F)); + addChild(cancel.onChange(minimizedListener).onAction(closeListener), new RelativeConstrain(0.5F), new ParentConstrain(10F).invert(), new RelativeConstrain(0.5F), new PixelConstrain(10F)); + addChild(message.onChange(minimizedListener), new PixelConstrain(10F), new PixelConstrain(11F), new ParentConstrain(10F), TextConstrain.height(message)); + addChild(input.onChange(minimizedListener).onAction(this::onListen), new PixelConstrain(10F), TextConstrain.height(message).setPadding(15F), new ParentConstrain(10F), new PixelConstrain(12F)); + getBox().setHeight(45F + message.getMetadata().getMaxHeight()); + } + + private void onListen() + { + notifyListeners(LISTENER_USER_ACTION); + closeListener.accept(this); + } + + @Override + public boolean isPopup() + { + return true; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/helper/animations/AnimationInstance.java b/src/main/java/speiger/src/coreengine/rendering/gui/helper/animations/AnimationInstance.java index cc4cec2..e0ff1c9 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/helper/animations/AnimationInstance.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/helper/animations/AnimationInstance.java @@ -1,53 +1,53 @@ -package speiger.src.coreengine.rendering.gui.helper.animations; - -import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap; -import speiger.src.collections.objects.utils.maps.Object2ObjectMaps; -import speiger.src.coreengine.math.value.ConstantValue; -import speiger.src.coreengine.math.value.IValue; -import speiger.src.coreengine.rendering.gui.helper.animations.Animation.AnimationListener; - -public class AnimationInstance -{ - Object2ObjectMap values; - float totalProgress; - boolean reverse; - AnimationListener listener; - float progress = 0F; - - public AnimationInstance(Object2ObjectMap values, float totalProgress, boolean reverse, AnimationListener listener) - { - this.values = values; - this.totalProgress = totalProgress; - this.reverse = reverse; - this.listener = listener; - } - - public void update(Animator animator, float particalTime) - { - progress += particalTime; - for(Object2ObjectMap.Entry entry : Object2ObjectMaps.fastIterable(values)) - { - entry.getKey().apply(animator, entry.getValue().update(particalTime)); - } - } - - public float getCurrentProgress(AnimationTarget target) - { - return values.getOrDefault(target, ConstantValue.ZERO).get(); - } - - public boolean isDone() - { - return reverse && progress >= totalProgress; - } - - public AnimationListener getListener() - { - return listener; - } - - public boolean isReverse() - { - return reverse; - } +package speiger.src.coreengine.rendering.gui.helper.animations; + +import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap; +import speiger.src.collections.objects.utils.maps.Object2ObjectMaps; +import speiger.src.coreengine.math.value.ConstantValue; +import speiger.src.coreengine.math.value.IValue; +import speiger.src.coreengine.rendering.gui.helper.animations.Animation.AnimationListener; + +public class AnimationInstance +{ + Object2ObjectMap values; + float totalProgress; + boolean reverse; + AnimationListener listener; + float progress = 0F; + + public AnimationInstance(Object2ObjectMap values, float totalProgress, boolean reverse, AnimationListener listener) + { + this.values = values; + this.totalProgress = totalProgress; + this.reverse = reverse; + this.listener = listener; + } + + public void update(Animator animator, float particalTime) + { + progress += particalTime; + for(Object2ObjectMap.Entry entry : Object2ObjectMaps.fastIterable(values)) + { + entry.getKey().apply(animator, entry.getValue().update(particalTime)); + } + } + + public float getCurrentProgress(AnimationTarget target) + { + return values.getOrDefault(target, ConstantValue.ZERO).get(); + } + + public boolean isDone() + { + return reverse && progress >= totalProgress; + } + + public AnimationListener getListener() + { + return listener; + } + + public boolean isReverse() + { + return reverse; + } } \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/helper/constrains/Constrains.java b/src/main/java/speiger/src/coreengine/rendering/gui/helper/constrains/Constrains.java index 177c5e7..7ac68eb 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/helper/constrains/Constrains.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/helper/constrains/Constrains.java @@ -1,125 +1,131 @@ -package speiger.src.coreengine.rendering.gui.helper.constrains; - -import java.util.function.BooleanSupplier; - -import speiger.src.coreengine.math.misc.Facing; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain.Target; -import speiger.src.coreengine.utils.functions.FloatSupplier; - -public class Constrains -{ - Constrain[] constrains = new Constrain[4]; - - private Constrains(Constrain[] array) - { - System.arraycopy(array, 0, constrains, 0, 4); - } - - public Constrains(Constrain xPos, Constrain yPos, Constrain width, Constrain height) - { - constrains[0] = xPos; - constrains[1] = yPos; - constrains[2] = width; - constrains[3] = height; - } - - public void setOwner(GuiComponent owner, GuiComponent parent) - { - for(int i = 0;i<4;i++) { - if(constrains[i] != null) { - constrains[i].setComponents(owner, parent, Target.by(i)); - } - } - } - - public void onComponentChanged() - { - for(int i = 0;i<4;i++) { - if(constrains[i] != null) constrains[i].apply(); - } - } - - public static Constrains parent() { return new Constrains(new ParentConstrain(), new ParentConstrain(), new ParentConstrain(), new ParentConstrain()); } - public static Constrains parent(float padding) { return new Constrains(new ParentConstrain(padding), new ParentConstrain(padding), new ParentConstrain(padding), new ParentConstrain(padding)); } - public static Constrains parent(float xPadding, float yPadding) { return new Constrains(new ParentConstrain(xPadding), new ParentConstrain(yPadding), new ParentConstrain(xPadding), new ParentConstrain(yPadding)); } - public static Constrains parent(float x, float y, float width, float height) { return new Constrains(new ParentConstrain(x), new ParentConstrain(y), new ParentConstrain(width), new ParentConstrain(height)); } - - public static Constrains scrollBar(BooleanSupplier supply, boolean horizontal, float barSize) { - Constrain bounds = new ConditionalConstraint(supply, new ParentConstrain(), new ParentConstrain(barSize / 2F)); - return horizontal ? new Constrains(new PixelConstrain(), new ParentConstrain(barSize).invert(), bounds, new PixelConstrain(barSize)) : new Constrains(new ParentConstrain(barSize).invert(), new PixelConstrain(), new PixelConstrain(barSize), bounds); - } - - public static Constrains verticalScrollBar(BooleanSupplier supply, float offset, float barSize) { return invParent(barSize, Target.X).yPos(offset).width(barSize).height(new ConditionalConstraint(supply, new ParentConstrain(offset * 0.5F), new ParentConstrain((barSize + offset) * 0.5F))).build(); } - - public static Constrains border(float size, Facing side, float offset) - { - switch(side) - { - case NORTH: return new Constrains(new ParentConstrain(), new ParentConstrain(offset), new ParentConstrain(), new PixelConstrain(size)); - case EAST: return new Constrains(new ParentConstrain(size+offset).invert(), new ParentConstrain(), new PixelConstrain(size), new ParentConstrain()); - case SOUTH: return new Constrains(new ParentConstrain(), new ParentConstrain(size+offset).invert(), new ParentConstrain(), new PixelConstrain(size)); - case WEST: return new Constrains(new ParentConstrain(offset), new ParentConstrain(), new PixelConstrain(size), new ParentConstrain()); - default: return null; - } - } - - public static ConstrainBuilder xPos(Constrain xPos) { return new ConstrainBuilder().set(xPos, Target.X); } - public static ConstrainBuilder yPos(Constrain yPos) { return new ConstrainBuilder().set(yPos, Target.Y); } - public static ConstrainBuilder width(Constrain width) { return new ConstrainBuilder().set(width, Target.WIDTH); } - public static ConstrainBuilder height(Constrain height) { return new ConstrainBuilder().set(height, Target.HEIGHT); } - - public static ConstrainBuilder xPos(float xPos) { return new ConstrainBuilder().set(new PixelConstrain(xPos), Target.X); } - public static ConstrainBuilder yPos(float yPos) { return new ConstrainBuilder().set(new PixelConstrain(yPos), Target.Y); } - public static ConstrainBuilder width(float width) { return new ConstrainBuilder().set(new PixelConstrain(width), Target.WIDTH); } - public static ConstrainBuilder height(float height) { return new ConstrainBuilder().set(new PixelConstrain(height), Target.HEIGHT); } - - public static ConstrainBuilder xPosR(float xPos) { return new ConstrainBuilder().set(new RelativeConstrain(xPos), Target.X); } - public static ConstrainBuilder yPosR(float yPos) { return new ConstrainBuilder().set(new RelativeConstrain(yPos), Target.Y); } - public static ConstrainBuilder widthR(float width) { return new ConstrainBuilder().set(new RelativeConstrain(width), Target.WIDTH); } - public static ConstrainBuilder heightR(float height) { return new ConstrainBuilder().set(new RelativeConstrain(height), Target.HEIGHT); } - - public static ConstrainBuilder parent(Target target) { return new ConstrainBuilder().set(new ParentConstrain(), target); } - public static ConstrainBuilder invParent(Target target) { return new ConstrainBuilder().set(new ParentConstrain().invert(), target); } - public static ConstrainBuilder parent(float padding, Target target) { return new ConstrainBuilder().set(new ParentConstrain(padding), target); } - public static ConstrainBuilder invParent(float padding, Target target) { return new ConstrainBuilder().set(new ParentConstrain(padding).invert(), target); } - public static ConstrainBuilder center(Target target) { return new ConstrainBuilder().set(new CenterConstrain(), target); } - public static ConstrainBuilder dynamic(FloatSupplier provider, Target target) { return new ConstrainBuilder().set(new DynamicConstrain(provider), target); } - - public static class ConstrainBuilder - { - Constrain[] constrains = new Constrain[4]; - - public ConstrainBuilder set(Constrain value, Target target) { - constrains[target.ordinal()] = value; - return this; - } - - public ConstrainBuilder xPos(Constrain xPos) { return set(xPos, Target.X); } - public ConstrainBuilder yPos(Constrain yPos) { return set(yPos, Target.Y); } - public ConstrainBuilder width(Constrain width) { return set(width, Target.WIDTH); } - public ConstrainBuilder height(Constrain height) { return set(height, Target.HEIGHT); } - - public ConstrainBuilder xPos(float xPos) { return set(new PixelConstrain(xPos), Target.X); } - public ConstrainBuilder yPos(float yPos) { return set(new PixelConstrain(yPos), Target.Y); } - public ConstrainBuilder width(float width) { return set(new PixelConstrain(width), Target.WIDTH); } - public ConstrainBuilder height(float height) { return set(new PixelConstrain(height), Target.HEIGHT); } - - public ConstrainBuilder xPosR(float xPos) { return set(new RelativeConstrain(xPos), Target.X); } - public ConstrainBuilder yPosR(float yPos) { return set(new RelativeConstrain(yPos), Target.Y); } - public ConstrainBuilder widthR(float width) { return set(new RelativeConstrain(width), Target.WIDTH); } - public ConstrainBuilder heightR(float height) { return set(new RelativeConstrain(height), Target.HEIGHT); } - - public ConstrainBuilder parent(Target target) { return set(new ParentConstrain(), target); } - public ConstrainBuilder invParent(Target target) { return set(new ParentConstrain().invert(), target); } - public ConstrainBuilder parent(float padding, Target target) { return set(new ParentConstrain(padding), target); } - public ConstrainBuilder invParent(float padding, Target target) { return set(new ParentConstrain(padding).invert(), target); } - public ConstrainBuilder center(Target target) { return set(new CenterConstrain(), target); } - public ConstrainBuilder dynamic(FloatSupplier provider, Target target) { return set(new DynamicConstrain(provider), target); } - - public Constrains build() - { - return new Constrains(constrains); - } - } -} +package speiger.src.coreengine.rendering.gui.helper.constrains; + +import java.util.function.BooleanSupplier; + +import speiger.src.coreengine.math.misc.Facing; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.gui.helper.constrains.Constrain.Target; +import speiger.src.coreengine.utils.functions.FloatSupplier; + +public class Constrains +{ + Constrain[] constrains = new Constrain[4]; + + private Constrains(Constrain[] array) + { + System.arraycopy(array, 0, constrains, 0, 4); + } + + public Constrains(Constrain xPos, Constrain yPos, Constrain width, Constrain height) + { + constrains[0] = xPos; + constrains[1] = yPos; + constrains[2] = width; + constrains[3] = height; + } + + public void setOwner(GuiComponent owner, GuiComponent parent) + { + for(int i = 0;i<4;i++) { + if(constrains[i] != null) { + constrains[i].setComponents(owner, parent, Target.by(i)); + } + } + } + + public void onComponentChanged() + { + for(int i = 0;i<4;i++) { + if(constrains[i] != null) constrains[i].apply(); + } + } + + public static Constrains parent() { return new Constrains(new ParentConstrain(), new ParentConstrain(), new ParentConstrain(), new ParentConstrain()); } + public static Constrains parent(float padding) { return new Constrains(new ParentConstrain(padding), new ParentConstrain(padding), new ParentConstrain(padding), new ParentConstrain(padding)); } + public static Constrains parent(float xPadding, float yPadding) { return new Constrains(new ParentConstrain(xPadding), new ParentConstrain(yPadding), new ParentConstrain(xPadding), new ParentConstrain(yPadding)); } + public static Constrains parent(float x, float y, float width, float height) { return new Constrains(new ParentConstrain(x), new ParentConstrain(y), new ParentConstrain(width), new ParentConstrain(height)); } + + public static Constrains scrollBar(BooleanSupplier supply, boolean horizontal, float barSize) { + Constrain bounds = new ConditionalConstraint(supply, new ParentConstrain(), new ParentConstrain(barSize / 2F)); + return horizontal ? new Constrains(new PixelConstrain(), new ParentConstrain(barSize).invert(), bounds, new PixelConstrain(barSize)) : new Constrains(new ParentConstrain(barSize).invert(), new PixelConstrain(), new PixelConstrain(barSize), bounds); + } + + public static Constrains verticalScrollBar(BooleanSupplier supply, float offset, float barSize) { return invParent(barSize, Target.X).yPos(offset).width(barSize).height(new ConditionalConstraint(supply, new ParentConstrain(offset * 0.5F), new ParentConstrain((barSize + offset) * 0.5F))).build(); } + + public static Constrains border(float size, Facing side, float offset) + { + switch(side) + { + case NORTH: return new Constrains(new ParentConstrain(), new ParentConstrain(offset), new ParentConstrain(), new PixelConstrain(size)); + case EAST: return new Constrains(new ParentConstrain(size+offset).invert(), new ParentConstrain(), new PixelConstrain(size), new ParentConstrain()); + case SOUTH: return new Constrains(new ParentConstrain(), new ParentConstrain(size+offset).invert(), new ParentConstrain(), new PixelConstrain(size)); + case WEST: return new Constrains(new ParentConstrain(offset), new ParentConstrain(), new PixelConstrain(size), new ParentConstrain()); + default: return null; + } + } + + public static ConstrainBuilder builder() { return new ConstrainBuilder(); }; + + public static ConstrainBuilder xPos(Constrain xPos) { return new ConstrainBuilder().set(xPos, Target.X); } + public static ConstrainBuilder yPos(Constrain yPos) { return new ConstrainBuilder().set(yPos, Target.Y); } + public static ConstrainBuilder width(Constrain width) { return new ConstrainBuilder().set(width, Target.WIDTH); } + public static ConstrainBuilder height(Constrain height) { return new ConstrainBuilder().set(height, Target.HEIGHT); } + + public static ConstrainBuilder xPos(float xPos) { return new ConstrainBuilder().set(new PixelConstrain(xPos), Target.X); } + public static ConstrainBuilder yPos(float yPos) { return new ConstrainBuilder().set(new PixelConstrain(yPos), Target.Y); } + public static ConstrainBuilder width(float width) { return new ConstrainBuilder().set(new PixelConstrain(width), Target.WIDTH); } + public static ConstrainBuilder height(float height) { return new ConstrainBuilder().set(new PixelConstrain(height), Target.HEIGHT); } + + public static ConstrainBuilder xPosR(float xPos) { return new ConstrainBuilder().set(new RelativeConstrain(xPos), Target.X); } + public static ConstrainBuilder yPosR(float yPos) { return new ConstrainBuilder().set(new RelativeConstrain(yPos), Target.Y); } + public static ConstrainBuilder widthR(float width) { return new ConstrainBuilder().set(new RelativeConstrain(width), Target.WIDTH); } + public static ConstrainBuilder heightR(float height) { return new ConstrainBuilder().set(new RelativeConstrain(height), Target.HEIGHT); } + + public static ConstrainBuilder parent(Target target) { return new ConstrainBuilder().set(new ParentConstrain(), target); } + public static ConstrainBuilder invParent(Target target) { return new ConstrainBuilder().set(new ParentConstrain().invert(), target); } + public static ConstrainBuilder parent(float padding, Target target) { return new ConstrainBuilder().set(new ParentConstrain(padding), target); } + public static ConstrainBuilder invParent(float padding, Target target) { return new ConstrainBuilder().set(new ParentConstrain(padding).invert(), target); } + public static ConstrainBuilder pixel(float pixels, Target target) { return new ConstrainBuilder().set(new PixelConstrain(pixels), target); } + public static ConstrainBuilder invPixel(float pixels, Target target) { return new ConstrainBuilder().set(new PixelConstrain(pixels).setInverted(), target); } + public static ConstrainBuilder center(Target target) { return new ConstrainBuilder().set(new CenterConstrain(), target); } + public static ConstrainBuilder dynamic(FloatSupplier provider, Target target) { return new ConstrainBuilder().set(new DynamicConstrain(provider), target); } + + public static class ConstrainBuilder + { + Constrain[] constrains = new Constrain[4]; + + public ConstrainBuilder set(Constrain value, Target target) { + constrains[target.ordinal()] = value; + return this; + } + + public ConstrainBuilder xPos(Constrain xPos) { return set(xPos, Target.X); } + public ConstrainBuilder yPos(Constrain yPos) { return set(yPos, Target.Y); } + public ConstrainBuilder width(Constrain width) { return set(width, Target.WIDTH); } + public ConstrainBuilder height(Constrain height) { return set(height, Target.HEIGHT); } + + public ConstrainBuilder xPos(float xPos) { return set(new PixelConstrain(xPos), Target.X); } + public ConstrainBuilder yPos(float yPos) { return set(new PixelConstrain(yPos), Target.Y); } + public ConstrainBuilder width(float width) { return set(new PixelConstrain(width), Target.WIDTH); } + public ConstrainBuilder height(float height) { return set(new PixelConstrain(height), Target.HEIGHT); } + + public ConstrainBuilder xPosR(float xPos) { return set(new RelativeConstrain(xPos), Target.X); } + public ConstrainBuilder yPosR(float yPos) { return set(new RelativeConstrain(yPos), Target.Y); } + public ConstrainBuilder widthR(float width) { return set(new RelativeConstrain(width), Target.WIDTH); } + public ConstrainBuilder heightR(float height) { return set(new RelativeConstrain(height), Target.HEIGHT); } + + public ConstrainBuilder parent(Target target) { return set(new ParentConstrain(), target); } + public ConstrainBuilder invParent(Target target) { return set(new ParentConstrain().invert(), target); } + public ConstrainBuilder parent(float padding, Target target) { return set(new ParentConstrain(padding), target); } + public ConstrainBuilder invParent(float padding, Target target) { return set(new ParentConstrain(padding).invert(), target); } + public ConstrainBuilder pixel(float pixels, Target target) { return set(new PixelConstrain(pixels), target); } + public ConstrainBuilder invPixel(float pixels, Target target) { return set(new PixelConstrain(pixels).setInverted(), target); } + public ConstrainBuilder center(Target target) { return set(new CenterConstrain(), target); } + public ConstrainBuilder dynamic(FloatSupplier provider, Target target) { return set(new DynamicConstrain(provider), target); } + + public Constrains build() + { + return new Constrains(constrains); + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/renderer/UIRenderer.java b/src/main/java/speiger/src/coreengine/rendering/gui/renderer/UIRenderer.java index 1fb5495..1dd63d6 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/renderer/UIRenderer.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/renderer/UIRenderer.java @@ -1,707 +1,707 @@ -package speiger.src.coreengine.rendering.gui.renderer; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - -import org.lwjgl.opengl.GL11; -import org.lwjgl.system.MemoryUtil; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.collections.objects.queues.ObjectArrayFIFOQueue; -import speiger.src.collections.objects.queues.ObjectPriorityDequeue; -import speiger.src.collections.utils.Stack; -import speiger.src.coreengine.assets.reloader.IReloadableResource; -import speiger.src.coreengine.math.misc.Facing; -import speiger.src.coreengine.math.vector.floats.Vec2f; -import speiger.src.coreengine.math.vector.floats.Vec3f; -import speiger.src.coreengine.math.vector.floats.Vec4f; -import speiger.src.coreengine.math.vector.matrix.Matrix4f; -import speiger.src.coreengine.math.vector.quaternion.Quaternion; -import speiger.src.coreengine.rendering.gui.GuiManager; -import speiger.src.coreengine.rendering.gui.helper.Align; -import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; -import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; -import speiger.src.coreengine.rendering.models.DrawCall; -import speiger.src.coreengine.rendering.shader.uniforms.UniformVec2f; -import speiger.src.coreengine.rendering.tesselation.GLCall; -import speiger.src.coreengine.rendering.tesselation.Tesselator; -import speiger.src.coreengine.rendering.tesselation.VertexType; -import speiger.src.coreengine.rendering.textures.base.ITexture; -import speiger.src.coreengine.rendering.textures.base.TextureManager; -import speiger.src.coreengine.rendering.utils.GLUtils; -import speiger.src.coreengine.utils.collections.pools.SimplePool; - -public class UIRenderer implements IReloadableResource -{ - SimplePool recylcePool = new SimplePool<>(100, Matrix4f::new); - Stack transformStack = new ObjectArrayList<>(); - Matrix4f transform = new Matrix4f(); - boolean isFastTransform = true; - SimplePool fastPool = new SimplePool<>(100, () -> Vec4f.mutable(0F, 0F, 0F, 1F)); - Stack fastStack = new ObjectArrayList<>(); - Vec4f fastTransform = Vec4f.mutable(0F, 0F, 0F, 1F); - - SimplePool callPool = new SimplePool<>(100, GLCall::new); - ObjectPriorityDequeue activeCalls = new ObjectArrayFIFOQueue<>(); - - Tesselator bufferHelper = new Tesselator(655340); - FloatBuffer renderBuffer = MemoryUtil.memAllocFloat(655340); - Tesselator renderer = new Tesselator(renderBuffer); - ITexture currentTexture; - boolean drawing = false; - boolean useTexture = false; - Vec4f currentFrame = Vec4f.mutable(); - float roundedNess = 0F; - - GuiModel texturedModel = GuiModel.createTextureModel(Short.MAX_VALUE * 2); - - Align horizontal = Align.CENTER; - Align vertical = Align.CENTER; - - Vec3f helper = Vec3f.mutable(); - Vec4f transformHelper = Vec4f.mutable(); - Vec4f alignHelper = Vec4f.mutable(); - Vec3f alignTranslation = Vec3f.mutable(0F); - Vec3f alignScale = Vec3f.mutable(1F); - - GuiManager manager; - - public UIRenderer(GuiManager manager) - { - this.manager = manager; - TextureManager.INSTANCE.getReloader().addReloadableResource(this); - } - - public RenderBuffer createBuffer() - { - return new RenderBuffer(bufferHelper); - } - - public UIRenderer push() - { - if(isFastTransform) fastStack.push(fastPool.get().set(fastTransform)); - else transformStack.push(recylcePool.get().load(transform)); - return this; - } - - public UIRenderer pop() - { - if(isFastTransform) - { - Vec4f pop = fastStack.pop(); - fastTransform.set(pop); - fastPool.accept(pop); - return this; - } - Matrix4f pop = transformStack.pop(); - transform.load(pop); - pop.getScale(alignScale); - recylcePool.accept(pop); - return this; - } - - public UIRenderer setVisibility(float visibility) - { - sanityCheck("Visibilty Change"); - renderer.setVisibilty(visibility); - return this; - } - - public UIRenderer setBrightness(float brightness) - { - sanityCheck("Brightness change"); - renderer.setBrightness(brightness); - return this; - } - - public UIRenderer resetEffects() - { - renderer.setBrightness(1F).setVisibilty(1F); - return this; - } - - public UIRenderer setActiveTexture(ITexture texture) - { - if(getTextureId(currentTexture) != getTextureId(texture)) - { - addDrawCall(); - currentTexture = texture; - } - return this; - } - - public UIRenderer setRoundness(IGuiBox box, float roundedNess) - { - if(roundedNess <= 0) - { - if(this.roundedNess > 0F) addDrawCall(); - this.roundedNess = roundedNess; - return this; - } - alignHelper.set(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY()); - if(!currentFrame.equals(alignHelper) || this.roundedNess != roundedNess) - { - addDrawCall(); - currentFrame.set(alignHelper); - this.roundedNess = roundedNess; - } - return this; - } - - protected void applyEffects(UniformVec2f vec) - { - vec.storeData(renderer.getBrightness(), renderer.getVisibility()); - } - - public UIRenderer translate(float x, float y) - { - return translate(x, y, 0F); - } - - public UIRenderer translate(Vec2f offset) - { - return translate(offset.getX(), offset.getY(), 0F); - } - - public UIRenderer translate(float x, float y, float z) - { - if(isFastTransform) - { - fastTransform.add(x, y, z, 0F); - return this; - } - transform.translate(x, y, z); - return this; - } - - public UIRenderer translate(Vec3f offset) - { - if(isFastTransform) - { - fastTransform.add(offset.getX(), offset.getY(), offset.getZ(), 0F); - return this; - } - transform.translate(offset); - return this; - } - - public UIRenderer rotate(Quaternion quad) - { - if(isFastTransform) return this; - transform.rotate(quad); - return this; - } - - public UIRenderer rotateX(float angle) - { - if(isFastTransform) return this; - transform.rotateX((float)Math.toRadians(angle)); - return this; - } - - public UIRenderer rotateY(float angle) - { - if(isFastTransform) return this; - transform.rotateY((float)Math.toRadians(angle)); - return this; - } - - public UIRenderer rotateZ(float angle) - { - if(isFastTransform) return this; - transform.rotateZ((float)Math.toRadians(angle)); - return this; - } - - public UIRenderer scale(float x, float y, float z) - { - if(isFastTransform) return this; - transform.scale(x, y, z); - alignScale.multiply(x, y, z); - return this; - } - - public UIRenderer scale(float scale) - { - if(isFastTransform) - { - fastTransform.multiply(1F, 1F, 1F, scale); - return this; - } - transform.scale(helper.set(scale, scale, scale)); - alignScale.multiply(scale); - return this; - } - - public UIRenderer unscale(float x, float y, float z) - { - if(isFastTransform) return this; - transform.scale(helper.set(1.0F / x, 1.0F / y, 1.0F / z)); - alignScale.multiply(helper); - return this; - } - - public UIRenderer unscale(float scale) - { - scale = 1.0F / scale; - if(isFastTransform) - { - fastTransform.multiply(1F, 1F, 1F, scale); - return this; - } - transform.scale(scale, scale, scale).getScale(alignScale); - alignScale.multiply(scale); - return this; - } - - public UIRenderer resetTransform() - { - if(isFastTransform) - { - fastTransform.set(0F, 0F, 0F, 1F); - return this; - } - transform.setIdentity(); - alignScale.set(Vec3f.ONE); - return this; - } - - public float getCurrentZ() - { - return isFastTransform ? fastTransform.getZ() : transform.get(3, 2); - } - - public ITexture getActiveTexture() - { - return currentTexture; - } - - protected Matrix4f getCurrentMatrix() - { - return transform; - } - - public Matrix4f createCurrentMatrix(Matrix4f matrix) - { - return isFastTransform ? matrix.setIdentity().translate(fastTransform.getX(), fastTransform.getY(), fastTransform.getZ()) : matrix.load(transform); - } - - public UIRenderer setFastTransform(boolean fast) - { - isFastTransform = fast; - return this; - } - - public UIRenderer beginFrame() - { - if(drawing) - { - throw new RuntimeException("Already Drawing!"); - } - drawing = true; - fastTransform.set(0F, 0F, 0F, 1F); - roundedNess = 0F; - currentFrame.negate(); - transform.setIdentity(); - alignScale.set(Vec3f.ONE); - transformStack.clear(); - fastStack.clear(); - return this; - } - - public UIRenderer flush() - { - if(!renderer.isDrawing()) - { - return this; - } - renderer.finishData(); - int count = renderer.getVertexCount(); - if(count <= 0) - { - return this; - } - if(count > (activeCalls.isEmpty() ? 0 : activeCalls.last().getCount())) - { - addDrawCall(); - } - texturedModel.storeData(renderBuffer); - GuiShader shader = manager.getShader(); - shader.bind(manager.getOrthoMatrixBuffer()); - texturedModel.bindArray(); - int last = 0; - while(!activeCalls.isEmpty()) - { - GLCall call = activeCalls.dequeue(); - shader.texture.storeTexture(call.getTexture()); - shader.useTexture.storeData(call.getTexture() > 0 ? 1F : 0F); - shader.roundeness.storeData(call.getRoundedNess()); - if(call.getRoundedNess() > 0F) shader.bounds.storeData(call.getFrame()); - GLUtils.drawArrays(call.getType(), last, call.getCount() - last); - last = call.getCount(); - callPool.accept(call); - } - texturedModel.unbindArray(); - shader.stopShader(); - renderer.resetVertexes(); - return this; - } - - public UIRenderer endFrame() - { - if(!drawing) - { - throw new RuntimeException("Not Drawing!"); - } - drawing = false; - isFastTransform = true; - flush(); - fastTransform.set(0F, 0F, 0F, 1F); - transform.setIdentity(); - renderer.resetEffects(); - useTexture = false; - while(!transformStack.isEmpty()) - { - recylcePool.accept(transformStack.pop()); - } - while(!fastStack.isEmpty()) - { - fastPool.accept(fastStack.pop()); - } - return this; - } - - @Override - public void reload() - { - texturedModel.remove(); - MemoryUtil.memFree(renderBuffer); - texturedModel = GuiModel.createTextureModel(Short.MAX_VALUE * 2); - renderBuffer = MemoryUtil.memAllocFloat(655340); - renderer = new Tesselator(renderBuffer); - } - - @Override - public void destroy() - { - texturedModel.remove(); - MemoryUtil.memFree(renderBuffer); - TextureManager.INSTANCE.getReloader().removeReloadableResource(this); - } - - public UIRenderer drawBuffers(Iterable drawCalls, float width, float height) - { - sanityCheck("Buffer Drawing"); - applyAlignment(0, 0, width, height, 0, alignHelper); - for(DrawCall call : drawCalls) - { - ensureDrawing(call.getGLType(), call.getTextureId() > 0); - FloatBuffer buffer = ByteBuffer.wrap(call.getData()).order(ByteOrder.nativeOrder()).asFloatBuffer(); - for(int i = 0,m=buffer.remaining();i+9<=m;i+=9) - { - pos(transformHelper.set(buffer.get(i)+alignHelper.getX(), buffer.get(i+1)+alignHelper.getY(), buffer.get(i+2), 1F)) - .tex(buffer.get(i+3), buffer.get(i+4)) - .color4f(buffer.get(i+5), buffer.get(i+6), buffer.get(i+7), buffer.get(i+8)).endVertex(); - } - } - alignTranslation.set(0F, 0F, 0F); - return this; - } - - public UIRenderer drawQuad(IGuiBox box, int color) - { - return drawQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), color); - } - - public UIRenderer drawQuad(IGuiBox box, float zLevel, int color) - { - return drawQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), zLevel, color); - } - - public UIRenderer drawQuad(float minX, float minY, float maxX, float maxY, int color) - { - return drawQuad(minX, minY, maxX, maxY, 0.0F, color); - } - - public UIRenderer drawQuad(float minX, float minY, float maxX, float maxY, float zLevel, int color) - { - ensureDrawing(GL11.GL_TRIANGLES, false); - applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - alignTranslation.set(0F, 0F, 0F); - return this; - } - - public UIRenderer drawTexturedQuad(IGuiBox box, int color, float minU, float minV, float maxU, float maxV) - { - return drawTexturedQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), color, minU, minV, maxU, maxV); - } - - public UIRenderer drawTexturedQuad(IGuiBox box, float zLevel, int color, float minU, float minV, float maxU, float maxV) - { - return drawTexturedQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), zLevel, color, minU, minV, maxU, maxV); - } - - public UIRenderer drawTexturedQuad(float minX, float minY, float maxX, float maxY, int color, float minU, float minV, float maxU, float maxV) - { - return drawTexturedQuad(minX, minY, maxX, maxY, 0F, color, minU, minV, maxU, maxV); - } - - public UIRenderer drawTexturedQuad(float minX, float minY, float maxX, float maxY, float zLevel, int color, float minU, float minV, float maxU, float maxV) - { - ensureDrawing(GL11.GL_TRIANGLES, true); - applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(minU, maxV).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(minU, minV).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(maxU, maxV).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(maxU, maxV).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(minU, minV).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(maxU, minV).color4f(color).endVertex(); - alignTranslation.set(0F, 0F, 0F); - return this; - } - - public UIRenderer drawGradientQuad(IGuiBox box, int from, int to, Facing direction) - { - return drawGradientQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), from, to, direction); - } - - public UIRenderer drawGradientQuad(float minX, float minY, float maxX, float maxY, int from, int to, Facing direction) - { - return drawGradientQuad(minX, minY, maxX, maxY, 0F, from, to, direction); - } - - public UIRenderer drawGradientQuad(float minX, float minY, float maxX, float maxY, float zLevel, int start, int end, Facing direction) - { - if(!direction.isPositive()) - { - int wrapper = start; - start = end; - end = wrapper; - } - ensureDrawing(GL11.GL_TRIANGLES, false); - applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? start : end).endVertex(); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? start : start).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? end : end).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? end : end).endVertex(); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? start : start).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? end : start).endVertex(); - alignTranslation.set(0F, 0F, 0F); - return this; - } - - public UIRenderer drawFrame(IGuiBox box, int color) - { - return drawFrame(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), color); - } - - public UIRenderer drawFrame(IGuiBox box, float zLevel, int color) - { - return drawFrame(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), zLevel, color); - } - - public UIRenderer drawFrame(float minX, float minY, float maxX, float maxY, int color) - { - return drawFrame(minX, minY, maxX, maxY, 0F, color); - } - - public UIRenderer drawFrame(float minX, float minY, float maxX, float maxY, float zLevel, int color) - { - ensureDrawing(GL11.GL_LINES, false); - applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - alignTranslation.set(0F, 0F, 0F); - return this; - } - - public UIRenderer drawLine(float minX, float minY, float maxX, float maxY, int color) - { - return drawLine(minX, minY, maxX, maxY, 0F, color); - } - - public UIRenderer drawLine(float minX, float minY, float maxX, float maxY, float zLevel, int color) - { - ensureDrawing(GL11.GL_LINES, false); - applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); - pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); - alignTranslation.set(0F, 0F, 0F); - return this; - } - - public UIRenderer startCustomShape(int shapeType, boolean needsTexture) - { - sanityCheck("Custom Shape"); - ensureDrawing(shapeType, needsTexture); - return this; - } - - public UIRenderer pos(float x, float y, float z) - { - pos(transformHelper.set(x, y, z, 1F)); - return this; - } - - public UIRenderer pos(Vec3f pos) - { - return pos(pos.getX(), pos.getY(), pos.getZ()); - } - - public UIRenderer color(float r, float g, float b) - { - renderer.color4f(r, g, b); - return this; - } - - public UIRenderer color(float r, float g, float b, float a) - { - renderer.color4f(r, g, b, a); - return this; - } - - public UIRenderer color(int color) - { - renderer.color4f(color); - return this; - } - - public UIRenderer tex(float u, float v) - { - renderer.tex(u, v); - return this; - } - - public UIRenderer tex(Vec2f tex) - { - return tex(tex.getX(), tex.getY()); - } - - public UIRenderer endVertex() - { - renderer.endVertex(); - return this; - } - - protected void sanityCheck(String task) - { - if(drawing) - { - return; - } - throw new RuntimeException(task); - } - - protected Tesselator pos(Vec4f pos) - { - if(isFastTransform) - { - return renderer.pos(fastTransform(pos.getX(), fastTransform.getX(), alignTranslation.getX()), fastTransform(pos.getY(), fastTransform.getY(), alignTranslation.getY()), fastTransform(pos.getZ(), fastTransform.getZ(), alignTranslation.getZ())); - } - float x = (transform.get(0) * pos.getX() + transform.get(4) * pos.getY() + transform.get(8) * pos.getZ() + transform.get(12)) + (alignTranslation.getX() * alignScale.getX()); - float y = (transform.get(1) * pos.getX() + transform.get(5) * pos.getY() + transform.get(9) * pos.getZ() + transform.get(13)) + (alignTranslation.getY() * alignScale.getY()); - float z = (transform.get(2) * pos.getX() + transform.get(6) * pos.getY() + transform.get(10) * pos.getZ() + transform.get(14)) + (alignTranslation.getZ() * alignScale.getZ()); - return renderer.pos(x, y, z); - } - - private float fastTransform(float pos, float offset, float align) - { - return ((pos + align) * fastTransform.getW()) + offset; - } - - protected void applyAlignment(float minX, float minY, float maxX, float maxY, float zLevel, Vec4f result) - { - applyAlignment(minX, minY, maxX, maxY, zLevel, vertical, horizontal, renderer, result); - } - - protected void applyAlignment(float minX, float minY, float maxX, float maxY, float zLevel, Align vertical, Align horizontal, Tesselator tes, Vec4f result) - { - float width = maxX - minX; - float height = maxY - minY; - float xOffset = 0F; - float yOffset = 0F; - switch(vertical) - { - case LEFT_TOP: - yOffset = 0; - result.setY(0F).setW(height); - break; - case CENTER: - yOffset = height / 2F; - result.setY(-yOffset).setW(yOffset); - break; - case RIGHT_BOTTOM: - yOffset = maxY; - result.setY(-height).setW(0F); - break; - } - switch(horizontal) - { - case LEFT_TOP: - xOffset = 0; - result.setX(0F).setZ(width); - break; - case CENTER: - xOffset = width / 2F; - result.setX(-xOffset).setZ(xOffset); - break; - case RIGHT_BOTTOM: - xOffset = maxX; - result.setX(-width).setZ(0F); - break; - } - alignTranslation.set(minX + xOffset, minY + yOffset, zLevel); - } - - protected void ensureDrawing(int glState, boolean textureNeeded) - { - if(!renderer.isDrawing()) - { - renderer.begin(glState, VertexType.UI); - } - if(glState != renderer.getGLDrawType() || useTexture != textureNeeded) - { - addDrawCall(); - renderer.changeGLType(glState); - useTexture = textureNeeded; - } - } - - protected void addDrawCall() - { - if(getDrawCall() >= renderer.getVertexCount()) - { - return; - } - GLCall call = callPool.get(); - call.setType(renderer.getGLDrawType()); - call.setCount(renderer.getVertexCount()); - call.setTexture(getTextureId(useTexture ? currentTexture : null)); - call.setFrame(currentFrame); - call.setRounded(roundedNess); - activeCalls.enqueue(call); - } - - private int getDrawCall() - { - return activeCalls.isEmpty() ? 0 : activeCalls.last().getCount(); - } - - private int getTextureId(ITexture texture) - { - return texture == null ? 0 : texture.getTextureId(); - } -} +package speiger.src.coreengine.rendering.gui.renderer; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.system.MemoryUtil; + +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.collections.objects.queues.ObjectArrayFIFOQueue; +import speiger.src.collections.objects.queues.ObjectPriorityDequeue; +import speiger.src.collections.utils.Stack; +import speiger.src.coreengine.assets.reloader.IReloadableResource; +import speiger.src.coreengine.math.misc.Facing; +import speiger.src.coreengine.math.vector.floats.Vec2f; +import speiger.src.coreengine.math.vector.floats.Vec3f; +import speiger.src.coreengine.math.vector.floats.Vec4f; +import speiger.src.coreengine.math.vector.matrix.Matrix4f; +import speiger.src.coreengine.math.vector.quaternion.Quaternion; +import speiger.src.coreengine.rendering.gui.GuiManager; +import speiger.src.coreengine.rendering.gui.helper.Align; +import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox; +import speiger.src.coreengine.rendering.gui.renderer.buffer.RenderBuffer; +import speiger.src.coreengine.rendering.models.DrawCall; +import speiger.src.coreengine.rendering.shader.uniforms.UniformVec2f; +import speiger.src.coreengine.rendering.tesselation.GLCall; +import speiger.src.coreengine.rendering.tesselation.Tesselator; +import speiger.src.coreengine.rendering.tesselation.VertexType; +import speiger.src.coreengine.rendering.textures.base.ITexture; +import speiger.src.coreengine.rendering.textures.base.TextureManager; +import speiger.src.coreengine.rendering.utils.GLUtils; +import speiger.src.coreengine.utils.collections.pools.SimplePool; + +public class UIRenderer implements IReloadableResource +{ + SimplePool recylcePool = new SimplePool<>(100, Matrix4f::new); + Stack transformStack = new ObjectArrayList<>(); + Matrix4f transform = new Matrix4f(); + boolean isFastTransform = true; + SimplePool fastPool = new SimplePool<>(100, Vec4f::of); + Stack fastStack = new ObjectArrayList<>(); + Vec4f fastTransform = Vec4f.mutable(0F, 0F, 0F, 1F); + + SimplePool callPool = new SimplePool<>(100, GLCall::new); + ObjectPriorityDequeue activeCalls = new ObjectArrayFIFOQueue<>(); + + Tesselator bufferHelper = new Tesselator(655340); + FloatBuffer renderBuffer = MemoryUtil.memAllocFloat(655340); + Tesselator renderer = new Tesselator(renderBuffer); + ITexture currentTexture; + boolean drawing = false; + boolean useTexture = false; + Vec4f currentFrame = Vec4f.mutable(); + float roundedNess = 0F; + + GuiModel texturedModel = GuiModel.createTextureModel(Short.MAX_VALUE * 2); + + Align horizontal = Align.CENTER; + Align vertical = Align.CENTER; + + Vec3f helper = Vec3f.mutable(); + Vec4f transformHelper = Vec4f.mutable(); + Vec4f alignHelper = Vec4f.mutable(); + Vec3f alignTranslation = Vec3f.mutable(0F); + Vec3f alignScale = Vec3f.mutable(1F); + + GuiManager manager; + + public UIRenderer(GuiManager manager) + { + this.manager = manager; + TextureManager.INSTANCE.getReloader().addReloadableResource(this); + } + + public RenderBuffer createBuffer() + { + return new RenderBuffer(bufferHelper); + } + + public UIRenderer push() + { + if(isFastTransform) fastStack.push(fastPool.get().set(fastTransform)); + else transformStack.push(recylcePool.get().load(transform)); + return this; + } + + public UIRenderer pop() + { + if(isFastTransform) + { + Vec4f pop = fastStack.pop(); + fastTransform.set(pop); + fastPool.accept(pop); + return this; + } + Matrix4f pop = transformStack.pop(); + transform.load(pop); + pop.getScale(alignScale); + recylcePool.accept(pop); + return this; + } + + public UIRenderer setVisibility(float visibility) + { + sanityCheck("Visibilty Change"); + renderer.setVisibilty(visibility); + return this; + } + + public UIRenderer setBrightness(float brightness) + { + sanityCheck("Brightness change"); + renderer.setBrightness(brightness); + return this; + } + + public UIRenderer resetEffects() + { + renderer.setBrightness(1F).setVisibilty(1F); + return this; + } + + public UIRenderer setActiveTexture(ITexture texture) + { + if(getTextureId(currentTexture) != getTextureId(texture)) + { + addDrawCall(); + currentTexture = texture; + } + return this; + } + + public UIRenderer setRoundness(IGuiBox box, float roundedNess) + { + if(roundedNess <= 0) + { + if(this.roundedNess > 0F) addDrawCall(); + this.roundedNess = roundedNess; + return this; + } + alignHelper.set(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY()); + if(!currentFrame.equals(alignHelper) || this.roundedNess != roundedNess) + { + addDrawCall(); + currentFrame.set(alignHelper); + this.roundedNess = roundedNess; + } + return this; + } + + protected void applyEffects(UniformVec2f vec) + { + vec.storeData(renderer.getBrightness(), renderer.getVisibility()); + } + + public UIRenderer translate(float x, float y) + { + return translate(x, y, 0F); + } + + public UIRenderer translate(Vec2f offset) + { + return translate(offset.getX(), offset.getY(), 0F); + } + + public UIRenderer translate(float x, float y, float z) + { + if(isFastTransform) + { + fastTransform.add(x, y, z, 0F); + return this; + } + transform.translate(x, y, z); + return this; + } + + public UIRenderer translate(Vec3f offset) + { + if(isFastTransform) + { + fastTransform.add(offset.getX(), offset.getY(), offset.getZ(), 0F); + return this; + } + transform.translate(offset); + return this; + } + + public UIRenderer rotate(Quaternion quad) + { + if(isFastTransform) return this; + transform.rotate(quad); + return this; + } + + public UIRenderer rotateX(float angle) + { + if(isFastTransform) return this; + transform.rotateX((float)Math.toRadians(angle)); + return this; + } + + public UIRenderer rotateY(float angle) + { + if(isFastTransform) return this; + transform.rotateY((float)Math.toRadians(angle)); + return this; + } + + public UIRenderer rotateZ(float angle) + { + if(isFastTransform) return this; + transform.rotateZ((float)Math.toRadians(angle)); + return this; + } + + public UIRenderer scale(float x, float y, float z) + { + if(isFastTransform) return this; + transform.scale(x, y, z); + alignScale.multiply(x, y, z); + return this; + } + + public UIRenderer scale(float scale) + { + if(isFastTransform) + { + fastTransform.multiply(1F, 1F, 1F, scale); + return this; + } + transform.scale(helper.set(scale, scale, scale)); + alignScale.multiply(scale); + return this; + } + + public UIRenderer unscale(float x, float y, float z) + { + if(isFastTransform) return this; + transform.scale(helper.set(1.0F / x, 1.0F / y, 1.0F / z)); + alignScale.multiply(helper); + return this; + } + + public UIRenderer unscale(float scale) + { + scale = 1.0F / scale; + if(isFastTransform) + { + fastTransform.multiply(1F, 1F, 1F, scale); + return this; + } + transform.scale(scale, scale, scale).getScale(alignScale); + alignScale.multiply(scale); + return this; + } + + public UIRenderer resetTransform() + { + if(isFastTransform) + { + fastTransform.set(0F, 0F, 0F, 1F); + return this; + } + transform.setIdentity(); + alignScale.set(Vec3f.ONE); + return this; + } + + public float getCurrentZ() + { + return isFastTransform ? fastTransform.getZ() : transform.get(3, 2); + } + + public ITexture getActiveTexture() + { + return currentTexture; + } + + protected Matrix4f getCurrentMatrix() + { + return transform; + } + + public Matrix4f createCurrentMatrix(Matrix4f matrix) + { + return isFastTransform ? matrix.setIdentity().translate(fastTransform.getX(), fastTransform.getY(), fastTransform.getZ()) : matrix.load(transform); + } + + public UIRenderer setFastTransform(boolean fast) + { + isFastTransform = fast; + return this; + } + + public UIRenderer beginFrame() + { + if(drawing) + { + throw new RuntimeException("Already Drawing!"); + } + drawing = true; + fastTransform.set(0F, 0F, 0F, 1F); + roundedNess = 0F; + currentFrame.negate(); + transform.setIdentity(); + alignScale.set(Vec3f.ONE); + transformStack.clear(); + fastStack.clear(); + return this; + } + + public UIRenderer flush() + { + if(!renderer.isDrawing()) + { + return this; + } + renderer.finishData(); + int count = renderer.getVertexCount(); + if(count <= 0) + { + return this; + } + if(count > (activeCalls.isEmpty() ? 0 : activeCalls.last().getCount())) + { + addDrawCall(); + } + texturedModel.storeData(renderBuffer); + GuiShader shader = manager.getShader(); + shader.bind(manager.getOrthoMatrixBuffer()); + texturedModel.bindArray(); + int last = 0; + while(!activeCalls.isEmpty()) + { + GLCall call = activeCalls.dequeue(); + shader.texture.storeTexture(call.getTexture()); + shader.useTexture.storeData(call.getTexture() > 0 ? 1F : 0F); + shader.roundeness.storeData(call.getRoundedNess()); + if(call.getRoundedNess() > 0F) shader.bounds.storeData(call.getFrame()); + GLUtils.drawArrays(call.getType(), last, call.getCount() - last); + last = call.getCount(); + callPool.accept(call); + } + texturedModel.unbindArray(); + shader.stopShader(); + renderer.resetVertexes(); + return this; + } + + public UIRenderer endFrame() + { + if(!drawing) + { + throw new RuntimeException("Not Drawing!"); + } + drawing = false; + isFastTransform = true; + flush(); + fastTransform.set(0F, 0F, 0F, 1F); + transform.setIdentity(); + renderer.resetEffects(); + useTexture = false; + while(!transformStack.isEmpty()) + { + recylcePool.accept(transformStack.pop()); + } + while(!fastStack.isEmpty()) + { + fastPool.accept(fastStack.pop()); + } + return this; + } + + @Override + public void reload() + { + texturedModel.remove(); + MemoryUtil.memFree(renderBuffer); + texturedModel = GuiModel.createTextureModel(Short.MAX_VALUE * 2); + renderBuffer = MemoryUtil.memAllocFloat(655340); + renderer = new Tesselator(renderBuffer); + } + + @Override + public void destroy() + { + texturedModel.remove(); + MemoryUtil.memFree(renderBuffer); + TextureManager.INSTANCE.getReloader().removeReloadableResource(this); + } + + public UIRenderer drawBuffers(Iterable drawCalls, float width, float height) + { + sanityCheck("Buffer Drawing"); + applyAlignment(0, 0, width, height, 0, alignHelper); + for(DrawCall call : drawCalls) + { + ensureDrawing(call.getGLType(), call.getTextureId() > 0); + FloatBuffer buffer = ByteBuffer.wrap(call.getData()).order(ByteOrder.nativeOrder()).asFloatBuffer(); + for(int i = 0,m=buffer.remaining();i+9<=m;i+=9) + { + pos(transformHelper.set(buffer.get(i)+alignHelper.getX(), buffer.get(i+1)+alignHelper.getY(), buffer.get(i+2), 1F)) + .tex(buffer.get(i+3), buffer.get(i+4)) + .color4f(buffer.get(i+5), buffer.get(i+6), buffer.get(i+7), buffer.get(i+8)).endVertex(); + } + } + alignTranslation.set(0F, 0F, 0F); + return this; + } + + public UIRenderer drawQuad(IGuiBox box, int color) + { + return drawQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), color); + } + + public UIRenderer drawQuad(IGuiBox box, float zLevel, int color) + { + return drawQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), zLevel, color); + } + + public UIRenderer drawQuad(float minX, float minY, float maxX, float maxY, int color) + { + return drawQuad(minX, minY, maxX, maxY, 0.0F, color); + } + + public UIRenderer drawQuad(float minX, float minY, float maxX, float maxY, float zLevel, int color) + { + ensureDrawing(GL11.GL_TRIANGLES, false); + applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + alignTranslation.set(0F, 0F, 0F); + return this; + } + + public UIRenderer drawTexturedQuad(IGuiBox box, int color, float minU, float minV, float maxU, float maxV) + { + return drawTexturedQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), color, minU, minV, maxU, maxV); + } + + public UIRenderer drawTexturedQuad(IGuiBox box, float zLevel, int color, float minU, float minV, float maxU, float maxV) + { + return drawTexturedQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), zLevel, color, minU, minV, maxU, maxV); + } + + public UIRenderer drawTexturedQuad(float minX, float minY, float maxX, float maxY, int color, float minU, float minV, float maxU, float maxV) + { + return drawTexturedQuad(minX, minY, maxX, maxY, 0F, color, minU, minV, maxU, maxV); + } + + public UIRenderer drawTexturedQuad(float minX, float minY, float maxX, float maxY, float zLevel, int color, float minU, float minV, float maxU, float maxV) + { + ensureDrawing(GL11.GL_TRIANGLES, true); + applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(minU, maxV).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(minU, minV).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(maxU, maxV).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(maxU, maxV).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(minU, minV).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(maxU, minV).color4f(color).endVertex(); + alignTranslation.set(0F, 0F, 0F); + return this; + } + + public UIRenderer drawGradientQuad(IGuiBox box, int from, int to, Facing direction) + { + return drawGradientQuad(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), from, to, direction); + } + + public UIRenderer drawGradientQuad(float minX, float minY, float maxX, float maxY, int from, int to, Facing direction) + { + return drawGradientQuad(minX, minY, maxX, maxY, 0F, from, to, direction); + } + + public UIRenderer drawGradientQuad(float minX, float minY, float maxX, float maxY, float zLevel, int start, int end, Facing direction) + { + if(!direction.isPositive()) + { + int wrapper = start; + start = end; + end = wrapper; + } + ensureDrawing(GL11.GL_TRIANGLES, false); + applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? start : end).endVertex(); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? start : start).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? end : end).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? end : end).endVertex(); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? start : start).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(direction.isXAxis() ? end : start).endVertex(); + alignTranslation.set(0F, 0F, 0F); + return this; + } + + public UIRenderer drawFrame(IGuiBox box, int color) + { + return drawFrame(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), color); + } + + public UIRenderer drawFrame(IGuiBox box, float zLevel, int color) + { + return drawFrame(box.getMinX(), box.getMinY(), box.getMaxX(), box.getMaxY(), zLevel, color); + } + + public UIRenderer drawFrame(float minX, float minY, float maxX, float maxY, int color) + { + return drawFrame(minX, minY, maxX, maxY, 0F, color); + } + + public UIRenderer drawFrame(float minX, float minY, float maxX, float maxY, float zLevel, int color) + { + ensureDrawing(GL11.GL_LINES, false); + applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + alignTranslation.set(0F, 0F, 0F); + return this; + } + + public UIRenderer drawLine(float minX, float minY, float maxX, float maxY, int color) + { + return drawLine(minX, minY, maxX, maxY, 0F, color); + } + + public UIRenderer drawLine(float minX, float minY, float maxX, float maxY, float zLevel, int color) + { + ensureDrawing(GL11.GL_LINES, false); + applyAlignment(minX, minY, maxX, maxY, zLevel, alignHelper); + pos(transformHelper.set(alignHelper.getX(), alignHelper.getY(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + pos(transformHelper.set(alignHelper.getZ(), alignHelper.getW(), 0F, 1F)).tex(0F, 0F).color4f(color).endVertex(); + alignTranslation.set(0F, 0F, 0F); + return this; + } + + public UIRenderer startCustomShape(int shapeType, boolean needsTexture) + { + sanityCheck("Custom Shape"); + ensureDrawing(shapeType, needsTexture); + return this; + } + + public UIRenderer pos(float x, float y, float z) + { + pos(transformHelper.set(x, y, z, 1F)); + return this; + } + + public UIRenderer pos(Vec3f pos) + { + return pos(pos.getX(), pos.getY(), pos.getZ()); + } + + public UIRenderer color(float r, float g, float b) + { + renderer.color4f(r, g, b); + return this; + } + + public UIRenderer color(float r, float g, float b, float a) + { + renderer.color4f(r, g, b, a); + return this; + } + + public UIRenderer color(int color) + { + renderer.color4f(color); + return this; + } + + public UIRenderer tex(float u, float v) + { + renderer.tex(u, v); + return this; + } + + public UIRenderer tex(Vec2f tex) + { + return tex(tex.getX(), tex.getY()); + } + + public UIRenderer endVertex() + { + renderer.endVertex(); + return this; + } + + protected void sanityCheck(String task) + { + if(drawing) + { + return; + } + throw new RuntimeException(task); + } + + protected Tesselator pos(Vec4f pos) + { + if(isFastTransform) + { + return renderer.pos(fastTransform(pos.getX(), fastTransform.getX(), alignTranslation.getX()), fastTransform(pos.getY(), fastTransform.getY(), alignTranslation.getY()), fastTransform(pos.getZ(), fastTransform.getZ(), alignTranslation.getZ())); + } + float x = (transform.get(0) * pos.getX() + transform.get(4) * pos.getY() + transform.get(8) * pos.getZ() + transform.get(12)) + (alignTranslation.getX() * alignScale.getX()); + float y = (transform.get(1) * pos.getX() + transform.get(5) * pos.getY() + transform.get(9) * pos.getZ() + transform.get(13)) + (alignTranslation.getY() * alignScale.getY()); + float z = (transform.get(2) * pos.getX() + transform.get(6) * pos.getY() + transform.get(10) * pos.getZ() + transform.get(14)) + (alignTranslation.getZ() * alignScale.getZ()); + return renderer.pos(x, y, z); + } + + private float fastTransform(float pos, float offset, float align) + { + return ((pos + align) * fastTransform.getW()) + offset; + } + + protected void applyAlignment(float minX, float minY, float maxX, float maxY, float zLevel, Vec4f result) + { + applyAlignment(minX, minY, maxX, maxY, zLevel, vertical, horizontal, renderer, result); + } + + protected void applyAlignment(float minX, float minY, float maxX, float maxY, float zLevel, Align vertical, Align horizontal, Tesselator tes, Vec4f result) + { + float width = maxX - minX; + float height = maxY - minY; + float xOffset = 0F; + float yOffset = 0F; + switch(vertical) + { + case LEFT_TOP: + yOffset = 0; + result.setY(0F).setW(height); + break; + case CENTER: + yOffset = height / 2F; + result.setY(-yOffset).setW(yOffset); + break; + case RIGHT_BOTTOM: + yOffset = maxY; + result.setY(-height).setW(0F); + break; + } + switch(horizontal) + { + case LEFT_TOP: + xOffset = 0; + result.setX(0F).setZ(width); + break; + case CENTER: + xOffset = width / 2F; + result.setX(-xOffset).setZ(xOffset); + break; + case RIGHT_BOTTOM: + xOffset = maxX; + result.setX(-width).setZ(0F); + break; + } + alignTranslation.set(minX + xOffset, minY + yOffset, zLevel); + } + + protected void ensureDrawing(int glState, boolean textureNeeded) + { + if(!renderer.isDrawing()) + { + renderer.begin(glState, VertexType.UI); + } + if(glState != renderer.getGLDrawType() || useTexture != textureNeeded) + { + addDrawCall(); + renderer.changeGLType(glState); + useTexture = textureNeeded; + } + } + + protected void addDrawCall() + { + if(getDrawCall() >= renderer.getVertexCount()) + { + return; + } + GLCall call = callPool.get(); + call.setType(renderer.getGLDrawType()); + call.setCount(renderer.getVertexCount()); + call.setTexture(getTextureId(useTexture ? currentTexture : null)); + call.setFrame(currentFrame); + call.setRounded(roundedNess); + activeCalls.enqueue(call); + } + + private int getDrawCall() + { + return activeCalls.isEmpty() ? 0 : activeCalls.last().getCount(); + } + + private int getTextureId(ITexture texture) + { + return texture == null ? 0 : texture.getTextureId(); + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/renderer/buffer/RenderBuffer.java b/src/main/java/speiger/src/coreengine/rendering/gui/renderer/buffer/RenderBuffer.java index 105b472..75ebb10 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/renderer/buffer/RenderBuffer.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/renderer/buffer/RenderBuffer.java @@ -1,80 +1,80 @@ -package speiger.src.coreengine.rendering.gui.renderer.buffer; - -import java.util.Iterator; -import java.util.List; -import java.util.function.Consumer; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.coreengine.rendering.gui.GuiComponent; -import speiger.src.coreengine.rendering.models.DrawCall; -import speiger.src.coreengine.rendering.tesselation.Tesselator; -import speiger.src.coreengine.rendering.tesselation.VertexList; -import speiger.src.coreengine.utils.collections.iterators.IndexIterator; -import speiger.src.coreengine.utils.collections.iterators.IterableWrapper; - -public class RenderBuffer implements Consumer, Iterable -{ - List drawCalls = new ObjectArrayList(); - Tesselator tesselator; - - public RenderBuffer(Tesselator tesselator) - { - this.tesselator = tesselator; - } - - @Override - public void accept(GuiComponent t) - { - clear(); - } - - public T get(int index, Class clz) - { - return (T)drawCalls.get(index); - } - - public void addDrawCall(DrawCall call) - { - drawCalls.add(call); - } - - public void clear() - { - drawCalls.clear(); - } - - public Tesselator start(int shape, VertexList format) - { - return tesselator.begin(shape, format); - } - - public void finishShape(int texture, Tesselator tesselator) - { - if(!tesselator.isDrawing()) - { - throw new IllegalStateException("Tesselator wasnt filled"); - } - tesselator.finishData(); - if(tesselator.getVertexCount() <= 0) - { - return; - } - drawCalls.add(tesselator.getDrawCall(texture)); - } - - public void finishShape(int texture) - { - finishShape(texture, tesselator); - } - - @Override - public Iterator iterator() - { - return drawCalls.iterator(); - } - - public Iterable selectionIterator(int...indexes) - { - return IterableWrapper.wrap(new IndexIterator<>(drawCalls, indexes)); - } -} +package speiger.src.coreengine.rendering.gui.renderer.buffer; + +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; + +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.coreengine.rendering.gui.GuiComponent; +import speiger.src.coreengine.rendering.models.DrawCall; +import speiger.src.coreengine.rendering.tesselation.Tesselator; +import speiger.src.coreengine.rendering.tesselation.VertexList; +import speiger.src.coreengine.utils.collections.iterators.IndexIterator; +import speiger.src.coreengine.utils.collections.iterators.IterableWrapper; + +public class RenderBuffer implements Consumer, Iterable +{ + List drawCalls = new ObjectArrayList<>(); + Tesselator tesselator; + + public RenderBuffer(Tesselator tesselator) + { + this.tesselator = tesselator; + } + + @Override + public void accept(GuiComponent t) + { + clear(); + } + + public T get(int index, Class clz) + { + return (T)drawCalls.get(index); + } + + public void addDrawCall(DrawCall call) + { + drawCalls.add(call); + } + + public void clear() + { + drawCalls.clear(); + } + + public Tesselator start(int shape, VertexList format) + { + return tesselator.begin(shape, format); + } + + public void finishShape(int texture, Tesselator tesselator) + { + if(!tesselator.isDrawing()) + { + throw new IllegalStateException("Tesselator wasnt filled"); + } + tesselator.finishData(); + if(tesselator.getVertexCount() <= 0) + { + return; + } + drawCalls.add(tesselator.getDrawCall(texture)); + } + + public void finishShape(int texture) + { + finishShape(texture, tesselator); + } + + @Override + public Iterator iterator() + { + return drawCalls.iterator(); + } + + public Iterable selectionIterator(int...indexes) + { + return IterableWrapper.wrap(new IndexIterator<>(drawCalls, indexes)); + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/gui/renderer/lexer/Line.java b/src/main/java/speiger/src/coreengine/rendering/gui/renderer/lexer/Line.java index 63df5c3..adc95e4 100644 --- a/src/main/java/speiger/src/coreengine/rendering/gui/renderer/lexer/Line.java +++ b/src/main/java/speiger/src/coreengine/rendering/gui/renderer/lexer/Line.java @@ -1,142 +1,142 @@ -package speiger.src.coreengine.rendering.gui.renderer.lexer; - -import java.util.List; - -import speiger.src.collections.objects.collections.ObjectIterator; -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.collections.objects.utils.ObjectIterators; -import speiger.src.coreengine.rendering.gui.renderer.IFontRenderer.CharInstance; -import speiger.src.coreengine.utils.collections.iterators.IterableWrapper; - -public class Line -{ - float totalWidth; - float width; - int totalLetters = 0; - String result = null; - List words = new ObjectArrayList(); - - public Line(float totalWidth) - { - this.totalWidth = totalWidth; - } - - public boolean attemptAddingWord(Word word) - { - if(word.getWidth() + width > totalWidth) - { - return false; - } - width += word.getWidth(); - words.add(word); - totalLetters += word.size(); - return true; - } - - public void addWord(Word word) - { - width += word.getWidth(); - words.add(word); - totalLetters += word.size(); - } - - protected void finishLine() - { - StringBuilder builder = new StringBuilder(); - for(Word word : words) - { - builder.append(word.getLetters()); - } - result = builder.toString(); - } - - public int getIndex(float width, boolean total) - { - if(width <= 0F) return (total && !words.isEmpty()) ? words.get(0).getStartIndex() : 0; - if(width >= this.width) return ((total && !words.isEmpty()) ? words.get(0).getStartIndex() : 0) + totalLetters; - int letters = (total && !words.isEmpty()) ? words.get(0).getStartIndex() : 0; - for(int i = 0,m=words.size();i width) - { - return letters + word.getIndex(width); - } - width -= word.getWidth(); - letters += word.size(); - } - return letters; - } - - public String getText() - { - return result; - } - - public boolean isEmpty() - { - return words.isEmpty(); - } - - public int size() - { - return totalLetters; - } - - public int getStart() - { - return words.isEmpty() ? 0 : words.get(0).getStartIndex(); - } - - public int getEnd() - { - return words.isEmpty() ? 0 : words.get(words.size() - 1).getEndIndex(); - } - - public Word getWord(int letterIndex) - { - for(int i = 0;i= letterIndex) - { - return word; - } - letterIndex -= word.size(); - } - return null; - } - - public float getWidth() - { - return width; - } - - public float getWidth(int index) - { - if(index <= 0) return 0F; - else if(index >= totalLetters) return width; - float width = 0F; - for(int i = 0,m=words.size();i index) - { - return width + word.getWidth(index); - } - width += word.getWidth(); - index -= word.size(); - } - return 0; - } - - public Iterable letterIterator() - { - ObjectIterator[] arrays = new ObjectIterator[words.size()]; - for(int i = 0,m=words.size();i words = new ObjectArrayList<>(); + + public Line(float totalWidth) + { + this.totalWidth = totalWidth; + } + + public boolean attemptAddingWord(Word word) + { + if(word.getWidth() + width > totalWidth) + { + return false; + } + width += word.getWidth(); + words.add(word); + totalLetters += word.size(); + return true; + } + + public void addWord(Word word) + { + width += word.getWidth(); + words.add(word); + totalLetters += word.size(); + } + + protected void finishLine() + { + StringBuilder builder = new StringBuilder(); + for(Word word : words) + { + builder.append(word.getLetters()); + } + result = builder.toString(); + } + + public int getIndex(float width, boolean total) + { + if(width <= 0F) return (total && !words.isEmpty()) ? words.get(0).getStartIndex() : 0; + if(width >= this.width) return ((total && !words.isEmpty()) ? words.get(0).getStartIndex() : 0) + totalLetters; + int letters = (total && !words.isEmpty()) ? words.get(0).getStartIndex() : 0; + for(int i = 0,m=words.size();i width) + { + return letters + word.getIndex(width); + } + width -= word.getWidth(); + letters += word.size(); + } + return letters; + } + + public String getText() + { + return result; + } + + public boolean isEmpty() + { + return words.isEmpty(); + } + + public int size() + { + return totalLetters; + } + + public int getStart() + { + return words.isEmpty() ? 0 : words.get(0).getStartIndex(); + } + + public int getEnd() + { + return words.isEmpty() ? 0 : words.get(words.size() - 1).getEndIndex(); + } + + public Word getWord(int letterIndex) + { + for(int i = 0;i= letterIndex) + { + return word; + } + letterIndex -= word.size(); + } + return null; + } + + public float getWidth() + { + return width; + } + + public float getWidth(int index) + { + if(index <= 0) return 0F; + else if(index >= totalLetters) return width; + float width = 0F; + for(int i = 0,m=words.size();i index) + { + return width + word.getWidth(index); + } + width += word.getWidth(); + index -= word.size(); + } + return 0; + } + + public Iterable letterIterator() + { + ObjectIterator[] arrays = new ObjectIterator[words.size()]; + for(int i = 0,m=words.size();i lines = new ObjectArrayList(); - float startX; - float startY; - float maxHeight; - float maxWidth = 0F; - float scale; - - public TextMetadata(TextComponent owner) - { - this.owner = owner; - } - - public void clear() - { - scale = owner.getTextScale(); - lines.clear(); - maxWidth = 0F; - maxHeight = 0F; - startX = 0F; - startY = 0F; - } - - public void addLine(Line line) - { - lines.add(line); - maxWidth = Math.max(maxWidth, line.getWidth()); - maxHeight = lines.size() * owner.getFont().height() * scale; - } - - public void setStart(float x, float y) - { - startX = x; - startY = y; - } - - public float getStartX() - { - return startX; - } - - public float getStartY() - { - return startY; - } - - public float getMaxHeight() - { - return maxHeight; - } - - public float getMaxWidth() - { - return maxWidth; - } - - public float getWidth(int letterIndex) - { - return lines.isEmpty() ? 0F : lines.get(0).getWidth(letterIndex); - } - - public float getWidth(int posX, int posY) - { - return lines.size() > posY ? lines.get(posY).getWidth(posX) : 0F; - } - - public float getLineWidth(int line) - { - return lines.size() > line ? lines.get(line).getWidth() : 0F; - } - - public Word getWord(int letterIndex) - { - return lines.isEmpty() ? null : lines.get(0).getWord(letterIndex); - } - - public Line getLine(int line) - { - return lines.size() > line ? lines.get(line) : null; - } - - public int moveUp(Vec2i pos) - { - if(pos.getY() + 1 < lines.size()) - { - float width = lines.get(pos.getY()).getWidth(pos.getX()); - return lines.get(pos.getY() + 1).getIndex(width, true); - } - return lines.isEmpty() ? 0 : lines.get(lines.size() - 1).getEnd(); - } - - public int moveDown(Vec2i pos) - { - if(pos.getY() > 0 && pos.getY() - 1 < lines.size()) - { - float width = lines.get(pos.getY()).getWidth(pos.getX()); - return lines.get(pos.getY() - 1).getIndex(width, true); - } - return lines.isEmpty() ? 0 : lines.get(0).getStart(); - } - - public int getIndex(float width) - { - return lines.size() > 0 ? lines.get(0).getIndex(width, false) : 0; - } - - public int getIndex(float width, float height) - { - return lines.isEmpty() ? 0 : lines.get(MathUtils.clamp(0, lines.size() - 1, (int)(height / (owner.getFont().height() * scale)))).getIndex(width, true); - } - - public void getIndex(float width, float height, Vec2i result) - { - if(lines.isEmpty()) - { - result.negate(); - return; - } - int index = MathUtils.clamp(0, lines.size() - 1, (int)(height / (owner.getFont().height() * scale))); - result.set(lines.get(index).getIndex(width, false), index); - } - - public void convert(int index, Vec2i result) - { - result.set(Vec2i.ZERO); - for(int i = 0,m=lines.size();i= index) - { - result.add(index, i); - return; - } - index -= line.size(); - } - } - - public int convert(Vec2i input) - { - int index = input.getX(); - for(int i = 0,m=input.getY();i lines = new ObjectArrayList<>(); + float startX; + float startY; + float maxHeight; + float maxWidth = 0F; + float scale; + + public TextMetadata(TextComponent owner) + { + this.owner = owner; + } + + public void clear() + { + scale = owner.getTextScale(); + lines.clear(); + maxWidth = 0F; + maxHeight = 0F; + startX = 0F; + startY = 0F; + } + + public void addLine(Line line) + { + lines.add(line); + maxWidth = Math.max(maxWidth, line.getWidth()); + maxHeight = lines.size() * owner.getFont().height() * scale; + } + + public void setStart(float x, float y) + { + startX = x; + startY = y; + } + + public float getStartX() + { + return startX; + } + + public float getStartY() + { + return startY; + } + + public float getMaxHeight() + { + return maxHeight; + } + + public float getMaxWidth() + { + return maxWidth; + } + + public float getWidth(int letterIndex) + { + return lines.isEmpty() ? 0F : lines.get(0).getWidth(letterIndex); + } + + public float getWidth(int posX, int posY) + { + return lines.size() > posY ? lines.get(posY).getWidth(posX) : 0F; + } + + public float getLineWidth(int line) + { + return lines.size() > line ? lines.get(line).getWidth() : 0F; + } + + public Word getWord(int letterIndex) + { + return lines.isEmpty() ? null : lines.get(0).getWord(letterIndex); + } + + public Line getLine(int line) + { + return lines.size() > line ? lines.get(line) : null; + } + + public int moveUp(Vec2i pos) + { + if(pos.getY() + 1 < lines.size()) + { + float width = lines.get(pos.getY()).getWidth(pos.getX()); + return lines.get(pos.getY() + 1).getIndex(width, true); + } + return lines.isEmpty() ? 0 : lines.get(lines.size() - 1).getEnd(); + } + + public int moveDown(Vec2i pos) + { + if(pos.getY() > 0 && pos.getY() - 1 < lines.size()) + { + float width = lines.get(pos.getY()).getWidth(pos.getX()); + return lines.get(pos.getY() - 1).getIndex(width, true); + } + return lines.isEmpty() ? 0 : lines.get(0).getStart(); + } + + public int getIndex(float width) + { + return lines.size() > 0 ? lines.get(0).getIndex(width, false) : 0; + } + + public int getIndex(float width, float height) + { + return lines.isEmpty() ? 0 : lines.get(MathUtils.clamp(0, lines.size() - 1, (int)(height / (owner.getFont().height() * scale)))).getIndex(width, true); + } + + public void getIndex(float width, float height, Vec2i result) + { + if(lines.isEmpty()) + { + result.negate(); + return; + } + int index = MathUtils.clamp(0, lines.size() - 1, (int)(height / (owner.getFont().height() * scale))); + result.set(lines.get(index).getIndex(width, false), index); + } + + public void convert(int index, Vec2i result) + { + result.set(Vec2i.ZERO); + for(int i = 0,m=lines.size();i= index) + { + result.add(index, i); + return; + } + index -= line.size(); + } + } + + public int convert(Vec2i input) + { + int index = input.getX(); + for(int i = 0,m=input.getY();i callbacks = new ObjectArrayList(); - List listeners = new ObjectArrayList(); - GLCapabilities capabilities; - - public Window() - { - GLFW.glfwDefaultWindowHints(); - GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, 0); // 0 = False, 1 = true - GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, 1); - GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4); - GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0); - GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);//GLFW.GLFW_OPENGL_COMPAT_PROFILE); - GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, 1); - } - - protected void initWindowListeners() - { - addCallback(T -> GLFW.glfwSetFramebufferSizeCallback(T, this::onResize)); - addCallback(T -> GLFW.glfwSetWindowMaximizeCallback(T, (K, V) -> flags.setFlag(FLAG_WINDOW_CHANGE))); - addCallback(T -> GLFW.glfwSetWindowPosCallback(T, (W, X, Y) -> setPosition(X, Y))); - addCallback(T -> GLFW.glfwSetWindowFocusCallback(T, (K, V) -> flags.setFlag(FLAG_FOCUS, V))); - } - - Window createWindow(WindowStats stat) - { - owner = stat.provider; - title = stat.name; - width = stat.width; - height = stat.height; - aaLevel = stat.antiAlis; - videoMode = stat.videoMode; - flags.setFlag(FLAG_BORDERLESS, stat.borderless); - flags.setFlag(FLAG_FULL_SCREEN, stat.fullScreen); - flags.setFlag(FLAG_FLOATING, stat.floating); - flags.setFlag(FLAG_VSYNC, stat.vsync); - flags.setFlag(FLAG_CPU_FPS_CAP, stat.fpsCap); - GLFW.glfwWindowHint(GLFW.GLFW_SAMPLES, aaLevel); - GLFW.glfwWindowHint(GLFW.GLFW_DECORATED, flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.isFlagSet(FLAG_BORDERLESS) ? 0 : 1); - GLFW.glfwWindowHint(GLFW.GLFW_FLOATING, flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.isFlagSet(FLAG_FLOATING) ? 1 : 0); - if(videoMode == null || videoMode.getMonitor() == null) - { - throw new IllegalStateException("Monitor or Video Mode is missing: "+videoMode); - } - Monitor monitor = videoMode.getMonitor(); - windowId = GLFW.glfwCreateWindow(flags.isFlagSet(FLAG_FULL_SCREEN) ? videoMode.getWidth() : width, flags.isFlagSet(FLAG_FULL_SCREEN) ? videoMode.getHeight() : height, title, flags.isFlagSet(FLAG_FULL_SCREEN) ? monitor.getMonitorId() : 0L, stat.parent == null ? 0 : stat.parent.windowId); - if(windowId == 0) - { - throw new IllegalStateException("Window Couldn't be Created"); - } - initWindowListeners(); - GLFW.glfwMakeContextCurrent(windowId); - if(capabilities == null) - { - capabilities = GL.createCapabilities(); - } - if(flags.isFlagNotSet(FLAG_FULL_SCREEN)) - { - xPos = stat.center ? (monitor.getXOffset() + (videoMode.getWidth() / 2) - (width / 2)) : monitor.getXOffset() + xPos; - yPos = stat.center ? (monitor.getYOffset() + (videoMode.getHeight() / 2) - (width / 2)) : monitor.getYOffset() + yPos; - GLFW.glfwSetWindowPos(windowId, xPos, yPos); - } - else - { - xPos = monitor.getXOffset() + (videoMode.getWidth() / 2) - (width / 2); - yPos = monitor.getYOffset() + (videoMode.getHeight() / 2) - (width / 2); - tempWidth = width; - tempHeight = height; - } - GLFW.glfwSwapInterval(flags.isFlagSet(FLAG_VSYNC) ? 1 : 0); - fetchWindowBounds(); - updateViewPort(); - return this; - } - - protected void onResize(long window, int newWidth, int newHeight) - { - if(flags.isFlagNotSet(FLAG_FULL_SCREEN | FLAG_MAXIMIZED) && window == windowId && (width != newWidth || height != newHeight)) - { - width = newWidth; - height = newHeight; - flags.setFlag(FLAG_WINDOW_CHANGE); - } - } - - protected void updateCallbacks() - { - for(int i = 0,m=callbacks.size();i provider) - { - if(provider == null) - { - return null; - } - WindowCallback callback = new WindowCallback(provider); - callbacks.add(callback); - if(windowId != 0) - { - callback.reload(windowId); - } - return callback; - } - - public void removeCallback(WindowCallback call) - { - if(callbacks.remove(call)) - { - call.destroy(); - } - } - - private void createProjectionMatrix() - { -// float aspectRatio = (float)width / (float)height; -// float y_scale = (float)((1f / Math.tan(Math.toRadians(fieldOfView / 2f))) * aspectRatio); -// float x_scale = y_scale / aspectRatio; -// float frustum_length = far_plane - near_plane; -// projection.setIdentity(); -// projection.set(0, x_scale); -// projection.set(5, y_scale); -// projection.set(10, -((far_plane + near_plane) / frustum_length)); -// projection.set(11, -1); -// projection.set(14, -((2 * near_plane * far_plane) / frustum_length)); -// projection.set(15, 0); -// invertedProjection.load(projection).invert(); -// - projection.setIdentity().setPerspective((float)Math.toRadians(fieldOfView), (float)width / (float)height, near_plane, far_plane); - invertedProjection.load(projection).invert(); - } - - protected void fetchWindowBounds() - { - int[] width = new int[1]; - int[] height = new int[1]; - GLFW.glfwGetWindowSize(windowId, width, height); - this.width = width[0]; - this.height = height[0]; - } -} +package speiger.src.coreengine.rendering.input.window; + +import java.util.List; +import java.util.function.LongFunction; + +import org.lwjgl.glfw.GLFW; +import org.lwjgl.opengl.GL; +import org.lwjgl.opengl.GLCapabilities; +import org.lwjgl.system.Callback; + +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.coreengine.math.MathUtils; +import speiger.src.coreengine.math.vector.matrix.Matrix4f; +import speiger.src.coreengine.rendering.input.window.WindowProvider.WindowStats; +import speiger.src.coreengine.rendering.utils.GLUtils; +import speiger.src.coreengine.utils.collections.FlagHolder; + +public class Window +{ + static final int FLAG_VISIBLE = 1; + static final int FLAG_VSYNC = 2; + static final int FLAG_FOCUS = 4; + static final int FLAG_CPU_FPS_CAP = 8; + static final int FLAG_FULL_SCREEN = 16; + static final int FLAG_MAXIMIZED = 32; + static final int FLAG_BORDERLESS = 64; + static final int FLAG_CLOSE = 128; + static final int FLAG_WINDOW_CHANGE = 256; + static final int FLAG_FLOATING = 512; + + WindowProvider owner; + long windowId; + VideoMode videoMode; + FlagHolder flags = new FlagHolder(); + String title = ""; + int xPos; + int yPos; + int tempWidth; + int tempHeight; + int width; + int height; + int aaLevel; + int uiScale; + ScaledResolution ui_frame = new ScaledResolution(this); + + float fieldOfView = 70F; + final float near_plane = 0.1F; + final float far_plane = 2000F; + Matrix4f projection = new Matrix4f(); + Matrix4f invertedProjection = new Matrix4f(); + + List callbacks = new ObjectArrayList<>(); + List listeners = new ObjectArrayList<>(); + GLCapabilities capabilities; + + public Window() + { + GLFW.glfwDefaultWindowHints(); + GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, 0); // 0 = False, 1 = true + GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, 1); + GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 4); + GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 0); + GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_PROFILE, GLFW.GLFW_OPENGL_CORE_PROFILE);//GLFW.GLFW_OPENGL_COMPAT_PROFILE); + GLFW.glfwWindowHint(GLFW.GLFW_OPENGL_FORWARD_COMPAT, 1); + } + + protected void initWindowListeners() + { + addCallback(T -> GLFW.glfwSetFramebufferSizeCallback(T, this::onResize)); + addCallback(T -> GLFW.glfwSetWindowMaximizeCallback(T, (K, V) -> flags.setFlag(FLAG_WINDOW_CHANGE))); + addCallback(T -> GLFW.glfwSetWindowPosCallback(T, (W, X, Y) -> setPosition(X, Y))); + addCallback(T -> GLFW.glfwSetWindowFocusCallback(T, (K, V) -> flags.setFlag(FLAG_FOCUS, V))); + } + + Window createWindow(WindowStats stat) + { + owner = stat.provider; + title = stat.name; + width = stat.width; + height = stat.height; + aaLevel = stat.antiAlis; + videoMode = stat.videoMode; + flags.setFlag(FLAG_BORDERLESS, stat.borderless); + flags.setFlag(FLAG_FULL_SCREEN, stat.fullScreen); + flags.setFlag(FLAG_FLOATING, stat.floating); + flags.setFlag(FLAG_VSYNC, stat.vsync); + flags.setFlag(FLAG_CPU_FPS_CAP, stat.fpsCap); + GLFW.glfwWindowHint(GLFW.GLFW_SAMPLES, aaLevel); + GLFW.glfwWindowHint(GLFW.GLFW_DECORATED, flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.isFlagSet(FLAG_BORDERLESS) ? 0 : 1); + GLFW.glfwWindowHint(GLFW.GLFW_FLOATING, flags.isFlagNotSet(FLAG_FULL_SCREEN) && flags.isFlagSet(FLAG_FLOATING) ? 1 : 0); + if(videoMode == null || videoMode.getMonitor() == null) + { + throw new IllegalStateException("Monitor or Video Mode is missing: "+videoMode); + } + Monitor monitor = videoMode.getMonitor(); + windowId = GLFW.glfwCreateWindow(flags.isFlagSet(FLAG_FULL_SCREEN) ? videoMode.getWidth() : width, flags.isFlagSet(FLAG_FULL_SCREEN) ? videoMode.getHeight() : height, title, flags.isFlagSet(FLAG_FULL_SCREEN) ? monitor.getMonitorId() : 0L, stat.parent == null ? 0 : stat.parent.windowId); + if(windowId == 0) + { + throw new IllegalStateException("Window Couldn't be Created"); + } + initWindowListeners(); + GLFW.glfwMakeContextCurrent(windowId); + if(capabilities == null) + { + capabilities = GL.createCapabilities(); + } + if(flags.isFlagNotSet(FLAG_FULL_SCREEN)) + { + xPos = stat.center ? (monitor.getXOffset() + (videoMode.getWidth() / 2) - (width / 2)) : monitor.getXOffset() + xPos; + yPos = stat.center ? (monitor.getYOffset() + (videoMode.getHeight() / 2) - (width / 2)) : monitor.getYOffset() + yPos; + GLFW.glfwSetWindowPos(windowId, xPos, yPos); + } + else + { + xPos = monitor.getXOffset() + (videoMode.getWidth() / 2) - (width / 2); + yPos = monitor.getYOffset() + (videoMode.getHeight() / 2) - (width / 2); + tempWidth = width; + tempHeight = height; + } + GLFW.glfwSwapInterval(flags.isFlagSet(FLAG_VSYNC) ? 1 : 0); + fetchWindowBounds(); + updateViewPort(); + return this; + } + + protected void onResize(long window, int newWidth, int newHeight) + { + if(flags.isFlagNotSet(FLAG_FULL_SCREEN | FLAG_MAXIMIZED) && window == windowId && (width != newWidth || height != newHeight)) + { + width = newWidth; + height = newHeight; + flags.setFlag(FLAG_WINDOW_CHANGE); + } + } + + protected void updateCallbacks() + { + for(int i = 0,m=callbacks.size();i provider) + { + if(provider == null) + { + return null; + } + WindowCallback callback = new WindowCallback(provider); + callbacks.add(callback); + if(windowId != 0) + { + callback.reload(windowId); + } + return callback; + } + + public void removeCallback(WindowCallback call) + { + if(callbacks.remove(call)) + { + call.destroy(); + } + } + + private void createProjectionMatrix() + { +// float aspectRatio = (float)width / (float)height; +// float y_scale = (float)((1f / Math.tan(Math.toRadians(fieldOfView / 2f))) * aspectRatio); +// float x_scale = y_scale / aspectRatio; +// float frustum_length = far_plane - near_plane; +// projection.setIdentity(); +// projection.set(0, x_scale); +// projection.set(5, y_scale); +// projection.set(10, -((far_plane + near_plane) / frustum_length)); +// projection.set(11, -1); +// projection.set(14, -((2 * near_plane * far_plane) / frustum_length)); +// projection.set(15, 0); +// invertedProjection.load(projection).invert(); +// + projection.setIdentity().setPerspective((float)Math.toRadians(fieldOfView), (float)width / (float)height, near_plane, far_plane); + invertedProjection.load(projection).invert(); + } + + protected void fetchWindowBounds() + { + int[] width = new int[1]; + int[] height = new int[1]; + GLFW.glfwGetWindowSize(windowId, width, height); + this.width = width[0]; + this.height = height[0]; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/shader/ShaderEntry.java b/src/main/java/speiger/src/coreengine/rendering/shader/ShaderEntry.java index 443adc2..66b5bcf 100644 --- a/src/main/java/speiger/src/coreengine/rendering/shader/ShaderEntry.java +++ b/src/main/java/speiger/src/coreengine/rendering/shader/ShaderEntry.java @@ -1,23 +1,23 @@ -package speiger.src.coreengine.rendering.shader; - -import java.util.List; -import java.util.function.Consumer; - -public class ShaderEntry implements Consumer -{ - List shaders; - int index; - - public ShaderEntry(List shaders, int index) - { - this.shaders = shaders; - this.index = index; - } - - @Override - public void accept(T t) - { - shaders.set(index, t); - } - -} +package speiger.src.coreengine.rendering.shader; + +import java.util.List; +import java.util.function.Consumer; + +public class ShaderEntry implements Consumer +{ + List shaders; + int index; + + public ShaderEntry(List shaders, int index) + { + this.shaders = shaders; + this.index = index; + } + + @Override + public void accept(T t) + { + shaders.set(index, t); + } + +} diff --git a/src/main/java/speiger/src/coreengine/rendering/tesselation/Tesselator.java b/src/main/java/speiger/src/coreengine/rendering/tesselation/Tesselator.java index c41b311..dddfc36 100644 --- a/src/main/java/speiger/src/coreengine/rendering/tesselation/Tesselator.java +++ b/src/main/java/speiger/src/coreengine/rendering/tesselation/Tesselator.java @@ -1,276 +1,276 @@ -package speiger.src.coreengine.rendering.tesselation; - -import java.nio.FloatBuffer; - -import speiger.src.coreengine.math.vector.floats.Vec2f; -import speiger.src.coreengine.math.vector.floats.Vec3f; -import speiger.src.coreengine.rendering.models.DrawCall; -import speiger.src.coreengine.rendering.tesselation.VertexElement.ElementUsage; - -public class Tesselator implements IVertexBuilder -{ - boolean drawing = false; - int drawType = 0; - - VertexList currentList; - VertexElement currentElement; - int currentIndex = 0; - - Vec3f offset = Vec3f.mutable(); - Vec2f effects = Vec2f.mutable(1F); - - FloatBuffer buffer; - int vertexes = 0; - - public Tesselator(int capacity) - { - buffer = FloatBuffer.allocate(capacity); - } - - public Tesselator(FloatBuffer buffer) - { - this.buffer = buffer; - } - - public Tesselator begin(int glType, VertexList list) - { - if(drawing) - { - throw new RuntimeException("Already Drawing"); - } - drawType = glType; - drawing = true; - currentList = list; - currentElement = list.getElement(0); - currentIndex = 0; - buffer.clear(); - vertexes = 0; - return this; - } - - public Tesselator changeGLType(int glType) - { - if(!drawing) - { - throw new RuntimeException("Can not change type"); - } - drawType = glType; - return this; - } - - public Tesselator resetVertexes() - { - vertexes = 0; - return this; - } - - public Tesselator setBrightness(float value) - { - effects.setX(value); - return this; - } - - public Tesselator setVisibilty(float value) - { - effects.setY(value); - return this; - } - - public float getBrightness() - { - return effects.getX(); - } - - public float getVisibility() - { - return effects.getY(); - } - - public Tesselator resetEffects() - { - effects.set(Vec2f.ONE); - return this; - } - - public Tesselator offset(float x, float y, float z) - { - offset.add(x, y, z); - return this; - } - - public Tesselator setOffset(float x, float y, float z) - { - offset.set(x, y, z); - return this; - } - - @Override - public Tesselator pos(float x, float y) - { - validateElement(ElementUsage.POS, 2); - buffer.put(x + offset.getX()); - buffer.put(y + offset.getY()); - nextElement(); - return this; - } - - @Override - public Tesselator pos(float x, float y, float z) - { - validateElement(ElementUsage.POS, 3); - buffer.put(x + offset.getX()); - buffer.put(y + offset.getY()); - buffer.put(z + offset.getZ()); - nextElement(); - return this; - } - - @Override - public Tesselator color3f(float r, float g, float b) - { - validateElement(ElementUsage.COLOR, 3); - buffer.put(r * effects.getX()); - buffer.put(g * effects.getX()); - buffer.put(b * effects.getX()); - nextElement(); - return this; - } - - @Override - public Tesselator color4f(float r, float g, float b, float a) - { - validateElement(ElementUsage.COLOR, 4); - buffer.put(r * effects.getX()); - buffer.put(g * effects.getX()); - buffer.put(b * effects.getX()); - buffer.put(a * effects.getY()); - nextElement(); - return this; - } - - @Override - public Tesselator tex(float u, float v) - { - validateElement(ElementUsage.UV, 2); - buffer.put(u); - buffer.put(v); - nextElement(); - return this; - } - - @Override - public Tesselator normal(float x, float y, float z) - { - validateElement(ElementUsage.NORMAL, 3); - buffer.put(x); - buffer.put(y); - buffer.put(z); - nextElement(); - return this; - } - - @Override - public Tesselator custom(float x) - { - validateElement(ElementUsage.CUSTOM, 1); - buffer.put(x); - nextElement(); - return this; - } - - @Override - public Tesselator custom(float x, float y) - { - validateElement(ElementUsage.CUSTOM, 2); - buffer.put(x); - buffer.put(y); - nextElement(); - return this; - } - - @Override - public Tesselator custom(float x, float y, float z) - { - validateElement(ElementUsage.CUSTOM, 3); - buffer.put(x); - buffer.put(y); - buffer.put(z); - nextElement(); - return this; - } - - @Override - public Tesselator custom(float x, float y, float z, float w) - { - validateElement(ElementUsage.CUSTOM, 4); - buffer.put(x); - buffer.put(y); - buffer.put(z); - buffer.put(w); - nextElement(); - return this; - } - - @Override - public Tesselator endVertex() - { - vertexes++; - return this; - } - - public Tesselator finishData() - { - drawing = false; - buffer.flip(); - return this; - } - - public float[] getData() - { - float[] data = new float[currentList.getOffsets() * vertexes]; - buffer.get(data); - return data; - } - - public DrawCall getDrawCall(int texture) - { - float[] data = new float[currentList.getOffsets() * vertexes]; - buffer.get(data); - return new DrawCall(drawType, texture, data, vertexes); - } - - public boolean isDrawing() - { - return drawing; - } - - public boolean hasTexture() - { - return currentList.hasType(ElementUsage.UV); - } - - public int getGLDrawType() - { - return drawType; - } - - public void validateElement(ElementUsage usage, int componentSize) - { - if(currentElement.getUsage() == usage && currentElement.getSize() == componentSize && drawing) - { - return; - } - throw new RuntimeException("Invalid Argument, Drawing: "+drawing+", Element: "+usage+", Expected: "+currentElement.getUsage()+", Size: "+componentSize+", Expected Size: "+currentElement.getSize()); - } - - protected void nextElement() - { - currentIndex = (currentIndex + 1) % currentList.getElementCount(); - currentElement = currentList.getElement(currentIndex); - } - - public int getVertexCount() - { - return vertexes; - } -} +package speiger.src.coreengine.rendering.tesselation; + +import java.nio.FloatBuffer; + +import speiger.src.coreengine.math.vector.floats.Vec2f; +import speiger.src.coreengine.math.vector.floats.Vec3f; +import speiger.src.coreengine.rendering.models.DrawCall; +import speiger.src.coreengine.rendering.tesselation.VertexElement.ElementUsage; + +public class Tesselator implements IVertexBuilder +{ + boolean drawing = false; + int drawType = 0; + + VertexList currentList; + VertexElement currentElement; + int currentIndex = 0; + + Vec3f offset = Vec3f.mutable(); + Vec2f effects = Vec2f.mutable(1F); + + FloatBuffer buffer; + int vertexes = 0; + + public Tesselator(int capacity) + { + buffer = FloatBuffer.allocate(capacity); + } + + public Tesselator(FloatBuffer buffer) + { + this.buffer = buffer; + } + + public Tesselator begin(int glType, VertexList list) + { + if(drawing) + { + throw new RuntimeException("Already Drawing"); + } + drawType = glType; + drawing = true; + currentList = list; + currentElement = list.get(0); + currentIndex = 0; + buffer.clear(); + vertexes = 0; + return this; + } + + public Tesselator changeGLType(int glType) + { + if(!drawing) + { + throw new RuntimeException("Can not change type"); + } + drawType = glType; + return this; + } + + public Tesselator resetVertexes() + { + vertexes = 0; + return this; + } + + public Tesselator setBrightness(float value) + { + effects.setX(value); + return this; + } + + public Tesselator setVisibilty(float value) + { + effects.setY(value); + return this; + } + + public float getBrightness() + { + return effects.getX(); + } + + public float getVisibility() + { + return effects.getY(); + } + + public Tesselator resetEffects() + { + effects.set(Vec2f.ONE); + return this; + } + + public Tesselator offset(float x, float y, float z) + { + offset.add(x, y, z); + return this; + } + + public Tesselator setOffset(float x, float y, float z) + { + offset.set(x, y, z); + return this; + } + + @Override + public Tesselator pos(float x, float y) + { + validateElement(ElementUsage.POS, 2); + buffer.put(x + offset.getX()); + buffer.put(y + offset.getY()); + nextElement(); + return this; + } + + @Override + public Tesselator pos(float x, float y, float z) + { + validateElement(ElementUsage.POS, 3); + buffer.put(x + offset.getX()); + buffer.put(y + offset.getY()); + buffer.put(z + offset.getZ()); + nextElement(); + return this; + } + + @Override + public Tesselator color3f(float r, float g, float b) + { + validateElement(ElementUsage.COLOR, 3); + buffer.put(r * effects.getX()); + buffer.put(g * effects.getX()); + buffer.put(b * effects.getX()); + nextElement(); + return this; + } + + @Override + public Tesselator color4f(float r, float g, float b, float a) + { + validateElement(ElementUsage.COLOR, 4); + buffer.put(r * effects.getX()); + buffer.put(g * effects.getX()); + buffer.put(b * effects.getX()); + buffer.put(a * effects.getY()); + nextElement(); + return this; + } + + @Override + public Tesselator tex(float u, float v) + { + validateElement(ElementUsage.UV, 2); + buffer.put(u); + buffer.put(v); + nextElement(); + return this; + } + + @Override + public Tesselator normal(float x, float y, float z) + { + validateElement(ElementUsage.NORMAL, 3); + buffer.put(x); + buffer.put(y); + buffer.put(z); + nextElement(); + return this; + } + + @Override + public Tesselator custom(float x) + { + validateElement(ElementUsage.CUSTOM, 1); + buffer.put(x); + nextElement(); + return this; + } + + @Override + public Tesselator custom(float x, float y) + { + validateElement(ElementUsage.CUSTOM, 2); + buffer.put(x); + buffer.put(y); + nextElement(); + return this; + } + + @Override + public Tesselator custom(float x, float y, float z) + { + validateElement(ElementUsage.CUSTOM, 3); + buffer.put(x); + buffer.put(y); + buffer.put(z); + nextElement(); + return this; + } + + @Override + public Tesselator custom(float x, float y, float z, float w) + { + validateElement(ElementUsage.CUSTOM, 4); + buffer.put(x); + buffer.put(y); + buffer.put(z); + buffer.put(w); + nextElement(); + return this; + } + + @Override + public Tesselator endVertex() + { + vertexes++; + return this; + } + + public Tesselator finishData() + { + drawing = false; + buffer.flip(); + return this; + } + + public float[] getData() + { + float[] data = new float[currentList.getOffsets() * vertexes]; + buffer.get(data); + return data; + } + + public DrawCall getDrawCall(int texture) + { + float[] data = new float[currentList.getOffsets() * vertexes]; + buffer.get(data); + return new DrawCall(drawType, texture, data, vertexes); + } + + public boolean isDrawing() + { + return drawing; + } + + public boolean hasTexture() + { + return currentList.hasType(ElementUsage.UV); + } + + public int getGLDrawType() + { + return drawType; + } + + public void validateElement(ElementUsage usage, int componentSize) + { + if(currentElement.getUsage() == usage && currentElement.getSize() == componentSize && drawing) + { + return; + } + throw new RuntimeException("Invalid Argument, Drawing: "+drawing+", Element: "+usage+", Expected: "+currentElement.getUsage()+", Size: "+componentSize+", Expected Size: "+currentElement.getSize()); + } + + protected void nextElement() + { + currentIndex = (currentIndex + 1) % currentList.size(); + currentElement = currentList.get(currentIndex); + } + + public int getVertexCount() + { + return vertexes; + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/tesselation/VertexList.java b/src/main/java/speiger/src/coreengine/rendering/tesselation/VertexList.java index 2cf9a39..e5d87f9 100644 --- a/src/main/java/speiger/src/coreengine/rendering/tesselation/VertexList.java +++ b/src/main/java/speiger/src/coreengine/rendering/tesselation/VertexList.java @@ -1,71 +1,69 @@ -package speiger.src.coreengine.rendering.tesselation; - -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import speiger.src.collections.ints.lists.IntArrayList; -import speiger.src.collections.ints.lists.IntList; -import speiger.src.coreengine.rendering.tesselation.VertexElement.ElementUsage; -import speiger.src.coreengine.utils.collections.iterators.ReadOnlyIterator; - -public class VertexList implements Iterable -{ - List elements = new ArrayList(); - Set types = EnumSet.noneOf(ElementUsage.class); - IntList offsets = new IntArrayList(); - int totalOffset; - - public VertexList() - { - } - - public VertexList(VertexList vertexList) - { - elements.addAll(vertexList.elements); - offsets.addAll(vertexList.offsets); - totalOffset = vertexList.totalOffset; - } - - public void addElement(VertexElement element) - { - elements.add(element); - offsets.add(totalOffset); - totalOffset += element.getSize(); - types.add(element.getUsage()); - } - - public int getOffsets() - { - return totalOffset; - } - - public int getElementCount() - { - return elements.size(); - } - - public VertexElement getElement(int index) - { - return elements.get(index); - } - - public int getOffset(int index) - { - return offsets.getInt(index); - } - - @Override - public Iterator iterator() - { - return new ReadOnlyIterator(elements.iterator()); - } - - public boolean hasType(ElementUsage type) - { - return types.contains(type); - } - -} +package speiger.src.coreengine.rendering.tesselation; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import speiger.src.collections.ints.lists.IntArrayList; +import speiger.src.collections.ints.lists.IntList; +import speiger.src.coreengine.rendering.tesselation.VertexElement.ElementUsage; +import speiger.src.coreengine.utils.collections.iterators.ReadOnlyIterator; + +public class VertexList implements Iterable +{ + List elements = new ArrayList(); + Set types = EnumSet.noneOf(ElementUsage.class); + IntList offsets = new IntArrayList(); + int totalOffset; + + public VertexList() {} + + public VertexList(VertexList vertexList) + { + elements.addAll(vertexList.elements); + offsets.addAll(vertexList.offsets); + totalOffset = vertexList.totalOffset; + } + + public VertexList add(VertexElement element) + { + elements.add(element); + offsets.add(totalOffset); + totalOffset += element.getSize(); + types.add(element.getUsage()); + return this; + } + + public int getOffsets() + { + return totalOffset; + } + + public int size() + { + return elements.size(); + } + + public VertexElement get(int index) + { + return elements.get(index); + } + + public int getOffset(int index) + { + return offsets.getInt(index); + } + + @Override + public Iterator iterator() + { + return new ReadOnlyIterator<>(elements.iterator()); + } + + public boolean hasType(ElementUsage type) + { + return types.contains(type); + } +} \ No newline at end of file diff --git a/src/main/java/speiger/src/coreengine/rendering/tesselation/VertexType.java b/src/main/java/speiger/src/coreengine/rendering/tesselation/VertexType.java index e2c2cb8..a47434b 100644 --- a/src/main/java/speiger/src/coreengine/rendering/tesselation/VertexType.java +++ b/src/main/java/speiger/src/coreengine/rendering/tesselation/VertexType.java @@ -1,47 +1,23 @@ -package speiger.src.coreengine.rendering.tesselation; - -import speiger.src.coreengine.rendering.tesselation.VertexElement.ElementUsage; - -public class VertexType -{ - public static final VertexElement POSITION_2F = new VertexElement(2, ElementUsage.POS); - public static final VertexElement POSITION_3F = new VertexElement(3, ElementUsage.POS); - public static final VertexElement TEXTURE_2F = new VertexElement(2, ElementUsage.UV); - public static final VertexElement COLOR_3F = new VertexElement(3, ElementUsage.COLOR); - public static final VertexElement COLOR_4F = new VertexElement(4, ElementUsage.COLOR); - public static final VertexElement NORMAL_3F = new VertexElement(3, ElementUsage.NORMAL); - public static final VertexElement CUSTOM_4F = new VertexElement(4, ElementUsage.CUSTOM); - - public static final VertexList POS_COLOR_3F = new VertexList(); - public static final VertexList POS_COLOR_4F = new VertexList(); - public static final VertexList POS_COLOR_2F = new VertexList(); - public static final VertexList POS_TEX = new VertexList(); - public static final VertexList TERRAIN = new VertexList(); - - public static final VertexList UI = new VertexList(); - public static final VertexList IN_WORLD_UI = new VertexList(); - - static - { - UI.addElement(POSITION_3F); - UI.addElement(TEXTURE_2F); - UI.addElement(COLOR_4F); - - IN_WORLD_UI.addElement(POSITION_3F); - IN_WORLD_UI.addElement(TEXTURE_2F); - IN_WORLD_UI.addElement(COLOR_4F); - IN_WORLD_UI.addElement(CUSTOM_4F); - - TERRAIN.addElement(POSITION_3F); - TERRAIN.addElement(COLOR_3F); - TERRAIN.addElement(NORMAL_3F); - POS_COLOR_2F.addElement(POSITION_2F); - POS_COLOR_2F.addElement(COLOR_4F); - POS_COLOR_3F.addElement(POSITION_3F); - POS_COLOR_3F.addElement(COLOR_3F); - POS_COLOR_4F.addElement(POSITION_3F); - POS_COLOR_4F.addElement(COLOR_4F); - POS_TEX.addElement(POSITION_3F); - POS_TEX.addElement(TEXTURE_2F); - } -} +package speiger.src.coreengine.rendering.tesselation; + +import speiger.src.coreengine.rendering.tesselation.VertexElement.ElementUsage; + +public class VertexType +{ + public static final VertexElement POSITION_2F = new VertexElement(2, ElementUsage.POS); + public static final VertexElement POSITION_3F = new VertexElement(3, ElementUsage.POS); + public static final VertexElement TEXTURE_2F = new VertexElement(2, ElementUsage.UV); + public static final VertexElement COLOR_3F = new VertexElement(3, ElementUsage.COLOR); + public static final VertexElement COLOR_4F = new VertexElement(4, ElementUsage.COLOR); + public static final VertexElement NORMAL_3F = new VertexElement(3, ElementUsage.NORMAL); + public static final VertexElement CUSTOM_4F = new VertexElement(4, ElementUsage.CUSTOM); + + public static final VertexList POS_COLOR_2F = new VertexList().add(POSITION_2F).add(COLOR_4F); + public static final VertexList POS_COLOR_3F = new VertexList().add(POSITION_3F).add(COLOR_3F); + public static final VertexList POS_COLOR_4F = new VertexList().add(POSITION_3F).add(COLOR_4F); + public static final VertexList POS_TEX = new VertexList().add(POSITION_3F).add(TEXTURE_2F); + public static final VertexList TERRAIN = new VertexList().add(POSITION_3F).add(COLOR_3F).add(NORMAL_3F); + + public static final VertexList UI = new VertexList().add(POSITION_3F).add(TEXTURE_2F).add(COLOR_4F); + public static final VertexList IN_WORLD_UI = new VertexList().add(POSITION_3F).add(TEXTURE_2F).add(COLOR_4F).add(CUSTOM_4F); +} diff --git a/src/main/java/speiger/src/coreengine/rendering/utils/GLUtils.java b/src/main/java/speiger/src/coreengine/rendering/utils/GLUtils.java index 2f1a280..b238bbf 100644 --- a/src/main/java/speiger/src/coreengine/rendering/utils/GLUtils.java +++ b/src/main/java/speiger/src/coreengine/rendering/utils/GLUtils.java @@ -1,131 +1,139 @@ -package speiger.src.coreengine.rendering.utils; - -import java.nio.IntBuffer; -import java.util.List; - -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL13; -import org.lwjgl.opengl.GL31; -import org.lwjgl.opengl.GL44; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.coreengine.rendering.utils.states.BlendState; -import speiger.src.coreengine.rendering.utils.states.CullState; -import speiger.src.coreengine.rendering.utils.states.GLProvoking; -import speiger.src.coreengine.rendering.utils.states.GLState; -import speiger.src.coreengine.rendering.utils.states.GLWireFrame; -import speiger.src.coreengine.rendering.utils.states.IGLState; -import speiger.src.coreengine.rendering.utils.states.LineSize; -import speiger.src.coreengine.rendering.utils.states.PointSize; -import speiger.src.coreengine.utils.counters.averager.Counter; - -public class GLUtils -{ - static final List ALL_STATES = new ObjectArrayList<>(); - public static final GLState MULTI_SAMPLING = addState(new GLState(GL13.GL_MULTISAMPLE, false)); - public static final GLState WIRE_FRAME = addState(new GLWireFrame()); - public static final GLState PROVOKING_VERTEX = addState(new GLProvoking()); - public static final GLState DEBTH_TEST = addState(new GLState(GL11.GL_DEPTH_TEST, false)); - public static final CullState CULL_FACE = addState(new CullState(GL11.GL_BACK)); - public static final BlendState BLEND = addState(new BlendState()); - public static final GLState CLIP_PLANE0 = addState(new GLState(GL11.GL_CLIP_PLANE0, false)); - public static final PointSize POINT_SIZE = addState(new PointSize()); - public static final LineSize LINE_SIZE = addState(new LineSize()); - public static final ScissorsManager TESTER = new ScissorsManager(100); - public static final Counter[] COUNTERS = Counter.createCounters(4); - public static final ViewPortStack VIEW_PORT = new ViewPortStack(); - - public static T addState(T state) - { - ALL_STATES.add(state); - return state; - } - - public static void onFrameEnded() - { - for(int i = 0,m=COUNTERS.length;i ALL_STATES = new ObjectArrayList<>(); + public static final GLState MULTI_SAMPLING = addState(new GLState(GL13.GL_MULTISAMPLE, false)); + public static final GLState WIRE_FRAME = addState(new GLWireFrame()); + public static final GLState PROVOKING_VERTEX = addState(new GLProvoking()); + public static final GLState DEBTH_TEST = addState(new GLState(GL11.GL_DEPTH_TEST, false)); + public static final CullState CULL_FACE = addState(new CullState(GL11.GL_BACK)); + public static final BlendState BLEND = addState(new BlendState()); + public static final GLState CLIP_PLANE0 = addState(new GLState(GL11.GL_CLIP_PLANE0, false)); + public static final PointSize POINT_SIZE = addState(new PointSize()); + public static final LineSize LINE_SIZE = addState(new LineSize()); + public static final ScissorsManager TESTER = new ScissorsManager(100); + public static final Counter[] COUNTERS = Counter.createCounters(4); + public static final ViewPortStack VIEW_PORT = new ViewPortStack(); + + public static T addState(T state) + { + ALL_STATES.add(state); + return state; + } + + public static void reapplyState() + { + for(int i = 0;i imageProvider = this::getData; - - public ScreenshotHandler(File helper) - { - FACTORY.setKeepAliveTime(1, TimeUnit.SECONDS); - FACTORY.allowCoreThreadTimeOut(true); - folder = new File(helper, "Screenshots"); - } - - @Override - public void onWindowChanged(Window window) - { - width = window.getWidth(); - height = window.getHeight(); - if(buffer != null) - { - MemoryUtil.memFree(buffer); - buffer = null; - } - buffer = MemoryUtil.memAlloc(width * height * 4); - } - - public void screenShot() - { - ZonedDateTime time = ZonedDateTime.now(); - File subFolder = new File(folder, time.format(FOLDER_FORMAT)); - FileUtils.ensureFolder(subFolder); - try - { - ImageIO.write(getScreenShot(), "png", new File(subFolder, "Screenshot_"+time.format(FILE_FORMAT)+".png")); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - - public boolean isRecording() - { - return recorder != null && !recorder.isFinished(); - } - - public void toggleRecording() - { - if(isRecording()) - { - stopRecording(); - } - else - { - startRecording(); - } - } - - //Undefined time recording - public void startRecording() - { - record("Capture_"+ZonedDateTime.now().format(FILE_FORMAT)+".gif", 15, Integer.MAX_VALUE); - } - - public void record(String fileName, int fps, int time) - { - if(recorder == null) - { - File subFolder = new File(folder, ZonedDateTime.now().format(FOLDER_FORMAT)); - FileUtils.ensureFolder(subFolder); - recorder = new GifRecorder(new File(subFolder, fileName), fps, time); - } - } - - public void stopRecording() - { - if(recorder != null) - { - recorder.finishPic(); - recorder = null; - } - } - - public void update() - { - if(recorder != null) - { - recorder.tick(imageProvider); - if(recorder.isFinished()) - { - recorder.finishPic(); - recorder = null; - } - } - } - - private BufferedImage getData() - { - buffer.clear(); - GL11.glReadBuffer(GL11.GL_FRONT); - GL11.glReadPixels(0, 0, width, height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); - BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - int[] data = ((DataBufferInt)image.getRaster().getDataBuffer()).getData(); - for(int x = 0;x < width;x++) - { - for(int y = 0;y < height;y++) - { - int i = (x + (width * y)) * 4; - int r = buffer.get(i) & 0xFF; - int g = buffer.get(i + 1) & 0xFF; - int b = buffer.get(i + 2) & 0xFF; - data[x + (width * (height - (y + 1)))] = (0xFF << 24) | (r << 16) | (g << 8) | b; - } - } - return image; - } - - public BufferedImage getScreenShot() - { - buffer.clear(); - GL11.glReadBuffer(GL11.GL_FRONT); - GL11.glReadPixels(0, 0, width, height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); - BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - int[] data = ((DataBufferInt)image.getRaster().getDataBuffer()).getData(); - for(int x = 0;x < width;x++) - { - for(int y = 0;y < height;y++) - { - int i = (x + (width * y)) * 4; - int r = buffer.get(i) & 0xFF; - int g = buffer.get(i + 1) & 0xFF; - int b = buffer.get(i + 2) & 0xFF; - data[x + (width * (height - (y + 1)))] = (0xFF << 24) | (r << 16) | (g << 8) | b; - } - } - return image; - } - - public void cleanup() - { - if(buffer != null) - { - MemoryUtil.memFree(buffer); - buffer = null; - } - } - - public static class GifRecorder - { - GifWriter writer; - long timeBetweenFrames; - long lastTime = -1L; - long freeTime; - int totalPics; - - public GifRecorder(File file, int fps, int time) - { - int ms = 1000 / fps; - writer = GifWriter.create(file, BufferedImage.TYPE_INT_ARGB, ms); - timeBetweenFrames = ms * 1000000L; - freeTime = ms * 1000000L; - totalPics = fps * time; - } - - public void tick(Supplier supply) - { - if(lastTime == -1L) - { - totalPics--; - insert(supply.get()); - lastTime = System.nanoTime(); - return; - } - long time = System.nanoTime(); - long happend = time - lastTime; - lastTime = time; - freeTime -= happend; - if(freeTime <= 0) - { - freeTime += timeBetweenFrames; - insert(supply.get()); - totalPics--; - } - } - - private void insert(final BufferedImage newBuffer) - { - FACTORY.execute(new Runnable(){ - BufferedImage buffer = newBuffer; - @Override - public void run() - { - if(writer != null) - { - writer.insertPicture(buffer); - } - } - }); - } - - public boolean isFinished() - { - return totalPics <= 0; - } - - public void finishPic() - { - FACTORY.execute(new Runnable(){ - @Override - public void run() - { - writer.close(); - writer = null; - } - }); - } - } -} +package speiger.src.coreengine.rendering.utils; + +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.io.File; +import java.nio.ByteBuffer; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +import javax.imageio.ImageIO; + +import org.lwjgl.opengl.GL11; +import org.lwjgl.system.MemoryUtil; + +import speiger.src.coreengine.rendering.input.window.IWindowListener; +import speiger.src.coreengine.rendering.input.window.Window; +import speiger.src.coreengine.utils.helpers.FileUtils; +import speiger.src.coreengine.utils.io.GifWriter; + +public class ScreenshotHandler implements IWindowListener +{ + public static final DateTimeFormatter FILE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss"); + public static final DateTimeFormatter FOLDER_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM"); + static final ThreadPoolExecutor FACTORY = (ThreadPoolExecutor)Executors.newFixedThreadPool(1); + + File folder; + int width; + int height; + ByteBuffer buffer; + GifRecorder recorder; + Supplier imageProvider = this::getData; + + public ScreenshotHandler(File helper) + { + FACTORY.setKeepAliveTime(1, TimeUnit.SECONDS); + FACTORY.allowCoreThreadTimeOut(true); + folder = new File(helper, "Screenshots"); + } + + @Override + public void onWindowChanged(Window window) + { + width = window.getWidth(); + height = window.getHeight(); + if(buffer != null) + { + MemoryUtil.memFree(buffer); + buffer = null; + } + buffer = MemoryUtil.memAlloc(width * height * 4); + } + + public void screenShot() + { + ZonedDateTime time = ZonedDateTime.now(); + File subFolder = new File(folder, time.format(FOLDER_FORMAT)); + FileUtils.ensureFolder(subFolder); + try + { + ImageIO.write(getScreenShot(), "png", new File(subFolder, "Screenshot_"+time.format(FILE_FORMAT)+".png")); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + + public boolean isRecording() + { + return recorder != null && !recorder.isFinished(); + } + + public void toggleRecording() + { + if(isRecording()) + { + stopRecording(); + } + else + { + startRecording(); + } + } + + //Undefined time recording + public void startRecording() + { + record("Capture_"+ZonedDateTime.now().format(FILE_FORMAT)+".gif", 15, Integer.MAX_VALUE); + } + + public void record(String fileName, int fps, int time) + { + if(recorder == null) + { + File subFolder = new File(folder, ZonedDateTime.now().format(FOLDER_FORMAT)); + FileUtils.ensureFolder(subFolder); + recorder = new GifRecorder(new File(subFolder, fileName), fps, time); + } + } + + public void stopRecording() + { + if(recorder != null) + { + recorder.finishPic(); + recorder = null; + } + } + + public void update() + { + if(recorder != null) + { + recorder.tick(imageProvider); + if(recorder.isFinished()) + { + recorder.finishPic(); + recorder = null; + } + } + } + + private BufferedImage getData() + { + buffer.clear(); + GL11.glReadBuffer(GL11.GL_FRONT); + GL11.glReadPixels(0, 0, width, height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + int[] data = ((DataBufferInt)image.getRaster().getDataBuffer()).getData(); + for(int x = 0;x < width;x++) + { + for(int y = 0;y < height;y++) + { + int i = (x + (width * y)) * 4; + int r = buffer.get(i) & 0xFF; + int g = buffer.get(i + 1) & 0xFF; + int b = buffer.get(i + 2) & 0xFF; + data[x + (width * (height - (y + 1)))] = (0xFF << 24) | (r << 16) | (g << 8) | b; + } + } + return image; + } + + public BufferedImage getScreenShot() + { + buffer.clear(); + GL11.glReadBuffer(GL11.GL_FRONT); + GL11.glReadPixels(0, 0, width, height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + int[] data = ((DataBufferInt)image.getRaster().getDataBuffer()).getData(); + for(int x = 0;x < width;x++) + { + for(int y = 0;y < height;y++) + { + int i = (x + (width * y)) * 4; + int r = buffer.get(i) & 0xFF; + int g = buffer.get(i + 1) & 0xFF; + int b = buffer.get(i + 2) & 0xFF; + data[x + (width * (height - (y + 1)))] = (0xFF << 24) | (r << 16) | (g << 8) | b; + } + } + return image; + } + + public void cleanup() + { + if(buffer != null) + { + MemoryUtil.memFree(buffer); + buffer = null; + } + } + + public static class GifRecorder + { + GifWriter writer; + long timeBetweenFrames; + long lastTime = -1L; + long freeTime; + int totalPics; + + public GifRecorder(File file, int fps, int time) + { + int ms = 1000 / fps; + writer = GifWriter.create(file, BufferedImage.TYPE_INT_ARGB, ms); + timeBetweenFrames = ms * 1000000L; + freeTime = ms * 1000000L; + totalPics = fps * time; + } + + public void tick(Supplier supply) + { + if(lastTime == -1L) + { + totalPics--; + insert(supply.get()); + lastTime = System.nanoTime(); + return; + } + long time = System.nanoTime(); + long happend = time - lastTime; + lastTime = time; + freeTime -= happend; + if(freeTime <= 0) + { + freeTime += timeBetweenFrames; + insert(supply.get()); + totalPics--; + } + } + + private void insert(final BufferedImage newBuffer) + { + FACTORY.execute(new Runnable(){ + BufferedImage buffer = newBuffer; + @Override + public void run() + { + if(writer != null) + { + writer.insertPicture(buffer); + } + } + }); + } + + public boolean isFinished() + { + return totalPics <= 0; + } + + public void finishPic() + { + FACTORY.execute(new Runnable(){ + @Override + public void run() + { + writer.close(); + writer = null; + } + }); + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/utils/states/BlendState.java b/src/main/java/speiger/src/coreengine/rendering/utils/states/BlendState.java index 98e82b5..787ba75 100644 --- a/src/main/java/speiger/src/coreengine/rendering/utils/states/BlendState.java +++ b/src/main/java/speiger/src/coreengine/rendering/utils/states/BlendState.java @@ -1,37 +1,44 @@ -package speiger.src.coreengine.rendering.utils.states; - -import org.lwjgl.opengl.GL11; - -public class BlendState extends GLState -{ - int src; - int func; - - public BlendState() - { - super(GL11.GL_BLEND, false); - } - - @Override - public BlendState push(boolean newValue) - { - super.push(newValue); - return this; - } - - public BlendState setFunction(int src, int func) - { - if(this.src != src && this.func != func) - { - this.src = src; - this.func = func; - GL11.glBlendFunc(src, func); - } - return this; - } - - public void setDefault() - { - setFunction(GL11.GL_ONE, GL11.GL_ONE); - } -} +package speiger.src.coreengine.rendering.utils.states; + +import org.lwjgl.opengl.GL11; + +public class BlendState extends GLState +{ + int src; + int func; + + public BlendState() + { + super(GL11.GL_BLEND, false); + } + + @Override + public BlendState push(boolean newValue) + { + super.push(newValue); + return this; + } + + public BlendState setFunction(int src, int func) + { + if(this.src != src && this.func != func) + { + this.src = src; + this.func = func; + GL11.glBlendFunc(src, func); + } + return this; + } + + @Override + public void reapply() + { + super.reapply(); + GL11.glBlendFunc(src, func); + } + + public void setDefault() + { + setFunction(GL11.GL_ONE, GL11.GL_ONE); + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/utils/states/CullState.java b/src/main/java/speiger/src/coreengine/rendering/utils/states/CullState.java index 4736126..f295db5 100644 --- a/src/main/java/speiger/src/coreengine/rendering/utils/states/CullState.java +++ b/src/main/java/speiger/src/coreengine/rendering/utils/states/CullState.java @@ -1,33 +1,40 @@ -package speiger.src.coreengine.rendering.utils.states; - -import org.lwjgl.opengl.GL11; - -public class CullState extends GLState -{ - int type; - - public CullState(int defaultState) - { - super(GL11.GL_CULL_FACE, false); - type = defaultState; - } - - @Override - public CullState push(boolean newValue) - { - super.push(newValue); - return this; - } - - public void setCullType(int type) - { - if(this.type != type) - { - this.type = type; - if(lastState) - { - GL11.glCullFace(type); - } - } - } -} +package speiger.src.coreengine.rendering.utils.states; + +import org.lwjgl.opengl.GL11; + +public class CullState extends GLState +{ + int type; + + public CullState(int defaultState) + { + super(GL11.GL_CULL_FACE, false); + type = defaultState; + } + + @Override + public CullState push(boolean newValue) + { + super.push(newValue); + return this; + } + + public void setCullType(int type) + { + if(this.type != type) + { + this.type = type; + if(lastState) + { + GL11.glCullFace(type); + } + } + } + + @Override + public void reapply() + { + super.reapply(); + GL11.glCullFace(type); + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/utils/states/FloatState.java b/src/main/java/speiger/src/coreengine/rendering/utils/states/FloatState.java index 8c20b71..e5ff7e2 100644 --- a/src/main/java/speiger/src/coreengine/rendering/utils/states/FloatState.java +++ b/src/main/java/speiger/src/coreengine/rendering/utils/states/FloatState.java @@ -1,58 +1,59 @@ -package speiger.src.coreengine.rendering.utils.states; - -import speiger.src.collections.floats.lists.FloatArrayList; -import speiger.src.collections.floats.lists.FloatList; - -public abstract class FloatState implements IGLState -{ - protected final float defaultValue; - protected FloatList states = new FloatArrayList(); - - public FloatState(float defaultValue) - { - this.defaultValue = defaultValue; - } - - public void push(float newValue) - { - if((states.isEmpty() && equalsNot(newValue, defaultValue)) || (states.size() > 0 && equalsNot(states.getFloat(states.size()-1), newValue))) - { - setValue(newValue); - } - states.add(newValue); - } - - public void pop() - { - if(states.isEmpty()) throw new IllegalStateException("State is already reset"); - if(states.size() == 1 && equalsNot(defaultValue, states.getFloat(0))) - { - setValue(defaultValue); - } - else if(states.size() > 1 && equalsNot(states.getFloat(states.size()-2), states.getFloat(states.size()-1))) - { - setValue(states.getFloat(states.size()-2)); - } - states.removeFloat(states.size()-1); - } - - protected abstract void setValue(float value); - - protected abstract String getName(); - - protected boolean equalsNot(float key, float value) - { - return Float.floatToIntBits(key) != Float.floatToIntBits(value); - } - - @Override - public void cleanup() - { - if(states.size() > 1) - { - float value = states.getFloat(states.size()-1); - states.clear(); - states.add(value); - } - } -} +package speiger.src.coreengine.rendering.utils.states; + +import speiger.src.collections.floats.collections.FloatStack; +import speiger.src.collections.floats.lists.FloatArrayList; + +public abstract class FloatState implements IGLState +{ + protected final float defaultValue; + protected FloatStack states = new FloatArrayList(); + + public FloatState(float defaultValue) + { + this.defaultValue = defaultValue; + } + + public void push(float newValue) + { + if((states.isEmpty() && equalsNot(newValue, defaultValue)) || (states.size() > 0 && equalsNot(states.top(), newValue))) + { + setValue(newValue); + } + states.push(newValue); + } + + public void pop() + { + if(states.isEmpty()) throw new IllegalStateException("State is already reset"); + float prev = states.pop(); + if(states.isEmpty() && equalsNot(defaultValue, prev)) setValue(defaultValue); + else if(!states.isEmpty() && equalsNot(states.top(), prev)) setValue(states.top()); + } + + protected abstract void setValue(float value); + + protected abstract String getName(); + + protected boolean equalsNot(float key, float value) + { + return Float.floatToIntBits(key) != Float.floatToIntBits(value); + } + + @Override + public void reapply() + { + if(states.isEmpty()) setValue(defaultValue); + else setValue(states.top()); + } + + @Override + public void cleanup() + { + if(states.size() > 1) + { + float value = states.top(); + states.clear(); + states.push(value); + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/utils/states/GLState.java b/src/main/java/speiger/src/coreengine/rendering/utils/states/GLState.java index 28f4f7c..02d4d14 100644 --- a/src/main/java/speiger/src/coreengine/rendering/utils/states/GLState.java +++ b/src/main/java/speiger/src/coreengine/rendering/utils/states/GLState.java @@ -1,65 +1,72 @@ -package speiger.src.coreengine.rendering.utils.states; - -import java.util.BitSet; - -import org.lwjgl.opengl.GL11; - -public class GLState implements IGLState -{ - final int id; - protected final boolean defaultValue; - protected final BitSet memory = new BitSet(); - protected int index = -1; - protected boolean lastState; - - public GLState(int id, boolean defaultValue) - { - this.id = id; - this.defaultValue = defaultValue; - } - - public GLState push(boolean newValue) - { - if((index < 0 && newValue != defaultValue) || (index >= 0 && memory.get(index) != newValue)) - { - setValue(newValue); - } - memory.set(++index, newValue); - return this; - } - - public void pop() - { - if(index < 0) throw new IllegalStateException("State is already reset"); - if(index == 0 && defaultValue != memory.get(0)) - { - setValue(defaultValue); - } - else if(index > 0 && memory.get(index-1) != memory.get(index)) - { - setValue(memory.get(index-1)); - } - index--; - } - - public boolean isEnabled() - { - return index < 0 ? defaultValue : memory.get(index); - } - - protected void setValue(boolean value) - { - if(value) GL11.glEnable(id); - else GL11.glDisable(id); - } - - @Override - public void cleanup() - { - if(index > 0) - { - memory.set(0, memory.get(index)); - index = 0; - } - } -} +package speiger.src.coreengine.rendering.utils.states; + +import java.util.BitSet; + +import org.lwjgl.opengl.GL11; + +public class GLState implements IGLState +{ + final int id; + protected final boolean defaultValue; + protected final BitSet memory = new BitSet(); + protected int index = -1; + protected boolean lastState; + + public GLState(int id, boolean defaultValue) + { + this.id = id; + this.defaultValue = defaultValue; + } + + public GLState push(boolean newValue) + { + if((index < 0 && newValue != defaultValue) || (index >= 0 && memory.get(index) != newValue)) + { + setValue(newValue); + } + memory.set(++index, newValue); + return this; + } + + public void pop() + { + if(index < 0) throw new IllegalStateException("State is already reset"); + if(index == 0 && defaultValue != memory.get(0)) + { + setValue(defaultValue); + } + else if(index > 0 && memory.get(index-1) != memory.get(index)) + { + setValue(memory.get(index-1)); + } + index--; + } + + public boolean isEnabled() + { + return index < 0 ? defaultValue : memory.get(index); + } + + protected void setValue(boolean value) + { + if(value) GL11.glEnable(id); + else GL11.glDisable(id); + } + + @Override + public void reapply() + { + if(index < 0) setValue(defaultValue); + else setValue(memory.get(index)); + } + + @Override + public void cleanup() + { + if(index > 0) + { + memory.set(0, memory.get(index)); + index = 0; + } + } +} diff --git a/src/main/java/speiger/src/coreengine/rendering/utils/states/IGLState.java b/src/main/java/speiger/src/coreengine/rendering/utils/states/IGLState.java index be57ac4..f461aea 100644 --- a/src/main/java/speiger/src/coreengine/rendering/utils/states/IGLState.java +++ b/src/main/java/speiger/src/coreengine/rendering/utils/states/IGLState.java @@ -1,6 +1,7 @@ -package speiger.src.coreengine.rendering.utils.states; - -public interface IGLState -{ - public void cleanup(); -} +package speiger.src.coreengine.rendering.utils.states; + +public interface IGLState +{ + public void cleanup(); + public void reapply(); +} diff --git a/src/main/java/speiger/src/coreengine/utils/collections/pools/ThreadPool.java b/src/main/java/speiger/src/coreengine/utils/collections/pools/ThreadPool.java index aa30f0e..7696468 100644 --- a/src/main/java/speiger/src/coreengine/utils/collections/pools/ThreadPool.java +++ b/src/main/java/speiger/src/coreengine/utils/collections/pools/ThreadPool.java @@ -1,76 +1,80 @@ -package speiger.src.coreengine.utils.collections.pools; - -import java.util.Collection; -import java.util.Iterator; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import speiger.src.collections.objects.lists.ObjectArrayList; -import speiger.src.collections.objects.lists.ObjectList; -import speiger.src.coreengine.utils.functions.Functions; - -public class ThreadPool implements IPool -{ - int cap; - ObjectList stack; - Supplier creator; - Consumer acceptor; - - public ThreadPool(int size, Supplier creator) - { - this(size, creator, Functions.getVoidConsumer()); - } - - public ThreadPool(int size, Supplier creator, Consumer acceptor) - { - cap = size; - stack = new ObjectArrayList(size); - this.creator = creator; - this.acceptor = acceptor; - } - - @Override - public synchronized void accept(T t) - { - if(stack.size() < cap) - { - stack.add(t); - acceptor.accept(t); - } - } - - @Override - public synchronized void accept(T[] array) - { - stack.addAll(array, 0, Math.min(array.length, cap - stack.size())); - for(int i = 0,m=Math.min(array.length, cap - stack.size());i array) - { - Iterator iter = array.iterator(); - for(int i = 0,m=Math.min(array.size(), cap - stack.size());i implements IPool +{ + int cap; + ObjectList stack; + Supplier creator; + Consumer acceptor; + + public ThreadPool(int size, Supplier creator) + { + this(size, creator, Functions.getVoidConsumer()); + } + + public ThreadPool(int size, Supplier creator, Consumer acceptor) + { + cap = size; + stack = new ObjectArrayList(size); + this.creator = creator; + this.acceptor = acceptor; + } + + @Override + public synchronized void accept(T t) + { + if(stack.size() < cap) + { + stack.add(t); + acceptor.accept(t); + } + } + + @Override + public synchronized void accept(T[] array) + { + int size = Math.min(array.length, cap - stack.size()); + if(size <= 0) return; + stack.addAll(array, 0, size); + for(int i = 0;i array) + { + int size = Math.min(array.size(), cap - stack.size()); + if(size <= 0) return; + Iterator iter = array.iterator(); + for(int i = 0;i children = new ArrayList(); - int debth = 0; - int totalTicks = 0; - - long maxTime = Long.MIN_VALUE; - long minTime = Long.MAX_VALUE; - long average = 0L; - LongPriorityQueue entries = new LongArrayFIFOQueue(); - long startTime = 0L; - long currentTime = 0L; - - ObjectPriorityDequeue stamps = new ObjectArrayFIFOQueue(); - - public GPUProfilerEntry(String name, IProfiler owner) - { - this.name = name; - pathName = name; - this.owner = owner; - } - - public void addChild(GPUProfilerEntry child) - { - if(child != null) - { - children.add(child); - child.setParent(this); - } - } - - private void setParent(GPUProfilerEntry parent) - { - this.parent = parent; - debth = parent.debth + 1; - pathName = parent.pathName+"/"+name; - } - - public void start() - { - stamps.enqueue(GLStamper.INSTANCE.createStamp(owner.getName()).start()); - } - - public void stop() - { - stamps.last().stop(); - } - - public void onFrameFinished(boolean end) - { - while(!stamps.isEmpty() && stamps.first().isFinished()) - { - GLStamp stamp = stamps.dequeue(); - currentTime += stamp.getResult(); - stamp.release(); - } - average += currentTime; - entries.enqueue(currentTime); - if(entries.size() > 20) - { - average -= entries.dequeue(); - } - currentTime = average / entries.size(); - minTime = Math.min(minTime, currentTime); - maxTime = Math.max(maxTime, currentTime); - currentTime = 0; - if(end && totalTicks++ >= 10) - { - minTime = currentTime; - maxTime = currentTime; - totalTicks = 0; - } - } - - @Override - public String getName() - { - return name; - } - - @Override - public String getPathName() - { - return pathName; - } - - @Override - public int getDebth() - { - return debth; - } - - @Override - public IProfiler getOwner() - { - return owner; - } - - @Override - public IProfilerEntry getParent() - { - return parent; - } - - @Override - public int getChildCount() - { - return children.size(); - } - - @Override - public IProfilerEntry getChild(int index) - { - return children.get(index); - } - - @Override - public long getMinTime() - { - return minTime; - } - - @Override - public long getNanoTime() - { - return entries.isEmpty() ? 0L : average / entries.size(); - } - - @Override - public long getMaxTime() - { - return maxTime; - } -} +package speiger.src.coreengine.utils.profiler; + +import java.util.ArrayList; +import java.util.List; + +import speiger.src.collections.longs.queues.LongArrayFIFOQueue; +import speiger.src.collections.longs.queues.LongPriorityQueue; +import speiger.src.collections.objects.queues.ObjectArrayFIFOQueue; +import speiger.src.collections.objects.queues.ObjectPriorityDequeue; +import speiger.src.coreengine.rendering.utils.GLStamper; +import speiger.src.coreengine.rendering.utils.GLStamper.GLStamp; +import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry; + +public class GPUProfilerEntry implements IProfilerEntry +{ + String name; + String pathName; + IProfiler owner; + IProfilerEntry parent; + List children = new ArrayList(); + int debth = 0; + int totalTicks = 0; + + long maxTime = Long.MIN_VALUE; + long minTime = Long.MAX_VALUE; + long average = 0L; + LongPriorityQueue entries = new LongArrayFIFOQueue(); + long startTime = 0L; + long currentTime = 0L; + + ObjectPriorityDequeue stamps = new ObjectArrayFIFOQueue(); + + public GPUProfilerEntry(String name, IProfiler owner) + { + this.name = name; + pathName = name; + this.owner = owner; + } + + public void addChild(GPUProfilerEntry child) + { + if(child != null) + { + children.add(child); + child.setParent(this); + } + } + + private void setParent(GPUProfilerEntry parent) + { + this.parent = parent; + debth = parent.debth + 1; + pathName = parent.pathName+"/"+name; + } + + public void start() + { + stamps.enqueue(GLStamper.INSTANCE.createStamp(owner.getName()).start()); + } + + public void stop() + { + stamps.last().stop(); + } + + public void onFrameFinished(boolean end) + { + while(!stamps.isEmpty() && stamps.first().isFinished()) + { + GLStamp stamp = stamps.dequeue(); + currentTime += stamp.getResult(); + stamp.release(); + } + average += currentTime; + entries.enqueue(currentTime); + if(entries.size() > 100) + { + average -= entries.dequeue(); + } + currentTime = average / entries.size(); + minTime = Math.min(minTime, currentTime); + maxTime = Math.max(maxTime, currentTime); + currentTime = 0; + if(end && totalTicks++ >= 10) + { + minTime = currentTime; + maxTime = currentTime; + totalTicks = 0; + } + } + + @Override + public String getName() + { + return name; + } + + @Override + public String getPathName() + { + return pathName; + } + + @Override + public int getDebth() + { + return debth; + } + + @Override + public IProfiler getOwner() + { + return owner; + } + + @Override + public IProfilerEntry getParent() + { + return parent; + } + + @Override + public int getChildCount() + { + return children.size(); + } + + @Override + public IProfilerEntry getChild(int index) + { + return children.get(index); + } + + @Override + public long getMinTime() + { + return minTime; + } + + @Override + public long getNanoTime() + { + return entries.isEmpty() ? 0L : average / entries.size(); + } + + @Override + public long getMaxTime() + { + return maxTime; + } +} diff --git a/src/main/java/speiger/src/coreengine/utils/profiler/IProfiler.java b/src/main/java/speiger/src/coreengine/utils/profiler/IProfiler.java index 168bb00..ce3dc15 100644 --- a/src/main/java/speiger/src/coreengine/utils/profiler/IProfiler.java +++ b/src/main/java/speiger/src/coreengine/utils/profiler/IProfiler.java @@ -1,163 +1,161 @@ -package speiger.src.coreengine.utils.profiler; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.function.ObjIntConsumer; - -import speiger.src.coreengine.utils.helpers.TextUtil; - -public interface IProfiler -{ - - public String getName(); - - public IProfilerEntry getEntry(String name); - - public long getTicksRan(); - - public void enable(); - - public void disable(); - - public default void setState(boolean enabled) - { - if(enabled) - { - enable(); - return; - } - disable(); - } - - public boolean isEnabled(); - - public void addListener(ObjIntConsumer listener); - - public void removeListener(ObjIntConsumer listener); - - public IProfiler start(String name); - - public IProfiler start(Class clz); - - public IProfiler stop(); - - public IProfiler next(String name); - - public void onFrameEnded(boolean count); - - public static interface IProfilerEntry - { - public String getName(); - - public default String getPathName() - { - return getName(); - } - - public long getMinTime(); - - public long getNanoTime(); - - public long getMaxTime(); - - public int getDebth(); - - public int getChildCount(); - - public IProfilerEntry getChild(int index); - - public IProfilerEntry getParent(); - - public IProfiler getOwner(); - - default long getTotalTime() - { - IProfilerEntry entry = this; - while(entry.getParent() != null) - { - entry = entry.getParent(); - } - return entry.getNanoTime(); - } - - public default List getData() - { - List list = new ArrayList(); - long time = getNanoTime(); - long totalTime = getTotalTime(); - long used = 0L; - for(int i = 0;i - { - String name; - int color; - long nanoTime; - double effect; - double totalEffect; - - public ProfilerData(String name, long time, double effect, double totalEffect) - { - this.name = name; - color = TextUtil.getColorFromText(name); - nanoTime = time; - this.effect = effect; - this.totalEffect = totalEffect; - } - - @Override - public int compareTo(ProfilerData o) - { - if(o.nanoTime > nanoTime) - { - return 1; - } - return o.nanoTime < nanoTime ? -1 : name.compareTo(o.name); - } - - public String getName() - { - return name; - } - - public int getColor() - { - return color; - } - - public long getNanoTime() - { - return nanoTime; - } - - public double getEffect() - { - return effect; - } - - public double getTotalEffect() - { - return totalEffect; - } - } -} +package speiger.src.coreengine.utils.profiler; + +import java.util.function.ObjIntConsumer; + +import speiger.src.collections.objects.lists.ObjectArrayList; +import speiger.src.collections.objects.lists.ObjectList; +import speiger.src.coreengine.utils.helpers.TextUtil; + +public interface IProfiler +{ + public String getName(); + + public IProfilerEntry getEntry(String name); + + public long getTicksRan(); + + public void enable(); + + public void disable(); + + public default void setState(boolean enabled) + { + if(enabled) + { + enable(); + return; + } + disable(); + } + + public boolean isEnabled(); + + public void addListener(ObjIntConsumer listener); + + public void removeListener(ObjIntConsumer listener); + + public IProfiler start(String name); + + public IProfiler start(Class clz); + + public IProfiler stop(); + + public IProfiler next(String name); + + public void onFrameEnded(boolean count); + + public static interface IProfilerEntry + { + public String getName(); + + public default String getPathName() + { + return getName(); + } + + public long getMinTime(); + + public long getNanoTime(); + + public long getMaxTime(); + + public int getDebth(); + + public int getChildCount(); + + public IProfilerEntry getChild(int index); + + public IProfilerEntry getParent(); + + public IProfiler getOwner(); + + default long getTotalTime() + { + IProfilerEntry entry = this; + while(entry.getParent() != null) + { + entry = entry.getParent(); + } + return entry.getNanoTime(); + } + + public default ObjectList getData() + { + ObjectList list = new ObjectArrayList<>(); + long time = getNanoTime(); + long totalTime = getTotalTime(); + long used = 0L; + for(int i = 0;i + { + String name; + int color; + long nanoTime; + double effect; + double totalEffect; + + public ProfilerData(String name, long time, double effect, double totalEffect) + { + this.name = name; + color = TextUtil.getColorFromText(name); + nanoTime = time; + this.effect = effect; + this.totalEffect = totalEffect; + } + + @Override + public int compareTo(ProfilerData o) + { + if(o.nanoTime > nanoTime) + { + return 1; + } + return o.nanoTime < nanoTime ? -1 : name.compareTo(o.name); + } + + public String getName() + { + return name; + } + + public int getColor() + { + return color; + } + + public long getNanoTime() + { + return nanoTime; + } + + public double getEffect() + { + return effect; + } + + public double getTotalEffect() + { + return totalEffect; + } + } +} diff --git a/src/main/java/speiger/src/coreengine/utils/profiler/ProfilerEntry.java b/src/main/java/speiger/src/coreengine/utils/profiler/ProfilerEntry.java index 3da21aa..82f6382 100644 --- a/src/main/java/speiger/src/coreengine/utils/profiler/ProfilerEntry.java +++ b/src/main/java/speiger/src/coreengine/utils/profiler/ProfilerEntry.java @@ -1,152 +1,152 @@ -package speiger.src.coreengine.utils.profiler; - -import java.util.ArrayList; -import java.util.List; - -import speiger.src.collections.longs.queues.LongArrayFIFOQueue; -import speiger.src.collections.longs.queues.LongPriorityQueue; -import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry; - -public class ProfilerEntry implements IProfilerEntry -{ - String name; - String pathName; - IProfiler owner; - IProfilerEntry parent; - List children = new ArrayList(); - int debth = 0; - int totalTicks = 0; - - long maxTime = Long.MIN_VALUE; - long minTime = Long.MAX_VALUE; - long average = 0L; - LongPriorityQueue entries = new LongArrayFIFOQueue(); - long startTime = 0L; - long currentTime = 0L; - boolean didTick = false; - - public ProfilerEntry(String name, IProfiler owner) - { - this.name = name; - pathName = name; - this.owner = owner; - } - - public void addChild(ProfilerEntry child) - { - if(child != null) - { - children.add(child); - child.setParent(this); - } - } - - private void setParent(ProfilerEntry parent) - { - this.parent = parent; - debth = parent.debth + 1; - pathName = parent.pathName+"/"+name; - } - - public void start() - { - startTime = System.nanoTime(); - } - - public void stop() - { - currentTime += (System.nanoTime() - startTime); - didTick = true; - } - - public void onFrameFinished(boolean end) - { - if(!didTick) - { - if(end && totalTicks++ >= 10) - { - minTime = 0; - maxTime = 0; - totalTicks = 0; - } - return; - } - didTick = false; - average += currentTime; - entries.enqueue(currentTime); - if(entries.size() > 20) - { - average -= entries.dequeue(); - } - currentTime = average / entries.size(); - minTime = Math.min(minTime, currentTime); - maxTime = Math.max(maxTime, currentTime); - currentTime = 0; - if(end && totalTicks++ >= 10) - { - minTime = currentTime; - maxTime = currentTime; - totalTicks = 0; - } - } - - @Override - public String getName() - { - return name; - } - - @Override - public String getPathName() - { - return pathName; - } - - @Override - public long getMinTime() - { - return minTime; - } - - @Override - public long getNanoTime() - { - return entries.isEmpty() ? 0L : average / entries.size(); - } - - @Override - public long getMaxTime() - { - return maxTime; - } - - @Override - public int getDebth() - { - return debth; - } - - @Override - public int getChildCount() - { - return children.size(); - } - - @Override - public IProfilerEntry getChild(int index) - { - return children.get(index); - } - - @Override - public IProfilerEntry getParent() - { - return parent; - } - - @Override - public IProfiler getOwner() - { - return owner; - } -} +package speiger.src.coreengine.utils.profiler; + +import java.util.ArrayList; +import java.util.List; + +import speiger.src.collections.longs.queues.LongArrayFIFOQueue; +import speiger.src.collections.longs.queues.LongPriorityQueue; +import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry; + +public class ProfilerEntry implements IProfilerEntry +{ + String name; + String pathName; + IProfiler owner; + IProfilerEntry parent; + List children = new ArrayList(); + int debth = 0; + int totalTicks = 0; + + long maxTime = Long.MIN_VALUE; + long minTime = Long.MAX_VALUE; + long average = 0L; + LongPriorityQueue entries = new LongArrayFIFOQueue(); + long startTime = 0L; + long currentTime = 0L; + boolean didTick = false; + + public ProfilerEntry(String name, IProfiler owner) + { + this.name = name; + pathName = name; + this.owner = owner; + } + + public void addChild(ProfilerEntry child) + { + if(child != null) + { + children.add(child); + child.setParent(this); + } + } + + private void setParent(ProfilerEntry parent) + { + this.parent = parent; + debth = parent.debth + 1; + pathName = parent.pathName+"/"+name; + } + + public void start() + { + startTime = System.nanoTime(); + } + + public void stop() + { + currentTime += (System.nanoTime() - startTime); + didTick = true; + } + + public void onFrameFinished(boolean end) + { + if(!didTick) + { + if(end && totalTicks++ >= 10) + { + minTime = Long.MAX_VALUE; + maxTime = Long.MIN_VALUE; + totalTicks = 0; + } + return; + } + didTick = false; + average += currentTime; + entries.enqueue(currentTime); + if(entries.size() > 100) + { + average -= entries.dequeue(); + } + currentTime = average / entries.size(); + minTime = Math.min(minTime, currentTime); + maxTime = Math.max(maxTime, currentTime); + currentTime = 0; + if(end && totalTicks++ >= 10) + { + minTime = currentTime; + maxTime = currentTime; + totalTicks = 0; + } + } + + @Override + public String getName() + { + return name; + } + + @Override + public String getPathName() + { + return pathName; + } + + @Override + public long getMinTime() + { + return minTime; + } + + @Override + public long getNanoTime() + { + return entries.isEmpty() ? 0L : average / entries.size(); + } + + @Override + public long getMaxTime() + { + return maxTime; + } + + @Override + public int getDebth() + { + return debth; + } + + @Override + public int getChildCount() + { + return children.size(); + } + + @Override + public IProfilerEntry getChild(int index) + { + return children.get(index); + } + + @Override + public IProfilerEntry getParent() + { + return parent; + } + + @Override + public IProfiler getOwner() + { + return owner; + } +} diff --git a/src/main/java/speiger/src/coreengine/utils/tasks/MainThreadTaskProcessor.java b/src/main/java/speiger/src/coreengine/utils/tasks/MainThreadTaskProcessor.java index acc7670..f6ca519 100644 --- a/src/main/java/speiger/src/coreengine/utils/tasks/MainThreadTaskProcessor.java +++ b/src/main/java/speiger/src/coreengine/utils/tasks/MainThreadTaskProcessor.java @@ -1,146 +1,146 @@ -package speiger.src.coreengine.utils.tasks; - -import speiger.src.collections.objects.queues.ObjectArrayFIFOQueue; -import speiger.src.collections.objects.queues.ObjectPriorityDequeue; -import speiger.src.collections.objects.utils.ObjectPriorityQueues; -import speiger.src.coreengine.utils.counters.timers.CountdownSync; - -public class MainThreadTaskProcessor -{ - ObjectPriorityDequeue tasks = ObjectPriorityQueues.synchronize(new ObjectArrayFIFOQueue()); - Watchdog watch; - Thread watchThread; - boolean running = false; - long timeout; - - public MainThreadTaskProcessor(long timeout, String name) - { - this.timeout = timeout; - watch = new Watchdog(Thread.currentThread()); - watchThread = new Thread(watch, name+"-Thread-Watchdog"); - watchThread.start(); - } - - public void setTimeout(long timeout) - { - this.timeout = timeout; - } - - public void addTask(ITask task) - { - tasks.enqueue(task); - } - - public void finishAllTasks() - { - if(tasks.isEmpty()) - { - return; - } - running = true; - while(!tasks.isEmpty()) - { - try - { - tasks.dequeue().execute(); - } - catch(InterruptedException e) - { - } - catch(Exception e) - { - e.printStackTrace(); - } - } - running = false; - } - - public void update() - { - if(tasks.isEmpty()) - { - return; - } - watch.unlock(); - running = true; - boolean interrupted = false; - while(!tasks.isEmpty() && !(interrupted |= Thread.interrupted())) - { - ITask task = tasks.dequeue(); - try - { - task.execute(); - } - catch(InterruptedException e) - { - interrupted = true; - } - catch(Exception e) - { - e.printStackTrace(); - } - if(!task.isFinished()) - { - tasks.enqueue(task); - } - } - running = false; - if(!interrupted) - { - watchThread.interrupt(); - } - } - - public void kill() - { - if(watchThread != null) - { - return; - } - watch.alive = false; - watchThread.interrupt(); - watchThread = null; - } - - class Watchdog implements Runnable - { - Thread owner; - boolean alive = true; - CountdownSync timer = new CountdownSync(); - Object lock = new Object(); - - public Watchdog(Thread thread) - { - owner = thread; - } - - @Override - public void run() - { - while(alive) - { - try - { - synchronized(lock) - { - lock.wait(); - } - timer.sync(timeout); - if(running) - { - owner.interrupt(); - } - } - catch(InterruptedException e) {} - } - } - - public void unlock() - { - synchronized(lock) - { - lock.notify(); - } - } - } -} +package speiger.src.coreengine.utils.tasks; + +import speiger.src.collections.objects.queues.ObjectArrayFIFOQueue; +import speiger.src.collections.objects.queues.ObjectPriorityDequeue; +import speiger.src.collections.objects.utils.ObjectPriorityQueues; +import speiger.src.coreengine.utils.counters.timers.CountdownSync; + +public class MainThreadTaskProcessor +{ + ObjectPriorityDequeue tasks = ObjectPriorityQueues.synchronize(new ObjectArrayFIFOQueue<>()); + Watchdog watch; + Thread watchThread; + boolean running = false; + long timeout; + + public MainThreadTaskProcessor(long timeout, String name) + { + this.timeout = timeout; + watch = new Watchdog(Thread.currentThread()); + watchThread = new Thread(watch, name+"-Thread-Watchdog"); + watchThread.start(); + } + + public void setTimeout(long timeout) + { + this.timeout = timeout; + } + + public void addTask(ITask task) + { + tasks.enqueue(task); + } + + public void finishAllTasks() + { + if(tasks.isEmpty()) + { + return; + } + running = true; + while(!tasks.isEmpty()) + { + try + { + tasks.dequeue().execute(); + } + catch(InterruptedException e) + { + } + catch(Exception e) + { + e.printStackTrace(); + } + } + running = false; + } + + public void update() + { + if(tasks.isEmpty()) + { + return; + } + watch.unlock(); + running = true; + boolean interrupted = false; + while(!tasks.isEmpty() && !(interrupted |= Thread.interrupted())) + { + ITask task = tasks.dequeue(); + try + { + task.execute(); + } + catch(InterruptedException e) + { + interrupted = true; + } + catch(Exception e) + { + e.printStackTrace(); + } + if(!task.isFinished()) + { + tasks.enqueue(task); + } + } + running = false; + if(!interrupted) + { + watchThread.interrupt(); + } + } + + public void kill() + { + if(watchThread != null) + { + return; + } + watch.alive = false; + watchThread.interrupt(); + watchThread = null; + } + + class Watchdog implements Runnable + { + Thread owner; + boolean alive = true; + CountdownSync timer = new CountdownSync(); + Object lock = new Object(); + + public Watchdog(Thread thread) + { + owner = thread; + } + + @Override + public void run() + { + while(alive) + { + try + { + synchronized(lock) + { + lock.wait(); + } + timer.sync(timeout); + if(running) + { + owner.interrupt(); + } + } + catch(InterruptedException e) {} + } + } + + public void unlock() + { + synchronized(lock) + { + lock.notify(); + } + } + } +}