package holeg.ui.view.canvas; import holeg.model.AbstractCanvasObject; import holeg.model.Edge; import holeg.model.GroupNode; import holeg.model.HolonObject; import holeg.model.HolonSwitch; import holeg.model.Node; import holeg.preferences.ColorPreference; import holeg.preferences.ImagePreference; import holeg.ui.model.GuiSettings; import holeg.ui.view.image.Import; import holeg.ui.view.main.Appearance; import holeg.utility.math.decimal.Format; import holeg.utility.math.vector.Vec2i; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.RenderingHints; class Rendering { private static final RenderingHints RenderingHint = new RenderingHints( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); private static final Font CanvasFont = new Font("TimesNewRoman", Font.PLAIN, Math.max((int) (GuiSettings.getPictureScale() / 3.5f), 10)); private static final BasicStroke OnePixelStroke = new BasicStroke(1); private static final BasicStroke TwoPixelStroke = new BasicStroke(2); private static final Dimension SupplyBarDimensions = new Dimension(GuiSettings.getPictureScale(), GuiSettings.getPictureScale() / 5); private static final Font SupplyBarFont = new Font("TimesNewRoman", Font.PLAIN, (int) (GuiSettings.getPictureScale() * 0.3) - 2); private static final Color[] GroupNodeBarColors = {ColorPreference.HolonObject.Producer, ColorPreference.HolonObject.NotSupplied, ColorPreference.HolonObject.PartiallySupplied, ColorPreference.HolonObject.Supplied, ColorPreference.HolonObject.OverSupplied, ColorPreference.HolonObject.NoEnergy}; static Graphics2D initGraphics2D(Graphics g) { Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHints(RenderingHint); g2d.setFont(CanvasFont); return g2d; } static void drawSwitchObject(Graphics2D g, HolonSwitch hS) { drawCanvasObject(g, hS); } static void drawHolonObject(Graphics2D g, HolonObject hO) { Vec2i pos = hO.getPosition(); Color stateColor = ColorPreference.HolonObject.getStateColor(hO.getState()); g.setColor(ColorPreference.Canvas.HolonObjectEnergy); if (Appearance.canvasObjectEnergyVisible) { final int gapBetweenRectAndEnergyString = 1; g.drawString(Format.doubleTwoPlaces(hO.getActualEnergy()), pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() - GuiSettings.getPictureScaleDiv2() - gapBetweenRectAndEnergyString); } g.setColor(stateColor); g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() - GuiSettings.getPictureScaleDiv2(), GuiSettings.getPictureScale(), GuiSettings.getPictureScale()); drawCanvasObject(g, hO.getImagePath(), pos); if (Appearance.supplyBarVisible && (hO.isConsumer() && !hO.getState() .equals(HolonObject.HolonObjectState.NO_ENERGY))) { drawSupplyBar(g, hO.getSupplyBarPercentage(), stateColor, pos); } } static void drawCanvasObject(Graphics2D g, AbstractCanvasObject obj) { drawCanvasObject(g, obj.getImagePath(), obj.getPosition()); } static void drawCanvasObject(Graphics2D g, String imageName, Vec2i pos) { int pictureScale = GuiSettings.getPictureScale(); int pictureScaleDiv2 = GuiSettings.getPictureScaleDiv2(); Image image = Import.loadImage(imageName, pictureScale, pictureScale); g.drawImage(image, pos.getX() - pictureScaleDiv2, pos.getY() - pictureScaleDiv2, pictureScale, pictureScale, null); } static void drawNode(Graphics2D g, Node node) { Vec2i pos = node.getPosition(); drawCanvasObject(g, ImagePreference.Canvas.Node.Unselected, pos); } static void drawEdge(Graphics2D g, Edge edge, AbstractCanvasObject a, AbstractCanvasObject b) { Vec2i start = a.getPosition(); Vec2i end = b.getPosition(); float currentEnergy = edge.getActualFlow(); float capacity = edge.maxCapacity; boolean unlimited = edge.mode == Edge.EdgeMode.Unlimited; switch (edge.getState()) { case Burned -> { g.setColor(ColorPreference.Edge.Burned); g.setStroke(TwoPixelStroke); } case Working -> { g.setColor(ColorPreference.Edge.Working); g.setStroke(new BasicStroke(unlimited ? 2f : (currentEnergy / capacity * 2f) + 1)); } } g.drawLine(start.getX(), start.getY(), end.getX(), end.getY()); Vec2i middle = new Vec2i((start.getX() + end.getX()) / 2, (start.getY() + end.getY()) / 2); if (Appearance.edgeCapacityVisible) { g.drawString(currentEnergy + "/" + (unlimited ? "\u221E" : capacity), middle.getX(), middle.getY()); } } static void drawExternConnection(Graphics2D g, AbstractCanvasObject object) { Vec2i pos = object.getPosition(); Dimension size = new Dimension(16, 16); Image image = Import.loadImage(ImagePreference.Canvas.ExternSymbol, size.width, size.height); g.drawImage(image, pos.getX() + GuiSettings.getPictureScaleDiv2(), pos.getY() - GuiSettings.getPictureScaleDiv2() - size.height, size.width, size.height, null); } static void drawNewEdgeLine(Graphics2D g, Vec2i start, Vec2i end) { g.setStroke(TwoPixelStroke); g.setColor(ColorPreference.Edge.Working); g.drawLine(start.getX(), start.getY(), end.getX(), end.getY()); } static void drawGroupNode(Graphics2D g, GroupNode groupNode) { Vec2i pos = groupNode.getPosition(); g.setColor(Color.gray); g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() - GuiSettings.getPictureScaleDiv2(), GuiSettings.getPictureScale(), GuiSettings.getPictureScale()); drawCanvasObject(g, groupNode.getImagePath(), pos); drawGroupNodeBar(g, groupNode, pos); } static void drawSelection(Graphics2D g) { g.setStroke(OnePixelStroke); for (AbstractCanvasObject aCps : GuiSettings.getSelectedObjects()) { Vec2i pos = aCps.getPosition(); if (aCps instanceof Node) { g.setColor(ColorPreference.Canvas.ObjectSelectionFill); g.fillOval(pos.getX() - (GuiSettings.getPictureScaleDiv2()), pos.getY() - (GuiSettings.getPictureScaleDiv2()), GuiSettings.getPictureScale(), GuiSettings.getPictureScale()); g.setColor(ColorPreference.Canvas.ObjectSelectionBorder); g.drawOval(pos.getX() - (GuiSettings.getPictureScaleDiv2()), pos.getY() - (GuiSettings.getPictureScaleDiv2()), GuiSettings.getPictureScale(), GuiSettings.getPictureScale()); } else { g.setColor(ColorPreference.Canvas.ObjectSelectionFill); g.fillRect(pos.getX() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f), pos.getY() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f), (int) (GuiSettings.getPictureScale() * 1.5f), (int) (GuiSettings.getPictureScale() * 1.5f)); g.setColor(ColorPreference.Canvas.ObjectSelectionBorder); g.drawRect(pos.getX() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f), pos.getY() - (int) (GuiSettings.getPictureScaleDiv2() * 1.5f), (int) (GuiSettings.getPictureScale() * 1.5f), (int) (GuiSettings.getPictureScale() * 1.5f)); } } } static void drawSelectionBox(Graphics2D g, Rectangle selectionBox) { g.setStroke(OnePixelStroke); g.setColor(ColorPreference.Canvas.MouseSelectionBorder); g.draw(selectionBox); g.setColor(ColorPreference.Canvas.MouseSelectionFill); g.fill(selectionBox); } private static void drawSupplyBar(Graphics2D g, float percentage, Color color, Vec2i pos) { // +1, -2, -1 little Adjustment for pixel perfect alignment g.setColor(Color.WHITE); g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, SupplyBarDimensions.width, SupplyBarDimensions.height); g.setColor(color); g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, (int) (SupplyBarDimensions.width * (percentage < 1 ? percentage : 1.0f) - 1), SupplyBarDimensions.height); g.setColor(Color.BLACK); g.setStroke(new BasicStroke(1)); g.drawRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, SupplyBarDimensions.width - 1, SupplyBarDimensions.height); g.setFont(SupplyBarFont); String percentageString = (Math.round((percentage * 100))) + "%"; int stringWidth = (int) g.getFontMetrics().getStringBounds(percentageString, g).getWidth(); if (percentage > 1.0f) { g.setColor(Color.WHITE); // Just to see better on purple } g.drawString(percentageString, pos.getX() + 1 - stringWidth / 2, pos.getY() + GuiSettings.getPictureScaleDiv2() - 1 + SupplyBarDimensions.height); } private static void drawGroupNodeBar(Graphics2D g, GroupNode groupNode, Vec2i pos) { // +1, -2, -1 little Adjustment for pixel perfect alignment g.setColor(Color.WHITE); g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, (int) SupplyBarDimensions.width, SupplyBarDimensions.height); float[] percentages = getGroupNodeBarPercentages(groupNode); for (int i = 5; i >= 0; i--) { g.setColor(GroupNodeBarColors[i]); g.fillRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, (int) (SupplyBarDimensions.width * percentages[i] - 1), SupplyBarDimensions.height); } g.setColor(Color.BLACK); g.setStroke(new BasicStroke(1)); g.drawRect(pos.getX() - GuiSettings.getPictureScaleDiv2(), pos.getY() + GuiSettings.getPictureScaleDiv2() - 1, SupplyBarDimensions.width - 1, SupplyBarDimensions.height); } /** * HardCoded Stuff */ public static float[] getGroupNodeBarPercentages(GroupNode groupNode) { int[] amountOfObjects = new int[6]; groupNode.getAllHolonObjectsRecursive().forEach(hO -> { switch (hO.getState()) { case PRODUCER -> amountOfObjects[0]++; case NOT_SUPPLIED -> amountOfObjects[1]++; case PARTIALLY_SUPPLIED -> amountOfObjects[2]++; case SUPPLIED -> amountOfObjects[3]++; case OVER_SUPPLIED -> amountOfObjects[4]++; case NO_ENERGY -> amountOfObjects[5]++; } }); int countHolonObjects = amountOfObjects[0] + amountOfObjects[1] + amountOfObjects[2] + amountOfObjects[3] + amountOfObjects[4] + amountOfObjects[5]; float[] percentages = new float[6]; int count = 0; for (int i = 0; i < 6; i++) { count += amountOfObjects[i]; percentages[i] = (float) count / (float) countHolonObjects; } return percentages; } public static void drawReplacementSymbol(Graphics2D g, AbstractCanvasObject hoveredObject) { Vec2i pos = hoveredObject.getPosition(); Dimension size = new Dimension(16, 16); Image image = Import.loadImage(ImagePreference.Canvas.ReplaceSymbol, size.width, size.height); g.drawImage(image, pos.getX() - GuiSettings.getPictureScaleDiv2() - size.width, pos.getY() - GuiSettings.getPictureScaleDiv2() - size.height, size.width, size.height, null); } }