001: /*
002: *
003: * Copyright (c) 2007, Sun Microsystems, Inc.
004: *
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * * Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * * Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * * Neither the name of Sun Microsystems nor the names of its contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032: package example.chooser;
033:
034: import javax.microedition.lcdui.Canvas;
035: import javax.microedition.lcdui.Font;
036: import javax.microedition.lcdui.Graphics;
037:
038: /**
039: * A Color chooser. This screen can be used to display and
040: * choose colors. The current color is always available
041: * via the getColor and getGrayScale methods. It can be
042: * set with setColor.
043: * A palette provides some reuse of colors, the current
044: * index in the palette can get set and retrieved.
045: * When the chooser is active the user may set the index
046: * in the palette, and change the red, green, and blue
047: * components.
048: * The application using the chooser must add commands
049: * to the chooser as appropriate to terminate selection
050: * and to change to other screens.
051: * The chooser adapts to the available screen size
052: * and font sizes.
053: */
054: public class ColorChooser extends Canvas {
055:
056: static final int BORDER = 2;
057:
058: private int width; // Width and height of canvas
059: private int height; // Width and height of canvas
060: private Font font;
061: private int label_w; // width of "999"
062: private int label_h; // height of "999"
063: private int gray;
064: private int rgbColor;
065: private int radix = 10; // radix to display numbers (10 or 16)
066: private int delta = 0x20; // default increment/decrement
067: private int ndx = 0; // 0 == blue, 1 == green, 2 == red
068: private boolean isColor;
069: private int pndx;
070: private int[] palette = { 0xffff00, 0x00ffff, 0xff00ff, 0xffff00,
071: 0xc00000, 0x00c000, 0x0000c0, 0x80ffff, 0xff80ff, 0xffff80 };
072:
073: public ColorChooser(boolean isColor) {
074: this .isColor = isColor;
075: ndx = 0;
076: pndx = 0;
077: setColor(palette[pndx]);
078:
079: width = getWidth();
080: height = getHeight();
081:
082: font = Font.getDefaultFont();
083: label_h = font.getHeight();
084:
085: if (label_h > (height / 6)) {
086: font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN,
087: Font.SIZE_SMALL);
088: label_h = font.getHeight();
089: }
090:
091: label_w = font.stringWidth("999");
092: }
093:
094: /**
095: * Select which entry in the Palette to use for the current color.
096: * @param index index into the palette; 0..10.
097: */
098: public boolean setPaletteIndex(int index) {
099: if (index >= palette.length) {
100: return false;
101: }
102:
103: pndx = index;
104: setColor(palette[index]);
105:
106: return true;
107: }
108:
109: /**
110: * Get the current palette index.
111: * @return the current index in the palette.
112: */
113: public int getPaletteIndex() {
114: return ndx;
115: }
116:
117: /**
118: * Sets the current color to the specified RGB values.
119: * @param red The red component of the color being set in range 0-255.
120: * @param green The green component of the color being set in range 0-255.
121: * @param blue The blue component of the color being set in range 0-255.
122: */
123: public void setColor(int red, int green, int blue) {
124: red = (red < 0) ? 0 : (red & 0xff);
125: green = (green < 0) ? 0 : (green & 0xff);
126: blue = (blue < 0) ? 0 : (blue & 0xff);
127:
128: setColor((red << 16) | (green << 8) | blue);
129: }
130:
131: /**
132: * Sets the current color to the specified RGB values. All subsequent
133: * rendering operations will use this specified color. The RGB value
134: * passed in is interpreted with the least significant eight bits
135: * giving the blue component, the next eight more significant bits
136: * giving the green component, and the next eight more significant
137: * bits giving the red component. That is to say, the color component
138: * is specified like 0x00RRGGBB.
139: * @param RGB The color being set.
140: */
141: public void setColor(int RGB) {
142: rgbColor = RGB & 0x00ffffff;
143: palette[pndx] = rgbColor;
144: updateGray();
145: }
146:
147: /*
148: * Compute the gray value from the RGB value.
149: */
150: private void updateGray() {
151: /*
152: * Gray is the value according to HSV. I think it would
153: * make more sense to use NTSC gray, but that's not what
154: * is currently in the spec. -- rib 20 Mar 2000
155: */
156: gray = Math.max((rgbColor >> 16) & 0xff, Math.max(
157: (rgbColor >> 8) & 0xff, rgbColor & 0xff));
158: }
159:
160: /**
161: * Gets the current color.
162: * @return an integer in form 0x00RRGGBB
163: * @see #setColor(int, int, int)
164: */
165: public int getColor() {
166: return rgbColor;
167: }
168:
169: /**
170: * Gets the red component of the current color.
171: * @return integer value in range 0-255
172: * @see #setColor(int, int, int)
173: */
174: public int getRedComponent() {
175: return (rgbColor >> 16) & 0xff;
176: }
177:
178: /**
179: * Gets the green component of the current color.
180: * @return integer value in range 0-255
181: * @see #setColor(int, int, int)
182: */
183: public int getGreenComponent() {
184: return (rgbColor >> 8) & 0xff;
185: }
186:
187: /**
188: * Gets the blue component of the current color.
189: * @return integer value in range 0-255
190: * @see #setColor(int, int, int)
191: */
192: public int getBlueComponent() {
193: return rgbColor & 0xff;
194: }
195:
196: /*
197: * Get the current grayscale value.
198: */
199: public int getGrayScale() {
200: return gray;
201: }
202:
203: /**
204: * Sets the current grayscale.
205: * For color the value is used to set each component.
206: * @param value the value in range 0-255
207: */
208: public void setGrayScale(int value) {
209: setColor(value, value, value);
210: }
211:
212: /**
213: * The canvas is being displayed. Compute the
214: * relative placement of items the depend on the screen size.
215: */
216: protected void showNotify() {
217: }
218:
219: /*
220: * Paint the canvas with the current color and controls to change it.
221: */
222: protected void paint(Graphics g) {
223: if (isColor) {
224: colorPaint(g);
225: } else {
226: grayPaint(g);
227: }
228: }
229:
230: /**
231: * Set the radix used to display numbers.
232: * The default is decimal (10).
233: */
234: public void setRadix(int rad) {
235: if ((rad != 10) && (rad != 16)) {
236: throw new IllegalArgumentException();
237: }
238:
239: radix = rad;
240: repaint();
241: }
242:
243: /**
244: * Get the radix used to display numbers.
245: */
246: public int getRadix() {
247: return radix;
248: }
249:
250: /**
251: * Set the delta used to increment/decrement.
252: * The default is 32.
253: */
254: public void setDelta(int delta) {
255: if ((delta > 0) && (delta <= 128)) {
256: this .delta = delta;
257: }
258: }
259:
260: /**
261: * Get the delta used to increment/decrement.
262: */
263: public int getDelta() {
264: return delta;
265: }
266:
267: /*
268: * Use Integer toString to convert.
269: * padding may be required.
270: */
271: private String format(int num) {
272: String s = Integer.toString(num, radix);
273:
274: if ((radix == 10) || (s.length() >= 2)) {
275: return s;
276: }
277:
278: return "0" + s;
279: }
280:
281: private void colorPaint(Graphics g) {
282: // Scale palette cells to fit 10 across
283: int p_w = width / palette.length;
284: int p_h = (height - (BORDER * 3)) / 4;
285: int usable_w = p_w * palette.length;
286:
287: int sample_w = (p_w * palette.length) - 1;
288: int sample_h = p_h;
289:
290: int sample_x = (width - usable_w) / 2;
291: int sample_y = 0;
292: int p_x = sample_x;
293: int p_y = sample_y + sample_h + 4;
294:
295: // Fill the background
296: g.setColor(0xffffff);
297: g.fillRect(0, 0, width, height);
298:
299: // Fill in the color sample
300: g.setColor(rgbColor);
301: gray = g.getGrayScale();
302: g.fillRect(sample_x, sample_y, sample_w, sample_h);
303: g.setColor((ndx < 0) ? 0x000000 : 0x808080);
304: g.drawRect(sample_x, sample_y, sample_w - 1, sample_h - 1);
305:
306: // Draw the palette
307: for (int i = 0; i < palette.length; i++) {
308: g.setColor(palette[i]);
309:
310: int shift = ((i == pndx) ? (BORDER * 2) : 0);
311: g.fillRect(p_x + (i * p_w), p_y - shift, p_w - 1, p_h);
312:
313: // If the palette is selected, outline it
314: if (i == pndx) {
315: g.setColor((ndx < 0) ? 0x000000 : 0x808080);
316: g.drawRect(p_x + (i * p_w), p_y - shift - 1, p_w - 2,
317: p_h + 1);
318: }
319: }
320:
321: int bars_y = p_y + p_h + BORDER;
322:
323: int bar_h = label_h + BORDER;
324: int bar_w = usable_w - label_w - BORDER;
325:
326: int b_x = label_w + BORDER;
327: int b_y = bars_y + BORDER;
328: int g_y = b_y + bar_h;
329: int r_y = g_y + bar_h;
330:
331: // Draw the color bars
332: g.setColor(0, 0, 255);
333:
334: int b_w = (bar_w * getBlueComponent()) / 255;
335: g.fillRect(b_x, b_y, b_w, bar_h - BORDER);
336: g.setColor((ndx == 0) ? 0x000000 : 0xa0a0ff);
337: g.drawRect(b_x, b_y, bar_w - 1, bar_h - BORDER - 1);
338:
339: int g_w = (bar_w * getGreenComponent()) / 255;
340: g.setColor(0, 255, 0);
341: g.fillRect(b_x, g_y, g_w, bar_h - BORDER);
342: g.setColor((ndx == 1) ? 0x000000 : 0xa0ffa0);
343: g.drawRect(b_x, g_y, bar_w - 1, bar_h - BORDER - 1);
344:
345: int r_w = (bar_w * getRedComponent()) / 255;
346: g.setColor(255, 0, 0);
347: g.fillRect(b_x, r_y, r_w, bar_h - BORDER);
348: g.setColor((ndx == 2) ? 0x000000 : 0xffa0a0);
349: g.drawRect(b_x, r_y, bar_w - 1, bar_h - BORDER - 1);
350:
351: g.setFont(font);
352: g.setColor(0, 0, 0);
353: g.drawString(format(getBlueComponent()), label_w, b_y + bar_h,
354: Graphics.BOTTOM | Graphics.RIGHT);
355: g.drawString(format(getGreenComponent()), label_w, g_y + bar_h,
356: Graphics.BOTTOM | Graphics.RIGHT);
357: g.drawString(format(getRedComponent()), label_w, r_y + bar_h,
358: Graphics.BOTTOM | Graphics.RIGHT);
359: }
360:
361: private void grayPaint(Graphics g) {
362: int sample_w = width;
363: int sample_h = height / 2;
364: int g_y = height / 2;
365: int g_w = width - (label_w + BORDER);
366: int g_h = label_h + BORDER;
367:
368: // Fill the background
369: g.setGrayScale(0xff);
370: g.fillRect(0, 0, width, height);
371:
372: // Fill in the gray sample
373: g.setGrayScale(gray);
374: g.fillRect(0, 0, sample_w, sample_h);
375: g.setGrayScale(0);
376: g.drawRect(0, 0, sample_w - 1, sample_h - 1);
377:
378: // Fill in the gray bar
379: g.setGrayScale(0);
380: g.fillRect(label_w + BORDER, g_y + BORDER, (g_w * gray) / 255,
381: g_h);
382: g.drawRect(label_w + BORDER, g_y + BORDER, g_w - 1, g_h - 1);
383: g.drawString(format(gray), label_w, g_y + BORDER + g_h,
384: Graphics.BOTTOM | Graphics.RIGHT);
385: }
386:
387: /*
388: * Handle repeat as in pressed.
389: */
390: public void keyRepeated(int key) {
391: keyPressed(key);
392: }
393:
394: /*
395: * Left and Right are used to change which color bar to change
396: * Up and Down are used to increase/decrease the value of that bar.
397: */
398: protected void keyPressed(int key) {
399: int action = getGameAction(key);
400: int dir = 0;
401:
402: switch (action) {
403: case RIGHT:
404: dir += 1;
405:
406: break;
407:
408: case LEFT:
409: dir -= 1;
410:
411: break;
412:
413: case UP:
414: ndx -= 1;
415:
416: break;
417:
418: case DOWN:
419: ndx += 1;
420:
421: break;
422:
423: default:
424: return; // nothing we recognize, exit
425: }
426:
427: // Gray scale event handling is simpler than color
428: if (isColor) {
429: // Limit selection to r,g,b and palette
430: if (ndx < -1) {
431: ndx = -1;
432: }
433:
434: if (ndx > 2) {
435: ndx = 2;
436: }
437:
438: if (ndx >= 0) {
439: int v = (rgbColor >> (ndx * 8)) & 0xff;
440: v += (dir * delta);
441:
442: if (v < 0) {
443: v = 0;
444: }
445:
446: if (v > 255) {
447: v = 255;
448: }
449:
450: int mask = 0xff << (ndx * 8);
451: rgbColor = (rgbColor & ~mask) | (v << (ndx * 8));
452: palette[pndx] = rgbColor;
453: } else {
454: pndx += dir;
455:
456: if (pndx < 0) {
457: pndx = 0;
458: }
459:
460: if (pndx >= palette.length) {
461: pndx = palette.length - 1;
462: }
463:
464: rgbColor = palette[pndx];
465: }
466: } else {
467: /*
468: * Gray scale; multiple dir and add to gray
469: * ignore (up/down) there is only one thing to select.
470: */
471: gray += (dir * delta);
472:
473: if (gray < 0) {
474: gray = 0;
475: }
476:
477: if (gray > 255) {
478: gray = 255;
479: }
480: }
481:
482: repaint();
483: }
484: }
|