diff --git a/src/main/java/workspace/render/ColorGenerator.java b/src/main/java/workspace/render/ColorGenerator.java index 7a742e98..dae613d8 100644 --- a/src/main/java/workspace/render/ColorGenerator.java +++ b/src/main/java/workspace/render/ColorGenerator.java @@ -4,13 +4,12 @@ public class ColorGenerator { - private int i = 0; - - public Color next() { - i++; - java.awt.Color c = new java.awt.Color(i); - Color c1 = Color.getColorFromInt(c.getRed(), c.getGreen(), c.getBlue()); - return c1; - } - + private int i = 0; + + public Color next() { + i++; + java.awt.Color c = new java.awt.Color(i); + Color c1 = Color.getColorFromInt(c.getRed(), c.getGreen(), c.getBlue()); + return c1; + } } diff --git a/src/main/java/workspace/render/Mesh3DRenderer.java b/src/main/java/workspace/render/Mesh3DRenderer.java index 2781aee7..10a09b56 100644 --- a/src/main/java/workspace/render/Mesh3DRenderer.java +++ b/src/main/java/workspace/render/Mesh3DRenderer.java @@ -14,286 +14,309 @@ public class Mesh3DRenderer { - private PApplet context; - - public Mesh3DRenderer(PApplet context) { - this.context = context; - } - - public void drawVertices(Mesh3D mesh) { - context.pushMatrix(); - context.beginShape(PApplet.POINTS); - for (int i = 0; i < mesh.vertices.size(); i++) { - Vector3f v = mesh.vertices.get(i); - context.vertex(v.getX(), v.getY(), v.getZ()); - } - context.endShape(); - context.popMatrix(); - } - - public void drawVertices(Mesh3D mesh, float size) { - context.pushStyle(); - context.pushMatrix(); - context.strokeWeight(size); - context.beginShape(PApplet.POINTS); - for (int i = 0; i < mesh.vertices.size(); i++) { - Vector3f v = mesh.vertices.get(i); - context.vertex(v.getX(), v.getY(), v.getZ()); - } - context.endShape(); - context.popMatrix(); - context.popStyle(); - } - - public void drawFaceNormals(Mesh3D mesh, float length) { - context.pushMatrix(); - context.beginShape(PApplet.LINES); - for (Face3D f : mesh.faces) { - Vector3f c = mesh.calculateFaceCenter(f); - Vector3f n = mesh.calculateFaceNormal(f); - Vector3f v = c.add(n.mult(length)); - context.vertex(c.getX(), c.getY(), c.getZ()); - context.vertex(v.getX(), v.getY(), v.getZ()); - } - context.endShape(); - context.popMatrix(); - } - - public void drawFaceNormals(Mesh3D mesh) { - drawFaceNormals(mesh, 0.1f); - } - - public void drawVertexNormals(Mesh3D mesh, List normals) { - float length = 0.1f; - context.pushMatrix(); - context.beginShape(PApplet.LINES); - for (int i = 0; i < mesh.vertices.size(); i++) { - Vector3f v0 = mesh.vertices.get(i); - Vector3f v1 = v0.add(normals.get(i).mult(length)); - context.vertex(v0.getX(), v0.getY(), v0.getZ()); - context.vertex(v1.getX(), v1.getY(), v1.getZ()); - } - context.endShape(); - context.popMatrix(); - } - - public void drawFaces(Mesh3D mesh, Collection faces, Shading shading) { - switch (shading) { - case FLAT: - drawFacesFlat((PGraphics3D) context.g, mesh, faces); - break; - case SMOOTH: - drawFacesSmooth(mesh, faces); - break; - } - } - - private void drawFacesSmooth(Mesh3D mesh, Collection faces) { - context.pushMatrix(); - - mesh.apply(new UpdateFaceNormalsModifier()); - - VertexNormals normals = new VertexNormals(mesh); - - for (Face3D f : faces) { - Vector3f v; - - if (f.indices.length == 3) { - context.beginShape(PApplet.TRIANGLES); - } - - if (f.indices.length == 4) { - context.beginShape(PApplet.QUADS); - } - - if (f.indices.length > 4) { - context.beginShape(); - } - - Vector3f fn = f.normal; - context.normal(fn.getX(), fn.getY(), fn.getZ()); - - for (int i = 0; i < f.indices.length; i++) { - Vector3f vn = normals.getVertexNormals().get(f.indices[i]); - v = mesh.vertices.get(f.indices[i]); - context.normal(vn.getX(), vn.getY(), vn.getZ()); - context.vertex(v.getX(), v.getY(), v.getZ()); - } - - if (f.indices.length > 4) { - context.endShape(PApplet.CLOSE); - } else { - context.endShape(); - } - - } - - context.popMatrix(); - } - - private void drawFacesFlat(PGraphics3D context, Mesh3D mesh, Collection faces) { - context.pushMatrix(); - - for (Face3D f : faces) { - Vector3f v; - - if (f.indices.length == 3) { - context.beginShape(PApplet.TRIANGLES); - } - - if (f.indices.length == 4) { - context.beginShape(PApplet.QUADS); - } - - if (f.indices.length > 4) { - context.beginShape(); - } - - for (int i = 0; i < f.indices.length; i++) { - v = mesh.vertices.get(f.indices[i]); - context.vertex(v.getX(), v.getY(), v.getZ()); - } - - if (f.indices.length > 4) { - context.endShape(PApplet.CLOSE); - } else { - context.endShape(); - } - - } - - context.popMatrix(); - } - - public void drawFacesColored(Mesh3D mesh) { - context.pushMatrix(); - for (Face3D f : mesh.faces) { - context.fill(f.color.getRedInt(), f.color.getGreenInt(), f.color.getBlueInt()); - - Vector3f v; - - if (f.indices.length == 3) { - context.beginShape(PApplet.TRIANGLES); - } - - if (f.indices.length == 4) { - context.beginShape(PApplet.QUADS); - } - - if (f.indices.length > 4) { - context.beginShape(); - } - - for (int i = 0; i < f.indices.length; i++) { - v = mesh.vertices.get(f.indices[i]); - context.vertex(v.getX(), v.getY(), v.getZ()); - } - - if (f.indices.length > 4) { - context.endShape(PApplet.CLOSE); - } else { - context.endShape(); - } - - } - - context.popMatrix(); - } - - public void drawFaces(Mesh3D mesh, Collection faces) { - drawFaces(mesh, faces, Shading.FLAT); - } - - public void drawFaces(Mesh3D mesh, FaceSelection selection) { - drawFaces(mesh, selection.getFaces(), Shading.FLAT); - } - - public void drawFaces(Mesh3D mesh) { - drawFaces(mesh, mesh.faces, Shading.FLAT); - } - - public void drawEdges(Mesh3D mesh) { - for (Face3D f : mesh.faces) { - for (int i = 0; i <= f.indices.length; i++) { - Vector3f v0 = mesh.vertices.get(f.indices[i % f.indices.length]); - Vector3f v1 = mesh.vertices.get(f.indices[(i + 1) % f.indices.length]); - context.line(v0.getX(), v0.getY(), v0.getZ(), v1.getX(), v1.getY(), v1.getZ()); - } - } - } - - public void drawGizmo(float length) { - context.pushStyle(); - context.noFill(); - context.stroke(255, 0, 0); - context.line(0f, 0f, 0f, length, 0, 0); - context.stroke(0, 255, 0); - context.line(0f, 0f, 0f, 0, length, 0); - context.stroke(0, 0, 255); - context.line(0f, 0f, 0f, 0, 0, length); - context.popStyle(); - } - - public void drawGrid(int rows, int cols, float size) { - context.pushStyle(); - context.noFill(); - - context.pushMatrix(); - context.rotateX(PApplet.radians(-90)); - context.translate(-cols * size / 2, -rows * size / 2); - - for (int i = 0; i < rows; i++) { - for (int j = 0; j < cols; j++) { - context.rect(j * size, i * size, size, size); - } - } - - context.popMatrix(); - context.popStyle(); - } - - public void drawCheckerGrid(int rows, int cols, float size) { - context.pushStyle(); - context.noStroke(); - - context.pushMatrix(); - context.rotateX(PApplet.radians(-90)); - context.translate(-cols * size / 2, -rows * size / 2); - - for (int i = 0; i < rows; i++) { - for (int j = 0; j < cols; j++) { - if ((i + j) % 2 == 0) - context.fill(132, 137, 154); - else - context.fill(150, 156, 173); - context.rect(j * size, i * size, size, size); - } - } - - context.popMatrix(); - context.popStyle(); - } - - public void lights(float scale) { - float x = 4.0762f; - float y = -5.9039f; - float z = -1.055f; - - context.pushMatrix(); - context.pushStyle(); - context.noLights(); - context.ambient(0); - - context.stroke(0); - context.line(x, y, z, x, 0, z); - - context.translate(x, y, z); - context.box(0.1f * scale); - - context.pointLight(255, 255, 255, x * scale, y * scale, z * scale); - - context.popStyle(); - context.popMatrix(); - } - + private PApplet context; + + public Mesh3DRenderer(PApplet context) { + this.context = context; + } + + public void drawVertices(Mesh3D mesh) { + context.pushMatrix(); + context.beginShape(PApplet.POINTS); + for (int i = 0; i < mesh.vertices.size(); i++) { + Vector3f v = mesh.vertices.get(i); + context.vertex(v.getX(), v.getY(), v.getZ()); + } + context.endShape(); + context.popMatrix(); + } + + public void drawVertices(Mesh3D mesh, float size) { + context.pushStyle(); + context.pushMatrix(); + context.strokeWeight(size); + context.beginShape(PApplet.POINTS); + for (int i = 0; i < mesh.vertices.size(); i++) { + Vector3f v = mesh.vertices.get(i); + context.vertex(v.getX(), v.getY(), v.getZ()); + } + context.endShape(); + context.popMatrix(); + context.popStyle(); + } + + public void drawFaceNormals(Mesh3D mesh, float length) { + context.pushMatrix(); + context.beginShape(PApplet.LINES); + for (Face3D f : mesh.faces) { + Vector3f c = mesh.calculateFaceCenter(f); + Vector3f n = mesh.calculateFaceNormal(f); + Vector3f v = c.add(n.mult(length)); + context.vertex(c.getX(), c.getY(), c.getZ()); + context.vertex(v.getX(), v.getY(), v.getZ()); + } + context.endShape(); + context.popMatrix(); + } + + public void drawFaceNormals(Mesh3D mesh) { + drawFaceNormals(mesh, 0.1f); + } + + public void drawVertexNormals(Mesh3D mesh, List normals) { + float length = 0.1f; + context.pushMatrix(); + context.beginShape(PApplet.LINES); + for (int i = 0; i < mesh.vertices.size(); i++) { + Vector3f v0 = mesh.vertices.get(i); + Vector3f v1 = v0.add(normals.get(i).mult(length)); + context.vertex(v0.getX(), v0.getY(), v0.getZ()); + context.vertex(v1.getX(), v1.getY(), v1.getZ()); + } + context.endShape(); + context.popMatrix(); + } + + public void drawFaces(Mesh3D mesh, Collection faces, Shading shading) { + switch (shading) { + case FLAT: + drawFacesFlat((PGraphics3D) context.g, mesh, faces); + break; + case SMOOTH: + drawFacesSmooth(mesh, faces); + break; + } + } + + private void drawFacesSmooth(Mesh3D mesh, Collection faces) { + context.pushMatrix(); + + mesh.apply(new UpdateFaceNormalsModifier()); + + VertexNormals normals = new VertexNormals(mesh); + + for (Face3D f : faces) { + Vector3f v; + + if (f.indices.length == 3) { + context.beginShape(PApplet.TRIANGLES); + } + + if (f.indices.length == 4) { + context.beginShape(PApplet.QUADS); + } + + if (f.indices.length > 4) { + context.beginShape(); + } + + Vector3f fn = f.normal; + context.normal(fn.getX(), fn.getY(), fn.getZ()); + + for (int i = 0; i < f.indices.length; i++) { + Vector3f vn = normals.getVertexNormals().get(f.indices[i]); + v = mesh.vertices.get(f.indices[i]); + context.normal(vn.getX(), vn.getY(), vn.getZ()); + context.vertex(v.getX(), v.getY(), v.getZ()); + } + + if (f.indices.length > 4) { + context.endShape(PApplet.CLOSE); + } else { + context.endShape(); + } + } + + context.popMatrix(); + } + + // private void drawFacesFlat(PGraphics3D context, Mesh3D mesh, + // Collection faces) { + // context.pushMatrix(); + // + // for (Face3D f : faces) { + // Vector3f v; + // + // if (f.indices.length == 3) { + // context.beginShape(PApplet.TRIANGLES); + // } + // + // if (f.indices.length == 4) { + // context.beginShape(PApplet.QUADS); + // } + // + // if (f.indices.length > 4) { + // context.beginShape(); + // } + // + // for (int i = 0; i < f.indices.length; i++) { + // v = mesh.vertices.get(f.indices[i]); + // context.vertex(v.getX(), v.getY(), v.getZ()); + // } + // + // if (f.indices.length > 4) { + // context.endShape(PApplet.CLOSE); + // } else { + // context.endShape(); + // } + // + // } + // + // context.popMatrix(); + // } + + private void drawFacesFlat(PGraphics3D context, Mesh3D mesh, Collection faces) { + for (Face3D f : faces) { + Vector3f v; + + // Use specific shape types based on face vertex count + if (f.indices.length == 3) { + context.beginShape(PApplet.TRIANGLES); + } else if (f.indices.length == 4) { + context.beginShape(PApplet.QUADS); + } else { + context.beginShape(PApplet.POLYGON); // Handle polygons directly + } + + // Set flat shading normal (assuming a calculateNormal method exists) + // Vector3f normal = f.calculateNormal(mesh); + // context.normal(normal.getX(), normal.getY(), normal.getZ()); + + // Add vertices + for (int index : f.indices) { + v = mesh.vertices.get(index); + context.vertex(v.getX(), v.getY(), v.getZ()); + } + + context.endShape(PApplet.CLOSE); // Ensure the shape is closed + } + } + + public void drawFacesColored(Mesh3D mesh) { + context.pushMatrix(); + for (Face3D f : mesh.faces) { + context.fill(f.color.getRedInt(), f.color.getGreenInt(), f.color.getBlueInt()); + + Vector3f v; + + if (f.indices.length == 3) { + context.beginShape(PApplet.TRIANGLES); + } + + if (f.indices.length == 4) { + context.beginShape(PApplet.QUADS); + } + + if (f.indices.length > 4) { + context.beginShape(); + } + + for (int i = 0; i < f.indices.length; i++) { + v = mesh.vertices.get(f.indices[i]); + context.vertex(v.getX(), v.getY(), v.getZ()); + } + + if (f.indices.length > 4) { + context.endShape(PApplet.CLOSE); + } else { + context.endShape(); + } + } + + context.popMatrix(); + } + + public void drawFaces(Mesh3D mesh, Collection faces) { + drawFaces(mesh, faces, Shading.FLAT); + } + + public void drawFaces(Mesh3D mesh, FaceSelection selection) { + drawFaces(mesh, selection.getFaces(), Shading.FLAT); + } + + public void drawFaces(Mesh3D mesh) { + drawFaces(mesh, mesh.faces, Shading.FLAT); + } + + public void drawEdges(Mesh3D mesh) { + for (Face3D f : mesh.faces) { + for (int i = 0; i <= f.indices.length; i++) { + Vector3f v0 = mesh.vertices.get(f.indices[i % f.indices.length]); + Vector3f v1 = mesh.vertices.get(f.indices[(i + 1) % f.indices.length]); + context.line(v0.getX(), v0.getY(), v0.getZ(), v1.getX(), v1.getY(), v1.getZ()); + } + } + } + + public void drawGizmo(float length) { + context.pushStyle(); + context.noFill(); + context.stroke(255, 0, 0); + context.line(0f, 0f, 0f, length, 0, 0); + context.stroke(0, 255, 0); + context.line(0f, 0f, 0f, 0, length, 0); + context.stroke(0, 0, 255); + context.line(0f, 0f, 0f, 0, 0, length); + context.popStyle(); + } + + public void drawGrid(int rows, int cols, float size) { + context.pushStyle(); + context.noFill(); + + context.pushMatrix(); + context.rotateX(PApplet.radians(-90)); + context.translate(-cols * size / 2, -rows * size / 2); + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + context.rect(j * size, i * size, size, size); + } + } + + context.popMatrix(); + context.popStyle(); + } + + public void drawCheckerGrid(int rows, int cols, float size) { + context.pushStyle(); + context.noStroke(); + + context.pushMatrix(); + context.rotateX(PApplet.radians(-90)); + context.translate(-cols * size / 2, -rows * size / 2); + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if ((i + j) % 2 == 0) context.fill(132, 137, 154); + else context.fill(150, 156, 173); + context.rect(j * size, i * size, size, size); + } + } + + context.popMatrix(); + context.popStyle(); + } + + public void lights(float scale) { + float x = 4.0762f; + float y = -5.9039f; + float z = -1.055f; + + context.pushMatrix(); + context.pushStyle(); + context.noLights(); + context.ambient(0); + + context.stroke(0); + context.line(x, y, z, x, 0, z); + + context.translate(x, y, z); + context.box(0.1f * scale); + + context.pointLight(255, 255, 255, x * scale, y * scale, z * scale); + + context.popStyle(); + context.popMatrix(); + } } diff --git a/src/main/java/workspace/render/ObjectSelectionRender.java b/src/main/java/workspace/render/ObjectSelectionRender.java index aafccb36..b240933e 100644 --- a/src/main/java/workspace/render/ObjectSelectionRender.java +++ b/src/main/java/workspace/render/ObjectSelectionRender.java @@ -12,112 +12,108 @@ public class ObjectSelectionRender { - private ColorGenerator generator; + private ColorGenerator generator; - private int width; + private int width; - private int height; + private int height; - private PApplet p; + private PApplet p; - private PGraphics3D g3d; + private PGraphics3D g3d; - private HashMap colorToObjectName; + private HashMap colorToObjectName; - private HashMap nameToColor; + private HashMap nameToColor; - public ObjectSelectionRender(PApplet p) { - colorToObjectName = new HashMap(); - nameToColor = new HashMap(); - generator = new ColorGenerator(); - this.p = p; - g3d = (PGraphics3D) p.createGraphics(p.width, p.height, PApplet.P3D); - p.registerMethod("pre", this); - } - - public void pre() { - if (p.width != this.width || p.height != this.height) { - this.width = p.width; - this.height = p.height; - g3d = (PGraphics3D) p - .createGraphics(p.width, p.height, PApplet.P3D); - } - } + public ObjectSelectionRender(PApplet p) { + colorToObjectName = new HashMap(); + nameToColor = new HashMap(); + generator = new ColorGenerator(); + this.p = p; + g3d = (PGraphics3D) p.createGraphics(p.width, p.height, PApplet.P3D); + p.registerMethod("pre", this); + } - public String getObject(int x, int y) { - int color = getColor(x, y); - return colorToObjectName.get(color); + public void pre() { + if (p.width != this.width || p.height != this.height) { + this.width = p.width; + this.height = p.height; + g3d = (PGraphics3D) p.createGraphics(p.width, p.height, PApplet.P3D); } - - public int getColor(int x, int y) { - int color = g3d.get(x, y); - return color; - } - - public void draw(List sceneObjects) { - g3d.beginDraw(); - g3d.setMatrix(p.getMatrix()); - g3d.noLights(); - g3d.background(0, 0, 0, 0); - g3d.noStroke(); - for (SceneObject sceneObject : sceneObjects) - drawBuffer(sceneObject); - g3d.endDraw(); + } + + public String getObject(int x, int y) { + int color = getColor(x, y); + return colorToObjectName.get(color); + } + + public int getColor(int x, int y) { + int color = g3d.get(x, y); + return color; + } + + public void draw(List sceneObjects) { + g3d.beginDraw(); + g3d.setMatrix(p.getMatrix()); + g3d.noLights(); + g3d.background(0, 0, 0, 0); + g3d.noStroke(); + for (SceneObject sceneObject : sceneObjects) drawBuffer(sceneObject); + g3d.endDraw(); + } + + public void drawColorBuffer() { + if (g3d == null) return; + p.image(g3d, 0, 0, p.width, p.height); + } + + private void drawBuffer(SceneObject sceneObject) { + PGraphics3D context = g3d; + Mesh3D mesh = sceneObject.getMesh(); + + int c = -1; + if (nameToColor.containsKey(sceneObject.getName())) { + c = nameToColor.get(sceneObject.getName()); + } else { + c = generator.next().getRGBA(); + nameToColor.put(sceneObject.getName(), c); } - public void drawColorBuffer() { - if (g3d == null) - return; - p.image(g3d, 0, 0, p.width, p.height); - } - - private void drawBuffer(SceneObject sceneObject) { - PGraphics3D context = g3d; - Mesh3D mesh = sceneObject.getMesh(); - - int c = -1; - if (nameToColor.containsKey(sceneObject.getName())) { - c = nameToColor.get(sceneObject.getName()); - } else { - c = generator.next().getRGBA(); - nameToColor.put(sceneObject.getName(), c); - } - - this.colorToObjectName.put(c, sceneObject.getName()); - - context.fill(c); + this.colorToObjectName.put(c, sceneObject.getName()); - context.pushMatrix(); + context.fill(c); - for (int i = 0; i < mesh.faces.size(); i++) { - Face3D f = mesh.getFaceAt(i); - Vector3f v; + context.pushMatrix(); - if (f.indices.length == 3) { - context.beginShape(PApplet.TRIANGLES); - } + for (int i = 0; i < mesh.faces.size(); i++) { + Face3D f = mesh.getFaceAt(i); + Vector3f v; - if (f.indices.length == 4) { - context.beginShape(PApplet.QUADS); - } + if (f.indices.length == 3) { + context.beginShape(PApplet.TRIANGLES); + } - if (f.indices.length > 4) { - context.beginShape(); - } + if (f.indices.length == 4) { + context.beginShape(PApplet.QUADS); + } - for (int j = 0; j < f.indices.length; j++) { - v = mesh.vertices.get(f.indices[j]); - context.vertex(v.getX(), v.getY(), v.getZ()); - } + if (f.indices.length > 4) { + context.beginShape(); + } - if (f.indices.length > 4) { - context.endShape(PApplet.CLOSE); - } else { - context.endShape(); - } - } + for (int j = 0; j < f.indices.length; j++) { + v = mesh.vertices.get(f.indices[j]); + context.vertex(v.getX(), v.getY(), v.getZ()); + } - context.popMatrix(); + if (f.indices.length > 4) { + context.endShape(PApplet.CLOSE); + } else { + context.endShape(); + } } + context.popMatrix(); + } } diff --git a/src/main/java/workspace/render/SelectionRenderer.java b/src/main/java/workspace/render/SelectionRenderer.java index e6ddbe3d..59783d60 100644 --- a/src/main/java/workspace/render/SelectionRenderer.java +++ b/src/main/java/workspace/render/SelectionRenderer.java @@ -11,98 +11,95 @@ public class SelectionRenderer { - private int width; + private int width; - private int height; + private int height; - private PApplet p; + private PApplet p; - private PGraphics3D g3d; + private PGraphics3D g3d; - private HashMap colorToFaceMap; + private HashMap colorToFaceMap; - public SelectionRenderer(PApplet p) { - this.p = p; - g3d = (PGraphics3D) p.createGraphics(p.width, p.height, PApplet.P3D); - colorToFaceMap = new HashMap(); - p.registerMethod("pre", this); - } - - public void pre() { - if (p.width != this.width || p.height != this.height) { - this.width = p.width; - this.height = p.height; - g3d = (PGraphics3D) p - .createGraphics(p.width, p.height, PApplet.P3D); - } - } - - public Face3D getFace(int x, int y) { - int color = getColor(x, y); - return colorToFaceMap.get(color); - } + public SelectionRenderer(PApplet p) { + this.p = p; + g3d = (PGraphics3D) p.createGraphics(p.width, p.height, PApplet.P3D); + colorToFaceMap = new HashMap(); + p.registerMethod("pre", this); + } - public int getColor(int x, int y) { - int color = g3d.get(x, y); - return color; + public void pre() { + if (p.width != this.width || p.height != this.height) { + this.width = p.width; + this.height = p.height; + g3d = (PGraphics3D) p.createGraphics(p.width, p.height, PApplet.P3D); } - - public void drawFaces(Mesh3D mesh) { - g3d.beginDraw(); - g3d.setMatrix(p.getMatrix()); - g3d.noLights(); - g3d.background(0, 0, 0, 0); - g3d.noStroke(); - drawFacesBuffer(mesh, mesh.faces); - g3d.endDraw(); - } - - public void drawColorBuffer() { - if (g3d == null) - return; - p.image(g3d, 0, 0, p.width, p.height); - } - - private void drawFacesBuffer(Mesh3D mesh, Collection faces) { - PGraphics3D context = g3d; - - context.pushMatrix(); - - ColorGenerator generator = new ColorGenerator(); - this.colorToFaceMap.clear(); - - for (int i = 0; i < mesh.faces.size(); i++) { - Face3D f = mesh.getFaceAt(i); - Vector3f v; - int c = generator.next().getRGBA(); - context.fill(c); - this.colorToFaceMap.put(c, f); - - if (f.indices.length == 3) { - context.beginShape(PApplet.TRIANGLES); - } - - if (f.indices.length == 4) { - context.beginShape(PApplet.QUADS); - } - - if (f.indices.length > 4) { - context.beginShape(); - } - - for (int j = 0; j < f.indices.length; j++) { - v = mesh.vertices.get(f.indices[j]); - context.vertex(v.getX(), v.getY(), v.getZ()); - } - - if (f.indices.length > 4) { - context.endShape(PApplet.CLOSE); - } else { - context.endShape(); - } - } - - context.popMatrix(); + } + + public Face3D getFace(int x, int y) { + int color = getColor(x, y); + return colorToFaceMap.get(color); + } + + public int getColor(int x, int y) { + int color = g3d.get(x, y); + return color; + } + + public void drawFaces(Mesh3D mesh) { + g3d.beginDraw(); + g3d.setMatrix(p.getMatrix()); + g3d.noLights(); + g3d.background(0, 0, 0, 0); + g3d.noStroke(); + drawFacesBuffer(mesh, mesh.faces); + g3d.endDraw(); + } + + public void drawColorBuffer() { + if (g3d == null) return; + p.image(g3d, 0, 0, p.width, p.height); + } + + private void drawFacesBuffer(Mesh3D mesh, Collection faces) { + PGraphics3D context = g3d; + + context.pushMatrix(); + + ColorGenerator generator = new ColorGenerator(); + this.colorToFaceMap.clear(); + + for (int i = 0; i < mesh.faces.size(); i++) { + Face3D f = mesh.getFaceAt(i); + Vector3f v; + int c = generator.next().getRGBA(); + context.fill(c); + this.colorToFaceMap.put(c, f); + + if (f.indices.length == 3) { + context.beginShape(PApplet.TRIANGLES); + } + + if (f.indices.length == 4) { + context.beginShape(PApplet.QUADS); + } + + if (f.indices.length > 4) { + context.beginShape(); + } + + for (int j = 0; j < f.indices.length; j++) { + v = mesh.vertices.get(f.indices[j]); + context.vertex(v.getX(), v.getY(), v.getZ()); + } + + if (f.indices.length > 4) { + context.endShape(PApplet.CLOSE); + } else { + context.endShape(); + } } + context.popMatrix(); + } } diff --git a/src/main/java/workspace/render/Shading.java b/src/main/java/workspace/render/Shading.java index 77d17adb..9353d406 100644 --- a/src/main/java/workspace/render/Shading.java +++ b/src/main/java/workspace/render/Shading.java @@ -1,9 +1,7 @@ package workspace.render; public enum Shading { + SMOOTH, - SMOOTH, - - FLAT - + FLAT } diff --git a/src/main/java/workspace/ui/elements/UiButton.java b/src/main/java/workspace/ui/elements/UiButton.java index 77c7b40f..e7372af8 100644 --- a/src/main/java/workspace/ui/elements/UiButton.java +++ b/src/main/java/workspace/ui/elements/UiButton.java @@ -6,103 +6,95 @@ /** * Represents a button component in the UI. - *

- * A button can display text and execute an associated action when clicked. - * Rendering is handled by a dedicated renderer, allowing for customizable - * visual styles. - *

+ * + *

A button can display text and execute an associated action when clicked. Rendering is handled + * by a dedicated renderer, allowing for customizable visual styles. */ public class UiButton extends UiComponent { - /** - * The text displayed on the button. - */ - private String text; + /** The text displayed on the button. */ + private String text; - /** - * The action listener for click events. - */ - private IActionListener actionListener; + /** The action listener for click events. */ + private IActionListener actionListener; - /** - * Constructs a new {@code UiButton} with the specified text. - * - * @param text The text to display on the button. - */ - public UiButton(String text) { - this(text, 0, 0, 0, 0); - } + /** + * Constructs a new {@code UiButton} with the specified text. + * + * @param text The text to display on the button. + */ + public UiButton(String text) { + this(text, 0, 0, 0, 0); + } - /** - * Constructs a new {@code UiButton} with the specified text and dimensions. - * - * @param text The text to display on the button. - * @param x The x-coordinate of the button. - * @param y The y-coordinate of the button. - * @param width The width of the button. - * @param height The height of the button. - */ - public UiButton(String text, int x, int y, int width, int height) { - this.text = text; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - setRenderer(new ButtonRenderer()); - } + /** + * Constructs a new {@code UiButton} with the specified text and dimensions. + * + * @param text The text to display on the button. + * @param x The x-coordinate of the button. + * @param y The y-coordinate of the button. + * @param width The width of the button. + * @param height The height of the button. + */ + public UiButton(String text, int x, int y, int width, int height) { + this.text = text; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + setRenderer(new ButtonRenderer()); + } - /** - * Handles mouse click events for the button. - *

- * If the button has an associated action listener, its - * {@link IActionListener#onActionPerformed()} method is invoked. - *

- * - * @param x The x-coordinate of the mouse click. - * @param y The y-coordinate of the mouse click. - */ - @Override - public void onMouseClicked(int x, int y) { - super.onMouseClicked(x, y); - if (actionListener != null) { - actionListener.onActionPerformed(); - } - } + /** + * Handles mouse click events for the button. + * + *

If the button has an associated action listener, its {@link + * IActionListener#onActionPerformed()} method is invoked. + * + * @param x The x-coordinate of the mouse click. + * @param y The y-coordinate of the mouse click. + */ + @Override + public void onMouseClicked(int x, int y) { + super.onMouseClicked(x, y); + if (actionListener != null) { + actionListener.onActionPerformed(); + } + } - /** - * Gets the text displayed on the button. - * - * @return The current text of the button. - */ - public String getText() { - return text; - } + /** + * Gets the text displayed on the button. + * + * @return The current text of the button. + */ + public String getText() { + return text; + } - /** - * Sets the text to display on the button. - * - * @param text The new text to display. - */ - public void setText(String text) { - this.text = text; - } + /** + * Sets the text to display on the button. + * + * @param text The new text to display. + */ + public void setText(String text) { + this.text = text; + } - /** - * Gets the action listener associated with the button. - * - * @return The current action listener, or {@code null} if none is set. - */ - public IActionListener getActionListener() { - return actionListener; - } + /** + * Gets the action listener associated with the button. + * + * @return The current action listener, or {@code null} if none is set. + */ + public IActionListener getActionListener() { + return actionListener; + } - /** - * Sets the action listener for the button. - * - * @param actionListener The action listener to associate with the button. - */ - public void setActionListener(IActionListener actionListener) { - this.actionListener = actionListener; - } - -} \ No newline at end of file + /** + * Sets the action listener for the button. + * + * @param actionListener The action listener to associate with the button. + */ + public void setActionListener(IActionListener actionListener) { + this.actionListener = actionListener; + } +} diff --git a/src/main/java/workspace/ui/elements/UiCheckBox.java b/src/main/java/workspace/ui/elements/UiCheckBox.java index c4a4c366..eee8e933 100644 --- a/src/main/java/workspace/ui/elements/UiCheckBox.java +++ b/src/main/java/workspace/ui/elements/UiCheckBox.java @@ -6,136 +6,122 @@ import workspace.ui.renderer.CheckBoxRenderer; /** - * A UI CheckBox component that can be toggled (selected/deselected) and - * supports click handling. - *

- * This class represents a checkbox UI element with a label, click interaction, - * and customizable rendering. - *

+ * A UI CheckBox component that can be toggled (selected/deselected) and supports click handling. + * + *

This class represents a checkbox UI element with a label, click interaction, and customizable + * rendering. */ public class UiCheckBox extends UiComponent { - /** - * Checkbox state. - */ - private boolean selected; - - /** - * Label text for the checkbox. - */ - private String text; - - /** - * Listener for click events. - */ - private IActionListener actionListener; - - private final CheckBoxRenderer renderer; - - /** - * Constructs a new {@code UiCheckBox} with the provided label text. - *

- * Initializes default dimensions and sets up the checkbox renderer. - *

- * - * @param text The label text to display next to the checkbox. - */ - public UiCheckBox(String text) { - this.text = text; - this.width = 20; - this.height = 20; - this.renderer = new CheckBoxRenderer(); - } - - /** - * Handles rendering for this checkbox component. - * - * @param g The {@link Graphics} context to draw on. - */ - @Override - public void renderSelf(Graphics g) { - renderer.render(g, this); - } - - /** - * Handles mouse click interactions. Toggles the selection state when clicked. - * - * @param x X-coordinate of the mouse click. - * @param y Y-coordinate of the mouse click. - */ - @Override - public void onMouseClicked(int x, int y) { - super.onMouseClicked(x, y); - toggleSelection(); - } - - /** - * Toggles the selection state of this checkbox and invokes the action - * listener, if any. - */ - private void toggleSelection() { - setSelected(!selected); - } - - /** - * Checks if the checkbox is currently selected. - * - * @return {@code true} if the checkbox is selected; {@code false} otherwise. - */ - public boolean isSelected() { - return selected; - } - - /** - * Updates the selection state of the checkbox and notifies listeners about - * the change. - * - * @param selected The new selection state to set. - */ - public void setSelected(boolean selected) { - if (this.selected == selected) { - return; // No state change - } - this.selected = selected; - if (actionListener != null) { - actionListener.onActionPerformed(); - } - } - - /** - * Gets the text label associated with the checkbox. - * - * @return The current text label. - */ - public String getText() { - return text; - } - - /** - * Updates the text label of the checkbox. - * - * @param text The new text label. - */ - public void setText(String text) { - this.text = text; - } - - /** - * Sets an action listener for handling click events on this checkbox. - * - * @param listener The action listener to set. - */ - public void setActionListener(IActionListener listener) { - this.actionListener = listener; - } - - /** - * Retrieves the currently set action listener. - * - * @return The action listener currently assigned to this checkbox. - */ - public IActionListener getActionListener() { - return actionListener; - } - -} \ No newline at end of file + /** Checkbox state. */ + private boolean selected; + + /** Label text for the checkbox. */ + private String text; + + /** Listener for click events. */ + private IActionListener actionListener; + + private final CheckBoxRenderer renderer; + + /** + * Constructs a new {@code UiCheckBox} with the provided label text. + * + *

Initializes default dimensions and sets up the checkbox renderer. + * + * @param text The label text to display next to the checkbox. + */ + public UiCheckBox(String text) { + this.text = text; + this.width = 15; + this.height = 15; + this.renderer = new CheckBoxRenderer(); + } + + /** + * Handles rendering for this checkbox component. + * + * @param g The {@link Graphics} context to draw on. + */ + @Override + public void renderSelf(Graphics g) { + renderer.render(g, this); + } + + /** + * Handles mouse click interactions. Toggles the selection state when clicked. + * + * @param x X-coordinate of the mouse click. + * @param y Y-coordinate of the mouse click. + */ + @Override + public void onMouseClicked(int x, int y) { + super.onMouseClicked(x, y); + toggleSelection(); + } + + /** Toggles the selection state of this checkbox and invokes the action listener, if any. */ + private void toggleSelection() { + setSelected(!selected); + } + + /** + * Checks if the checkbox is currently selected. + * + * @return {@code true} if the checkbox is selected; {@code false} otherwise. + */ + public boolean isSelected() { + return selected; + } + + /** + * Updates the selection state of the checkbox and notifies listeners about the change. + * + * @param selected The new selection state to set. + */ + public void setSelected(boolean selected) { + if (this.selected == selected) { + return; // No state change + } + this.selected = selected; + if (actionListener != null) { + actionListener.onActionPerformed(); + } + } + + /** + * Gets the text label associated with the checkbox. + * + * @return The current text label. + */ + public String getText() { + return text; + } + + /** + * Updates the text label of the checkbox. + * + * @param text The new text label. + */ + public void setText(String text) { + this.text = text; + } + + /** + * Sets an action listener for handling click events on this checkbox. + * + * @param listener The action listener to set. + */ + public void setActionListener(IActionListener listener) { + this.actionListener = listener; + } + + /** + * Retrieves the currently set action listener. + * + * @return The action listener currently assigned to this checkbox. + */ + public IActionListener getActionListener() { + return actionListener; + } +} diff --git a/src/main/java/workspace/ui/elements/UiEditorMenu.java b/src/main/java/workspace/ui/elements/UiEditorMenu.java index dc86d8fb..a5c1bb58 100644 --- a/src/main/java/workspace/ui/elements/UiEditorMenu.java +++ b/src/main/java/workspace/ui/elements/UiEditorMenu.java @@ -7,42 +7,37 @@ /** * Represents an editor menu component in the UI. - *

- * The menu displays a background and customizable text, styled using values - * from the Look and Feel (LAF) system. Rendering is delegated to a dedicated - * renderer for modularity. - *

+ * + *

The menu displays a background and customizable text, styled using values from the Look and + * Feel (LAF) system. Rendering is delegated to a dedicated renderer for modularity. */ public class UiEditorMenu extends UiComponent { - private String text; // The menu's display text. + private String text; // The menu's display text. - /** - * Constructs a new {@code UiEditorMenu} with default styles. - */ - public UiEditorMenu() { - setText(""); - setForeground(UiValues.getColor(UiConstants.KEY_MENU_FOREGROUND_COLOR)); - setBackground(UiValues.getColor(UiConstants.KEY_MENU_BACKGROUND_COLOR)); - setRenderer(new EditorMenuRenderer()); - } + /** Constructs a new {@code UiEditorMenu} with default styles. */ + public UiEditorMenu() { + setText(""); + setForeground(UiValues.getColor(UiConstants.KEY_MENU_FOREGROUND_COLOR)); + setBackground(UiValues.getColor(UiConstants.KEY_MENU_BACKGROUND_COLOR)); + setRenderer(new EditorMenuRenderer()); + } - /** - * Gets the text displayed in this menu. - * - * @return The current text of the menu. - */ - public String getText() { - return text; - } + /** + * Gets the text displayed in this menu. + * + * @return The current text of the menu. + */ + public String getText() { + return text; + } - /** - * Sets the text displayed in this menu. - * - * @param text The new text to display. - */ - public void setText(String text) { - this.text = text; - } - -} \ No newline at end of file + /** + * Sets the text displayed in this menu. + * + * @param text The new text to display. + */ + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/workspace/ui/elements/UiElement.java b/src/main/java/workspace/ui/elements/UiElement.java index ba2abd57..75b6e9c4 100644 --- a/src/main/java/workspace/ui/elements/UiElement.java +++ b/src/main/java/workspace/ui/elements/UiElement.java @@ -10,230 +10,200 @@ /** * Core abstraction for all UI elements. - *

- * This interface defines the essential methods required for a UI element, such - * as rendering, layout management, and interaction capabilities. - * Implementations of this interface represent individual components within a - * user interface hierarchy. - *

+ * + *

This interface defines the essential methods required for a UI element, such as rendering, + * layout management, and interaction capabilities. Implementations of this interface represent + * individual components within a user interface hierarchy. */ public interface UiElement { - /** - * Gets the X-coordinate of this element. - * - * @return The X-coordinate in pixels. - */ - int getX(); - - /** - * Sets the X-coordinate of this element. - * - * @param x The new X-coordinate in pixels. - */ - void setX(int x); - - /** - * Gets the Y-coordinate of this element. - * - * @return The Y-coordinate in pixels. - */ - int getY(); - - /** - * Sets the Y-coordinate of this element. - * - * @param y The new Y-coordinate in pixels. - */ - void setY(int y); - - /** - * Retrieves the width of this {@code UiElement}. - *

- * The width represents the horizontal size of the UI element. It is used - * during rendering and layout calculations to determine how much horizontal - * space the element occupies. - *

- * - * @return The width of this UI element in pixels. - */ - int getWidth(); - - /** - * Sets the width of this {@link UiElement} to the specified new width. - * - * @see #getWidth() - * @param width The new width in pixels. - */ - void setWidth(int width); - - /** - * Retrieves the height of this {@code UiElement}. - *

- * The height represents the vertical size of the UI element. It is used - * during rendering and layout calculations to determine how much vertical - * space the element occupies. - *

- * - * @return The height of this UI element in pixels. - */ - int getHeight(); - - /** - * Sets the height of this {@link UiElement} to the specified new height. - * - * @see #getHeight() - * @param height The new height in pixels. - */ - void setHeight(int height); - - /** - * Renders this {@code UiElement} using its specific rendering logic. - *

- * The rendering logic should account for the element's visual representation, - * including its position, size, background, border, and children if - * applicable. - *

- * - * @param g The {@link Graphics} context used for drawing. - */ - void render(Graphics g); - - /** - * Sets a custom renderer for this {@code UiElement}. - * - * @param renderer The {@link Renderer} to assign to this element. A - * {@code null} value may disable custom rendering logic or - * fall back to defaults. - */ - void setRenderer(Renderer renderer); - - /** - * Retrieves the current renderer assigned to this UI element. - * - * @return The {@link Renderer} currently used by this UI element. - */ - Renderer getRenderer(); - - /** - * Assigns a layout manager to this {@code UiElement}. - *

- * The layout manager defines how this element's child components are - * positioned and sized. Assigning a new layout manager should immediately - * trigger a re-layout of the element's children. - *

- * - * @param layout The {@link Layout} manager to set. A {@code null} value may - * default to a no-op layout or an implementation-specific - * behavior. - */ - void setLayout(Layout layout); - - /** - * Retrieves the current anchor type of this UI element. - *

- * Anchors define how this element is aligned relative to its parent or - * specific layout logic. Examples include {@code TOP_LEFT}, {@code CENTER}, - * and {@code BOTTOM_RIGHT}. - *

- * - * @return The current {@link Anchor} setting for this element. - */ - Anchor getAnchor(); - - /** - * Sets the anchor type for this UI element. - *

- * The anchor determines how this element aligns in its container based on the - * defined anchor type, such as centering, top-left, or bottom-right - * alignment. - *

- * - * @param anchor The {@link Anchor} to set for this element. - */ - void setAnchor(Anchor anchor); - - /** - * Determines if the specified coordinates are within the bounds of this - * {@code UiElement}. - *

- * The coordinates are relative to the element's parent or local coordinate - * system. This method can be used for hit-testing, such as determining - * whether a mouse event occurred within the element's area. - *

- * - * @param x The X-coordinate to check. - * @param y The Y-coordinate to check. - * @return {@code true} if the coordinates are within this element's bounds; - * {@code false} otherwise. - */ - boolean contains(int x, int y); - - /** - * Checks if this {@code UiElement} is currently visible. - *

- * A visible {@code UiElement} is rendered and participates in interactions - * such as event handling. Invisible elements are typically excluded from - * rendering and interaction logic. - *

- * - * @return {@code true} if the element is visible; {@code false} otherwise. - */ - boolean isVisible(); - - /** - * Sets the visibility of this {@code UiElement}. - *

- * Setting visibility to {@code false} hides the element from rendering and - * may exclude it from event handling or layout calculations. Setting it to - * {@code true} restores its visibility and functionality. - *

- * - * @param visible {@code true} to make the element visible, or {@code false} - * to hide it. - */ - void setVisible(boolean visible); - - /** - * Sets the border for this {@code UiElement}. - *

- * The border defines the visual boundary or outline surrounding the UI - * element. It can be styled or configured to visually separate UI components - * or provide additional visual context. Setting a new border will affect the - * element's appearance during rendering. - *

- * - * @param border The {@link Border} to associate with this UI element. A - * {@code null} value may remove any existing border from the - * element. - */ - void setBorder(Border border); - - /** - * Retrieves the insets (margins or padding) for this {@code UiElement}. - *

- * Insets define the space between the element's content and its border or - * edges. This can represent padding within the UI element or margins for - * layout purposes. If no border or layout manager defines specific insets, - * the method will return a default empty insets object. - *

- * - * @return An instance of {@link Insets} representing the current insets for - * this UI element. - */ - Insets getInsets(); - - /** - * Retrieves the background color of this {@code UiElement}. - *

- * The background color determines the visual fill of the UI element's area. - * If no background color has been explicitly defined, the element may render - * with a default or transparent background depending on the implementation. - *

- * - * @return The {@link Color} instance representing the background color of - * this UI element. - */ - Color getBackground(); - + /** + * Gets the X-coordinate of this element. + * + * @return The X-coordinate in pixels. + */ + int getX(); + + /** + * Sets the X-coordinate of this element. + * + * @param x The new X-coordinate in pixels. + */ + void setX(int x); + + /** + * Gets the Y-coordinate of this element. + * + * @return The Y-coordinate in pixels. + */ + int getY(); + + /** + * Sets the Y-coordinate of this element. + * + * @param y The new Y-coordinate in pixels. + */ + void setY(int y); + + /** + * Retrieves the width of this {@code UiElement}. + * + *

The width represents the horizontal size of the UI element. It is used during rendering and + * layout calculations to determine how much horizontal space the element occupies. + * + * @return The width of this UI element in pixels. + */ + int getWidth(); + + /** + * Sets the width of this {@link UiElement} to the specified new width. + * + * @see #getWidth() + * @param width The new width in pixels. + */ + void setWidth(int width); + + /** + * Retrieves the height of this {@code UiElement}. + * + *

The height represents the vertical size of the UI element. It is used during rendering and + * layout calculations to determine how much vertical space the element occupies. + * + * @return The height of this UI element in pixels. + */ + int getHeight(); + + /** + * Sets the height of this {@link UiElement} to the specified new height. + * + * @see #getHeight() + * @param height The new height in pixels. + */ + void setHeight(int height); + + /** + * Renders this {@code UiElement} using its specific rendering logic. + * + *

The rendering logic should account for the element's visual representation, including its + * position, size, background, border, and children if applicable. + * + * @param g The {@link Graphics} context used for drawing. + */ + void render(Graphics g); + + /** + * Sets a custom renderer for this {@code UiElement}. + * + * @param renderer The {@link Renderer} to assign to this element. A {@code null} value may + * disable custom rendering logic or fall back to defaults. + */ + void setRenderer(Renderer renderer); + + /** + * Retrieves the current renderer assigned to this UI element. + * + * @return The {@link Renderer} currently used by this UI element. + */ + Renderer getRenderer(); + + /** + * Assigns a layout manager to this {@code UiElement}. + * + *

The layout manager defines how this element's child components are positioned and sized. + * Assigning a new layout manager should immediately trigger a re-layout of the element's + * children. + * + * @param layout The {@link Layout} manager to set. A {@code null} value may default to a no-op + * layout or an implementation-specific behavior. + */ + void setLayout(Layout layout); + + /** + * Retrieves the current anchor type of this UI element. + * + *

Anchors define how this element is aligned relative to its parent or specific layout logic. + * Examples include {@code TOP_LEFT}, {@code CENTER}, and {@code BOTTOM_RIGHT}. + * + * @return The current {@link Anchor} setting for this element. + */ + Anchor getAnchor(); + + /** + * Sets the anchor type for this UI element. + * + *

The anchor determines how this element aligns in its container based on the defined anchor + * type, such as centering, top-left, or bottom-right alignment. + * + * @param anchor The {@link Anchor} to set for this element. + */ + void setAnchor(Anchor anchor); + + /** + * Determines if the specified coordinates are within the bounds of this {@code UiElement}. + * + *

The coordinates are relative to the element's parent or local coordinate system. This method + * can be used for hit-testing, such as determining whether a mouse event occurred within the + * element's area. + * + * @param x The X-coordinate to check. + * @param y The Y-coordinate to check. + * @return {@code true} if the coordinates are within this element's bounds; {@code false} + * otherwise. + */ + boolean contains(int x, int y); + + /** + * Checks if this {@code UiElement} is currently visible. + * + *

A visible {@code UiElement} is rendered and participates in interactions such as event + * handling. Invisible elements are typically excluded from rendering and interaction logic. + * + * @return {@code true} if the element is visible; {@code false} otherwise. + */ + boolean isVisible(); + + /** + * Sets the visibility of this {@code UiElement}. + * + *

Setting visibility to {@code false} hides the element from rendering and may exclude it from + * event handling or layout calculations. Setting it to {@code true} restores its visibility and + * functionality. + * + * @param visible {@code true} to make the element visible, or {@code false} to hide it. + */ + void setVisible(boolean visible); + + /** + * Sets the border for this {@code UiElement}. + * + *

The border defines the visual boundary or outline surrounding the UI element. It can be + * styled or configured to visually separate UI components or provide additional visual context. + * Setting a new border will affect the element's appearance during rendering. + * + * @param border The {@link Border} to associate with this UI element. A {@code null} value may + * remove any existing border from the element. + */ + void setBorder(Border border); + + /** + * Retrieves the insets (margins or padding) for this {@code UiElement}. + * + *

Insets define the space between the element's content and its border or edges. This can + * represent padding within the UI element or margins for layout purposes. If no border or layout + * manager defines specific insets, the method will return a default empty insets object. + * + * @return An instance of {@link Insets} representing the current insets for this UI element. + */ + Insets getInsets(); + + /** + * Retrieves the background color of this {@code UiElement}. + * + *

The background color determines the visual fill of the UI element's area. If no background + * color has been explicitly defined, the element may render with a default or transparent + * background depending on the implementation. + * + * @return The {@link Color} instance representing the background color of this UI element. + */ + Color getBackground(); } diff --git a/src/main/java/workspace/ui/elements/UiLabel.java b/src/main/java/workspace/ui/elements/UiLabel.java index 1f56ebdb..cd51573c 100644 --- a/src/main/java/workspace/ui/elements/UiLabel.java +++ b/src/main/java/workspace/ui/elements/UiLabel.java @@ -5,45 +5,40 @@ /** * A simple UI label component for displaying text. - *

- * The label supports customizable text, background, and foreground colors. - * Rendering logic is delegated to a dedicated renderer for consistency with the - * framework's modular design. - *

+ * + *

The label supports customizable text, background, and foreground colors. Rendering logic is + * delegated to a dedicated renderer for consistency with the framework's modular design. */ public class UiLabel extends UiComponent { - /** - * The text displayed by the label. - */ - private String title; + /** The text displayed by the label. */ + private String title; - /** - * Constructs a new {@code UiLabel} with the given title. - * - * @param title The text to display on the label. - */ - public UiLabel(String title) { - this.title = title; - setRenderer(new LabelRenderer()); - } + /** + * Constructs a new {@code UiLabel} with the given title. + * + * @param title The text to display on the label. + */ + public UiLabel(String title) { + this.title = title; + setRenderer(new LabelRenderer()); + } - /** - * Gets the title (text) displayed by this label. - * - * @return The current title of the label. - */ - public String getTitle() { - return title; - } + /** + * Gets the title (text) displayed by this label. + * + * @return The current title of the label. + */ + public String getTitle() { + return title; + } - /** - * Sets the title (text) of this label. - * - * @param title The new text to display on the label. - */ - public void setTitle(String title) { - this.title = title; - } - -} \ No newline at end of file + /** + * Sets the title (text) of this label. + * + * @param title The new text to display on the label. + */ + public void setTitle(String title) { + this.title = title; + } +} diff --git a/src/main/java/workspace/ui/elements/UiPanel.java b/src/main/java/workspace/ui/elements/UiPanel.java index 9fdde2cd..3059bf43 100644 --- a/src/main/java/workspace/ui/elements/UiPanel.java +++ b/src/main/java/workspace/ui/elements/UiPanel.java @@ -4,29 +4,22 @@ import workspace.ui.renderer.PanelRenderer; /** - * Represents a simple UI panel component that serves as a container for other - * UI elements. - *

- * This class extends {@link UiComponent} and initializes itself with the - * default rendering logic provided by {@link PanelRenderer}. The panel - * is responsible for managing its background rendering and acts as a building - * block for creating layouts and grouping child components within the user + * Represents a simple UI panel component that serves as a container for other UI elements. + * + *

This class extends {@link UiComponent} and initializes itself with the default rendering logic + * provided by {@link PanelRenderer}. The panel is responsible for managing its background rendering + * and acts as a building block for creating layouts and grouping child components within the user * interface. - *

*/ public class UiPanel extends UiComponent { - /** - * Constructs a new {@code UiPanel} instance and sets its renderer to the - * default panel renderer. - *

- * The {@link PanelRenderer} handles the rendering of this panel's - * visual appearance, including painting its background and respecting any - * defined insets or layout configuration. - *

- */ - public UiPanel() { - setRenderer(new PanelRenderer()); - } - + /** + * Constructs a new {@code UiPanel} instance and sets its renderer to the default panel renderer. + * + *

The {@link PanelRenderer} handles the rendering of this panel's visual appearance, including + * painting its background and respecting any defined insets or layout configuration. + */ + public UiPanel() { + setRenderer(new PanelRenderer()); + } } diff --git a/src/main/java/workspace/ui/elements/UiSlider.java b/src/main/java/workspace/ui/elements/UiSlider.java index b6f92b3e..cc48d468 100644 --- a/src/main/java/workspace/ui/elements/UiSlider.java +++ b/src/main/java/workspace/ui/elements/UiSlider.java @@ -7,115 +7,114 @@ import workspace.ui.renderer.SliderRenderer; /** - * A customizable UI slider component for selecting a value within a defined - * range. Supports dragging and value change callbacks. + * A customizable UI slider component for selecting a value within a defined range. Supports + * dragging and value change callbacks. */ public class UiSlider extends UiComponent { - private float value; + private float value; - private float minValue = 0; + private float minValue = 0; - private float maxValue = 1; + private float maxValue = 1; - private float handlePosition; + private float handlePosition; - private String text = "Slider"; + private String text = "Slider"; - private ISliderCallBack callback; + private ISliderCallBack callback; - public UiSlider() { - setRenderer(new SliderRenderer()); - } + public UiSlider() { + setRenderer(new SliderRenderer()); + } - @Override - public void onMouseDragged(int mouseX, int mouseY) { - super.onMouseDragged(mouseX, mouseY); - updateHandlePosition(mouseX); - updateValue(); - if (callback != null) { - callback.valueChanged(value); - } - } + @Override + public void onMouseDragged(int mouseX, int mouseY) { + super.onMouseDragged(mouseX, mouseY); + updateHandlePosition(mouseX); + updateValue(); + if (callback != null) { + callback.valueChanged(value); + } + } - @Override - public void onMouseClicked(int mouseX, int mouseY) { - super.onMouseClicked(mouseX, mouseY); - updateHandlePosition(mouseX); - updateValue(); - if (callback != null) { - callback.valueChanged(value); - } - } + @Override + public void onMouseClicked(int mouseX, int mouseY) { + super.onMouseClicked(mouseX, mouseY); + updateHandlePosition(mouseX); + updateValue(); + if (callback != null) { + callback.valueChanged(value); + } + } - private void updateHandlePosition(int mouseX) { - Insets insets = getInsets(); - int trackStart = getX() + insets.getLeft(); // Account for global x position - int trackWidth = getWidth() - insets.getHorizontalInsets(); + private void updateHandlePosition(int mouseX) { + Insets insets = getInsets(); + int trackStart = getX() + insets.getLeft(); // Account for global x position + int trackWidth = getWidth() - insets.getHorizontalInsets(); - // Adjust handlePosition relative to the track's start position - handlePosition = Mathf.clamp(mouseX - trackStart, 0, trackWidth); - } + // Adjust handlePosition relative to the track's start position + handlePosition = Mathf.clamp(mouseX - trackStart, 0, trackWidth); + } - private void updateValue() { - Insets insets = getInsets(); - int trackWidth = getWidth() - insets.getHorizontalInsets(); + private void updateValue() { + Insets insets = getInsets(); + int trackWidth = getWidth() - insets.getHorizontalInsets(); - value = Mathf.map(handlePosition, 0, trackWidth, minValue, maxValue); - } + value = Mathf.map(handlePosition, 0, trackWidth, minValue, maxValue); + } - public float getValue() { - return value; - } + public float getValue() { + return value; + } - public void setValue(float value) { - this.value = Mathf.clamp(value, minValue, maxValue); - updateHandlePositionFromValue(); - } + public void setValue(float value) { + this.value = Mathf.clamp(value, minValue, maxValue); + updateHandlePositionFromValue(); + } - private void updateHandlePositionFromValue() { - Insets insets = getInsets(); - int trackWidth = getWidth() - insets.getHorizontalInsets(); + private void updateHandlePositionFromValue() { + Insets insets = getInsets(); + int trackWidth = getWidth() - insets.getHorizontalInsets(); -// handlePosition = Mathf.map(value, minValue, maxValue, 0, trackWidth); - } + // handlePosition = Mathf.map(value, minValue, maxValue, 0, trackWidth); + } - public float getMinValue() { - return minValue; - } + public float getMinValue() { + return minValue; + } - public void setMinValue(float minValue) { - this.minValue = minValue; - updateHandlePositionFromValue(); - } + public void setMinValue(float minValue) { + this.minValue = minValue; + updateHandlePositionFromValue(); + } - public float getMaxValue() { - return maxValue; - } + public float getMaxValue() { + return maxValue; + } - public void setMaxValue(float maxValue) { - this.maxValue = maxValue; - updateHandlePositionFromValue(); - } + public void setMaxValue(float maxValue) { + this.maxValue = maxValue; + updateHandlePositionFromValue(); + } - public String getText() { - return text; - } + public String getText() { + return text; + } - public void setText(String text) { - this.text = text; - } + public void setText(String text) { + this.text = text; + } - public ISliderCallBack getSliderCallback() { - return callback; - } - - public void setSliderCallBack(ISliderCallBack callback) { - this.callback = callback; - } - - public float getHandlePosition() { - return handlePosition; - } + public ISliderCallBack getSliderCallback() { + return callback; + } + public void setSliderCallBack(ISliderCallBack callback) { + this.callback = callback; + } + + public float getHandlePosition() { + return handlePosition; + } } diff --git a/src/main/java/workspace/ui/elements/ViewportCompass.java b/src/main/java/workspace/ui/elements/ViewportCompass.java index 7a6f9c50..f8067074 100644 --- a/src/main/java/workspace/ui/elements/ViewportCompass.java +++ b/src/main/java/workspace/ui/elements/ViewportCompass.java @@ -15,144 +15,133 @@ import workspace.ui.UiComponent; /** - * Represents a simple viewport compass in the upper-right corner of the mesh - * viewer UI. The compass visualizes the current rotation/orientation of the - * viewport in 3D space. This component is non-interactive and purely for - * visualization purposes. + * Represents a simple viewport compass in the upper-right corner of the mesh viewer UI. The compass + * visualizes the current rotation/orientation of the viewport in 3D space. This component is + * non-interactive and purely for visualization purposes. */ public class ViewportCompass extends UiComponent { - private static final float DEFAULT_HEIGHT = 2; - - private static final float DEFAULT_SIZE = 10; - - private float size; - - private float height; - - private Vector3f rotation; - - private Mesh3D cube; - - private Mesh3D coneX; - - private Mesh3D coneY; - - private Mesh3D coneZ; - - /** - * Default constructor initializes the compass with default height, size, and - * creates all required meshes for rendering the compass. - */ - public ViewportCompass() { - this.size = DEFAULT_SIZE; - this.height = DEFAULT_HEIGHT; - this.rotation = new Vector3f(); - createMeshes(); - } - - /** - * Renders the viewport compass in the UI's graphics context. This method sets - * the translation, applies rotations, and renders the gizmo axes and center - * mesh. - * - * @param g The graphics context for rendering. - */ - @Override - public void render(Graphics g) { - g.pushMatrix(); - g.translate(x, y); - g.rotateX(rotation.x); - g.rotateY(rotation.y); - g.rotateZ(rotation.z); - - renderMesh(g, cube, UiConstants.KEY_GIZMO_CENTER_COLOR); - renderMesh(g, coneX, UiConstants.KEY_GIZMO_AXIS_X_COLOR); - renderMesh(g, coneY, UiConstants.KEY_GIZMO_AXIS_Y_COLOR); - renderMesh(g, coneZ, UiConstants.KEY_GIZMO_AXIS_Z_COLOR); - - g.popMatrix(); - } - - /** - * Helper method to render a given mesh with its associated color key. - * - * @param g The graphics context for rendering. - * @param mesh The mesh to render. - * @param colorKey The key identifying the color to use from UiValues. - */ - private void renderMesh(Graphics g, Mesh3D mesh, String colorKey) { - g.setColor(UiValues.getColor(colorKey)); - g.fillFaces(mesh); - } - - /** - * Creates and initializes all necessary meshes for the compass visualization. - */ - private void createMeshes() { - createCube(); - createConeX(); - createConeY(); - createConeZ(); - } - - /** - * Creates the X-axis cone and applies necessary transformations to position - * and rotate it. - */ - private void createConeX() { - coneX = createCone(); - coneX.apply(new RotateZModifier(-Mathf.HALF_PI)); - coneX.apply(new TranslateModifier(height * size, 0, 0)); - } - - /** - * Creates the Y-axis cone and applies necessary transformations to position - * it in the Y direction. - */ - private void createConeY() { - coneY = createCone(); - coneY.apply(new TranslateModifier(0, height * size, 0)); - } - - /** - * Creates the Z-axis cone and applies transformations to rotate and position - * it in the Z direction. - */ - private void createConeZ() { - coneZ = createCone(); - coneZ.apply(new RotateXModifier(Mathf.HALF_PI)); - coneZ.apply(new TranslateModifier(0, 0, height * size)); - } - - /** - * Creates a cone mesh, scales it appropriately, and prepares it for - * rendering. - * - * @return The scaled and ready-to-render cone mesh. - */ - private Mesh3D createCone() { - Mesh3D cone = new ConeCreator().create(); - cone.apply(new ScaleModifier(size)); - return cone; - } - - /** - * Creates the central cube for visualization. - */ - private void createCube() { - cube = new CubeCreator(size).create(); - } - - /** - * Sets the viewport's rotation. - * - * @param rotation The desired rotation vector. - */ - public void setRotation(Vector3f rotation) { - this.rotation.setX(rotation.x); - this.rotation.setY(rotation.y); - this.rotation.setZ(rotation.z); - } - + private static final float DEFAULT_HEIGHT = 2; + + private static final float DEFAULT_SIZE = 10; + + private float size; + + private float height; + + private Vector3f rotation; + + private Mesh3D cube; + + private Mesh3D coneX; + + private Mesh3D coneY; + + private Mesh3D coneZ; + + /** + * Default constructor initializes the compass with default height, size, and creates all required + * meshes for rendering the compass. + */ + public ViewportCompass() { + this.size = DEFAULT_SIZE; + this.height = DEFAULT_HEIGHT; + this.rotation = new Vector3f(); + createMeshes(); + } + + /** + * Renders the viewport compass in the UI's graphics context. This method sets the translation, + * applies rotations, and renders the gizmo axes and center mesh. + * + * @param g The graphics context for rendering. + */ + @Override + public void render(Graphics g) { + g.pushMatrix(); + g.translate(x, y); + g.rotateX(rotation.x); + g.rotateY(rotation.y); + g.rotateZ(rotation.z); + + renderMesh(g, cube, UiConstants.KEY_GIZMO_CENTER_COLOR); + renderMesh(g, coneX, UiConstants.KEY_GIZMO_AXIS_X_COLOR); + renderMesh(g, coneY, UiConstants.KEY_GIZMO_AXIS_Y_COLOR); + renderMesh(g, coneZ, UiConstants.KEY_GIZMO_AXIS_Z_COLOR); + + g.popMatrix(); + } + + /** + * Helper method to render a given mesh with its associated color key. + * + * @param g The graphics context for rendering. + * @param mesh The mesh to render. + * @param colorKey The key identifying the color to use from UiValues. + */ + private void renderMesh(Graphics g, Mesh3D mesh, String colorKey) { + g.setColor(UiValues.getColor(colorKey)); + g.fillFaces(mesh); + } + + /** Creates and initializes all necessary meshes for the compass visualization. */ + private void createMeshes() { + createCube(); + createConeX(); + createConeY(); + createConeZ(); + } + + /** Creates the X-axis cone and applies necessary transformations to position and rotate it. */ + private void createConeX() { + coneX = createCone(); + coneX.apply(new RotateZModifier(-Mathf.HALF_PI)); + coneX.apply(new TranslateModifier(height * size, 0, 0)); + } + + /** + * Creates the Y-axis cone and applies necessary transformations to position it in the Y + * direction. + */ + private void createConeY() { + coneY = createCone(); + coneY.apply(new TranslateModifier(0, height * size, 0)); + } + + /** + * Creates the Z-axis cone and applies transformations to rotate and position it in the Z + * direction. + */ + private void createConeZ() { + coneZ = createCone(); + coneZ.apply(new RotateXModifier(Mathf.HALF_PI)); + coneZ.apply(new TranslateModifier(0, 0, height * size)); + } + + /** + * Creates a cone mesh, scales it appropriately, and prepares it for rendering. + * + * @return The scaled and ready-to-render cone mesh. + */ + private Mesh3D createCone() { + Mesh3D cone = new ConeCreator().create(); + cone.apply(new ScaleModifier(size)); + return cone; + } + + /** Creates the central cube for visualization. */ + private void createCube() { + cube = new CubeCreator(size).create(); + } + + /** + * Sets the viewport's rotation. + * + * @param rotation The desired rotation vector. + */ + public void setRotation(Vector3f rotation) { + this.rotation.setX(rotation.x); + this.rotation.setY(rotation.y); + this.rotation.setZ(rotation.z); + } } diff --git a/src/main/java/workspace/ui/event/EventManager.java b/src/main/java/workspace/ui/event/EventManager.java new file mode 100644 index 00000000..7ecf85a1 --- /dev/null +++ b/src/main/java/workspace/ui/event/EventManager.java @@ -0,0 +1,54 @@ +package workspace.ui.event; + +import java.util.ArrayList; +import java.util.List; + +/** Central event manager for handling mouse events. */ +public class EventManager { + + private List listeners = new ArrayList<>(); + + /** + * Adds a listener to receive mouse events. + * + * @param listener Listener to add. + */ + public void addListener(MouseEventListener listener) { + if (listener != null && !listeners.contains(listener)) { + listeners.add(listener); + } + } + + /** + * Removes a listener from receiving mouse events. + * + * @param listener Listener to remove. + */ + public void removeListener(MouseEventListener listener) { + listeners.remove(listener); + } + + public void dispatchMouseClicked(MouseEvent e) { + for (MouseEventListener listener : listeners) { + listener.onMouseClicked(e); + } + } + + public void dispatchMouseDragged(MouseEvent e) { + for (MouseEventListener listener : listeners) { + listener.onMouseDragged(e); + } + } + + public void dispatchMouseReleased(MouseEvent e) { + for (MouseEventListener listener : listeners) { + listener.onMouseReleased(e); + } + } + + public void dispatchMousePressed(MouseEvent e) { + for (MouseEventListener listener : listeners) { + listener.onMousePressed(e); + } + } +} diff --git a/src/main/java/workspace/ui/event/IActionListener.java b/src/main/java/workspace/ui/event/IActionListener.java index 1bf31956..dfb464f5 100644 --- a/src/main/java/workspace/ui/event/IActionListener.java +++ b/src/main/java/workspace/ui/event/IActionListener.java @@ -2,21 +2,16 @@ /** * Represents a listener for action events in the UI framework. - *

- * Implementations of this interface can be used to handle user interactions, - * such as button clicks, menu selections, or other actions triggered within the - * user interface. - *

- * - *

- * To use this interface, implement the {@code onActionPerformed()} method and - * associate the listener with a UI component that supports actions, such as a - * button or menu item. - *

- * + * + *

Implementations of this interface can be used to handle user interactions, such as button + * clicks, menu selections, or other actions triggered within the user interface. + * + *

To use this interface, implement the {@code onActionPerformed()} method and associate the + * listener with a UI component that supports actions, such as a button or menu item. + * *

  * Example usage:
- * 
+ *
  * UiButton button = new UiButton("Click Me");
  * button.setActionListener(new IActionListener() {
  *     @Override
@@ -25,19 +20,15 @@
  *     }
  * });
  * 
- *

*/ public interface IActionListener { - /** - * Called when an action is performed. - *

- * This method is invoked in response to a user interaction with a UI - * component, such as clicking a button or selecting a menu item. - * Implementations should define the behavior to execute when the action - * occurs. - *

- */ - void onActionPerformed(); - -} \ No newline at end of file + /** + * Called when an action is performed. + * + *

This method is invoked in response to a user interaction with a UI component, such as + * clicking a button or selecting a menu item. Implementations should define the behavior to + * execute when the action occurs. + */ + void onActionPerformed(); +} diff --git a/src/main/java/workspace/ui/event/ISliderCallBack.java b/src/main/java/workspace/ui/event/ISliderCallBack.java index 3c417fa8..f64eea80 100644 --- a/src/main/java/workspace/ui/event/ISliderCallBack.java +++ b/src/main/java/workspace/ui/event/ISliderCallBack.java @@ -2,6 +2,5 @@ public interface ISliderCallBack { - void valueChanged(float value); - + void valueChanged(float value); } diff --git a/src/main/java/workspace/ui/event/MouseEvent.java b/src/main/java/workspace/ui/event/MouseEvent.java index 086e781a..fc912947 100644 --- a/src/main/java/workspace/ui/event/MouseEvent.java +++ b/src/main/java/workspace/ui/event/MouseEvent.java @@ -1,17 +1,15 @@ package workspace.ui.event; /** - * Represents a mouse event, containing information about the current and - * previous mouse positions. - *

- * This class is used to encapsulate the state of the mouse during an event, - * such as mouse movement or mouse clicks. It provides details about the mouse's - * current coordinates as well as its previous position. - *

- * + * Represents a mouse event, containing information about the current and previous mouse positions. + * + *

This class is used to encapsulate the state of the mouse during an event, such as mouse + * movement or mouse clicks. It provides details about the mouse's current coordinates as well as + * its previous position. + * *

  * Example usage:
- * 
+ *
  * MouseEvent event = new MouseEvent(100, 200, 90, 180);
  * int currentX = event.getMouseX();
  * int previousX = event.getPreviousMouseX();
@@ -19,69 +17,66 @@
  */
 public class MouseEvent {
 
-	/** The current X-coordinate of the mouse. */
-	private final int mouseX;
+  /** The current X-coordinate of the mouse. */
+  private final int mouseX;
 
-	/** The current Y-coordinate of the mouse. */
-	private final int mouseY;
+  /** The current Y-coordinate of the mouse. */
+  private final int mouseY;
 
-	/** The previous X-coordinate of the mouse. */
-	private final int previousMouseX;
+  /** The previous X-coordinate of the mouse. */
+  private final int previousMouseX;
 
-	/** The previous Y-coordinate of the mouse. */
-	private final int previousMouseY;
+  /** The previous Y-coordinate of the mouse. */
+  private final int previousMouseY;
 
-	/**
-	 * Constructs a new {@code MouseEvent} with the specified current and previous
-	 * mouse coordinates.
-	 * 
-	 * @param mouseX         The current X-coordinate of the mouse.
-	 * @param mouseY         The current Y-coordinate of the mouse.
-	 * @param previousMouseX The previous X-coordinate of the mouse.
-	 * @param previousMouseY The previous Y-coordinate of the mouse.
-	 */
-	public MouseEvent(int mouseX, int mouseY, int previousMouseX,
-	    int previousMouseY) {
-		this.mouseX = mouseX;
-		this.mouseY = mouseY;
-		this.previousMouseX = previousMouseX;
-		this.previousMouseY = previousMouseY;
-	}
+  /**
+   * Constructs a new {@code MouseEvent} with the specified current and previous mouse coordinates.
+   *
+   * @param mouseX The current X-coordinate of the mouse.
+   * @param mouseY The current Y-coordinate of the mouse.
+   * @param previousMouseX The previous X-coordinate of the mouse.
+   * @param previousMouseY The previous Y-coordinate of the mouse.
+   */
+  public MouseEvent(int mouseX, int mouseY, int previousMouseX, int previousMouseY) {
+    this.mouseX = mouseX;
+    this.mouseY = mouseY;
+    this.previousMouseX = previousMouseX;
+    this.previousMouseY = previousMouseY;
+  }
 
-	/**
-	 * Gets the current X-coordinate of the mouse.
-	 * 
-	 * @return The current X-coordinate.
-	 */
-	public int getMouseX() {
-		return mouseX;
-	}
+  /**
+   * Gets the current X-coordinate of the mouse.
+   *
+   * @return The current X-coordinate.
+   */
+  public int getMouseX() {
+    return mouseX;
+  }
 
-	/**
-	 * Gets the current Y-coordinate of the mouse.
-	 * 
-	 * @return The current Y-coordinate.
-	 */
-	public int getMouseY() {
-		return mouseY;
-	}
+  /**
+   * Gets the current Y-coordinate of the mouse.
+   *
+   * @return The current Y-coordinate.
+   */
+  public int getMouseY() {
+    return mouseY;
+  }
 
-	/**
-	 * Gets the previous X-coordinate of the mouse.
-	 * 
-	 * @return The previous X-coordinate.
-	 */
-	public int getPreviousMouseX() {
-		return previousMouseX;
-	}
+  /**
+   * Gets the previous X-coordinate of the mouse.
+   *
+   * @return The previous X-coordinate.
+   */
+  public int getPreviousMouseX() {
+    return previousMouseX;
+  }
 
-	/**
-	 * Gets the previous Y-coordinate of the mouse.
-	 * 
-	 * @return The previous Y-coordinate.
-	 */
-	public int getPreviousMouseY() {
-		return previousMouseY;
-	}
-
-}
\ No newline at end of file
+  /**
+   * Gets the previous Y-coordinate of the mouse.
+   *
+   * @return The previous Y-coordinate.
+   */
+  public int getPreviousMouseY() {
+    return previousMouseY;
+  }
+}
diff --git a/src/main/java/workspace/ui/event/MouseEventListener.java b/src/main/java/workspace/ui/event/MouseEventListener.java
new file mode 100644
index 00000000..c9ee943f
--- /dev/null
+++ b/src/main/java/workspace/ui/event/MouseEventListener.java
@@ -0,0 +1,13 @@
+package workspace.ui.event;
+
+/** Interface for listening to mouse-related events. */
+public interface MouseEventListener {
+
+  void onMouseClicked(MouseEvent e);
+
+  void onMouseDragged(MouseEvent e);
+
+  void onMouseReleased(MouseEvent e);
+
+  void onMousePressed(MouseEvent e);
+}
diff --git a/src/main/java/workspace/ui/layout/Layout.java b/src/main/java/workspace/ui/layout/Layout.java
index edb398b6..7cce21c0 100644
--- a/src/main/java/workspace/ui/layout/Layout.java
+++ b/src/main/java/workspace/ui/layout/Layout.java
@@ -4,37 +4,28 @@
 
 /**
  * Interface: Layout
- * 
- * Defines the contract for applying a layout strategy to a given
- * {@link workspace.ui.elements.UiElement}. The layout logic determines how a UI
- * element's child components are positioned, sized, and arranged within its
- * allocated space based on specific layout rules. This abstraction allows
- * flexible and reusable layout behaviors to be implemented independently of the
- * actual UI element logic.
- * 
- * 

- * Implementations of this interface can represent various layout strategies - * such as grid-based alignment, horizontal stacking, vertical stacking, or - * custom user-defined layouts. - *

- * + * + *

Defines the contract for applying a layout strategy to a given {@link + * workspace.ui.elements.UiElement}. The layout logic determines how a UI element's child components + * are positioned, sized, and arranged within its allocated space based on specific layout rules. + * This abstraction allows flexible and reusable layout behaviors to be implemented independently of + * the actual UI element logic. + * + *

Implementations of this interface can represent various layout strategies such as grid-based + * alignment, horizontal stacking, vertical stacking, or custom user-defined layouts. + * * @see workspace.ui.elements.UiElement */ public interface Layout { - /** - * Applies the layout logic to the specified UI element and its children. - * - *

- * This method should compute and set the positions, sizes, and other layout - * properties of the provided {@code UiElement} and its child elements - * according to the specific layout strategy implemented by the concrete - * class. - *

- * - * @param uiElement The UI element to which the layout logic should be - * applied. - */ - void layout(UiElement uiElement); - -} \ No newline at end of file + /** + * Applies the layout logic to the specified UI element and its children. + * + *

This method should compute and set the positions, sizes, and other layout properties of the + * provided {@code UiElement} and its child elements according to the specific layout strategy + * implemented by the concrete class. + * + * @param uiElement The UI element to which the layout logic should be applied. + */ + void layout(UiElement uiElement); +} diff --git a/src/main/java/workspace/ui/renderer/ButtonRenderer.java b/src/main/java/workspace/ui/renderer/ButtonRenderer.java index a2f0de48..2239d86e 100644 --- a/src/main/java/workspace/ui/renderer/ButtonRenderer.java +++ b/src/main/java/workspace/ui/renderer/ButtonRenderer.java @@ -6,39 +6,38 @@ /** * Renderer implementation for the {@code UiButton} component. - *

- * Handles the visual representation of the button, including its background, - * text, and dimensions. - *

+ * + *

Handles the visual representation of the button, including its background, text, and + * dimensions. */ public class ButtonRenderer implements Renderer { - @Override - public void render(Graphics g, UiElement component) { - if (!(component instanceof UiButton)) - return; - - UiButton button = (UiButton) component; - String text = button.getText(); - - // Measure text width and height - int textWidth = (int) g.textWidth(text); - int textHeight = (int) (g.textAscent() + g.textDescent()); - - // Adjust button dimensions to fit text if necessary - button.setWidth(Math.max(button.getWidth(), textWidth)); - button.setHeight(Math.max(button.getHeight(), textHeight)); - - // Draw button background - g.setColor(button.getBackground()); - g.fillRect(0, 0, button.getWidth(), button.getHeight()); - - // Draw button text - if (text != null && !text.isEmpty()) { - g.setColor(button.getForeground()); - g.text(text, (button.getWidth() - textWidth) / 2, - (button.getHeight() + textHeight) / 2 - g.textDescent()); - } - } - -} \ No newline at end of file + @Override + public void render(Graphics g, UiElement component) { + if (!(component instanceof UiButton)) return; + + UiButton button = (UiButton) component; + String text = button.getText(); + + // Measure text width and height + int textWidth = (int) g.textWidth(text); + int textHeight = (int) (g.textAscent() + g.textDescent()); + + // Adjust button dimensions to fit text if necessary + button.setWidth(Math.max(button.getWidth(), textWidth)); + button.setHeight(Math.max(button.getHeight(), textHeight)); + + // Draw button background + g.setColor(button.getBackground()); + g.fillRect(0, 0, button.getWidth(), button.getHeight()); + + // Draw button text + if (text != null && !text.isEmpty()) { + g.setColor(button.getForeground()); + g.text( + text, + (button.getWidth() - textWidth) / 2, + (button.getHeight() + textHeight) / 2 - g.textDescent()); + } + } +} diff --git a/src/main/java/workspace/ui/renderer/CheckBoxRenderer.java b/src/main/java/workspace/ui/renderer/CheckBoxRenderer.java index 0f17fad2..0a5ee8f5 100644 --- a/src/main/java/workspace/ui/renderer/CheckBoxRenderer.java +++ b/src/main/java/workspace/ui/renderer/CheckBoxRenderer.java @@ -7,39 +7,34 @@ /** * Renderer implementation for rendering the {@code UiCheckBox}. - *

- * Responsible for drawing the checkbox, its state (checked/unchecked), and its - * label text. - *

+ * + *

Responsible for drawing the checkbox, its state (checked/unchecked), and its label text. */ public class CheckBoxRenderer implements Renderer { - @Override - public void render(Graphics g, UiElement element) { - if (!(element instanceof UiCheckBox)) - return; - - UiCheckBox checkBox = (UiCheckBox) element; - Insets insets = checkBox.getInsets(); - int offsetX = insets.getLeft(); - int offsetY = insets.getTop(); - int boxWidth = checkBox.getWidth() - insets.getHorizontalInsets(); - int boxHeight = checkBox.getHeight() - insets.getVerticalInsets(); - - // Render checkbox box - g.setColor(checkBox.getBackground()); - g.fillRect(offsetX, offsetY, boxWidth, boxHeight); - - // If checked, fill the inner box with checkmark - if (checkBox.isSelected()) { - g.setColor(checkBox.getForeground()); - g.fillRect(offsetX + 4, offsetY + 4, boxWidth - 8, boxHeight - 8); - } - - // Render text - g.setColor(checkBox.getForeground()); - g.text(checkBox.getText(), offsetX + boxWidth + 4, - offsetY + (boxHeight / 2)); - } - -} \ No newline at end of file + @Override + public void render(Graphics g, UiElement element) { + if (!(element instanceof UiCheckBox)) return; + + UiCheckBox checkBox = (UiCheckBox) element; + Insets insets = checkBox.getInsets(); + int offsetX = insets.getLeft(); + int offsetY = insets.getTop(); + int boxWidth = checkBox.getWidth() - insets.getHorizontalInsets(); + int boxHeight = checkBox.getHeight() - insets.getVerticalInsets(); + + // Render checkbox box + g.setColor(checkBox.getBackground()); + g.fillRect(offsetX, offsetY, boxWidth, boxHeight); + + // If checked, fill the inner box with checkmark + if (checkBox.isSelected()) { + g.setColor(checkBox.getForeground()); + g.fillRect(offsetX + 4, offsetY + 4, boxWidth - 8, boxHeight - 8); + } + + // Render text + g.setColor(checkBox.getForeground()); + g.text(checkBox.getText(), offsetX + boxWidth + 4, offsetY + (boxHeight / 2)); + } +} diff --git a/src/main/java/workspace/ui/renderer/EditorMenuRenderer.java b/src/main/java/workspace/ui/renderer/EditorMenuRenderer.java index 6cd82153..0601d0dc 100644 --- a/src/main/java/workspace/ui/renderer/EditorMenuRenderer.java +++ b/src/main/java/workspace/ui/renderer/EditorMenuRenderer.java @@ -8,39 +8,36 @@ /** * Renderer implementation for the {@code UiEditorMenu} component. - *

- * Handles drawing the background, text, and decorative lines of the editor - * menu, using styles defined in the Look and Feel (LAF) system. - *

+ * + *

Handles drawing the background, text, and decorative lines of the editor menu, using styles + * defined in the Look and Feel (LAF) system. */ public class EditorMenuRenderer implements Renderer { - @Override - public void render(Graphics g, UiElement element) { - if (!(element instanceof UiEditorMenu)) - return; - - UiEditorMenu menu = (UiEditorMenu) element; - String text = menu.getText(); - - // Draw the dark header bar - g.setColor(66, 66, 66); - g.fillRect(0, 0, g.getWidth(), 55); - - // Draw the menu background - g.setColor(menu.getBackground()); - g.fillRect(0, 0, g.getWidth(), 30); - - // Draw the menu text - if (text != null && !text.isEmpty()) { - g.setColor(menu.getForeground()); - g.textSize(UiValues.getInt(UiConstants.KEY_MENU_TEXT_SIZE)); - g.text(text, 10, 20); - } - - // Draw the bottom divider line - g.setColor(31, 31, 31); - g.fillRect(0, 28, g.getWidth(), 1); - } - -} \ No newline at end of file + @Override + public void render(Graphics g, UiElement element) { + if (!(element instanceof UiEditorMenu)) return; + + UiEditorMenu menu = (UiEditorMenu) element; + String text = menu.getText(); + + // Draw the dark header bar + g.setColor(66, 66, 66); + g.fillRect(0, 0, g.getWidth(), 55); + + // Draw the menu background + g.setColor(menu.getBackground()); + g.fillRect(0, 0, g.getWidth(), 30); + + // Draw the menu text + if (text != null && !text.isEmpty()) { + g.setColor(menu.getForeground()); + g.textSize(UiValues.getInt(UiConstants.KEY_MENU_TEXT_SIZE)); + g.text(text, 10, 20); + } + + // Draw the bottom divider line + g.setColor(31, 31, 31); + g.fillRect(0, 28, g.getWidth(), 1); + } +} diff --git a/src/main/java/workspace/ui/renderer/LabelRenderer.java b/src/main/java/workspace/ui/renderer/LabelRenderer.java index e7d5b6db..b486d553 100644 --- a/src/main/java/workspace/ui/renderer/LabelRenderer.java +++ b/src/main/java/workspace/ui/renderer/LabelRenderer.java @@ -7,38 +7,33 @@ /** * Renderer implementation for rendering {@code UiLabel} components. - *

- * Handles the drawing of the label's background, text, and ensures proper - * alignment. - *

+ * + *

Handles the drawing of the label's background, text, and ensures proper alignment. */ public class LabelRenderer implements Renderer { - @Override - public void render(Graphics g, UiElement element) { - if (!(element instanceof UiLabel)) - return; + @Override + public void render(Graphics g, UiElement element) { + if (!(element instanceof UiLabel)) return; - UiLabel label = (UiLabel) element; - String title = label.getTitle(); - if (title == null || title.isEmpty()) - return; + UiLabel label = (UiLabel) element; + String title = label.getTitle(); + if (title == null || title.isEmpty()) return; - Insets insets = element.getInsets(); - int x = insets.getLeft(); - int y = insets.getTop(); + Insets insets = element.getInsets(); + int x = insets.getLeft(); + int y = insets.getTop(); - // Calculate text dimensions - float textWidth = g.textWidth(title); - float textHeight = g.textAscent() + g.textDescent(); + // Calculate text dimensions + float textWidth = g.textWidth(title); + float textHeight = g.textAscent() + g.textDescent(); - // Render background - g.setColor(label.getBackground()); - g.fillRect(x, y, textWidth, textHeight); + // Render background + g.setColor(label.getBackground()); + g.fillRect(x, y, textWidth, textHeight); - // Render text - g.setColor(label.getForeground()); - g.text(title, x, y + g.textAscent()); - } - -} \ No newline at end of file + // Render text + g.setColor(label.getForeground()); + g.text(title, x, y + g.textAscent()); + } +} diff --git a/src/main/java/workspace/ui/renderer/PanelRenderer.java b/src/main/java/workspace/ui/renderer/PanelRenderer.java index beffc9bd..9448f1c2 100644 --- a/src/main/java/workspace/ui/renderer/PanelRenderer.java +++ b/src/main/java/workspace/ui/renderer/PanelRenderer.java @@ -5,41 +5,34 @@ import workspace.ui.elements.UiElement; /** - * Default implementation of the {@link Renderer} interface for rendering a - * standard panel. - *

- * This class provides a simple rendering strategy by drawing a solid background - * rectangle for a given {@code UiElement} based on its background color and - * insets. It ensures that rendering respects the defined padding or margins - * (insets) and only draws if a background color is set. - *

+ * Default implementation of the {@link Renderer} interface for rendering a standard panel. + * + *

This class provides a simple rendering strategy by drawing a solid background rectangle for a + * given {@code UiElement} based on its background color and insets. It ensures that rendering + * respects the defined padding or margins (insets) and only draws if a background color is set. */ public class PanelRenderer implements Renderer { - /** - * Renders the panel's background onto the given graphics context. - *

- * The rendering accounts for the insets (margins or padding) defined by the - * element's layout and only fills the visible area with the panel's - * background color if it is set. - *

- * - * @param g The {@link Graphics} object used for rendering. - * @param element The {@link UiElement} representing the UI component to - * render. - */ - @Override - public void render(Graphics g, UiElement element) { - Insets insets = element.getInsets(); - int x = insets.getLeft(); - int y = insets.getTop(); - int width = element.getWidth() - insets.getHorizontalInsets(); - int height = element.getHeight() - insets.getVerticalInsets(); + /** + * Renders the panel's background onto the given graphics context. + * + *

The rendering accounts for the insets (margins or padding) defined by the element's layout + * and only fills the visible area with the panel's background color if it is set. + * + * @param g The {@link Graphics} object used for rendering. + * @param element The {@link UiElement} representing the UI component to render. + */ + @Override + public void render(Graphics g, UiElement element) { + Insets insets = element.getInsets(); + int x = insets.getLeft(); + int y = insets.getTop(); + int width = element.getWidth() - insets.getHorizontalInsets(); + int height = element.getHeight() - insets.getVerticalInsets(); - if (element.getBackground() != null) { - g.setColor(element.getBackground()); - g.fillRect(x, y, width, height); - } - } - -} \ No newline at end of file + if (element.getBackground() != null) { + g.setColor(element.getBackground()); + g.fillRect(x, y, width, height); + } + } +} diff --git a/src/main/java/workspace/ui/renderer/Renderer.java b/src/main/java/workspace/ui/renderer/Renderer.java index 13a1347d..47431ed3 100644 --- a/src/main/java/workspace/ui/renderer/Renderer.java +++ b/src/main/java/workspace/ui/renderer/Renderer.java @@ -5,38 +5,30 @@ /** * Interface: Renderer - * - * Defines the contract for rendering UI elements onto a provided Graphics - * context. This abstraction allows different rendering strategies to be - * implemented, promoting flexibility and loose coupling in the rendering logic. - * Implementations of this interface are responsible for visually representing - * {@link workspace.ui.elements.UiElement} instances, including their layout, + * + *

Defines the contract for rendering UI elements onto a provided Graphics context. This + * abstraction allows different rendering strategies to be implemented, promoting flexibility and + * loose coupling in the rendering logic. Implementations of this interface are responsible for + * visually representing {@link workspace.ui.elements.UiElement} instances, including their layout, * visual properties, and child components. - * - *

- * The Renderer allows for customizable rendering implementations, such as 2D, - * 3D, or other rendering pipelines without requiring changes to the underlying - * UI component logic. - *

- * + * + *

The Renderer allows for customizable rendering implementations, such as 2D, 3D, or other + * rendering pipelines without requiring changes to the underlying UI component logic. + * * @see workspace.ui.elements.UiElement * @see workspace.ui.Graphics */ public interface Renderer { - /** - * Renders a given UI element on the specified Graphics context. - * - *

- * Implementations of this method will handle drawing the provided - * {@code UiElement} onto the rendering surface represented by the given - * {@code Graphics} context. This includes handling UI styles, dimensions, - * borders, backgrounds, or any visual representation logic. - *

- * - * @param g The Graphics context where the rendering will occur. - * @param element The UiElement instance to render. - */ - void render(Graphics g, UiElement element); - -} \ No newline at end of file + /** + * Renders a given UI element on the specified Graphics context. + * + *

Implementations of this method will handle drawing the provided {@code UiElement} onto the + * rendering surface represented by the given {@code Graphics} context. This includes handling UI + * styles, dimensions, borders, backgrounds, or any visual representation logic. + * + * @param g The Graphics context where the rendering will occur. + * @param element The UiElement instance to render. + */ + void render(Graphics g, UiElement element); +} diff --git a/src/main/java/workspace/ui/renderer/SliderRenderer.java b/src/main/java/workspace/ui/renderer/SliderRenderer.java index 91d37070..e89d65b2 100644 --- a/src/main/java/workspace/ui/renderer/SliderRenderer.java +++ b/src/main/java/workspace/ui/renderer/SliderRenderer.java @@ -5,43 +5,39 @@ import workspace.ui.elements.UiElement; import workspace.ui.elements.UiSlider; -/** - * Renderer for the slider component. - */ +/** Renderer for the slider component. */ public class SliderRenderer implements Renderer { - @Override - public void render(Graphics g, UiElement element) { - UiSlider slider = (UiSlider) element; - Insets insets = slider.getInsets(); - - int trackStartX = insets.getLeft(); - int trackStartY = insets.getTop(); - int trackWidth = slider.getWidth() - insets.getHorizontalInsets(); - int trackHeight = slider.getHeight() - insets.getVerticalInsets(); - - // Draw track - g.setColor(slider.getBackground()); - g.fillRect(trackStartX, trackStartY, trackWidth, trackHeight); - - // Draw filled portion -// g.setColor(slider.getForeground()); - g.setColor(60, 60, 60); - g.fillRect(trackStartX, trackStartY, (int) slider.getHandlePosition(), - trackHeight); - - // Draw handle - g.setColor(slider.getForeground()); - int handleWidth = 5; - int handleX = (int) (trackStartX + slider.getHandlePosition() - - handleWidth / 2); - g.fillRect(handleX, trackStartY, handleWidth, trackHeight); - - // Draw label and value - g.setColor(slider.getForeground()); - g.text(slider.getText() + ":" + slider.getValue(), - insets.getLeft() + slider.getWidth() + 10, - g.getTextSize() + g.textDescent()); - } - -} \ No newline at end of file + @Override + public void render(Graphics g, UiElement element) { + UiSlider slider = (UiSlider) element; + Insets insets = slider.getInsets(); + + int trackStartX = insets.getLeft(); + int trackStartY = insets.getTop(); + int trackWidth = slider.getWidth() - insets.getHorizontalInsets(); + int trackHeight = slider.getHeight() - insets.getVerticalInsets(); + + // Draw track + g.setColor(slider.getBackground()); + g.fillRect(trackStartX, trackStartY, trackWidth, trackHeight); + + // Draw filled portion + // g.setColor(slider.getForeground()); + g.setColor(60, 60, 60); + g.fillRect(trackStartX, trackStartY, (int) slider.getHandlePosition(), trackHeight); + + // Draw handle + g.setColor(slider.getForeground()); + int handleWidth = 5; + int handleX = (int) (trackStartX + slider.getHandlePosition() - handleWidth / 2); + g.fillRect(handleX, trackStartY, handleWidth, trackHeight); + + // Draw label and value + g.setColor(slider.getForeground()); + g.text( + slider.getText() + ":" + slider.getValue(), + insets.getLeft() + slider.getWidth() + 10, + g.getTextSize() + g.textDescent()); + } +} diff --git a/src/main/java/workspace/ui/ui3d/Axis3D.java b/src/main/java/workspace/ui/ui3d/Axis3D.java index 375ccc27..602a14df 100644 --- a/src/main/java/workspace/ui/ui3d/Axis3D.java +++ b/src/main/java/workspace/ui/ui3d/Axis3D.java @@ -5,192 +5,171 @@ import workspace.ui.Graphics; /** - * Represents a 3D axis visualization that can be rendered with customizable - * visibility for each axis. Each axis is drawn with its corresponding color, as - * defined by the UI constants, and can be toggled on or off individually. - *

- * The axis lines are rendered in the X, Y, and Z directions, with their lengths - * determined by the specified size parameter. - *

+ * Represents a 3D axis visualization that can be rendered with customizable visibility for each + * axis. Each axis is drawn with its corresponding color, as defined by the UI constants, and can be + * toggled on or off individually. + * + *

The axis lines are rendered in the X, Y, and Z directions, with their lengths determined by + * the specified size parameter. */ public class Axis3D { - /** - * Visibility flag for the X-axis. - */ - private boolean xAxisVisible; - - /** - * Visibility flag for the Y-axis. - */ - private boolean yAxisVisible; - - /** - * Visibility flag for the Z-axis. - */ - private boolean zAxisVisible; - - /** - * The length of each axis, extending equally in both positive and negative - * directions. - */ - private float size; - - /** - * Constructs an {@code Axis3D} with the specified size. All axes are visible - * by default. - * - * @param size the length of each axis; must be positive - * @throws IllegalArgumentException if the size is not positive - */ - public Axis3D(float size) { - if (size <= 0) { - throw new IllegalArgumentException("Size must be positive."); - } - this.size = size; - this.xAxisVisible = true; - this.yAxisVisible = true; - this.zAxisVisible = true; - } - - /** - * Renders the 3D axis using the provided {@link Graphics} context. The axis - * lines are drawn based on their visibility flags and scaled according to the - * specified stroke weight factor. - * - * @param g the {@link Graphics} context to draw on - * @param scale the scale factor for adjusting the stroke weight; must be - * positive - */ - public void render(Graphics g, float scale) { - if (scale <= 0) { - throw new IllegalArgumentException("Scale must be positive."); - } - g.pushMatrix(); - g.strokeWeight(1.5f / scale); - renderXAxis(g); - renderYAxis(g); - renderZAxis(g); - g.popMatrix(); - } - - /** - * Renders the X-axis if it is visible. The X-axis is drawn in the positive - * and negative X directions with the color defined by - * {@link UiConstants#KEY_AXIS_X_COLOR}. - * - * @param g the {@link Graphics} context to draw on - */ - private void renderXAxis(Graphics g) { - if (!xAxisVisible) { - return; - } - g.setColor(UiValues.getColor(UiConstants.KEY_AXIS_X_COLOR)); - g.drawLine(size, 0, 0, 0, 0, 0); - g.drawLine(-size, 0, 0, 0, 0, 0); - } - - /** - * Renders the Y-axis if it is visible. The Y-axis is drawn in the positive - * and negative Y directions with the color defined by - * {@link UiConstants#KEY_AXIS_Y_COLOR}. - * - * @param g the {@link Graphics} context to draw on - */ - private void renderYAxis(Graphics g) { - if (!yAxisVisible) { - return; - } - g.setColor(UiValues.getColor(UiConstants.KEY_AXIS_Y_COLOR)); - g.drawLine(0, size, 0, 0, 0, 0); - g.drawLine(0, -size, 0, 0, 0, 0); - } - - /** - * Renders the Z-axis if it is visible. The Z-axis is drawn in the positive - * and negative Z directions with the color defined by - * {@link UiConstants#KEY_AXIS_Z_COLOR}. - * - * @param g the {@link Graphics} context to draw on - */ - private void renderZAxis(Graphics g) { - if (!zAxisVisible) { - return; - } - g.setColor(UiValues.getColor(UiConstants.KEY_AXIS_Z_COLOR)); - g.drawLine(0, 0, size, 0, 0, 0); - g.drawLine(0, 0, -size, 0, 0, 0); - } - - /** - * Returns whether the X-axis is visible. - * - * @return {@code true} if the X-axis is visible; {@code false} otherwise - */ - public boolean isXAxisVisible() { - return xAxisVisible; - } - - /** - * Sets the visibility of the X-axis. - * - * @param xAxisVisible {@code true} to make the X-axis visible; {@code false} - * to hide it - */ - public void setXAxisVisible(boolean xAxisVisible) { - this.xAxisVisible = xAxisVisible; - } - - /** - * Returns whether the Y-axis is visible. - * - * @return {@code true} if the Y-axis is visible; {@code false} otherwise - */ - public boolean isYAxisVisible() { - return yAxisVisible; - } - - /** - * Sets the visibility of the Y-axis. - * - * @param yAxisVisible {@code true} to make the Y-axis visible; {@code false} - * to hide it - */ - public void setYAxisVisible(boolean yAxisVisible) { - this.yAxisVisible = yAxisVisible; - } - - /** - * Returns whether the Z-axis is visible. - * - * @return {@code true} if the Z-axis is visible; {@code false} otherwise - */ - public boolean isZAxisVisible() { - return zAxisVisible; - } - - /** - * Sets the visibility of the Z-axis. - * - * @param zAxisVisible {@code true} to make the Z-axis visible; {@code false} - * to hide it - */ - public void setZAxisVisible(boolean zAxisVisible) { - this.zAxisVisible = zAxisVisible; - } - - /** - * Sets the length of each axis, extending equally in both positive and - * negative directions. - * - * @param newSize the new size of the axes; must be positive - * @throws IllegalArgumentException if the new size is not positive - */ - public void setSize(float newSize) { - if (newSize <= 0) { - throw new IllegalArgumentException("Size must be positive."); - } - this.size = newSize; - } - -} \ No newline at end of file + /** Visibility flag for the X-axis. */ + private boolean xAxisVisible; + + /** Visibility flag for the Y-axis. */ + private boolean yAxisVisible; + + /** Visibility flag for the Z-axis. */ + private boolean zAxisVisible; + + /** The length of each axis, extending equally in both positive and negative directions. */ + private float size; + + /** + * Constructs an {@code Axis3D} with the specified size. All axes are visible by default. + * + * @param size the length of each axis; must be positive + * @throws IllegalArgumentException if the size is not positive + */ + public Axis3D(float size) { + if (size <= 0) { + throw new IllegalArgumentException("Size must be positive."); + } + this.size = size; + this.xAxisVisible = true; + this.yAxisVisible = true; + this.zAxisVisible = true; + } + + /** + * Renders the 3D axis using the provided {@link Graphics} context. The axis lines are drawn based + * on their visibility flags and scaled according to the specified stroke weight factor. + * + * @param g the {@link Graphics} context to draw on + * @param scale the scale factor for adjusting the stroke weight; must be positive + */ + public void render(Graphics g, float scale) { + if (scale <= 0) { + throw new IllegalArgumentException("Scale must be positive."); + } + g.pushMatrix(); + g.strokeWeight(1.5f / scale); + renderXAxis(g); + renderYAxis(g); + renderZAxis(g); + g.popMatrix(); + } + + /** + * Renders the X-axis if it is visible. The X-axis is drawn in the positive and negative X + * directions with the color defined by {@link UiConstants#KEY_AXIS_X_COLOR}. + * + * @param g the {@link Graphics} context to draw on + */ + private void renderXAxis(Graphics g) { + if (!xAxisVisible) { + return; + } + g.setColor(UiValues.getColor(UiConstants.KEY_AXIS_X_COLOR)); + g.drawLine(size, 0, 0, 0, 0, 0); + g.drawLine(-size, 0, 0, 0, 0, 0); + } + + /** + * Renders the Y-axis if it is visible. The Y-axis is drawn in the positive and negative Y + * directions with the color defined by {@link UiConstants#KEY_AXIS_Y_COLOR}. + * + * @param g the {@link Graphics} context to draw on + */ + private void renderYAxis(Graphics g) { + if (!yAxisVisible) { + return; + } + g.setColor(UiValues.getColor(UiConstants.KEY_AXIS_Y_COLOR)); + g.drawLine(0, size, 0, 0, 0, 0); + g.drawLine(0, -size, 0, 0, 0, 0); + } + + /** + * Renders the Z-axis if it is visible. The Z-axis is drawn in the positive and negative Z + * directions with the color defined by {@link UiConstants#KEY_AXIS_Z_COLOR}. + * + * @param g the {@link Graphics} context to draw on + */ + private void renderZAxis(Graphics g) { + if (!zAxisVisible) { + return; + } + g.setColor(UiValues.getColor(UiConstants.KEY_AXIS_Z_COLOR)); + g.drawLine(0, 0, size, 0, 0, 0); + g.drawLine(0, 0, -size, 0, 0, 0); + } + + /** + * Returns whether the X-axis is visible. + * + * @return {@code true} if the X-axis is visible; {@code false} otherwise + */ + public boolean isXAxisVisible() { + return xAxisVisible; + } + + /** + * Sets the visibility of the X-axis. + * + * @param xAxisVisible {@code true} to make the X-axis visible; {@code false} to hide it + */ + public void setXAxisVisible(boolean xAxisVisible) { + this.xAxisVisible = xAxisVisible; + } + + /** + * Returns whether the Y-axis is visible. + * + * @return {@code true} if the Y-axis is visible; {@code false} otherwise + */ + public boolean isYAxisVisible() { + return yAxisVisible; + } + + /** + * Sets the visibility of the Y-axis. + * + * @param yAxisVisible {@code true} to make the Y-axis visible; {@code false} to hide it + */ + public void setYAxisVisible(boolean yAxisVisible) { + this.yAxisVisible = yAxisVisible; + } + + /** + * Returns whether the Z-axis is visible. + * + * @return {@code true} if the Z-axis is visible; {@code false} otherwise + */ + public boolean isZAxisVisible() { + return zAxisVisible; + } + + /** + * Sets the visibility of the Z-axis. + * + * @param zAxisVisible {@code true} to make the Z-axis visible; {@code false} to hide it + */ + public void setZAxisVisible(boolean zAxisVisible) { + this.zAxisVisible = zAxisVisible; + } + + /** + * Sets the length of each axis, extending equally in both positive and negative directions. + * + * @param newSize the new size of the axes; must be positive + * @throws IllegalArgumentException if the new size is not positive + */ + public void setSize(float newSize) { + if (newSize <= 0) { + throw new IllegalArgumentException("Size must be positive."); + } + this.size = newSize; + } +} diff --git a/src/main/java/workspace/ui/ui3d/Grid3D.java b/src/main/java/workspace/ui/ui3d/Grid3D.java index a21f8f52..b2d6d6e0 100644 --- a/src/main/java/workspace/ui/ui3d/Grid3D.java +++ b/src/main/java/workspace/ui/ui3d/Grid3D.java @@ -7,101 +7,92 @@ /** * Represents a 3D grid visualization that can be rendered in a 3D UI space. - *

- * This class provides the logic for creating and rendering a 3D spatial grid - * with a given number of rows, columns, and cell size. It is designed to work - * with a custom 3D graphics rendering context, allowing visualization of UI - * layouts or spatial relationships. - *

+ * + *

This class provides the logic for creating and rendering a 3D spatial grid with a given number + * of rows, columns, and cell size. It is designed to work with a custom 3D graphics rendering + * context, allowing visualization of UI layouts or spatial relationships. */ public class Grid3D { - /** The number of rows in the 3D grid. */ - private int rows; + /** The number of rows in the 3D grid. */ + private int rows; - /** The number of columns in the 3D grid. */ - private int cols; + /** The number of columns in the 3D grid. */ + private int cols; - /** The size of each individual cell in the 3D grid. */ - private float size; + /** The size of each individual cell in the 3D grid. */ + private float size; - /** - * Indicates whether the 3D grid should currently be visible when rendered. - */ - private boolean visible; + /** Indicates whether the 3D grid should currently be visible when rendered. */ + private boolean visible; - /** - * Constructs a new {@code Grid3D} instance with the specified number of rows, - * columns, and cell size. - * - * @param rows The number of rows to create in the 3D grid. - * @param cols The number of columns to create in the 3D grid. - * @param size The size (width/height) of each individual cell in the 3D grid. - */ - public Grid3D(int rows, int cols, float size) { - this.rows = rows; - this.cols = cols; - this.size = size; - this.visible = true; - } + /** + * Constructs a new {@code Grid3D} instance with the specified number of rows, columns, and cell + * size. + * + * @param rows The number of rows to create in the 3D grid. + * @param cols The number of columns to create in the 3D grid. + * @param size The size (width/height) of each individual cell in the 3D grid. + */ + public Grid3D(int rows, int cols, float size) { + this.rows = rows; + this.cols = cols; + this.size = size; + this.visible = true; + } - /** - * Renders the 3D grid visualization using the provided graphics context. - *

- * This method only performs rendering if the grid is currently visible. The - * rendering logic draws a series of rectangles in a 3D space to represent the - * cells of the grid. It applies necessary transformations for proper - * alignment and orientation in a 3D context. - *

- * - * @param g The graphics context used for rendering the 3D grid. - */ - public void render(Graphics g) { - if (!isVisible()) { - return; - } - g.setColor(UiValues.getColor(UiConstants.KEY_GRID_COLOR)); - g.pushMatrix(); - g.rotateX(-Mathf.HALF_PI); - g.translate(-cols / 2.0f, -rows / 2.0f); - renderGridLines(g); - g.popMatrix(); - } + /** + * Renders the 3D grid visualization using the provided graphics context. + * + *

This method only performs rendering if the grid is currently visible. The rendering logic + * draws a series of rectangles in a 3D space to represent the cells of the grid. It applies + * necessary transformations for proper alignment and orientation in a 3D context. + * + * @param g The graphics context used for rendering the 3D grid. + */ + public void render(Graphics g) { + if (!isVisible()) { + return; + } + g.setColor(UiValues.getColor(UiConstants.KEY_GRID_COLOR)); + g.pushMatrix(); + g.rotateX(-Mathf.HALF_PI); + g.translate(-cols / 2.0f, -rows / 2.0f); + renderGridLines(g); + g.popMatrix(); + } - /** - * Renders the grid lines. - * - * @param g The graphics context used for rendering. - */ - private void renderGridLines(Graphics g) { - for (int i = 0; i < rows; i++) { - for (int j = 0; j < cols; j++) { - g.drawRect(j * size, i * size, size, size); - } - } - } + /** + * Renders the grid lines. + * + * @param g The graphics context used for rendering. + */ + private void renderGridLines(Graphics g) { + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + g.drawRect(j * size, i * size, size, size); + } + } + } - /** - * Checks whether the 3D grid visualization is currently visible. - * - * @return {@code true} if the 3D grid is visible; {@code false} otherwise. - */ - public boolean isVisible() { - return visible; - } + /** + * Checks whether the 3D grid visualization is currently visible. + * + * @return {@code true} if the 3D grid is visible; {@code false} otherwise. + */ + public boolean isVisible() { + return visible; + } - /** - * Sets the visibility state of the 3D grid visualization. - *

- * When set to {@code true}, the grid will be rendered during the next - * invocation of the {@code render} method. If set to {@code false}, rendering - * will be skipped. - *

- * - * @param visible The new visibility state of the 3D grid. - */ - public void setVisible(boolean visible) { - this.visible = visible; - } - -} \ No newline at end of file + /** + * Sets the visibility state of the 3D grid visualization. + * + *

When set to {@code true}, the grid will be rendered during the next invocation of the {@code + * render} method. If set to {@code false}, rendering will be skipped. + * + * @param visible The new visibility state of the 3D grid. + */ + public void setVisible(boolean visible) { + this.visible = visible; + } +}