Browse Source

Ported ColorChooser.

pull/1/head
weisj 5 years ago
parent
commit
52583d8ef4
  1. 1
      src/main/java/com/weis/darklaf/DarkLaf.java
  2. 69
      src/main/java/com/weis/darklaf/color/DarkColorModel.java
  3. 76
      src/main/java/com/weis/darklaf/color/DarkColorModelCMYK.java
  4. 135
      src/main/java/com/weis/darklaf/color/DarkColorModelHSB.java
  5. 129
      src/main/java/com/weis/darklaf/color/DarkColorModelHSL.java
  6. 172
      src/main/java/com/weis/darklaf/components/border/ShadowPainter.java
  7. 8
      src/main/java/com/weis/darklaf/ui/colorchooser/ColorListener.java
  8. 38
      src/main/java/com/weis/darklaf/ui/colorchooser/ColorPipette.java
  9. 204
      src/main/java/com/weis/darklaf/ui/colorchooser/ColorValueFormatter.java
  10. 185
      src/main/java/com/weis/darklaf/ui/colorchooser/ColorWheel.java
  11. 82
      src/main/java/com/weis/darklaf/ui/colorchooser/ColorWheelImageProducer.java
  12. 78
      src/main/java/com/weis/darklaf/ui/colorchooser/ColorWheelPanel.java
  13. 407
      src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserPanel.java
  14. 73
      src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserUI.java
  15. 182
      src/main/java/com/weis/darklaf/ui/colorchooser/DarkPreviewPanel.java
  16. 31
      src/main/java/com/weis/darklaf/ui/colorchooser/DarkSwatchesChooserPanel.java
  17. 281
      src/main/java/com/weis/darklaf/ui/colorchooser/SlideComponent.java
  18. 16
      src/main/java/com/weis/darklaf/ui/rootpane/DarkRootPaneUI.java
  19. 11
      src/main/java/com/weis/darklaf/ui/rootpane/DarkTitlePane.java
  20. 1
      src/main/java/com/weis/darklaf/ui/table/DarkColorTableCellRendererEditor.java
  21. 252
      src/main/java/com/weis/darklaf/util/ColorPipetteBase.java
  22. 59
      src/main/java/com/weis/darklaf/util/ColorUtil.java
  23. 1
      src/main/java/com/weis/darklaf/util/DarkUIUtil.java
  24. 203
      src/main/java/com/weis/darklaf/util/DefaultColorPipette.java
  25. 2
      src/main/java/com/weis/darklaf/util/GraphicsContext.java
  26. 2
      src/main/java/com/weis/darklaf/util/GraphicsUtil.java
  27. 13
      src/main/java/com/weis/darklaf/util/ImageUtil.java
  28. 57
      src/main/java/com/weis/darklaf/util/StringUtil.java
  29. 32
      src/main/java/com/weis/darklaf/util/TimerUtil.java
  30. 2
      src/main/java/com/weis/darklaf/util/WindowsFrameUtil.java
  31. 15
      src/main/resources/com/weis/darklaf/darcula.properties
  32. 4
      src/main/resources/com/weis/darklaf/icons/dark/misc/pipette.svg
  33. 4
      src/main/resources/com/weis/darklaf/icons/dark/misc/pipette_rollover.svg
  34. 4
      src/main/resources/com/weis/darklaf/icons/light/misc/pipette.svg
  35. 4
      src/main/resources/com/weis/darklaf/icons/light/misc/pipette_rollover.svg
  36. 14
      src/test/java/ColorChooserDemo.java
  37. 41
      src/test/java/ColorModelTest.java

1
src/main/java/com/weis/darklaf/DarkLaf.java

