Skip to content

Commit

Permalink
Merge pull request #4716 from SJuliez/rotateCamo
Browse files Browse the repository at this point in the history
Camo rotation and scaling
  • Loading branch information
HammerGS authored Aug 23, 2023
2 parents 8ac2100 + fb8ae89 commit 1aacd32
Show file tree
Hide file tree
Showing 14 changed files with 339 additions and 57 deletions.
12 changes: 5 additions & 7 deletions megamek/i18n/megamek/client/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -570,14 +570,12 @@ BoardView1.Tooltip.HiddenActivating=<FONT COLOR=RED>Hidden unit will activate in
BombPayloadDialog.FighterBombDesc=Select the number and type of bombs you wish to drop.
BombPayloadDialog.SquadronBombDesc=<html>Select the number of salvos for each bomb type you wish to drop.<br> The number in parenthesis represents the number of bombs that will be dropped.</html>

#Camo Choices
CamoChoiceDialog.error_getting_camo=Error getting camo
CamoChoiceDialog.keep_old_camo=Keep\nOld Camo
CamoChoiceDialog.no_camo=No Camo
btnParent.text=Use Parent Camouflage
btnParent.toolTipText=This reverts the selected item's camouflage to their parent item's camouflage.
#CamoChooser
CamoChoiceDialog.btnParent.text=Reset
CamoChoiceDialog.btnParent.toolTipText=Reverts the camouflage to the player's camouflage
CamoChoiceDialog.select_camo_pattern=Select Camo Pattern
CamoChoiceDialog.select_new_camo=Select\nNew Camo
CamoChoiceDialog.rotation=Rotation
CamoChoiceDialog.scale=Scale

#Chat Lounge
ChatLounge.0=Infantry
Expand Down
13 changes: 7 additions & 6 deletions megamek/i18n/megamek/client/messages_de.properties
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,13 @@ BoardView1.TipJungle=Jungle ({0})
BoardView1.TipIce=Eis({0})
BoardView1.Unload=Abladen
BoardView1.Vibrabomb=Vibrabomb
CamoChoiceDialog.error_getting_camo=Konnte Tarnung nicht laden
CamoChoiceDialog.keep_old_camo=Alte Tarnung\nbeibehalten
CamoChoiceDialog.no_camo=Kaine Tarnung
CamoChoiceDialog.select_camo_pattern=Tarnmuster Wählen
CamoChoiceDialog.select_new_camo=Neue Tarnung\nauswählen
CamoChoiceListener.NoCammo=Kein Tarnung

#CamoChooser
CamoChoiceDialog.select_camo_pattern=Tarnmuster wählen
CamoChoiceDialog.btnParent.text=Zurücksetzen
CamoChoiceDialog.btnParent.toolTipText=Entfernt das individuelle Tarnmuster der ausgewählten Einheiten
CamoChoiceDialog.rotation=Drehung
CamoChoiceDialog.scale=Größenanpassung

ChatLounge.0=Infanterie
ChatLounge.1=Protomech
Expand Down
12 changes: 5 additions & 7 deletions megamek/i18n/megamek/client/messages_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -628,14 +628,12 @@ BoardView1.Tooltip.HiddenActivating=<FONT COLOR=RED>¡La unidad oculta se activa
BombPayloadDialog.FighterBombDesc=Seleccione el número y tipo de bombas que desea lanzar.
BombPayloadDialog.SquadronBombDesc=<html>Seleccione el número de salvas para cada tipo de bomba que desee lanzar.<br>El número entre paréntesis representa el número de bombas que se lanzarán.</html>

