0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026:
0027: package javax.microedition.lcdui;
0028:
0029: /* import javax.microedition.lcdui.KeyConverter; */
0030:
0031: import com.sun.midp.log.Logging;
0032: import com.sun.midp.log.LogChannels;
0033: import com.sun.midp.configurator.Constants;
0034:
0035: // **************************************************************************
0036: // Package Private - These are all methods which delegate calls to
0037: // CustomItem application code, locking on the calloutLock
0038: // before doing so
0039: // **************************************************************************
0040:
0041: /**
0042: * This is the look and feel implementation for <code>CustomItem</code>.
0043: */
0044: class CustomItemLFImpl extends ItemLFImpl implements CustomItemLF {
0045:
0046: /**
0047: * Creates <code>CustomItemLF</code> associated with the passed in
0048: * <code>CustomItem</code>.
0049: *
0050: * @param ci the <code>CustomItem</code> associated with this
0051: * look & feel.
0052: */
0053: CustomItemLFImpl(CustomItem ci) {
0054: super (ci);
0055:
0056: dirtyRegion = new int[4];
0057:
0058: resetDirtyRegion();
0059:
0060: customItem = ci;
0061: }
0062:
0063: // **********************************************************
0064: // CustItemLF interface implementation
0065: // ***********************************************************
0066:
0067: /**
0068: * Notifies L&F that repaint of the entire custom item is needed.
0069: */
0070: public void lRepaint() {
0071:
0072: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0073: Logging.report(Logging.INFORMATION,
0074: LogChannels.LC_HIGHUI_ITEM_REPAINT,
0075: ">>> CustomItemLFImpl -- lRepaint()");
0076: }
0077:
0078: // content area is empty no repaint is needed
0079: if (contentImageData == null) {
0080: return;
0081: }
0082:
0083: setDirtyRegionFull();
0084:
0085: try {
0086: int pad = getItemPad();
0087: // We prune off the label area when doing a complete repaint
0088: lRequestPaint(pad, pad + getLabelHeight(bounds[WIDTH]),
0089: contentImageData.getWidth(), contentImageData
0090: .getHeight());
0091: } catch (Exception e) {
0092: Display.handleThrowable(e);
0093: }
0094: }
0095:
0096: /**
0097: * Notifies L&F that repaint of the specified region is needed.
0098: *
0099: * @param x the x coordinate of the origin of the dirty region
0100: * @param y the y coordinate of the origin of the dirty region
0101: * @param width the width of the dirty region
0102: * @param height the height of the dirty region
0103: */
0104: public void lRepaint(int x, int y, int width, int height) {
0105:
0106: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0107: Logging.report(Logging.INFORMATION,
0108: LogChannels.LC_HIGHUI_ITEM_REPAINT,
0109: ">>> CustomItemLFImpl -- lRepaint(" + x + "," + y
0110: + "," + width + "," + height + ")");
0111: }
0112:
0113: try {
0114:
0115: // Content area is empty there is no need to do anything
0116: if (contentImageData == null) {
0117: return;
0118: }
0119:
0120: int pad = getItemPad();
0121: // int lH = getLabelHeight(bounds[WIDTH]);
0122:
0123: // no need to do anything if the repaint region
0124: // is complete outside the content area
0125:
0126: if (x >= bounds[WIDTH] - 2 * pad
0127: || y >= bounds[HEIGHT] - 2 * pad /* - lH */
0128: || x + width <= 0 || y + height <= 0) {
0129: return;
0130: }
0131:
0132: // passed in region is expressed in the same coordinate system
0133: // as the dirtyRegion; join those 2 regions
0134: if (x <= 0) {
0135: dirtyRegion[X1] = 0;
0136: } else {
0137: // when dirty region is unset the following will be true
0138: // and dirtyRegion[X1] will be correctly set
0139: if (dirtyRegion[X1] > x) {
0140: dirtyRegion[X1] = x;
0141: }
0142: }
0143:
0144: if (y <= 0) {
0145: dirtyRegion[Y1] = 0;
0146: } else {
0147: // when dirty region is unset the following will be true
0148: // and dirtyRegion[Y1] will be correctly set
0149: if (dirtyRegion[Y1] > y) {
0150: dirtyRegion[Y1] = y;
0151: }
0152: }
0153:
0154: if (x + width >= bounds[WIDTH] - pad) {
0155: dirtyRegion[X2] = bounds[WIDTH] - pad;
0156: } else {
0157: // when dirty region is unset the following will be true
0158: // and dirtyRegion[X2] will be correctly set
0159: if (x + width > dirtyRegion[X2]) {
0160: dirtyRegion[X2] = x + width;
0161: }
0162: }
0163:
0164: if (y + height >= bounds[HEIGHT] - pad) {
0165: dirtyRegion[Y2] = bounds[HEIGHT] - pad;
0166: } else {
0167: // when dirty region is unset the following will be true
0168: // and dirtyRegion[Y2] will be correctly set
0169: if (y + height > dirtyRegion[Y2]) {
0170: dirtyRegion[Y2] = y + height;
0171: }
0172: }
0173:
0174: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0175: Logging.report(Logging.INFORMATION,
0176: LogChannels.LC_HIGHUI_ITEM_REPAINT,
0177: "after join ..... \t\t dirtyRegion ("
0178: + dirtyRegion[X1] + ","
0179: + dirtyRegion[Y1] + ") - ("
0180: + dirtyRegion[X2] + ","
0181: + dirtyRegion[Y2] + ")");
0182: }
0183:
0184: // obsolete - can use any number...
0185: super .lRequestPaint(0, 0, 0, 0);
0186:
0187: /*
0188: // repaint should be requested in Item's coordinate
0189: // system (translate by padding and labelHeight)
0190: super.lRequestPaint(dirtyRegion[X1] + pad,
0191: dirtyRegion[Y1] + pad + lH,
0192: dirtyRegion[X2] - dirtyRegion[X1] + 1,
0193: dirtyRegion[Y2] - dirtyRegion[Y1] + 1);
0194: */
0195:
0196: } catch (Exception e) {
0197: Display.handleThrowable(e);
0198: }
0199: }
0200:
0201: /**
0202: * Notifies L&F that <code>CustomItem</code> was invalidated.
0203: */
0204: public void lInvalidate() {
0205: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0206: Logging.report(Logging.INFORMATION,
0207: LogChannels.LC_HIGHUI_ITEM_LAYOUT,
0208: ">>> CustomItemLFImpl -- lInvalidate()");
0209: }
0210: setDirtyRegionFull();
0211: lRequestInvalidate(true, true);
0212: }
0213:
0214: /**
0215: * Get the preferred width of this <code>Item</code>, including
0216: * the preferred content width and room for the label.
0217: * This is the callback for <code>Item</code>'s public
0218: * getPreferredWidth() method.
0219: *
0220: * @param h the height to base the width size on
0221: *
0222: * @return the preferred width
0223: */
0224: private int uCallPreferredWidth(int h) {
0225:
0226: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0227: Logging.report(Logging.INFORMATION,
0228: LogChannels.LC_HIGHUI_ITEM_LAYOUT,
0229: "CustomItem -- uCallPreferredWidth h=" + h);
0230: }
0231:
0232: // SYNC NOTE: Call into app code. Must not hold LCDUILock.
0233: int pW = customItem.uGetContentSize(CustomItem.SIZE_PREF_WIDTH,
0234: h);
0235:
0236: // preferred width should be at least the minimum allowed,
0237: // this is checked and fixed at Item level
0238:
0239: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0240: Logging.report(Logging.INFORMATION,
0241: LogChannels.LC_HIGHUI_ITEM_LAYOUT,
0242: "\t -- uCallPreferredWidth item returned " + pW);
0243: }
0244:
0245: synchronized (Display.LCDUILock) {
0246: // if width is not locked item.lockedWidth will be -1
0247: // which means that all available width can be used
0248: int lw = getLabelWidth(item.lockedWidth);
0249:
0250: // if label is wider than customItem body, we're allowed
0251: // to make the body wider.
0252: if (lw > pW) {
0253: pW = lw;
0254: }
0255:
0256: if (pW > 0) {
0257: pW += 2 * getItemPad();
0258: }
0259: }
0260:
0261: return pW;
0262: }
0263:
0264: /**
0265: * Get the preferred height of this <code>Item</code>, including the
0266: * preferred content height and room for the label.
0267: * This is the callback for <code>Item</code>'s public
0268: * getPreferredHeight() method.
0269: *
0270: * @param w the width to base the height size on
0271: *
0272: * @return the preferred height
0273: */
0274: private int uCallPreferredHeight(int w) {
0275:
0276: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0277: Logging.report(Logging.INFORMATION,
0278: LogChannels.LC_HIGHUI_ITEM_LAYOUT,
0279: "CustomItem -- uCallPreferredHeight w=" + w);
0280: }
0281: // SYNC NOTE: Call into app code. Must not hold LCDUILock.
0282: int pH = customItem.uGetContentSize(
0283: CustomItem.SIZE_PREF_HEIGHT, w);
0284:
0285: // preferred height should be at least the minimum allowed,
0286: // this is checked and fixed at Item level
0287:
0288: synchronized (Display.LCDUILock) {
0289: pH += getLabelHeight(w);
0290:
0291: if (pH > 0) {
0292: pH += 2 * getItemPad();
0293: }
0294: }
0295:
0296: return pH;
0297: }
0298:
0299: /**
0300: * Get the minimum width of this <code>Item</code>, including the
0301: * minimum content width and room for the label.
0302: * This is the callback for <code>Item</code>'s public
0303: * getMinimumWidth() method.
0304: *
0305: * @return the minimum width
0306: */
0307: private int uCallMinimumWidth() {
0308: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0309: Logging.report(Logging.INFORMATION,
0310: LogChannels.LC_HIGHUI_ITEM_LAYOUT,
0311: "CustomItemLFImpl -- uCallMinimumWidth");
0312: }
0313: // SYNC NOTE: Call into app code. Must not hold LCDUILock.
0314: int mW = customItem.uGetContentSize(CustomItem.SIZE_MIN_WIDTH,
0315: 0);
0316:
0317: synchronized (Display.LCDUILock) {
0318: int lw = getLabelWidth(-1);
0319:
0320: // if label is wider than customItem body, we're allowed
0321: // to make the body wider.
0322: if (lw > mW) {
0323: mW = lw;
0324: }
0325:
0326: if (mW > 0) {
0327: mW += 2 * getItemPad();
0328: }
0329: }
0330:
0331: return mW;
0332: }
0333:
0334: /**
0335: * Get the minimum height of this <code>Item</code>, including the
0336: * minimum content height and room for the label.
0337: * This is the callback for <code>Item</code>'s public
0338: * getMinimumHeight() method.
0339: *
0340: * @return the minimum height
0341: */
0342: private int uCallMinimumHeight() {
0343: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0344: Logging.report(Logging.INFORMATION,
0345: LogChannels.LC_HIGHUI_ITEM_LAYOUT,
0346: "CustomItemLFImpl -- uCallMinimumHeight");
0347: }
0348: // SYNC NOTE: Call into app code. Must not hold LCDUILock.
0349: int mH = customItem.uGetContentSize(CustomItem.SIZE_MIN_HEIGHT,
0350: 0);
0351:
0352: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0353: Logging.report(Logging.INFORMATION,
0354: LogChannels.LC_HIGHUI_ITEM_LAYOUT,
0355: "CustomItem -- uCallMinimumHeight ret: " + mH);
0356: }
0357: synchronized (Display.LCDUILock) {
0358: mH += getLabelHeight(-1);
0359:
0360: if (mH > 0) {
0361: mH += 2 * getItemPad();
0362: }
0363: }
0364:
0365: return mH;
0366: }
0367:
0368: /**
0369: * Get minimum and preferred sizes from <code>CustomItem</code>
0370: * subclass and cache the result in super class.
0371: */
0372: public void uCallSizeRefresh() {
0373:
0374: if (isRequestedSizesValid()) {
0375: return;
0376: }
0377:
0378: int mw = uCallMinimumWidth();
0379: if (mw < 0)
0380: mw = 0;
0381:
0382: int mh = uCallMinimumHeight();
0383: if (mh < 0)
0384: mh = 0;
0385:
0386: int pw = uCallPreferredWidth(item.lockedHeight);
0387: if (pw < mw)
0388: pw = mw;
0389:
0390: int ph = uCallPreferredHeight(pw);
0391:
0392: synchronized (Display.LCDUILock) {
0393: // NOTE: When the item should shrink, the minimum size is used,
0394: // and the minimum size is calculated with the label
0395: // on the same line
0396: if (shouldHShrink() && item.label != null
0397: && item.label.length() > 0) {
0398: mh += DEFAULT_LABEL_HEIGHT;
0399: }
0400: if (ph < mh)
0401: ph = mh;
0402:
0403: // Cache the result in ItemLFImpl
0404: lSetRequestedSizes(mw, mh, pw, ph);
0405: }
0406: }
0407:
0408: /**
0409: * Overriding <code>ItemLFImpl</code>.
0410: * Notifies L&F of a label change in the corresponding
0411: * <code>Item</code>.
0412: *
0413: * @param label the new label string
0414: */
0415: public void lSetLabel(String label) {
0416: super .lSetLabel(label);
0417: }
0418:
0419: // JAVADOC COMMENT ELIDED
0420: public int lGetInteractionModes() {
0421:
0422: // removed support for traversal.
0423: // (MIDlets should use low level key events instead)
0424:
0425: int result = customItem.TRAVERSE_HORIZONTAL
0426: | customItem.TRAVERSE_VERTICAL | customItem.KEY_PRESS
0427: | customItem.KEY_RELEASE;
0428: if (Constants.REPEAT_SUPPORTED) {
0429: result = result | customItem.KEY_REPEAT;
0430: }
0431: if (Constants.POINTER_SUPPORTED) {
0432: result = result | customItem.POINTER_PRESS
0433: | customItem.POINTER_RELEASE;
0434: }
0435: if (Constants.MOTION_SUPPORTED) {
0436: result = result | customItem.POINTER_DRAG;
0437: }
0438: return result;
0439: }
0440:
0441: // *****************************************************
0442: // Package private methods
0443: // *****************************************************
0444:
0445: /**
0446: * Calculate minimum and preferred width and height of this item and
0447: * store the result in instance variables
0448: * minimumWidth, minimumHeight, preferredWidth and preferredHeight.
0449: *
0450: * Override the version in <code>ItemLFImpl</code> to do nothing.
0451: */
0452: void lGetRequestedSizes() {
0453: // Even if (isRequestedSizesValid() == false), we won't be able to
0454: // call into app code for the content sizes since we
0455: // are holding LCDUILock and may be even on event dispatch thread.
0456: // Do nothing here so the cached requested sizes will be used.
0457: }
0458:
0459: /**
0460: * Called by the system to indicate the size available to this
0461: * <code>Item</code> has changed.
0462: *
0463: * SYNC NOTE: Caller must not hold LCDUILock.
0464: *
0465: * @param w the new width of the item's content area
0466: * @param h the new height of the item's content area
0467: */
0468: void uCallSizeChanged(int w, int h) {
0469: try {
0470: synchronized (Display.calloutLock) {
0471: int pad = getItemPad();
0472: h -= 2 * pad + getLabelHeight(w);
0473: w -= 2 * pad;
0474: customItem.sizeChanged(w, h);
0475: }
0476: } catch (Throwable thr) {
0477: Display.handleThrowable(thr);
0478: }
0479: }
0480:
0481: /**
0482: * Called to paint this <code>CustomItem</code>.
0483: *
0484: * @param g the <code>Graphics</code> object to be used for
0485: * rendering the item.
0486: * @param w current width of the item in pixels
0487: * @param h current height of the item in pixels
0488: */
0489: void uCallPaint(Graphics g, int w, int h) {
0490:
0491: // ignore passed in graphics and use Custom Item's muttable image
0492:
0493: // contentImageData consists only of content so there is
0494: // no need to do translation by the label height and
0495: // around item padding
0496:
0497: int x1, x2, y1, y2;
0498:
0499: boolean visInViewport;
0500:
0501: synchronized (Display.LCDUILock) {
0502:
0503: // spec requires not to call CustomItem's paint
0504: // if content area width or height is 0 that is why:
0505: // if content area is empty or dirty region is unset
0506: // no repaint is needed
0507: if (contentImageData == null
0508: || dirtyRegion[Y2] <= dirtyRegion[Y1]
0509: || dirtyRegion[X2] <= dirtyRegion[X1]) {
0510: return;
0511: }
0512:
0513: x1 = dirtyRegion[X1];
0514: x2 = dirtyRegion[X2];
0515: y1 = dirtyRegion[Y1];
0516: y2 = dirtyRegion[Y2];
0517: visInViewport = visibleInViewport;
0518:
0519: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0520: Logging
0521: .report(Logging.INFORMATION,
0522: LogChannels.LC_HIGHUI_ITEM_REPAINT,
0523: "<<< \t\t Current clip: ("
0524: + g.getClipX()
0525: + ","
0526: + g.getClipY()
0527: + ") - ("
0528: + (g.getClipWidth())
0529: + ","
0530: + (g.getClipHeight())
0531: + ")"
0532: + "<<< \t\t clipping to: ("
0533: + dirtyRegion[X1]
0534: + ","
0535: + dirtyRegion[Y1]
0536: + ") - ("
0537: + (dirtyRegion[X2]
0538: - dirtyRegion[X1] + 1)
0539: + ","
0540: + (dirtyRegion[Y2]
0541: - dirtyRegion[Y1] + 1)
0542: + ")\n\n");
0543: }
0544:
0545: contentGraphics.setClip(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
0546:
0547: contentGraphics.setColor(Theme
0548: .getColor(Display.COLOR_BACKGROUND));
0549: contentGraphics.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
0550:
0551: contentGraphics.setColor(0);
0552: contentGraphics.setFont(Font.getDefaultFont());
0553: contentGraphics.setStrokeStyle(Graphics.SOLID);
0554:
0555: resetDirtyRegion();
0556:
0557: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0558: contentGraphics.drawLine(dirtyRegion[X1],
0559: dirtyRegion[Y1], dirtyRegion[X2]
0560: - dirtyRegion[X1] + 1, dirtyRegion[Y2]
0561: - dirtyRegion[Y1] + 1);
0562: Logging.report(Logging.INFORMATION,
0563: LogChannels.LC_HIGHUI_ITEM_REPAINT,
0564: "<<< CustomItemLFImpl -- uCallPaint "
0565: + nativeId + " / " + w + "x" + h);
0566: }
0567: }
0568:
0569: // SYNC NOTE: Call into app code. Must not hold LCDUILock.
0570: try {
0571: synchronized (Display.calloutLock) {
0572: // call to the MIDlet even if it is not visible
0573: // but do not refresh if it is not visible in viewport
0574:
0575: // SYNC NOTE: the change of contentGraphics and use of
0576: // contentGraphics happen on the event dispatch thread
0577: // so there is no problem of doing it outside of
0578: // the LCDUILock
0579: customItem.paint(contentGraphics, contentImageData
0580: .getWidth(), contentImageData.getHeight());
0581: }
0582:
0583: // Show the buffer onto screen
0584: synchronized (Display.LCDUILock) {
0585: // Need to check nativeId again since it might have been
0586: // deleted if the CustomItem is removed from the form
0587: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
0588: refresh0(nativeId, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
0589: }
0590: }
0591: } catch (Throwable thr) {
0592: Display.handleThrowable(thr);
0593: }
0594: }
0595:
0596: /**
0597: * Reset the values to invalid coordinates.
0598: */
0599: private void resetDirtyRegion() {
0600: dirtyRegion[X1] = 1000;
0601: dirtyRegion[Y1] = 1000;
0602: dirtyRegion[X2] = 0;
0603: dirtyRegion[Y2] = 0;
0604: }
0605:
0606: /**
0607: * Reset the values to invalid coordinates.
0608: */
0609: private void setDirtyRegionFull() {
0610: dirtyRegion[X1] = 0;
0611: dirtyRegion[Y1] = 0;
0612: if (contentImageData == null) {
0613: dirtyRegion[X2] = dirtyRegion[Y2] = 0;
0614: } else {
0615: dirtyRegion[X2] = contentImageData.getWidth();
0616: dirtyRegion[Y2] = contentImageData.getHeight();
0617: }
0618: }
0619:
0620: /**
0621: * Called by the system to notify internal traverse into the item.
0622: *
0623: * @param dir the direction of traversal
0624: * @param viewportWidth the width of the container's viewport
0625: * @param viewportHeight the height of the container's viewport
0626: * @param visRect_inout passes the visible rectangle into the method, and
0627: * returns the updated traversal rectangle from the
0628: * method
0629: *
0630: * @return <code>true</code> if internal traversal had occurred,
0631: * <code>false</code> if traversal should proceed out
0632: *
0633: * @see #getInteractionModes
0634: * @see #traverseOut
0635: * @see #TRAVERSE_HORIZONTAL
0636: * @see #TRAVERSE_VERTICAL
0637: */
0638: boolean uCallTraverse(int dir, int viewportWidth,
0639: int viewportHeight, int[] visRect_inout) {
0640: // the super implementation has to set the focus to this item
0641:
0642: boolean ret = super .uCallTraverse(dir, viewportWidth,
0643: viewportHeight, visRect_inout);
0644: try {
0645: synchronized (Display.calloutLock) {
0646: if (hasFocus) {
0647: int lH = getLabelHeight(bounds[WIDTH]);
0648:
0649: // We shave off the label height from the overall
0650: // item viewport
0651: visRect_inout[HEIGHT] -= lH;
0652:
0653: // NOTE: visRect_inout should reflect native scroll
0654: ret |= customItem.traverse(dir, viewportWidth,
0655: viewportHeight - lH, visRect_inout);
0656: // We shift the return value from the item's traverse
0657: // by the label height to give the real location
0658: visRect_inout[Y] += lH;
0659: if (ret) {
0660: setDirtyRegionFull();
0661: }
0662: }
0663: }
0664: } catch (Throwable thr) {
0665: Display.handleThrowable(thr);
0666: }
0667: return ret;
0668: }
0669:
0670: /**
0671: * Called by the system to indicate traversal has left this
0672: * <code>Item</code>.
0673: *
0674: * @see #getInteractionModes
0675: * @see #traverse
0676: * @see #TRAVERSE_HORIZONTAL
0677: * @see #TRAVERSE_VERTICAL
0678: */
0679: void uCallTraverseOut() {
0680: super .uCallTraverseOut();
0681:
0682: try {
0683: synchronized (Display.calloutLock) {
0684: customItem.traverseOut();
0685: setDirtyRegionFull();
0686: }
0687: } catch (Throwable thr) {
0688: Display.handleThrowable(thr);
0689: }
0690: }
0691:
0692: /**
0693: * Called by the system to signal a key press.
0694: *
0695: * @param keyCode the key code of the key that has been pressed.
0696: *
0697: * @see #getInteractionModes
0698: */
0699: void uCallKeyPressed(int keyCode) {
0700: ItemCommandListener cl = null;
0701: Command defaultCmd = null;
0702: FormLFImpl ownerLFImpl = null;
0703: boolean internalTraverse = false;
0704: int vis_Rect[] = new int[4];
0705: // vpY1 the y coordinate of the top left visible pixel
0706: int vpY1 = 0;
0707: // vpY2 the y coordinate of bottom left visible pixel
0708: int vpY2 = 0;
0709:
0710: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0711: Logging
0712: .report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
0713: "CustomItemLFImpl: got uCallKeyPressed: "
0714: + keyCode);
0715: }
0716:
0717: synchronized (Display.LCDUILock) {
0718: cl = customItem.commandListener;
0719: defaultCmd = customItem.defaultCommand;
0720:
0721: if (item.owner != null) {
0722: ownerLFImpl = (FormLFImpl) item.owner.getLF();
0723: }
0724: } // synchronized
0725:
0726: // SYNC NOTE: The call to the listener must occur outside the lock
0727:
0728: try {
0729: // SYNC NOTE: We lock on calloutLock around any calls
0730: // into application code
0731: synchronized (Display.calloutLock) {
0732: if ((cl != null) && (defaultCmd != null)
0733: && (keyCode == Constants.KEYCODE_SELECT)) {
0734: cl.commandAction(defaultCmd, customItem);
0735: } else {
0736: customItem.keyPressed(keyCode);
0737: }
0738: } // end synchronized
0739: } catch (Throwable thr) {
0740: Display.handleThrowable(thr);
0741: }
0742:
0743: synchronized (Display.LCDUILock) {
0744: if (internalTraverse) {
0745: scrollforInternalTraversal(ownerLFImpl, vis_Rect);
0746: }
0747: } // end synchronized
0748: }
0749:
0750: /**
0751: * Called by the system to signal a key release.
0752: *
0753: * @param keyCode the key code of the key that has been released.
0754: *
0755: * @see #getInteractionModes
0756: */
0757: void uCallKeyReleased(int keyCode) {
0758: try {
0759: synchronized (Display.calloutLock) {
0760: customItem.keyReleased(keyCode);
0761: }
0762: } catch (Throwable thr) {
0763: Display.handleThrowable(thr);
0764: }
0765: }
0766:
0767: /**
0768: * Called by the system to signal a key repeat.
0769: *
0770: * @param keyCode the key code of the key that has been repeated.
0771: *
0772: * @see #getInteractionModes
0773: */
0774: void uCallKeyRepeated(int keyCode) {
0775: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0776: Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
0777: "CustomItemLFImpl: uCallKeyRepeated!! " + keyCode);
0778: }
0779:
0780: try {
0781: synchronized (Display.calloutLock) {
0782: customItem.keyRepeated(keyCode);
0783: }
0784: } catch (Throwable thr) {
0785: Display.handleThrowable(thr);
0786: }
0787: }
0788:
0789: /**
0790: * Called by the system to signal a pointer press.
0791: *
0792: * @param x the x coordinate of the pointer down
0793: * @param y the y coordinate of the pointer down
0794: *
0795: * @see #getInteractionModes
0796: */
0797: void uCallPointerPressed(int x, int y) {
0798: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0799: Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
0800: "*-* CustomItem: uCallPointerPressed *-*");
0801: }
0802: try {
0803: synchronized (Display.calloutLock) {
0804: customItem.pointerPressed(x, y);
0805: }
0806: } catch (Throwable thr) {
0807: Display.handleThrowable(thr);
0808: }
0809: }
0810:
0811: /**
0812: * Called by the system to signal a pointer release.
0813: *
0814: * @param x the x coordinate of the pointer up
0815: * @param y the x coordinate of the pointer up
0816: *
0817: * @see #getInteractionModes
0818: */
0819: void uCallPointerReleased(int x, int y) {
0820: try {
0821: synchronized (Display.calloutLock) {
0822: customItem.pointerReleased(x, y);
0823: }
0824: } catch (Throwable thr) {
0825: Display.handleThrowable(thr);
0826: }
0827: }
0828:
0829: /**
0830: * Called by the system to signal a pointer drag.
0831: *
0832: * @param x the x coordinate of the pointer drag
0833: * @param y the x coordinate of the pointer drag
0834: *
0835: * @see #getInteractionModes
0836: */
0837: void uCallPointerDragged(int x, int y) {
0838: try {
0839: synchronized (Display.calloutLock) {
0840: customItem.pointerDragged(x, y);
0841: }
0842: } catch (Throwable thr) {
0843: Display.handleThrowable(thr);
0844: }
0845: }
0846:
0847: /**
0848: * Override <code>ItemLFImpl</code> method to
0849: * set the dirty region and the content buffer
0850: * before showing the native resource.
0851: */
0852: void lShowNativeResource() {
0853: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
0854: setContentBuffer0(nativeId, contentImageData);
0855: super .lShowNativeResource();
0856: }
0857: }
0858:
0859: /**
0860: * Override <code>ItemLFImpl</code> method to reset
0861: * the dirty region before hiding the native resource
0862: */
0863: void lHideNativeResource() {
0864: resetDirtyRegion();
0865: super .lHideNativeResource();
0866: }
0867:
0868: /**
0869: * Overrides the default method in <code>ItemLFImpl</code>.
0870: * Called by the system to notify this <code>CustomItem</code>
0871: * that it is being shown. This method will be called only
0872: * if this <code>CustomItem</code> was made visible.
0873: *
0874: * The default implementation changes the visibleInViewport flag.
0875: */
0876: void uCallShowNotify() {
0877:
0878: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0879: Logging.report(Logging.INFORMATION,
0880: LogChannels.LC_HIGHUI_ITEM_REPAINT,
0881: "CustomItemLFImpl: uCallShowNotify()");
0882: }
0883:
0884: super .uCallShowNotify();
0885:
0886: try {
0887: synchronized (Display.calloutLock) {
0888: customItem.showNotify();
0889: }
0890:
0891: } catch (Throwable thr) {
0892: Display.handleThrowable(thr);
0893: }
0894: }
0895:
0896: /**
0897: * Overrides the default method to set dirty region to full size.
0898: */
0899: void lCallShowNotify() {
0900: super .lCallShowNotify();
0901: setDirtyRegionFull();
0902: }
0903:
0904: /**
0905: * Overrides the default method in <code>ItemLFImpl</code>.
0906: * Called by the system to notify this <code>CustomItem</code>
0907: * that it is being hidden. This method will be called only
0908: * if this <code>CustomItem</code> was hidden.
0909: *
0910: * The default implementation changes the visibleInViewport flag.
0911: */
0912: void uCallHideNotify() {
0913:
0914: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0915: Logging.report(Logging.INFORMATION,
0916: LogChannels.LC_HIGHUI_ITEM_REPAINT,
0917: "CustomItemLFImpl: uCallHideNotify()");
0918: }
0919:
0920: super .uCallHideNotify();
0921:
0922: try {
0923: synchronized (Display.calloutLock) {
0924: customItem.hideNotify();
0925: }
0926: } catch (Throwable thr) {
0927: Display.handleThrowable(thr);
0928: }
0929: }
0930:
0931: /**
0932: * Sets custom item's size
0933: *
0934: * @param w - the new width of the item
0935: * @param h - the new height of the item
0936: */
0937: void lSetSize(int w, int h) {
0938: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0939: Logging.report(Logging.INFORMATION,
0940: LogChannels.LC_HIGHUI_ITEM_LAYOUT,
0941: " CustomItemLFImpl - setSize: " + w + "x" + h);
0942: }
0943:
0944: if (w == bounds[WIDTH] && h == bounds[HEIGHT]) {
0945: return;
0946: }
0947: int pad = getItemPad();
0948: int contentW = w - 2 * pad;
0949: int contentH = h - 2 * pad - getLabelHeight(w);
0950:
0951: if (contentImageData == null
0952: || contentImageData.getWidth() != contentW
0953: || contentImageData.getHeight() != contentH) {
0954: if (contentW > 0 && contentH > 0) {
0955: Image contentImage = Image.createImage(contentW,
0956: contentH);
0957: contentImageData = contentImage.getImageData();
0958: if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) {
0959: setContentBuffer0(nativeId, contentImageData);
0960: }
0961: contentGraphics = contentImage.getGraphics();
0962: // no need to paint background of the newly created
0963: // Mutable image since according to the spec
0964: // it will be set to white color
0965: setDirtyRegionFull();
0966: }
0967: }
0968:
0969: super .lSetSize(w, h);
0970: }
0971:
0972: /**
0973: * Get label height.
0974: *
0975: * @param w width available for label
0976: *
0977: * @return label height
0978: */
0979: private int getLabelHeight(int w) {
0980:
0981: // check empty label case:
0982: if (customItem.label == null || customItem.label.equals("")
0983: || (w >= 0 && w <= 2 * getItemPad())) {
0984: return 0;
0985: }
0986:
0987: if (w > 0) {
0988: w -= 2 * getItemPad();
0989: } else if (w != -1) {
0990: w = -1;
0991: }
0992:
0993: // query native for real preferred size
0994: boolean wasNoNative = (nativeId == DisplayableLFImpl.INVALID_NATIVE_ID);
0995:
0996: // Native resource not yet created, do it now
0997: if (wasNoNative) {
0998: createTempNativeResource();
0999: }
1000:
1001: int h = getLabelHeight0(nativeId, w);
1002:
1003: if (wasNoNative) {
1004: deleteNativeResource();
1005: }
1006:
1007: return h;
1008: }
1009:
1010: /**
1011: * Gets label width used in native. If -1 is passed as a width
1012: * parameter the whole available width should be used. Note
1013: * that padding will be subtracted from the passed in width.
1014: *
1015: * @param w the width to be used to get label width.
1016: * @return actual width of the label.
1017: */
1018: private int getLabelWidth(int w) {
1019:
1020: // check empty label case:
1021: if (customItem.label == null || customItem.label.equals("")
1022: || (w >= 0 && w <= getItemPad())) {
1023: return 0;
1024: }
1025:
1026: if (w > 0) {
1027: w -= 2 * getItemPad();
1028: } else if (w != -1) {
1029: w = -1;
1030: }
1031:
1032: // query native for real preferred size
1033: boolean wasNoNative = (nativeId == DisplayableLFImpl.INVALID_NATIVE_ID);
1034:
1035: // Native resource not yet created, do it now
1036: if (wasNoNative) {
1037: createTempNativeResource();
1038: }
1039:
1040: int lw = getLabelWidth0(nativeId, w);
1041:
1042: if (wasNoNative) {
1043: deleteNativeResource();
1044: }
1045:
1046: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1047: Logging.report(Logging.INFORMATION,
1048: LogChannels.LC_HIGHUI_ITEM_REPAINT,
1049: "CustomItemLFImpl: getLabelWidth(" + w
1050: + ")... nativeId==" + nativeId
1051: + " \t returning: " + lw);
1052: }
1053: return lw;
1054: }
1055:
1056: /**
1057: * Returns item pad used in native. The value is fetched only once
1058: * and cached in Java.
1059: *
1060: * @return item pad used in native
1061: */
1062: private int getItemPad() {
1063:
1064: if (ITEM_PAD == 0) {
1065: // query native for real preferred size
1066: boolean wasNoNative = (nativeId == DisplayableLFImpl.INVALID_NATIVE_ID);
1067:
1068: // Native resource not yet created, do it now
1069: if (wasNoNative) {
1070: createTempNativeResource();
1071: }
1072:
1073: ITEM_PAD = getItemPad0(nativeId);
1074:
1075: if (wasNoNative) {
1076: deleteNativeResource();
1077: }
1078: }
1079:
1080: return ITEM_PAD;
1081: }
1082:
1083: /**
1084: * The <code>CustomItem</code> associated with this view.
1085: */
1086: private CustomItem customItem;
1087:
1088: /**
1089: * Create native resource for current <code>CustomItem</code>.
1090: * Override function in <code>ItemLFImpl</code>.
1091: *
1092: * @param ownerId Owner screen's native resource id.
1093: */
1094: void createNativeResource(int ownerId) {
1095: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1096: Logging
1097: .report(
1098: Logging.INFORMATION,
1099: LogChannels.LC_HIGHUI,
1100: "****************************************"
1101: + "CustomItem: createNativeResource -- ownerId="
1102: + ownerId
1103: + "bounds are: "
1104: + bounds[X]
1105: + ","
1106: + bounds[Y]
1107: + " -- "
1108: + bounds[WIDTH]
1109: + "x"
1110: + bounds[HEIGHT]
1111: + "****************************************");
1112: }
1113: nativeId = createNativeResource0(ownerId, customItem.label,
1114: customItem.layout);
1115: }
1116:
1117: /**
1118: * Called by <code>Display</code> to notify an <code>ItemLF</code>
1119: * in current <code>FormLF</code> of a change in its peer state.
1120: * Return false since no notification is needed.
1121: * @param hint notification sub-type defined as above
1122: *
1123: * @return always <code>false</code> since no internal state changes.
1124: */
1125: boolean uCallPeerStateChanged(int hint) {
1126: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1127: Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
1128: "-=- CustomItemLFImpl uCallPeerStateChanged "
1129: + hint);
1130: }
1131: return false;
1132: }
1133:
1134: // *****************************************************
1135: // Private methods
1136: // *****************************************************
1137:
1138: /**
1139: * Called by traverse method to
1140: * scroll the CustomItem for InternalTraversal.
1141: * @param ownerLFImpl FormLFImpl
1142: * @param vis_Rect the updated traversal rectangle from
1143: * the traverse method
1144: */
1145: private void scrollforInternalTraversal(FormLFImpl ownerLFImpl,
1146: int[] vis_Rect) {
1147: int yOffset = 0;
1148:
1149: // check the returned vis_Rect
1150: // to check the validity of x,y,w,h
1151: // x and y values are relative to item's origin
1152:
1153: if (vis_Rect[X] < 0) {
1154: vis_Rect[X] = 0;
1155: }
1156: if (vis_Rect[WIDTH] < 0) {
1157: vis_Rect[WIDTH] = 0;
1158: }
1159: if (vis_Rect[X] > bounds[WIDTH]) {
1160: vis_Rect[X] = bounds[WIDTH];
1161: }
1162: if (vis_Rect[Y] < 0) {
1163: vis_Rect[Y] = 0;
1164: }
1165: if (vis_Rect[HEIGHT] < 0) {
1166: vis_Rect[HEIGHT] = 0;
1167: }
1168: if (vis_Rect[Y] > bounds[HEIGHT]) {
1169: vis_Rect[Y] = bounds[HEIGHT];
1170: }
1171:
1172: // shouldn't exceed viewportHeight
1173: if (vis_Rect[HEIGHT] > ownerLFImpl.height) {
1174: vis_Rect[HEIGHT] = ownerLFImpl.height;
1175: }
1176: // shouldn't exceed viewportwidth
1177: if (vis_Rect[WIDTH] > ownerLFImpl.width) {
1178: vis_Rect[WIDTH] = ownerLFImpl.width;
1179: }
1180:
1181: // current scroll position
1182: int vpY1 = ownerLFImpl.getScrollPosition0();
1183: // vpY2 the y coordinate of bottom left visible pixel
1184: int vpY2 = vpY1 + ownerLFImpl.height;
1185:
1186: // convert vis_Rect Y into form's co-ordinates
1187: vis_Rect[Y] += bounds[Y];
1188:
1189: int itemHeight = vis_Rect[HEIGHT];
1190: int vpHeight = ownerLFImpl.height;
1191:
1192: // make sure that the item is visible
1193: ItemLFImpl itemLFInFocus = ownerLFImpl.getItemInFocus();
1194: if ((itemLFInFocus != null)
1195: && (itemLFInFocus.nativeId != ownerLFImpl.INVALID_NATIVE_ID)) {
1196: // find the y offset depending on
1197: // the vis_Rect returned
1198:
1199: int vpMidpoint = vpY1 + vpHeight / 2;
1200: int itemMidpoint = vis_Rect[Y] + itemHeight / 2;
1201:
1202: if (itemHeight <= vpHeight) { // center it
1203: // HI DECISION: short circuit scrolling all together
1204: // if the complete vis_Rect area is in the viewport
1205:
1206: if (itemMidpoint > vpMidpoint) { // lower
1207: yOffset = itemMidpoint - vpMidpoint;
1208: } else if (itemMidpoint < vpMidpoint) { // upper
1209: yOffset = vpMidpoint - itemMidpoint;
1210: }
1211: } else if (itemHeight > vpHeight) { // top it
1212: if (itemMidpoint > vpMidpoint) { // lower
1213: yOffset = vis_Rect[Y] - vpY1;
1214: } else if (itemMidpoint < vpMidpoint) { // upper
1215: yOffset = vpY1 - vis_Rect[Y];
1216: }
1217: }
1218:
1219: // QT makes this visible with at least
1220: // 50 pixel margins (if possible, otherwise centered)
1221: ownerLFImpl.setCurrentItem0(nativeId,
1222: itemLFInFocus.nativeId, yOffset);
1223: }
1224: }
1225:
1226: /**
1227: * KNI function that creates native resource for current
1228: * <code>CustomItem</code>.
1229: *
1230: * @param ownerId Owner screen's native resource id
1231: * (<code>MidpDisplayable *</code>)
1232: * @param label - label to be used for this <code>Item</code>
1233: * @param layout - layout directive associated with this <code>Item</code>
1234: *
1235: * @return native resource id (<code>MidpItem *</code>) of this
1236: * <code>CustomItem</code>
1237: */
1238: private static native int createNativeResource0(int ownerId,
1239: String label, int layout);
1240:
1241: /**
1242: * Call to blit the paint result to the <code>CustomItem</code>.
1243: *
1244: * @param nativeId native resource id for this <code>Item</code>
1245: * @param x coordinate relative to the widget
1246: * @param y coordinate relative to the widget
1247: * @param width invalid width to repaint. If < 0 than paint all.
1248: * @param height invalid height to repaint. If < 0 than paint all.
1249: */
1250: private static native void refresh0(int nativeId, int x, int y,
1251: int width, int height);
1252:
1253: /**
1254: * Returns label height in native widget.
1255: *
1256: * @param nativeId native resource id for this <code>Item</code>
1257: * @param width tentative width used to calculate the height
1258: *
1259: * @return label height in native widget
1260: */
1261: private static native int getLabelHeight0(int nativeId, int width);
1262:
1263: /**
1264: * Get the actual width required for the label.
1265: *
1266: * @param nativeId native resource id for this <code>Item</code>
1267: * @param contentWidth hint for the native widget to decide on label layout
1268: *
1269: * @return actual label width in native widget
1270: */
1271: private static native int getLabelWidth0(int nativeId,
1272: int contentWidth);
1273:
1274: /**
1275: * Returns item pad used in native.
1276: *
1277: * @param nativeId native resource id for this <code>Item</code>
1278: *
1279: * @return item pad used in native
1280: */
1281: private static native int getItemPad0(int nativeId);
1282:
1283: /**
1284: * Sets the content buffer. All paints are done to that buffer.
1285: * When paint is processed snapshot of the buffer is flushed to
1286: * the native resource content area.
1287: * @param nativeId native resource is for this CustomItem
1288: * @param imgData mutable <tt>ImageData</tt>
1289: * associated with an <tt>Image</tt>
1290: * that serves as an offscreen buffer
1291: */
1292: private static native void setContentBuffer0(int nativeId,
1293: ImageData imgData);
1294:
1295: /**
1296: * Parameter used by dirtyRegion[].
1297: */
1298: private final static int X1 = 0;
1299:
1300: /**
1301: * Parameter used by dirtyRegion[].
1302: */
1303: private final static int Y1 = 1;
1304:
1305: /**
1306: * Parameter used by dirtyRegion[].
1307: */
1308: private final static int X2 = 2;
1309:
1310: /**
1311: * Parameter used by dirtyRegion[].
1312: */
1313: private final static int Y2 = 3;
1314:
1315: /**
1316: * Represents the dirty region since last repaint.
1317: * Array of 4 integers, representing the two corners: (x1,y1), (x2,y2)
1318: */
1319: private int[] dirtyRegion = null;
1320:
1321: /**
1322: * Internal spacing between <code>Item</code>'s inner components -
1323: * label and body.
1324: * This value is taken from native, and cached here, to minimize native
1325: * calls.
1326: */
1327: private static int ITEM_PAD = 0;
1328:
1329: /**
1330: * Mutable image that holds CustomItem repaints
1331: */
1332: private ImageData contentImageData; // = NULL;
1333:
1334: /**
1335: * Graphics associated with contentImage
1336: */
1337: private Graphics contentGraphics; // = NULL;
1338:
1339: } // CustomItemLF
|