001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package javax.microedition.lcdui;
028:
029: /* import javax.microedition.lcdui.KeyConverter; */
030:
031: import com.sun.midp.lcdui.EventConstants;
032: import com.sun.midp.lcdui.Text;
033: import com.sun.midp.configurator.Constants;
034: import com.sun.midp.chameleon.skins.ChoiceGroupSkin;
035: import com.sun.midp.chameleon.skins.resources.ChoiceGroupResources;
036: import com.sun.midp.chameleon.skins.ScrollIndSkin;
037: import com.sun.midp.chameleon.skins.ScreenSkin;
038: import com.sun.midp.chameleon.layers.ScrollablePopupLayer;
039: import com.sun.midp.chameleon.layers.ScrollIndLayer;
040: import com.sun.midp.chameleon.CGraphicsUtil;
041: import com.sun.midp.chameleon.skins.resources.ScrollIndResourcesConstants;
042:
043: /**
044: * This is the Look &s; Feel implementation for ChoiceGroupPopup.
045: */
046: class ChoiceGroupPopupLFImpl extends ChoiceGroupLFImpl {
047:
048: /**
049: * Creates ChoiceGroupPopupLF for the passed in choiceGroup of
050: * Choice.POPUP type.
051: * @param choiceGroup the ChoiceGroup object associated with this view
052: */
053: ChoiceGroupPopupLFImpl(ChoiceGroup choiceGroup) {
054: super (choiceGroup);
055:
056: ChoiceGroupResources.load();
057:
058: viewable = new int[4];
059: popupLayer = new CGPopupLayer(this );
060: }
061:
062: /**
063: * Sets the content size in the passed in array.
064: * Content is calculated based on the availableWidth.
065: * size[WIDTH] and size[HEIGHT] should be set by this method.
066: * @param size The array that holds Item content size and location
067: * in Item internal bounds coordinate system.
068: * @param width The width available for this Item
069: */
070: public void lGetContentSize(int size[], int width) {
071:
072: // no label and empty popup => nothing is drawn
073: // no elements => only label is drawn
074: if (cg.numOfEls == 0) {
075: size[WIDTH] = size[HEIGHT] = 0;
076: return;
077: }
078:
079: int w = getAvailableContentWidth(Choice.POPUP, width);
080: int maxContentWidth = getMaxElementWidth(w);
081:
082: viewable[HEIGHT] = calculateHeight(w);
083:
084: int s = (selectedIndex < 0) ? 0 : selectedIndex;
085: size[HEIGHT] = cg.cgElements[s].getFont().getHeight()
086: + (2 * ChoiceGroupSkin.PAD_V);
087:
088: if (maxContentWidth < w) {
089: size[WIDTH] = width - w + maxContentWidth;
090: } else {
091: size[WIDTH] = width;
092: }
093: viewable[WIDTH] = size[WIDTH];
094: }
095:
096: // *****************************************************
097: // Package private methods
098: // *****************************************************
099:
100: /**
101: * Paints the content area of the ChoiceGroup POPUP.
102: * Graphics is translated to contents origin.
103: * @param g The graphics where Item content should be painted
104: * @param width The width available for the Item's content
105: * @param height The height available for the Item's content
106: */
107: void lPaintContent(Graphics g, int width, int height) {
108: // paint closed state of the popup
109:
110: // if there are no elements, we are done
111: if (cg.numOfEls == 0) {
112: return;
113: }
114:
115: // draw background
116: if (ChoiceGroupSkin.IMAGE_BG != null) {
117: CGraphicsUtil.draw9pcsBackground(g, 0, 0, width, height,
118: ChoiceGroupSkin.IMAGE_BG);
119: } else {
120: // draw widget instead of using images
121: CGraphicsUtil.drawDropShadowBox(g, 0, 0, width, height,
122: ChoiceGroupSkin.COLOR_BORDER,
123: ChoiceGroupSkin.COLOR_BORDER_SHD,
124: ChoiceGroupSkin.COLOR_BG);
125: }
126:
127: // draw icon
128: if (ChoiceGroupSkin.IMAGE_BUTTON_ICON != null) {
129: int w = ChoiceGroupSkin.IMAGE_BUTTON_ICON.getWidth();
130: int yOffset = height
131: - ChoiceGroupSkin.IMAGE_BUTTON_ICON.getHeight();
132: if (yOffset > 0) {
133: yOffset = yOffset / 2;
134: } else {
135: yOffset = 0;
136: }
137: width -= (w + 1);
138: if (ChoiceGroupSkin.IMAGE_BUTTON_BG != null) {
139: CGraphicsUtil.draw9pcsBackground(g, width, 1, w,
140: height - 2, ChoiceGroupSkin.IMAGE_BUTTON_BG);
141: }
142: g.drawImage(ChoiceGroupSkin.IMAGE_BUTTON_ICON, width,
143: yOffset + 1, Graphics.LEFT | Graphics.TOP);
144: width -= ChoiceGroupSkin.PAD_H;
145: }
146:
147: g.translate(ChoiceGroupSkin.PAD_H, ChoiceGroupSkin.PAD_V);
148:
149: int s = selectedIndex < 0 ? 0 : selectedIndex;
150:
151: // paint value
152:
153: int textOffset = 0;
154:
155: if (cg.cgElements[s].imageEl != null) {
156: int iX = g.getClipX();
157: int iY = g.getClipY();
158: int iW = g.getClipWidth();
159: int iH = g.getClipHeight();
160:
161: g.clipRect(0, 0, ChoiceGroupSkin.WIDTH_IMAGE,
162: ChoiceGroupSkin.HEIGHT_IMAGE);
163: g.drawImage(cg.cgElements[s].imageEl, 0, 0, Graphics.LEFT
164: | Graphics.TOP);
165: g.setClip(iX, iY, iW, iH);
166: textOffset = ChoiceGroupSkin.WIDTH_IMAGE
167: + ChoiceGroupSkin.PAD_H;
168: }
169:
170: g.translate(textOffset, 0);
171: Text.drawTruncString(g, cg.cgElements[s].stringEl,
172: cg.cgElements[s].getFont(),
173: (hasFocus) ? ScreenSkin.COLOR_FG_HL
174: : ChoiceGroupSkin.COLOR_FG, width);
175: g.translate(-textOffset, 0);
176:
177: g.translate(-ChoiceGroupSkin.PAD_H, -ChoiceGroupSkin.PAD_V);
178:
179: if (popupLayer.isSizeChanged() && cachedWidth != INVALID_SIZE) {
180: popupLayer.refresh();
181: popupLayer.setSizeChanged(false);
182: }
183: }
184:
185: /**
186: * Called by the system to indicate traversal has left this Item
187: * This function simply calls lCallTraverseOut() after obtaining LCDUILock.
188: */
189: void uCallTraverseOut() {
190: super .uCallTraverseOut();
191:
192: synchronized (Display.LCDUILock) {
193: if (popupLayer.isPopupOpen()) {
194: hilightedIndex = 0;
195: popupLayer.hide();
196: }
197: }
198: }
199:
200: /**
201: * Handle traversal within this ChoiceGroup
202: *
203: * @param dir the direction of traversal
204: * @param viewportWidth the width of the viewport
205: * @param viewportHeight the height of the viewport
206: * @param visRect the in/out rectangle for the internal traversal location
207: * @return true if traversal occurred within this ChoiceGroup
208: */
209: boolean lCallTraverse(int dir, int viewportWidth,
210: int viewportHeight, int[] visRect) {
211:
212: boolean ret = false;
213: // If we have no elements, or if the user pressed left/right,
214: // don't bother with the visRect and just return false
215: if (cg.numOfEls > 0) {
216:
217: // If we are a closed popup, don't bother with the visRect
218: // and return true on the initial traverse, false on subsequent
219: // traverses
220: if (popupLayer.isPopupOpen()) {
221: ret = super .lCallTraverse(dir, viewportWidth,
222: viewportHeight, visRect);
223: } else {
224: visRect[X] = 0;
225: visRect[Y] = 0;
226: visRect[HEIGHT] = bounds[HEIGHT];
227: visRect[WIDTH] = bounds[WIDTH];
228: }
229: }
230:
231: return ret;
232: }
233:
234: /**
235: * Handle traversal in the open popup
236: * @param dir - the direction of traversal (Canvas.UP, Canvas.DOWN)
237: * @param viewportWidth - the width of the viewport
238: * @param viewportHeight - the height of the viewport
239: * @return true if traverse event was handled, false - otherwise
240: */
241: boolean traverseInPopup(int dir, int viewportWidth,
242: int viewportHeight) {
243: boolean ret = false;
244: if (popupLayer.isPopupOpen()) {
245: if (cg.numOfEls > 1) {
246: int prevIndex = hilightedIndex;
247: int hilightY = 0;
248: switch (dir) {
249: case Canvas.UP:
250: if (hilightedIndex > 0) {
251: hilightedIndex--;
252: } else {
253: hilightedIndex = cg.numOfEls - 1;
254: }
255: break;
256: case Canvas.DOWN:
257: if (hilightedIndex < (cg.numOfEls - 1)) {
258: hilightedIndex++;
259: } else {
260: hilightedIndex = 0;
261: }
262: break;
263: default:
264: break;
265: }
266:
267: if (ret = prevIndex != hilightedIndex) {
268: for (int i = 0; i < hilightedIndex; i++) {
269: hilightY += elHeights[i];
270: }
271: int y2 = hilightY + elHeights[hilightedIndex];
272:
273: if (hilightY < viewable[Y]) {
274: viewable[Y] = hilightY;
275: } else if (y2 > viewable[Y] + viewportHeight) {
276: viewable[Y] = y2 - viewportHeight;
277: }
278: lRequestPaint();
279: }
280: }
281: } // popus is opened
282: return ret;
283: }
284:
285: /**
286: * Handle a key press event
287: *
288: * @param keyCode the key which was pressed
289: */
290: void uCallKeyPressed(int keyCode) {
291:
292: Form form = null;
293:
294: synchronized (Display.LCDUILock) {
295:
296: if (cg.numOfEls == 0) {
297: return;
298: }
299:
300: if (!popupLayer.isPopupOpen()) {
301: if (keyCode != Constants.KEYCODE_SELECT) {
302: return;
303: }
304: // show popup
305:
306: ScreenLFImpl sLF = (ScreenLFImpl) cg.owner.getLF();
307: int x = getInnerBounds(X) - sLF.viewable[X]
308: + contentBounds[X];
309: int y = getInnerBounds(Y) - sLF.viewable[Y]
310: + contentBounds[Y];
311: hilightedIndex = selectedIndex > 0 ? selectedIndex : 0;
312:
313: popupLayer.show(x, y, contentBounds[WIDTH],
314: contentBounds[HEIGHT], viewable[WIDTH],
315: viewable[HEIGHT], y, sLF.viewport[HEIGHT] - y
316: - contentBounds[HEIGHT]);
317: } else {
318:
319: // popup is closed when SELECT, LEFT or RIGHT is pressed;
320: // popup selection is changed only when SELECT is pressed
321: if (keyCode != Constants.KEYCODE_SELECT
322: && keyCode != Constants.KEYCODE_LEFT
323: && keyCode != Constants.KEYCODE_RIGHT) {
324: return;
325: }
326:
327: // IMPL_NOTE Check if we need notification if selected element
328: // did not change
329: if (keyCode == Constants.KEYCODE_SELECT) {
330: if (selectedIndex >= 0) {
331: lSetSelectedIndex(hilightedIndex, true);
332: form = (Form) cg.owner; // To be called outside the lock
333: }
334: }
335: hilightedIndex = 0;
336: popupLayer.hide();
337: }
338: lRequestPaint();
339: } // synchronized
340:
341: // Notify itemStateListener if necessary
342: if (form != null) {
343: form.uCallItemStateChanged(cg);
344: }
345: }
346:
347: /**
348: * Check if the pointer is clicked to the item
349: * @param x x coordinate of pointer
350: * @param y y coordinate of pointer
351: * @return true if the item contains the pointer, otherwise - false
352: */
353: boolean itemContainsPointer(int x, int y) {
354: if (!popupLayer.isPopupOpen()) {
355: return super .itemContainsPointer(x, y);
356: } else {
357: // We grab the whole screen, so consider all clicks contained
358: // by this item.
359: return true;
360: }
361: }
362:
363: /**
364: * Find the choice index inside of the list containing the pointer
365: * @param x x coordinate of pointer
366: * @param y y coordinate of pointer
367: * @return choice index, -1 - if index is not found
368: */
369: int getIndexByPointer(int x, int y) {
370: int popupLayer_bounds[] = popupLayer.getBounds();
371: int id = -1;
372: if (cg.numOfEls > 0) {
373: ScreenLFImpl sLF = (ScreenLFImpl) cg.owner.getLF();
374: x = x + (bounds[X] - sLF.viewable[X])
375: - popupLayer_bounds[X];
376: y = y + (bounds[Y] - sLF.viewable[Y])
377: - popupLayer_bounds[Y];
378:
379: if (x >= 0 && x <= popupLayer_bounds[WIDTH] && y >= 0
380: && y <= popupLayer_bounds[HEIGHT]) {
381: int visY = 0;
382: int i = 0;
383:
384: // calculate the scroll position and update the y coordinate accordingly.
385: y += viewable[Y];
386:
387: for (i = 0; i < cg.numOfEls; i++) {
388: int h = elHeights[i];
389: if (y > visY && y < visY + h) {
390: break;
391: }
392: visY += h;
393: }
394: if (i < cg.numOfEls) {
395: id = i;
396: }
397: }
398: }
399: return id;
400: }
401:
402: /**
403: * Called by the system to signal a pointer press
404: *
405: * @param x the x coordinate of the pointer down
406: * @param y the y coordinate of the pointer down
407: */
408: void uCallPointerPressed(int x, int y) {
409: itemWasPressed = true;
410: itemSelectedWhenPressed = false;
411: if (popupLayer.isPopupOpen()) {
412: // popupLayer.
413: int i = getIndexByPointer(x, y);
414: if (i >= 0) {
415: itemSelectedWhenPressed = true;
416: if (hilightedIndex != i) {
417: hilightedIndex = i;
418: uRequestPaint();//request paint as the highlighted changed
419: popupLayer.requestRepaint();//of course, we should repaint the popupLayer
420: getCurrentDisplay().serviceRepaints(
421: cg.owner.getLF());
422: }
423: } else {
424: hilightedIndex = 0;
425: popupLayer.hide();
426: uRequestPaint();
427: }
428: }
429: }
430:
431: /**
432: * Called by the system to signal a pointer release
433: *
434: * @param x the x coordinate of the pointer up
435: * @param y the x coordinate of the pointer up
436: */
437: void uCallPointerReleased(int x, int y) {
438: if (!itemWasPressed)
439: return;
440:
441: if (popupLayer.isPopupOpen()) {
442: // do not dismiss the popup until a new selection is made.
443: int i = getIndexByPointer(x, y);
444: if ((i >= 0 && hilightedIndex == i && itemSelectedWhenPressed)
445: || (!itemSelectedWhenPressed)) {
446: uCallKeyPressed(itemSelectedWhenPressed ?
447: // close the popup with highlighted item selected
448: Constants.KEYCODE_SELECT
449: :
450: // close the popup as cancel
451: Constants.KEYCODE_RIGHT);
452: }
453: } else if (super .itemContainsPointer(x + bounds[X], y
454: + bounds[Y])) {
455: uCallKeyPressed(Constants.KEYCODE_SELECT);
456: }
457: itemSelectedWhenPressed = false;
458: itemWasPressed = false;
459:
460: }
461:
462: /**
463: * Called by the system to indicate the size available to this Item
464: * has changed
465: *
466: * @param w the new width of the item's content area
467: * @param h the new height of the item's content area
468: */
469: void uCallSizeChanged(int w, int h) {
470: super .uCallSizeChanged(w, h);
471: synchronized (Display.LCDUILock) {
472: popupLayer.setSizeChanged(true);
473: }
474: }
475:
476: // *****************************************************
477: // Private methods
478: // *****************************************************
479:
480: /** pressed on a valid item in popup layer **/
481: private boolean itemSelectedWhenPressed = false;
482:
483: /** The PopupLayer that represents open state of this ChoiceGroup POPUP. */
484: CGPopupLayer popupLayer;
485:
486: /**
487: * Content of the popupLayer is drawn in ChoiceGroupPopupLFImpl.
488: * That content can be taller then the layer itself.
489: * viewable holds information of the current scroll position
490: * and the size of the content (X, Y, WIDTH, HEIGHT)
491: */
492: int viewable[];
493:
494: // *****************************************************
495: // Inner class
496: // *****************************************************
497: /**
498: * The following is the implementation of the ChoiceGroup POPUP
499: * open state. The popup is shown and hidden on a KEYCODE_SELECT.
500: * It is placed above or below the ChoiceGroup POPUP button (closed
501: * state) depending on the space available. If there are too
502: * many elements to display in the popup
503: * scrollbar will be added on the right.
504: * If possible popup should be displayed below the button.
505: * If possible the entire content of the popup should be seen.
506: */
507: class CGPopupLayer extends ScrollablePopupLayer {
508:
509: /**
510: * CGPopupLayer constructor. Sets ChoiceGroupPopupLFImpl that
511: * is associated with this CGPopupLayer.
512: * @param lf - The ChoiceGroupPopupLFImpl associated with this
513: * CGPopupLayer
514: */
515: CGPopupLayer(ChoiceGroupPopupLFImpl lf) {
516: super (
517: ScrollIndSkin.MODE == ScrollIndResourcesConstants.MODE_ARROWS ? ChoiceGroupSkin.IMAGE_POPUP_BG
518: : null, ChoiceGroupSkin.COLOR_BG);
519: this .lf = lf;
520: }
521:
522: /**
523: * Initializes internal structures of CGPopupLayer.
524: */
525: protected void initialize() {
526: super .initialize();
527: viewport = new int[4];
528: }
529:
530: /**
531: * Handles key event in the open popup
532: * @param type - The type of this key event (pressed, released)
533: * @param code - The code of this key event
534: * @return true if the key event was handled and false - otherwise
535: */
536: public boolean keyInput(int type, int code) {
537: if (type == EventConstants.PRESSED && lf != null) {
538:
539: if (code == Constants.KEYCODE_UP
540: || code == Constants.KEYCODE_DOWN) {
541: if (lf.traverseInPopup(KeyConverter
542: .getGameAction(code), viewport[WIDTH],
543: viewport[HEIGHT])) {
544: // the viewable[Y] is correct after traverseInPopup() calls,
545: // but we should update scroll position
546: updateScrollIndicator();
547: requestRepaint();
548: return true;
549: }
550: }
551:
552: lf.uCallKeyPressed(code);
553: }
554: // PopupLayers always swallow all key events
555: return true;
556: }
557:
558: /**
559: * Paints popup background (including borders) and scrollbar
560: * if it is present
561: * @param g - The graphics object to paint background on
562: */
563: protected void paintBackground(Graphics g) {
564: super .paintBackground(g);
565: // draw border if there is no background image
566: if (bgImage == null) {
567: g.setColor(ChoiceGroupSkin.COLOR_BORDER);
568: g.drawRect(0, 0, bounds[W] - 1, bounds[HEIGHT] - 1);
569:
570: g.setColor(ChoiceGroupSkin.COLOR_BORDER_SHD);
571: g.drawLine(1, 1, 1, bounds[HEIGHT] - 2);
572: }
573:
574: if (sbVisible
575: && ScrollIndSkin.MODE == ScrollIndResourcesConstants.MODE_ARROWS) {
576: int sbX = bounds[WIDTH]
577: - (ChoiceGroupSkin.WIDTH_SCROLL / 2) - 1;
578: int sbY = ChoiceGroupSkin.PAD_V;
579: int sbH = bounds[HEIGHT] - (2 * ChoiceGroupSkin.PAD_V);
580: int thumbY = sbY
581: + 4
582: + ((lf.viewable[Y] * (sbH - 8 - ChoiceGroupSkin.HEIGHT_THUMB)) / (lf.viewable[HEIGHT] - viewport[HEIGHT]));
583:
584: if (bgImage == null) {
585: // draw scrollbar with arrrows
586: g.setColor(ChoiceGroupSkin.COLOR_SCROLL);
587:
588: int sbY2 = sbY + sbH - 1;
589: g.drawLine(sbX, sbY, sbX, sbY2);
590:
591: g.drawLine(sbX - 2, sbY + 2, sbX - 1, sbY + 1);
592: g.drawLine(sbX + 1, sbY + 1, sbX + 2, sbY + 2);
593: g.drawLine(sbX - 2, sbY2 - 2, sbX - 1, sbY2 - 1);
594: g.drawLine(sbX + 1, sbY2 - 1, sbX + 2, sbY2 - 2);
595: }
596:
597: // draw scrollbar thumb
598: g.setColor(ChoiceGroupSkin.COLOR_THUMB);
599: g.fillRect(sbX - (ChoiceGroupSkin.WIDTH_THUMB / 2),
600: thumbY, ChoiceGroupSkin.WIDTH_THUMB,
601: ChoiceGroupSkin.HEIGHT_THUMB);
602: }
603: }
604:
605: /**
606: * Paints the content area of ChoiceGroup popup
607: * @param g - The Graphics object to paint content on
608: */
609: protected void paintBody(Graphics g) {
610: g.clipRect(viewport[X], viewport[Y], viewport[WIDTH],
611: viewport[HEIGHT]);
612:
613: g.translate(viewport[X] - lf.viewable[X], viewport[Y]
614: - lf.viewable[Y]);
615:
616: lf.lPaintElements(g, bounds[WIDTH], viewable[HEIGHT]);
617:
618: g.translate(-viewport[X] + lf.viewable[X], -viewport[Y]
619: + lf.viewable[Y]);
620: }
621:
622: /**
623: * Shows popup for the ChoiceGroup POPUP button that
624: * is drawn at the passed in location.
625: * It will determine if popup will be drawn above or
626: * below the ChoiceGroup POPUP button depending on the
627: * passed in info.
628: * @param buttonX - the x location of ChoiceGroup POPUP button
629: * in BodyLayer's coordinate system.
630: * @param buttonY - the y location of ChoiceGroup POPUP button
631: * in BodyLayer's coordinate system.
632: * @param buttonW - the width of ChoiceGroup POPUP button
633: * @param buttonH - the height of ChoiceGroup POPUP button
634: * @param elementsWidth - the width of the widest element in
635: * the popup
636: * @param elementsHeight - the height of all elements if they are
637: * drawn vertically one after another
638: * @param top - the amount of space available for popup above the
639: * ChoiceGroup POPUP button
640: * @param bottom - the amount of space available for popup below the
641: * ChoiceGroup POPUP button
642: */
643: void show(int buttonX, int buttonY, int buttonW, int buttonH,
644: int elementsWidth, int elementsHeight, int top,
645: int bottom) {
646: // popup with all elements displayed fits under the popup button
647:
648: if (elementsHeight + 1 <= bottom - ChoiceGroupSkin.PAD_V) {
649: setBounds(buttonX, buttonY + buttonH - 1, // hide top border
650: buttonW, elementsHeight + 2); // border width
651: popupDrawnDown = true;
652: sbVisible = false;
653:
654: // popup with all elements displayed fits above the popup button
655: } else if (elementsHeight + 1 <= top
656: - ChoiceGroupSkin.PAD_V) {
657: setBounds(buttonX, buttonY - elementsHeight - 1, // show top border
658: buttonW, elementsHeight + 2); // border width
659: popupDrawnDown = false;
660: sbVisible = false;
661:
662: } else if (bottom > top) { // there is more space at the bottom
663: setBounds(buttonX, buttonY + buttonH - 1, // hide top border width
664: buttonW, bottom - ChoiceGroupSkin.PAD_V);
665: popupDrawnDown = true;
666: sbVisible = true;
667:
668: } else { // there is more space at the top
669: setBounds(buttonX, buttonY - top + buttonH + 1, // show top border
670: buttonW, top - ChoiceGroupSkin.PAD_V + buttonH
671: + 1);
672: popupDrawnDown = false;
673: sbVisible = true;
674: }
675:
676: // set viewport in popup's coordinate system
677: viewport[X] = 2; // border width
678: viewport[Y] = 1; // border width
679: viewport[WIDTH] = viewable[WIDTH];
680: viewport[HEIGHT] = bounds[HEIGHT] - 2; // border width
681:
682: // ASSERT: since we are receiving key events,
683: // currentDisplay cannot be null.
684:
685: lf.getCurrentDisplay().showPopup(popupLayer);
686: popUpOpen = true;
687:
688: if (ScrollIndSkin.MODE == ScrollIndResourcesConstants.MODE_BAR) {
689: setScrollInd(ScrollIndLayer
690: .getInstance(ScrollIndSkin.MODE));
691: setBackground(sbVisible ? null
692: : ChoiceGroupSkin.IMAGE_POPUP_BG,
693: ChoiceGroupSkin.COLOR_BG);
694: }
695: updatePopupLayer(viewable[Y]);
696: }
697:
698: /**
699: * Hide popup for choice group
700: */
701:
702: void hide() {
703: if (scrollInd != null) {
704: scrollInd.setVisible(false);
705: sbVisible = false;
706: updateScrollIndicator();
707: setScrollInd(null);
708: }
709:
710: lf.getCurrentDisplay().hidePopup(popupLayer);
711: popUpOpen = false;
712: }
713:
714: /**
715: * Scroll content inside of the CouiceGroup.
716: * @param scrollType scrollType. Scroll type can be one of the following
717: * @see ScrollIndLayer.SCROLL_NONE
718: * @see ScrollIndLayer.SCROLL_PAGEUP
719: * @see ScrollIndLayer.SCROLL_PAGEDOWN
720: * @see ScrollIndLayer.SCROLL_LINEUP
721: * @see ScrollIndLayer.SCROLL_LINEDOWN or
722: * @see ScrollIndLayer.SCROLL_THUMBTRACK
723: * @param thumbPosition
724: */
725: public void scrollContent(int scrollType, int thumbPosition) {
726: switch (scrollType) {
727: case ScrollIndLayer.SCROLL_PAGEUP:
728: uScrollViewport(Canvas.UP);
729: break;
730: case ScrollIndLayer.SCROLL_PAGEDOWN:
731: uScrollViewport(Canvas.DOWN);
732: break;
733: case ScrollIndLayer.SCROLL_LINEUP:
734: uScrollByLine(Canvas.UP);
735: break;
736: case ScrollIndLayer.SCROLL_LINEDOWN:
737: uScrollByLine(Canvas.DOWN);
738: break;
739: case ScrollIndLayer.SCROLL_THUMBTRACK:
740: uScrollAt(thumbPosition);
741: break;
742: default:
743: break;
744: }
745: }
746:
747: /**
748: * Perform a line scrolling in the given direction. This method will
749: * attempt to scroll the view to show next/previous line.
750: *
751: * @param dir the direction of the flip, either DOWN or UP
752: */
753: private void uScrollByLine(int dir) {
754: int newY = viewable[Y];
755: switch (dir) {
756: case Canvas.UP:
757: newY -= PIXELS_LEFT_ON_PAGE;
758: if (newY < 0) {
759: newY = 0;
760: }
761: break;
762: case Canvas.DOWN:
763: newY += PIXELS_LEFT_ON_PAGE;
764: if (newY > viewable[HEIGHT] - viewport[HEIGHT]) {
765: newY = viewable[HEIGHT] - viewport[HEIGHT];
766: }
767: break;
768: }
769: updatePopupLayer(newY);
770: }
771:
772: /**
773: * Perform a page flip in the given direction. This method will
774: * attempt to scroll the view to show as much of the next page
775: * as possible. It uses the locations and bounds of the items on
776: * the page to best determine a new location - taking into account
777: * items which may lie on page boundaries as well as items which
778: * may span several pages.
779: *
780: * @param dir the direction of the flip, either DOWN or UP
781: */
782: private void uScrollViewport(int dir) {
783: int newY = viewable[Y];
784: switch (dir) {
785: case Canvas.UP:
786: newY -= viewport[HEIGHT] - PIXELS_LEFT_ON_PAGE;
787: if (newY < 0) {
788: newY = 0;
789: }
790: break;
791: case Canvas.DOWN:
792: newY += viewport[HEIGHT] - PIXELS_LEFT_ON_PAGE;
793: if (newY > viewable[HEIGHT] - viewport[HEIGHT]) {
794: newY = viewable[HEIGHT] - viewport[HEIGHT];
795: }
796: break;
797: }
798: updatePopupLayer(newY);
799: }
800:
801: /**
802: * Perform a scrolling at the given position.
803: * @param position
804: */
805: void uScrollAt(int position) {
806: int newY = (viewable[HEIGHT] - viewport[HEIGHT]) * position
807: / 100;
808: if (newY < 0) {
809: newY = 0;
810: } else if (newY > viewable[HEIGHT] - viewport[HEIGHT]) {
811: newY = viewable[HEIGHT] - viewport[HEIGHT];
812: }
813: updatePopupLayer(newY);
814: }
815:
816: /**
817: * This method initiate repaint of the popup layer
818: *
819: * @param newY
820: */
821: private void updatePopupLayer(int newY) {
822: viewable[Y] = newY;
823:
824: // correct hilighted index depending on new viewport. The hilighted item
825: // always has to be visible
826: if (hilightedIndex >= 0) {
827: // calculate y coordinates of hilighted item
828:
829: int vy1 = viewable[Y];
830: int vy2 = viewable[Y] + viewport[HEIGHT];
831: for (int i = 0, y = 0; i <= cg.numOfEls - 1; i++, y += elHeights[i]) {
832:
833: if (y >= vy1) {
834: if (y + elHeights[i] <= vy2) {
835: if (hilightedIndex <= i) {
836: hilightedIndex = i;
837: break;
838: }
839: } else {
840: if (hilightedIndex >= i) {
841: hilightedIndex = i;
842: if (i > 0 && y > vy1) {
843: hilightedIndex--;
844: }
845: break;
846: }
847: }
848: } else if (y + elHeights[i] >= vy2) {
849: hilightedIndex = i;
850: break;
851: }
852: }
853: }
854:
855: requestRepaint();
856: updateScrollIndicator();
857: }
858:
859: /**
860: * Updates the scroll indicator.
861: */
862: public void updateScrollIndicator() {
863: if (scrollInd != null) {
864: if (sbVisible) {
865: scrollInd
866: .setVerticalScroll(
867: (viewable[Y] * 100 / (viewable[HEIGHT] - viewport[HEIGHT])),
868: (viewport[HEIGHT] * 100 / viewable[HEIGHT]));
869: } else {
870: scrollInd.setVerticalScroll(0, 100);
871: }
872: super .updateScrollIndicator();
873: }
874: }
875:
876: /**
877: * Handle pointer events
878: * @param type pointer event type
879: * @param x x coordinate of pointer
880: * @param y y coordinate of pointer
881: * @return true if the event is processed and should not be passed
882: * to other layers, false - otherwise
883: */
884: public boolean pointerInput(int type, int x, int y) {
885: ScreenLFImpl sLF = (ScreenLFImpl) lf.item.owner.getLF();
886: int transX = x + this .bounds[X] + sLF.viewable[X]
887: - lf.bounds[X];
888: int transY = y + this .bounds[Y] + sLF.viewable[Y]
889: - lf.bounds[Y];
890:
891: boolean consume = true;
892:
893: if (!containsPoint(x + bounds[X], y + bounds[Y])) {
894: consume = false;
895: }
896:
897: switch (type) {
898: case EventConstants.PRESSED:
899: lf.uCallPointerPressed(transX, transY);
900: break;
901: case EventConstants.RELEASED:
902: lf.uCallPointerReleased(transX, transY);
903: break;
904: }
905: return consume;
906: }
907:
908: /**
909: * Update bounds of popup anf show
910: */
911: public void refresh() {
912: // show popup
913: if (popUpOpen) {
914: ScreenLFImpl sLF = (ScreenLFImpl) cg.owner.getLF();
915: int x = getInnerBounds(X) - sLF.viewable[X]
916: + contentBounds[X];
917: int y = getInnerBounds(Y) - sLF.viewable[Y]
918: + contentBounds[Y];
919:
920: popupLayer.show(x, y, contentBounds[WIDTH],
921: contentBounds[HEIGHT], viewable[WIDTH],
922: viewable[HEIGHT], y, sLF.viewport[HEIGHT] - y
923: - contentBounds[HEIGHT]);
924: }
925: }
926:
927: /**
928: * Return sizeChanged flag
929: * @return true if size change iccurs
930: */
931: public boolean isSizeChanged() {
932: return sizeChanged;
933: }
934:
935: /**
936: * Set sizeChanged flag
937: * @param sizeChanged true if size change occurs
938: */
939: public void setSizeChanged(boolean sizeChanged) {
940: this .sizeChanged = sizeChanged;
941: }
942:
943: /**
944: * Return Popup layer flag
945: * @return true if popup Layer is shown
946: */
947: public boolean isPopupOpen() {
948: return popUpOpen;
949: }
950:
951: /**
952: * Set popup Layer flag
953: */
954: public void setPopupOpen() {
955: this .popUpOpen = true;
956: }
957:
958: /** The ChoiceGroupPopupLFImpl associated with this popup */
959: ChoiceGroupPopupLFImpl lf; // = null;
960:
961: /**
962: * The viewport setting inside this popup (X, Y, WIDTH, HEIGHT).
963: * It is set in layer's coordinate system.
964: */
965: private int viewport[]; // = null;
966:
967: /** True if popup is drawn below Popup button, false - otherwise */
968: boolean popupDrawnDown; // = false;
969:
970: /** True if sb is present in the Popup layer, false - otherwise */
971: private boolean sbVisible; // = false;
972:
973: // True if size of screen was changed
974: private boolean sizeChanged;
975:
976: /** The state of the popup ChoiceGroup (false by default) */
977: private boolean popUpOpen; // = false;
978:
979: /**
980: * This is the number of pixels left from the previous "page"
981: * when a page up or down occurs
982: */
983: static final int PIXELS_LEFT_ON_PAGE = 15;
984:
985: }
986:
987: }
|