#Camo Choices
CamoChoiceDialog.error_getting_camo=Error al obtener camuflaje
CamoChoiceDialog.keep_old_camo=Conserva\nCamuflaje antiguo
CamoChoiceDialog.no_camo=Sin camuflaje
btnParent.text=Usar Camuflaje Principal
btnParent.toolTipText=Esto revierte el camuflaje del elemento seleccionado al camuflaje del elemento principal.
#CamoChooser
CamoChoiceDialog.btnParent.text=Usar Camuflaje Principal
CamoChoiceDialog.btnParent.toolTipText=Esto revierte el camuflaje del elemento seleccionado al camuflaje del elemento principal
CamoChoiceDialog.select_camo_pattern=Seleccionar patrón de camuflaje
CamoChoiceDialog.select_new_camo=Seleccionar\nNuevo camuflaje
CamoChoiceDialog.rotation=Rotación
CamoChoiceDialog.scale=Tamaño

#Chat Lounge
ChatLounge.0=Infantería
Expand Down
9 changes: 2 additions & 7 deletions megamek/i18n/megamek/client/messages_ru.properties
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,9 @@ BoardView1.ROLLED=ВЫБРОСИЛ
BombPayloadDialog.FighterBombDesc=Выберите количество и тип бомб, которые хотите сбросить.
BombPayloadDialog.SquadronBombDesc=<html>Выберите количество залпов для каждого типа бомб, которые хотите сбросить.<br> Число в кавычках означает количество бомб, которое будет сброшено.</html>

CamoChoiceDialog.error_getting_camo=Ошибка при загрузке раскраски
CamoChoiceDialog.Cancel=Отмена
CamoChoiceDialog.keep_old_camo=Оставить\nстарую раскраску
CamoChoiceDialog.no_camo=Без раскраски
#CamoChooser
CamoChoiceDialog.select_camo_pattern=Выбрать узор раскраски
CamoChoiceDialog.select_new_camo=Выбрать\nНовую раскраску
CamoChoiceDialog.Select=Выбрать
CamoChoiceListener.NoCammo=Не менять раскраску

ChatLounge.0=Пехота
ChatLounge.1=Протомех
ChatLounge.2=Огневая точка
Expand Down
134 changes: 114 additions & 20 deletions megamek/src/megamek/client/ui/dialogs/CamoChooserDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,20 @@
*/
package megamek.client.ui.dialogs;

import megamek.client.ui.baseComponents.MMButton;
import megamek.client.ui.Messages;
import megamek.client.ui.WrapLayout;
import megamek.client.ui.panels.CamoChooser;
import megamek.client.ui.panels.EntityImagePanel;
import megamek.client.ui.swing.dialog.DialogButton;
import megamek.client.ui.swing.util.UIUtil;
import megamek.common.Entity;
import megamek.common.annotations.Nullable;
import megamek.common.icons.AbstractIcon;
import megamek.common.icons.Camouflage;

import javax.swing.*;
import java.awt.*;
import java.util.Hashtable;

