package org.multiverseking.game.gui.control; import com.jme3.input.KeyInput; import com.jme3.input.event.KeyInputEvent; import com.jme3.input.event.MouseButtonEvent; import com.jme3.math.FastMath; import com.jme3.math.Vector2f; import com.jme3.math.Vector4f; import static org.multiverseking.game.gui.control.LayoutWindow.HAlign.full; import static org.multiverseking.game.gui.control.LayoutWindow.HAlign.left; import static org.multiverseking.game.gui.control.LayoutWindow.HAlign.right; import java.util.ArrayList; import org.hexgridapi.utility.Vector2Int; import tonegod.gui.controls.buttons.ButtonAdapter; import tonegod.gui.controls.buttons.CheckBox; import tonegod.gui.controls.lists.SelectBox; import tonegod.gui.controls.lists.Spinner; import tonegod.gui.controls.lists.Spinner.ChangeType; import tonegod.gui.controls.text.Label; import tonegod.gui.controls.text.TextField; import tonegod.gui.core.Element; import tonegod.gui.core.Screen; /** * * @author roah */ public abstract class EditorWindow extends LayoutWindow { // <editor-fold defaultstate="collapsed" desc="Constructor"> /** * * @param screen used to show the window. * @param parent if any. * @param name window name. */ public EditorWindow(Screen screen, Element parent, String name) { super(screen, null, parent, name); } /** * * @param screen used to show the window. * @param parent if any. * @param name window name. * @param align Element alignement type to use for element position. * @param alignElement max element count on the selected alignement. */ public EditorWindow(Screen screen, Element parent, String name, Align align, int alignElement) { super(screen, null, parent, name, align, alignElement); } /** * * @param screen used to show the window. * @param parent if any. * @param name window name. * @param align Element alignement type to use for element position. * @param gridSize size of an element on X and Y. */ public EditorWindow(Screen screen, Element parent, String name, Vector2f gridSize) { super(screen, null, parent, name, gridSize); } /** * * @param screen used to show the window. * @param parent if any. * @param name window name. * @param gridSize size of an element on X and Y. * @param align Element alignement type to use for element position. * @param elementAlignMaxCount max element count on the selected alignement. */ public EditorWindow(Screen screen, String UID, Element parent, String name, Vector2f gridSize, Align align, int elementAlignMaxCount) { super(screen, UID, parent, name, gridSize, align, elementAlignMaxCount); } // </editor-fold> // <editor-fold defaultstate="collapsed" desc="Add Method"> /** * Add an empty space into the grid. */ protected final void addSpace() { elementList.put(generateUID(getUID() + ".space_" + elementList.size()), null); } /** * Add a button field to this menu without label attached to it. * label HAlign.left. * * @param UID unique identifier (if null UID = labelName) * @param triggerName button text * @param hAlign button alignement * @param bType button type */ protected final void addButtonField(String UID, String triggerName, HAlign hAlign, ButtonType bType) { addButtonField(UID, null, HAlign.left, triggerName, hAlign, bType); } /** * Add a button field to this menu. UID generated from labelName. * * @param UID unique identifier (if null UID = labelName) * @param labelName field name. * @param labelHAlign Horizontal alignement to use for label. * @param triggerName name used for the button. * @param triggerHAlign Horizontal alignement to use for button. * @param addLabel define if a label have to be added for the button. */ protected final void addButtonField(String UID, String labelName, HAlign labelHAlign, String triggerName, HAlign triggerHAlign, ButtonType bType) { UID = UID != null ? UID : generateUID(labelName != null ? labelName : triggerName); if (labelName != null) { if (labelHAlign == HAlign.full) { System.err.println("Label name isn't allowed with HAlign.full on button.\n " + "labelName : " + labelName + " will be ignored."); elementList.put(UID, generateButton(null, triggerName, labelHAlign, bType)); return; } elementList.put(UID, generateLabel(labelName, labelHAlign, false)); elementList.get(UID).addChild(generateButton(UID, triggerName, triggerHAlign, bType)); } else { elementList.put(UID, generateButton(null, triggerName, triggerHAlign, bType)); } } /** * Add a list off button (button group). * * @param listUID storage UID. * @param triggersNames button label list. * @param hAlign alignement to use * @param bType button type */ protected final void addButtonList(String listUID, String[] triggersNames, HAlign hAlign, ButtonType bType) { addButtonList(listUID, null, hAlign, triggersNames, hAlign, bType, 1); } /** * Add a button List (button group). * * @param UID unique identifier * @param labelName if not null a label of this name is added * @param triggersNames list of button to add. * @param hAlign alignement of the button. * @param type type of button to use * @param fieldGridSize gridSlot to use */ protected final void addButtonList(String UID, String labelName, HAlign labelAlign, String[] triggersNames, HAlign btnAlign, ButtonType type, int fieldGridSize) { addList(UID, labelName, labelAlign, triggersNames, btnAlign, type, fieldGridSize, "btn"); } /** * Add a numeric list Field, limited to number as input. * * @param UID unique identifier * @param labelName if not null a label of this name is added * @param baseValue * @param hAlign */ protected final void addNumericListField(String UID, String labelName, Integer[] baseValue, HAlign hAlign) { addList(UID, labelName, hAlign, baseValue, hAlign, ButtonType.TEXT, 1, "num"); } /** * Add spinner list field. */ protected final void addSpinnerList(String UID, String labelName, int[][] value, HAlign hAlign) { addList(UID, labelName, hAlign, value, hAlign, ButtonType.TEXT, 1, "spin"); } private void addList(String UID, String labelName, HAlign labelAlign, Object[] triggersNames, HAlign btnAlign, ButtonType bType, int fieldGridSize, String listType) { UID = UID + "." + "List"; Element holder; if (labelName != null) { holder = generateLabel(labelName, labelAlign, false); } else { holder = new Element(screen, UID, new Vector2f(), new Vector2f(), Vector4f.ZERO, null); holder.setAsContainerOnly(); } generateList(UID, holder, triggersNames, btnAlign, listType, bType, fieldGridSize); } /** * Add a checkbox Element to this window. * * @param labelName field name. * @param active is the checkbox switched on. * @param offset value to be added on top of the gridPosition. */ protected final void addCheckBoxField(String UID, String labelName, boolean active) { CheckBox b = new CheckBox(screen, (UID != null ? UID : labelName) + "." + getUID() + "CheckBox", new Vector2f(2, spacement), new Vector2f(15,15)); b.setIsChecked(active); b.setLabelText(labelName); elementList.put(UID != null ? UID : labelName, b); } /** * Add a spinner Element to this menu. * <li> value[0] = min </li> * <li> value[1] = max </li> * <li> value[2] = step </li> * <li> value[3] = current </li> * * @param labelName field name. * @param value first value to show. * @param hAlign horizontal alignemenet to use. */ protected final void addSpinnerField(String UID, String labelName, int[] value, HAlign hAlign) { if (labelName != null) { Label label = generateLabel(labelName, hAlign, false); elementList.put(UID != null ? UID : generateUID(labelName), label); label.addChild(generateSpinner(UID, labelName, value)); } else { elementList.put(UID != null ? UID : generateUID(labelName), generateSpinner(UID, labelName, value)); } } /** * Add a Text Field element to this menu with an extended grid slot use. * * @param UID unique identifier * @param labelName field name. * @param baseValue first value to show. * @param hAlign horizontal alignemenet to use. * @param fieldSize the grid slot taken for the field. */ protected final void addTextField(String UID, String labelName, String baseValue, HAlign hAlign, int fieldSize) { Vector2Int size = new Vector2Int(1, 1); if (fieldSize != 0 && fieldSize > 0) { int pos = (int) FastMath.ceil((float) (elementList.size() + 1) / (float) elementAlignMaxCount); pos = (int) ((float) (elementList.size() + 1) / (float) pos); if (windowElementAlignement == Align.Horizontal) { if (fieldSize + pos <= elementAlignMaxCount) { size.x = fieldSize + pos - 1; } else { size.y = (int) FastMath.ceil((float) (fieldSize) / (float) elementAlignMaxCount); for (int i = pos; i > 1; i--) { addSpace(); } size.x = elementAlignMaxCount; } } else if (windowElementAlignement == Align.Vertical) { if (fieldSize + pos <= elementAlignMaxCount) { size.y = fieldSize + pos - 1; } else { size.x = (int) FastMath.ceil((float) (fieldSize + pos) / (float) elementAlignMaxCount); size.y = elementAlignMaxCount - 1; } } } String uid = generateUID(labelName); elementList.put(uid, generateLabel(labelName, hAlign, false)); generateTextField(uid, baseValue, size); } /** * Add a Text Field element to this menu, limited to number as input. * * @param labelName field name. * @param baseValue first value to show. * @param hAlign horizontal alignemenet to use. */ protected final void addNumericField(String labelName, int baseValue, HAlign hAlign) { String uid = generateUID(labelName); Label field = generateLabel(labelName, hAlign, false); elementList.put(uid, field); field.addChild(generateNumericField(uid, baseValue, hAlign)); } /** * Add a selectionList Element based on a enum to this menu. * * @param labelName field name. * @param baseValue first value to show. * @param value all possible value. * @param hAlign horizontal alignemenet to use. */ protected final void addSelectionField(String labelName, Enum<?> baseValue, Enum[] value, HAlign hAlign) { String uid = generateUID(labelName); elementList.put(uid, generateLabel(labelName, hAlign, false)); generateSelectBoxField(uid, baseValue, value); } /** * Add a selectionList Element based on a enum to this menu. * * @param UID unique identifier * @param labelName field name. * @param hAlign horizontal alignemenet to use. */ protected final void addLabelField(String UID, String labelName, HAlign hAlign) { if (UID == null) { UID = generateUID(labelName); } elementList.put(UID, generateLabel(labelName, hAlign, true)); } /** * Add a selectionList Element based on a enum to this menu. * * @param labelName field name. * @param value x as current value && y as max value. * @param hAlign horizontal alignemenet to use. */ protected final void addLabelPropertieField(String labelName, Vector2Int value, HAlign hAlign) { String uid = generateUID(labelName); elementList.put(uid, generateLabel(labelName + " : " + value.x + " / " + value.y, hAlign, true)); } /** * Add a selectionList Element based on a enum to this menu. * * @param labelName field name. * @param value value to show. * @param hAlign horizontal alignemenet to use. */ protected final void addLabelPropertieField(String labelName, int value, HAlign hAlign) { String uid = generateUID(labelName); elementList.put(uid, generateLabel(labelName + " : " + value, hAlign, true)); } // </editor-fold> // <editor-fold defaultstate="collapsed" desc="Generate Method"> protected final Label generateLabel(String labelName, HAlign hAlign, boolean labelOnly) { String UID = labelName.replaceAll("\\s", "") + "." + getUID() + "Label"; Label label; if (hAlign.equals(HAlign.left)) { label = new Label(screen, UID, Vector2f.ZERO, new Vector2f((labelName.toCharArray().length + (labelOnly ? 1 : 3)) * 8, layoutGridSize.y)); label.setText(labelName + (labelOnly ? "" : " : ")); } else if (hAlign.equals(HAlign.right)) { label = new Label(screen, UID, new Vector2f(layoutGridSize.x - (spacement + ((labelName.toCharArray().length + 2) * 8)), 0), new Vector2f((labelName.toCharArray().length + 3) * 8, layoutGridSize.y)); label.setText((labelOnly ? "" : " : ") + labelName); } else { throw new UnsupportedOperationException(hAlign + " : Cannot be used with a label or isn't implemented."); } return label; } protected final ButtonAdapter generateNumericField(final String labelUID, int baseValue, final HAlign hAlign) { ButtonAdapter numButton = new ButtonAdapter(screen, labelUID + "." + getUID() + ".NumericFieldButton", new Vector2f(), new Vector2f(layoutGridSize.x - (((labelUID.toCharArray().length + 2) * 8) + (spacement * 2)), layoutGridSize.y)) { @Override public void onButtonMouseLeftUp(MouseButtonEvent evt, boolean toggled) { super.onButtonMouseLeftUp(evt, toggled); TextField field = new TextField(screen, getUID() + labelUID + "NumericField", new Vector2f(getPosition().x, getPosition().y + 8), new Vector2f(getWidth(), layoutGridSize.y)) { @Override public void onKeyRelease(KeyInputEvent evt) { super.onKeyRelease(evt); if (evt.getKeyCode() == KeyInput.KEY_RETURN) { switchText(getText()); /** * There, the System have to be call to know a * change have been done. */ // hover.setCardName(getText()); onNumericFieldInput(Integer.decode(getText())); getElementParent().removeChild(this); } } }; field.setType(TextField.Type.NUMERIC); field.setMaxLength(4); field.setText(getText()); getElementParent().addChild(field); } private void switchText(String text) { setText(text); } }; switch (hAlign) { case full: break; case left: numButton.setPosition(((labelUID.toCharArray().length + 2) * 8) + spacement, 4); break; case right: numButton.setPosition(-numButton.getDimensions().x, 4); break; } numButton.setText(Integer.toString(baseValue)); return numButton; } protected final void generateTextField(final String labelUID, String baseValue, Vector2Int fieldSize) { TextField field = new TextField(screen, labelUID + "." + getUID() + ".TextField", new Vector2f(elementList.get(labelUID).getDimensions().x, 4), new Vector2f((layoutGridSize.x * fieldSize.x) - elementList.get(labelUID).getDimensions().x - spacement, layoutGridSize.y * fieldSize.y)) { @Override public void onKeyRelease(KeyInputEvent evt) { super.onKeyRelease(evt); if (evt.getKeyCode() == KeyInput.KEY_RETURN) { onTextFieldInput(labelUID, getText(), true); } else if (evt.getKeyCode() == KeyInput.KEY_ESCAPE) { onTextFieldInput(labelUID, getText(), false); } } }; field.setType(TextField.Type.EXCLUDE_SPECIAL); if (baseValue != null) { field.setText(baseValue); } if (fieldSize.x > 1) { for (int j = fieldSize.x; j > 1; j--) { addSpace(); } } if (fieldSize.y > 1) { for (int i = fieldSize.y; i > 1; i--) { for (int j = fieldSize.x; j > 0; j--) { addSpace(); } } } elementList.get(labelUID).addChild(field); } protected final void generateSelectBoxField(final String labelUID, Enum<?> baseValue, Enum[] value) { SelectBox selectBox = new SelectBox(screen, labelUID + "." + getUID() + ".BoxField", new Vector2f(elementList.get(labelUID).getDimensions().x, 4), new Vector2f(layoutGridSize.x - elementList.get(labelUID).getDimensions().x - spacement, layoutGridSize.y)) { @Override public void onChange(int selectedIndex, Object value) { onSelectBoxFieldChange((Enum) value); } }; for (Enum e : value) { selectBox.addListItem(e.toString(), e); } elementList.get(labelUID).addChild(selectBox); selectBox.setSelectedIndex(baseValue.ordinal()); } protected final Spinner generateSpinner(final String UID, final String labelName, int[] intValue) { final int startIndex = (int) (FastMath.abs(intValue[0]) + FastMath.abs(intValue[1])) / 2 + intValue[3]; Spinner spinner = new Spinner(screen, (labelName != null ? labelName : UID) + "." + getUID() + ".Spinner", new Vector2f((labelName != null ? elementList.get(UID != null ? UID : generateUID(labelName)).getDimensions().x : 0), 4), new Vector2f((labelName != null ? layoutGridSize.x - elementList.get( UID != null ? UID : generateUID(labelName)).getDimensions().x - spacement : 0), layoutGridSize.y), Spinner.Orientation.HORIZONTAL, true) { @Override public void onChange(int selectedIndex, String value, ChangeType type) { onSpinnerChange(labelName != null ? labelName : UID, selectedIndex, type); } }; spinner.setStepIntegerRange(intValue[0], intValue[1], intValue[2]); spinner.setSelectedIndex(startIndex); return spinner; } protected final ButtonAdapter generateButton(String labelName, String triggerName, HAlign hAlign, ButtonType bType) { Vector2f bSize = bType.equals(ButtonType.TEXT) ? new Vector2f(((triggerName.toCharArray().length + 2) * 8), layoutGridSize.y) : new Vector2f(layoutGridSize.y, layoutGridSize.y); ButtonAdapter button = new ButtonAdapter(screen, generateUID(triggerName) + "." + getUID() + ".Button" + bType.toString(), new Vector2f(), bSize, bType.equals(ButtonType.IMG) ? Vector4f.ZERO : screen.getStyle("Window").getVector4f("resizeBorders"), bType.equals(ButtonType.IMG) ? "Textures/Icons/Buttons/" + triggerName + ".png" : screen.getStyle("Button").getString("defaultImg")) { @Override public void onButtonMouseLeftUp(MouseButtonEvent evt, boolean toggled) { super.onButtonMouseLeftUp(evt, toggled); // onButtonTrigger((labelName != null ? labelName + "." : "") + triggerName); onButtonTrigger(this.getUID().split("\\.")[0]); } }; if (bType.equals(ButtonType.TEXT)) { button.setText(triggerName); } switch (hAlign) { case left: // button.setPosition(new Vector2f((labelName != null ? (labelName.toCharArray().length + 1) * 8 - spacement : spacement) + offset.x, 4)); button.setPosition(new Vector2f((labelName != null ? elementList.get(labelName).getDimensions().x - spacement : spacement), 4)); return button; case right: button.setPosition(new Vector2f(layoutGridSize.x - (spacement + button.getDimensions().x), 4)); return button; case full: button.setDimensions(new Vector2f(layoutGridSize.x - (labelName != null ? (labelName.toCharArray().length + 1) * 8 : spacement), layoutGridSize.y)); button.setPosition(new Vector2f((labelName != null ? (labelName.toCharArray().length + 1) * 8 - spacement : 0), 4)); return button; default: throw new UnsupportedOperationException(hAlign + " isn't supported."); } } private void generateList(String UID, Element holder, Object[] elements, HAlign hAlign, String listType, ButtonType bType, int fieldGridSize) { int i = 0; float posX = 0f; float fillValue = spacement; ArrayList<Element> eList = new ArrayList<>(); for (Object o : elements) { switch (listType) { case "btn": eList.add(generateButton(null, o.toString(), hAlign, bType)); break; case "num": eList.add(generateNumericField(UID + i, i, hAlign)); break; case "spin": eList.add(generateSpinner(UID + i, null, (int[]) o)); break; default: throw new UnsupportedOperationException(listType + " is not a supported type."); } eList.get(eList.size() - 1).setPosition(posX, eList.get(eList.size() - 1).getPosition().y); posX += eList.get(eList.size() - 1).getWidth(); fillValue += eList.get(eList.size() - 1).getWidth(); holder.addChild(eList.get(eList.size() - 1)); i++; } if (hAlign == HAlign.right && listType.equals("num")) { holder.setPosition(layoutGridSize.x - (posX + 10), holder.getPosition().y); } else if (hAlign == HAlign.right && listType.equals("btn")) { holder.setPosition(layoutGridSize.x - posX, holder.getPosition().y); } else if (listType.equals("spin") && fieldGridSize <= 1) { fillValue = (layoutGridSize.x - fillValue) / elements.length; i = 0; for (Element e : eList) { e.setDimensions(e.getDimensions().x + fillValue - (e.getDimensions().y * 2), e.getDimensions().y); e.setPosition(e.getPosition().x + fillValue * i + e.getDimensions().y, e.getPosition().y - layoutGridSize.y); e.getChildElementById(e.getUID() + ":btnInc").setPosition(e.getDimensions().x, 0); ((Spinner) e).setSelectedIndex(((Spinner) e).getSelectedIndex()); i++; } fieldGridSize++; } else if (hAlign.equals(HAlign.full)) { i = 0; fillValue = (layoutGridSize.x * fieldGridSize - fillValue - holder.getDimensions().x) / elements.length; for (Element e : eList) { e.setDimensions(e.getDimensions().x + fillValue, e.getDimensions().y); if (i == 0 && hAlign.equals(HAlign.left)) { e.setPosition(e.getPosition().x + (hAlign.equals(HAlign.left) ? holder.getDimensions().x : 0), e.getPosition().y); } else if (i != 0) { e.setPosition(e.getPosition().x + (fillValue * i) + (hAlign.equals(HAlign.left) ? holder.getDimensions().x : 0), e.getPosition().y); } i++; } } else if (hAlign.equals(HAlign.left)) { i = 0; for (Element e : eList) { e.setPosition(holder.getDimensions().x - spacement + e.getDimensions().x * i, e.getPosition().y); i++; } } elementList.put(UID, holder); if (fieldGridSize > 1) { for (i = fieldGridSize; i > 1; i--) { addSpace(); } } } // </editor-fold> // <editor-fold defaultstate="collapsed" desc="get Fields Method"> protected final Element getField(String UID, String labelName) { return elementList.get(UID != null ? UID : generateUID(labelName)); } protected final Element getListButtonField(String listUID, ButtonType bType, String buttonLabel) { return getListField(listUID, bType, buttonLabel).getChildElementById(generateUID(buttonLabel) + "." + getUID() + ".Button" + bType.toString()); } protected final Element getListField(String listUID, ButtonType bType, String buttonLabel) { return elementList.get(generateUID(listUID) + ".List"); } protected final Element getSpinnerListField(String listUID, int index) { return elementList.get(generateUID(listUID) + ".spinList").getChildElementById(getUID() + generateUID(listUID) + ".spinList" + index); } protected final Element getNumericListField(String listUID, int index) { return elementList.get(generateUID(listUID) + ".numList").getChildElementById(getUID() + ".numList" + index + "NumericFieldButton"); } protected final ButtonAdapter getButtonField(String UID, String labelName, String triggerName, ButtonType bType) { ButtonAdapter btn; String btnUID = generateUID(triggerName) + "." + getUID() + ".Button" + bType.toString(); if (UID != null) { btn = (ButtonAdapter) elementList.get(UID).getChildElementById(btnUID); } else if (labelName != null) { btn = (ButtonAdapter) getField(UID, labelName).getChildElementById(btnUID); } else { btn = (ButtonAdapter) getField(UID, labelName); } return btn; } protected final CheckBox getCheckBoxField(String labelName) { return (CheckBox) elementList.get(generateUID(labelName)); } protected final TextField getTextField(String UID, String labelName) { return (TextField) getField(UID, labelName).getChildElementById(generateUID(labelName) + "." + getUID() + ".TextField"); } protected final ButtonAdapter getNumericField(String UID, String labelName) { return (ButtonAdapter) getField(UID, labelName).getChildElementById(generateUID(labelName) + "." + getUID() + ".NumericFieldButton"); } protected final Spinner getSpinnerField(String UID, String labelName) { return (Spinner) getField(UID, labelName).getChildElementById(generateUID(labelName) + "." + getUID() + ".Spinner"); } protected final SelectBox getSelectBoxField(String UID, String labelName) { return (SelectBox) getField(UID, labelName).getChildElementById(generateUID(labelName) + "." + getUID() + ".BoxField"); } // </editor-fold> // <editor-fold defaultstate="collapsed" desc="Trigger Method"> protected abstract void onButtonTrigger(String label); protected abstract void onTextFieldInput(String UID, String input, boolean triggerOn); protected abstract void onNumericFieldInput(Integer input); protected abstract void onSelectBoxFieldChange(Enum value); protected abstract void onSpinnerChange(String sTrigger, int currentIndex, ChangeType type); // </editor-fold> public enum ButtonType { IMG, TEXT; } }