Monday, August 16, 2010

Update 5: DnD means Drag and Drop... no character sheets necessary

Thought I'd post a lil' snippet of code here for any wide-eyed web wanderer to use. Its a JTextField that looks like a label until double clicked, or clicked and held for 1 second. When the field looses focus, or enter is pressed it goes back to looking like a label.

Its useful in creating a condensed GUI with high functionality. Disagree? Well Photoshop's got a neat little label just like this ;-). I just wrote a Java implementation. Please subscribe, or at least lemme know if this is useful for you.


/**
* A textfield that appears as a label unless double clicked, or clicked and
* held for 1 second.
*
* @author Will Morrison
*/
public class JTextFieldLabel extends JTextField {
/**
* Default serial version ID, here to remove warnings
*/
private static final long serialVersionUID = 1L;

/**
* The original border this JTextfield used upon first instantiation
*/
private Border origBorder;
private static final Border emptyBorder = BorderFactory.createEmptyBorder();

public JTextFieldLabel() {
this("");
}

public JTextFieldLabel(String text) {
super(text, 10);
setEditable(false);
setOpaque(false);
origBorder = this.getBorder();
privateSetBorder(emptyBorder);

TextFieldLabelListener listener = new TextFieldLabelListener();
addMouseListener(listener);
addMouseMotionListener(listener);
addFocusListener(listener);
addActionListener(listener);
}

public void setBorder(Border b) {
this.origBorder = b;
super.setBorder(b);
}

private void privateSetBorder(Border b) {
super.setBorder(b);
}

public void paintComponent(Graphics g) {
if (!hasFocus()) {
super.setBorder(emptyBorder);
}
super.paintComponent(g);
}

private class TextFieldLabelListener extends MouseAdapter implements
FocusListener, ActionListener {
private Timer timer;
private boolean mouseHasMoved;

public TextFieldLabelListener() {
timer = new Timer(1000, this);
}

public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
setEditable(true);
setOpaque(true);
privateSetBorder(origBorder);
}
}

public void mousePressed(MouseEvent e) {
if (!timer.isRunning() && !mouseHasMoved) {
timer.start();
}
}

public void mouseDragged(MouseEvent e) {
mouseHasMoved = true;
timer.stop();
}

public void mouseReleased(MouseEvent e) {
mouseHasMoved = false;
timer.stop();
}

public void focusGained(FocusEvent e) {
// intentionally left blank
}

public void focusLost(FocusEvent e) {
privateSetBorder(emptyBorder);
setEditable(false);
setOpaque(false);
}

public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof Timer) {
timer.stop();
privateSetBorder(origBorder);
setEditable(true);
setOpaque(true);
requestFocus();
} else {
privateSetBorder(emptyBorder);
setEditable(false);
setOpaque(false);
}
}
}
}


As far as my editor goes, I just got TileLayer's z values to update properly with GUI panel's ordering. It looks pretty nice. Developing a DnD list with functioning GUI components in Java is a major pain, but I did it. Its even nicer because when I drag and drop components my TileMap is now updated.

Thursday, July 29, 2010

Update 4: Photoshop is 4 Lo53rS

I've created a Google repository to better track changes in my project as its becoming rather large. Also have changed my mind for now. I think I'll just stick to a basic selection type instead of following Photoshop's example and having actual masks.

I'm editing my first post to point to the repository. Now onto selection and cut/copy/paste!

Monday, July 19, 2010

Progress Report #3: Unit Testing and pick Selections

Decided to delay undo/redo support till I get all the tools working. I plan to focus on selection, cut/copy/paste over the next couple days.

Was having a lot of difficulties with intersections between Selections, so I wrote some unit tests. This solved my problems. I'm not even sure which case I fixed which solved all the issues, but everything seems to be working now. I plan to write unit tests for all significant classes eventually, but that's a little further down on my list.

Thursday, July 15, 2010

Progress Report #2: LWJGL Night Terrors