@ -157,6 +157,7 @@ public class DarkLaf extends BasicLookAndFeel {
patchComboBox(metalDefaults, defaults);
loadStyleSheet();
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
if (SystemInfo.isMac
&& !"true".equalsIgnoreCase(System.getProperty("apple.laf.useScreenMenuBar", "false"))) {

69
src/main/java/com/weis/darklaf/color/DarkColorModel.java

@ -0,0 +1,69 @@
package com.weis.darklaf.color;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
public class DarkColorModel {
private final String prefix;
private final String[] labels;
@Contract(pure = true)
public DarkColorModel(final String name, final String... labels) {
this.prefix = "ColorChooser." + name;
this.labels = labels;
}
@Contract(pure = true)
public DarkColorModel() {
this("rgb", "Red", "Green", "Blue");
}
public int getCount() {
return this.labels.length;
}
public int getMinimum(final int index) {
return 0;
}
public int getMaximum(final int index) {
return 255;
}
public int getDefault(final int index) {
return 0;
}
public final String getText(@NotNull final Component component, final String suffix) {
return UIManager.getString(this.prefix + suffix + "Text", component.getLocale());
}
@Override
public String toString() {
return "RGB";
}
public int getValueCount() {
return 3;
}
public char[] getLabelDescriptorsBefore() {
return new char[]{'R', 'G', 'B'};
}
public char[] getLabelDescriptorsAfter() {
return new char[]{Character.MIN_VALUE, Character.MIN_VALUE, Character.MIN_VALUE, Character.MIN_VALUE};
}
public int[] getValuesFromColor(@NotNull final Color color) {
return new int[]{color.getRed(), color.getGreen(), color.getBlue()};
}
public Color getColorFromValues(@NotNull final int[] values) {
return new Color(values[0], values[1], values[2]);
}
}

76
src/main/java/com/weis/darklaf/color/DarkColorModelCMYK.java

@ -0,0 +1,76 @@
package com.weis.darklaf.color;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
public class DarkColorModelCMYK extends DarkColorModel {
private static final int[] cmyk = new int[4];
private static final int[] rgb = new int[3];
public DarkColorModelCMYK() {
super("cmyk", "Cyan", "Magenta", "Yellow", "Black");
}
@NotNull
private static int[] CMYKtoRGB(final double c, final double m, final double y, final double k) {
rgb[0] = (int) Math.round(255 * (1.0f + c * k - k - c));
rgb[1] = (int) Math.round(255 * (1.0f + m * k - k - m));
rgb[2] = (int) Math.round(255 * (1.0f + y * k - k - y));
return rgb;
}
@NotNull
private static int[] RGBtoCMYK(final int r, final int g, final int b) {
double max = DarkColorModelHSL.max(r / 255.0, g / 255.0, b / 255.0);
if (max > 0.0f) {
cmyk[0] = (int) Math.round((1.0f - (r / 255.0) / max) * 100);
cmyk[1] = (int) Math.round((1.0f - (g / 255.0) / max) * 100);
cmyk[2] = (int) Math.round((1.0f - (b / 255.0) / max) * 100);
} else {
cmyk[0] = 0;
cmyk[1] = 0;
cmyk[2] = 0;
}
cmyk[3] = (int) Math.round((1.0f - max) * 100);
return cmyk;
}
@Override
public int getMaximum(final int index) {
return 100;
}
@Override
public String toString() {
return "CMYK";
}
@Override
public int getValueCount() {
return 4;
}
@Override
public char[] getLabelDescriptorsBefore() {
return new char[]{'C', 'M', 'Y', 'K'};
}
@Override
public char[] getLabelDescriptorsAfter() {
return new char[]{'%', '%', '%', '%'};
}
@Override
public int[] getValuesFromColor(@NotNull final Color color) {
return RGBtoCMYK(color.getRed(), color.getGreen(), color.getBlue());
}
@Override
public Color getColorFromValues(@NotNull final int[] values) {
var rgb = CMYKtoRGB(values[0] / 100.0, values[1] / 100.0, values[2] / 100.0, values[3] / 100.0);
return new Color(rgb[0], rgb[1], rgb[2]);
}
}

135
src/main/java/com/weis/darklaf/color/DarkColorModelHSB.java

@ -0,0 +1,135 @@
package com.weis.darklaf.color;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
public class DarkColorModelHSB extends DarkColorModel {
private static final int[] hsb = new int[3];
private static final int[] rgb = new int[3];
public DarkColorModelHSB() {
super("hsv", "Hue", "Saturation", "Brightness");
}
@Contract("_, _, _ -> new")
@NotNull
public static int[] RGBtoHSB(final int r, final int g, final int b) {
double hue, saturation, brightness;
int cmax = Math.max(r, g);
if (b > cmax) cmax = b;
int cmin = Math.min(r, g);
if (b < cmin) cmin = b;
brightness = ((double) cmax) / 255.0f;
if (cmax != 0) {
saturation = ((double) (cmax - cmin)) / ((double) cmax);
} else {
saturation = 0;
}
if (saturation == 0) {
hue = 0;
} else {
double redc = ((double) (cmax - r)) / ((double) (cmax - cmin));
double greenc = ((double) (cmax - g)) / ((double) (cmax - cmin));
double bluec = ((double) (cmax - b)) / ((double) (cmax - cmin));
if (r == cmax) {
hue = bluec - greenc;
} else if (g == cmax) {
hue = 2.0f + redc - bluec;
} else {
hue = 4.0f + greenc - redc;
}
hue = hue / 6.0f;
if (hue < 0) {
hue = hue + 1.0f;
}
}
hsb[0] = (int) Math.round(hue * 360);
hsb[1] = (int) Math.round(saturation * 100);
hsb[1] = (int) Math.round(brightness * 100);
return hsb;
}
public static int[] HSBtoRGB(final double hue, final double saturation, final double brightness) {
double r = 0, g = 0, b = 0;
if (saturation == 0) {
r = g = b = (brightness * 255.0f + 0.5f);
} else {
double h = (hue - Math.floor(hue)) * 6.0f;
double f = h - Math.floor(h);
double p = brightness * (1.0f - saturation);
double q = brightness * (1.0f - saturation * f);
double t = brightness * (1.0f - (saturation * (1.0f - f)));
switch ((int) Math.round(h)) {
case 0:
r = (brightness * 255.0f + 0.5f);
g = (t * 255.0f + 0.5f);
b = (p * 255.0f + 0.5f);
break;
case 1:
r = (q * 255.0f + 0.5f);
g = (brightness * 255.0f + 0.5f);
b = (p * 255.0f + 0.5f);
break;
case 2:
r = (p * 255.0f + 0.5f);
g = (brightness * 255.0f + 0.5f);
b = (t * 255.0f + 0.5f);
break;
case 3:
r = (p * 255.0f + 0.5f);
g = (q * 255.0f + 0.5f);
b = (brightness * 255.0f + 0.5f);
break;
case 4:
r = (t * 255.0f + 0.5f);
g = (p * 255.0f + 0.5f);
b = (brightness * 255.0f + 0.5f);
break;
case 5:
r = (brightness * 255.0f + 0.5f);
g = (p * 255.0f + 0.5f);
b = (q * 255.0f + 0.5f);
break;
}
}
rgb[0] = ((int) Math.round(r));
rgb[1] = ((int) Math.round(g));
rgb[2] = ((int) Math.round(b));
return rgb;
}
@Override
public int getMaximum(final int index) {
return (index == 0) ? 359 : 100;
}
@Override
public String toString() {
return "HSB";
}
@Override
public char[] getLabelDescriptorsBefore() {
return new char[]{'H', 'S', 'B'};
}
@Override
public char[] getLabelDescriptorsAfter() {
return new char[]{'\u00B0', '%', '%'};
}
@Override
public int[] getValuesFromColor(@NotNull final Color color) {
return RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue());
}
@Override
public Color getColorFromValues(@NotNull final int[] values) {
var rgb = HSBtoRGB(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0);
return new Color(rgb[0], rgb[1], rgb[2]);
}
}

129
src/main/java/com/weis/darklaf/color/DarkColorModelHSL.java

@ -0,0 +1,129 @@
package com.weis.darklaf.color;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
public class DarkColorModelHSL extends DarkColorModel {
private static final int[] hsl = new int[3];
private static final int[] rgb = new int[3];
public DarkColorModelHSL() {
super("hsl", "Hue", "Saturation", "Lightness");
}
@NotNull
private static int[] HSLtoRGB(final double h, final double saturation, final double lightness) {
double hue = h;
if (saturation > 0.0f) {
hue = (hue < 1.0f) ? hue * 6.0f : 0.0f;
double q = lightness + saturation * ((lightness > 0.5f) ? 1.0f - lightness : lightness);
double p = 2.0f * lightness - q;
rgb[0] = (int) Math.round(255 * normalize(q, p, (hue < 4.0f) ? (hue + 2.0f) : (hue - 4.0f)));
rgb[1] = (int) Math.round(255 * normalize(q, p, hue));
rgb[2] = (int) Math.round(255 * normalize(q, p, (hue < 2.0f) ? (hue + 4.0f) : (hue - 2.0f)));
} else {
rgb[0] = (int) Math.round(255 * lightness);
rgb[1] = rgb[0];
rgb[2] = rgb[0];
}
return rgb;
}
@NotNull
private static int[] RGBtoHSL(final int r, final int g, final int b) {
double max = max(r, g, b) / 255.0;
double min = min(r, g, b) / 255.0;
double summa = (max + min);
double saturation = (max - min);
if (saturation > 0.0f) {
saturation /= (summa > 1.0f)
? 2.0f - summa
: summa;
}
hsl[0] = (int) Math.round(360 * getHue(r / 255.0, g / 255.0, b / 255.0, max, min));
hsl[1] = (int) Math.round(100 * saturation);
hsl[2] = (int) Math.round(100 * (summa / 2.0));
return hsl;
}
protected static double min(final double red, final double green, final double blue) {
double min = Math.min(red, green);
return Math.min(min, blue);
}
@Contract(pure = true)
protected static double max(final double red, final double green, final double blue) {
double max = Math.max(red, green);
return Math.max(max, blue);
}
@Contract(pure = true)
private static double getHue(final double red, final double green, final double blue,
final double max, final double min) {
double hue = max - min;
if (hue > 0.0f) {
if (max == red) {
hue = (green - blue) / hue;
if (hue < 0.0f) {
hue += 6.0f;
}
} else if (max == green) {
hue = 2.0f + (blue - red) / hue;
} else /*max == blue*/ {
hue = 4.0f + (red - green) / hue;
}
hue /= 6.0f;
}
return hue;
}
@Contract(pure = true)
private static double normalize(final double q, final double p, final double color) {
if (color < 1.0f) {
return p + (q - p) * color;
}
if (color < 3.0f) {
return q;
}
if (color < 4.0f) {
return p + (q - p) * (4.0f - color);
}
return p;
}
@Override
public int getMaximum(final int index) {
return (index == 0) ? 359 : 100;
}
@Override
public String toString() {
return "HSL";
}
@Override
public char[] getLabelDescriptorsBefore() {
return new char[]{'H', 'S', 'L'};
}
@Override
public char[] getLabelDescriptorsAfter() {
return new char[]{'\u00B0', '%', '%'};
}
@Override
public int[] getValuesFromColor(@NotNull final Color color) {
return RGBtoHSL(color.getRed(), color.getGreen(), color.getBlue());
}
@Override
public Color getColorFromValues(@NotNull final int[] values) {
var rgb = HSLtoRGB(values[0] / 360.0, values[1] / 100.0, values[2] / 100.0);
return new Color(rgb[0], rgb[1], rgb[2]);
}
}

172
src/main/java/com/weis/darklaf/components/border/ShadowPainter.java

@ -0,0 +1,172 @@
package com.weis.darklaf.components.border;
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be
// found in the LICENSE file.
import com.weis.darklaf.util.GraphicsUtil;
import com.weis.darklaf.util.ImageUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import static com.weis.darklaf.util.GraphicsUtil.SCALE;
/**
* @author Konstantin Bulenkov
*/
public class ShadowPainter {
protected final Icon myTop;
protected final Icon myTopRight;
protected final Icon myRight;
protected final Icon myBottomRight;
protected final Icon myBottom;
protected final Icon myBottomLeft;
protected final Icon myLeft;
protected final Icon myTopLeft;
private Icon myCroppedTop = null;
private Icon myCroppedRight = null;
private Icon myCroppedBottom = null;
private Icon myCroppedLeft = null;
@Nullable
private Color myBorderColor;
public ShadowPainter(final Icon top, final Icon topRight, final Icon right,
final Icon bottomRight, final Icon bottom, final Icon bottomLeft,
final Icon left, final Icon topLeft) {
myTop = top;
myTopRight = topRight;
myRight = right;
myBottomRight = bottomRight;
myBottom = bottom;
myBottomLeft = bottomLeft;
myLeft = left;
myTopLeft = topLeft;
updateIcons();
}
@Contract(pure = true)
public ShadowPainter(final Icon top, final Icon topRight, final Icon right,
final Icon bottomRight, final Icon bottom, final Icon bottomLeft,
final Icon left, final Icon topLeft, @Nullable final Color borderColor) {
this(top, topRight, right, bottomRight, bottom, bottomLeft, left, topLeft);
myBorderColor = borderColor;
}
private static void fill(final Graphics g, final Icon pattern, final int x, final int y, final int from,
final int to, final boolean horizontally) {
double scale = SCALE;
if (GraphicsUtil.isHighDpiEnabled() && Math.ceil(scale) > scale) {
// Direct painting for fractional scale
BufferedImage img = ImageUtil.toBufferedImage(ImageUtil.toImage(pattern));
int patternSize = horizontally ? img.getWidth() : img.getHeight();
Graphics2D g2d = (Graphics2D) g.create();
try {
g2d.scale(1 / scale, 1 / scale);
g2d.translate(x * scale, y * scale);
for (int at = (int) Math.floor(from * scale); at < to * scale; at += patternSize) {
if (horizontally) {
g2d.drawImage(img, at, 0, null);
} else {
g2d.drawImage(img, 0, at, null);
}
}
} finally {
g2d.dispose();
}
} else {
for (int at = from; at < to; at++) {
if (horizontally) {
pattern.paintIcon(null, g, x + at, y);
} else {
pattern.paintIcon(null, g, x, y + at);
}
}
}
}
public void setBorderColor(@Nullable final Color borderColor) {
myBorderColor = borderColor;
}
private void updateIcons() {
myCroppedTop = ImageUtil.cropIcon(myTop, 1, Integer.MAX_VALUE);
myCroppedRight = ImageUtil.cropIcon(myRight, Integer.MAX_VALUE, 1);
myCroppedBottom = ImageUtil.cropIcon(myBottom, 1, Integer.MAX_VALUE);
myCroppedLeft = ImageUtil.cropIcon(myLeft, Integer.MAX_VALUE, 1);
}
public BufferedImage createShadow(@NotNull final JComponent c, final int width, final int height) {
final BufferedImage image = c.getGraphicsConfiguration()
.createCompatibleImage(width, height, Transparency.TRANSLUCENT);
final Graphics2D g = image.createGraphics();
paintShadow(c, g, 0, 0, width, height);
g.dispose();
return image;
}
public void paintShadow(final Component c, final Graphics2D g, final int x, final int y,
final int width, final int height) {
final int leftSize = myCroppedLeft.getIconWidth();
final int rightSize = myCroppedRight.getIconWidth();
final int bottomSize = myCroppedBottom.getIconHeight();
final int topSize = myCroppedTop.getIconHeight();
// updateIcons();
int delta = myTopLeft.getIconHeight() + myBottomLeft.getIconHeight() - height;
if (delta > 0) { // Corner icons are overlapping. Need to handle this
Shape clip = g.getClip();
int topHeight = myTopLeft.getIconHeight() - delta / 2;
Area top = new Area(new Rectangle2D.Float(x, y, width, topHeight));
if (clip != null) {
top.intersect(new Area(clip));
}
g.setClip(top);
myTopLeft.paintIcon(c, g, x, y);
myTopRight.paintIcon(c, g, x + width - myTopRight.getIconWidth(), y);
int bottomHeight = myBottomLeft.getIconHeight() - delta + delta / 2;
Area bottom = new Area(new Rectangle2D.Float(x, y + topHeight, width, bottomHeight));
if (clip != null) {
bottom.intersect(new Area(clip));
}
g.setClip(bottom);
myBottomLeft.paintIcon(c, g, x, y + height - myBottomLeft.getIconHeight());
myBottomRight.paintIcon(c, g, x + width - myBottomRight.getIconWidth(),
y + height - myBottomRight.getIconHeight());
g.setClip(clip);
} else {
myTopLeft.paintIcon(c, g, x, y);
myTopRight.paintIcon(c, g, x + width - myTopRight.getIconWidth(), y);
myBottomLeft.paintIcon(c, g, x, y + height - myBottomLeft.getIconHeight());
myBottomRight.paintIcon(c, g, x + width - myBottomRight.getIconWidth(),
y + height - myBottomRight.getIconHeight());
}
fill(g, myCroppedTop, x, y, myTopLeft.getIconWidth(),
width - myTopRight.getIconWidth(), true);
fill(g, myCroppedBottom, x, y + height - bottomSize, myBottomLeft.getIconWidth(),
width - myBottomRight.getIconWidth(), true);
fill(g, myCroppedLeft, x, y, myTopLeft.getIconHeight(),
height - myBottomLeft.getIconHeight(), false);
fill(g, myCroppedRight, x + width - rightSize, y, myTopRight.getIconHeight(),
height - myBottomRight.getIconHeight(), false);
if (myBorderColor != null) {
g.setColor(myBorderColor);
g.drawRect(x + leftSize - 1, y + topSize - 1, width - leftSize - rightSize + 1,
height - topSize - bottomSize + 1);
}
}
}

8
src/main/java/com/weis/darklaf/ui/colorchooser/ColorListener.java

@ -0,0 +1,8 @@
package com.weis.darklaf.ui.colorchooser;
import java.awt.*;
public interface ColorListener {
void colorChanged(final Color color, final Object source);
}

38
src/main/java/com/weis/darklaf/ui/colorchooser/ColorPipette.java

@ -0,0 +1,38 @@
package com.weis.darklaf.ui.colorchooser;
/*
* 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.
*/
import com.intellij.openapi.Disposable;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.awt.image.ImageObserver;
public interface ColorPipette extends ImageObserver, Disposable {
void setInitialColor(@Nullable Color initialColor);
@Nullable
Color getColor();
Window show();
void pickAndClose();
void cancelPipette();
boolean isAvailable();
}

204
src/main/java/com/weis/darklaf/ui/colorchooser/ColorValueFormatter.java

@ -0,0 +1,204 @@
package com.weis.darklaf.ui.colorchooser;
import com.weis.darklaf.color.DarkColorModel;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.DocumentFilter;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.ParseException;
import static java.util.Locale.ENGLISH;
public final class ColorValueFormatter extends JFormattedTextField.AbstractFormatter implements FocusListener {
private final int fieldIndex;
private final int radix;
private final boolean hex;
private DarkColorModel model;
private boolean transparencyEnabled;
private JFormattedTextField text;
private final DocumentFilter filter = new DocumentFilter() {
@Override
public void remove(@NotNull final FilterBypass fb, final int offset,
final int length) throws BadLocationException {
if (isValid(fb.getDocument().getLength() - length)) {
fb.remove(offset, length);
commit();
} else {
Toolkit.getDefaultToolkit().beep();
}
}
@Override
public void replace(@NotNull final FilterBypass fb, final int offset, final int length,
@NotNull final String text, final AttributeSet set) throws BadLocationException {
if (isValid(fb.getDocument().getLength() + text.length() - length) && isValid(text)) {
var newText = new StringBuilder(fb.getDocument().getText(0, fb.getDocument().getLength()));
newText.replace(offset, offset + length, text);
if (hex || isValidValue(newText.toString())) {
fb.replace(offset, length, text.toUpperCase(ENGLISH), set);
commit();
return;
}
}
Toolkit.getDefaultToolkit().beep();
}
@Override
public void insertString(@NotNull final FilterBypass fb, final int offset,
@NotNull final String text, final AttributeSet set) throws BadLocationException {
if (isValid(fb.getDocument().getLength() + text.length())
&& isValid(text)) {
var newText = new StringBuilder(fb.getDocument().getText(0, fb.getDocument().getLength()));
newText.insert(offset, text);
if (hex || isValidValue(newText.toString())) {
fb.insertString(offset, text.toUpperCase(ENGLISH), set);
commit();
return;
}
}
Toolkit.getDefaultToolkit().beep();
}
};
private ColorValueFormatter(final DarkColorModel model, final int index, final boolean hex) {
this.model = model;
this.fieldIndex = index;
this.radix = hex ? 16 : 10;
this.hex = hex;
}
@NotNull
static ColorValueFormatter init(final DarkColorModel model, final int index,
final boolean hex, @NotNull final JFormattedTextField text) {
ColorValueFormatter formatter = new ColorValueFormatter(model, index, hex);
text.setFormatterFactory(new DefaultFormatterFactory(formatter));
text.setMinimumSize(text.getPreferredSize());
text.addFocusListener(formatter);
return formatter;
}
private void commit() {
SwingUtilities.invokeLater(() -> {
try {
if (text != null) {
text.commitEdit();
}
} catch (ParseException e) {
e.printStackTrace();
}
});
}
public void setModel(final DarkColorModel model) {
this.model = model;
}
public void setTransparencyEnabled(final boolean transparencyEnabled) {
this.transparencyEnabled = transparencyEnabled;
}
@Override
public Object stringToValue(@NotNull final String text) throws ParseException {
try {
if (text.isEmpty()) {
return model.getDefault(fieldIndex);
}
if (hex) {
return String.format("%-8s", text).replace(' ', '0');
}
var value = Integer.valueOf(text, this.radix);
var min = model.getMinimum(fieldIndex);
var max = model.getMaximum(fieldIndex);
if (value > max || value < min) {
throw new ParseException("Value not in range [" + min + "," + max + "]", 0);
}
return ((Number) value).intValue();
} catch (NumberFormatException nfe) {
ParseException pe = new ParseException("illegal format", 0);
pe.initCause(nfe);
throw pe;
}
}
@Override
public String valueToString(final Object object) throws ParseException {
if (object instanceof Integer) {
if (this.radix == 10) {
return object.toString();
}
int value = (Integer) object;
int index = getLength();
char[] array = new char[index];
while (0 < index--) {
array[index] = Character.forDigit(value & 0x0F, this.radix);
value >>= 4;
}
return new String(array).toUpperCase(ENGLISH);
}
throw new ParseException("illegal object", 0);
}
@Contract(pure = true)
@Override
protected DocumentFilter getDocumentFilter() {
return this.filter;
}
public void focusGained(@NotNull final FocusEvent event) {
Object source = event.getSource();
if (source instanceof JFormattedTextField) {
this.text = (JFormattedTextField) source;
SwingUtilities.invokeLater(() -> {
if (this.text != null) {
this.text.selectAll();
}
});
}
}
public void focusLost(final FocusEvent event) {
SwingUtilities.invokeLater(() -> text.select(0, 0));
}
private int getLength() {
return hex ? getHexLength() : String.valueOf(model.getMaximum(fieldIndex)).length();
}
@Contract(pure = true)
private int getHexLength() {
return transparencyEnabled ? 8 : 6;
}
@Contract(pure = true)
private boolean isValid(final int length) {
return (0 <= length) && (length <= getLength());
}
private boolean isValid(@NotNull final String text) {
int length = text.length();
for (int i = 0; i < length; i++) {
char ch = text.charAt(i);
if (Character.digit(ch, this.radix) < 0) {
return false;
}
}
return true;
}
private boolean isValidValue(final String text) {
try {
stringToValue(text);
} catch (ParseException e) {
return false;
}
return true;
}
}

185
src/main/java/com/weis/darklaf/ui/colorchooser/ColorWheel.java

@ -0,0 +1,185 @@
package com.weis.darklaf.ui.colorchooser;
import com.weis.darklaf.util.ColorUtil;
import com.weis.darklaf.util.GraphicsContext;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
public class ColorWheel extends JComponent {
private static final int BORDER_SIZE = 5;
private final List<ColorListener> myListeners = new ArrayList<>();
private float myBrightness = 1f;
private float myHue = 1f;
private float mySaturation = 0f;
private Image myImage;
private Rectangle myWheel;
private boolean myShouldInvalidate = true;
private Color myColor;
private int myOpacity;
private boolean pressedInside;
public ColorWheel() {
setOpaque(true);
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(final ComponentEvent e) {
myShouldInvalidate = true;
}
});
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseDragged(final MouseEvent e) {
if (!pressedInside) return;
final int x = e.getX();
final int y = e.getY();
int mx = myWheel.x + myWheel.width / 2;
int my = myWheel.y + myWheel.height / 2;
double s;
double h;
s = Math.sqrt((x - mx) * (x - mx) + (y - my) * (y - my)) / (myWheel.height / 2.0);
h = -Math.atan2(y - my, x - mx) / (2 * Math.PI);
if (h < 0) h += 1.0;
if (s > 1) s = 1.0;
setHSBValue((float) h, (float) s, myBrightness, myOpacity);
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent e) {
final int x = e.getX();
final int y = e.getY();
int mx = myWheel.x + myWheel.width / 2;
int my = myWheel.y + myWheel.height / 2;
double s;
double h;
s = Math.sqrt((x - mx) * (x - mx) + (y - my) * (y - my)) / (myWheel.height / 2.0);
h = -Math.atan2(y - my, x - mx) / (2 * Math.PI);
if (h < 0) h += 1.0;
if (s <= 1) {
pressedInside = true;
setHSBValue((float) h, (float) s, myBrightness, myOpacity);
} else {
pressedInside = false;
}
}
@Override
public void mouseReleased(final MouseEvent e) {
pressedInside = false;
}
});
}
private void setHSBValue(final float h, final float s, final float b, final int opacity) {
Color rgb = new Color(Color.HSBtoRGB(h, s, b));
setColor(ColorUtil.toAlpha(rgb, opacity), this, h, s, b);
}
public void setColor(@NotNull final Color color, final Object source,
final float h, final float s, final float b) {
myColor = color;
myHue = h;
mySaturation = s;
myBrightness = b;
myOpacity = color.getAlpha();
fireColorChanged(source);
repaint();
}
public void addListener(final ColorListener listener) {
myListeners.add(listener);
}
private void fireColorChanged(final Object source) {
for (ColorListener listener : myListeners) {
listener.colorChanged(myColor, source);
}
}
public void setBrightness(final float brightness) {
if (brightness != myBrightness) {
myImage = null;
setHSBValue(myHue, mySaturation, brightness, myOpacity);
}
}
public void setOpacity(final int opacity) {
if (opacity != myOpacity) {
setHSBValue(myHue, mySaturation, myBrightness, opacity);
}
}
@Override
public Dimension getPreferredSize() {
return getMinimumSize();
}
@Override
public Dimension getMinimumSize() {
return new Dimension(300, 300);
}
@Override
protected void paintComponent(final Graphics g) {
Graphics2D g2d = (Graphics2D) g;
final Dimension size = getSize();
int _size = Math.min(size.width, size.height);
_size = Math.min(_size, 600);
if (myImage != null && myShouldInvalidate) {
if (myImage.getWidth(null) != _size) {
myImage = null;
}
}
myShouldInvalidate = false;
if (myImage == null) {
myImage = createImage(new ColorWheelImageProducer(
_size - BORDER_SIZE * 2, _size - BORDER_SIZE * 2, myBrightness));
myWheel = new Rectangle(BORDER_SIZE, BORDER_SIZE, _size - BORDER_SIZE * 2,
_size - BORDER_SIZE * 2);
}
g2d.setColor(UIManager.getColor("Panel.background"));
g2d.fillRect(0, 0, getWidth(), getHeight());
var config = new GraphicsContext(g);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, ((float) myOpacity) / 255f));
g2d.drawImage(myImage, myWheel.x, myWheel.y, null);
config.restore();
int mx = myWheel.x + myWheel.width / 2;
int my = myWheel.y + myWheel.height / 2;
int arcw = (int) (myWheel.width * mySaturation / 2);
int arch = (int) (myWheel.height * mySaturation / 2);
double th = myHue * 2 * Math.PI;
final int x = (int) (mx + arcw * Math.cos(th));
final int y = (int) (my - arch * Math.sin(th));
g2d.setColor(UIManager.getColor("ColorChooser.colorWheelDropBackgroundColor"));
g2d.fillRect(x - 2, y - 2, 4, 4);
g2d.setColor(UIManager.getColor("ColorChooser.colorWheelDropBorderColor"));
g2d.drawRect(x - 2, y - 2, 4, 4);
}
public void dropImage() {
myImage = null;
}
}

