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 select(JPanel panel, String[] options) { var cmb = new JComboBox(); 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; } }