Finished all the tile writing tools. Today I'm working on Undo/Redo support, and handling some errors. Also might work on some non-tile writing related TileLayer editing functionality. Pushing back clip selection tools. Might not even include them as they're seeming a little overkill now.

I noticed some serious lag when rendering many, many images. Ah, Java2D's old nemesis, software rendering... this isn't entirely true. I'm doing a lot of scaling to simulate zoom. So I did some tests and determined there is lag when rendering many small images, even without scaling. How many do I consider "many?" Lets say 2500 or so.

So I started looking for hardware accelerated graphics. I'd planned on adding a plug-in for hardware accelerated rendering anyway, and I can always work to optimize rendering with Java2D later right? So I started by looking into LWJGL and JOGL in depth.

LWJGL only uses heavyweight components while JOGL focuses on lightweight. Also JOGL seems to have more of Sun's support and has MUCH MUCH better documentation than LWJGL. Unfortunately, JOGL development is very inactive, JOGL seems less popular, and seems more platform focused than LWJGL (ie. individual builds of the project for each OS.) Bad news for a Java application like mine, aiming at all platforms. So I settle with LWJGL for all those reasons.

Thus begins my nightmare of dealing with AWTGLCanvas. First its heavyweight. It doesn't fit in my nice JScrollPane. So I put it in ScrollPane. No, this doesn't work either. ScrollPane flickers in and out of view beneath the pane. So I have to write a custom scroll bar beneath the panel. Fine, I can handle that. What I didn't plan on was struggling for 3 hours trying to figure out why my rendering was so distorted. Eventually I figured it out. I was calling glOrth to set my perspective correctly, but was not setting the clipping planes with glViewport.

I also learned about an alternative to Swing/AWT called SWT (though I hardly consider AWT a real option nowadays.) Maybe I'll look into SWT once I get everything else functioning in my editor.

Friday, July 2, 2010

Progress Report #1

Finished editing the TileLayer class to handle its own rendering. It makes more since, since the class should handle its own behavior. Now working on getting more tools functional, and some clipping mask tools.

Went ahead and typed up a description of the Tile Writing Pipe-line for the eventual Developer's Guide for the editor.

There are 4 steps the tile writing pipeline:
1. The user either clicks or drags their mouse on the map. From this event the program calculates a rectangular area formed by a primary point, and a secondary point, the primary point being the rectangles upper left corner and the secondary point the rectangles bottom right corner. If the mouse event was a drag, the point where the mouse was first pressed becomes the primary point and the point where the mouse was released the secondary point. If the event was a click, that point becomes the primary point, and the secondary point just the primary point offset by the dimensions of the bounding rectangle of the currently selected tiles.

2. The rectangular area is passed to the SelectionShapeModifier which alters the rectangle further based on user preferences, for example making the selection proportional, or centering it on the primary point.

3. Next the rectangle is passed to the active SelectionTool, which decides which points within the rectangular area are part of the final selection, and which are not. Examples include Rectangular, Elliptical, and Flood Fill selection.

4. The Selection is then passed to a tile writer. Most tile writers do a final comparison against a mask to determine which parts of the selection make it to the underlying TileLayer.

Thursday, July 1, 2010

Hello World!

So this is my Tile Map Editor progress blog. There's a lot of competition out there, but I feel they all fall just short of being a full-fledged editor in terms of usability, and/or functionality. I intend to remedy that with my editor!

My unique approach is what really sets my editor apart. I've separated behavior up differently than most editors. For example:

I treat the tiles as pixels in an image. Each tool performing an edit first makes a selection, then performs some geometric operations on that edit, then determines which underlying tiles are actually in the selection. For example, a rectangle tool would consider all points in a rectangular selection while an ellipse tool would not.

Tile Writers handle actual setting tile values in underlying tile layers. Doing this prevents unnecessary code, and allows different types of writing (random, sequential etc.)

My project is hosted on Google.
Check It Out (pun intended): http://code.google.com/p/mapbrew/