82
src/main/java/com/weis/darklaf/ui/colorchooser/ColorWheelImageProducer.java

@ -0,0 +1,82 @@
package com.weis.darklaf.ui.colorchooser;
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;
public class ColorWheelImageProducer extends MemoryImageSource {
private final int[] myPixels;
private final int myWidth;
private final int myHeight;
private float myBrightness = 1f;
private float[] myHues;
private float[] mySat;
private int[] myAlphas;
public ColorWheelImageProducer(final int w, final int h, final float brightness) {
super(w, h, null, 0, w);
myPixels = new int[w * h];
myWidth = w;
myHeight = h;
myBrightness = brightness;
generateLookupTables();
newPixels(myPixels, ColorModel.getRGBdefault(), 0, w);
setAnimated(true);
generateColorWheel();
}
public int getRadius() {
return Math.min(myWidth, myHeight) / 2 - 2;
}
private void generateLookupTables() {
mySat = new float[myWidth * myHeight];
myHues = new float[myWidth * myHeight];
myAlphas = new int[myWidth * myHeight];
float radius = getRadius();
// blend is used to create a linear alpha gradient of two extra pixels
float blend = (radius + 2f) / radius - 1f;
// Center of the color wheel circle
int cx = myWidth / 2;
int cy = myHeight / 2;
for (int x = 0; x < myWidth; x++) {
int kx = x - cx; // cartesian coordinates of x
int squarekx = kx * kx; // Square of cartesian x
for (int y = 0; y < myHeight; y++) {
int ky = cy - y; // cartesian coordinates of y
int index = x + y * myWidth;
mySat[index] = (float) Math.sqrt(squarekx + ky
* ky)
/ radius;
if (mySat[index] <= 1f) {
myAlphas[index] = 0xff000000;
} else {
myAlphas[index] = (int) ((blend - Math.min(blend,
mySat[index] - 1f)) * 255 / blend) << 24;
mySat[index] = 1f;
}
if (myAlphas[index] != 0) {
myHues[index] = (float) (Math.atan2(ky, kx) / Math.PI / 2d);
}
}
}
}
public void generateColorWheel() {
for (int index = 0; index < myPixels.length; index++) {
if (myAlphas[index] != 0) {
myPixels[index] = myAlphas[index] | 0xffffff & Color.HSBtoRGB(myHues[index],
mySat[index],
myBrightness);
}
}
newPixels();
}
}

78
src/main/java/com/weis/darklaf/ui/colorchooser/ColorWheelPanel.java

