mirror of
https://github.com/OMGeeky/ATCS.git
synced 2025-12-26 15:57:22 +01:00
440 lines
17 KiB
Java
440 lines
17 KiB
Java
package com.gpl.rpg.atcontentstudio.ui.sprites;
|
|
|
|
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.DefaultIcons;
|
|
import com.gpl.rpg.atcontentstudio.ui.Editor;
|
|
import com.gpl.rpg.atcontentstudio.ui.FieldUpdateListener;
|
|
import com.gpl.rpg.atcontentstudio.ui.ListenerListModel;
|
|
import com.gpl.rpg.atcontentstudio.utils.DesktopIntegration;
|
|
import com.jidesoft.swing.JideBoxLayout;
|
|
import com.jidesoft.swing.JideTabbedPane;
|
|
|
|
import javax.swing.*;
|
|
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 java.awt.*;
|
|
import java.awt.event.*;
|
|
import java.util.List;
|
|
import java.util.*;
|
|
import java.util.concurrent.CopyOnWriteArrayList;
|
|
|
|
public class SpritesheetEditor extends Editor {
|
|
|
|
private static final long serialVersionUID = 3956109815682889863L;
|
|
|
|
Map<String, JPanel> editorTabs = new LinkedHashMap<String, JPanel>();
|
|
JideTabbedPane editorTabsHolder;
|
|
|
|
private JSpinner widthField;
|
|
private JSpinner heightField;
|
|
private JCheckBox animatedBox;
|
|
@SuppressWarnings("rawtypes")
|
|
private JComboBox categoryBox;
|
|
private JPanel spriteViewPane;
|
|
|
|
|
|
public static JComponent getWarningLabel() {
|
|
JLabel label = new JLabel(
|
|
"<html><i>" +
|
|
"The data accompamying the image here is not part of the game.<br/>" +
|
|
"What you change here will be changed in your ATCS project only.<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.name = sheet.id;
|
|
this.target = sheet;
|
|
Image icon = sheet.getIcon(0);
|
|
if (icon == null) {
|
|
Notification.addError("Unable to open spritesheet " + sheet.id + " because the image is missing. This might be because its an UI spritesheet, which is not supported in ATCS");
|
|
return;
|
|
}
|
|
this.icon = new ImageIcon(icon);
|
|
|
|
JPanel pane = new JPanel();
|
|
|
|
final FieldUpdateListener listener = new SpritesheetFieldUpdater();
|
|
|
|
pane.setLayout(new JideBoxLayout(pane, JideBoxLayout.PAGE_AXIS, 6));
|
|
|
|
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
|
|
public void actionPerformed(ActionEvent e) {
|
|
DesktopIntegration.openImage(((Spritesheet) target).spritesheetFile);
|
|
}
|
|
});
|
|
buttonPane.add(openImage, JideBoxLayout.FIX);
|
|
buttonPane.add(getWarningLabel(), JideBoxLayout.FIX);
|
|
final JButton bookmark = new JButton(new ImageIcon(sheet.bookmark != null ? DefaultIcons.getBookmarkActiveIcon() : DefaultIcons.getBookmarkInactiveIcon()));
|
|
buttonPane.add(bookmark, JideBoxLayout.FIX);
|
|
bookmark.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent arg0) {
|
|
if (target.bookmark == null) {
|
|
target.getProject().bookmark(target);
|
|
bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkActiveIcon()));
|
|
} else {
|
|
target.bookmark.delete();
|
|
bookmark.setIcon(new ImageIcon(DefaultIcons.getBookmarkInactiveIcon()));
|
|
}
|
|
}
|
|
});
|
|
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);
|
|
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 + 4);
|
|
col.setMaxWidth(sheet.spriteWidth + 4);
|
|
}
|
|
spritesTable.setRowHeight(sheet.spriteHeight + 4);
|
|
pane.add(new JScrollPane(spritesTable), BorderLayout.CENTER);
|
|
}
|
|
}
|
|
|
|
|
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
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 CopyOnWriteArrayList<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 ListenerListModel<ProjectTreeNode> {
|
|
|
|
Spritesheet sheet;
|
|
|
|
public SpritesheetsBacklinksListModel(Spritesheet sheet) {
|
|
this.sheet = sheet;
|
|
}
|
|
|
|
@Override
|
|
public int getSize() {
|
|
return sheet.getBacklinks().size();
|
|
}
|
|
|
|
@Override
|
|
public ProjectTreeNode getElementAt(int index) {
|
|
for (ProjectTreeNode node : sheet.getBacklinks()) {
|
|
if (index == 0) return node;
|
|
index--;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
List<ListDataListener> listeners = new CopyOnWriteArrayList<ListDataListener>();
|
|
|
|
@Override
|
|
public List<ListDataListener> getListeners() {
|
|
return listeners;
|
|
}
|
|
}
|
|
|
|
public static class BacklinkCellRenderer extends DefaultListCellRenderer {
|
|
|
|
private static final long serialVersionUID = 6819681566800482793L;
|
|
|
|
private boolean includeType;
|
|
|
|
public BacklinkCellRenderer(boolean includeType) {
|
|
super();
|
|
this.includeType = includeType;
|
|
|
|
}
|
|
|
|
@Override
|
|
public Component getListCellRendererComponent(@SuppressWarnings("rawtypes") 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;
|
|
}
|
|
sheet.save();
|
|
}
|
|
}
|
|
|
|
}
|