View Javadoc
1   package edu.jiangxin.apktoolbox.convert.color;
2   
3   import edu.jiangxin.apktoolbox.convert.color.utils.ColorUtils;
4   import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
5   import edu.jiangxin.apktoolbox.utils.Constants;
6   
7   import javax.swing.*;
8   import javax.swing.event.ChangeEvent;
9   import javax.swing.event.ChangeListener;
10  import javax.swing.event.DocumentEvent;
11  import javax.swing.event.DocumentListener;
12  import java.awt.*;
13  import java.io.Serial;
14  
15  public class ColorConvertPanel extends EasyPanel {
16      @Serial
17      private static final long serialVersionUID = 1L;
18  
19      private Color color;
20  
21      private JTextField colorBoxTextField;
22  
23      private JSpinner redSpinner;
24  
25      private JSpinner greenInRgbSpinner;
26  
27      private JSpinner blueInRgbSpinner;
28  
29      private JTextField hexInRgbTextField;
30  
31      private JSpinner hueInHsbSpinner;
32  
33      private JSpinner saturationInHsbSpinner;
34  
35      private JSpinner brightnessInHsbSpinner;
36  
37      private JSpinner hueInHslSpinner;
38  
39      private JSpinner saturationInHslSpinner;
40  
41      private JSpinner lightnessInHslSpinner;
42  
43      private JSpinner cyanInCmykSpinner;
44  
45      private JSpinner magentaInCmykSpinner;
46  
47      private JSpinner yellowInCmykSpinner;
48  
49      private JSpinner blackInCmykSpinner;
50  
51      private JSpinner lInCielabSpinner;
52  
53      private JSpinner aInCielabSpinner;
54  
55      private JSpinner bInCielabSpinner;
56  
57      private JSpinner toolsetValueSpinner;
58  
59      private JSpinner toolsetPercentageSpinner;
60  
61      private JTextField toolsetHexTextField;
62  
63      private boolean isChangedByUser = true;
64  
65      public ColorConvertPanel() throws HeadlessException {
66          super();
67      }
68  
69      @Override
70      public void initUI() {
71          BoxLayout boxLayout = new BoxLayout(this, BoxLayout.Y_AXIS);
72          setLayout(boxLayout);
73  
74          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
75          createColorBoxPanel();
76  
77          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
78          createRgbPanel();
79  
80          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
81          createHsbPanel();
82  
83          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
84          createHslPanel();
85  
86          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
87          createCmykPanel();
88  
89          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
90          createCielabPanel();
91  
92          add(Box.createVerticalStrut(Constants.DEFAULT_Y_BORDER));
93          createToolSetPanel();
94      }
95  
96      public void createColorBoxPanel() {
97          JPanel colorBoxPanel = new JPanel();
98          add(colorBoxPanel);
99          colorBoxPanel.setLayout(new BorderLayout());
100         colorBoxPanel.setBorder(BorderFactory.createTitledBorder("Color Box"));
101 
102         JPanel xPanel = new JPanel();
103         colorBoxPanel.add(xPanel);
104         xPanel.setLayout(new BoxLayout(xPanel, BoxLayout.X_AXIS));
105 
106         colorBoxTextField = new JTextField();
107         colorBoxTextField.setEditable(false);
108         colorBoxTextField.setOpaque(false);
109 
110         xPanel.add(colorBoxTextField);
111     }
112 
113     private void createRgbPanel() {
114         JPanel rgbPanel = new JPanel();
115         add(rgbPanel);
116         rgbPanel.setLayout(new BorderLayout());
117         rgbPanel.setBorder(BorderFactory.createTitledBorder("RGB"));
118 
119         JPanel xPanel = new JPanel();
120         rgbPanel.add(xPanel);
121         xPanel.setLayout(new BoxLayout(xPanel, BoxLayout.X_AXIS));
122 
123         JLabel rebLabel = new JLabel("R(Red, [0-255])");
124         redSpinner = new JSpinner();
125         redSpinner.setModel(new SpinnerNumberModel(0, 0, 255, 1));
126         redSpinner.addChangeListener(new RgbChangeListener());
127 
128         JLabel greenLabel = new JLabel("G(Green, [0-255])");
129         greenInRgbSpinner = new JSpinner();
130         greenInRgbSpinner.setModel(new SpinnerNumberModel(0, 0, 255, 1));
131         greenInRgbSpinner.addChangeListener(new RgbChangeListener());
132 
133         JLabel blueLabel = new JLabel("B(Blue, [0-255])");
134         blueInRgbSpinner = new JSpinner();
135         blueInRgbSpinner.setModel(new SpinnerNumberModel(0, 0, 255, 1));
136         blueInRgbSpinner.addChangeListener(new RgbChangeListener());
137 
138         JLabel hexLabel = new JLabel("Hex");
139         hexInRgbTextField = new JTextField();
140         hexInRgbTextField.setToolTipText("0xFFFFFF格式常用在通用语言中(Java/C++等), #FFFFFF格式常用在标记语言中(XML/HTML等)");
141         hexInRgbTextField.setEditable(true);
142         hexInRgbTextField.getDocument().addDocumentListener(new HexDocumentListener());
143 
144         xPanel.add(rebLabel);
145         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
146         xPanel.add(redSpinner);
147         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
148         xPanel.add(greenLabel);
149         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
150         xPanel.add(greenInRgbSpinner);
151         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
152         xPanel.add(blueLabel);
153         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
154         xPanel.add(blueInRgbSpinner);
155         xPanel.add(Box.createHorizontalStrut(3 * Constants.DEFAULT_X_BORDER));
156         xPanel.add(hexLabel);
157         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
158         xPanel.add(hexInRgbTextField);
159     }
160 
161     private void createHsbPanel() {
162         JPanel hsbPanel = new JPanel();
163         add(hsbPanel);
164         hsbPanel.setLayout(new BorderLayout());
165         hsbPanel.setBorder(BorderFactory.createTitledBorder("HSB/HSV"));
166 
167         JPanel xPanel = new JPanel();
168         hsbPanel.add(xPanel);
169         xPanel.setLayout(new BoxLayout(xPanel, BoxLayout.X_AXIS));
170 
171         JLabel hueLabel = new JLabel("H(Hue, [0-360])");
172         hueInHsbSpinner = new JSpinner();
173         hueInHsbSpinner.setModel(new SpinnerNumberModel(0, 0, 360, 1));
174         hueInHsbSpinner.addChangeListener(new HsbChangeListener());
175 
176         JLabel saturationLabel = new JLabel("S(Saturation, [0-100])");
177         saturationInHsbSpinner = new JSpinner();
178         saturationInHsbSpinner.setModel(new SpinnerNumberModel(100, 0, 100, 1));
179         saturationInHsbSpinner.addChangeListener(new HsbChangeListener());
180 
181 
182         JLabel brightnessLabel = new JLabel("B/V(Brightness/Value, [0-100])");
183         brightnessInHsbSpinner = new JSpinner();
184         brightnessInHsbSpinner.setModel(new SpinnerNumberModel(100, 0, 100, 1));
185         brightnessInHsbSpinner.addChangeListener(new HsbChangeListener());
186 
187         xPanel.add(hueLabel);
188         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
189         xPanel.add(hueInHsbSpinner);
190         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
191         xPanel.add(saturationLabel);
192         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
193         xPanel.add(saturationInHsbSpinner);
194         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
195         xPanel.add(brightnessLabel);
196         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
197         xPanel.add(brightnessInHsbSpinner);
198     }
199 
200     private void createHslPanel() {
201         JPanel hslPanel = new JPanel();
202         add(hslPanel);
203         hslPanel.setLayout(new BorderLayout());
204         hslPanel.setBorder(BorderFactory.createTitledBorder("HSL"));
205 
206         JPanel xPanel = new JPanel();
207         hslPanel.add(xPanel);
208         xPanel.setLayout(new BoxLayout(xPanel, BoxLayout.X_AXIS));
209 
210         JLabel hueLabel = new JLabel("H(Hue, [0-360])");
211         hueInHslSpinner = new JSpinner();
212         hueInHslSpinner.setModel(new SpinnerNumberModel(0, 0, 360, 1));
213         hueInHslSpinner.addChangeListener(new HslChangeListener());
214 
215         JLabel saturationLabel = new JLabel("S(Saturation, [0-100])");
216         saturationInHslSpinner = new JSpinner();
217         saturationInHslSpinner.setModel(new SpinnerNumberModel(100, 0, 100, 1));
218         saturationInHslSpinner.addChangeListener(new HslChangeListener());
219 
220 
221         JLabel lightnessLabel = new JLabel("L(Lightness, [0-100])");
222         lightnessInHslSpinner = new JSpinner();
223         lightnessInHslSpinner.setModel(new SpinnerNumberModel(50, 0, 100, 1));
224         lightnessInHslSpinner.addChangeListener(new HslChangeListener());
225 
226         xPanel.add(hueLabel);
227         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
228         xPanel.add(hueInHslSpinner);
229         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
230         xPanel.add(saturationLabel);
231         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
232         xPanel.add(saturationInHslSpinner);
233         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
234         xPanel.add(lightnessLabel);
235         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
236         xPanel.add(lightnessInHslSpinner);
237     }
238 
239     private void createCmykPanel() {
240         JPanel cmykPanel = new JPanel();
241         add(cmykPanel);
242         cmykPanel.setLayout(new BorderLayout());
243         cmykPanel.setBorder(BorderFactory.createTitledBorder("CMYK"));
244 
245         JPanel xPanel = new JPanel();
246         cmykPanel.add(xPanel);
247         xPanel.setLayout(new BoxLayout(xPanel, BoxLayout.X_AXIS));
248 
249         JLabel cyanLabel = new JLabel("C(Cyan, [0-100])");
250         cyanInCmykSpinner = new JSpinner();
251         cyanInCmykSpinner.setModel(new SpinnerNumberModel(100, 0, 100, 1));
252         cyanInCmykSpinner.addChangeListener(new CmykChangeListener());
253 
254         JLabel magentaLabel = new JLabel("M(Magenta, [0-100])");
255         magentaInCmykSpinner = new JSpinner();
256         magentaInCmykSpinner.setModel(new SpinnerNumberModel(100, 0, 100, 1));
257         magentaInCmykSpinner.addChangeListener(new CmykChangeListener());
258 
259 
260         JLabel yellowLabel = new JLabel("Y(Yellow, [0-100])");
261         yellowInCmykSpinner = new JSpinner();
262         yellowInCmykSpinner.setModel(new SpinnerNumberModel(100, 0, 100, 1));
263         yellowInCmykSpinner.addChangeListener(new CmykChangeListener());
264 
265         JLabel blackLabel = new JLabel("K(Black, [0-100])");
266         blackInCmykSpinner = new JSpinner();
267         blackInCmykSpinner.setModel(new SpinnerNumberModel(0, 0, 100, 1));
268         blackInCmykSpinner.addChangeListener(new CmykChangeListener());
269 
270         xPanel.add(cyanLabel);
271         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
272         xPanel.add(cyanInCmykSpinner);
273         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
274         xPanel.add(magentaLabel);
275         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
276         xPanel.add(magentaInCmykSpinner);
277         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
278         xPanel.add(yellowLabel);
279         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
280         xPanel.add(yellowInCmykSpinner);
281         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
282         xPanel.add(blackLabel);
283         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
284         xPanel.add(blackInCmykSpinner);
285     }
286 
287     private void createCielabPanel() {
288         JPanel cielabPanel = new JPanel();
289         add(cielabPanel);
290         cielabPanel.setLayout(new BorderLayout());
291         cielabPanel.setBorder(BorderFactory.createTitledBorder("CIELAB"));
292 
293         JPanel xPanel = new JPanel();
294         cielabPanel.add(xPanel);
295         xPanel.setLayout(new BoxLayout(xPanel, BoxLayout.X_AXIS));
296 
297         JLabel lLabel = new JLabel("L([0-100])");
298         lInCielabSpinner = new JSpinner();
299         lInCielabSpinner.setModel(new SpinnerNumberModel(50, 0, 100, 1));
300         lInCielabSpinner.addChangeListener(new CielabChangeListener());
301 
302         JLabel magentaLabel = new JLabel("A([-128-127])");
303         aInCielabSpinner = new JSpinner();
304         aInCielabSpinner.setModel(new SpinnerNumberModel(0, -128, 127, 1));
305         aInCielabSpinner.addChangeListener(new CielabChangeListener());
306 
307 
308         JLabel yellowLabel = new JLabel("B([-128-127])");
309         bInCielabSpinner = new JSpinner();
310         bInCielabSpinner.setModel(new SpinnerNumberModel(0, -128, 127, 1));
311         bInCielabSpinner.addChangeListener(new CielabChangeListener());
312 
313         xPanel.add(lLabel);
314         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
315         xPanel.add(lInCielabSpinner);
316         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
317         xPanel.add(magentaLabel);
318         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
319         xPanel.add(aInCielabSpinner);
320         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
321         xPanel.add(yellowLabel);
322         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
323         xPanel.add(bInCielabSpinner);
324     }
325 
326     private void createToolSetPanel() {
327         JPanel toolSetPanel = new JPanel();
328         add(toolSetPanel);
329         toolSetPanel.setLayout(new BorderLayout());
330         toolSetPanel.setBorder(BorderFactory.createTitledBorder("数值/百分比/16进制"));
331 
332         JPanel xPanel = new JPanel();
333         toolSetPanel.add(xPanel);
334         xPanel.setLayout(new BoxLayout(xPanel, BoxLayout.X_AXIS));
335 
336         JLabel valueLabel = new JLabel("[0-255]");
337         toolsetValueSpinner = new JSpinner();
338         toolsetValueSpinner.setModel(new SpinnerNumberModel(0, 0, 255, 1));
339         toolsetValueSpinner.addChangeListener(new ToolsetValueChangeListener());
340 
341         JLabel percentLabel = new JLabel("[0%-100%]");
342         toolsetPercentageSpinner = new JSpinner();
343         toolsetPercentageSpinner.setModel(new SpinnerNumberModel(0, 0, 100, 1));
344         toolsetPercentageSpinner.addChangeListener(new ToolsetPercentChangeListener());
345 
346 
347         JLabel hexLabel = new JLabel("[0x00-0xFF]");
348         toolsetHexTextField = new JTextField();
349         toolsetHexTextField.setToolTipText("0xFF格式常用在通用语言中(Java/C++等), #FF格式常用在标记语言中(XML/HTML等)");
350         toolsetHexTextField.getDocument().addDocumentListener(new ToolsetHexDocumentListener());
351 
352         xPanel.add(valueLabel);
353         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
354         xPanel.add(toolsetValueSpinner);
355         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
356         xPanel.add(percentLabel);
357         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
358         xPanel.add(toolsetPercentageSpinner);
359         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
360         xPanel.add(hexLabel);
361         xPanel.add(Box.createHorizontalStrut(Constants.DEFAULT_X_BORDER));
362         xPanel.add(toolsetHexTextField);
363     }
364 
365     private void syncToOthersFormat(String colorMode) {
366         if (!colorMode.equalsIgnoreCase("RGB")) {
367             redSpinner.setValue(color.getRed());
368             greenInRgbSpinner.setValue(color.getGreen());
369             blueInRgbSpinner.setValue(color.getBlue());
370         }
371         if (!colorMode.equalsIgnoreCase("HEX")) {
372             hexInRgbTextField.setText(ColorUtils.color2Hex(color));
373         }
374         if (!colorMode.equalsIgnoreCase("HSB")) {
375             int[] hsbArray = ColorUtils.color2Hsb(color);
376             hueInHsbSpinner.setValue(hsbArray[0]);
377             saturationInHsbSpinner.setValue(hsbArray[1]);
378             brightnessInHsbSpinner.setValue(hsbArray[2]);
379         }
380         if (!colorMode.equalsIgnoreCase("HSL")) {
381             int[] hsbArray = ColorUtils.color2Hsl(color);
382             hueInHslSpinner.setValue(hsbArray[0]);
383             saturationInHslSpinner.setValue(hsbArray[1]);
384             lightnessInHslSpinner.setValue(hsbArray[2]);
385         }
386         if (!colorMode.equalsIgnoreCase("CMYK")) {
387             int[] cmykArray = ColorUtils.color2Cmyk(color);
388             cyanInCmykSpinner.setValue(cmykArray[0]);
389             magentaInCmykSpinner.setValue(cmykArray[1]);
390             yellowInCmykSpinner.setValue(cmykArray[2]);
391             blackInCmykSpinner.setValue(cmykArray[3]);
392         }
393         if (!colorMode.equalsIgnoreCase("CIELAB")) {
394             int[] cielabArray = ColorUtils.color2Cielab(color);
395             lInCielabSpinner.setValue(cielabArray[0]);
396             aInCielabSpinner.setValue(cielabArray[1]);
397             bInCielabSpinner.setValue(cielabArray[2]);
398         }
399         colorBoxTextField.setBackground(color);
400         //paint the color box with the converted output color
401         colorBoxTextField.setOpaque(true);
402     }
403 
404     class RgbChangeListener implements ChangeListener {
405         @Override
406         public void stateChanged(ChangeEvent e) {
407             if (!isChangedByUser) {
408                 return;
409             }
410             isChangedByUser = false;
411             int red = (Integer) redSpinner.getValue();
412             int green = (Integer) greenInRgbSpinner.getValue();
413             int blue = (Integer) blueInRgbSpinner.getValue();
414             color = new Color(red, green, blue);
415             syncToOthersFormat("RGB");
416             isChangedByUser = true;
417         }
418     }
419 
420     class HsbChangeListener implements ChangeListener {
421         @Override
422         public void stateChanged(ChangeEvent e) {
423             if (!isChangedByUser) {
424                 return;
425             }
426             isChangedByUser = false;
427             int hue = (Integer) hueInHsbSpinner.getValue();
428             int saturation = (Integer) saturationInHsbSpinner.getValue();
429             int brightness = (Integer) brightnessInHsbSpinner.getValue();
430             color = ColorUtils.hsb2Color(hue, saturation, brightness);
431             syncToOthersFormat("HSB");
432             isChangedByUser = true;
433         }
434     }
435 
436     class HslChangeListener implements ChangeListener {
437         @Override
438         public void stateChanged(ChangeEvent e) {
439             if (!isChangedByUser) {
440                 return;
441             }
442             isChangedByUser = false;
443             int hue = (Integer) hueInHslSpinner.getValue();
444             int saturation = (Integer) saturationInHslSpinner.getValue();
445             int lightness = (Integer) lightnessInHslSpinner.getValue();
446             color = ColorUtils.hsl2Color(hue, saturation, lightness);
447             syncToOthersFormat("HSL");
448             isChangedByUser = true;
449         }
450     }
451 
452     class CmykChangeListener implements ChangeListener {
453         @Override
454         public void stateChanged(ChangeEvent e) {
455             if (!isChangedByUser) {
456                 return;
457             }
458             isChangedByUser = false;
459             int cyan = (Integer) cyanInCmykSpinner.getValue();
460             int magenta = (Integer) magentaInCmykSpinner.getValue();
461             int yellow = (Integer) yellowInCmykSpinner.getValue();
462             int black = (Integer) blackInCmykSpinner.getValue();
463             color = ColorUtils.cmyk2Color(cyan, magenta, yellow, black);
464             syncToOthersFormat("CMYK");
465             isChangedByUser = true;
466         }
467     }
468 
469     class CielabChangeListener implements ChangeListener {
470         @Override
471         public void stateChanged(ChangeEvent e) {
472             if (!isChangedByUser) {
473                 return;
474             }
475             isChangedByUser = false;
476             int l = (Integer) lInCielabSpinner.getValue();
477             int a = (Integer) aInCielabSpinner.getValue();
478             int b = (Integer) bInCielabSpinner.getValue();
479             color = ColorUtils.cielab2Color(l, a, b);
480             syncToOthersFormat("CIELAB");
481             isChangedByUser = true;
482         }
483     }
484 
485     class HexDocumentListener implements DocumentListener {
486         @Override
487         public void insertUpdate(DocumentEvent e) {
488             onValueUpdate();
489         }
490 
491         @Override
492         public void removeUpdate(DocumentEvent e) {
493             onValueUpdate();
494         }
495 
496         @Override
497         public void changedUpdate(DocumentEvent e) {
498             onValueUpdate();
499         }
500 
501         private void onValueUpdate() {
502             if (!isChangedByUser) {
503                 return;
504             }
505             isChangedByUser = false;
506             String hex = hexInRgbTextField.getText();
507             try {
508                 color = ColorUtils.hex2Color(hex);
509                 syncToOthersFormat("HEX");
510             } catch (NumberFormatException e) {
511                 logger.error("Invalid hex value: {}", hex);
512             }
513             isChangedByUser = true;
514         }
515     }
516 
517     class ToolsetValueChangeListener implements ChangeListener {
518         @Override
519         public void stateChanged(ChangeEvent e) {
520             int value = (Integer) toolsetValueSpinner.getValue();
521             setToolsetNewValue(value, 1);
522         }
523     }
524 
525     class ToolsetPercentChangeListener implements ChangeListener {
526         @Override
527         public void stateChanged(ChangeEvent e) {
528             int percent = (Integer) toolsetPercentageSpinner.getValue();
529             int value = percent / 100.0f >= 1.0f ? 255 : Math.round((percent / 100.0f) * 255);
530             setToolsetNewValue(value, 2);
531         }
532     }
533 
534     class ToolsetHexDocumentListener implements DocumentListener {
535         @Override
536         public void insertUpdate(DocumentEvent e) {
537             onValueUpdate();
538         }
539 
540         @Override
541         public void removeUpdate(DocumentEvent e) {
542             onValueUpdate();
543         }
544 
545         @Override
546         public void changedUpdate(DocumentEvent e) {
547             onValueUpdate();
548         }
549 
550         private void onValueUpdate() {
551             String hex = toolsetHexTextField.getText();
552             int value = ColorUtils.parseByteHex(hex);
553             if (value == -1) {
554                 return;
555             }
556             setToolsetNewValue(value, 3);
557         }
558     }
559 
560     private void setToolsetNewValue(int value, int from) {
561         if (!isChangedByUser) {
562             return;
563         }
564         isChangedByUser = false;
565         if (from == 1) {
566             int percentage = Math.round((value / 255.0f) * 100);
567             toolsetPercentageSpinner.setValue(percentage);
568             String hexString = String.format("0x%02X", value);
569             toolsetHexTextField.setText(hexString);
570         } else if (from == 2) {
571             toolsetValueSpinner.setValue(value);
572             String hexString = String.format("0x%02X", value);
573             toolsetHexTextField.setText(hexString);
574         } else if (from == 3) {
575             toolsetValueSpinner.setValue(value);
576             int percentage = Math.round((value / 255.0f) * 100);
577             toolsetPercentageSpinner.setValue(percentage);
578         }
579         isChangedByUser = true;
580     }
581 }