From e79bdb4326e16ed526a5046c67b281bf9ddfb55c Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 24 Aug 2021 21:08:26 +0700 Subject: [PATCH] Scissor and draggable canvas panel for android research window --- .../mc/otm/screen/AndroidStationScreen.java | 25 +++++- .../mc/otm/screen/RenderHelper.java | 48 +++++++++++ .../screen/panels/DraggableCanvasPanel.java | 51 ++++++++++++ .../mc/otm/screen/panels/EditablePanel.java | 81 ++++++++++++++----- 4 files changed, 185 insertions(+), 20 deletions(-) create mode 100644 src/main/java/ru/dbotthepony/mc/otm/screen/panels/DraggableCanvasPanel.java diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java b/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java index d162e164e..8c5838926 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/AndroidStationScreen.java @@ -115,7 +115,27 @@ public class AndroidStationScreen extends MatteryScreen impl autoAttachToFrame(frame); - var grid = new GridPanel(this, frame, 0, 0, GRID_WIDTH * 22, 0, GRID_WIDTH, GRID_HEIGHT); + var canvas = new DraggableCanvasPanel(this, frame, 0, 0, GRID_WIDTH * 22, 0); + + var grid = new GridPanel(this, canvas, 0, 0, 0, 0, GRID_WIDTH, GRID_HEIGHT) { + @Override + protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) { + // pass event to canvas + return false; + } + + @Override + protected boolean mouseReleasedInner(double mouse_x, double mouse_y, int flag) { + // pass event to canvas + return false; + } + + @Override + protected boolean mouseDraggedInner(double mouse_x, double mouse_y, int flag, double drag_x, double drag_y) { + // pass event to canvas + return false; + } + }; minecraft.player.getCapability(MatteryCapability.ANDROID).ifPresent(_cap -> { if (_cap instanceof AndroidCapabilityPlayer cap) { @@ -129,7 +149,8 @@ public class AndroidStationScreen extends MatteryScreen impl } }); - grid.setDock(Dock.RIGHT); + canvas.setDock(Dock.RIGHT); + grid.setDock(Dock.FILL); return frame; } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/RenderHelper.java b/src/main/java/ru/dbotthepony/mc/otm/screen/RenderHelper.java index 4d752e202..c05e1ff63 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/RenderHelper.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/RenderHelper.java @@ -3,10 +3,13 @@ package ru.dbotthepony.mc.otm.screen; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; import com.mojang.math.Matrix4f; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.resources.ResourceLocation; import ru.dbotthepony.mc.otm.OverdriveThatMatters; +import java.util.Stack; + import static org.lwjgl.opengl.GL11.GL_ALWAYS; import static org.lwjgl.opengl.GL11.GL_LESS; @@ -553,4 +556,49 @@ public class RenderHelper { ) { drawRect(stack.last().pose(), x, y, width, height); } + + record ScissorRect(int x, int y, int width, int height) {} + + private static final Stack SCISSOR = new Stack<>(); + + public static void ensureScissorStackEmpty() { + if (!SCISSOR.empty()) { + throw new IllegalStateException("Unbalanced scissor rects: Popping less than pushing"); + } + } + + public static void pushScissorRect(int x, int y, int width, int height) { + if (!SCISSOR.empty()) { + final var peek = SCISSOR.peek(); + x = Math.max(x, peek.x); + y = Math.max(y, peek.y); + width = Math.min(width, peek.width); + height = Math.min(height, peek.height); + } + + SCISSOR.push(new ScissorRect(x, y, width, height)); + + final var window = Minecraft.getInstance().getWindow(); + y = window.getHeight() - y - height; + + RenderSystem.enableScissor(x, y, width, height); + } + + public static void popScissorRect() { + if (SCISSOR.empty()) { + throw new IllegalStateException("Unbalanced scissor rects: Popping more than pushing"); + } + + SCISSOR.pop(); + + if (SCISSOR.empty()) { + RenderSystem.disableScissor(); + return; + } + + final var value = SCISSOR.peek(); + final var window = Minecraft.getInstance().getWindow(); + final var y = window.getHeight() - value.y - value.height; + RenderSystem.enableScissor(value.x, y, value.width, value.height); + } } diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/panels/DraggableCanvasPanel.java b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/DraggableCanvasPanel.java new file mode 100644 index 000000000..370acaeb5 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/DraggableCanvasPanel.java @@ -0,0 +1,51 @@ +package ru.dbotthepony.mc.otm.screen.panels; + +import ru.dbotthepony.mc.otm.screen.MatteryScreen; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class DraggableCanvasPanel extends EditablePanel { + public DraggableCanvasPanel(@Nonnull MatteryScreen screen, @Nullable EditablePanel parent, float x, float y, float width, float height) { + super(screen, parent, x, y, width, height); + scissor = true; + } + + public DraggableCanvasPanel(@Nonnull MatteryScreen screen, @Nullable EditablePanel parent) { + super(screen, parent); + scissor = true; + } + + protected boolean dragging = false; + protected double last_mouse_x; + protected double last_mouse_y; + + @Override + protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) { + dragging = true; + last_mouse_x = mouse_x; + last_mouse_y = mouse_y; + setIgnoreMouseEventBoundaries(true); + return true; + } + + @Override + protected boolean mouseReleasedInner(double mouse_x, double mouse_y, int flag) { + dragging = false; + setIgnoreMouseEventBoundaries(false); + return true; + } + + @Override + protected boolean mouseDraggedInner(double mouse_x, double mouse_y, int flag, double drag_x, double drag_y) { + if (dragging) { + x_offset -= last_mouse_x - mouse_x; + y_offset -= last_mouse_y - mouse_y; + + last_mouse_x = mouse_x; + last_mouse_y = mouse_y; + } + + return true; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/screen/panels/EditablePanel.java b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/EditablePanel.java index b8fd0c2a6..69a83c0a1 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/screen/panels/EditablePanel.java +++ b/src/main/java/ru/dbotthepony/mc/otm/screen/panels/EditablePanel.java @@ -2,8 +2,12 @@ package ru.dbotthepony.mc.otm.screen.panels; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Vector3f; +import com.mojang.math.Vector4f; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; import ru.dbotthepony.mc.otm.screen.MatteryScreen; +import ru.dbotthepony.mc.otm.screen.RenderHelper; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -56,6 +60,37 @@ public class EditablePanel implements GuiEventListener { protected float parent_x; protected float parent_y; + // allows to offset children by given amount of pixels + protected float x_offset; + protected float y_offset; + + // whenever is to scissor render bounds + protected boolean scissor = false; + + public float getXOffset() { + return x_offset; + } + + public void setXOffset(float x_offset) { + this.x_offset = x_offset; + } + + public float getYOffset() { + return y_offset; + } + + public void setYOffset(float y_offset) { + this.y_offset = y_offset; + } + + public boolean getEnableScissor() { + return scissor; + } + + public void setEnableScissor(boolean scissor) { + this.scissor = scissor; + } + protected float accumulated_depth = 0; public float getMost3DHeight() { @@ -151,8 +186,16 @@ public class EditablePanel implements GuiEventListener { is_hovered = parent.is_hovered && mouse_x >= parent_x && mouse_x < parent_x + width && mouse_y >= parent_y && mouse_y < parent_y + height; } + var scissor = this.scissor; + + if (scissor) { + var window = Minecraft.getInstance().getWindow(); + var scale = window.getGuiScale(); + RenderHelper.pushScissorRect((int) (parent_x * scale), (int) (parent_y * scale), (int) (width * scale), (int) (height * scale)); + } + stack.pushPose(); - stack.translate(parent_x, parent_y, accumulated_depth); + stack.translate(parent_x + getXOffset(), parent_y + getYOffset(), accumulated_depth); innerRender(stack, mouse_x, mouse_y, flag); stack.popPose(); @@ -161,14 +204,18 @@ public class EditablePanel implements GuiEventListener { for (var child : children) { if (child.getVisible()) { child.accumulated_depth = accumulated_depth + 1; - child.parent_x = parent_x + child.x; - child.parent_y = parent_y + child.y; + child.parent_x = parent_x + child.x + getXOffset(); + child.parent_y = parent_y + child.y + getYOffset(); RenderSystem.setShaderColor(1F, 1F, 1F, 1F); most_depth = Math.max(most_depth, child.render(stack, mouse_x, mouse_y, flag)); } } + if (scissor) { + RenderHelper.popScissorRect(); + } + return most_depth; } @@ -278,8 +325,8 @@ public class EditablePanel implements GuiEventListener { var get_parent = getParent(); while (get_parent != null) { - x += get_parent.getX(); - y += get_parent.getY(); + x += get_parent.getX() + get_parent.getXOffset(); + y += get_parent.getY() + get_parent.getYOffset(); get_parent = get_parent.getParent(); } @@ -741,7 +788,7 @@ public class EditablePanel implements GuiEventListener { } protected boolean mouseClickedInner(double mouse_x, double mouse_y, int flag) { - return false; + return true; } public boolean withinBounds(double mouse_x, double mouse_y) { @@ -781,8 +828,7 @@ public class EditablePanel implements GuiEventListener { if (getMouseInputEnabled() && parent == null) screen.popup(this); - mouseClicked(mouse_x, mouse_y, flag); - return true; + return mouseClicked(mouse_x, mouse_y, flag); } else if (withinExtendedBounds(mouse_x, mouse_y)) { for (var child : children) { if (child.mouseClickedChecked(mouse_x, mouse_y, flag)) { @@ -802,7 +848,7 @@ public class EditablePanel implements GuiEventListener { } protected boolean mouseReleasedInner(double mouse_x, double mouse_y, int flag) { - return false; + return true; } @Override @@ -827,8 +873,7 @@ public class EditablePanel implements GuiEventListener { return false; if (getIgnoreMouseEventBoundaries() || withinBounds(mouse_x, mouse_y)) { - mouseReleased(mouse_x, mouse_y, flag); - return true; + return mouseReleased(mouse_x, mouse_y, flag); } else if (withinExtendedBounds(mouse_x, mouse_y)) { for (var child : children) { if (child.mouseReleasedChecked(mouse_x, mouse_y, flag)) { @@ -841,7 +886,7 @@ public class EditablePanel implements GuiEventListener { } protected boolean mouseDraggedInner(double mouse_x, double mouse_y, int flag, double drag_x, double drag_y) { - return false; + return true; } @Override @@ -866,8 +911,7 @@ public class EditablePanel implements GuiEventListener { return false; if (getIgnoreMouseEventBoundaries() || withinBounds(mouse_x, mouse_y)) { - mouseDragged(mouse_x, mouse_y, flag, drag_x, drag_y); - return true; + return mouseDragged(mouse_x, mouse_y, flag, drag_x, drag_y); } else if (withinExtendedBounds(mouse_x, mouse_y)) { for (var child : children) { if (child.mouseDraggedChecked(mouse_x, mouse_y, flag, drag_x, drag_y)) { @@ -880,7 +924,7 @@ public class EditablePanel implements GuiEventListener { } protected boolean mouseScrolledInner(double mouse_x, double mouse_y, double scroll) { - return false; + return true; } @Override @@ -905,8 +949,7 @@ public class EditablePanel implements GuiEventListener { return false; if (getIgnoreMouseEventBoundaries() || withinBounds(mouse_x, mouse_y)) { - mouseScrolled(mouse_x, mouse_y, scroll); - return true; + return mouseScrolled(mouse_x, mouse_y, scroll); } else if (withinExtendedBounds(mouse_x, mouse_y)) { for (var child : children) { if (child.mouseScrolledChecked(mouse_x, mouse_y, scroll)) { @@ -1011,7 +1054,9 @@ public class EditablePanel implements GuiEventListener { } public void tick() { - + for (var child : children) { + child.tick(); + } } private boolean is_removed = false;