/******************************************************************************* * Copyright (c) 2015 - 2017 * * 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.panel.content; import go.graphics.GLDrawContext; import java.util.Arrays; import java.util.BitSet; import jsettlers.common.images.ImageLink; import jsettlers.common.map.IGraphicsGrid; import jsettlers.common.map.partition.IPartitionData; import jsettlers.common.map.partition.IStockSettings; import jsettlers.common.material.EMaterialType; import jsettlers.common.position.ShortPoint2D; import jsettlers.graphics.action.Action; import jsettlers.graphics.action.SetMaterialPrioritiesAction; import jsettlers.graphics.map.controls.original.panel.button.MaterialButton.DotColor; import jsettlers.graphics.map.controls.original.panel.button.SelectionManagedMaterialButton; import jsettlers.graphics.map.controls.original.panel.button.SelectionManager; import jsettlers.graphics.ui.Button; import jsettlers.graphics.ui.UIPanel; import jsettlers.graphics.ui.layout.MaterialPriorityLayout; /** * This panel lets the user select the priorities in which the materials should be transported by settlers. * * @author Michael Zangl */ public class MaterialPriorityContent extends AbstractContentProvider { private static final int MAX_MOVE_AMOUNT = 100; /** * Displays an ordered list of materials. * * @author Michael Zangl */ public static class MaterialPriorityPanel extends UIPanel { private static final int COLUMNS = 6; private static final int ROWS = 5; private static final float BUTTON_HEIGHT_RELATIVE_TO_ROW = 18f / (269 - 236); private static final float BUTTON_WIDTH = 1f / COLUMNS; private static final float BUTTON_HEIGHT = 1f / ROWS * BUTTON_HEIGHT_RELATIVE_TO_ROW; /** * Points on which materials can be placed. * <p> * They are indexed by slot. */ private final float[] xpoints = new float[EMaterialType.NUMBER_OF_MATERIALS]; private final float[] ypoints = new float[EMaterialType.NUMBER_OF_MATERIALS]; /** * This is a mapping: {@link EMaterialType} -> label position. */ private final AnimatablePosition[] positions = new AnimatablePosition[EMaterialType.NUMBER_OF_MATERIALS]; private final SelectionManagedMaterialButton[] buttons = new SelectionManagedMaterialButton[EMaterialType.NUMBER_OF_DROPPABLE_MATERIALS]; private final SelectionManager selectionManager = new SelectionManager(); /** * The order that is currently displayed. */ private EMaterialType[] order = new EMaterialType[0]; private ShortPoint2D currentPos; private IGraphicsGrid currentGrid; /** * Creates a new material panel. */ public MaterialPriorityPanel() { for (int i = 0; i < ROWS; i++) { addRowPositions(i, (i % 2) == 0); } for (EMaterialType material : EMaterialType.DROPPABLE_MATERIALS) { buttons[material.ordinal] = new SelectionManagedMaterialButton(material); } selectionManager.setButtons(buttons); } private void addRowPositions(int rowIndex, boolean descent) { for (int column = 0; column < COLUMNS; column++) { int index = rowIndex * COLUMNS + column; if (index < xpoints.length) { xpoints[index] = (float) (descent ? column : (COLUMNS - column - 1)) / COLUMNS; float inRowY = (float) column / (COLUMNS - 1) * (1 - BUTTON_HEIGHT_RELATIVE_TO_ROW) + BUTTON_HEIGHT_RELATIVE_TO_ROW; ypoints[index] = 1 - (rowIndex + inRowY) / ROWS; } } } /** * Updates the material oder. * * @param orderIn * The new material order. */ public synchronized void setOrder(EMaterialType[] orderIn) { if (orderIn == null) { order = null; return; } EMaterialType[] newOrder = Arrays.copyOf(orderIn, orderIn.length); // and we assume they contain the same elements for (int i = 0; i < newOrder.length; i++) { if (order == null || order.length <= i || newOrder[i] != order[i]) { EMaterialType material = newOrder[i]; setToPosition(material, i); } } this.order = newOrder; } private void setToPosition(EMaterialType material, int newindex) { AnimatablePosition pos = positions[material.ordinal]; if (pos == null) { positions[material.ordinal] = new AnimatablePosition(xpoints[newindex], ypoints[newindex]); } else { pos.setPosition(xpoints[newindex], ypoints[newindex]); } } @Override public synchronized void drawAt(GLDrawContext gl) { updatePositions(); super.drawAt(gl); } private IPartitionData getPartitonData() { if (currentGrid == null) { return null; } else { return currentGrid.getPartitionData(currentPos.x, currentPos.y); } } private void updatePositions() { IPartitionData data = getPartitonData(); if (data == null) { setOrder(null); removeAll(); } else { EMaterialType[] newOrder = new EMaterialType[EMaterialType.DROPPABLE_MATERIALS.length]; BitSet materialsAccepted = new BitSet(); for (int i = 0; i < newOrder.length; i++) { // FIXME: Synchronize! newOrder[i] = data.getPartitionSettings().getMaterialTypeForPriority(i); } IStockSettings stockSettings = data.getPartitionSettings().getStockSettings(); for (EMaterialType materialType : EMaterialType.DROPPABLE_MATERIALS) { materialsAccepted.set(materialType.ordinal, stockSettings.isAccepted(materialType)); } setOrder(newOrder); for (EMaterialType material : newOrder) { SelectionManagedMaterialButton button = buttons[material.ordinal]; AnimatablePosition position = positions[material.ordinal]; button.setDotColor(getColor(materialsAccepted, button)); removeChild(button); addChild(button, position.getX(), position.getY(), position.getX() + BUTTON_WIDTH, position.getY() + BUTTON_HEIGHT); } } } private DotColor getColor(BitSet materialsAccepted, SelectionManagedMaterialButton button) { if (materialsAccepted.get(button.getMaterial().ordinal)) { return DotColor.GREEN; } else { return DotColor.RED; } } /** * Reorder a material. * * @param type * The material to move. * @param desiredNewPosition * The new position of that material. * @return The new ordered array. */ public synchronized EMaterialType[] reorder(EMaterialType type, int desiredNewPosition) { int oldPos = indexOf(type); EMaterialType[] newOrder = order.clone(); if (oldPos < 0) { return newOrder; } int newPos = Math.max(Math.min(desiredNewPosition, order.length - 1), 0); if (newPos > oldPos) { for (int i = oldPos; i < newPos; i++) { newOrder[i] = newOrder[i + 1]; } } else { for (int i = oldPos; i > newPos; i--) { newOrder[i] = newOrder[i - 1]; } } newOrder[newPos] = type; return newOrder; } /** * Gets the current position of that material. * * @param type * The material to search. * @return The position of that material. */ public int indexOf(EMaterialType type) { for (int i = 0; i < order.length; i++) { if (order[i] == type) { return i; } } return -1; } /** * Loads the content for the given map position. * * @param pos * The map position * @param grid * The map grid to use. */ public void showMapPosition(ShortPoint2D pos, IGraphicsGrid grid) { currentPos = pos; currentGrid = grid; } /** * Gets the selected material type. * * @return The selected material. */ public EMaterialType getSelected() { return selectionManager.getSelected(); } /** * Gets the currently used map position. * * @return The map position in use. */ public ShortPoint2D getMapPosition() { return currentPos; } } /** * This is a reorder button that allows you to reorder the selected material. * * @author Michael Zangl * */ public static class ReorderButton extends Button { private MaterialPriorityPanel panel; private int add = 0; /** * Creates a new reoder button. * * @param image * The image to display. * @param description * The description this button should have. */ public ReorderButton(ImageLink image, String description) { super(null, image, image, description); } @Override public Action getAction() { if (panel == null) { return null; } EMaterialType selected = panel.getSelected(); ShortPoint2D mapPosition = panel.getMapPosition(); if (selected == null || mapPosition == null) { return null; } EMaterialType[] order = panel.reorder(selected, panel.indexOf(selected) + add); return new SetMaterialPrioritiesAction(mapPosition, order); } } private final MaterialPriorityLayout layout; /** * Creates a new {@link MaterialPriorityContent}. */ public MaterialPriorityContent() { layout = new MaterialPriorityLayout(); layout.stock_accept.configure(layout.panel::getSelected, layout.panel::getMapPosition, true, false); layout.stock_reject.configure(layout.panel::getSelected, layout.panel::getMapPosition, false, false); layout.all_up.panel = layout.panel; layout.all_up.add = -MAX_MOVE_AMOUNT; layout.one_up.panel = layout.panel; layout.one_up.add = -1; layout.one_down.panel = layout.panel; layout.one_down.add = 1; layout.all_down.panel = layout.panel; layout.all_down.add = MAX_MOVE_AMOUNT; } @Override public synchronized void showMapPosition(ShortPoint2D pos, IGraphicsGrid grid) { layout.panel.showMapPosition(pos, grid); } @Override public UIPanel getPanel() { return layout._root; } @Override public ESecondaryTabType getTabs() { return ESecondaryTabType.GOODS; } }