001: /*
002: * Javu WingS - Lightweight Java Component Set
003: * Copyright (c) 2005-2007 Krzysztof A. Sadlocha
004: * e-mail: ksadlocha@programics.com
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020:
021: package com.javujavu.javux.wings;
022:
023: import java.awt.AWTEvent;
024: import java.awt.AWTEventMulticaster;
025: import java.awt.Adjustable;
026: import java.awt.Dimension;
027: import java.awt.Graphics;
028: import java.awt.Point;
029: import java.awt.event.ActionEvent;
030: import java.awt.event.AdjustmentEvent;
031: import java.awt.event.AdjustmentListener;
032: import java.awt.event.MouseEvent;
033:
034: /**
035: * This class implements a scrollbar.
036: * <br>
037: * <b>This class is thread safe.</b>
038: **/
039: public class WingScroll extends WingComponent implements Adjustable {
040: private static final int NONE = -1;
041: private static final int LEFT = 0;
042: private static final int PAGELEFT = 1;
043: private static final int PAGERIGHT = 2;
044: private static final int RIGHT = 3;
045: private static final int THUMB = 4;
046: private static final int PARTS = 5;
047: private static final int NORMAL = 0;
048: private static final int HOVER = 1;
049: private static final int PRESSED = 2;
050: private static final int DISABLED = 3;
051: private static final int ICON = 4;
052: private static final int ICON_DISABLED = 5;
053: private static final int STYLES = 6;
054: private static final String[] partsHor = { "left", "pageleft",
055: "pageright", "right", "hthumb" };
056: private static final String[] partsVer = { "up", "pageup",
057: "pagedown", "down", "vthumb" };
058: private static final String[] styles = { "normal", "hover",
059: "pressed", "disabled", "normal.icon", "disabled.icon" };
060:
061: private int orientation;
062: private int value;
063: private int maximum;
064: private int minimum;
065: private int extent;
066: private int pageIncrement = 10;
067: private int lineIncrement = 1;
068:
069: private int width;
070: private int height;
071: private int thumbMin;
072: private WingImage[][] images;
073: private int[] partPos = new int[PARTS];
074: private int[] partWidth = new int[PARTS];
075: private int hover = NONE;
076: private int pressed = NONE;
077: private/*final*/WingTimer timer;
078: private Point mouse;
079: private int thumbTrack = -1;
080: private AdjustmentListener adjustmentListener;
081:
082: public WingScroll(int orientation) {
083: this (orientation, 0, 10, 0, 100);
084: }
085:
086: public WingScroll(int orientation, int value, int extent,
087: int minimum, int maximum) {
088: this .orientation = orientation;
089:
090: timer = new WingTimer(500, true, this );
091:
092: setValues(value, extent, minimum, maximum);
093:
094: enableEvents(AWTEvent.MOUSE_EVENT_MASK
095: | AWTEvent.MOUSE_MOTION_EVENT_MASK);
096:
097: WingToolkit.the().addWheelListener(this , this );
098: }
099:
100: public void loadSkin() {
101: String idx, idx2;
102: idx = WingSkin.catKeys(styleId, "scroll");
103:
104: stNormal = WingSkin.getStyle(idx, null, WingConst.NORMAL, null);
105: stDisabled = WingSkin.getStyle(idx, null, WingConst.DISABLED,
106: stNormal);
107:
108: String[] parts = (orientation == WingConst.HORIZONTAL) ? partsHor
109: : partsVer;
110: images = new WingImage[PARTS][STYLES];
111: for (int p = 0; p < images.length; p++) {
112: idx2 = WingSkin.catKeys(idx, parts[p]);
113: for (int s = 0; s < images[p].length; s++) {
114: if ((p == PAGELEFT || p == PAGERIGHT) && s >= ICON)
115: continue;
116:
117: if (s == HOVER || s == DISABLED)
118: images[p][s] = WingSkin.getImage(idx2, styles[s],
119: images[p][NORMAL]);
120: else if (s == ICON_DISABLED)
121: images[p][s] = WingSkin.getImage(idx2, styles[s],
122: images[p][ICON]);
123: else if (s == ICON)
124: images[p][s] = WingSkin.getImage(idx2, styles[s],
125: null);
126: else
127: images[p][s] = WingSkin.getImage(idx2, styles[s]);
128: }
129: }
130:
131: width = WingSkin.getInteger(styleId, "scroll.width",
132: images[LEFT][NORMAL].getWidth());
133: height = WingSkin.getInteger(styleId, "scroll.height",
134: images[LEFT][NORMAL].getHeight());
135: thumbMin = WingSkin.getInteger(styleId, "scroll.thumb.min", 8);
136: }
137:
138: public synchronized void setValues(int value, int extent,
139: int minimum, int maximum) {
140: if (maximum < minimum)
141: maximum = minimum;
142: if ((long) maximum - (long) minimum > Integer.MAX_VALUE) {
143: maximum = minimum + Integer.MAX_VALUE;
144: }
145:
146: if (extent < 0)
147: extent = 0;
148: if (extent > maximum - minimum)
149: extent = maximum - minimum;
150: if (value < minimum)
151: value = minimum;
152: if (value > maximum - extent)
153: value = maximum - extent;
154: this .value = value;
155: this .extent = extent;
156: this .minimum = minimum;
157: this .maximum = maximum;
158:
159: layoutParts();
160: repaint();
161: }
162:
163: public Dimension getPreferredSize() {
164: Dimension prefSize = wingPrefSize;
165: if (prefSize == null) {
166: if (orientation == WingConst.HORIZONTAL)
167: prefSize = new Dimension(100, height);
168: else
169: prefSize = new Dimension(width, 100);
170: wingPrefSize = prefSize;
171: }
172: return prefSize;
173: }
174:
175: private void layoutParts() {
176: int leftWidth, rightWidth, centerWidth, areaWidth;
177: if (images == null)
178: return;
179:
180: Dimension size = getSize();
181: if (orientation == WingConst.HORIZONTAL) {
182: leftWidth = images[LEFT][NORMAL].getWidth();
183: rightWidth = images[RIGHT][NORMAL].getWidth();
184: areaWidth = size.width;
185: } else {
186: leftWidth = images[LEFT][NORMAL].getHeight();
187: rightWidth = images[RIGHT][NORMAL].getHeight();
188: areaWidth = size.height;
189: }
190: centerWidth = areaWidth - leftWidth - rightWidth;
191: if (centerWidth <= 0) {
192: leftWidth = areaWidth / 2;
193: rightWidth = areaWidth - leftWidth;
194: centerWidth = 0;
195: }
196:
197: partPos[LEFT] = 0;
198: partWidth[LEFT] = leftWidth;
199: partPos[RIGHT] = areaWidth - rightWidth;
200: partWidth[RIGHT] = rightWidth;
201:
202: if (centerWidth <= 0) {
203: partWidth[PAGELEFT] = partWidth[PAGERIGHT] = partWidth[THUMB] = 0;
204:
205: } else {
206: int thumbWidth = (maximum > minimum) ? (int) (((long) (extent * centerWidth)) / ((long) (maximum - minimum)))
207: : centerWidth;
208:
209: if (thumbWidth < thumbMin)
210: thumbWidth = thumbMin;
211: if (centerWidth < thumbWidth) {
212: partWidth[THUMB] = 0;
213: partPos[PAGELEFT] = partWidth[LEFT];
214: partWidth[PAGELEFT] = centerWidth / 2;
215: } else {
216: partWidth[THUMB] = thumbWidth;
217: partPos[THUMB] = partWidth[LEFT];
218: long divisor = (maximum - minimum - extent);
219: if (divisor > 0)
220: partPos[THUMB] += (((long) (centerWidth - thumbWidth)) * ((long) (value - minimum)))
221: / divisor;
222: partPos[PAGELEFT] = partWidth[LEFT];
223: partWidth[PAGELEFT] = partPos[THUMB]
224: - partPos[PAGELEFT] + thumbWidth / 2;
225: }
226: partPos[PAGERIGHT] = partPos[PAGELEFT]
227: + partWidth[PAGELEFT];
228: partWidth[PAGERIGHT] = partPos[RIGHT] - partPos[PAGERIGHT];
229: }
230:
231: if (hover != NONE)
232: hover = partForPoint(mouse);
233: }
234:
235: public void doLayout() {
236: layoutParts();
237: }
238:
239: private void drawPart(Graphics g, int part, int x, int y,
240: int width, int height) {
241: if (width <= 0)
242: return;
243: if (part == THUMB && !isEnabled())
244: return;
245: if (orientation == WingConst.VERTICAL) {
246: int t = x;
247: x = y;
248: y = t;
249: t = width;
250: width = height;
251: height = t;
252: }
253: boolean disabled = !isEnabled()
254: || (part == LEFT && value == minimum)
255: || (part == RIGHT && value + extent == maximum);
256:
257: int style = (!isEnabled()) ? DISABLED
258: : (pressed == part && (hover == part || part == THUMB)) ? PRESSED
259: : (hover == part && pressed == NONE) ? HOVER
260: : NORMAL;
261:
262: images[part][style].drawImage(g, x, y, width, height, this );
263:
264: WingImage img = images[part][(disabled) ? ICON_DISABLED : ICON];
265: if (img == null)
266: return;
267: int dx = (width - img.getWidth());
268: int dy = (height - img.getHeight());
269: if (dx < 0 || dy < 0)
270: return;
271: img.drawImage(g, x + dx / 2, y + dy / 2, null);
272: }
273:
274: public void wingPaint(Graphics g) {
275: Dimension size = getSize();
276: int h = (orientation == WingConst.HORIZONTAL) ? size.height
277: : size.width;
278:
279: drawPart(g, LEFT, partPos[LEFT], 0, partWidth[LEFT], h);
280: drawPart(g, PAGELEFT, partPos[PAGELEFT], 0,
281: partWidth[PAGELEFT], h);
282: drawPart(g, PAGERIGHT, partPos[PAGERIGHT], 0,
283: partWidth[PAGERIGHT], h);
284: drawPart(g, RIGHT, partPos[RIGHT], 0, partWidth[RIGHT], h);
285: drawPart(g, THUMB, partPos[THUMB], 0, partWidth[THUMB], h);
286: }
287:
288: private synchronized int partForPoint(Point p) {
289: Dimension d = getSize();
290: if (p.x < 0 || p.y < 0 || p.x >= d.width || p.y >= d.height)
291: return NONE;
292:
293: int pos = (orientation == WingConst.HORIZONTAL) ? p.x : p.y;
294: if (partWidth[THUMB] > 0 && pos >= partPos[THUMB]
295: && pos < partPos[THUMB] + partWidth[THUMB]) {
296: return THUMB;
297: }
298:
299: if (pos < partWidth[LEFT])
300: return LEFT;
301: if (pos >= partPos[RIGHT])
302: return RIGHT;
303: return (pos < partPos[PAGERIGHT]) ? PAGELEFT : PAGERIGHT;
304: }
305:
306: protected void wingProcessMouseEvent(MouseEvent e) {
307: boolean enabled = isEnabled();
308: int id = e.getID();
309: int newHover = hover;
310: mouse = e.getPoint();
311: if (id == MouseEvent.MOUSE_ENTERED && enabled) {
312: if ((e.getModifiers() & (MouseEvent.BUTTON1_MASK
313: | MouseEvent.BUTTON2_MASK | MouseEvent.BUTTON3_MASK)) == 0) {
314: newHover = partForPoint(mouse);
315: }
316: } else if (id == MouseEvent.MOUSE_EXITED) {
317: newHover = NONE;
318: } else if (id == MouseEvent.MOUSE_PRESSED && enabled) {
319: pressed = partForPoint(mouse);
320:
321: if (pressed == THUMB) {
322: thumbTrack = ((orientation == WingConst.HORIZONTAL) ? mouse.x
323: : mouse.y)
324: - partPos[THUMB];
325: } else {
326: pressedAction();
327: timer.setDelay(500);
328: timer.start();
329: newHover = partForPoint(mouse);
330: }
331: repaint();
332: } else if (id == MouseEvent.MOUSE_RELEASED) {
333: pressed = NONE;
334: thumbTrack = -1;
335: timer.stop();
336: repaint();
337: } else if (enabled) {
338: if (id == MouseEvent.MOUSE_DRAGGED) {
339: if (thumbTrack != -1) {
340: int newValue;
341: synchronized (this ) {
342: int newThumbPos = ((orientation == WingConst.HORIZONTAL) ? mouse.x
343: : mouse.y)
344: - thumbTrack;
345: if (newThumbPos < partPos[PAGELEFT])
346: newThumbPos = partPos[PAGELEFT];
347: if (newThumbPos > partPos[RIGHT]
348: - partWidth[THUMB])
349: newThumbPos = partPos[RIGHT]
350: - partWidth[THUMB];
351: long divisor = (partWidth[PAGELEFT]
352: + partWidth[PAGERIGHT] - partWidth[THUMB]);
353: if (divisor != 0)
354: newValue = minimum
355: + (int) ((((long) (newThumbPos - partPos[PAGELEFT])) * ((long) (maximum
356: - minimum - extent))) / divisor);
357: else
358: newValue = value;
359: }
360: if (newValue != value) {
361: setValue(newValue);
362: postEvent(AdjustmentEvent.TRACK);
363: }
364: }
365: newHover = partForPoint(mouse);
366: } else if (id == MouseEvent.MOUSE_MOVED) {
367: newHover = partForPoint(mouse);
368: }
369: }
370: if (newHover != hover) {
371: hover = newHover;
372: repaint();
373: }
374: }
375:
376: public void wingProcessActionEvent(ActionEvent e) {
377: if (e.getSource() == timer) {
378: pressedAction();
379: timer.setDelay(100);
380: // timer.start();
381: } else
382: super .wingProcessActionEvent(e);
383: }
384:
385: private void pressedAction() {
386: if (pressed != hover)
387: return;
388:
389: boolean changed;
390: int type = 0;
391:
392: synchronized (this ) {
393: int oldValue = value;
394: if (pressed == LEFT) {
395: value -= lineIncrement;
396: if (value < minimum)
397: value = minimum;
398: type = AdjustmentEvent.UNIT_DECREMENT;
399: } else if (pressed == PAGELEFT) {
400: value -= pageIncrement;
401: if (value < minimum)
402: value = minimum;
403: type = AdjustmentEvent.BLOCK_DECREMENT;
404: } else if (pressed == RIGHT) {
405: value += lineIncrement;
406: if (value > maximum - extent)
407: value = maximum - extent;
408: type = AdjustmentEvent.UNIT_INCREMENT;
409: } else if (pressed == PAGERIGHT) {
410: value += pageIncrement;
411: if (value > maximum - extent)
412: value = maximum - extent;
413: type = AdjustmentEvent.BLOCK_INCREMENT;
414: }
415: changed = (value != oldValue);
416: }
417: if (changed) {
418: layoutParts();
419: postEvent(type);
420: repaint();
421: }
422: }
423:
424: public void addAdjustmentListener(AdjustmentListener l) {
425: adjustmentListener = AWTEventMulticaster.add(
426: adjustmentListener, l);
427: }
428:
429: public void removeAdjustmentListener(AdjustmentListener l) {
430: adjustmentListener = AWTEventMulticaster.remove(
431: adjustmentListener, l);
432: }
433:
434: protected void postEvent(int type) {
435: AdjustmentListener l = adjustmentListener;
436: if (l != null)
437: l.adjustmentValueChanged(new AdjustmentEvent(this ,
438: AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, type,
439: value));
440: }
441:
442: public int getUnitIncrement() {
443: return lineIncrement;
444: }
445:
446: public int getBlockIncrement() {
447: return pageIncrement;
448: }
449:
450: public void setUnitIncrement(int u) {
451: lineIncrement = (u > 0) ? u : 1;
452: }
453:
454: public void setBlockIncrement(int b) {
455: pageIncrement = (b > 0) ? b : 1;
456: }
457:
458: public int getMaximum() {
459: return maximum;
460: }
461:
462: public int getMinimum() {
463: return minimum;
464: }
465:
466: public int getOrientation() {
467: return orientation;
468: }
469:
470: public int getValue() {
471: return value;
472: }
473:
474: public int getVisibleAmount() {
475: return extent;
476: }
477:
478: public void setMaximum(int maximum) {
479: setValues(value, extent, minimum, maximum);
480: }
481:
482: public void setMinimum(int minimum) {
483: setValues(value, extent, minimum, maximum);
484: }
485:
486: public void setValue(int value) {
487: setValues(value, extent, minimum, maximum);
488: }
489:
490: public void setVisibleAmount(int extent) {
491: setValues(value, extent, minimum, maximum);
492: }
493:
494: public void mouseWheelMoved(Object src, int rotation) {
495: if (isVisible() && isEnabled()) {
496: setValue(value + rotation * lineIncrement);
497: postEvent(AdjustmentEvent.TRACK);
498: }
499: }
500: }
|