Migrated the bulk of the scene editor into Stage. It's just lovely.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3442 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,192 @@
|
|||||||
|
//
|
||||||
|
// $Id: DirectionButton.java 5784 2003-01-08 04:17:40Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.event.MouseAdapter;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import javax.swing.AbstractButton;
|
||||||
|
import javax.swing.DefaultButtonModel;
|
||||||
|
|
||||||
|
import com.threerings.media.image.ColorUtil;
|
||||||
|
|
||||||
|
import com.threerings.util.DirectionCodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A button that allows for selection from the compass directions.
|
||||||
|
*/
|
||||||
|
public class DirectionButton extends AbstractButton
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Construct a 41x41 DirectionButton.
|
||||||
|
*/
|
||||||
|
public DirectionButton ()
|
||||||
|
{
|
||||||
|
this(41);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a DirectionButton with the specified preferred diameter.
|
||||||
|
*/
|
||||||
|
public DirectionButton (int preferredDiameter)
|
||||||
|
{
|
||||||
|
_prefdia = preferredDiameter;
|
||||||
|
configSize(_prefdia);
|
||||||
|
|
||||||
|
setModel(new DefaultButtonModel());
|
||||||
|
|
||||||
|
addMouseListener(new MouseAdapter() {
|
||||||
|
public void mousePressed (MouseEvent event)
|
||||||
|
{
|
||||||
|
if (isEnabled()) {
|
||||||
|
_armed = getDirection(event.getX(), event.getY());
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseReleased (MouseEvent event)
|
||||||
|
{
|
||||||
|
if ((_armed != -1) &&
|
||||||
|
isEnabled() &&
|
||||||
|
(_armed == getDirection(event.getX(), event.getY())) &&
|
||||||
|
(_direction != _armed)) {
|
||||||
|
|
||||||
|
_direction = _armed;
|
||||||
|
fireStateChanged();
|
||||||
|
}
|
||||||
|
_armed = -1;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paint this component and the selected direction,
|
||||||
|
* dimmed if we're inactive.
|
||||||
|
*/
|
||||||
|
public void paintComponent (Graphics g)
|
||||||
|
{
|
||||||
|
super.paintComponent(g);
|
||||||
|
|
||||||
|
// draw the selected direction circle
|
||||||
|
g.setColor(isEnabled() ? Color.red
|
||||||
|
: ColorUtil.blend(Color.red, getBackground()));
|
||||||
|
g.fillOval(_coords[_direction][0], _coords[_direction][1],
|
||||||
|
_cdia, _cdia);
|
||||||
|
|
||||||
|
if (_armed != -1) {
|
||||||
|
g.setColor(ColorUtil.blend(Color.black, getBackground()));
|
||||||
|
g.fillOval(_coords[_armed][0], _coords[_armed][1],
|
||||||
|
_cdia, _cdia);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw a circle around the various direction circles
|
||||||
|
g.setColor(isEnabled() ? Color.black
|
||||||
|
: ColorUtil.blend(Color.black, getBackground()));
|
||||||
|
g.drawOval(0, 0, _dia, _dia);
|
||||||
|
|
||||||
|
// draw each direction circle
|
||||||
|
for (int ii=DirectionCodes.SOUTHWEST;
|
||||||
|
ii < DirectionCodes.DIRECTION_COUNT;
|
||||||
|
ii++) {
|
||||||
|
|
||||||
|
g.drawOval(_coords[ii][0], _coords[ii][1], _cdia, _cdia);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the direction that is currently selected.
|
||||||
|
*/
|
||||||
|
public int getDirection ()
|
||||||
|
{
|
||||||
|
return _direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the currently displayed direction
|
||||||
|
*/
|
||||||
|
public void setDirection (int direction)
|
||||||
|
{
|
||||||
|
if (direction != _direction) {
|
||||||
|
_direction = direction;
|
||||||
|
fireStateChanged();
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the direction specified by the mouse coordinates
|
||||||
|
*/
|
||||||
|
protected int getDirection (int x, int y)
|
||||||
|
{
|
||||||
|
for (int ii=0; ii < DirectionCodes.DIRECTION_COUNT; ii++) {
|
||||||
|
if ((x > _coords[ii][0]) && (x < (_coords[ii][0] + _cdia)) &&
|
||||||
|
(y > _coords[ii][1]) && (y < (_coords[ii][1] + _cdia))) {
|
||||||
|
return ii;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public void setSize (Dimension d)
|
||||||
|
{
|
||||||
|
super.setSize(d);
|
||||||
|
|
||||||
|
configSize(Math.min(d.width, d.height));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconfigure the way we look for a new size
|
||||||
|
*/
|
||||||
|
protected void configSize (int diameter)
|
||||||
|
{
|
||||||
|
// recompute our sizes
|
||||||
|
_dia = diameter - 1;
|
||||||
|
_cdia = _dia / 4;
|
||||||
|
|
||||||
|
int mid = (_dia - _cdia) / 2;
|
||||||
|
|
||||||
|
int num = DirectionCodes.DIRECTION_COUNT; // oh we all know it's 8.
|
||||||
|
|
||||||
|
for (int ii=0; ii < num; ii++) {
|
||||||
|
double rads = Math.PI * 2 * ii / num;
|
||||||
|
|
||||||
|
// 0 radians specifies EAST, so we offset
|
||||||
|
int dir = (ii + DirectionCodes.EAST) % num;
|
||||||
|
|
||||||
|
_coords[dir][0] = mid + ((int) (mid * Math.cos(rads)));
|
||||||
|
_coords[dir][1] = mid + ((int) (mid * Math.sin(rads)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public Dimension getPreferredSize ()
|
||||||
|
{
|
||||||
|
return new Dimension(_prefdia, _prefdia);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The current direction displayed by the button. */
|
||||||
|
protected int _direction = DirectionCodes.SOUTH;
|
||||||
|
|
||||||
|
// if we're "armed" for a possible state change, which direction is armed?
|
||||||
|
// (-1 for unarmed)
|
||||||
|
protected int _armed = -1;
|
||||||
|
|
||||||
|
/** Diameter of the drawn enclosing circle. */
|
||||||
|
protected int _dia;
|
||||||
|
|
||||||
|
/** Diameter of selection circles. */
|
||||||
|
protected int _cdia;
|
||||||
|
|
||||||
|
/** Coordinates of each of the selection circles. */
|
||||||
|
protected int[][] _coords = new int[DirectionCodes.DIRECTION_COUNT][2];
|
||||||
|
|
||||||
|
/** Our preferred diameter. */
|
||||||
|
protected int _prefdia;
|
||||||
|
}
|
||||||
@@ -0,0 +1,356 @@
|
|||||||
|
//
|
||||||
|
// $Id: EditorApp.java 19661 2005-03-09 02:40:29Z andrzej $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.DisplayMode;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.GraphicsDevice;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.JProgressBar;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.samskivert.swing.util.SwingUtil;
|
||||||
|
import com.samskivert.util.DebugChords;
|
||||||
|
import com.samskivert.util.RuntimeAdjust;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
import com.threerings.util.KeyDispatcher;
|
||||||
|
import com.threerings.util.KeyboardManager;
|
||||||
|
import com.threerings.util.MessageBundle;
|
||||||
|
import com.threerings.util.MessageManager;
|
||||||
|
|
||||||
|
import com.threerings.resource.ResourceManager;
|
||||||
|
|
||||||
|
import com.threerings.media.FrameManager;
|
||||||
|
import com.threerings.media.IconManager;
|
||||||
|
import com.threerings.media.image.ColorPository;
|
||||||
|
import com.threerings.media.image.ImageManager;
|
||||||
|
import com.threerings.media.sound.SoundManager;
|
||||||
|
import com.threerings.media.util.ModeUtil;
|
||||||
|
|
||||||
|
import com.threerings.media.tile.TileSetRepository;
|
||||||
|
import com.threerings.media.tile.bundle.BundledTileSetRepository;
|
||||||
|
|
||||||
|
import com.threerings.cast.ComponentRepository;
|
||||||
|
import com.threerings.cast.bundle.BundledComponentRepository;
|
||||||
|
import com.threerings.miso.tile.MisoTileManager;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageSceneModel;
|
||||||
|
import com.threerings.stage.tools.editor.util.EditorContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A scene editor application that provides facilities for viewing,
|
||||||
|
* editing, and saving the scene templates that comprise a game.
|
||||||
|
*/
|
||||||
|
public class EditorApp implements Runnable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Construct and initialize the EditorApp object.
|
||||||
|
*/
|
||||||
|
public EditorApp (final String target)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// we need to use heavy-weight popup menus so that they can overly
|
||||||
|
// our non-lightweight Miso view
|
||||||
|
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
|
||||||
|
|
||||||
|
// create and size the main application frame
|
||||||
|
_frame = new EditorFrame();
|
||||||
|
|
||||||
|
// create our frame manager
|
||||||
|
_framemgr = FrameManager.newInstance(_frame);
|
||||||
|
|
||||||
|
// create our myriad managers, repositories, etc.
|
||||||
|
_rmgr = new ResourceManager("rsrc");
|
||||||
|
|
||||||
|
// build up a simple ui for displaying progress
|
||||||
|
JPanel progressPanel = new JPanel(new BorderLayout());
|
||||||
|
final JLabel progressLabel = new JLabel();
|
||||||
|
final JProgressBar progress = new JProgressBar(0,100);
|
||||||
|
final JPanel spacer = new JPanel();
|
||||||
|
|
||||||
|
progressPanel.add(progressLabel, BorderLayout.CENTER);
|
||||||
|
progressPanel.add(progress, BorderLayout.SOUTH);
|
||||||
|
progressPanel.setPreferredSize(new Dimension(300,80));
|
||||||
|
spacer.add(progressPanel);
|
||||||
|
|
||||||
|
_frame.getContentPane().add(spacer);
|
||||||
|
|
||||||
|
final EditorFrame frameRef = _frame;
|
||||||
|
|
||||||
|
ResourceManager.InitObserver obs = new ResourceManager.InitObserver() {
|
||||||
|
public void progress (int percent, long remaining) {
|
||||||
|
String msg = "Unpacking...";
|
||||||
|
if (remaining >= 0) {
|
||||||
|
msg += " " + remaining + " seconds remaining.";
|
||||||
|
}
|
||||||
|
progressLabel.setText(msg);
|
||||||
|
progress.setValue(percent);
|
||||||
|
|
||||||
|
if (percent >= 100) {
|
||||||
|
frameRef.getContentPane().remove(spacer);
|
||||||
|
EditorApp.this.finishInit(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initializationFailed (Exception e) {
|
||||||
|
Log.warning("Failed unpacking bundles [e=" + e + "].");
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// we want our methods called on the AWT thread
|
||||||
|
obs = new ResourceManager.AWTInitObserver(obs);
|
||||||
|
_rmgr.initBundles(null, "config/resource/editor.properties", obs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finishInit (String target)
|
||||||
|
{
|
||||||
|
_msgmgr = new MessageManager("rsrc.i18n");
|
||||||
|
_imgr = new ImageManager(_rmgr, _frame);
|
||||||
|
_tilemgr = new MisoTileManager(_rmgr, _imgr);
|
||||||
|
|
||||||
|
try {
|
||||||
|
_tsrepo = new BundledTileSetRepository(_rmgr, _imgr, "tilesets");
|
||||||
|
_tilemgr.setTileSetRepository(_tsrepo);
|
||||||
|
_iconmgr = new IconManager(_tilemgr, ICON_MANAGER_CONFIG);
|
||||||
|
_crepo = new BundledComponentRepository(
|
||||||
|
_rmgr, _imgr, "components");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.warning("Exception loading tilesets and and icon manager " +
|
||||||
|
"[Exception=" + e + "].");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_iconmgr.setSource("general");
|
||||||
|
_colpos = ColorPository.loadColorPository(_rmgr);
|
||||||
|
_soundmgr = new SoundManager(_rmgr, null, null);
|
||||||
|
_kbdmgr = new KeyboardManager();
|
||||||
|
_keydisp = new KeyDispatcher(_frame);
|
||||||
|
|
||||||
|
_ctx = new EditorContextImpl();
|
||||||
|
|
||||||
|
// initialize the frame with the now-prepared context
|
||||||
|
_frame.init(_ctx, target);
|
||||||
|
|
||||||
|
// wire up our runtime adjustment editor
|
||||||
|
DebugChords.activate();
|
||||||
|
|
||||||
|
// if we have a target file, load it up
|
||||||
|
if (target != null) {
|
||||||
|
_frame.openScene(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a subdirectory name (that should correspond to the calling
|
||||||
|
* service), returns a file path that can be used to store local data.
|
||||||
|
*/
|
||||||
|
public static String localDataDir (String subdir)
|
||||||
|
{
|
||||||
|
String appdir = System.getProperty("appdir");
|
||||||
|
if (StringUtil.blank(appdir)) {
|
||||||
|
appdir = ".narya-editor";
|
||||||
|
String home = System.getProperty("user.home");
|
||||||
|
if (!StringUtil.blank(home)) {
|
||||||
|
appdir = home + File.separator + appdir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return appdir + File.separator + subdir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the application.
|
||||||
|
*/
|
||||||
|
public void run ()
|
||||||
|
{
|
||||||
|
// enter full-screen exclusive mode if available and if we have
|
||||||
|
// the right display mode
|
||||||
|
GraphicsEnvironment env =
|
||||||
|
GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||||
|
GraphicsDevice gd = env.getDefaultScreenDevice();
|
||||||
|
DisplayMode pmode = null;
|
||||||
|
try {
|
||||||
|
DisplayMode cmode = gd.getDisplayMode();
|
||||||
|
pmode = ModeUtil.getDisplayMode(
|
||||||
|
gd, cmode.getWidth(), cmode.getHeight(), 16, 15);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// Win98 seems to choke on it's own vomit when we attempt to
|
||||||
|
// enumerate the available display modes; yay!
|
||||||
|
Log.warning("Failed to probe display mode.");
|
||||||
|
Log.logStackTrace(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_viewFullScreen.getValue() && gd.isFullScreenSupported() &&
|
||||||
|
pmode != null) {
|
||||||
|
Log.info("Switching to screen mode " +
|
||||||
|
"[mode=" + ModeUtil.toString(pmode) + "].");
|
||||||
|
// set the frame to undecorated, full-screen
|
||||||
|
_frame.setUndecorated(true);
|
||||||
|
gd.setFullScreenWindow(_frame);
|
||||||
|
// switch to our happy custom display mode
|
||||||
|
gd.setDisplayMode(pmode);
|
||||||
|
// lay the frame out properly (we can't do this before making
|
||||||
|
// it full screen because packing causes the window to become
|
||||||
|
// displayable which apparently prevents the window from
|
||||||
|
// subsequently being made a full-screen window)
|
||||||
|
_frame.pack();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_frame.setSize(1024, 768);
|
||||||
|
SwingUtil.centerWindow(_frame);
|
||||||
|
_frame.setVisible(true);
|
||||||
|
}
|
||||||
|
_framemgr.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate the application object and start it running.
|
||||||
|
*/
|
||||||
|
public static void main (String[] args)
|
||||||
|
{
|
||||||
|
String target = (args.length > 0) ? args[0] : null;
|
||||||
|
|
||||||
|
if (System.getProperty("no_log_redir") != null) {
|
||||||
|
Log.info("Logging to console only.");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
String dlog = localDataDir("editor.log");
|
||||||
|
try {
|
||||||
|
PrintStream logOut = new PrintStream(
|
||||||
|
new BufferedOutputStream(new FileOutputStream(dlog)));
|
||||||
|
System.setOut(logOut);
|
||||||
|
System.setErr(logOut);
|
||||||
|
Log.info("Opened debug log '" + dlog + "'.");
|
||||||
|
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.warning("Failed to open debug log [path=" + dlog +
|
||||||
|
", error=" + ioe + "].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
EditorApp app = new EditorApp(target);
|
||||||
|
// start up the UI on the AWT thread to avoid deadlocks
|
||||||
|
EventQueue.invokeLater(app);
|
||||||
|
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.warning("Unable to initialize editor.");
|
||||||
|
Log.logStackTrace(ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The implementation of the EditorContext interface that provides
|
||||||
|
* handles to the config and manager objects that offer commonly
|
||||||
|
* used services.
|
||||||
|
*/
|
||||||
|
protected class EditorContextImpl implements EditorContext
|
||||||
|
{
|
||||||
|
public MisoTileManager getTileManager () {
|
||||||
|
return _tilemgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameManager getFrameManager () {
|
||||||
|
return _framemgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceManager getResourceManager () {
|
||||||
|
return _rmgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageManager getImageManager () {
|
||||||
|
return _imgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageManager getMessageManager () {
|
||||||
|
return _msgmgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IconManager getIconManager () {
|
||||||
|
return _iconmgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SoundManager getSoundManager() {
|
||||||
|
return _soundmgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyboardManager getKeyboardManager() {
|
||||||
|
return _kbdmgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComponentRepository getComponentRepository () {
|
||||||
|
return _crepo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyDispatcher getKeyDispatcher () {
|
||||||
|
return _keydisp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String xlate (String message) {
|
||||||
|
return xlate("stage.editor", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String xlate (String bundle, String message) {
|
||||||
|
MessageBundle mbundle = _msgmgr.getBundle(bundle);
|
||||||
|
if (mbundle == null) {
|
||||||
|
Log.warning("Requested to translate message with " +
|
||||||
|
"non-existent bundle [bundle=" + bundle +
|
||||||
|
", message=" + message + "].");
|
||||||
|
return message;
|
||||||
|
} else {
|
||||||
|
return mbundle.xlate(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TileSetRepository getTileSetRepository () {
|
||||||
|
return _tsrepo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorPository getColorPository () {
|
||||||
|
return _colpos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enumerateSceneTypes (List types) {
|
||||||
|
types.add(StageSceneModel.WORLD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EditorContext _ctx;
|
||||||
|
protected EditorFrame _frame;
|
||||||
|
protected FrameManager _framemgr;
|
||||||
|
|
||||||
|
protected ResourceManager _rmgr;
|
||||||
|
protected ImageManager _imgr;
|
||||||
|
protected MisoTileManager _tilemgr;
|
||||||
|
protected TileSetRepository _tsrepo;
|
||||||
|
protected ColorPository _colpos;
|
||||||
|
protected MessageManager _msgmgr;
|
||||||
|
protected IconManager _iconmgr;
|
||||||
|
protected SoundManager _soundmgr;
|
||||||
|
protected KeyboardManager _kbdmgr;
|
||||||
|
protected BundledComponentRepository _crepo;
|
||||||
|
protected KeyDispatcher _keydisp;
|
||||||
|
|
||||||
|
/** The path to the config file for the icon manager. */
|
||||||
|
protected static final String ICON_MANAGER_CONFIG =
|
||||||
|
"rsrc/config/stage/iconmgr.properties";
|
||||||
|
|
||||||
|
/** A debug hook that toggles debug rendering of traversable tiles. */
|
||||||
|
protected static RuntimeAdjust.BooleanAdjust _viewFullScreen =
|
||||||
|
new RuntimeAdjust.BooleanAdjust(
|
||||||
|
"Toggles whether or not the scene editor uses full screen mode.",
|
||||||
|
"stage.editor.full_screen", EditorConfig.config, false);
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// $Id: EditorConfig.java 1352 2002-03-28 23:55:21Z ray $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import com.samskivert.util.Config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides access to configuration data for the editor.
|
||||||
|
*/
|
||||||
|
public class EditorConfig
|
||||||
|
{
|
||||||
|
/** Provides access to config data for this package. */
|
||||||
|
public static Config config = new Config("rsrc/config/stage/tools/editor");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessor method for getting the test tile directory.
|
||||||
|
*/
|
||||||
|
public static String getTestTileDirectory ()
|
||||||
|
{
|
||||||
|
return config.getValue(TESTTILE_KEY, TESTTILE_DEF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessor method for setting the test tile directory.
|
||||||
|
*/
|
||||||
|
public static void setTestTileDirectory (String newvalue)
|
||||||
|
{
|
||||||
|
config.setValue(TESTTILE_KEY, newvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String TESTTILE_KEY = "testtiledir";
|
||||||
|
private static final String TESTTILE_DEF = ".";
|
||||||
|
}
|
||||||
@@ -0,0 +1,552 @@
|
|||||||
|
//
|
||||||
|
// $Id: EditorFrame.java 19411 2005-02-19 00:28:49Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.MouseWheelEvent;
|
||||||
|
import java.awt.event.MouseWheelListener;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javax.swing.JInternalFrame;
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JMenuBar;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollBar;
|
||||||
|
import javax.swing.KeyStroke;
|
||||||
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
|
||||||
|
import com.samskivert.swing.GroupLayout;
|
||||||
|
import com.samskivert.swing.HGroupLayout;
|
||||||
|
import com.samskivert.swing.util.MenuUtil;
|
||||||
|
import com.samskivert.swing.util.SwingUtil;
|
||||||
|
|
||||||
|
import com.threerings.media.ManagedJFrame;
|
||||||
|
|
||||||
|
import com.threerings.miso.tile.BaseTileSet;
|
||||||
|
import com.threerings.miso.util.MisoSceneMetrics;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageScene;
|
||||||
|
import com.threerings.stage.data.StageSceneModel;
|
||||||
|
|
||||||
|
import com.threerings.stage.tools.editor.util.EditorContext;
|
||||||
|
import com.threerings.stage.tools.editor.util.EditorDialogUtil;
|
||||||
|
import com.threerings.stage.tools.xml.StageSceneParser;
|
||||||
|
import com.threerings.stage.tools.xml.StageSceneWriter;
|
||||||
|
|
||||||
|
public class EditorFrame extends ManagedJFrame
|
||||||
|
{
|
||||||
|
public EditorFrame ()
|
||||||
|
{
|
||||||
|
// treat a closing window as a request to quit
|
||||||
|
addWindowListener(new WindowAdapter () {
|
||||||
|
public void windowClosing (WindowEvent e) {
|
||||||
|
handleQuit(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// set our initial window title
|
||||||
|
setFilePath(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init (EditorContext ctx, String target)
|
||||||
|
{
|
||||||
|
_ctx = ctx;
|
||||||
|
|
||||||
|
// create the editor data model for reference by the panels
|
||||||
|
_model = new EditorModel(_ctx.getTileManager());
|
||||||
|
|
||||||
|
// create the file chooser used for saving and loading scenes
|
||||||
|
if (target == null) {
|
||||||
|
target = EditorConfig.config.getValue(
|
||||||
|
"editor.last_dir", System.getProperty("user.dir"));
|
||||||
|
}
|
||||||
|
_chooser = (target == null) ?
|
||||||
|
new JFileChooser() : new JFileChooser(target);
|
||||||
|
_chooser.setFileFilter(new FileFilter () {
|
||||||
|
public boolean accept (File f) {
|
||||||
|
return (f.isDirectory() || f.getName().endsWith(".xml"));
|
||||||
|
}
|
||||||
|
public String getDescription () {
|
||||||
|
return "XML Files";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// instead of using a popup, we slip the file chooser into the
|
||||||
|
// main interface (so the editor can run full-screen); thus we
|
||||||
|
// can't use the standard business and have to add an action
|
||||||
|
// listen to our file chooser
|
||||||
|
_chooser.addActionListener(_openListener);
|
||||||
|
|
||||||
|
// set up the menu bar
|
||||||
|
createMenuBar();
|
||||||
|
|
||||||
|
// create a top-level panel to manage everything
|
||||||
|
JPanel top = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
|
// create a sub-panel to contain the toolbar and scene view
|
||||||
|
_main = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
|
// set up the scene view panel with a default scene
|
||||||
|
_svpanel = new EditorScenePanel(_ctx, this, _model);
|
||||||
|
_main.add(_svpanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
// create a toolbar for action selection and other options
|
||||||
|
JPanel upper = new JPanel(
|
||||||
|
new HGroupLayout(GroupLayout.NONE, GroupLayout.LEFT));
|
||||||
|
upper.add(new EditorToolBarPanel(_ctx.getTileManager(), _model),
|
||||||
|
GroupLayout.FIXED);
|
||||||
|
_sceneInfoPanel = new SceneInfoPanel(_ctx, _model, _svpanel);
|
||||||
|
upper.add(_sceneInfoPanel, GroupLayout.FIXED);
|
||||||
|
_main.add(upper, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
// create a couple of scroll bars
|
||||||
|
JScrollBar horiz = new JScrollBar(JScrollBar.HORIZONTAL);
|
||||||
|
horiz.setBlockIncrement(500);
|
||||||
|
horiz.setModel(_svpanel.getHorizModel());
|
||||||
|
_main.add(horiz, BorderLayout.SOUTH);
|
||||||
|
JScrollBar vert = new JScrollBar(JScrollBar.VERTICAL);
|
||||||
|
vert.setBlockIncrement(500);
|
||||||
|
vert.setModel(_svpanel.getVertModel());
|
||||||
|
_main.add(vert, BorderLayout.EAST);
|
||||||
|
|
||||||
|
// add the scene view and toolbar to the top-level panel
|
||||||
|
top.add(_main, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
// set up our left sidebar panel
|
||||||
|
JPanel west = GroupLayout.makeVStretchBox(5);
|
||||||
|
_tpanel = new TileInfoPanel(_ctx, _model);
|
||||||
|
west.add(_tpanel);
|
||||||
|
|
||||||
|
JPanel boxPane = GroupLayout.makeHBox();
|
||||||
|
boxPane.add(_scrollBox = new EditorScrollBox(_svpanel));
|
||||||
|
west.add(boxPane, GroupLayout.FIXED);
|
||||||
|
|
||||||
|
// add the sub-panel to the top panel
|
||||||
|
top.add(west, BorderLayout.WEST);
|
||||||
|
|
||||||
|
// now add our top-level panel
|
||||||
|
getContentPane().add(top, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
// observe mouse-wheel events in the scene view panel to allow
|
||||||
|
// scrolling the wheel to select the tile to be placed
|
||||||
|
_svpanel.addMouseWheelListener(new MouseWheelListener() {
|
||||||
|
public void mouseWheelMoved (MouseWheelEvent e) {
|
||||||
|
if (e.getWheelRotation() < 0) {
|
||||||
|
_tpanel.selectPreviousTile();
|
||||||
|
} else {
|
||||||
|
_tpanel.selectNextTile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// finally set a default scene
|
||||||
|
newScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the menu bar and menu items and add them to the frame.
|
||||||
|
*/
|
||||||
|
public void createMenuBar ()
|
||||||
|
{
|
||||||
|
KeyStroke accel = null;
|
||||||
|
|
||||||
|
// create the "File" menu
|
||||||
|
JMenu menuFile = new JMenu("File");
|
||||||
|
menuFile.setMnemonic(KeyEvent.VK_F);
|
||||||
|
accel = KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK);
|
||||||
|
MenuUtil.addMenuItem(menuFile, "New", KeyEvent.VK_N, accel,
|
||||||
|
this, "handleNew");
|
||||||
|
accel = KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK);
|
||||||
|
MenuUtil.addMenuItem(menuFile, "Open", KeyEvent.VK_O, accel,
|
||||||
|
this, "handleOpen");
|
||||||
|
//addMenuItem(menuFile, "Close", KeyEvent.VK_C);
|
||||||
|
accel = KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK);
|
||||||
|
MenuUtil.addMenuItem(menuFile, "Save", KeyEvent.VK_S, accel,
|
||||||
|
this, "handleSave");
|
||||||
|
MenuUtil.addMenuItem(menuFile, "Save As", KeyEvent.VK_A, null,
|
||||||
|
this, "handleSaveAs");
|
||||||
|
accel = KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK);
|
||||||
|
MenuUtil.addMenuItem(menuFile, "Quit", KeyEvent.VK_Q, accel,
|
||||||
|
this, "handleQuit");
|
||||||
|
|
||||||
|
// create the "Edit" menu
|
||||||
|
// JMenu menuEdit = new JMenu("Edit");
|
||||||
|
// MenuUtil.addMenuItem(menuEdit, "Undo", this, "handleUndo");
|
||||||
|
// MenuUtil.addMenuItem(menuEdit, "Cut", this, "handleCut");
|
||||||
|
// MenuUtil.addMenuItem(menuEdit, "Copy", this, "handleCopy");
|
||||||
|
// MenuUtil.addMenuItem(menuEdit, "Paste", this, "handlePaste");
|
||||||
|
// MenuUtil.addMenuItem(menuEdit, "Clear", this, "handleClear");
|
||||||
|
// MenuUtil.addMenuItem(menuEdit, "Select All", this, "handleSelectAll");
|
||||||
|
// menuEdit.setMnemonic(KeyEvent.VK_E);
|
||||||
|
|
||||||
|
// create the "Actions" menu
|
||||||
|
JMenu menuActions = new JMenu("Actions");
|
||||||
|
MenuUtil.addMenuItem(menuActions, "Load (reload) test tiles", this,
|
||||||
|
"handleTestTiles");
|
||||||
|
menuActions.setMnemonic(KeyEvent.VK_A);
|
||||||
|
|
||||||
|
accel = KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.CTRL_MASK);
|
||||||
|
MenuUtil.addMenuItem(menuActions, "Make default base tile",
|
||||||
|
KeyEvent.VK_M, accel, this, "handleSetDefBase");
|
||||||
|
|
||||||
|
accel = KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.CTRL_MASK);
|
||||||
|
MenuUtil.addMenuItem(menuActions, "Update mini view",
|
||||||
|
KeyEvent.VK_M, accel, this, "updateMiniView");
|
||||||
|
|
||||||
|
// create the "Settings" menu
|
||||||
|
JMenu menuSettings = new JMenu("Settings");
|
||||||
|
menuSettings.setMnemonic(KeyEvent.VK_S);
|
||||||
|
accel = KeyStroke.getKeyStroke(
|
||||||
|
KeyEvent.VK_SEMICOLON, ActionEvent.CTRL_MASK);
|
||||||
|
MenuUtil.addMenuItem(menuSettings, "Preferences...", KeyEvent.VK_P,
|
||||||
|
accel, this, "handlePreferences");
|
||||||
|
|
||||||
|
// create the menu bar
|
||||||
|
JMenuBar bar = new JMenuBar();
|
||||||
|
bar.add(menuFile);
|
||||||
|
// bar.add(menuEdit);
|
||||||
|
bar.add(menuActions);
|
||||||
|
bar.add(menuSettings);
|
||||||
|
|
||||||
|
// add the menu bar to the frame
|
||||||
|
setJMenuBar(bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setScene (StageScene scene)
|
||||||
|
{
|
||||||
|
// save off the scene objects
|
||||||
|
_scene = scene;
|
||||||
|
|
||||||
|
// display the name of the scene
|
||||||
|
_sceneInfoPanel.setScene(_scene);
|
||||||
|
|
||||||
|
// set up the scene view panel with the new scene
|
||||||
|
_svpanel.setScene(_scene);
|
||||||
|
_svpanel.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void newScene ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
MisoSceneMetrics metrics = _svpanel.getSceneMetrics();
|
||||||
|
StageSceneModel model = StageSceneModel.blankStageSceneModel();
|
||||||
|
model.type = StageSceneModel.WORLD;
|
||||||
|
setScene(new StageScene(model, null));
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.warning("Unable to set blank scene.");
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a blank scene and configures the editor to begin editing
|
||||||
|
* it. Eventually this should make sure the user has a chance to save
|
||||||
|
* any scene for which editing is currently in progress.
|
||||||
|
*/
|
||||||
|
public void handleNew (ActionEvent evt)
|
||||||
|
{
|
||||||
|
// clear out the fiel path so that "Save" pops up "Save as" rather
|
||||||
|
// than overwriting whatever you were editing before
|
||||||
|
setFilePath(null);
|
||||||
|
|
||||||
|
newScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Presents the user with an open file dialog and loads the scenes
|
||||||
|
* from the selected file.
|
||||||
|
*/
|
||||||
|
public void handleOpen (ActionEvent evt)
|
||||||
|
{
|
||||||
|
_chooser.setDialogType(JFileChooser.OPEN_DIALOG);
|
||||||
|
_main.remove(_svpanel);
|
||||||
|
_main.add(_chooser, BorderLayout.CENTER);
|
||||||
|
SwingUtil.refresh(_main);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the scene from the specified path.
|
||||||
|
*/
|
||||||
|
public void openScene (String path)
|
||||||
|
{
|
||||||
|
String errmsg = null;
|
||||||
|
|
||||||
|
// attempt loading and installation of the scene
|
||||||
|
try {
|
||||||
|
StageSceneModel model = (StageSceneModel)_parser.parseScene(path);
|
||||||
|
if (model == null) {
|
||||||
|
errmsg = "No scene data found";
|
||||||
|
} else {
|
||||||
|
setScene(new StageScene(model, null));
|
||||||
|
// keep track of the path for later saving
|
||||||
|
setFilePath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
errmsg = "Parse error: " + e;
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errmsg != null) {
|
||||||
|
errmsg = "Unable to load scene from " + path + ":\n" + errmsg;
|
||||||
|
JOptionPane.showMessageDialog(
|
||||||
|
this, errmsg, "Load error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the scenes to the file they were last associated with.
|
||||||
|
*/
|
||||||
|
public void handleSave (ActionEvent evt)
|
||||||
|
{
|
||||||
|
if (_filepath == null) {
|
||||||
|
handleSaveAs(evt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkSaveOk()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// we don't write directly to the file in question, in case
|
||||||
|
// something craps out during the writing process
|
||||||
|
File tmpfile = new File(_filepath + ".tmp");
|
||||||
|
_writer.writeScene(tmpfile, _scene.getSceneModel());
|
||||||
|
|
||||||
|
// now that we've successfully written the new file, delete
|
||||||
|
// the old file
|
||||||
|
File sfile = new File(_filepath);
|
||||||
|
if (!sfile.delete()) {
|
||||||
|
Log.warning("Aiya! Not able to remove " + _filepath +
|
||||||
|
" so that we can replace it with " +
|
||||||
|
tmpfile.getPath() + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// now rename the new save file into place
|
||||||
|
if (!tmpfile.renameTo(sfile)) {
|
||||||
|
Log.warning("Fork! Not able to rename " + tmpfile.getPath() +
|
||||||
|
" to " + _filepath + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
String errmsg = "Unable to save scene to " + _filepath + ":\n" + e;
|
||||||
|
JOptionPane.showMessageDialog(
|
||||||
|
this, errmsg, "Save error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
Log.warning("Error writing scene " +
|
||||||
|
"[fname=" + _filepath + ", e=" + e + "].");
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if the save can proceed, and pop up errors if it
|
||||||
|
* can't.
|
||||||
|
*/
|
||||||
|
protected boolean checkSaveOk ()
|
||||||
|
{
|
||||||
|
String name = _scene.getName();
|
||||||
|
String type = _scene.getType();
|
||||||
|
|
||||||
|
String err = "";
|
||||||
|
if (name.equals("") || name.indexOf("<") != -1 ||
|
||||||
|
name.indexOf(">") != -1) {
|
||||||
|
err += "Invalid scene name.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.equals("")) {
|
||||||
|
err += "No scene type specified.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_svpanel.getEntrance() == null) {
|
||||||
|
err += "No default entrance portal.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("".equals(err)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
JOptionPane.showMessageDialog(
|
||||||
|
this, err + "\nPlease fix and try again.",
|
||||||
|
"Won't save: scene is broken!",
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Present the user with a save file dialog and save the scenes to
|
||||||
|
* the selected file.
|
||||||
|
*/
|
||||||
|
public void handleSaveAs (ActionEvent evt)
|
||||||
|
{
|
||||||
|
_chooser.setDialogType(JFileChooser.SAVE_DIALOG);
|
||||||
|
_main.remove(_svpanel);
|
||||||
|
_main.add(_chooser, BorderLayout.CENTER);
|
||||||
|
SwingUtil.refresh(_main);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps our file path around and conveys that information in the
|
||||||
|
* window title.
|
||||||
|
*/
|
||||||
|
protected void setFilePath (String filepath)
|
||||||
|
{
|
||||||
|
_filepath = filepath;
|
||||||
|
setTitle("Narya Scene Editor: " +
|
||||||
|
(_filepath == null ? "<new>" : _filepath));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a request to quit. Presently this just quits, but
|
||||||
|
* eventually it should give the user the chance to save any edits in
|
||||||
|
* progress.
|
||||||
|
*/
|
||||||
|
public void handleQuit (ActionEvent evt)
|
||||||
|
{
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a request to reload the test tiles.
|
||||||
|
*/
|
||||||
|
public void handleTestTiles (ActionEvent evt)
|
||||||
|
{
|
||||||
|
// don't instantiate a testLoader until we actually need one
|
||||||
|
if (_testLoader == null) {
|
||||||
|
_testLoader = new TestTileLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
_tpanel.insertTestTiles(_testLoader.loadTestTiles());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the mini view in the scrollbox.
|
||||||
|
*/
|
||||||
|
public void updateMiniView (ActionEvent evt)
|
||||||
|
{
|
||||||
|
_scrollBox.updateView();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a request to open the preferences dialog.
|
||||||
|
*/
|
||||||
|
public void handlePreferences (ActionEvent evt)
|
||||||
|
{
|
||||||
|
PreferencesDialog pd = new PreferencesDialog();
|
||||||
|
EditorDialogUtil.display(this, pd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the currently selected base tile into the scene's default
|
||||||
|
* tile.
|
||||||
|
*/
|
||||||
|
public void handleSetDefBase (ActionEvent evt)
|
||||||
|
{
|
||||||
|
if (_model.getTileSet() instanceof BaseTileSet) {
|
||||||
|
_svpanel.updateDefaultTileSet(_model.getTileSetId());
|
||||||
|
} else {
|
||||||
|
Log.warning("Not making non-base tileset into default " +
|
||||||
|
_model.getTileSet() + ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handles JFileChooser responses when opening files. */
|
||||||
|
protected ActionListener _openListener = new ActionListener() {
|
||||||
|
public void actionPerformed (ActionEvent event) {
|
||||||
|
String cmd = event.getActionCommand();
|
||||||
|
|
||||||
|
// restore the scene view
|
||||||
|
_main.remove(_chooser);
|
||||||
|
_main.add(_svpanel);
|
||||||
|
SwingUtil.refresh(_main);
|
||||||
|
|
||||||
|
// load up the scene if they selected one
|
||||||
|
if (cmd.equals(JFileChooser.APPROVE_SELECTION)) {
|
||||||
|
File filescene = _chooser.getSelectedFile();
|
||||||
|
switch (_chooser.getDialogType()) {
|
||||||
|
case JFileChooser.OPEN_DIALOG:
|
||||||
|
openScene(filescene.getPath());
|
||||||
|
EditorConfig.config.setValue(
|
||||||
|
"editor.last_dir", filescene.getParent());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JFileChooser.SAVE_DIALOG:
|
||||||
|
setFilePath(filescene.getPath());
|
||||||
|
handleSave(null);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log.warning("Wha? Weird dialog type " +
|
||||||
|
_chooser.getDialogType() + ".");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// oh god the hackery; on linux at least, the focus seems
|
||||||
|
// to be hosed after we hide the chooser and we can't just
|
||||||
|
// request to move it somewhere useful because it just
|
||||||
|
// ignores us; so instead we have to wait for the current
|
||||||
|
// event queue to flush before we can transfer focus
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run () {
|
||||||
|
_sceneInfoPanel.requestFocus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The scene currently undergoing edit. */
|
||||||
|
protected StageScene _scene;
|
||||||
|
|
||||||
|
/** The file last associated with the current scene. */
|
||||||
|
protected String _filepath;
|
||||||
|
|
||||||
|
/** Contains the scene view panel or other fun stuff. */
|
||||||
|
protected JPanel _main;
|
||||||
|
|
||||||
|
/** Used for displaying dialogs. */
|
||||||
|
protected JInternalFrame _dialog;
|
||||||
|
|
||||||
|
/** The file chooser used for loading and saving scenes. */
|
||||||
|
protected JFileChooser _chooser;
|
||||||
|
|
||||||
|
/** The panel that displays the scene view. */
|
||||||
|
protected EditorScenePanel _svpanel;
|
||||||
|
|
||||||
|
/** The panel that displays tile info. */
|
||||||
|
protected TileInfoPanel _tpanel;
|
||||||
|
|
||||||
|
/** The panel that displays scene info. */
|
||||||
|
protected SceneInfoPanel _sceneInfoPanel;
|
||||||
|
|
||||||
|
/** The scrollbox used to display the view position within the scene. */
|
||||||
|
protected EditorScrollBox _scrollBox;
|
||||||
|
|
||||||
|
/** The editor data model. */
|
||||||
|
protected EditorModel _model;
|
||||||
|
|
||||||
|
/** The editor context. */
|
||||||
|
protected EditorContext _ctx;
|
||||||
|
|
||||||
|
/** We use this to load scenes. */
|
||||||
|
protected StageSceneParser _parser = new StageSceneParser();
|
||||||
|
|
||||||
|
/** We use this to save scenes. */
|
||||||
|
protected StageSceneWriter _writer = new StageSceneWriter();
|
||||||
|
|
||||||
|
/** The test tileset loader. */
|
||||||
|
protected TestTileLoader _testLoader;
|
||||||
|
}
|
||||||
@@ -0,0 +1,262 @@
|
|||||||
|
//
|
||||||
|
// $Id: EditorModel.java 17780 2004-11-10 23:00:07Z ray $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import com.threerings.media.tile.Tile;
|
||||||
|
import com.threerings.media.tile.TileManager;
|
||||||
|
import com.threerings.media.tile.TileSet;
|
||||||
|
import com.threerings.media.tile.TileUtil;
|
||||||
|
|
||||||
|
import com.threerings.util.DirectionCodes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The EditorModel class provides a holding place for storing,
|
||||||
|
* modifying and retrieving data that is shared across the Editor
|
||||||
|
* application and its myriad UI components.
|
||||||
|
*/
|
||||||
|
public class EditorModel
|
||||||
|
{
|
||||||
|
/** Action mode constants. */
|
||||||
|
public static final int ACTION_PLACE_TILE = 0;
|
||||||
|
public static final int ACTION_EDIT_TILE = 1;
|
||||||
|
public static final int ACTION_PLACE_PORTAL = 2;
|
||||||
|
|
||||||
|
/** The number of actions. */
|
||||||
|
public static final int NUM_ACTIONS = 3;
|
||||||
|
|
||||||
|
/** Miso layer constants. */
|
||||||
|
public static final int BASE_LAYER = 0;
|
||||||
|
public static final int OBJECT_LAYER = 1;
|
||||||
|
public static final String[] LAYER_NAMES = { "Base", "Object" };
|
||||||
|
|
||||||
|
/** Prose descriptions of actions suitable for tool tip display. */
|
||||||
|
public static final String[] TIP_ACTIONS = {
|
||||||
|
"Place/Delete tiles.", "Edit object tiles.",
|
||||||
|
"Create/Edit/Delete portal."
|
||||||
|
};
|
||||||
|
|
||||||
|
/** String translations for action identifiers. */
|
||||||
|
public static final String[] CMD_ACTIONS = {
|
||||||
|
"place_tile", "edit_tile", "place_portal"
|
||||||
|
};
|
||||||
|
|
||||||
|
public EditorModel (TileManager tilemgr)
|
||||||
|
{
|
||||||
|
_tilemgr = tilemgr;
|
||||||
|
_tileSetId = _tileIndex = -1;
|
||||||
|
_lnum = _mode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an editor model listener.
|
||||||
|
*
|
||||||
|
* @param l the listener.
|
||||||
|
*/
|
||||||
|
public void addListener (EditorModelListener l)
|
||||||
|
{
|
||||||
|
if (!_listeners.contains(l)) {
|
||||||
|
_listeners.add(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify all model listeners that the editor model has changed.
|
||||||
|
*/
|
||||||
|
protected void notifyListeners (int event)
|
||||||
|
{
|
||||||
|
int size = _listeners.size();
|
||||||
|
for (int ii = 0; ii < size; ii++) {
|
||||||
|
((EditorModelListener)_listeners.get(ii)).modelChanged(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the currently selected tile is valid.
|
||||||
|
*/
|
||||||
|
public boolean isTileValid ()
|
||||||
|
{
|
||||||
|
return (_tile != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current editor action mode.
|
||||||
|
*/
|
||||||
|
public int getActionMode ()
|
||||||
|
{
|
||||||
|
return _mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current scene layer index undergoing edit.
|
||||||
|
*/
|
||||||
|
public int getLayerIndex ()
|
||||||
|
{
|
||||||
|
return _lnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently selected tile set.
|
||||||
|
*/
|
||||||
|
public TileSet getTileSet ()
|
||||||
|
{
|
||||||
|
return _tileSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently selected tile set id.
|
||||||
|
*/
|
||||||
|
public int getTileSetId ()
|
||||||
|
{
|
||||||
|
return _tileSetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently selected tile id within the selected tile
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
public int getTileId ()
|
||||||
|
{
|
||||||
|
return _tileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently selected tile for placement within the
|
||||||
|
* scene.
|
||||||
|
*/
|
||||||
|
public Tile getTile ()
|
||||||
|
{
|
||||||
|
return _tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fully qualified tile id of the currently selected tile.
|
||||||
|
*/
|
||||||
|
public int getFQTileId ()
|
||||||
|
{
|
||||||
|
return _fqTileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the currently selected tile as invalid such that editing
|
||||||
|
* when no tiles are available can be properly effected.
|
||||||
|
*/
|
||||||
|
public void clearTile ()
|
||||||
|
{
|
||||||
|
_tileSet = null;
|
||||||
|
_tileSetId = -1;
|
||||||
|
_tileIndex = -1;
|
||||||
|
_tile = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the editor action mode. The specified mode should be one
|
||||||
|
* of <code>CMD_ACTIONS</code>.
|
||||||
|
*/
|
||||||
|
public void setActionMode (String cmd)
|
||||||
|
{
|
||||||
|
for (int ii = 0; ii < CMD_ACTIONS.length; ii++) {
|
||||||
|
if (CMD_ACTIONS[ii].equals(cmd)) {
|
||||||
|
_mode = ii;
|
||||||
|
notifyListeners(EditorModelListener.ACTION_MODE_CHANGED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.warning("Attempt to set to unknown mode [cmd=" + cmd + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scene layer index undergoing edit.
|
||||||
|
*/
|
||||||
|
public void setLayerIndex (int lnum)
|
||||||
|
{
|
||||||
|
if (lnum != _lnum) {
|
||||||
|
_lnum = lnum;
|
||||||
|
notifyListeners(EditorModelListener.LAYER_INDEX_CHANGED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the selected tile for placement within the scene.
|
||||||
|
*/
|
||||||
|
public void setTile (TileSet set, int tileSetId, int tileIndex)
|
||||||
|
{
|
||||||
|
_tile = set.getTile(tileIndex);
|
||||||
|
_tileSet = set;
|
||||||
|
_tileSetId = tileSetId;
|
||||||
|
_tileIndex = tileIndex;
|
||||||
|
_fqTileId = TileUtil.getFQTileId(tileSetId, tileIndex);
|
||||||
|
notifyListeners(EditorModelListener.TILE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the tile id of the tile selected for placement within the
|
||||||
|
* scene.
|
||||||
|
*/
|
||||||
|
public void setTileId (int tileIndex)
|
||||||
|
{
|
||||||
|
setTile(_tileSet, _tileSetId, tileIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the direction in which we should grip objects.
|
||||||
|
*/
|
||||||
|
public void setObjectGripDirection (int direction)
|
||||||
|
{
|
||||||
|
_objectGrip = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the direction in which we should grip objects.
|
||||||
|
*/
|
||||||
|
public int getObjectGripDirection ()
|
||||||
|
{
|
||||||
|
return _objectGrip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the editor model.
|
||||||
|
*/
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
buf.append("[set=").append(_tileSet);
|
||||||
|
buf.append(", tid=").append(_tileIndex);
|
||||||
|
buf.append(", lnum=").append(_lnum);
|
||||||
|
buf.append(", tile=").append(_tile);
|
||||||
|
return buf.append("]").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The currently selected action mode. */
|
||||||
|
protected int _mode;
|
||||||
|
|
||||||
|
/** The currently selected tileset. */
|
||||||
|
protected TileSet _tileSet;
|
||||||
|
|
||||||
|
/** The currently selected tileset id. */
|
||||||
|
protected int _tileSetId;
|
||||||
|
|
||||||
|
/** The currently selected tile id. */
|
||||||
|
protected int _tileIndex;
|
||||||
|
|
||||||
|
/** The fully qualified tile id of the currently selected tile. */
|
||||||
|
protected int _fqTileId;
|
||||||
|
|
||||||
|
/** The currently selected layer number. */
|
||||||
|
protected int _lnum;
|
||||||
|
|
||||||
|
/** The currently selected tile for placement in the scene. */
|
||||||
|
protected Tile _tile;
|
||||||
|
|
||||||
|
/** The model listeners. */
|
||||||
|
protected ArrayList _listeners = new ArrayList();
|
||||||
|
|
||||||
|
/** The tile manager. */
|
||||||
|
protected TileManager _tilemgr;
|
||||||
|
|
||||||
|
/** Direction (which corner) we grip an object by. */
|
||||||
|
protected int _objectGrip = DirectionCodes.SOUTH;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// $Id: EditorModelListener.java 217 2001-11-29 00:29:31Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The editor model listener interface should be implemented by
|
||||||
|
* classes that would like to be notified when the editor model is
|
||||||
|
* changed.
|
||||||
|
*
|
||||||
|
* @see EditorModel
|
||||||
|
*/
|
||||||
|
public interface EditorModelListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Called by the {@link EditorModel} when the model is changed.
|
||||||
|
*/
|
||||||
|
public void modelChanged (int event);
|
||||||
|
|
||||||
|
/** Notification event constants. */
|
||||||
|
public static final int ACTION_MODE_CHANGED = 0;
|
||||||
|
public static final int LAYER_INDEX_CHANGED = 1;
|
||||||
|
public static final int TILE_CHANGED = 2;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,174 @@
|
|||||||
|
//
|
||||||
|
// $Id: EditorScrollBox.java 19363 2005-02-17 21:36:41Z ray $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import java.awt.event.ComponentAdapter;
|
||||||
|
import java.awt.event.ComponentEvent;
|
||||||
|
|
||||||
|
import com.samskivert.swing.ScrollBox;
|
||||||
|
import com.samskivert.swing.util.SwingUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A scrollbox that shows our position in the editor.
|
||||||
|
*/
|
||||||
|
public class EditorScrollBox extends ScrollBox
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create the tightly-coupled EditorScrollBox.
|
||||||
|
*/
|
||||||
|
public EditorScrollBox (EditorScenePanel panel)
|
||||||
|
{
|
||||||
|
super(panel.getHorizModel(), panel.getVertModel());
|
||||||
|
|
||||||
|
_panel = panel;
|
||||||
|
_panel.setEditorScrollBox(this);
|
||||||
|
_panel.addComponentListener(new ComponentAdapter() {
|
||||||
|
public void componentResized (ComponentEvent e)
|
||||||
|
{
|
||||||
|
SwingUtil.refresh(EditorScrollBox.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
createMiniMap(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the view of the editor map.
|
||||||
|
*/
|
||||||
|
public void updateView ()
|
||||||
|
{
|
||||||
|
_updatingView = true;
|
||||||
|
_horz.setValue(_horz.getMinimum());
|
||||||
|
_vert.setValue(_vert.getMinimum());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the graphics to draw into when rendering onto the minimap.
|
||||||
|
*/
|
||||||
|
public Graphics2D getMiniGraphics ()
|
||||||
|
{
|
||||||
|
Graphics2D gfx = (Graphics2D) _miniMap.getGraphics();
|
||||||
|
gfx.transform(AffineTransform.getTranslateInstance(_box.x, _box.y));
|
||||||
|
gfx.transform(AffineTransform.getScaleInstance(
|
||||||
|
_hFactor, _vFactor));
|
||||||
|
|
||||||
|
if (_updatingView) {
|
||||||
|
EventQueue.invokeLater(new Runnable() {
|
||||||
|
public void run ()
|
||||||
|
{
|
||||||
|
doNextPieceOfUpdate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return gfx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do the next piece of the update of the view.
|
||||||
|
*/
|
||||||
|
protected void doNextPieceOfUpdate ()
|
||||||
|
{
|
||||||
|
int x = _horz.getValue();
|
||||||
|
int y = _vert.getValue();
|
||||||
|
int lastX = _horz.getMaximum() - _horz.getExtent();
|
||||||
|
if (x != lastX) {
|
||||||
|
x = Math.min(x + _horz.getExtent(), lastX);
|
||||||
|
} else {
|
||||||
|
x = _horz.getMinimum();
|
||||||
|
|
||||||
|
int lastY = _vert.getMaximum() - _vert.getExtent();
|
||||||
|
if (y != lastY) {
|
||||||
|
y = Math.min(y + _vert.getExtent(), lastY);
|
||||||
|
} else {
|
||||||
|
// we're done
|
||||||
|
_updatingView = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_horz.setValue(x);
|
||||||
|
_vert.setValue(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public Dimension getPreferredSize ()
|
||||||
|
{
|
||||||
|
int horz = _horz.getMaximum() - _horz.getMinimum();
|
||||||
|
int vert = _vert.getMaximum() - _vert.getMinimum();
|
||||||
|
int height = MAX_HEIGHT;
|
||||||
|
int width = (int) Math.round(horz * (((float) height) / vert));
|
||||||
|
|
||||||
|
int maxwidth = getParent().getWidth();
|
||||||
|
if (maxwidth > 0 && width > maxwidth) {
|
||||||
|
height = (int) Math.round(height * (((float) maxwidth) / width));
|
||||||
|
width = maxwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Dimension(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public void setBounds (int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
super.setBounds(x, y, w, h);
|
||||||
|
|
||||||
|
if ((w != _miniMap.getWidth()) || (h != _miniMap.getHeight())) {
|
||||||
|
createMiniMap(w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected void paintBackground (Graphics g)
|
||||||
|
{
|
||||||
|
g.drawImage(_miniMap, 0, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a mini map image of the correct dimensions.
|
||||||
|
*/
|
||||||
|
protected void createMiniMap (int w, int h)
|
||||||
|
{
|
||||||
|
BufferedImage newMini = new BufferedImage(
|
||||||
|
w, h, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
|
// TODO: copy stuff over?
|
||||||
|
_miniMap = newMini;
|
||||||
|
Graphics g = _miniMap.getGraphics();
|
||||||
|
g.setColor(Color.black);
|
||||||
|
g.fillRect(0, 0, w, h);
|
||||||
|
g.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected boolean isActiveButton (MouseEvent e)
|
||||||
|
{
|
||||||
|
// all buttons are ok.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The minimap image. */
|
||||||
|
protected BufferedImage _miniMap;
|
||||||
|
|
||||||
|
/** The panel we box for. */
|
||||||
|
protected EditorScenePanel _panel;
|
||||||
|
|
||||||
|
/** Whether or not we're updating our little view. */
|
||||||
|
protected boolean _updatingView;
|
||||||
|
|
||||||
|
/** Our maximum height. */
|
||||||
|
protected static final int MAX_HEIGHT = 200;
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
//
|
||||||
|
// $Id: EditorToolBarPanel.java 17780 2004-11-10 23:00:07Z ray $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import javax.swing.*;
|
||||||
|
import com.samskivert.swing.*;
|
||||||
|
|
||||||
|
import com.threerings.media.tile.Tile;
|
||||||
|
import com.threerings.media.tile.TileIcon;
|
||||||
|
import com.threerings.media.tile.TileManager;
|
||||||
|
import com.threerings.media.tile.UniformTileSet;
|
||||||
|
|
||||||
|
public class EditorToolBarPanel extends JPanel implements ActionListener
|
||||||
|
{
|
||||||
|
public EditorToolBarPanel (TileManager tilemgr, EditorModel model)
|
||||||
|
{
|
||||||
|
_model = model;
|
||||||
|
|
||||||
|
// use of flowlayout positions the toolbar and floats properly
|
||||||
|
setLayout(new FlowLayout(FlowLayout.LEFT));
|
||||||
|
|
||||||
|
// get our toolbar icons
|
||||||
|
UniformTileSet tbset = tilemgr.loadTileSet(ICONS_PATH, 40, 40);
|
||||||
|
|
||||||
|
// create the toolbar
|
||||||
|
JToolBar toolbar = new JToolBar();
|
||||||
|
|
||||||
|
// add all of the toolbar buttons
|
||||||
|
_buttons = new ArrayList();
|
||||||
|
for (int ii = 0; ii < EditorModel.NUM_ACTIONS; ii++) {
|
||||||
|
// get the button icon images
|
||||||
|
Tile tile = tbset.getTile(ii);
|
||||||
|
if (tile != null) {
|
||||||
|
String cmd = EditorModel.CMD_ACTIONS[ii];
|
||||||
|
String tip = EditorModel.TIP_ACTIONS[ii];
|
||||||
|
|
||||||
|
// create the button
|
||||||
|
JButton b = addButton(toolbar, cmd, tip, new TileIcon(tile));
|
||||||
|
|
||||||
|
// add it to the set of buttons we're managing
|
||||||
|
_buttons.add(b);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.warning("Unable to load toolbar icon " +
|
||||||
|
"[index=" + ii + "].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default to the first button
|
||||||
|
setSelectedButton((JButton)_buttons.get(0));
|
||||||
|
|
||||||
|
// add the toolbar
|
||||||
|
add(toolbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JButton addButton (JToolBar toolbar, String cmd, String tip,
|
||||||
|
TileIcon icon)
|
||||||
|
{
|
||||||
|
// create the button and configure accordingly
|
||||||
|
JButton button = new JButton(new DimmedIcon(icon));
|
||||||
|
button.setSelectedIcon(icon);
|
||||||
|
button.addActionListener(this);
|
||||||
|
button.setActionCommand("tbar_" + cmd);
|
||||||
|
button.setToolTipText(tip);
|
||||||
|
|
||||||
|
// add the button to the toolbar
|
||||||
|
toolbar.add(button);
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setSelectedButton (JButton button)
|
||||||
|
{
|
||||||
|
for (int ii = 0; ii < _buttons.size(); ii++) {
|
||||||
|
JButton tb = (JButton)_buttons.get(ii);
|
||||||
|
tb.setSelected(tb == button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void actionPerformed (ActionEvent e)
|
||||||
|
{
|
||||||
|
String cmd = e.getActionCommand();
|
||||||
|
|
||||||
|
if (cmd.startsWith("tbar")) {
|
||||||
|
|
||||||
|
// select the chosen mode in the toolbar
|
||||||
|
setSelectedButton((JButton)e.getSource());
|
||||||
|
|
||||||
|
// update the active mode in the model, stripping the
|
||||||
|
// "tbar_" prefix from the command string
|
||||||
|
_model.setActionMode(cmd.substring(5));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.warning("Unknown action command [cmd=" + cmd + "].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The buttons in the tool bar. */
|
||||||
|
protected ArrayList _buttons;
|
||||||
|
|
||||||
|
/** The editor data model. */
|
||||||
|
protected EditorModel _model;
|
||||||
|
|
||||||
|
protected static final String ICONS_PATH =
|
||||||
|
"media/stage/tools/editor/toolbar_icons.png";
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// $Id: Log.java 8859 2003-05-16 20:05:45Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder class that contains a reference to the log object used by
|
||||||
|
* this package.
|
||||||
|
*/
|
||||||
|
public class Log
|
||||||
|
{
|
||||||
|
public static com.samskivert.util.Log log =
|
||||||
|
new com.samskivert.util.Log("stage.tools.editor");
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void debug (String message)
|
||||||
|
{
|
||||||
|
log.debug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void info (String message)
|
||||||
|
{
|
||||||
|
log.info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void warning (String message)
|
||||||
|
{
|
||||||
|
log.warning(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void logStackTrace (Throwable t)
|
||||||
|
{
|
||||||
|
log.logStackTrace(com.samskivert.util.Log.WARNING, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
|
||||||
|
// $Id: ObjectEditorDialog.java 16959 2004-08-30 22:09:53Z ray $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JInternalFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JSlider;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
|
||||||
|
import com.samskivert.swing.HGroupLayout;
|
||||||
|
import com.samskivert.swing.VGroupLayout;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
import com.threerings.media.image.ColorPository.ColorRecord;
|
||||||
|
import com.threerings.media.image.ColorPository;
|
||||||
|
|
||||||
|
import com.threerings.media.tile.NoSuchTileSetException;
|
||||||
|
import com.threerings.media.tile.RecolorableTileSet;
|
||||||
|
import com.threerings.media.tile.TileSet;
|
||||||
|
import com.threerings.media.tile.TileUtil;
|
||||||
|
|
||||||
|
import com.threerings.miso.client.SceneObject;
|
||||||
|
|
||||||
|
import com.threerings.stage.tools.editor.util.EditorContext;
|
||||||
|
import com.threerings.stage.tools.editor.util.EditorDialogUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to edit object attributes.
|
||||||
|
*/
|
||||||
|
public class ObjectEditorDialog extends JInternalFrame
|
||||||
|
implements ActionListener
|
||||||
|
{
|
||||||
|
public ObjectEditorDialog (EditorContext ctx, EditorScenePanel panel)
|
||||||
|
{
|
||||||
|
super("Edit object attributes", true);
|
||||||
|
_ctx = ctx;
|
||||||
|
_panel = panel;
|
||||||
|
|
||||||
|
// get a handle on the top-level panel
|
||||||
|
JPanel top = (JPanel)getContentPane();
|
||||||
|
|
||||||
|
// set up a layout manager for the panel
|
||||||
|
VGroupLayout gl = new VGroupLayout(
|
||||||
|
VGroupLayout.STRETCH, VGroupLayout.STRETCH, 5, VGroupLayout.CENTER);
|
||||||
|
top.setLayout(gl);
|
||||||
|
top.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||||
|
|
||||||
|
// object action editor elements
|
||||||
|
JPanel sub = new JPanel(new HGroupLayout(HGroupLayout.STRETCH));
|
||||||
|
sub.add(new JLabel("Object action command:"), HGroupLayout.FIXED);
|
||||||
|
sub.add(_action = new JTextField());
|
||||||
|
_action.addActionListener(this);
|
||||||
|
_action.setActionCommand("ok");
|
||||||
|
top.add(sub);
|
||||||
|
|
||||||
|
// create the priority slider
|
||||||
|
sub = new JPanel(new HGroupLayout(HGroupLayout.STRETCH));
|
||||||
|
sub.add(new JLabel("Render priority:"), HGroupLayout.FIXED);
|
||||||
|
sub.add(_priority = new JSlider(-5, 5));
|
||||||
|
_priority.setMajorTickSpacing(5);
|
||||||
|
_priority.setMinorTickSpacing(1);
|
||||||
|
_priority.setPaintTicks(true);
|
||||||
|
top.add(sub);
|
||||||
|
|
||||||
|
// create colorization selectors
|
||||||
|
JPanel zations = HGroupLayout.makeButtonBox(HGroupLayout.LEFT);
|
||||||
|
zations.add(new JLabel("Colorizations:"));
|
||||||
|
zations.add(_primary = new JComboBox(NO_CHOICES));
|
||||||
|
zations.add(_secondary = new JComboBox(NO_CHOICES));
|
||||||
|
top.add(zations);
|
||||||
|
|
||||||
|
// create our OK/Cancel buttons
|
||||||
|
sub = HGroupLayout.makeButtonBox(HGroupLayout.CENTER);
|
||||||
|
EditorDialogUtil.addButton(this, sub, "OK", "ok");
|
||||||
|
EditorDialogUtil.addButton(this, sub, "Cancel", "cancel");
|
||||||
|
top.add(sub);
|
||||||
|
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the dialog for display. This method should be called
|
||||||
|
* before <code>display()</code> is called.
|
||||||
|
*
|
||||||
|
* @param scobj the object to edit.
|
||||||
|
*/
|
||||||
|
public void prepare (SceneObject scobj)
|
||||||
|
{
|
||||||
|
_scobj = scobj;
|
||||||
|
|
||||||
|
// set our title to the name of the tileset and the tile index
|
||||||
|
String title;
|
||||||
|
int tsid = TileUtil.getTileSetId(scobj.info.tileId);
|
||||||
|
int tidx = TileUtil.getTileIndex(scobj.info.tileId);
|
||||||
|
TileSet tset = null;
|
||||||
|
try {
|
||||||
|
tset = _ctx.getTileManager().getTileSet(tsid);
|
||||||
|
title = tset.getName() + ": " + tidx;
|
||||||
|
} catch (NoSuchTileSetException nstse) {
|
||||||
|
title = "Error(" + tsid + "): " + tidx;
|
||||||
|
}
|
||||||
|
title += " (" + StringUtil.coordsToString(
|
||||||
|
_scobj.info.x, _scobj.info.y) + ")";
|
||||||
|
setTitle(title);
|
||||||
|
|
||||||
|
// configure our elements
|
||||||
|
String atext = (scobj.info.action == null ? "" : scobj.info.action);
|
||||||
|
_action.setText(atext);
|
||||||
|
_priority.setValue(scobj.getPriority());
|
||||||
|
|
||||||
|
// if the object supports colorizations, configure those
|
||||||
|
boolean haveZations = false;
|
||||||
|
Object[] pzations = null;
|
||||||
|
Object[] szations = null;
|
||||||
|
if (tset != null) {
|
||||||
|
String[] zations = null;
|
||||||
|
if (tset instanceof RecolorableTileSet) {
|
||||||
|
zations = ((RecolorableTileSet)tset).getColorizations();
|
||||||
|
}
|
||||||
|
if (zations != null) {
|
||||||
|
pzations = computeZations(zations, 0);
|
||||||
|
szations = computeZations(zations, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
configureZations(_primary, pzations, _scobj.info.getPrimaryZation());
|
||||||
|
configureZations(_secondary, szations,
|
||||||
|
_scobj.info.getSecondaryZation());
|
||||||
|
|
||||||
|
// select the text edit field and focus it
|
||||||
|
_action.setCaretPosition(0);
|
||||||
|
_action.moveCaretPosition(atext.length());
|
||||||
|
_action.requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object[] computeZations (String[] zations, int index)
|
||||||
|
{
|
||||||
|
if (zations.length <= index || StringUtil.blank(zations[index])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ColorPository cpos = _ctx.getColorPository();
|
||||||
|
ColorRecord[] crecs = cpos.enumerateColors(zations[index]);
|
||||||
|
if (crecs == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object[] czations = new Object[crecs.length+1];
|
||||||
|
czations[0] = new ZationChoice(0, "none");
|
||||||
|
for (int ii = 0; ii < crecs.length; ii++) {
|
||||||
|
czations[ii+1] =
|
||||||
|
new ZationChoice(crecs[ii].colorId, crecs[ii].name);
|
||||||
|
}
|
||||||
|
Arrays.sort(czations);
|
||||||
|
return czations;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void configureZations (
|
||||||
|
JComboBox combo, Object[] zations, int colorId)
|
||||||
|
{
|
||||||
|
int selidx = 0;
|
||||||
|
combo.setEnabled(zations != null);
|
||||||
|
if (zations != null) {
|
||||||
|
combo.removeAllItems();
|
||||||
|
for (int ii = 0; ii < zations.length; ii++) {
|
||||||
|
combo.addItem(zations[ii]);
|
||||||
|
if (((ZationChoice)zations[ii]).colorId == colorId) {
|
||||||
|
selidx = ii;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
combo.setSelectedIndex(selidx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface
|
||||||
|
public void actionPerformed (ActionEvent e)
|
||||||
|
{
|
||||||
|
String cmd = e.getActionCommand();
|
||||||
|
|
||||||
|
if (cmd.equals("ok")) {
|
||||||
|
_scobj.info.action = _action.getText();
|
||||||
|
byte prio = (byte)_priority.getValue();
|
||||||
|
if (prio != _scobj.getPriority()) {
|
||||||
|
_scobj.setPriority(prio);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ozations = _scobj.info.zations;
|
||||||
|
ZationChoice pchoice = (ZationChoice)_primary.getSelectedItem();
|
||||||
|
ZationChoice schoice = (ZationChoice)_secondary.getSelectedItem();
|
||||||
|
_scobj.info.setZations(pchoice.colorId, schoice.colorId);
|
||||||
|
if (ozations != _scobj.info.zations) {
|
||||||
|
_scobj.refreshObjectTile(_panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
_panel.objectEditorDismissed();
|
||||||
|
|
||||||
|
} else if (cmd.equals("cancel")) {
|
||||||
|
// do nothing except hide the dialog
|
||||||
|
_panel.objectEditorDismissed();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
System.err.println("Received unknown action: " + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// hide the dialog
|
||||||
|
EditorDialogUtil.dismiss(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used to display colorization choices. */
|
||||||
|
protected static class ZationChoice
|
||||||
|
implements Comparable
|
||||||
|
{
|
||||||
|
public short colorId;
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
public ZationChoice (int colorId, String name) {
|
||||||
|
this.colorId = (short)colorId;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo (Object other) {
|
||||||
|
return colorId - ((ZationChoice)other).colorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EditorContext _ctx;
|
||||||
|
protected EditorScenePanel _panel;
|
||||||
|
protected JTextField _action;
|
||||||
|
protected JSlider _priority;
|
||||||
|
protected SceneObject _scobj;
|
||||||
|
protected JComboBox _primary, _secondary;
|
||||||
|
|
||||||
|
protected static final ZationChoice[] NO_CHOICES = new ZationChoice[] {
|
||||||
|
new ZationChoice(0, "none") };
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
//
|
||||||
|
// $Id: PortalDialog.java 9371 2003-06-02 20:28:21Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import com.samskivert.swing.*;
|
||||||
|
|
||||||
|
import com.threerings.whirled.spot.data.Portal;
|
||||||
|
import com.threerings.whirled.spot.tools.EditablePortal;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageScene;
|
||||||
|
import com.threerings.stage.tools.editor.util.EditorDialogUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>PortalDialog</code> is used to present the user with a dialog
|
||||||
|
* allowing them to enter the information associated with an
|
||||||
|
* <code>EditablePortal</code>. The dialog is used both to set up a new
|
||||||
|
* portal and to edit an existing portal.
|
||||||
|
*/
|
||||||
|
public class PortalDialog extends JInternalFrame
|
||||||
|
implements ActionListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs the portal dialog.
|
||||||
|
*/
|
||||||
|
public PortalDialog ()
|
||||||
|
{
|
||||||
|
super("Edit Portal", true);
|
||||||
|
|
||||||
|
// get a handle on the top-level panel
|
||||||
|
JPanel top = (JPanel)getContentPane();
|
||||||
|
|
||||||
|
// set up a layout manager for the panel
|
||||||
|
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
|
||||||
|
gl.setOffAxisPolicy(GroupLayout.STRETCH);
|
||||||
|
top.setLayout(gl);
|
||||||
|
top.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||||
|
|
||||||
|
// add the dialog instruction text
|
||||||
|
top.add(new JLabel("Enter settings for this portal:"));
|
||||||
|
|
||||||
|
// create a panel to contain the portal name info
|
||||||
|
JPanel sub = new JPanel(new HGroupLayout(GroupLayout.STRETCH));
|
||||||
|
sub.add(new JLabel("Portal name:", SwingConstants.RIGHT));
|
||||||
|
|
||||||
|
// create and add the portal name text entry field
|
||||||
|
sub.add(_portalText = new JTextField());
|
||||||
|
|
||||||
|
// add the portal name info to the top-level panel
|
||||||
|
top.add(sub);
|
||||||
|
|
||||||
|
// create a check box to allow making this the default
|
||||||
|
// entrance portal
|
||||||
|
_entrance = new JCheckBox("Default Entrance");
|
||||||
|
_entrance.addActionListener(this);
|
||||||
|
_entrance.setActionCommand("entrance");
|
||||||
|
top.add(_entrance);
|
||||||
|
|
||||||
|
// create a panel to contain the OK/Cancel buttons
|
||||||
|
sub = new JPanel(new HGroupLayout());
|
||||||
|
EditorDialogUtil.addButton(this, sub, "OK", "ok");
|
||||||
|
|
||||||
|
// add the buttons to the top-level panel
|
||||||
|
top.add(sub);
|
||||||
|
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the dialog for display. This method should be called
|
||||||
|
* before <code>display()</code> is called.
|
||||||
|
*
|
||||||
|
* @param port the portal to edit.
|
||||||
|
*/
|
||||||
|
public void prepare (StageScene scene, EditablePortal port)
|
||||||
|
{
|
||||||
|
_port = port;
|
||||||
|
_scene = scene;
|
||||||
|
|
||||||
|
// if the location is already a portal, fill the text entry field
|
||||||
|
// with the current scene name, else clear it
|
||||||
|
String text = port.name;
|
||||||
|
_portalText.setText(text);
|
||||||
|
|
||||||
|
// select the text edit field
|
||||||
|
_portalText.setCaretPosition(0);
|
||||||
|
_portalText.moveCaretPosition(text.length());
|
||||||
|
|
||||||
|
// select the default entrance check box appropriately
|
||||||
|
Portal entry = _scene.getDefaultEntrance();
|
||||||
|
_entrance.setSelected(entry == null ||
|
||||||
|
entry.portalId == _port.portalId);
|
||||||
|
|
||||||
|
// request the keyboard focus so that the destination scene
|
||||||
|
// name can be typed immediately
|
||||||
|
_portalText.requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle action events on the dialog user interface elements.
|
||||||
|
*/
|
||||||
|
public void actionPerformed (ActionEvent e)
|
||||||
|
{
|
||||||
|
String cmd = e.getActionCommand();
|
||||||
|
|
||||||
|
if (cmd.equals("entrance")) {
|
||||||
|
_entrance.setSelected(_entrance.isSelected());
|
||||||
|
|
||||||
|
} else if (cmd.equals("ok")) {
|
||||||
|
handleSubmit();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.warning("Unknown action command [cmd=" + cmd + "].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the user submitting the dialog via the "OK" button.
|
||||||
|
*/
|
||||||
|
protected void handleSubmit ()
|
||||||
|
{
|
||||||
|
// get the destination scene name
|
||||||
|
_port.name = _portalText.getText();
|
||||||
|
|
||||||
|
// update the scene's default entrance
|
||||||
|
if (_entrance.isSelected()) {
|
||||||
|
_scene.setDefaultEntrance(_port);
|
||||||
|
|
||||||
|
} else if (_scene.getDefaultEntrance() == _port) {
|
||||||
|
_scene.setDefaultEntrance(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hide the dialog
|
||||||
|
EditorDialogUtil.dismiss(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected void processKeyEvent (KeyEvent e)
|
||||||
|
{
|
||||||
|
switch (e.getKeyCode()) {
|
||||||
|
case KeyEvent.VK_ENTER: handleSubmit(); break;
|
||||||
|
case KeyEvent.VK_ESCAPE: setVisible(false); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The scene. */
|
||||||
|
protected StageScene _scene;
|
||||||
|
|
||||||
|
/** The portal name text entry field. */
|
||||||
|
protected JTextField _portalText;
|
||||||
|
|
||||||
|
/** The portal default entrance check box. */
|
||||||
|
protected JCheckBox _entrance;
|
||||||
|
|
||||||
|
/** The location object denoting the portal location. */
|
||||||
|
protected EditablePortal _port;
|
||||||
|
|
||||||
|
/** The combo box listing the direction orientations. */
|
||||||
|
protected JComboBox _orientcombo;
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
//
|
||||||
|
// $Id: PortalTool.java 20143 2005-03-30 01:12:48Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import javax.swing.event.MouseInputAdapter;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.threerings.miso.util.MisoUtil;
|
||||||
|
import com.threerings.util.DirectionCodes;
|
||||||
|
import com.threerings.util.DirectionUtil;
|
||||||
|
|
||||||
|
import com.threerings.whirled.spot.tools.EditablePortal;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageScene;
|
||||||
|
import com.threerings.stage.tools.editor.util.ExtrasPainter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tool for setting a portal.
|
||||||
|
*/
|
||||||
|
public class PortalTool extends MouseInputAdapter
|
||||||
|
implements ExtrasPainter
|
||||||
|
{
|
||||||
|
public void init (EditorScenePanel panel, int centerx, int centery)
|
||||||
|
{
|
||||||
|
_panel = panel;
|
||||||
|
_scene = (StageScene)_panel.getScene();
|
||||||
|
|
||||||
|
// adjust the center screen coordinate so that it is positioned at
|
||||||
|
// the closest full coordinate where a portal may be placed
|
||||||
|
Point p = _panel.getFullCoords(centerx, centery);
|
||||||
|
|
||||||
|
// configure the portal with these full coordinates
|
||||||
|
_portal = new EditablePortal();
|
||||||
|
_portal.x = p.x;
|
||||||
|
_portal.y = p.y;
|
||||||
|
|
||||||
|
// we want to listen to drags and clicks
|
||||||
|
_panel.addMouseListener(this);
|
||||||
|
_panel.addMouseMotionListener(this);
|
||||||
|
_panel.addExtrasPainter(this);
|
||||||
|
|
||||||
|
// now map that back to a screen coordinate
|
||||||
|
_center = _panel.getScreenCoords(p.x, p.y);
|
||||||
|
|
||||||
|
calculateOrientation(centerx, centery);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the mouse is dragged we update the current portal.
|
||||||
|
*/
|
||||||
|
public void mouseDragged (MouseEvent event)
|
||||||
|
{
|
||||||
|
calculateOrientation(event.getX(), event.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If button1 is released, we store the new portal, if button3: we
|
||||||
|
* cancel.
|
||||||
|
*/
|
||||||
|
public void mouseReleased (MouseEvent event)
|
||||||
|
{
|
||||||
|
switch (event.getButton()) {
|
||||||
|
case MouseEvent.BUTTON1:
|
||||||
|
savePortal();
|
||||||
|
// fall through to BUTTON3
|
||||||
|
|
||||||
|
case MouseEvent.BUTTON3:
|
||||||
|
dispose();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paint what the clusters would look like if we were to add them to
|
||||||
|
* the scene.
|
||||||
|
*/
|
||||||
|
public void paintExtras (Graphics2D gfx)
|
||||||
|
{
|
||||||
|
_panel.paintPortal(gfx, _portal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the orientation of the portal based on the current mouse
|
||||||
|
* position and potentially repaints.
|
||||||
|
*/
|
||||||
|
protected void calculateOrientation (int x, int y)
|
||||||
|
{
|
||||||
|
// get the orientation towards the center from the current x/y
|
||||||
|
int norient = MisoUtil.getProjectedIsoDirection(
|
||||||
|
x, y, _center.x, _center.y);
|
||||||
|
norient = DirectionUtil.getOpposite(norient);
|
||||||
|
if (norient == DirectionCodes.NONE) {
|
||||||
|
norient = DirectionCodes.NORTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if our orientation changed, repaint
|
||||||
|
if (norient != _portal.orient) {
|
||||||
|
_portal.orient = (byte)norient;
|
||||||
|
_panel.repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds our portal to the scene.
|
||||||
|
*/
|
||||||
|
protected void savePortal ()
|
||||||
|
{
|
||||||
|
// try to come up with a reasonable name
|
||||||
|
String dirname = DirectionUtil.toString(_portal.orient).toLowerCase();
|
||||||
|
String name = dirname;
|
||||||
|
for (int ii=1; portalNameExists(name); ii++) {
|
||||||
|
name = dirname + ii;
|
||||||
|
}
|
||||||
|
_portal.name = name;
|
||||||
|
|
||||||
|
// add the portal to the scene and pop up the editor dialog
|
||||||
|
_scene.addPortal(_portal);
|
||||||
|
_panel.editPortal(_portal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if the portal name already exists.
|
||||||
|
*/
|
||||||
|
protected boolean portalNameExists (String name)
|
||||||
|
{
|
||||||
|
Iterator iter = _scene.getPortals();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
if (((EditablePortal)iter.next()).name.equals(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get rid of ourselves.
|
||||||
|
*/
|
||||||
|
protected void dispose ()
|
||||||
|
{
|
||||||
|
_panel.removeMouseListener(this);
|
||||||
|
_panel.removeMouseMotionListener(this);
|
||||||
|
_panel.removeExtrasPainter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The panel. */
|
||||||
|
protected EditorScenePanel _panel;
|
||||||
|
|
||||||
|
/** The scene. */
|
||||||
|
protected StageScene _scene;
|
||||||
|
|
||||||
|
/** Center coordinates. */
|
||||||
|
protected Point _center;
|
||||||
|
|
||||||
|
/** Our newly created portal. */
|
||||||
|
protected EditablePortal _portal;
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
//
|
||||||
|
// $Id: PreferencesDialog.java 9938 2003-06-20 03:55:58Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
import javax.swing.JInternalFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import com.samskivert.swing.GroupLayout;
|
||||||
|
import com.samskivert.swing.HGroupLayout;
|
||||||
|
import com.samskivert.swing.VGroupLayout;
|
||||||
|
|
||||||
|
import com.threerings.stage.tools.editor.util.EditorDialogUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A dialog for editing preferences.
|
||||||
|
*/
|
||||||
|
public class PreferencesDialog extends JInternalFrame
|
||||||
|
implements ActionListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates a preferences dialog.
|
||||||
|
*/
|
||||||
|
public PreferencesDialog ()
|
||||||
|
{
|
||||||
|
super("Editor Preferences", true);
|
||||||
|
|
||||||
|
// set up a layout manager for the panel
|
||||||
|
JPanel top = (JPanel)getContentPane();
|
||||||
|
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
|
||||||
|
gl.setOffAxisPolicy(GroupLayout.STRETCH);
|
||||||
|
top.setLayout(gl);
|
||||||
|
top.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||||
|
|
||||||
|
// create the display for the test tile directory pref
|
||||||
|
JPanel sub = new JPanel(new HGroupLayout(GroupLayout.STRETCH));
|
||||||
|
sub.add(new JLabel("Directory to search for test tiles:"),
|
||||||
|
GroupLayout.FIXED);
|
||||||
|
EditorDialogUtil.addButton(this, sub,
|
||||||
|
EditorConfig.getTestTileDirectory(), "testtiledir");
|
||||||
|
top.add(sub);
|
||||||
|
|
||||||
|
sub = new JPanel(new HGroupLayout());
|
||||||
|
EditorDialogUtil.addButton(this, sub, "OK", "ok");
|
||||||
|
top.add(sub);
|
||||||
|
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle action events.
|
||||||
|
*/
|
||||||
|
public void actionPerformed (ActionEvent e)
|
||||||
|
{
|
||||||
|
String cmd = e.getActionCommand();
|
||||||
|
|
||||||
|
if (cmd.equals("testtiledir")) {
|
||||||
|
changeTestTileDir((JButton) e.getSource());
|
||||||
|
|
||||||
|
} else if (cmd.equals("ok")) {
|
||||||
|
EditorDialogUtil.dispose(this);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.warning("Unknown action command [cmd=" + cmd + "].");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pop up a file selection box for specifying the directory to look
|
||||||
|
* in for test tiles.
|
||||||
|
*/
|
||||||
|
protected void changeTestTileDir (JButton button)
|
||||||
|
{
|
||||||
|
JFileChooser chooser;
|
||||||
|
|
||||||
|
// figure out which
|
||||||
|
File f = new File(button.getText());
|
||||||
|
if (!f.exists()) {
|
||||||
|
chooser = new JFileChooser();
|
||||||
|
} else {
|
||||||
|
chooser = new JFileChooser(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||||
|
chooser.setSelectedFile(f);
|
||||||
|
|
||||||
|
int result = chooser.showDialog(this, "Select");
|
||||||
|
if (JFileChooser.APPROVE_OPTION == result) {
|
||||||
|
f = chooser.getSelectedFile();
|
||||||
|
String newdir = f.getPath();
|
||||||
|
button.setText(newdir);
|
||||||
|
EditorConfig.setTestTileDirectory(newdir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
//
|
||||||
|
// $Id: SceneInfoPanel.java 20143 2005-03-30 01:12:48Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.FocusAdapter;
|
||||||
|
import java.awt.event.FocusEvent;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import javax.swing.DefaultComboBoxModel;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
|
||||||
|
import javax.swing.event.ChangeEvent;
|
||||||
|
import javax.swing.event.ChangeListener;
|
||||||
|
import javax.swing.event.PopupMenuEvent;
|
||||||
|
import javax.swing.event.PopupMenuListener;
|
||||||
|
|
||||||
|
import com.samskivert.swing.GroupLayout;
|
||||||
|
import com.samskivert.swing.HGroupLayout;
|
||||||
|
import com.samskivert.util.CollectionUtil;
|
||||||
|
import com.samskivert.util.SortableArrayList;
|
||||||
|
import com.samskivert.util.SortedIterator;
|
||||||
|
|
||||||
|
import com.threerings.miso.data.ObjectInfo;
|
||||||
|
import com.threerings.miso.data.SparseMisoSceneModel.ObjectVisitor;
|
||||||
|
|
||||||
|
import com.threerings.media.image.ColorPository;
|
||||||
|
|
||||||
|
import com.threerings.media.tile.NoSuchTileSetException;
|
||||||
|
import com.threerings.media.tile.RecolorableTileSet;
|
||||||
|
import com.threerings.media.tile.TileManager;
|
||||||
|
import com.threerings.media.tile.TileSet;
|
||||||
|
import com.threerings.media.tile.TileUtil;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageMisoSceneModel;
|
||||||
|
import com.threerings.stage.data.StageScene;
|
||||||
|
|
||||||
|
import com.threerings.stage.tools.editor.util.EditorContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scene info panel presents the user with options to select the
|
||||||
|
* scene layer to edit, and whether to display tile coordinates and
|
||||||
|
* locations in the scene view.
|
||||||
|
*/
|
||||||
|
public class SceneInfoPanel extends JPanel
|
||||||
|
implements ActionListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs the scene info panel.
|
||||||
|
*/
|
||||||
|
public SceneInfoPanel (EditorContext ctx, EditorModel model,
|
||||||
|
EditorScenePanel svpanel)
|
||||||
|
{
|
||||||
|
_ctx = ctx;
|
||||||
|
_svpanel = svpanel;
|
||||||
|
|
||||||
|
// configure the panel
|
||||||
|
GroupLayout gl = new HGroupLayout();
|
||||||
|
gl.setGap(12);
|
||||||
|
setLayout(gl);
|
||||||
|
|
||||||
|
JPanel vert = GroupLayout.makeVStretchBox(5);
|
||||||
|
|
||||||
|
JPanel hbox = GroupLayout.makeHBox();
|
||||||
|
|
||||||
|
// create a panel for the name label
|
||||||
|
hbox.add(createLabel("Scene name:", _scenename = new JTextField(10)));
|
||||||
|
_scenename.addActionListener(this);
|
||||||
|
_scenename.addFocusListener(new FocusAdapter() {
|
||||||
|
public void focusLost (FocusEvent e) {
|
||||||
|
_scenename.postActionEvent();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// create a drop-down for selecting the scene type
|
||||||
|
SortableArrayList types = new SortableArrayList();
|
||||||
|
ctx.enumerateSceneTypes(types);
|
||||||
|
types.sort();
|
||||||
|
types.add(0, "");
|
||||||
|
hbox.add(createLabel("Scene type:",
|
||||||
|
_scenetype = new JComboBox(types.toArray())));
|
||||||
|
_scenetype.addActionListener(this);
|
||||||
|
|
||||||
|
vert.add(hbox);
|
||||||
|
|
||||||
|
// set up the scene colorization stuff
|
||||||
|
hbox = GroupLayout.makeButtonBox(GroupLayout.LEFT);
|
||||||
|
hbox.add(_colorClasses = new JComboBox());
|
||||||
|
hbox.add(_colorIds = new JComboBox());
|
||||||
|
vert.add(createLabel("Colorizations:", hbox), GroupLayout.FIXED);
|
||||||
|
_colorClasses.addActionListener(this);
|
||||||
|
_colorIds.addActionListener(this);
|
||||||
|
_colorClasses.addPopupMenuListener(new PopupMenuListener() {
|
||||||
|
public void popupMenuCanceled (PopupMenuEvent e) { }
|
||||||
|
public void popupMenuWillBecomeInvisible (PopupMenuEvent e) { }
|
||||||
|
public void popupMenuWillBecomeVisible (PopupMenuEvent e) {
|
||||||
|
recomputeColorClasses();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
add(vert, GroupLayout.FIXED);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JPanel createLabel (String label, JComponent comp)
|
||||||
|
{
|
||||||
|
JPanel panel = GroupLayout.makeButtonBox(GroupLayout.CENTER);
|
||||||
|
panel.add(new JLabel(label), GroupLayout.FIXED);
|
||||||
|
panel.add(comp);
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the scene in the editor changes.
|
||||||
|
*/
|
||||||
|
public void setScene (StageScene scene)
|
||||||
|
{
|
||||||
|
_scene = scene;
|
||||||
|
_scenename.setText(scene.getName());
|
||||||
|
_scenetype.setSelectedItem(scene.getType());
|
||||||
|
|
||||||
|
recomputeColorClasses();
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface ActionListener
|
||||||
|
public void actionPerformed (ActionEvent e)
|
||||||
|
{
|
||||||
|
Object src = e.getSource();
|
||||||
|
if (src == _scenename) {
|
||||||
|
_scene.setName(_scenename.getText().trim());
|
||||||
|
|
||||||
|
} else if (src == _scenetype) {
|
||||||
|
_scene.setType((String) _scenetype.getSelectedItem());
|
||||||
|
|
||||||
|
} else if (src == _colorClasses) {
|
||||||
|
String cclass = (String) _colorClasses.getSelectedItem();
|
||||||
|
configureColorIds(cclass);
|
||||||
|
|
||||||
|
} else if (src == _colorIds) {
|
||||||
|
setNewDefaultColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prior to the color classes popup popping up, recompute the possible
|
||||||
|
* values.
|
||||||
|
*/
|
||||||
|
protected void recomputeColorClasses ()
|
||||||
|
{
|
||||||
|
// add all possible colorization names to the list
|
||||||
|
final TileManager tilemgr = _ctx.getTileManager();
|
||||||
|
final HashSet set = new HashSet();
|
||||||
|
StageMisoSceneModel msmodel = StageMisoSceneModel.getSceneModel(
|
||||||
|
_scene.getSceneModel());
|
||||||
|
msmodel.visitObjects(new ObjectVisitor() {
|
||||||
|
public void visit (ObjectInfo info) {
|
||||||
|
int tsid = TileUtil.getTileSetId(info.tileId);
|
||||||
|
TileSet tset;
|
||||||
|
try {
|
||||||
|
tset = tilemgr.getTileSet(tsid);
|
||||||
|
} catch (NoSuchTileSetException nstse) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String[] zations;
|
||||||
|
if (tset instanceof RecolorableTileSet) {
|
||||||
|
zations = ((RecolorableTileSet) tset).getColorizations();
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (zations != null) {
|
||||||
|
for (int ii=0; ii < zations.length; ii++) {
|
||||||
|
set.add(zations[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object selected = _colorClasses.getSelectedItem();
|
||||||
|
DefaultComboBoxModel model =
|
||||||
|
(DefaultComboBoxModel) _colorClasses.getModel();
|
||||||
|
model.removeAllElements();
|
||||||
|
for (Iterator itr = new SortedIterator(set); itr.hasNext(); ) {
|
||||||
|
model.addElement(itr.next());
|
||||||
|
}
|
||||||
|
if (selected != null) {
|
||||||
|
_colorClasses.setSelectedItem(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show which color Ids are available for the currently selected
|
||||||
|
* colorization class, and select the selected one.
|
||||||
|
*/
|
||||||
|
protected void configureColorIds (String cclass)
|
||||||
|
{
|
||||||
|
_colorIds.removeActionListener(this);
|
||||||
|
try {
|
||||||
|
DefaultComboBoxModel model =
|
||||||
|
(DefaultComboBoxModel) _colorIds.getModel();
|
||||||
|
model.removeAllElements();
|
||||||
|
if (cclass == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorPository cpos = _ctx.getColorPository();
|
||||||
|
|
||||||
|
String noChoice = "<none>";
|
||||||
|
String choice = noChoice;
|
||||||
|
|
||||||
|
ColorPository.ClassRecord classRec = cpos.getClassRecord(cclass);
|
||||||
|
int pick = _scene.getDefaultColor(classRec.classId);
|
||||||
|
|
||||||
|
ColorPository.ColorRecord[] colors = cpos.enumerateColors(cclass);
|
||||||
|
SortableArrayList list = new SortableArrayList();
|
||||||
|
for (int ii=0; ii < colors.length; ii++) {
|
||||||
|
list.insertSorted(colors[ii].name);
|
||||||
|
if (colors[ii].colorId == pick) {
|
||||||
|
choice = colors[ii].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model.addElement(noChoice);
|
||||||
|
for (int ii=0; ii < list.size(); ii++) {
|
||||||
|
model.addElement(list.get(ii));
|
||||||
|
}
|
||||||
|
_colorIds.setSelectedItem(choice);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
_colorIds.addActionListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a _colorIds color is selected.
|
||||||
|
*/
|
||||||
|
protected void setNewDefaultColor ()
|
||||||
|
{
|
||||||
|
String cclass = (String) _colorClasses.getSelectedItem();
|
||||||
|
if (cclass == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorPository cpos = _ctx.getColorPository();
|
||||||
|
ColorPository.ClassRecord classRec = cpos.getClassRecord(cclass);
|
||||||
|
ColorPository.ColorRecord[] colors = cpos.enumerateColors(cclass);
|
||||||
|
Object selected = _colorIds.getSelectedItem();
|
||||||
|
int pick = -1;
|
||||||
|
|
||||||
|
for (int ii=0; ii < colors.length; ii++) {
|
||||||
|
if (colors[ii].name.equals(selected)) {
|
||||||
|
pick = colors[ii].colorId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// only update the scene if our selection has actually changed
|
||||||
|
if (_scene.getDefaultColor(classRec.classId) != pick) {
|
||||||
|
_scene.setDefaultColor(classRec.classId, pick);
|
||||||
|
_svpanel.setScene(_scene);
|
||||||
|
_svpanel.repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The giver of life. */
|
||||||
|
protected EditorContext _ctx;
|
||||||
|
|
||||||
|
/** The scene we're controlling. */
|
||||||
|
protected StageScene _scene;
|
||||||
|
|
||||||
|
/** The scene name entry field. */
|
||||||
|
protected JTextField _scenename;
|
||||||
|
|
||||||
|
/** The scene type selector. */
|
||||||
|
protected JComboBox _scenetype, _colorClasses, _colorIds;
|
||||||
|
|
||||||
|
/** The scene panel, which we hackily repaint when default colors change. */
|
||||||
|
protected EditorScenePanel _svpanel;
|
||||||
|
|
||||||
|
/** The object grip direction button. */
|
||||||
|
protected DirectionButton _dirbutton;
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
//
|
||||||
|
// $Id: TestTileLoader.java 9938 2003-06-20 03:55:58Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
import com.samskivert.util.HashIntMap;
|
||||||
|
|
||||||
|
import com.threerings.media.tile.ImageProvider;
|
||||||
|
import com.threerings.media.tile.SimpleCachingImageProvider;
|
||||||
|
import com.threerings.media.tile.TileSet;
|
||||||
|
import com.threerings.media.tile.TileSetIDBroker;
|
||||||
|
|
||||||
|
import com.threerings.miso.tile.tools.xml.BaseTileSetRuleSet;
|
||||||
|
import com.threerings.media.tile.tools.xml.ObjectTileSetRuleSet;
|
||||||
|
import com.threerings.media.tile.tools.xml.SwissArmyTileSetRuleSet;
|
||||||
|
import com.threerings.media.tile.tools.xml.XMLTileSetParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TestTileLoader handles test tiles. Test tiles are tiles that an
|
||||||
|
* artist can load in on-the-fly to see how things look in the scene editor.
|
||||||
|
*/
|
||||||
|
public class TestTileLoader implements TileSetIDBroker
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Construct the TestTileLoader.
|
||||||
|
*/
|
||||||
|
public TestTileLoader ()
|
||||||
|
{
|
||||||
|
// our xml parser
|
||||||
|
_parser = new XMLTileSetParser();
|
||||||
|
// add some rulesets
|
||||||
|
_parser.addRuleSet("bundle/base", new BaseTileSetRuleSet());
|
||||||
|
_parser.addRuleSet("bundle/object", new ObjectTileSetRuleSet());
|
||||||
|
|
||||||
|
// we used to parse fringes, but we don't anymore
|
||||||
|
//_parser.addRuleSet("bundle/fringe", new SwissArmyTileSetRuleSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the specified directory and all its subdirectories for xml files.
|
||||||
|
* Each directory should contain at most one xml file, each xml file
|
||||||
|
* should specify at most one tileset. That tileset specification
|
||||||
|
* will be used to create tilesets for all the .png files in the same
|
||||||
|
* directory.
|
||||||
|
*
|
||||||
|
* @return a HashIntMap containing a TileSetId -> TileSet mapping for
|
||||||
|
* all the tilesets we create.
|
||||||
|
*/
|
||||||
|
public HashIntMap loadTestTiles ()
|
||||||
|
{
|
||||||
|
String directory = EditorConfig.getTestTileDirectory();
|
||||||
|
HashIntMap map = new HashIntMap();
|
||||||
|
|
||||||
|
// recurse test directory, making a tileset from the xml file inside
|
||||||
|
// and cloning it for each image we find in there.
|
||||||
|
File testdir = new File(directory);
|
||||||
|
// make sure it's a directory
|
||||||
|
if (!testdir.isDirectory()) {
|
||||||
|
Log.warning("Test tileset directory is not actually a directory: " +
|
||||||
|
directory);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursively load all the test tiles
|
||||||
|
loadTestTilesFromDir(testdir, map);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load xml tile sets from a directory.
|
||||||
|
*/
|
||||||
|
protected void loadTestTilesFromDir (File directory,
|
||||||
|
HashIntMap sets)
|
||||||
|
{
|
||||||
|
// first recurse
|
||||||
|
File[] subdirs = directory.listFiles(new FileFilter() {
|
||||||
|
public boolean accept (File f) {
|
||||||
|
return f.isDirectory();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (int ii=0; ii < subdirs.length; ii++) {
|
||||||
|
loadTestTilesFromDir(subdirs[ii], sets);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now look for the xml file
|
||||||
|
String[] xml = directory.list(new FilenameFilter() {
|
||||||
|
public boolean accept (File dir, String name) {
|
||||||
|
return name.endsWith(".xml");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int ii=0; ii < xml.length; ii++) {
|
||||||
|
File xmlfile = new File(directory, xml[ii]);
|
||||||
|
|
||||||
|
HashMap tiles = new HashMap();
|
||||||
|
try {
|
||||||
|
_parser.loadTileSets(xmlfile, tiles);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
Log.warning("Error while parsing " + xmlfile.getPath());
|
||||||
|
Log.logStackTrace(ioe);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator iter = tiles.values().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
TileSet ts = (TileSet) iter.next();
|
||||||
|
String path = new File(directory, ts.getImagePath()).getPath();
|
||||||
|
|
||||||
|
// before we insert, make sure we can load the image
|
||||||
|
if (null != _improv.getTileSetImage(path, null)) {
|
||||||
|
ts.setImageProvider(_improv);
|
||||||
|
ts.setImagePath(path);
|
||||||
|
sets.put(getTileSetID(path), ts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate unique and completely fake tileset IDs that will be stable
|
||||||
|
* even after a reload of test tiles.
|
||||||
|
*/
|
||||||
|
public int getTileSetID (String tileSetPath)
|
||||||
|
{
|
||||||
|
Integer id = (Integer) _idmap.get(tileSetPath);
|
||||||
|
if (null == id) {
|
||||||
|
id = new Integer(_fakeID--);
|
||||||
|
_idmap.put(tileSetPath, id);
|
||||||
|
}
|
||||||
|
return id.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public boolean tileSetMapped (String tilesetPath)
|
||||||
|
{
|
||||||
|
return _idmap.containsKey(tilesetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since we're just testing, we don't save these crazy IDs.
|
||||||
|
*/
|
||||||
|
public void commit ()
|
||||||
|
{
|
||||||
|
// this method does nothing. perhaps it should be called "committee".
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The value of the next fakeID we'll hand out. */
|
||||||
|
protected int _fakeID = -1;
|
||||||
|
|
||||||
|
/** A mapping of pathname -> tileset id. */
|
||||||
|
protected HashMap _idmap = new HashMap();
|
||||||
|
|
||||||
|
/** Our xml parser. */
|
||||||
|
protected XMLTileSetParser _parser;
|
||||||
|
|
||||||
|
/** Our image provider. */
|
||||||
|
protected ImageProvider _improv = new SimpleCachingImageProvider() {
|
||||||
|
protected BufferedImage loadImage (String path)
|
||||||
|
throws IOException {
|
||||||
|
return ImageIO.read(new File(path));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,707 @@
|
|||||||
|
//
|
||||||
|
// $Id: TileInfoPanel.java 17625 2004-10-28 17:50:03Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.event.KeyAdapter;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.DefaultListCellRenderer;
|
||||||
|
import javax.swing.DefaultListModel;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.JSplitPane;
|
||||||
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.JTree;
|
||||||
|
import javax.swing.ListSelectionModel;
|
||||||
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.event.ListSelectionEvent;
|
||||||
|
import javax.swing.event.ListSelectionListener;
|
||||||
|
import javax.swing.event.TreeSelectionEvent;
|
||||||
|
import javax.swing.event.TreeSelectionListener;
|
||||||
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
|
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||||
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
|
import javax.swing.tree.TreePath;
|
||||||
|
import javax.swing.tree.TreeSelectionModel;
|
||||||
|
|
||||||
|
import com.samskivert.util.HashIntMap;
|
||||||
|
import com.samskivert.util.QuickSort;
|
||||||
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
|
import com.threerings.media.SafeScrollPane;
|
||||||
|
|
||||||
|
import com.threerings.media.tile.TileSet;
|
||||||
|
import com.threerings.media.tile.TileSetRepository;
|
||||||
|
|
||||||
|
import com.threerings.stage.tools.editor.util.EditorContext;
|
||||||
|
import com.threerings.stage.tools.editor.util.TileSetUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tile info panel presents the user with options to select the
|
||||||
|
* tile to be applied to the scene.
|
||||||
|
*/
|
||||||
|
public class TileInfoPanel extends JSplitPane
|
||||||
|
implements ListSelectionListener, TreeSelectionListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs the tile info panel.
|
||||||
|
*/
|
||||||
|
public TileInfoPanel (EditorContext ctx, EditorModel model)
|
||||||
|
{
|
||||||
|
TileSetRepository tsrepo = ctx.getTileSetRepository();
|
||||||
|
|
||||||
|
// set up our key observers
|
||||||
|
registerKeyListener(ctx);
|
||||||
|
|
||||||
|
_model = model;
|
||||||
|
|
||||||
|
// we're going to sort all of the available tilesets into those
|
||||||
|
// which are applicable to each layer
|
||||||
|
try {
|
||||||
|
_layerSets = new ArrayList[2];
|
||||||
|
_layerLengths = new int[2];
|
||||||
|
for (int ii=0; ii < 2; ii++) {
|
||||||
|
_layerSets[ii] = new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator tsids = tsrepo.enumerateTileSetIds();
|
||||||
|
while (tsids.hasNext()) {
|
||||||
|
Integer tsid = (Integer)tsids.next();
|
||||||
|
TileSet set = tsrepo.getTileSet(tsid.intValue());
|
||||||
|
|
||||||
|
// determine which layer to which this tileset applies
|
||||||
|
int lidx = TileSetUtil.getLayerIndex(set);
|
||||||
|
if (lidx != -1) {
|
||||||
|
_layerSets[lidx].add(
|
||||||
|
new TileSetRecord(lidx, tsid.intValue(), set));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int ii=0; ii < 2; ii++) {
|
||||||
|
_layerLengths[ii] = _layerSets[ii].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.warning("Error enumerating tilesets.");
|
||||||
|
Log.logStackTrace(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up a border denoting our contents
|
||||||
|
Border border = BorderFactory.createEtchedBorder();
|
||||||
|
setBorder(BorderFactory.createTitledBorder(border, "Tile Info"));
|
||||||
|
|
||||||
|
// create a tree for selecting tileset
|
||||||
|
DefaultMutableTreeNode root = new DefaultMutableTreeNode("");
|
||||||
|
_tsettree = new JTree(root);
|
||||||
|
|
||||||
|
// don't draw any funny little icons in the tree
|
||||||
|
DefaultTreeCellRenderer cellrend =
|
||||||
|
(DefaultTreeCellRenderer) _tsettree.getCellRenderer();
|
||||||
|
cellrend.setLeafIcon(null);
|
||||||
|
cellrend.setOpenIcon(null);
|
||||||
|
cellrend.setClosedIcon(null);
|
||||||
|
|
||||||
|
// tree- only let one thing be selected, and let us know when it haps
|
||||||
|
_tsettree.getSelectionModel().setSelectionMode(
|
||||||
|
TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||||
|
_tsettree.addTreeSelectionListener(this);
|
||||||
|
|
||||||
|
// create a scrollpane to hold the tree
|
||||||
|
SafeScrollPane scrolly = new SafeScrollPane(_tsettree);
|
||||||
|
scrolly.setVerticalScrollBarPolicy(
|
||||||
|
SafeScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
|
||||||
|
|
||||||
|
DefaultListModel qmodel = new DefaultListModel();
|
||||||
|
for (int ii=0; ii < 10; ii++) {
|
||||||
|
qmodel.addElement("");
|
||||||
|
}
|
||||||
|
_quickList = new JList(qmodel);
|
||||||
|
_quickList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
|
_quickList.addListSelectionListener(this);
|
||||||
|
_quickList.setCellRenderer(new DefaultListCellRenderer() {
|
||||||
|
public Component getListCellRendererComponent (
|
||||||
|
JList list, Object value, int index, boolean isSelected,
|
||||||
|
boolean cellHasFocus)
|
||||||
|
{
|
||||||
|
// put the key number in front of each element
|
||||||
|
Component result = super.getListCellRendererComponent(
|
||||||
|
list, value, index, isSelected, cellHasFocus);
|
||||||
|
setText("" + ((index + 11) % 10) + ". " + getText());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
JSplitPane leftSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
|
||||||
|
leftSplit.setTopComponent(new SafeScrollPane(_quickList));
|
||||||
|
leftSplit.setBottomComponent(scrolly);
|
||||||
|
|
||||||
|
// add the west side
|
||||||
|
setLeftComponent(leftSplit);
|
||||||
|
|
||||||
|
// create a table to display the tiles in the selected tileset
|
||||||
|
_tiletable = new JTable(_tablemodel = new TileTableModel());
|
||||||
|
_tiletable.getSelectionModel().addListSelectionListener(this);
|
||||||
|
_tiletable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
|
updateTileTable();
|
||||||
|
|
||||||
|
// wrap the table in a scrollpane for lengthy tilesets
|
||||||
|
_scroller = new SafeScrollPane(_tiletable);
|
||||||
|
_scroller.setVerticalScrollBarPolicy(
|
||||||
|
SafeScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
|
||||||
|
|
||||||
|
// add the tile table as the entire east side
|
||||||
|
setRightComponent(_scroller);
|
||||||
|
|
||||||
|
// add the tilesets and select the starting tile set
|
||||||
|
updateTileSetTree();
|
||||||
|
|
||||||
|
// The damn splitpane freaks out unless we do this
|
||||||
|
setDividerLocation(230);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register key listeners to do things with the quick list.
|
||||||
|
*/
|
||||||
|
protected void registerKeyListener (EditorContext ctx)
|
||||||
|
{
|
||||||
|
ctx.getKeyDispatcher().addGlobalKeyListener(new KeyAdapter() {
|
||||||
|
public void keyTyped (KeyEvent e)
|
||||||
|
{
|
||||||
|
char keychar = e.getKeyChar();
|
||||||
|
if ((keychar < '0') || (keychar > '9')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn 1 into 0, and 0 into 9
|
||||||
|
int index = (keychar - '0' + 9) % 10;
|
||||||
|
if (e.isControlDown() || e.isAltDown()) {
|
||||||
|
// add
|
||||||
|
if (_curTrec == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_quickList.clearSelection();
|
||||||
|
DefaultListModel model =
|
||||||
|
(DefaultListModel) _quickList.getModel();
|
||||||
|
int olddex = model.indexOf(_curTrec);
|
||||||
|
if (olddex != -1) {
|
||||||
|
model.set(olddex, "");
|
||||||
|
}
|
||||||
|
model.set(index, _curTrec);
|
||||||
|
_quickList.setSelectedIndex(index);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// select
|
||||||
|
_quickList.setSelectedIndex(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the previous tile in the list of available tiles.
|
||||||
|
*/
|
||||||
|
public void selectPreviousTile ()
|
||||||
|
{
|
||||||
|
int row = _tiletable.getSelectedRow();
|
||||||
|
if (--row >= 0) {
|
||||||
|
_tiletable.setRowSelectionInterval(row, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the next tile in the list of available tiles.
|
||||||
|
*/
|
||||||
|
public void selectNextTile ()
|
||||||
|
{
|
||||||
|
int row = _tiletable.getSelectedRow();
|
||||||
|
if (++row < _tiletable.getRowCount()) {
|
||||||
|
_tiletable.setRowSelectionInterval(row, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public Dimension getPreferredSize ()
|
||||||
|
{
|
||||||
|
return new Dimension(WIDTH, HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the tiles in a tileset when it is selected.
|
||||||
|
*/
|
||||||
|
public void valueChanged (TreeSelectionEvent e)
|
||||||
|
{
|
||||||
|
DefaultMutableTreeNode node =
|
||||||
|
(DefaultMutableTreeNode) _tsettree.getLastSelectedPathComponent();
|
||||||
|
|
||||||
|
// we only care when a leaf is selected
|
||||||
|
if ((node != null) && (node.isLeaf())) {
|
||||||
|
|
||||||
|
_selected = node;
|
||||||
|
|
||||||
|
Object uobj = node.getUserObject();
|
||||||
|
if (!(uobj instanceof TileSetRecord)) {
|
||||||
|
Log.info("Eh? Non-TileSetRecord leaf [obj=" + uobj +
|
||||||
|
", class=" + StringUtil.shortClassName(uobj) + "].");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tileSetSelected((TileSetRecord) uobj);
|
||||||
|
_quickList.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a tileset is selected, either via the tree
|
||||||
|
* or the recent list.
|
||||||
|
*/
|
||||||
|
protected void tileSetSelected (TileSetRecord trec)
|
||||||
|
{
|
||||||
|
// if they've selected something new, update our tile display
|
||||||
|
if (_model.getTileSet() != trec.tileSet) {
|
||||||
|
_curTrec = trec;
|
||||||
|
_model.setLayerIndex(trec.layer);
|
||||||
|
|
||||||
|
// update the model to reflect new tile set and select tile
|
||||||
|
// zero by default
|
||||||
|
_model.setTile(trec.tileSet, trec.tileSetId, 0);
|
||||||
|
|
||||||
|
// update the tile table to reflect the new tileset
|
||||||
|
updateTileTable();
|
||||||
|
|
||||||
|
// _quickList.removeListSelectionListener(this);
|
||||||
|
// // add it to the recent list
|
||||||
|
// DefaultListModel recentModel = (DefaultListModel)
|
||||||
|
// _quickList.getModel();
|
||||||
|
// recentModel.removeElement(trec);
|
||||||
|
// recentModel.add(0, trec);
|
||||||
|
// _quickList.setSelectedIndex(0);
|
||||||
|
// _quickList.addListSelectionListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove previous test tiles and insert the new batch.
|
||||||
|
*/
|
||||||
|
protected void insertTestTiles (HashIntMap tests)
|
||||||
|
{
|
||||||
|
// trim the tilesets back to remove any previous test tiles
|
||||||
|
for (int ii=0; ii < 2; ii++) {
|
||||||
|
for (int jj=_layerSets[ii].size() - 1; jj >= _layerLengths[ii];
|
||||||
|
jj--) {
|
||||||
|
_layerSets[ii].remove(jj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the new test tiles
|
||||||
|
Iterator iter = tests.keys();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Integer tsid = (Integer) iter.next();
|
||||||
|
|
||||||
|
TileSet set = (TileSet) tests.get(tsid);
|
||||||
|
|
||||||
|
// determine which layer to which this tileset applies
|
||||||
|
int lidx = TileSetUtil.getLayerIndex(set);
|
||||||
|
if (lidx != -1) {
|
||||||
|
// make up a negative number to refer to this temporary tileset
|
||||||
|
_layerSets[lidx].add(
|
||||||
|
new TileSetRecord(lidx, tsid.intValue(), set));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTileSetTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The layer has changed, update the tree to reflect the tilesets
|
||||||
|
* now available.
|
||||||
|
*/
|
||||||
|
public void updateTileSetTree ()
|
||||||
|
{
|
||||||
|
// first clear out the tree
|
||||||
|
DefaultTreeModel model = (DefaultTreeModel) _tsettree.getModel();
|
||||||
|
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
|
||||||
|
root.removeAllChildren();
|
||||||
|
|
||||||
|
ArrayList expand = new ArrayList();
|
||||||
|
|
||||||
|
// add all the elements in the base layer
|
||||||
|
DefaultMutableTreeNode base = new DefaultMutableTreeNode("Base Layer");
|
||||||
|
root.add(base);
|
||||||
|
addNodes(base, getSortedTileSets(EditorModel.BASE_LAYER),
|
||||||
|
"", 0, expand);
|
||||||
|
|
||||||
|
// add all the elements in the object layer
|
||||||
|
DefaultMutableTreeNode obj = new DefaultMutableTreeNode("Object Layer");
|
||||||
|
root.add(obj);
|
||||||
|
addNodes(obj, getSortedTileSets(EditorModel.OBJECT_LAYER),
|
||||||
|
"", 0, expand);
|
||||||
|
|
||||||
|
// notify the JTree that we've put some brand new branches on it.
|
||||||
|
model.reload();
|
||||||
|
|
||||||
|
// expand our container categories
|
||||||
|
for (Iterator iter = expand.iterator(); iter.hasNext(); ) {
|
||||||
|
_tsettree.expandPath((TreePath)iter.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
// now select the previously selected item, or the first...
|
||||||
|
if (_selected == null) {
|
||||||
|
_selected = (DefaultMutableTreeNode) root.getFirstLeaf();
|
||||||
|
}
|
||||||
|
_tsettree.setSelectionPath(new TreePath(_selected.getPath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the tree with the available tilesets for the selected layer.
|
||||||
|
*/
|
||||||
|
protected TileSetRecord[] getSortedTileSets (int layer)
|
||||||
|
{
|
||||||
|
// get the list of tilesets we now want to show
|
||||||
|
ArrayList sets = _layerSets[layer];
|
||||||
|
|
||||||
|
// we don't want to sort the actual array since we have
|
||||||
|
// kept the test tiles at the end
|
||||||
|
TileSetRecord[] sorted = new TileSetRecord[sets.size()];
|
||||||
|
sets.toArray(sorted);
|
||||||
|
QuickSort.sort(sorted);
|
||||||
|
|
||||||
|
return sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively add tilesets to the tree.
|
||||||
|
*
|
||||||
|
* @param prefix The portion of the full tileset name that we've
|
||||||
|
* already parsed, it corresponds to the node we're adding to.
|
||||||
|
* @param position The position in the array from whence to start adding.
|
||||||
|
* @return the number of elements added to 'node' from 'list'.
|
||||||
|
*/
|
||||||
|
protected int addNodes (DefaultMutableTreeNode node,
|
||||||
|
TileSetRecord[] list, String prefix, int position,
|
||||||
|
ArrayList expand)
|
||||||
|
{
|
||||||
|
int prefixlen = prefix.length();
|
||||||
|
|
||||||
|
for (int ii = position; ii < list.length; ) {
|
||||||
|
String name = list[ii].fullname();
|
||||||
|
|
||||||
|
// if the next name on the list doesn't start with the prefix,
|
||||||
|
// we have no business adding it to this node.
|
||||||
|
if (!name.startsWith(prefix)) {
|
||||||
|
return ii - position;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is there another category name?
|
||||||
|
int dex = name.indexOf('/', prefixlen);
|
||||||
|
if (dex == -1) {
|
||||||
|
// nope, just add this item to the node.
|
||||||
|
DefaultMutableTreeNode item = new DefaultMutableTreeNode(
|
||||||
|
list[ii]);
|
||||||
|
node.add(item);
|
||||||
|
|
||||||
|
// oh, we're so sneaky!
|
||||||
|
// if the item we're adding has the same TileSetRecord
|
||||||
|
// as the previously selected item, we're going to want to
|
||||||
|
// select it..
|
||||||
|
if ((_selected != null) &&
|
||||||
|
(list[ii].equals(_selected.getUserObject()))) {
|
||||||
|
_selected = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
ii++;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// new category!
|
||||||
|
String catname = name.substring(prefixlen, dex);
|
||||||
|
DefaultMutableTreeNode category =
|
||||||
|
new DefaultMutableTreeNode(catname);
|
||||||
|
node.add(category);
|
||||||
|
|
||||||
|
// if we have further categories below, start expanded
|
||||||
|
if (name.indexOf('/', dex+1) != -1) {
|
||||||
|
expand.add(new TreePath(category.getPath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse..
|
||||||
|
ii += addNodes(category, list, name.substring(0, dex + 1),
|
||||||
|
ii, expand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.length - position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the tile table to reflect the currently selected tile set.
|
||||||
|
*/
|
||||||
|
protected void updateTileTable ()
|
||||||
|
{
|
||||||
|
// get the table width before we update the table model since
|
||||||
|
// updating the model seems to reset the table width to an
|
||||||
|
// incorrect default
|
||||||
|
TableColumn tcol = _tiletable.getColumnModel().getColumn(0);
|
||||||
|
_tablewid = tcol.getWidth() - (2 * EDGE_TILE_H);
|
||||||
|
|
||||||
|
// clear out the old selection because we're going to change
|
||||||
|
// tilesets
|
||||||
|
_tiletable.clearSelection();
|
||||||
|
|
||||||
|
// update the table model with the new tile set tiles
|
||||||
|
_tablemodel.updateTileSet();
|
||||||
|
|
||||||
|
// if there are no tiles in the current tile set, we're done
|
||||||
|
if (!_model.isTileValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set row heights to match the scaled tile image heights
|
||||||
|
int numTiles = getTileCount();
|
||||||
|
TileSet set = _model.getTileSet();
|
||||||
|
for (int ii = 0; ii < numTiles; ii++) {
|
||||||
|
Image img = set.getRawTileImage(ii);
|
||||||
|
int hei = getScaledTileImageHeight(img);
|
||||||
|
_tiletable.setRowHeight(ii, hei + (2 * EDGE_TILE_V));
|
||||||
|
}
|
||||||
|
|
||||||
|
// select the selected tile
|
||||||
|
int tid = _model.getTileId();
|
||||||
|
_tiletable.setRowSelectionInterval(tid, tid);
|
||||||
|
|
||||||
|
if (_scroller != null) {
|
||||||
|
// scroll to the selected tile
|
||||||
|
Rectangle r = _tiletable.getCellRect(tid, 0, true);
|
||||||
|
_scroller.getViewport().setViewPosition(new Point(r.x, r.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle tile table selections.
|
||||||
|
*/
|
||||||
|
public void valueChanged (ListSelectionEvent e)
|
||||||
|
{
|
||||||
|
// ignore extra messages
|
||||||
|
if (e.getValueIsAdjusting()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object src = e.getSource();
|
||||||
|
if (src == _quickList) {
|
||||||
|
Object o = _quickList.getSelectedValue();
|
||||||
|
if (o instanceof TileSetRecord) {
|
||||||
|
tileSetSelected((TileSetRecord) o);
|
||||||
|
if (o != _selected.getUserObject()) {
|
||||||
|
_tsettree.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// otherwise they clicked on the tile table.
|
||||||
|
ListSelectionModel lsm = (ListSelectionModel) src;
|
||||||
|
if (!lsm.isSelectionEmpty()) {
|
||||||
|
_model.setTileId(lsm.getMinSelectionIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of tiles in the currently selected tileset.
|
||||||
|
*/
|
||||||
|
protected int getTileCount ()
|
||||||
|
{
|
||||||
|
if (!_model.isTileValid()) {
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
TileSet set = _model.getTileSet();
|
||||||
|
return (set == null) ? 0 : set.getTileCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the height of the given tile image after scaling to fit
|
||||||
|
* within the width of the tile table.
|
||||||
|
*/
|
||||||
|
protected int getScaledTileImageHeight (Image img)
|
||||||
|
{
|
||||||
|
int wid = img.getWidth(null), hei = img.getHeight(null);
|
||||||
|
if (wid > _tablewid) {
|
||||||
|
float frac = (float)wid / (float)_tablewid;
|
||||||
|
return (int)(hei / frac);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hei;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends the {@link AbstractTableModel} to encapsulate the table
|
||||||
|
* layout and display options required when displaying the tiles in
|
||||||
|
* the currently selected tileset.
|
||||||
|
*/
|
||||||
|
protected class TileTableModel extends AbstractTableModel
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Called when the tile set associated with the table has been
|
||||||
|
* changed. Clears the cached image icons used to display each
|
||||||
|
* cell and updates the number of rows in the table to properly
|
||||||
|
* deal with tile sets of varying sizes.
|
||||||
|
*/
|
||||||
|
public synchronized void updateTileSet ()
|
||||||
|
{
|
||||||
|
int numTiles = getTileCount();
|
||||||
|
_icons = new ImageIcon[numTiles];
|
||||||
|
fireTableRowsInserted(0, numTiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public int getColumnCount ()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public String getColumnName (int columnIndex)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public int getRowCount ()
|
||||||
|
{
|
||||||
|
return getTileCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public Object getValueAt (int row, int col)
|
||||||
|
{
|
||||||
|
// return the icon immediately if it's already cached
|
||||||
|
if (_icons[row] != null) {
|
||||||
|
return _icons[row];
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate and save off the tile image scaled to fit the table
|
||||||
|
TileSet set = _model.getTileSet();
|
||||||
|
Image img = set.getRawTileImage(row);
|
||||||
|
int hei = getScaledTileImageHeight(img);
|
||||||
|
|
||||||
|
if (hei != img.getHeight(null)) {
|
||||||
|
img = img.getScaledInstance(
|
||||||
|
_tablewid, hei, Image.SCALE_SMOOTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (_icons[row] = new ImageIcon(img));
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public Class getColumnClass (int c)
|
||||||
|
{
|
||||||
|
// return the object associated with the column to force
|
||||||
|
// rendering of our icon images rather than straight text
|
||||||
|
return getValueAt(0, c).getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The image icons used to display the table cell contents. */
|
||||||
|
protected ImageIcon _icons[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to manage tilesets in the tileset selection combobox.
|
||||||
|
*/
|
||||||
|
protected static class TileSetRecord implements Comparable
|
||||||
|
{
|
||||||
|
public int layer;
|
||||||
|
public int tileSetId;
|
||||||
|
public TileSet tileSet;
|
||||||
|
public String shortname;
|
||||||
|
|
||||||
|
public TileSetRecord (int layer, int tileSetId, TileSet tileSet)
|
||||||
|
{
|
||||||
|
this.layer = layer;
|
||||||
|
this.tileSetId = tileSetId;
|
||||||
|
this.tileSet = tileSet;
|
||||||
|
|
||||||
|
shortname = fullname();
|
||||||
|
|
||||||
|
// cut everything before the last slash for our shortname
|
||||||
|
int lastdex = shortname.lastIndexOf('/');
|
||||||
|
if (lastdex != -1) {
|
||||||
|
shortname = shortname.substring(lastdex + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String fullname ()
|
||||||
|
{
|
||||||
|
return tileSet.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return shortname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compareTo (Object o)
|
||||||
|
{
|
||||||
|
return fullname().compareToIgnoreCase(
|
||||||
|
((TileSetRecord) o).fullname());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals (Object o)
|
||||||
|
{
|
||||||
|
if (o instanceof TileSetRecord) {
|
||||||
|
TileSetRecord tsr = (TileSetRecord) o;
|
||||||
|
return ((tsr.layer == layer) && (tsr.tileSetId == tileSetId));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Default desired panel dimensions. */
|
||||||
|
protected static final int WIDTH = 400;
|
||||||
|
protected static final int HEIGHT = 300;
|
||||||
|
|
||||||
|
/** Buffer space surrounding each tile in the tile table. */
|
||||||
|
protected static final int EDGE_TILE_H = 4;
|
||||||
|
protected static final int EDGE_TILE_V = 4;
|
||||||
|
|
||||||
|
/** An ArrayList of TileSetRecords for each layer. */
|
||||||
|
protected ArrayList[] _layerSets;
|
||||||
|
|
||||||
|
/** The original number of TileSetRecords for each layer. */
|
||||||
|
protected int[] _layerLengths;
|
||||||
|
|
||||||
|
/** The tree listing available tilesets. */
|
||||||
|
protected JTree _tsettree;
|
||||||
|
|
||||||
|
/** The selected tree node. */
|
||||||
|
protected DefaultMutableTreeNode _selected;
|
||||||
|
|
||||||
|
/** The table listing all tiles in the selected tileset. */
|
||||||
|
protected JTable _tiletable;
|
||||||
|
|
||||||
|
/** The list of quickly-selectable tilesets. */
|
||||||
|
protected JList _quickList;
|
||||||
|
|
||||||
|
/** The currently selected tileset record. */
|
||||||
|
protected TileSetRecord _curTrec;
|
||||||
|
|
||||||
|
/** The width of the tile table column in pixels. */
|
||||||
|
protected int _tablewid;
|
||||||
|
|
||||||
|
/** The scroll pane containing the tile table. */
|
||||||
|
protected SafeScrollPane _scroller;
|
||||||
|
|
||||||
|
/** The editor model. */
|
||||||
|
protected EditorModel _model;
|
||||||
|
|
||||||
|
/** The tile table data model. */
|
||||||
|
protected TileTableModel _tablemodel;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// $Id: EditorContext.java 7429 2003-04-01 02:19:34Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor.util;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.threerings.media.image.ColorPository;
|
||||||
|
import com.threerings.media.tile.TileSetRepository;
|
||||||
|
|
||||||
|
import com.threerings.stage.util.StageContext;
|
||||||
|
|
||||||
|
public interface EditorContext extends StageContext
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Return a reference to the tile set repository in use by the tile
|
||||||
|
* manager. This reference is valid for the lifetime of the
|
||||||
|
* application.
|
||||||
|
*/
|
||||||
|
public TileSetRepository getTileSetRepository ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a colorization repository for use by the editor.
|
||||||
|
*/
|
||||||
|
public ColorPository getColorPository ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts all known scene types into the supplied list.
|
||||||
|
*/
|
||||||
|
public void enumerateSceneTypes (List types);
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
//
|
||||||
|
// $Id: EditorDialogUtil.java 9223 2003-05-27 02:35:00Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor.util;
|
||||||
|
|
||||||
|
import java.awt.Container;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JInternalFrame;
|
||||||
|
import javax.swing.JLayeredPane;
|
||||||
|
|
||||||
|
import com.threerings.util.DirectionUtil;
|
||||||
|
|
||||||
|
public class EditorDialogUtil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Add a button to a container with the given parameters and
|
||||||
|
* action listener.
|
||||||
|
*
|
||||||
|
* @param l the listener.
|
||||||
|
* @param container the container.
|
||||||
|
* @param name the button name.
|
||||||
|
* @param cmd the action command.
|
||||||
|
*/
|
||||||
|
public static void addButton (ActionListener l, Container container,
|
||||||
|
String name, String cmd)
|
||||||
|
{
|
||||||
|
JButton button = new JButton(name);
|
||||||
|
button.addActionListener(l);
|
||||||
|
button.setActionCommand(cmd);
|
||||||
|
container.add(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and return a combo box seeded with the various possible
|
||||||
|
* orientation direction names.
|
||||||
|
*
|
||||||
|
* @param l the listener.
|
||||||
|
*
|
||||||
|
* @return the combo box.
|
||||||
|
*/
|
||||||
|
public static JComboBox getOrientationComboBox (ActionListener l)
|
||||||
|
{
|
||||||
|
JComboBox box = new JComboBox(DirectionUtil.getDirectionNames());
|
||||||
|
box.addActionListener(l);
|
||||||
|
box.setActionCommand("orient");
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centers the supplied dialog in its parent's bounds.
|
||||||
|
*/
|
||||||
|
public static void center (JFrame parent, JInternalFrame dialog)
|
||||||
|
{
|
||||||
|
Dimension psize = parent.getSize();
|
||||||
|
Dimension dsize = dialog.getSize();
|
||||||
|
dialog.setLocation((psize.width-dsize.width)/2,
|
||||||
|
(psize.height-dsize.height)/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a dialog centered within the given frame.
|
||||||
|
*
|
||||||
|
* @param parent the parent frame.
|
||||||
|
* @param dialog the dialog.
|
||||||
|
*/
|
||||||
|
public static void display (JFrame parent, JInternalFrame dialog)
|
||||||
|
{
|
||||||
|
center(parent, dialog);
|
||||||
|
parent.getLayeredPane().add(dialog, JLayeredPane.POPUP_LAYER);
|
||||||
|
dialog.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the supplied dialog from its parent container, but does not
|
||||||
|
* dispose it.
|
||||||
|
*/
|
||||||
|
public static void dismiss (JInternalFrame dialog)
|
||||||
|
{
|
||||||
|
Container parent = dialog.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.remove(dialog);
|
||||||
|
parent.repaint();
|
||||||
|
}
|
||||||
|
dialog.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles safely dismissing and disposing of the supplied dialog.
|
||||||
|
*/
|
||||||
|
public static void dispose (JInternalFrame dialog)
|
||||||
|
{
|
||||||
|
dismiss(dialog);
|
||||||
|
dialog.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// $Id: ExtrasPainter.java 7998 2003-04-18 18:34:41Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor.util;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for painting extra stuff.
|
||||||
|
*/
|
||||||
|
public interface ExtrasPainter
|
||||||
|
{
|
||||||
|
public void paintExtras (Graphics2D gfx);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// $Id: TileSetUtil.java 9371 2003-06-02 20:28:21Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.editor.util;
|
||||||
|
|
||||||
|
import com.threerings.media.tile.TileSet;
|
||||||
|
import com.threerings.miso.tile.BaseTileSet;
|
||||||
|
|
||||||
|
import com.threerings.stage.tools.editor.Log;
|
||||||
|
import com.threerings.stage.tools.editor.EditorModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Miscellaneous useful routines for working with lists of {@link TileSet}
|
||||||
|
* and {@link BaseTileSet} objects.
|
||||||
|
*/
|
||||||
|
public class TileSetUtil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the layer index of the layer for which this tileset
|
||||||
|
* provides tiles.
|
||||||
|
*/
|
||||||
|
public static int getLayerIndex (TileSet set)
|
||||||
|
{
|
||||||
|
if (set instanceof BaseTileSet) {
|
||||||
|
return EditorModel.BASE_LAYER;
|
||||||
|
} else {
|
||||||
|
return EditorModel.OBJECT_LAYER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// $Id: StageMisoSceneRuleSet.java 20143 2005-03-30 01:12:48Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.xml;
|
||||||
|
|
||||||
|
import com.threerings.miso.data.SparseMisoSceneModel;
|
||||||
|
import com.threerings.miso.tools.xml.SparseMisoSceneRuleSet;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageMisoSceneModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customizes the miso scene rule set such that it creates {@link
|
||||||
|
* StageMisoSceneModel} instances.
|
||||||
|
*/
|
||||||
|
public class StageMisoSceneRuleSet extends SparseMisoSceneRuleSet
|
||||||
|
{
|
||||||
|
protected SparseMisoSceneModel createMisoSceneModel ()
|
||||||
|
{
|
||||||
|
return new StageMisoSceneModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
//
|
||||||
|
// $Id: StageSceneParser.java 16546 2004-07-27 20:49:56Z ray $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.xml;
|
||||||
|
|
||||||
|
import org.apache.commons.digester.Rule;
|
||||||
|
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
|
import com.threerings.whirled.spot.tools.xml.SpotSceneRuleSet;
|
||||||
|
import com.threerings.whirled.tools.xml.SceneParser;
|
||||||
|
import com.threerings.whirled.tools.xml.SceneRuleSet;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageSceneModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses {@link StageSceneModel} instances from an XML description file.
|
||||||
|
*/
|
||||||
|
public class StageSceneParser extends SceneParser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a parser that can be used to parse Stage scene models.
|
||||||
|
*/
|
||||||
|
public StageSceneParser ()
|
||||||
|
{
|
||||||
|
super("");
|
||||||
|
|
||||||
|
// add a rule to parse scene colorizations
|
||||||
|
_digester.addRule("scene/zations/zation", new Rule() {
|
||||||
|
public void begin (String namespace, String name,
|
||||||
|
Attributes attrs) throws Exception {
|
||||||
|
StageSceneModel yoscene = (StageSceneModel) digester.peek();
|
||||||
|
int classId = Integer.parseInt(attrs.getValue("classId"));
|
||||||
|
int colorId = Integer.parseInt(attrs.getValue("colorId"));
|
||||||
|
yoscene.setDefaultColor(classId, colorId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// add rule sets for our aux scene models
|
||||||
|
registerAuxRuleSet(new SpotSceneRuleSet());
|
||||||
|
registerAuxRuleSet(new StageMisoSceneRuleSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface
|
||||||
|
protected SceneRuleSet createSceneRuleSet ()
|
||||||
|
{
|
||||||
|
return new StageSceneRuleSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple hook for parsing a single scene from the command line.
|
||||||
|
*/
|
||||||
|
public static void main (String[] args)
|
||||||
|
{
|
||||||
|
if (args.length < 1) {
|
||||||
|
System.err.println("Usage: StageSceneParser scene.xml");
|
||||||
|
System.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
System.out.println(
|
||||||
|
"Parsed " + new StageSceneParser().parseScene(args[0]));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
//
|
||||||
|
// $Id: StageSceneRuleSet.java 6370 2003-02-12 07:32:00Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.xml;
|
||||||
|
|
||||||
|
import com.threerings.whirled.tools.xml.SceneRuleSet;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageScene;
|
||||||
|
import com.threerings.stage.data.StageSceneModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to parse an {@link StageScene} from XML.
|
||||||
|
*/
|
||||||
|
public class StageSceneRuleSet extends SceneRuleSet
|
||||||
|
{
|
||||||
|
// documentation inherited
|
||||||
|
protected Class getSceneClass ()
|
||||||
|
{
|
||||||
|
return StageSceneModel.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
//
|
||||||
|
// $Id: StageSceneWriter.java 20143 2005-03-30 01:12:48Z mdb $
|
||||||
|
|
||||||
|
package com.threerings.stage.tools.xml;
|
||||||
|
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.helpers.AttributesImpl;
|
||||||
|
|
||||||
|
import com.megginson.sax.DataWriter;
|
||||||
|
|
||||||
|
import com.threerings.miso.tools.xml.SparseMisoSceneWriter;
|
||||||
|
|
||||||
|
import com.threerings.whirled.spot.data.SpotSceneModel;
|
||||||
|
import com.threerings.whirled.spot.tools.xml.SpotSceneWriter;
|
||||||
|
|
||||||
|
import com.threerings.whirled.data.SceneModel;
|
||||||
|
import com.threerings.whirled.tools.xml.SceneWriter;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageMisoSceneModel;
|
||||||
|
|
||||||
|
import com.threerings.stage.data.StageSceneModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an XML representation of a {@link StageSceneModel}.
|
||||||
|
*/
|
||||||
|
public class StageSceneWriter extends SceneWriter
|
||||||
|
{
|
||||||
|
public StageSceneWriter ()
|
||||||
|
{
|
||||||
|
// register our auxiliary model writers
|
||||||
|
registerAuxWriter(SpotSceneModel.class, new SpotSceneWriter());
|
||||||
|
registerAuxWriter(StageMisoSceneModel.class,
|
||||||
|
new SparseMisoSceneWriter());
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected void addSceneAttributes (SceneModel scene, AttributesImpl attrs)
|
||||||
|
{
|
||||||
|
super.addSceneAttributes(scene, attrs);
|
||||||
|
StageSceneModel sscene = (StageSceneModel)scene;
|
||||||
|
attrs.addAttribute("", "type", "", "", sscene.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected void writeSceneData (SceneModel scene, DataWriter writer)
|
||||||
|
throws SAXException
|
||||||
|
{
|
||||||
|
// write out any default colorizations
|
||||||
|
StageSceneModel sscene = (StageSceneModel)scene;
|
||||||
|
if (sscene.defaultColors != null) {
|
||||||
|
writer.startElement("zations");
|
||||||
|
int[] keys = sscene.defaultColors.getKeys();
|
||||||
|
for (int ii=0, nn=keys.length; ii < nn; ii++) {
|
||||||
|
int value = sscene.defaultColors.get(keys[ii]);
|
||||||
|
AttributesImpl attrs = new AttributesImpl();
|
||||||
|
attrs.addAttribute("", "classId", "", "",
|
||||||
|
String.valueOf(keys[ii]));
|
||||||
|
attrs.addAttribute("", "colorId", "", "",
|
||||||
|
String.valueOf(value));
|
||||||
|
writer.emptyElement("", "zation", "", attrs);
|
||||||
|
}
|
||||||
|
writer.endElement("zations");
|
||||||
|
}
|
||||||
|
|
||||||
|
super.writeSceneData(scene, writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#
|
||||||
|
# $Id: manager.properties 2121 2003-01-13 22:55:28Z mdb $
|
||||||
|
#
|
||||||
|
# Test resource manager configuration
|
||||||
|
|
||||||
|
# configure the BundledTileSetRepository
|
||||||
|
resource.set.tilesets = bundles/tiles/ground/bundle.jar:\
|
||||||
|
bundles/tiles/objects/bundle.jar
|
||||||
|
|
||||||
|
# configure the BundledComponentRepository
|
||||||
|
resource.set.components = bundles/components/metadata.jar:\
|
||||||
|
bundles/components/pirate/components.jar: \
|
||||||
|
bundles/components/vessel/components.jar
|
||||||
|
|
||||||
|
resource.set.general = \
|
||||||
|
bundles/components/pirate/components.jar
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#
|
||||||
|
# $Id: iconmgr.properties 20012 2005-03-24 23:19:41Z ray $
|
||||||
|
#
|
||||||
|
# Configuration for the icon manager
|
||||||
|
|
||||||
|
# simple arrow images in the order: down, up, right, left
|
||||||
|
arrows.path = media/yohoho/icons/arrows.png
|
||||||
|
arrows.metrics = 16, 16
|
||||||
|
|
||||||
|
# simpler arrows used to change values
|
||||||
|
valuearrows.path = media/yohoho/icons/value_arrows.png
|
||||||
|
valuearrows.metrics = 16, 15
|
||||||
|
|
||||||
|
# up and down arrows with "+" and "-" in them
|
||||||
|
zoomarrows.path = media/yohoho/icons/zoom_arrows.png
|
||||||
|
zoomarrows.metrics = 24, 14
|
||||||
|
|
||||||
|
# collapsible entry plus and minus icons
|
||||||
|
collapse.path = media/yohoho/icons/collapse.png
|
||||||
|
collapse.metrics = 8, 8
|
||||||
|
|
||||||
|
# icons for the tabbed panes
|
||||||
|
tabtitles.path = media/yohoho/icons/tabtitles.png
|
||||||
|
tabtitles.metrics = 16, 16
|
||||||
|
|
||||||
|
# icons for crew ranks
|
||||||
|
ranks.path = media/yohoho/icons/crew_ranks.png
|
||||||
|
ranks.metrics = 25, 25
|
||||||
|
|
||||||
|
# icon for mateys
|
||||||
|
matey.path = media/yohoho/icons/matey_icon.png
|
||||||
|
matey.metrics = 25, 25
|
||||||
|
|
||||||
|
# icons for radial menus
|
||||||
|
radmenu.path = media/yohoho/icons/radial.png
|
||||||
|
radmenu.metrics = 32, 32
|
||||||
|
|
||||||
|
# icons for portal traversal
|
||||||
|
portal.path = media/yohoho/icons/portal_arrows.png
|
||||||
|
portal.metrics = 48, 48
|
||||||
|
|
||||||
|
# icons for youser activities
|
||||||
|
activity.path = media/yohoho/icons/activity.png
|
||||||
|
activity.metrics = 27, 27
|
||||||
|
|
||||||
|
# icons for youser activities
|
||||||
|
puzzles.path = media/yohoho/icons/puzzles.png
|
||||||
|
puzzles.metrics = 24, 24
|
||||||
|
|
||||||
|
# icons for pirate info icons
|
||||||
|
pirateinfo.path = media/yohoho/icons/pirate_info.png
|
||||||
|
pirateinfo.metrics = 28, 28
|
||||||
|
|
||||||
|
# icons for scrolly history
|
||||||
|
historyscroll.path = media/yohoho/icons/history-scroll.png
|
||||||
|
historyscroll.metrics = 14, 11
|
||||||
|
|
||||||
|
# icons for full-screen history
|
||||||
|
historyfull.path = media/yohoho/icons/history-full.png
|
||||||
|
historyfull.metrics = 14, 11
|
||||||
|
|
||||||
|
# icons for the duty status button
|
||||||
|
dutystatus.path = media/yohoho/icons/duty-status.png
|
||||||
|
dutystatus.metrics = 16, 12
|
||||||
|
|
||||||
|
hiring.path = media/yohoho/icons/hiring.png
|
||||||
|
hiring.metrics = 17, 17
|
||||||
|
|
||||||
|
# icons for the wee lock images
|
||||||
|
lock.path = media/yohoho/icons/lock.png
|
||||||
|
lock.metrics = 23, 18
|
||||||
|
|
||||||
|
# icon for the ferry
|
||||||
|
ferry.path = media/yohoho/icons/ferry.png
|
||||||
|
ferry.metrics = 58, 48
|
||||||
|
|
||||||
|
# icon for whisking
|
||||||
|
whisk.path = media/yohoho/icons/whisk.png
|
||||||
|
whisk.metrics = 12, 11
|
||||||
|
|
||||||
|
# icon to indicate that a player was present for a sea battle
|
||||||
|
sea_battle.path = media/yohoho/icons/sea_battle.png
|
||||||
|
sea_battle.metrics = 13, 12
|
||||||
|
|
||||||
|
# item menu icons
|
||||||
|
item_action.path = media/yohoho/icons/item_actions.png
|
||||||
|
item_action.metrics = 27, 27
|
||||||
|
|
||||||
|
# portrait eye menu icons
|
||||||
|
portrait_eyes_male.path = media/yohoho/icons/portrait_eyes_male.png
|
||||||
|
portrait_eyes_male.metrics = 70, 25
|
||||||
|
portrait_eyes_female.path = media/yohoho/icons/portrait_eyes_female.png
|
||||||
|
portrait_eyes_female.metrics = 70, 25
|
||||||
|
|
||||||
|
# portrait mouth menu icons
|
||||||
|
portrait_mouths_male.path = media/yohoho/icons/portrait_mouths_male.png
|
||||||
|
portrait_mouths_male.metrics = 70, 25
|
||||||
|
portrait_mouths_female.path = media/yohoho/icons/portrait_mouths_female.png
|
||||||
|
portrait_mouths_female.metrics = 70, 25
|
||||||
|
|
||||||
|
# dnd icon
|
||||||
|
dnd.path = media/yohoho/icons/dnd.png
|
||||||
|
dnd.metrics = 32, 32
|
||||||
Reference in New Issue
Block a user