Initial commit

This commit is contained in:
Zukero
2015-02-23 22:43:19 +01:00
commit 59d8ad1cdb
212 changed files with 29432 additions and 0 deletions

View File

@@ -0,0 +1,152 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Desktop;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Scanner;
import javax.swing.ImageIcon;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.event.HyperlinkListener;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.SaveEvent;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.jidesoft.swing.JideTabbedPane;
public class AboutEditor extends Editor {
private static final long serialVersionUID = 6230549148222457139L;
public static final String WELCOME_STRING =
"<html><body>" +
"<table><tr valign=\"top\">" +
"<td><img src=\""+ATContentStudio.class.getResource("/com/gpl/rpg/atcontentstudio/img/atcs_border_banner.png")+"\"/></td>" +
"<td><font size=+1>Welcome to "+ATContentStudio.APP_NAME+" "+ATContentStudio.APP_VERSION+"</font><br/>" +
"<br/>" +
"This is a content editor for Andor's Trail.<br/>" +
"<b>Right click on the left area or use the \"File\" menu to create a project.</b><br/>" +
"<br/>" +
"Play <a href=\"https://play.google.com/store/apps/details?id=com.gpl.rpg.AndorsTrail\">Andor's Trail</a> for free on your Android device.<br/>" +
"Visit <a href=\"http://andorstrail.com/\">the official forum</a> to give or receive help.<br/>" +
"Open the project's <a href=\"https://code.google.com/p/andors-trail/\">Google Code page</a> to check out the game's source code.<br/>" +
"<br/>" +
"For content creation help, make sure to use the following resources:<br/>" +
"<a href=\"http://andorstrail.com/viewtopic.php?f=6&t=4560\">The contribution guide on the forums</a><br/>" +
"<a href=\"http://andorstrail.com/wiki/doku.php?id=andors_trail_wiki:developer_section\">The developer section of the Andor's Trail wiki</a><br/>" +
"<a href=\"https://docs.google.com/document/d/1BwWD1tLgPcmA2bwudrVnOc6f2dkPLFCjWdn7tXlIp5g\">The design outline document on Google Drive/Docs</a><br/>" +
"<br/>" +
"<font size=+1>Credits:</font><br/>" +
"<br/>" +
"Author: <a href=\"http://andorstrail.com/memberlist.php?mode=viewprofile&u=2875\">Zukero</a><br/>" +
"Licence: <a href=\"http://www.gnu.org/licenses/gpl-3.0.html\">GPL v3</a><br/>" +
"Sources are included in this package.<br/>" +
"<br/>" +
"This project uses the following libraries:<br/>" +
"<a href=\"http://code.google.com/p/json-simple/\">JSON.simple</a> by Yidong Fang & Chris Nokleberg.<br/>" +
"License: <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">Apache License 2.0</a><br/>" +
"<br/>" +
"<a href=\"http://fifesoft.com/rsyntaxtextarea/\">RSyntaxTextArea</a> by Robert Futrell.<br/>" +
"License: <a href=\"http://fifesoft.com/rsyntaxtextarea/RSyntaxTextArea.License.txt\">Modified BSD License (a.k.a. 3-Clause BSD)</a><br/>" +
"<br/>" +
"<a href=\"http://www.jidesoft.com/products/oss.htm\">JIDE Common Layer</a> by JIDE Software.<br/>" +
"License: <a href=\"http://openjdk.java.net/legal/gplv2+ce.html\">GPL v2 with classpath exception</a><br/>" +
"<br/>" +
"A modified version of <a href=\"https://github.com/bjorn/tiled/tree/master/util/java/libtiled-java\">libtiled-java</a> by Adam Turk & Thorbjorn Lindeijer.<br/>" +
"License: <a href=\"https://github.com/bjorn/tiled/blob/master/LICENSE.BSD\">Simplified BSD License (a.k.a 2-Clause BSD)</a><br/>" +
"Sources of the modified version are included in this package.<br/>" +
"<br/>" +
"<a href=\"http://prefuse.org/\">Prefuse</a> by the Berkeley Institue of Design.<br/>" +
"License: <a href=\"http://prefuse.org/license-prefuse.txt\">Modified BSD License (a.k.a 3-Clause BSD)</a><br/>" +
"<br/>" +
"See the tabs below to find the full license text for each of these.<br/>" +
"<br/>" +
"The Windows installer was created with:<br/>" +
"<a href=\"http://nsis.sourceforge.net/Main_Page\">NSIS (Nullsoft Scriptable Install System) v2.46</a>" +
"</td></tr></table>" +
"</body></html>";
public static final AboutEditor instance = new AboutEditor();
private AboutEditor() {
this.name="About "+ATContentStudio.APP_NAME;
this.icon = new ImageIcon(DefaultIcons.getMainIconIcon());
this.target = new GameDataElement(){
private static final long serialVersionUID = -227480102288529682L;
@Override
public GameDataSet getDataSet() {return null;}
@Override
public String getDesc() {return null;}
@Override
public void parse() {}
@Override
public void link() {}
@Override
public GameDataElement clone() {return null;}
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {}
@Override
public String getProjectFilename() {return null;}
@Override
public void save() {}
@Override
public List<SaveEvent> attemptSave() {return null;}
};
setLayout(new BorderLayout());
JideTabbedPane editorTabsHolder = new JideTabbedPane(JideTabbedPane.BOTTOM);
editorTabsHolder.setTabShape(JideTabbedPane.SHAPE_FLAT);
editorTabsHolder.setUseDefaultShowCloseButtonOnTab(false);
editorTabsHolder.setShowCloseButtonOnTab(false);
add(editorTabsHolder, BorderLayout.CENTER);
editorTabsHolder.add("Welcome", getInfoPane(WELCOME_STRING, "text/html"));
editorTabsHolder.add("JSON.simple License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.JSON.simple.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("RSyntaxTextArea License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/RSyntaxTextArea.License.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("JIDE Common Layer License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.JIDE.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("libtiled-java License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.libtiled.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("prefuse License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/license-prefuse.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
editorTabsHolder.add("ATCS License", getInfoPane(new Scanner(ATContentStudio.class.getResourceAsStream("/LICENSE.GPLv3.txt"), "UTF-8").useDelimiter("\\A").next(), "text/text"));
}
private JPanel getInfoPane(String content, String mime) {
JEditorPane welcome = new JEditorPane();
welcome.setContentType(mime);
welcome.setText(content);
welcome.setEditable(false);
welcome.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent arg0) {
arg0.getEventType();
if (arg0.getEventType() == EventType.ACTIVATED) {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
try {
Desktop.getDesktop().browse(arg0.getURL().toURI());
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
}
});
JPanel pane = new JPanel();
pane.setLayout(new BorderLayout());
pane.add(new JScrollPane(welcome), BorderLayout.CENTER);
return pane;
}
@Override
public void targetUpdated() {}
}

View File

@@ -0,0 +1,17 @@
package com.gpl.rpg.atcontentstudio.ui;
import javax.swing.JCheckBox;
public class BooleanBasedCheckBox extends JCheckBox {
private static final long serialVersionUID = 3941646360487399554L;
public Boolean getBooleanValue() {
return isSelected() ? Boolean.TRUE : null;
}
public void setBooleanValue(Boolean val) {
setSelected(val != null && val);
}
}

View File

@@ -0,0 +1,160 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
public class CollapsiblePanel extends JPanel {
private static final long serialVersionUID = 319384990345722150L;
String title;
TitledBorder border;
public CollapsiblePanel(String title) {
super();
this.title = title;
border = BorderFactory.createTitledBorder(title);
setBorder(border);
BorderLayout borderLayout = new BorderLayout();
setLayout(borderLayout);
addMouseListener(mouseListener);
}
MouseListener mouseListener = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
toggleVisibility();
}
};
ComponentListener contentComponentListener = new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent e) {
updateBorderTitle();
}
@Override
public void componentHidden(ComponentEvent e) {
updateBorderTitle();
}
};
public String getTitle() {
return title;
}
public void setTitle(String title) {
String oldTitle = this.title;
this.title = title;
firePropertyChange("title", oldTitle, this.title);
updateBorderTitle();
}
@Override
public Component add(Component comp) {
comp.addComponentListener(contentComponentListener);
Component r = super.add(comp);
updateBorderTitle();
return r;
}
@Override
public Component add(String name, Component comp) {
comp.addComponentListener(contentComponentListener);
Component r = super.add(name, comp);
updateBorderTitle();
return r;
}
@Override
public Component add(Component comp, int index) {
comp.addComponentListener(contentComponentListener);
Component r = super.add(comp, index);
updateBorderTitle();
return r;
}
@Override
public void add(Component comp, Object constraints) {
comp.addComponentListener(contentComponentListener);
super.add(comp, constraints);
updateBorderTitle();
}
@Override
public void add(Component comp, Object constraints, int index) {
comp.addComponentListener(contentComponentListener);
super.add(comp, constraints, index);
updateBorderTitle();
}
@Override
public void remove(int index) {
Component comp = getComponent(index);
comp.removeComponentListener(contentComponentListener);
super.remove(index);
}
@Override
public void remove(Component comp) {
comp.removeComponentListener(contentComponentListener);
super.remove(comp);
}
@Override
public void removeAll() {
for (Component c : getComponents()) {
c.removeComponentListener(contentComponentListener);
}
super.removeAll();
}
protected void toggleVisibility() {
toggleVisibility(hasInvisibleComponent());
}
protected void toggleVisibility(boolean visible) {
for (Component c : getComponents()) {
c.setVisible(visible);
}
updateBorderTitle();
}
protected void updateBorderTitle() {
String arrow = "";
if (getComponentCount() > 0) {
arrow = (hasInvisibleComponent()?"[+] ":"[-] ");
}
border.setTitle(arrow+title);
repaint();
}
protected final boolean hasInvisibleComponent() {
for (Component c : getComponents()) {
if (!c.isVisible()) {
return true;
}
}
return false;
}
public void collapse() {
toggleVisibility(false);
}
public void expand() {
toggleVisibility(true);
}
public void setExpanded(boolean expand) {
toggleVisibility(expand);
}
}

View File

@@ -0,0 +1,254 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.Image;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import com.gpl.rpg.atcontentstudio.Notification;
public class DefaultIcons {
private static Map<String, Image> imageCache = new HashMap<String, Image>();
private static Map<String, Image> iconCache = new HashMap<String, Image>();
private static String MAIN_ICON_RES = "/com/gpl/rpg/atcontentstudio/img/andorstrainer.png";
public static Image getMainIconImage() { return getImage(MAIN_ICON_RES); }
public static Image getMainIconIcon() { return getIcon(MAIN_ICON_RES); }
private static String FOLDER_STD_CLOSED_RES = "/com/gpl/rpg/atcontentstudio/img/folder_std_closed.png";
public static Image getStdClosedImage() { return getImage(FOLDER_STD_CLOSED_RES); }
public static Image getStdClosedIcon() { return getIcon(FOLDER_STD_CLOSED_RES); }
private static String FOLDER_STD_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_std_open.png";
public static Image getStdOpenImage() { return getImage(FOLDER_STD_OPEN_RES); }
public static Image getStdOpenIcon() { return getIcon(FOLDER_STD_OPEN_RES); }
private static String FOLDER_JSON_CLOSED_RES = "/com/gpl/rpg/atcontentstudio/img/folder_json_closed.png";
public static Image getJsonClosedImage() { return getImage(FOLDER_JSON_CLOSED_RES); }
public static Image getJsonClosedIcon() { return getIcon(FOLDER_JSON_CLOSED_RES); }
private static String FOLDER_JSON_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_json_open.png";
public static Image getJsonOpenImage() { return getImage(FOLDER_JSON_OPEN_RES); }
public static Image getJsonOpenIcon() { return getIcon(FOLDER_JSON_OPEN_RES); }
private static String FOLDER_SAV_CLOSED_RES = "/com/gpl/rpg/atcontentstudio/img/folder_sav_closed.png";
public static Image getSavClosedImage() { return getImage(FOLDER_SAV_CLOSED_RES); }
public static Image getSavClosedIcon() { return getIcon(FOLDER_SAV_CLOSED_RES); }
private static String FOLDER_SAV_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_sav_open.png";
public static Image getSavOpenImage() { return getImage(FOLDER_SAV_OPEN_RES); }
public static Image getSavOpenIcon() { return getIcon(FOLDER_SAV_OPEN_RES); }
private static String FOLDER_SPRITE_CLOSED_RES = "/com/gpl/rpg/atcontentstudio/img/folder_sprite_closed.png";
public static Image getSpriteClosedImage() { return getImage(FOLDER_SPRITE_CLOSED_RES); }
public static Image getSpriteClosedIcon() { return getIcon(FOLDER_SPRITE_CLOSED_RES); }
private static String FOLDER_SPRITE_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_sprite_open.png";
public static Image getSpriteOpenImage() { return getImage(FOLDER_SPRITE_OPEN_RES); }
public static Image getSpriteOpenIcon() { return getIcon(FOLDER_SPRITE_OPEN_RES); }
private static String FOLDER_TMX_CLOSED_RES = "/com/gpl/rpg/atcontentstudio/img/folder_tmx_closed.png";
public static Image getTmxClosedImage() { return getImage(FOLDER_TMX_CLOSED_RES); }
public static Image getTmxClosedIcon() { return getIcon(FOLDER_TMX_CLOSED_RES); }
private static String FOLDER_TMX_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_tmx_open.png";
public static Image getTmxOpenImage() { return getImage(FOLDER_TMX_OPEN_RES); }
public static Image getTmxOpenIcon() { return getIcon(FOLDER_TMX_OPEN_RES); }
private static String FOLDER_MAP_CLOSED_RES = "/com/gpl/rpg/atcontentstudio/img/folder_map_closed.png";
public static Image getMapClosedImage() { return getImage(FOLDER_MAP_CLOSED_RES); }
public static Image getMapClosedIcon() { return getIcon(FOLDER_MAP_CLOSED_RES); }
private static String FOLDER_MAP_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_map_open.png";
public static Image getMapOpenImage() { return getImage(FOLDER_MAP_OPEN_RES); }
public static Image getMapOpenIcon() { return getIcon(FOLDER_MAP_OPEN_RES); }
private static String FOLDER_AT_CLOSED_RES = "/com/gpl/rpg/atcontentstudio/img/folder_at_closed.png";
public static Image getATClosedImage() { return getImage(FOLDER_AT_CLOSED_RES); }
public static Image getATClosedIcon() { return getIcon(FOLDER_AT_CLOSED_RES); }
private static String FOLDER_AT_OPEN_RES = "/com/gpl/rpg/atcontentstudio/img/folder_at_open.png";
public static Image getATOpenImage() { return getImage(FOLDER_AT_OPEN_RES); }
public static Image getATOpenIcon() { return getIcon(FOLDER_AT_OPEN_RES); }
private static String TILED_ICON_RES = "/com/gpl/rpg/atcontentstudio/img/tiled-icon.png";
public static Image getTiledIconImage() { return getImage(TILED_ICON_RES); }
public static Image getTiledIconIcon() { return getIcon(TILED_ICON_RES); }
private static String UI_MAP_RES = "/com/gpl/rpg/atcontentstudio/img/ui_icon_map.png";
public static Image getUIMapImage() { return getImage(UI_MAP_RES); }
public static Image getUIMapIcon() { return getIcon(UI_MAP_RES); }
private static String HERO_RES = "/com/gpl/rpg/atcontentstudio/img/char_hero.png";
public static Image getHeroImage() { return getImage(HERO_RES); }
public static Image getHeroIcon() { return getIcon(HERO_RES); }
private static String TILE_LAYER_RES = "/com/gpl/rpg/atcontentstudio/img/tile_layer.png";
public static Image getTileLayerImage() { return getImage(TILE_LAYER_RES); }
public static Image getTileLayerIcon() { return getIcon(TILE_LAYER_RES); }
private static String OBJECT_LAYER_RES = "/com/gpl/rpg/atcontentstudio/img/object_layer.png";
public static Image getObjectLayerImage() { return getImage(OBJECT_LAYER_RES); }
public static Image getObjectLayerIcon() { return getIcon(OBJECT_LAYER_RES); }
private static String ACTOR_CONDITION_RES = "/com/gpl/rpg/atcontentstudio/img/actor_condition.png";
public static Image getActorConditionImage() { return getImage(ACTOR_CONDITION_RES); }
public static Image getActorConditionIcon() { return getIcon(ACTOR_CONDITION_RES); }
private static String ITEM_RES = "/com/gpl/rpg/atcontentstudio/img/item.png";
public static Image getItemImage() { return getImage(ITEM_RES); }
public static Image getItemIcon() { return getIcon(ITEM_RES); }
private static String NPC_RES = "/com/gpl/rpg/atcontentstudio/img/npc.png";
public static Image getNPCImage() { return getImage(NPC_RES); }
public static Image getNPCIcon() { return getIcon(NPC_RES); }
private static String NPC_CLOSE_RES = "/com/gpl/rpg/atcontentstudio/img/npc_close.png";
public static Image getNPCCloseImage() { return getImage(NPC_CLOSE_RES); }
public static Image getNPCCloseIcon() { return getIcon(NPC_CLOSE_RES); }
private static String DIALOGUE_RES = "/com/gpl/rpg/atcontentstudio/img/dialogue.png";
public static Image getDialogueImage() { return getImage(DIALOGUE_RES); }
public static Image getDialogueIcon() { return getIcon(DIALOGUE_RES); }
private static String QUEST_RES = "/com/gpl/rpg/atcontentstudio/img/ui_icon_quest.png";
public static Image getQuestImage() { return getImage(QUEST_RES); }
public static Image getQuestIcon() { return getIcon(QUEST_RES); }
private static String DROPLIST_RES = "/com/gpl/rpg/atcontentstudio/img/ui_icon_equipment.png";
public static Image getDroplistImage() { return getImage(DROPLIST_RES); }
public static Image getDroplistIcon() { return getIcon(DROPLIST_RES); }
private static String COMBAT_RES = "/com/gpl/rpg/atcontentstudio/img/ui_icon_combat.png";
public static Image getCombatImage() { return getImage(COMBAT_RES); }
public static Image getCombatIcon() { return getIcon(COMBAT_RES); }
private static String GOLD_RES = "/com/gpl/rpg/atcontentstudio/img/ui_icon_coins.png";
public static Image getGoldImage() { return getImage(GOLD_RES); }
public static Image getGoldIcon() { return getIcon(GOLD_RES); }
private static String ITEM_CATEGORY_RES = "/com/gpl/rpg/atcontentstudio/img/equip_weapon.png";
public static Image getItemCategoryImage() { return getImage(ITEM_CATEGORY_RES); }
public static Image getItemCategoryIcon() { return getIcon(ITEM_CATEGORY_RES); }
private static String NULLIFY_RES = "/com/gpl/rpg/atcontentstudio/img/nullify.png";
public static Image getNullifyImage() { return getImage(NULLIFY_RES); }
public static Image getNullifyIcon() { return getIcon(NULLIFY_RES); }
private static String CREATE_RES = "/com/gpl/rpg/atcontentstudio/img/file_create.png";
public static Image getCreateImage() { return getImage(CREATE_RES); }
public static Image getCreateIcon() { return getIcon(CREATE_RES); }
private static String ARROW_UP_RES = "/com/gpl/rpg/atcontentstudio/img/arrow_up.png";
public static Image getArrowUpImage() { return getImage(ARROW_UP_RES); }
public static Image getArrowUpIcon() { return getIcon(ARROW_UP_RES); }
private static String ARROW_DOWN_RES = "/com/gpl/rpg/atcontentstudio/img/arrow_down.png";
public static Image getArrowDownImage() { return getImage(ARROW_DOWN_RES); }
public static Image getArrowDownIcon() { return getIcon(ARROW_DOWN_RES); }
private static String ARROW_LEFT_RES = "/com/gpl/rpg/atcontentstudio/img/arrow_left.png";
public static Image getArrowLeftImage() { return getImage(ARROW_LEFT_RES); }
public static Image getArrowLeftIcon() { return getIcon(ARROW_LEFT_RES); }
private static String ARROW_RIGHT_RES = "/com/gpl/rpg/atcontentstudio/img/arrow_right.png";
public static Image getArrowRightImage() { return getImage(ARROW_RIGHT_RES); }
public static Image getArrowRightIcon() { return getIcon(ARROW_RIGHT_RES); }
private static String CONTAINER_RES = "/com/gpl/rpg/atcontentstudio/img/container.png";
public static Image getContainerImage() { return getImage(CONTAINER_RES); }
public static Image getContainerIcon() { return getIcon(CONTAINER_RES); }
private static String KEY_RES = "/com/gpl/rpg/atcontentstudio/img/key.png";
public static Image getKeyImage() { return getImage(KEY_RES); }
public static Image getKeyIcon() { return getIcon(KEY_RES); }
private static String MAPCHANGE_RES = "/com/gpl/rpg/atcontentstudio/img/mapchange.png";
public static Image getMapchangeImage() { return getImage(MAPCHANGE_RES); }
public static Image getMapchangeIcon() { return getIcon(MAPCHANGE_RES); }
private static String REPLACE_RES = "/com/gpl/rpg/atcontentstudio/img/replace.png";
public static Image getReplaceImage() { return getImage(REPLACE_RES); }
public static Image getReplaceIcon() { return getIcon(REPLACE_RES); }
private static String REST_RES = "/com/gpl/rpg/atcontentstudio/img/rest.png";
public static Image getRestImage() { return getImage(REST_RES); }
public static Image getRestIcon() { return getIcon(REST_RES); }
private static String SCRIPT_RES = "/com/gpl/rpg/atcontentstudio/img/script.png";
public static Image getScriptImage() { return getImage(SCRIPT_RES); }
public static Image getScriptIcon() { return getIcon(SCRIPT_RES); }
private static String SIGN_RES = "/com/gpl/rpg/atcontentstudio/img/sign.png";
public static Image getSignImage() { return getImage(SIGN_RES); }
public static Image getSignIcon() { return getIcon(SIGN_RES); }
private static String CREATE_CONTAINER_RES = "/com/gpl/rpg/atcontentstudio/img/create_container.png";
public static Image getCreateContainerImage() { return getImage(CREATE_CONTAINER_RES); }
public static Image getCreateContainerIcon() { return getIcon(CREATE_CONTAINER_RES); }
private static String CREATE_KEY_RES = "/com/gpl/rpg/atcontentstudio/img/create_key.png";
public static Image getCreateKeyImage() { return getImage(CREATE_KEY_RES); }
public static Image getCreateKeyIcon() { return getIcon(CREATE_KEY_RES); }
private static String CREATE_REPLACE_RES = "/com/gpl/rpg/atcontentstudio/img/create_replace.png";
public static Image getCreateReplaceImage() { return getImage(CREATE_REPLACE_RES); }
public static Image getCreateReplaceIcon() { return getIcon(CREATE_REPLACE_RES); }
private static String CREATE_REST_RES = "/com/gpl/rpg/atcontentstudio/img/create_rest.png";
public static Image getCreateRestImage() { return getImage(CREATE_REST_RES); }
public static Image getCreateRestIcon() { return getIcon(CREATE_REST_RES); }
private static String CREATE_SCRIPT_RES = "/com/gpl/rpg/atcontentstudio/img/create_script.png";
public static Image getCreateScriptImage() { return getImage(CREATE_SCRIPT_RES); }
public static Image getCreateScriptIcon() { return getIcon(CREATE_SCRIPT_RES); }
private static String CREATE_SIGN_RES = "/com/gpl/rpg/atcontentstudio/img/create_sign.png";
public static Image getCreateSignImage() { return getImage(CREATE_SIGN_RES); }
public static Image getCreateSignIcon() { return getIcon(CREATE_SIGN_RES); }
private static String CREATE_SPAWNAREA_RES = "/com/gpl/rpg/atcontentstudio/img/create_spawnarea.png";
public static Image getCreateSpawnareaImage() { return getImage(CREATE_SPAWNAREA_RES); }
public static Image getCreateSpawnareaIcon() { return getIcon(CREATE_SPAWNAREA_RES); }
private static String CREATE_MAPCHANGE_RES = "/com/gpl/rpg/atcontentstudio/img/create_tiled.png";
public static Image getCreateMapchangeImage() { return getImage(CREATE_MAPCHANGE_RES); }
public static Image getCreateMapchangeIcon() { return getIcon(CREATE_MAPCHANGE_RES); }
private static String CREATE_OBJECT_GROUP_RES = "/com/gpl/rpg/atcontentstudio/img/create_object_group.png";
public static Image getCreateObjectGroupImage() { return getImage(CREATE_OBJECT_GROUP_RES); }
public static Image getCreateObjectGroupIcon() { return getIcon(CREATE_OBJECT_GROUP_RES); }
private static String CREATE_TILE_LAYER_RES = "/com/gpl/rpg/atcontentstudio/img/create_tile_layer.png";
public static Image getCreateTileLayerImage() { return getImage(CREATE_TILE_LAYER_RES); }
public static Image getCreateTileLayerIcon() { return getIcon(CREATE_TILE_LAYER_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); }
private static Image getImage(String res) {
if (imageCache.get(res) == null) {
try {
Image img = ImageIO.read(DefaultIcons.class.getResourceAsStream(res));
imageCache.put(res, img);
} catch (IOException e) {
Notification.addError("Failed to load image "+res);
e.printStackTrace();
}
}
return imageCache.get(res);
}
private static Image getIcon(String res) {
if (iconCache.get(res) == null) {
Image icon = getImage(res).getScaledInstance(16, 16, Image.SCALE_SMOOTH);
iconCache.put(res, icon);
}
return iconCache.get(res);
}
}

View File

