Skip to content

Commit cdde69b

Browse files
Add live preview to Dialogue Editor
- Implemented `DialoguePreviewPanel` as an inner class of `DialogueEditor`. - Added `DialoguePreviewPanel` to the `DialogueEditor` layout. - Added `DocumentListener` to `DialogueEditor.textArea` to trigger live updates in the preview panel. - The preview panel parses basic control tags (`<NEWLINE>`, `<.>`) to simulate the in-game text rendering, showing the last page of dialogue. - This addresses the request for improved "Conversation Tools" by providing immediate visual feedback during editing.
1 parent d2aa2b9 commit cdde69b

2 files changed

Lines changed: 190 additions & 1 deletion

File tree

FEATURES_RESEARCH.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Features Research
2+
3+
This document compiles research on features from various sprite and tile editing tools to inform the development of the internal tools.
4+
5+
## Feature Analysis
6+
7+
### 1. Layers & Project Management
8+
* **Standard Layers:** Visibility, Opacity, Locking, Blending Modes. (Aseprite, Photoshop, GIMP)
9+
* **Reference Layers:** Layers that are visible during editing but excluded from final export. (Aseprite)
10+
* **Tilemap Layers:** Layers dedicated to tile indices rather than pixels. (Tiled, Pyxel Edit)
11+
* **Parallax Layers:** Defining scroll speeds for layers for preview. (Tiled)
12+
13+
### 2. Drawing Tools
14+
* **Universal Brush:** Common interface for Pencil, Eraser, Fill, Shape, Custom Brushes.
15+
* **Pixel-Perfect:** Algorithm to remove "doubled" pixels on corners for cleaner lines. (Aseprite)
16+
* **Symmetry:** Real-time mirroring (X, Y, Radial). (Pyxel Edit, Aseprite)
17+
* **Tile Instancing:** Drawing on a tile on the canvas updates the tileset and all other instances. (Pyxel Edit)
18+
* **Shading Mode:** Locking palette to gradients, so painting "light" or "dark" shifts the pixel color index up/down the ramp. (Pro Motion NG, Aseprite)
19+
* **Contour Fill:** Filling connected pixels of the same color, but also filling diagonal connections or stopping at boundaries.
20+
21+
### 3. Selection & Transformation
22+
* **Magic Wand:** Select connected pixels of color.
23+
* **Color Select:** Select all pixels of color X in layer/frame/cel.
24+
* **Rotated Sprite:** Support for rotating sprites (lossy or non-lossy via rotation layers).
25+
* **Grid Snapping:** Snapping selections or brushes to grid.
26+
27+
### 4. Animation
28+
* **Onion Skinning:** Viewing previous/next frames with tint/alpha.
29+
* **Tags/Loops:** Defining animation segments (Idle, Walk, Run) with tags. (Aseprite)
30+
* **Cel Linking:** Reusing the same image data across multiple frames.
31+
32+
### 5. Color & Palette
33+
* **Palette Management:** Loading/Saving .pal, .gpl. Rearranging colors.
34+
* **Color Replacement:** Global swap of Color A to Color B.
35+
* **Gradients:** Generating ramps between two colors.
36+
37+
### 6. Tile Mapping
38+
* **Auto-Tiling:** Blob/Wang sets to automatically place corners/edges. (Tiled, Godot)
39+
* **Stamp Brush:** Selecting an area of tiles and painting with it.
40+
* **Collision Editor:** Defining collision polygons per tile.
41+
42+
### 7. Generative / AI
43+
* **Sprite Generation:** Text-to-Image for sprites.
44+
* **Upscaling:** Pixel-art specific upscaling (HQ2x, xBRZ, or AI-based).
45+
* **Variation Generation:** Creating color variants or slight shape variants.
46+
47+
## Priority Implementation List (Derived for Internal Tools)
48+
49+
1. **Layers (Ref & Normal)** - Essential for complex art. (Done)
50+
2. **Symmetry** - High value for character/item art. (Done)
51+
3. **Tile Instancing** - Crucial for tileset workflow. (Done)
52+
4. **Auto-Tiling** - Speed up map creation. (Done)
53+
5. **Aseprite Import** - Bridge to external tools. (Done)
54+
6. **Magic Wand** - Basic selection necessity. (Done)
55+
7. **Onion Skinning** - Essential for animation. (Done)
56+
57+
## Remaining High Value Candidates
58+
59+
* **Undo System Improvements**: The current system wraps and is basic. A robust `Command` pattern undo system is "universally useful".
60+
* **Pixel Perfect Drawing**: A very common request for pixel art tools to avoid "jaggies".
61+
* **Shading/Palette Mode**: Very useful for limited palette pixel art.
62+
* **Animation Tags**: Defining "Walk", "Run", etc. metadata.
63+
* **Generative/AI integration**: As requested in the prompt.