@ -0,0 +1,78 @@
package com.weis.darklaf.ui.colorchooser;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.colorchooser.AbstractColorChooserPanel;
import java.awt.*;
public class ColorWheelPanel extends JPanel {
private final ColorWheel myColorWheel;
private final SlideComponent myBrightnessComponent;
private final boolean opacityInPercent;
private SlideComponent myOpacityComponent = null;
private boolean enableOpacity;
public ColorWheelPanel(final ColorListener colorListener, final boolean enableOpacity,
final boolean opacityInPercent) {
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
this.enableOpacity = enableOpacity;
this.opacityInPercent = opacityInPercent;
myColorWheel = new ColorWheel();
add(myColorWheel, BorderLayout.CENTER);
myColorWheel.addListener(colorListener);
myBrightnessComponent = new SlideComponent("Brightness", true);
myBrightnessComponent.setToolTipText("Brightness");
myBrightnessComponent.addListener(value -> {
myColorWheel.setBrightness(1f - (value / 255f));
myColorWheel.repaint();
});
add(myBrightnessComponent, BorderLayout.EAST);
if (enableOpacity) {
myOpacityComponent = new SlideComponent("Opacity", false);
myOpacityComponent.setUnits(opacityInPercent ? SlideComponent.Unit.PERCENT : SlideComponent.Unit.LEVEL);
myOpacityComponent.setToolTipText("Opacity");
myOpacityComponent.addListener(integer -> {
myColorWheel.setOpacity(integer);
myColorWheel.repaint();
});
add(myOpacityComponent, BorderLayout.SOUTH);
}
}
public void setColor(@NotNull final Color color, final Object source) {
float[] hsb = new float[3];
Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsb);
myBrightnessComponent.setValue(255 - (int) (hsb[2] * 255));
myBrightnessComponent.repaint();
myColorWheel.dropImage();
if (myOpacityComponent != null && source instanceof AbstractColorChooserPanel) {
myOpacityComponent.setValue(color.getAlpha());
myOpacityComponent.repaint();
}
myColorWheel.setColor(color, source, hsb[0], hsb[1], hsb[2]);
}
public boolean isColorTransparencySelectionEnabled() {
return enableOpacity;
}
public void setColorTransparencySelectionEnabled(final boolean b) {
if (b != enableOpacity) {
enableOpacity = b;
myOpacityComponent.setEnabled(b);
myOpacityComponent.setVisible(b);
}
}
}

407
src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserPanel.java

@ -0,0 +1,407 @@
package com.weis.darklaf.ui.colorchooser;
import com.weis.darklaf.color.DarkColorModel;
import com.weis.darklaf.util.ColorUtil;
import com.weis.darklaf.util.DefaultColorPipette;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.colorchooser.AbstractColorChooserPanel;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import java.awt.*;
public class DarkColorChooserPanel extends AbstractColorChooserPanel implements ColorListener {
private final ColorPipette pipette;
private final ColorWheelPanel colorWheelPanel;
private final JFormattedTextField textHex;
private final ColorValueFormatter hexFormatter;
private final JFormattedTextField[] valueFields;
private final ColorValueFormatter[] formatters;
private final JComboBox<DarkColorModel> formatBox;
private final ColorPreviewComponent previewComponent;
private final JLabel[] descriptors;
private final JLabel[] descriptorsAfter;
private final boolean doneInit;
private Color currentColor;
private boolean isChanging;
@Contract("null -> fail")
public DarkColorChooserPanel(final DarkColorModel... colorModels) {
if (colorModels == null || colorModels.length == 0) {
throw new IllegalArgumentException("Must pass at least one valid colorModel");
}
previewComponent = new ColorPreviewComponent();
colorWheelPanel = new ColorWheelPanel(this, true, true);
pipette = new DefaultColorPipette(this, colorWheelPanel::setColor);
formatBox = new JComboBox<>(colorModels);
formatBox.addActionListener(e -> {
updateDescriptors();
updateValueFields();
updateFormatters();
applyColorToFields(getColorFromModel());
doLayout();
});
int record = 0;
DarkColorModel prototype = null;
for (var model : colorModels) {
record = Math.max(model.getValueCount(), record);
var name = model.toString();
if (prototype == null || prototype.toString().length() < name.length()) {
prototype = model;
}
}
formatBox.setPrototypeDisplayValue(prototype);
descriptors = new JLabel[record];
descriptorsAfter = new JLabel[record];
textHex = createColorField(true);
textHex.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(final AncestorEvent event) {
textHex.requestFocus();
textHex.removeAncestorListener(this);
}
@Override
public void ancestorRemoved(final AncestorEvent event) {
}
@Override
public void ancestorMoved(final AncestorEvent event) {
}
});
hexFormatter = ColorValueFormatter.init(getDarkColorModel(), 0, true, textHex);
hexFormatter.setTransparencyEnabled(isColorTransparencySelectionEnabled());
valueFields = new JFormattedTextField[record];
formatters = new ColorValueFormatter[record];
for (int i = 0; i < record; i++) {
descriptors[i] = new JLabel();
descriptorsAfter[i] = new JLabel();
valueFields[i] = createColorField(false);
formatters[i] = ColorValueFormatter.init(getDarkColorModel(), i, false, valueFields[i]);
}
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
add(buildTopPanel(true), BorderLayout.NORTH);
add(colorWheelPanel, BorderLayout.CENTER);
add(Box.createVerticalStrut(10), BorderLayout.SOUTH);
updateValueFields();
updateDescriptors();
doneInit = true;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(520, 420);
}
private void updateFormatters() {
for (ColorValueFormatter formatter : formatters) {
formatter.setModel(getDarkColorModel());
}
}
private void updateValueFields() {
var model = getDarkColorModel();
int count = model.getValueCount();
for (int i = 0; i < valueFields.length; i++) {
valueFields[i].setEnabled(i < count);
valueFields[i].setVisible(i < count);
}
}
private void updateDescriptors() {
var desc = getDarkColorModel().getLabelDescriptorsBefore();
var descAfter = getDarkColorModel().getLabelDescriptorsAfter();
for (int i = 0; i < descriptors.length; i++) {
if (i < desc.length) {
descriptors[i].setText(desc[i] + ":");
} else {
descriptors[i].setText("");
}
if (i < descAfter.length) {
descriptorsAfter[i].setText(String.valueOf(descAfter[i]));
} else {
descriptorsAfter[i].setText("");
}
}
}
@NotNull
private JComponent buildTopPanel(final boolean enablePipette) {
final JPanel result = new JPanel(new BorderLayout());
final JPanel previewPanel = new JPanel(new BorderLayout());
if (enablePipette && pipette != null) {
JButton pipetteButton = new JButton();
pipetteButton.putClientProperty("JButton.variant", "onlyLabel");
pipetteButton.putClientProperty("JButton.thin", Boolean.TRUE);
pipetteButton.setRolloverEnabled(true);
pipetteButton.setIcon(getPipetteIcon());
pipetteButton.setRolloverIcon(getPipetteRolloverIcon());
pipetteButton.setDisabledIcon(getPipetteRolloverIcon());
pipetteButton.setPressedIcon(getPipetteRolloverIcon());
pipetteButton.setFocusable(false);
pipetteButton.addActionListener(e -> {
pipetteButton.setEnabled(false);
pipette.setInitialColor(getColorFromModel());
pipette.show();
});
((DefaultColorPipette) pipette).setCloseAction(() -> pipetteButton.setEnabled(true));
previewPanel.add(pipetteButton, BorderLayout.WEST);
}
previewPanel.add(previewComponent, BorderLayout.CENTER);
result.add(previewPanel, BorderLayout.NORTH);
final JPanel valuePanel = new JPanel();
valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.X_AXIS));
valuePanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
for (int i = 0; i < descriptorsAfter.length; i++) {
descriptorsAfter[i].setPreferredSize(new Dimension(14, -1));
descriptors[i].setPreferredSize(new Dimension(14, -1));
valuePanel.add(descriptors[i]);
valuePanel.add(valueFields[i]);
valuePanel.add(descriptorsAfter[i]);
if (i < descriptorsAfter.length - 1) {
valuePanel.add(Box.createHorizontalStrut(2));
}
}
result.add(valuePanel, BorderLayout.WEST);
final JPanel hexPanel = new JPanel();
hexPanel.setLayout(new BoxLayout(hexPanel, BoxLayout.X_AXIS));
hexPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
hexPanel.add(formatBox);
hexPanel.add(Box.createHorizontalStrut(2));
hexPanel.add(new JLabel("#"));
hexPanel.add(textHex);
result.add(hexPanel, BorderLayout.EAST);
return result;
}
protected Icon getPipetteIcon() {
return UIManager.getIcon("ColorChooser.pipette.icon");
}
protected Icon getPipetteRolloverIcon() {
return UIManager.getIcon("ColorChooser.pipetteRollover.icon");
}
@NotNull
private JFormattedTextField createColorField(final boolean hex) {
JFormattedTextField field = new JFormattedTextField(0);
field.setColumns(hex ? 8 : 4);
if (!hex) {
field.addPropertyChangeListener(e -> {
if ("value".equals(e.getPropertyName())) {
updatePreviewFromTextFields();
}
});
} else {
field.addPropertyChangeListener(e -> {
if ("value".equals(e.getPropertyName())) {
if (isChanging) return;
var hexStr = e.getNewValue().toString();
var alpha = isColorTransparencySelectionEnabled()
? Integer.valueOf(hexStr.substring(6, 8), 16) : 255;
var c = new Color(
Integer.valueOf(hexStr.substring(0, 2), 16),
Integer.valueOf(hexStr.substring(2, 4), 16),
Integer.valueOf(hexStr.substring(4, 6), 16),
alpha);
colorWheelPanel.setColor(c, textHex);
}
});
}
field.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT);
return field;
}
protected DarkColorModel getDarkColorModel() {
return (DarkColorModel) formatBox.getSelectedItem();
}
@Override
public void updateChooser() {
if (isChanging) return;
Color color = getColorFromModel();
if (color != null) {
colorWheelPanel.setColor(color, this);
}
}
@Override
protected void buildChooser() {
}
@Override
public String getDisplayName() {
return "Test";
}
@Override
public int getMnemonic() {
return 0;
}
@Override
public int getDisplayedMnemonicIndex() {
return 0;
}
@Override
public boolean isColorTransparencySelectionEnabled() {
return colorWheelPanel.isColorTransparencySelectionEnabled();
}
@Override
public void setColorTransparencySelectionEnabled(final boolean b) {
boolean oldValue = isColorTransparencySelectionEnabled();
if (b != oldValue) {
var color = getColorFromModel();
color = new Color(color.getRed(), color.getBlue(), color.getGreen());
var model = getColorSelectionModel();
if (model != null) {
model.setSelectedColor(color);
}
currentColor = color;
hexFormatter.setTransparencyEnabled(b);
applyColorToHEX(getColorFromModel());
colorWheelPanel.setColorTransparencySelectionEnabled(b);
firePropertyChange(TRANSPARENCY_ENABLED_PROPERTY,
oldValue, b);
}
}
@Override
public Icon getSmallDisplayIcon() {
return null;
}
@Override
public Icon getLargeDisplayIcon() {
return null;
}
@Override
protected Color getColorFromModel() {
var c = super.getColorFromModel();
return c == null ? currentColor : c;
}
@Override
public void colorChanged(final Color color, final Object source) {
isChanging = true;
if (color != null && !color.equals(currentColor)) {
var newColor = !isColorTransparencySelectionEnabled()
? new Color(color.getRed(), color.getBlue(), color.getGreen()) : color;
var model = getColorSelectionModel();
if (model != null) {
model.setSelectedColor(newColor);
}
currentColor = newColor;
previewComponent.setColor(newColor);
if (!(source instanceof JFormattedTextField)) {
applyColorToFields(newColor);
}
if (source != textHex) {
applyColorToHEX(newColor);
}
}
isChanging = false;
}
private void applyColorToHEX(@NotNull final Color c) {
boolean transparencyEnabled = isColorTransparencySelectionEnabled();
if (transparencyEnabled) {
textHex.setText(String.format("%02X%02X%02X%02X", c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()));
} else {
textHex.setText(String.format("%02X%02X%02X", c.getRed(), c.getGreen(), c.getBlue()));
}
}
private void applyColorToFields(final Color color) {
var model = getDarkColorModel();
isChanging = true;
int[] values = model.getValuesFromColor(color);
for (int i = 0; i < values.length; i++) {
valueFields[i].setValue(values[i]);
}
isChanging = false;
}
private void updatePreviewFromTextFields() {
if (!doneInit || isChanging) return;
isChanging = true;
int[] values = new int[valueFields.length];
for (int i = 0; i < valueFields.length; i++) {
values[i] = (((Integer) valueFields[i].getValue()));
}
var color = getDarkColorModel().getColorFromValues(values);
if (isColorTransparencySelectionEnabled()) {
color = ColorUtil.toAlpha(color, getColorFromModel().getAlpha());
}
colorWheelPanel.setColor(color, valueFields[0]);
isChanging = false;
}
private static final class ColorPreviewComponent extends JComponent {
private Color myColor;
private ColorPreviewComponent() {
setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2));
}
@NotNull
@Contract(value = " -> new", pure = true)
@Override
public Dimension getPreferredSize() {
return new Dimension(100, 32);
}
public void setColor(final Color c) {
myColor = c;
repaint();
}
@Override
protected void paintComponent(@NotNull final Graphics g) {
final Insets i = getInsets();
final Rectangle r = getBounds();
final int width = r.width - i.left - i.right;
final int height = r.height - i.top - i.bottom;
g.setColor(Color.WHITE);
g.fillRect(i.left, i.top, width, height);
g.setColor(myColor);
g.fillRect(i.left + 1, i.top + 1, width - 2, height - 2);
g.setColor(UIManager.getColor("ColorChooser.previewBorderColor"));
g.fillRect(i.left, i.top, width, 1);
g.fillRect(i.left, i.top, 1, height);
g.fillRect(i.left + width - 1, i.top, 1, height);
g.fillRect(i.left, i.top + height - 1, width, 1);
}
}
}