@@ -0,0 +1,735 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Component;
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.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JSpinner.NumberEditor;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.text.DefaultFormatter;
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.Project;
import com.gpl.rpg.atcontentstudio.model.ProjectElementListener;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
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.maps.TMXMap;
import com.jidesoft.swing.ComboBoxSearchable;
import com.jidesoft.swing.JideBoxLayout;
public abstract class Editor extends JPanel implements ProjectElementListener {
private static final long serialVersionUID = 241750514033596878L;
private static final FieldUpdateListener nullListener = new FieldUpdateListener() {@Override public void valueChanged(JComponent source, Object value) {}};
public static final String SAVE = "Save";
public static final String DELETE = "Delete";
public static final String REVERT = "Revert to original";
public static final String ALTER = "Alter";
public static final String GO_TO_ALTERED = "Go to altered";
public static final String READ_ONLY_MESSAGE =
"<html><i>" +
"This element is not modifiable.<br/>" +
"Click on the \"Alter\" button to create a writable copy." +
"</i></html>";
public static final String ALTERED_EXISTS_MESSAGE =
"<html><i>" +
"This element is not modifiable.<br/>" +
"A writable copy exists in this project. Click on \"Go to altered\" to open it." +
"</i></html>";
public static final String ALTERED_MESSAGE =
"<html><i>" +
"This element is a writable copy of an element of the referenced game source.<br/>" +
"Take care not to break existing content when modifying it." +
"</i></html>";
public static final String CREATED_MESSAGE =
"<html><i>" +
"This element is a creation of yours.<br/>" +
"Do as you please." +
"</i></html>";
public String name = "Editor";
public Icon icon = null;
public GameDataElement target = null;
public JLabel message = null;
public static JTextField addLabelField(JPanel pane, String label, String value) {
return addTextField(pane, label, value, false, nullListener);
}
public static JTextField addTextField(JPanel pane, String label, String initialValue, boolean editable, final FieldUpdateListener listener) {
JPanel tfPane = new JPanel();
tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6));
JLabel tfLabel = new JLabel(label);
tfPane.add(tfLabel, JideBoxLayout.FIX);
final JTextField tfField = new JTextField(initialValue);
tfField.setEditable(editable);
tfPane.add(tfField, JideBoxLayout.VARY);
JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
tfPane.add(nullify, JideBoxLayout.FIX);
nullify.setEnabled(editable);
pane.add(tfPane, JideBoxLayout.FIX);
nullify.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
tfField.setText("");
listener.valueChanged(tfField, null);
}
});
tfField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
listener.valueChanged(tfField, tfField.getText());
}
@Override
public void insertUpdate(DocumentEvent e) {
listener.valueChanged(tfField, tfField.getText());
}
@Override
public void changedUpdate(DocumentEvent e) {
listener.valueChanged(tfField, tfField.getText());
}
});
tfField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(tfField, tfField.getText());
}
});
return tfField;
}
// public static JSpinner addIntegerField(JPanel pane, String label, Integer initialValue, boolean allowNegatives, boolean editable) {
// return addIntegerField(pane, label, initialValue, allowNegatives, editable, nullListener);
// }
public static JSpinner addIntegerField(JPanel pane, String label, Integer initialValue, boolean allowNegatives, boolean editable, final FieldUpdateListener listener) {
JPanel tfPane = new JPanel();
tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6));
JLabel tfLabel = new JLabel(label);
tfPane.add(tfLabel, JideBoxLayout.FIX);
final JSpinner spinner = new JSpinner(new SpinnerNumberModel(initialValue != null ? initialValue.intValue() : 0, allowNegatives ? Integer.MIN_VALUE : 0, Integer.MAX_VALUE, 1));
((JSpinner.DefaultEditor)spinner.getEditor()).getTextField().setHorizontalAlignment(JTextField.LEFT);
spinner.setEnabled(editable);
((DefaultFormatter)((NumberEditor)spinner.getEditor()).getTextField().getFormatter()).setCommitsOnValidEdit(true);
tfPane.add(spinner, JideBoxLayout.VARY);
JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
tfPane.add(nullify, JideBoxLayout.FIX);
nullify.setEnabled(editable);
pane.add(tfPane, JideBoxLayout.FIX);
spinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
listener.valueChanged(spinner, spinner.getValue());
}
});
nullify.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
spinner.setValue(0);
listener.valueChanged(spinner, null);
}
});
return spinner;
}
// public static JSpinner addDoubleField(JPanel pane, String label, Double initialValue, boolean editable) {
// return addDoubleField(pane, label, initialValue, editable, nullListener);
// }
public static JSpinner addDoubleField(JPanel pane, String label, Double initialValue, boolean editable, final FieldUpdateListener listener) {
JPanel tfPane = new JPanel();
tfPane.setLayout(new JideBoxLayout(tfPane, JideBoxLayout.LINE_AXIS, 6));
JLabel tfLabel = new JLabel(label);
tfPane.add(tfLabel, JideBoxLayout.FIX);
final JSpinner spinner = new JSpinner(new SpinnerNumberModel(initialValue != null ? initialValue.doubleValue() : 0.0d, 0.0d, new Float(Float.MAX_VALUE).doubleValue(), 1.0d));
((JSpinner.DefaultEditor)spinner.getEditor()).getTextField().setHorizontalAlignment(JTextField.LEFT);
spinner.setEnabled(editable);
((DefaultFormatter)((NumberEditor)spinner.getEditor()).getTextField().getFormatter()).setCommitsOnValidEdit(true);
tfPane.add(spinner, JideBoxLayout.VARY);
JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
tfPane.add(nullify, JideBoxLayout.FIX);
nullify.setEnabled(editable);
pane.add(tfPane, JideBoxLayout.FIX);
pane.add(tfPane, JideBoxLayout.FIX);
spinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
listener.valueChanged(spinner, spinner.getValue());
}
});
nullify.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
spinner.setValue(0.0d);
listener.valueChanged(spinner, null);
}
});
return spinner;
}
public static IntegerBasedCheckBox addIntegerBasedCheckBox(JPanel pane, String label, Integer initialValue, boolean editable) {
return addIntegerBasedCheckBox(pane, label, initialValue, editable, nullListener);
}
public static IntegerBasedCheckBox addIntegerBasedCheckBox(JPanel pane, String label, Integer initialValue, boolean editable, final FieldUpdateListener listener) {
JPanel ibcbPane = new JPanel();
ibcbPane.setLayout(new BorderLayout());
final IntegerBasedCheckBox ibcb = new IntegerBasedCheckBox();
ibcb.setText(label);
ibcb.setIntegerValue(initialValue);
ibcb.setEnabled(editable);
ibcbPane.add(ibcb, BorderLayout.WEST);
ibcbPane.add(new JPanel(), BorderLayout.CENTER);
pane.add(ibcbPane, JideBoxLayout.FIX);
ibcb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(ibcb, ibcb.getIntegerValue());
}
});
return ibcb;
}
public static BooleanBasedCheckBox addBooleanBasedCheckBox(JPanel pane, String label, Boolean initialValue, boolean editable, final FieldUpdateListener listener) {
JPanel bbcbPane = new JPanel();
bbcbPane.setLayout(new BorderLayout());
final BooleanBasedCheckBox bbcb = new BooleanBasedCheckBox();
bbcb.setText(label);
bbcb.setBooleanValue(initialValue);
bbcb.setEnabled(editable);
bbcbPane.add(bbcb, BorderLayout.WEST);
bbcbPane.add(new JPanel(), BorderLayout.CENTER);
pane.add(bbcbPane, JideBoxLayout.FIX);
bbcb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
listener.valueChanged(bbcb, bbcb.isSelected());
}
});
return bbcb;
}
public static JComboBox addEnumValueBox(JPanel pane, String label, @SuppressWarnings("rawtypes") Enum[] values, @SuppressWarnings("rawtypes") Enum initialValue, boolean writable) {
return addEnumValueBox(pane, label, values, initialValue, writable, new FieldUpdateListener() {@Override public void valueChanged(JComponent source, Object value) {}});
}
public static JComboBox addEnumValueBox(JPanel pane, String label, @SuppressWarnings("rawtypes") Enum[] values, @SuppressWarnings("rawtypes") Enum initialValue, boolean writable, final FieldUpdateListener listener) {
JPanel comboPane = new JPanel();
comboPane.setLayout(new JideBoxLayout(comboPane, JideBoxLayout.LINE_AXIS, 6));
JLabel comboLabel = new JLabel(label);
comboPane.add(comboLabel, JideBoxLayout.FIX);
final JComboBox enumValuesCombo = new JComboBox(values);
enumValuesCombo.setEnabled(writable);
enumValuesCombo.setSelectedItem(initialValue);
comboPane.add(enumValuesCombo, JideBoxLayout.VARY);
enumValuesCombo.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
listener.valueChanged(enumValuesCombo, e.getItem());
}
}
});
JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
comboPane.add(nullify, JideBoxLayout.FIX);
nullify.setEnabled(writable);
nullify.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
enumValuesCombo.setSelectedItem(null);
listener.valueChanged(enumValuesCombo, null);
}
});
pane.add(comboPane, JideBoxLayout.FIX);
return enumValuesCombo;
}
public MyComboBox addNPCBox(JPanel pane, Project proj, String label, NPC npc, boolean writable, FieldUpdateListener listener) {
final GDEComboModel<NPC> comboModel = new GDEComboModel<NPC>(proj, npc){
private static final long serialVersionUID = 2638082961277241764L;
@Override
public Object getTypedElementAt(int index) {
return project.getNPC(index);
}
@Override
public int getSize() {
return project.getNPCCount()+1;
}
};
return addGDEBox(pane, label, npc, NPC.class, comboModel, writable, listener);
}
public MyComboBox addActorConditionBox(JPanel pane, Project proj, String label, ActorCondition acond, boolean writable, FieldUpdateListener listener) {
final GDEComboModel<ActorCondition> comboModel = new GDEComboModel<ActorCondition>(proj, acond){
private static final long serialVersionUID = 2638082961277241764L;
@Override
public Object getTypedElementAt(int index) {
return project.getActorCondition(index);
}
@Override
public int getSize() {
return project.getActorConditionCount()+1;
}
};
return addGDEBox(pane, label, acond, ActorCondition.class, comboModel, writable, listener);
}
public MyComboBox addItemBox(JPanel pane, Project proj, String label, Item item, boolean writable, FieldUpdateListener listener) {
final GDEComboModel<Item> comboModel = new GDEComboModel<Item>(proj, item){
private static final long serialVersionUID = 2638082961277241764L;
@Override
public Object getTypedElementAt(int index) {
return project.getItem(index);
}
@Override
public int getSize() {
return project.getItemCount()+1;
}
};
return addGDEBox(pane, label, item, Item.class, comboModel, writable, listener);
}
public MyComboBox addItemCategoryBox(JPanel pane, Project proj, String label, ItemCategory ic, boolean writable, FieldUpdateListener listener) {
final GDEComboModel<ItemCategory> comboModel = new GDEComboModel<ItemCategory>(proj, ic){
private static final long serialVersionUID = 2638082961277241764L;
@Override
public Object getTypedElementAt(int index) {
return project.getItemCategory(index);
}
@Override
public int getSize() {
return project.getItemCategoryCount()+1;
}
};
return addGDEBox(pane, label, ic, ItemCategory.class, comboModel, writable, listener);
}
public MyComboBox addQuestBox(JPanel pane, Project proj, String label, Quest quest, boolean writable, FieldUpdateListener listener) {
final GDEComboModel<Quest> comboModel = new GDEComboModel<Quest>(proj, quest){
private static final long serialVersionUID = 2638082961277241764L;
@Override
public Object getTypedElementAt(int index) {
return project.getQuest(index);
}
@Override
public int getSize() {
return project.getQuestCount()+1;
}
};
return addGDEBox(pane, label, quest, Quest.class, comboModel, writable, listener);
}
public MyComboBox addDroplistBox(JPanel pane, Project proj, String label, Droplist droplist, boolean writable, FieldUpdateListener listener) {
final GDEComboModel<Droplist> comboModel = new GDEComboModel<Droplist>(proj, droplist){
private static final long serialVersionUID = 2638082961277241764L;
@Override
public Object getTypedElementAt(int index) {
return project.getDroplist(index);
}
@Override
public int getSize() {
return project.getDroplistCount()+1;
}
};
return addGDEBox(pane, label, droplist, Droplist.class, comboModel, writable, listener);
}
public MyComboBox addDialogueBox(JPanel pane, Project proj, String label, Dialogue dialogue, boolean writable, final FieldUpdateListener listener) {
final GDEComboModel<Dialogue> comboModel = new GDEComboModel<Dialogue>(proj, dialogue){
private static final long serialVersionUID = 2638082961277241764L;
@Override
public Object getTypedElementAt(int index) {
return project.getDialogue(index);
}
@Override
public int getSize() {
return project.getDialogueCount()+1;
}
};
return addGDEBox(pane, label, dialogue, Dialogue.class, comboModel, writable, listener);
}
public MyComboBox addMapBox(JPanel pane, Project proj, String label, TMXMap map, boolean writable, final FieldUpdateListener listener) {
final GDEComboModel<TMXMap> comboModel = new GDEComboModel<TMXMap>(proj, map){
private static final long serialVersionUID = 2638082961277241764L;
@Override
public Object getTypedElementAt(int index) {
return project.getMap(index);
}
@Override
public int getSize() {
return project.getMapCount()+1;
}
};
return addGDEBox(pane, label, map, TMXMap.class, comboModel, writable, listener);
}
public MyComboBox addGDEBox(JPanel pane, String label, GameDataElement gde, final Class<? extends GameDataElement> dataClass, final GDEComboModel<? extends GameDataElement> comboModel, final boolean writable, final FieldUpdateListener listener) {
JPanel gdePane = new JPanel();
gdePane.setLayout(new JideBoxLayout(gdePane, JideBoxLayout.LINE_AXIS, 6));
JLabel gdeLabel = new JLabel(label);
gdePane.add(gdeLabel, JideBoxLayout.FIX);
final MyComboBox gdeBox = new MyComboBox(dataClass, comboModel);
gdeBox.setRenderer(new GDERenderer(false, writable));
new ComboBoxSearchable(gdeBox){
@Override
protected String convertElementToString(Object object) {
if (object == null) return "none";
else return ((GameDataElement)object).getDesc();
}
};
gdeBox.setEnabled(writable);
gdePane.add(gdeBox, JideBoxLayout.VARY);
final JButton goToGde = new JButton((Icon) ((gde != null) ? new ImageIcon(gde.getIcon()) : (writable ? new ImageIcon(DefaultIcons.getCreateIcon()) : null)));
goToGde.setEnabled(gde != null || writable);
goToGde.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
GameDataElement selected = ((GameDataElement)comboModel.getSelectedItem());
if (selected != null) {
ATContentStudio.frame.openEditor(((GameDataElement)comboModel.getSelectedItem()));
ATContentStudio.frame.selectInTree((GameDataElement)comboModel.getSelectedItem());
} else if (writable) {
JSONCreationWizard wizard = new JSONCreationWizard(((GameDataElement)target).getProject(), dataClass);
wizard.addCreationListener(new JSONCreationWizard.CreationCompletedListener() {
@Override
public void elementCreated(JSONElement created) {
gdeBox.setSelectedItem(created);
}
});
wizard.setVisible(true);
}
}
});
gdePane.add(goToGde, JideBoxLayout.FIX);
gdeBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (gdeBox.getModel().getSelectedItem() == null) {
goToGde.setIcon((writable ? new ImageIcon(DefaultIcons.getCreateIcon()) : null));
goToGde.setEnabled(writable);
} else {
goToGde.setIcon(new ImageIcon(((GameDataElement)comboModel.getSelectedItem()).getIcon()));
goToGde.setEnabled(true);
}
listener.valueChanged(gdeBox, gdeBox.getModel().getSelectedItem());
}
});
JButton nullify = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
gdePane.add(nullify, JideBoxLayout.FIX);
nullify.setEnabled(writable);
nullify.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
gdeBox.setSelectedItem(null);
}
});
pane.add(gdePane, JideBoxLayout.FIX);
return gdeBox;
}
public JList addBacklinksList(JPanel pane, GameDataElement gde) {
final JList list = new JList(new GDEBacklinksListModel(gde));
list.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
ATContentStudio.frame.openEditor((GameDataElement)list.getSelectedValue());
ATContentStudio.frame.selectInTree((GameDataElement)list.getSelectedValue());
}
}
});
list.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
ATContentStudio.frame.openEditor((GameDataElement)list.getSelectedValue());
ATContentStudio.frame.selectInTree((GameDataElement)list.getSelectedValue());
}
}
});
list.setCellRenderer(new GDERenderer(true, false));
CollapsiblePanel colPane = new CollapsiblePanel("Elements linking to this one");
colPane.setLayout(new JideBoxLayout(colPane, JideBoxLayout.PAGE_AXIS));
colPane.add(new JScrollPane(list), JideBoxLayout.FIX);
colPane.add(new JPanel(), JideBoxLayout.FIX);
if (gde.getBacklinks() == null || gde.getBacklinks().isEmpty()) {
colPane.collapse();
}
pane.add(colPane, JideBoxLayout.FIX);
return list;
}
public static abstract class GDEComboModel<E extends GameDataElement> extends AbstractListModel implements ComboBoxModel {
private static final long serialVersionUID = -5854574666510314715L;
public Project project;
public E selected;
public GDEComboModel(Project proj, E initial) {
this.project = proj;
this.selected = initial;
}
@Override
public abstract int getSize();
@Override
public Object getElementAt(int index) {
if (index == 0) {
return null;
}
return getTypedElementAt(index - 1);
}
public abstract Object getTypedElementAt(int index);
@SuppressWarnings("unchecked")
@Override
public void setSelectedItem(Object anItem) {
selected = (E) anItem;
}
@Override
public Object getSelectedItem() {
return selected;
}
public void itemAdded(E item, int index) {
fireIntervalAdded(this, index, index);
}
public void itemRemoved(E item, int index) {
fireIntervalRemoved(this, index, index);
}
}
public static class GDERenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 6819681566800482793L;
private boolean includeType = false;
private boolean writable = false;
public GDERenderer(boolean includeType, boolean writable) {
super();
this.includeType = includeType;
this.writable = writable;
}
@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"+(writable ? ". Click on the button to create one." : ""));
} else {
if (includeType && ((GameDataElement)value).getDataType() != null) {
label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc());
} 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 GDEBacklinksListModel implements ListModel {
GameDataElement source;
public GDEBacklinksListModel(GameDataElement source) {
super();
this.source = source;
source.addBacklinkListener(new GameDataElement.BacklinksListener() {
@Override
public void backlinkRemoved(GameDataElement gde) {
fireListChanged();
}
@Override
public void backlinkAdded(GameDataElement gde) {
fireListChanged();
}
});
}
@Override
public int getSize() {
return source.getBacklinks().size();
}
@Override
public Object getElementAt(int index) {
for (GameDataElement gde : source.getBacklinks()) {
if (index == 0) return gde;
index --;
}
return null;
}
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 void fireListChanged() {
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, this.getSize()));
}
}
}
public class MyComboBox extends JComboBox implements ProjectElementListener {
private static final long serialVersionUID = -4184228604170642567L;
Class<? extends GameDataElement> dataType;
public MyComboBox(Class<? extends GameDataElement> dataType, ComboBoxModel model) {
super(model);
this.dataType = dataType;
Editor.this.addElementListener(dataType, this);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void elementAdded(GameDataElement added, int index) {
((GDEComboModel)getModel()).itemAdded(added, index);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void elementRemoved(GameDataElement removed, int index) {
((GDEComboModel)getModel()).itemRemoved(removed, index);
}
@Override
public Class<? extends GameDataElement> getDataType() {
return dataType;
}
}
public abstract void targetUpdated();
transient Map<Class<? extends GameDataElement>, List<ProjectElementListener>> projectElementListeners = new HashMap<Class<? extends GameDataElement>, List<ProjectElementListener>>();
public void addElementListener(Class<? extends GameDataElement> interestingType, ProjectElementListener listener) {
if (projectElementListeners.get(interestingType) == null) {
projectElementListeners.put(interestingType, new ArrayList<ProjectElementListener>());
target.getProject().addElementListener(interestingType, this);
}
projectElementListeners.get(interestingType).add(listener);
}
public void removeElementListener(ProjectElementListener listener) {
if (listener == null) return;
if (projectElementListeners.get(listener.getDataType()) != null) {
projectElementListeners.get(listener.getDataType()).remove(listener);
if (projectElementListeners.get(listener.getDataType()).isEmpty()) {
target.getProject().removeElementListener(listener.getDataType(), this);
projectElementListeners.remove(listener.getDataType());
}
}
}
public void elementAdded(GameDataElement element, int index) {
if (projectElementListeners.get(element.getClass()) != null) {
for (ProjectElementListener l : projectElementListeners.get(element.getClass())) {
l.elementAdded(element, index);
}
}
}
public void elementRemoved(GameDataElement element, int index) {
if (projectElementListeners.get(element.getClass()) != null) {
for (ProjectElementListener l : projectElementListeners.get(element.getClass())) {
l.elementRemoved(element, index);
}
}
}
public void clearElementListeners() {
for (Class<? extends GameDataElement> type : projectElementListeners.keySet()) {
target.getProject().removeElementListener(type, this);
}
}
public Class<? extends GameDataElement> getDataType() {
return null;
}
}

View File

@@ -0,0 +1,187 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Action;
import javax.swing.JPanel;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
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.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.gpl.rpg.atcontentstudio.model.saves.SavedGame;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.ActorConditionEditor;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.DialogueEditor;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.DroplistEditor;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.ItemCategoryEditor;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.ItemEditor;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.NPCEditor;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.QuestEditor;
import com.gpl.rpg.atcontentstudio.ui.map.TMXMapEditor;
import com.gpl.rpg.atcontentstudio.ui.map.WorldMapEditor;
import com.gpl.rpg.atcontentstudio.ui.saves.SavedGameEditor;
import com.gpl.rpg.atcontentstudio.ui.sprites.SpritesheetEditor;
import com.jidesoft.swing.JideTabbedPane;
public class EditorsArea extends JPanel {
private static final long serialVersionUID = 8801849846876081538L;
private Map<Object, Editor> editors = new HashMap<Object, Editor>();
private JideTabbedPane tabHolder;
public EditorsArea() {
super();
setLayout(new BorderLayout());
tabHolder = new JideTabbedPane();
tabHolder.setTabPlacement(JideTabbedPane.TOP);
tabHolder.setTabShape(JideTabbedPane.SHAPE_FLAT);
tabHolder.setUseDefaultShowCloseButtonOnTab(false);
tabHolder.setShowCloseButtonOnTab(true);
tabHolder.setCloseAction(new Action() {
@Override
public void actionPerformed(ActionEvent e) {
closeEditor((Editor) e.getSource());
}
@Override
public void setEnabled(boolean b) {
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
}
@Override
public void putValue(String key, Object value) {
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public Object getValue(String key) {
return null;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
}
});
add(tabHolder, BorderLayout.CENTER);
}
public void openEditor(Editor e) {
if (!editors.containsKey(e.target) && !editors.containsValue(e)) {
editors.put(e.target, e);
tabHolder.addTab(e.name, e.icon, e);
tabHolder.setSelectedComponent(e);
}
}
public void closeEditor(Editor e) {
if (editors.containsValue(e)) {
tabHolder.remove(e);
editors.remove(e.target);
e.clearElementListeners();
}
}
public void openEditor(JSONElement node) {
if (editors.containsKey(node)) {
tabHolder.setSelectedComponent(editors.get(node));
return;
}
if (node instanceof Quest) {
openEditor(new QuestEditor((Quest)node));
} else if (node instanceof Dialogue) {
openEditor(new DialogueEditor((Dialogue) node));
} else if (node instanceof Droplist) {
openEditor(new DroplistEditor((Droplist) node));
} else if (node instanceof ActorCondition) {
openEditor(new ActorConditionEditor((ActorCondition) node));
} else if (node instanceof ItemCategory) {
openEditor(new ItemCategoryEditor((ItemCategory) node));
} else if (node instanceof Item) {
openEditor(new ItemEditor((Item) node));
} else if (node instanceof NPC) {
openEditor(new NPCEditor((NPC) node));
}
}
public void openEditor(Spritesheet node) {
if (editors.containsKey(node)) {
tabHolder.setSelectedComponent(editors.get(node));
return;
}
node.link();
openEditor(new SpritesheetEditor((Spritesheet) node));
}
public void openEditor(TMXMap node) {
if (editors.containsKey(node)) {
tabHolder.setSelectedComponent(editors.get(node));
return;
}
node.link();
openEditor(new TMXMapEditor(node));
}
public void openEditor(SavedGame save) {
if (editors.containsKey(save)) {
tabHolder.setSelectedComponent(editors.get(save));
return;
}
openEditor(new SavedGameEditor(save));
}
public void openEditor(WorldmapSegment node) {
if (editors.containsKey(node)) {
tabHolder.setSelectedComponent(editors.get(node));
return;
}
node.link();
openEditor(new WorldMapEditor(node));
}
public void closeEditor(ProjectTreeNode node) {
if (editors.containsKey(node)) {
closeEditor(editors.get(node));
}
}
public void editorTabChanged(Editor e) {
int index = tabHolder.indexOfComponent(e);
if (index >= 0) {
tabHolder.setTitleAt(index, e.name);
tabHolder.setIconAt(index, e.icon);
}
}
public void editorTabChanged(ProjectTreeNode node) {
if (editors.get(node) != null) {
editors.get(node).targetUpdated();
editorTabChanged(editors.get(node));
}
}
public void showAbout() {
if (editors.containsKey(AboutEditor.instance)) {
tabHolder.setSelectedComponent(AboutEditor.instance);
return;
}
openEditor(AboutEditor.instance);
}
}

View File

@@ -0,0 +1,9 @@
package com.gpl.rpg.atcontentstudio.ui;
import javax.swing.JComponent;
public interface FieldUpdateListener {
public void valueChanged(JComponent source, Object value);
}

View File

@@ -0,0 +1,19 @@
package com.gpl.rpg.atcontentstudio.ui;
import javax.swing.JCheckBox;
public class IntegerBasedCheckBox extends JCheckBox {
private static final long serialVersionUID = 3941646360487399554L;
static final Integer one = 1;
public Integer getIntegerValue() {
return isSelected() ? one : null;
}
public void setIntegerValue(Integer val) {
setSelected(val != null && val.equals(one));
}
}

View File

@@ -0,0 +1,96 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import javax.swing.JComponent;
public class JMovingIdler extends JComponent {
private static final long serialVersionUID = -2980521421870322717L;
int position = 0;
boolean destroyed=false, running=false;
Thread moverThread = new Thread(){
public void run() {
while (!destroyed) {
boolean back = false;
while (running) {
if (back) {
position = --position % 100;
if (position == 0) {
back = false;
}
} else {
position = ++position % 100;
if (position == 99) {
back = true;
}
}
try {
sleep(10);
} catch (InterruptedException e) {}
JMovingIdler.this.revalidate();
JMovingIdler.this.repaint();
}
}
}
};
public void start() {
if (!moverThread.isAlive()) {
moverThread.start();
}
running = true;
}
public void stop() {
running = false;
}
public void destroy() {
destroyed = true;
running = false;
try {
moverThread.join();
} catch (InterruptedException e) {}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int w = this.getWidth();
int h = this.getHeight();
g2.setColor(getBackground());
g2.fillRect(0,0,w,h);
int x = w * position / 100;
Paint p = new GradientPaint(x - (w/8), 0, getBackground(), x , 0, getForeground());
g2.setPaint(p);
g2.fillRect(Math.max(0,x-(w/8)),0, Math.min(x, w), h);
p = new GradientPaint(x, 0, getForeground(), x + (w/8), 0, getBackground());
g2.setPaint(p);
g2.fillRect(Math.max(0,x),0, Math.min(x+(w/8), w), h);
g2.setColor(Color.BLACK);
g2.drawLine(0,0,0,h);
g2.drawLine(0,0,w,0);
g2.drawLine(w,0,w,h);
g2.drawLine(0,h,w,h);
}
@Override
public void setVisible(boolean aFlag) {
super.setVisible(aFlag);
if (!aFlag) destroy();
}
}

View File

@@ -0,0 +1,593 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataListener;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
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.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.ui.sprites.SpriteChooser;
import com.jidesoft.swing.JideBoxLayout;
public class JSONCreationWizard extends JDialog {
private static final long serialVersionUID = -5744628699021314026L;
public static enum DataType {
none,
actorCondition,
dialogue,
droplist,
item,
itemCategory,
npc,
quest
}
private JSONElement creation = null;
final JLabel message;
final JComboBox dataTypeCombo;
final JTextField idField;
final JTextField nameField;
final JButton ok;
final Project proj;
public JSONCreationWizard(final Project proj, Class<? extends GameDataElement> dataClass) {
this(proj);
if (dataClass == ActorCondition.class) {
dataTypeCombo.setSelectedItem(DataType.actorCondition);
} else if (dataClass == Dialogue.class) {
dataTypeCombo.setSelectedItem(DataType.dialogue);
} else if (dataClass == Droplist.class) {
dataTypeCombo.setSelectedItem(DataType.droplist);
} else if (dataClass == Item.class) {
dataTypeCombo.setSelectedItem(DataType.item);
} else if (dataClass == ItemCategory.class) {
dataTypeCombo.setSelectedItem(DataType.itemCategory);
} else if (dataClass == NPC.class) {
dataTypeCombo.setSelectedItem(DataType.npc);
} else if (dataClass == Quest.class) {
dataTypeCombo.setSelectedItem(DataType.quest);
}
dataTypeCombo.setEnabled(false);
}
public JSONCreationWizard(final Project proj) {
super(ATContentStudio.frame);
this.proj = proj;
setTitle("Create Game Data Element (JSON)");
JPanel pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
pane.add(new JLabel("Create a new game data element."), JideBoxLayout.FIX);
message = new JLabel("Select a data type below:");
pane.add(message, JideBoxLayout.FIX);
dataTypeCombo = new JComboBox(new DataTypeComboModel());
dataTypeCombo.setRenderer(new DataTypeComboCellRenderer());
pane.add(dataTypeCombo);
final JPanel idPane = new JPanel();
idPane.setLayout(new BorderLayout());
JLabel idLabel = new JLabel("Internal ID: ");
idPane.add(idLabel, BorderLayout.WEST);
idField = new JTextField("");
idField.setEditable(true);
idPane.add(idField, BorderLayout.CENTER);
pane.add(idPane, JideBoxLayout.FIX);
final JPanel namePane = new JPanel();
namePane.setLayout(new BorderLayout());
JLabel nameLabel = new JLabel("Display name: ");
namePane.add(nameLabel, BorderLayout.WEST);
nameField = new JTextField("");
nameField.setEditable(true);
namePane.add(nameField, BorderLayout.CENTER);
pane.add(namePane, JideBoxLayout.FIX);
final JPanel iconPane = new JPanel();
iconPane.setLayout(new BorderLayout());
final JLabel iconLabel = new JLabel("Icon: ");
iconPane.add(iconLabel, BorderLayout.WEST);
final JButton iconButton = new JButton(new ImageIcon(DefaultIcons.getActorConditionImage()));
iconPane.add(iconButton, BorderLayout.CENTER);
pane.add(iconPane, JideBoxLayout.FIX);
iconPane.setVisible(true);
dataTypeCombo.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
idPane.setVisible(true);
switch ((DataType)e.getItem()) {
case actorCondition:
iconPane.setVisible(true);
namePane.setVisible(true);
iconButton.setIcon(new ImageIcon(DefaultIcons.getActorConditionImage()));
creation = new ActorCondition();
break;
case dialogue:
iconPane.setVisible(false);
namePane.setVisible(false);
creation = new Dialogue();
break;
case droplist:
iconPane.setVisible(false);
namePane.setVisible(false);
creation = new Droplist();
break;
case item:
iconPane.setVisible(true);
namePane.setVisible(true);
creation = new Item();
iconButton.setIcon(new ImageIcon(DefaultIcons.getItemImage()));
break;
case itemCategory:
iconPane.setVisible(false);
namePane.setVisible(true);
creation = new ItemCategory();
break;
case npc:
iconPane.setVisible(true);
namePane.setVisible(true);
creation = new NPC();
iconButton.setIcon(new ImageIcon(DefaultIcons.getNPCImage()));
break;
case quest:
iconPane.setVisible(false);
namePane.setVisible(true);
creation = new Quest();
break;
default:
idPane.setVisible(false);
iconPane.setVisible(false);
namePane.setVisible(false);
creation = null;
break;
}
updateStatus();
idPane.revalidate();
namePane.revalidate();
iconPane.revalidate();
idPane.repaint();
namePane.repaint();
iconPane.repaint();
}
}
});
iconButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Spritesheet.Category cat = null;
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
cat = Spritesheet.Category.actorcondition;
break;
case dialogue:
break;
case droplist:
break;
case item:
cat = Spritesheet.Category.item;
break;
case itemCategory:
break;
case npc:
cat = Spritesheet.Category.monster;
break;
case quest:
break;
default:
break;
}
if (cat == null) return;
SpriteChooser chooser = SpriteChooser.getChooser(proj, cat);
chooser.setSelectionListener(new SpriteChooser.SelectionListener() {
@Override
public void iconSelected(String selected) {
if (selected != null) {
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
((ActorCondition)creation).icon_id = selected;
break;
case item:
((Item)creation).icon_id = selected;
break;
case npc:
((NPC)creation).icon_id = selected;
break;
case dialogue:
case droplist:
case itemCategory:
case quest:
default:
break;
}
iconButton.setIcon(new ImageIcon(proj.getImage(selected)));
iconButton.revalidate();
iconButton.repaint();
updateStatus();
}
}
});
chooser.setVisible(true);
}
});
pane.add(new JPanel(), JideBoxLayout.VARY);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
JButton cancel = new JButton("Cancel");
buttonPane.add(cancel, JideBoxLayout.FIX);
ok = new JButton("Ok");
buttonPane.add(ok, JideBoxLayout.FIX);
pane.add(buttonPane, JideBoxLayout.FIX);
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
((ActorCondition)creation).display_name = nameField.getText();
break;
case item:
((Item)creation).name = nameField.getText();
break;
case npc:
((NPC)creation).name = nameField.getText();
break;
case dialogue:
case droplist:
break;
case itemCategory:
((ItemCategory)creation).name = nameField.getText();
break;
case quest:
((Quest)creation).name = nameField.getText();
break;
default:
return;
}
creation.id = idField.getText();
JSONCreationWizard.this.setVisible(false);
JSONCreationWizard.this.dispose();
proj.createElement(creation);
notifyCreated();
ATContentStudio.frame.selectInTree(creation);
ATContentStudio.frame.openEditor(creation);
}
});
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
creation = null;
JSONCreationWizard.this.setVisible(false);
JSONCreationWizard.this.dispose();
}
});
DocumentListener statusUpdater = new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void insertUpdate(DocumentEvent e) {
updateStatus();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateStatus();
}
};
idField.getDocument().addDocumentListener(statusUpdater);
nameField.getDocument().addDocumentListener(statusUpdater);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
setMinimumSize(new Dimension(350,250));
idPane.setVisible(false);
iconPane.setVisible(false);
namePane.setVisible(false);
updateStatus();
pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = getSize();
setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
}
public void updateStatus() {
boolean trouble = false;
message.setText("<html><font color=\"#00AA00\">Looks OK to me.</font></html>");
if (creation == null) {
message.setText("<html><font color=\"#FF0000\">Select a data type below:</font></html>");
trouble = true;
} else if (idField.getText() == null || idField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">Internal ID must not be empty.</font></html>");
trouble = true;
} else {
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">An actor condition must have a name.</font></html>");
trouble = true;
} else if (((ActorCondition)creation).icon_id == null) {
message.setText("<html><font color=\"#FF0000\">An actor condition must have an icon.</font></html>");
trouble = true;
} else if (proj.getActorCondition(idField.getText()) != null) {
if (proj.getActorCondition(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">An actor condition with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getActorCondition(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">An actor condition with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getActorCondition(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">An actor condition with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case item:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">An item must have a name.</font></html>");
trouble = true;
} else if (((Item)creation).icon_id == null) {
message.setText("<html><font color=\"#FF0000\">An item must have an icon.</font></html>");
trouble = true;
} else if (proj.getItem(idField.getText()) != null) {
if (proj.getItem(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">An item with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getItem(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">An item with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getItem(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">An item with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case npc:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">A NPC must have a name.</font></html>");
trouble = true;
} else if (((NPC)creation).icon_id == null) {
message.setText("<html><font color=\"#FF0000\">A NPC must have an icon.</font></html>");
trouble = true;
} else if (proj.getNPC(idField.getText()) != null) {
if (proj.getNPC(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A NPC with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getNPC(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A NPC with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getNPC(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A NPC with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case dialogue:
if (proj.getDialogue(idField.getText()) != null) {
if (proj.getDialogue(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A dialogue with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getDialogue(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A dialogue with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getDialogue(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A dialogue with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case droplist:
if (proj.getDroplist(idField.getText()) != null) {
if (proj.getDroplist(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A droplist with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getDroplist(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A droplist with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getDroplist(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A droplist with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case itemCategory:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">An item category must have a name.</font></html>");
trouble = true;
} else if (proj.getItemCategory(idField.getText()) != null) {
if (proj.getItemCategory(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">An item category with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getItemCategory(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">An item category with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getItemCategory(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">An item category with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
case quest:
if(nameField.getText() == null || nameField.getText().length() <= 0) {
message.setText("<html><font color=\"#FF0000\">A quest must have a name.</font></html>");
trouble = true;
} else if (proj.getQuest(idField.getText()) != null) {
if (proj.getQuest(idField.getText()).getDataType() == GameSource.Type.created) {
message.setText("<html><font color=\"#FF0000\">A quest with the same ID was already created in this project.</font></html>");
trouble = true;
} else if (proj.getQuest(idField.getText()).getDataType() == GameSource.Type.altered) {
message.setText("<html><font color=\"#FF0000\">A quest with the same ID exists in the game and is already altered in this project.</font></html>");
trouble = true;
} else if (proj.getQuest(idField.getText()).getDataType() == GameSource.Type.source) {
message.setText("<html><font color=\"#FF9000\">A quest with the same ID exists in the game. It will be added under \"altered\".</font></html>");
}
}
break;
default:
break;
}
}
ok.setEnabled(!trouble);
message.revalidate();
message.repaint();
}
public static String dataTypeDesc(DataType type) {
switch (type) {
case actorCondition:
return "Actor Condition";
case dialogue:
return "Dialogue";
case droplist:
return "Droplist";
case item:
return "Item";
case itemCategory:
return "Item Category";
case npc:
return "NPC";
case quest:
return "Quest";
default:
return "Select below";
}
}
public static class DataTypeComboModel implements ComboBoxModel {
DataType selected = DataType.none;
@Override
public int getSize() {
return DataType.values().length;
}
@Override
public Object getElementAt(int index) {
return DataType.values()[index];
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
@Override
public void setSelectedItem(Object anItem) {
selected = (DataType) anItem;
}
@Override
public Object getSelectedItem() {
return selected;
}
}
public static class DataTypeComboCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 5621373849299980998L;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
((JLabel)c).setText(JSONCreationWizard.dataTypeDesc((DataType) value));
switch ((DataType)value) {
case actorCondition:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getActorConditionIcon()));
break;
case dialogue:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getDialogueIcon()));
break;
case droplist:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getDroplistIcon()));
break;
case item:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getItemIcon()));
break;
case itemCategory:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getDroplistIcon()));
break;
case npc:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getNPCIcon()));
break;
case quest:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getQuestIcon()));
break;
default:
break;
}
}
return c;
}
}
public static interface CreationCompletedListener {
public void elementCreated(JSONElement created);
}
private List<CreationCompletedListener> listeners = new ArrayList<JSONCreationWizard.CreationCompletedListener>();
public void addCreationListener(CreationCompletedListener l) {
listeners.add(l);
}
public void notifyCreated() {
for (CreationCompletedListener l : listeners) {
l.elementCreated(creation);
}
}
}

View File

@@ -0,0 +1,720 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.swing.ButtonGroup;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
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.Project;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
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.jidesoft.swing.JideBoxLayout;
public class JSONImportWizard extends JDialog {
private static final long serialVersionUID = 661234868711700156L;
public static enum DataType {
none,
actorCondition,
dialogue,
droplist,
item,
itemCategory,
npc,
quest
}
Project proj;
JPanel pane;
JLabel message;
JComboBox dataTypeCombo;
JRadioButton importFromFile;
JRadioButton importPasted;
JPanel fileSelectionPane;
JTextField jsonFileName;
JButton browse;
RSyntaxTextArea jsonPasteArea;
JScrollPane scroller;
JList createdPreview;
JPanel buttonPane;
JButton ok, cancel;
ActionListener okListener, cancelListener;
public JSONImportWizard(Project proj) {
super(ATContentStudio.frame);
setTitle("Import data from JSON");
this.proj = proj;
pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
pane.add(new JLabel("Import data in JSON format."), JideBoxLayout.FIX);
message = new JLabel();
dataTypeCombo = new JComboBox(new DataTypeComboModel());
dataTypeCombo.setRenderer(new DataTypeComboCellRenderer());
dataTypeCombo.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
checkEnableNext();
}
}
});
importPasted = new JRadioButton("Paste JSON text");
importFromFile = new JRadioButton("Select .json file");
importPasted.setSelected(true);
ButtonGroup radioGroup = new ButtonGroup();
radioGroup.add(importPasted);
radioGroup.add(importFromFile);
importPasted.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (importPasted.isSelected()) {
scroller.setVisible(true);
fileSelectionPane.setVisible(false);
pane.revalidate();
pane.repaint();
}
}
});
importFromFile.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (importFromFile.isSelected()) {
scroller.setVisible(false);
fileSelectionPane.setVisible(true);
pane.revalidate();
pane.repaint();
}
}
});
jsonFileName = new JTextField();
jsonFileName.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
checkEnableNext();
}
@Override
public void insertUpdate(DocumentEvent e) {
checkEnableNext();
}
@Override
public void changedUpdate(DocumentEvent e) {
checkEnableNext();
}
});
browse = new JButton("Browse");
browse.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser jfc = new JFileChooser(){
private static final long serialVersionUID = -3001082967957619011L;
@Override
public boolean accept(File f) {
if (f.isDirectory() || f.getName().endsWith(".json") || f.getName().endsWith(".JSON")) {
return super.accept(f);
} else {
return false;
}
}
};
jfc.setMultiSelectionEnabled(false);
int result = jfc.showOpenDialog(ATContentStudio.frame);
if (result == JFileChooser.APPROVE_OPTION) {
jsonFileName.setText(jfc.getSelectedFile().getAbsolutePath());
checkEnableNext();
}
}
});
fileSelectionPane = new JPanel();
fileSelectionPane.setLayout(new JideBoxLayout(fileSelectionPane, JideBoxLayout.LINE_AXIS, 6));
fileSelectionPane.add(new JLabel("JSON File: "), JideBoxLayout.FIX);
fileSelectionPane.add(jsonFileName, JideBoxLayout.VARY);
fileSelectionPane.add(browse, JideBoxLayout.FIX);
jsonPasteArea = new RSyntaxTextArea();
jsonPasteArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JSON);
jsonPasteArea.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
checkEnableNext();
}
@Override
public void insertUpdate(DocumentEvent e) {
checkEnableNext();
}
@Override
public void changedUpdate(DocumentEvent e) {
checkEnableNext();
}
});
buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
cancel = new JButton("Cancel");
buttonPane.add(cancel, JideBoxLayout.FIX);
ok = new JButton("Next");
buttonPane.add(ok, JideBoxLayout.FIX);
createdPreview = new JList(new GDEListModel(new ArrayList<GameDataElement>()));
showFirstScreen();
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
setMinimumSize(new Dimension(450,350));
pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = getSize();
setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
}
private void showFirstScreen() {
pane.removeAll();
message.setText("Select a data type & paste your JSON data below:");
pane.add(message, JideBoxLayout.FIX);
pane.add(dataTypeCombo, JideBoxLayout.FIX);
pane.add(importPasted, JideBoxLayout.FIX);
pane.add(importFromFile, JideBoxLayout.FIX);
pane.add(fileSelectionPane, JideBoxLayout.FIX);
scroller = new JScrollPane(jsonPasteArea);
scroller.getVerticalScrollBar().setUnitIncrement(16);
JPanel scrollHolder = new JPanel();
scrollHolder.setLayout(new BorderLayout());
scrollHolder.add(scroller, BorderLayout.CENTER);
pane.add(scrollHolder, JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
ok.setText("Next");
ok.setEnabled(jsonPasteArea.getText() != null && jsonPasteArea.getText().length() > 0 && dataTypeCombo.getSelectedItem() != null && dataTypeCombo.getSelectedItem() != DataType.none);
ok.removeActionListener(okListener);
okListener = new ActionListener() {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void actionPerformed(ActionEvent e) {
List<String> errors = new ArrayList<String>();
List<String> warnings = new ArrayList<String>();
List<JSONElement> created = new ArrayList<JSONElement>();
Object jsonParserOutput = null;
try {
if (importPasted.isSelected()) {
jsonParserOutput = new JSONParser().parse(jsonPasteArea.getText());
} else if (importFromFile.isSelected()) {
jsonParserOutput = new JSONParser().parse(new FileReader(new File(jsonFileName.getText())));
}
} catch (ParseException e1) {
errors.add("Invalid JSON content: "+e1.getMessage());
} catch (FileNotFoundException e1) {
errors.add("Unable to access file: "+e1.getMessage());
} catch (IOException e1) {
errors.add("Error while accessing file: "+e1.getMessage());
}
if (jsonParserOutput != null) {
List<Map> jsonObjects = null;
if (jsonParserOutput instanceof List) {
jsonObjects = (List)jsonParserOutput;
} else if (jsonParserOutput instanceof Map) {
jsonObjects = new ArrayList<Map>();
jsonObjects.add((Map) jsonParserOutput);
} else {
errors.add("Invalid JSON content: neither an array nor an object.");
}
if (jsonObjects != null) {
JSONElement node = null;
JSONElement existingNode = null;
int i = 0;
for (Map jsonObject : jsonObjects) {
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
node = ActorCondition.fromJson(jsonObject);
existingNode = proj.getActorCondition(node.id);
break;
case item:
node = Item.fromJson(jsonObject);
existingNode = proj.getItem(node.id);
break;
case npc:
node = NPC.fromJson(jsonObject);
existingNode = proj.getNPC(node.id);
break;
case dialogue:
node = Dialogue.fromJson(jsonObject);
existingNode = proj.getDialogue(node.id);
break;
case droplist:
node = Droplist.fromJson(jsonObject);
existingNode = proj.getDroplist(node.id);
break;
case itemCategory:
node = ItemCategory.fromJson(jsonObject);
existingNode = proj.getItemCategory(node.id);
break;
case quest:
node = Quest.fromJson(jsonObject);
existingNode = proj.getQuest(node.id);
break;
default:
return;
}
i++;
if (node instanceof JSONElement) {
node.parse(jsonObject);
created.add(node);
if (existingNode != null) {
if (existingNode.getDataType() == GameSource.Type.created) {
errors.add("An item with id "+node.id+" is already created in this project.");
} else if (existingNode.getDataType() == GameSource.Type.altered) {
errors.add("An item with id "+node.id+" is already altered in this project.");
} else {
warnings.add("An item with id "+node.id+" exists in the used game source. This one will be inserted as \"altered\"");
}
existingNode = null;
}
node = null;
} else {
warnings.add("Failed to load element #"+i);
}
}
}
}
if (errors.isEmpty() && warnings.isEmpty()) {
showImportPreviewScreen(created);
} else if (!errors.isEmpty()) {
showErrorScreen(errors);
} else {
showWarningScreen(warnings, created);
}
}
};
ok.addActionListener(okListener);
cancel.setText("Cancel");
cancel.removeActionListener(cancelListener);
cancelListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JSONImportWizard.this.setVisible(false);
JSONImportWizard.this.dispose();
}
};
cancel.addActionListener(cancelListener);
if (importPasted.isSelected()) {
scroller.setVisible(true);
fileSelectionPane.setVisible(false);
pane.revalidate();
pane.repaint();
} else if (importFromFile.isSelected()) {
scroller.setVisible(false);
fileSelectionPane.setVisible(true);
pane.revalidate();
pane.repaint();
}
pane.revalidate();
pane.repaint();
}
private void checkEnableNext() {
if (dataTypeCombo.getSelectedItem() != null && dataTypeCombo.getSelectedItem() != DataType.none) {
if (importPasted.isSelected()) {
ok.setEnabled(jsonPasteArea.getText() != null && jsonPasteArea.getText().length() > 0);
} else if (importFromFile.isSelected()) {
ok.setEnabled(jsonFileName.getText() != null && jsonFileName.getText().length() > 0 && new File(jsonFileName.getText()).exists() && !(new File(jsonFileName.getText()).isDirectory()));
}
}
}
private void showImportPreviewScreen(final List<JSONElement> created) {
pane.removeAll();
message.setText("The following data has been found. Click \"Ok\" to confirm.");
pane.add(message, JideBoxLayout.FIX);
createdPreview.setModel(new GDEListModel(created));
createdPreview.setCellRenderer(new GDERenderer(false));
pane.add(new JScrollPane(createdPreview), JideBoxLayout.FIX);
pane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
ok.setText("Ok");
ok.removeActionListener(okListener);
okListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JSONElement lastNode = null;
for (JSONElement node : created) {
proj.createElement(node);
lastNode = node;
}
if (lastNode != null) {
lastNode.save();
ATContentStudio.frame.selectInTree(lastNode);
}
JSONImportWizard.this.setVisible(false);
JSONImportWizard.this.dispose();
}
};
ok.addActionListener(okListener);
cancel.setText("Back");
cancel.removeActionListener(cancelListener);
cancelListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showFirstScreen();
}
};
cancel.addActionListener(cancelListener);
pane.revalidate();
pane.repaint();
}
private void showErrorScreen(List<String> errors) {
pane.removeAll();
message.setText("Failed to import. The following error(s) have been encountered:");
pane.add(message, JideBoxLayout.FIX);
createdPreview.setModel(new GDEListModel(errors));
createdPreview.setCellRenderer(new ErrorRenderer());
pane.add(new JScrollPane(createdPreview), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
cancel.setText("Back");
cancel.removeActionListener(cancelListener);
cancelListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showFirstScreen();
}
};
cancel.addActionListener(cancelListener);
ok.setText("Close");
ok.removeActionListener(okListener);
okListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JSONImportWizard.this.setVisible(false);
JSONImportWizard.this.dispose();
}
};
ok.addActionListener(okListener);
pane.revalidate();
pane.repaint();
}
private void showWarningScreen(List<String> warnings, final List<JSONElement> created) {
pane.removeAll();
message.setText("The following warnings(s) were raised while importing:");
pane.add(message, JideBoxLayout.FIX);
createdPreview.setModel(new GDEListModel(warnings));
createdPreview.setCellRenderer(new WarningRenderer());
pane.add(new JScrollPane(createdPreview), JideBoxLayout.VARY);
pane.add(buttonPane, JideBoxLayout.FIX);
ok.setText("Continue anyway");
ok.removeActionListener(okListener);
okListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
showImportPreviewScreen(created);
}
};
ok.addActionListener(okListener);
cancel.setText("Close");
cancel.removeActionListener(cancelListener);
cancelListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JSONImportWizard.this.setVisible(false);
JSONImportWizard.this.dispose();
}
};
cancel.addActionListener(cancelListener);
pane.revalidate();
pane.repaint();
}
public class GDERenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 6819681566800482793L;
private boolean includeType = false;
public GDERenderer(boolean includeType) {
super();
this.includeType = includeType;
}
@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 {
if (includeType && ((GameDataElement)value).getDataType() != null) {
label.setText(((GameDataElement)value).getDataType().toString()+"/"+((GameDataElement)value).getDesc());
} else {
label.setText(((GameDataElement)value).getDesc());
}
switch ((DataType)dataTypeCombo.getSelectedItem()) {
case actorCondition:
label.setIcon(new ImageIcon(proj.getIcon(((ActorCondition)value).icon_id)));
break;
case item:
label.setIcon(new ImageIcon(proj.getIcon(((Item)value).icon_id)));
break;
case npc:
label.setIcon(new ImageIcon(proj.getIcon(((NPC)value).icon_id)));
break;
case dialogue:
label.setIcon(new ImageIcon(((Dialogue)value).getIcon()));
break;
case droplist:
label.setIcon(new ImageIcon(((Droplist)value).getIcon()));
break;
case itemCategory:
label.setIcon(new ImageIcon(((ItemCategory)value).getIcon()));
break;
case quest:
label.setIcon(new ImageIcon(((Quest)value).getIcon()));
break;
default:
Notification.addError("Unable to find icon for "+((GameDataElement)value).getDesc());
}
}
return label;
}
}
public static class ErrorRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = -4265342800284721660L;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
((JLabel)c).setIcon(NotificationsPane.icons.get(Notification.Type.ERROR));
}
return c;
}
}
public static class WarningRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = -3836045237946111606L;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
((JLabel)c).setIcon(NotificationsPane.icons.get(Notification.Type.WARN));
}
return c;
}
}
public static class GDEListModel implements ListModel {
List<? extends Object> source;
public GDEListModel(List<? extends Object> source) {
this.source = source;
}
@Override
public int getSize() {
return source.size();
}
@Override
public Object getElementAt(int index) {
for (Object obj : source) {
if (index == 0) return obj;
index --;
}
return null;
}
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 void fireListChanged() {
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, this.getSize()));
}
}
}
public static class DataTypeComboModel implements ComboBoxModel {
DataType selected = DataType.none;
@Override
public int getSize() {
return DataType.values().length;
}
@Override
public Object getElementAt(int index) {
return DataType.values()[index];
}
List<ListDataListener> listeners = new ArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
@Override
public void setSelectedItem(Object anItem) {
selected = (DataType) anItem;
}
@Override
public Object getSelectedItem() {
return selected;
}
}
public static class DataTypeComboCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 5621373849299980998L;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
((JLabel)c).setText(dataTypeDesc((DataType) value));
switch ((DataType)value) {
case actorCondition:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getActorConditionIcon()));
break;
case dialogue:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getDialogueIcon()));
break;
case droplist:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getDroplistIcon()));
break;
case item:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getItemIcon()));
break;
case itemCategory:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getDroplistIcon()));
break;
case npc:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getNPCIcon()));
break;
case quest:
((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getQuestIcon()));
break;
default:
break;
}
}
return c;
}
}
public static String dataTypeDesc(DataType type) {
switch (type) {
case actorCondition:
return "Actor Condition";
case dialogue:
return "Dialogue";
case droplist:
return "Droplist";
case item:
return "Item";
case itemCategory:
return "Item Category";
case npc:
return "NPC";
case quest:
return "Quest";
default:
return "Select below";
}
}
}

