Compare commits

..

4 Commits

Author SHA1 Message Date
Zukero
e04c3ee2fd v0.6.2 released! Redesigned WorldMap editor. Many new UI features. Fixed
Trainer.
2017-05-05 15:07:50 +02:00
Zukero
38a1e90aad Redesigned Worldmap editor. Better UI & support for town labels.
Searchable map list that mirrors the on-map selection.
2017-05-04 14:27:38 +02:00
Zukero
83d459021b Simple bug fix that broke the NPC icon selection window. 2017-04-21 15:55:15 +02:00
Zukero
fb8dcb9fb4 v0.6.1! Rebuilt completely the Quest editor. Each quest stage has its
own backlinks now. Quest log entries and dialogue replies are now
translatable too. Multiple minor UI improvements (notably multiline text
area are now taller, and rewards and requirements appear more clearly in
the dialogue tree view).
2017-04-14 15:52:32 +02:00
23 changed files with 1477 additions and 560 deletions

View File

@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="res"/>
<classpathentry kind="src" path="hacked-libtiled"/>
<classpathentry kind="src" path="siphash-zackehh/src/main/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="lib/jide-oss.jar"/>
<classpathentry kind="lib" path="lib/json_simple-1.1.jar"/>
<classpathentry kind="lib" path="lib/junit-4.10.jar"/>
<classpathentry kind="lib" path="lib/prefuse.jar"/>
<classpathentry kind="lib" path="lib/rsyntaxtextarea.jar"/>
<classpathentry kind="lib" path="lib/ui.jar"/>
<classpathentry kind="lib" path="lib/bsh-2.0b4.jar"/>
<classpathentry kind="lib" path="lib/AndorsTrainer_v0.1.3.jar"/>
<classpathentry kind="lib" path="lib/jsoup-1.10.2.jar" sourcepath="lib/jsoup-1.10.2-sources.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="res"/>
<classpathentry kind="src" path="hacked-libtiled"/>
<classpathentry kind="src" path="siphash-zackehh/src/main/java"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="lib/jide-oss.jar"/>
<classpathentry kind="lib" path="lib/json_simple-1.1.jar"/>
<classpathentry kind="lib" path="lib/junit-4.10.jar"/>
<classpathentry kind="lib" path="lib/prefuse.jar"/>
<classpathentry kind="lib" path="lib/rsyntaxtextarea.jar"/>
<classpathentry kind="lib" path="lib/ui.jar"/>
<classpathentry kind="lib" path="lib/bsh-2.0b4.jar"/>
<classpathentry kind="lib" path="lib/jsoup-1.10.2.jar" sourcepath="lib/jsoup-1.10.2-sources.jar"/>
<classpathentry kind="lib" path="lib/AndorsTrainer_v0.1.4.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<jardesc>
<jar path="ATContentStudio/ATCS_v0.6.0.jar"/>
<jar path="ATContentStudio/ATCS_v0.6.2.jar"/>
<options buildIfNeeded="true" compress="true" descriptionLocation="/ATContentStudio/ATCS_JAR.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
<selectedProjects/>

BIN
itemScroll.xcf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,7 +1,7 @@
!include MUI2.nsh
!define VERSION "0.6.0"
!define TRAINER_VERSION "0.1.3"
!define VERSION "0.6.2"
!define TRAINER_VERSION "0.1.4"
!define JAVA_BIN "javaw"
Name "Andor's Trail Content Studio v${VERSION}"

View File

