Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ test {
repositories {
mavenCentral()
mavenLocal()
maven {
name "JEI"
url "https://maven.blamejared.com"
}
maven {
name "Cyclops Repo"
url "https://maven.pkg.github.com/CyclopsMC/packages"
Expand Down Expand Up @@ -136,6 +140,9 @@ dependencies {
}
}

// Optional, only used to hide JEI in focus mode
compileOnly "mezz.jei:jei-${project.minecraft_version}-neoforge-api:${project.jei_version}"

modLib "com.google.re2j:re2j:1.1"
modLib ("io.netty:netty-codec-http:4.1.77.Final") {
transitive = false
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ org.gradle.caching=true
graal_version=25.2.4
cyclopscore_version=1.25.5-643
integrateddynamics_version=1.24.1-1004
jei_version=19.16.0.152
commoncapabilities_version=2.9.3-147
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.commons.lang3.tuple.Pair;
import org.joml.Vector2i;
import org.cyclops.cyclopscore.client.gui.component.WidgetScrollBar;
import org.cyclops.cyclopscore.client.gui.component.input.IInputListener;
import org.cyclops.cyclopscore.helper.Helpers;
Expand Down Expand Up @@ -82,7 +83,16 @@ public class WidgetTextArea extends EditBox implements GuiEventListener {
private static final int POPUP_SELECTED = 0xFF505050;
private static final int POPUP_TEXT = 0xFFE0E0E0;
private static final int POPUP_DETAIL = 0xFF909090;
public static final int SCROLLBAR_WIDTH = 14;
public static final int SCROLLBAR_WIDTH = 7;
// Same height as the vanilla scroller, which the scrollbar's drag handling assumes
private static final int SCROLLBAR_HANDLE_HEIGHT = 15;
// Height of the arrow between a syntax error tooltip and its error
private static final int TOOLTIP_ARROW = 4;
// How far vanilla tooltip backgrounds extend beyond their contents
private static final int TOOLTIP_BORDER = 4;
// Colors of vanilla tooltips
private static final int TOOLTIP_BACKGROUND = 0xF0100010;
private static final int TOOLTIP_BORDER_COLOR = 0x505000FF;

private final TextFieldHelperExtended textFieldHelper;
private final Font font;
Expand Down Expand Up @@ -164,9 +174,15 @@ public int getTotalRows() {

@Override
public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) {
// Only show scrollbar if needed
// Only show scrollbar if needed, and draw a narrower handle than the vanilla scroller to leave more room for text
if (this.needsScrollBars()) {
super.renderWidget(guiGraphics, mouseX, mouseY, partialTicks);
int x = this.getX();
int y = this.getY() + (int) ((this.getHeight() - SCROLLBAR_HANDLE_HEIGHT - 2) * this.getCurrentScroll());
int x2 = x + SCROLLBAR_WIDTH - 1;
int y2 = y + SCROLLBAR_HANDLE_HEIGHT;
guiGraphics.fill(x, y, x2, y2, Helpers.RGBAToInt(85, 85, 85, 255));
guiGraphics.fill(x, y, x2 - 1, y2 - 1, Helpers.RGBAToInt(255, 255, 255, 255));
guiGraphics.fill(x + 1, y + 1, x2 - 1, y2 - 1, Helpers.RGBAToInt(198, 198, 198, 255));
}
}
};
Expand Down Expand Up @@ -945,15 +961,21 @@ public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float

// Render scrollbar
if (this.scrollBar != null) {
this.scrollBar.render(guiGraphics, getX(), getY(), partialTicks);

// Mark the position of the syntax error on the scrollbar, so it can be found when scrolled out of view
// Mark the position of the syntax error on the scrollbar, so it can be found when scrolled out of view.
// This is drawn below the handle, which only covers it when the error is roughly in view.
if (this.syntaxError != null && displayCache.linesTotal > this.scrollBar.getVisibleRows()) {
int errorRow = findLineFromPos(displayCache.lineStarts, TextEditing.lineOffset(this.getValue(), this.syntaxError.line()));
int y = this.getY() + (int) ((long) errorRow * (this.getHeight() - 2) / displayCache.linesTotal);
int x = this.getX() + this.getWidth() - SCROLLBAR_WIDTH + 1;
guiGraphics.fill(x, y, x + SCROLLBAR_WIDTH - 2, y + 2, Helpers.RGBAToInt(220, 0, 0, 255));
int x = this.getX() + this.getWidth() - SCROLLBAR_WIDTH;
guiGraphics.fill(x, y, x + SCROLLBAR_WIDTH - 1, y + 2, Helpers.RGBAToInt(220, 0, 0, 255));

// Show the message when hovering the mark
if (mouseX >= x && mouseX < x + SCROLLBAR_WIDTH - 1 && mouseY >= y - 1 && mouseY < y + 3 && Minecraft.getInstance().screen != null) {
Minecraft.getInstance().screen.setTooltipForNextRenderPass(this.font.split(Component.literal(this.syntaxError.message()), 200));
}
}

this.scrollBar.render(guiGraphics, getX(), getY(), partialTicks);
}
}

Expand All @@ -963,22 +985,64 @@ private void renderSyntaxError(GuiGraphics guiGraphics, DisplayCache displayCach
int pos = Math.min(value.length(), TextEditing.lineOffset(value, this.syntaxError.line()) + Math.max(0, this.syntaxError.column() - 1));
int line = findLineFromPos(displayCache.lineStarts, pos);
int row = line - this.firstRow;
int errorCenterX = -1;
if (row >= 0 && row < this.getHeight() / ROW_HEIGHT) {
int x = this.font.width(value.substring(displayCache.lineStarts[line], pos));
int width = pos < value.length() && value.charAt(pos) != '\n' ? this.font.width(value.substring(pos, pos + 1)) : 4;
Pos2i screenPos = this.convertLocalToScreen(new Pos2i(x, row * ROW_HEIGHT));
guiGraphics.fill(screenPos.x, screenPos.y + ROW_HEIGHT - 2, screenPos.x + width, screenPos.y + ROW_HEIGHT - 1, Helpers.RGBAToInt(220, 0, 0, 255));
errorCenterX = screenPos.x + width / 2;
}

// Show the message when hovering the error line
// Show the message when hovering the error line, which may be wrapped over multiple rows
int top = Integer.MAX_VALUE;
int bottom = Integer.MIN_VALUE;
boolean hovering = false;
for (LineInfo lineInfo : lines) {
if (lineInfo.lineNumber + 1 == this.syntaxError.line() && mouseX >= this.getX() && mouseX < this.getX() + this.getWidth()
&& mouseY >= lineInfo.y && mouseY < lineInfo.y + ROW_HEIGHT && Minecraft.getInstance().screen != null) {
Minecraft.getInstance().screen.setTooltipForNextRenderPass(this.font.split(Component.literal(this.syntaxError.message()), 200));
if (lineInfo.lineNumber + 1 == this.syntaxError.line()) {
top = Math.min(top, lineInfo.y);
bottom = Math.max(bottom, lineInfo.y + ROW_HEIGHT);
hovering |= mouseX >= this.getX() && mouseX < this.getX() + this.getWidth()
&& mouseY >= lineInfo.y && mouseY < lineInfo.y + ROW_HEIGHT;
}
}
if (hovering && Minecraft.getInstance().screen != null) {
List<FormattedCharSequence> message = this.font.split(Component.literal(this.syntaxError.message()), 200);
int screenHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight();
// Same height as vanilla tooltips of text lines
int tooltipHeight = message.size() * 10 - (message.size() == 1 ? 2 : 0);

// Like in other editors, show the message below the line, or above it if there is no room
boolean below = bottom + TOOLTIP_ARROW + TOOLTIP_BORDER + tooltipHeight + TOOLTIP_BORDER <= screenHeight
|| top - TOOLTIP_ARROW - TOOLTIP_BORDER - tooltipHeight - TOOLTIP_BORDER < 0;
int tooltipY = below ? bottom + TOOLTIP_ARROW + TOOLTIP_BORDER : top - TOOLTIP_ARROW - TOOLTIP_BORDER - tooltipHeight;
int anchorX = errorCenterX >= 0 ? errorCenterX - 12 : mouseX + 12;
Minecraft.getInstance().screen.setTooltipForNextRenderPass(message, (screenWidth, screenHeightIgnored, mouseXIgnored, mouseYIgnored, width, height) ->
new Vector2i(Math.max(TOOLTIP_BORDER, Math.min(anchorX, screenWidth - width - TOOLTIP_BORDER)), tooltipY), true);

// Point at the column of the error
if (errorCenterX >= 0) {
this.renderTooltipArrow(guiGraphics, errorCenterX, below ? bottom : top - 1, below);
}
}
}

/**
* Draw an arrow between a tooltip and the given position, in the style of vanilla tooltips.
*/
private void renderTooltipArrow(GuiGraphics guiGraphics, int x, int tipY, boolean pointUp) {
guiGraphics.pose().pushPose();
// Same depth as tooltips
guiGraphics.pose().translate(0, 0, 400);
for (int i = 0; i < TOOLTIP_ARROW; i++) {
int y = pointUp ? tipY + i : tipY - i;
guiGraphics.fill(x - i, y, x + i + 1, y + 1, TOOLTIP_BACKGROUND);
guiGraphics.fill(x - i, y, x - i + 1, y + 1, TOOLTIP_BORDER_COLOR);
guiGraphics.fill(x + i, y, x + i + 1, y + 1, TOOLTIP_BORDER_COLOR);
}
guiGraphics.pose().popPose();
}

private void renderCharBackground(GuiGraphics guiGraphics, DisplayCache displayCache, int pos, int color) {
int line = findLineFromPos(displayCache.lineStarts, pos);
int row = line - this.firstRow;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import net.minecraft.util.StringUtil;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.neoforged.fml.ModList;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.Level;
import org.cyclops.cyclopscore.client.gui.component.WidgetScrollBar;
Expand Down Expand Up @@ -87,6 +88,8 @@ public class ContainerScreenTerminalScripting extends ContainerScreenExtended<Co
public static int SCRIPT_WIDTH = 168;
public static int SCRIPT_HEIGHT = 115;
public static int FOCUS_MARGIN = 20;
// JEI keeps its bookmark and config buttons in the bottom corners, even when its overlay is hidden
public static int FOCUS_MARGIN_JEI = 28;

private final Player player;

Expand Down Expand Up @@ -159,8 +162,9 @@ public int getTotalRows() {

if (focusMode) {
// Let the editor take up most of the screen
int height = (this.height - 2 * FOCUS_MARGIN) / WidgetTextArea.ROW_HEIGHT * WidgetTextArea.ROW_HEIGHT;
textArea = new WidgetTextArea(Minecraft.getInstance().font, FOCUS_MARGIN, FOCUS_MARGIN, this.width - 2 * FOCUS_MARGIN, height, Component.translatable("gui.integratedscripting.script"), true, true);
int margin = getFocusMargin();
int height = (this.height - 2 * margin) / WidgetTextArea.ROW_HEIGHT * WidgetTextArea.ROW_HEIGHT;
textArea = new WidgetTextArea(Minecraft.getInstance().font, margin, margin, this.width - 2 * margin, height, Component.translatable("gui.integratedscripting.script"), true, true);
} else {
textArea = new WidgetTextArea(Minecraft.getInstance().font, this.leftPos + SCRIPT_X + 1, this.topPos + SCRIPT_Y + 1, SCRIPT_WIDTH, SCRIPT_HEIGHT, Component.translatable("gui.integratedscripting.script"), true, true);
}
Expand Down Expand Up @@ -218,7 +222,7 @@ public int getTotalRows() {
}

if (focusMode) {
this.addToolbar(this.width - FOCUS_MARGIN, FOCUS_MARGIN - 12);
this.addToolbar(this.width - getFocusMargin(), getFocusMargin() - 12);
} else {
this.addToolbar(this.leftPos + SCRIPT_X + SCRIPT_WIDTH, this.topPos + 5);
}
Expand Down Expand Up @@ -384,7 +388,7 @@ protected void drawCurrentScreen(GuiGraphics guiGraphics, int mouseX, int mouseY
guiGraphics.fill(textArea.getX() - 1, textArea.getY() - 1, textArea.getX() + textArea.getWidth() + 1, textArea.getY() + textArea.getHeight() + 1, Helpers.RGBAToInt(224, 224, 224, 255));
Path path = getMenu().getActiveScriptPath();
if (path != null) {
guiGraphics.drawString(font, path.toString(), FOCUS_MARGIN, FOCUS_MARGIN - 11, 16777215);
guiGraphics.drawString(font, path.toString(), getFocusMargin(), getFocusMargin() - 11, 16777215);
}
for (net.minecraft.client.gui.components.Renderable renderable : this.renderables) {
renderable.render(guiGraphics, mouseX, mouseY, partialTicks);
Expand Down Expand Up @@ -741,6 +745,14 @@ public void setFirstRow(int firstRow) {
this.firstRow = firstRow;
}

protected int getFocusMargin() {
return ModList.get().isLoaded("jei") ? FOCUS_MARGIN_JEI : FOCUS_MARGIN;
}

public boolean isFocusMode() {
return focusMode;
}

@Nullable
private ILanguageHandler getActiveLanguageHandler() {
Path path = getMenu().getActiveScriptPath();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.cyclops.integratedscripting.modcompat.jei;

import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin;
import mezz.jei.api.gui.handlers.IGuiContainerHandler;
import mezz.jei.api.registration.IGuiHandlerRegistration;
import net.minecraft.client.renderer.Rect2i;
import net.minecraft.resources.ResourceLocation;
import org.cyclops.integratedscripting.Reference;
import org.cyclops.integratedscripting.client.gui.container.ContainerScreenTerminalScripting;

import java.util.Collections;
import java.util.List;

/**
* Only loaded by JEI if it is installed.
* @author rubensworks
*/
@JeiPlugin
public class JEIIntegratedScriptingPlugin implements IModPlugin {

@Override
public ResourceLocation getPluginUid() {
return ResourceLocation.fromNamespaceAndPath(Reference.MOD_ID, "main");
}

@Override
public void registerGuiHandlers(IGuiHandlerRegistration registration) {
registration.addGuiContainerHandler(ContainerScreenTerminalScripting.class, new IGuiContainerHandler<>() {
@Override
public List<Rect2i> getGuiExtraAreas(ContainerScreenTerminalScripting screen) {
// Claim the whole screen in focus mode, so JEI hides its overlays instead of drawing them over the editor
return screen.isFocusMode() ? List.of(new Rect2i(0, 0, screen.width, screen.height)) : Collections.emptyList();
}
});
}

}
Loading