View File

@@ -0,0 +1,113 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import com.gpl.rpg.atcontentstudio.Notification;
import com.gpl.rpg.atcontentstudio.NotificationListener;
public class NotificationsPane extends JList {
private static final long serialVersionUID = -1100364214372392608L;
public static final String success_img_name = "/com/gpl/rpg/atcontentstudio/img/success.png";
public static final String info_img_name = "/com/gpl/rpg/atcontentstudio/img/info.png";
public static final String warn_img_name = "/com/gpl/rpg/atcontentstudio/img/warn.png";
public static final String error_img_name = "/com/gpl/rpg/atcontentstudio/img/error.png";
public static final Map<Notification.Type, Icon> icons = new HashMap<Notification.Type, Icon>(Notification.Type.values().length);
static {
try {
icons.put(Notification.Type.SUCCESS, new ImageIcon(ImageIO.read(NotificationsPane.class.getResourceAsStream(success_img_name))));
icons.put(Notification.Type.INFO, new ImageIcon(ImageIO.read(NotificationsPane.class.getResourceAsStream(info_img_name))));
icons.put(Notification.Type.WARN, new ImageIcon(ImageIO.read(NotificationsPane.class.getResourceAsStream(warn_img_name))));
icons.put(Notification.Type.ERROR, new ImageIcon(ImageIO.read(NotificationsPane.class.getResourceAsStream(error_img_name))));
} catch (IOException e) {
e.printStackTrace();
}
}
public NotificationsPane() {
super();
MyListModel model = new MyListModel();
setModel(model);
setCellRenderer(new ListCellRenderer(){
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel label = new JLabel();
Font f = label.getFont();
label.setIcon(NotificationsPane.icons.get(((Notification)value).type));
label.setText(((Notification)value).text);
if (isSelected) {
// label.setBackground(Color.RED);
label.setBorder(BorderFactory.createLineBorder(Color.BLUE));
// label.setForeground(Color.WHITE);
}
f = f.deriveFont(10f);
label.setFont(f);
return label;
}
});
Notification.addNotificationListener(model);
}
private class MyListModel implements ListModel, NotificationListener {
@Override
public Object getElementAt(int index) {
return Notification.notifs.get(index);
}
@Override
public int getSize() {
return Notification.notifs.size();
}
@Override
public void onNewNotification(Notification n) {
for (ListDataListener l : listeners) {
l.intervalAdded(new ListDataEvent(NotificationsPane.this, ListDataEvent.INTERVAL_ADDED, Notification.notifs.size() - 1 , Notification.notifs.size() - 1));
}
NotificationsPane.this.ensureIndexIsVisible(Notification.notifs.indexOf(n));
}
@Override
public void onListCleared(int i) {
for (ListDataListener l : listeners) {
l.intervalRemoved(new ListDataEvent(NotificationsPane.this, ListDataEvent.INTERVAL_REMOVED, 0 , i));
}
}
private List<ListDataListener> listeners = new ArrayList<ListDataListener>();
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
}
}

View File

@@ -0,0 +1,250 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
import com.gpl.rpg.atcontentstudio.model.sprites.SpriteSheetSet;
public class ProjectCreationWizard extends JDialog {
private static final long serialVersionUID = -2854969975146867119L;
final JTextField projectNameField;
final JComboBox atSourceSelectionCombo;
final JButton browse;
final JButton okButton;
final JButton cancelButton;
final JLabel errorLabel;
public ProjectCreationWizard() {
super(ATContentStudio.frame);
setTitle("Create project");
projectNameField = new JTextField();
atSourceSelectionCombo = new JComboBox();
browse = new JButton("Browse...");
okButton = new JButton("Ok");
cancelButton = new JButton("Cancel");
errorLabel = new JLabel("Enter the following information about your project.");
projectNameField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
updateOkButtonEnablement();
}
@Override
public void insertUpdate(DocumentEvent e) {
updateOkButtonEnablement();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateOkButtonEnablement();
}
});
for (File f : Workspace.activeWorkspace.knownMapSourcesFolders) {
atSourceSelectionCombo.addItem(f.getAbsolutePath());
}
atSourceSelectionCombo.setEditable(true);
atSourceSelectionCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateOkButtonEnablement();
}
});
browse.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser();
boolean keepTrying = true;
if (atSourceSelectionCombo.getSelectedItem() != null && ((String)atSourceSelectionCombo.getSelectedItem()).length() > 0) {
File f = new File((String)atSourceSelectionCombo.getSelectedItem());
if (f.exists()) {
chooser.setCurrentDirectory(f);
keepTrying = false;
}
}
if (keepTrying && Workspace.activeWorkspace.knownMapSourcesFolders != null && !Workspace.activeWorkspace.knownMapSourcesFolders.isEmpty()) {
chooser.setCurrentDirectory(Workspace.activeWorkspace.knownMapSourcesFolders.iterator().next());
}
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int result = chooser.showOpenDialog(ProjectCreationWizard.this);
if (result == JFileChooser.APPROVE_OPTION) {
atSourceSelectionCombo.setSelectedItem(chooser.getSelectedFile().getAbsolutePath());
updateOkButtonEnablement();
}
}
});
okButton.setEnabled(false);
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
File atSourceFolder = new File((String) atSourceSelectionCombo.getSelectedItem());
if (!Workspace.activeWorkspace.knownMapSourcesFolders.contains(atSourceFolder)) {
Workspace.activeWorkspace.knownMapSourcesFolders.add(atSourceFolder);
}
Workspace.createProject(projectNameField.getText(), atSourceFolder);
ProjectCreationWizard.this.dispose();
}
});
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ProjectCreationWizard.this.dispose();
}
});
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
GridBagConstraints c =new GridBagConstraints();
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
c.gridheight = 1;
c.gridwidth = 3;
c.gridx = 1;
c.gridy = 1;
c.weightx = 100;
c.weighty = 100;
panel.add(errorLabel, c);
c.gridy++;
c.gridx = 1;
c.gridwidth = 1;
c.weightx = 20;
panel.add(new JLabel("Project name: "), c);
c.gridx++;
c.gridwidth = 2;
c.weightx = 80;
panel.add(projectNameField, c);
c.gridy++;
c.gridx = 1;
c.gridwidth = 1;
c.weightx = 20;
panel.add(new JLabel("AT Source: "), c);
c.gridx++;
c.weightx = 60;
panel.add(atSourceSelectionCombo, c);
c.gridx++;
c.weightx = 20;
panel.add(browse, c);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new GridBagLayout());
GridBagConstraints c2 = new GridBagConstraints();
c2.fill = GridBagConstraints.HORIZONTAL;
c2.gridx = 1;
c2.weightx = 80;
c2.gridx = 1;
c2.weightx = 80;
buttonPane.add(new JLabel(), c2);
c2.gridx++;
c2.weightx = 10;
c.fill = GridBagConstraints.NONE;
buttonPane.add(cancelButton, c2);
c2.gridx++;
c2.weightx = 10;
buttonPane.add(okButton, c2);
c.gridy++;
c.fill = GridBagConstraints.HORIZONTAL;
c.gridwidth = 3;
panel.add(buttonPane, c);
updateOkButtonEnablement();
setContentPane(panel);
pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = getSize();
setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
}
protected void updateOkButtonEnablement() {
if (projectNameField.getText() == null || projectNameField.getText().length() <= 0) {
errorLabel.setText("<html><font color=\"#FF0000\">Select a project name.</font></html>");
this.okButton.setEnabled(false);
return;
}
if (atSourceSelectionCombo.getSelectedItem() == null || ((String)atSourceSelectionCombo.getSelectedItem()).length() <= 0) {
errorLabel.setText("<html><font color=\"#FF0000\">Select an AT source root folder.</font></html>");
this.okButton.setEnabled(false);
return;
}
File projFolder = new File(Workspace.activeWorkspace.baseFolder, projectNameField.getText()+File.separator);
File sourceFolder = new File((String) atSourceSelectionCombo.getSelectedItem());
if (projFolder.exists()) {
errorLabel.setText("<html><font color=\"#FF0000\">A project with this name already exists.</font></html>");
this.okButton.setEnabled(false);
return;
} else {
try {
projFolder.getCanonicalPath();
} catch (IOException ioe) {
errorLabel.setText("<html><font color=\"#FF0000\">"+projectNameField.getText()+" is not a valid project name.</font></html>");
this.okButton.setEnabled(false);
return;
}
}
if (!sourceFolder.exists()) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected AT source root folder does not exist.</font></html>");
this.okButton.setEnabled(false);
return;
} else {
File res = new File(sourceFolder, GameDataSet.DEFAULT_REL_PATH_IN_SOURCE);
if (!res.exists()) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected AT source root folder does not contain the \"res\" folder.</font></html>");
this.okButton.setEnabled(false);
return;
}
File drawable = new File(sourceFolder, SpriteSheetSet.DEFAULT_REL_PATH_IN_SOURCE);
if (!drawable.exists()) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected AT source root folder does not contain the \"drawable\" folder.</font></html>");
this.okButton.setEnabled(false);
return;
}
File xml = new File(sourceFolder, TMXMapSet.DEFAULT_REL_PATH_IN_SOURCE);
if (!xml.exists()) {
errorLabel.setText("<html><font color=\"#FF0000\">The selected AT source root folder does not contain the \"xml\" folder.</font></html>");
this.okButton.setEnabled(false);
return;
}
}
if (!projFolder.exists() && sourceFolder.exists()) {
errorLabel.setText("<html><font color=\"#00AA00\">Everything looks good !</font></html>");
this.okButton.setEnabled(true);
return;
}
}
}

View File

@@ -0,0 +1,739 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JTree;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import com.gpl.rpg.andorstrainer.AndorsTrainer;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.gpl.rpg.atcontentstudio.model.saves.SavedGame;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
import com.jidesoft.swing.TreeSearchable;
public class ProjectsTree extends JPanel {
private static final long serialVersionUID = 6332593891796576708L;
private JTree projectsTree;
private JPopupMenu popupMenu;
private Thread konamiTimeout = null;
private boolean exit = false;
private int timeout = 200;
private Integer[] konamiBuffer = new Integer[]{null, null, null, null, null, null, null, null, null, null};
private boolean konamiCodeEntered = false;
public ProjectsTree() {
super();
setLayout(new BorderLayout());
projectsTree = new JTree(new ProjectsTreeModel());
new TreeSearchable(projectsTree){
@Override
protected String convertElementToString(Object object) {
return ((ProjectTreeNode)((TreePath)object).getLastPathComponent()).getDesc();
}
};
add(projectsTree, BorderLayout.CENTER);
projectsTree.setRootVisible(false);
projectsTree.setShowsRootHandles(true);
projectsTree.setExpandsSelectedPaths(true);
popupMenu = new JPopupMenu();
makePopupMenu();
projectsTree.setCellRenderer(new ProjectsTreeCellRenderer());
projectsTree.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (projectsTree.getSelectionPath() != null) {
itemAction((ProjectTreeNode) projectsTree.getSelectionPath().getLastPathComponent());
}
} else {
if (konamiTimeout == null) {
startKonamiCount();
}
int i = 0;
while (i < konamiBuffer.length && konamiBuffer[i] != null) {
i++;
}
if (i < konamiBuffer.length) {
konamiBuffer[i] = e.getKeyCode();
if (!compareBuffers()) {
exit = true;
} else {
resetTimeout();
}
}
}
}
});
projectsTree.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
popupActivated(e);
} else if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) {
TreePath path = projectsTree.getPathForLocation (e.getX(), e.getY());
projectsTree.setSelectionPath(path);
if (path != null) {
itemAction((ProjectTreeNode) path.getLastPathComponent());
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
popupActivated(e);
}
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) {
popupActivated(e);
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
popupActivated(e);
}
}
});
projectsTree.addTreeSelectionListener(new TreeSelectionListener() {
@Override
public void valueChanged(TreeSelectionEvent e) {
List<TreePath> newPaths = new ArrayList<TreePath>();
for (TreePath path : e.getPaths()) {
if (e.isAddedPath(path)) newPaths.add(path);
}
if (e.getPath() == null) {
ATContentStudio.frame.actions.selectionChanged(null, newPaths.toArray(new TreePath[newPaths.size()]));
} else {
ATContentStudio.frame.actions.selectionChanged((ProjectTreeNode) e.getPath().getLastPathComponent(), newPaths.toArray(new TreePath[newPaths.size()]));
}
}
});
}
public void makePopupMenu() {
popupMenu.removeAll();
if (ATContentStudio.frame == null || ATContentStudio.frame.actions == null) return;
WorkspaceActions actions = ATContentStudio.frame.actions;
boolean addNextSeparator = false;
if (actions.createProject.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.createProject));
}
if (actions.openProject.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.openProject));
}
if (actions.closeProject.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.closeProject));
}
if (actions.deleteProject.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.deleteProject));
}
if (addNextSeparator) {
popupMenu.add(new JSeparator());
addNextSeparator = false;
}
if (actions.saveElement.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.saveElement));
}
if (actions.deleteSelected.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.deleteSelected));
}
if (addNextSeparator) {
popupMenu.add(new JSeparator());
addNextSeparator = false;
}
if (actions.createGDE.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.createGDE));
}
if (actions.importJSON.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.importJSON));
}
if (actions.loadSave.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.loadSave));
}
if (addNextSeparator) {
popupMenu.add(new JSeparator());
addNextSeparator = false;
}
if (actions.compareItems.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.compareItems));
}
if (actions.compareNPCs.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.compareNPCs));
}
if (actions.exportProject.isEnabled()) {
addNextSeparator = true;
popupMenu.add(new JMenuItem(actions.exportProject));
}
if (addNextSeparator) {
popupMenu.add(new JSeparator());
addNextSeparator = false;
}
if (konamiCodeEntered) {
JMenuItem openTrainer = new JMenuItem("Start Andor's Trainer...");
popupMenu.add(openTrainer);
popupMenu.addSeparator();
openTrainer.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new Thread() {
public void run() {
AndorsTrainer.startApp(false);
}
}.start();
}
});
}
// if (projectsTree.getSelectionPath() == null || projectsTree.getSelectionPath().getLastPathComponent() == null) {
// JMenuItem addProject = new JMenuItem("Create project...");
// popupMenu.add(addProject);
// addProject.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// new ProjectCreationWizard().setVisible(true);
// }
// });
// popupMenu.addSeparator();
// } else if (projectsTree.getSelectionPaths().length > 1) {
// boolean deleteAll = false;
// final List<GameDataElement> elementsToDelete = new ArrayList<GameDataElement>();
// for (TreePath selected : projectsTree.getSelectionPaths()) {
// if (selected.getLastPathComponent() instanceof GameDataElement && ((GameDataElement)selected.getLastPathComponent()).writable) {
// elementsToDelete.add((GameDataElement) selected.getLastPathComponent());
// deleteAll = true;
// } else {
// deleteAll = false;
// break;
// }
// }
// if (deleteAll) {
// JMenuItem deleteItems = new JMenuItem("Delete all selected elements");
// popupMenu.add(deleteItems);
// deleteItems.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// final Map<GameDataCategory<JSONElement>, Set<File>> impactedCategories = new IdentityHashMap<GameDataCategory<JSONElement>, Set<File>>();
// for (GameDataElement element : elementsToDelete) {
// ATContentStudio.frame.closeEditor(element);
// element.childrenRemoved(new ArrayList<ProjectTreeNode>());
// if (element instanceof JSONElement) {
// @SuppressWarnings("unchecked")
// GameDataCategory<JSONElement> category = (GameDataCategory<JSONElement>) element.getParent();
// category.remove(element);
// if (impactedCategories.get(category) == null) {
// impactedCategories.put(category, new HashSet<File>());
// }
// impactedCategories.get(category).add(((JSONElement) element).jsonFile);
// } else if (element instanceof TMXMap) {
// TMXMapSet parent = (TMXMapSet) element.getParent();
// parent.tmxMaps.remove(element);
// }
// }
// new Thread() {
// @Override
// public void run() {
// final List<SaveEvent> events = new ArrayList<SaveEvent>();
// List<SaveEvent> catEvents = null;
// for (GameDataCategory<JSONElement> category : impactedCategories.keySet()) {
// for (File f : impactedCategories.get(category)) {
// catEvents = category.attemptSave(true, f.getName());
// if (catEvents.isEmpty()) {
// category.save(f);
// } else {
// events.addAll(catEvents);
// }
// }
// }
// if (!events.isEmpty()) {
// new SaveItemsWizard(events, null).setVisible(true);
// }
// }
// }.start();
// }
// });
// }
//
// popupMenu.addSeparator();
// } else {
// final ProjectTreeNode selected = (ProjectTreeNode) projectsTree.getSelectionPath().getLastPathComponent();
// if (selected instanceof Project) {
// JMenuItem closeProject = new JMenuItem("Close Project...");
// JMenuItem deleteProject = new JMenuItem("Delete Project...");
// popupMenu.add(closeProject);
// popupMenu.add(deleteProject);
// popupMenu.addSeparator();
// closeProject.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// Workspace.closeProject((Project) selected);
// }
// });
// deleteProject.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// int confirm = JOptionPane.showConfirmDialog(ProjectsTree.this, "Are you sure you wish to delete this project ?\nAll files created for it will be deleted too...", "Delete this project ?", JOptionPane.OK_CANCEL_OPTION);
// if (confirm == JOptionPane.OK_OPTION) {
// Workspace.deleteProject(((Project)projectsTree.getSelectionPath().getLastPathComponent()));
// }
// }
// });
// }
// if (selected instanceof ClosedProject) {
// JMenuItem openProject = new JMenuItem("Open Project...");
// JMenuItem deleteProject = new JMenuItem("Delete Project...");
// popupMenu.add(openProject);
// popupMenu.add(deleteProject);
// popupMenu.addSeparator();
// openProject.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// Workspace.openProject(((ClosedProject)selected));
// }
// });
// deleteProject.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// int confirm = JOptionPane.showConfirmDialog(ProjectsTree.this, "Are you sure you wish to delete this project ?\nAll files created for it will be deleted too...", "Delete this project ?", JOptionPane.OK_CANCEL_OPTION);
// if (confirm == JOptionPane.OK_OPTION) {
// Workspace.deleteProject(((ClosedProject)selected));
// }
// }
// });
// }
// if (selected.getProject() != null) {
// final Project proj = ((ProjectTreeNode)selected).getProject();
// JMenuItem createGDE = new JMenuItem("Create Game Data Element (JSON)");
// popupMenu.add(createGDE);
// createGDE.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// new JSONCreationWizard(proj).setVisible(true);
// }
// });
// JMenuItem importJson = new JMenuItem("Import JSON data");
// popupMenu.add(importJson);
// importJson.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// new JSONImportWizard(proj).setVisible(true);
// }
// });
// //TODO move somewhere else
// JMenu compareElementsMenu = new JMenu("Open comparator for...");
// JMenuItem compareItems = new JMenuItem("Items");
// compareElementsMenu.add(compareItems);
// compareItems.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// ATContentStudio.frame.editors.openEditor(new ItemsTableView(selected.getProject()));
// }
// });
// JMenuItem compareNPCs = new JMenuItem("NPCs");
// compareElementsMenu.add(compareNPCs);
// compareNPCs.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// ATContentStudio.frame.editors.openEditor(new NPCsTableView(selected.getProject()));
// }
// });
// popupMenu.add(compareElementsMenu);
//
// JMenuItem exportProjectPackage = new JMenuItem("Export project");
// exportProjectPackage.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// JFileChooser chooser = new JFileChooser() {
// private static final long serialVersionUID = 8039332384370636746L;
// public boolean accept(File f) {
// return f.isDirectory() || f.getName().endsWith(".zip") || f.getName().endsWith(".ZIP");
// }
// };
// chooser.setMultiSelectionEnabled(false);
// int result = chooser.showSaveDialog(ATContentStudio.frame);
// if (result == JFileChooser.APPROVE_OPTION) {
// selected.getProject().generateExportPackage(chooser.getSelectedFile());
// }
// }
// });
// popupMenu.add(exportProjectPackage);
// popupMenu.addSeparator();
// }
// if (selected instanceof GameDataElement) {
// final GameDataElement node = ((GameDataElement)selected);
// if (node.state == GameDataElement.State.modified){
// JMenuItem saveItem = new JMenuItem("Save this element");
// saveItem.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// node.save();
// ATContentStudio.frame.nodeChanged(node);
// }
// });
// popupMenu.add(saveItem);
// }
//
// JMenuItem deleteItem = null;
// if (node.getDataType() == GameSource.Type.created) {
// deleteItem = new JMenuItem("Delete this element");
// } else if (node.getDataType() == GameSource.Type.altered) {
// deleteItem = new JMenuItem("Revert to original");
// }
// if (deleteItem != null) {
// popupMenu.add(deleteItem);
// deleteItem.addActionListener(new ActionListener() {
// @SuppressWarnings("unchecked")
// @Override
// public void actionPerformed(ActionEvent e) {
// ATContentStudio.frame.closeEditor(node);
// new Thread() {
// @Override
// public void run() {
// node.childrenRemoved(new ArrayList<ProjectTreeNode>());
// if (node.getParent() instanceof GameDataCategory<?>) {
// ((GameDataCategory<?>)node.getParent()).remove(node);
// List<SaveEvent> events = node.attemptSave();
// if (events == null || events.isEmpty()) {
// node.save();
// } else {
// new SaveItemsWizard(events, null).setVisible(true);
// }
// }
// }
// }.start();
// }
// });
// }
// popupMenu.addSeparator();
//
// }
// if (selected instanceof Project || selected instanceof SavedGamesSet) {
// JMenuItem addSave = new JMenuItem("Load saved game...");
// popupMenu.add(addSave);
// popupMenu.addSeparator();
// addSave.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// JFileChooser chooser = new JFileChooser("Select an Andor's Trail save file");
// if (chooser.showOpenDialog(ATContentStudio.frame) == JFileChooser.APPROVE_OPTION) {
// selected.getProject().addSave(chooser.getSelectedFile());
// selected.getProject().save();
// }
// }
// });
//
// }
// }
// if (konamiCodeEntered) {
// JMenuItem openTrainer = new JMenuItem("Start Andor's Trainer...");
// popupMenu.add(openTrainer);
// popupMenu.addSeparator();
// openTrainer.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// new Thread() {
// public void run() {
// AndorsTrainer.startApp(false);
// }
// }.start();
// }
// });
// }
// JMenu changeLaF = new JMenu("Change Look and Feel");
// for (final LookAndFeelInfo i : UIManager.getInstalledLookAndFeels()) {
// final JMenuItem lafItem = new JMenuItem("Switch to "+i.getName());
// changeLaF.add(lafItem);
// lafItem.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// try {
// UIManager.setLookAndFeel(i.getClassName());
// SwingUtilities.updateComponentTreeUI(ATContentStudio.frame);
// ConfigCache.setFavoriteLaFClassName(i.getClassName());
// } catch (ClassNotFoundException e1) {
// e1.printStackTrace();
// } catch (InstantiationException e1) {
// e1.printStackTrace();
// } catch (IllegalAccessException e1) {
// e1.printStackTrace();
// } catch (UnsupportedLookAndFeelException e1) {
// e1.printStackTrace();
// }
// }
// });
// }
// popupMenu.add(changeLaF);
// popupMenu.addSeparator();
// JMenuItem showAbout = new JMenuItem("About...");
// popupMenu.add(showAbout);
// popupMenu.addSeparator();
// showAbout.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// ATContentStudio.frame.showAbout();
// }
// });
}
public void popupActivated(MouseEvent e) {
TreePath path = projectsTree.getPathForLocation (e.getX(), e.getY());
TreePath[] allSelected = projectsTree.getSelectionPaths();
boolean selectClickedItem = true;
if (allSelected != null) {
for (TreePath selected : allSelected) {
if (selected.equals(path)) {
selectClickedItem = false;
break;
}
}
}
if (selectClickedItem) projectsTree.setSelectionPath(path);
makePopupMenu();
if (popupMenu.getComponentCount() > 0) {
popupMenu.show(projectsTree, e.getX(), e.getY());
}
}
public void itemAction(ProjectTreeNode node) {
if (node instanceof JSONElement) {
ATContentStudio.frame.openEditor((JSONElement)node);
} else if (node instanceof Spritesheet) {
ATContentStudio.frame.openEditor((Spritesheet)node);
} else if (node instanceof TMXMap) {
ATContentStudio.frame.openEditor((TMXMap)node);
} else if (node instanceof WorldmapSegment) {
ATContentStudio.frame.openEditor((WorldmapSegment)node);
} else if (node instanceof SavedGame) {
if (konamiCodeEntered) {
ATContentStudio.frame.openEditor((SavedGame)node);
}
}
}
public class ProjectsTreeModel implements TreeModel {
public ProjectsTreeModel() {
Workspace.activeWorkspace.projectsTreeModel = this;
}
@Override
public Object getRoot() {
return Workspace.activeWorkspace;
}
@Override
public Object getChild(Object parent, int index) {
return ((ProjectTreeNode)parent).getChildAt(index);
}
@Override
public int getChildCount(Object parent) {
return ((ProjectTreeNode)parent).getChildCount();
}
@Override
public boolean isLeaf(Object node) {
return ((ProjectTreeNode)node).isLeaf();
}
@Override
public void valueForPathChanged(TreePath path, Object newValue) {
//Unused
}
public void insertNode(TreePath node) {
for (TreeModelListener l : listeners) {
l.treeNodesInserted(new TreeModelEvent(node.getLastPathComponent(), node.getParentPath().getPath(), new int[]{((ProjectTreeNode)node.getParentPath().getLastPathComponent()).getIndex((ProjectTreeNode)node.getLastPathComponent())}, new Object[]{node.getLastPathComponent()} ));
}
}
public void changeNode(TreePath node) {
for (TreeModelListener l : listeners) {
l.treeNodesChanged(new TreeModelEvent(node.getLastPathComponent(), node.getParentPath(), new int[]{((ProjectTreeNode)node.getParentPath().getLastPathComponent()).getIndex((ProjectTreeNode)node.getLastPathComponent())}, new Object[]{node.getLastPathComponent()} ));
}
}
public void removeNode(TreePath node) {
for (TreeModelListener l : listeners) {
l.treeNodesRemoved(new TreeModelEvent(node.getLastPathComponent(), node.getParentPath(), new int[]{((ProjectTreeNode)node.getParentPath().getLastPathComponent()).getIndex((ProjectTreeNode)node.getLastPathComponent())}, new Object[]{node.getLastPathComponent()} ));
}
}
@Override
public int getIndexOfChild(Object parent, Object child) {
return ((ProjectTreeNode)parent).getIndex((ProjectTreeNode) child);
}
List<TreeModelListener> listeners = new ArrayList<TreeModelListener>();
@Override
public void addTreeModelListener(TreeModelListener l) {
listeners.add(l);
}
@Override
public void removeTreeModelListener(TreeModelListener l) {
listeners.remove(l);
}
}
public class ProjectsTreeCellRenderer extends DefaultTreeCellRenderer {
private static final long serialVersionUID = 8100380694034797135L;
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
Component c = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
if (c instanceof JLabel) {
JLabel label = (JLabel)c;
String text = ((ProjectTreeNode)value).getDesc();
if (text != null) label.setText(text);
Image img = null;
if (leaf) img = ((ProjectTreeNode)value).getLeafIcon();
else if (expanded) img = ((ProjectTreeNode)value).getOpenIcon();
else img = ((ProjectTreeNode)value).getClosedIcon();
if (img != null) {
label.setIcon(new ImageIcon(img));
}
}
return c;
}
}
public void setSelectedNode(ProjectTreeNode node) {
List<TreeNode> path = new ArrayList<TreeNode>();
path.add(node);
TreeNode parent = node.getParent();
while (parent != null) {
path.add(0, parent);
parent = parent.getParent();
}
TreePath tp = new TreePath(path.toArray());
projectsTree.setSelectionPath(tp);
projectsTree.scrollPathToVisible(tp);
}
protected void startKonamiCount() {
resetTimeout();
exit = false;
konamiTimeout = new Thread() {
@Override
public void run() {
while (!exit && timeout > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
timeout -= 10;
}
konamiTimeout = null;
konamiBuffer = new Integer[]{null, null, null, null, null, null, null, null, null, null};
}
};
konamiTimeout.start();
}
protected void resetTimeout() {
timeout = 400;
}
protected boolean compareBuffers() {
if (konamiBuffer[0] == null) return true;
else if (konamiBuffer[0] != KeyEvent.VK_UP) return false;
if (konamiBuffer[1] == null) return true;
else if (konamiBuffer[1] != KeyEvent.VK_UP) return false;
if (konamiBuffer[2] == null) return true;
else if (konamiBuffer[2] != KeyEvent.VK_DOWN) return false;
if (konamiBuffer[3] == null) return true;
else if (konamiBuffer[3] != KeyEvent.VK_DOWN) return false;
if (konamiBuffer[4] == null) return true;
else if (konamiBuffer[4] != KeyEvent.VK_LEFT) return false;
if (konamiBuffer[5] == null) return true;
else if (konamiBuffer[5] != KeyEvent.VK_RIGHT) return false;
if (konamiBuffer[6] == null) return true;
else if (konamiBuffer[6] != KeyEvent.VK_LEFT) return false;
if (konamiBuffer[7] == null) return true;
else if (konamiBuffer[7] != KeyEvent.VK_RIGHT) return false;
if (konamiBuffer[8] == null) return true;
else if (konamiBuffer[8] != KeyEvent.VK_B) return false;
if (konamiBuffer[9] == null) return true;
else if (konamiBuffer[9] != KeyEvent.VK_A) return false;
konamiCodeEntered = true;
exit = true;
return true;
}
}

