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