73
src/main/java/com/weis/darklaf/ui/colorchooser/DarkColorChooserUI.java

@ -0,0 +1,73 @@
package com.weis.darklaf.ui.colorchooser;
import com.weis.darklaf.color.DarkColorModel;
import com.weis.darklaf.color.DarkColorModelCMYK;
import com.weis.darklaf.color.DarkColorModelHSL;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.colorchooser.AbstractColorChooserPanel;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicColorChooserUI;
import java.awt.*;
import java.beans.PropertyChangeListener;
public class DarkColorChooserUI extends BasicColorChooserUI {
private final PropertyChangeListener propertyChangeListener = e -> {
if ("ancestor".equals(e.getPropertyName())) {
var pane = (JComponent) e.getNewValue();
if (pane != null) {
pane = (JComponent) pane.getRootPane().getContentPane();
} else {
return;
}
var children = pane.getComponents();
if (children.length >= 2 && children[1] instanceof JComponent) {
var layout = ((JComponent) children[1]).getLayout();
if (layout instanceof FlowLayout) {
((FlowLayout) layout).setAlignment(FlowLayout.TRAILING);
}
children[1].doLayout();
}
}
};
public DarkColorChooserUI() {
var c = new Color(25, 60, 2);
}
@NotNull
@Contract("_ -> new")
public static ComponentUI createUI(final JComponent c) {
return new DarkColorChooserUI();
}
@Override
protected AbstractColorChooserPanel[] createDefaultChoosers() {
return new AbstractColorChooserPanel[]{
new DarkColorChooserPanel(new DarkColorModel(),
new DarkColorModelHSL(),
// new DarkColorModelHSB(),
new DarkColorModelCMYK())};
}
@Override
protected void installListeners() {
super.installListeners();
chooser.addPropertyChangeListener(propertyChangeListener);
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
chooser.removePropertyChangeListener(propertyChangeListener);
}
@Override
public void installUI(final JComponent c) {
super.installUI(c);
chooser.setPreviewPanel(new DarkPreviewPanel());
}
}

182
src/main/java/com/weis/darklaf/ui/colorchooser/DarkPreviewPanel.java

@ -0,0 +1,182 @@
package com.weis.darklaf.ui.colorchooser;
import org.jetbrains.annotations.NotNull;
import sun.swing.SwingUtilities2;
import javax.swing.*;
import java.awt.*;
public class DarkPreviewPanel extends JPanel {
private static final int SQUARE_SIZE = 28;
private static final int SQUARE_GAP = 4;
private static final int INNER_GAP = 4;
private static final int SWATCH_WIDTH = 75;
private static final int TEXT_GAP = 5;
private String sampleText;
private Color oldColor = null;
private JColorChooser getColorChooser() {
return (JColorChooser) SwingUtilities.getAncestorOfClass(JColorChooser.class, this);
}
public Dimension getPreferredSize() {
JComponent host = getColorChooser();
if (host == null) {
host = this;
}
FontMetrics fm = host.getFontMetrics(getFont());
int ascent = fm.getAscent();
int height = fm.getHeight();
int width = SwingUtilities2.stringWidth(host, fm, getSampleText());
int y = height * 3 + TEXT_GAP * 3;
int x = SQUARE_SIZE * 3 + SQUARE_GAP * 2 + SWATCH_WIDTH + width + TEXT_GAP * 3;
return new Dimension(x, y);
}
public void paintComponent(final Graphics g) {
if (oldColor == null) oldColor = getForeground();
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
if (this.getComponentOrientation().isLeftToRight()) {
int squareWidth = paintSquares(g, 0);
int textWidth = paintText(g, squareWidth);
paintSwatch(g, squareWidth + textWidth);
} else {
int swatchWidth = paintSwatch(g, 0);
int textWidth = paintText(g, swatchWidth);
paintSquares(g, swatchWidth + textWidth);
}
}
private int paintSwatch(@NotNull final Graphics g, final int offsetX) {
g.setColor(oldColor);
g.fillRect(offsetX, 0, SWATCH_WIDTH, SQUARE_SIZE + SQUARE_GAP / 2);
g.setColor(getForeground());
g.fillRect(offsetX, SQUARE_SIZE + SQUARE_GAP / 2, SWATCH_WIDTH, SQUARE_SIZE + SQUARE_GAP / 2);
return (offsetX + SWATCH_WIDTH);
}
private int paintText(@NotNull final Graphics g, final int offsetX) {
g.setFont(getFont());
JComponent host = getColorChooser();
if (host == null) {
host = this;
}
FontMetrics fm = SwingUtilities2.getFontMetrics(host, g);
int ascent = fm.getAscent();
int height = fm.getHeight();
int width = SwingUtilities2.stringWidth(host, fm, getSampleText());
int textXOffset = offsetX + TEXT_GAP;
Color color = getForeground();
g.setColor(color);
SwingUtilities2.drawString(host, g, getSampleText(), textXOffset + (TEXT_GAP / 2), ascent);
g.fillRect(textXOffset, (height) + TEXT_GAP, width + (TEXT_GAP), height + 2);
g.setColor(Color.black);
SwingUtilities2.drawString(host, g, getSampleText(), textXOffset + (TEXT_GAP / 2),
height + ascent + TEXT_GAP + 2);
g.setColor(Color.white);
g.fillRect(textXOffset, (height + TEXT_GAP) * 2, width + (TEXT_GAP), height + 2);
g.setColor(color);
SwingUtilities2.drawString(host, g, getSampleText(), textXOffset + (TEXT_GAP / 2),
((height + TEXT_GAP) * 2) + ascent + 2);
return width + TEXT_GAP * 3;
}
private int paintSquares(@NotNull final Graphics g, final int offsetX) {
Color color = getForeground();
g.setColor(Color.white);
g.fillRect(offsetX, 0, SQUARE_SIZE, SQUARE_SIZE);
g.setColor(color);
g.fillRect(offsetX + INNER_GAP,
INNER_GAP,
SQUARE_SIZE - (INNER_GAP * 2),
SQUARE_SIZE - (INNER_GAP * 2));
g.setColor(Color.white);
g.fillRect(offsetX + INNER_GAP * 2,
INNER_GAP * 2,
SQUARE_SIZE - (INNER_GAP * 4),
SQUARE_SIZE - (INNER_GAP * 4));
g.setColor(color);
g.fillRect(offsetX, SQUARE_SIZE + SQUARE_GAP, SQUARE_SIZE, SQUARE_SIZE);
g.translate(SQUARE_SIZE + SQUARE_GAP, 0);
g.setColor(Color.black);
g.fillRect(offsetX, 0, SQUARE_SIZE, SQUARE_SIZE);
g.setColor(color);
g.fillRect(offsetX + INNER_GAP,
INNER_GAP,
SQUARE_SIZE - (INNER_GAP * 2),
SQUARE_SIZE - (INNER_GAP * 2));
g.setColor(Color.white);
g.fillRect(offsetX + INNER_GAP * 2,
INNER_GAP * 2,
SQUARE_SIZE - (INNER_GAP * 4),
SQUARE_SIZE - (INNER_GAP * 4));
g.translate(-(SQUARE_SIZE + SQUARE_GAP), 0);
g.translate(SQUARE_SIZE + SQUARE_GAP, SQUARE_SIZE + SQUARE_GAP);
g.setColor(Color.white);
g.fillRect(offsetX, 0, SQUARE_SIZE, SQUARE_SIZE);
g.setColor(color);
g.fillRect(offsetX + INNER_GAP,
INNER_GAP,
SQUARE_SIZE - (INNER_GAP * 2),
SQUARE_SIZE - (INNER_GAP * 2));
g.translate(-(SQUARE_SIZE + SQUARE_GAP), -(SQUARE_SIZE + SQUARE_GAP));
g.translate((SQUARE_SIZE + SQUARE_GAP) * 2, 0);
g.setColor(Color.white);
g.fillRect(offsetX, 0, SQUARE_SIZE, SQUARE_SIZE);
g.setColor(color);
g.fillRect(offsetX + INNER_GAP,
INNER_GAP,
SQUARE_SIZE - (INNER_GAP * 2),
SQUARE_SIZE - (INNER_GAP * 2));
g.setColor(Color.black);
g.fillRect(offsetX + INNER_GAP * 2,
INNER_GAP * 2,
SQUARE_SIZE - (INNER_GAP * 4),
SQUARE_SIZE - (INNER_GAP * 4));
g.translate(-((SQUARE_SIZE + SQUARE_GAP) * 2), 0);
g.translate((SQUARE_SIZE + SQUARE_GAP) * 2, (SQUARE_SIZE + SQUARE_GAP));
g.setColor(Color.black);
g.fillRect(offsetX, 0, SQUARE_SIZE, SQUARE_SIZE);
g.setColor(color);
g.fillRect(offsetX + INNER_GAP,
INNER_GAP,
SQUARE_SIZE - (INNER_GAP * 2),
SQUARE_SIZE - (INNER_GAP * 2));
g.translate(-((SQUARE_SIZE + SQUARE_GAP) * 2), -(SQUARE_SIZE + SQUARE_GAP));
return (SQUARE_SIZE * 3 + SQUARE_GAP * 2);
}
private String getSampleText() {
if (this.sampleText == null) {
this.sampleText = UIManager.getString("ColorChooser.sampleText", getLocale());
}
return this.sampleText;
}
}

31
src/main/java/com/weis/darklaf/ui/colorchooser/DarkSwatchesChooserPanel.java