View File

@@ -0,0 +1,271 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
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.jidesoft.swing.JideBoxLayout;
public class SaveItemsWizard extends JDialog {
private static final long serialVersionUID = -3301878024575930527L;
List<SaveEvent> events;
JList movedToCreated;
JList movedToAltered;
JList willBeSaved;
public SaveItemsWizard(List<SaveEvent> events, GameDataElement originalRequester) {
super(ATContentStudio.frame);
this.events = events;
final List<SaveEvent> movedToAlteredList = new ArrayList<SaveEvent>();
final List<SaveEvent> movedToCreatedList = new ArrayList<SaveEvent>();
final List<SaveEvent> alsoSavedList = new ArrayList<SaveEvent>();
final List<SaveEvent> errors = new ArrayList<SaveEvent>();
for (SaveEvent event : events) {
if (event.error) {
errors.add(event);
} else {
switch (event.type) {
case alsoSave:
alsoSavedList.add(event);
break;
case moveToAltered:
movedToAlteredList.add(event);
break;
case moveToCreated:
movedToCreatedList.add(event);
break;
}
}
}
if (!errors.isEmpty()) {
setTitle("Errors in project. Cannot save.");
JPanel pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
if (originalRequester != null) {
pane.add(new JLabel(" While trying to save: "), JideBoxLayout.FIX);
JLabel origItemDesc = new JLabel();
origItemDesc.setIcon(new ImageIcon(originalRequester.getIcon()));
origItemDesc.setText(originalRequester.getDataType().toString()+"/"+originalRequester.id);
pane.add(origItemDesc, JideBoxLayout.FIX);
pane.add(new JLabel(" the following errors have been encountered and must be corrected before saving can occur: "), JideBoxLayout.FIX);
} else {
pane.add(new JLabel("After deleting element(s), the following errors have been encountered and must be coorected before saving can occur: "), JideBoxLayout.FIX);
}
movedToCreated = new JList(errors.toArray());
movedToCreated.setCellRenderer(new SaveEventsListCellRenderer());
JPanel movedToCreatedPane = new JPanel();
movedToCreatedPane.setLayout(new BorderLayout());
movedToCreatedPane.add(new JScrollPane(movedToCreated), BorderLayout.CENTER);
pane.add(movedToCreatedPane, JideBoxLayout.FLEXIBLE);
pane.add(new JPanel(), JideBoxLayout.VARY);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
JButton cancelButton = new JButton("Ok, back to work...");
buttonPane.add(cancelButton, JideBoxLayout.FIX);
pane.add(buttonPane, JideBoxLayout.FIX);
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SaveItemsWizard.this.setVisible(false);
SaveItemsWizard.this.dispose();
}
});
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
} else {
setTitle("Other elements impacted.");
JPanel pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
if (originalRequester != null) {
pane.add(new JLabel(" While trying to save: "), JideBoxLayout.FIX);
JLabel origItemDesc = new JLabel();
origItemDesc.setIcon(new ImageIcon(originalRequester.getIcon()));
origItemDesc.setText(originalRequester.getDataType().toString()+"/"+originalRequester.id);
pane.add(origItemDesc, JideBoxLayout.FIX);
pane.add(new JLabel(" the following side-effects have been identified and must be applied to the project before saving: "), JideBoxLayout.FIX);
} else {
pane.add(new JLabel("After deleting element(s), the following side-effects have been identified and must be applied to the project before saving: "), JideBoxLayout.FIX);
}
if (!movedToCreatedList.isEmpty()) {
movedToCreated = new JList(movedToCreatedList.toArray());
movedToCreated.setCellRenderer(new SaveEventsListCellRenderer());
JPanel movedToCreatedPane = new JPanel();
movedToCreatedPane.setLayout(new BorderLayout());
movedToCreatedPane.setBorder(BorderFactory.createTitledBorder("The following elements will be moved under the \"Created\" folder and saved:"));
movedToCreatedPane.add(new JScrollPane(movedToCreated), BorderLayout.CENTER);
pane.add(movedToCreatedPane, JideBoxLayout.FLEXIBLE);
}
if (!movedToAlteredList.isEmpty()) {
movedToAltered = new JList(movedToAlteredList.toArray());
movedToAltered.setCellRenderer(new SaveEventsListCellRenderer());
JPanel movedToAlteredPane = new JPanel();
movedToAlteredPane.setLayout(new BorderLayout());
movedToAlteredPane.setBorder(BorderFactory.createTitledBorder("The following elements will be moved under the \"Altered\" folder and saved:"));
movedToAlteredPane.add(new JScrollPane(movedToAltered), BorderLayout.CENTER);
pane.add(movedToAlteredPane, JideBoxLayout.FLEXIBLE);
}
if (!alsoSavedList.isEmpty()) {
willBeSaved = new JList(alsoSavedList.toArray());
willBeSaved.setCellRenderer(new SaveEventsListCellRenderer());
JPanel willBeSavedPane = new JPanel();
willBeSavedPane.setLayout(new BorderLayout());
willBeSavedPane.setBorder(BorderFactory.createTitledBorder("The following elements will be saved too:"));
willBeSavedPane.add(new JScrollPane(willBeSaved), BorderLayout.CENTER);
pane.add(willBeSavedPane, JideBoxLayout.FLEXIBLE);
}
pane.add(new JPanel(), JideBoxLayout.VARY);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS, 6));
buttonPane.add(new JPanel(), JideBoxLayout.VARY);
JButton cancelButton = new JButton("Cancel");
buttonPane.add(cancelButton, JideBoxLayout.FIX);
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SaveItemsWizard.this.setVisible(false);
SaveItemsWizard.this.dispose();
}
});
JButton okButton = new JButton("Apply all changes and save");
buttonPane.add(okButton, JideBoxLayout.FIX);
pane.add(buttonPane, JideBoxLayout.FIX);
okButton.addActionListener(new ActionListener() {
@SuppressWarnings("unchecked")
@Override
public void actionPerformed(ActionEvent e) {
Map<GameDataCategory<JSONElement>, Set<File>> jsonToSave = new IdentityHashMap<GameDataCategory<JSONElement>, Set<File>>();
for (SaveEvent event : movedToCreatedList) {
if (event.target instanceof JSONElement) {
if (!jsonToSave.containsKey(event.target.getParent())){
jsonToSave.put((GameDataCategory<JSONElement>) event.target.getParent(), new HashSet<File>());
}
jsonToSave.get((GameDataCategory<JSONElement>) event.target.getParent()).add(((JSONElement)event.target).jsonFile);
event.target.getProject().moveToCreated((JSONElement) event.target);
if (!jsonToSave.containsKey(event.target.getParent())){
jsonToSave.put((GameDataCategory<JSONElement>) event.target.getParent(), new HashSet<File>());
}
jsonToSave.get((GameDataCategory<JSONElement>) event.target.getParent()).add(((JSONElement)event.target).jsonFile);
}
//TODO movable maps, when ID is editable.
}
for (SaveEvent event : movedToAlteredList) {
if (event.target instanceof JSONElement) {
if (!jsonToSave.containsKey(event.target.getParent())){
jsonToSave.put((GameDataCategory<JSONElement>) event.target.getParent(), new HashSet<File>());
}
jsonToSave.get((GameDataCategory<JSONElement>) event.target.getParent()).add(((JSONElement)event.target).jsonFile);
event.target.getProject().moveToAltered((JSONElement) event.target);
if (!jsonToSave.containsKey(event.target.getParent())){
jsonToSave.put((GameDataCategory<JSONElement>) event.target.getParent(), new HashSet<File>());
}
jsonToSave.get((GameDataCategory<JSONElement>) event.target.getParent()).add(((JSONElement)event.target).jsonFile);
}
//TODO movable maps, when ID is editable.
}
for (SaveEvent event : alsoSavedList) {
if (event.target instanceof JSONElement) {
if (!jsonToSave.containsKey(event.target.getParent())){
jsonToSave.put((GameDataCategory<JSONElement>) event.target.getParent(), new HashSet<File>());
}
jsonToSave.get((GameDataCategory<JSONElement>) event.target.getParent()).add(((JSONElement)event.target).jsonFile);
}
}
for (GameDataCategory<JSONElement> cat : jsonToSave.keySet()) {
if (jsonToSave.get(cat) != null && !jsonToSave.get(cat).isEmpty()) {
for (File f : jsonToSave.get(cat)) {
cat.save(f);
}
}
}
for (SaveEvent event : movedToCreatedList) {
ATContentStudio.frame.nodeChanged(event.target);
}
for (SaveEvent event : movedToAlteredList) {
ATContentStudio.frame.nodeChanged(event.target);
}
for (SaveEvent event : alsoSavedList) {
ATContentStudio.frame.nodeChanged(event.target);
}
SaveItemsWizard.this.setVisible(false);
SaveItemsWizard.this.dispose();
}
});
getContentPane().setLayout(new BorderLayout());
getContentPane().add(pane, BorderLayout.CENTER);
}
pack();
}
public class SaveEventsListCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 5764079243906396333L;
@Override
public Component getListCellRendererComponent(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;
SaveEvent event = (SaveEvent) value;
label.setIcon(new ImageIcon(event.target.getIcon()));
if (event.error) {
label.setText(event.target.getDataType().toString()+"/"+event.target.id+": "+event.errorText);
} else {
label.setText(event.target.getDataType().toString()+"/"+event.target.id);
}
}
return c;
}
}
}

View File

@@ -0,0 +1,338 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import javax.swing.JPanel;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;
public class ScrollablePanel extends JPanel implements Scrollable, SwingConstants {
private static final long serialVersionUID = 6498229143202972325L;
public enum ScrollableSizeHint
{
NONE,
FIT,
STRETCH;
}
public enum IncrementType
{
PERCENT,
PIXELS;
}
private ScrollableSizeHint scrollableHeight = ScrollableSizeHint.NONE;
private ScrollableSizeHint scrollableWidth = ScrollableSizeHint.NONE;
private IncrementInfo horizontalBlock;
private IncrementInfo horizontalUnit;
private IncrementInfo verticalBlock;
private IncrementInfo verticalUnit;
/**
* Default constructor that uses a FlowLayout
*/
public ScrollablePanel()
{
this( new FlowLayout() );
}
/**
* Constuctor for specifying the LayoutManager of the panel.
*
* @param layout the LayountManger for the panel
*/
public ScrollablePanel(LayoutManager layout)
{
super( layout );
IncrementInfo block = new IncrementInfo(IncrementType.PERCENT, 100);
IncrementInfo unit = new IncrementInfo(IncrementType.PERCENT, 10);
setScrollableBlockIncrement(HORIZONTAL, block);
setScrollableBlockIncrement(VERTICAL, block);
setScrollableUnitIncrement(HORIZONTAL, unit);
setScrollableUnitIncrement(VERTICAL, unit);
}
/**
* Get the height ScrollableSizeHint enum
*
* @return the ScrollableSizeHint enum for the height
*/
public ScrollableSizeHint getScrollableHeight()
{
return scrollableHeight;
}
/**
* Set the ScrollableSizeHint enum for the height. The enum is used to
* determine the boolean value that is returned by the
* getScrollableTracksViewportHeight() method. The valid values are:
*
* ScrollableSizeHint.NONE - return "false", which causes the height
* of the panel to be used when laying out the children
* ScrollableSizeHint.FIT - return "true", which causes the height of
* the viewport to be used when laying out the children
* ScrollableSizeHint.STRETCH - return "true" when the viewport height
* is greater than the height of the panel, "false" otherwise.
*
* @param scrollableHeight as represented by the ScrollableSizeHint enum.
*/
public void setScrollableHeight(ScrollableSizeHint scrollableHeight)
{
this.scrollableHeight = scrollableHeight;
revalidate();
}
/**
* Get the width ScrollableSizeHint enum
*
* @return the ScrollableSizeHint enum for the width
*/
public ScrollableSizeHint getScrollableWidth()
{
return scrollableWidth;
}
/**
* Set the ScrollableSizeHint enum for the width. The enum is used to
* determine the boolean value that is returned by the
* getScrollableTracksViewportWidth() method. The valid values are:
*
* ScrollableSizeHint.NONE - return "false", which causes the width
* of the panel to be used when laying out the children
* ScrollableSizeHint.FIT - return "true", which causes the width of
* the viewport to be used when laying out the children
* ScrollableSizeHint.STRETCH - return "true" when the viewport width
* is greater than the width of the panel, "false" otherwise.
*
* @param scrollableWidth as represented by the ScrollableSizeHint enum.
*/
public void setScrollableWidth(ScrollableSizeHint scrollableWidth)
{
this.scrollableWidth = scrollableWidth;
revalidate();
}
/**
* Get the block IncrementInfo for the specified orientation
*
* @return the block IncrementInfo for the specified orientation
*/
public IncrementInfo getScrollableBlockIncrement(int orientation)
{
return orientation == SwingConstants.HORIZONTAL ? horizontalBlock : verticalBlock;
}
/**
* Specify the information needed to do block scrolling.
*
* @param orientation specify the scrolling orientation. Must be either:
* SwingContants.HORIZONTAL or SwingContants.VERTICAL.
* @paran type specify how the amount parameter in the calculation of
* the scrollable amount. Valid values are:
* IncrementType.PERCENT - treat the amount as a % of the viewport size
* IncrementType.PIXEL - treat the amount as the scrollable amount
* @param amount a value used with the IncrementType to determine the
* scrollable amount
*/
public void setScrollableBlockIncrement(int orientation, IncrementType type, int amount)
{
IncrementInfo info = new IncrementInfo(type, amount);
setScrollableBlockIncrement(orientation, info);
}
/**
* Specify the information needed to do block scrolling.
*
* @param orientation specify the scrolling orientation. Must be either:
* SwingContants.HORIZONTAL or SwingContants.VERTICAL.
* @param info An IncrementInfo object containing information of how to
* calculate the scrollable amount.
*/
public void setScrollableBlockIncrement(int orientation, IncrementInfo info)
{
switch(orientation)
{
case SwingConstants.HORIZONTAL:
horizontalBlock = info;
break;
case SwingConstants.VERTICAL:
verticalBlock = info;
break;
default:
throw new IllegalArgumentException("Invalid orientation: " + orientation);
}
}
/**
* Get the unit IncrementInfo for the specified orientation
*
* @return the unit IncrementInfo for the specified orientation
*/
public IncrementInfo getScrollableUnitIncrement(int orientation)
{
return orientation == SwingConstants.HORIZONTAL ? horizontalUnit : verticalUnit;
}
/**
* Specify the information needed to do unit scrolling.
*
* @param orientation specify the scrolling orientation. Must be either:
* SwingContants.HORIZONTAL or SwingContants.VERTICAL.
* @paran type specify how the amount parameter in the calculation of
* the scrollable amount. Valid values are:
* IncrementType.PERCENT - treat the amount as a % of the viewport size
* IncrementType.PIXEL - treat the amount as the scrollable amount
* @param amount a value used with the IncrementType to determine the
* scrollable amount
*/
public void setScrollableUnitIncrement(int orientation, IncrementType type, int amount)
{
IncrementInfo info = new IncrementInfo(type, amount);
setScrollableUnitIncrement(orientation, info);
}
/**
* Specify the information needed to do unit scrolling.
*
* @param orientation specify the scrolling orientation. Must be either:
* SwingContants.HORIZONTAL or SwingContants.VERTICAL.
* @param info An IncrementInfo object containing information of how to
* calculate the scrollable amount.
*/
public void setScrollableUnitIncrement(int orientation, IncrementInfo info)
{
switch(orientation)
{
case SwingConstants.HORIZONTAL:
horizontalUnit = info;
break;
case SwingConstants.VERTICAL:
verticalUnit = info;
break;
default:
throw new IllegalArgumentException("Invalid orientation: " + orientation);
}
}
//Implement Scrollable interface
public Dimension getPreferredScrollableViewportSize()
{
return getPreferredSize();
}
public int getScrollableUnitIncrement(
Rectangle visible, int orientation, int direction)
{
switch(orientation)
{
case SwingConstants.HORIZONTAL:
return getScrollableIncrement(horizontalUnit, visible.width);
case SwingConstants.VERTICAL:
return getScrollableIncrement(verticalUnit, visible.height);
default:
throw new IllegalArgumentException("Invalid orientation: " + orientation);
}
}
public int getScrollableBlockIncrement(
Rectangle visible, int orientation, int direction)
{
switch(orientation)
{
case SwingConstants.HORIZONTAL:
return getScrollableIncrement(horizontalBlock, visible.width);
case SwingConstants.VERTICAL:
return getScrollableIncrement(verticalBlock, visible.height);
default:
throw new IllegalArgumentException("Invalid orientation: " + orientation);
}
}
protected int getScrollableIncrement(IncrementInfo info, int distance)
{
if (info.getIncrement() == IncrementType.PIXELS)
return info.getAmount();
else
return distance * info.getAmount() / 100;
}
public boolean getScrollableTracksViewportWidth()
{
if (scrollableWidth == ScrollableSizeHint.NONE)
return false;
if (scrollableWidth == ScrollableSizeHint.FIT)
return true;
// STRETCH sizing, use the greater of the panel or viewport width
if (getParent() instanceof JViewport)
{
return (((JViewport)getParent()).getWidth() > getPreferredSize().width);
}
return false;
}
public boolean getScrollableTracksViewportHeight()
{
if (scrollableHeight == ScrollableSizeHint.NONE)
return false;
if (scrollableHeight == ScrollableSizeHint.FIT)
return true;
// STRETCH sizing, use the greater of the panel or viewport height
if (getParent() instanceof JViewport)
{
return (((JViewport)getParent()).getHeight() > getPreferredSize().height);
}
return false;
}
/**
* Helper class to hold the information required to calculate the scroll amount.
*/
static class IncrementInfo
{
private IncrementType type;
private int amount;
public IncrementInfo(IncrementType type, int amount)
{
this.type = type;
this.amount = amount;
}
public IncrementType getIncrement()
{
return type;
}
public int getAmount()
{
return amount;
}
public String toString()
{
return
"ScrollablePanel[" +
type + ", " +
amount + "]";
}
}
}

View File

@@ -0,0 +1,239 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.ConfigCache;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
import com.gpl.rpg.atcontentstudio.model.saves.SavedGame;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
public class StudioFrame extends JFrame {
private static final long serialVersionUID = -3391514100319186661L;
final ProjectsTree projectTree;
final EditorsArea editors;
final WorkspaceActions actions = new WorkspaceActions();
public StudioFrame(String name) {
super(name);
setIconImage(DefaultIcons.getMainIconImage());
final JSplitPane topDown = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
final JSplitPane leftRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
JList notifs = new NotificationsPane();
projectTree = new ProjectsTree();
editors = new EditorsArea();
setJMenuBar(new JMenuBar());
buildMenu();
JScrollPane treeScroller = new JScrollPane(projectTree);
treeScroller.getVerticalScrollBar().setUnitIncrement(16);
leftRight.setLeftComponent(treeScroller);
leftRight.setRightComponent(editors);
leftRight.setName("StudioFrame.leftRight");
topDown.setTopComponent(leftRight);
JScrollPane notifScroller = new JScrollPane(notifs);
notifScroller.getVerticalScrollBar().setUnitIncrement(16);
topDown.setBottomComponent(notifScroller);
topDown.setName("StudioFrame.topDown");
getContentPane().setLayout(new BorderLayout());
getContentPane().add(topDown, BorderLayout.CENTER);
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
Workspace.activeWorkspace.preferences.windowSize = StudioFrame.this.getSize();
}
});
pack();
if (Workspace.activeWorkspace.preferences.windowSize != null) {
setSize(Workspace.activeWorkspace.preferences.windowSize);
} else {
setSize(800, 600);
}
if (Workspace.activeWorkspace.preferences.splittersPositions.get(topDown.getName()) != null) {
topDown.setDividerLocation(Workspace.activeWorkspace.preferences.splittersPositions.get(topDown.getName()));
} else {
topDown.setDividerLocation(0.2);
}
topDown.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
Workspace.activeWorkspace.preferences.splittersPositions.put(topDown.getName(), topDown.getDividerLocation());
}
});
if (Workspace.activeWorkspace.preferences.splittersPositions.get(leftRight.getName()) != null) {
leftRight.setDividerLocation(Workspace.activeWorkspace.preferences.splittersPositions.get(leftRight.getName()));
} else {
leftRight.setDividerLocation(0.3);
}
leftRight.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
Workspace.activeWorkspace.preferences.splittersPositions.put(leftRight.getName(), leftRight.getDividerLocation());
}
});
showAbout();
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
Workspace.saveActive();
}
});
}
private void buildMenu() {
JMenu fileMenu = new JMenu("File");
fileMenu.add(new JMenuItem(actions.createProject));
fileMenu.add(new JMenuItem(actions.openProject));
fileMenu.add(new JMenuItem(actions.closeProject));
fileMenu.add(new JMenuItem(actions.deleteProject));
fileMenu.add(new JSeparator());
fileMenu.add(new JMenuItem(actions.exitATCS));
getJMenuBar().add(fileMenu);
JMenu projectMenu = new JMenu("Project");
projectMenu.add(new JMenuItem(actions.saveElement));
projectMenu.add(new JMenuItem(actions.deleteSelected));
projectMenu.add(new JSeparator());
projectMenu.add(new JMenuItem(actions.createGDE));
projectMenu.add(new JMenuItem(actions.importJSON));
projectMenu.add(new JMenuItem(actions.loadSave));
getJMenuBar().add(projectMenu);
JMenu toolsMenu = new JMenu("Tools");
toolsMenu.add(new JMenuItem(actions.compareItems));
toolsMenu.add(new JMenuItem(actions.compareNPCs));
toolsMenu.add(new JSeparator());
toolsMenu.add(new JMenuItem(actions.exportProject));
getJMenuBar().add(toolsMenu);
JMenu viewMenu = new JMenu("View");
JMenu changeLaF = new JMenu("Change Look and Feel");
for (final LookAndFeelInfo i : UIManager.getInstalledLookAndFeels()) {
final JMenuItem lafItem = new JMenuItem("Switch to "+i.getName());
changeLaF.add(lafItem);
lafItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
UIManager.setLookAndFeel(i.getClassName());
SwingUtilities.updateComponentTreeUI(ATContentStudio.frame);
ConfigCache.setFavoriteLaFClassName(i.getClassName());
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
}
});
}
viewMenu.add(changeLaF);
viewMenu.add(new JSeparator());
viewMenu.add(new JMenuItem(actions.showAbout));
getJMenuBar().add(viewMenu);
}
public void openEditor(JSONElement node) {
node.link();
editors.openEditor(node);
}
public void openEditor(Spritesheet node) {
editors.openEditor(node);
}
public void openEditor(TMXMap node) {
node.parse();
editors.openEditor(node);
}
public void openEditor(GameDataElement node) {
if (node instanceof JSONElement) {
openEditor((JSONElement) node);
} else if (node instanceof Spritesheet) {
openEditor((Spritesheet) node);
} else if (node instanceof TMXMap) {
openEditor((TMXMap) node);
}
}
public void openEditor(SavedGame save) {
editors.openEditor(save);
}
public void openEditor(WorldmapSegment node) {
editors.openEditor(node);
}
public void closeEditor(ProjectTreeNode node) {
editors.closeEditor(node);
}
public void selectInTree(ProjectTreeNode node) {
projectTree.setSelectedNode(node);
}
public void editorChanged(Editor e) {
editors.editorTabChanged(e);
}
public void editorChanged(ProjectTreeNode node) {
editors.editorTabChanged(node);
}
public void nodeChanged(ProjectTreeNode node) {
node.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(node);
}
public void showAbout() {
editors.showAbout();
}
}

View File

@@ -0,0 +1,53 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Toolkit;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import com.jidesoft.swing.JideBoxLayout;
public class WorkerDialog extends JDialog {
private static final long serialVersionUID = 8239669104275145995L;
private WorkerDialog(String message, Frame parent) {
super(parent, "Loading...");
this.setIconImage(DefaultIcons.getMainIconImage());
this.getContentPane().setLayout(new JideBoxLayout(this.getContentPane(), JideBoxLayout.PAGE_AXIS, 6));
this.getContentPane().add(new JLabel("<html><font size=5>Please wait.<br/>"+message+"</font></html>"), JideBoxLayout.VARY);
JMovingIdler idler = new JMovingIdler();
idler.setBackground(Color.WHITE);
idler.setForeground(Color.GREEN);
idler.start();
this.getContentPane().add(idler, JideBoxLayout.FIX);
this.pack();
Dimension sdim = Toolkit.getDefaultToolkit().getScreenSize();
Dimension wdim = this.getSize();
idler.setPreferredSize(new Dimension(wdim.width, 10));
this.pack();
wdim = this.getSize();
this.setLocation((sdim.width - wdim.width)/2, (sdim.height - wdim.height)/2);
this.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
}
public static void showTaskMessage(String message, Frame parent, Runnable workload) {
showTaskMessage(message, parent, false, workload);
}
public static void showTaskMessage(final String message, final Frame parent, final boolean showConfirm, final Runnable workload) {
new Thread() {
public void run() {
WorkerDialog info = new WorkerDialog(message, parent);
info.setVisible(true);
workload.run();
info.dispose();
if (showConfirm) JOptionPane.showMessageDialog(parent, "<html><font size=5>Done !</font></html>");
};
}.start();
}
}

View File

