File Source: ColourPickerPanel.java
/*
P/P * Method: com.dmdirc.addons.ui_swing.components.ColourPickerPanel__static_init
*/
1 /*
2 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 package com.dmdirc.addons.ui_swing.components;
24
25 import com.dmdirc.ui.messages.ColourManager;
26
27 import java.awt.Color;
28 import java.awt.Dimension;
29 import java.awt.Graphics;
30 import java.awt.Polygon;
31 import java.awt.Rectangle;
32 import java.awt.event.ActionEvent;
33 import java.awt.event.ActionListener;
34 import java.awt.event.MouseEvent;
35 import java.awt.event.MouseListener;
36 import java.awt.event.MouseMotionListener;
37 import java.awt.event.MouseWheelEvent;
38 import java.awt.event.MouseWheelListener;
39 import java.util.ArrayList;
40 import java.util.List;
41
42 import javax.swing.JPanel;
43
44 /**
45 * The ColourPickerPanel allows users to pick either an IRC colour or a hex
46 * colour visually.
47 * @author chris
48 */
49 public final class ColourPickerPanel extends JPanel implements MouseListener,
50 MouseMotionListener, MouseWheelListener {
51
52 /**
53 * A version number for this class. It should be changed whenever the class
54 * structure is changed (or anything else that would prevent serialized
55 * objects being unserialized with the new class).
56 */
57 private static final long serialVersionUID = 1;
58 /** ActionEvent ID for when a hex colour is selected. */
59 public static final int ACTION_HEX = 10001;
60 /** ActionEvent ID for when an irc colour is selected. */
61 public static final int ACTION_IRC = 10002;
62 /** The width of each IRC colour patch. */
63 private static final int IRC_WIDTH = 9;
64 /** The height of each IRC colour patch. */
65 private static final int IRC_HEIGHT = 16;
66 /** The width of the hex colour patch. */
67 private static final int HEX_WIDTH = 125;
68 /** The height of the hex colour patch. */
69 private static final int HEX_HEIGHT = 125;
70 /** The size of borders to use. */
71 private static final int BORDER_SIZE = 7;
72 /** The size of slider to use. */
73 private static final int SLIDER_WIDTH = 10;
74 /** The height of the preview area. */
75 private static final int PREVIEW_HEIGHT = 20;
76 /** Whether to show IRC colours. */
77 private final boolean showIrc;
78 /** Whether to show hex colours. */
79 private final boolean showHex;
80 /** The y-coord of the start of the IRC colours block. */
81 private int ircOffset;
82 /** The y-coord of the start of the hex colours block. */
83 private int hexOffset;
84 /** The y-coord of the start of the preview block. */
85 private int previewOffset;
86 /** The saturation to use. */
87 private float saturation = (float) 1.0;
88 /** The colour to show in the preview window. */
89 private Color preview;
90 /** Rectangle we use to indicate that only the preview should be drawn. */
91 private Rectangle previewRect;
92 /** A list of registered actionlisteners. */
93 private final List<ActionListener> listeners =
94 new ArrayList<ActionListener>();
95
96 /**
97 * Creates a new instance of ColourPickerPanel.
98 * @param newShowIrc Whether to show IRC colours or not
99 * @param newShowHex Whether to show hex colours or not
100 */
101 public ColourPickerPanel(final boolean newShowIrc,
102 final boolean newShowHex) {
/*
P/P * Method: void com.dmdirc.addons.ui_swing.components.ColourPickerPanel(bool, bool)
*
* Postconditions:
* this.listeners == &new ArrayList(ColourPickerPanel#1)
* this.saturation == 1
* this.showHex == newShowHex
* init'ed(this.showHex)
* this.showIrc == newShowIrc
* init'ed(this.showIrc)
* new ArrayList(ColourPickerPanel#1) num objects == 1
*/
103 super();
104
105 this.showIrc = newShowIrc;
106 this.showHex = newShowHex;
107
108 final int height = 65 + (showIrc ? 30 : 0) + (showHex ? 145 : 0) + (showHex & showIrc
109 ? 10 : 0);
110
111 setPreferredSize(new Dimension(160, height));
112
113 addMouseListener(this);
114 addMouseMotionListener(this);
115 addMouseWheelListener(this);
116 }
117
118 /**
119 * Creates a new instance of ColourPickerPanel, showing both IRC and Hex
120 * colours.
121 */
122 public ColourPickerPanel() {
/*
P/P * Method: void com.dmdirc.addons.ui_swing.components.ColourPickerPanel()
*
* Postconditions:
* this.listeners == &new ArrayList(ColourPickerPanel#1)
* this.saturation == 1
* this.showHex == 1
* this.showIrc == 1
* new ArrayList(ColourPickerPanel#1) num objects == 1
*/
123 this(true, true);
124 }
125
126 /** {@inheritDoc} */
127 @Override
128 public void paint(final Graphics g) {
/*
P/P * Method: void paint(Graphics)
*
* Preconditions:
* g != null
* init'ed(this.previewRect)
* init'ed(this.preview)
* (soft) this.previewOffset <= 4_294_967_275
* (soft) init'ed(this.saturation)
*
* Presumptions:
* com.dmdirc.addons.ui_swing.components.ColourPickerPanel:getWidth(...)@215 >= -2_147_483_634
* com.dmdirc.addons.ui_swing.components.ColourPickerPanel:getWidth(...)@220 >= -2_147_483_633
* com.dmdirc.addons.ui_swing.components.ColourPickerPanel:getWidth(...)@223 >= -231+7
* com.dmdirc.addons.ui_swing.components.ColourPickerPanel:getWidth(...)@227 >= -2_147_483_633
* init'ed(java.awt.Color.BLACK)
* ...
*
* Postconditions:
* this.hexOffset == One-of{old this.hexOffset, One-of{20, 63} + 7}
* this.ircOffset == One-of{old this.ircOffset, 27}
* this.previewOffset == One-of{One-of{20, 63, One-of{20, 63} + 152} + 7, old this.previewOffset}
* this.previewOffset <= 4_294_967_275
* this.previewRect == One-of{old this.previewRect, &new Rectangle(paint#4)}
* this.previewRect != null
* new Rectangle(paint#4) num objects <= 1
*
* Test Vectors:
* this.previewRect: Addr_Set{null}, Inverse{null}
* this.preview: Inverse{null}, Addr_Set{null}
* this.showHex: {0}, {1}
* this.showIrc: {0}, {1}
* java.awt.Rectangle:equals(...)@131: {1}, {0}
*/
129 int offset = 20;
130
131 if (previewRect == null || !previewRect.equals(g.getClipBounds())) {
132 g.setColor(getBackground());
133
134 g.fillRect(0, 0, getWidth(), getHeight());
135
136 g.setColor(Color.BLACK);
137
138 if (showIrc) {
139 g.drawString("IRC Colours", BORDER_SIZE, offset);
140
141 offset += BORDER_SIZE;
142
143 ircOffset = offset;
144
145 for (int i = 0; i < 16; i++) {
146 g.setColor(ColourManager.getColour(i));
147 g.fillRect(i * IRC_WIDTH + BORDER_SIZE, offset, IRC_WIDTH,
148 IRC_HEIGHT);
149 g.setColor(Color.BLACK);
150 g.drawRect(i * IRC_WIDTH + BORDER_SIZE, offset, IRC_WIDTH,
151 IRC_HEIGHT);
152 }
153
154 offset += IRC_HEIGHT + 20;
155 }
156
157 if (showHex) {
158 g.drawString("Hex Colours", BORDER_SIZE, offset);
159
160 offset += BORDER_SIZE;
161
162 hexOffset = offset;
163
164 for (int i = HEX_WIDTH; i > 0; i--) {
165 for (int j = HEX_HEIGHT; j > 0; j--) {
166 g.setColor(new Color(Color.HSBtoRGB((float) i /
167 HEX_WIDTH, saturation, (float) j / HEX_HEIGHT)));
168 g.drawLine(BORDER_SIZE + i, offset + HEX_HEIGHT - j,
169 BORDER_SIZE + i, offset + HEX_HEIGHT - j);
170 }
171 }
172
173 g.setColor(Color.BLACK);
174 g.drawRect(BORDER_SIZE, offset, HEX_HEIGHT, HEX_WIDTH);
175
176 g.drawRect(BORDER_SIZE * 2 + HEX_WIDTH, offset, 10, HEX_HEIGHT);
177
178 for (int i = 1; i < HEX_HEIGHT; i++) {
179 g.setColor(new Color(Color.HSBtoRGB(0, (float) i /
180 HEX_HEIGHT, 1)));
181 g.drawLine(BORDER_SIZE * 2 + HEX_WIDTH + 1, offset + i,
182 BORDER_SIZE * 2 + HEX_WIDTH + SLIDER_WIDTH - 1,
183 offset + i);
184 }
185
186 final Polygon arrow = new Polygon();
187
188 arrow.addPoint(HEX_WIDTH + BORDER_SIZE * 2 + 4, offset +
189 Math.round(saturation * HEX_HEIGHT));
190 arrow.addPoint(HEX_WIDTH + BORDER_SIZE * 2 + 13, offset +
191 Math.round(saturation * HEX_HEIGHT) + 5);
192 arrow.addPoint(HEX_WIDTH + BORDER_SIZE * 2 + 13, offset +
193 Math.round(saturation * HEX_HEIGHT) - 5);
194
195 g.setColor(Color.BLACK);
196 g.fillPolygon(arrow);
197
198 offset += HEX_HEIGHT + 20;
199 }
200
201 g.drawString("Preview", BORDER_SIZE, offset);
202
203 offset += BORDER_SIZE;
204
205 previewOffset = offset;
206
207 if (previewRect == null) {
208 previewRect = new Rectangle(0, previewOffset, getWidth(),
209 PREVIEW_HEIGHT);
210 }
211 } else {
212 offset = previewOffset;
213 }
214
215 g.drawRect(BORDER_SIZE, offset, getWidth() - BORDER_SIZE * 2,
216 PREVIEW_HEIGHT);
217
218 if (preview == null) {
219 g.setColor(getBackground());
220 g.fillRect(BORDER_SIZE + 1, offset + 1,
221 getWidth() - BORDER_SIZE * 2 - 1, PREVIEW_HEIGHT - 1);
222 g.setColor(Color.BLACK);
223 g.drawLine(BORDER_SIZE, offset, getWidth() - BORDER_SIZE, offset +
224 PREVIEW_HEIGHT);
225 } else {
226 g.setColor(preview);
227 g.fillRect(BORDER_SIZE + 1, offset + 1,
228 getWidth() - BORDER_SIZE * 2 - 1, PREVIEW_HEIGHT - 1);
229 }
230 }
231
232 /**
233 * Retrieves the hex colour beneath the mouse. It is assumed that this
234 * method is only called if the mouse is within the hex area.
235 * @param e The mouse event that triggered this call
236 * @return A colour object representing the colour beneat the mouse
237 */
238 private Color getHexColour(final MouseEvent e) {
/*
P/P * Method: Color getHexColour(MouseEvent)
*
* Preconditions:
* e != null
* init'ed(this.hexOffset)
* init'ed(this.saturation)
*
* Presumptions:
* java.awt.event.MouseEvent:getX(...)@239 >= -231+7
* java.awt.event.MouseEvent:getY(...)@240 - this.hexOffset in {-4_294_967_170..2_147_483_773}
*
* Postconditions:
* return_value == &new Color(getHexColour#1)
* new Color(getHexColour#1) num objects == 1
*/
239 final int i = e.getX() - BORDER_SIZE;
240 final int j = HEX_HEIGHT - (e.getY() - hexOffset);
241
242 return new Color(Color.HSBtoRGB((float) i / HEX_WIDTH, saturation,
243 (float) j / HEX_HEIGHT));
244 }
245
246 /**
247 * Retrieves the irc colour beneath the mouse. It is assumed that this
248 * method is only called if the mouse is within the irc colour area.
249 * @param e The mouse event that triggered this call
250 * @return A colour object representing the colour beneat the mouse
251 */
252 private Color getIrcColour(final MouseEvent e) {
/*
P/P * Method: Color getIrcColour(MouseEvent)
*
* Preconditions:
* e != null
*
* Postconditions:
* init'ed(return_value)
*/
253 final int i = (e.getX() - BORDER_SIZE) / IRC_WIDTH;
254
255 return ColourManager.getColour(i);
256 }
257
258 /**
259 * Adds an action listener to this object. Action events are generated (and
260 * passed to all action listeners) when the user selects a colour. The two
261 * IDs used by this object are ACTION_HEX and ACTION_IRC, to indicate a
262 * hex colour or an irc colour was selected, respectively.
263 * @param listener The action listener to register
264 */
265 public void addActionListener(final ActionListener listener) {
/*
P/P * Method: void addActionListener(ActionListener)
*
* Preconditions:
* this.listeners != null
*/
266 listeners.add(listener);
267 }
268
269 /**
270 * Removes an action listener from this object.
271 * @param listener The listener to be removed
272 */
273 public void removeActionListener(final ActionListener listener) {
/*
P/P * Method: void removeActionListener(ActionListener)
*
* Preconditions:
* this.listeners != null
*/
274 listeners.remove(listener);
275 }
276
277 /**
278 * Throws a new action event to all listeners.
279 * @param id The id of the action
280 * @param message The 'message' to use for the event
281 */
282 private void throwAction(final int id, final String message) {
/*
P/P * Method: void throwAction(int, String)
*
* Preconditions:
* this.listeners != null
*
* Presumptions:
* java.util.Iterator:next(...)@285 != null
*
* Test Vectors:
* java.util.Iterator:hasNext(...)@285: {0}, {1}
*/
283 final ActionEvent event = new ActionEvent(this, id, message);
284
285 for (ActionListener listener : listeners) {
286 listener.actionPerformed(event);
287 }
288 }
289
290 /**
291 * Converts the specified integer (in the range 0-255) into a hex string.
292 * @param value The integer to convert
293 * @return A char digit hex string representing the specified integer
294 */
295 private String toHex(final int value) {
/*
P/P * Method: String toHex(int)
*
* Preconditions:
* value in {0..255}
*
* Postconditions:
* java.lang.StringBuilder:toString(...)._tainted == 0
* return_value == &java.lang.StringBuilder:toString(...)
*/
296 final char[] chars = {
297 '0', '1', '2', '3', '4', '5', '6', '7',
298 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
299 };
300
301 return ("" + chars[value / 16]) + chars[value % 16];
302 }
303
304 /**
305 * {@inheritDoc}
306 *
307 * @param e Mouse event
308 */
309 @Override
310 public void mouseClicked(final MouseEvent e) {
/*
P/P * Method: void mouseClicked(MouseEvent)
*
* Preconditions:
* (soft) e != null
* (soft) init'ed(this.saturation)
* (soft) init'ed(this.hexOffset)
* (soft) init'ed(this.ircOffset)
* (soft) this.listeners != null
*
* Presumptions:
* java.awt.Color:getBlue(...)@326 in {0..255}
* java.awt.Color:getGreen(...)@326 in {0..255}
* java.awt.Color:getRed(...)@326 in {0..255}
*
* Postconditions:
* init'ed(this.saturation)
*
* Test Vectors:
* this.showHex: {0}, {1}
* this.showIrc: {0}, {1}
* java.awt.event.MouseEvent:getX(...)@311: {-231..7}, {8..232-1}
* java.awt.event.MouseEvent:getX(...)@311: {151..232-1}, {-231..150}
* java.awt.event.MouseEvent:getX(...)@322: {-231..7}, {8..232-1}
* java.awt.event.MouseEvent:getX(...)@322: {132..232-1}, {-231..131}
* java.awt.event.MouseEvent:getX(...)@329: {-231..139}, {140..232-1}
* java.awt.event.MouseEvent:getX(...)@329: {156..232-1}, {-231..155}
*/
311 if (showIrc && e.getY() > ircOffset && e.getY() < ircOffset + IRC_HEIGHT &&
312 e.getX() > BORDER_SIZE && e.getX() < BORDER_SIZE + 16 *
313 IRC_WIDTH) {
314
315 final int i = (e.getX() - BORDER_SIZE) / IRC_WIDTH;
316
317 throwAction(ACTION_IRC, "" + i);
318
319 } else if (showHex && e.getY() > hexOffset && e.getY() < hexOffset +
320 HEX_HEIGHT) {
321
322 if (e.getX() > BORDER_SIZE && e.getX() < BORDER_SIZE + HEX_WIDTH) {
323
324 final Color color = getHexColour(e);
325
326 throwAction(ACTION_HEX, toHex(color.getRed()) +
327 toHex(color.getGreen()) + toHex(color.getBlue()));
328
329 } else if (e.getX() > BORDER_SIZE * 2 + HEX_WIDTH && e.getX() <
330 BORDER_SIZE * 3 + HEX_WIDTH + SLIDER_WIDTH) {
331 saturation = (float) (e.getY() - hexOffset) / 125;
332 repaint();
333 }
334 }
335 }
336
337 /**
338 * {@inheritDoc}
339 *
340 * @param e Mouse event
341 */
342 @Override
343 public void mousePressed(final MouseEvent e) {
344 // Do nothing
/*
P/P * Method: void mousePressed(MouseEvent)
*/
345 }
346
347 /**
348 * {@inheritDoc}
349 *
350 * @param e Mouse event
351 */
352 @Override
353 public void mouseReleased(final MouseEvent e) {
354 // Do nothing
/*
P/P * Method: void mouseReleased(MouseEvent)
*/
355 }
356
357 /**
358 * {@inheritDoc}
359 *
360 * @param e Mouse event
361 */
362 @Override
363 public void mouseEntered(final MouseEvent e) {
364 // Do nothing
/*
P/P * Method: void mouseEntered(MouseEvent)
*/
365 }
366
367 /**
368 * {@inheritDoc}
369 *
370 * @param e Mouse event
371 */
372 @Override
373 public void mouseExited(final MouseEvent e) {
374 // Do nothing
/*
P/P * Method: void mouseExited(MouseEvent)
*/
375 }
376
377 /**
378 * {@inheritDoc}
379 *
380 * @param e Mouse event
381 */
382 @Override
383 public void mouseDragged(final MouseEvent e) {
384 // Do nothing
/*
P/P * Method: void mouseDragged(MouseEvent)
*/
385 }
386
387 /**
388 * {@inheritDoc}
389 *
390 * @param e Mouse event
391 */
392 @Override
393 public void mouseMoved(final MouseEvent e) {
/*
P/P * Method: void mouseMoved(MouseEvent)
*
* Preconditions:
* init'ed(this.previewRect)
* (soft) e != null
* (soft) init'ed(this.hexOffset)
* (soft) init'ed(this.ircOffset)
* (soft) init'ed(this.saturation)
*
* Postconditions:
* init'ed(this.preview)
* new Color(getHexColour#1) num objects <= 1
*
* Test Vectors:
* this.showHex: {0}, {1}
* this.showIrc: {0}, {1}
* java.awt.event.MouseEvent:getX(...)@394: {-231..7}, {8..232-1}
* java.awt.event.MouseEvent:getX(...)@394: {151..232-1}, {-231..150}
* java.awt.event.MouseEvent:getX(...)@398: {-231..7}, {8..232-1}
* java.awt.event.MouseEvent:getX(...)@398: {132..232-1}, {-231..131}
*/
394 if (showIrc && e.getY() > ircOffset && e.getY() < ircOffset + IRC_HEIGHT &&
395 e.getX() > BORDER_SIZE && e.getX() < BORDER_SIZE + 16 *
396 IRC_WIDTH) {
397 preview = getIrcColour(e);
398 } else if (showHex && e.getY() > hexOffset && e.getY() < hexOffset +
399 HEX_HEIGHT && e.getX() > BORDER_SIZE && e.getX() < BORDER_SIZE +
400 HEX_WIDTH) {
401 preview = getHexColour(e);
402 } else {
403 preview = null;
404 }
405
406 repaint(previewRect);
407 }
408
409 /**
410 * {@inheritDoc}
411 *
412 * @param e Mouse event
413 */
414 @Override
415 public void mouseWheelMoved(final MouseWheelEvent e) {
/*
P/P * Method: void mouseWheelMoved(MouseWheelEvent)
*
* Preconditions:
* (soft) e != null
* (soft) init'ed(this.saturation)
* (soft) init'ed(this.hexOffset)
* (soft) init'ed(this.ircOffset)
* (soft) init'ed(this.previewRect)
*
* Postconditions:
* possibly_updated(this.preview)
* this.saturation == One-of{old this.saturation, old this.saturation + One-of{5_368_709/268_435_456, -5_368_709/268_435_456}, +0, 1}
* init'ed(this.saturation)
* new Color(getHexColour#1) num objects <= 1
*
* Test Vectors:
* this.showHex: {0}, {1}
*/
416 if (showHex) {
417 saturation = saturation + (e.getWheelRotation() >= 0 ? 0.02f : -0.02f);
418
419 if (saturation < 0) {
420 saturation = 0f;
421 }
422 if (saturation > 1) {
423 saturation = 1f;
424 }
425
426 mouseMoved(e);
427 repaint();
428 }
429 }
430 }
SofCheck Inspector Build Version : 2.17854
| ColourPickerPanel.java |
2009-Jun-25 01:54:24 |
| ColourPickerPanel.class |
2009-Sep-02 17:04:14 |