Worldmap Segment's label edition capability.
First version of the BeanShell console.
Bug fixes...
This commit is contained in:
Zukero
2015-06-23 17:33:12 +02:00
parent 4b62b65537
commit adf65b47db
16 changed files with 820 additions and 16 deletions

View File

@@ -18,7 +18,7 @@ import com.gpl.rpg.atcontentstudio.ui.WorkspaceSelector;
public class ATContentStudio {
public static final String APP_NAME = "Andor's Trail Content Studio";
public static final String APP_VERSION = "v0.3.4.dev";
public static final String APP_VERSION = "v0.4.0";
public static boolean STARTED = false;
public static StudioFrame frame = null;

View File

@@ -773,6 +773,26 @@ public class Project implements ProjectTreeNode, Serializable {
((JSONElement) target).jsonFile = new File(baseContent.gameData.getGameDataElement(((JSONElement)target).getClass(), target.id).jsonFile.getAbsolutePath());
alteredContent.gameData.addElement((JSONElement) target);
}
public void createWorldmapSegment(WorldmapSegment node) {
node.writable = true;
if (getWorldmapSegment(node.id) != null) {
WorldmapSegment existingNode = getWorldmapSegment(node.id);
for (GameDataElement backlink : existingNode.getBacklinks()) {
backlink.elementChanged(existingNode, node);
}
existingNode.getBacklinks().clear();
node.writable = true;
node.state = GameDataElement.State.created;
alteredContent.worldmap.addSegment(node);
node.link();
} else {
createdContent.worldmap.addSegment(node);
node.state = GameDataElement.State.created;
node.link();
}
fireElementAdded(node, getNodeIndex(node));
}
@Override

View File

@@ -4,6 +4,7 @@ import java.awt.Image;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
@@ -48,6 +49,12 @@ public class TMXMapSet implements ProjectTreeNode {
}
}
}
Collections.sort(tmxMaps, new Comparator<TMXMap>() {
@Override
public int compare(TMXMap o1, TMXMap o2) {
return o1.id.compareTo(o2.id);
}
});
}
@Override

View File