@@ -0,0 +1,389 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.Action;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.tree.TreePath;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.ClosedProject;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.SaveEvent;
import com.gpl.rpg.atcontentstudio.model.Workspace;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataCategory;
import com.gpl.rpg.atcontentstudio.model.gamedata.JSONElement;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMapSet;
import com.gpl.rpg.atcontentstudio.model.saves.SavedGamesSet;
import com.gpl.rpg.atcontentstudio.ui.tools.ItemsTableView;
import com.gpl.rpg.atcontentstudio.ui.tools.NPCsTableView;
public class WorkspaceActions {
ProjectTreeNode selectedNode = null;
TreePath[] selectedPaths = null;
public ATCSAction createProject = new ATCSAction("Create project...", "Opens the project creation wizard") {
public void actionPerformed(ActionEvent e) {
new ProjectCreationWizard().setVisible(true);
};
};
public ATCSAction closeProject = new ATCSAction("Close project", "Closes the project, unloading all resources from memory") {
public void actionPerformed(ActionEvent e) {
if (!(selectedNode instanceof Project)) return;
Workspace.closeProject((Project) selectedNode);
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode instanceof Project);
};
};
public ATCSAction openProject = new ATCSAction("Open project", "Opens the project, loading all necessary resources in memory") {
public void actionPerformed(ActionEvent e) {
if (!(selectedNode instanceof ClosedProject)) return;
Workspace.openProject((ClosedProject) selectedNode);
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode instanceof ClosedProject);
};
};
public ATCSAction deleteProject = new ATCSAction("Delete project", "Deletes the project, and all created/altered data, from disk") {
public void actionPerformed(ActionEvent e) {
if (selectedNode instanceof Project) {
if (JOptionPane.showConfirmDialog(ATContentStudio.frame, "Are you sure you wish to delete this project ?\nAll files created for it will be deleted too...", "Delete this project ?", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
Workspace.deleteProject((Project)selectedNode);
}
} else if (selectedNode instanceof ClosedProject) {
if (JOptionPane.showConfirmDialog(ATContentStudio.frame, "Are you sure you wish to delete this project ?\nAll files created for it will be deleted too...", "Delete this project ?", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
Workspace.deleteProject((ClosedProject)selectedNode);
}
}
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode instanceof Project || selectedNode instanceof ClosedProject);
};
};
public ATCSAction saveElement = new ATCSAction("Save this element", "Saves the current state of this element on disk"){
public void actionPerformed(ActionEvent e) {
if (!(selectedNode instanceof GameDataElement)) return;
final GameDataElement node = ((GameDataElement)selectedNode);
if (node.state == GameDataElement.State.modified){
node.save();
ATContentStudio.frame.nodeChanged(node);
}
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
if (selectedNode instanceof GameDataElement) {
setEnabled(((GameDataElement)selectedNode).state == GameDataElement.State.modified);
} else {
setEnabled(false);
}
};
};
public ATCSAction deleteSelected = new ATCSAction("Delete", "Deletes the selected items") {
boolean multiMode = false;
List<GameDataElement> elementsToDelete = null;
public void init() {
putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
};
public void actionPerformed(ActionEvent e) {
if (multiMode) {
if (elementsToDelete == null) return;
final Map<GameDataCategory<JSONElement>, Set<File>> impactedCategories = new IdentityHashMap<GameDataCategory<JSONElement>, Set<File>>();
for (GameDataElement element : elementsToDelete) {
ATContentStudio.frame.closeEditor(element);
element.childrenRemoved(new ArrayList<ProjectTreeNode>());
if (element instanceof JSONElement) {
@SuppressWarnings("unchecked")
GameDataCategory<JSONElement> category = (GameDataCategory<JSONElement>) element.getParent();
category.remove(element);
if (impactedCategories.get(category) == null) {
impactedCategories.put(category, new HashSet<File>());
}
impactedCategories.get(category).add(((JSONElement) element).jsonFile);
} else if (element instanceof TMXMap) {
TMXMapSet parent = (TMXMapSet) element.getParent();
parent.tmxMaps.remove(element);
}
}
new Thread() {
@Override
public void run() {
final List<SaveEvent> events = new ArrayList<SaveEvent>();
List<SaveEvent> catEvents = null;
for (GameDataCategory<JSONElement> category : impactedCategories.keySet()) {
for (File f : impactedCategories.get(category)) {
catEvents = category.attemptSave(true, f.getName());
if (catEvents.isEmpty()) {
category.save(f);
} else {
events.addAll(catEvents);
}
}
}
if (!events.isEmpty()) {
new SaveItemsWizard(events, null).setVisible(true);
}
}
}.start();
} else {
if (!(selectedNode instanceof GameDataElement)) return;
final GameDataElement node = ((GameDataElement)selectedNode);
ATContentStudio.frame.closeEditor(node);
new Thread() {
@Override
public void run() {
node.childrenRemoved(new ArrayList<ProjectTreeNode>());
if (node.getParent() instanceof GameDataCategory<?>) {
((GameDataCategory<?>)node.getParent()).remove(node);
List<SaveEvent> events = node.attemptSave();
if (events == null || events.isEmpty()) {
node.save();
} else {
new SaveItemsWizard(events, null).setVisible(true);
}
}
}
}.start();
}
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
elementsToDelete = null;
if (selectedPaths != null && selectedPaths.length > 1) {
multiMode = false;
elementsToDelete = new ArrayList<GameDataElement>();
for (TreePath selected : selectedPaths) {
if (selected.getLastPathComponent() instanceof GameDataElement && ((GameDataElement)selected.getLastPathComponent()).writable) {
elementsToDelete.add((GameDataElement) selected.getLastPathComponent());
multiMode = true;
} else {
multiMode = false;
break;
}
}
putValue(Action.NAME, "Delete all selected elements");
setEnabled(multiMode);
} else if (selectedNode instanceof GameDataElement && ((GameDataElement)selectedNode).writable) {
multiMode = false;
if (selectedNode.getDataType() == GameSource.Type.created) {
putValue(Action.NAME, "Delete this element");
setEnabled(true);
} else if (selectedNode.getDataType() == GameSource.Type.altered) {
putValue(Action.NAME, "Revert to original");
setEnabled(true);
} else {
setEnabled(false);
}
} else {
setEnabled(false);
}
};
};
public ATCSAction createGDE = new ATCSAction("Create Game Data Element (JSON)", "Opens the game object creation wizard") {
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
new JSONCreationWizard(selectedNode.getProject()).setVisible(true);
}
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode != null && selectedNode.getProject() != null);
}
};
public ATCSAction importJSON = new ATCSAction("Import JSON data", "Opens the JSON import wizard") {
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
new JSONImportWizard(selectedNode.getProject()).setVisible(true);
}
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode != null && selectedNode.getProject() != null);
}
};
public ATCSAction loadSave = new ATCSAction("Load saved game...", "Opens the saved game loading wizard"){
public void actionPerformed(ActionEvent e) {
if(!(selectedNode instanceof Project || selectedNode instanceof SavedGamesSet)) return;
JFileChooser chooser = new JFileChooser("Select an Andor's Trail save file");
if (chooser.showOpenDialog(ATContentStudio.frame) == JFileChooser.APPROVE_OPTION) {
selectedNode.getProject().addSave(chooser.getSelectedFile());
selectedNode.getProject().save();
}
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode instanceof Project || selectedNode instanceof SavedGamesSet);
};
};
public ATCSAction compareItems = new ATCSAction("Items comparator", "Opens an editor showing all the items of the project in a table"){
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
ATContentStudio.frame.editors.openEditor(new ItemsTableView(selectedNode.getProject()));
}
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode != null && selectedNode.getProject() != null);
}
};
public ATCSAction compareNPCs = new ATCSAction("NPCs comparator", "Opens an editor showing all the NPCs of the project in a table"){
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
ATContentStudio.frame.editors.openEditor(new NPCsTableView(selectedNode.getProject()));
}
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode != null && selectedNode.getProject() != null);
}
};
public ATCSAction exportProject = new ATCSAction("Export project", "Generates a zip file containing all the created & altered resources of the project, ready to merge with the game source."){
public void actionPerformed(ActionEvent e) {
if (selectedNode == null || selectedNode.getProject() == null) return;
JFileChooser chooser = new JFileChooser() {
private static final long serialVersionUID = 8039332384370636746L;
public boolean accept(File f) {
return f.isDirectory() || f.getName().endsWith(".zip") || f.getName().endsWith(".ZIP");
}
};
chooser.setMultiSelectionEnabled(false);
int result = chooser.showSaveDialog(ATContentStudio.frame);
if (result == JFileChooser.APPROVE_OPTION) {
File f = chooser.getSelectedFile();
if (!f.getAbsolutePath().substring(f.getAbsolutePath().length() - 4, f.getAbsolutePath().length()).equalsIgnoreCase(".zip")) {
f = new File(f.getAbsolutePath()+".zip");
}
selectedNode.getProject().generateExportPackage(f);
}
};
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) {
setEnabled(selectedNode != null && selectedNode.getProject() != null);
};
};
public ATCSAction showAbout = new ATCSAction("About...", "Displays credits and other informations about ATCS"){
public void actionPerformed(ActionEvent e) {
ATContentStudio.frame.showAbout();
};
};
public ATCSAction exitATCS = new ATCSAction("Exit", "Closes the program"){
public void actionPerformed(ActionEvent e) {
//TODO ouch.
System.exit(0);
};
};
List<ATCSAction> actions = new ArrayList<WorkspaceActions.ATCSAction>();
public WorkspaceActions() {
actions.add(createProject);
actions.add(closeProject);
actions.add(openProject);
actions.add(deleteProject);
actions.add(saveElement);
actions.add(deleteSelected);
actions.add(createGDE);
actions.add(importJSON);
actions.add(loadSave);
actions.add(compareItems);
actions.add(compareNPCs);
actions.add(exportProject);
actions.add(showAbout);
actions.add(exitATCS);
selectionChanged(null, null);
}
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths){
this.selectedNode = selectedNode;
this.selectedPaths = selectedPaths;
synchronized(actions) {
for (ATCSAction action : actions) {
action.selectionChanged(selectedNode, selectedPaths);
}
}
}
public static class ATCSAction implements Action {
boolean enabled = true;
public ATCSAction(String name, String desc) {
putValue(Action.NAME, name);
putValue(Action.SHORT_DESCRIPTION, desc);
init();
}
public void init(){}
public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths){}
@Override
public void actionPerformed(ActionEvent e) {};
public Map<String, Object> values = new HashMap<String, Object>();
@Override
public Object getValue(String key) {
return values.get(key);
}
@Override
public void putValue(String key, Object value) {
PropertyChangeEvent event = new PropertyChangeEvent(this, key, values.get(key), value);
values.put(key, value);
for (PropertyChangeListener l : listeners) {
l.propertyChange(event);
}
}
@Override
public void setEnabled(boolean b) {
PropertyChangeEvent event = new PropertyChangeEvent(this, "enabled", isEnabled(), b);
enabled = b;
for (PropertyChangeListener l : listeners) {
l.propertyChange(event);
}
}
@Override
public boolean isEnabled() {
return enabled;
}
private Set<PropertyChangeListener> listeners = new HashSet<PropertyChangeListener>();
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
listeners.add(listener);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
listeners.remove(listener);
}
}
}

View File

@@ -0,0 +1,143 @@
package com.gpl.rpg.atcontentstudio.ui;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import com.gpl.rpg.atcontentstudio.ConfigCache;
public class WorkspaceSelector extends JFrame {
private static final long serialVersionUID = 7518745499760748574L;
public String selected = null;
public WorkspaceSelector() {
super("Select your workspace");
setIconImage(DefaultIcons.getMainIconImage());
//Data
final List<File> workspaces = ConfigCache.getKnownWorkspaces();
final List<String> wsPaths = new ArrayList<String>();
//Active widgets declaration
final JComboBox combo = new JComboBox();
final JButton browse = new JButton("Browse...");
final JButton cancel = new JButton("Cancel");
final JButton ok = new JButton("Ok");
//Widgets behavior
combo.setEditable(true);
for (File f : workspaces) {
String path = f.getAbsolutePath();
wsPaths.add(path);
combo.addItem(path);
}
if (ConfigCache.getLatestWorkspace() != null) {
combo.setSelectedItem(wsPaths.get(workspaces.indexOf(ConfigCache.getLatestWorkspace())));
}
combo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (combo.getSelectedItem() != null) {
ok.setEnabled(true);
}
}
});
ok.setEnabled(ConfigCache.getLatestWorkspace() != null);
ok.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
WorkspaceSelector.this.selected = (String) combo.getSelectedItem();
WorkspaceSelector.this.dispose();
}
});
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
WorkspaceSelector.this.selected = null;
WorkspaceSelector.this.dispose();
}
});
browse.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fc;
if(workspaces.isEmpty()) {
fc = new JFileChooser();
} else {
if (ConfigCache.getLatestWorkspace() != null) {
fc = new JFileChooser(ConfigCache.getLatestWorkspace());
} else {
fc = new JFileChooser(workspaces.get(0));
}
}
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fc.setMultiSelectionEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int result = fc.showSaveDialog(WorkspaceSelector.this);
if (result == JFileChooser.APPROVE_OPTION) {
String selected = fc.getSelectedFile().getAbsolutePath();
for (String s : wsPaths) {
if (s.equals(selected)) {
selected = s;
}
}
combo.setSelectedItem(selected);
}
}
});
//Layout, labels and dialog behavior.
setTitle("Select your workspace");
JPanel dialogPane = new JPanel();
dialogPane.setLayout(new BorderLayout());
dialogPane.add(new JLabel("Workspace : "), BorderLayout.WEST);
dialogPane.add(combo, BorderLayout.CENTER);
dialogPane.add(browse, BorderLayout.EAST);
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.EAST;
c.gridx = 0;
c.gridy = 0;
c.weightx = 1;
buttonPane.add(new JLabel(), c);
c.fill = GridBagConstraints.VERTICAL;
c.weightx = 0;
c.gridx++;
buttonPane.add(cancel, c);
c.gridx++;
buttonPane.add(ok, c);
dialogPane.add(buttonPane, BorderLayout.SOUTH);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setContentPane(dialogPane);
setResizable(false);
}
}

View File

@@ -0,0 +1,526 @@
package com.gpl.rpg.atcontentstudio.ui.gamedataeditors;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
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.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.ui.CollapsiblePanel;
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
import com.gpl.rpg.atcontentstudio.ui.IntegerBasedCheckBox;
import com.jidesoft.swing.JideBoxLayout;
public class ActorConditionEditor extends JSONElementEditor {
private static final long serialVersionUID = 799130864545495819L;
private static final String form_view_id = "Form";
private static final String json_view_id = "JSON";
private JButton acIcon;
private JTextField idField;
private JTextField nameField;
private JComboBox categoryBox;
private IntegerBasedCheckBox positiveBox;
private IntegerBasedCheckBox stackingBox;
private JTextField roundVisualField;
private JSpinner roundHpMinField;
private JSpinner roundHpMaxField;
private JSpinner roundApMinField;
private JSpinner roundApMaxField;
private JTextField fullRoundVisualField;
private JSpinner fullRoundHpMinField;
private JSpinner fullRoundHpMaxField;
private JSpinner fullRoundApMinField;
private JSpinner fullRoundApMaxField;
private JSpinner abilityHpField;
private JSpinner abilityApField;
private JSpinner abilityMoveCost;
private JSpinner abilityUseCost;
private JSpinner abilityReequipCost;
private JSpinner abilityAttackCost;
private JSpinner abilityAttackChance;
private JSpinner abilityDamageMinField;
private JSpinner abilityDamageMaxField;
private JSpinner abilityCriticalSkill;
private JSpinner abilityBlockChance;
private JSpinner abilityDamageResistance;
public ActorConditionEditor(ActorCondition ac) {
super(ac, ac.getDesc(), ac.getIcon());
addEditorTab(form_view_id, getFormView());
addEditorTab(json_view_id, getJSONView());
}
@Override
public void insertFormViewDataField(JPanel pane) {
final ActorCondition ac = ((ActorCondition)target);
final FieldUpdateListener listener = new ActorConditionFieldUpdater();
acIcon = createButtonPane(pane, ac.getProject(), ac, ActorCondition.class, ac.getImage(), Spritesheet.Category.actorcondition, listener);
idField = addTextField(pane, "Internal ID: ", ac.id, ac.writable, listener);
nameField = addTextField(pane, "Display name: ", ac.display_name, ac.writable, listener);
categoryBox = addEnumValueBox(pane, "Category: ", ActorCondition.ACCategory.values(), ac.category, ac.writable, listener);
positiveBox = addIntegerBasedCheckBox(pane, "Positive", ac.positive, ac.writable, listener);
stackingBox = addIntegerBasedCheckBox(pane, "Stacking", ac.stacking, ac.writable, listener);
CollapsiblePanel roundEffectPane = new CollapsiblePanel("Effect every round (4s): ");
roundEffectPane.setLayout(new JideBoxLayout(roundEffectPane, JideBoxLayout.PAGE_AXIS));
final ActorCondition.RoundEffect roundEffect;
if (ac.round_effect != null) {
roundEffect = ac.round_effect;
} else {
roundEffect = new ActorCondition.RoundEffect();
}
roundVisualField = addTextField(roundEffectPane, "Visual effect ID: ", roundEffect.visual_effect, ac.writable, listener);
roundHpMinField = addIntegerField(roundEffectPane, "HP Bonus Min: ", roundEffect.hp_boost_min, true, ac.writable, listener);
roundHpMaxField = addIntegerField(roundEffectPane, "HP Bonus Max: ", roundEffect.hp_boost_max, true, ac.writable, listener);
roundApMinField = addIntegerField(roundEffectPane, "AP Bonus Min: ", roundEffect.ap_boost_min, true, ac.writable, listener);
roundApMaxField = addIntegerField(roundEffectPane, "AP Bonus Max: ", roundEffect.ap_boost_max, true, ac.writable, listener);
roundEffectPane.setExpanded(ac.round_effect != null);
pane.add(roundEffectPane, JideBoxLayout.FIX);
CollapsiblePanel fullRoundEffectPane = new CollapsiblePanel("Effect every full round (20s): ");
fullRoundEffectPane.setLayout(new JideBoxLayout(fullRoundEffectPane, JideBoxLayout.PAGE_AXIS));
final ActorCondition.RoundEffect fullRoundEffect;
if (ac.full_round_effect != null) {
fullRoundEffect = ac.full_round_effect;
} else {
fullRoundEffect = new ActorCondition.RoundEffect();
}
fullRoundVisualField = addTextField(fullRoundEffectPane, "Visual effect ID: ", fullRoundEffect.visual_effect, ac.writable, listener);
fullRoundHpMinField = addIntegerField(fullRoundEffectPane, "HP Bonus min: ", fullRoundEffect.hp_boost_min, true, ac.writable, listener);
fullRoundHpMaxField = addIntegerField(fullRoundEffectPane, "HP Bonus max: ", fullRoundEffect.hp_boost_max, true, ac.writable, listener);
fullRoundApMinField = addIntegerField(fullRoundEffectPane, "AP Bonus min: ", fullRoundEffect.ap_boost_min, true, ac.writable, listener);
fullRoundApMaxField = addIntegerField(fullRoundEffectPane, "AP Bonus max: ", fullRoundEffect.ap_boost_max, true, ac.writable, listener);
fullRoundEffectPane.setExpanded(ac.full_round_effect != null);
pane.add(fullRoundEffectPane, JideBoxLayout.FIX);
CollapsiblePanel abilityEffectPane = new CollapsiblePanel("Constant ability effect: ");
abilityEffectPane.setLayout(new JideBoxLayout(abilityEffectPane, JideBoxLayout.PAGE_AXIS));
ActorCondition.AbilityEffect abilityEffect;
if (ac.constant_ability_effect != null) {
abilityEffect = ac.constant_ability_effect;
} else {
abilityEffect = new ActorCondition.AbilityEffect();
}
abilityHpField = addIntegerField(abilityEffectPane, "Boost max HP: ", abilityEffect.max_hp_boost, true, ac.writable, listener);
abilityApField = addIntegerField(abilityEffectPane, "Boost max AP: ", abilityEffect.max_ap_boost, true, ac.writable, listener);
abilityDamageMinField = addIntegerField(abilityEffectPane, "Boost min damage: ", abilityEffect.increase_damage_min, true, ac.writable, listener);
abilityDamageMaxField = addIntegerField(abilityEffectPane, "Boost max damage: ", abilityEffect.increase_damage_max, true, ac.writable, listener);
abilityAttackChance = addIntegerField(abilityEffectPane, "Boost attack chance: ", abilityEffect.increase_attack_chance, true, ac.writable, listener);
abilityBlockChance = addIntegerField(abilityEffectPane, "Boost block chance: ", abilityEffect.increase_block_chance, true, ac.writable, listener);
abilityCriticalSkill = addIntegerField(abilityEffectPane, "Boost critical skill: ", abilityEffect.increase_critical_skill, true, ac.writable, listener);
abilityDamageResistance = addIntegerField(abilityEffectPane, "Boost damage resistance: ", abilityEffect.increase_damage_resistance, true, ac.writable, listener);
abilityMoveCost = addIntegerField(abilityEffectPane, "Increase move cost: ", abilityEffect.increase_move_cost, true, ac.writable, listener);
abilityAttackCost = addIntegerField(abilityEffectPane, "Increase attack cost: ", abilityEffect.increase_attack_cost, true, ac.writable, listener);
abilityUseCost = addIntegerField(abilityEffectPane, "Increase item use cost: ", abilityEffect.increase_use_cost, true, ac.writable, listener);
abilityReequipCost = addIntegerField(abilityEffectPane, "Increase reequip cost: ", abilityEffect.increase_reequip_cost, true, ac.writable, listener);
abilityEffectPane.setExpanded(ac.constant_ability_effect != null);
pane.add(abilityEffectPane, JideBoxLayout.FIX);
}
//TODO enhancement. Split this in smaller pieces (one for each base field, and one for each "*Effect". later, later....
public class ActorConditionFieldUpdater implements FieldUpdateListener {
@Override
public void valueChanged(JComponent source, Object value) {
ActorCondition aCond = (ActorCondition)target;
if (source == idField) {
aCond.id = (String) value;
ActorConditionEditor.this.name = aCond.getDesc();
aCond.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(ActorConditionEditor.this);
} else if (source == nameField) {
aCond.display_name = (String) value;
ActorConditionEditor.this.name = aCond.getDesc();
aCond.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(ActorConditionEditor.this);
} else if (source == acIcon) {
aCond.icon_id = (String) value;
aCond.childrenChanged(new ArrayList<ProjectTreeNode>());
ActorConditionEditor.this.icon = new ImageIcon(aCond.getProject().getIcon((String) value));
ATContentStudio.frame.editorChanged(ActorConditionEditor.this);
acIcon.setIcon(new ImageIcon(aCond.getProject().getImage((String) value)));
acIcon.revalidate();
acIcon.repaint();
} else if (source == positiveBox) {
aCond.positive = (Integer) value;
} else if (source == stackingBox) {
aCond.positive = (Integer) value;
} else if (source == categoryBox) {
aCond.category = (ActorCondition.ACCategory) value;
} else if (source == roundVisualField) {
if (value == null) {
if (aCond.round_effect != null) {
aCond.round_effect.visual_effect = null;
if (isEmpty(aCond.round_effect)) {
aCond.round_effect = null;
}
}
} else {
if (aCond.round_effect == null) {
aCond.round_effect = new ActorCondition.RoundEffect();
}
aCond.round_effect.visual_effect = (String) value;
}
} else if (source == roundHpMinField) {
if (value == null) {
if (aCond.round_effect != null) {
aCond.round_effect.hp_boost_min = null;
if (isEmpty(aCond.round_effect)) {
aCond.round_effect = null;
}
}
} else {
if (aCond.round_effect == null) {
aCond.round_effect = new ActorCondition.RoundEffect();
}
aCond.round_effect.hp_boost_min = (Integer) value;
}
} else if (source == roundHpMaxField) {
if (value == null) {
if (aCond.round_effect != null) {
aCond.round_effect.hp_boost_max = null;
if (isEmpty(aCond.round_effect)) {
aCond.round_effect = null;
}
}
} else {
if (aCond.round_effect == null) {
aCond.round_effect = new ActorCondition.RoundEffect();
}
aCond.round_effect.hp_boost_max = (Integer) value;
}
} else if (source == roundApMinField) {
if (value == null) {
if (aCond.round_effect != null) {
aCond.round_effect.ap_boost_min = null;
if (isEmpty(aCond.round_effect)) {
aCond.round_effect = null;
}
}
} else {
if (aCond.round_effect == null) {
aCond.round_effect = new ActorCondition.RoundEffect();
}
aCond.round_effect.ap_boost_min = (Integer) value;
}
} else if (source == roundApMaxField) {
if (value == null) {
if (aCond.round_effect != null) {
aCond.round_effect.ap_boost_max = null;
if (isEmpty(aCond.round_effect)) {
aCond.round_effect = null;
}
}
} else {
if (aCond.round_effect == null) {
aCond.round_effect = new ActorCondition.RoundEffect();
}
aCond.round_effect.ap_boost_max = (Integer) value;
}
} else if (source == fullRoundVisualField) {
if (value == null) {
if (aCond.full_round_effect != null) {
aCond.full_round_effect.visual_effect = null;
if (isEmpty(aCond.full_round_effect)) {
aCond.full_round_effect = null;
}
}
} else {
if (aCond.full_round_effect == null) {
aCond.full_round_effect = new ActorCondition.RoundEffect();
}
aCond.full_round_effect.visual_effect = (String) value;
}
} else if (source == fullRoundHpMinField) {
if (value == null) {
if (aCond.full_round_effect != null) {
aCond.full_round_effect.hp_boost_min = null;
if (isEmpty(aCond.full_round_effect)) {
aCond.full_round_effect = null;
}
}
} else {
if (aCond.full_round_effect == null) {
aCond.full_round_effect = new ActorCondition.RoundEffect();
}
aCond.full_round_effect.hp_boost_min = (Integer) value;
}
} else if (source == fullRoundHpMaxField) {
if (value == null) {
if (aCond.full_round_effect != null) {
aCond.full_round_effect.hp_boost_max = null;
if (isEmpty(aCond.full_round_effect)) {
aCond.full_round_effect = null;
}
}
} else {
if (aCond.full_round_effect == null) {
aCond.full_round_effect = new ActorCondition.RoundEffect();
}
aCond.full_round_effect.hp_boost_max = (Integer) value;
}
} else if (source == fullRoundApMinField) {
if (value == null) {
if (aCond.full_round_effect != null) {
aCond.full_round_effect.ap_boost_min = null;
if (isEmpty(aCond.full_round_effect)) {
aCond.full_round_effect = null;
}
}
} else {
if (aCond.full_round_effect == null) {
aCond.full_round_effect = new ActorCondition.RoundEffect();
}
aCond.full_round_effect.ap_boost_min = (Integer) value;
}
} else if (source == fullRoundApMaxField) {
if (value == null) {
if (aCond.full_round_effect != null) {
aCond.full_round_effect.ap_boost_max = null;
if (isEmpty(aCond.full_round_effect)) {
aCond.full_round_effect = null;
}
}
} else {
if (aCond.full_round_effect == null) {
aCond.full_round_effect = new ActorCondition.RoundEffect();
}
aCond.full_round_effect.ap_boost_max = (Integer) value;
}
} else if (source == abilityHpField) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.max_hp_boost = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.max_hp_boost = (Integer) value;
}
} else if (source == abilityApField) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.max_ap_boost = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.max_ap_boost = (Integer) value;
}
} else if (source == abilityMoveCost) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_move_cost = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_move_cost = (Integer) value;
}
} else if (source == abilityUseCost) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_use_cost = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_use_cost = (Integer) value;
}
} else if (source == abilityReequipCost) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_reequip_cost = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_reequip_cost = (Integer) value;
}
} else if (source == abilityAttackCost) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_attack_cost = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_attack_cost = (Integer) value;
}
} else if (source == abilityAttackChance) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_attack_chance = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_attack_chance = (Integer) value;
}
} else if (source == abilityDamageMinField) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_damage_min = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_damage_min = (Integer) value;
}
} else if (source == abilityDamageMaxField) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_damage_max = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_damage_max = (Integer) value;
}
} else if (source == abilityCriticalSkill) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_critical_skill = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_critical_skill = (Integer) value;
}
} else if (source == abilityBlockChance) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_block_chance = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_block_chance = (Integer) value;
}
} else if (source == abilityDamageResistance) {
if (value == null) {
if (aCond.constant_ability_effect != null) {
aCond.constant_ability_effect.increase_damage_resistance = null;
if (isEmpty(aCond.constant_ability_effect)) {
aCond.constant_ability_effect = null;
}
}
} else {
if (aCond.constant_ability_effect == null) {
aCond.constant_ability_effect = new ActorCondition.AbilityEffect();
}
aCond.constant_ability_effect.increase_damage_resistance = (Integer) value;
}
}
if (aCond.state != GameDataElement.State.modified) {
aCond.state = GameDataElement.State.modified;
ActorConditionEditor.this.name = aCond.getDesc();
aCond.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(ActorConditionEditor.this);
}
updateJsonViewText(aCond.toJsonString());
}
private boolean isEmpty(ActorCondition.RoundEffect round_effect) {
return round_effect == null || (
round_effect.visual_effect == null &&
round_effect.hp_boost_min == null &&
round_effect.hp_boost_max == null &&
round_effect.ap_boost_min == null &&
round_effect.ap_boost_max == null
);
}
private boolean isEmpty(ActorCondition.AbilityEffect ability_effect) {
return ability_effect == null || (
ability_effect.max_hp_boost == null &&
ability_effect.max_ap_boost == null &&
ability_effect.increase_move_cost == null &&
ability_effect.increase_use_cost == null &&
ability_effect.increase_reequip_cost == null &&
ability_effect.increase_attack_cost == null &&
ability_effect.increase_attack_chance == null &&
ability_effect.increase_damage_min == null &&
ability_effect.increase_damage_max == null &&
ability_effect.increase_critical_skill == null &&
ability_effect.increase_block_chance == null &&
ability_effect.increase_damage_resistance == null
);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,285 @@
package com.gpl.rpg.atcontentstudio.ui.gamedataeditors;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
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.JSpinner;
import javax.swing.JTextField;
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 com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist.DroppedItem;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
import com.gpl.rpg.atcontentstudio.ui.CollapsiblePanel;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
import com.jidesoft.swing.JideBoxLayout;
public class DroplistEditor extends JSONElementEditor {
private static final long serialVersionUID = 1139455254096811058L;
private static final String form_view_id = "Form";
private static final String json_view_id = "JSON";
private Droplist.DroppedItem selectedItem;
private JTextField idField;
private MyComboBox itemCombo;
private DroppedItemsListModel droppedItemsListModel;
private JSpinner qtyMinField;
private JSpinner qtyMaxField;
private JSpinner chanceField;
public DroplistEditor(Droplist droplist) {
super(droplist, droplist.getDesc(), droplist.getIcon());
addEditorTab(form_view_id, getFormView());
addEditorTab(json_view_id, getJSONView());
}
@Override
public void insertFormViewDataField(JPanel pane) {
final Droplist droplist = (Droplist)target;
final FieldUpdateListener listener = new DroplistFieldUpdater();
createButtonPane(pane, droplist.getProject(), droplist, Droplist.class, Droplist.getImage(), null, listener);
idField = addTextField(pane, "Droplist ID: ", droplist.id, droplist.writable, listener);
CollapsiblePanel itemsPane = new CollapsiblePanel("Items in this droplist: ");
itemsPane.setLayout(new JideBoxLayout(itemsPane, JideBoxLayout.PAGE_AXIS));
droppedItemsListModel = new DroppedItemsListModel(droplist);
final JList itemsList = new JList(droppedItemsListModel);
itemsList.setCellRenderer(new DroppedItemsCellRenderer());
itemsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
itemsPane.add(new JScrollPane(itemsList), JideBoxLayout.FIX);
final JPanel droppedItemsEditorPane = new JPanel();
final JButton createDroppedItem = new JButton(new ImageIcon(DefaultIcons.getCreateIcon()));
final JButton deleteDroppedItem = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
deleteDroppedItem.setEnabled(false);
itemsList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
selectedItem = (Droplist.DroppedItem) itemsList.getSelectedValue();
if (selectedItem == null) {
deleteDroppedItem.setEnabled(false);
} else {
deleteDroppedItem.setEnabled(true);
}
updateDroppedItemsEditorPane(droppedItemsEditorPane, selectedItem, listener);
}
});
if (droplist.writable) {
JPanel listButtonsPane = new JPanel();
listButtonsPane.setLayout(new JideBoxLayout(listButtonsPane, JideBoxLayout.LINE_AXIS, 6));
createDroppedItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Droplist.DroppedItem tempItem = new Droplist.DroppedItem();
droppedItemsListModel.addItem(tempItem);
itemsList.setSelectedValue(tempItem, true);
listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
});
deleteDroppedItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedItem != null) {
droppedItemsListModel.removeItem(selectedItem);
selectedItem = null;
itemsList.clearSelection();
listener.valueChanged(new JLabel(), null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
}
});
listButtonsPane.add(createDroppedItem, JideBoxLayout.FIX);
listButtonsPane.add(deleteDroppedItem, JideBoxLayout.FIX);
listButtonsPane.add(new JPanel(), JideBoxLayout.VARY);
itemsPane.add(listButtonsPane, JideBoxLayout.FIX);
}
droppedItemsEditorPane.setLayout(new JideBoxLayout(droppedItemsEditorPane, JideBoxLayout.PAGE_AXIS));
itemsPane.add(droppedItemsEditorPane, JideBoxLayout.FIX);
if (droplist.dropped_items == null || droplist.dropped_items.isEmpty()) {
itemsPane.collapse();
}
pane.add(itemsPane, JideBoxLayout.FIX);
}
public void updateDroppedItemsEditorPane(JPanel pane, DroppedItem di, FieldUpdateListener listener) {
boolean writable = ((Droplist)target).writable;
Project proj = ((Droplist)target).getProject();
pane.removeAll();
if (itemCombo != null) {
removeElementListener(itemCombo);
}
if (di != null) {
itemCombo = addItemBox(pane, proj, "Item: ", di.item, writable, listener);
qtyMinField = addIntegerField(pane, "Quantity min: ", di.quantity_min, false, writable, listener);
qtyMaxField = addIntegerField(pane, "Quantity max: ", di.quantity_max, false, writable, listener);
chanceField = addDoubleField(pane, "Chance: ", di.chance, writable, listener);
}
pane.revalidate();
pane.repaint();
}
public class DroppedItemsListModel implements ListModel {
Droplist source;
public DroppedItemsListModel(Droplist droplist) {
this.source = droplist;
}
@Override
public int getSize() {
if (source.dropped_items == null) return 0;
return source.dropped_items.size();
}
@Override
public Object getElementAt(int index) {
if (source.dropped_items == null) return null;
return source.dropped_items.get(index);
}
public void addItem(Droplist.DroppedItem item) {
if (source.dropped_items == null) {
source.dropped_items = new ArrayList<Droplist.DroppedItem>();
}
source.dropped_items.add(item);
int index = source.dropped_items.indexOf(item);
for (ListDataListener l : listeners) {
l.intervalAdded(new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, index, index));
}
}
public void removeItem(Droplist.DroppedItem item) {
int index = source.dropped_items.indexOf(item);
source.dropped_items.remove(item);
if (source.dropped_items.isEmpty()) {
source.dropped_items = null;
}
for (ListDataListener l : listeners) {
l.intervalRemoved(new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, index, index));
}
}
public void itemChanged(Droplist.DroppedItem item) {
int index = source.dropped_items.indexOf(item);
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index));
}
}
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 DroppedItemsCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 7987880146189575234L;
@Override
public Component getListCellRendererComponent(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);
Droplist.DroppedItem di = (Droplist.DroppedItem)value;
if (di.item != null) {
label.setIcon(new ImageIcon(di.item.getIcon()));
label.setText(di.chance+"% to get "+di.quantity_min+"-"+di.quantity_max+" "+di.item.getDesc());
} else if (!isNull(di)) {
label.setText(di.chance+"% to get "+di.quantity_min+"-"+di.quantity_max+" "+di.item_id);
} else {
label.setText("New, undefined, dropped item.");
}
}
return c;
}
public boolean isNull(Droplist.DroppedItem item) {
return ((item == null) || (
item.item == null &&
item.item_id == null &&
item.quantity_min == null &&
item.quantity_max == null &&
item.chance == null
));
}
}
public class DroplistFieldUpdater implements FieldUpdateListener {
@Override
public void valueChanged(JComponent source, Object value) {
Droplist droplist = ((Droplist)target);
if (source == idField) {
droplist.id = (String) value;
DroplistEditor.this.name = droplist.getDesc();
droplist.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(DroplistEditor.this);
} else if (source == itemCombo) {
if (selectedItem.item != null) {
selectedItem.item.removeBacklink(droplist);
}
selectedItem.item = (Item) value;
if (selectedItem.item != null) {
selectedItem.item_id = selectedItem.item.id;
selectedItem.item.addBacklink(droplist);
} else {
selectedItem.item_id = null;
}
droppedItemsListModel.itemChanged(selectedItem);
} else if (source == qtyMinField) {
selectedItem.quantity_min = (Integer) value;
droppedItemsListModel.itemChanged(selectedItem);
} else if (source == qtyMaxField) {
selectedItem.quantity_max = (Integer) value;
droppedItemsListModel.itemChanged(selectedItem);
} else if (source == chanceField) {
selectedItem.chance = (Double) value;
droppedItemsListModel.itemChanged(selectedItem);
}
if (droplist.state != GameDataElement.State.modified) {
droplist.state = GameDataElement.State.modified;
DroplistEditor.this.name = droplist.getDesc();
droplist.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(DroplistEditor.this);
}
updateJsonViewText(droplist.toJsonString());
}
}
}

View File

