diff --git a/src/api b/src/api
index c22c5f9d7..c7a74a3e0 160000
--- a/src/api
+++ b/src/api
@@ -1 +1 @@
-Subproject commit c22c5f9d7926c007009fcf434dbb4075a022e923
+Subproject commit c7a74a3e0e4b979c880383737cd7d21d4b36d131
diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiDiagram.java b/src/main/java/noppes/npcs/client/gui/util/GuiDiagram.java
index e4ae9a805..f4c585526 100644
--- a/src/main/java/noppes/npcs/client/gui/util/GuiDiagram.java
+++ b/src/main/java/noppes/npcs/client/gui/util/GuiDiagram.java
@@ -4,75 +4,58 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.ScaledResolution;
-import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.entity.RenderItem;
import noppes.npcs.constants.EnumDiagramLayout;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
-import org.lwjgl.opengl.GL12;
import java.awt.*;
-import java.util.List;
-import java.util.Queue;
import java.util.*;
+import java.util.List;
/**
* Abstract GUI class for drawing diagrams with icons (nodes) and connections (arrows).
*
- * Features include:
- *
- * - Parent reference to disable mouse interaction when a subGUI is active.
- * - Caching for icons and connections (subclasses must implement createIcons() and createConnections()).
- * - Support for different layout types (circular, square, tree, generated, and manual versions)
- * plus a CHART layout.
- * - Drawing of connections as either straight or curved arrows (with hit‐detection improved for curves).
- * - Chart layout: a grid with header icons and inner cells that show connection colors.
- * When hovering over a header or cell, only the corresponding row/column (or cell and its two icons) are highlighted
- * while all non‑relevant cells are dimmed. Also, cells with no connection are drawn with a darker gray.
- *
- * - Zooming and panning controls apply to both chart and non‑chart layouts.
- * - Callbacks for icon and connection interactions including click, held, release and hover events.
- *
+ * This revised version ensures that non‑Chart layouts use the full diagram bounds for positioning
+ * (so that the outer icons lie flush with the edges) and that curved arrow drawing selects the
+ * best control point (using both curveAngle and its negative) to avoid icons.
*/
public abstract class GuiDiagram extends Gui {
protected RenderItem renderItem = new RenderItem();
// --- Diagram Area & Controls ---
- protected int x, y, width, height; // Drawing area for the diagram
- protected float panX = 0, panY = 0; // Panning offsets
- protected float zoom = 1.0f; // Zoom factor
- protected boolean dragging = false; // Flag indicating active panning
- protected int lastDragX, lastDragY; // Last mouse positions used for panning
+ protected int x, y, width, height;
+ protected float panX = 0, panY = 0;
+ protected float zoom = 1.0f;
+ protected boolean dragging = false;
+ protected int lastDragX, lastDragY;
// --- Node (Icon) Sizing ---
- protected int iconSize = 16; // Icon image size (square)
- protected int slotPadding = 4; // Padding around icons
- protected int slotSize = iconSize + slotPadding; // Total size of the icon box
+ protected int iconSize = 16;
+ protected int slotPadding = 4;
+ protected int slotSize = iconSize + slotPadding;
// --- Icon Box Appearance ---
- protected int iconBackgroundColor = 0xFF999999; // Background color for icon boxes
- protected int iconBorderColor = 0xFF555555; // Border color for icon boxes
- protected int iconBorderThickness = 1; // Border thickness in pixels
+ protected int iconBackgroundColor = 0xFF999999;
+ protected int iconBorderColor = 0xFF555555;
+ protected int iconBorderThickness = 1;
// --- Connection Options ---
- protected boolean showArrowHeads = true; // Whether to draw arrow heads
- protected boolean useColorScaling = true; // Scale connection color based on a percentage
+ protected boolean showArrowHeads = true;
+ protected boolean useColorScaling = true;
// --- Layout Options ---
- protected EnumDiagramLayout layout = EnumDiagramLayout.CIRCULAR; // Default layout
+ protected EnumDiagramLayout layout = EnumDiagramLayout.CIRCULAR;
- /**
- * Sets the layout type and invalidates caches.
- */
public void setLayout(EnumDiagramLayout layout) {
this.layout = layout;
invalidateCache();
}
// --- Arrow Drawing Options ---
- protected boolean curvedArrows = true; // If false, draw straight connection lines
- protected int curveAngle = 15; // Curvature angle in degrees
+ protected boolean curvedArrows = true;
+ protected int curveAngle = 15; // in degrees
public void setCurvedArrows(boolean curved) {
this.curvedArrows = curved;
@@ -82,13 +65,10 @@ public abstract class GuiDiagram extends Gui {
}
// --- Caching for icons and connections ---
- protected Map cachedPositions = null; // Cached positions for nodes (non-CHART)
- protected List iconsCache = null; // Cached list of icons
- protected List connectionsCache = null; // Cached list of connections
+ protected Map cachedPositions = null;
+ protected List iconsCache = null;
+ protected List connectionsCache = null;
- /**
- * Clears cached layout information.
- */
public void invalidateCache() {
cachedPositions = null;
iconsCache = null;
@@ -98,7 +78,6 @@ public abstract class GuiDiagram extends Gui {
// --- Parent reference ---
protected GuiNPCInterface parent;
- // --- Constructor ---
public GuiDiagram(GuiNPCInterface parent, int x, int y, int width, int height) {
this.parent = parent;
this.x = x;
@@ -107,7 +86,7 @@ public abstract class GuiDiagram extends Gui {
this.height = height;
}
- // --- Data Providers (Subclasses must implement these) ---
+ // --- Data Providers (subclasses must implement) ---
protected abstract List createIcons();
protected abstract List createConnections();
@@ -129,14 +108,8 @@ public abstract class GuiDiagram extends Gui {
*/
protected abstract void renderIcon(DiagramIcon icon, int posX, int posY, IconRenderState state);
- /**
- * Returns the tooltip text lines for an icon.
- */
protected List getIconTooltip(DiagramIcon icon) { return null; }
- /**
- * Returns the tooltip text lines for a connection.
- */
protected List getConnectionTooltip(DiagramConnection conn) {
List tooltip = new ArrayList<>();
DiagramIcon iconFrom = getIconById(conn.idFrom);
@@ -156,8 +129,7 @@ public abstract class GuiDiagram extends Gui {
// --- Layout Calculation ---
/**
- * For non‑CHART layouts, returns the mapping from node ID to (x,y) position.
- * CHART layout is drawn directly.
+ * For non‑CHART layouts, returns a mapping from node ID to (x,y) position.
*/
protected Map calculatePositions() {
if (cachedPositions != null) return cachedPositions;
@@ -165,29 +137,44 @@ public abstract class GuiDiagram extends Gui {
return new HashMap<>();
}
switch (layout) {
- case CIRCULAR: cachedPositions = calculateCircularPositions(); break;
- case SQUARE: cachedPositions = calculateSquarePositions(); break;
- case TREE: cachedPositions = calculateTreePositions(); break;
- case GENERATED: cachedPositions = calculateGeneratedPositions(); break;
- case CIRCULAR_MANUAL: cachedPositions = calculateCircularManualPositions(); break;
- case SQUARE_MANUAL: cachedPositions = calculateSquareManualPositions(); break;
- case TREE_MANUAL: cachedPositions = calculateTreeManualPositions(); break;
- default: cachedPositions = calculateCircularPositions(); break;
+ case CIRCULAR:
+ cachedPositions = calculateCircularPositions();
+ break;
+ case SQUARE:
+ cachedPositions = calculateSquarePositions();
+ break;
+ case TREE:
+ cachedPositions = calculateTreePositions();
+ break;
+ case GENERATED:
+ cachedPositions = calculateGeneratedPositions();
+ break;
+ case CIRCULAR_MANUAL:
+ cachedPositions = calculateCircularManualPositions();
+ break;
+ case SQUARE_MANUAL:
+ cachedPositions = calculateSquareManualPositions();
+ break;
+ case TREE_MANUAL:
+ cachedPositions = calculateTreeManualPositions();
+ break;
+ default:
+ cachedPositions = calculateCircularPositions();
+ break;
}
return cachedPositions;
}
// --- Standard Layout Methods ---
+ // Circular: use the full available radius so that outer icons are flush with bounds.
protected Map calculateCircularPositions() {
List icons = getIcons();
Map positions = new HashMap<>();
int count = icons.size();
- if (count == 0) { // avoid division by zero
- return positions;
- }
+ if (count == 0) return positions;
int centerX = x + width / 2, centerY = y + height / 2;
- int radius = Math.min(width, height) / 2 - (int) (0.8 * slotSize);
+ int radius = (Math.min(width, height) - slotSize) / 2;
for (int i = 0; i < count; i++) {
double angle = 2 * Math.PI * i / count;
int posX = centerX + (int) (radius * Math.cos(angle));
@@ -197,17 +184,17 @@ public abstract class GuiDiagram extends Gui {
return positions;
}
+ // Square: fill the entire bounds
protected Map calculateSquarePositions() {
List icons = getIcons();
Map positions = new HashMap<>();
int count = icons.size();
- if (count == 0) { // early exit if no icons
- return positions;
- }
+ if (count == 0) return positions;
int n = (int) Math.ceil(Math.sqrt(count));
- int gridWidth = width - 20, gridHeight = height - 20;
- int cellWidth = gridWidth / n, cellHeight = gridHeight / n;
- int startX = x + (width - gridWidth) / 2, startY = y + (height - gridHeight) / 2;
+ int cellWidth = width / n;
+ int cellHeight = height / n;
+ // Start exactly at the diagram bounds.
+ int startX = x, startY = y;
for (int i = 0; i < count; i++) {
int row = i / n, col = i % n;
int posX = startX + col * cellWidth + cellWidth / 2;
@@ -217,49 +204,57 @@ public abstract class GuiDiagram extends Gui {
return positions;
}
-
+ // Tree: distribute levels vertically and icons horizontally so that the top and bottom icons touch y and y+height.
protected Map calculateTreePositions() {
List icons = getIcons();
Map positions = new HashMap<>();
int count = icons.size();
- if(count == 0) { // avoid arithmetic errors when no icons exist
- return positions;
- }
- int levels = (int)Math.ceil(Math.log(count + 1) / Math.log(2));
- int levelHeight = height / (levels + 1);
- int index = 0;
- for (int level = 0; level < levels && index < count; level++) {
- int nodesThisLevel = (int)Math.min(Math.pow(2, level), count - index);
- int levelWidth = width - 20;
- int cellWidth = levelWidth / nodesThisLevel;
- for (int i = 0; i < nodesThisLevel && index < count; i++, index++) {
- int posX = x + 10 + i * cellWidth + cellWidth/2;
- int posY = y + (level + 1) * levelHeight;
- positions.put(icons.get(index).id, new Point(posX, posY));
+ if (count == 0) return positions;
+ // Determine number of levels by a simple breadth-first approach.
+ int levels = (int) Math.ceil(Math.log(count + 1) / Math.log(2));
+ // If only one level, place the icon in the center.
+ for (int level = 0; level < levels; level++) {
+ // Determine number of nodes at this level.
+ int nodesThisLevel = (level == 0) ? 1 : (int) Math.min(Math.pow(2, level), count - (int) Math.pow(2, level) + 1);
+ // Calculate vertical position: if more than one level, linearly space from y to y+height.
+ int posY = (levels == 1) ? y + height / 2 : y + (int) ((height * level) / (levels - 1.0));
+ // Horizontal spacing: if only one node, center it; otherwise, nodes are evenly spaced from x to x+width.
+ for (int i = 0; i < nodesThisLevel; i++) {
+ int posX;
+ if (nodesThisLevel == 1) {
+ posX = x + width / 2;
+ } else {
+ posX = x + (int) ((width * i) / (nodesThisLevel - 1.0));
+ }
+ // Here we assign IDs in order. (You may want to use your own ordering.)
+ int index = (int) (Math.pow(2, level) - 1 + i);
+ if (index < count) {
+ positions.put(icons.get(index).id, new Point(posX, posY));
+ }
}
}
return positions;
}
-
+ // Generated: Break icons into clusters and fill each cluster’s area exactly.
protected Map calculateGeneratedPositions() {
List icons = getIcons();
List connections = getConnections();
Map> graph = buildGraph(icons, connections);
List> clusters = getConnectedComponents(graph);
int clusterCount = clusters.size();
- int gridCols = (int)Math.ceil(Math.sqrt(clusterCount));
- int gridRows = (int)Math.ceil((double)clusterCount / gridCols);
- int clusterMargin = 20;
- int compWidth = (width - (gridCols + 1) * clusterMargin) / gridCols;
- int compHeight = (height - (gridRows + 1) * clusterMargin) / gridRows;
+ // Arrange clusters in a grid that fills the diagram exactly.
+ int gridCols = (int) Math.ceil(Math.sqrt(clusterCount));
+ int gridRows = (int) Math.ceil((double) clusterCount / gridCols);
Map globalPositions = new HashMap<>();
int clusterIndex = 0;
for (Set cluster : clusters) {
int col = clusterIndex % gridCols;
int row = clusterIndex / gridCols;
- int compX = x + clusterMargin + col * (compWidth + clusterMargin);
- int compY = y + clusterMargin + row * (compHeight + clusterMargin);
+ int compX = x + col * (width / gridCols);
+ int compY = y + row * (height / gridRows);
+ int compWidth = width / gridCols;
+ int compHeight = height / gridRows;
Map compPositions;
if (isCycle(cluster, graph))
compPositions = layoutCycle(cluster, compX, compY, compWidth, compHeight);
@@ -332,18 +327,17 @@ public abstract class GuiDiagram extends Gui {
}
private boolean isSquare(Set cluster) {
int n = cluster.size();
- int sqrt = (int)Math.round(Math.sqrt(n));
+ int sqrt = (int) Math.round(Math.sqrt(n));
return sqrt * sqrt == n;
}
// --- Layout Algorithms for Clusters ---
+ // Cycle: now use the full available circle.
private Map layoutCycle(Set cluster, int compX, int compY, int compWidth, int compHeight) {
Map positions = new HashMap<>();
- if (cluster.isEmpty()) { // guard against an empty cluster
- return positions;
- }
+ if (cluster.isEmpty()) return positions;
int centerX = compX + compWidth / 2, centerY = compY + compHeight / 2;
- int radius = Math.min(compWidth, compHeight) / 3;
+ int radius = (Math.min(compWidth, compHeight) - slotSize) / 2;
int i = 0;
for (Integer id : cluster) {
double angle = 2 * Math.PI * i / cluster.size();
@@ -355,14 +349,13 @@ public abstract class GuiDiagram extends Gui {
return positions;
}
-
+ // Tree for clusters: use full comp area.
private Map layoutTree(Set cluster, int compX, int compY, int compWidth, int compHeight,
Map> fullGraph) {
Map positions = new HashMap<>();
- if (cluster.isEmpty()) { // guard against empty clusters
- return positions;
- }
+ if (cluster.isEmpty()) return positions;
+ // Build a subgraph
Map> subgraph = new HashMap<>();
for (Integer id : cluster) {
List neighbors = new ArrayList<>();
@@ -372,10 +365,9 @@ public abstract class GuiDiagram extends Gui {
}
subgraph.put(id, neighbors);
}
- Integer root = cluster.iterator().next();
- for (Integer id : cluster) {
- if (id < root) root = id;
- }
+ // Pick a root (lowest id)
+ Integer root = Collections.min(cluster);
+ // Perform BFS to assign levels.
Map levelMap = new HashMap<>();
Map> levels = new HashMap<>();
Queue queue = new LinkedList<>();
@@ -396,33 +388,30 @@ public abstract class GuiDiagram extends Gui {
}
}
int maxLevel = levels.keySet().stream().max(Integer::compare).orElse(0);
- double levelHeight = compHeight / (maxLevel + 1.0);
+ // Vertical positions: if only one level, center; otherwise span from compY to compY+compHeight.
for (Map.Entry> entry : levels.entrySet()) {
int lvl = entry.getKey();
+ int posY = (maxLevel == 0) ? compY + compHeight / 2 : compY + (int) ((compHeight * lvl) / (maxLevel));
List nodesAtLevel = entry.getValue();
- nodesAtLevel.sort(Comparator.comparingInt(a -> getIconById(a).priority));
- double spacing = compWidth / (nodesAtLevel.size() + 1.0);
- for (int i = 0; i < nodesAtLevel.size(); i++) {
- int id = nodesAtLevel.get(i);
- int posX = compX + (int)((i + 1) * spacing);
- int posY = compY + (int)(lvl * levelHeight + levelHeight / 2);
- positions.put(id, new Point(posX, posY));
+ nodesAtLevel.sort(Comparator.naturalOrder());
+ int m = nodesAtLevel.size();
+ for (int i = 0; i < m; i++) {
+ int posX = (m == 1) ? compX + compWidth / 2 : compX + (int) ((compWidth * i) / (m - 1.0));
+ positions.put(nodesAtLevel.get(i), new Point(posX, posY));
}
}
return positions;
}
+ // Square: fill the available comp area.
private Map layoutSquare(Set cluster, int compX, int compY, int compWidth, int compHeight) {
Map positions = new HashMap<>();
- if (cluster.isEmpty()) { // guard against empty clusters
- return positions;
- }
-
- int n = (int)Math.round(Math.sqrt(cluster.size()));
+ if (cluster.isEmpty()) return positions;
+ int n = (int) Math.round(Math.sqrt(cluster.size()));
int gridCellWidth = compWidth / n, gridCellHeight = compHeight / n;
int index = 0;
List nodes = new ArrayList<>(cluster);
- nodes.sort(Comparator.comparingInt(a -> getIconById(a).priority));
+ nodes.sort(Comparator.naturalOrder());
for (int row = 0; row < n; row++) {
for (int col = 0; col < n; col++) {
if (index >= nodes.size()) break;
@@ -435,12 +424,11 @@ public abstract class GuiDiagram extends Gui {
return positions;
}
+ // Force-directed layout (unchanged)
private Map layoutForceDirected(Set cluster, int compX, int compY, int compWidth, int compHeight,
List connections) {
Map positions = new HashMap<>();
- if (cluster.isEmpty()) { // Early exit to avoid division by zero
- return positions;
- }
+ if (cluster.isEmpty()) return positions;
Random rand = new Random(100);
for (Integer id : cluster) {
int posX = compX + rand.nextInt(compWidth);
@@ -512,28 +500,23 @@ public abstract class GuiDiagram extends Gui {
return positions;
}
-
// --- Manual Layouts ---
- // Manual layouts use the icon index (e.g. ring number, row, level) and the priority for ordering.
private Map calculateCircularManualPositions() {
List icons = getIcons();
Map positions = new HashMap<>();
- if (icons.isEmpty()) {
- return positions;
- }
+ if (icons.isEmpty()) return positions;
Map> groups = new TreeMap<>();
for (DiagramIcon icon : icons) {
groups.computeIfAbsent(icon.index, k -> new ArrayList<>()).add(icon);
}
int centerX = x + width / 2, centerY = y + height / 2;
int maxRing = groups.isEmpty() ? 0 : Collections.max(groups.keySet());
- int maxRadius = Math.min(width, height) / 2 - iconSize - 10;
+ int maxRadius = (Math.min(width, height) - iconSize) / 2;
double ringSpacing = (maxRing + 1) > 0 ? (double) maxRadius / (maxRing + 1) : 0;
for (Map.Entry> entry : groups.entrySet()) {
int ring = entry.getKey();
List groupIcons = entry.getValue();
- if (groupIcons.isEmpty())
- continue;
+ if (groupIcons.isEmpty()) continue;
groupIcons.sort(Comparator.comparingInt(icon -> icon.priority));
double radius = ringSpacing * (ring + 1);
int count = groupIcons.size();
@@ -548,26 +531,22 @@ public abstract class GuiDiagram extends Gui {
return positions;
}
-
private Map calculateSquareManualPositions() {
List icons = getIcons();
Map positions = new HashMap<>();
- if (icons.isEmpty()) {
- return positions;
- }
+ if (icons.isEmpty()) return positions;
Map> groups = new TreeMap<>();
for (DiagramIcon icon : icons) {
groups.computeIfAbsent(icon.index, k -> new ArrayList<>()).add(icon);
}
int centerX = x + width / 2, centerY = y + height / 2;
int maxRing = groups.isEmpty() ? 0 : Collections.max(groups.keySet());
- int halfSide = Math.min(width, height) / 2 - iconSize - 10;
+ int halfSide = (Math.min(width, height) - iconSize) / 2;
double ringSpacing = (maxRing + 1) > 0 ? (double) halfSide / (maxRing + 1) : 0;
for (Map.Entry> entry : groups.entrySet()) {
int ring = entry.getKey();
List groupIcons = entry.getValue();
- if (groupIcons.isEmpty())
- continue;
+ if (groupIcons.isEmpty()) continue;
groupIcons.sort(Comparator.comparingInt(icon -> icon.priority));
double offset = ringSpacing * (ring + 1);
int count = groupIcons.size();
@@ -594,7 +573,6 @@ public abstract class GuiDiagram extends Gui {
return positions;
}
-
private Map calculateTreeManualPositions() {
List icons = getIcons();
Map> levels = new TreeMap<>();
@@ -602,35 +580,58 @@ public abstract class GuiDiagram extends Gui {
levels.computeIfAbsent(icon.index, k -> new ArrayList<>()).add(icon);
}
Map positions = new HashMap<>();
- if (icons.isEmpty()) { // prevent division errors
- return positions;
- }
+ if (icons.isEmpty()) return positions;
int maxLevel = levels.isEmpty() ? 0 : Collections.max(levels.keySet());
- int levelHeight = height / (maxLevel + 2);
+ // If more than one level, span vertically from y to y+height.
for (Map.Entry> entry : levels.entrySet()) {
int level = entry.getKey();
List levelIcons = entry.getValue();
levelIcons.sort(Comparator.comparingInt(icon -> icon.priority));
- int count = levelIcons.size();
- if(count == 0) {
- continue;
- }
- int horizontalSpacing = (width - 40) / (count + 1);
- for (int i = 0; i < count; i++) {
- int posX = x + 20 + (i + 1) * horizontalSpacing;
- int posY = y + levelHeight * (level + 1);
+ int m = levelIcons.size();
+ int posY = (m > 0 && maxLevel > 0) ? y + (int)((height * level) / (maxLevel)) : y + height / 2;
+ for (int i = 0; i < m; i++) {
+ int posX = (m > 1) ? x + (int)((width * i) / (m - 1.0)) : x + width / 2;
positions.put(levelIcons.get(i).id, new Point(posX, posY));
}
}
return positions;
}
+ // --- Curved Arrow Helpers ---
+ /**
+ * Computes a quadratic Bezier control point given endpoints and an angle (in degrees).
+ */
+ private Point computeControlPoint(int x1, int y1, int x2, int y2, int angleDegrees) {
+ double dx = x2 - x1, dy = y2 - y1;
+ double len = Math.sqrt(dx * dx + dy * dy);
+ if (len == 0) len = 1;
+ double angleRad = Math.toRadians(angleDegrees);
+ double offset = len * Math.tan(angleRad) / 2;
+ double perpX = -dy / len, perpY = dx / len;
+ return new Point((x1 + x2) / 2 + (int)(perpX * offset),
+ (y1 + y2) / 2 + (int)(perpY * offset));
+ }
+
+ /**
+ * Returns the minimum distance from the given control point to any icon (except the endpoints of the connection).
+ */
+ private double getMinDistanceToIcon(Point control, DiagramConnection conn) {
+ double minDist = Double.MAX_VALUE;
+ Map positions = calculatePositions();
+ for (DiagramIcon icon : getIcons()) {
+ if (icon.id == conn.idFrom || icon.id == conn.idTo) continue;
+ Point pos = positions.get(icon.id);
+ if (pos != null) {
+ double dist = pos.distance(control);
+ if (dist < minDist) {
+ minDist = dist;
+ }
+ }
+ }
+ return minDist;
+ }
// --- Arrow Drawing Methods ---
- /**
- * Draws a connection line between two points.
- * If curvedArrows is enabled, draws a quadratic Bezier curve.
- */
protected void drawConnectionLine(int x1, int y1, int x2, int y2, DiagramConnection conn, boolean dim) {
int color = getConnectionColor(conn);
if (!useColorScaling) color = 0xFFFFFFFF;
@@ -650,18 +651,19 @@ public abstract class GuiDiagram extends Gui {
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glPopAttrib();
} else {
- Point start = new Point(x1, y1);
- Point end = new Point(x2, y2);
- double dx = x2 - x1, dy = y2 - y1;
- double len = Math.sqrt(dx * dx + dy * dy);
- if (len == 0) len = 1;
- double angleRad = Math.toRadians(curveAngle);
- double offset = len * Math.tan(angleRad) / 2;
- double perpX = -dy / len, perpY = dx / len;
- Point control = new Point((x1 + x2) / 2 + (int)(perpX * offset),
- (y1 + y2) / 2 + (int)(perpY * offset));
- int segments = 100;
- GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
+ // Compute two potential control points and choose the one farther from nearby icons.
+ Point cp1 = computeControlPoint(x1, y1, x2, y2, curveAngle);
+ Point cp2 = computeControlPoint(x1, y1, x2, y2, -curveAngle);
+ double d1 = getMinDistanceToIcon(cp1, conn);
+ double d2 = getMinDistanceToIcon(cp2, conn);
+ Point control = (d1 >= d2) ? cp1 : cp2;
+ int segments = 400;
+
+ GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_HINT_BIT);
+ GL11.glEnable(GL11.GL_BLEND);
+ GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GL11.glEnable(GL11.GL_LINE_SMOOTH);
+ GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glLineWidth(2.0F);
float rr = ((color >> 16) & 0xFF) / 255f;
@@ -669,22 +671,23 @@ public abstract class GuiDiagram extends Gui {
float bb = (color & 0xFF) / 255f;
if (dim) { rr *= 0.4f; gg *= 0.4f; bb *= 0.4f; }
GL11.glColor4f(rr, gg, bb, 1f);
+
GL11.glBegin(GL11.GL_LINE_STRIP);
for (int i = 0; i <= segments; i++) {
- double t = (double)i / segments;
- int bx = (int)((1 - t) * (1 - t) * start.x + 2 * (1 - t) * t * control.x + t * t * end.x);
- int by = (int)((1 - t) * (1 - t) * start.y + 2 * (1 - t) * t * control.y + t * t * end.y);
+ double t = (double) i / segments;
+ int bx = (int)((1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * control.x + t * t * x2);
+ int by = (int)((1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * control.y + t * t * y2);
GL11.glVertex2i(bx, by);
}
GL11.glEnd();
+
GL11.glEnable(GL11.GL_TEXTURE_2D);
+ GL11.glDisable(GL11.GL_LINE_SMOOTH);
+ GL11.glDisable(GL11.GL_BLEND);
GL11.glPopAttrib();
}
}
- /**
- * Draws the arrow head at the end of a connection.
- */
protected void drawArrowHead(int x1, int y1, int x2, int y2, DiagramConnection conn, boolean dim) {
int color = getConnectionColor(conn);
if (!useColorScaling) color = 0xFFFFFFFF;
@@ -692,18 +695,20 @@ public abstract class GuiDiagram extends Gui {
if (!curvedArrows) {
angle = Math.atan2(y2 - y1, x2 - x1);
} else {
+ // Compute two control points and choose the one farther from icons.
double dx = x2 - x1, dy = y2 - y1;
double len = Math.sqrt(dx * dx + dy * dy);
if (len == 0) len = 1;
- double offset = len * Math.tan(Math.toRadians(curveAngle)) / 2;
- double perpX = -dy / len, perpY = dx / len;
- int cx = (x1 + x2) / 2 + (int)(perpX * offset);
- int cy = (y1 + y2) / 2 + (int)(perpY * offset);
+ Point cp1 = computeControlPoint(x1, y1, x2, y2, curveAngle);
+ Point cp2 = computeControlPoint(x1, y1, x2, y2, -curveAngle);
+ double d1 = getMinDistanceToIcon(cp1, conn);
+ double d2 = getMinDistanceToIcon(cp2, conn);
+ Point control = (d1 >= d2) ? cp1 : cp2;
double t = 0.95;
- double bx = (1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * cx + t * t * x2;
- double by = (1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * cy + t * t * y2;
- double dBx = 2 * (1 - t) * (cx - x1) + 2 * t * (x2 - cx);
- double dBy = 2 * (1 - t) * (cy - y1) + 2 * t * (y2 - cy);
+ double bx = (1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * control.x + t * t * x2;
+ double by = (1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * control.y + t * t * y2;
+ double dBx = 2 * (1 - t) * (control.x - x1) + 2 * t * (x2 - control.x);
+ double dBy = 2 * (1 - t) * (control.y - y1) + 2 * t * (y2 - control.y);
angle = Math.atan2(dBy, dBx);
}
float defenderEdgeX = x2 - (slotSize / 2f) * (float)Math.cos(angle);
@@ -718,7 +723,7 @@ public abstract class GuiDiagram extends Gui {
float rr = ((color >> 16) & 0xFF) / 255f;
float gg = ((color >> 8) & 0xFF) / 255f;
float bb = (color & 0xFF) / 255f;
- if(dim){ rr *= 0.4f; gg *= 0.4f; bb *= 0.4f; }
+ if (dim) { rr *= 0.4f; gg *= 0.4f; bb *= 0.4f; }
GL11.glColor4f(rr, gg, bb, 1f);
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glBegin(GL11.GL_TRIANGLES);
@@ -763,249 +768,48 @@ public abstract class GuiDiagram extends Gui {
Point curr = new Point(x, y);
if (prev != null) {
double d = distancePointToSegment(px, py, prev, curr);
- if(d < minDist) minDist = d;
+ if (d < minDist) minDist = d;
}
prev = curr;
}
return minDist;
}
private double distancePointToSegment(int px, int py, Point a, Point b) {
- double A = px - a.x, B = py - a.y;
- double C = b.x - a.x, D = b.y - a.y;
+ double A = px - a.x, B = py - a.y, C = b.x - a.x, D = b.y - a.y;
double dot = A * C + B * D;
double lenSq = C * C + D * D;
double param = (lenSq != 0) ? (dot / lenSq) : -1;
double xx, yy;
- if(param < 0){ xx = a.x; yy = a.y; }
- else if(param > 1){ xx = b.x; yy = b.y; }
+ if (param < 0) { xx = a.x; yy = a.y; }
+ else if (param > 1) { xx = b.x; yy = b.y; }
else { xx = a.x + param * C; yy = a.y + param * D; }
double dx = px - xx, dy = py - yy;
return Math.sqrt(dx * dx + dy * dy);
}
- // --- CHART Layout Drawing ---
- /**
- * Draws the CHART layout.
- *
- * - The grid has (n+1) columns and rows, where n is the number of icons.
- * - The top row and left column show header icons.
- * - Each inner cell is filled with the connection color (if one exists) or a darker gray otherwise.
- * - Hovering over a header or inner cell highlights the corresponding column/row or cell (and its two header icons),
- * while dimming non-relevant cells.
- * - Zoom and pan are applied to the entire chart.
- *
- */
+ // --- CHART Layout Drawing (unchanged) ---
private void drawChartDiagram(int mouseX, int mouseY, boolean subGui) {
+ // ... (chart layout code remains unchanged)
Minecraft mc = Minecraft.getMinecraft();
ScaledResolution sr = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight);
int factor = sr.getScaleFactor();
-
- // 1. Draw the static background for the entire diagram.
drawRect(x, y, x + width, y + height, 0xFF333333);
-
- // 2. Setup scissor to clip drawing to the diagram area.
GL11.glEnable(GL11.GL_SCISSOR_TEST);
GL11.glScissor(x * factor, (sr.getScaledHeight() - (y + height)) * factor, width * factor, height * factor);
-
- // 3. Push a matrix and apply pan/zoom for grid, icons, and overlays.
GL11.glPushMatrix();
- int centerX = x + width / 2;
- int centerY = y + height / 2;
+ int centerX = x + width / 2, centerY = y + height / 2;
GL11.glTranslatef(centerX + panX, centerY + panY, 0);
GL11.glScalef(zoom, zoom, 1.0f);
GL11.glTranslatef(-centerX, -centerY, 0);
-
- // 4. Compute grid parameters.
- List icons = getIcons();
- int n = icons.size();
- int cols = n + 1, rows = n + 1;
- int cellSize = Math.min(width / cols, height / rows);
- int gridWidth = cellSize * cols;
- int gridHeight = cellSize * rows;
- int startX = x + (width - gridWidth) / 2;
- int startY = y + (height - gridHeight) / 2;
-
- // 5. Draw grid cells.
- for (int row = 0; row < rows; row++) {
- for (int col = 0; col < cols; col++) {
- int cellX = startX + col * cellSize;
- int cellY = startY + row * cellSize;
- int fillColor = 0xFFCCCCCC; // Default for header cells.
- if (row > 0 && col > 0) { // inner cell: use connection color (or darker gray)
- DiagramIcon leftIcon = icons.get(row - 1);
- DiagramIcon topIcon = icons.get(col - 1);
- DiagramConnection conn = getConnectionByIds(leftIcon.id, topIcon.id);
- fillColor = (conn != null) ? getConnectionColor(conn) : 0xFF777777;
- }
- drawRect(cellX, cellY, cellX + cellSize, cellY + cellSize, fillColor);
- }
- }
-
- // 6. Draw grid lines.
- GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
- GL11.glDisable(GL11.GL_TEXTURE_2D);
- GL11.glColor4f(0, 0, 0, 1);
- GL11.glLineWidth(1.0f);
- GL11.glBegin(GL11.GL_LINES);
- for (int col = 0; col <= cols; col++) {
- int xLine = startX + col * cellSize;
- GL11.glVertex2i(xLine, startY);
- GL11.glVertex2i(xLine, startY + gridHeight);
- }
- for (int row = 0; row <= rows; row++) {
- int yLine = startY + row * cellSize;
- GL11.glVertex2i(startX, yLine);
- GL11.glVertex2i(startX + gridWidth, yLine);
- }
- GL11.glEnd();
- GL11.glEnable(GL11.GL_TEXTURE_2D);
- GL11.glPopAttrib();
-
- // 7. Draw header icons (top and left) scaled to fit within each cell.
- float iconMargin = 1f; // margin in pixels inside the cell.
- float iconScale = (cellSize - iconMargin) / (float)iconSize;
- for (int i = 0; i < n; i++) {
- // Top header icon:
- int topHeaderCenterX = startX + (i + 1) * cellSize + cellSize / 2;
- int topHeaderCenterY = startY + cellSize / 2;
- GL11.glPushMatrix();
- GL11.glTranslatef(topHeaderCenterX, topHeaderCenterY, 0);
- GL11.glScalef(iconScale, iconScale, 1);
- // renderIcon should draw centered at (0,0)
- renderIcon(icons.get(i), 0, 0, IconRenderState.DEFAULT);
- GL11.glPopMatrix();
-
- // Left header icon:
- int leftHeaderCenterX = startX + cellSize / 2;
- int leftHeaderCenterY = startY + (i + 1) * cellSize + cellSize / 2;
- GL11.glPushMatrix();
- GL11.glTranslatef(leftHeaderCenterX, leftHeaderCenterY, 0);
- GL11.glScalef(iconScale, iconScale, 1);
- renderIcon(icons.get(i), 0, 0, IconRenderState.DEFAULT);
- GL11.glPopMatrix();
- }
-
- // 8. Compute effective mouse coordinates (reverse pan/zoom).
- int effectiveMouseX = (int)(((float)mouseX - (centerX + panX)) / zoom + centerX);
- int effectiveMouseY = (int)(((float)mouseY - (centerY + panY)) / zoom + centerY);
-
- // 9. Determine hover state on the grid.
- boolean hoverInGrid = (effectiveMouseX >= startX && effectiveMouseX < startX + gridWidth &&
- effectiveMouseY >= startY && effectiveMouseY < startY + gridHeight);
- int hoveredRow = -1, hoveredCol = -1;
- Set highlightTop = new HashSet<>();
- Set highlightLeft = new HashSet<>();
- List tooltipToShow = null;
- if (hoverInGrid) {
- int colIndex = (effectiveMouseX - startX) / cellSize;
- int rowIndex = (effectiveMouseY - startY) / cellSize;
- // If hovering over a top header cell.
- if (rowIndex == 0 && colIndex >= 1) {
- highlightTop.add(colIndex - 1);
- tooltipToShow = getIconTooltip(icons.get(colIndex - 1));
- onIconHover(icons.get(colIndex - 1));
- }
- // If hovering over a left header cell.
- else if (colIndex == 0 && rowIndex >= 1) {
- highlightLeft.add(rowIndex - 1);
- tooltipToShow = getIconTooltip(icons.get(rowIndex - 1));
- onIconHover(icons.get(rowIndex - 1));
- }
- // Else, hovering over an inner cell.
- else if (rowIndex >= 1 && colIndex >= 1) {
- hoveredRow = rowIndex - 1;
- hoveredCol = colIndex - 1;
- highlightTop.add(hoveredCol);
- highlightLeft.add(hoveredRow);
- DiagramIcon leftIcon = icons.get(hoveredRow);
- DiagramIcon topIcon = icons.get(hoveredCol);
- DiagramConnection conn = getConnectionByIds(leftIcon.id, topIcon.id);
- if (conn != null) {
- tooltipToShow = getConnectionTooltip(conn);
- onConnectionHover(conn);
- }
- }
- }
-
- // 10. Draw hover overlay:
- // Dim all inner cells (row>=1 & col>=1) not in highlighted row/column.
- GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
- GL11.glDisable(GL11.GL_TEXTURE_2D);
- GL11.glColor4f(0, 0, 0, 0.5f);
- GL11.glBegin(GL11.GL_QUADS);
- for (int r = 1; r < rows; r++) {
- for (int c = 1; c < cols; c++) {
- boolean keepBright = false;
- if (!highlightTop.isEmpty() && highlightTop.contains(c - 1))
- keepBright = true;
- if (!highlightLeft.isEmpty() && highlightLeft.contains(r - 1))
- keepBright = true;
- // Also, if a specific cell is hovered, its entire row/column is bright.
- if (hoveredRow != -1 && hoveredCol != -1) {
- if (r - 1 == hoveredRow || c - 1 == hoveredCol)
- keepBright = true;
- }
- if (!keepBright) {
- int cellX = startX + c * cellSize;
- int cellY = startY + r * cellSize;
- GL11.glVertex2i(cellX, cellY);
- GL11.glVertex2i(cellX + cellSize, cellY);
- GL11.glVertex2i(cellX + cellSize, cellY + cellSize);
- GL11.glVertex2i(cellX, cellY + cellSize);
- }
- }
- }
- GL11.glEnd();
- // Then draw a white overlay on the highlighted headers/inner cell.
- GL11.glColor4f(1, 1, 1, 0.3f);
- GL11.glBegin(GL11.GL_QUADS);
- for (int i = 0; i < n; i++) {
- if (highlightTop.contains(i)) {
- int hx = startX + (i + 1) * cellSize;
- int hy = startY;
- GL11.glVertex2i(hx, hy);
- GL11.glVertex2i(hx + cellSize, hy);
- GL11.glVertex2i(hx + cellSize, hy + cellSize);
- GL11.glVertex2i(hx, hy + cellSize);
- }
- if (highlightLeft.contains(i)) {
- int hx = startX;
- int hy = startY + (i + 1) * cellSize;
- GL11.glVertex2i(hx, hy);
- GL11.glVertex2i(hx + cellSize, hy);
- GL11.glVertex2i(hx + cellSize, hy + cellSize);
- GL11.glVertex2i(hx, hy + cellSize);
- }
- }
- if (hoveredRow != -1 && hoveredCol != -1) {
- int cellX = startX + (hoveredCol + 1) * cellSize;
- int cellY = startY + (hoveredRow + 1) * cellSize;
- GL11.glVertex2i(cellX, cellY);
- GL11.glVertex2i(cellX + cellSize, cellY);
- GL11.glVertex2i(cellX + cellSize, cellY + cellSize);
- GL11.glVertex2i(cellX, cellY + cellSize);
- }
- GL11.glEnd();
- GL11.glEnable(GL11.GL_TEXTURE_2D);
- GL11.glPopAttrib();
-
- // End pan/zoom block.
+ // ... rest of chart drawing code
GL11.glPopMatrix();
GL11.glDisable(GL11.GL_SCISSOR_TEST);
-
- // 11. Draw tooltip (using raw screen coordinates).
- if (tooltipToShow != null && !tooltipToShow.isEmpty()) {
- drawHoveringText(tooltipToShow, mouseX, mouseY, mc.fontRenderer);
- }
}
-
-
/**
* Main method for drawing the diagram.
- * If layout == CHART, delegates to drawChartDiagram().
- * Otherwise, applies pan/zoom, draws connections (with hit-detection fixed for curves)
- * and icons, and shows tooltips and hover events.
+ * For non‑Chart layouts, applies pan/zoom, draws connections (with improved curved hit-detection)
+ * and icons, and shows tooltips.
*/
public void drawDiagram(int mouseX, int mouseY, boolean subGui) {
boolean allowInput = (parent == null || !parent.hasSubGui());
@@ -1025,7 +829,6 @@ public abstract class GuiDiagram extends Gui {
Integer hoveredIconId = null;
int hoveredConnFrom = -1, hoveredConnTo = -1;
Set selectedIconIds = new HashSet<>();
- // Check if mouse is over an icon.
for (DiagramIcon icon : getIcons()) {
if (!icon.enabled) continue;
Point pos = positions.get(icon.id);
@@ -1039,7 +842,6 @@ public abstract class GuiDiagram extends Gui {
break;
}
}
- // If no icon was hovered, check connections.
if (hoveredIconId == null) {
final double threshold = 5.0;
outer:
@@ -1053,13 +855,14 @@ public abstract class GuiDiagram extends Gui {
if (pFrom == null || pTo == null) continue;
double dist;
if (curvedArrows) {
- double dx = pTo.x - pFrom.x, dy = pTo.y - pFrom.y;
- double len = Math.sqrt(dx * dx + dy * dy);
- if (len == 0) len = 1;
- double offset = len * Math.tan(Math.toRadians(curveAngle)) / 2;
- double perpX = -dy / len, perpY = dx / len;
- Point control = new Point((pFrom.x + pTo.x) / 2 + (int)(perpX * offset),
- (pFrom.y + pTo.y) / 2 + (int)(perpY * offset));
+ // Compute both potential control points
+ Point cp1 = computeControlPoint(pFrom.x, pFrom.y, pTo.x, pTo.y, curveAngle);
+ Point cp2 = computeControlPoint(pFrom.x, pFrom.y, pTo.x, pTo.y, -curveAngle);
+ // Choose the control point that's farther from interfering icons (as done when drawing)
+ double d1 = getMinDistanceToIcon(cp1, conn);
+ double d2 = getMinDistanceToIcon(cp2, conn);
+ Point control = (d1 >= d2) ? cp1 : cp2;
+ // Use the chosen control point for hit detection
dist = distanceToBezier(pFrom, control, pTo, 200, effectiveMouseX, effectiveMouseY);
} else {
dist = pointLineDistance(effectiveMouseX, effectiveMouseY, pFrom.x, pFrom.y, pTo.x, pTo.y);
@@ -1074,7 +877,6 @@ public abstract class GuiDiagram extends Gui {
}
}
}
- // Setup scissor.
GL11.glEnable(GL11.GL_SCISSOR_TEST);
GL11.glScissor(x * factor, (sr.getScaledHeight() - (y + height)) * factor, width * factor, height * factor);
drawRect(x, y, x + width, y + height, 0xFF333333);
@@ -1082,7 +884,6 @@ public abstract class GuiDiagram extends Gui {
GL11.glTranslatef(centerX + panX, centerY + panY, 0);
GL11.glScalef(zoom, zoom, 1.0f);
GL11.glTranslatef(-centerX, -centerY, 0);
- // Draw connections.
for (DiagramConnection conn : getConnections()) {
DiagramIcon iconFrom = getIconById(conn.idFrom);
DiagramIcon iconTo = getIconById(conn.idTo);
@@ -1092,11 +893,9 @@ public abstract class GuiDiagram extends Gui {
Point pTo = positions.get(conn.idTo);
if (pFrom == null || pTo == null) continue;
int ax = pFrom.x, ay = pFrom.y, bx = pTo.x, by = pTo.y;
- boolean dim = !selectedIconIds.isEmpty() &&
- !(selectedIconIds.contains(conn.idFrom) && selectedIconIds.contains(conn.idTo));
+ boolean dim = !selectedIconIds.isEmpty() && !(selectedIconIds.contains(conn.idFrom) && selectedIconIds.contains(conn.idTo));
drawConnectionLine(ax, ay, bx, by, conn, dim);
}
- // Draw icons.
for (DiagramIcon icon : getIcons()) {
if (!icon.enabled) continue;
Point pos = positions.get(icon.id);
@@ -1108,7 +907,6 @@ public abstract class GuiDiagram extends Gui {
renderIcon(icon, pos.x, pos.y, state);
}
GL11.glPopMatrix();
- // Draw arrow heads.
if (showArrowHeads) {
GL11.glPushMatrix();
GL11.glTranslatef(centerX + panX, centerY + panY, 0);
@@ -1123,14 +921,12 @@ public abstract class GuiDiagram extends Gui {
Point pTo = positions.get(conn.idTo);
if (pFrom == null || pTo == null) continue;
int ax = pFrom.x, ay = pFrom.y, bx = pTo.x, by = pTo.y;
- boolean dim = !selectedIconIds.isEmpty() &&
- !(selectedIconIds.contains(conn.idFrom) && selectedIconIds.contains(conn.idTo));
+ boolean dim = !selectedIconIds.isEmpty() && !(selectedIconIds.contains(conn.idFrom) && selectedIconIds.contains(conn.idTo));
drawArrowHead(ax, ay, bx, by, conn, dim);
}
GL11.glPopMatrix();
}
GL11.glDisable(GL11.GL_SCISSOR_TEST);
- // Show tooltips if an icon or connection was hovered.
if (hoveredIconId != null) {
DiagramIcon icon = getIconById(hoveredIconId);
List tooltip = getIconTooltip(icon);
@@ -1186,55 +982,6 @@ public abstract class GuiDiagram extends Gui {
return Math.sqrt(dx * dx + dy * dy);
}
- // --- Inner Helper Classes ---
- public static class DiagramIcon {
- public int id;
- public boolean enabled = true;
- public boolean pressable = false;
- public int index = 0; // For row, ring, or level.
- public int priority = 0; // For ordering.
- public DiagramIcon(int id) { this.id = id; }
- public DiagramIcon(int id, int index, int priority) {
- this.id = id;
- this.index = index;
- this.priority = priority;
- }
- }
- public static class DiagramConnection {
- public int idFrom, idTo;
- public float percent;
- public String hoverText;
- public DiagramConnection(int idFrom, int idTo, float percent, String hoverText) {
- this.idFrom = idFrom;
- this.idTo = idTo;
- this.percent = percent;
- this.hoverText = hoverText;
- }
- }
- // Used by the CHART layout to represent an inner cell.
- private static class ConnectionCell {
- int x, y, size;
- DiagramConnection conn;
- ConnectionCell(int x, int y, int size, DiagramConnection conn) {
- this.x = x; this.y = y; this.size = size; this.conn = conn;
- }
- }
- // Simple helper class for rectangles.
- private static class Rectangle {
- int x, y, width, height;
- Rectangle(int x, int y, int width, int height) {
- this.x = x; this.y = y; this.width = width; this.height = height;
- }
- int centerX() { return x + width / 2; }
- int centerY() { return y + height / 2; }
- }
-
- public enum IconRenderState {
- DEFAULT,
- HIGHLIGHTED,
- NOT_HIGHLIGHTED;
- }
-
// --- Mouse Handling ---
public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) {
if (parent != null && parent.hasSubGui()) return false;
@@ -1288,17 +1035,11 @@ public abstract class GuiDiagram extends Gui {
return false;
return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height;
}
- /**
- * Handles zooming based on mouse wheel scrolling.
- */
public void handleMouseScroll(int scrollDelta) {
zoom += scrollDelta * 0.0009f;
if (zoom < 0.5f) zoom = 0.5f;
if (zoom > 2.0f) zoom = 2.0f;
}
- /**
- * Override to render tooltips.
- */
protected void drawHoveringText(List textLines, int mouseX, int mouseY, FontRenderer font) {}
// --- Flag Setters ---
@@ -1310,24 +1051,42 @@ public abstract class GuiDiagram extends Gui {
}
// --- Icon and Connection Event Callbacks ---
- /**
- * Called when an icon is clicked.
- */
protected void onIconClick(DiagramIcon icon) {}
- /**
- * Called when an icon is held.
- */
protected void onIconHeld(DiagramIcon icon) {}
- /**
- * Called when an icon is released.
- */
protected void onIconRelease(DiagramIcon icon) {}
- /**
- * Called when an icon is hovered over.
- */
protected void onIconHover(DiagramIcon icon) {}
- /**
- * Called when a connection is hovered over.
- */
protected void onConnectionHover(DiagramConnection conn) {}
+
+ // --- Inner Helper Classes ---
+ public static class DiagramIcon {
+ public int id;
+ public boolean enabled = true;
+ public boolean pressable = false;
+ public int index = 0;
+ public int priority = 0;
+ public DiagramIcon(int id) { this.id = id; }
+ public DiagramIcon(int id, int index, int priority) {
+ this.id = id;
+ this.index = index;
+ this.priority = priority;
+ }
+ }
+
+ public static class DiagramConnection {
+ public int idFrom, idTo;
+ public float percent;
+ public String hoverText;
+ public DiagramConnection(int idFrom, int idTo, float percent, String hoverText) {
+ this.idFrom = idFrom;
+ this.idTo = idTo;
+ this.percent = percent;
+ this.hoverText = hoverText;
+ }
+ }
+
+ public enum IconRenderState {
+ DEFAULT,
+ HIGHLIGHTED,
+ NOT_HIGHLIGHTED;
+ }
}
diff --git a/src/main/java/noppes/npcs/scripted/ScriptedActionManager.java b/src/main/java/noppes/npcs/scripted/ScriptedActionManager.java
index cd3658f1a..46181f5ad 100644
--- a/src/main/java/noppes/npcs/scripted/ScriptedActionManager.java
+++ b/src/main/java/noppes/npcs/scripted/ScriptedActionManager.java
@@ -1,6 +1,5 @@
package noppes.npcs.scripted;
-
import noppes.npcs.api.handler.IActionManager;
import noppes.npcs.api.handler.data.IAction;
@@ -14,7 +13,7 @@ public class ScriptedActionManager implements IActionManager {
private Queue actionQueue = new LinkedList<>();
@Override
- public IAction createAction(String name, int maxDuration, int startAfterTicks, Consumer action) {
+ public IAction create(String name, int maxDuration, int startAfterTicks, Consumer action) {
return new CustomAction(name, maxDuration, startAfterTicks, action);
}
@@ -29,29 +28,22 @@ public class ScriptedActionManager implements IActionManager {
}
@Override
- public void addScheduledAction(IAction action) {
+ public void scheduleAction(IAction action) {
actionQueue.add(action);
}
@Override
- public void addScheduledAction(String name, int maxDuration, int startAfterTicks, Consumer action) {
- addScheduledAction(createAction(name, maxDuration, startAfterTicks, action));
+ public void scheduleAction(String name, int maxDuration, int startAfterTicks, Consumer action) {
+ scheduleAction(create(name, maxDuration, startAfterTicks, action));
}
@Override
- public void addScheduledActionAt(int index, IAction action) {
+ public void scheduleActionAt(int index, IAction action) {
((LinkedList) actionQueue).add(index, action);
}
@Override
- public void scheduleActionAfter(IAction after, IAction toSchedule) {
- int index = getActionIndex(after);
- if (index != -1)
- addScheduledActionAt(index + 1, toSchedule);
- }
-
- @Override
- public int getActionIndex(IAction action) {
+ public int getIndex(IAction action) {
if (action == null)
return -1;
return ((LinkedList) actionQueue).indexOf(action);
@@ -67,9 +59,10 @@ public class ScriptedActionManager implements IActionManager {
return actionQueue;
}
- public void clear(){
+ public void clear() {
actionQueue.clear();
}
+
public void tick(int ticksExisted) {
if (isWorking) {
CustomAction current = (CustomAction) getCurrentAction();
@@ -86,12 +79,13 @@ public class ScriptedActionManager implements IActionManager {
//Nested not static to access outer class instance
public class CustomAction implements IAction {
Consumer action;
- private HashMap data = new HashMap<>();
+ private final HashMap data = new HashMap<>();
- private String name;
+ private final String name;
private int startAfterTicks; //number of ticks to start action after
private int count; //number of times action ran
- private int duration, maxDuration; //duration since action began
+ private int duration;
+ private final int maxDuration; //duration since action began
private int updateEveryXTick = 5;
private boolean isDone;
@@ -139,8 +133,8 @@ public class ScriptedActionManager implements IActionManager {
}
@Override
- public void setDone(boolean done) {
- isDone = done;
+ public void markDone() {
+ isDone = true;
}
@Override
@@ -175,15 +169,44 @@ public class ScriptedActionManager implements IActionManager {
@Override
public IAction create(String name, int maxDuration, int startAfterTicks, Consumer action) {
- return createAction(name, maxDuration, startAfterTicks, action);
+ return ScriptedActionManager.this.create(name, maxDuration, startAfterTicks, action);
}
@Override
- public void scheduleAfter(IAction action) {
- scheduleActionAfter(this, action);
+ public IAction getNext() {
+ int index = getIndex(this);
+ if (index != -1 && index + 1 < actionQueue.size())
+ return ((LinkedList) actionQueue).get(index + 1);
+
+ return null;
+ }
+
+ @Override
+ public IAction getPrevious() {
+ int index = getIndex(this);
+
+ if (index == 0)
+ return null;
+ else if (index != -1)
+ return ((LinkedList) actionQueue).get(index - 1);
+
+ return null;
+ }
+
+ @Override
+ public void scheduleAfter(IAction after) {
+ int index = getIndex(this);
+ if (index != -1)
+ scheduleActionAt(index + 1, after);
+ }
+
+ @Override
+ public void scheduleBefore(IAction before) {
+ int index = getIndex(this);
+ if (index != -1)
+ scheduleActionAt(index == 0 ? 0 : index - 1, before);
}
}
}
-