@@ -24,7 +24,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.6.0";
public static final String APP_VERSION = "v0.6.2";
public static boolean STARTED = false;
public static StudioFrame frame = null;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -39,6 +39,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.ItemCategory;
import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.model.gamedata.Quest;
import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
import com.gpl.rpg.atcontentstudio.model.maps.Worldmap;
@@ -669,7 +670,7 @@ public class Project implements ProjectTreeNode, Serializable {
public Spritesheet getSpritesheet(int index) {
if (index < createdContent.gameSprites.spritesheets.size()) {
return createdContent.gameSprites.spritesheets.get(index);
} else if (index < getQuestCount()){
} else if (index < getSpritesheetCount()){
return getSpritesheet(baseContent.gameSprites.spritesheets.get(index - createdContent.gameSprites.spritesheets.size()).id);
}
return null;
@@ -758,6 +759,15 @@ public class Project implements ProjectTreeNode, Serializable {
} else {
if (type == GameSource.Type.source) {
JSONElement clone = (JSONElement) node.clone();
if (node instanceof Quest) {
for (QuestStage oldStage : ((Quest) node).stages) {
QuestStage newStage = ((Quest) clone).getStage(oldStage.progress);
for (GameDataElement backlink : oldStage.getBacklinks()) {
backlink.elementChanged(oldStage, newStage);
}
oldStage.getBacklinks().clear();
}
}
for (GameDataElement backlink : node.getBacklinks()) {
backlink.elementChanged(node, clone);
}

View File

@@ -265,6 +265,12 @@ public class Dialogue extends JSONElement {
break;
case questProgress:
reward.reward_obj = proj.getQuest(reward.reward_obj_id);
if (reward.reward_obj != null && reward.reward_value != null) {
QuestStage stage = ((Quest)reward.reward_obj).getStage(reward.reward_value);
if (stage != null) {
stage.addBacklink(this);
}
}
break;
case skillIncrease:
//Nothing to do (yet ?).
@@ -361,11 +367,7 @@ public class Dialogue extends JSONElement {
}
if (r.requirements != null) {
for (Requirement req : r.requirements) {
if (req.required_obj == oldOne) {
oldOne.removeBacklink(this);
req.required_obj = newOne;
if (newOne != null) newOne.addBacklink(this);
}
req.elementChanged(oldOne, newOne);
}
}
}
@@ -377,6 +379,12 @@ public class Dialogue extends JSONElement {
r.reward_obj = newOne;
if (newOne != null) newOne.addBacklink(this);
}
if (oldOne instanceof QuestStage) {
if (r.reward_obj != null && r.reward_obj.equals(oldOne.parent) && r.reward_value != null && r.reward_value.equals(((QuestStage) oldOne).progress)) {
oldOne.removeBacklink((GameDataElement) this);
if (newOne != null) newOne.addBacklink((GameDataElement) this);
}
}
}
}
}

View File

@@ -30,22 +30,6 @@ public class Quest extends JSONElement {
public Integer visible_in_log = null;
public List<QuestStage> stages = null;
public static class QuestStage implements Cloneable {
public Integer progress = null;
public String log_text = null;
public Integer exp_reward = null;
public Integer finishes_quest = null;
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
@Override
public String getDesc() {
return (needsSaving() ? "*" : "")+name+" ("+id+")";
@@ -105,6 +89,8 @@ public class Quest extends JSONElement {
Quest quest = new Quest();
quest.id = (String) questJson.get("id");
quest.name = (String) questJson.get("name");
//Quests have to be parsed to have their stages initialized.
quest.parse(questJson);
return quest;
}
@@ -117,15 +103,12 @@ public class Quest extends JSONElement {
this.stages = new ArrayList<QuestStage>();
for (Object questStageJsonObj : questStagesJson) {
Map questStageJson = (Map)questStageJsonObj;
QuestStage questStage = new QuestStage();
questStage.progress = JSONElement.getInteger((Number) questStageJson.get("progress"));
questStage.log_text = (String) questStageJson.get("logText");
questStage.exp_reward = JSONElement.getInteger((Number) questStageJson.get("rewardExperience"));
questStage.finishes_quest = JSONElement.getInteger((Number) questStageJson.get("finishesQuest"));
QuestStage questStage = new QuestStage(this);
questStage.parse(questStageJson);
this.stages.add(questStage);
}
}
this.state = State.parsed;
}
@Override
@@ -142,6 +125,9 @@ public class Quest extends JSONElement {
return;
}
for (QuestStage stage : stages) {
stage.link();
}
//Nothing to link to :D
this.state = State.linked;
}
@@ -164,9 +150,9 @@ public class Quest extends JSONElement {
clone.name = this.name;
clone.visible_in_log = this.visible_in_log;
if (this.stages != null) {
clone.stages = new ArrayList<Quest.QuestStage>();
clone.stages = new ArrayList<QuestStage>();
for (QuestStage stage : this.stages){
clone.stages.add((QuestStage) stage.clone());
clone.stages.add((QuestStage) stage.clone(clone));
}
}
return clone;
@@ -188,12 +174,7 @@ public class Quest extends JSONElement {
List stagesJson = new ArrayList();
questJson.put("stages", stagesJson);
for (QuestStage stage : this.stages) {
Map stageJson = new LinkedHashMap();
stagesJson.add(stageJson);
if (stage.progress != null) stageJson.put("progress", stage.progress);
if (stage.log_text != null) stageJson.put("logText", stage.log_text);
if (stage.exp_reward != null) stageJson.put("rewardExperience", stage.exp_reward);
if (stage.finishes_quest != null) stageJson.put("finishesQuest", stage.finishes_quest);
stagesJson.add(stage.toJson());
}
}
return questJson;
@@ -204,5 +185,14 @@ public class Quest extends JSONElement {
public String getProjectFilename() {
return "questlist_"+getProject().name+".json";
}
public QuestStage getStage(Integer stageId) {
for (QuestStage stage : stages) {
if (stage.progress.equals(stageId)) {
return stage;
}
}
return null;
}
}

View File

@@ -0,0 +1,103 @@
package com.gpl.rpg.atcontentstudio.model.gamedata;
import java.awt.Image;
import java.util.LinkedHashMap;
import java.util.Map;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
public class QuestStage extends JSONElement {
private static final long serialVersionUID = 8313645819951513431L;
public Integer progress = null;
public String log_text = null;
public Integer exp_reward = null;
public Integer finishes_quest = null;
public QuestStage(Quest parent){
this.parent = parent;
}
public QuestStage clone(Quest cloneParent) {
QuestStage clone = new QuestStage(cloneParent);
clone.progress = progress != null ? new Integer(progress) : null;
clone.log_text = log_text != null ? new String(log_text) : null;
clone.exp_reward = exp_reward != null ? new Integer(exp_reward) : null;
clone.finishes_quest = finishes_quest != null ? new Integer(finishes_quest) : null;
clone.id = this.id;
return clone;
}
@SuppressWarnings("rawtypes")
@Override
public void parse(Map jsonObj) {
progress = JSONElement.getInteger((Number) jsonObj.get("progress"));
this.id = ((Quest)parent).id+":"+progress;
log_text = (String) jsonObj.get("logText");
exp_reward = JSONElement.getInteger((Number) jsonObj.get("rewardExperience"));
finishes_quest = JSONElement.getInteger((Number) jsonObj.get("finishesQuest"));
state = State.parsed;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Map toJson() {
Map stageJson = new LinkedHashMap();
if (progress != null) stageJson.put("progress", progress);
if (log_text != null) stageJson.put("logText", log_text);
if (exp_reward != null) stageJson.put("rewardExperience", exp_reward);
if (finishes_quest != null) stageJson.put("finishesQuest", finishes_quest);
return stageJson;
}
@Override
public String getDesc() {
return progress+" - "+(exp_reward != null ? "["+exp_reward+"XP]" : "")+((finishes_quest != null) && (finishes_quest == 1) ? "[END]" : "")+log_text;
}
@Override
public void link() {
if (this.state == State.created || this.state == State.modified || this.state == State.saved) {
//This type of state is unrelated to parsing/linking.
return;
}
if (this.state == State.init) {
//Not parsed yet.
this.parse();
} else if (this.state == State.linked) {
//Already linked.
return;
}
//Nothing to link to :D
this.state = State.linked;
}
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {
// Nothing to link to.
}
@Override
public String getProjectFilename() {
return ((Quest)parent).getProjectFilename();
}
@Override
public GameDataElement clone() {
return null;
}
@Override
public Image getIcon() {
return DefaultIcons.getQuestIcon();
}
public Image getImage() {
return DefaultIcons.getQuestImage();
}
}

View File

@@ -112,6 +112,12 @@ public class Requirement extends JSONElement {
case questLatestProgress:
case questProgress:
this.required_obj = proj.getQuest(required_obj_id);
if (this.required_obj != null && this.required_value != null) {
QuestStage stage = ((Quest)this.required_obj).getStage(this.required_value);
if (stage != null) {
stage.addBacklink((GameDataElement) this.parent);
}
}
break;
case consumedBonemeals:
case skillLevel:
@@ -150,6 +156,12 @@ public class Requirement extends JSONElement {
this.required_obj = newOne;
if (newOne != null) newOne.addBacklink((GameDataElement) this.parent);
}
if (oldOne instanceof QuestStage) {
if (this.required_obj != null && this.required_obj.equals(oldOne.parent) && this.required_value != null && this.required_value.equals(((QuestStage) oldOne).progress)) {
oldOne.removeBacklink((GameDataElement) this.parent);
if (newOne != null) newOne.addBacklink((GameDataElement) this.parent);
}
}
}
@Override
public String getProjectFilename() {

View File

@@ -32,6 +32,8 @@ public class WorldmapSegment extends GameDataElement {
private static final long serialVersionUID = 2658610076889592723L;
public static final String TEMP_LABEL_KEY = "ATCS_INTERNAL_TEMPORARY_KEY_FOR_LABEL";
public int segmentX;
public int segmentY;
public Map<String, Point> mapLocations = new LinkedHashMap<String, Point>();
@@ -154,6 +156,7 @@ public class WorldmapSegment extends GameDataElement {
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 (TEMP_LABEL_KEY.equals(label)) continue;
if (labelledMaps.get(label).contains(s)) {
map.setAttribute("area", label);
}
@@ -161,7 +164,9 @@ public class WorldmapSegment extends GameDataElement {
element.appendChild(map);
}
for (NamedArea area : labels.values()) {
for (String key : labels.keySet()) {
if (TEMP_LABEL_KEY.equals(key)) continue;
NamedArea area = labels.get(key);
Element namedArea = doc.createElement("namedarea");
namedArea.setAttribute("id", area.id);
namedArea.setAttribute("name", area.name);

View File

@@ -227,6 +227,10 @@ public class DefaultIcons {
public static Image getCreateTileLayerImage() { return getImage(CREATE_TILE_LAYER_RES); }
public static Image getCreateTileLayerIcon() { return getIcon(CREATE_TILE_LAYER_RES); }
private static String LABEL_RES = "/com/gpl/rpg/atcontentstudio/img/label.png";
public static Image getLabelImage() { return getImage(LABEL_RES); }
public static Image getLabelIcon() { return getIcon(LABEL_RES); }
private static String ZOOM_RES = "/com/gpl/rpg/atcontentstudio/img/zoom.png";
public static Image getZoomImage() { return getImage(ZOOM_RES); }
public static Image getZoomIcon() { return getIcon(ZOOM_RES); }

View File

@@ -39,6 +39,7 @@ import javax.swing.JSpinner.NumberEditor;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.Scrollable;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@@ -63,6 +64,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.ItemCategory;
import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.model.gamedata.Quest;
import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.utils.WeblateIntegration;
import com.jidesoft.swing.ComboBoxSearchable;
@@ -118,7 +120,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
public static void addTranslationPane(JPanel pane, final JTextComponent tfComponent, final String initialValue) {if (Workspace.activeWorkspace.settings.translatorLanguage.getCurrentValue() != null) {
JPanel labelPane = new JPanel();
labelPane.setLayout(new JideBoxLayout(labelPane, JideBoxLayout.LINE_AXIS));
labelPane.setLayout(new JideBoxLayout(labelPane, JideBoxLayout.LINE_AXIS, 6));
final JLabel translateLinkLabel = new JLabel(getWeblateLabelLink(initialValue));
labelPane.add(translateLinkLabel, JideBoxLayout.FIX);
labelPane.add(new JLabel(" "), JideBoxLayout.FIX);
@@ -270,6 +272,9 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
tfPane.add(tfLabel, JideBoxLayout.FIX);
final JTextArea tfArea = new JTextArea(text);
tfArea.setEditable(editable);
tfArea.setRows(2);
tfArea.setLineWrap(true);
tfArea.setWrapStyleWord(true);
tfPane.add(new JScrollPane(tfArea), JideBoxLayout.VARY);
JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
tfPane.add(nullify, JideBoxLayout.FIX);
@@ -644,8 +649,63 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
return gdeBox;
}
public JComboBox<QuestStage> addQuestStageBox(JPanel pane, Project proj, String label, Integer initialValue, boolean writable, final FieldUpdateListener listener, Quest quest, final JComboBox questSelectionBox) {
JPanel gdePane = new JPanel();
gdePane.setLayout(new JideBoxLayout(gdePane, JideBoxLayout.LINE_AXIS, 6));
JLabel gdeLabel = new JLabel(label);
gdePane.add(gdeLabel, JideBoxLayout.FIX);
QuestStage initial = null;
if (quest != null) {
initial = quest.getStage(initialValue);
}
final QuestStageComboModel comboModel = new QuestStageComboModel(proj, initial, quest);
final JComboBox<QuestStage> combo = new JComboBox<QuestStage>(comboModel);
combo.setRenderer(new GDERenderer(false, writable));
new ComboBoxSearchable(combo){
@Override
protected String convertElementToString(Object object) {
if (object == null) return "none";
else return ((GameDataElement)object).getDesc();
}
};
questSelectionBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (comboModel.selected != null) {
Editor.this.target.removeBacklink(comboModel.selected);
}
Quest newQuest = (Quest) questSelectionBox.getSelectedItem();
comboModel.changeQuest(newQuest);
combo.revalidate();
}
});
combo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(combo, comboModel.selected == null ? null : comboModel.selected.progress);
}
});
combo.setEnabled(writable);
gdePane.add(combo, JideBoxLayout.VARY);
pane.add(gdePane, JideBoxLayout.FIX);
return combo;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public JList addBacklinksList(JPanel pane, GameDataElement gde) {
return addBacklinksList(pane, gde, "Elements linking to this one");
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public JList addBacklinksList(JPanel pane, GameDataElement gde, String title) {
final JList list = new JList(new GDEBacklinksListModel(gde));
list.addMouseListener(new MouseAdapter() {
@Override
@@ -666,7 +726,7 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
}
});
list.setCellRenderer(new GDERenderer(true, false));
CollapsiblePanel colPane = new CollapsiblePanel("Elements linking to this one");
CollapsiblePanel colPane = new CollapsiblePanel(title);
colPane.setLayout(new JideBoxLayout(colPane, JideBoxLayout.PAGE_AXIS));
colPane.add(new JScrollPane(list), JideBoxLayout.FIX);
colPane.add(new JPanel(), JideBoxLayout.FIX);
@@ -744,9 +804,25 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
label.setText("None"+(writable ? ". Click on the button to create one." : ""));
} else {
if (includeType && ((GameDataElement)value).getDataType() != null) {
label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc());
if (value instanceof QuestStage) {
String text = ((GameDataElement)value).getDesc();
if (text.length() > 60) {
text = text.substring(0, 57)+"...";
}
label.setText(((GameDataElement)value).getDataType().toString()+"/"+((Quest)((QuestStage)value).parent).id+":"+text);
} else {
label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc());
}
} else {
label.setText(((GameDataElement)value).getDesc());
if (value instanceof QuestStage) {
String text = ((GameDataElement)value).getDesc();
if (text.length() > 60) {
text = text.substring(0, 57)+"...";
}
label.setText(text);
} else {
label.setText(((GameDataElement)value).getDesc());
}
}
if (((GameDataElement)value).getIcon() == null) {
Notification.addError("Unable to find icon for "+((GameDataElement)value).getDesc());
@@ -759,6 +835,65 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
}
public static class QuestStageComboModel extends AbstractListModel<QuestStage> implements ComboBoxModel<QuestStage> {
private static final long serialVersionUID = -5854574666510314715L;
public Project project;
public Quest currentQuest;
public QuestStage selected;
public QuestStageComboModel(Project proj, QuestStage initial, Quest quest) {
this.project = proj;
this.currentQuest = quest;
this.selected = initial;
}
@Override
public int getSize() {
if (currentQuest == null) return 1;
return currentQuest.stages.size()+1;
}
@Override
public QuestStage getElementAt(int index) {
if (index == 0) {
return null;
}
return currentQuest.stages.get(index - 1);
}
@SuppressWarnings("unchecked")
@Override
public void setSelectedItem(Object anItem) {
selected = (QuestStage) anItem;
}
@Override
public Object getSelectedItem() {
return selected;
}
public void itemAdded(QuestStage item, int index) {
fireIntervalAdded(this, index, index);
}
public void itemRemoved(QuestStage item, int index) {
fireIntervalRemoved(this, index, index);
}
public void changeQuest(Quest newQuest) {
int size = getSize();
currentQuest = null;
selected = null;
fireIntervalRemoved(this, 1, size);
currentQuest = newQuest;
fireIntervalAdded(this, 1, getSize());
}
}
public static class GDEBacklinksListModel implements ListModel<GameDataElement> {
GameDataElement source;
@@ -892,7 +1027,5 @@ public abstract class Editor extends JPanel implements ProjectElementListener {
return null;
}
}

View File

@@ -43,6 +43,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.model.gamedata.Quest;
import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage;
import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.ui.BooleanBasedCheckBox;
@@ -94,7 +95,7 @@ public class DialogueEditor extends JSONElementEditor {
private JTextField rewardObjId;
private JComboBox rewardObjIdCombo;
private MyComboBox rewardObj;
private JSpinner rewardValue;
private JComponent rewardValue;
private RepliesListModel repliesListModel;
@SuppressWarnings("rawtypes")
@@ -114,7 +115,7 @@ public class DialogueEditor extends JSONElementEditor {
private JPanel requirementParamsPane;
private MyComboBox requirementObj;
private JTextField requirementObjId;
private JSpinner requirementValue;
private JComponent requirementValue;
private BooleanBasedCheckBox requirementNegated;
private DialogueGraphView dialogueGraphView;
@@ -421,7 +422,7 @@ public class DialogueEditor extends JSONElementEditor {
rewardObjId = null;
rewardObjIdCombo = null;
rewardObj = addQuestBox(pane, ((Dialogue)target).getProject(), "Quest: ", (Quest) reward.reward_obj, writable, listener);
rewardValue = addIntegerField(pane, "Step ID: ", reward.reward_value, false, writable, listener);
rewardValue = addQuestStageBox(pane, ((Dialogue)target).getProject(), "Quest stage: ", reward.reward_value, writable, listener, (Quest) reward.reward_obj, rewardObj);
break;
case skillIncrease:
rewardMap = null;
@@ -613,10 +614,10 @@ public class DialogueEditor extends JSONElementEditor {
replyText = null;
replyNextPhrase = addDialogueBox(pane, ((Dialogue)target).getProject(), "Next phrase: ", reply.next_phrase, writable, listener);
} else if (Dialogue.Reply.KEY_PHRASE_ID.contains(reply.next_phrase_id)) {
replyText = addTextField(pane, "Reply text: ", reply.text, writable, listener);
replyText = addTranslatableTextField(pane, "Reply text: ", reply.text, writable, listener);
replyNextPhrase = null;
} else {
replyText = addTextField(pane, "Reply text: ", reply.text, writable, listener);
replyText = addTranslatableTextField(pane, "Reply text: ", reply.text, writable, listener);
replyNextPhrase = addDialogueBox(pane, ((Dialogue)target).getProject(), "Next phrase: ", reply.next_phrase, writable, listener);
}
@@ -679,7 +680,7 @@ public class DialogueEditor extends JSONElementEditor {
case questProgress:
requirementObj = addQuestBox(pane, project, "Quest: ", (Quest) requirement.required_obj, writable, listener);
requirementObjId = null;
requirementValue = addIntegerField(pane, "Quest stage: ", requirement.required_value, false, writable, listener);
requirementValue = addQuestStageBox(pane, project, "Quest stage: ", requirement.required_value, writable, listener, (Quest) requirement.required_obj, requirementObj);
break;
case skillLevel:
requirementObj = null;
@@ -1149,7 +1150,21 @@ public class DialogueEditor extends JSONElementEditor {
}
rewardsListModel.itemChanged(selectedReward);
} else if (source == rewardValue) {
//Backlink removal to quest stages when selecting another quest are handled in the addQuestStageBox() method. Too complex too handle here
Quest quest = null;
QuestStage stage = null;
if (rewardValue instanceof JComboBox<?>) {
quest = ((Quest)selectedReward.reward_obj);
if (quest != null && selectedReward.reward_value != null) {
stage = quest.getStage(selectedReward.reward_value);
if (stage != null) stage.removeBacklink(dialogue);
}
}
selectedReward.reward_value = (Integer) value;
if (quest != null) {
stage = quest.getStage(selectedReward.reward_value);
if (stage != null) stage.addBacklink(dialogue);
}
rewardsListModel.itemChanged(selectedReward);
} else if (source == replyTypeCombo) {
updateRepliesParamsEditorPane(repliesParamsPane, selectedReply, this);
@@ -1190,7 +1205,21 @@ public class DialogueEditor extends JSONElementEditor {
selectedRequirement.required_obj = null;
requirementsListModel.itemChanged(selectedRequirement);
} else if (source == requirementValue) {
//Backlink removal to quest stages when selecting another quest are handled in the addQuestStageBox() method. Too complex too handle here
Quest quest = null;
QuestStage stage = null;
if (requirementValue instanceof JComboBox<?>) {
quest = ((Quest)selectedRequirement.required_obj);
if (quest != null && selectedRequirement.required_value != null) {
stage = quest.getStage(selectedRequirement.required_value);
if (stage != null) stage.removeBacklink(dialogue);
}
}
selectedRequirement.required_value = (Integer) value;
if (quest != null) {
stage = quest.getStage(selectedRequirement.required_value);
if (stage != null) stage.addBacklink(dialogue);
}
requirementsListModel.itemChanged(selectedRequirement);
} else if (source == requirementNegated) {
selectedRequirement.negated = (Boolean) value;

View File

@@ -16,6 +16,7 @@ import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
@@ -29,6 +30,8 @@ import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.SaveEvent;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataCategory;
import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.gamedata.Quest;
import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
@@ -37,8 +40,11 @@ import com.gpl.rpg.atcontentstudio.ui.Editor;
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
import com.gpl.rpg.atcontentstudio.ui.IdChangeImpactWizard;
import com.gpl.rpg.atcontentstudio.ui.SaveItemsWizard;
import com.gpl.rpg.atcontentstudio.ui.ScrollablePanel;
import com.gpl.rpg.atcontentstudio.ui.ScrollablePanel.ScrollableSizeHint;
import com.gpl.rpg.atcontentstudio.ui.sprites.SpriteChooser;
import com.jidesoft.swing.JideBoxLayout;
import com.jidesoft.swing.JideScrollPane;
import com.jidesoft.swing.JideTabbedPane;
public abstract class JSONElementEditor extends Editor {
@@ -65,7 +71,11 @@ public abstract class JSONElementEditor extends Editor {
}
public void addEditorTab(String id, JPanel editor) {
JScrollPane scroller = new JScrollPane(editor);
ScrollablePanel view = new ScrollablePanel(new BorderLayout());
view.setScrollableWidth(ScrollableSizeHint.FIT);
view.setScrollableHeight(ScrollableSizeHint.STRETCH);
view.add(editor, BorderLayout.CENTER);
JScrollPane scroller = new JScrollPane(view, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroller.getVerticalScrollBar().setUnitIncrement(16);
editorTabsHolder.addTab(id, scroller);
editorTabs.put(id, editor);
@@ -178,8 +188,17 @@ public abstract class JSONElementEditor extends Editor {
if (node.getParent() instanceof GameDataCategory<?>) {
((GameDataCategory<?>)node.getParent()).remove(node);
node.save();
GameDataElement newOne = proj.getGameDataElement(node.getClass(), node.id);
if (node instanceof Quest) {
for (QuestStage oldStage : ((Quest) node).stages) {
QuestStage newStage = newOne != null ? ((Quest) newOne).getStage(oldStage.progress) : null;
for (GameDataElement backlink : oldStage.getBacklinks()) {
backlink.elementChanged(oldStage, newStage);
}
}
}
for (GameDataElement backlink : node.getBacklinks()) {
backlink.elementChanged(node, proj.getGameDataElement(node.getClass(), node.id));
backlink.elementChanged(node, newOne);
}
}
}

View File

@@ -1,6 +1,5 @@
package com.gpl.rpg.atcontentstudio.ui.gamedataeditors;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -8,27 +7,30 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.gamedata.Quest;
import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage;
import com.gpl.rpg.atcontentstudio.ui.CollapsiblePanel;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
import com.gpl.rpg.atcontentstudio.ui.IntegerBasedCheckBox;
@@ -43,15 +45,20 @@ public class QuestEditor extends JSONElementEditor {
private static final String form_view_id = "Form";
private static final String json_view_id = "JSON";
private QuestStage selectedStage = null;
private JTextField idField;
private JTextField nameField;
private IntegerBasedCheckBox visibleBox;
private QuestStageTableModel stagesModel;
private JTable stagesTable;
private JButton createStage;
private JButton deleteStage;
private JButton moveUp;
private JButton moveDown;
private StagesListModel stagesListModel;
private JList<QuestStage> stagesList;
// private JPanel stagesParamPane;
private JSpinner progressField;
private JTextArea logTextField;
private JSpinner xpRewardField;
private IntegerBasedCheckBox finishQuestBox;
public QuestEditor(Quest quest) {
@@ -72,242 +79,214 @@ public class QuestEditor extends JSONElementEditor {
nameField = addTranslatableTextField(pane, "Quest Name: ", quest.name, quest.writable, listener);
visibleBox = addIntegerBasedCheckBox(pane, "Visible in quest log", quest.visible_in_log, quest.writable, listener);
JPanel stagesPane = new JPanel();
stagesPane.setLayout(new JideBoxLayout(stagesPane, JideBoxLayout.PAGE_AXIS, 6));
stagesModel = new QuestStageTableModel(quest, listener);
stagesTable = new JTable(stagesModel);
stagesTable.getColumnModel().getColumn(0).setMinWidth(100);
stagesTable.getColumnModel().getColumn(0).setMaxWidth(100);
// stagesTable.getColumnModel().getColumn(1).setPreferredWidth(40);
// stagesTable.getColumnModel().getColumn(1).setPreferredWidth(40);
stagesTable.getColumnModel().getColumn(2).setMinWidth(100);
stagesTable.getColumnModel().getColumn(2).setMaxWidth(100);
stagesTable.getColumnModel().getColumn(3).setMinWidth(130);
stagesTable.getColumnModel().getColumn(3).setMaxWidth(130);
stagesTable.setCellSelectionEnabled(true);
stagesTable.getColumnModel().getColumn(1).setCellRenderer(new MultilineCellRenderer());
stagesPane.add(new JScrollPane(stagesTable), BorderLayout.CENTER);
if (quest.writable) {
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
createStage = new JButton(new ImageIcon(DefaultIcons.getCreateIcon()));
deleteStage = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
moveUp = new JButton(new ImageIcon(DefaultIcons.getArrowUpIcon()));
moveDown = new JButton(new ImageIcon(DefaultIcons.getArrowDownIcon()));
buttonPane.add(createStage, JideBoxLayout.FIX);
buttonPane.add(deleteStage, JideBoxLayout.FIX);
buttonPane.add(moveUp, JideBoxLayout.FIX);
buttonPane.add(moveDown, JideBoxLayout.FIX);
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
deleteStage.setEnabled(false);
moveUp.setEnabled(false);
moveDown.setEnabled(false);
stagesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
updateTableButtons();
CollapsiblePanel stagesPane = new CollapsiblePanel("Quest stages: ");
stagesPane.setLayout(new JideBoxLayout(stagesPane, JideBoxLayout.PAGE_AXIS));
stagesListModel = new StagesListModel(quest);
stagesList = new JList<QuestStage>(stagesListModel);
stagesList.setCellRenderer(new StagesCellRenderer());
stagesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
stagesPane.add(new JScrollPane(stagesList), JideBoxLayout.FIX);
final JPanel stagesEditorPane = new JPanel();
final JButton createStage = new JButton(new ImageIcon(DefaultIcons.getCreateIcon()));
final JButton deleteStage = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
final JButton moveStageUp = new JButton(new ImageIcon(DefaultIcons.getArrowUpIcon()));
final JButton moveStageDown = new JButton(new ImageIcon(DefaultIcons.getArrowDownIcon()));
deleteStage.setEnabled(false);
moveStageUp.setEnabled(false);
moveStageDown.setEnabled(false);
stagesList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
selectedStage = (QuestStage) stagesList.getSelectedValue();
if (selectedStage != null) {
deleteStage.setEnabled(true);
moveStageUp.setEnabled(stagesList.getSelectedIndex() > 0);
moveStageDown.setEnabled(stagesList.getSelectedIndex() < (stagesListModel.getSize() - 1));
} else {
deleteStage.setEnabled(false);
moveStageUp.setEnabled(false);
moveStageDown.setEnabled(false);
}
});
updateStageEditorPane(stagesEditorPane, selectedStage, listener);
}
});
if (quest.writable) {
JPanel listButtonsPane = new JPanel();
listButtonsPane.setLayout(new JideBoxLayout(listButtonsPane, JideBoxLayout.LINE_AXIS, 6));
createStage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stagesModel.createStage();
listener.valueChanged(stagesTable, null);
stagesTable.revalidate();
stagesTable.repaint();
QuestStage stage = new QuestStage(quest);
stagesListModel.addItem(stage);
stagesList.setSelectedValue(stage, true);
listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
});
deleteStage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stagesModel.deleteRow(stagesTable.getSelectedRow());
listener.valueChanged(stagesTable, null);
stagesTable.revalidate();
stagesTable.repaint();
updateTableButtons();
if (selectedStage != null) {
stagesListModel.removeItem(selectedStage);
selectedStage = null;
stagesList.clearSelection();
listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
}
});
moveUp.addActionListener(new ActionListener() {
moveStageUp.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stagesModel.moveRow(stagesTable.getSelectedRow(), true);
listener.valueChanged(stagesTable, null);
stagesTable.setRowSelectionInterval(stagesTable.getSelectedRow() - 1, stagesTable.getSelectedRow() - 1);
updateTableButtons();
if (selectedStage != null) {
stagesListModel.moveUp(selectedStage);
stagesList.setSelectedValue(selectedStage, true);
listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
}
});
moveDown.addActionListener(new ActionListener() {
moveStageDown.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stagesModel.moveRow(stagesTable.getSelectedRow(), false);
listener.valueChanged(stagesTable, null);
stagesTable.setRowSelectionInterval(stagesTable.getSelectedRow() + 1, stagesTable.getSelectedRow() + 1);
updateTableButtons();
if (selectedStage != null) {
stagesListModel.moveDown(selectedStage);
stagesList.setSelectedValue(selectedStage, true);
listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
}
});
stagesPane.add(buttonPane, JideBoxLayout.FIX);
listButtonsPane.add(createStage, JideBoxLayout.FIX);
listButtonsPane.add(deleteStage, JideBoxLayout.FIX);
listButtonsPane.add(moveStageUp, JideBoxLayout.FIX);
listButtonsPane.add(moveStageDown, JideBoxLayout.FIX);
listButtonsPane.add(new JPanel(), JideBoxLayout.VARY);
stagesPane.add(listButtonsPane, JideBoxLayout.FIX);
}
if (quest.stages == null || quest.stages.isEmpty()) {
stagesPane.collapse();
}
stagesEditorPane.setLayout(new JideBoxLayout(stagesEditorPane, JideBoxLayout.PAGE_AXIS));
stagesPane.add(stagesEditorPane, JideBoxLayout.FIX);
pane.add(stagesPane, JideBoxLayout.FIX);
}
public void updateTableButtons() {
public void updateStageEditorPane(JPanel pane, QuestStage selectedStage, FieldUpdateListener listener) {
pane.removeAll();
if (selectedStage != null) {
boolean writable = ((Quest)target).writable;
progressField = addIntegerField(pane, "Progress ID: ", selectedStage.progress, false, writable, listener);
logTextField = addTranslatableTextArea(pane, "Log text: ", selectedStage.log_text, writable, listener);
xpRewardField = addIntegerField(pane, "XP Reward: ", selectedStage.exp_reward, false, writable, listener);
finishQuestBox = addIntegerBasedCheckBox(pane, "Finishes quest", selectedStage.finishes_quest, writable, listener);
addBacklinksList(pane, selectedStage, "Elements linking to this quest stage");
if (stagesTable.getSelectedRow() >= 0 && stagesTable.getSelectedRow() < stagesModel.getRowCount()) {
deleteStage.setEnabled(true);
if (stagesTable.getSelectedRow() == 0) {
moveUp.setEnabled(false);
} else {
moveUp.setEnabled(true);
}
if (stagesTable.getSelectedRow() >= stagesModel.getRowCount() - 1) {
moveDown.setEnabled(false);
} else {
moveDown.setEnabled(true);
}
} else {
deleteStage.setEnabled(false);
moveUp.setEnabled(false);
moveDown.setEnabled(false);
}
pane.revalidate();
pane.repaint();
}
public class QuestStageTableModel implements TableModel {
public static class StagesListModel implements ListModel<QuestStage> {
Quest quest;
FieldUpdateListener listener;
public QuestStageTableModel(Quest q, FieldUpdateListener listener) {
this.quest = q;
this.listener = listener;
Quest source;
public StagesListModel(Quest quest) {
this.source = quest;
}
@Override
public int getRowCount() {
if (quest.stages == null) return 0;
return quest.stages.size();
public int getSize() {
if (source.stages == null) return 0;
return source.stages.size();
}
@Override
public int getColumnCount() {
return 4;
public QuestStage getElementAt(int index) {
if (source.stages == null) return null;
return source.stages.get(index);
}
@Override
public String getColumnName(int columnIndex) {
switch (columnIndex) {
case 0:
return "Progress ID";
case 1:
return "Log text";
case 2:
return "XP reward";
case 3:
return "Finishes quest";
default:
return "???";
public void addItem(QuestStage item) {
if (source.stages == null) {
source.stages = new ArrayList<QuestStage>();
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return Integer.class;
case 1:
return String.class;
case 2:
return Integer.class;
case 3:
return Boolean.class;
default:
return null;
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return quest.writable;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
return quest.stages.get(rowIndex).progress;
case 1:
return quest.stages.get(rowIndex).log_text;
case 2:
return quest.stages.get(rowIndex).exp_reward;
case 3:
return quest.stages.get(rowIndex).finishes_quest != null && quest.stages.get(rowIndex).finishes_quest.equals(1);
default:
return null;
}
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
switch (columnIndex) {
case 0:
quest.stages.get(rowIndex).progress = (Integer)aValue;
break;
case 1:
quest.stages.get(rowIndex).log_text = (String)aValue;
break;
case 2:
quest.stages.get(rowIndex).exp_reward = (Integer)aValue;
break;
case 3:
quest.stages.get(rowIndex).finishes_quest = ((Boolean)aValue) ? one : null;
break;
}
listener.valueChanged(stagesTable, aValue);
}
public void createStage() {
if (quest.stages == null) quest.stages = new ArrayList<Quest.QuestStage>();
quest.stages.add(new Quest.QuestStage());
for (TableModelListener l: listeners) {
l.tableChanged(new TableModelEvent(this, quest.stages.size() - 1));
source.stages.add(item);
int index = source.stages.indexOf(item);
for (ListDataListener l : listeners) {
l.intervalAdded(new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, index, index));
}
}
public void moveRow(int rowNumber, boolean moveUp) {
Quest.QuestStage stage = quest.stages.get(rowNumber);
quest.stages.remove(stage);
quest.stages.add(rowNumber + (moveUp ? -1 : 1), stage);
for (TableModelListener l : listeners) {
l.tableChanged(new TableModelEvent(this, rowNumber + (moveUp ? -1 : 0), rowNumber + (moveUp ? 0 : 1)));
public void removeItem(QuestStage item) {
int index = source.stages.indexOf(item);
source.stages.remove(item);
if (source.stages.isEmpty()) {
source.stages = null;
}
for (ListDataListener l : listeners) {
l.intervalRemoved(new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, index, index));
}
}
public void itemChanged(QuestStage item) {
int index = source.stages.indexOf(item);
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index));
}
}
public void deleteRow(int rowNumber) {
quest.stages.remove(rowNumber);
for (TableModelListener l: listeners) {
l.tableChanged(new TableModelEvent(this, rowNumber, quest.stages.size()));
public void moveUp(QuestStage item) {
int index = source.stages.indexOf(item);
QuestStage exchanged = source.stages.get(index - 1);
source.stages.set(index, exchanged);
source.stages.set(index - 1, item);
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index - 1, index));
}
if (quest.stages.isEmpty()) quest.stages = null;
}
public List<TableModelListener> listeners = new CopyOnWriteArrayList<TableModelListener>();
public void moveDown(QuestStage item) {
int index = source.stages.indexOf(item);
QuestStage exchanged = source.stages.get(index + 1);
source.stages.set(index, exchanged);
source.stages.set(index + 1, item);
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index + 1));
}
}
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
@Override
public void addTableModelListener(TableModelListener l) {
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public void removeTableModelListener(TableModelListener l) {
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
}
public static class StagesCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 7987880146189575234L;
@Override
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
JLabel label = ((JLabel)c);
label.setText(((QuestStage)value).getDesc());
label.setIcon(new ImageIcon(((QuestStage)value).getIcon()));
}
return c;
}
}
public class QuestFieldUpdater implements FieldUpdateListener {
@Override
@@ -337,6 +316,18 @@ public class QuestEditor extends JSONElementEditor {
ATContentStudio.frame.editorChanged(QuestEditor.this);
} else if (source == visibleBox) {
quest.visible_in_log = (Integer) value;
} else if (source == progressField) {
selectedStage.progress = (Integer) value;
stagesListModel.itemChanged(selectedStage);
} else if (source == logTextField) {
selectedStage.log_text = (String) value;
stagesListModel.itemChanged(selectedStage);
} else if (source == xpRewardField) {
selectedStage.exp_reward = (Integer) value;
stagesListModel.itemChanged(selectedStage);
} else if (source == finishQuestBox) {
selectedStage.finishes_quest = (Integer) value;
stagesListModel.itemChanged(selectedStage);
}
@@ -351,47 +342,6 @@ public class QuestEditor extends JSONElementEditor {
}
public class MultilineCellRenderer extends JTextArea implements TableCellRenderer {
private static final long serialVersionUID = 6539816623608859506L;
public MultilineCellRenderer() {
setLineWrap(true);
setWrapStyleWord(true);
//setOpaque(true);
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
if (isSelected) {
setForeground(stagesTable.getSelectionForeground());
setBackground(stagesTable.getSelectionBackground());
} else {
setForeground(stagesTable.getForeground());
setBackground(stagesTable.getBackground());
}
setFont(stagesTable.getFont());
if (hasFocus) {
setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
if (stagesTable.isCellEditable(row, column)) {
setForeground(UIManager.getColor("Table.focusCellForeground"));
setBackground(UIManager.getColor("Table.focusCellBackground"));
}
} else {
setBorder(BorderFactory.createLineBorder(getBackground(), 1));
}
setText((value == null ? "" : value.toString()));
int fh = getFontMetrics(getFont()).getHeight();
// int tl = getText().length();
setSize(stagesTable.getWidth(), fh);
stagesTable.setRowHeight(row, getPreferredSize().height);
return this;
}
}
}

View File

@@ -15,6 +15,7 @@ import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToolTip;
import javax.swing.SwingConstants;
import javax.swing.ToolTipManager;
import prefuse.Display;
@@ -68,6 +69,7 @@ public class DialogueGraphView extends Display {
public static final String ICON = "icon";
public static final String TARGET = "target";
public static final String REPLY = "reply";
public static final String HIDDEN_REPLY = "hidden_reply";
public static final String HAS_REQS = "has_reqs";
private static final Schema DECORATOR_SCHEMA = PrefuseLib.getVisualItemSchema();
@@ -174,6 +176,7 @@ public class DialogueGraphView extends Display {
graph.addColumn(ICON, Image.class, DefaultIcons.getNullifyIcon());
graph.addColumn(TARGET, GameDataElement.class, null);
graph.addColumn(REPLY, Dialogue.Reply.class, null);
graph.addColumn(HIDDEN_REPLY, Dialogue.Reply.class, null);
graph.addColumn(HAS_REQS, boolean.class, false);
addDialogue(dialogue, npcIcon);
}
@@ -224,6 +227,8 @@ public class DialogueGraphView extends Display {
} else if (r.next_phrase != null) {
//Go directly to next phrase
rNode = addDialogue(r.next_phrase, npcIcon);
//Add a pointer to the hidden reply, in order to fetch requirements later.
rNode.set(HIDDEN_REPLY, r);
} else if (Dialogue.Reply.KEY_PHRASE_ID.contains(r.next_phrase_id)) {
//Go directly to key phrase
rNode = addKeyPhraseNode(d, r.next_phrase_id);
@@ -499,27 +504,32 @@ public class DialogueGraphView extends Display {
label = new JLabel(new ImageIcon(DefaultIcons.getDialogueIcon()));
label.setText(d.id);
content.add(label, JideBoxLayout.FIX);
if (tooltippedItem.get(REPLY) == null) {
if (d.rewards != null && !d.rewards.isEmpty()) {
for (Dialogue.Reward r : d.rewards) {
label = new JLabel();
DialogueEditor.decorateRewardJLabel(label, r);
Object replObj = tooltippedItem.get(REPLY);
if (replObj == null) {
replObj = tooltippedItem.get(HIDDEN_REPLY);
}
if (replObj != null && replObj instanceof Dialogue.Reply) {
Dialogue.Reply r = (Dialogue.Reply) replObj;
if (r.requirements != null && !r.requirements.isEmpty()) {
JLabel reqTitle = new JLabel("--Requirements--", SwingConstants.CENTER);
content.add(reqTitle, JideBoxLayout.FIX);
for (Requirement req : r.requirements) {
label = new JLabel("", SwingConstants.CENTER);
DialogueEditor.decorateRequirementJLabel(label, req);
content.add(label, JideBoxLayout.FIX);
}
}
} else {
Object replObj = tooltippedItem.get(REPLY);
if (replObj instanceof Dialogue.Reply) {
Dialogue.Reply r = (Dialogue.Reply) replObj;
if (r.requirements != null && !r.requirements.isEmpty()) {
for (Requirement req : r.requirements) {
label = new JLabel();
DialogueEditor.decorateRequirementJLabel(label, req);
content.add(label, JideBoxLayout.FIX);
}
}
}
}
if (d.rewards != null && !d.rewards.isEmpty()) {
JLabel rewTitle = new JLabel("--Rewards--", SwingConstants.CENTER);
rewTitle.setAlignmentY(CENTER_ALIGNMENT);
content.add(rewTitle, JideBoxLayout.FIX);
for (Dialogue.Reward r : d.rewards) {
label = new JLabel("", SwingConstants.CENTER);
DialogueEditor.decorateRewardJLabel(label, r);
content.add(label, JideBoxLayout.FIX);
}
}
}
}

View File

@@ -81,6 +81,7 @@ import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.model.gamedata.Quest;
import com.gpl.rpg.atcontentstudio.model.gamedata.QuestStage;
import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement;
import com.gpl.rpg.atcontentstudio.model.maps.ContainerArea;
import com.gpl.rpg.atcontentstudio.model.maps.KeyArea;
@@ -172,7 +173,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe
@SuppressWarnings("rawtypes")
private JComboBox requirementObj;
private JTextField requirementObjId;
private JSpinner requirementValue;
private JComponent requirementValue;
private BooleanBasedCheckBox requirementNegated;
@SuppressWarnings("rawtypes")
@@ -642,7 +643,7 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe
case questProgress:
requirementObj = addQuestBox(pane, project, "Quest: ", (Quest) requirement.required_obj, writable, listener);
requirementObjId = null;
requirementValue = addIntegerField(pane, "Quest stage: ", requirement.required_value, false, writable, listener);
requirementValue = addQuestStageBox(pane, project, "Quest stage: ", requirement.required_value, writable, listener, (Quest) requirement.required_obj, requirementObj);
break;
case skillLevel:
requirementObj = null;
@@ -1949,11 +1950,37 @@ public class TMXMapEditor extends Editor implements TMXMap.MapChangedOnDiskListe
} else if (source == requirementValue) {
if (selectedMapObject instanceof KeyArea) {
KeyArea area = (KeyArea) selectedMapObject;
Quest quest = null;
QuestStage stage = null;
if (requirementValue instanceof JComboBox<?>) {
quest = ((Quest)area.requirement.required_obj);
if (quest != null && area.requirement.required_value != null) {
stage = quest.getStage(area.requirement.required_value);
if (stage != null) stage.removeBacklink(map);
}
}
area.requirement.required_value = (Integer) value;
if (quest != null) {
stage = quest.getStage(area.requirement.required_value);
if (stage != null) stage.addBacklink(map);
}
if (area.oldSchoolRequirement) area.updateNameFromRequirementChange();
} else if (selectedMapObject instanceof ReplaceArea) {
ReplaceArea area = (ReplaceArea) selectedMapObject;
Quest quest = null;
QuestStage stage = null;
if (requirementValue instanceof JComboBox<?>) {
quest = ((Quest)area.requirement.required_obj);
if (quest != null && area.requirement.required_value != null) {
stage = quest.getStage(area.requirement.required_value);
if (stage != null) stage.removeBacklink(map);
}
}
area.requirement.required_value = (Integer) value;
if (quest != null) {
stage = quest.getStage(area.requirement.required_value);
if (stage != null) stage.addBacklink(map);
}
if (area.oldSchoolRequirement) area.updateNameFromRequirementChange();
}
} else if (source == requirementNegated) {

View File

@@ -1,33 +1,47 @@
package com.gpl.rpg.atcontentstudio.ui.map;
import java.awt.BorderLayout;
import java.awt.Component;
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.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
@@ -35,16 +49,16 @@ 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.FieldUpdateListener;
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;
import com.jidesoft.swing.ListSearchable;
public class WorldMapEditor extends Editor {
public class WorldMapEditor extends Editor implements FieldUpdateListener {
private static final long serialVersionUID = -8358238912588729094L;
@@ -56,14 +70,31 @@ public class WorldMapEditor extends Editor {
public enum EditMode {
moveViewSelect,
moveMaps,
deleteMaps,
addMap,
editLabelCoverage
addMap
}
public String mapBeingAddedID = null;
public String selectedLabel = null;
WorldMapView mapView = null;
WorldmapSegment.NamedArea selectedLabel = null;
MapSegmentMapsListModel msmListModel = null;
ListSelectionModel msmListSelectionModel = null;
MapSegmentLabelsListModel mslListModel = null;
MapSegmentLabelMapsListModel mslmListModel = null;
ListSelectionModel mslmListSelectionModel = null;
ListModel<TMXMap> currentSelectionListModel = null;
ListSelectionModel currentSelectionSelectionModel = null;
ListModel<TMXMap> currentHighlightListModel = null;
JList<TMXMap> mapsShown;
JList<WorldmapSegment.NamedArea> labelList;
JTextField labelIdField;
JTextField labelNameField;
JTextField labelTypeField;
public WorldMapEditor(WorldmapSegment worldmap) {
target = worldmap;
@@ -128,10 +159,6 @@ 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();
@@ -143,9 +170,6 @@ public class WorldMapEditor extends Editor {
JRadioButton moveMaps = new JRadioButton("Move selected map(s)");
mapToolsGroup.add(moveMaps);
mapToolsPane.add(moveMaps, JideBoxLayout.FIX);
JRadioButton deleteMaps = new JRadioButton("Delete maps");
mapToolsGroup.add(deleteMaps);
mapToolsPane.add(deleteMaps, JideBoxLayout.FIX);
JRadioButton addMap = new JRadioButton("Add map");
mapToolsGroup.add(addMap);
mapToolsPane.add(addMap, JideBoxLayout.FIX);
@@ -176,22 +200,6 @@ public class WorldMapEditor extends Editor {
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) {
@@ -220,20 +228,6 @@ public class WorldMapEditor extends Editor {
}
});
deleteMaps.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
editMode = EditMode.deleteMaps;
mapBox.setEnabled(false);
if (mapBeingAddedID != null) {
mapView.mapLocations.remove(mapBeingAddedID);
mapBeingAddedID = null;
mapView.revalidate();
mapView.repaint();
}
}
});
addMap.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@@ -268,109 +262,27 @@ public class WorldMapEditor extends Editor {
}
});
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 ArrayList<String>());
}
for (String s : mapView.selected) {
map.labelledMaps.get(selectedLabel).add(s);
}
notifyModelModified();
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;
notifyModelModified();
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;
notifyModelModified();
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 ArrayList<String>());
worldmap.labelledMaps.get(created.id).addAll(mapView.selected);
notifyModelModified();
mapView.revalidate();
mapView.repaint();
}
});
wiz.setVisible(true);
}
});
}
JPanel mapZoomPane = new JPanel();
mapZoomPane.setLayout(new BorderLayout());
mapZoomPane.add(zoomSliderPane, BorderLayout.WEST);
mapZoomPane.add(mapScroller, BorderLayout.CENTER);
pane.add(mapZoomPane, JideBoxLayout.VARY);
JPanel mapPropsPane = new JPanel();
buildMapPropsPane(mapPropsPane, worldmap);
setCurrentSelectionModel(msmListModel, msmListSelectionModel);
final JSplitPane mapAndPropsSplitter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mapZoomPane, mapPropsPane);
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
mapAndPropsSplitter.setDividerLocation(0.8d);
}
});
pane.add(mapAndPropsSplitter, JideBoxLayout.VARY);
zoomSlider.addChangeListener(new ChangeListener() {
@Override
@@ -410,39 +322,29 @@ public class WorldMapEditor extends Editor {
break;
}
}
if (editMode == EditMode.moveViewSelect || editMode == EditMode.editLabelCoverage) {
if (editMode == EditMode.moveViewSelect) {
if (selectedMap == null) return;
if (e.getButton() == MouseEvent.BUTTON1) {
if (e.isControlDown() || e.isShiftDown()) {
if (mapView.selected.contains(selectedMap)) {
if (editMode != EditMode.editLabelCoverage || mapView.selected.size() > 1) {
mapView.selected.remove(selectedMap);
mapSelectionChanged();
if (mapView.getSelectedMapsIDs().contains(selectedMap)) {
if (mapView.getSelectedMapsIDs().size() > 1) {
removeFromSelection(selectedMap);
// mapView.selected.remove(selectedMap);
update = true;
}
} else {
mapView.selected.add(selectedMap);
mapSelectionChanged();
addToSelection(selectedMap);
// mapView.selected.add(selectedMap);
update = true;
}
} else {
mapView.selected.clear();
mapView.selected.add(selectedMap);
mapSelectionChanged();
clearSelection();
// mapView.selected.clear();
addToSelection(selectedMap);
// mapView.selected.add(selectedMap);
update = true;
}
if (e.getClickCount() == 2) {
ATContentStudio.frame.openEditor(worldmap.getProject().getMap(selectedMap));
}
}
} else if (editMode == EditMode.deleteMaps) {
worldmap.mapLocations.remove(selectedMap);
worldmap.labels.remove(selectedMap);
mapView.selected.remove(selectedMap);
mapSelectionChanged();
mapView.updateFromModel();
notifyModelModified();
update = true;
} else if (editMode == EditMode.addMap && mapBeingAddedID != null) {
if (e.getButton() == MouseEvent.BUTTON1) {
mapView.recomputeSize();
@@ -452,10 +354,9 @@ public class WorldMapEditor extends Editor {
update = true;
mapBeingAddedID = null;
}
if (update) {
mapView.revalidate();
mapView.repaint();
}
// if (update) {
// validateSelection();
// }
}
@Override
@@ -515,7 +416,7 @@ public class WorldMapEditor extends Editor {
mapDeltaX -= mapDeltaX % WorldMapView.TILE_SIZE;
mapDeltaY -= mapDeltaY % WorldMapView.TILE_SIZE;
for (String s : mapView.selected) {
for (String s : mapView.getSelectedMapsIDs()) {
mapView.mapLocations.get(s).x = (worldmap.mapLocations.get(s).x * WorldMapView.TILE_SIZE) + mapDeltaX;
mapView.mapLocations.get(s).y = (worldmap.mapLocations.get(s).y * WorldMapView.TILE_SIZE) + mapDeltaY;
}
@@ -531,54 +432,441 @@ public class WorldMapEditor extends Editor {
}
}
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);
mapView.addMouseMotionListener(mouseListener);
mapView.addMapClickListener(new WorldMapView.MapClickListener() {
@Override
public void mapClicked(MouseEvent e, TMXMap m) {
if (e.getClickCount() == 2) {
ATContentStudio.frame.openEditor(m);
}
}
@Override
public void mapChangeClicked(MouseEvent e, TMXMap m, TMXMap changeTarget) {
if (e.getClickCount() == 2) {
ATContentStudio.frame.openEditor(changeTarget);
}
}
@Override
public void backgroundClicked(MouseEvent e) {
}
});
return pane;
}
private void buildMapPropsPane(JPanel mapPropsPane, final WorldmapSegment worldmap) {
JideTabbedPane tabPane = new JideTabbedPane(JideTabbedPane.TOP);
JPanel mapListPane = new JPanel();
mapListPane.setLayout(new JideBoxLayout(mapListPane, JideBoxLayout.PAGE_AXIS));
mapListPane.add(new JLabel("Maps shown here"), JideBoxLayout.FIX);
msmListModel = new MapSegmentMapsListModel(worldmap);
mapsShown = new JList<TMXMap>(msmListModel);
mapsShown.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
msmListSelectionModel = mapsShown.getSelectionModel();
mapsShown.setCellRenderer(new MapCellRenderer());
new ListSearchable(mapsShown) {
@Override
protected String convertElementToString(Object object) {
return ((TMXMap)object).id;
}
};
mapListPane.add(new JScrollPane(mapsShown), JideBoxLayout.VARY);
mapsShown.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
ATContentStudio.frame.openEditor(mapsShown.getSelectedValue());
ATContentStudio.frame.selectInTree(mapsShown.getSelectedValue());
}
}
});
mapsShown.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
ATContentStudio.frame.openEditor(mapsShown.getSelectedValue());
ATContentStudio.frame.selectInTree(mapsShown.getSelectedValue());
}
}
});
mapsShown.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
setCurrentSelectionModel(msmListModel, msmListSelectionModel);
}
});
tabPane.addTab("Map list", mapListPane);
final JPanel labelEditPane = new JPanel();
labelEditPane.setLayout(new JideBoxLayout(labelEditPane, JideBoxLayout.PAGE_AXIS));
labelEditPane.add(new JLabel("Labels on the worldmap"), JideBoxLayout.FIX);
mslListModel = new MapSegmentLabelsListModel(worldmap);
labelList = new JList<WorldmapSegment.NamedArea>(mslListModel);
labelList.setCellRenderer(new MapLabelCellRenderer());
labelList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
labelEditPane.add(new JScrollPane(labelList), JideBoxLayout.FLEXIBLE);
JPanel labelListButtonsPane = new JPanel();
labelListButtonsPane.setLayout(new JideBoxLayout(labelListButtonsPane, JideBoxLayout.LINE_AXIS));
final JButton createLabel = new JButton(new ImageIcon(DefaultIcons.getCreateIcon()));
labelListButtonsPane.add(createLabel, JideBoxLayout.FIX);
final JButton deleteLabel = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
labelListButtonsPane.add(deleteLabel, JideBoxLayout.FIX);
labelListButtonsPane.add(new JPanel(), JideBoxLayout.VARY);
labelEditPane.add(labelListButtonsPane, JideBoxLayout.FIX);
final JPanel labelParametersPane = new JPanel();
labelEditPane.add(labelParametersPane, JideBoxLayout.FLEXIBLE);
labelList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
selectedLabel = labelList.getSelectedValue();
updateLabelParamsPane(labelParametersPane, worldmap);
labelEditPane.revalidate();
labelEditPane.repaint();
}
});
createLabel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
WorldmapSegment.NamedArea creation = new WorldmapSegment.NamedArea(null, null, null);
worldmap.labels.put(WorldmapSegment.TEMP_LABEL_KEY, creation);
worldmap.labelledMaps.put(WorldmapSegment.TEMP_LABEL_KEY, new ArrayList<String>());
mslListModel.listChanged();
labelList.setSelectedValue(creation, true);
}
});
deleteLabel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedLabel.id != null) {
worldmap.labelledMaps.remove(selectedLabel.id);
worldmap.labels.remove(selectedLabel.id);
} else {
worldmap.labelledMaps.remove(WorldmapSegment.TEMP_LABEL_KEY);
worldmap.labels.remove(WorldmapSegment.TEMP_LABEL_KEY);
}
labelList.clearSelection();
mslListModel.listChanged();
notifyModelModified();
}
});
tabPane.addTab("Labels", labelEditPane);
mapPropsPane.setLayout(new BorderLayout());
mapPropsPane.add(tabPane, BorderLayout.CENTER);
}
private void updateLabelParamsPane(JPanel labelParametersPane, final WorldmapSegment worldmap) {
labelParametersPane.removeAll();
if (selectedLabel == null) {
setCurrentHighlightModel(null);
return;
}
labelParametersPane.setLayout(new JideBoxLayout(labelParametersPane, JideBoxLayout.PAGE_AXIS));
labelIdField = addTextField(labelParametersPane, "Internal ID: ", selectedLabel.id, worldmap.writable, this);
labelNameField = addTranslatableTextField(labelParametersPane, "Name: ", selectedLabel.name, worldmap.writable, this);
labelTypeField = addTextField(labelParametersPane, "Type: ", selectedLabel.type, worldmap.writable, this);
labelParametersPane.add(new JLabel("Label covers the following maps"), JideBoxLayout.FIX);
mslmListModel = new MapSegmentLabelMapsListModel(worldmap, selectedLabel);
final JList<TMXMap> labelCoverageList = new JList<TMXMap>(mslmListModel);
labelCoverageList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
mslmListSelectionModel = labelCoverageList.getSelectionModel();
labelCoverageList.setCellRenderer(new MapCellRenderer());
labelParametersPane.add(new JScrollPane(labelCoverageList), JideBoxLayout.VARY);
labelCoverageList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
setCurrentHighlightModel(mslmListModel);
}
});
JPanel labelCoverageButtonsPane = new JPanel();
labelCoverageButtonsPane.setLayout(new JideBoxLayout(labelCoverageButtonsPane, JideBoxLayout.LINE_AXIS));
JButton addCoverage = new JButton("Add on-map selection");
labelCoverageButtonsPane.add(addCoverage, JideBoxLayout.FIX);
JButton replaceCoverage = new JButton("Replace by on-map selection");
labelCoverageButtonsPane.add(replaceCoverage, JideBoxLayout.FIX);
JButton removeFromCoverage = new JButton("Remove selected in list");
labelCoverageButtonsPane.add(removeFromCoverage, JideBoxLayout.FIX);
labelCoverageButtonsPane.add(new JPanel(), JideBoxLayout.VARY);
addCoverage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedLabel == null) return;
String labelId = selectedLabel.id;
if (labelId == null) labelId = WorldmapSegment.TEMP_LABEL_KEY;
List<String> currentCoverage = worldmap.labelledMaps.get(labelId);
if (currentCoverage == null) {
worldmap.labelledMaps.put(labelId, new ArrayList<String>());
currentCoverage = worldmap.labelledMaps.get(labelId);
}
for (int i = 0; i < msmListModel.getSize(); i++) {
if (msmListSelectionModel.isSelectedIndex(i)) {
if (!currentCoverage.contains(msmListModel.getElementAt(i).id)) {
currentCoverage.add(msmListModel.getElementAt(i).id);
}
}
}
mslmListModel.listChanged();
repaintMap();
}
});
replaceCoverage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedLabel == null) return;
String labelId = selectedLabel.id;
if (labelId == null) labelId = WorldmapSegment.TEMP_LABEL_KEY;
List<String> currentCoverage = worldmap.labelledMaps.get(labelId);
if (currentCoverage == null) {
worldmap.labelledMaps.put(labelId, new ArrayList<String>());
currentCoverage = worldmap.labelledMaps.get(labelId);
} else {
currentCoverage.clear();
}
for (int i = 0; i < msmListModel.getSize(); i++) {
if (msmListSelectionModel.isSelectedIndex(i)) {
if (!currentCoverage.contains(msmListModel.getElementAt(i).id)) {
currentCoverage.add(msmListModel.getElementAt(i).id);
}
}
}
mslmListModel.listChanged();
repaintMap();
}
});
removeFromCoverage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedLabel == null) return;
String labelId = selectedLabel.id;
if (labelId == null) labelId = WorldmapSegment.TEMP_LABEL_KEY;
List<String> currentCoverage = worldmap.labelledMaps.get(labelId);
if (currentCoverage == null) return;
List<String> toRemove = new ArrayList<String>();
for (int i = 0; i < mslmListModel.getSize(); i++) {
if (mslmListSelectionModel.isSelectedIndex(i)) {
if (currentCoverage.contains(mslmListModel.getElementAt(i).id)) {
toRemove.add(mslmListModel.getElementAt(i).id);
}
}
}
currentCoverage.removeAll(toRemove);
mslmListModel.listChanged();
repaintMap();
}
});
labelParametersPane.add(labelCoverageButtonsPane, JideBoxLayout.FIX);
setCurrentHighlightModel(mslmListModel);
}
public class MapSegmentMapsListModel implements ListModel<TMXMap> {
WorldmapSegment segment;
public MapSegmentMapsListModel(WorldmapSegment segment) {
this.segment = segment;
}
@Override
public int getSize() {
return segment.mapLocations.size();
}
@Override
public TMXMap getElementAt(int index) {
return segment.getProject().getMap(((String)segment.mapLocations.keySet().toArray()[index]));
}
public void listChanged() {
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, getSize() - 1));
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
}
public class MapSegmentLabelMapsListModel implements ListModel<TMXMap> {
WorldmapSegment segment;
WorldmapSegment.NamedArea area;
public MapSegmentLabelMapsListModel(WorldmapSegment segment, WorldmapSegment.NamedArea area) {
this.segment = segment;
this.area = area;
}
@Override
public int getSize() {
if (area.id == null) return segment.labelledMaps.get(WorldmapSegment.TEMP_LABEL_KEY).size();
return segment.labelledMaps.get(area.id).size();
}
@Override
public TMXMap getElementAt(int index) {
if (area.id == null) return segment.getProject().getMap(segment.labelledMaps.get(WorldmapSegment.TEMP_LABEL_KEY).get(index));
return segment.getProject().getMap(segment.labelledMaps.get(area.id).get(index));
}
public void listChanged() {
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, getSize() - 1));
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
}
public class MapSegmentLabelsListModel implements ListModel<WorldmapSegment.NamedArea> {
WorldmapSegment segment;
public MapSegmentLabelsListModel(WorldmapSegment segment) {
this.segment = segment;
}
@Override
public int getSize() {
return segment.labels.values().size();
}
@Override
public WorldmapSegment.NamedArea getElementAt(int index) {
return new ArrayList<WorldmapSegment.NamedArea>(segment.labels.values()).get(index);
}
public void listChanged() {
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, getSize() - 1));
}
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
}
public static class MapCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 6819681566800482793L;
public MapCellRenderer() {
super();
}
@SuppressWarnings("rawtypes")
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value == null) {
label.setText("None");
} else {
label.setText(((GameDataElement)value).getDesc());
if (((GameDataElement)value).getIcon() == null) {
Notification.addError("Unable to find icon for "+((GameDataElement)value).getDesc());
} else {
label.setIcon(new ImageIcon(((GameDataElement)value).getIcon()));
}
}
return label;
}
}
public static class MapLabelCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 6819681566800482793L;
public MapLabelCellRenderer() {
super();
}
@SuppressWarnings("rawtypes")
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value == null) {
label.setText("None");
} else {
WorldmapSegment.NamedArea area = (WorldmapSegment.NamedArea) value;
if (area.id != null) {
label.setText(area.name+" ("+area.id+")");
label.setIcon(new ImageIcon(DefaultIcons.getLabelIcon()));
} else {
label.setText("Incomplete Label. Enter an ID.");
label.setIcon(new ImageIcon(DefaultIcons.getNullifyIcon()));
}
}
return label;
}
}
public JPanel createButtonPane(final WorldmapSegment node) {
final JButton gdeIcon = new JButton(new ImageIcon(DefaultIcons.getUIMapImage()));
JPanel savePane = new JPanel();
@@ -721,7 +1009,9 @@ public class WorldMapEditor extends Editor {
public void pushToModel() {
mapView.pushToModel();
msmListModel.listChanged();
notifyModelModified();
updateXmlViewText(((WorldmapSegment)target).toXml());
}
public void notifyModelModified() {
@@ -730,5 +1020,98 @@ public class WorldMapEditor extends Editor {
target.childrenChanged(new ArrayList<ProjectTreeNode>());
}
ListSelectionListener activeSelectionListSelectionListener = new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
repaintMap();
};
};
private void setCurrentSelectionModel(ListModel<TMXMap> listModel, ListSelectionModel listSelectionModel) {
if (currentSelectionSelectionModel != null) {
currentSelectionSelectionModel.removeListSelectionListener(activeSelectionListSelectionListener);
}
currentSelectionListModel = listModel;
currentSelectionSelectionModel = listSelectionModel;
mapView.selectedListModel = listModel;
mapView.selectedSelectionModel = listSelectionModel;
currentSelectionSelectionModel.addListSelectionListener(activeSelectionListSelectionListener);
repaintMap();
}
private void setCurrentHighlightModel(ListModel<TMXMap> listModel) {
mapView.highlightedListModel = listModel;
repaintMap();
}
public void clearSelection() {
currentSelectionSelectionModel.clearSelection();
}
public void addToSelection(String mapId) {
if (mapId == null) return;
int index = -1;
for (int i = 0; i < currentSelectionListModel.getSize(); i++) {
if (currentSelectionListModel.getElementAt(i).id.equals(mapId)) {
index = i;
break;
}
}
currentSelectionSelectionModel.addSelectionInterval(index, index);
}
public void removeFromSelection(String mapId) {
if (mapId == null) return;
int index = -1;
for (int i = 0; i < currentSelectionListModel.getSize(); i++) {
if (currentSelectionListModel.getElementAt(i).id.equals(mapId)) {
index = i;
break;
}
}
currentSelectionSelectionModel.removeSelectionInterval(index, index);
}
public void repaintMap() {
mapView.revalidate();
mapView.repaint();
}
@Override
public void valueChanged(JComponent source, Object value) {
WorldmapSegment worldmap = (WorldmapSegment)target;
boolean changed = false;
if (source == labelIdField) {
List<String> coverage;
if (selectedLabel.id != null) {
coverage = worldmap.labelledMaps.get(selectedLabel.id);
worldmap.labelledMaps.remove(selectedLabel.id);
worldmap.labels.remove(selectedLabel.id);
} else {
coverage = worldmap.labelledMaps.get(WorldmapSegment.TEMP_LABEL_KEY);
worldmap.labels.remove(WorldmapSegment.TEMP_LABEL_KEY);
}
selectedLabel.id = (String) value;
if (value != null) {
worldmap.labelledMaps.put(selectedLabel.id, coverage);
worldmap.labels.put(selectedLabel.id, selectedLabel);
}
mslListModel.listChanged();
changed = true;
} else if (source == labelNameField) {
selectedLabel.name = (String) value;
mslListModel.listChanged();
changed = true;
repaintMap();
} else if (source == labelTypeField) {
selectedLabel.type = (String) value;
changed = true;
}
if (changed) {
notifyModelModified();
updateXmlViewText(worldmap.toXml());
}
}
}