@ -0,0 +1,31 @@
package com.weis.darklaf.ui.colorchooser;
import javax.swing.*;
import javax.swing.colorchooser.AbstractColorChooserPanel;
public class DarkSwatchesChooserPanel extends AbstractColorChooserPanel {
@Override
public void updateChooser() {
}
@Override
protected void buildChooser() {
}
@Override
public String getDisplayName() {
return null;
}
@Override
public Icon getSmallDisplayIcon() {
return null;
}
@Override
public Icon getLargeDisplayIcon() {
return null;
}
}

281
src/main/java/com/weis/darklaf/ui/colorchooser/SlideComponent.java

@ -0,0 +1,281 @@
package com.weis.darklaf.ui.colorchooser;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
/**
* @author Alexey Pegov
* @author Konstantin Bulenkov
*/
class SlideComponent extends JComponent {
private static final int OFFSET = 11;
private final boolean myVertical;
private final String myTitle;
private final List<Consumer<Integer>> myListeners = new ArrayList<>();
//Todo.
// private LightweightHint myTooltipHint;
private final JLabel myLabel = new JLabel();
private int myPointerValue = 0;
private int myValue = 0;
private Unit myUnit = Unit.LEVEL;
SlideComponent(final String title, final boolean vertical) {
myTitle = title;
myVertical = vertical;
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseDragged(final MouseEvent e) {
processMouse(e);
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent e) {
processMouse(e);
}
@Override
public void mouseEntered(final MouseEvent e) {
updateBalloonText();
}
@Override
public void mouseMoved(final MouseEvent e) {
updateBalloonText();
}
@Override
public void mouseExited(final MouseEvent e) {
//Todo
// if (myTooltipHint != null) {
// myTooltipHint.hide();
// myTooltipHint = null;
// }
}
});
addMouseWheelListener(event -> {
int units = event.getUnitsToScroll();
if (units == 0) return;
int pointerValue = myPointerValue + units;
pointerValue = Math.max(pointerValue, OFFSET);
int size = myVertical ? getHeight() : getWidth();
pointerValue = Math.min(pointerValue, (size - 12));
myPointerValue = pointerValue;
myValue = pointerValueToValue(myPointerValue);
repaint();
fireValueChanged();
});
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(final ComponentEvent e) {
setValue(getValue());
fireValueChanged();
repaint();
}
});
}
private static void drawKnob(@NotNull final Graphics2D g2d, int x, int y, final boolean vertical) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//Todo Colors
if (vertical) {
y -= 6;
Polygon arrowShadow = new Polygon();
arrowShadow.addPoint(x - 5, y + 1);
arrowShadow.addPoint(x + 7, y + 7);
arrowShadow.addPoint(x - 5, y + 13);
g2d.setColor(new Color(0, 0, 0, 70));
g2d.fill(arrowShadow);
Polygon arrowHead = new Polygon();
arrowHead.addPoint(x - 6, y);
arrowHead.addPoint(x + 6, y + 6);
arrowHead.addPoint(x - 6, y + 12);
g2d.setColor(UIManager.getColor("ColorChooser.sliderKnobColor"));
g2d.fill(arrowHead);
} else {
x -= 6;
Polygon arrowShadow = new Polygon();
arrowShadow.addPoint(x + 1, y - 5);
arrowShadow.addPoint(x + 13, y - 5);
arrowShadow.addPoint(x + 7, y + 7);
g2d.setColor(new Color(0, 0, 0, 70));
g2d.fill(arrowShadow);
Polygon arrowHead = new Polygon();
arrowHead.addPoint(x, y - 6);
arrowHead.addPoint(x + 12, y - 6);
arrowHead.addPoint(x + 6, y + 6);
g2d.setColor(UIManager.getColor("ColorChooser.sliderKnobColor"));
g2d.fill(arrowHead);
}
}
void setUnits(final Unit unit) {
myUnit = unit;
}
private void updateBalloonText() {
final Point point = myVertical ? new Point(0, myPointerValue) : new Point(myPointerValue, 0);
myLabel.setText(myTitle + ": " + Unit.formatValue(myValue, myUnit));
//Todo
// if (myTooltipHint == null) {
// myTooltipHint = new LightweightHint(myLabel);
// myTooltipHint.setCancelOnClickOutside(false);
// myTooltipHint.setCancelOnOtherWindowOpen(false);
//
// final HintHint hint = new HintHint(this, point)
// .setPreferredPosition(myVertical ? Balloon.Position.atLeft : Balloon
// .Position.above)
// .setBorderColor(Color.BLACK)
// .setAwtTooltip(true)
// .setFont(UIUtil.getLabelFont().deriveFont(Font.BOLD))
// .setTextBg(HintUtil.getInformationColor())
// .setShowImmediately(true);
//
// final Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
// myTooltipHint.show(this, point.x, point.y, owner instanceof JComponent ? (JComponent)owner : null, hint);
// }
// else {
// myTooltipHint.setLocation(new RelativePoint(this, point));
// }
}
@Override
protected void processMouseMotionEvent(final MouseEvent e) {
super.processMouseMotionEvent(e);
updateBalloonText();
}
private void processMouse(final MouseEvent e) {
int pointerValue = myVertical ? e.getY() : e.getX();
pointerValue = Math.max(pointerValue, OFFSET);
int size = myVertical ? getHeight() : getWidth();
pointerValue = Math.min(pointerValue, (size - 12));
myPointerValue = pointerValue;
myValue = pointerValueToValue(myPointerValue);
repaint();
fireValueChanged();
}
public void addListener(final Consumer<Integer> listener) {
myListeners.add(listener);
}
private void fireValueChanged() {
for (Consumer<Integer> listener : myListeners) {
listener.accept(myValue);
}
}
public int getValue() {
return myValue;
}
// 0 - 255
public void setValue(final int value) {
myPointerValue = valueToPointerValue(value);
myValue = value;
}
private int pointerValueToValue(int pointerValue) {
pointerValue -= OFFSET;
final int size = myVertical ? getHeight() : getWidth();
float proportion = (size - 23) / 255f;
return Math.round((pointerValue / proportion));
}
private int valueToPointerValue(final int value) {
final int size = myVertical ? getHeight() : getWidth();
float proportion = (size - 23) / 255f;
return OFFSET + (int) (value * proportion);
}
@Override
public Dimension getPreferredSize() {
return myVertical ? new Dimension(22, 100)
: new Dimension(100, 22);
}
@Override
public Dimension getMinimumSize() {
return myVertical ? new Dimension(22, 50)
: new Dimension(50, 22);
}
@Override
public final void setToolTipText(final String text) {
//disable tooltips
}
@Override
protected void paintComponent(final Graphics g) {
final Graphics2D g2d = (Graphics2D) g;
if (myVertical) {
g2d.setPaint(new GradientPaint(0f, 0f, Color.WHITE, 0f, getHeight(), Color.BLACK));
g.fillRect(7, 10, 12, getHeight() - 20);
g.setColor(UIManager.getColor("ColorChooser.sliderBorderColor"));
g.fillRect(7, 10, 12, 1);
g.fillRect(7, 10, 1, getHeight() - 20);
g.fillRect(7 + 12 - 1, 10, 1, getHeight() - 20);
g.fillRect(7, 10 + getHeight() - 20 - 1, 12, 1);
} else {
g2d.setPaint(new GradientPaint(0f, 0f, Color.WHITE, getWidth(), 0f, Color.BLACK));
g.fillRect(10, 7, getWidth() - 20, 12);
g.setColor(UIManager.getColor("ColorChooser.sliderBorderColor"));
g.fillRect(10, 7, 1, 12);
g.fillRect(10, 7, getWidth() - 20, 1);
g.fillRect(10, 7 + 12 - 1, getWidth() - 20, 1);
g.fillRect(10 + getWidth() - 20 - 1, 7, 1, 12);
}
drawKnob(g2d, myVertical ? 7 : myPointerValue, myVertical ? myPointerValue : 7, myVertical);
}
enum Unit {
PERCENT,
LEVEL;
private static final float PERCENT_MAX_VALUE = 100f;
private static final float LEVEL_MAX_VALUE = 255f;
@Contract(pure = true)
private static float getMaxValue(final Unit unit) {
return LEVEL.equals(unit) ? LEVEL_MAX_VALUE : PERCENT_MAX_VALUE;
}
private static String formatValue(final int value, final Unit unit) {
return String.format("%d%s", (int) (getMaxValue(unit) / LEVEL_MAX_VALUE * value),
unit.equals(PERCENT) ? "%" : "");
}
}
}

16
src/main/java/com/weis/darklaf/ui/rootpane/DarkRootPaneUI.java