@@ -0,0 +1,128 @@
package com.gpl.rpg.atcontentstudio.ui.gamedataeditors;
import java.awt.Component;
import java.util.ArrayList;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
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.ItemCategory;
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
public class ItemCategoryEditor extends JSONElementEditor {
private static final long serialVersionUID = -2893876158803488355L;
private static final String form_view_id = "Form";
private static final String json_view_id = "JSON";
public ItemCategoryEditor(ItemCategory ic) {
super(ic, ic.getDesc(), ic.getIcon());
addEditorTab(form_view_id, getFormView());
addEditorTab(json_view_id, getJSONView());
}
private JButton icIcon;
private JTextField idField;
private JTextField nameField;
private JComboBox slotBox;
private JComboBox typeBox;
private JComboBox sizeBox;
@Override
public void insertFormViewDataField(JPanel pane) {
final ItemCategory ic = ((ItemCategory)target);
final FieldUpdateListener listener = new ItemCategoryFieldUpdater();
icIcon = createButtonPane(pane, ic.getProject(), ic, ItemCategory.class, ic.getImage(), null, listener);
idField = addTextField(pane, "Internal ID: ", ic.id, ic.writable, listener);
nameField = addTextField(pane, "Display name: ", ic.name, ic.writable, listener);
typeBox = addEnumValueBox(pane, "Action type: ", ItemCategory.ActionType.values(), ic.action_type, ic.writable, listener);
slotBox = addEnumValueBox(pane, "Inventory slot: ", ItemCategory.InventorySlot.values(), ic.slot, ic.writable, listener);
sizeBox = addEnumValueBox(pane, "Item size: ", ItemCategory.Size.values(), ic.size, ic.writable, listener);
if (ic.action_type != ItemCategory.ActionType.equip) {
slotBox.setEnabled(false);
}
slotBox.setRenderer(new SlotCellRenderer());
}
public class SlotCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = -8359181274986492979L;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
((JLabel)c).setIcon(new ImageIcon(ItemCategory.getIcon((ItemCategory.InventorySlot) value)));
if (value == null) {
if (typeBox.getSelectedItem() == ItemCategory.ActionType.equip) {
((JLabel)c).setText("Undefined. Select the slot to use when equipped.");
} else {
((JLabel)c).setText("Non equippable. Select \"equip\" action type.");
}
}
}
return c;
}
}
public class ItemCategoryFieldUpdater implements FieldUpdateListener {
@Override
public void valueChanged(JComponent source, Object value) {
ItemCategory ic = (ItemCategory)target;
if (source == idField) {
ic.id = (String) value;
ItemCategoryEditor.this.name = ic.getDesc();
ic.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(ItemCategoryEditor.this);
} else if (source == nameField) {
ic.name = (String) value;
ItemCategoryEditor.this.name = ic.getDesc();
ic.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(ItemCategoryEditor.this);
} else if (source == slotBox) {
ic.slot = (ItemCategory.InventorySlot) value;
icIcon.setIcon(new ImageIcon(ic.getImage()));
ItemCategoryEditor.this.icon = new ImageIcon(ic.getIcon());
ic.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(ItemCategoryEditor.this);
} else if (source == typeBox) {
ic.action_type = (ItemCategory.ActionType) value;
if (ic.action_type != ItemCategory.ActionType.equip && ic.slot != null) {
ic.slot = null;
slotBox.setSelectedItem(null);
slotBox.setEnabled(false);
icIcon.setIcon(new ImageIcon(ic.getImage()));
ItemCategoryEditor.this.icon = new ImageIcon(ic.getIcon());
ic.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(ItemCategoryEditor.this);
} else if (ic.action_type == ItemCategory.ActionType.equip) {
slotBox.setEnabled(true);
}
} else if (source == sizeBox) {
ic.size = (ItemCategory.Size) value;
}
if (ic.state != GameDataElement.State.modified) {
ic.state = GameDataElement.State.modified;
ItemCategoryEditor.this.name = ic.getDesc();
ic.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(ItemCategoryEditor.this);
}
updateJsonViewText(ic.toJsonString());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,269 @@
package com.gpl.rpg.atcontentstudio.ui.gamedataeditors;
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.Project;
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.sprites.Spritesheet;
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.sprites.SpriteChooser;
import com.jidesoft.swing.JideBoxLayout;
import com.jidesoft.swing.JideTabbedPane;
public abstract class JSONElementEditor extends Editor {
private static final long serialVersionUID = -5889046987755079563L;
Map<String, JPanel> editorTabs = new HashMap<String, JPanel>();
JideTabbedPane editorTabsHolder;
RSyntaxTextArea jsonEditorPane;
public JSONElementEditor(JSONElement target, String desc, Image icon) {
super();
this.target = target;
this.name = desc;
this.icon = new ImageIcon(icon);
setLayout(new BorderLayout());
editorTabsHolder = new JideTabbedPane(JideTabbedPane.BOTTOM);
editorTabsHolder.setTabShape(JideTabbedPane.SHAPE_FLAT);
editorTabsHolder.setUseDefaultShowCloseButtonOnTab(false);
editorTabsHolder.setShowCloseButtonOnTab(false);
add(editorTabsHolder, BorderLayout.CENTER);
}
public void addEditorTab(String id, JPanel editor) {
JScrollPane scroller = new JScrollPane(editor);
scroller.getVerticalScrollBar().setUnitIncrement(16);
editorTabsHolder.addTab(id, scroller);
editorTabs.put(id, editor);
}
public JPanel getJSONView() {
jsonEditorPane = new RSyntaxTextArea();
jsonEditorPane.setText(((JSONElement)target).toJsonString());
jsonEditorPane.setEditable(((JSONElement)target).writable);
jsonEditorPane.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JSON);
JPanel result = new JPanel();
result.setLayout(new BorderLayout());
result.add(jsonEditorPane, BorderLayout.CENTER);
return result;
}
public void updateJsonViewText(String text) {
jsonEditorPane.setText(text);
}
public JPanel getFormView() {
JPanel pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
if (((JSONElement)target).jsonFile != null) {
addLabelField(pane, "JSON File: ", ((JSONElement)target).jsonFile.getAbsolutePath());
}
insertFormViewDataField(pane);
addBacklinksList(pane, (JSONElement) target);
//Placeholder. Fills the eventual remaining space.
pane.add(new JPanel(), JideBoxLayout.VARY);
return pane;
}
public abstract void insertFormViewDataField(JPanel pane);
public JButton createButtonPane(JPanel pane, final Project proj, final JSONElement node, final Class<? extends JSONElement> concreteNodeClass, Image icon, final Spritesheet.Category iconCat, final FieldUpdateListener listener) {
final JButton gdeIcon = new JButton(new ImageIcon(icon));
JPanel savePane = new JPanel();
savePane.add(gdeIcon, JideBoxLayout.FIX);
savePane.setLayout(new JideBoxLayout(savePane, JideBoxLayout.LINE_AXIS, 6));
if (node.writable) {
if (iconCat != null) {
gdeIcon.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SpriteChooser chooser = SpriteChooser.getChooser(proj, iconCat);
chooser.setSelectionListener(new SpriteChooser.SelectionListener() {
@Override
public void iconSelected(String selected) {
if (selected != null) {
listener.valueChanged(gdeIcon, selected);
}
}
});
chooser.setVisible(true);
}
});
}
if (node.getDataType() == GameSource.Type.altered) {
savePane.add(message = new JLabel(ALTERED_MESSAGE), JideBoxLayout.FIX);
} else if (node.getDataType() == GameSource.Type.created) {
savePane.add(message = new JLabel(CREATED_MESSAGE), JideBoxLayout.FIX);
}
JButton save = new JButton(SAVE);
save.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (node.getParent() instanceof GameDataCategory<?>) {
if (node.state != GameDataElement.State.saved) {
final List<SaveEvent> events = node.attemptSave();
if (events == null) {
ATContentStudio.frame.nodeChanged(node);
} else {
new Thread() {
@Override
public void run() {
new SaveItemsWizard(events, node).setVisible(true);
}
}.start();
}
}
}
}
});
savePane.add(save, JideBoxLayout.FIX);
JButton delete = new JButton(DELETE);
if (node.getDataType() == GameSource.Type.altered) {
delete.setText(REVERT);
}
delete.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ATContentStudio.frame.closeEditor(node);
node.childrenRemoved(new ArrayList<ProjectTreeNode>());
if (node.getParent() instanceof GameDataCategory<?>) {
((GameDataCategory<?>)node.getParent()).remove(node);
node.save();
for (GameDataElement backlink : node.getBacklinks()) {
backlink.elementChanged(node, proj.getGameDataElement(node.getClass(), node.id));
}
}
}
});
savePane.add(delete, JideBoxLayout.FIX);
} else {
if (proj.alteredContent.gameData.getGameDataElement(concreteNodeClass, node.id) != null) {
savePane.add(message = new JLabel(ALTERED_EXISTS_MESSAGE), JideBoxLayout.FIX);
JButton makeWritable = new JButton("Go to altered");
makeWritable.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (node.getProject().getGameDataElement(concreteNodeClass, node.id) != node) {
ATContentStudio.frame.openEditor(node.getProject().getGameDataElement(concreteNodeClass, node.id));
ATContentStudio.frame.closeEditor(node);
ATContentStudio.frame.selectInTree(node.getProject().getGameDataElement(concreteNodeClass, node.id));
}
}
});
savePane.add(makeWritable, JideBoxLayout.FIX);
} else {
savePane.add(message = new JLabel(READ_ONLY_MESSAGE), JideBoxLayout.FIX);
JButton makeWritable = new JButton("Alter");
makeWritable.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (node.getProject().getGameDataElement(concreteNodeClass, node.id) == node) {
node.getProject().makeWritable(node);
}
if (node.getProject().getGameDataElement(concreteNodeClass, node.id) != node) {
ATContentStudio.frame.openEditor(node.getProject().getGameDataElement(concreteNodeClass, node.id));
ATContentStudio.frame.closeEditor(node);
ATContentStudio.frame.selectInTree(node.getProject().getGameDataElement(concreteNodeClass, node.id));
}
updateMessage();
}
});
savePane.add(makeWritable, JideBoxLayout.FIX);
}
}
JButton prev = new JButton(new ImageIcon(DefaultIcons.getArrowLeftIcon()));
JButton next = new JButton(new ImageIcon(DefaultIcons.getArrowRightIcon()));
savePane.add(prev, JideBoxLayout.FIX);
savePane.add(next, JideBoxLayout.FIX);
if (node.getParent().getIndex(node) == 0) {
prev.setEnabled(false);
}
if (node.getParent().getIndex(node) == node.getParent().getChildCount() - 1) {
next.setEnabled(false);
}
prev.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ProjectTreeNode prevNode = (ProjectTreeNode) node.getParent().getChildAt(node.getParent().getIndex(node) - 1);
if (prevNode != null && prevNode instanceof GameDataElement) {
ATContentStudio.frame.openEditor((GameDataElement) prevNode);
}
}
});
next.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ProjectTreeNode nextNode = (ProjectTreeNode) node.getParent().getChildAt(node.getParent().getIndex(node) + 1);
if (nextNode != null && nextNode instanceof GameDataElement) {
ATContentStudio.frame.openEditor((GameDataElement) nextNode);
}
}
});
//Placeholder. Fills the eventual remaining space.
savePane.add(new JPanel(), JideBoxLayout.VARY);
pane.add(savePane, JideBoxLayout.FIX);
return gdeIcon;
}
@Override
public void targetUpdated() {
this.icon = new ImageIcon(((GameDataElement)target).getIcon());
this.name = ((GameDataElement)target).getDesc();
updateMessage();
}
public void updateMessage() {
//TODO make this a full update of the button panel.
JSONElement node = (JSONElement) target;
if (node.writable) {
if (node.getDataType() == GameSource.Type.altered) {
message.setText(ALTERED_MESSAGE);
} else if (node.getDataType() == GameSource.Type.created) {
message.setText(CREATED_MESSAGE);
}
} else if (node.getProject().alteredContent.gameData.getGameDataElement(node.getClass(), node.id) != null) {
message.setText(ALTERED_EXISTS_MESSAGE);
} else {
message.setText(READ_ONLY_MESSAGE);
}
message.revalidate();
message.repaint();
}
}

View File

@@ -0,0 +1,612 @@
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;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
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 com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.gamedata.ActorCondition;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.Droplist;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
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;
import com.gpl.rpg.atcontentstudio.ui.gamedataeditors.dialoguetree.DialogueGraphView;
import com.jidesoft.swing.JideBoxLayout;
public class NPCEditor extends JSONElementEditor {
private static final long serialVersionUID = 4001483665523721800L;
private static final String form_view_id = "Form";
private static final String json_view_id = "JSON";
private NPC.TimedConditionEffect selectedHitEffectSourceCondition;
private NPC.TimedConditionEffect selectedHitEffectTargetCondition;
private JButton npcIcon;
private JTextField idField;
private JTextField nameField;
private JTextField spawnGroupField;
private JSpinner experienceField;
private MyComboBox dialogueBox;
private MyComboBox droplistBox;
private JComboBox monsterClassBox;
private IntegerBasedCheckBox uniqueBox;
private JComboBox moveTypeBox;
private CollapsiblePanel combatTraitPane;
private JSpinner maxHP;
private JSpinner maxAP;
private JSpinner moveCost;
private JSpinner atkDmgMin;
private JSpinner atkDmgMax;
private JSpinner atkCost;
private JSpinner atkChance;
private JSpinner critSkill;
private JSpinner critMult;
private JSpinner blockChance;
private JSpinner dmgRes;
private NPC.HitEffect hitEffect;
private CollapsiblePanel hitEffectPane;
private JSpinner hitEffectHPMin;
private JSpinner hitEffectHPMax;
private JSpinner hitEffectAPMin;
private JSpinner hitEffectAPMax;
private SourceTimedConditionsListModel hitSourceConditionsListModel;
private JList hitSourceConditionsList;
private MyComboBox sourceConditionBox;
private JSpinner sourceConditionMagnitude;
private JSpinner sourceConditionDuration;
private JSpinner sourceConditionChance;
private TargetTimedConditionsListModel hitTargetConditionsListModel;
private JList hitTargetConditionsList;
private MyComboBox targetConditionBox;
private JSpinner targetConditionMagnitude;
private JSpinner targetConditionDuration;
private JSpinner targetConditionChance;
public NPCEditor(NPC npc) {
super(npc, npc.getDesc(), npc.getIcon());
addEditorTab(form_view_id, getFormView());
addEditorTab(json_view_id, getJSONView());
if (npc.dialogue != null) {
JPanel pane = new JPanel();
pane.setLayout(new BorderLayout());
pane.add(new JScrollPane(new DialogueGraphView(npc.dialogue, npc)), BorderLayout.CENTER);
addEditorTab("Dialogue Tree", pane);
}
}
@Override
public void insertFormViewDataField(JPanel pane) {
final NPC npc = (NPC) target;
final FieldUpdateListener listener = new NPCFieldUpdate();
npcIcon = createButtonPane(pane, npc.getProject(), npc, NPC.class, npc.getImage(), Spritesheet.Category.monster, listener);
idField = addTextField(pane, "Internal ID: ", npc.id, npc.writable, listener);
nameField = addTextField(pane, "Display name: ", npc.name, npc.writable, listener);
spawnGroupField = addTextField(pane, "Spawn group ID: ", npc.spawngroup_id, npc.writable, listener);
experienceField = addIntegerField(pane, "Experience reward: ", npc.getMonsterExperience(), false, false, listener);
dialogueBox = addDialogueBox(pane, npc.getProject(), "Initial phrase: ", npc.dialogue, npc.writable, listener);
droplistBox = addDroplistBox(pane, npc.getProject(), "Droplist / Shop inventory: ", npc.droplist, npc.writable, listener);
monsterClassBox = addEnumValueBox(pane, "Monster class: ", NPC.MonsterClass.values(), npc.monster_class, npc.writable, listener);
uniqueBox = addIntegerBasedCheckBox(pane, "Unique", npc.unique, npc.writable, listener);
moveTypeBox = addEnumValueBox(pane, "Movement type: ", NPC.MovementType.values(), npc.movement_type, npc.writable, listener);
combatTraitPane = new CollapsiblePanel("Combat traits: ");
combatTraitPane.setLayout(new JideBoxLayout(combatTraitPane, JideBoxLayout.PAGE_AXIS, 6));
maxHP = addIntegerField(combatTraitPane, "Max HP: ", npc.max_hp, false, npc.writable, listener);
maxAP = addIntegerField(combatTraitPane, "Max AP: ", npc.max_ap, false, npc.writable, listener);
moveCost = addIntegerField(combatTraitPane, "Move cost: ", npc.move_cost, false, npc.writable, listener);
atkDmgMin = addIntegerField(combatTraitPane, "Attack Damage min: ", npc.attack_damage_min, false, npc.writable, listener);
atkDmgMax = addIntegerField(combatTraitPane, "Attack Damage max: ", npc.attack_damage_max, false, npc.writable, listener);
atkCost = addIntegerField(combatTraitPane, "Attack cost: ", npc.attack_cost, false, npc.writable, listener);
atkChance = addIntegerField(combatTraitPane, "Attack chance: ", npc.attack_chance, false, npc.writable, listener);
critSkill = addIntegerField(combatTraitPane, "Critical skill: ", npc.critical_skill, false, npc.writable, listener);
critMult = addDoubleField(combatTraitPane, "Critical multiplier: ", npc.critical_multiplier, npc.writable, listener);
blockChance = addIntegerField(combatTraitPane, "Block chance: ", npc.block_chance, false, npc.writable, listener);
dmgRes = addIntegerField(combatTraitPane, "Damage resistance: ", npc.damage_resistance, false, npc.writable, listener);
hitEffectPane = new CollapsiblePanel("Effect on every hit: ");
hitEffectPane.setLayout(new JideBoxLayout(hitEffectPane, JideBoxLayout.PAGE_AXIS));
if (npc.hit_effect == null) {
hitEffect = new NPC.HitEffect();
} else {
hitEffect = npc.hit_effect;
}
hitEffectHPMin = addIntegerField(hitEffectPane, "HP bonus min: ", hitEffect.hp_boost_min, true, npc.writable, listener);
hitEffectHPMax = addIntegerField(hitEffectPane, "HP bonus max: ", hitEffect.hp_boost_max, true, npc.writable, listener);
hitEffectAPMin = addIntegerField(hitEffectPane, "AP bonus min: ", hitEffect.ap_boost_min, true, npc.writable, listener);
hitEffectAPMax = addIntegerField(hitEffectPane, "AP bonus max: ", hitEffect.ap_boost_max, true, npc.writable, listener);
CollapsiblePanel hitSourceConditionsPane = new CollapsiblePanel("Actor Conditions applied to the source: ");
hitSourceConditionsPane.setLayout(new JideBoxLayout(hitSourceConditionsPane, JideBoxLayout.PAGE_AXIS));
hitSourceConditionsListModel = new SourceTimedConditionsListModel(hitEffect);
hitSourceConditionsList = new JList(hitSourceConditionsListModel);
hitSourceConditionsList.setCellRenderer(new TimedConditionsCellRenderer());
hitSourceConditionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
hitSourceConditionsPane.add(new JScrollPane(hitSourceConditionsList), JideBoxLayout.FIX);
final JPanel sourceTimedConditionsEditorPane = new JPanel();
final JButton createHitSourceCondition = new JButton(new ImageIcon(DefaultIcons.getCreateIcon()));
final JButton deleteHitSourceCondition = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
hitSourceConditionsList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
selectedHitEffectSourceCondition = (NPC.TimedConditionEffect) hitSourceConditionsList.getSelectedValue();
updateSourceTimedConditionEditorPane(sourceTimedConditionsEditorPane, selectedHitEffectSourceCondition, listener);
}
});
if (npc.writable) {
JPanel listButtonsPane = new JPanel();
listButtonsPane.setLayout(new JideBoxLayout(listButtonsPane, JideBoxLayout.LINE_AXIS, 6));
createHitSourceCondition.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
NPC.TimedConditionEffect condition = new NPC.TimedConditionEffect();
hitSourceConditionsListModel.addItem(condition);
hitSourceConditionsList.setSelectedValue(condition, true);
listener.valueChanged(hitSourceConditionsList, null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
});
deleteHitSourceCondition.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedHitEffectSourceCondition != null) {
hitSourceConditionsListModel.removeItem(selectedHitEffectSourceCondition);
selectedHitEffectSourceCondition = null;
hitSourceConditionsList.clearSelection();
listener.valueChanged(hitSourceConditionsList, null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
}
});
listButtonsPane.add(createHitSourceCondition, JideBoxLayout.FIX);
listButtonsPane.add(deleteHitSourceCondition, JideBoxLayout.FIX);
listButtonsPane.add(new JPanel(), JideBoxLayout.VARY);
hitSourceConditionsPane.add(listButtonsPane, JideBoxLayout.FIX);
}
sourceTimedConditionsEditorPane.setLayout(new JideBoxLayout(sourceTimedConditionsEditorPane, JideBoxLayout.PAGE_AXIS));
hitSourceConditionsPane.add(sourceTimedConditionsEditorPane, JideBoxLayout.FIX);
if (npc.hit_effect == null || npc.hit_effect.conditions_source == null || npc.hit_effect.conditions_source.isEmpty()) {
hitSourceConditionsPane.collapse();
}
hitEffectPane.add(hitSourceConditionsPane, JideBoxLayout.FIX);
final CollapsiblePanel hitTargetConditionsPane = new CollapsiblePanel("Actor Conditions applied to the target: ");
hitTargetConditionsPane.setLayout(new JideBoxLayout(hitTargetConditionsPane, JideBoxLayout.PAGE_AXIS));
hitTargetConditionsListModel = new TargetTimedConditionsListModel(hitEffect);
hitTargetConditionsList = new JList(hitTargetConditionsListModel);
hitTargetConditionsList.setCellRenderer(new TimedConditionsCellRenderer());
hitTargetConditionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
hitTargetConditionsPane.add(new JScrollPane(hitTargetConditionsList), JideBoxLayout.FIX);
final JPanel targetTimedConditionsEditorPane = new JPanel();
final JButton createHitTargetCondition = new JButton(new ImageIcon(DefaultIcons.getCreateIcon()));
final JButton deleteHitTargetCondition = new JButton(new ImageIcon(DefaultIcons.getNullifyIcon()));
hitTargetConditionsList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
selectedHitEffectTargetCondition = (NPC.TimedConditionEffect) hitTargetConditionsList.getSelectedValue();
updateTargetTimedConditionEditorPane(targetTimedConditionsEditorPane, selectedHitEffectTargetCondition, listener);
}
});
if (npc.writable) {
JPanel listButtonsPane = new JPanel();
listButtonsPane.setLayout(new JideBoxLayout(listButtonsPane, JideBoxLayout.LINE_AXIS, 6));
createHitTargetCondition.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
NPC.TimedConditionEffect condition = new NPC.TimedConditionEffect();
hitTargetConditionsListModel.addItem(condition);
hitTargetConditionsList.setSelectedValue(condition, true);
listener.valueChanged(hitTargetConditionsList, null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
});
deleteHitTargetCondition.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedHitEffectTargetCondition != null) {
hitTargetConditionsListModel.removeItem(selectedHitEffectTargetCondition);
selectedHitEffectTargetCondition = null;
hitTargetConditionsList.clearSelection();
listener.valueChanged(hitTargetConditionsList, null); //Item changed, but we took care of it, just do the usual notification and JSON update stuff.
}
}
});
listButtonsPane.add(createHitTargetCondition, JideBoxLayout.FIX);
listButtonsPane.add(deleteHitTargetCondition, JideBoxLayout.FIX);
listButtonsPane.add(new JPanel(), JideBoxLayout.VARY);
hitTargetConditionsPane.add(listButtonsPane, JideBoxLayout.FIX);
}
targetTimedConditionsEditorPane.setLayout(new JideBoxLayout(targetTimedConditionsEditorPane, JideBoxLayout.PAGE_AXIS));
hitTargetConditionsPane.add(targetTimedConditionsEditorPane, JideBoxLayout.FIX);
hitEffectPane.add(hitTargetConditionsPane, JideBoxLayout.FIX);
if (npc.hit_effect == null || npc.hit_effect.conditions_target == null || npc.hit_effect.conditions_target.isEmpty()) {
hitTargetConditionsPane.collapse();
}
combatTraitPane.add(hitEffectPane, JideBoxLayout.FIX);
pane.add(combatTraitPane, JideBoxLayout.FIX);
}
public void updateSourceTimedConditionEditorPane(JPanel pane, NPC.TimedConditionEffect condition, FieldUpdateListener listener) {
pane.removeAll();
if (sourceConditionBox != null) {
removeElementListener(sourceConditionBox);
}
boolean writable = ((NPC)target).writable;
Project proj = ((NPC)target).getProject();
sourceConditionBox = addActorConditionBox(pane, proj, "Actor Condition: ", condition.condition, writable, listener);
sourceConditionMagnitude = addIntegerField(pane, "Magnitude: ", condition.magnitude, false, writable, listener);
sourceConditionDuration = addIntegerField(pane, "Duration: ", condition.duration, false, writable, listener);
sourceConditionChance = addDoubleField(pane, "Chance: ", condition.chance, writable, listener);
pane.revalidate();
pane.repaint();
}
public void updateTargetTimedConditionEditorPane(JPanel pane, NPC.TimedConditionEffect condition, FieldUpdateListener listener) {
pane.removeAll();
if (targetConditionBox != null) {
removeElementListener(targetConditionBox);
}
boolean writable = ((NPC)target).writable;
Project proj = ((NPC)target).getProject();
targetConditionBox = addActorConditionBox(pane, proj, "Actor Condition: ", condition.condition, writable, listener);
targetConditionMagnitude = addIntegerField(pane, "Magnitude: ", condition.magnitude, false, writable, listener);
targetConditionDuration = addIntegerField(pane, "Duration: ", condition.duration, false, writable, listener);
targetConditionChance = addDoubleField(pane, "Chance: ", condition.chance, writable, listener);
pane.revalidate();
pane.repaint();
}
public static class TargetTimedConditionsListModel implements ListModel {
NPC.HitEffect source;
public TargetTimedConditionsListModel(NPC.HitEffect effect) {
this.source = effect;
}
@Override
public int getSize() {
if (source.conditions_target == null) return 0;
return source.conditions_target.size();
}
@Override
public Object getElementAt(int index) {
if (source.conditions_target == null) return null;
return source.conditions_target.get(index);
}
public void addItem(NPC.TimedConditionEffect item) {
if (source.conditions_target == null) {
source.conditions_target = new ArrayList<NPC.TimedConditionEffect>();
}
source.conditions_target.add(item);
int index = source.conditions_target.indexOf(item);
for (ListDataListener l : listeners) {
l.intervalAdded(new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, index, index));
}
}
public void removeItem(NPC.TimedConditionEffect item) {
int index = source.conditions_target.indexOf(item);
source.conditions_target.remove(item);
if (source.conditions_target.isEmpty()) {
source.conditions_target = null;
}
for (ListDataListener l : listeners) {
l.intervalRemoved(new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, index, index));
}
}
public void itemChanged(NPC.TimedConditionEffect item) {
int index = source.conditions_target.indexOf(item);
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index));
}
}
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 SourceTimedConditionsListModel implements ListModel {
NPC.HitEffect source;
public SourceTimedConditionsListModel(NPC.HitEffect effect) {
this.source = effect;
}
@Override
public int getSize() {
if (source.conditions_source == null) return 0;
return source.conditions_source.size();
}
@Override
public Object getElementAt(int index) {
if (source.conditions_source == null) return null;
return source.conditions_source.get(index);
}
public void addItem(NPC.TimedConditionEffect item) {
if (source.conditions_source == null) {
source.conditions_source = new ArrayList<NPC.TimedConditionEffect>();
}
source.conditions_source.add(item);
int index = source.conditions_source.indexOf(item);
for (ListDataListener l : listeners) {
l.intervalAdded(new ListDataEvent(this, ListDataEvent.INTERVAL_ADDED, index, index));
}
}
public void removeItem(NPC.TimedConditionEffect item) {
int index = source.conditions_source.indexOf(item);
source.conditions_source.remove(item);
if (source.conditions_source.isEmpty()) {
source.conditions_source = null;
}
for (ListDataListener l : listeners) {
l.intervalRemoved(new ListDataEvent(this, ListDataEvent.INTERVAL_REMOVED, index, index));
}
}
public void itemChanged(NPC.TimedConditionEffect item) {
int index = source.conditions_source.indexOf(item);
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, index, index));
}
}
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 TimedConditionsCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 7987880146189575234L;
@Override
public Component getListCellRendererComponent(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);
NPC.TimedConditionEffect effect = (NPC.TimedConditionEffect) value;
if (effect.condition != null) {
label.setIcon(new ImageIcon(effect.condition.getIcon()));
label.setText(effect.chance+"% chances to give "+effect.duration+" rounds of "+effect.condition.getDesc()+" x"+effect.magnitude);
} else {
label.setText("New, undefined actor condition effect.");
}
}
return c;
}
}
public static boolean isNull(NPC.HitEffect effect) {
if (effect.ap_boost_min != null) return false;
if (effect.ap_boost_max != null) return false;
if (effect.hp_boost_min != null) return false;
if (effect.hp_boost_max != null) return false;
if (effect.conditions_source != null) return false;
if (effect.conditions_target != null) return false;
return true;
}
public class NPCFieldUpdate implements FieldUpdateListener {
@Override
public void valueChanged(JComponent source, Object value) {
NPC npc = (NPC)target;
boolean updateHit = false;
if (source == idField) {
npc.id = (String) value;
NPCEditor.this.name = npc.getDesc();
npc.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(NPCEditor.this);
} else if (source == nameField) {
npc.name = (String) value;
NPCEditor.this.name = npc.getDesc();
npc.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(NPCEditor.this);
} else if (source == npcIcon) {
npc.icon_id = (String) value;
npc.childrenChanged(new ArrayList<ProjectTreeNode>());
NPCEditor.this.icon = new ImageIcon(npc.getProject().getIcon((String) value));
ATContentStudio.frame.editorChanged(NPCEditor.this);
npcIcon.setIcon(new ImageIcon(npc.getProject().getImage((String) value)));
npcIcon.revalidate();
npcIcon.repaint();
} else if (source == spawnGroupField) {
npc.spawngroup_id = (String) value;
} else if (source == dialogueBox) {
if (npc.dialogue != null) {
npc.dialogue.removeBacklink(npc);
}
npc.dialogue = (Dialogue) value;
if (npc.dialogue != null) {
npc.dialogue_id =npc.dialogue.id;
npc.dialogue.addBacklink(npc);
} else {
npc.dialogue_id = null;
}
} else if (source == droplistBox) {
if (npc.droplist != null) {
npc.droplist.removeBacklink(npc);
}
npc.droplist = (Droplist) value;
if (npc.droplist != null) {
npc.droplist_id = npc.droplist.id;
npc.droplist.addBacklink(npc);
} else {
npc.droplist_id = null;
}
} else if (source == monsterClassBox) {
npc.monster_class = (NPC.MonsterClass) value;
} else if (source == uniqueBox) {
npc.unique = (Integer) value;
} else if (source == moveTypeBox) {
npc.movement_type = (NPC.MovementType) value;
} else if (source == maxHP) {
npc.max_hp = (Integer) value;
} else if (source == maxAP) {
npc.max_ap = (Integer) value;
} else if (source == moveCost) {
npc.move_cost = (Integer) value;
} else if (source == atkDmgMin) {
npc.attack_damage_min = (Integer) value;
} else if (source == atkDmgMax) {
npc.attack_damage_max = (Integer) value;
} else if (source == atkCost) {
npc.attack_cost = (Integer) value;
} else if (source == atkChance) {
npc.attack_chance = (Integer) value;
} else if (source == critSkill) {
npc.critical_skill = (Integer) value;
} else if (source == critMult) {
npc.critical_multiplier = (Double) value;
} else if (source == blockChance) {
npc.block_chance = (Integer) value;
} else if (source == dmgRes) {
npc.damage_resistance = (Integer) value;
} else if (source == hitEffectHPMin) {
hitEffect.hp_boost_min = (Integer) value;
updateHit = true;
} else if (source == hitEffectHPMax) {
hitEffect.hp_boost_max = (Integer) value;
updateHit = true;
} else if (source == hitEffectAPMin) {
hitEffect.ap_boost_min = (Integer) value;
updateHit = true;
} else if (source == hitEffectAPMax) {
hitEffect.ap_boost_max = (Integer) value;
updateHit = true;
} else if (source == hitSourceConditionsList) {
//TODO
} else if (source == sourceConditionBox) {
if (selectedHitEffectSourceCondition.condition != null) {
selectedHitEffectSourceCondition.condition.removeBacklink(npc);
}
selectedHitEffectSourceCondition.condition = (ActorCondition) value;
if (selectedHitEffectSourceCondition.condition != null) {
selectedHitEffectSourceCondition.condition.addBacklink(npc);
selectedHitEffectSourceCondition.condition_id = selectedHitEffectSourceCondition.condition.id;
} else {
selectedHitEffectSourceCondition.condition_id = null;
}
hitSourceConditionsListModel.itemChanged(selectedHitEffectSourceCondition);
} else if (source == sourceConditionMagnitude) {
selectedHitEffectSourceCondition.magnitude = (Integer) value;
hitSourceConditionsListModel.itemChanged(selectedHitEffectSourceCondition);
} else if (source == sourceConditionDuration) {
selectedHitEffectSourceCondition.duration = (Integer) value;
hitSourceConditionsListModel.itemChanged(selectedHitEffectSourceCondition);
} else if (source == sourceConditionChance) {
selectedHitEffectSourceCondition.chance = (Double) value;
hitSourceConditionsListModel.itemChanged(selectedHitEffectSourceCondition);
} else if (source == hitTargetConditionsList) {
//TODO
} else if (source == targetConditionBox) {
if (selectedHitEffectTargetCondition.condition != null) {
selectedHitEffectTargetCondition.condition.removeBacklink(npc);
}
selectedHitEffectTargetCondition.condition = (ActorCondition) value;
if (selectedHitEffectTargetCondition.condition != null) {
selectedHitEffectTargetCondition.condition_id = selectedHitEffectTargetCondition.condition.id;
selectedHitEffectTargetCondition.condition.addBacklink(npc);
} else {
selectedHitEffectTargetCondition.condition_id = null;
}
hitTargetConditionsListModel.itemChanged(selectedHitEffectTargetCondition);
} else if (source == targetConditionMagnitude) {
selectedHitEffectTargetCondition.magnitude = (Integer) value;
hitTargetConditionsListModel.itemChanged(selectedHitEffectTargetCondition);
} else if (source == targetConditionDuration) {
selectedHitEffectTargetCondition.duration = (Integer) value;
hitTargetConditionsListModel.itemChanged(selectedHitEffectTargetCondition);
} else if (source == targetConditionChance) {
selectedHitEffectTargetCondition.chance = (Double) value;
hitTargetConditionsListModel.itemChanged(selectedHitEffectTargetCondition);
}
if (updateHit) {
if (isNull(hitEffect)) {
npc.hit_effect = null;
} else {
npc.hit_effect = hitEffect;
}
}
experienceField.setValue(npc.getMonsterExperience());
if (npc.state != GameDataElement.State.modified) {
npc.state = GameDataElement.State.modified;
NPCEditor.this.name = npc.getDesc();
npc.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(NPCEditor.this);
}
updateJsonViewText(npc.toJsonString());
}
}
}

View File

@@ -0,0 +1,334 @@
package com.gpl.rpg.atcontentstudio.ui.gamedataeditors;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
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.ui.DefaultIcons;
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
import com.gpl.rpg.atcontentstudio.ui.IntegerBasedCheckBox;
import com.jidesoft.swing.JideBoxLayout;
public class QuestEditor extends JSONElementEditor {
private static final long serialVersionUID = 5701667955210615366L;
private static final Integer one = 1;
private static final String form_view_id = "Form";
private static final String json_view_id = "JSON";
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;
public QuestEditor(Quest quest) {
super(quest, quest.getDesc(), quest.getIcon());
addEditorTab(form_view_id, getFormView());
addEditorTab(json_view_id, getJSONView());
}
public void insertFormViewDataField(JPanel pane) {
final Quest quest = ((Quest)target);
final FieldUpdateListener listener = new QuestFieldUpdater();
createButtonPane(pane, quest.getProject(), quest, Quest.class, quest.getImage(), null, listener);
addTextField(pane, "Internal ID: ", quest.id, quest.writable, listener);
addTextField(pane, "Quest Name: ", quest.name, quest.writable, listener);
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);
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();
}
});
createStage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stagesModel.createStage();
listener.valueChanged(stagesTable, null);
stagesTable.revalidate();
stagesTable.repaint();
}
});
deleteStage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
stagesModel.deleteRow(stagesTable.getSelectedRow());
listener.valueChanged(stagesTable, null);
stagesTable.revalidate();
stagesTable.repaint();
updateTableButtons();
}
});
moveUp.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();
}
});
moveDown.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();
}
});
stagesPane.add(buttonPane, JideBoxLayout.FIX);
}
pane.add(stagesPane, JideBoxLayout.FIX);
}
public void updateTableButtons() {
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);
}
}
public class QuestStageTableModel implements TableModel {
Quest quest;
FieldUpdateListener listener;
public QuestStageTableModel(Quest q, FieldUpdateListener listener) {
this.quest = q;
this.listener = listener;
}
@Override
public int getRowCount() {
if (quest.stages == null) return 0;
return quest.stages.size();
}
@Override
public int getColumnCount() {
return 4;
}
@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 "???";
}
}
@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() {
quest.stages.add(new Quest.QuestStage());
for (TableModelListener l: listeners) {
l.tableChanged(new TableModelEvent(this, quest.stages.size() - 1));
}
}
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 deleteRow(int rowNumber) {
quest.stages.remove(rowNumber);
for (TableModelListener l: listeners) {
l.tableChanged(new TableModelEvent(this, rowNumber, quest.stages.size()));
}
}
public List<TableModelListener> listeners = new ArrayList<TableModelListener>();
@Override
public void addTableModelListener(TableModelListener l) {
listeners.add(l);
}
@Override
public void removeTableModelListener(TableModelListener l) {
listeners.remove(l);
}
}
public class QuestFieldUpdater implements FieldUpdateListener {
@Override
public void valueChanged(JComponent source, Object value) {
Quest quest = (Quest) target;
if (source == idField) {
quest.id = (String) value;
QuestEditor.this.name = quest.getDesc();
quest.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(QuestEditor.this);
} else if (source == nameField) {
quest.name = (String) value;
QuestEditor.this.name = quest.getDesc();
quest.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(QuestEditor.this);
} else if (source == visibleBox) {
quest.visible_in_log = (Integer) value;
}
if (quest.state != GameDataElement.State.modified) {
quest.state = GameDataElement.State.modified;
QuestEditor.this.name = quest.getDesc();
quest.childrenChanged(new ArrayList<ProjectTreeNode>());
ATContentStudio.frame.editorChanged(QuestEditor.this);
}
updateJsonViewText(quest.toJsonString());
}
}
}

