mirror of https://github.com/weisJ/darklaf.git
weisj
5 years ago
37 changed files with 2870 additions and 18 deletions
@ -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]); |
||||||
|
} |
||||||
|
} |
@ -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]); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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]); |
||||||
|
} |
||||||
|
} |
@ -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]); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
package com.weis.darklaf.ui.colorchooser; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
|
||||||
|
public interface ColorListener { |
||||||
|
|
||||||
|
void colorChanged(final Color color, final Object source); |
||||||
|
} |
@ -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(); |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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()); |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
@ -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) ? "%" : ""); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 658 B |
After Width: | Height: | Size: 658 B |
After Width: | Height: | Size: 686 B |
After Width: | Height: | Size: 658 B |
@ -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); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -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…
Reference in new issue