package mapwriter.gui; import java.awt.Point; import mapwriter.Mw; import mapwriter.MwUtil; import mapwriter.api.IMwDataProvider; import mapwriter.api.MwAPI; import mapwriter.forge.MwKeyHandler; import mapwriter.map.MapRenderer; import mapwriter.map.MapView; import mapwriter.map.Marker; import mapwriter.map.mapmode.FullScreenMapMode; import mapwriter.map.mapmode.MapMode; import mapwriter.tasks.MergeTask; import mapwriter.tasks.RebuildRegionsTask; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @SideOnly(Side.CLIENT) public class MwGui extends GuiScreen { private Mw mw; private MapMode mapMode; private MapView mapView; private MapRenderer map; private final static double PAN_FACTOR = 0.3D; private static final int menuY = 5; private static final int menuX = 5; private int mouseLeftHeld = 0; //private int mouseRightHeld = 0; //private int mouseMiddleHeld = 0; private int mouseLeftDragStartX = 0; private int mouseLeftDragStartY = 0; private double viewXStart; private double viewZStart; private Marker movingMarker = null; private int movingMarkerXStart = 0; private int movingMarkerZStart = 0; private int mouseBlockX = 0; private int mouseBlockY = 0; private int mouseBlockZ = 0; private int exit = 0; private Label helpLabel; private Label optionsLabel; private Label dimensionLabel; private Label groupLabel; private Label overlayLabel; class Label { int x = 0, y = 0, w = 1, h = 12; public Label() { } public void draw(int x, int y, String s) { this.x = x; this.y = y; this.w = MwGui.this.fontRendererObj.getStringWidth(s) + 4; MwGui.drawRect(this.x, this.y, this.x + this.w, this.y + this.h, 0x80000000); MwGui.this.drawString(MwGui.this.fontRendererObj, s, this.x + 2, this.y + 2, 0xffffff); } public void drawToRightOf(Label label, String s) { this.draw(label.x + label.w + 5, label.y, s); } public boolean posWithin(int x, int y) { return (x >= this.x) && (y >= this.y) && (x <= (this.x + this.w)) && (y <= (this.y + this.h)); } } public MwGui(Mw mw) { this.mw = mw; this.mapMode = new FullScreenMapMode(mw.config); this.mapView = new MapView(this.mw); this.map = new MapRenderer(this.mw, this.mapMode, this.mapView); this.mapView.setDimension(this.mw.miniMap.view.getDimension()); this.mapView.setViewCentreScaled(this.mw.playerX, this.mw.playerZ, this.mw.playerDimension); this.mapView.setZoomLevel(0); this.helpLabel = new Label(); this.optionsLabel = new Label(); this.dimensionLabel = new Label(); this.groupLabel = new Label(); this.overlayLabel = new Label(); } public MwGui(Mw mw, int dim, int x, int z){ this(mw); this.mapView.setDimension(dim); this.mapView.setViewCentreScaled(x, z, dim); this.mapView.setZoomLevel(0); } // called when gui is displayed and every time the screen // is resized public void initGui() { } // called when a button is pressed protected void actionPerformed(GuiButton button) { } public void exitGui() { //MwUtil.log("closing GUI"); // set the mini map dimension to the GUI map dimension when closing this.mw.miniMap.view.setDimension(this.mapView.getDimension()); this.mapMode.close(); Keyboard.enableRepeatEvents(false); this.mc.displayGuiScreen((GuiScreen) null); this.mc.setIngameFocus(); this.mc.getSoundHandler().resumeSounds(); } // get a marker near the specified block pos if it exists. // the maxDistance is based on the view width so that you need to click closer // to a marker when zoomed in to select it. public Marker getMarkerNearScreenPos(int x, int y) { Marker nearMarker = null; for (Marker marker : this.mw.markerManager.visibleMarkerList) { if (marker.screenPos != null) { if (marker.screenPos.distanceSq(x, y) < 6.0) { nearMarker = marker; } } } return nearMarker; } public int getHeightAtBlockPos(int bX, int bZ) { int bY = 0; int worldDimension = this.mw.mc.theWorld.provider.dimensionId; if ((worldDimension == this.mapView.getDimension()) && (worldDimension != -1)) { bY = this.mw.mc.theWorld.getChunkFromBlockCoords(bX, bZ).getHeightValue(bX & 0xf, bZ & 0xf); } return bY; } public boolean isPlayerNearScreenPos(int x, int y) { Point.Double p = this.map.playerArrowScreenPos; return p.distanceSq(x, y) < 9.0; } public void deleteSelectedMarker() { if (this.mw.markerManager.selectedMarker != null) { //MwUtil.log("deleting marker %s", this.mw.markerManager.selectedMarker.name); this.mw.markerManager.delMarker(this.mw.markerManager.selectedMarker); this.mw.markerManager.update(); this.mw.markerManager.selectedMarker = null; } } public void mergeMapViewToImage() { this.mw.chunkManager.saveChunks(); this.mw.executor.addTask(new MergeTask(this.mw.regionManager, (int) this.mapView.getX(), (int) this.mapView.getZ(), (int) this.mapView.getWidth(), (int) this.mapView.getHeight(), this.mapView.getDimension(), this.mw.worldDir, this.mw.worldDir.getName())); MwUtil.printBoth("merging to '" + this.mw.worldDir.getAbsolutePath() + "'"); } public void regenerateView() { MwUtil.printBoth(String.format("regenerating %dx%d blocks starting from (%d, %d)", (int) this.mapView.getWidth(), (int) this.mapView.getHeight(), (int) this.mapView.getMinX(), (int) this.mapView.getMinZ())); this.mw.reloadBlockColours(); this.mw.executor.addTask(new RebuildRegionsTask( this.mw, (int) this.mapView.getMinX(), (int) this.mapView.getMinZ(), (int) this.mapView.getWidth(), (int) this.mapView.getHeight(), this.mapView.getDimension())); } // c is the ascii equivalent of the key typed. // key is the lwjgl key code. protected void keyTyped(char c, int key) { //MwUtil.log("MwGui.keyTyped(%c, %d)", c, key); switch(key) { case Keyboard.KEY_ESCAPE: this.exitGui(); break; case Keyboard.KEY_DELETE: this.deleteSelectedMarker(); break; case Keyboard.KEY_SPACE: // next marker group this.mw.markerManager.nextGroup(); this.mw.markerManager.update(); break; case Keyboard.KEY_C: // cycle selected marker colour if (this.mw.markerManager.selectedMarker != null) { this.mw.markerManager.selectedMarker.colourNext(); } break; case Keyboard.KEY_N: // select next visible marker this.mw.markerManager.selectNextMarker(); break; case Keyboard.KEY_HOME: // centre map on player this.mapView.setViewCentreScaled(this.mw.playerX, this.mw.playerZ, this.mw.playerDimension); break; case Keyboard.KEY_END: // centre map on selected marker if (this.mw.markerManager.selectedMarker != null) { this.mapView.setViewCentreScaled( this.mw.markerManager.selectedMarker.x, this.mw.markerManager.selectedMarker.z, 0 ); } break; case Keyboard.KEY_P: this.mergeMapViewToImage(); this.exitGui(); break; case Keyboard.KEY_T: if (this.mw.markerManager.selectedMarker != null) { this.mw.teleportToMarker(this.mw.markerManager.selectedMarker); this.exitGui(); } else { this.mc.displayGuiScreen( new MwGuiTeleportDialog( this, this.mw, this.mapView, this.mouseBlockX, this.mw.defaultTeleportHeight, this.mouseBlockZ ) ); } break; case Keyboard.KEY_LEFT: this.mapView.panView(-PAN_FACTOR, 0); break; case Keyboard.KEY_RIGHT: this.mapView.panView(PAN_FACTOR, 0); break; case Keyboard.KEY_UP: this.mapView.panView(0, -PAN_FACTOR); break; case Keyboard.KEY_DOWN: this.mapView.panView(0, PAN_FACTOR); break; case Keyboard.KEY_R: this.regenerateView(); this.exitGui(); break; //case Keyboard.KEY_9: // MwUtil.log("refreshing maptexture"); // this.mw.mapTexture.updateTexture(); // break; default: if (key == MwKeyHandler.keyMapGui.getKeyCode()) { // exit on the next tick this.exit = 1; } else if (key == MwKeyHandler.keyZoomIn.getKeyCode()) { this.mapView.adjustZoomLevel(-1); } else if (key == MwKeyHandler.keyZoomOut.getKeyCode()) { this.mapView.adjustZoomLevel(1); } else if (key == MwKeyHandler.keyNextGroup.getKeyCode()) { this.mw.markerManager.nextGroup(); this.mw.markerManager.update(); } else if (key == MwKeyHandler.keyUndergroundMode.getKeyCode()) { this.mw.toggleUndergroundMode(); this.mapView.setUndergroundMode(this.mw.undergroundMode); } break; } } // override GuiScreen's handleMouseInput to process // the scroll wheel. @Override public void handleMouseInput() { if (MwAPI.getCurrentDataProvider() != null && MwAPI.getCurrentDataProvider().onMouseInput(this.mapView, this.mapMode)) return; int x = Mouse.getEventX() * this.width / this.mc.displayWidth; int y = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; int direction = Mouse.getEventDWheel(); if (direction != 0) { this.mouseDWheelScrolled(x, y, direction); } super.handleMouseInput(); } // mouse button clicked. 0 = LMB, 1 = RMB, 2 = MMB protected void mouseClicked(int x, int y, int button) { //MwUtil.log("MwGui.mouseClicked(%d, %d, %d)", x, y, button); //int bX = this.mouseToBlockX(x); //int bZ = this.mouseToBlockZ(y); //int bY = this.getHeightAtBlockPos(bX, bZ); Marker marker = this.getMarkerNearScreenPos(x, y); Marker prevMarker = this.mw.markerManager.selectedMarker; if (button == 0) { if (this.dimensionLabel.posWithin(x, y)) { this.mc.displayGuiScreen( new MwGuiDimensionDialog( this, this.mw, this.mapView, this.mapView.getDimension() ) ); } else if (this.optionsLabel.posWithin(x, y)) { this.mc.displayGuiScreen(new MwGuiOptions(this, this.mw)); } else { this.mouseLeftHeld = 1; this.mouseLeftDragStartX = x; this.mouseLeftDragStartY = y; this.mw.markerManager.selectedMarker = marker; if ((marker != null) && (prevMarker == marker)) { // clicked previously selected marker. // start moving the marker. this.movingMarker = marker; this.movingMarkerXStart = marker.x; this.movingMarkerZStart = marker.z; } } } else if (button == 1) { //this.mouseRightHeld = 1; if ((marker != null) && (prevMarker == marker)) { // right clicked previously selected marker. // edit the marker this.mc.displayGuiScreen( new MwGuiMarkerDialog( this, this.mw.markerManager, marker ) ); } else if (marker == null) { // open new marker dialog String group = this.mw.markerManager.getVisibleGroupName(); if (group.equals("none")) { group = "group"; } int mx, my, mz; if (this.isPlayerNearScreenPos(x, y)) { // marker at player's locations mx = this.mw.playerXInt; my = this.mw.playerYInt; mz = this.mw.playerZInt; } else { // marker at mouse pointer location mx = this.mouseBlockX; my = (this.mouseBlockY > 0) ? this.mouseBlockY : this.mw.defaultTeleportHeight; mz = this.mouseBlockZ; } this.mc.displayGuiScreen( new MwGuiMarkerDialog( this, this.mw.markerManager, "", group, mx, my, mz, this.mapView.getDimension() ) ); } } else if (button == 2) { Point blockPoint = this.mapMode.screenXYtoBlockXZ(this.mapView, x, y); IMwDataProvider provider = MwAPI.getCurrentDataProvider(); if (provider != null) provider.onMiddleClick(this.mapView.getDimension(), blockPoint.x, blockPoint.y, this.mapView); } this.viewXStart = this.mapView.getX(); this.viewZStart = this.mapView.getZ(); //this.viewSizeStart = this.mapManager.getViewSize(); } // mouse button released. 0 = LMB, 1 = RMB, 2 = MMB // not called on mouse movement. protected void mouseMovedOrUp(int x, int y, int button) { //MwUtil.log("MwGui.mouseMovedOrUp(%d, %d, %d)", x, y, button); if (button == 0) { this.mouseLeftHeld = 0; this.movingMarker = null; } else if (button == 1) { //this.mouseRightHeld = 0; } } // zoom on mouse direction wheel scroll public void mouseDWheelScrolled(int x, int y, int direction) { Marker marker = this.getMarkerNearScreenPos(x, y); if ((marker != null) && (marker == this.mw.markerManager.selectedMarker)) { if (direction > 0) { marker.colourNext(); } else { marker.colourPrev(); } } else if (this.dimensionLabel.posWithin(x, y)) { int n = (direction > 0) ? 1 : -1; this.mapView.nextDimension(this.mw.dimensionList, n); } else if (this.groupLabel.posWithin(x, y)) { int n = (direction > 0) ? 1 : -1; this.mw.markerManager.nextGroup(n); this.mw.markerManager.update(); } else if (this.overlayLabel.posWithin(x, y)) { int n = (direction > 0) ? 1 : -1; if (MwAPI.getCurrentDataProvider() != null) MwAPI.getCurrentDataProvider().onOverlayDeactivated(this.mapView); if (n == 1) MwAPI.setNextProvider(); else MwAPI.setPrevProvider(); if (MwAPI.getCurrentDataProvider() != null) MwAPI.getCurrentDataProvider().onOverlayActivated(this.mapView); } else { int zF = (direction > 0) ? -1 : 1; this.mapView.zoomToPoint(this.mapView.getZoomLevel() + zF, this.mouseBlockX, this.mouseBlockZ); } } // called every frame public void updateScreen() { //MwUtil.log("MwGui.updateScreen() " + Thread.currentThread().getName()); // need to wait one tick before exiting so that the game doesn't // handle the 'm' key and re-open the gui. // there should be a better way. if (this.exit > 0) { this.exit++; } if (this.exit > 2) { this.exitGui(); } super.updateScreen(); } public void drawStatus(int bX, int bY, int bZ) { String s; if (bY != 0) { s = String.format("cursor: (%d, %d, %d)", bX, bY, bZ); } else { s = String.format("cursor: (%d, ?, %d)", bX, bZ); } if (this.mc.theWorld != null) { if (!this.mc.theWorld.getChunkFromBlockCoords(bX, bZ).isEmpty()) { s += String.format(", biome: %s", this.mc.theWorld.getBiomeGenForCoords(bX, bZ).biomeName); } } /*if (this.mw.markerManager.selectedMarker != null) { s += ", current marker: " + this.mw.markerManager.selectedMarker.name; }*/ IMwDataProvider provider = MwAPI.getCurrentDataProvider(); if (provider != null) s += provider.getStatusString(this.mapView.getDimension(), bX, bY, bZ); drawRect(10, this.height - 21, this.width - 20, this.height - 6, 0x80000000); this.drawCenteredString(this.fontRendererObj, s, this.width / 2, this.height - 18, 0xffffff); } public void drawHelp() { drawRect(10, 20, this.width - 20, this.height - 30, 0x80000000); this.fontRendererObj.drawSplitString( "Keys:\n\n" + " Space\n" + " Delete\n" + " C\n" + " Home\n" + " End\n" + " N\n" + " T\n" + " P\n" + " R\n" + " U\n\n" + "Left click drag or arrow keys pan the map.\n" + "Mouse wheel or Page Up/Down zooms map.\n" + "Right click map to create a new marker.\n" + "Left click drag a selected marker to move it.\n" + "Mouse wheel over selected marker to cycle colour.\n" + "Mouse wheel over dimension or group box to cycle.\n", 15, 24, this.width - 30, 0xffffff); this.fontRendererObj.drawSplitString( "| Next marker group\n" + "| Delete selected marker\n" + "| Cycle selected marker colour\n" + "| Centre map on player\n" + "| Centre map on selected marker\n" + "| Select next marker\n" + "| Teleport to cursor or selected marker\n" + "| Save PNG of visible map area\n" + "| Regenerate visible map area from region files\n" + "| Underground map mode\n", 75, 42, this.width - 90, 0xffffff); } public void drawMouseOverHint(int x, int y, String title, int mX, int mY, int mZ) { String desc = String.format("(%d, %d, %d)", mX, mY, mZ); int stringW = Math.max( this.fontRendererObj.getStringWidth(title), this.fontRendererObj.getStringWidth(desc)); x = Math.min(x, this.width - (stringW + 16)); y = Math.min(Math.max(10, y), this.height - 14); drawRect(x + 8, y - 10, x + stringW + 16, y + 14, 0x80000000); this.drawString(this.fontRendererObj, title, x + 10, y - 8, 0xffffff); this.drawString(this.fontRendererObj, desc, x + 10, y + 4, 0xcccccc); } // also called every frame public void drawScreen(int mouseX, int mouseY, float f) { this.drawDefaultBackground(); double xOffset = 0.0; double yOffset = 0.0; //double zoomFactor = 1.0; if (this.mouseLeftHeld > 2) { xOffset = (this.mouseLeftDragStartX - mouseX) * this.mapView.getWidth() / this.mapMode.w; yOffset = (this.mouseLeftDragStartY - mouseY) * this.mapView.getHeight() / this.mapMode.h; if (this.movingMarker != null) { double scale = this.mapView.getDimensionScaling(this.movingMarker.dimension); this.movingMarker.x = this.movingMarkerXStart - (int) (xOffset / scale); this.movingMarker.z = this.movingMarkerZStart - (int) (yOffset / scale); } else { this.mapView.setViewCentre(this.viewXStart + xOffset, this.viewZStart + yOffset); } } if (this.mouseLeftHeld > 0) { this.mouseLeftHeld++; } // draw the map this.map.draw(); // let the renderEngine know we have changed the texture. //this.mc.renderEngine.resetBoundTexture(); // get the block the mouse is currently hovering over Point p = this.mapMode.screenXYtoBlockXZ(this.mapView, mouseX, mouseY); this.mouseBlockX = p.x; this.mouseBlockZ = p.y; this.mouseBlockY = this.getHeightAtBlockPos(this.mouseBlockX, this.mouseBlockZ); // draw name of marker under mouse cursor Marker marker = this.getMarkerNearScreenPos(mouseX, mouseY); if (marker != null) { this.drawMouseOverHint(mouseX, mouseY, marker.name, marker.x, marker.y, marker.z); } // draw name of player under mouse cursor if (this.isPlayerNearScreenPos(mouseX, mouseY)) { this.drawMouseOverHint(mouseX, mouseY, this.mc.thePlayer.getDisplayName(), this.mw.playerXInt, this.mw.playerYInt, this.mw.playerZInt); } // draw status message this.drawStatus(this.mouseBlockX, this.mouseBlockY, this.mouseBlockZ); // draw labels this.helpLabel.draw(menuX, menuY, "[help]"); this.optionsLabel.drawToRightOf(this.helpLabel, "[options]"); String dimString = String.format("[dimension: %d]", this.mapView.getDimension()); this.dimensionLabel.drawToRightOf(this.optionsLabel, dimString); String groupString = String.format("[group: %s]", this.mw.markerManager.getVisibleGroupName()); this.groupLabel.drawToRightOf(this.dimensionLabel, groupString); String overlayString = String.format("[overlay : %s]", MwAPI.getCurrentProviderName()); this.overlayLabel.drawToRightOf(this.groupLabel, overlayString); // help message on mouse over if (this.helpLabel.posWithin(mouseX, mouseY)) { this.drawHelp(); } super.drawScreen(mouseX, mouseY, f); } }