/* * * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package javax.microedition.lcdui; /* import javax.microedition.lcdui.KeyConverter; */ import com.sun.midp.log.Logging; import com.sun.midp.log.LogChannels; import com.sun.midp.configurator.Constants; // ************************************************************************** // Package Private - These are all methods which delegate calls to // CustomItem application code, locking on the calloutLock // before doing so // ************************************************************************** /** * This is the look and feel implementation for <code>CustomItem</code>. */ class CustomItemLFImpl extends ItemLFImpl implements CustomItemLF { /** * Creates <code>CustomItemLF</code> associated with the passed in * <code>CustomItem</code>. * * @param ci the <code>CustomItem</code> associated with this * look & feel. */ CustomItemLFImpl(CustomItem ci) { super(ci); dirtyRegion = new int[4]; resetDirtyRegion(); customItem = ci; } // ********************************************************** // CustItemLF interface implementation // *********************************************************** /** * Notifies L&F that repaint of the entire custom item is needed. */ public void lRepaint() { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_REPAINT, ">>> CustomItemLFImpl -- lRepaint()"); } // content area is empty no repaint is needed if (contentImageData == null) { return; } setDirtyRegionFull(); try { int pad = getItemPad(); // We prune off the label area when doing a complete repaint lRequestPaint(pad, pad + getLabelHeight(bounds[WIDTH]), contentImageData.getWidth(), contentImageData.getHeight()); } catch (Exception e) { Display.handleThrowable(e); } } /** * Notifies L&F that repaint of the specified region is needed. * * @param x the x coordinate of the origin of the dirty region * @param y the y coordinate of the origin of the dirty region * @param width the width of the dirty region * @param height the height of the dirty region */ public void lRepaint(int x, int y, int width, int height) { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_REPAINT, ">>> CustomItemLFImpl -- lRepaint(" + x + "," + y + "," + width + "," + height + ")"); } try { // Content area is empty there is no need to do anything if (contentImageData == null) { return; } int pad = getItemPad(); // int lH = getLabelHeight(bounds[WIDTH]); // no need to do anything if the repaint region // is complete outside the content area if (x >= bounds[WIDTH] - 2*pad || y >= bounds[HEIGHT] - 2*pad /* - lH */ || x + width <= 0 || y + height <= 0) { return; } // passed in region is expressed in the same coordinate system // as the dirtyRegion; join those 2 regions if (x <= 0) { dirtyRegion[X1] = 0; } else { // when dirty region is unset the following will be true // and dirtyRegion[X1] will be correctly set if (dirtyRegion[X1] > x) { dirtyRegion[X1] = x; } } if (y <= 0) { dirtyRegion[Y1] = 0; } else { // when dirty region is unset the following will be true // and dirtyRegion[Y1] will be correctly set if (dirtyRegion[Y1] > y) { dirtyRegion[Y1] = y; } } if (x + width >= bounds[WIDTH] - pad) { dirtyRegion[X2] = bounds[WIDTH] - pad; } else { // when dirty region is unset the following will be true // and dirtyRegion[X2] will be correctly set if (x + width > dirtyRegion[X2]) { dirtyRegion[X2] = x + width; } } if (y + height >= bounds[HEIGHT] - pad) { dirtyRegion[Y2] = bounds[HEIGHT] - pad; } else { // when dirty region is unset the following will be true // and dirtyRegion[Y2] will be correctly set if (y + height > dirtyRegion[Y2]) { dirtyRegion[Y2] = y + height; } } if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_REPAINT, "after join ..... \t\t dirtyRegion (" + dirtyRegion[X1] + "," + dirtyRegion[Y1] + ") - (" + dirtyRegion[X2] + "," + dirtyRegion[Y2] + ")"); } // obsolete - can use any number... super.lRequestPaint(0, 0, 0, 0); /* // repaint should be requested in Item's coordinate // system (translate by padding and labelHeight) super.lRequestPaint(dirtyRegion[X1] + pad, dirtyRegion[Y1] + pad + lH, dirtyRegion[X2] - dirtyRegion[X1] + 1, dirtyRegion[Y2] - dirtyRegion[Y1] + 1); */ } catch (Exception e) { Display.handleThrowable(e); } } /** * Notifies L&F that <code>CustomItem</code> was invalidated. */ public void lInvalidate() { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_LAYOUT, ">>> CustomItemLFImpl -- lInvalidate()"); } setDirtyRegionFull(); lRequestInvalidate(true, true); } /** * Get the preferred width of this <code>Item</code>, including * the preferred content width and room for the label. * This is the callback for <code>Item</code>'s public * getPreferredWidth() method. * * @param h the height to base the width size on * * @return the preferred width */ private int uCallPreferredWidth(int h) { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_LAYOUT, "CustomItem -- uCallPreferredWidth h=" + h); } // SYNC NOTE: Call into app code. Must not hold LCDUILock. int pW = customItem.uGetContentSize(CustomItem.SIZE_PREF_WIDTH, h); // preferred width should be at least the minimum allowed, // this is checked and fixed at Item level if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_LAYOUT, "\t -- uCallPreferredWidth item returned " + pW); } synchronized (Display.LCDUILock) { // if width is not locked item.lockedWidth will be -1 // which means that all available width can be used int lw = getLabelWidth(item.lockedWidth); // if label is wider than customItem body, we're allowed // to make the body wider. if (lw > pW) { pW = lw; } if (pW > 0) { pW += 2 * getItemPad(); } } return pW; } /** * Get the preferred height of this <code>Item</code>, including the * preferred content height and room for the label. * This is the callback for <code>Item</code>'s public * getPreferredHeight() method. * * @param w the width to base the height size on * * @return the preferred height */ private int uCallPreferredHeight(int w) { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_LAYOUT, "CustomItem -- uCallPreferredHeight w=" + w); } // SYNC NOTE: Call into app code. Must not hold LCDUILock. int pH = customItem.uGetContentSize(CustomItem.SIZE_PREF_HEIGHT, w); // preferred height should be at least the minimum allowed, // this is checked and fixed at Item level synchronized (Display.LCDUILock) { pH += getLabelHeight(w); if (pH > 0) { pH += 2 * getItemPad(); } } return pH; } /** * Get the minimum width of this <code>Item</code>, including the * minimum content width and room for the label. * This is the callback for <code>Item</code>'s public * getMinimumWidth() method. * * @return the minimum width */ private int uCallMinimumWidth() { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_LAYOUT, "CustomItemLFImpl -- uCallMinimumWidth"); } // SYNC NOTE: Call into app code. Must not hold LCDUILock. int mW = customItem.uGetContentSize(CustomItem.SIZE_MIN_WIDTH, 0); synchronized (Display.LCDUILock) { int lw = getLabelWidth(-1); // if label is wider than customItem body, we're allowed // to make the body wider. if (lw > mW) { mW = lw; } if (mW > 0) { mW += 2 * getItemPad(); } } return mW; } /** * Get the minimum height of this <code>Item</code>, including the * minimum content height and room for the label. * This is the callback for <code>Item</code>'s public * getMinimumHeight() method. * * @return the minimum height */ private int uCallMinimumHeight() { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_LAYOUT, "CustomItemLFImpl -- uCallMinimumHeight"); } // SYNC NOTE: Call into app code. Must not hold LCDUILock. int mH = customItem.uGetContentSize(CustomItem.SIZE_MIN_HEIGHT, 0); if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_LAYOUT, "CustomItem -- uCallMinimumHeight ret: " + mH); } synchronized (Display.LCDUILock) { mH += getLabelHeight(-1); if (mH > 0) { mH += 2 * getItemPad(); } } return mH; } /** * Get minimum and preferred sizes from <code>CustomItem</code> * subclass and cache the result in super class. */ public void uCallSizeRefresh() { if (isRequestedSizesValid()) { return; } int mw = uCallMinimumWidth(); if (mw < 0) mw = 0; int mh = uCallMinimumHeight(); if (mh < 0) mh = 0; int pw = uCallPreferredWidth(item.lockedHeight); if (pw < mw) pw = mw; int ph = uCallPreferredHeight(pw); synchronized (Display.LCDUILock) { // NOTE: When the item should shrink, the minimum size is used, // and the minimum size is calculated with the label // on the same line if (shouldHShrink() && item.label != null && item.label.length() > 0) { mh += DEFAULT_LABEL_HEIGHT; } if (ph < mh) ph = mh; // Cache the result in ItemLFImpl lSetRequestedSizes(mw, mh, pw, ph); } } /** * Overriding <code>ItemLFImpl</code>. * Notifies L&F of a label change in the corresponding * <code>Item</code>. * * @param label the new label string */ public void lSetLabel(String label) { super.lSetLabel(label); } // JAVADOC COMMENT ELIDED public int lGetInteractionModes() { // removed support for traversal. // (MIDlets should use low level key events instead) int result = customItem.TRAVERSE_HORIZONTAL | customItem.TRAVERSE_VERTICAL | customItem.KEY_PRESS | customItem.KEY_RELEASE; if (Constants.REPEAT_SUPPORTED) { result = result | customItem.KEY_REPEAT; } if (Constants.POINTER_SUPPORTED) { result = result | customItem.POINTER_PRESS | customItem.POINTER_RELEASE; } if (Constants.MOTION_SUPPORTED) { result = result | customItem.POINTER_DRAG; } return result; } // ***************************************************** // Package private methods // ***************************************************** /** * Calculate minimum and preferred width and height of this item and * store the result in instance variables * minimumWidth, minimumHeight, preferredWidth and preferredHeight. * * Override the version in <code>ItemLFImpl</code> to do nothing. */ void lGetRequestedSizes() { // Even if (isRequestedSizesValid() == false), we won't be able to // call into app code for the content sizes since we // are holding LCDUILock and may be even on event dispatch thread. // Do nothing here so the cached requested sizes will be used. } /** * Called by the system to indicate the size available to this * <code>Item</code> has changed. * * SYNC NOTE: Caller must not hold LCDUILock. * * @param w the new width of the item's content area * @param h the new height of the item's content area */ void uCallSizeChanged(int w, int h) { try { synchronized (Display.calloutLock) { int pad = getItemPad(); h -= 2*pad + getLabelHeight(w); w -= 2*pad; customItem.sizeChanged(w, h); } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Called to paint this <code>CustomItem</code>. * * @param g the <code>Graphics</code> object to be used for * rendering the item. * @param w current width of the item in pixels * @param h current height of the item in pixels */ void uCallPaint(Graphics g, int w, int h) { // ignore passed in graphics and use Custom Item's muttable image // contentImageData consists only of content so there is // no need to do translation by the label height and // around item padding int x1, x2, y1, y2; boolean visInViewport; synchronized (Display.LCDUILock) { // spec requires not to call CustomItem's paint // if content area width or height is 0 that is why: // if content area is empty or dirty region is unset // no repaint is needed if (contentImageData == null || dirtyRegion[Y2] <= dirtyRegion[Y1] || dirtyRegion[X2] <= dirtyRegion[X1]) { return; } x1 = dirtyRegion[X1]; x2 = dirtyRegion[X2]; y1 = dirtyRegion[Y1]; y2 = dirtyRegion[Y2]; visInViewport = visibleInViewport; if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_REPAINT, "<<< \t\t Current clip: (" + g.getClipX() + "," + g.getClipY() + ") - (" + (g.getClipWidth()) + "," + (g.getClipHeight()) + ")" + "<<< \t\t clipping to: (" + dirtyRegion[X1] + "," + dirtyRegion[Y1] + ") - (" + (dirtyRegion[X2] - dirtyRegion[X1] + 1) + "," + (dirtyRegion[Y2] - dirtyRegion[Y1] + 1) + ")\n\n"); } contentGraphics.setClip(x1, y1, x2 - x1 + 1, y2 - y1 +1); contentGraphics.setColor( Theme.getColor(Display.COLOR_BACKGROUND)); contentGraphics.fillRect(x1, y1, x2 - x1 + 1, y2 - y1 + 1); contentGraphics.setColor(0); contentGraphics.setFont(Font.getDefaultFont()); contentGraphics.setStrokeStyle(Graphics.SOLID); resetDirtyRegion(); if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { contentGraphics.drawLine(dirtyRegion[X1], dirtyRegion[Y1], dirtyRegion[X2] - dirtyRegion[X1] + 1, dirtyRegion[Y2] - dirtyRegion[Y1] + 1); Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_REPAINT, "<<< CustomItemLFImpl -- uCallPaint " + nativeId +" / " + w + "x" + h); } } // SYNC NOTE: Call into app code. Must not hold LCDUILock. try { synchronized (Display.calloutLock) { // call to the MIDlet even if it is not visible // but do not refresh if it is not visible in viewport // SYNC NOTE: the change of contentGraphics and use of // contentGraphics happen on the event dispatch thread // so there is no problem of doing it outside of // the LCDUILock customItem.paint(contentGraphics, contentImageData.getWidth(), contentImageData.getHeight()); } // Show the buffer onto screen synchronized (Display.LCDUILock) { // Need to check nativeId again since it might have been // deleted if the CustomItem is removed from the form if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) { refresh0(nativeId, x1, y1, x2 - x1 + 1, y2 - y1 + 1); } } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Reset the values to invalid coordinates. */ private void resetDirtyRegion() { dirtyRegion[X1] = 1000; dirtyRegion[Y1] = 1000; dirtyRegion[X2] = 0; dirtyRegion[Y2] = 0; } /** * Reset the values to invalid coordinates. */ private void setDirtyRegionFull() { dirtyRegion[X1] = 0; dirtyRegion[Y1] = 0; if (contentImageData == null) { dirtyRegion[X2] = dirtyRegion[Y2] = 0; } else { dirtyRegion[X2] = contentImageData.getWidth(); dirtyRegion[Y2] = contentImageData.getHeight(); } } /** * Called by the system to notify internal traverse into the item. * * @param dir the direction of traversal * @param viewportWidth the width of the container's viewport * @param viewportHeight the height of the container's viewport * @param visRect_inout passes the visible rectangle into the method, and * returns the updated traversal rectangle from the * method * * @return <code>true</code> if internal traversal had occurred, * <code>false</code> if traversal should proceed out * * @see #getInteractionModes * @see #traverseOut * @see #TRAVERSE_HORIZONTAL * @see #TRAVERSE_VERTICAL */ boolean uCallTraverse(int dir, int viewportWidth, int viewportHeight, int[] visRect_inout) { // the super implementation has to set the focus to this item boolean ret = super.uCallTraverse(dir, viewportWidth, viewportHeight, visRect_inout); try { synchronized (Display.calloutLock) { if (hasFocus) { int lH = getLabelHeight(bounds[WIDTH]); // We shave off the label height from the overall // item viewport visRect_inout[HEIGHT] -= lH; // NOTE: visRect_inout should reflect native scroll ret |= customItem.traverse(dir, viewportWidth, viewportHeight - lH, visRect_inout); // We shift the return value from the item's traverse // by the label height to give the real location visRect_inout[Y] += lH; if (ret) { setDirtyRegionFull(); } } } } catch (Throwable thr) { Display.handleThrowable(thr); } return ret; } /** * Called by the system to indicate traversal has left this * <code>Item</code>. * * @see #getInteractionModes * @see #traverse * @see #TRAVERSE_HORIZONTAL * @see #TRAVERSE_VERTICAL */ void uCallTraverseOut() { super.uCallTraverseOut(); try { synchronized (Display.calloutLock) { customItem.traverseOut(); setDirtyRegionFull(); } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Called by the system to signal a key press. * * @param keyCode the key code of the key that has been pressed. * * @see #getInteractionModes */ void uCallKeyPressed(int keyCode) { ItemCommandListener cl = null; Command defaultCmd = null; FormLFImpl ownerLFImpl = null; boolean internalTraverse = false; int vis_Rect[] = new int[4]; // vpY1 the y coordinate of the top left visible pixel int vpY1 = 0; // vpY2 the y coordinate of bottom left visible pixel int vpY2 = 0; if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI, "CustomItemLFImpl: got uCallKeyPressed: " + keyCode); } synchronized (Display.LCDUILock) { cl = customItem.commandListener; defaultCmd = customItem.defaultCommand; if (item.owner != null) { ownerLFImpl = (FormLFImpl)item.owner.getLF(); } } // synchronized // SYNC NOTE: The call to the listener must occur outside the lock try { // SYNC NOTE: We lock on calloutLock around any calls // into application code synchronized (Display.calloutLock) { if ((cl != null) && (defaultCmd != null) && (keyCode == Constants.KEYCODE_SELECT)) { cl.commandAction(defaultCmd, customItem); } else { customItem.keyPressed(keyCode); } } // end synchronized } catch (Throwable thr) { Display.handleThrowable(thr); } synchronized (Display.LCDUILock) { if (internalTraverse) { scrollforInternalTraversal( ownerLFImpl, vis_Rect); } } // end synchronized } /** * Called by the system to signal a key release. * * @param keyCode the key code of the key that has been released. * * @see #getInteractionModes */ void uCallKeyReleased(int keyCode) { try { synchronized (Display.calloutLock) { customItem.keyReleased(keyCode); } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Called by the system to signal a key repeat. * * @param keyCode the key code of the key that has been repeated. * * @see #getInteractionModes */ void uCallKeyRepeated(int keyCode) { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI, "CustomItemLFImpl: uCallKeyRepeated!! " + keyCode); } try { synchronized (Display.calloutLock) { customItem.keyRepeated(keyCode); } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Called by the system to signal a pointer press. * * @param x the x coordinate of the pointer down * @param y the y coordinate of the pointer down * * @see #getInteractionModes */ void uCallPointerPressed(int x, int y) { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI, "*-* CustomItem: uCallPointerPressed *-*"); } try { synchronized (Display.calloutLock) { customItem.pointerPressed(x, y); } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Called by the system to signal a pointer release. * * @param x the x coordinate of the pointer up * @param y the x coordinate of the pointer up * * @see #getInteractionModes */ void uCallPointerReleased(int x, int y) { try { synchronized (Display.calloutLock) { customItem.pointerReleased(x, y); } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Called by the system to signal a pointer drag. * * @param x the x coordinate of the pointer drag * @param y the x coordinate of the pointer drag * * @see #getInteractionModes */ void uCallPointerDragged(int x, int y) { try { synchronized (Display.calloutLock) { customItem.pointerDragged(x, y); } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Override <code>ItemLFImpl</code> method to * set the dirty region and the content buffer * before showing the native resource. */ void lShowNativeResource() { if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) { setContentBuffer0(nativeId, contentImageData); super.lShowNativeResource(); } } /** * Override <code>ItemLFImpl</code> method to reset * the dirty region before hiding the native resource */ void lHideNativeResource() { resetDirtyRegion(); super.lHideNativeResource(); } /** * Overrides the default method in <code>ItemLFImpl</code>. * Called by the system to notify this <code>CustomItem</code> * that it is being shown. This method will be called only * if this <code>CustomItem</code> was made visible. * * The default implementation changes the visibleInViewport flag. */ void uCallShowNotify() { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_REPAINT, "CustomItemLFImpl: uCallShowNotify()"); } super.uCallShowNotify(); try { synchronized (Display.calloutLock) { customItem.showNotify(); } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Overrides the default method to set dirty region to full size. */ void lCallShowNotify() { super.lCallShowNotify(); setDirtyRegionFull(); } /** * Overrides the default method in <code>ItemLFImpl</code>. * Called by the system to notify this <code>CustomItem</code> * that it is being hidden. This method will be called only * if this <code>CustomItem</code> was hidden. * * The default implementation changes the visibleInViewport flag. */ void uCallHideNotify() { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_REPAINT, "CustomItemLFImpl: uCallHideNotify()"); } super.uCallHideNotify(); try { synchronized (Display.calloutLock) { customItem.hideNotify(); } } catch (Throwable thr) { Display.handleThrowable(thr); } } /** * Sets custom item's size * * @param w - the new width of the item * @param h - the new height of the item */ void lSetSize(int w, int h) { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_LAYOUT, " CustomItemLFImpl - setSize: " + w + "x" + h); } if (w == bounds[WIDTH] && h == bounds[HEIGHT]) { return; } int pad = getItemPad(); int contentW = w - 2*pad; int contentH = h - 2*pad - getLabelHeight(w); if (contentImageData == null || contentImageData.getWidth() != contentW || contentImageData.getHeight() != contentH) { if (contentW > 0 && contentH > 0) { Image contentImage = Image.createImage(contentW, contentH); contentImageData = contentImage.getImageData(); if (nativeId != DisplayableLFImpl.INVALID_NATIVE_ID) { setContentBuffer0(nativeId, contentImageData); } contentGraphics = contentImage.getGraphics(); // no need to paint background of the newly created // Mutable image since according to the spec // it will be set to white color setDirtyRegionFull(); } } super.lSetSize(w, h); } /** * Get label height. * * @param w width available for label * * @return label height */ private int getLabelHeight(int w) { // check empty label case: if (customItem.label == null || customItem.label.equals("") || (w >= 0 && w <= 2*getItemPad())) { return 0; } if (w > 0) { w -= 2*getItemPad(); } else if (w != -1) { w = -1; } // query native for real preferred size boolean wasNoNative = (nativeId == DisplayableLFImpl.INVALID_NATIVE_ID); // Native resource not yet created, do it now if (wasNoNative) { createTempNativeResource(); } int h = getLabelHeight0(nativeId, w); if (wasNoNative) { deleteNativeResource(); } return h; } /** * Gets label width used in native. If -1 is passed as a width * parameter the whole available width should be used. Note * that padding will be subtracted from the passed in width. * * @param w the width to be used to get label width. * @return actual width of the label. */ private int getLabelWidth(int w) { // check empty label case: if (customItem.label == null || customItem.label.equals("") || (w >= 0 && w <= getItemPad())) { return 0; } if (w > 0) { w -= 2*getItemPad(); } else if (w != -1) { w = -1; } // query native for real preferred size boolean wasNoNative = (nativeId == DisplayableLFImpl.INVALID_NATIVE_ID); // Native resource not yet created, do it now if (wasNoNative) { createTempNativeResource(); } int lw = getLabelWidth0(nativeId, w); if (wasNoNative) { deleteNativeResource(); } if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI_ITEM_REPAINT, "CustomItemLFImpl: getLabelWidth(" + w + ")... nativeId==" + nativeId + " \t returning: " + lw); } return lw; } /** * Returns item pad used in native. The value is fetched only once * and cached in Java. * * @return item pad used in native */ private int getItemPad() { if (ITEM_PAD == 0) { // query native for real preferred size boolean wasNoNative = (nativeId == DisplayableLFImpl.INVALID_NATIVE_ID); // Native resource not yet created, do it now if (wasNoNative) { createTempNativeResource(); } ITEM_PAD = getItemPad0(nativeId); if (wasNoNative) { deleteNativeResource(); } } return ITEM_PAD; } /** * The <code>CustomItem</code> associated with this view. */ private CustomItem customItem; /** * Create native resource for current <code>CustomItem</code>. * Override function in <code>ItemLFImpl</code>. * * @param ownerId Owner screen's native resource id. */ void createNativeResource(int ownerId) { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI, "****************************************" + "CustomItem: createNativeResource -- ownerId=" + ownerId + "bounds are: " + bounds[X] + "," + bounds[Y] + " -- " + bounds[WIDTH] + "x" + bounds[HEIGHT] + "****************************************"); } nativeId = createNativeResource0(ownerId, customItem.label, customItem.layout); } /** * Called by <code>Display</code> to notify an <code>ItemLF</code> * in current <code>FormLF</code> of a change in its peer state. * Return false since no notification is needed. * @param hint notification sub-type defined as above * * @return always <code>false</code> since no internal state changes. */ boolean uCallPeerStateChanged(int hint) { if (Logging.REPORT_LEVEL <= Logging.INFORMATION) { Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI, "-=- CustomItemLFImpl uCallPeerStateChanged " + hint); } return false; } // ***************************************************** // Private methods // ***************************************************** /** * Called by traverse method to * scroll the CustomItem for InternalTraversal. * @param ownerLFImpl FormLFImpl * @param vis_Rect the updated traversal rectangle from * the traverse method */ private void scrollforInternalTraversal( FormLFImpl ownerLFImpl, int[] vis_Rect) { int yOffset = 0; // check the returned vis_Rect // to check the validity of x,y,w,h // x and y values are relative to item's origin if (vis_Rect[X] < 0) { vis_Rect[X] = 0; } if (vis_Rect[WIDTH] < 0) { vis_Rect[WIDTH] = 0; } if (vis_Rect[X] > bounds[WIDTH]) { vis_Rect[X] = bounds[WIDTH]; } if (vis_Rect[Y] < 0) { vis_Rect[Y] = 0; } if (vis_Rect[HEIGHT] < 0) { vis_Rect[HEIGHT] = 0; } if (vis_Rect[Y] > bounds[HEIGHT]) { vis_Rect[Y] = bounds[HEIGHT]; } // shouldn't exceed viewportHeight if (vis_Rect[HEIGHT] > ownerLFImpl.height) { vis_Rect[HEIGHT] = ownerLFImpl.height; } // shouldn't exceed viewportwidth if (vis_Rect[WIDTH] > ownerLFImpl.width) { vis_Rect[WIDTH] = ownerLFImpl.width; } // current scroll position int vpY1 = ownerLFImpl.getScrollPosition0(); // vpY2 the y coordinate of bottom left visible pixel int vpY2 = vpY1 + ownerLFImpl.height; // convert vis_Rect Y into form's co-ordinates vis_Rect[Y] += bounds[Y]; int itemHeight = vis_Rect[HEIGHT]; int vpHeight = ownerLFImpl.height; // make sure that the item is visible ItemLFImpl itemLFInFocus = ownerLFImpl.getItemInFocus(); if ((itemLFInFocus != null) && (itemLFInFocus.nativeId != ownerLFImpl.INVALID_NATIVE_ID)) { // find the y offset depending on // the vis_Rect returned int vpMidpoint = vpY1 + vpHeight/2; int itemMidpoint = vis_Rect[Y] + itemHeight/2; if (itemHeight <= vpHeight) { // center it // HI DECISION: short circuit scrolling all together // if the complete vis_Rect area is in the viewport if (itemMidpoint > vpMidpoint) { // lower yOffset = itemMidpoint - vpMidpoint; } else if (itemMidpoint < vpMidpoint) { // upper yOffset = vpMidpoint - itemMidpoint; } } else if (itemHeight > vpHeight) { // top it if (itemMidpoint > vpMidpoint) { // lower yOffset = vis_Rect[Y] - vpY1; } else if (itemMidpoint < vpMidpoint) { // upper yOffset = vpY1 - vis_Rect[Y]; } } // QT makes this visible with at least // 50 pixel margins (if possible, otherwise centered) ownerLFImpl.setCurrentItem0( nativeId, itemLFInFocus.nativeId, yOffset); } } /** * KNI function that creates native resource for current * <code>CustomItem</code>. * * @param ownerId Owner screen's native resource id * (<code>MidpDisplayable *</code>) * @param label - label to be used for this <code>Item</code> * @param layout - layout directive associated with this <code>Item</code> * * @return native resource id (<code>MidpItem *</code>) of this * <code>CustomItem</code> */ private static native int createNativeResource0(int ownerId, String label, int layout); /** * Call to blit the paint result to the <code>CustomItem</code>. * * @param nativeId native resource id for this <code>Item</code> * @param x coordinate relative to the widget * @param y coordinate relative to the widget * @param width invalid width to repaint. If < 0 than paint all. * @param height invalid height to repaint. If < 0 than paint all. */ private static native void refresh0(int nativeId, int x, int y, int width, int height); /** * Returns label height in native widget. * * @param nativeId native resource id for this <code>Item</code> * @param width tentative width used to calculate the height * * @return label height in native widget */ private static native int getLabelHeight0(int nativeId, int width); /** * Get the actual width required for the label. * * @param nativeId native resource id for this <code>Item</code> * @param contentWidth hint for the native widget to decide on label layout * * @return actual label width in native widget */ private static native int getLabelWidth0(int nativeId, int contentWidth); /** * Returns item pad used in native. * * @param nativeId native resource id for this <code>Item</code> * * @return item pad used in native */ private static native int getItemPad0(int nativeId); /** * Sets the content buffer. All paints are done to that buffer. * When paint is processed snapshot of the buffer is flushed to * the native resource content area. * @param nativeId native resource is for this CustomItem * @param imgData mutable <tt>ImageData</tt> * associated with an <tt>Image</tt> * that serves as an offscreen buffer */ private static native void setContentBuffer0(int nativeId, ImageData imgData); /** * Parameter used by dirtyRegion[]. */ private final static int X1 = 0; /** * Parameter used by dirtyRegion[]. */ private final static int Y1 = 1; /** * Parameter used by dirtyRegion[]. */ private final static int X2 = 2; /** * Parameter used by dirtyRegion[]. */ private final static int Y2 = 3; /** * Represents the dirty region since last repaint. * Array of 4 integers, representing the two corners: (x1,y1), (x2,y2) */ private int[] dirtyRegion = null; /** * Internal spacing between <code>Item</code>'s inner components - * label and body. * This value is taken from native, and cached here, to minimize native * calls. */ private static int ITEM_PAD = 0; /** * Mutable image that holds CustomItem repaints */ private ImageData contentImageData; // = NULL; /** * Graphics associated with contentImage */ private Graphics contentGraphics; // = NULL; } // CustomItemLF