/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ui;
import com.intellij.util.ui.JBInsets;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import static java.beans.EventHandler.create;
import static java.util.Locale.ENGLISH;
public class ColorPanel extends JComponent {
private static final RelativeFont MONOSPACED_FONT = RelativeFont.SMALL.family(Font.MONOSPACED);
private final List<ActionListener> myListeners = new CopyOnWriteArrayList<ActionListener>();
private final JTextField myTextField = new JTextField(8);
private boolean myEditable;
private ActionEvent myEvent;
private Color myColor;
public ColorPanel() {
addImpl(myTextField, null, 0);
setEditable(true);
setMinimumSize(JBUI.size(10, 10));
myTextField.addMouseListener(create(MouseListener.class, this, "onPressed", null, "mousePressed"));
myTextField.addKeyListener(create(KeyListener.class, this, "onPressed", "keyCode", "keyPressed"));
myTextField.setEditable(false);
MONOSPACED_FONT.install(myTextField);
Painter.BACKGROUND.install(myTextField, true);
}
@SuppressWarnings("unused") // used from event handler
public void onPressed(int keyCode) {
if (keyCode == KeyEvent.VK_SPACE) {
onPressed();
}
}
public void onPressed() {
if (myEditable && isEnabled()) {
Color color = ColorChooser.chooseColor(this, UIBundle.message("color.panel.select.color.dialog.description"), myColor);
if (color != null) {
setSelectedColor(color);
if (!myListeners.isEmpty() && (myEvent == null)) {
try {
myEvent = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "colorPanelChanged");
for (ActionListener listener : myListeners) {
listener.actionPerformed(myEvent);
}
}
finally {
myEvent = null;
}
}
}
}
}
@Override
public void doLayout() {
Rectangle bounds = new Rectangle(getWidth(), getHeight());
JBInsets.removeFrom(bounds, getInsets());
myTextField.setBounds(bounds);
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
Dimension size = myTextField.getPreferredSize();
JBInsets.addTo(size, getInsets());
return size;
}
@Override
public String getToolTipText() {
return myTextField.getToolTipText();
}
public void removeActionListener(ActionListener actionlistener) {
myListeners.remove(actionlistener);
}
public void addActionListener(ActionListener actionlistener) {
myListeners.add(actionlistener);
}
@Nullable
public Color getSelectedColor() {
return myColor;
}
public void setSelectedColor(@Nullable Color color) {
myColor = color;
updateSelectedColor();
}
@SuppressWarnings("UseJBColor")
private void updateSelectedColor() {
boolean enabled = isEnabled();
if (enabled && myEditable) {
myTextField.setEnabled(true);
myTextField.setToolTipText(UIBundle.message("color.panel.select.color.tooltip.text"));
}
else {
myTextField.setEnabled(false);
myTextField.setToolTipText(null);
}
Color color = enabled ? myColor : null;
if (color != null) {
myTextField.setText(' ' + ColorUtil.toHex(color).toUpperCase(ENGLISH) + ' ');
}
else {
myTextField.setText(null);
color = getBackground();
}
myTextField.setBackground(color);
myTextField.setSelectedTextColor(color);
if (color != null) {
int gray = (int)(0.212656 * color.getRed() + 0.715158 * color.getGreen() + 0.072186 * color.getBlue());
int delta = gray < 0x20 ? 0x60 : gray < 0x50 ? 0x40 : gray < 0x80 ? 0x20 : gray < 0xB0 ? -0x20 : gray < 0xE0 ? -0x40 : -0x60;
gray += delta;
color = new Color(gray, gray, gray);
myTextField.setDisabledTextColor(color);
myTextField.setSelectionColor(color);
gray += delta;
color = new Color(gray, gray, gray);
myTextField.setForeground(color);
}
}
public void setEditable(boolean editable) {
myEditable = editable;
updateSelectedColor();
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
updateSelectedColor();
}
@Override
public void repaint() {
super.repaint();
}
private static class Painter implements Highlighter.HighlightPainter, PropertyChangeListener {
private static final String PROPERTY = "highlighter";
private static final Painter BACKGROUND = new Painter();
@Override
public void paint(Graphics g, int p0, int p1, Shape shape, JTextComponent component) {
Color color = component.getBackground();
if (color != null) {
g.setColor(color);
Rectangle bounds = shape instanceof Rectangle ? (Rectangle)shape : shape.getBounds();
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
@Override
public void propertyChange(PropertyChangeEvent event) {
Object source = event.getSource();
if ((source instanceof JTextComponent) && PROPERTY.equals(event.getPropertyName())) {
install((JTextComponent)source, false);
}
}
private void install(JTextComponent component, boolean listener) {
try {
Highlighter highlighter = component.getHighlighter();
if (highlighter != null) highlighter.addHighlight(0, 0, this);
}
catch (BadLocationException ignored) {
}
if (listener) {
component.addPropertyChangeListener(PROPERTY, this);
}
}
}
}