package com.vitco.layout.frames;
import com.jidesoft.action.CommandMenuBar;
import com.jidesoft.swing.JideToggleButton;
import com.vitco.core.data.Data;
import com.vitco.core.data.container.Voxel;
import com.vitco.layout.content.colorchooser.ColorPaletteChooser;
import com.vitco.layout.content.colorchooser.basic.ColorChangeListener;
import com.vitco.layout.content.console.ConsoleInterface;
import com.vitco.layout.frames.custom.CDockableFrame;
import com.vitco.manager.action.ComplexActionManager;
import com.vitco.manager.action.types.StateActionPrototype;
import com.vitco.manager.error.ErrorHandlerInterface;
import com.vitco.manager.menu.MenuGeneratorInterface;
import com.vitco.manager.pref.PrefChangeListener;
import com.vitco.settings.VitcoSettings;
import com.vitco.util.file.FileTools;
import com.vitco.util.misc.CFileDialog;
import com.vitco.util.misc.SaveResourceLoader;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/**
* construct the color palette frame
*/
public class ColorPaletteLinkage extends FrameLinkagePrototype {
// the dialog that is shown for import and export
private final CFileDialog dialog = new CFileDialog();
// register palette color picker button
private final ColorPaletteChooser colorPaletteChooser = new ColorPaletteChooser();
// var & setter
private ComplexActionManager complexActionManager;
@Autowired
public final void setComplexActionManager(ComplexActionManager complexActionManager) {
this.complexActionManager = complexActionManager;
}
// var & setter
protected Data data;
@Autowired
public final void setData(Data data) {
this.data = data;
}
// var & setter
protected MenuGeneratorInterface menuGenerator;
@Autowired(required=true)
public final void setMenuGenerator(MenuGeneratorInterface menuGenerator) {
this.menuGenerator = menuGenerator;
}
// var & setter
private ErrorHandlerInterface errorHandler;
@Autowired(required=true)
public final void setErrorHandler(ErrorHandlerInterface errorHandler) {
this.errorHandler = errorHandler;
}
// var & setter
protected ConsoleInterface console;
@Autowired
public final void setConsole(ConsoleInterface console) {
this.console = console;
}
@Override
public CDockableFrame buildFrame(String key, final Frame mainFrame) {
// construct frame
frame = new CDockableFrame(key,
new SaveResourceLoader("resource/img/icons/frames/colorpalette.png").asIconImage(),
langSelector
);
updateTitle(); // update the title
// load the colors
if (preferences.contains("color-palette_set-colors")) {
colorPaletteChooser.loadColors(
FileTools.castHash((HashMap) preferences.loadObject("color-palette_set-colors"), Point.class, Color.class)
);
} else {
colorPaletteChooser.loadDefaultColors();
}
// add listener to this color palette (when the internal color changes)
colorPaletteChooser.addColorChangeListener(new ColorChangeListener() {
@Override
public void colorChanged(float[] hsb) {
preferences.storeObject("currently_used_color", hsb);
}
});
// refresh the internal color when the current (global) color changes
preferences.addPrefChangeListener("currently_used_color", new PrefChangeListener() {
@Override
public void onPrefChange(final Object o) {
colorPaletteChooser.setColor((float[])o);
}
});
// set border
colorPaletteChooser.setBorder(BorderFactory.createMatteBorder(1,1,0,1, VitcoSettings.DEFAULT_BORDER_COLOR));
frame.add(colorPaletteChooser, BorderLayout.CENTER);
// --------------
// register that this action is used (needed b/c this is inner action)
complexActionManager.registerActionIsUsed("color-palette_lock_current-icon");
// create locking logic
actionManager.registerAction("color-palette_lock", new StateActionPrototype() {
private boolean locked = true; // always false on startup
@Override
public void action(ActionEvent actionEvent) {
locked = !locked;
colorPaletteChooser.setLocked(locked);
// show the correct icon
complexActionManager.performWhenActionIsReady("color-palette_lock_current-icon", new Runnable() {
@Override
public void run() {
// create and set the icon
ImageIcon icon;
if (locked) {
icon = new SaveResourceLoader("resource/img/framebars/colorpalette/locked.png").asIconImage();
} else {
icon = new SaveResourceLoader("resource/img/framebars/colorpalette/unlocked.png").asIconImage();
}
((JideToggleButton) complexActionManager.getAction("color-palette_lock_current-icon")).setIcon(icon);
}
});
}
@Override
public boolean getStatus() {
return locked;
}
});
// --------------
// create shortcut action
actionManager.registerAction("color-palette_color_left", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
colorPaletteChooser.left();
}
});
actionManager.registerAction("color-palette_color_right", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
colorPaletteChooser.right();
}
});
actionManager.registerAction("color-palette_color_up", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
colorPaletteChooser.up();
}
});
actionManager.registerAction("color-palette_color_down", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
colorPaletteChooser.down();
}
});
// ------------------
// create import logic
actionManager.registerAction("color-palette_import", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.setTitle(langSelector.getString("color-palette_import-file_title"));
File file = dialog.openFile(mainFrame);
if (file != null) {
try {
BufferedImage img = ImageIO.read(file);
HashMap<Point, Color> colors = new HashMap<Point, Color>();
for (int x = 0, lenX = Math.min(img.getWidth(), 50); x < lenX; x++) {
for (int y = 0, lenY = Math.min(img.getHeight(), 50); y < lenY; y++) {
Color col = new Color(img.getRGB(x,y), true);
if (col.getAlpha() == 255) {
colors.put(new Point(x,y), col);
}
}
}
colorPaletteChooser.loadColors(colors);
console.addLine("Color Palette imported successfully.");
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
// create export logic
actionManager.registerAction("color-palette_export", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.setTitle(langSelector.getString("color-palette_export-file_title"));
File file = dialog.saveFile(mainFrame);
if (file != null) {
String dir = file.getPath();
if (!file.exists() ||
JOptionPane.showConfirmDialog(mainFrame,
dir + " " + langSelector.getString("replace_file_query"),
langSelector.getString("replace_file_query_title"),
JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
HashMap<Point, Color> colors = colorPaletteChooser.getColors();
int xMax = 0, yMax = 0;
for (Point p : colors.keySet()) {
xMax = Math.max(xMax, p.x + 1);
yMax = Math.max(yMax, p.y + 1);
}
if (xMax > 0 && yMax > 0) {
BufferedImage img = new BufferedImage(xMax, yMax, BufferedImage.TYPE_INT_ARGB);
for (Map.Entry<Point, Color> entry : colors.entrySet()) {
img.setRGB(entry.getKey().x, entry.getKey().y, entry.getValue().getRGB());
}
try {
if (ImageIO.write(img, "png", file)) {
console.addLine("Color Palette exported successfully.");
}
} catch (IOException e1) {
errorHandler.handle(e1);
}
}
}
}
}
});
// extract colors from selected voxels
actionManager.registerAction("color-palette_extract-colors", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
HashSet<Integer> colors = new HashSet<Integer>();
for (Voxel voxel : data.getSelectedVoxels()) {
colors.add(voxel.getColor().getRGB());
}
for (Color color : colorPaletteChooser.getColors().values()) {
colors.remove(color.getRGB());
}
colorPaletteChooser.addColors(colors);
}
});
// erase colors
actionManager.registerAction("color-palette_erase-colors", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
colorPaletteChooser.loadColors(new HashMap<Point, Color>());
}
});
// rearrange color palette
actionManager.registerAction("color-palette_reorder-colors", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
colorPaletteChooser.reorderColors();
}
});
// create menu
CommandMenuBar menuPanel = new CommandMenuBar();
menuGenerator.buildMenuFromXML(menuPanel, "com/vitco/layout/frames/toolbars/colorpalette.xml");
// so the background doesn't show
menuPanel.setOpaque(true);
frame.add(menuPanel, BorderLayout.SOUTH);
// register action to hide/show this frame and get visible state
actionManager.registerAction("colorPalette_state-action_show", new StateActionPrototype() {
@Override
public boolean getStatus() {
return frame.isVisible();
}
@Override
public void action(ActionEvent e) {
toggleVisible();
}
});
return frame;
}
@PostConstruct
public final void init() {
// load folder locations
if (preferences.contains("color_palette_imp_exp_dialog_last_directory")) {
File file = new File(preferences.loadString("color_palette_imp_exp_dialog_last_directory"));
dialog.setDialogPath(file);
}
// set the filter for the imp/exp dialog
dialog.addFileType("png");
}
@PreDestroy
public final void savePref() {
// store palette colors
preferences.storeObject("color-palette_set-colors", colorPaletteChooser.getColors());
// save folder locations
preferences.storeString("color_palette_imp_exp_dialog_last_directory", dialog.getDialogPath());
}
}