diff --git a/src/com/gpl/rpg/atcontentstudio/model/Project.java b/src/com/gpl/rpg/atcontentstudio/model/Project.java index 84ddf83..570db25 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/Project.java +++ b/src/com/gpl/rpg/atcontentstudio/model/Project.java @@ -850,6 +850,34 @@ public class Project implements ProjectTreeNode, Serializable { } } + /** + * + * @param node. Before calling this method, make sure that no other map with the same id exist in either created or altered. + */ + public void createElement(TMXMap node) { + node.writable = true; + if (getMap(node.id) != null) { + GameDataElement existingNode = getMap(node.id); + for (GameDataElement backlink : existingNode.getBacklinks()) { + backlink.elementChanged(existingNode, node); + } + existingNode.getBacklinks().clear(); + node.writable = true; + node.tmxFile = new File(alteredContent.baseFolder, node.tmxFile.getName()); + node.parent = alteredContent.gameMaps; + alteredContent.gameMaps.addMap(node); + node.link(); + node.state = GameDataElement.State.created; + } else { + node.tmxFile = new File(createdContent.baseFolder, node.tmxFile.getName()); + node.parent = createdContent.gameMaps; + createdContent.gameMaps.addMap(node); + node.link(); + node.state = GameDataElement.State.created; + } + fireElementAdded(node, getNodeIndex(node)); + } + public void moveToCreated(JSONElement target) { target.childrenRemoved(new ArrayList()); diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/ActorCondition.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/ActorCondition.java index 98d26a7..02a653a 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/ActorCondition.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/ActorCondition.java @@ -86,7 +86,7 @@ public class ActorCondition extends JSONElement { @Override public String getDesc() { - return (this.state == State.modified ? "*" : "")+display_name+" ("+id+")"; + return ((this.state == State.modified || this.state == State.created) ? "*" : "")+display_name+" ("+id+")"; } @SuppressWarnings("rawtypes") diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java index 124e155..de8907a 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Dialogue.java @@ -18,6 +18,7 @@ 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.GameDataElement.State; import com.gpl.rpg.atcontentstudio.model.gamedata.Requirement.RequirementType; import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; @@ -91,7 +92,7 @@ public class Dialogue extends JSONElement { @Override public String getDesc() { - return (this.state == State.modified ? "*" : "")+id; + return ((this.state == State.modified || this.state == State.created) ? "*" : "")+id; } public static String getStaticDesc() { diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Droplist.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Droplist.java index e346398..4b33256 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Droplist.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Droplist.java @@ -17,6 +17,7 @@ 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.GameDataElement.State; import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; @@ -46,7 +47,7 @@ public class Droplist extends JSONElement { @Override public String getDesc() { - return (this.state == State.modified ? "*" : "")+id; + return ((this.state == State.modified || this.state == State.created) ? "*" : "")+id; } public static String getStaticDesc() { diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Item.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Item.java index 4e04bcc..1c76975 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Item.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Item.java @@ -17,6 +17,7 @@ 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.GameDataElement.State; public class Item extends JSONElement { @@ -101,7 +102,7 @@ public class Item extends JSONElement { @Override public String getDesc() { - return (this.state == State.modified ? "*" : "")+name+" ("+id+")"; + return ((this.state == State.modified || this.state == State.created) ? "*" : "")+name+" ("+id+")"; } public static String getStaticDesc() { diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/ItemCategory.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/ItemCategory.java index be957a3..3e311e0 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/ItemCategory.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/ItemCategory.java @@ -17,6 +17,7 @@ import org.json.simple.parser.ParseException; 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.GameDataElement.State; public class ItemCategory extends JSONElement { @@ -99,7 +100,7 @@ public class ItemCategory extends JSONElement { @Override public String getDesc() { - return (this.state == State.modified ? "*" : "")+name+" ("+id+")"; + return ((this.state == State.modified || this.state == State.created) ? "*" : "")+name+" ("+id+")"; } public static String getStaticDesc() { diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/NPC.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/NPC.java index 0530cfc..bb973bb 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/NPC.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/NPC.java @@ -17,6 +17,7 @@ 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.GameDataElement.State; public class NPC extends JSONElement { @@ -95,7 +96,7 @@ public class NPC extends JSONElement { @Override public String getDesc() { - return (this.state == State.modified ? "*" : "")+name+" ("+id+")"; + return ((this.state == State.modified || this.state == State.created) ? "*" : "")+name+" ("+id+")"; } public static String getStaticDesc() { diff --git a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Quest.java b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Quest.java index 4f2175b..c00bd49 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/gamedata/Quest.java +++ b/src/com/gpl/rpg/atcontentstudio/model/gamedata/Quest.java @@ -16,6 +16,7 @@ import org.json.simple.parser.ParseException; 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.GameDataElement.State; import com.gpl.rpg.atcontentstudio.ui.DefaultIcons; public class Quest extends JSONElement { @@ -48,7 +49,7 @@ public class Quest extends JSONElement { @Override public String getDesc() { - return (this.state == State.modified ? "*" : "")+name+" ("+id+")"; + return ((this.state == State.modified || this.state == State.created) ? "*" : "")+name+" ("+id+")"; } public static String getStaticDesc() { diff --git a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java index 4aa3cac..8aa5efb 100644 --- a/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java +++ b/src/com/gpl/rpg/atcontentstudio/model/maps/TMXMap.java @@ -197,7 +197,7 @@ public class TMXMap extends GameDataElement { } @Override public String getDesc() { - return (this.state == State.modified ? "*" : "")+id; + return ((this.state == State.modified || this.state == State.created) ? "*" : "")+id; } @Override @@ -309,8 +309,10 @@ public class TMXMap extends GameDataElement { parse(); } if (this.state == GameDataElement.State.parsed || this.state == GameDataElement.State.created) { - for (MapObjectGroup group : groups) { - group.link(); + if (groups != null) { + for (MapObjectGroup group : groups) { + group.link(); + } } } } diff --git a/src/com/gpl/rpg/atcontentstudio/ui/ProjectsTree.java b/src/com/gpl/rpg/atcontentstudio/ui/ProjectsTree.java index 6c07a46..7d5bc42 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/ProjectsTree.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/ProjectsTree.java @@ -202,6 +202,10 @@ public class ProjectsTree extends JPanel { addNextSeparator = true; popupMenu.add(new JMenuItem(actions.importJSON)); } + if (actions.createMap.isEnabled()) { + addNextSeparator = true; + popupMenu.add(new JMenuItem(actions.createMap)); + } if (actions.createWorldmap.isEnabled()) { addNextSeparator = true; popupMenu.add(new JMenuItem(actions.createWorldmap)); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/StudioFrame.java b/src/com/gpl/rpg/atcontentstudio/ui/StudioFrame.java index 8522a78..035cd1c 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/StudioFrame.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/StudioFrame.java @@ -140,6 +140,7 @@ public class StudioFrame extends JFrame { projectMenu.add(new JSeparator()); projectMenu.add(new JMenuItem(actions.createGDE)); projectMenu.add(new JMenuItem(actions.importJSON)); + projectMenu.add(new JMenuItem(actions.createMap)); projectMenu.add(new JMenuItem(actions.createWorldmap)); projectMenu.add(new JMenuItem(actions.loadSave)); getJMenuBar().add(projectMenu); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/TMXMapCreationWizard.java b/src/com/gpl/rpg/atcontentstudio/ui/TMXMapCreationWizard.java new file mode 100644 index 0000000..373f6ce --- /dev/null +++ b/src/com/gpl/rpg/atcontentstudio/ui/TMXMapCreationWizard.java @@ -0,0 +1,299 @@ +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.io.File; +import java.util.ArrayList; +import java.util.List; + +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.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +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.State; +import com.gpl.rpg.atcontentstudio.model.GameSource; +import com.gpl.rpg.atcontentstudio.model.Project; +import com.gpl.rpg.atcontentstudio.model.maps.TMXMap; +import com.jidesoft.swing.JideBoxLayout; + +public class TMXMapCreationWizard extends JDialog { + + private static final long serialVersionUID = -474689694453543575L; + private static final String DEFAULT_TEMPLATE = "template.tmx"; + + + private TMXMap creation = null; + final File templateFile; + + final JLabel message; + final JRadioButton useTemplate, copyMap; + final JComboBox templateCombo; + final JTextField idField; + final JButton ok; + final Project proj; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public TMXMapCreationWizard(final Project proj) { + super(ATContentStudio.frame); + this.proj = proj; + templateFile=new File(proj.baseContent.gameMaps.mapFolder, DEFAULT_TEMPLATE); + + setTitle("Create new TMX map"); + + JPanel pane = new JPanel(); + pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6)); + + pane.add(new JLabel("Create a new TMX map."), JideBoxLayout.FIX); + + message = new JLabel("Enter new map name:"); + pane.add(message, JideBoxLayout.FIX); + + final JPanel idPane = new JPanel(); + idPane.setLayout(new BorderLayout()); + JLabel idLabel = new JLabel("Internal ID: "); + idPane.add(idLabel, BorderLayout.WEST); + idField = new JTextField(""); + idField.setEditable(true); + idPane.add(idField, BorderLayout.CENTER); + pane.add(idPane, JideBoxLayout.FIX); + + useTemplate = new JRadioButton("Use default template file ("+DEFAULT_TEMPLATE+")"); + useTemplate.setToolTipText(templateFile.getAbsolutePath()); + pane.add(useTemplate, JideBoxLayout.FIX); + copyMap = new JRadioButton("Copy existing map"); + pane.add(copyMap, JideBoxLayout.FIX); + + ButtonGroup radioGroup = new ButtonGroup(); + radioGroup.add(useTemplate); + radioGroup.add(copyMap); + + final JPanel templatePane = new JPanel(); + templatePane.setLayout(new BorderLayout()); + JLabel templateLabel = new JLabel("Template to copy: "); + templatePane.add(templateLabel, BorderLayout.WEST); + templateCombo = new JComboBox(new TemplateComboModel()); + templateCombo.setRenderer(new TemplateComboCellRenderer()); + if (proj.getMap(DEFAULT_TEMPLATE) != null) templateCombo.setSelectedItem(proj.getMap(DEFAULT_TEMPLATE)); + templatePane.add(templateCombo, BorderLayout.CENTER); + pane.add(templatePane, JideBoxLayout.FIX); + pane.add(templateCombo); + + if (templateFile.exists()) { + useTemplate.setSelected(true); + copyMap.setSelected(false); + templateCombo.setEnabled(false); + } else { + useTemplate.setSelected(false); + useTemplate.setEnabled(false); + useTemplate.setToolTipText("Cannot find file "+templateFile.getAbsolutePath()); + templateCombo.setEnabled(true); + copyMap.setSelected(true); + } + + ActionListener radioListener = new ActionListener() { + + @Override + public void actionPerformed(ActionEvent e) { + if (useTemplate.isSelected()) { + templateCombo.setEnabled(false); + } else if(copyMap.isSelected()) { + templateCombo.setEnabled(true); + } + updateStatus(); + } + }; + useTemplate.addActionListener(radioListener); + copyMap.addActionListener(radioListener); + + templateCombo.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + updateStatus(); + } + }); + + 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(new JPanel(), JideBoxLayout.VARY); + pane.add(buttonPane, JideBoxLayout.FIX); + + ok.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + + if (copyMap.isSelected()) { + creation = ((TMXMap)templateCombo.getSelectedItem()).clone(); + } else if (useTemplate.isSelected()) { + creation = new TMXMap(proj.createdContent.gameMaps, templateFile); + creation.parse(); + } + creation.id = idField.getText(); + creation.tmxFile = new File(creation.id+".tmx"); + TMXMapCreationWizard.this.setVisible(false); + TMXMapCreationWizard.this.dispose(); + creation.state = State.created; + proj.createElement(creation); + notifyCreated(); + ATContentStudio.frame.selectInTree(creation); + ATContentStudio.frame.openEditor(creation); + } + }); + + cancel.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + creation = null; + TMXMapCreationWizard.this.setVisible(false); + TMXMapCreationWizard.this.dispose(); + } + }); + + DocumentListener statusUpdater = new DocumentListener() { + @Override + public void removeUpdate(DocumentEvent e) { + updateStatus(); + } + @Override + public void insertUpdate(DocumentEvent e) { + updateStatus(); + } + @Override + public void changedUpdate(DocumentEvent e) { + updateStatus(); + } + }; + idField.getDocument().addDocumentListener(statusUpdater); + + getContentPane().setLayout(new BorderLayout()); + getContentPane().add(pane, BorderLayout.CENTER); + + setMinimumSize(new Dimension(350,250)); + 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("Looks OK to me."); + if (copyMap.isSelected() && templateCombo.getSelectedItem() == null) { + message.setText("Select a map template below:"); + trouble = true; + } else if (idField.getText() == null || idField.getText().length() <= 0) { + message.setText("Internal ID must not be empty."); + trouble = true; + } else if (proj.getMap(idField.getText()) != null) { + if (proj.getMap(idField.getText()).getDataType() == GameSource.Type.created) { + message.setText("A map with the same ID was already created in this project."); + trouble = true; + } else if (proj.getMap(idField.getText()).getDataType() == GameSource.Type.altered) { + message.setText("A map with the same ID exists in the game and is already altered in this project."); + trouble = true; + } else if (proj.getMap(idField.getText()).getDataType() == GameSource.Type.source) { + message.setText("A map with the same ID exists in the game. The new one will be added under \"altered\"."); + } + } + + ok.setEnabled(!trouble); + + message.revalidate(); + message.repaint(); + } + + public static interface CreationCompletedListener { + public void mapCreated(TMXMap created); + } + + private List listeners = new ArrayList(); + + public void addCreationListener(CreationCompletedListener l) { + listeners.add(l); + } + + public void notifyCreated() { + for (CreationCompletedListener l : listeners) { + l.mapCreated(creation); + } + } + + class TemplateComboModel implements ComboBoxModel { + + Object selected; + + @Override + public int getSize() { + return proj.getMapCount(); + } + + @Override + public TMXMap getElementAt(int index) { + return proj.getMap(index); + } + + List listeners = new ArrayList(); + + @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 = anItem; + } + + @Override + public Object getSelectedItem() { + return selected; + } + + } + + class TemplateComboCellRenderer extends DefaultListCellRenderer { + private static final long serialVersionUID = 5621373849299980998L; + + @Override + public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (c instanceof JLabel && value != null) { + ((JLabel)c).setText(((TMXMap)value).getDesc()); + ((JLabel)c).setIcon(new ImageIcon(DefaultIcons.getTiledIconIcon())); + } + return c; + } + } + + +} diff --git a/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java b/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java index c2bbca2..482cbbf 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/WorkspaceActions.java @@ -226,7 +226,16 @@ public class WorkspaceActions { } }; - + public ATCSAction createMap = new ATCSAction("Create TMX Map", "Opens the TMX Map creation wizard") { + public void actionPerformed(ActionEvent e) { + if (selectedNode == null || selectedNode.getProject() == null) return; + new TMXMapCreationWizard(selectedNode.getProject()).setVisible(true); + } + public void selectionChanged(ProjectTreeNode selectedNode, TreePath[] selectedPaths) { + setEnabled(selectedNode != null && selectedNode.getProject() != null); + } + }; + public ATCSAction createWorldmap = new ATCSAction("Create Worldmap segment", "Opens the worldmap segment creation wizard") { public void actionPerformed(ActionEvent e) { if (selectedNode == null || selectedNode.getProject() == null) return; @@ -389,6 +398,7 @@ public class WorkspaceActions { actions.add(saveElement); actions.add(deleteSelected); actions.add(createGDE); + actions.add(createMap); actions.add(importJSON); actions.add(loadSave); actions.add(compareItems); diff --git a/src/com/gpl/rpg/atcontentstudio/ui/sprites/SpritesheetEditor.java b/src/com/gpl/rpg/atcontentstudio/ui/sprites/SpritesheetEditor.java index f20f779..de92ffa 100644 --- a/src/com/gpl/rpg/atcontentstudio/ui/sprites/SpritesheetEditor.java +++ b/src/com/gpl/rpg/atcontentstudio/ui/sprites/SpritesheetEditor.java @@ -69,8 +69,8 @@ public class SpritesheetEditor extends Editor { public static JComponent getWarningLabel() { JLabel label = new JLabel( "" + - "The data presented here is not part of the game.
" + - "What you change here will be changed in your ATCS project.
" + + "The data accompamying the image here is not part of the game.
" + + "What you change here will be changed in your ATCS project only.
" + "None of this is exported to JSON or TMX, although it must be set correctly in order to choose tiles & icons correctly.
" + "
"); return label; @@ -88,7 +88,8 @@ public class SpritesheetEditor extends Editor { pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6)); - add(getWarningLabel(), JideBoxLayout.FIX); + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new JideBoxLayout(buttonPane, JideBoxLayout.LINE_AXIS)); JButton openImage = new JButton(new ImageIcon(DefaultIcons.getTileLayerImage())); openImage.addActionListener(new ActionListener() { @Override @@ -96,7 +97,10 @@ public class SpritesheetEditor extends Editor { DesktopIntegration.openImage(((Spritesheet)target).spritesheetFile); } }); - pane.add(openImage, JideBoxLayout.FIX); + buttonPane.add(openImage, JideBoxLayout.FIX); + buttonPane.add(getWarningLabel(), JideBoxLayout.FIX); + buttonPane.add(new JPanel(), JideBoxLayout.VARY); + pane.add(buttonPane, 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);