@ -77,11 +77,6 @@ public class DarkRootPaneUI extends BasicRootPaneUI {
public void installUI(final JComponent c) {
super.installUI(c);
rootPane = (JRootPane) c;
int style = rootPane.getWindowDecorationStyle();
if (style != JRootPane.NONE) {
installClientDecorations(rootPane);
}
}
@Override
@ -102,7 +97,6 @@ public class DarkRootPaneUI extends BasicRootPaneUI {
LookAndFeel.uninstallBorder(root);
} else {
LookAndFeel.uninstallBorder(root);
// LookAndFeel.installBorder(root, "RootPane.border");
}
}
@ -261,6 +255,10 @@ public class DarkRootPaneUI extends BasicRootPaneUI {
currWindow.addComponentListener(windowComponentListener);
}
if (currWindow != window) {
installClientDecorations(rootPane);
}
window = currWindow;
}
currentWindow = currWindow;
@ -313,7 +311,11 @@ public class DarkRootPaneUI extends BasicRootPaneUI {
installWindowListeners(root, root.getParent());
installLayout(root);
if (window != null) {
((Frame) window).setUndecorated(false);
if (window instanceof Frame) {
((Frame) window).setUndecorated(root.getWindowDecorationStyle() == JRootPane.NONE);
} else if (window instanceof Dialog) {
((Dialog) window).setUndecorated(root.getWindowDecorationStyle() == JRootPane.NONE);
}
root.revalidate();
root.repaint();
}

11
src/main/java/com/weis/darklaf/ui/rootpane/DarkTitlePane.java

@ -216,11 +216,11 @@ public class DarkTitlePane extends JComponent {
int decorationStyle = getWindowDecorationStyle();
titleLabel = new JLabel();
add(titleLabel);
if (decorationStyle == JRootPane.FRAME) {
createIcons();
createActions();
createButtons();
createIcons();
createActions();
createButtons();
if (decorationStyle == JRootPane.FRAME) {
windowIconButton = createWindowIcon();
add(windowIconButton);
add(minimizeButton);
@ -233,8 +233,6 @@ public class DarkTitlePane extends JComponent {
decorationStyle == JRootPane.FILE_CHOOSER_DIALOG ||
decorationStyle == JRootPane.QUESTION_DIALOG ||
decorationStyle == JRootPane.WARNING_DIALOG) {
createActions();
createButtons();
add(closeButton);
}
}
@ -409,7 +407,6 @@ public class DarkTitlePane extends JComponent {
maximizeIcon.setActive(active);
restoreIcon.setActive(active);
}
getRootPane().repaint();
}

1
src/main/java/com/weis/darklaf/ui/table/DarkColorTableCellRendererEditor.java

@ -39,7 +39,6 @@ public class DarkColorTableCellRendererEditor extends AbstractCellEditor impleme
if (color != null) {
savedColor = color;
label.setBackground(color);
System.out.println(color);
}
}

252
src/main/java/com/weis/darklaf/util/ColorPipetteBase.java

@ -0,0 +1,252 @@
package com.weis.darklaf.util;
import com.bulenkov.iconloader.util.SystemInfo;
import com.weis.darklaf.ui.colorchooser.ColorListener;
import com.weis.darklaf.ui.colorchooser.ColorPipette;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.plaf.basic.BasicRootPaneUI;
import java.awt.*;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
public abstract class ColorPipetteBase implements ColorPipette, AWTEventListener {
protected final JComponent parent;
protected final Robot robot;
private final ColorListener colorListener;
private Runnable closeAction;
private JWindow pickerWindow;
private boolean keyDown;
private int downKeyCode;
private Color currentColor;
private Color initialColor;
public ColorPipetteBase(@NotNull final JComponent parent, @NotNull final ColorListener colorListener) {
this.parent = parent;
this.colorListener = colorListener;
robot = createRobot();
}
@Nullable
private static Robot createRobot() {
try {
return new Robot();
} catch (AWTException e) {
return null;
}
}
public boolean isKeyDown() {
return keyDown;
}
public int getPressedKeyCode() {
return downKeyCode;
}
public void setCloseAction(final Runnable closeAction) {
this.closeAction = closeAction;
}
@Override
public void pickAndClose() {
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
Color pixelColor = getPixelColor(pointerInfo.getLocation());
cancelPipette();
notifyListener(pixelColor);
setInitialColor(pixelColor);
}
protected Color getPixelColor(@NotNull final Point location) {
return robot.getPixelColor(location.x, location.y);
}
@Nullable
protected Color getInitialColor() {
return initialColor;
}
@Override
public void setInitialColor(@Nullable final Color initialColor) {
this.initialColor = initialColor;
setColor(initialColor);
}
@Nullable
@Override
public Color getColor() {
return currentColor;
}
protected void setColor(@Nullable final Color color) {
currentColor = color;
}
@Override
public Window show() {
Window picker = getOrCreatePickerWindow();
Toolkit.getDefaultToolkit().addAWTEventListener(this,
AWTEvent.MOUSE_MOTION_EVENT_MASK
| AWTEvent.MOUSE_EVENT_MASK
| AWTEvent.KEY_EVENT_MASK);
updateLocation();
picker.setVisible(true);
return picker;
}
@Nullable
protected Point updateLocation() {
PointerInfo pointerInfo = MouseInfo.getPointerInfo();
if (pointerInfo == null) return null;
Point mouseLocation = pointerInfo.getLocation();
Window pickerWindow = getPickerWindow();
if (pickerWindow != null && mouseLocation != null) {
pickerWindow.setLocation(adjustPickerLocation(mouseLocation, pickerWindow));
}
return mouseLocation;
}
protected Point adjustPickerLocation(@NotNull final Point mouseLocation, @NotNull final Window pickerWindow) {
return new Point(mouseLocation.x - pickerWindow.getWidth() / 2,
mouseLocation.y - pickerWindow.getHeight() / 2);
}
@Nullable
protected Window getPickerWindow() {
return pickerWindow;
}
@NotNull
protected Window getOrCreatePickerWindow() {
if (pickerWindow == null) {
Window owner = SwingUtilities.getWindowAncestor(parent);
pickerWindow = createPickerWindow(owner);
pickerWindow.setName("DarkLafPickerDialog");
JRootPane rootPane = pickerWindow.getRootPane();
rootPane.putClientProperty("Window.shadow", Boolean.FALSE);
}
return pickerWindow;
}
@Override
public void eventDispatched(@NotNull final AWTEvent event) {
if (pickerWindow == null || !pickerWindow.isVisible()) return;
switch (event.getID()) {
case MouseEvent.MOUSE_PRESSED:
((MouseEvent) event).consume();
pickAndClose();
break;
case MouseEvent.MOUSE_CLICKED:
((MouseEvent) event).consume();
break;
case KeyEvent.KEY_PRESSED:
downKeyCode = ((KeyEvent) event).getKeyCode();
switch (downKeyCode) {
case KeyEvent.VK_ESCAPE:
cancelPipette();
break;
case KeyEvent.VK_ENTER:
pickAndClose();
break;
default:
break;
}
if (!keyDown) {
keyDown = true;
updatePipette(true);
}
break;
case KeyEvent.KEY_RELEASED:
keyDown = false;
var picker = getPickerWindow();
if (picker != null) {
picker.repaint();
}
break;
default:
break;
}
}
protected abstract void updatePipette(final boolean force);
protected void notifyListener(@NotNull final Color c) {
colorListener.colorChanged(c, this);
}
@Override
public boolean imageUpdate(final Image image, final int i, final int i1,
final int i2, final int i3, final int i4) {
return false;
}
@Override
public void cancelPipette() {
Window pickerWindow = getPickerWindow();
if (pickerWindow != null) {
pickerWindow.setVisible(false);
}
Color initialColor = getInitialColor();
if (initialColor != null) {
notifyListener(initialColor);
}
if (closeAction != null) {
closeAction.run();
}
Toolkit.getDefaultToolkit().removeAWTEventListener(this);
if (SystemInfo.isWindows) {
WindowsFrameUtil.User32dll.INSTANCE.ShowCursor(true);
}
}
@Override
public void dispose() {
pickerWindow.dispose();
pickerWindow = null;
setInitialColor(null);
setColor(null);
}
protected JWindow createPickerWindow(final Window parent) {
return new PickerWindow(parent);
}
protected static class PickerWindow extends JWindow {
protected PickerWindow(final Window parent) {
super(parent);
setBackground(DarkUIUtil.TRANSPARENT_COLOR);
BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
Cursor blankCursor = Toolkit.getDefaultToolkit()
.createCustomCursor(cursorImg, new Point(), "BlankCursor");
setCursor(blankCursor);
}
@NotNull
@Override
public Cursor getCursor() {
return super.getCursor();
}
@Override
protected JRootPane createRootPane() {
return new JRootPane() {
@Override
public void updateUI() {
setUI(new BasicRootPaneUI());
}
@Override
public int getWindowDecorationStyle() {
return NONE;
}
};
}
}
}

59
src/main/java/com/weis/darklaf/util/ColorUtil.java

@ -0,0 +1,59 @@
package com.weis.darklaf.util;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
public final class ColorUtil {
@Contract(pure = true)
private ColorUtil() {
}
@Contract(pure = true)
private static int shift(final int colorComponent, final double d) {
int n = (int) ((double) colorComponent * d);
return n > 255 ? 255 : (Math.max(n, 0));
}
@NotNull
@Contract("_, _ -> new")
public static Color shift(@NotNull final Color c, final double d) {
return new Color(shift(c.getRed(), d), shift(c.getGreen(), d), shift(c.getBlue(), d), c.getAlpha());
}
@NotNull
@Contract("_, _ -> new")
public static Color toAlpha(final Color color, final int a) {
Color c = color != null ? color : Color.black;
return new Color(c.getRed(), c.getGreen(), c.getBlue(), a);
}
@NotNull
public static Color fromHex(@NotNull String str) {
if (str.startsWith("#")) {
str = str.substring(1);
}
if (str.length() == 3) {
return new Color(17 * Integer.valueOf(String.valueOf(str.charAt(0)), 16),
17 * Integer.valueOf(String.valueOf(str.charAt(1)), 16),
17 * Integer.valueOf(String.valueOf(str.charAt(2)), 16));
} else if (str.length() == 6) {
return Color.decode("0x" + str);
} else {
throw new IllegalArgumentException("Should be String of 3 or 6 chars length.");
}
}
public static Color fromHex(final String str, final Color defaultValue) {
try {
return fromHex(str);
} catch (Exception var3) {
return defaultValue;
}
}
}

1
src/main/java/com/weis/darklaf/util/DarkUIUtil.java

@ -22,6 +22,7 @@ import java.awt.geom.RoundRectangle2D;
public final class DarkUIUtil {
public static final Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0);
public final static AlphaComposite ALPHA_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f);
public final static AlphaComposite ALPHA_COMPOSITE_2 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);
public final static AlphaComposite SHADOW_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f);

203
src/main/java/com/weis/darklaf/util/DefaultColorPipette.java

@ -0,0 +1,203 @@
package com.weis.darklaf.util;
import com.weis.darklaf.ui.colorchooser.ColorListener;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
public class DefaultColorPipette extends ColorPipetteBase {
private static final int SIZE = 36;
private static final int DIALOG_SIZE = 50;
private static final int MOUSE_OFF_X = 7;
private static final int MOUSE_OFF_Y = -7;
private final Rectangle captureRect = new Rectangle();
private final Point previousLocation = new Point();
private final Timer timer;
private Graphics2D zoomGraphics;
private BufferedImage zoomImage;
public DefaultColorPipette(@NotNull final JComponent parent, @NotNull final ColorListener colorListener) {
super(parent, colorListener);
timer = TimerUtil.createNamedTimer("DefaultColorPipette", 5, e -> updatePipette());
}
@Override
public Window show() {
Window picker = super.show();
timer.start();
return picker;
}
@Override
protected Point adjustPickerLocation(@NotNull final Point mouseLocation, @NotNull final Window pickerWindow) {
var p = super.adjustPickerLocation(mouseLocation, pickerWindow);
p.x += DIALOG_SIZE / 2 - MOUSE_OFF_X;
p.y -= DIALOG_SIZE / 2 + MOUSE_OFF_Y;
return p;
}
@Override
public boolean isAvailable() {
if (robot != null) {
robot.createScreenCapture(new Rectangle(0, 0, 1, 1));
return true;
}
return false;
}
@Override
protected Color getPixelColor(@NotNull final Point location) {
return super.getPixelColor(getHotSPot(location));
}
protected Point getHotSPot(@NotNull final Point location) {
location.x -= MOUSE_OFF_X - 2;
location.y -= MOUSE_OFF_Y + 2;
return location;
}
@Override
@NotNull
protected Window getOrCreatePickerWindow() {
Window pickerWindow = getPickerWindow();
if (pickerWindow == null) {
pickerWindow = super.getOrCreatePickerWindow();
pickerWindow.addMouseListener(new MouseAdapter() {
@Override
public void mouseExited(final MouseEvent event) {
updatePipette();
}
});
pickerWindow.addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(final MouseEvent e) {
updatePipette();
}
});
pickerWindow.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(final FocusEvent e) {
pickAndClose();
}
});
pickerWindow.setSize(DIALOG_SIZE, DIALOG_SIZE);
zoomImage = parent.getGraphicsConfiguration().createCompatibleImage(SIZE, SIZE, Transparency.TRANSLUCENT);
zoomGraphics = (Graphics2D) zoomImage.getGraphics();
zoomGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
}
return pickerWindow;
}
protected Icon getPipetteIcon() {
return UIManager.getIcon("ColorChooser.pipette.icon");
}
protected Color getPipetteBorderColor() {
return UIManager.getColor("ColorChooser.pipetteBorderColor");
}
protected void updatePipette() {
updatePipette(false);
}
protected void updatePipette(final boolean force) {
Window pickerWindow = getPickerWindow();
if (pickerWindow != null && pickerWindow.isShowing()) {
Point mouseLoc = updateLocation();
if (mouseLoc == null) return;
final Color c = getPixelColor(mouseLoc);
if (!c.equals(getColor()) || !mouseLoc.equals(previousLocation) || force) {
setColor(c);
previousLocation.setLocation(mouseLoc);
if (isKeyDown() && getPressedKeyCode() == KeyEvent.VK_SHIFT) {
var p = pickerWindow.getLocationOnScreen();
p.y += pickerWindow.getHeight() - 2;
p.x += 2;
captureRect.setBounds(p.x - 9, p.y - 9, 18, 18);
BufferedImage capture = robot.createScreenCapture(captureRect);
zoomGraphics.drawImage(capture, 0, 0, zoomImage.getWidth(), zoomImage.getHeight(), this);
}
pickerWindow.repaint();
notifyListener(c);
}
}
}
@Override
public void cancelPipette() {
timer.stop();
super.cancelPipette();
}
@Override
public void dispose() {
timer.stop();
super.dispose();
if (zoomGraphics != null) {
zoomGraphics.dispose();
}
zoomImage = null;
}
@Override
protected JWindow createPickerWindow(final Window parent) {
return new DefaultPickerWindow(parent, this);
}
protected static class DefaultPickerWindow extends PickerWindow {
private final DefaultColorPipette pipette;
protected DefaultPickerWindow(final Window parent, final DefaultColorPipette pipette) {
super(parent);
this.pipette = pipette;
}
@Override
public void paint(final Graphics g2) {
super.paint(g2);
GraphicsUtil.setupStrokePainting(g2);
Graphics2D g = (Graphics2D) g2;
//Draw region to be recognised as inside the window.
g.setColor(Color.WHITE);
var config = GraphicsUtil.paintWithAlpha(g, 0.005f);
var p = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(p, this);
g.fillRect(p.x - 5, p.y - 5, 10, 10);
config.restore();
var icon = pipette.getPipetteIcon();
if (pipette.isKeyDown() && pipette.getPressedKeyCode() == KeyEvent.VK_SHIFT) {
var oldCLip = g.getClip();
var circ = new Ellipse2D.Float(icon.getIconWidth() - 4, 2,
getWidth() - icon.getIconWidth() - 2 + 4,
getHeight() - 2 - icon.getIconHeight() + 4);
g.setClip(circ);
g.drawImage(pipette.zoomImage, icon.getIconWidth() - 4, 2, null);
g.setClip(oldCLip);
g.setColor(pipette.getPipetteBorderColor());
g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g.draw(circ);
}
icon.paintIcon(null, g, 0, getHeight() - icon.getIconHeight());
}
}
}