/**
* This dialog allows players to select the camouflage pattern (or colour) used by their units. It
Expand All @@ -34,6 +39,11 @@
public class CamoChooserDialog extends AbstractIconChooserDialog {
//region Variable Declarations
private boolean useDefault = false;
private JSlider rotationSlider;
private JSlider scaleSlider;
private final Camouflage originalCamo;
private Entity entity;
private EntityImagePanel entityImage;
//endregion Variable Declarations

//region Constructors
Expand All @@ -45,6 +55,7 @@ public CamoChooserDialog(final JFrame frame, final @Nullable AbstractIcon camouf
final boolean canHaveIndividualCamouflage) {
super(frame, "CamoChooserDialog", "CamoChoiceDialog.select_camo_pattern",
new CamoChooser(frame, camouflage, canHaveIndividualCamouflage), true);
originalCamo = (Camouflage) camouflage;
}
//endregion Constructors

Expand All @@ -53,6 +64,10 @@ public boolean isUseDefault() {
return useDefault;
}

public void setDisplayedEntity(Entity entity) {
this.entity = entity;
}

public void setUseDefault(final boolean useDefault) {
this.useDefault = useDefault;
}
Expand All @@ -61,25 +76,80 @@ public void setUseDefault(final boolean useDefault) {
//region Initialization
@Override
protected JPanel createButtonPanel() {
final JPanel panel = new JPanel(new GridLayout(1, 3));
panel.setName("buttonPanel");

panel.add(new MMButton("btnOk", resources, "Ok.text", "Ok.toolTipText",
this::okButtonActionPerformed));
if (getChooser().canHaveIndividualCamouflage()) {
panel.add(new MMButton("btnParent", resources, "btnParent.text",
"btnParent.toolTipText", evt -> {
setUseDefault(true);
okButtonActionPerformed(evt);
}));
}
JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));

rotationSlider = new JSlider(-180, 180);
rotationSlider.setMajorTickSpacing(90);
rotationSlider.setMinorTickSpacing(10);
rotationSlider.setPaintTicks(true);
rotationSlider.setSnapToTicks(true);
rotationSlider.addChangeListener(e -> updatePreview());
rotationSlider.setPaintLabels(true);

scaleSlider = new JSlider(3, 15);
scaleSlider.setSnapToTicks(true);
scaleSlider.setPaintTicks(true);
scaleSlider.setMajorTickSpacing(1);
scaleSlider.setPaintLabels(true);
Hashtable<Integer, JComponent> labelTable = new Hashtable<>();
labelTable.put(5, new JLabel("0.5"));
labelTable.put(10, new JLabel("1"));
labelTable.put(15, new JLabel("1.5"));
scaleSlider.setLabelTable(labelTable);
scaleSlider.addChangeListener(e -> updatePreview());

entityImage = new EntityImagePanel(null, null);

JPanel rotationPanel = new JPanel();
rotationPanel.add(UIUtil.scaledHorizontalSpacer(20));
rotationPanel.add(new JLabel(Messages.getString("CamoChoiceDialog.rotation") + ":"));
rotationPanel.add(rotationSlider);

JPanel scalePanel = new JPanel();
scalePanel.add(UIUtil.scaledHorizontalSpacer(30));
scalePanel.add(new JLabel(Messages.getString("CamoChoiceDialog.scale") + ":"));
scalePanel.add(scaleSlider);

JPanel modifierPanel = new JPanel();
modifierPanel.add(entityImage);
modifierPanel.add(rotationPanel);
modifierPanel.add(scalePanel);

JScrollPane modifierScrollPane = new JScrollPane(modifierPanel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

var okButton = new DialogButton(Messages.getString("Ok.text"));
okButton.addActionListener(this::okButtonActionPerformed);
getRootPane().setDefaultButton(okButton);

var cancelButton = new DialogButton(Messages.getString("Cancel.text"));
cancelButton.addActionListener(this::cancelActionPerformed);

panel.add(new MMButton("btnCancel", resources, "Cancel.text", "Cancel.toolTipText",
this::cancelActionPerformed));
panel.add(new MMButton("btnRefresh", resources, "RefreshDirectory.text",
"RefreshDirectory.toolTipText", evt -> getChooser().refreshDirectory()));
var refreshButton = new DialogButton(Messages.getString("RefreshDirectory.text"));
refreshButton.setToolTipText(Messages.getString("RefreshDirectory.toolTipText"));
refreshButton.addActionListener(evt -> getChooser().refreshDirectory());

return panel;
var parentCamoButton = new DialogButton(Messages.getString("CamoChoiceDialog.btnParent.text"));
parentCamoButton.setToolTipText(Messages.getString("CamoChoiceDialog.btnParent.toolTipText"));
parentCamoButton.addActionListener(evt -> {
setUseDefault(true);
okButtonActionPerformed(evt);
});
parentCamoButton.setEnabled(getChooser().canHaveIndividualCamouflage());

final JPanel buttonPanel = new JPanel(new WrapLayout(FlowLayout.RIGHT));
buttonPanel.setName("buttonPanel");
buttonPanel.add(parentCamoButton);
buttonPanel.add(refreshButton);
buttonPanel.add(UIUtil.scaledHorizontalSpacer(30));
buttonPanel.add(okButton);
buttonPanel.add(cancelButton);

container.add(modifierScrollPane);
container.add(buttonPanel);

return container;
}
//endregion Initialization

Expand All @@ -90,7 +160,13 @@ protected CamoChooser getChooser() {

@Override
public Camouflage getSelectedItem() {
return isUseDefault() ? new Camouflage() : ((Camouflage) super.getSelectedItem()).clone();
Camouflage result = new Camouflage();
if (!isUseDefault() && (super.getSelectedItem() != null)) {
result = ((Camouflage) super.getSelectedItem()).clone();
}
result.setScale(scaleSlider.getValue());
result.setRotationAngle(rotationSlider.getValue());
return result;
}

@Override
Expand All @@ -102,4 +178,22 @@ protected void finalizeInitialization() throws Exception {
private void adaptToGUIScale() {
UIUtil.adjustDialog(this, UIUtil.FONT_SCALE1);
}
}

@Override
public void setVisible(boolean b) {
if ((originalCamo != null) && b) {
rotationSlider.setValue(originalCamo.getRotationAngle());
scaleSlider.setValue(originalCamo.getScale());
}
if (b) {
getChooser().getImageList().addListSelectionListener(e -> updatePreview());
}
super.setVisible(b);
}

private void updatePreview() {
if (getSelectedItem() != null) {
entityImage.updateDisplayedEntity(entity, getSelectedItem());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import megamek.client.ui.renderers.AbstractIconRenderer;
import megamek.common.annotations.Nullable;
import megamek.common.icons.AbstractIcon;
import megamek.common.icons.Camouflage;
import megamek.common.util.fileUtils.AbstractDirectory;
import org.apache.logging.log4j.LogManager;

Expand Down Expand Up @@ -422,7 +423,9 @@ protected void setSelection(final @Nullable AbstractIcon icon) {
// Select the root if the selection could not be found
if (found) {
getTreeCategories().setSelectionPath(new TreePath(currentNode.getPath()));
getImageList().setSelectedValue(icon, true);
// Since camos in the chooser are all free of rotation and scaling, must remove these to find the item
Camouflage cleanedCamo = new Camouflage(icon.getCategory(), icon.getFilename());
getImageList().setSelectedValue(cleanedCamo, true);
} else {
getTreeCategories().setSelectionPath(new TreePath(root.getPath()));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class DialogButton extends JButton {
private static final long serialVersionUID = 952919304556828345L;

/** The minimum width this button will have at GUI scale == 1 */
private final static int BUTTON_MIN_WIDTH = 120;
private final static int BUTTON_MIN_WIDTH = 95;