@@ -3,6 +3,8 @@ package com.gpl.rpg.atcontentstudio.model.maps;
import java.awt.Image;
import java.awt.Point;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -21,8 +23,9 @@ public class WorldmapSegment extends GameDataElement {
public int segmentX;
public int segmentY;
public Map<String, Point> mapLocations = new HashMap<String, Point>();
public Map<String, NamedArea> labelLocations = new HashMap<String, NamedArea>();
public Map<String, Point> mapLocations = new LinkedHashMap<String, Point>();
public Map<String, List<String>> labelledMaps = new LinkedHashMap<String, List<String>>();
public Map<String, NamedArea> labels = new LinkedHashMap<String, NamedArea>();
public Element xmlNode;
public WorldmapSegment(Worldmap parent, String name, Element xmlNode) {
@@ -49,11 +52,18 @@ public class WorldmapSegment extends GameDataElement {
for (int j = 0; j < mapsList.getLength(); j++) {
Element mapNode = (Element) mapsList.item(j);
mapLocations.put(mapNode.getAttribute("id"), new Point(Integer.parseInt(mapNode.getAttribute("x")) - segmentX, Integer.parseInt(mapNode.getAttribute("y")) - segmentY));
String area;
if ((area = mapNode.getAttribute("area")) != null && !"".equals(area)) {
if (labelledMaps.get(area) == null) {
labelledMaps.put(area, new LinkedList<String>());
}
labelledMaps.get(area).add(mapNode.getAttribute("id"));
}
}
NodeList namedAreasNodeList = xmlNode.getElementsByTagName("namedarea");
for (int j = 0; j < namedAreasNodeList.getLength(); j++) {
Element namedAreaNode = (Element) namedAreasNodeList.item(j);
labelLocations.put(namedAreaNode.getAttribute("id"), new NamedArea(namedAreaNode.getAttribute("id"), namedAreaNode.getAttribute("name"), namedAreaNode.getAttribute("type")));
labels.put(namedAreaNode.getAttribute("id"), new NamedArea(namedAreaNode.getAttribute("id"), namedAreaNode.getAttribute("name"), namedAreaNode.getAttribute("type")));
}
this.state = State.parsed;
}
@@ -104,10 +114,15 @@ public class WorldmapSegment extends GameDataElement {
map.setAttribute("id", s);
map.setAttribute("x", Integer.toString(mapLocations.get(s).x + segmentX));
map.setAttribute("y", Integer.toString(mapLocations.get(s).y + segmentY));
for (String label : labelledMaps.keySet()) {
if (labelledMaps.get(label).contains(s)) {
map.setAttribute("area", label);
}
}
element.appendChild(map);
}
for (NamedArea area : labelLocations.values()) {
for (NamedArea area : labels.values()) {
Element namedArea = doc.createElement("namedarea");
namedArea.setAttribute("id", area.id);
namedArea.setAttribute("name", area.name);
@@ -117,6 +132,7 @@ public class WorldmapSegment extends GameDataElement {
return element;
}
@Override
public List<SaveEvent> attemptSave() {
@@ -126,9 +142,9 @@ public class WorldmapSegment extends GameDataElement {
}
public static class NamedArea {
String id;
String name;
String type;
public String id;
public String name;
public String type;
public NamedArea(String id, String name, String type) {
this.id = id;

View File

@@ -69,6 +69,9 @@ public class AboutEditor extends Editor {
"<a href=\"http://prefuse.org/\">Prefuse</a> by the Berkeley Institue of Design.<br/>" +
"License: <a href=\"http://prefuse.org/license-prefuse.txt\">Modified BSD License (a.k.a 3-Clause BSD)</a><br/>" +
"<br/>" +
"<a href=\"http://www.beanshell.org/\">BeanShell</a> by Pat Niemeyer.<br/>" +
"License: <a href=\"http://www.beanshell.org/license.html\">LGPL v3</a><br/>" +
"<br/>" +
"See the tabs below to find the full license text for each of these.<br/>" +
"<br/>" +
"The Windows installer was created with:<br/>" +
@@ -116,6 +119,7 @@ public class AboutEditor extends Editor {
editorTabsHolder.add("JIDE Common Layer License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.JIDE.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("libtiled-java License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.libtiled.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("prefuse License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/license-prefuse.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("BeanShell License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.LGPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("ATCS License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.GPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
}

View File

@@ -262,6 +262,7 @@ public class JSONCreationWizard extends JDialog {
buttonPane.add(cancel, JideBoxLayout.FIX);
ok = new JButton("Ok");
buttonPane.add(ok, JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
ok.addActionListener(new ActionListener() {

View File

@@ -201,6 +201,10 @@ public class ProjectsTree extends JPanel {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.importJSON));
}
if (actions.createWorldmap.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.createWorldmap));
}
if (actions.loadSave.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.loadSave));
@@ -219,6 +223,10 @@ public class ProjectsTree extends JPanel {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.compareNPCs));
}
if (actions.runBeanShell.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.runBeanShell));
}
if (actions.exportProject.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.exportProject));

View File

@@ -136,6 +136,7 @@ public class StudioFrame extends JFrame {
projectMenu.add(new JSeparator());
projectMenu.add(new JMenuItem(actions.createGDE));
projectMenu.add(new JMenuItem(actions.importJSON));
projectMenu.add(new JMenuItem(actions.createWorldmap));
projectMenu.add(new JMenuItem(actions.loadSave));
getJMenuBar().add(projectMenu);
@@ -143,6 +144,8 @@ public class StudioFrame extends JFrame {
toolsMenu.add(new JMenuItem(actions.compareItems));
toolsMenu.add(new JMenuItem(actions.compareNPCs));
toolsMenu.add(new JSeparator());
toolsMenu.add(new JMenuItem(actions.runBeanShell));
toolsMenu.add(new JSeparator());
toolsMenu.add(new JMenuItem(actions.exportProject));
getJMenuBar().add(toolsMenu);

View File

@@ -19,6 +19,8 @@ import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.tree.TreePath;
import bsh.util.JConsole;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.ClosedProject;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
@@ -32,6 +34,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
import com.gpl.rpg.atcontentstudio.model.saves.SavedGamesSet;
import com.gpl.rpg.atcontentstudio.ui.tools.BeanShellView;
import com.gpl.rpg.atcontentstudio.ui.tools.ItemsTableView;
import com.gpl.rpg.atcontentstudio.ui.tools.NPCsTableView;
@@ -213,6 +216,17 @@ public class WorkspaceActions {
}
};
public ATCSAction createWorldmap = new ATCSAction("Create Worldmap segment", "Opens the worldmap segment creation wizard") {
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
new WorldmapCreationWizard(selectedNode.getProject()).setVisible(true);
}
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode != null && selectedNode.getProject() != null);
}
};
public ATCSAction importJSON = new ATCSAction("Import JSON data", "Opens the JSON import wizard") {
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
@@ -281,6 +295,12 @@ public class WorkspaceActions {
};
};
public ATCSAction runBeanShell = new ATCSAction("Run Beanshell console", "Opens a beanshell scripting pad."){
public void actionPerformed(ActionEvent e) {
new BeanShellView();
};
};
public ATCSAction showAbout = new ATCSAction("About...", "Displays credits and other informations about ATCS"){
public void actionPerformed(ActionEvent e) {
ATContentStudio.frame.showAbout();

View File

@@ -0,0 +1,158 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.jidesoft.swing.JideBoxLayout;
public class WorldmapCreationWizard extends JDialog {
private static final long serialVersionUID = 6491044105090917567L;
private WorldmapSegment creation = new WorldmapSegment(null, null, null);
final JLabel message;
final JTextField idField;
final JButton ok;
final Project proj;
public WorldmapCreationWizard(final Project proj) {
super(ATContentStudio.frame);
this.proj = proj;
setTitle("Create Worldmap segment");
JPanel pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
pane.add(new JLabel("Create a new worldmap segment."), JideBoxLayout.FIX);
message = new JLabel("Enter a map segment ID below: ");
pane.add(message, JideBoxLayout.FIX);
final JPanel idPane = new JPanel();
idPane.setLayout(new BorderLayout());
JLabel idLabel = new JLabel("Internal ID: ");
idPane.add(idLabel, BorderLayout.WEST);
idField = new JTextField("");
idField.setEditable(true);
idPane.add(idField, BorderLayout.CENTER);
pane.add(idPane, JideBoxLayout.FIX);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
JButton cancel = new JButton("Cancel");
buttonPane.add(cancel, JideBoxLayout.FIX);
ok = new JButton("Ok");
buttonPane.add(ok, JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
creation.id = idField.getText();
WorldmapCreationWizard.this.setVisible(false);
WorldmapCreationWizard.this.dispose();
proj.createWorldmapSegment(creation);
notifyCreated();
ATContentStudio.frame.selectInTree(creation);
ATContentStudio.frame.openEditor(creation);
}
});
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
creation = null;
WorldmapCreationWizard.this.setVisible(false);
WorldmapCreationWizard.this.dispose();
}
});
DocumentListener statusUpdater = new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void insertUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateStatus();
}
};
idField.getDocument().addDocumentListener(statusUpdater);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
setMinimumSize(new Dimension(350,120));
updateStatus();
pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = getSize();
setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
}
public void updateStatus() {
boolean trouble = false;
message.setText("<html><font color=\"#00AA00\">Looks OK to me.</font></html>");
if (idField.getText() == null || idField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">Internal ID must not be empty.</font></html>");
trouble = true;
} else if (proj.getWorldmapSegment(idField.getText()) != null) {
if (proj.getWorldmapSegment(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A worldmap segment with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getWorldmapSegment(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A worldmap segment with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getWorldmapSegment(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A worldmap segment with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
ok.setEnabled(!trouble);
message.revalidate();
message.repaint();
}
public static interface CreationCompletedListener {
public void segmentCreated(WorldmapSegment created);
}
private List<CreationCompletedListener> listeners = new ArrayList<WorldmapCreationWizard.CreationCompletedListener>();
public void addCreationListener(CreationCompletedListener l) {
listeners.add(l);
}
public void notifyCreated() {
for (CreationCompletedListener l : listeners) {
l.segmentCreated(creation);
}
}
}

View File

@@ -0,0 +1,190 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.jidesoft.swing.JideBoxLayout;
public class WorldmapLabelEditionWizard extends JDialog {
private static final long serialVersionUID = 4911946705579386332L;
final JLabel message;
final JTextField idField;
final JTextField labelField;
final JTextField typeField;
final JButton ok;
final WorldmapSegment segment;
final WorldmapSegment.NamedArea label;
boolean createMode = false;
public WorldmapLabelEditionWizard(WorldmapSegment segment) {
this(segment, new WorldmapSegment.NamedArea(null, null, null), true);
}
public WorldmapLabelEditionWizard(WorldmapSegment segment, WorldmapSegment.NamedArea label) {
this(segment, label, false);
}
public WorldmapLabelEditionWizard(WorldmapSegment segment, WorldmapSegment.NamedArea namedArea, boolean createMode) {
super(ATContentStudio.frame);
this.createMode = createMode;
this.segment = segment;
this.label = namedArea;
setTitle(createMode ? "Create Worldmap Label" : "Edit Worldmap Label");
JPanel pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
pane.add(new JLabel(createMode ? "Create a worldmap label." : "Edit a worldmap label."), JideBoxLayout.FIX);
message = new JLabel("Enter a label ID below: ");
pane.add(message, JideBoxLayout.FIX);
final JPanel idPane = new JPanel();
idPane.setLayout(new BorderLayout());
JLabel idLabel = new JLabel("Internal ID: ");
idPane.add(idLabel, BorderLayout.WEST);
idField = new JTextField(label.id);
idField.setEditable(true);
idPane.add(idField, BorderLayout.CENTER);
pane.add(idPane, JideBoxLayout.FIX);
final JPanel labelPane = new JPanel();
labelPane.setLayout(new BorderLayout());
JLabel labelLabel = new JLabel("Label: ");
labelPane.add(labelLabel, BorderLayout.WEST);
labelField = new JTextField(label.name);
labelField.setEditable(true);
labelPane.add(labelField, BorderLayout.CENTER);
pane.add(labelPane, JideBoxLayout.FIX);
final JPanel typePane = new JPanel();
typePane.setLayout(new BorderLayout());
JLabel typeLabel = new JLabel("Type: ");
typePane.add(typeLabel, BorderLayout.WEST);
typeField = new JTextField(label.type);
if (typeField.getText().equals("")) {
typeField.setText("settlement");
}
typeField.setEditable(true);
typePane.add(typeField, BorderLayout.CENTER);
pane.add(typePane, JideBoxLayout.FIX);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
JButton cancel = new JButton("Cancel");
buttonPane.add(cancel, JideBoxLayout.FIX);
ok = new JButton("Ok");
buttonPane.add(ok, JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
label.id = idField.getText();
label.name = labelField.getText();
label.type = labelField.getText();
WorldmapLabelEditionWizard.this.setVisible(false);
WorldmapLabelEditionWizard.this.dispose();
if (WorldmapLabelEditionWizard.this.createMode) {
WorldmapLabelEditionWizard.this.segment.labels.put(label.id, label);
}
notifyCreated();
}
});
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
WorldmapLabelEditionWizard.this.setVisible(false);
WorldmapLabelEditionWizard.this.dispose();
}
});
DocumentListener statusUpdater = new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void insertUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateStatus();
}
};
idField.getDocument().addDocumentListener(statusUpdater);
labelField.getDocument().addDocumentListener(statusUpdater);
typeField.getDocument().addDocumentListener(statusUpdater);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
setMinimumSize(new Dimension(350,170));
updateStatus();
pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = getSize();
setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
}
public void updateStatus() {
boolean trouble = false;
message.setText("<html><font color=\"#00AA00\">Looks OK to me.</font></html>");
if (idField.getText() == null || idField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">Internal ID must not be empty.</font></html>");
trouble = true;
} else if (segment.labels.get(idField.getText()) != null && segment.labels.get(idField.getText()) != label) {
message.setText("<html><font color=\"#FF0000\">A worldmap label with the same ID already exists in this worldmap.</font></html>");
trouble = true;
} else if (labelField.getText() == null || labelField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">Label must not be empty.</font></html>");
trouble = true;
}
// message.setText("<html><font color=\"#FF9000\">This is a Warning example</font></html>");
ok.setEnabled(!trouble);
message.revalidate();
message.repaint();
}
public static interface CreationCompletedListener {
public void labelCreated(WorldmapSegment.NamedArea created);
}
private List<CreationCompletedListener> listeners = new ArrayList<WorldmapLabelEditionWizard.CreationCompletedListener>();
public void addCreationListener(CreationCompletedListener l) {
listeners.add(l);
}
public void notifyCreated() {
for (CreationCompletedListener l : listeners) {
l.labelCreated(label);
}
}
}

