001: // Slider.java
002: // $Id: Slider.java,v 1.15 2000/08/16 21:37:57 ylafon Exp $
003: // Author: bmahe@sophia.inria.fr
004: // (c) COPYRIGHT MIT and INRIA, 1997.
005: // Please first read the full copyright statement in file COPYRIGHT.html
006:
007: package org.w3c.tools.widgets;
008:
009: import java.awt.Canvas;
010: import java.awt.Color;
011: import java.awt.Component;
012: import java.awt.Dimension;
013: import java.awt.Font;
014: import java.awt.FontMetrics;
015: import java.awt.Frame;
016: import java.awt.Graphics;
017: import java.awt.GridLayout;
018: import java.awt.Image;
019: import java.awt.Point;
020: import java.awt.Shape;
021: import java.awt.event.MouseAdapter;
022: import java.awt.event.MouseEvent;
023: import java.awt.event.MouseMotionListener;
024:
025: /**
026: * Slider :
027: * @author Benoit Mahe <bmahe@sophia.inria.fr>
028: */
029:
030: public class Slider extends Canvas {
031:
032: //inner classes
033:
034: class PointerClickListener extends MouseAdapter {
035:
036: Slider slider = null;
037:
038: public void mouseClicked(MouseEvent e) {
039: Object target = e.getComponent();
040: if (target == slider)
041: slider.movePointerTo(e.getX(), e.getY());
042: }
043:
044: public PointerClickListener(Slider s) {
045: this .slider = s;
046: }
047:
048: }
049:
050: class PointerMotionListener implements MouseMotionListener {
051:
052: Slider slider = null;
053:
054: public void mouseDragged(MouseEvent e) {
055: Object target = e.getComponent();
056: if (target == slider)
057: slider.movePointerTo(e.getX(), e.getY());
058: }
059:
060: public void mouseMoved(MouseEvent e) {
061: }
062:
063: PointerMotionListener(Slider s) {
064: this .slider = s;
065: }
066:
067: }
068:
069: class Pointer {
070:
071: private int width = 0;
072: private int height = 0;
073:
074: private int centerX = 0;
075:
076: Dimension size = null;
077:
078: int x = 0;
079: int y = 0;
080:
081: public void fill3DPointer(Graphics g, int x, int y, int width,
082: int height, boolean raised) {
083: int xPoints[] = new int[3];
084: int yPoints[] = new int[3];
085: int nPoints = 3;
086:
087: Color c = g.getColor();
088: Color brighter = c.brighter();
089: Color darker = c.darker();
090:
091: if (!raised)
092: g.setColor(darker);
093:
094: g.fillRect(x + 1, y + 1, width - 2, 2 * height / 3);
095: xPoints[0] = x;
096: yPoints[0] = y + 2 * height / 3;
097: xPoints[1] = x + width / 2;
098: yPoints[1] = y + height;
099: xPoints[2] = x + width;
100: yPoints[2] = y + 2 * height / 3;
101: g.fillPolygon(xPoints, yPoints, nPoints);
102: g.setColor(raised ? brighter : darker);
103: g.drawLine(x, y, x, y + (2 * height / 3) - 1);
104: g.drawLine(x + 1, y, x + width - 2, y);
105: g.drawLine(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
106: g.setColor(raised ? darker : brighter);
107: g.drawLine(x + width - 1, y, x + width - 1, y
108: + (2 * height / 3) - 2);
109: g.drawLine(xPoints[1], yPoints[1], xPoints[2] - 1,
110: yPoints[2] - 1);
111: }
112:
113: public void paint(Graphics g) {
114: fill3DPointer(g, getLocation().x, getLocation().y, width,
115: height, true);
116: }
117:
118: public void setSize(int width, int height) {
119: this .width = width;
120: this .height = height;
121: size = new Dimension(width, height);
122: }
123:
124: public int getCenterX() {
125: return centerX;
126: }
127:
128: public void setLocation(int x, int y) {
129: pposition = new Point(x, y);
130: this .x = x - (width / 2);
131: this .y = y - (height / 2);
132: this .centerX = x;
133: }
134:
135: public void setLocation(Point p) {
136: setLocation(p.x, p.y);
137: }
138:
139: public Point getLocation() {
140: return new Point(x, y);
141: }
142:
143: public Point getNewLocation(int x, int y) {
144: return new Point(getLocation().x + x, getLocation().y + y);
145: }
146:
147: Pointer(int width, int height, Point location) {
148: setSize(width, height);
149: setLocation(location);
150: }
151:
152: }
153:
154: class Graduation {
155: boolean isDouble;
156: public int x1;
157: public int y1;
158: public int x2;
159: public int y2;
160:
161: public double value;
162:
163: public void draw(Graphics g, boolean display) {
164: g.drawLine(x1, y1, x2, y2);
165: if (display) {
166: String svalue = getStringValue();
167: FontMetrics f = g.getFontMetrics();
168: int height = f.getHeight();
169: int width = f.stringWidth(svalue);
170: g.drawString(svalue, x1 - width / 2, y2 + height);
171: }
172: }
173:
174: public String getStringValue() {
175: if (isDouble)
176: return String.valueOf((float) value); //FIXME
177: else
178: return String.valueOf((long) value);
179: }
180:
181: public void showValue(Graphics g) {
182: String svalue = getStringValue();
183: FontMetrics f = g.getFontMetrics();
184: int height = f.getHeight();
185: int width = f.stringWidth(svalue);
186: g.drawString(svalue, x1 - width / 2, y2 + height);
187: }
188:
189: public int dx(int x) {
190: int dx = x1 - x;
191: return ((dx < 0) ? -dx : dx);
192: }
193:
194: public Graduation(int x1, int y1, int x2, int y2, double value) {
195: this .x1 = x1;
196: this .y1 = y1;
197: this .x2 = x2;
198: this .y2 = y2;
199: this .value = value;
200: isDouble = true;
201: }
202:
203: public Graduation(int x1, int y1, int x2, int y2, long value) {
204: this .x1 = x1;
205: this .y1 = y1;
206: this .x2 = x2;
207: this .y2 = y2;
208: this .value = value;
209: isDouble = false;
210: }
211:
212: }
213:
214: //SLIDER itself
215:
216: int marginx = 10;
217: int marginy = 5;
218: int defaultWidth = 180;
219: int defaultHeight = 53;
220: int width = 0;
221: int height = 0;
222:
223: int minheight = 53;
224: int minwidth = 150;
225:
226: int rect_margin_x = 20;
227: int rect_margin_y = 10;
228:
229: int pointerWidth = 12;
230: int pointerHeight = 20;
231:
232: int pointerX = 0;
233: int pointerY = 0;
234:
235: int guideHeight = 2;
236: int graduationHeight = 5;
237:
238: double min = 0;
239: double max = 0;
240: double step = 0;
241:
242: int minpixelstep = 2;
243:
244: boolean border = false;
245: boolean manageLong = false;
246:
247: Color color = Color.gray;
248:
249: Dimension size = null;
250:
251: Point pposition = null;
252:
253: Graduation graduations[] = null;
254:
255: Graduation currentGraduation = null;
256:
257: protected Pointer pointer = null;
258:
259: protected void updateCurrentGraduation() {
260: if (pposition.x > (width - marginx - rect_margin_x)) {
261: currentGraduation = graduations[graduations.length - 1];
262: } else if (pposition.x < (marginx + rect_margin_x)) {
263: currentGraduation = graduations[0];
264: } else {
265: int dx = -1;
266: int mindx = getGraduationLength() + 50;
267: int i = 0;
268: while (i < graduations.length) {
269: dx = (graduations[i].dx(pposition.x));
270: if (dx < mindx) {
271: mindx = dx;
272: i++;
273: } else
274: break;
275: }
276: currentGraduation = graduations[i - 1];
277: }
278: }
279:
280: protected int getGoodX(int x) {
281: if (x > (width - marginx - rect_margin_x)) {
282: if (graduations[graduations.length - 1].x1 != pointer
283: .getCenterX()) {
284: currentGraduation = graduations[graduations.length - 1];
285: return graduations[graduations.length - 1].x1;
286: } else
287: return -1;
288: } else if (x < (marginx + rect_margin_x)) {
289: if (graduations[0].x1 != pointer.getCenterX()) {
290: currentGraduation = graduations[0];
291: return graduations[0].x1;
292: } else
293: return -1;
294: } else {
295: // find the nearest graduation.
296: int dx = -1;
297: int mindx = getGraduationLength() + 50;
298: int i = 0;
299: while (i < graduations.length) {
300: dx = (graduations[i].dx(x));
301: if (dx < mindx) {
302: mindx = dx;
303: i++;
304: } else
305: break;
306: }
307: if (graduations[i - 1].x1 != pointer.getCenterX()) {
308: currentGraduation = graduations[i - 1];
309: return graduations[i - 1].x1;
310: }
311: return -1; //FIXME
312: }
313: }
314:
315: /**
316: * Get the current value pointed by the slider.
317: * @return the value.
318: */
319: public double getValue() {
320: if (currentGraduation != null) {
321: return currentGraduation.value;
322: } else
323: return min;
324: }
325:
326: protected void updatePointerPosition(double value) {
327: if (value <= graduations[0].value) {
328: pointer.setLocation(graduations[0].x1, pposition.y);
329: return;
330: }
331: int maxidx = graduations.length - 1;
332: if (value == graduations[maxidx].value) {
333: pointer.setLocation(graduations[maxidx].x1, pposition.y);
334: return;
335: }
336: if (value > graduations[graduations.length - 1].value)
337: setMax(value + 10 * step);
338: for (int i = 1; i < graduations.length - 2; i++) {
339: if (value - graduations[i].value < step) {
340: pointer.setLocation(graduations[i].x1, pposition.y);
341: return;
342: }
343: }
344: }
345:
346: /**
347: * Set the value pointed by the slider.
348: * if the value is too high, resize the slider.
349: * @param The value to point.
350: */
351: public void setValue(double value) {
352: updatePointerPosition(value);
353: updateCurrentGraduation();
354: if (getGraphics() != null)
355: paint(getGraphics());
356: }
357:
358: public void setValue(long value) {
359: setValue((double) value);
360: }
361:
362: protected void movePointerTo(int x, int y) {
363: int gx = getGoodX(x);
364: if (gx != -1) {
365: pointer.setLocation(gx, pposition.y);
366: if (getGraphics() != null)
367: paint(getGraphics());
368: }
369: }
370:
371: protected void movePointerTo(Point p) {
372: int gx = getGoodX(p.x);
373: if (gx != -1) {
374: pointer.setLocation(gx, pposition.y);
375: if (getGraphics() != null)
376: paint(getGraphics());
377: }
378: }
379:
380: /**
381: * paint the slider.
382: */
383: public void paint(Graphics g) {
384: Dimension d = getSize();
385: updateSize(d);
386: Shape s = g.getClip();
387: Image dbi = null;
388: Graphics dbg = null;
389: dbi = ImageCache.getImage(this , d.width, d.height);
390: dbg = dbi.getGraphics();
391: dbg.setClip(s);
392: dbg.setColor(color);
393: dbg.clearRect(0, 0, d.width, d.height);
394: dbg.fillRect(marginx, marginy, width - (2 * marginx), height
395: - (2 * marginy));
396: if (border) {
397: dbg.setColor(color.darker());
398: dbg.drawRect(marginx, marginy, width - (2 * marginx),
399: height - (2 * marginy));
400: }
401: dbg.setColor(Color.white);
402: dbg.fill3DRect(marginx + rect_margin_x, marginy + rect_margin_y
403: - guideHeight / 2, getGraduationLength(), guideHeight,
404: false);
405: paintGraduation(dbg);
406: dbg.setColor(color.darker());
407: pointer.paint(dbg);
408: g.drawImage(dbi, 0, 0, this );
409: }
410:
411: protected int getGraduationLength() {
412: // use to recover arround error.
413: int length = width - 2 * (marginx + rect_margin_x);
414: int nbpart = (int) ((max - min) / step);
415: int pixelstep = length / nbpart;
416: return pixelstep * nbpart;
417: }
418:
419: protected void updateGraduationPosition() {
420: int length = width - 2 * (marginx + rect_margin_x);
421: int nbpart = (int) ((max - min) / step);
422: int pixelstep = length / nbpart;
423: int y1 = marginy + 5 * rect_margin_y / 3;
424: int y2 = y1 + graduationHeight;
425: int minpixel = marginx + rect_margin_x;
426: int maxpixel = length + minpixel;
427: int gradx = minpixel;
428: graduations = new Graduation[nbpart + 1];
429: int i = 0;
430: while (i < graduations.length) {
431: if (manageLong) {
432: graduations[i] = new Graduation(gradx, y1, gradx, y2,
433: (long) (min + i * step));
434: } else {
435: graduations[i] = new Graduation(gradx, y1, gradx, y2,
436: min + i * step);
437: }
438: gradx += pixelstep;
439: i++;
440: }
441: }
442:
443: protected void paintGraduation(Graphics g) {
444: g.setColor(Color.black);
445: Font font = new Font(g.getFont().getName(), g.getFont()
446: .getStyle(), g.getFont().getSize() - 1);
447: g.setFont(font);
448: for (int i = 0; i < graduations.length; i++)
449: graduations[i].draw(g, (i == 0)
450: || (i == graduations.length - 1));
451: g.setColor(Color.white);
452: currentGraduation.showValue(g);
453: }
454:
455: /**
456: * update the slider.
457: */
458: public void update(Graphics g) {
459: paint(g);
460: }
461:
462: protected void setDefaultSize(double min, double max, double step) {
463: int length = minwidth - 2 * (marginx + rect_margin_x);
464: int nbpart = (int) ((max - min) / step);
465: int pixelstep = length / nbpart;
466: if (pixelstep < minpixelstep) {
467: minwidth = (minpixelstep * nbpart) + 2
468: * (marginx + rect_margin_x);
469: defaultWidth = minwidth;
470: }
471: updateSize(defaultWidth, defaultHeight);
472: pposition = new Point(pposition.x, marginy + rect_margin_y);
473: pointer.setLocation(pposition);
474: currentGraduation = graduations[0];
475: }
476:
477: /**
478: * Resizes this component so that it has width "width" and height "height".
479: * @param d - The dimension specifying the new size of this slider.
480: */
481: public void updateSize(Dimension d) {
482: updateSize(d.width, d.height);
483: }
484:
485: private Dimension oldsize = new Dimension(0, 0);
486:
487: /**
488: * Resizes this component so that it has width "width"
489: * and height "height".
490: * @param width - The new width of this slider
491: * @param height - The new height of this slider
492: */
493: public void updateSize(int width, int height) {
494: if ((oldsize.width != width) || (oldsize.height != height)) {
495: double value = getValue();
496: if (height < minheight)
497: height = minheight;
498: if (width < minwidth)
499: width = minwidth;
500: super .setSize(width, height);
501: oldsize = getSize();
502: this .width = width;
503: this .height = height;
504: rect_margin_y = (height - (2 * marginy)) / 3;
505: updateGraduationPosition();
506: pposition.y = marginy + rect_margin_y;
507: updatePointerPosition(value);
508: updateCurrentGraduation();
509: }
510: }
511:
512: /**
513: * Gets the mininimum size of this component.
514: * @return A dimension object indicating this slider's minimum size.
515: */
516: public Dimension getMinimumSize() {
517: return new Dimension(minwidth, minheight);
518: }
519:
520: /**
521: * Set the slider's color.
522: * @param color - the slider's color.
523: */
524: public void setColor(Color color) {
525: this .color = color;
526: }
527:
528: /**
529: * Set the minimum bound of the slider.
530: * Use initialize or SetBounds if you want to set more than one value.
531: * @param min - the min bound
532: * @see #setMax
533: * @see #setBounds
534: * @see #setStep
535: * @see #initialize
536: */
537: public void setMin(double min) {
538: this .min = min;
539: update();
540: }
541:
542: /**
543: * Set the maximum bound of the slider.
544: * Use initialize or SetBounds if you want to set more than one value.
545: * @param max - the max bound
546: * @see #setMin
547: * @see #setBounds
548: * @see #setStep
549: * @see #initialize
550: */
551: public void setMax(double max) {
552: this .max = max;
553: update();
554: }
555:
556: /**
557: * Set the bounds of the slider.
558: * @param min - the min bound
559: * @param max - the max bound
560: * @see #setMin
561: * @see #setMax
562: * @see #setStep
563: * @see #initialize
564: */
565: public void setBounds(double min, double max) {
566: this .min = min;
567: this .max = max;
568: update();
569: }
570:
571: /**
572: * Set the step of the slider.
573: * Use initialize or SetBounds if you want to set more than one value.
574: * @param step - the step between two position
575: * @see #setMin
576: * @see #setMax
577: * @see #setBounds
578: * @see #initialize
579: */
580: public void setStep(double step) {
581: this .step = step;
582: update();
583: }
584:
585: /**
586: * Initialize the slider's bounds and Step
587: * @param min - the min bound
588: * @param max - the max bound
589: * @param step - the step between two position
590: * @see #setMin
591: * @see #setMax
592: * @see #setBounds
593: * @see #initialize
594: */
595: public void initialize(double min, double max, double step) {
596: this .manageLong = false;
597: this .min = min;
598: this .max = max;
599: this .step = step;
600: update();
601: }
602:
603: public void initialize(double min, double max, double step,
604: boolean border) {
605: initialize(min, max, step);
606: this .border = border;
607: }
608:
609: public void initialize(long min, long max, long step) {
610: initialize((double) min, (double) max, (double) step);
611: this .manageLong = true;
612: update();
613: }
614:
615: public void initialize(long min, long max, long step, boolean border) {
616: initialize(min, max, step);
617: this .border = border;
618: }
619:
620: protected void update() {
621: setDefaultSize(min, max, step);
622: updateGraduationPosition();
623: if (graduations != null)
624: currentGraduation = graduations[0];
625: setVisible(true);
626: Component parent = getParent();
627: if (parent != null)
628: parent.validate();
629: }
630:
631: /**
632: * Constructs an invisible Slider.
633: * use initialize to define it.
634: * @param minPixelStep - the min step (in pixels) between two positions.
635: * @param border - if true draw a border arround the slider.
636: */
637: public Slider(int minPixelStep, boolean border) {
638: this ();
639: this .minpixelstep = minPixelStep;
640: this .border = border;
641: }
642:
643: /**
644: * Constructs an invisible Slider.
645: * use initialize to define it.
646: */
647: public Slider() {
648: pposition = new Point(marginx + rect_margin_x, marginy
649: + rect_margin_y);
650: pointer = new Pointer(pointerWidth, pointerHeight, pposition);
651: PointerClickListener clickListener = new PointerClickListener(
652: this );
653: PointerMotionListener motionListener = new PointerMotionListener(
654: this );
655: addMouseListener(clickListener);
656: addMouseMotionListener(motionListener);
657: setVisible(false);
658: }
659:
660: // TEST
661: public static void main(String argv[]) {
662: Frame f = new Frame("Slider");
663: f.setLayout(new GridLayout(6, 1));
664: Slider slider = null;
665:
666: slider = new Slider();
667: slider.initialize(0.0, 1.0, 0.1);
668: slider.setColor(Color.lightGray);
669: f.add(slider);
670:
671: slider = new Slider();
672: slider.initialize(0.0, 0.1, 0.01);
673: slider.setColor(Color.lightGray);
674: f.add(slider);
675:
676: slider = new Slider();
677: slider.initialize(0.0, 0.01, 0.0005);
678: slider.setColor(Color.lightGray);
679: f.add(slider);
680:
681: slider = new Slider();
682: slider.initialize(0, 100, 10);
683: slider.setColor(Color.lightGray);
684: f.add(slider);
685:
686: slider = new Slider();
687: slider.initialize(0, 30000, 5000);
688: slider.setColor(Color.lightGray);
689: f.add(slider);
690:
691: slider = new Slider();
692: slider.initialize(0, 30000, 1000);
693: slider.setColor(Color.lightGray);
694: f.add(slider);
695:
696: if (argv.length > 1) {
697: int width = Integer.parseInt(argv[0]);
698: int height = Integer.parseInt(argv[1]);
699: slider.setSize(width, height);
700: }
701: f.pack();
702: f.show();
703: }
704:
705: }
|