/*
*
*
* Copyright 1990-2007 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
|