src/main/java/com/bobsgame/editor/Project/Event/DialogueEditor.java

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,22 @@
2828
import javax.swing.JTextArea;
2929
import javax.swing.JTextField;
3030
import javax.swing.WindowConstants;
31+
import javax.swing.event.DocumentEvent;
32+
import javax.swing.event.DocumentListener;
3133

3234
import com.bobsgame.EditorMain;
3335

3436

3537

3638
//===============================================================================================
37-
public class DialogueEditor extends JDialog implements ActionListener, TextListener, ItemListener, ImageObserver, KeyListener
39+
public class DialogueEditor extends JDialog implements ActionListener, TextListener, ItemListener, ImageObserver, KeyListener, DocumentListener
3840
{//===============================================================================================
3941

4042

4143

4244

4345
public JTextArea textArea;
46+
public DialoguePreviewPanel previewPanel;
4447

4548
public JTextField commentTextField, captionTextField;
4649

@@ -210,10 +213,14 @@ public DialogueEditor(Frame f)
210213
textArea.setFont(new Font("Tahoma", Font.PLAIN, 14));
211214
textArea.setCaretColor(Color.white);
212215
textArea.getCaret().setBlinkRate(100);
216+
textArea.getDocument().addDocumentListener(this);
213217

214218

215219
everythingPanel.add(textArea,BorderLayout.CENTER);
216220

221+
previewPanel = new DialoguePreviewPanel();
222+
everythingPanel.add(previewPanel, BorderLayout.SOUTH);
223+
217224

218225

219226

@@ -987,4 +994,123 @@ public boolean imageUpdate(Image img, int infoflags, int x, int y,
987994
return false;
988995
}
989996

997+
@Override
998+
public void insertUpdate(DocumentEvent e) {
999+
previewPanel.updatePreview(textArea.getText());
1000+
}
1001+
1002+
@Override
1003+
public void removeUpdate(DocumentEvent e) {
1004+
previewPanel.updatePreview(textArea.getText());
1005+
}
1006+
1007+
@Override
1008+
public void changedUpdate(DocumentEvent e) {
1009+
previewPanel.updatePreview(textArea.getText());
1010+
}
1011+
1012+
//===============================================================================================
1013+
public class DialoguePreviewPanel extends JPanel
1014+
{//===============================================================================================
1015+
private String text = "";
1016+
1017+
public DialoguePreviewPanel() {
1018+
setPreferredSize(new java.awt.Dimension(600, 150));
1019+
setBackground(Color.BLACK);
1020+
setBorder(javax.swing.BorderFactory.createLineBorder(Color.WHITE));
1021+
}
1022+
1023+
public void updatePreview(String text) {
1024+
this.text = text;
1025+
repaint();
1026+
}
1027+
1028+
@Override
1029+
protected void paintComponent(java.awt.Graphics g) {
1030+
super.paintComponent(g);
1031+
1032+
g.setColor(Color.WHITE);
1033+
g.setFont(new Font("Monospaced", Font.PLAIN, 12)); // Simulating game font
1034+
1035+
String[] pages = text.split("<\\.>"); // Split by pages
1036+
String lastPage = pages.length > 0 ? pages[pages.length - 1] : "";
1037+
1038+
// Replace newlines with a split token
1039+
String cleanText = lastPage.replace("<NEWLINE>", "\n");
1040+
String[] lines = cleanText.split("\n");
1041+
1042+
int startY = 20;
1043+
int startX = 10;
1044+
int lineHeight = 15;
1045+
1046+
int currentY = startY;
1047+
1048+
for(String line : lines) {
1049+
int currentX = startX;
1050+
1051+
// Parse color tags per line (simple approach)
1052+
// Supports <RED>, <BLUE>, <GREEN>, <WHITE>, <BLACK>, <GRAY>, <ORANGE>, <YELLOW>, <PURPLE>, <PINK>
1053+
1054+
// Tokenize by '<' and '>'
1055+
// But we need to keep text between tags.
1056+
// Regex split keeping delimiters is hard in java split
1057+
1058+
// Manual scan
1059+
Color currentColor = g.getColor(); // Keep previous color across lines? usually resets per box in game logic, but tags persist.
1060+
// Let's assume it persists.
1061+
1062+
int lastIndex = 0;
1063+
while(lastIndex < line.length()) {
1064+
int tagStart = line.indexOf("<", lastIndex);
1065+
if(tagStart != -1) {
1066+
// Draw text before tag
1067+
if(tagStart > lastIndex) {
1068+
String segment = line.substring(lastIndex, tagStart);
1069+
g.setColor(currentColor);
1070+
g.drawString(segment, currentX, currentY);
1071+
currentX += g.getFontMetrics().stringWidth(segment);
1072+
}
1073+
1074+
int tagEnd = line.indexOf(">", tagStart);
1075+
if(tagEnd != -1) {
1076+
String tag = line.substring(tagStart, tagEnd + 1);
1077+
// Check if color tag
1078+
if(tag.equals("<RED>")) currentColor = Color.RED;
1079+
else if(tag.equals("<BLUE>")) currentColor = Color.BLUE;
1080+
else if(tag.equals("<GREEN>")) currentColor = Color.GREEN;
1081+
else if(tag.equals("<WHITE>")) currentColor = Color.WHITE;
1082+
else if(tag.equals("<BLACK>")) currentColor = Color.DARK_GRAY; // Black on black bg is bad, use dark gray or fix bg
1083+
else if(tag.equals("<GRAY>")) currentColor = Color.GRAY;
1084+
else if(tag.equals("<ORANGE>")) currentColor = Color.ORANGE;
1085+
else if(tag.equals("<YELLOW>")) currentColor = Color.YELLOW;
1086+
else if(tag.equals("<PURPLE>")) currentColor = new Color(150,0,255);
1087+
else if(tag.equals("<PINK>")) currentColor = Color.PINK;
1088+
// Else ignore (control tag)
1089+
1090+
lastIndex = tagEnd + 1;
1091+
} else {
1092+
// Malformed tag, just print rest
1093+
String segment = line.substring(lastIndex);
1094+
g.setColor(currentColor);
1095+
g.drawString(segment, currentX, currentY);
1096+
break;
1097+
}
1098+
} else {
1099+
// No more tags
1100+
String segment = line.substring(lastIndex);
1101+
g.setColor(currentColor);
1102+
g.drawString(segment, currentX, currentY);
1103+
break;
1104+
}
1105+
}
1106+
1107+
currentY += lineHeight;
1108+
}
1109+
1110+
g.setColor(Color.GRAY);
1111+
g.drawRect(0, 0, getWidth()-1, getHeight()-1);
1112+
g.drawString("Preview (Last Page)", getWidth() - 150, getHeight() - 5);
1113+
}
1114+
}
1115+
9901116
}

0 commit comments

Comments
 (0)