318 lines
11 KiB
Java
318 lines
11 KiB
Java
package app;
|
|
|
|
// Java imports
|
|
import java.awt.*;
|
|
import java.awt.event.*;
|
|
import java.util.*;
|
|
import javax.swing.*;
|
|
|
|
// Project imports
|
|
import util.*;
|
|
|
|
// VIP characters window
|
|
class CharactersWindow extends ChildWindow {
|
|
|
|
// Instance fields
|
|
private int color; // Selected color index
|
|
|
|
// UI components
|
|
private JPanel client; // Client area
|
|
private JPanel panCharacters; // Characters panel
|
|
private JPanel panPalette; // Palette panel
|
|
private JPanel panPattern; // Pattern panel
|
|
private JScrollPane scrControls; // Controls panel
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Constructors //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Default constructor
|
|
CharactersWindow(MainWindow parent) {
|
|
super(parent, "characters.title");
|
|
|
|
// Configure instance fields
|
|
color = 0;
|
|
|
|
// Configure client area
|
|
client = new JPanel(new BorderLayout());
|
|
client.setBackground(SystemColor.control);
|
|
client.setFocusable(true);
|
|
client.setPreferredSize(new Dimension(480, 360));
|
|
client.addComponentListener(Util.onResize(e->onResize()));
|
|
|
|
// Configure controls panel
|
|
var ctrls = new JPanel(new GridBagLayout());
|
|
ctrls.setBackground(SystemColor.control);
|
|
ctrls.addMouseListener(
|
|
Util.onMouse(e->client.requestFocus(), null));
|
|
scrControls = new JScrollPane(ctrls,
|
|
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
|
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
|
scrControls.setBorder(null);
|
|
scrControls.getVerticalScrollBar().setUnitIncrement(20);
|
|
client.add(scrControls, BorderLayout.WEST);
|
|
|
|
label(ctrls, "characters.index", true);
|
|
spinner(ctrls, 0, 2047, 0, true);
|
|
label(ctrls, "characters.address", false);
|
|
textBox(ctrls);
|
|
label(ctrls, "characters.mirror", false);
|
|
textBox(ctrls);
|
|
|
|
// Pattern panel
|
|
var panPattern = new JPanel();
|
|
panPattern.setBackground(Color.black);
|
|
panPattern.setPreferredSize(new Dimension(96, 96));
|
|
var gbc = new GridBagConstraints();
|
|
gbc.anchor = GridBagConstraints.CENTER;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(4, 2, 2, 2);
|
|
ctrls.add(panPattern, gbc);
|
|
|
|
// Palette panel
|
|
panPalette = new JPanel() {
|
|
public void paintComponent(Graphics g) {
|
|
super.paintComponent(g);
|
|
onPaintPalette((Graphics2D) g, getWidth(), getHeight());
|
|
}
|
|
};
|
|
panPalette.setOpaque(false);
|
|
panPalette.setPreferredSize(new Dimension(0, 20 + 6));
|
|
panPalette.addMouseListener(
|
|
Util.onMouse(e->onMouseDownPalette(e), null));
|
|
gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 2, 4, 2);
|
|
ctrls.add(panPalette, gbc);
|
|
|
|
// Fill the extra space above the view controls
|
|
var spacer = new JPanel();
|
|
spacer.setOpaque(false);
|
|
gbc = new GridBagConstraints();
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.weighty = 1;
|
|
ctrls.add(spacer, gbc);
|
|
|
|
label(ctrls, "characters.grid", false);
|
|
checkBox(ctrls).setSelected(true);
|
|
label(ctrls, "characters.wide", false);
|
|
spinner(ctrls, 0, 2048, 0, false);
|
|
label(ctrls, "characters.palette", false);
|
|
select(ctrls, new String[] { "palette.generic",
|
|
"palette.gplt0", "palette.gplt1", "palette.gplt2", "palette.gplt3",
|
|
"palette.jplt0", "palette.jplt1", "palette.jplt2", "palette.jplt3"
|
|
});
|
|
label(ctrls, "characters.scale", false);
|
|
slider(ctrls, 1, 10, 1);
|
|
|
|
// Terminate the list of controls
|
|
spacer = new JPanel();
|
|
spacer.setOpaque(false);
|
|
spacer.setPreferredSize(new Dimension(0, 0));
|
|
gbc = new GridBagConstraints();
|
|
gbc.gridheight = GridBagConstraints.REMAINDER;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
ctrls.add(spacer, gbc);
|
|
|
|
// Configure characters panel
|
|
panCharacters = new JPanel() {
|
|
public void paintComponent(Graphics g) {
|
|
super.paintComponent(g);
|
|
onPaintCharacters((Graphics2D) g, getWidth(), getHeight());
|
|
}
|
|
};
|
|
panCharacters.setBackground(SystemColor.control);
|
|
panCharacters.addMouseListener(
|
|
Util.onMouse(e->client.requestFocus(), null));
|
|
var scr = new JScrollPane(panCharacters);
|
|
client.add(scr, BorderLayout.CENTER);
|
|
|
|
// Configure component
|
|
setContentPane(client);
|
|
pack();
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Package Methods //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Update the display
|
|
void refresh() {
|
|
repaint();
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Event Handlers //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Palette mouse button press
|
|
private void onMouseDownPalette(MouseEvent e) {
|
|
|
|
// Common processing
|
|
client.requestFocus();
|
|
|
|
// Only consider left clicks
|
|
if (e.getButton() != MouseEvent.BUTTON1)
|
|
return;
|
|
|
|
// Working variables
|
|
int height = panPalette.getHeight();
|
|
int width = panPalette.getWidth();
|
|
int size = Math.max(1, Math.min((width - 18) / 4, height - 6));
|
|
int left = (width - size * 4 - 18) / 2;
|
|
int top = (height - size - 6) / 2;
|
|
int x = e.getX() - left - 3;
|
|
int y = e.getY() - top - 3;
|
|
|
|
// The click was not on top of a color
|
|
if (
|
|
x < 0 || x >= (size + 4) * 4 ||
|
|
x % (size + 4) >= size ||
|
|
y < 0 || y >= size
|
|
) return;
|
|
|
|
// Select the clicked color
|
|
color = x / (size + 4);
|
|
panPalette.repaint();
|
|
}
|
|
|
|
// Characters paint
|
|
private void onPaintCharacters(Graphics2D g, int width, int height) {
|
|
g.setColor(new Color(0x001830));
|
|
g.fillRect(0, 0, 256, 512);
|
|
}
|
|
|
|
// Palette paint
|
|
private void onPaintPalette(Graphics2D g, int width, int height) {
|
|
int size = Math.max(1, Math.min((width - 18) / 4, height - 6));
|
|
int left = (width - size * 4 - 18) / 2;
|
|
int top = (height - size - 6) / 2;
|
|
|
|
// Draw the color picker
|
|
for (int x = 0; x < 4; x++, left += size + 4) {
|
|
|
|
// The current color is selected
|
|
if (x == color) {
|
|
g.setColor(SystemColor.textHighlight);
|
|
g.fillRect(left , top , size + 6, size + 6);
|
|
g.setColor(SystemColor.control);
|
|
g.fillRect(left + 2, top + 2, size + 2, size + 2);
|
|
}
|
|
|
|
// Draw the color area
|
|
g.setColor(Color.black);
|
|
g.fillRect(left + 3, top + 3, size , size );
|
|
}
|
|
|
|
}
|
|
|
|
// Window resize
|
|
private void onResize() {
|
|
var viewport = scrControls.getViewport();
|
|
int inner = viewport.getView().getPreferredSize().width;
|
|
int outer = viewport.getExtentSize().width;
|
|
|
|
// The controls container does not need to be resized
|
|
if (inner == outer)
|
|
return;
|
|
|
|
// Size the controls container to match the inner component
|
|
scrControls.setPreferredSize(new Dimension(
|
|
scrControls.getPreferredSize().width + inner - outer, 0));
|
|
scrControls.revalidate();
|
|
scrControls.repaint();
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Private Methods //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Add a check box to the controls panel
|
|
private JCheckBox checkBox(JPanel panel) {
|
|
var chk = new JCheckBox();
|
|
chk.setBorder(null);
|
|
chk.setFocusable(false);
|
|
var gbc = new GridBagConstraints();
|
|
gbc.anchor = GridBagConstraints.WEST;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 0, 2, 2);
|
|
panel.add(chk, gbc);
|
|
return chk;
|
|
}
|
|
|
|
// Add a label to the controls panel
|
|
private void label(JPanel panel, String key, boolean top) {
|
|
var lbl = new JLabel();
|
|
parent.app.localizer.add(lbl, key);
|
|
var gbc = new GridBagConstraints();
|
|
gbc.anchor = GridBagConstraints.WEST;
|
|
gbc.insets = new Insets(top ? 2 : 0, 2, 2, 2);
|
|
panel.add(lbl, gbc);
|
|
}
|
|
|
|
// Add a combo box to the controls panel
|
|
private JComboBox<String> select(JPanel panel, String[] options) {
|
|
var cmb = new JComboBox<String>();
|
|
parent.app.localizer.add(cmb, options);
|
|
cmb.setSelectedIndex(0);
|
|
var gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.BOTH;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 0, 1, 2);
|
|
panel.add(cmb, gbc);
|
|
return cmb;
|
|
}
|
|
|
|
// Add a slider to the controls panel
|
|
private JSlider slider(JPanel panel, int min, int max, int value) {
|
|
var sld = new JSlider(min, max, value);
|
|
sld.setFocusable(false);
|
|
sld.setPreferredSize(new Dimension(0, sld.getPreferredSize().height));
|
|
var gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.BOTH;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 0, 1, 2);
|
|
panel.add(sld, gbc);
|
|
return sld;
|
|
}
|
|
|
|
// Add a spinner to the controls panel
|
|
private JSpinner spinner(JPanel panel, int min, int max, int value,
|
|
boolean top) {
|
|
var spn = new JSpinner(new SpinnerNumberModel(value, min, max, 1));
|
|
spn.setEditor(new JSpinner.NumberEditor(spn, "#"));
|
|
var gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.BOTH;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(top ? 2 : 0, 0, 2, 2);
|
|
gbc.weightx = 1;
|
|
panel.add(spn, gbc);
|
|
return spn;
|
|
}
|
|
|
|
// Add a text box to the controls panel
|
|
private JTextField textBox(JPanel panel) {
|
|
var txt = new JTextField();
|
|
txt.setFont(parent.app.fntMono);
|
|
var size = txt.getPreferredSize();
|
|
txt.setPreferredSize(new Dimension(
|
|
parent.app.hexDigitWidth * 8 + 2 + size.width, size.height));
|
|
var gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.BOTH;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 0, 2, 2);
|
|
panel.add(txt, gbc);
|
|
return txt;
|
|
}
|
|
|
|
}
|