View File

@@ -7,10 +7,14 @@ import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.Rectangle2D;
@@ -20,14 +24,21 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.swing.JComponent;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.Scrollable;
import javax.swing.ToolTipManager;
import tiled.view.MapRenderer;
import tiled.view.OrthogonalRenderer;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.maps.MapChange;
import com.gpl.rpg.atcontentstudio.model.maps.MapObject;
import com.gpl.rpg.atcontentstudio.model.maps.MapObjectGroup;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
@@ -46,26 +57,140 @@ public class WorldMapView extends JComponent implements Scrollable {
public Map<String, Rectangle> mapLocations = new LinkedHashMap<String, Rectangle>();
public ListSelectionModel selectedSelectionModel = null;
public ListModel<TMXMap> selectedListModel = null;
public Set<String> selected = new HashSet<String>();
public ListModel<TMXMap> highlightedListModel = null;
public float zoomLevel = 0.1f;
int sizeX = 0, sizeY = 0;
int offsetX = 0, offsetY = 0;
static final Color selectOutlineColor = new Color(255, 0, 0);
static final Stroke selectOutlineStroke = new BasicStroke(4f);
static final Color highlightOutlineColor = Color.CYAN;
static final Stroke highlightOutlineStroke = new BasicStroke(4f);
static final Color mapIdLabelOutlineColor = Color.BLACK;
static final Stroke thinLabelOutlineStroke = new BasicStroke(1.5f);
static final Stroke labelOutlineStroke = new BasicStroke(3f);
public WorldMapView(WorldmapSegment worldmap) {
this.worldmap = worldmap;
this.proj = worldmap.getProject();
updateFromModel();
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
String selectedMap = null;
boolean update = false;
int x = (int) (e.getX() / zoomLevel);
int y = (int) (e.getY() / zoomLevel);
for (String s : mapLocations.keySet()) {
if (mapLocations.get(s).contains(x, y)) {
selectedMap = s;
break;
}
}
if (selectedMap != null) {
x = x - mapLocations.get(selectedMap).x;
y = y - mapLocations.get(selectedMap).y;
//Look for a mapchange there
TMXMap map = proj.getMap(selectedMap);
boolean mapchangeFound = false;
for (MapObjectGroup group : map.groups) {
for (MapObject obj : group.mapObjects) {
if (obj instanceof MapChange) {
if (x >= obj.x && x < obj.x + obj.w && y >= obj.y && y < obj.y + obj.h) {
String mapId = ((MapChange)obj).map != null ? ((MapChange)obj).map.id : ((MapChange)obj).map_id;
mapChangeClicked(e, proj.getMap(selectedMap), proj.getMap(mapId));
mapchangeFound = true;
}
}
}
}
if (!mapchangeFound) {
mapClicked(e, WorldMapView.this.worldmap.getProject().getMap(selectedMap));
}
} else {
backgroundClicked(e);
}
}
});
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
String selectedMap = null;
int x = (int) (e.getX() / zoomLevel);
int y = (int) (e.getY() / zoomLevel);
for (String s : mapLocations.keySet()) {
if (mapLocations.get(s).contains(x, y)) {
selectedMap = s;
break;
}
}
if (selectedMap != null) {
//Reuse x,y to indicate to tile-within-the-map coordinates.
x = x - mapLocations.get(selectedMap).x;
y = y - mapLocations.get(selectedMap).y;
//Look for a mapchange there
TMXMap map = proj.getMap(selectedMap);
boolean mapchangeFound = false;
for (MapObjectGroup group : map.groups) {
for (MapObject obj : group.mapObjects) {
if (obj instanceof MapChange) {
if (x >= obj.x && x < obj.x + obj.w && y >= obj.y && y < obj.y + obj.h) {
String mapId = ((MapChange)obj).map != null ? ((MapChange)obj).map.id : ((MapChange)obj).map_id;
setToolTipText(selectedMap+"->"+mapId);
mapchangeFound = true;
}
}
}
}
if (!mapchangeFound) {
setToolTipText(selectedMap);
}
ToolTipManager.sharedInstance().registerComponent(WorldMapView.this);
ToolTipManager.sharedInstance().setEnabled(true);
} else {
ToolTipManager.sharedInstance().setEnabled(false);
ToolTipManager.sharedInstance().unregisterComponent(WorldMapView.this);
setToolTipText(null);
}
}
});
}
@Override
public Point getToolTipLocation(MouseEvent event) {
return event.getPoint();
}
private void paintOnGraphics(Graphics2D g2) {
g2.setPaint(new Color(100, 100, 100));
g2.fillRect(0, 0, sizeX, sizeY);
g2.setPaint(new Color(255, 0, 0));
g2.setStroke(new BasicStroke(4));
g2.setPaint(selectOutlineColor);
g2.setStroke(selectOutlineStroke);
Font areaNameFont = g2.getFont();
areaNameFont = areaNameFont.deriveFont(70f).deriveFont(Font.BOLD);
Font mapIdFont = g2.getFont();
mapIdFont = mapIdFont.deriveFont(50f).deriveFont(Font.BOLD);
g2.setFont(mapIdFont);
FontMetrics mifm = g2.getFontMetrics();
int mapIdLabelHeight = mifm.getHeight();
for (String s : mapLocations.keySet()) {
int x = mapLocations.get(s).x;
@@ -83,8 +208,8 @@ public class WorldMapView extends JComponent implements Scrollable {
if (layer instanceof tiled.core.TileLayer && layer.isVisible()) {
if (layer.getName().equalsIgnoreCase("walkable")) continue;
renderer.paintTileLayer(g2, (tiled.core.TileLayer) layer);
} else if (layer instanceof tiled.core.ObjectGroup && layer.isVisible()) {
// paintObjectGroup(g2, map, (tiled.core.ObjectGroup) layer);
} else if (layer instanceof tiled.core.ObjectGroup) {
paintObjectGroup(g2, map, (tiled.core.ObjectGroup) layer);
}
}
if (map.colorFilter != null) {
@@ -93,39 +218,119 @@ public class WorldMapView extends JComponent implements Scrollable {
MapColorFilters.applyColorfilter(map.colorFilter, g2);
g2.setClip(oldClip);
}
if (selected.contains(s)) {
g2.drawRect(0, 0, map.tmxMap.getWidth() * TILE_SIZE, map.tmxMap.getHeight() * TILE_SIZE);
}
g2.translate(-x, -y);
}
if (highlightedListModel != null) {
outlineFromListModel(g2, highlightedListModel, null, highlightOutlineColor, highlightOutlineStroke, mapIdFont, mapIdLabelHeight);
}
Font f = g2.getFont();
f = f.deriveFont(70f).deriveFont(Font.BOLD);
g2.setFont(f);
g2.setStroke(new BasicStroke(3));
if (selectedListModel != null && selectedSelectionModel != null) {
outlineFromListModel(g2, selectedListModel, selectedSelectionModel, selectOutlineColor, selectOutlineStroke, mapIdFont, mapIdLabelHeight);
}
g2.setStroke(labelOutlineStroke);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setFont(areaNameFont);
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));
if (label != null) {
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 = areaNameFont.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())));
}
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())));
}
}
private void paintObjectGroup(Graphics2D g2d, TMXMap map, tiled.core.ObjectGroup layer) {
for (MapObjectGroup group : map.groups) {
if (group.tmxGroup == layer) {
for (MapObject object : group.mapObjects) {
if (object instanceof MapChange) {
// Only show mapchange areas pointing to maps not shown in this worldmap
if (((MapChange)object).map != null && !mapLocations.containsKey(((MapChange)object).map.id)) {
drawObject(object, g2d, new Color(20, 20, 190));
}
}
}
break;
}
}
}
private void drawObject(MapObject object, Graphics2D g2d, Color color) {
g2d.setPaint(color);
g2d.drawRect(object.x+1, object.y+1, object.w-3, object.h-3);
g2d.drawRect(object.x+2, object.y+2, object.w-5, object.h-5);
g2d.setPaint(color.darker().darker());
g2d.drawLine(object.x, object.y + object.h - 1, object.x + object.w - 1, object.y + object.h - 1);
g2d.drawLine(object.x + object.w - 1, object.y, object.x + object.w - 1, object.y + object.h - 1);
g2d.drawLine(object.x + 3, object.y + 3, object.x + object.w - 4, object.y + 3);
g2d.drawLine(object.x + 3, object.y + 3, object.x + 3, object.y + object.h - 4);
g2d.setPaint(color.brighter().brighter().brighter());
g2d.drawLine(object.x, object.y, object.x + object.w - 1, object.y);
g2d.drawLine(object.x, object.y, object.x, object.y + object.h - 1);
g2d.drawLine(object.x + 3, object.y + object.h - 4, object.x + object.w - 4, object.y + object.h - 4);
g2d.drawLine(object.x + object.w - 4, object.y + 3, object.x + object.w - 4, object.y + object.h - 4);
Image img = object.getIcon();
g2d.setColor(new Color(255, 255, 255, 120));
g2d.fillRect(object.x + 2, object.y + 2, img.getWidth(null), img.getHeight(null));
g2d.drawImage(object.getIcon(), object.x + 2, object.y + 2, null);
}
private void outlineFromListModel(Graphics2D g2, ListModel<TMXMap> listModel, ListSelectionModel selectionModel, Color outlineColor, Stroke outlineStroke, Font mapIdFont, int mapIdLabelHeight) {
for (int i =0; i<listModel.getSize(); i++) {
//No selection model ? We want to highlight the whole list.
if (selectionModel == null || selectionModel.isSelectedIndex(i)) {
TMXMap map = listModel.getElementAt(i);
int x = mapLocations.get(map.id).x;
int y = mapLocations.get(map.id).y;
g2.translate(x, y);
GlyphVector gv = mapIdFont.createGlyphVector(g2.getFontRenderContext(), map.id);
g2.setStroke(outlineStroke);
g2.setColor(outlineColor);
g2.drawRect(0, 0, map.tmxMap.getWidth() * TILE_SIZE, map.tmxMap.getHeight() * TILE_SIZE);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(thinLabelOutlineStroke);
g2.fill(gv.getOutline(8, 8 + mapIdLabelHeight));
g2.setColor(mapIdLabelOutlineColor);
g2.draw(gv.getOutline(8, 8 + mapIdLabelHeight));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
g2.translate(-x, -y);
}
}
}
public List<String> getSelectedMapsIDs() {
List<String> result = new ArrayList<String>();
for (int i =0; i<selectedListModel.getSize(); i++) {
if (selectedSelectionModel.isSelectedIndex(i)) {
TMXMap map = selectedListModel.getElementAt(i);
result.add(map.id);
}
}
return result;
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g.create();
@@ -140,6 +345,35 @@ public class WorldMapView extends JComponent implements Scrollable {
}
public interface MapClickListener {
public void mapClicked(MouseEvent e, TMXMap m);
public void mapChangeClicked(MouseEvent e, TMXMap m, TMXMap changeTarget);
public void backgroundClicked(MouseEvent e);
}
private List<MapClickListener> listeners = new CopyOnWriteArrayList<MapClickListener>();
public void addMapClickListener(MapClickListener l) {
listeners.add(l);
}
public void removeMapClickListener(MapClickListener l) {
listeners.remove(l);
}
private void mapClicked(MouseEvent e, TMXMap m) {
for (MapClickListener l : listeners) l.mapClicked(e, m);
}
private void mapChangeClicked(MouseEvent e, TMXMap m, TMXMap changeTarget) {
for (MapClickListener l : listeners) l.mapChangeClicked(e, m, changeTarget);
}
private void backgroundClicked(MouseEvent e) {
for (MapClickListener l : listeners) l.backgroundClicked(e);
}
// private boolean paintObjectGroup(Graphics2D g2d, TMXMap map, tiled.core.ObjectGroup layer) {
// boolean paintSelected = false;
// for (MapObjectGroup group : map.groups) {