View File

@@ -0,0 +1,440 @@
package com.gpl.rpg.atcontentstudio.ui.gamedataeditors.dialoguetree;
import java.awt.BasicStroke;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import prefuse.Display;
import prefuse.Visualization;
import prefuse.action.ActionList;
import prefuse.action.RepaintAction;
import prefuse.action.assignment.ColorAction;
import prefuse.action.assignment.FontAction;
import prefuse.action.assignment.StrokeAction;
import prefuse.action.layout.Layout;
import prefuse.action.layout.graph.NodeLinkTreeLayout;
import prefuse.activity.Activity;
import prefuse.controls.ControlAdapter;
import prefuse.controls.PanControl;
import prefuse.controls.WheelZoomControl;
import prefuse.controls.ZoomControl;
import prefuse.data.Edge;
import prefuse.data.Graph;
import prefuse.data.Node;
import prefuse.data.Schema;
import prefuse.render.DefaultRendererFactory;
import prefuse.render.EdgeRenderer;
import prefuse.render.LabelRenderer;
import prefuse.util.ColorLib;
import prefuse.util.GraphicsLib;
import prefuse.util.PrefuseLib;
import prefuse.visual.DecoratorItem;
import prefuse.visual.EdgeItem;
import prefuse.visual.VisualItem;
import prefuse.visual.expression.InGroupPredicate;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.gamedata.Dialogue;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
public class DialogueGraphView extends Display {
private static final long serialVersionUID = -6431503090775579301L;
public static final String GRAPH = "graph";
public static final String NODES = "graph.nodes";
public static final String EDGES = "graph.edges";
public static final String EDGES_LABELS = "edgesLabels";
public static final String AGGR = "aggregates";
public static final String LABEL = "label";
public static final String ICON = "icon";
public static final String TARGET = "target";
public static final String REPLY = "reply";
public static final String HAS_REQS = "has_reqs";
private static final Schema DECORATOR_SCHEMA = PrefuseLib.getVisualItemSchema();
private Dialogue dialogue;
private Image npcIcon;
private Graph graph;
private Map<Dialogue, Node> cells = new HashMap<Dialogue, Node>();
public DialogueGraphView(Dialogue dialogue, NPC npc) {
super(new Visualization());
this.dialogue = dialogue;
if (npc != null) {
npcIcon = npc.getIcon();
} else {
npcIcon = DefaultIcons.getNPCIcon();
}
loadGraph();
// add visual data groups
m_vis.addGraph(GRAPH, graph);
m_vis.setInteractive(EDGES, null, false);
LabelRenderer nodeR = new MyLabelRenderer(LABEL);
nodeR.setHorizontalTextAlignment(prefuse.Constants.LEFT);
EdgeRenderer edgeR = new EdgeRenderer(prefuse.Constants.EDGE_TYPE_LINE, prefuse.Constants.EDGE_ARROW_FORWARD);
// edgeR.setEdgeType(prefuse.Constants.EDGE_TYPE_CURVE);
LabelRenderer edgeLabelR = new LabelRenderer(LABEL);
edgeLabelR.setRenderType(LabelRenderer.RENDER_TYPE_DRAW);
DefaultRendererFactory drf = new DefaultRendererFactory();
drf.setDefaultRenderer(nodeR);
drf.setDefaultEdgeRenderer(edgeR);
drf.add(new InGroupPredicate(EDGES_LABELS), edgeLabelR);
m_vis.setRendererFactory(drf);
DECORATOR_SCHEMA.setDefault(VisualItem.FILLCOLOR, ColorLib.gray(255));
DECORATOR_SCHEMA.setDefault(VisualItem.STROKECOLOR, ColorLib.rgba(0, 0, 0, 0));
DECORATOR_SCHEMA.setDefault(VisualItem.TEXTCOLOR, ColorLib.gray(0));
m_vis.addDecorators(EDGES_LABELS, EDGES, DECORATOR_SCHEMA);
// set up the visual operators
// first set up all the color actions
ColorAction nStrokeColor = new ColorAction(NODES, VisualItem.STROKECOLOR);
nStrokeColor.setDefaultColor(ColorLib.gray(100));
nStrokeColor.add("_hover", ColorLib.rgb(255,100,100));
StrokeAction nStroke = new EdgesStrokeAction(NODES);
ColorAction nFill = new NPCPhraseColorAction(NODES, VisualItem.FILLCOLOR);
ColorAction eEdges = new ConnectedEdgeColorAction(EDGES, VisualItem.STROKECOLOR);
ColorAction eArrows = new ConnectedEdgeColorAction(EDGES, VisualItem.FILLCOLOR);
ColorAction eEdgesLabels = new ConnectedEdgeColorAction(EDGES_LABELS, VisualItem.TEXTCOLOR);
StrokeAction eStroke = new EdgesStrokeAction(EDGES);
FontAction aFont = new FontAction();
ColorAction aFontColor = new ColorAction(NODES, VisualItem.TEXTCOLOR);
aFontColor.setDefaultColor(ColorLib.rgb(0, 0, 0));
// bundle the color actions
ActionList colors = new ActionList(Activity.INFINITY);
colors.add(nStrokeColor);
colors.add(nFill);
colors.add(nStroke);
colors.add(eEdges);
colors.add(eArrows);
colors.add(eEdgesLabels);
colors.add(eStroke);
colors.add(aFont);
colors.add(aFontColor);
colors.add(new RepaintAction());
m_vis.putAction("colors", colors);
// now create the main layout routine
ActionList layout = new ActionList();//Activity.INFINITY);
NodeLinkTreeLayout treeLayout = new NodeLinkTreeLayout(GRAPH, prefuse.Constants.ORIENT_LEFT_RIGHT, 120, 40, 40);
treeLayout.setLayoutAnchor(new Point2D.Double(25,300));
layout.add(treeLayout);
layout.add(new EdgesLabelDecoratorLayout(EDGES_LABELS));
layout.add(new RepaintAction());
m_vis.putAction("layout", layout);
// set up the display
setSize(500,500);
pan(250, 250);
setHighQuality(true);
addControlListener(new DoubleClickControl());
addControlListener(new WheelZoomControl());
addControlListener(new ZoomControl());
addControlListener(new PanControl());
// set things running
m_vis.run("colors");
m_vis.run("layout");
}
public void loadGraph() {
graph = new Graph(true);
graph.addColumn(LABEL, String.class, "");
graph.addColumn(ICON, Image.class, DefaultIcons.getNullifyIcon());
graph.addColumn(TARGET, GameDataElement.class, null);
graph.addColumn(REPLY, Dialogue.Reply.class, null);
graph.addColumn(HAS_REQS, boolean.class, false);
addDialogue(dialogue, npcIcon);
}
public Node addDialogue(Dialogue dialogue, Image npcIcon) {
if (cells.get(dialogue) == null) {
if (dialogue.switch_to_npc != null) {
npcIcon = dialogue.switch_to_npc.getIcon();
}
Node dNode = graph.addNode();
cells.put(dialogue, dNode);
dNode.setString(LABEL, dialogue.message != null ? dialogue.message : "[Selector]");
dNode.set(ICON, npcIcon);
dNode.set(TARGET, dialogue);
if (dialogue.replies != null) {
Node rNode;
int i = 1;
for (Dialogue.Reply r : dialogue.replies) {
rNode = addReply(dialogue, r, npcIcon);
Edge e = graph.addEdge(dNode, rNode);
e.setString(LABEL, "#"+i++);
e.setBoolean(HAS_REQS, r.requirements != null && !r.requirements.isEmpty());
}
}
}
return cells.get(dialogue);
}
public Node addReply(Dialogue d, Dialogue.Reply r, Image npcIcon) {
Node rNode;
if (r.text != null && !r.text.equals(Dialogue.Reply.GO_NEXT_TEXT)) {
//Normal reply...
rNode = graph.addNode();
rNode.setString(LABEL, r.text);
rNode.set(ICON, DefaultIcons.getHeroIcon());
rNode.set(TARGET, d);
rNode.set(REPLY, r);
if (r.next_phrase != null) {
//...that leads to another phrase
Node dNode = addDialogue(r.next_phrase, npcIcon);
graph.addEdge(rNode, dNode);
} else if (Dialogue.Reply.KEY_PHRASE_ID.contains(r.next_phrase_id)) {
//...that leads to a key phrase
Node kNode = addKeyPhraseNode(d, r.next_phrase_id);
kNode.set(REPLY, r);
graph.addEdge(rNode, kNode);
}
} else if (r.next_phrase != null) {
//Go directly to next phrase
rNode = addDialogue(r.next_phrase, npcIcon);
} else if (Dialogue.Reply.KEY_PHRASE_ID.contains(r.next_phrase_id)) {
//Go directly to key phrase
rNode = addKeyPhraseNode(d, r.next_phrase_id);
rNode.set(REPLY, r);
} else {
//Incomplete.
rNode = graph.addNode();
rNode.setString(LABEL, "[Incomplete reply]");
rNode.set(ICON, DefaultIcons.getNullifyIcon());
}
return rNode;
}
public Node addKeyPhraseNode(Dialogue d, String key) {
Node kNode = graph.addNode();
if (key.equals(Dialogue.Reply.EXIT_PHRASE_ID)) {
kNode.setString(LABEL, "[Ends dialogue]");
kNode.set(ICON, DefaultIcons.getNullifyIcon());
} else if (key.equals(Dialogue.Reply.FIGHT_PHRASE_ID)) {
kNode.setString(LABEL, "[Starts fight]");
kNode.set(ICON, DefaultIcons.getCombatIcon());
} else if (key.equals(Dialogue.Reply.REMOVE_PHRASE_ID)) {
kNode.setString(LABEL, "[NPC vanishes]");
kNode.set(ICON, DefaultIcons.getNPCCloseIcon());
} else if (key.equals(Dialogue.Reply.SHOP_PHRASE_ID)) {
kNode.setString(LABEL, "[Start trading]");
kNode.set(ICON, DefaultIcons.getGoldIcon());
} else {
//Should never reach, unless new key phrase ID are added to the model, but not here...
kNode.setString(LABEL, "[WTF !!]"+key);
}
kNode.set(TARGET, d);
return kNode;
}
class MyLabelRenderer extends LabelRenderer {
public MyLabelRenderer(String label) {
super(label);
}
@Override
protected Image getImage(VisualItem item) {
return (Image) item.get(ICON);
}
@Override
protected String getText(VisualItem item) {
return wordWrap(super.getText(item), 40);
}
public String wordWrap(String in, int length) {
final String newline = "\n";
//:: Trim
while(in.length() > 0 && (in.charAt(0) == '\t' || in.charAt(0) == ' ')) in = in.substring(1);
//:: If Small Enough Already, Return Original
if(in.length() < length) return in;
//:: If Next length Contains Newline, Split There
if(in.substring(0, length).contains(newline)) return in.substring(0, in.indexOf(newline)).trim() + newline + wordWrap(in.substring(in.indexOf("\n") + 1), length);
//:: Otherwise, Split Along Nearest Previous Space/Tab/Dash
int spaceIndex = Math.max(Math.max( in.lastIndexOf(" ", length), in.lastIndexOf("\t", length)), in.lastIndexOf("-", length));
//:: If No Nearest Space, Split At length
if(spaceIndex == -1) spaceIndex = length;
//:: Split
return in.substring(0, spaceIndex).trim() + newline + wordWrap(in.substring(spaceIndex), length);
}
}
class ConnectedEdgeColorAction extends ColorAction {
final int outgoing = ColorLib.rgb(255, 100, 100);
final int incoming = ColorLib.rgb(100, 255, 100);
final int none = ColorLib.gray(100);
public ConnectedEdgeColorAction(String group, String field) {
super(group, field);
}
@Override
public int getColor(VisualItem item) {
if (item instanceof DecoratorItem) {
item = ((DecoratorItem) item).getDecoratedItem();
}
if (item instanceof EdgeItem) {
if (((EdgeItem) item).getSourceItem().isHover()) {
return outgoing;
} else if (((EdgeItem) item).getTargetItem().isHover()) {
return incoming;
}
}
return none;
}
}
class NPCPhraseColorAction extends ColorAction {
final int none = ColorLib.gray(255);
final int hover = ColorLib.gray(200);
final int has_rewards = ColorLib.rgb(255, 255, 0);
final int has_rewards_hover = ColorLib.rgb(200, 200, 0);
public NPCPhraseColorAction(String group, String field) {
super(group, field);
}
@Override
public int getColor(VisualItem item) {
// Change color for Dialogues, not replies.
if (item.get(TARGET) != null && item.get(REPLY) == null) {
Dialogue d = (Dialogue) item.get(TARGET);
if (d.rewards != null && !d.rewards.isEmpty()) {
if (item.isHover()) {
return has_rewards_hover;
} else {
return has_rewards;
}
}
}
if (item.isHover()) {
return hover;
} else {
return none;
}
}
}
class EdgesStrokeAction extends StrokeAction {
public final BasicStroke req_stroke = new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1.0f, new float[]{3.5f, 2.5f}, 1.0f);
public final BasicStroke hover_stroke = new BasicStroke(3.0f);
public final BasicStroke hover_req_stroke = new BasicStroke(4.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 1.0f, new float[]{3.5f, 2.5f}, 1.0f);
public EdgesStrokeAction(String group) {
super(group);
}
@Override
public BasicStroke getStroke(VisualItem item) {
if (item.getBoolean(HAS_REQS)) {
if (item instanceof EdgeItem) {
if (((EdgeItem) item).getSourceItem().isHover()) {
return hover_req_stroke;
} else if (((EdgeItem) item).getTargetItem().isHover()) {
return hover_req_stroke;
}
}
return req_stroke;
} else {
if (item.isHover()) {
return hover_stroke;
} else if (item instanceof EdgeItem) {
if (((EdgeItem) item).getSourceItem().isHover()) {
return hover_stroke;
} else if (((EdgeItem) item).getTargetItem().isHover()) {
return hover_stroke;
}
}
}
return super.getStroke(item);
}
}
class EdgesLabelDecoratorLayout extends Layout {
public EdgesLabelDecoratorLayout(String group) {
super(group);
}
public void run(double frac) {
Iterator<?> iter = m_vis.items(m_group);
while ( iter.hasNext() ) {
DecoratorItem decorator = (DecoratorItem)iter.next();
if( decorator.getDecoratedItem() instanceof EdgeItem) {
EdgeItem edgeItem = (EdgeItem) decorator.getDecoratedItem();
double deltaX = edgeItem.getTargetItem().getX() - edgeItem.getSourceItem().getX();
double deltaY = edgeItem.getTargetItem().getY() - edgeItem.getSourceItem().getY();
double hypo = Math.hypot(deltaX, deltaY);
double edgePropX = deltaX / hypo;
double edgePropY = deltaY / hypo;
Point2D start = new Point2D.Double(edgeItem.getSourceItem().getBounds().getCenterX(), edgeItem.getSourceItem().getBounds().getCenterY());
Point2D end = new Point2D.Double(edgeItem.getTargetItem().getBounds().getCenterX(), edgeItem.getTargetItem().getBounds().getCenterY());
Point2D[] realStart = new Point2D[]{new Point2D.Double(), new Point2D.Double()};
// Point2D[] realEnd = new Point2D[]{new Point2D.Double(), new Point2D.Double()};
int i = GraphicsLib.intersectLineRectangle(start, end, edgeItem.getSourceItem().getBounds(), realStart);
if (i > 0) {
start = realStart[0];
}
// i = GraphicsLib.intersectLineRectangle(start, end, edgeItem.getTargetItem().getBounds(), realEnd);
// if (i > 0) {
// end = realEnd[0];
// }
double coef = 20 * Math.atan(hypo / 100.0) + 20;
setX(decorator, null, start.getX() + coef * edgePropX + 6 * Math.random() - 3);
setY(decorator, null, start.getY() + coef * edgePropY + 6 * Math.random() - 3);
} else {
VisualItem decoratedItem = decorator.getDecoratedItem();
Rectangle2D bounds = decoratedItem.getBounds();
double x = bounds.getCenterX();
double y = bounds.getCenterY();
setX(decorator, null, x + 10 * Math.random() - 5);
setY(decorator, null, y + 10 * Math.random() - 5);
}
}
}
}
class DoubleClickControl extends ControlAdapter {
@Override
public void itemClicked(VisualItem item, MouseEvent e) {
if (e.getClickCount() == 2) {
if (item.get(TARGET) != null) {
ATContentStudio.frame.openEditor((GameDataElement)item.get(TARGET));
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,511 @@
package com.gpl.rpg.atcontentstudio.ui.map;
import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JViewport;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.GameSource;
import com.gpl.rpg.atcontentstudio.model.ProjectTreeNode;
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.ui.DefaultIcons;
import com.gpl.rpg.atcontentstudio.ui.Editor;
import com.gpl.rpg.atcontentstudio.ui.SaveItemsWizard;
import com.jidesoft.swing.ComboBoxSearchable;
import com.jidesoft.swing.JideBoxLayout;
import com.jidesoft.swing.JideTabbedPane;
public class WorldMapEditor extends Editor {
private static final long serialVersionUID = -8358238912588729094L;
public EditMode editMode = EditMode.moveViewSelect;
public enum EditMode {
moveViewSelect,
moveMaps,
deleteMaps,
addMap
}
public String mapBeingAddedID = null;
public WorldMapEditor(WorldmapSegment worldmap) {
target = worldmap;
this.name = worldmap.id;
this.icon = new ImageIcon(worldmap.getIcon());
setLayout(new BorderLayout());
JideTabbedPane editorTabsHolder = new JideTabbedPane(JideTabbedPane.BOTTOM);
editorTabsHolder.setTabShape(JideTabbedPane.SHAPE_FLAT);
editorTabsHolder.setUseDefaultShowCloseButtonOnTab(false);
editorTabsHolder.setShowCloseButtonOnTab(false);
add(editorTabsHolder, BorderLayout.CENTER);
editorTabsHolder.add("Map", buildSegmentTab(worldmap));
}
@Override
public void targetUpdated() {
// TODO Auto-generated method stub
}
private JPanel buildSegmentTab(final WorldmapSegment worldmap) {
JPanel pane = new JPanel();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS));
addLabelField(pane, "Worldmap File: ", ((Worldmap)worldmap.getParent()).worldmapFile.getAbsolutePath());
pane.add(createButtonPane(worldmap), JideBoxLayout.FIX);
final WorldMapView mapView = new WorldMapView(worldmap);
JScrollPane mapScroller = new JScrollPane(mapView);
final JViewport vPort = mapScroller.getViewport();
final JSlider zoomSlider = new JSlider(WorldMapView.MIN_ZOOM, WorldMapView.MAX_ZOOM, (int)(mapView.zoomLevel / WorldMapView.ZOOM_RATIO));
zoomSlider.setSnapToTicks(true);
zoomSlider.setMinorTickSpacing(WorldMapView.INC_ZOOM);
zoomSlider.setOrientation(JSlider.VERTICAL);
JPanel zoomSliderPane = new JPanel();
zoomSliderPane.setLayout(new JideBoxLayout(zoomSliderPane, JideBoxLayout.PAGE_AXIS));
zoomSliderPane.add(zoomSlider, JideBoxLayout.VARY);
zoomSliderPane.add(new JLabel(new ImageIcon(DefaultIcons.getZoomIcon())), JideBoxLayout.FIX);
if (target.writable) {
JPanel mapToolsPane = new JPanel();
mapToolsPane.setLayout(new JideBoxLayout(mapToolsPane, JideBoxLayout.LINE_AXIS));
ButtonGroup mapToolsGroup = new ButtonGroup();
JRadioButton moveView = new JRadioButton("Select maps");
mapToolsGroup.add(moveView);
mapToolsPane.add(moveView, JideBoxLayout.FIX);
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);
final GDEComboModel<TMXMap> mapComboModel = new GDEComboModel<TMXMap>(worldmap.getProject(), null){
private static final long serialVersionUID = 2638082961277241764L;
@Override
public Object getTypedElementAt(int index) {
return project.getMap(index);
}
@Override
public int getSize() {
return project.getMapCount()+1;
}
};
final MyComboBox mapBox = new MyComboBox(TMXMap.class, mapComboModel);
mapBox.setRenderer(new GDERenderer(false, false));
new ComboBoxSearchable(mapBox){
@Override
protected String convertElementToString(Object object) {
if (object == null) return "none";
else return ((GameDataElement)object).getDesc();
}
};
mapBox.setEnabled(false);
mapToolsPane.add(mapBox, JideBoxLayout.FIX);
mapToolsPane.add(new JPanel(), JideBoxLayout.VARY);
moveView.setSelected(true);
pane.add(mapToolsPane, JideBoxLayout.FIX);
moveView.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
editMode = EditMode.moveViewSelect;
mapBox.setEnabled(false);
if (mapBeingAddedID != null) {
mapView.mapLocations.remove(mapBeingAddedID);
mapBeingAddedID = null;
mapView.revalidate();
mapView.repaint();
}
}
});
moveMaps.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
editMode = EditMode.moveMaps;
mapBox.setEnabled(false);
if (mapBeingAddedID != null) {
mapView.mapLocations.remove(mapBeingAddedID);
mapBeingAddedID = null;
mapView.revalidate();
mapView.repaint();
}
}
});
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) {
editMode = EditMode.addMap;
mapBox.setEnabled(true);
if (mapBox.getSelectedItem() != null) {
mapBeingAddedID = ((TMXMap)mapBox.getSelectedItem()).id;
}
}
});
mapBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (mapBox.getSelectedItem() == null) {
mapBeingAddedID = null;
} else {
mapBeingAddedID = ((TMXMap)mapBox.getSelectedItem()).id;
}
}
});
}
JPanel mapZoomPane = new JPanel();
mapZoomPane.setLayout(new BorderLayout());
mapZoomPane.add(zoomSliderPane, BorderLayout.WEST);
mapZoomPane.add(mapScroller, BorderLayout.CENTER);
pane.add(mapZoomPane, JideBoxLayout.VARY);
zoomSlider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
Rectangle view = vPort.getViewRect();
float oldZoomLevel = mapView.zoomLevel;
mapView.zoomLevel = zoomSlider.getValue() * WorldMapView.ZOOM_RATIO;
int newCenterX = (int) (view.getCenterX() / oldZoomLevel * mapView.zoomLevel);
int newCenterY = (int) (view.getCenterY() / oldZoomLevel * mapView.zoomLevel);
view.x = newCenterX - (view.width / 2);
view.y = newCenterY - (view.height / 2);
mapView.scrollRectToVisible(view);
mapView.revalidate();
mapView.repaint();
}
});
MouseAdapter mouseListener = new MouseAdapter() {
final int skipRecomputeDefault = 5;
Point dragStart = null;
int skipRecompute = 0;
@Override
public void mouseClicked(MouseEvent e) {
String selectedMap = null;
boolean update = false;
int x = (int) (e.getX() / mapView.zoomLevel);
int y = (int) (e.getY() / mapView.zoomLevel);
for (String s : mapView.mapLocations.keySet()) {
if (mapView.mapLocations.get(s).contains(x, y)) {
selectedMap = s;
break;
}
}
if (editMode == EditMode.moveViewSelect) {
if (selectedMap == null) return;
if (e.getButton() == MouseEvent.BUTTON1) {
if (e.isControlDown() || e.isShiftDown()) {
if (mapView.selected.contains(selectedMap)) {
mapView.selected.remove(selectedMap);
update = true;
} else {
mapView.selected.add(selectedMap);
update = true;
}
} else {
mapView.selected.clear();
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.labelLocations.remove(selectedMap);
mapView.selected.remove(selectedMap);
mapView.updateFromModel();
update = true;
} else if (editMode == EditMode.addMap && mapBeingAddedID != null) {
if (e.getButton() == MouseEvent.BUTTON1) {
mapView.recomputeSize();
mapView.pushToModel();
}
mapView.updateFromModel();
update = true;
mapBeingAddedID = null;
}
if (update) {
mapView.revalidate();
mapView.repaint();
}
}
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
dragStart = e.getLocationOnScreen();
}
}
@Override
public void mouseReleased(MouseEvent e) {
dragStart = null;
if (editMode == EditMode.moveMaps) {
mapView.pushToModel();
}
}
@Override
public void mouseMoved(MouseEvent e) {
if (editMode == EditMode.addMap && mapBeingAddedID != null) {
int x = (int) (e.getX() / mapView.zoomLevel);
int y = (int) (e.getY() / mapView.zoomLevel);
TMXMap map = target.getProject().getMap(mapBeingAddedID);
int w = map.tmxMap.getWidth() * WorldMapView.TILE_SIZE;
int h = map.tmxMap.getHeight() * WorldMapView.TILE_SIZE;
x -= w / 2;
x -= x % WorldMapView.TILE_SIZE;
y -= h / 2;
y -= y % WorldMapView.TILE_SIZE;
mapView.mapLocations.put(mapBeingAddedID, new Rectangle(x, y, w, h));
if (--skipRecompute <= 0) {
if (mapView.recomputeSize()) {
skipRecompute = skipRecomputeDefault;
}
}
mapView.revalidate();
mapView.repaint();
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (dragStart == null) return;
int deltaX = e.getXOnScreen() - dragStart.x;
int deltaY = e.getYOnScreen() - dragStart.y;
if (editMode != EditMode.moveMaps) {
Rectangle view = vPort.getViewRect();
view.setLocation(view.x - deltaX, view.y - deltaY);
mapView.scrollRectToVisible(view);
dragStart = e.getLocationOnScreen();
} else {
int mapDeltaX = (int) ((deltaX / mapView.zoomLevel));
int mapDeltaY = (int) ((deltaY / mapView.zoomLevel));
mapDeltaX -= mapDeltaX % WorldMapView.TILE_SIZE;
mapDeltaY -= mapDeltaY % WorldMapView.TILE_SIZE;
for (String s : mapView.selected) {
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;
}
if (--skipRecompute <= 0) {
if (mapView.recomputeSize()) {
skipRecompute = skipRecomputeDefault;
}
}
mapView.revalidate();
mapView.repaint();
}
}
};
mapView.addMouseListener(mouseListener);
mapView.addMouseMotionListener(mouseListener);
return pane;
}
public JPanel createButtonPane(final WorldmapSegment node) {
final JButton gdeIcon = new JButton(new ImageIcon(DefaultIcons.getUIMapImage()));
JPanel savePane = new JPanel();
savePane.add(gdeIcon, JideBoxLayout.FIX);
savePane.setLayout(new JideBoxLayout(savePane, JideBoxLayout.LINE_AXIS, 6));
if (node.writable) {
if (node.getDataType() == GameSource.Type.altered) {
savePane.add(message = new JLabel(ALTERED_MESSAGE), JideBoxLayout.FIX);
} else if (node.getDataType() == GameSource.Type.created) {
savePane.add(message = new JLabel(CREATED_MESSAGE), JideBoxLayout.FIX);
}
JButton save = new JButton(SAVE);
save.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (node.getParent() instanceof Worldmap) {
if (node.state != GameDataElement.State.saved) {
final List<SaveEvent> events = node.attemptSave();
if (events == null) {
ATContentStudio.frame.nodeChanged(node);
} else {
new Thread() {
@Override
public void run() {
new SaveItemsWizard(events, node).setVisible(true);
}
}.start();
}
}
}
}
});
savePane.add(save, JideBoxLayout.FIX);
JButton delete = new JButton(DELETE);
if (node.getDataType() == GameSource.Type.altered) {
delete.setText(REVERT);
}
delete.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ATContentStudio.frame.closeEditor(node);
node.childrenRemoved(new ArrayList<ProjectTreeNode>());
if (node.getParent() instanceof Worldmap) {
((Worldmap)node.getParent()).remove(node);
node.save();
for (GameDataElement backlink : node.getBacklinks()) {
backlink.elementChanged(node, node.getProject().getWorldmapSegment(node.id));
}
}
}
});
savePane.add(delete, JideBoxLayout.FIX);
} else {
if (node.getProject().alteredContent.getWorldmapSegment(node.id) != null) {
savePane.add(message = new JLabel(ALTERED_EXISTS_MESSAGE), JideBoxLayout.FIX);
JButton makeWritable = new JButton("Go to altered");
makeWritable.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (node.getProject().getWorldmapSegment(node.id) != node) {
ATContentStudio.frame.openEditor(node.getProject().getWorldmapSegment(node.id));
ATContentStudio.frame.closeEditor(node);
ATContentStudio.frame.selectInTree(node.getProject().getWorldmapSegment(node.id));
}
}
});
savePane.add(makeWritable, JideBoxLayout.FIX);
} else {
savePane.add(message = new JLabel(READ_ONLY_MESSAGE), JideBoxLayout.FIX);
JButton makeWritable = new JButton("Alter");
makeWritable.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (node.getProject().getWorldmapSegment(node.id) == node) {
node.getProject().makeWritable(node);
}
if (node.getProject().getWorldmapSegment(node.id) != node) {
ATContentStudio.frame.openEditor(node.getProject().getWorldmapSegment(node.id));
ATContentStudio.frame.closeEditor(node);
ATContentStudio.frame.selectInTree(node.getProject().getWorldmapSegment(node.id));
}
updateMessage();
}
});
savePane.add(makeWritable, JideBoxLayout.FIX);
}
}
JButton prev = new JButton(new ImageIcon(DefaultIcons.getArrowLeftIcon()));
JButton next = new JButton(new ImageIcon(DefaultIcons.getArrowRightIcon()));
savePane.add(prev, JideBoxLayout.FIX);
savePane.add(next, JideBoxLayout.FIX);
if (node.getParent().getIndex(node) == 0) {
prev.setEnabled(false);
}
if (node.getParent().getIndex(node) == node.getParent().getChildCount() - 1) {
next.setEnabled(false);
}
prev.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ProjectTreeNode prevNode = (ProjectTreeNode) node.getParent().getChildAt(node.getParent().getIndex(node) - 1);
if (prevNode != null && prevNode instanceof GameDataElement) {
ATContentStudio.frame.openEditor((GameDataElement) prevNode);
}
}
});
next.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ProjectTreeNode nextNode = (ProjectTreeNode) node.getParent().getChildAt(node.getParent().getIndex(node) + 1);
if (nextNode != null && nextNode instanceof GameDataElement) {
ATContentStudio.frame.openEditor((GameDataElement) nextNode);
}
}
});
//Placeholder. Fills the eventual remaining space.
savePane.add(new JPanel(), JideBoxLayout.VARY);
return savePane;
}
public void updateMessage() {
//TODO make this a full update of the button panel.
WorldmapSegment node = (WorldmapSegment) target;
if (node.writable) {
if (node.getDataType() == GameSource.Type.altered) {
message.setText(ALTERED_MESSAGE);
} else if (node.getDataType() == GameSource.Type.created) {
message.setText(CREATED_MESSAGE);
}
} else if (node.getProject().alteredContent.getWorldmapSegment(node.id) != null) {
message.setText(ALTERED_EXISTS_MESSAGE);
} else {
message.setText(READ_ONLY_MESSAGE);
}
message.revalidate();
message.repaint();
}
}

View File

@@ -0,0 +1,245 @@
package com.gpl.rpg.atcontentstudio.ui.map;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.Scrollable;
import tiled.view.MapRenderer;
import tiled.view.OrthogonalRenderer;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.maps.WorldmapSegment;
public class WorldMapView extends JComponent implements Scrollable {
private static final long serialVersionUID = -4111374378777093799L;
public static final int TILE_SIZE = 32;
public static final int MIN_ZOOM = 5;
public static final int MAX_ZOOM = 250;
public static final int INC_ZOOM = 5;
public static final float ZOOM_RATIO = 0.01f;
WorldmapSegment worldmap;
Project proj;
public Map<String, Rectangle> mapLocations = new HashMap<String, Rectangle>();
public Set<String> selected = new HashSet<String>();
public float zoomLevel = 0.1f;
int sizeX = 0, sizeY = 0;
int offsetX = 0, offsetY = 0;
public WorldMapView(WorldmapSegment worldmap) {
this.worldmap = worldmap;
this.proj = worldmap.getProject();
updateFromModel();
}
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));
for (String s : mapLocations.keySet()) {
int x = mapLocations.get(s).x;
int y = mapLocations.get(s).y;
g2.translate(x, y);
TMXMap map = proj.getMap(s);
if (map == null) continue;
MapRenderer renderer = new OrthogonalRenderer(map.tmxMap);
// Draw each tile map layer
for (tiled.core.MapLayer layer : ((TMXMap)map).tmxMap) {
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);
}
}
if (selected.contains(s)) {
g2.drawRect(0, 0, map.tmxMap.getWidth() * TILE_SIZE, map.tmxMap.getHeight() * TILE_SIZE);
}
g2.translate(-x, -y);
}
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g.create();
try {
g2.scale(zoomLevel, zoomLevel);
// g2.drawImage(img, 0, 0, null);
paintOnGraphics(g2);
} finally {
g2.dispose();
}
}
// private boolean paintObjectGroup(Graphics2D g2d, TMXMap map, tiled.core.ObjectGroup layer) {
// boolean paintSelected = false;
// for (MapObjectGroup group : map.groups) {
// if (group.tmxGroup == layer) {
// for (MapObject object : group.mapObjects) {
// drawObject(object, g2d, new Color(20, 20, 190));
// }
// break;
// }
// }
// return paintSelected;
// }
//
// 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);
// }
@Override
public Dimension getPreferredSize() {
return new Dimension((int)(zoomLevel * sizeX), (int)(zoomLevel * sizeY));
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return TILE_SIZE;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 4 * TILE_SIZE;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return false;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
public boolean recomputeSize() {
sizeX = sizeY = 0;
boolean originMoved = false;
int minX = Integer.MAX_VALUE, minY= Integer.MAX_VALUE;
for (String s : mapLocations.keySet()) {
int x = mapLocations.get(s).x;
int w = proj.getMap(s).tmxMap.getWidth() * TILE_SIZE;
int y = mapLocations.get(s).y;
int h = proj.getMap(s).tmxMap.getHeight() * TILE_SIZE;
sizeX = Math.max(sizeX, x + w);
sizeY = Math.max(sizeY, y + h);
minX = Math.min(minX, x);
minY = Math.min(minY, y);
}
if (minX != 0) {
for (String s : mapLocations.keySet()) {
mapLocations.get(s).x -= minX;
}
sizeX -= minX;
offsetX += minX;
originMoved = true;
}
if (minY != 0) {
for (String s : mapLocations.keySet()) {
mapLocations.get(s).y -= minY;
}
sizeY -= minY;
offsetY += minY;
originMoved = true;
}
return originMoved;
}
public void updateFromModel() {
mapLocations.clear();
sizeX = sizeY = 0;
offsetX = worldmap.segmentX * TILE_SIZE;
offsetY = worldmap.segmentY * TILE_SIZE;
for (String s : worldmap.mapLocations.keySet()) {
int x = worldmap.mapLocations.get(s).x * TILE_SIZE;
int w = proj.getMap(s).tmxMap.getWidth() * TILE_SIZE;
int y = worldmap.mapLocations.get(s).y * TILE_SIZE;
int h = proj.getMap(s).tmxMap.getHeight() * TILE_SIZE;
sizeX = Math.max(sizeX, x + w);
sizeY = Math.max(sizeY, y + h);
mapLocations.put(s, new Rectangle(x, y, w, h));
}
}
public void pushToModel() {
worldmap.segmentX = offsetX / TILE_SIZE;
worldmap.segmentY = offsetY / TILE_SIZE;
worldmap.mapLocations.clear();
for (String s : mapLocations.keySet()) {
int x = mapLocations.get(s).x / TILE_SIZE;
int y = mapLocations.get(s).y / TILE_SIZE;
worldmap.mapLocations.put(s, new Point(x, y));
}
List<String> toRemove = new ArrayList<String>();
for (String s : worldmap.labelLocations.keySet()) {
if (!mapLocations.containsKey(s)) {
toRemove.add(s);
}
}
for (String s : toRemove) {
worldmap.labelLocations.remove(s);
}
}
}

