/******************************************************************************* * Copyright (c) 2015 * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *******************************************************************************/ package jsettlers.graphics.map.controls.original; import go.graphics.GLDrawContext; import go.graphics.UIPoint; import go.graphics.event.GOEvent; import go.graphics.event.GOModalEventHandler; import go.graphics.event.mouse.GODrawEvent; import jsettlers.common.map.shapes.MapRectangle; import jsettlers.common.menu.action.EActionType; import jsettlers.common.menu.action.IAction; import jsettlers.common.player.IInGamePlayer; import jsettlers.common.position.FloatRectangle; import jsettlers.common.position.ShortPoint2D; import jsettlers.common.selectable.ISelectionSet; import jsettlers.graphics.action.Action; import jsettlers.graphics.action.ActionFireable; import jsettlers.graphics.action.ChangePanelAction; import jsettlers.graphics.action.ExecutableAction; import jsettlers.graphics.action.PointAction; import jsettlers.graphics.map.MapDrawContext; import jsettlers.graphics.map.controls.IControls; import jsettlers.graphics.map.controls.original.panel.MainPanel; import jsettlers.graphics.map.controls.original.panel.content.ContentType; import jsettlers.graphics.map.controls.original.panel.content.MessageContent; import jsettlers.graphics.map.controls.original.panel.selection.BearerSelectionContent; import jsettlers.graphics.map.controls.original.panel.selection.BuildingSelectionContent; import jsettlers.graphics.map.controls.original.panel.selection.SoilderSelectionContent; import jsettlers.graphics.map.controls.original.panel.selection.SpecialistSelectionContent; import jsettlers.graphics.map.minimap.Minimap; import jsettlers.graphics.map.minimap.MinimapMode; import jsettlers.graphics.ui.Button; import jsettlers.graphics.ui.UIPanel; /** * This is the entry class for the {@link OriginalControls} map overlay. * * @author Michael Zangl * */ public class OriginalControls implements IControls { private static final int DEFAULT_LAYOUT_SIZE = 480; private final MinimapMode minimapSettings = new MinimapMode(); private final MainPanel mainPanel; private final Button chatButton; private ControlPanelLayoutProperties layoutProperties; private UIPanel uiBase; private Minimap minimap; private boolean lastSelectionWasNull = true; private MapDrawContext context; /** * Creates a new {@link OriginalControls} overlay. * * @param actionFireable * The {@link ActionFireable} to send actions from the user to. * @param player * The player this interface should be for. */ public OriginalControls(ActionFireable actionFireable, IInGamePlayer player) { layoutProperties = ControlPanelLayoutProperties.getLayoutPropertiesFor(DEFAULT_LAYOUT_SIZE); final MiniMapLayoutProperties miniMap = layoutProperties.miniMap; mainPanel = new MainPanel(actionFireable, player); chatButton = new Button( new ShowChatAction(), miniMap.IMAGELINK_BUTTON_CHAT_ACTIVE, miniMap.IMAGELINK_BUTTON_CHAT_INACTIVE, ""); uiBase = createInterface(); mainPanel.layoutPanel(layoutProperties); } private UIPanel createInterface() { UIPanel panel = new UIPanel(); addMiniMap(panel); mainPanel.setBackground(layoutProperties.IMAGELINK_MAIN); panel.addChild(mainPanel, 0, 0, layoutProperties.miniMap.RIGHT_DECORATION_LEFT, layoutProperties.MAIN_PANEL_TOP); UIPanel rightDecoration = new UIPanel(); rightDecoration.setBackground(layoutProperties.IMAGELINK_DECORATION_RIGHT); panel.addChild( rightDecoration, layoutProperties.miniMap.RIGHT_DECORATION_LEFT, 0, layoutProperties.miniMap.RIGHT_DECORATION_LEFT + layoutProperties.RIGHT_DECORATION_WIDTH, layoutProperties.MAIN_PANEL_TOP); return panel; } private void addMiniMap(UIPanel panel) { MiniMapLayoutProperties miniMap = layoutProperties.miniMap; UIPanel minimapBackgroundLeft = new UIPanel(); minimapBackgroundLeft.setBackground(miniMap.LEFT_DECORATION); minimapBackgroundLeft.addChild( chatButton, miniMap.BUTTON_CHAT_LEFT, miniMap.BUTTON_CHAT_TOP - miniMap.BUTTON_HEIGHT, miniMap.BUTTON_CHAT_LEFT + miniMap.BUTTON_WIDTH, miniMap.BUTTON_CHAT_TOP); minimapBackgroundLeft.addChild( new MinimapOccupiedButton(minimapSettings), miniMap.BUTTON_FEATURES_LEFT, miniMap.BUTTON_FEATURES_TOP - miniMap.BUTTON_HEIGHT, miniMap.BUTTON_FEATURES_LEFT + miniMap.BUTTON_WIDTH, miniMap.BUTTON_FEATURES_TOP); minimapBackgroundLeft.addChild( new MinimapSettlersButton(minimapSettings), miniMap.BUTTON_SETTLERS_LEFT, miniMap.BUTTON_SETTLERS_TOP - miniMap.BUTTON_HEIGHT, miniMap.BUTTON_SETTLERS_LEFT + miniMap.BUTTON_WIDTH, miniMap.BUTTON_SETTLERS_TOP); minimapBackgroundLeft.addChild( new MinimapBuildingButton(minimapSettings), miniMap.BUTTON_BUILDINGS_LEFT, miniMap.BUTTON_BUILDINGS_TOP - miniMap.BUTTON_HEIGHT, miniMap.BUTTON_BUILDINGS_LEFT + miniMap.BUTTON_WIDTH, miniMap.BUTTON_BUILDINGS_TOP); UIPanel minimapBackgroundRight = new UIPanel(); minimapBackgroundRight.setBackground(miniMap.RIGHT_DECORATION); panel.addChild(minimapBackgroundLeft, 0, layoutProperties.MAIN_PANEL_TOP, miniMap.RIGHT_DECORATION_LEFT, 1); panel.addChild(minimapBackgroundRight, miniMap.RIGHT_DECORATION_LEFT, layoutProperties.MAIN_PANEL_TOP, 1, 1); } @Override public void resizeTo(float newWidth, float newHeight) { ControlPanelLayoutProperties newLayoutProperties = ControlPanelLayoutProperties.getLayoutPropertiesFor(newHeight); if (!newLayoutProperties.equals(layoutProperties)) { layoutProperties = newLayoutProperties; uiBase = createInterface(); mainPanel.layoutPanel(layoutProperties); } int width = (int) (layoutProperties.ASPECT_RATIO * newHeight); this.uiBase.setPosition(new FloatRectangle(0, 0, width, newHeight)); minimap.setSize( (int) Math.ceil(layoutProperties.miniMap.MAP_WIDTH * width), (int) Math.ceil(layoutProperties.miniMap.MAP_HEIGHT * (1 - layoutProperties.MAIN_PANEL_TOP) * newHeight)); } @Override public void drawAt(GLDrawContext gl) { if (minimap != null) { gl.glPushMatrix(); gl.glTranslatef(getMinimapLeft(), getMinimapBottom(), 0); minimap.draw(gl); gl.glPopMatrix(); } uiBase.drawAt(gl); // Frame decoration should be drawn after and over the edges of the minimap. } private float getMinimapLeft() { return layoutProperties.miniMap.MAP_LEFT * uiBase.getPosition().getWidth(); } private float getMinimapBottom() { return (layoutProperties.MAIN_PANEL_TOP + (1f - layoutProperties.MAIN_PANEL_TOP) * layoutProperties.miniMap.MAP_BOTTOM) * uiBase.getPosition().getHeight(); } @Override public boolean containsPoint(UIPoint position) { float width = uiBase.getPosition().getWidth(); float uicenter = layoutProperties.miniMap.RIGHT_DECORATION_LEFT * width; return position.getX() < Math.max(uicenter, getMinimapOffset(position.getY()) + uicenter); } /** * Gets the X-Offset of the minimap at the given y position. * * @param y * The y position * @return The x offset for that row. */ private double getMinimapOffset(double y) { float width = uiBase.getPosition().getWidth(); float height = uiBase.getPosition().getHeight(); float m = 1 / (1 - layoutProperties.miniMap.RIGHT_DECORATION_LEFT) / width * (1 - layoutProperties.MAIN_PANEL_TOP) * height; return y / m - layoutProperties.MAIN_PANEL_TOP * height / m; } @Override public Action getActionFor(UIPoint position, boolean selecting) { float relativex = (float) position.getX() / this.uiBase.getPosition().getWidth(); float relativey = (float) position.getY() / this.uiBase.getPosition().getHeight(); Action action; if (minimap != null && relativey > layoutProperties.MAIN_PANEL_TOP && getMinimapOffset(position.getY()) < position.getX()) { action = getForMinimap(relativex, relativey, selecting); startMapPosition = null; // to prevent it from jumping back. } else { action = uiBase.getAction(relativex, relativey); } if (action != null && action.getActionType() == EActionType.CHANGE_PANEL) { mainPanel.setContent(((ChangePanelAction) action).getContent()); return null; } else { return action; } } /** * Gets the action for a click on the minimap. * * @param relativex * The position on the minimap. * @param relativey * The position on the minimap. * @param selecting * <code>true</code> if it was a selection click and the view should move there. * @return the action for that point or <code>null</code> for no action. */ private Action getForMinimap(float relativex, float relativey, boolean selecting) { float minimapx = (relativex - layoutProperties.miniMap.MAP_LEFT) / layoutProperties.miniMap.MAP_WIDTH; float minimapy = ((relativey - layoutProperties.MAIN_PANEL_TOP) / (1 - layoutProperties.MAIN_PANEL_TOP) - layoutProperties.miniMap.MAP_BOTTOM) / layoutProperties.miniMap.MAP_HEIGHT; ShortPoint2D clickPosition = minimap.getClickPositionIfOnMap(minimapx, minimapy); if (clickPosition != null) { if (selecting) { return new PointAction(EActionType.PAN_TO, clickPosition); } else { return new PointAction(EActionType.MOVE_TO, clickPosition); } } else { return null; } } @Override public String getDescriptionFor(UIPoint position) { float relativex = (float) position.getX() / this.uiBase.getPosition().getWidth(); float relativey = (float) position.getY() / this.uiBase.getPosition().getHeight(); return uiBase.getDescription(relativex, relativey); } @Override public void setMapViewport(MapRectangle screenArea) { if (minimap != null) { minimap.setMapViewport(screenArea); } if (context != null) { mainPanel.setMapViewport(screenArea, context.getMap()); } } @Override public void action(IAction action) { } private ShortPoint2D startMapPosition; @Override public boolean handleDrawEvent(GODrawEvent event) { if (!containsPoint(event.getDrawPosition())) { return false; } Action action = getActionForDraw(event); if (action != null && context != null && minimap != null) { float y = context.getScreen().getHeight() / 2; float x = context.getScreen().getWidth() / 2; startMapPosition = context.getPositionOnScreen(x, y); event.setHandler(new DrawMinimapHandler()); return true; } else { return false; } } private Action getActionForDraw(GODrawEvent event) { UIPoint position = event.getDrawPosition(); float width = this.uiBase.getPosition().getWidth(); float relativex = (float) position.getX() / width; float height = this.uiBase.getPosition().getHeight(); float relativey = (float) position.getY() / height; return getForMinimap(relativex, relativey, true); } /** * This should one day display the chat. */ private final class ShowChatAction extends ExecutableAction { private final MessageContent messageContent = new MessageContent( "This is not yet implemented.", "Cancel", new ExecutableAction() { @Override public void execute() { mainPanel.setContent(ContentType.BUILD_NORMAL); chatButton.setActive(false); } }, "Ok", new ExecutableAction() { @Override public void execute() { mainPanel.setContent(ContentType.BUILD_NORMAL); chatButton.setActive(false); } }); @Override public void execute() { mainPanel.setContent(messageContent); chatButton.setActive(true); // TODO needs to be unset when content changes. } } /** * This class handles a draw action (mouse pressed and moved) on the mini map. * * @author Michael Zangl */ private class DrawMinimapHandler implements GOModalEventHandler { @Override public void phaseChanged(GOEvent event) { } @Override public void finished(GOEvent event) { eventDataChanged(event); } @Override public void aborted(GOEvent event) { if (startMapPosition != null) { minimap.getContext().scrollTo(startMapPosition); } } @Override public void eventDataChanged(GOEvent event) { Action action = getActionForDraw((GODrawEvent) event); if (action != null && action.getActionType() == EActionType.PAN_TO) { minimap.getContext().scrollTo( ((PointAction) action).getPosition()); } } } @Override public void displaySelection(ISelectionSet selection) { if (selection == null || selection.getSize() == 0) { if (!lastSelectionWasNull) { lastSelectionWasNull = true; if (mainPanel.isSelectionActive()) { mainPanel.setContent(ContentType.EMPTY); } } // else: nothing to do } else { lastSelectionWasNull = false; switch (selection.getSelectionType()) { case PEOPLE: mainPanel.setContent(new BearerSelectionContent(selection)); break; case SOLDIERS: mainPanel.setContent(new SoilderSelectionContent(selection)); break; case SPECIALISTS: mainPanel.setContent(new SpecialistSelectionContent(selection)); break; case BUILDING: mainPanel.setContent(new BuildingSelectionContent(selection)); break; default: System.err .println("got Selection but couldn't handle it! SelectionType: " + selection.getSelectionType()); break; } } } @Override public void setDrawContext(ActionFireable actionFireable, MapDrawContext context) { this.context = context; this.minimap = new Minimap(context, minimapSettings); } @Override public IAction replaceAction(IAction action) { return mainPanel.catchAction(action); } @Override public String getMapTooltip(ShortPoint2D point) { return null; } @Override public void stop() { minimap.stop(); } }