public DialogButton(String text) {
super(text);
Expand Down
4 changes: 4 additions & 0 deletions megamek/src/megamek/client/ui/swing/lobby/ChatLounge.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,10 @@ public void focusLost(FocusEvent e) {
}
Player player = getSelectedClient().getLocalPlayer();
CamoChooserDialog ccd = new CamoChooserDialog(clientgui.getFrame(), player.getCamouflage());
List<Entity> playerEntities = game().getPlayerEntities(player, false);
if (!playerEntities.isEmpty()) {
ccd.setDisplayedEntity(CollectionUtil.anyOneElement(playerEntities));
}

// If the dialog was canceled or nothing selected, do nothing
if (!ccd.showDialog().isConfirmed()) {
Expand Down
4 changes: 3 additions & 1 deletion megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,9 @@ public void individualCamo(Collection<Entity> entities) {
// Display the CamoChooser and await the result
// The dialog is preset to a random entity's settings
Entity entity = CollectionUtil.anyOneElement(entities);
CamoChooserDialog ccd = new CamoChooserDialog(frame(), entity.getOwner().getCamouflage());
boolean hasIndividualCamo = entities.stream().anyMatch(e -> !e.getCamouflage().hasDefaultCategory());
CamoChooserDialog ccd = new CamoChooserDialog(frame(), entity.getCamouflageOrElseOwners(), hasIndividualCamo);
ccd.setDisplayedEntity(entity);
if (ccd.showDialog().isCancelled()) {
return;
}
Expand Down
Loading

0 comments on commit 1aacd32

Please sign in to comment.