View File

@@ -0,0 +1,32 @@
package com.gpl.rpg.atcontentstudio.ui.saves;
import java.awt.BorderLayout;
import javax.swing.ImageIcon;
import javax.swing.JScrollPane;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.saves.SavedGame;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
import com.gpl.rpg.atcontentstudio.ui.Editor;
public class SavedGameEditor extends Editor {
private static final long serialVersionUID = 6055910379650778737L;
public SavedGameEditor(SavedGame save) {
this.name = save.loadedSave.displayInfo;
this.icon = new ImageIcon(DefaultIcons.getHeroIcon());
this.target = save;
setLayout(new BorderLayout());
add(new JScrollPane(new com.gpl.rpg.andorstrainer.ui.SavedGameEditor(save.loadedSave, ATContentStudio.frame)), BorderLayout.CENTER);
}
@Override
public void targetUpdated() {
// TODO Auto-generated method stub
}
}

View File

@@ -0,0 +1,235 @@
package com.gpl.rpg.atcontentstudio.ui.sprites;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.ScrollPaneConstants;
import com.gpl.rpg.atcontentstudio.ATContentStudio;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet.Category;
public class SpriteChooser extends JDialog {
private static final long serialVersionUID = -6018113265015159521L;
private static final int STD_WIDTH = 32;
private static final int STD_HEIGHT = 32;
private static final int MAX_PER_ROW = 10;
public static Map<Project, Map<Spritesheet.Category, SpriteChooser>> cache = new HashMap<Project, Map<Spritesheet.Category,SpriteChooser>>();
public static SpriteChooser getChooser(Project proj, Spritesheet.Category category) {
if (cache.get(proj) == null) {
cache.put(proj, new HashMap<Spritesheet.Category, SpriteChooser>());
}
if (cache.get(proj).get(category) == null) {
cache.get(proj).put(category, new SpriteChooser(proj, category));
}
SpriteChooser wanted = cache.get(proj).get(category);
wanted.group.clearSelection();
wanted.selectedIconId = null;
// wanted.selectedOne = null;
wanted.listener = null;
// wanted.ok.setEnabled(false);
wanted.pack();
return wanted;
}
private ButtonGroup group;
// private IconButton selectedOne = null;
// private JButton ok;
// private JButton cancel;
public String selectedIconId = null;
public SpriteChooser(Project proj, Category category) {
super(ATContentStudio.frame);
setTitle("Select a sprite");
setModalityType(ModalityType.APPLICATION_MODAL);
List<Spritesheet> spritesheets = new ArrayList<Spritesheet>();
for (Spritesheet sheet : proj.baseContent.gameSprites.spritesheets) {
if (sheet.category == category) {
spritesheets.add(sheet);
}
}
JPanel pane = new JPanel();
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.weightx = 1;
c.weighty = 1;
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 1;
c.gridheight = 1;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
List<Point> reservedSlots = new ArrayList<Point>();
Point nextFreeSlot = new Point(0, 0);
int i;
Image img;
group = new ButtonGroup();
for (Spritesheet sheet : spritesheets) {
i = 0;
while ((img = sheet.getImage(i)) != null) {
IconButton button = new IconButton(img, sheet.id, i);
group.add(button);
if (sheet.spriteWidth == STD_WIDTH && sheet.spriteHeight == STD_HEIGHT) {
pane.add(button, c);
c.gridx++;
if (c.gridx >= MAX_PER_ROW) {
c.gridx = 0;
c.gridy++;
}
nextFreeSlot.setLocation(c.gridx, c.gridy);
} else {
c.gridwidth = (sheet.spriteWidth / STD_WIDTH) + (sheet.spriteWidth % STD_WIDTH == 0 ? 0 : 1);
c.gridheight = (sheet.spriteHeight / STD_HEIGHT) + (sheet.spriteHeight % STD_HEIGHT == 0 ? 0 : 1);
boolean slotOk = false;
while (!slotOk) {
slotOk = true;
for (int x = c.gridx; x < c.gridx + c.gridwidth; x++) {
for (int y = c.gridy; y < c.gridy + c.gridwidth; y++) {
if (reservedSlots.contains(new Point(x, y))) {
slotOk = false;
}
}
}
if (slotOk && c.gridx + c.gridwidth > MAX_PER_ROW) {
c.gridx = 0;
c.gridy++;
slotOk = false;
}
}
pane.add(button, c);
for (int x = c.gridx; x < c.gridx + c.gridwidth; x++) {
for (int y = c.gridy; y < c.gridy + c.gridwidth; y++) {
reservedSlots.add(new Point(x, y));
}
}
c.gridwidth = 1;
c.gridheight = 1;
c.gridx = nextFreeSlot.x;
c.gridy = nextFreeSlot.y;
}
while (reservedSlots.contains(nextFreeSlot)) {
c.gridx++;
if (c.gridx >= MAX_PER_ROW) {
c.gridx = 0;
c.gridy++;
}
nextFreeSlot.setLocation(c.gridx, c.gridy);
}
i++;
}
}
// ok = new JButton("Ok");
// cancel = new JButton("Cancel");
c.gridx = 0;
boolean emptyLine = false;
while (!emptyLine) {
c.gridy++;
emptyLine = true;
for (i = MAX_PER_ROW - 1; i >= 0; i--) {
if (reservedSlots.contains(new Point(i, c.gridy))) {
emptyLine = false;
continue;
}
}
}
// JPanel buttonPane = new JPanel();
// buttonPane.add(cancel, BorderLayout.WEST);
// buttonPane.add(ok, BorderLayout.EAST);
JPanel wrapper = new JPanel();
wrapper.setLayout(new BorderLayout());
JScrollPane scroller = new JScrollPane(pane);
scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
wrapper.add(scroller, BorderLayout.CENTER);
// wrapper.add(buttonPane, BorderLayout.SOUTH);
// ok.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// selectedIconId = selectedOne.sheetId+":"+selectedOne.spriteIndex;
// SpriteChooser.this.setVisible(false);
// SpriteChooser.this.dispose();
// if (listener != null) listener.iconSelected(selectedIconId);
// }
// });
// cancel.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// selectedIconId = null;
// SpriteChooser.this.setVisible(false);
// SpriteChooser.this.dispose();
// if (listener != null) listener.iconSelected(null);
// }
// });
setContentPane(wrapper);
}
private SpriteChooser.SelectionListener listener = null;
public void setSelectionListener(SpriteChooser.SelectionListener l) {
listener = l;
}
public class IconButton extends JToggleButton {
private static final long serialVersionUID = 7559407153561178455L;
public String sheetId;
public int spriteIndex;
public IconButton(Image img, String sheetId, int spriteIndex) {
super(new ImageIcon(img));
this.sheetId = sheetId;
this.spriteIndex = spriteIndex;
setToolTipText(sheetId+":"+spriteIndex);
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (IconButton.this.isSelected()) {
selectedIconId = IconButton.this.sheetId+":"+IconButton.this.spriteIndex;
SpriteChooser.this.setVisible(false);
SpriteChooser.this.dispose();
if (listener != null) listener.iconSelected(selectedIconId);
}
}
});
}
}
public static interface SelectionListener {
public void iconSelected(String selected);
}
}

View File

@@ -0,0 +1,431 @@
package com.gpl.rpg.atcontentstudio.ui.sprites;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Image;
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.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
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.ProjectTreeNode;
import com.gpl.rpg.atcontentstudio.model.maps.TMXMap;
import com.gpl.rpg.atcontentstudio.model.sprites.Spritesheet;
import com.gpl.rpg.atcontentstudio.ui.Editor;
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
import com.jidesoft.swing.JideBoxLayout;
import com.jidesoft.swing.JideTabbedPane;
public class SpritesheetEditor extends Editor {
private static final long serialVersionUID = 3956109815682889863L;
Map<String, JPanel> editorTabs = new HashMap<String, JPanel>();
JideTabbedPane editorTabsHolder;
private JSpinner widthField;
private JSpinner heightField;
private JCheckBox animatedBox;
private JComboBox categoryBox;
private JPanel spriteViewPane;
public static JComponent getWarningLabel() {
JLabel label = new JLabel(
"<html><i>" +
"The data presented here is not part of the game.<br/>" +
"What you change here will be changed in your ATCS project.<br/>" +
"None of this is exported to JSON or TMX, although it must be set correctly in order to choose tiles & icons correctly.<br/>" +
"</i></html>");
return label;
}
public SpritesheetEditor(Spritesheet sheet) {
super();
this.icon = new ImageIcon(sheet.getIcon(0));
this.name = sheet.id;
this.target = sheet;
JPanel pane = new JPanel();
final FieldUpdateListener listener = new SpritesheetFieldUpdater();
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
add(getWarningLabel(), JideBoxLayout.FIX);
addLabelField(pane, "Spritesheet ID: ", sheet.id);
addLabelField(pane, "File: ", sheet.spritesheetFile.getAbsolutePath());
widthField = addIntegerField(pane, "Sprite width (px): ", sheet.spriteWidth, false, true, listener);
heightField = addIntegerField(pane, "Sprite height (px): ", sheet.spriteHeight, false, true, listener);
animatedBox = addBooleanBasedCheckBox(pane, "Is an animation", sheet.animated, true, listener);
categoryBox = addEnumValueBox(pane, "Category: ", Spritesheet.Category.values(), sheet.category, true, listener);
spriteViewPane = new JPanel();
updateView(spriteViewPane);
pane.add(spriteViewPane, JideBoxLayout.FIX);
addBacklinksList(pane, sheet);
//Placeholder. Fills the eventual remaining space.
pane.add(new JPanel(), JideBoxLayout.VARY);
setLayout(new BorderLayout());
editorTabsHolder = new JideTabbedPane(JideTabbedPane.BOTTOM);
editorTabsHolder.setTabShape(JideTabbedPane.SHAPE_FLAT);
editorTabsHolder.setUseDefaultShowCloseButtonOnTab(false);
editorTabsHolder.setShowCloseButtonOnTab(false);
add(editorTabsHolder, BorderLayout.CENTER);
JScrollPane sheetScroller = new JScrollPane(pane);
sheetScroller.getVerticalScrollBar().setUnitIncrement(16);
editorTabsHolder.add("Spritesheet",sheetScroller);
JScrollPane rawScroller = new JScrollPane(new JLabel(new ImageIcon(sheet.spritesheet)));
rawScroller.getVerticalScrollBar().setUnitIncrement(16);
editorTabsHolder.add("Raw image", rawScroller);
}
private Thread animator = new Thread();
private boolean animate = true;
private JLabel iconLabel;
private List<ImageIcon> icons = null;
public void updateView(JPanel pane) {
Spritesheet sheet = (Spritesheet)target;
pane.removeAll();
pane.setLayout(new BorderLayout());
if (sheet.animated) {
iconLabel = new JLabel();
iconLabel.setBackground(Color.WHITE);
if (icons == null) {
icons = new ArrayList<ImageIcon>();
} else {
icons.clear();
}
int i = 0;
Image img;
while ((img = sheet.getImage(i++)) != null) {
icons.add(new ImageIcon(img));
}
if (i > 0) {
iconLabel.setIcon(icons.get(0));
}
pane.add(iconLabel, BorderLayout.CENTER);
resetAnimator();
} else {
JTable spritesTable = new JTable(new SpritesheetTableModel(sheet));
spritesTable.setDefaultRenderer(Image.class, new SpritesheetCellRenderer(sheet));
spritesTable.setCellSelectionEnabled(true);
spritesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
spritesTable.getTableHeader().setVisible(false);
Enumeration<TableColumn> columns = spritesTable.getColumnModel().getColumns();
TableColumn col;
while (columns.hasMoreElements()) {
col = columns.nextElement();
col.setMinWidth(sheet.spriteWidth + 1);
col.setMaxWidth(sheet.spriteWidth + 1);
}
spritesTable.setRowHeight(sheet.spriteHeight + 1);
pane.add(new JScrollPane(spritesTable), BorderLayout.CENTER);
}
}
public static JList addBacklinksList(JPanel pane, Spritesheet sheet) {
final JList list = new JList(new SpritesheetsBacklinksListModel(sheet));
list.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
if (list.getSelectedValue() instanceof TMXMap) {
ATContentStudio.frame.openEditor((TMXMap)list.getSelectedValue());
ATContentStudio.frame.selectInTree((TMXMap)list.getSelectedValue());
} else if (list.getSelectedValue() instanceof GameDataElement) {
ATContentStudio.frame.openEditor((GameDataElement)list.getSelectedValue());
ATContentStudio.frame.selectInTree((GameDataElement)list.getSelectedValue());
}
}
}
});
list.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
if (list.getSelectedValue() instanceof TMXMap) {
ATContentStudio.frame.openEditor((TMXMap)list.getSelectedValue());
ATContentStudio.frame.selectInTree((TMXMap)list.getSelectedValue());
} else if (list.getSelectedValue() instanceof GameDataElement) {
ATContentStudio.frame.openEditor((GameDataElement)list.getSelectedValue());
ATContentStudio.frame.selectInTree((GameDataElement)list.getSelectedValue());
}
}
}
});
list.setCellRenderer(new BacklinkCellRenderer(true));
JScrollPane scroller = new JScrollPane(list);
scroller.setBorder(BorderFactory.createTitledBorder("Elements pointing to this spritesheet."));
pane.add(scroller, JideBoxLayout.FIX);
return list;
}
public static class SpritesheetTableModel implements TableModel {
Spritesheet sheet;
public SpritesheetTableModel(Spritesheet sheet) {
this.sheet = sheet;
}
@Override
public int getRowCount() {
return (sheet.spritesheet.getHeight() / sheet.spriteHeight) + ((sheet.spritesheet.getHeight() % sheet.spriteHeight) == 0 ? 0 : 1);
}
@Override
public int getColumnCount() {
return (sheet.spritesheet.getWidth() / sheet.spriteWidth) + ((sheet.spritesheet.getWidth() % sheet.spriteWidth) == 0 ? 0 : 1);
}
@Override
public String getColumnName(int columnIndex) {
return "";
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return Image.class;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return sheet.getImage((rowIndex * getColumnCount()) + columnIndex);
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
List<TableModelListener> listeners = new ArrayList<TableModelListener>();
@Override
public void addTableModelListener(TableModelListener l) {
listeners.add(l);
}
@Override
public void removeTableModelListener(TableModelListener l) {
listeners.remove(l);
}
}
public static class SpritesheetCellRenderer extends DefaultTableCellRenderer {
private static final long serialVersionUID = -4213756343124247612L;
Spritesheet sheet;
public SpritesheetCellRenderer(Spritesheet sheet) {
super();
this.sheet = sheet;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (c instanceof JLabel) {
((JLabel)c).setText("");
if (value != null) {
((JLabel)c).setIcon(new ImageIcon((Image)value));
((JLabel)c).setToolTipText(sheet.id+":"+((row * table.getColumnCount())+column));
}
}
return c;
}
}
@Override
public void setVisible(boolean aFlag) {
super.setVisible(aFlag);
animate = aFlag;
if (aFlag && animator != null) {
resetAnimator();
}
}
private void resetAnimator() {
new Thread() {
public void run() {
if (animator != null && animator.isAlive()) {
try {
animator.join();
} catch (InterruptedException e) {}
}
animate = true;
animator = new Thread() {
public void run() {
int i = -1;
while (animate) {
if (icons != null) {
synchronized (icons) {
i = (i + 1) % icons.size();
iconLabel.setIcon(icons.get(i));
}
iconLabel.revalidate();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
};
};
animator.start();
}
}.start();
}
public static class SpritesheetsBacklinksListModel implements ListModel {
Spritesheet sheet;
public SpritesheetsBacklinksListModel(Spritesheet sheet) {
this.sheet = sheet;
}
@Override
public int getSize() {
return sheet.getBacklinks().size();
}
@Override
public Object getElementAt(int index) {
for (ProjectTreeNode node : sheet.getBacklinks()) {
if (index == 0) return node;
index --;
}
return null;
}
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 void fireListChanged() {
for (ListDataListener l : listeners) {
l.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, this.getSize()));
}
}
}
public static class BacklinkCellRenderer extends DefaultListCellRenderer {
private static final long serialVersionUID = 6819681566800482793L;
private boolean includeType = false;
public BacklinkCellRenderer(boolean includeType) {
super();
this.includeType = includeType;
}
@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 {
if (includeType && ((ProjectTreeNode)value).getDataType() != null) {
label.setText(((ProjectTreeNode)value).getDataType().toString()+"/"+((ProjectTreeNode)value).getDesc());
} else {
label.setText(((ProjectTreeNode)value).getDesc());
}
if (((ProjectTreeNode)value).getIcon() == null) {
Notification.addError("Unable to find icon for "+((ProjectTreeNode)value).getDesc());
} else {
label.setIcon(new ImageIcon(((ProjectTreeNode)value).getIcon()));
}
}
return label;
}
}
@Override
public void targetUpdated() {
this.icon = new ImageIcon(((Spritesheet)target).getIcon(0));
this.name = ((Spritesheet)target).id;
}
public class SpritesheetFieldUpdater implements FieldUpdateListener {
@Override
public void valueChanged(JComponent source, Object value) {
Spritesheet sheet = (Spritesheet) target;
if (source == widthField) {
sheet.spriteWidth = (Integer) value;
sheet.clearCache();
updateView(spriteViewPane);
spriteViewPane.revalidate();
spriteViewPane.repaint();
} else if (source == heightField) {
sheet.spriteHeight = (Integer) value;
sheet.clearCache();
updateView(spriteViewPane);
spriteViewPane.revalidate();
spriteViewPane.repaint();
} else if (source == animatedBox) {
sheet.animated = (Boolean) value;
if (!sheet.animated) {
animate = false;
}
updateView(spriteViewPane);
spriteViewPane.revalidate();
spriteViewPane.repaint();
} else if (source == categoryBox) {
sheet.category = (Spritesheet.Category) value;
}
}
}
}

View File

@@ -0,0 +1,81 @@
package com.gpl.rpg.atcontentstudio.ui.tools;
import java.awt.BorderLayout;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.TableModel;
import com.gpl.rpg.atcontentstudio.model.GameDataElement;
import com.gpl.rpg.atcontentstudio.model.SaveEvent;
import com.gpl.rpg.atcontentstudio.model.gamedata.GameDataSet;
import com.gpl.rpg.atcontentstudio.ui.Editor;
public class ElementTableView extends Editor {
private static final long serialVersionUID = 8048693233599125878L;
public ElementTableView(TableModel elementTableModel, String title, Icon icon) {
this.target = new DummyGDE();
this.name = title;
this.icon = icon;
setLayout(new BorderLayout());
JTable table = new JTable(elementTableModel) {
private static final long serialVersionUID = -2738230330859706440L;
public boolean getScrollableTracksViewportWidth() {
return getPreferredSize().width < getParent().getWidth();
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.setAutoCreateRowSorter(true);
table.setAutoscrolls(true);
table.setCellSelectionEnabled(false);
table.setRowSelectionAllowed(true);
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
add(new JScrollPane(table), BorderLayout.CENTER);
}
@Override
public void targetUpdated() {
}
class DummyGDE extends GameDataElement {
private static final long serialVersionUID = 5889666999423783180L;
@Override
public GameDataSet getDataSet() {return null;}
@Override
public String getDesc() {return null;}
@Override
public void parse() {}
@Override
public void link() {}
@Override
public GameDataElement clone() {return null;}
@Override
public void elementChanged(GameDataElement oldOne, GameDataElement newOne) {}
@Override
public String getProjectFilename() {return null;}
@Override
public void save() {}
@Override
public List<SaveEvent> attemptSave() {return null;}
}
}

View File

@@ -0,0 +1,214 @@
package com.gpl.rpg.atcontentstudio.ui.tools;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.gamedata.Item;
import com.gpl.rpg.atcontentstudio.model.gamedata.ItemCategory;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
public class ItemsTableView extends ElementTableView {
private static final long serialVersionUID = 1474255176349837609L;
public ItemsTableView(Project proj) {
super(new ItemsTableModel(proj), "Compare "+proj.getItemCount()+" items.", new ImageIcon(DefaultIcons.getItemIcon()));
}
private static class ItemsTableModel implements TableModel {
Project proj;
public ItemsTableModel(Project proj) {
this.proj = proj;
}
@Override
public int getRowCount() {
// return proj.getItemCount() + 1;
return proj.getItemCount();
}
@Override
public int getColumnCount() {
return 32;
}
@Override
public String getColumnName(int columnIndex) {
switch (columnIndex) {
case 0: return "Icon"; //Icon
case 1: return "ID"; //ID
case 2: return "Name"; //Name
case 3: return "Folder type"; //Source type (created, altered, source)
case 4: return "Use type"; //Use type ("none", "use", or equip slot name).
case 5: return "Category"; //Category id.
case 6: return "Manually set price ?"; //Has manual price
case 7: return "Price"; //Price
case 8: return "On use/hit - HP min";
case 9: return "On use/hit - HP max";
case 10: return "On use/hit - AP min";
case 11: return "On use/hit - AP max";
case 12: return "On use/hit - # conditions";
case 13: return "On kill - HP min";
case 14: return "On kill - HP max";
case 15: return "On kill - AP min";
case 16: return "On kill - AP max";
case 17: return "On kill - # conditions";
case 18: return "AD min";
case 19: return "AD max";
case 20: return "Max HP";
case 21: return "Max AP";
case 22: return "Attack cost";
case 23: return "AC";
case 24: return "BC";
case 25: return "DR";
case 26: return "CS";
case 27: return "CM";
case 28: return "Move cost";
case 29: return "Use cost";
case 30: return "Reequip cost";
case 31: return "# conditions";
}
return null;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
// return String.class;
switch (columnIndex) {
case 0: return Icon.class; // Icon
case 1: return String.class; //ID
case 2: return String.class; //Name
case 3: return String.class; //Source type (created, altered, source)
case 4: return String.class; //Use type ("none", "use", or equip slot name).
case 5: return String.class; //Category id.
case 6: return Boolean.class; //Has manual price
case 7: return Integer.class; //Price
case 8: return Integer.class;//"On use/hit - HP min";
case 9: return Integer.class;//"On use/hit - HP max";
case 10: return Integer.class;//"On use/hit - AP min";
case 11: return Integer.class;//"On use/hit - AP max";
case 12: return Integer.class;//"On use/hit - # conditions";
case 13: return Integer.class;//"On kill - HP min";
case 14: return Integer.class;//"On kill - HP max";
case 15: return Integer.class;//"On kill - AP min";
case 16: return Integer.class;//"On kill - AP max";
case 17: return Integer.class;//"On kill - # conditions";
case 18: return Integer.class;//"AD min";
case 19: return Integer.class;//"AD max";
case 20: return Integer.class;//"Max HP";
case 21: return Integer.class;//"Max AP";
case 22: return Integer.class;//"Attack cost";
case 23: return Integer.class;//"AC";
case 24: return Integer.class;//"BC";
case 25: return Integer.class;//"DR";
case 26: return Integer.class;//"CS";
case 27: return Double.class;//"CM";
case 28: return Integer.class;//"Move cost";
case 29: return Integer.class;//"Use cost";
case 30: return Integer.class;//"Reequip cost";
case 31: return Integer.class;//"# conditions";
}
return null;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
// if (rowIndex == 0) {
// return getColumnName(columnIndex);
// }
// Item item = proj.getItem(rowIndex - 1);
Item item = proj.getItem(rowIndex);
boolean canUse = item.category != null && item.category.action_type == ItemCategory.ActionType.use;
boolean canEquip = item.category != null && item.category.action_type == ItemCategory.ActionType.equip;
switch (columnIndex) {
case 0: return new ImageIcon(item.getIcon()); //Icon
case 1: return item.id; //ID
case 2: return item.name; //Name
case 3: return item.getDataType().toString(); //Source type (created, altered, source)
case 4: //Use type ("none", "use", or equip slot name).
if (item.category == null) return "none";
if (item.category.action_type == null) return "none";
if (item.category.action_type != ItemCategory.ActionType.equip) return item.category.action_type.toString();
return item.category.slot.toString();
case 5: return item.category != null ? item.category.id : (item.category_id != null ? item.category_id : null ); //Category id.
case 6: return item.has_manual_price == null ? false : (item.has_manual_price == 1); //Has manual price
case 7: //Price
if (item.has_manual_price == null || item.has_manual_price != 1) return item.computePrice();
return item.base_market_cost;
case 8: return canUse ? (item.kill_effect != null ? item.kill_effect.hp_boost_min : null) : (item.hit_effect != null ? item.hit_effect.hp_boost_min : null);//"On use/hit - HP min";
case 9: return canUse ? (item.kill_effect != null ? item.kill_effect.hp_boost_max : null) : (item.hit_effect != null ? item.hit_effect.hp_boost_max : null);//"On use/hit - HP max";
case 10: return canUse ? (item.kill_effect != null ? item.kill_effect.ap_boost_min : null) : (item.hit_effect != null ? item.hit_effect.ap_boost_min : null);//"On use/hit - AP min";
case 11: return canUse ? (item.kill_effect != null ? item.kill_effect.ap_boost_max : null) : (item.hit_effect != null ? item.hit_effect.ap_boost_max : null);//"On use/hit - AP max";
case 12: //"On use/hit - # conditions";
if (canUse) {
if (item.kill_effect != null && item.kill_effect.conditions_source != null) {
return item.kill_effect.conditions_source.size();
}
return 0;
} else if (item.hit_effect != null) {
int val = 0;
if (item.hit_effect.conditions_source != null) {
val += item.hit_effect.conditions_source.size();
}
if (item.hit_effect.conditions_target != null) {
val += item.hit_effect.conditions_target.size();
}
return val;
}
return null;
case 13: return (!canUse && item.kill_effect != null) ? item.kill_effect.hp_boost_min : null;//"On kill - HP min";
case 14: return (!canUse && item.kill_effect != null) ? item.kill_effect.hp_boost_max : null;//"On kill - HP max";
case 15: return (!canUse && item.kill_effect != null) ? item.kill_effect.ap_boost_min : null;//"On kill - AP min";
case 16: return (!canUse && item.kill_effect != null) ? item.kill_effect.ap_boost_max : null;//"On kill - AP max";
case 17: return (!canUse && item.kill_effect != null && item.kill_effect.conditions_source != null) ? item.kill_effect.conditions_source.size() : null;//"On kill - # conditions";
case 18: return (canEquip && item.equip_effect != null) ? item.equip_effect.damage_boost_min : null;//"AD min";
case 19: return (canEquip && item.equip_effect != null) ? item.equip_effect.damage_boost_max : null;//"AD max";
case 20: return (canEquip && item.equip_effect != null) ? item.equip_effect.max_hp_boost : null;//"Max HP";
case 21: return (canEquip && item.equip_effect != null) ? item.equip_effect.max_ap_boost : null;//"Max AP";
case 22: return (canEquip && item.equip_effect != null) ? item.equip_effect.increase_attack_cost : null;//"Attack cost";
case 23: return (canEquip && item.equip_effect != null) ? item.equip_effect.increase_attack_chance : null;//"AC";
case 24: return (canEquip && item.equip_effect != null) ? item.equip_effect.increase_block_chance : null;//"BC";
case 25: return (canEquip && item.equip_effect != null) ? item.equip_effect.increase_damage_resistance : null;//"DR";
case 26: return (canEquip && item.equip_effect != null) ? item.equip_effect.increase_critical_skill : null;//"CS";
case 27: return (canEquip && item.equip_effect != null) ? item.equip_effect.critical_multiplier : null;//"CM";
case 28: return (canEquip && item.equip_effect != null) ? item.equip_effect.increase_move_cost : null;//"Move cost";
case 29: return (canEquip && item.equip_effect != null) ? item.equip_effect.increase_use_item_cost : null;//"Use cost";
case 30: return (canEquip && item.equip_effect != null) ? item.equip_effect.increase_reequip_cost : null;//"Reequip cost";
case 31: return (canEquip && item.equip_effect != null && item.equip_effect.conditions != null) ? item.equip_effect.conditions.size() : null;//"# conditions";
}
return null;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
//not editable.
}
List<TableModelListener> listeners = new ArrayList<TableModelListener>();
@Override
public void addTableModelListener(TableModelListener l) {
listeners.add(l);
}
@Override
public void removeTableModelListener(TableModelListener l) {
listeners.remove(l);
}
}
}

View File

@@ -0,0 +1,175 @@
package com.gpl.rpg.atcontentstudio.ui.tools;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import com.gpl.rpg.atcontentstudio.model.Project;
import com.gpl.rpg.atcontentstudio.model.gamedata.NPC;
import com.gpl.rpg.atcontentstudio.ui.DefaultIcons;
public class NPCsTableView extends ElementTableView {
private static final long serialVersionUID = -4196852140899079621L;
public NPCsTableView(Project proj) {
super(new NPCsTableModel(proj), "Compare "+proj.getNPCCount()+" NPCs.", new ImageIcon(DefaultIcons.getNPCIcon()));
}
private static class NPCsTableModel implements TableModel {
Project proj;
public NPCsTableModel(Project proj) {
this.proj = proj;
}
@Override
public int getRowCount() {
return proj.getNPCCount();
}
@Override
public int getColumnCount() {
return 25;
}
@Override
public String getColumnName(int columnIndex) {
switch (columnIndex) {
case 0: return "Icon"; //Icon
case 1: return "ID"; //ID
case 2: return "Name"; //Name
case 3: return "Category type"; //Source type (created, altered, source)
case 4: return "Unique";
case 5: return "Class";
case 6: return "Movement type";
case 7: return "Spawngroup";
case 8: return "Faction";
case 9: return "HP";
case 10: return "AP";
case 11: return "Attack Cost";
case 12: return "AC";
case 13: return "BC";
case 14: return "AD min";
case 15: return "AD max";
case 16: return "DR";
case 17: return "CS";
case 18: return "CM";
case 19: return "On hit - HP min";
case 20: return "On hit - HP max";
case 21: return "On hit - AP min";
case 22: return "On hit - AP max";
case 23: return "On hit - # conditions";
case 24: return "Experience reward";
}
return null;
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0: return Icon.class; //Icon
case 1: return String.class; //ID
case 2: return String.class; //Name
case 3: return String.class; //Source type (created, altered, source)
case 4: return Boolean.class; //"Unique";
case 5: return String.class; //"Class";
case 6: return String.class; //"Movement type";
case 7: return String.class; //"Spawngroup";
case 8: return String.class; //"Faction";
case 9: return Integer.class; //"HP";
case 10: return Integer.class; //"AP";
case 11: return Integer.class; //"Attack Cost";
case 12: return Integer.class; //"AC";
case 13: return Integer.class; //"BC";
case 14: return Integer.class; //"AD min";
case 15: return Integer.class; //"AD max";
case 16: return Integer.class; //"DR";
case 17: return Integer.class; //"CS";
case 18: return Double.class; //"CM";
case 19: return Integer.class; //"On hit - HP min";
case 20: return Integer.class; //"On hit - HP max";
case 21: return Integer.class; //"On hit - AP min";
case 22: return Integer.class; //"On hit - AP max";
case 23: return Integer.class; //"On hit - # conditions";
case 24: return Integer.class; //"Experience reward";
}
return null;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
NPC npc = proj.getNPC(rowIndex);
switch (columnIndex) {
case 0: return new ImageIcon(npc.getIcon()); // Icon
case 1: return npc.id; //ID
case 2: return npc.name; //Name
case 3: return npc.getDataType().toString(); //Source type (created, altered, source)
case 4: return npc.unique != null && npc.unique == 1;//"Unique";
case 5: return npc.monster_class != null ? npc.monster_class.toString() : null; //"Class";
case 6: return npc.movement_type != null ? npc.movement_type.toString() : null; //"Movement type";
case 7: return npc.spawngroup_id; //"Spawngroup";
case 8: return npc.faction_id; //"Faction";
case 9: return npc.max_hp; //"HP";
case 10: return npc.max_ap; //"AP";
case 11: return npc.attack_cost; //"Attack Cost";
case 12: return npc.attack_chance; //"AC";
case 13: return npc.block_chance; //"BC";
case 14: return npc.attack_damage_min; //"AD min";
case 15: return npc.attack_damage_max; //"AD max";
case 16: return npc.damage_resistance; //"DR";
case 17: return npc.critical_skill; //"CS";
case 18: return npc.critical_multiplier; //"CM";
case 19: return npc.hit_effect != null ? npc.hit_effect.hp_boost_min : null; //"On hit - HP min";
case 20: return npc.hit_effect != null ? npc.hit_effect.hp_boost_max : null; //"On hit - HP max";
case 21: return npc.hit_effect != null ? npc.hit_effect.ap_boost_min : null; //"On hit - AP min";
case 22: return npc.hit_effect != null ? npc.hit_effect.ap_boost_max : null; //"On hit - AP max";
case 23: //"On hit - # conditions";
if (npc.hit_effect != null) {
Integer val = null;
if (npc.hit_effect.conditions_source != null) {
val = npc.hit_effect.conditions_source.size();
}
if (npc.hit_effect.conditions_target != null) {
if (val == null) val = npc.hit_effect.conditions_target.size();
else val += npc.hit_effect.conditions_target.size();
}
return val;
}
return null;
case 24: return npc.getMonsterExperience();
}
return null;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
//not editable.
}
List<TableModelListener> listeners = new ArrayList<TableModelListener>();
@Override
public void addTableModelListener(TableModelListener l) {
listeners.add(l);
}
@Override
public void removeTableModelListener(TableModelListener l) {
listeners.remove(l);
}
}
}