// Near Infinity - An Infinity Engine Browser and Editor // Copyright (C) 2001 - 2005 Jon Olav Hauglid // See LICENSE.txt for license information package org.infinity.gui.converter; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dialog; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.awt.image.IndexColorModel; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.WindowConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.infinity.gui.ButtonPopupMenu; import org.infinity.gui.ColorGrid; import org.infinity.gui.ViewerUtil; import org.infinity.icon.Icons; import org.infinity.resource.graphics.ColorConvert; import org.infinity.resource.graphics.PseudoBamDecoder.PseudoBamFrameEntry; import org.infinity.util.io.StreamUtils; /** * A dialog for managing BAM v1 palette entries. */ class BamPaletteDialog extends JDialog implements FocusListener, ActionListener, ChangeListener, ColorGrid.MouseOverListener { /** Specifies generated palette type */ public static final int TYPE_GENERATED = 0; /** Specifies external palette type */ public static final int TYPE_EXTERNAL = 1; private static final String[] PaletteTypeInfo = {"Generated palette", "External palette"}; private static final String FmtInfoRGB = "%1$d %2$d %3$d"; private static final String FmtInfoHexRGB = "#%1$02X%2$02X%3$02X"; // Stores all available color values of the current BAM and their number of occurence for faster palette creation private final LinkedHashMap<Integer, Integer> colorMap = new LinkedHashMap<Integer, Integer>(); private final int[][] palettes = new int[2][]; private ConvertToBam converter; private ColorGrid cgPalette; private JLabel lInfoType, lInfoIndex, lInfoRGB, lInfoHexRGB, lColorIndex; private JTextField tfColorRed, tfColorGreen, tfColorBlue, tfCompressedColor; private JMenuItem miPaletteSet, miPaletteClear; private ButtonPopupMenu bpmPalette; private JCheckBox cbLockPalette; private JButton bClose; private int currentPaletteType, currentRed, currentGreen, currentBlue, rleIndex; private boolean lockedPalette, hasExternalPalette, paletteModified; public BamPaletteDialog(ConvertToBam parent) { super(parent, "Palette", Dialog.ModalityType.DOCUMENT_MODAL); this.converter = parent; init(); } /** Shows the dialog. */ public void open() { if (!isVisible()) { updateGeneratedPalette(); setLocationRelativeTo(getOwner()); setVisible(true); toFront(); requestFocusInWindow(); } } /** Hides the dialog */ public void close() { if (isVisible()) { setVisible(false); } } /** Resets the current palette dialog state. */ public void clear() { Arrays.fill(palettes[TYPE_GENERATED], 0); Arrays.fill(palettes[TYPE_EXTERNAL], 0); cgPalette.setSelectedIndex(-1); currentRed = currentGreen = currentBlue = 0; rleIndex = 0; currentPaletteType = TYPE_GENERATED; hasExternalPalette = false; lockedPalette = false; colorMap.clear(); cbLockPalette.setEnabled(true); cbLockPalette.setSelected(lockedPalette); miPaletteClear.setEnabled(false); applyPalette(currentPaletteType); updateInfoBox(-1); updateColorBox(-1, null); } /** Returns the associated ConverToBam instance. */ public ConvertToBam getConverter() { return converter; } /** Returns the index of the RLE-compressed color. */ public int getRleIndex() { return rleIndex; } /** Returns the global color map for the current BAM structure. */ public HashMap<Integer, Integer> getColorMap() { return colorMap; } /** Indicates whether to prevent updating the current palette automatically. */ public boolean isPaletteLocked() { return isExternalPalette() || lockedPalette; } /** A convenience method for determining the current type of the palette. */ public boolean isExternalPalette() { return (currentPaletteType == TYPE_EXTERNAL); } /** Returns the currently active palette. (Either one of TYPE_GENERATED or TYPE_EXTERNAL.) */ public int getPaletteType() { return currentPaletteType; } /** Specify the new active palette. (Either one of TYPE_GENERATED or TYPE_EXTERNAL.) */ public void setPaletteType(int type) { switch (type) { case TYPE_EXTERNAL: if (!hasExternalPalette()) { break; } case TYPE_GENERATED: if (type != currentPaletteType) { currentPaletteType = type; applyPalette(currentPaletteType); lInfoType.setText(PaletteTypeInfo[currentPaletteType]); } break; } } /** Returns the specified palette if available. Returns {@code null} if palette is not available. */ public int[] getPalette(int type) { switch (type) { case TYPE_EXTERNAL: if (!hasExternalPalette()) { break; } case TYPE_GENERATED: { return palettes[type]; } } return null; } /** * Defines the colors of a specific palette. * @param type either one of TYPE_GENERATED or TYPE_EXTERNAL. * @param palette The palette data to assign. */ public void setPalette(int type, int[] palette) { switch (type) { case TYPE_EXTERNAL: hasExternalPalette = (palette != null); case TYPE_GENERATED: { if (!isPaletteLocked() || type == TYPE_EXTERNAL) { if (palette != null) { // loading palette data for (int i = 0; i < palette.length; i++) { palettes[type][i] = palette[i] & 0x00ffffff; } for (int i = palette.length; i < palettes[type].length; i++) { palettes[type][i] = 0; } // updating current palette if needed if (type == currentPaletteType) { applyPalette(type); } } } break; } } } /** Returns whether an external palette has been defined. */ public boolean hasExternalPalette() { return hasExternalPalette; } /** Loads the palette from the specified file resource into the specified palette slot. */ public void loadExternalPalette(int type, Path paletteFile) throws Exception { if (type != TYPE_EXTERNAL && type != TYPE_GENERATED) { throw new Exception("Internal error: Invalid palette slot specified!"); } // fetching file signature if (paletteFile != null && Files.isRegularFile(paletteFile)) { byte[] signature = new byte[8]; try (InputStream is = StreamUtils.getInputStream(paletteFile)) { is.read(signature); } catch (IOException e) { throw new Exception("Error reading from file " + paletteFile.getFileName()); } // fetching palette data int[] palette = null; if ("BM".equals(new String(signature, 0, 2))) { palette = ColorConvert.loadPaletteBMP(paletteFile); } else if ("RIFF".equals(new String(signature, 0, 4))) { palette = ColorConvert.loadPalettePAL(paletteFile); } else { String s = new String(signature); if ("BAM V1 ".equals(s) || "BAMCV1 ".equals(s)) { palette = ColorConvert.loadPaletteBAM(paletteFile); } else { // Photoshop ACT files don't have a header palette = ColorConvert.loadPaletteACT(paletteFile); } } // applying palette if (palette != null && palette.length > 0) { for (int i = 0; i < palette.length; i++) { palettes[type][i] = palette[i]; } for (int i = palette.length; i < palettes[type].length; i++) { palettes[type][i] = 0; } } else { throw new Exception("No palette found in file " + paletteFile.getFileName()); } } else { throw new Exception("File does not exist."); } hasExternalPalette = true; } /** Removes the currently assigned external palette. */ public void clearExternalPalette() { setPaletteType(TYPE_GENERATED); if (hasExternalPalette()) { Arrays.fill(palettes[TYPE_EXTERNAL], 0); hasExternalPalette = false; } } /** Returns whether the palette has been modified after the last call to {@link #paletteUpdate()}. */ public boolean isPaletteModified() { return paletteModified; } /** Marks generated palette as modified. */ public void setPaletteModified() { paletteModified = true; } /** * Calculates a new palette based on the currently registered colors and stores it in the * PaletteDialog instance. */ public void updateGeneratedPalette() { if (isPaletteModified() && !lockedPalette) { if (colorMap.size() <= 256) { // checking whether all frames share the same palette boolean sharedPalette = true; List<PseudoBamFrameEntry> listFrames = getConverter().getBamDecoder(ConvertToBam.BAM_ORIGINAL).getFramesList(); int[] palette = null; int[] tmpPalette = new int[256]; for (int i = 0; i < listFrames.size(); i++) { BufferedImage image = listFrames.get(i).getFrame(); if (image.getType() == BufferedImage.TYPE_BYTE_INDEXED) { IndexColorModel cm = (IndexColorModel)image.getColorModel(); if (palette == null) { palette = new int[256]; cm.getRGBs(palette); } else { cm.getRGBs(tmpPalette); if (!Arrays.equals(palette, tmpPalette)) { sharedPalette = false; break; } } } else { sharedPalette = false; break; } } tmpPalette = null; if (sharedPalette) { // using shared palette as is for (int i = 0; i < palette.length; i++) { palettes[TYPE_GENERATED][i] = palette[i]; } } else { // creating palette directly from color map without reduction Iterator<Integer> iter = colorMap.keySet().iterator(); int idx = 0; while (idx < 256 && iter.hasNext()) { palettes[TYPE_GENERATED][idx] = iter.next(); idx++; } for (; idx < 256; idx++) { palettes[TYPE_GENERATED][idx] = 0; } } } else { // reducing color count to max. 256 int[] pixels = new int[colorMap.size()]; Iterator<Integer> iter = colorMap.keySet().iterator(); int idx = 0; while (idx < pixels.length && iter.hasNext()) { pixels[idx] = iter.next(); idx++; } ColorConvert.medianCut(pixels, 256, palettes[TYPE_GENERATED], true); } // moving special "green" to the first index for (int i = 0; i < palettes[TYPE_GENERATED].length; i++) { if ((palettes[TYPE_GENERATED][i] & 0x00ffffff) == 0x0000ff00) { int v = palettes[TYPE_GENERATED][0]; palettes[TYPE_GENERATED][0] = palettes[TYPE_GENERATED][i]; palettes[TYPE_GENERATED][i] = v; break; } } paletteModified = false; } // updating palette dialog if (currentPaletteType == TYPE_GENERATED) { applyPalette(currentPaletteType); } } //--------------------- Begin Interface ActionListener --------------------- @Override public void actionPerformed(ActionEvent event) { if (event.getSource() == bClose) { close(); } else if (event.getSource() == cgPalette) { updateColorBox(cgPalette.getSelectedIndex(), cgPalette.getSelectedColor()); } else if (event.getSource() == miPaletteClear) { clearExternalPalette(); cbLockPalette.setEnabled(true); cbLockPalette.setSelected(lockedPalette); miPaletteClear.setEnabled(false); lInfoType.setText(PaletteTypeInfo[currentPaletteType]); } else if (event.getSource() == miPaletteSet) { Path[] files = ConvertToBam.getOpenFileName(this, "Load palette from", null, false, ConvertToBam.getPaletteFilters(), 0); if (files != null && files.length > 0) { try { loadExternalPalette(TYPE_EXTERNAL, files[0]); setPaletteType(TYPE_EXTERNAL); applyPalette(TYPE_EXTERNAL); miPaletteClear.setEnabled(true); cbLockPalette.setSelected(true); cbLockPalette.setEnabled(false); } catch (Exception e) { JOptionPane.showMessageDialog(this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE); } } } else if (event.getSource() == cbLockPalette) { lockedPalette = cbLockPalette.isSelected(); } } //--------------------- End Interface ActionListener --------------------- //--------------------- Begin Interface ChangeListener --------------------- @Override public void stateChanged(ChangeEvent event) { if (event.getSource() == cgPalette) { updatePalette(); } } //--------------------- End Interface ChangeListener --------------------- //--------------------- Begin Interface FocusListener --------------------- @Override public void focusGained(FocusEvent event) { if (event.getSource() instanceof JTextField) { ((JTextField)event.getSource()).selectAll(); } } @Override public void focusLost(FocusEvent event) { if (event.getSource() == tfColorRed) { currentRed = ConvertToBam.numberValidator(tfColorRed.getText(), 0, 255, currentRed); tfColorRed.setText(Integer.toString(currentRed)); updateCurrentColor(); } else if (event.getSource() == tfColorGreen) { currentGreen = ConvertToBam.numberValidator(tfColorGreen.getText(), 0, 255, currentGreen); tfColorGreen.setText(Integer.toString(currentGreen)); updateCurrentColor(); } else if (event.getSource() == tfColorBlue) { currentBlue = ConvertToBam.numberValidator(tfColorBlue.getText(), 0, 255, currentBlue); tfColorBlue.setText(Integer.toString(currentBlue)); updateCurrentColor(); } else if (event.getSource() == tfCompressedColor) { rleIndex = ConvertToBam.numberValidator(tfCompressedColor.getText(), 0, 255, rleIndex); tfCompressedColor.setText(Integer.toString(rleIndex)); } } //--------------------- End Interface FocusListener --------------------- //--------------------- Begin Interface MouseOverListener --------------------- @Override public void mouseOver(ColorGrid.MouseOverEvent event) { if (event.getSource() == cgPalette) { updateInfoBox(event.getColorIndex()); } } //--------------------- End Interface MouseOverListener --------------------- private void init() { // first-time initializations palettes[TYPE_GENERATED] = new int[256]; palettes[TYPE_EXTERNAL] = new int[256]; currentPaletteType = TYPE_GENERATED; currentRed = currentGreen = currentBlue = 0; rleIndex = 0; lockedPalette = false; hasExternalPalette = false; paletteModified = true; GridBagConstraints c = new GridBagConstraints(); // creating palette section JPanel pPalette = new JPanel(new GridBagLayout()); pPalette.setBorder(BorderFactory.createTitledBorder("Palette ")); cgPalette = new ColorGrid(256); cgPalette.setSelectionFrame(ColorGrid.Frame.DOUBLE_LINE); cgPalette.setDragDropEnabled(true); cgPalette.addActionListener(this); cgPalette.addMouseOverListener(this); cgPalette.addChangeListener(this); c = ViewerUtil.setGBC(c, 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NONE, new Insets(0, 4, 2, 4), 0, 0); pPalette.add(cgPalette, c); // creating information panel JPanel pInfo = new JPanel(new GridBagLayout()); pInfo.setBorder(BorderFactory.createTitledBorder("Information ")); lInfoType = new JLabel(PaletteTypeInfo[currentPaletteType]); JLabel lInfoIndexTitle = new JLabel("Index:"); JLabel lInfoRGBTitle = new JLabel("RGB:"); JLabel lInfoHexRGBTitle = new JLabel("Hex:"); lInfoIndex = new JLabel("255"); lInfoIndex.setMinimumSize(lInfoIndex.getPreferredSize()); lInfoRGB = new JLabel(String.format(FmtInfoRGB, 255, 255, 255)); lInfoHexRGB = new JLabel(String.format(FmtInfoHexRGB, 255, 255, 255)); lInfoHexRGB.setMinimumSize(lInfoHexRGB.getPreferredSize()); c = ViewerUtil.setGBC(c, 0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 4, 0, 4), 0, 0); pInfo.add(lInfoType, c); c = ViewerUtil.setGBC(c, 0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 4, 0, 0), 0, 0); pInfo.add(lInfoIndexTitle, c); c = ViewerUtil.setGBC(c, 1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 8, 0, 4), 0, 0); pInfo.add(lInfoIndex, c); c = ViewerUtil.setGBC(c, 0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 4, 0, 0), 0, 0); pInfo.add(lInfoRGBTitle, c); c = ViewerUtil.setGBC(c, 1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 8, 0, 4), 0, 0); pInfo.add(lInfoRGB, c); c = ViewerUtil.setGBC(c, 0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 4, 4, 0), 0, 0); pInfo.add(lInfoHexRGBTitle, c); c = ViewerUtil.setGBC(c, 1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 8, 4, 4), 0, 0); pInfo.add(lInfoHexRGB, c); // creating color edit panel JPanel pColor = new JPanel(new GridBagLayout()); pColor.setBorder(BorderFactory.createTitledBorder("Color ")); JLabel lColorIndexTitle = new JLabel("Index:"); JLabel lColorRedTitle = new JLabel("Red:"); JLabel lColorGreenTitle = new JLabel("Green:"); JLabel lColorBlueTitle = new JLabel("Blue:"); lColorIndex = new JLabel("255"); tfColorRed = new JTextField(4); tfColorRed.addFocusListener(this); tfColorGreen = new JTextField(4); tfColorGreen.addFocusListener(this); tfColorBlue = new JTextField(4); tfColorBlue.addFocusListener(this); c = ViewerUtil.setGBC(c, 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0); pColor.add(lColorIndexTitle, c); c = ViewerUtil.setGBC(c, 1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 10, 0, 4), 0, 0); pColor.add(lColorIndex, c); c = ViewerUtil.setGBC(c, 0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 4, 0, 0), 0, 0); pColor.add(lColorRedTitle, c); c = ViewerUtil.setGBC(c, 1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 8, 0, 4), 0, 0); pColor.add(tfColorRed, c); c = ViewerUtil.setGBC(c, 0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 4, 0, 0), 0, 0); pColor.add(lColorGreenTitle, c); c = ViewerUtil.setGBC(c, 1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 8, 0, 4), 0, 0); pColor.add(tfColorGreen, c); c = ViewerUtil.setGBC(c, 0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 4, 4, 0), 0, 0); pColor.add(lColorBlueTitle, c); c = ViewerUtil.setGBC(c, 1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 8, 4, 4), 0, 0); pColor.add(tfColorBlue, c); pColor.setMinimumSize(pColor.getPreferredSize()); // creating Options panel JPanel pOptions = new JPanel(new GridBagLayout()); pOptions.setBorder(BorderFactory.createTitledBorder("Options ")); miPaletteSet = new JMenuItem("Load palette..."); miPaletteSet.addActionListener(this); miPaletteClear = new JMenuItem("Clear palette"); miPaletteClear.addActionListener(this); miPaletteClear.setEnabled(currentPaletteType == TYPE_EXTERNAL); bpmPalette = new ButtonPopupMenu("External palette", new JMenuItem[]{miPaletteClear, miPaletteSet}); bpmPalette.setIcon(Icons.getIcon(Icons.ICON_ARROW_UP_15)); bpmPalette.setIconTextGap(8); cbLockPalette = new JCheckBox("Lock palette"); cbLockPalette.setToolTipText("Selecting this option prevents automatic palette generation when modifying the global frames list"); cbLockPalette.addActionListener(this); JLabel lCompressedColor = new JLabel("Compressed color:"); tfCompressedColor = new JTextField(4); tfCompressedColor.setText("0"); tfCompressedColor.setToolTipText("The compressed color index for RLE encoded frames"); tfCompressedColor.addFocusListener(this); c = ViewerUtil.setGBC(c, 0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 4, 0, 4), 0, 0); pOptions.add(bpmPalette, c); c = ViewerUtil.setGBC(c, 0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(8, 0, 0, 4), 0, 0); pOptions.add(cbLockPalette, c); c = ViewerUtil.setGBC(c, 0, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(4, 4, 4, 0), 0, 0); pOptions.add(lCompressedColor, c); c = ViewerUtil.setGBC(c, 1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(4, 4, 4, 4), 0, 0); pOptions.add(tfCompressedColor, c); // putting right sidebar together JPanel pSideBar = new JPanel(new GridBagLayout()); c = ViewerUtil.setGBC(c, 0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0); pSideBar.add(pInfo, c); c = ViewerUtil.setGBC(c, 0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.HORIZONTAL, new Insets(4, 0, 0, 0), 0, 0); pSideBar.add(pColor, c); c = ViewerUtil.setGBC(c, 0, 2, 1, 1, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.HORIZONTAL, new Insets(4, 0, 0, 0), 0, 0); pSideBar.add(pOptions, c); JPanel pBottom = new JPanel(new GridBagLayout()); bClose = new JButton("Close"); bClose.addActionListener(this); bClose.setMargin(new Insets(4, bClose.getInsets().left, 4, bClose.getInsets().right)); c = ViewerUtil.setGBC(c, 0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0); pBottom.add(bClose, c); // putting all together JPanel pMain = new JPanel(new GridBagLayout()); c = ViewerUtil.setGBC(c, 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NONE, new Insets(4, 4, 4, 0), 0, 0); pMain.add(pPalette, c); c = ViewerUtil.setGBC(c, 1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.HORIZONTAL, new Insets(4, 8, 4, 4), 0, 0); pMain.add(pSideBar, c); c = ViewerUtil.setGBC(c, 0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.HORIZONTAL, new Insets(4, 0, 8, 0), 0, 0); pMain.add(pBottom, c); setLayout(new BorderLayout()); add(pMain, BorderLayout.CENTER); pack(); setResizable(false); // "Closing" the dialog only makes it invisible setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); getRootPane().setDefaultButton(bClose); getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), getRootPane()); getRootPane().getActionMap().put(getRootPane(), new AbstractAction() { @Override public void actionPerformed(ActionEvent event) { close(); } }); updateInfoBox(cgPalette.getSelectedIndex()); updateColorBox(cgPalette.getSelectedIndex(), cgPalette.getSelectedColor()); } // Applies the specified palette to the color grid control and updates the edit box private void applyPalette(int paletteType) { switch (paletteType) { case TYPE_GENERATED: case TYPE_EXTERNAL: { for (int i = 0; i < palettes[paletteType].length; i++) { cgPalette.setColor(i, new Color(palettes[paletteType][i])); } updateColorBox(cgPalette.getSelectedIndex(), cgPalette.getSelectedColor()); break; } } } // Updates the information panel private void updateInfoBox(int index) { if (index >= 0 && index < cgPalette.getColorCount()) { Color c = cgPalette.getColor(index); lInfoType.setText(PaletteTypeInfo[currentPaletteType]); lInfoIndex.setText(Integer.toString(index)); lInfoRGB.setText(String.format(FmtInfoRGB, c.getRed(), c.getGreen(), c.getBlue())); lInfoHexRGB.setText(String.format(FmtInfoHexRGB, c.getRed(), c.getGreen(), c.getBlue())); } else { lInfoType.setText(PaletteTypeInfo[currentPaletteType]); lInfoIndex.setText(""); lInfoRGB.setText(""); lInfoHexRGB.setText(""); } } // Applies the color values specified in the color edit controls to the currently selected color private void updateCurrentColor() { if (cgPalette.getSelectedIndex() >= 0) { Color c = new Color(currentRed, currentGreen, currentBlue); cgPalette.setColor(cgPalette.getSelectedIndex(), c); palettes[currentPaletteType][cgPalette.getSelectedIndex()] = c.getRGB(); } } // Applies all colors of the color grid to the currently active palette private void updatePalette() { for (int i = 0; i < palettes[currentPaletteType].length; i++) { palettes[currentPaletteType][i] = cgPalette.getColor(i).getRGB(); } } // Updates the color edit panel with the selected color data private void updateColorBox(int index, Color color) { boolean isValid = (index >= 0 && index < cgPalette.getColorCount()); if (isValid) { lColorIndex.setText(Integer.toString(index)); } else { lColorIndex.setText(""); } if (color != null) { currentRed = color.getRed(); currentGreen = color.getGreen(); currentBlue = color.getBlue(); } else { currentRed = currentGreen = currentBlue = 0; } tfColorRed.setText(Integer.toString(currentRed)); tfColorGreen.setText(Integer.toString(currentGreen)); tfColorBlue.setText(Integer.toString(currentBlue)); tfColorRed.setEnabled(isValid); tfColorGreen.setEnabled(isValid); tfColorBlue.setEnabled(isValid); } }