2
src/main/java/com/weis/darklaf/util/GraphicsContext.java

@ -31,7 +31,7 @@ public class GraphicsContext {
return this;
}
public Graphics2D getG() {
public Graphics2D getGraphics() {
return this.graphics2D;
}

2
src/main/java/com/weis/darklaf/util/GraphicsUtil.java

@ -78,7 +78,7 @@ public final class GraphicsUtil {
GraphicsContext config = new GraphicsContext(g);
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(3, alpha));
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
return config;
}

13
src/main/java/com/weis/darklaf/util/ImageUtil.java

@ -104,4 +104,17 @@ public final class ImageUtil {
g.dispose();
return new ImageIcon(img);
}
@NotNull
@Contract("_, _, _ -> new")
public static BufferedImage createImage(final int width, final int height, final int type) {
return new BufferedImage((int) (width * SCALE_X), (int) (height * SCALE_Y), type) {
@Override
public Graphics2D createGraphics() {
var g = super.createGraphics();
g.scale(SCALE_X, SCALE_Y);
return g;
}
};
}
}

57
src/main/java/com/weis/darklaf/util/StringUtil.java

@ -0,0 +1,57 @@
package com.weis.darklaf.util;
import com.intellij.openapi.util.text.StringUtilRt;
import org.jetbrains.annotations.Contract;
public final class StringUtil {
@Contract(pure = true)
private StringUtil() {
}
@Contract("null -> null; !null -> !null")
public static String toUpperCase(final String a) {
return a == null ? null : StringUtilRt.toUpperCase(a).toString();
}
@Contract("null -> fail")
public static CharSequence toUpperCase(final CharSequence s) {
if (s == null) {
throw new NullPointerException();
}
StringBuilder answer = null;
for (int i = 0; i < s.length(); ++i) {
char c = s.charAt(i);
char upCased = toUpperCase(c);
if (answer == null && upCased != c) {
answer = new StringBuilder(s.length());
answer.append(s.subSequence(0, i));
}
if (answer != null) {
answer.append(upCased);
}
}
return answer;
}
@Contract(pure = true)
public static char toUpperCase(final char a) {
if (a < 'a') {
return a;
} else {
return a <= 'z' ? (char) (a + -32) : Character.toUpperCase(a);
}
}
@Contract(pure = true)
public static char toLowerCase(final char a) {
if (a >= 'A' && (a < 'a' || a > 'z')) {
return a <= 'Z' ? (char) (a + 32) : Character.toLowerCase(a);
} else {
return a;
}
}
}

32
src/main/java/com/weis/darklaf/util/TimerUtil.java

@ -0,0 +1,32 @@
package com.weis.darklaf.util;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.event.ActionListener;
public final class TimerUtil {
@Contract("_, _, _ -> new")
@NotNull
public static Timer createNamedTimer(@NotNull final String name, final int delay,
@NotNull final ActionListener listener) {
return new Timer(delay, listener) {
@Override
public String toString() {
return name;
}
};
}
@Contract("_, _ -> new")
@NotNull
public static Timer createNamedTimer(@NotNull final String name, final int delay) {
return new Timer(delay, null) {
@Override
public String toString() {
return name;
}
};
}
}

2
src/main/java/com/weis/darklaf/util/WindowsFrameUtil.java

@ -60,6 +60,8 @@ public final class WindowsFrameUtil {
LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, WNDPROC wndProc) throws LastErrorException;
int ShowCursor(boolean bShow);
void DisableProcessWindowsGhosting() throws LastErrorException;
INT_PTR GetWindowDC(HWND hwnd);

15
src/main/resources/com/weis/darklaf/darcula.properties

@ -83,6 +83,9 @@ OptionPane.questionIcon = dialog/questionDialo
OptionPane.warningIcon = dialog/warningDialog.svg[aware](32,32)
OptionPane.errorIcon = dialog/errorDialog.svg[aware](32,32)
ColorChooser.pipette.icon = misc/pipette.svg[aware]
ColorChooser.pipetteRollover.icon = misc/pipette_rollover.svg[aware]
#Shadows Experimental
#Shadow.Top.icon = shadow/top.svg(4,7)
#Shadow.TopRight.icon = shadow/topRight.svg(18,14)
@ -422,4 +425,14 @@ InternalFrameTitlePane.darcula.selected.borderColorBottom = 313C4C
InternalFrameTitlePane.darcula.backgroundColor = 3A3D3F
InternalFrameTitlePane.darcula.selected.backgroundColor = 424D5F
InternalFrameTitlePane.darcula.buttonColor = 8B8B8B
InternalFrameTitlePane.darcula.hovered.buttonColor = A8A8A8
InternalFrameTitlePane.darcula.hovered.buttonColor = A8A8A8
#ColorChooser
ColorChooserUI = com.weis.darklaf.ui.colorchooser.DarkColorChooserUI
ColorChooser.previewBorderColor = 646464
ColorChooser.sliderBorderColor = 646464
ColorChooser.sliderKnobColor = 993300
ColorChooser.showPreviewPanelText = false
ColorChooser.colorWheelDropBackgroundColor = FFFFFF
ColorChooser.colorWheelDropBorderColor = 646464
ColorChooser.pipetteBorderColor = 646464

4
src/main/resources/com/weis/darklaf/icons/dark/misc/pipette.svg

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#AFB1B3"
d="M15.0494737,2.67473684 L13.3252632,0.950526316 C13.0378947,0.663157895 12.5736842,0.663157895 12.2863158,0.950526316 L9.98736842,3.24947368 L8.56526316,1.84210526 L7.52631579,2.88105263 L8.57263158,3.92736842 L2,10.5 L2,14 L5.5,14 L12.0726316,7.42736842 L13.1189474,8.47368421 L14.1578947,7.43473684 L12.7431579,6.02 L15.0421053,3.72105263 C15.3368421,3.42631579 15.3368421,2.96210526 15.0494737,2.67473684 Z M4.88842105,12.5263158 L3.47368421,11.1115789 L9.41263158,5.17263158 L10.8273684,6.58736842 L4.88842105,12.5263158 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 658 B

4
src/main/resources/com/weis/darklaf/icons/dark/misc/pipette_rollover.svg

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#C75450"
d="M15.0494737,2.67473684 L13.3252632,0.950526316 C13.0378947,0.663157895 12.5736842,0.663157895 12.2863158,0.950526316 L9.98736842,3.24947368 L8.56526316,1.84210526 L7.52631579,2.88105263 L8.57263158,3.92736842 L2,10.5 L2,14 L5.5,14 L12.0726316,7.42736842 L13.1189474,8.47368421 L14.1578947,7.43473684 L12.7431579,6.02 L15.0421053,3.72105263 C15.3368421,3.42631579 15.3368421,2.96210526 15.0494737,2.67473684 Z M4.88842105,12.5263158 L3.47368421,11.1115789 L9.41263158,5.17263158 L10.8273684,6.58736842 L4.88842105,12.5263158 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 658 B

4
src/main/resources/com/weis/darklaf/icons/light/misc/pipette.svg

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#6E6E6E"
d="M15.0494737,2.67474772 L13.3252632,0.950527524 C13.0378947,0.663157492 12.5736842,0.663157492 12.2863158,0.950527524 L9.98736842,3.24948779 L8.56526316,1.84211147 L7.52631579,2.88106467 L8.57263158,3.92738632 L2,10.5000548 L2,14.0000744 L5.5,14.0000744 L12.0726316,7.42740595 L13.1189474,8.47372761 L14.1578947,7.43477441 L12.7431579,6.02002964 L15.0421053,3.72106938 C15.3368421,3.42633088 15.3368421,2.96211775 15.0494737,2.67474772 Z M4.88842105,12.5263819 L3.47368421,11.1116371 L9.41263158,5.17265646 L10.8273684,6.58740124 L4.88842105,12.5263819 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 686 B

4
src/main/resources/com/weis/darklaf/icons/light/misc/pipette_rollover.svg

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#DB5860"
d="M15.0494737,2.67473684 L13.3252632,0.950526316 C13.0378947,0.663157895 12.5736842,0.663157895 12.2863158,0.950526316 L9.98736842,3.24947368 L8.56526316,1.84210526 L7.52631579,2.88105263 L8.57263158,3.92736842 L2,10.5 L2,14 L5.5,14 L12.0726316,7.42736842 L13.1189474,8.47368421 L14.1578947,7.43473684 L12.7431579,6.02 L15.0421053,3.72105263 C15.3368421,3.42631579 15.3368421,2.96210526 15.0494737,2.67473684 Z M4.88842105,12.5263158 L3.47368421,11.1115789 L9.41263158,5.17263158 L10.8273684,6.58736842 L4.88842105,12.5263158 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 658 B

14
src/test/java/ColorChooserDemo.java

@ -0,0 +1,14 @@
import com.weis.darklaf.LafManager;
import javax.swing.*;
import java.awt.*;
public final class ColorChooserDemo {
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
LafManager.loadLaf(LafManager.Theme.Dark);
JColorChooser.showDialog(null, "Color Chooser with transparency", Color.RED, true);
});
}
}

41
src/test/java/ColorModelTest.java

@ -0,0 +1,41 @@
import com.weis.darklaf.color.DarkColorModel;
import com.weis.darklaf.color.DarkColorModelCMYK;
import com.weis.darklaf.color.DarkColorModelHSB;
import com.weis.darklaf.color.DarkColorModelHSL;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.util.Arrays;
public class ColorModelTest {
public static void main(final String[] args) {
var color = new Color(10, 20, 30);
var m1 = new DarkColorModel();
var m2 = new DarkColorModelHSB();
var m3 = new DarkColorModelHSL();
var m4 = new DarkColorModelCMYK();
// test(m1);
test(m2);
// test(m3);
// test(m4);
}
private static void test(@NotNull final DarkColorModel model) {
System.out.println("Testing " + model.toString());
for (int r = model.getMinimum(0); r < model.getMaximum(0); r++) {
for (int g = model.getMinimum(1); g < model.getMaximum(1); g++) {
for (int b = model.getMinimum(2); b < model.getMaximum(2); b++) {
var c = new int[]{r, g, b};
var interm = model.getColorFromValues(c);
var nc = model.getValuesFromColor(interm);
if (!Arrays.equals(c, nc)) {
throw new RuntimeException(
"Not equals " + Arrays.toString(c) + " : " + interm + " : " + Arrays.toString(nc));
}
}
}
}
}
}
Loading…
Cancel
Save