View File

@@ -5,9 +5,12 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.swing.ButtonGroup;
@@ -30,9 +33,11 @@ import com.gpl.rpg.atcontentstudio.model.SaveEvent;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.Worldmap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment.NamedArea;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
import com.gpl.rpg.atcontentstudio.ui.Editor;
import com.gpl.rpg.atcontentstudio.ui.SaveItemsWizard;
import com.gpl.rpg.atcontentstudio.ui.WorldmapLabelEditionWizard;
import com.jidesoft.swing.ComboBoxSearchable;
import com.jidesoft.swing.JideBoxLayout;
import com.jidesoft.swing.JideTabbedPane;
@@ -47,10 +52,12 @@ public class WorldMapEditor extends Editor {
moveViewSelect,
moveMaps,
deleteMaps,
addMap
addMap,
editLabelCoverage
}
public String mapBeingAddedID = null;
public String selectedLabel = null;
public WorldMapEditor(WorldmapSegment worldmap) {
target = worldmap;
@@ -94,6 +101,11 @@ public class WorldMapEditor extends Editor {
zoomSliderPane.add(zoomSlider, JideBoxLayout.VARY);
zoomSliderPane.add(new JLabel(new ImageIcon(DefaultIcons.getZoomIcon())), JideBoxLayout.FIX);
final JRadioButton editLabelCoverage = new JRadioButton("Edit label coverage");
final JButton editLabel = new JButton("Edit map label");
final JButton createLabel = new JButton("Create map label");
final JButton deleteLabel = new JButton("Delete map label");
if (target.writable) {
JPanel mapToolsPane = new JPanel();
mapToolsPane.setLayout(new JideBoxLayout(mapToolsPane, JideBoxLayout.LINE_AXIS));
@@ -136,7 +148,23 @@ public class WorldMapEditor extends Editor {
mapToolsPane.add(new JPanel(), JideBoxLayout.VARY);
moveView.setSelected(true);
pane.add(mapToolsPane, JideBoxLayout.FIX);
JPanel labelToolsPane = new JPanel();
labelToolsPane.setLayout(new JideBoxLayout(labelToolsPane, JideBoxLayout.LINE_AXIS));
mapToolsGroup.add(editLabelCoverage);
editLabelCoverage.setEnabled(false);
labelToolsPane.add(editLabelCoverage, JideBoxLayout.FIX);
editLabel.setEnabled(false);
labelToolsPane.add(editLabel, JideBoxLayout.FIX);
deleteLabel.setEnabled(false);
labelToolsPane.add(deleteLabel, JideBoxLayout.FIX);
createLabel.setEnabled(false);
labelToolsPane.add(createLabel, JideBoxLayout.FIX);
labelToolsPane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(labelToolsPane, JideBoxLayout.FIX);
moveView.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -196,10 +224,114 @@ public class WorldMapEditor extends Editor {
if (mapBox.getSelectedItem() == null) {
mapBeingAddedID = null;
} else {
if (mapBeingAddedID != null) {
mapView.updateFromModel();
}
mapBeingAddedID = ((TMXMap)mapBox.getSelectedItem()).id;
if (mapView.mapLocations.isEmpty()) {
TMXMap map = target.getProject().getMap(mapBeingAddedID);
int w = map.tmxMap.getWidth() * WorldMapView.TILE_SIZE;
int h = map.tmxMap.getHeight() * WorldMapView.TILE_SIZE;
mapView.mapLocations.put(mapBeingAddedID, new Rectangle(0, 0, w, h));
mapView.recomputeSize();
mapView.revalidate();
mapView.repaint();
}
}
}
});
editLabelCoverage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
editMode = EditMode.editLabelCoverage;
mapBox.setEnabled(false);
mapView.selected.clear();
mapView.selected.addAll(((WorldmapSegment)target).labelledMaps.get(selectedLabel));
if (mapBeingAddedID != null) {
mapView.mapLocations.remove(mapBeingAddedID);
mapBeingAddedID = null;
}
mapView.revalidate();
mapView.repaint();
}
});
editLabelCoverage.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.DESELECTED) {
WorldmapSegment map = (WorldmapSegment)target;
if (map.labelledMaps.get(selectedLabel) != null) {
map.labelledMaps.get(selectedLabel).clear();
} else {
map.labelledMaps.put(selectedLabel, new LinkedList<String>());
}
for (String s : mapView.selected) {
map.labelledMaps.get(selectedLabel).add(s);
}
mapView.revalidate();
mapView.repaint();
}
}
});
editLabel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
mapView.selected.clear();
mapView.selected.addAll(((WorldmapSegment)target).labelledMaps.get(selectedLabel));
mapView.revalidate();
mapView.repaint();
WorldmapLabelEditionWizard wiz = new WorldmapLabelEditionWizard(worldmap, worldmap.labels.get(selectedLabel));
wiz.addCreationListener(new WorldmapLabelEditionWizard.CreationCompletedListener() {
@Override
public void labelCreated(NamedArea created) {
if (!created.id.equals(selectedLabel)) {
worldmap.labelledMaps.put(created.id, worldmap.labelledMaps.get(selectedLabel));
worldmap.labelledMaps.remove(selectedLabel);
worldmap.labels.put(created.id, created);
worldmap.labels.remove(selectedLabel);
selectedLabel = created.id;
mapView.revalidate();
mapView.repaint();
}
}
});
wiz.setVisible(true);
}
});
deleteLabel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
worldmap.labelledMaps.remove(selectedLabel);
worldmap.labels.remove(selectedLabel);
selectedLabel = null;
mapView.revalidate();
mapView.repaint();
}
});
createLabel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
WorldmapLabelEditionWizard wiz = new WorldmapLabelEditionWizard(worldmap);
wiz.addCreationListener(new WorldmapLabelEditionWizard.CreationCompletedListener() {
@Override
public void labelCreated(NamedArea created) {
worldmap.labelledMaps.put(created.id, new LinkedList<String>());
worldmap.labelledMaps.get(created.id).addAll(mapView.selected);
mapView.revalidate();
mapView.repaint();
}
});
wiz.setVisible(true);
}
});
}
@@ -247,20 +379,25 @@ public class WorldMapEditor extends Editor {
break;
}
}
if (editMode == EditMode.moveViewSelect) {
if (editMode == EditMode.moveViewSelect || editMode == EditMode.editLabelCoverage) {
if (selectedMap == null) return;
if (e.getButton() == MouseEvent.BUTTON1) {
if (e.isControlDown() || e.isShiftDown()) {
if (mapView.selected.contains(selectedMap)) {
mapView.selected.remove(selectedMap);
update = true;
if (editMode != EditMode.editLabelCoverage || mapView.selected.size() > 1) {
mapView.selected.remove(selectedMap);
mapSelectionChanged();
update = true;
}
} else {
mapView.selected.add(selectedMap);
mapSelectionChanged();
update = true;
}
} else {
mapView.selected.clear();
mapView.selected.add(selectedMap);
mapSelectionChanged();
update = true;
}
if (e.getClickCount() == 2) {
@@ -269,8 +406,9 @@ public class WorldMapEditor extends Editor {
}
} else if (editMode == EditMode.deleteMaps) {
worldmap.mapLocations.remove(selectedMap);
worldmap.labelLocations.remove(selectedMap);
worldmap.labels.remove(selectedMap);
mapView.selected.remove(selectedMap);
mapSelectionChanged();
mapView.updateFromModel();
update = true;
} else if (editMode == EditMode.addMap && mapBeingAddedID != null) {
@@ -360,6 +498,47 @@ public class WorldMapEditor extends Editor {
mapView.repaint();
}
}
public void mapSelectionChanged() {
if (mapView.selected.isEmpty()) {
editLabelCoverage.setEnabled(false);
editLabel.setEnabled(false);
createLabel.setEnabled(false);
selectedLabel = null;
} else {
String label = null;
boolean multiLabel = false;
for (String map : mapView.selected) {
for (String existingLabel : ((WorldmapSegment)target).labelledMaps.keySet()) {
if (((WorldmapSegment)target).labelledMaps.get(existingLabel).contains(map)) {
if (label != null && !label.equals(existingLabel)) {
multiLabel = true;
}
label = existingLabel;
}
}
}
if (multiLabel) {
editLabelCoverage.setEnabled(false);
editLabel.setEnabled(false);
createLabel.setEnabled(false);
deleteLabel.setEnabled(false);
selectedLabel = null;
} else if (label != null) {
editLabelCoverage.setEnabled(true);
editLabel.setEnabled(true);
deleteLabel.setEnabled(true);
createLabel.setEnabled(false);
selectedLabel = label;
} else {
editLabelCoverage.setEnabled(false);
editLabel.setEnabled(false);
deleteLabel.setEnabled(false);
createLabel.setEnabled(true);
selectedLabel = null;
}
}
}
};
mapView.addMouseListener(mouseListener);

View File

@@ -3,10 +3,16 @@ package com.gpl.rpg.atcontentstudio.ui.map;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -87,6 +93,30 @@ public class WorldMapView extends JComponent implements Scrollable {
g2.translate(-x, -y);
}
Font f = g2.getFont();
f = f.deriveFont(70f).deriveFont(Font.BOLD);
g2.setFont(f);
g2.setStroke(new BasicStroke(3));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
FontMetrics fm = g2.getFontMetrics();
FontRenderContext frc = g2.getFontRenderContext();
for (String s : worldmap.labels.keySet()) {
String label = worldmap.labels.get(s).name;
Rectangle areaCovered = new Rectangle(0, 0, -1, -1);
for (String map : worldmap.labelledMaps.get(s)) {
areaCovered.add(mapLocations.get(map));
}
Rectangle2D stringBounds = fm.getStringBounds(label, g2);
GlyphVector gv = f.createGlyphVector(frc, label);
g2.setColor(Color.WHITE);
g2.fill(gv.getOutline((int)(areaCovered.getCenterX() - stringBounds.getCenterX()), (int)(areaCovered.getCenterY() - stringBounds.getCenterY())));
g2.setColor(Color.BLACK);
g2.draw(gv.getOutline((int)(areaCovered.getCenterX() - stringBounds.getCenterX()), (int)(areaCovered.getCenterY() - stringBounds.getCenterY())));
}
}
@Override
@@ -202,6 +232,8 @@ public class WorldMapView extends JComponent implements Scrollable {
return originMoved;
}
public void updateFromModel() {
mapLocations.clear();
sizeX = sizeY = 0;
@@ -232,13 +264,13 @@ public class WorldMapView extends JComponent implements Scrollable {
}
List<String> toRemove = new ArrayList<String>();
for (String s : worldmap.labelLocations.keySet()) {
for (String s : worldmap.labels.keySet()) {
if (!mapLocations.containsKey(s)) {
toRemove.add(s);
}
}
for (String s : toRemove) {
worldmap.labelLocations.remove(s);
worldmap.labels.remove(s);
}
}