FormLFImplpublic class FormLFImpl extends DisplayableLFImpl implements FormLFLook and feel class for Form . |
Fields Summary |
---|
static final int | LAYOUT_HMASKA bit mask to capture the horizontal layout directive of an item. | static final int | LAYOUT_VMASKA bit mask to capture the vertical layout directive of an item. | static final int | FULL_LAYOUTDo a full layout. | static final int | UPDATE_LAYOUTOnly update layout. | private static final int | GROW_SIZEThis is the rate at which the internal array of Items grows if
it gets filled up. | static final int | PIXELS_LEFT_ON_PAGEThis is the number of pixels left from the previous "page"
when a page up or down occurs | int | traverseIndexThe item index which has the traversal focus | Item | pendingCurrentItemItem that was made visible using display.setCurrentItem() call
while FormLF was in HIDDEN or FROZEN state. | ItemLFImpl | lastTraverseItemThis is a special case variable which tracks the last
traversed item when a new item is traversed to via the
setCurrentItem() call. | boolean | itemTraverseA flag indicating the return value of the currently
selected Item from its traverse() method | boolean | itemsModifiedA flag that shows that itemLFs[] storage has been modified
(items inserted/deleted) and earlier made copies (extends itemsCopy[])
are outdated.
flag is set by item insert/delete operations,
cleared when copy operation is performed. | int[] | visRectWhen a Form calls an Item's traverse() method, it passes in
an in-out int[] that represents the Item's traversal
bounds. This gets cached in the visRect variable | private ItemLFImpl[] | itemLFsArray of ItemLF s that correspond to the array of items
in Form . | private static final int | DISPATCH_ITEM_ARRAY_BLOCKBlock size of the temporary array of ItemLF s used
in dispatch. | private static ItemLFImpl[] | dispatchItemLFsTemporary array of ItemLF s that is ONLY used in
dispatch thread during show, hide and re-layout this Form .
ensureDispatchItemArray() should be called before use and
resetDispatchItemArray() should be called when it is no longer needed,
to allow ItemLFImpl objects been GC'ed. | private int | numOfLFsThe number of views present in this FormLF . | private boolean | firstShownThis helps an optimization. | boolean | resetToTopScreens should automatically reset to the top of the when
they are shown, except in cases where it is interrupted by
a system menu or an off-screen editor - in which case it
should be reshown exactly as it was. | private int | viewportHeightViewport height in the native resource | int[] | viewableOverall dimensions of the view. It is an array so it could be passed
as a reference to LayoutManager . | static final boolean | ltrLeft to right layout is default.
Used by isImplicitLineBreak. |
Constructors Summary |
---|
FormLFImpl(Form form, Item[] items, int numOfItems)Creates FormLF associated with passed in form.
FormLFImpl maintains an array of views associated
with its items.
super(form);
// Initialize the in-out rect for Item traversal
visRect = new int[4];
width -= Constants.VERT_SCROLLBAR_WIDTH;
if (items == null) {
itemLFs = new ItemLFImpl[GROW_SIZE];
// numOfLFs was initialized to 0
// so there is no need to update it
} else {
this.itemLFs = new ItemLFImpl[items.length > GROW_SIZE ?
items.length : GROW_SIZE];
for (int i = 0; i < numOfItems; i++) {
itemLFs[i] = (ItemLFImpl)items[i].getLF();
}
// right now we have the same number of views as items
numOfLFs = numOfItems;
}
| FormLFImpl(Screen screen, Item item)Creates FormLF for the passed in screen.
Passed in ItemLF is added as the only itemLF present.
This constructor is used by List and TextBox .
super(screen);
itemLFs = new ItemLFImpl[1];
itemLFs[0] = (ItemLFImpl)item.getLF();
numOfLFs = 1;
// Initialize the in-out rect for Item traversal
visRect = new int[4];
|
Methods Summary |
---|
void | createNativeResource()Create native resource for this Form .
Item s' resources are not created here.
setScrollPosition0(0);
nativeId = createNativeResource0(owner.title,
owner.ticker == null ? null
: owner.ticker.getString());
| private native int | createNativeResource0(java.lang.String title, java.lang.String tickerText)Create the native resource of this Form .
| private static void | ensureDispatchItemArray(int size)Ensure that dispatchItemLFs array has enough space for use.
SYNC NOTE: This function must only be used in event dispatch thread.
if (size > dispatchItemLFs.length) {
dispatchItemLFs = new ItemLFImpl[size];
}
| ItemLFImpl | getItemInFocus()Service method - returns the ItemLFImpl that has focus.
if (traverseIndex < 0) {
return null;
} else {
return itemLFs[traverseIndex];
}
| int | getNextInteractiveItem(ItemLFImpl[] items, int dir, int index)This method will return the index of the next interactive
item which is wholly visible on the screen given the traversal
direction, or -1 if no visible items in that traversal direction
are interactive (or completely visible).
try {
int scrollPos = getScrollPosition0();
while (true) {
switch (dir) {
case Canvas.UP:
case Canvas.LEFT:
index -= 1;
break;
case Canvas.DOWN:
case Canvas.RIGHT:
index += 1;
break;
case CustomItem.NONE:
// no - op
break;
default:
// for safety/completeness.
Logging.report(Logging.ERROR,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"FormLFImpl: dir=" + dir);
return index;
}
// If we've exhausted the set, stop looking
if (index < 0 || index >= items.length) {
break;
}
// If we've found a non-interactive item, continue
if (!items[index].item.acceptFocus()) {
continue;
}
// If we've found a completely visible, interactive
// item, stop and traverse to it
if (itemCompletelyVisible(items[index])) {
break;
}
// If we've found a partially visible, interactive
// item, there is some special casing involved with
// how to scroll appropriately
if (itemPartiallyVisible(items[index])) {
if (dir == Canvas.RIGHT || dir == Canvas.DOWN) {
// If we're paging down and the item's top
// is at the top of the viewport, stop and
// traverse to that item (its bigger than the
// viewport
if (items[index].bounds[Y] == scrollPos) {
break;
}
// If we're paging down and the item's bottom
// is the very last thing in the view, stop and
// keep traversal on that item (item is bigger
// than the viewport and we can go no further)
if (items[index].bounds[Y] +
items[index].bounds[HEIGHT] ==
viewable[HEIGHT])
{
break;
}
} else if (dir == Canvas.LEFT || dir == Canvas.UP) {
// If we're paging up and the item's bottom is the
// very bottom of the viewport, stop and keep
// traversal on that item (item is bigger than the
// viewport and we start at the bottom)
if (items[index].bounds[Y] +
items[index].bounds[HEIGHT] ==
viewable[HEIGHT])
{
break;
}
// If we're paging up and the item's top is at
// the top of the viewport, stop and traverse
// to that item (its bigger than the viewport
// and we should show the top of it before leaving)
if (items[index].bounds[Y] == scrollPos &&
scrollPos == 0)
{
break;
}
}
}
} // while
} catch (Throwable t) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_HIGHUI,
"Throwable while finding next item for traversal");
}
return -1;
}
// This means there was no interactive item in the currently
// visible viewport
if (index < 0 || index >= items.length) {
return -1;
}
return index;
| native int | getScrollPosition0()Current Y position in a scrollable form.
| private native int | getViewportHeight0()Current viewport height in the native resource
| private ItemLFImpl | id2Item(int nativeId)Service method - find the ItemLFImpl from a given
native id.
ItemLFImpl focus = getItemInFocus();
if (focus != null && focus.nativeId == nativeId) {
return focus;
} else {
for (int i = 0; i < numOfLFs; i++) {
if (itemLFs[i].nativeId == nativeId) {
return itemLFs[i];
}
}
// there is no matching ItemLFImpl
return null;
}
| private boolean | isNavigationKey(int key)Check the key and return true if it's navigation key
return key == Canvas.UP ||
key == Canvas.LEFT ||
key == Canvas.DOWN ||
key == Canvas.RIGHT;
| private int | item2Index(ItemLFImpl itemLF)Service method - find the ItemLFImpl index.
for (int i = 0; i < numOfLFs; i++) {
if (itemLFs[i] == itemLF) {
return i;
}
}
return -1;
| boolean | itemCompletelyVisible(ItemLFImpl item)Determine if the given item is at completely visible
in the current viewport.
// If the Form is being hidden, all the items are
// hidden and we just return false
if (super.state == HIDDEN) {
return false;
}
// If the Item's top and bottom are within the viewport,
// return true
int scrollPos = getScrollPosition0();
return (item.bounds[Y] >= scrollPos) &&
(item.bounds[Y] + item.bounds[HEIGHT] <= scrollPos + viewportHeight);
| boolean | itemPartiallyVisible(ItemLFImpl item)Determine if the given item is at least partially visible
in the current viewport.
// If the Form is hidden, all the items are
// hidden and we just return false
if (super.state == HIDDEN) {
return false;
}
int scrollPos = getScrollPosition0();
// If the Item's top is within the viewport, return true
return !(item.bounds[Y] > scrollPos + viewportHeight ||
item.bounds[Y] + item.bounds[HEIGHT] < scrollPos);
| public void | lDelete(int itemNum, Item deleteditem)Notifies look&feel object of an item deleted in the corresponding
Form .
// if the previous item has new line after, or the next item has
// new line before, and it's not the last item,
// than we could just mark the next item as actualBoundsInvalid[Y]
if (itemNum < (numOfLFs-1)) {
if (((itemNum > 0) && (itemLFs[itemNum-1].equateNLA()) ||
itemLFs[itemNum+1].equateNLB()) &&
itemLFs[itemNum+1].isNewLine) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" setting actualBoundsInvalid[Y] #" +
(itemNum + 1));
if (itemNum > 0) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" | itemLFs[itemNum-1] = "+
itemLFs[itemNum - 1]);
}
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" | itemLFs[itemNum] = " +
itemLFs[itemNum]);
if (itemNum < numOfLFs - 1) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" | itemLFs[itemNum+1] = " +
itemLFs[itemNum+1]);
}
}
itemLFs[itemNum+1].actualBoundsInvalid[Y] = true;
} else {
itemLFs[itemNum+1].actualBoundsInvalid[X] = true;
}
}
if (traverseIndex == itemNum) {
lastTraverseItem = itemLFs[traverseIndex];
}
if (traverseIndex >= 0 && traverseIndex >= itemNum) {
traverseIndex--;
}
numOfLFs--;
itemsModified = true;
if (itemNum < numOfLFs) {
System.arraycopy(itemLFs, itemNum + 1, itemLFs, itemNum,
numOfLFs - itemNum);
}
// Delete reference to the last item view
// that was left after array copy
itemLFs[numOfLFs] = null;
if (pendingCurrentItem == deleteditem) {
pendingCurrentItem = null;
}
lRequestInvalidate();
| public void | lDeleteAll()Notifies look&feel object that all items are deleted in
the corresponding Form .
if (traverseIndex != -1) {
lastTraverseItem = itemLFs[traverseIndex];
}
// Dereference all ItemLFImpls so they can be GC'ed
while (numOfLFs > 0) {
itemLFs[--numOfLFs] = null;
}
traverseIndex = -1;
itemsModified = true;
pendingCurrentItem = null;
lRequestInvalidate();
| public Item | lGetCurrentItem()Gets item currently in focus.
ItemLFImpl v = getItemInFocus();
if (v == null) {
return null;
}
return v.item;
| public int | lGetHeight()Returns the height in pixels of the displayable area available
for items.
This value is the height of the form that can be displayed without
scrolling.
The value may depend on how the device uses the screen and may be
affected by the presence or absence of the ticker, title,
or commands.
return height;
| public int | lGetWidth()Returns the width in pixels of the displayable area available for
items.
The value may depend on how the device uses the screen and may be
affected by the presence or absence of the ticker, title,
or commands.
The Item s of the Form are
laid out to fit within this width.
return width;
| public void | lInsert(int itemNum, Item item)Notifies look&feel object of an item inserted in the corresponding
Form .
if (itemLFs.length == numOfLFs) {
ItemLFImpl newItemLFs[] =
new ItemLFImpl[numOfLFs + GROW_SIZE];
System.arraycopy(itemLFs, 0, newItemLFs, 0, itemNum);
System.arraycopy(itemLFs, itemNum, newItemLFs, itemNum + 1,
numOfLFs - itemNum);
itemLFs = newItemLFs;
} else {
// if we're not appending
if (itemNum != numOfLFs) {
System.arraycopy(itemLFs, itemNum, itemLFs, itemNum + 1,
numOfLFs - itemNum);
}
}
itemLFs[itemNum] = (ItemLFImpl)item.getLF();
numOfLFs++;
itemsModified = true;
// Focus remains on the same item
if (traverseIndex >= itemNum) {
traverseIndex++;
}
lRequestInvalidate();
| private ItemLFImpl[] | lRefreshItems(ItemLFImpl[] itemsCopy, int traverseIndexCopy, int nextIndex)Synchronizes itemLFs[] array with itemsCopy[] array,
as well as traverseIndex with traverseIndexCopy & nextIndex.
Since most of work with copies occurs outside of LCDUILock
(this is, BTW, the reason, why copies are used instead of original
fields), there is a risk, that
itemLFs[] content can be changed (ex. insert/delete/replace Item):
traverseIndexCopy can point to a different object
(including non-interactive),
or outside of changed itemLFs array (throws exception),
or we can refer to a deleted item (deleted in itemLFs,
but still exists in a copy).
This method tries to find item, referred by nextIndex in itemsCopy[],
in itelLFs[], and if found, sets traverseIndex to foundItem,
else sets traverse index to -1.
This method indended to be called in LCDUILock-protected code,
from uInitItemsInViewport(...) & uTraverse(...).
final int nextIndexInLFs = nextIndex +
(traverseIndex - traverseIndexCopy);
traverseIndex = (
(traverseIndex > -1) &&
/* (traverseIndex < numOfLFs) && */
(traverseIndexCopy > -1) &&
/* (traverseIndexCopy < itemsCopy.length) && */
(nextIndex > -1) &&
/* (nextIndex < itemsCopy.length) && */
(nextIndexInLFs > -1) &&
(nextIndexInLFs < numOfLFs) &&
!itemLFs[nextIndexInLFs].item.acceptFocus())
/* (itemsCopy[nextIndex] == itemLFs[nextIndexInLFs])) */
/*
* Assume that:
* 1). traverseIndex has always valid value:
* i.e. -1 or within [0..numOfLFs[ range of itemLFs[] array.
* 2). traverseIndexCopy & nextIndex have always valid values:
* i.e. -1 or within [0..itemsCopy.length[ range
* of itemsCopy[] array.
* As the result we need to check them only for "-1" value.
* Computed "nextIndexInLFs" needs to be checked for
* being in bounds of itemLFs[].
*
* Need revisit : if last condition in the above "IF" is needed,
* however it ensures, that the next current item
* will be exactly the same item that has been found
* by "getNext...".
* Without thast statement we have a risk to point to
* a completely different item: still valid &
* in the range, but probably NON-interactive :-(
* To avoid this, "shouldSkipTraverse()" could be used insead ...
*/
? nextIndexInLFs
: -1;
// refresh itemsCopy array ...
itemsCopy = new ItemLFImpl[numOfLFs];
System.arraycopy(itemLFs, 0, itemsCopy, 0, numOfLFs);
itemsModified = false;
return itemsCopy;
| void | lRequestPaintItem(Item item, int x, int y, int w, int h)Paint an Item contained in this Screen .
The Item requests a paint in its own coordinate space.
Screen translates those coordinates into the overall
coordinate space and schedules the repaint
ItemLFImpl iLF = (ItemLFImpl)item.getLF();
lRequestPaint(iLF.bounds[X] + x, iLF.bounds[Y] + y, w, h, item);
| private void | lScrollToItem(Item item)Scrolls to the passed in Item.
if (item == null || item.owner != owner) {
return;
}
int index = -1;
ItemLFImpl itemLF = null;
if (traverseIndex != -1 && (itemLFs[traverseIndex].item == item)) {
index = traverseIndex;
} else {
for (int i = 0; i < numOfLFs; i++) {
if (itemLFs[i].item == item) {
index = i;
break;
}
}
}
// item not found
if (index==-1) {
return;
}
itemLF = itemLFs[index];
if (index != traverseIndex) {
// Ensure the item is visible
if (!itemCompletelyVisible(itemLF)) {
int scrollPos = itemLF.bounds[Y];
if (scrollPos + viewportHeight > viewable[HEIGHT]) {
scrollPos = viewable[HEIGHT] - viewportHeight;
}
setScrollPosition0(scrollPos);
}
// We record the present traverseItem because if it
// is valid, we will have to call traverseOut() on that
// item when we process the invalidate call.
if (traverseIndex != -1) {
lastTraverseItem = itemLFs[traverseIndex];
}
// If the item is not interactive, we just leave it
// visible on the screen, but set traverseIndex to -1
// so that any interactive item which is visible will
// be traversed to when the invalidate occurs
traverseIndex = itemLF.item.acceptFocus() ? index : -1;
lRequestInvalidate();
} else {
// Ensure the item is visible
if (!itemPartiallyVisible(itemLF)) {
int scrollPos = itemLF.bounds[Y];
if (scrollPos + viewportHeight > viewable[HEIGHT]) {
scrollPos = viewable[HEIGHT] - viewportHeight;
}
setScrollPosition0(scrollPos);
}
}
| public void | lSet(int itemNum, Item item)Notifies look&feel object of an item set in the corresponding
Form .
itemLFs[itemNum] = (ItemLFImpl)item.getLF();
itemsModified = true;
// Focus index remains at the same location
lRequestInvalidate();
| private static void | resetDispatchItemArray(boolean alsoShrink)Clear contents of dispatchItemLFs array after use.
SYNC NOTE: This function must only be used in event dispatch thread.
if (alsoShrink && dispatchItemLFs.length > DISPATCH_ITEM_ARRAY_BLOCK) {
dispatchItemLFs = new ItemLFImpl[DISPATCH_ITEM_ARRAY_BLOCK];
} else {
// Only clean up existing array contents
for (int i = 0; i < dispatchItemLFs.length; i++) {
dispatchItemLFs[i] = null;
}
}
| boolean | scrollForBounds(int dir, int[] bounds)Determine if scrolling is needed for a given bounding box,
and perform such scrolling if necessary.
if (bounds == null || bounds[0] == -1) {
return false;
}
int scrollPos = getScrollPosition0();
// There is a special case whereby the CustomItem
// spec mandates the upper left corner of the internal
// traversal rect be visible if the rect is larger than
// the available viewport
if (bounds[HEIGHT] >= viewportHeight &&
scrollPos != bounds[Y])
{
setScrollPosition0(bounds[Y]);
return true;
}
switch (dir) {
case Canvas.LEFT:
case Canvas.UP:
if (bounds[Y] >= scrollPos) {
return false;
}
scrollPos -= (viewportHeight - PIXELS_LEFT_ON_PAGE);
if (scrollPos < 0) {
scrollPos = 0;
}
setScrollPosition0(scrollPos);
return true;
case Canvas.RIGHT:
case Canvas.DOWN:
if (bounds[Y] + bounds[HEIGHT] <=
scrollPos + viewportHeight)
{
return false;
}
scrollPos += (viewportHeight - PIXELS_LEFT_ON_PAGE);
if (scrollPos > bounds[Y]) {
scrollPos = bounds[Y];
}
if (scrollPos + viewportHeight > viewable[HEIGHT]) {
scrollPos = viewable[HEIGHT] - viewportHeight;
}
setScrollPosition0(scrollPos);
return true;
default:
// for safety/completeness, don't scroll.
Logging.report(Logging.ERROR,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"FormLFImpl: bounds, dir=" + dir);
break;
}
return false;
| native void | setCurrentItem0(int nativeId, int itemId, int yOffset)Scroll to show an Item and give focus to it if possible.
| native void | setScrollPosition0(int pos)Set Y position in a scrollable form.
| private void | setVisRect(ItemLFImpl item, int[] visRect)Calculate the rectangle representing the region of the item that is
currently visible. This region might have zero area if no part of the
item is visible, for example, if it is scrolled offscreen.
synchronized (Display.LCDUILock) {
// Initialize the in-out rect for traversal
visRect[X] = 0;
visRect[WIDTH] = width;
// take the coordinates from the overall
// coordinate space
int itemY1 = item.bounds[Y];
int itemY2 = item.bounds[Y] + item.bounds[HEIGHT];
// vpY1 the y coordinate of the top left visible pixel
// current scroll position
int vpY1 = getScrollPosition0();;
// vpY2 the y coordinate of bottom left pixel
int vpY2 = vpY1 + height;
// return only the visible region of item
// item completely visible in viewport
visRect[Y] = 0;
visRect[HEIGHT] = item.bounds[HEIGHT];
if ((itemY1 >= vpY2) || (itemY2 <= vpY1)) {
// no part of the item is visible
// so this region has zero area
visRect[WIDTH] = 0;
visRect[HEIGHT] = 0;
} else {
if (itemY1 < vpY1) {
// upper overlap
visRect[Y] = vpY1 - itemY1;
visRect[HEIGHT] -= (vpY1 - itemY1);
}
if (itemY2 > vpY2) {
// lower overlap
visRect[HEIGHT] -= (itemY2 - vpY2);
}
}
}
| private native void | showNativeResource0(int nativeId, int modelVersion, int w, int h)Populate the native Form with visible ItemLF s
and then show.
| public void | uCallFreeze()Notify this Form that it is being frozen.
if (state == SHOWN) {
resetToTop = false;
}
uCallItemHide();
// Delete Form's native resource including title and ticker
super.uCallFreeze();
| public void | uCallHide()Notify this Form that it is being hidden.
synchronized (Display.LCDUILock) {
pendingCurrentItem = null;
}
uCallItemHide();
// Delete Form's native resource including title and ticker
super.uCallHide();
| public void | uCallInvalidate()This method is responsible for:
(1) Re-validate the contents of this Form , possibly due
to an individual item
(2) setup the viewable/scroll position
(3) repaint the currently visible Item s
super.uCallInvalidate();
int new_width = Display.getScreenWidth0();
int new_height = Display.getScreenHeight0();
// It could be that setCurrentItem() was called and we
// have done an 'artificial' traversal. In this case, we
// manually call traverseOut() on the last traversed item
// if there is one.
if (lastTraverseItem != null) {
try {
lastTraverseItem.uCallTraverseOut();
} catch (Throwable t) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_HIGHUI,
"Throwable while traversing out");
}
}
lastTraverseItem = null;
updateCommandSet();
}
synchronized (Display.LCDUILock) {
// Do nothing if paint is suspended in current Display
if (!lIsShown()) {
return;
}
// Do not reset the Form from the top since this is an update
resetToTop = false;
}
// Setup items and show form native resource
// SYNC NOTE:
// called without LCDUILock, since it may end up calling into a MIDlet
if (new_width != width || new_height != height) {
width = new_width;
height = new_height;
firstShown = true;
}
// IMPL NOTES: Remove this line after UDPATE_LAYOUT is fixed
firstShown = true;
// Update contents
uShowContents(false);
// SYNC NOTE:
// 1. We are on event dispatch thread, currentDisplay won't change.
// 2. We are on event dispatch thread, call paint synchronously.
// 3. Since we could call into app's functions, like traverse(),
// showNotify() and paint(), do this outside LCDUILock block.
currentDisplay.callPaint(0, 0, width, height, null);
| void | uCallItemHide()Hide items when Form is frozen or hidden
// No more than one custom item can be in focus at a time
ItemLFImpl customItemToTraverseOut = null;
ItemLFImpl[] itemsCopy = null;
int count = 0;
synchronized (Display.LCDUILock) {
// We need to loop through our Items to identify those
// that traverseOut and hideNotify need to be called.
//
// SYNC NOTE:
// We cannot call into app code while holding LCDUILock.
// For CustomItems, we postpone calls to outside this
// sync. block.
itemsCopy = new ItemLFImpl[numOfLFs];
for (int x = 0; x < numOfLFs; x++) {
try {
// callTraverseOut needs to happen on the item in focus
if (itemLFs[x].hasFocus) {
if (itemLFs[x] instanceof CustomItemLFImpl) {
customItemToTraverseOut = itemLFs[x];
} else {
// SYNC NOTE: Items other than CustomItem do not
// call into app code in their traverseOut.
// We can call it while holding the LCDUILock.
itemLFs[x].uCallTraverseOut();
}
}
itemLFs[x].lHideNativeResource();
// Free native resource of each ItemLF
itemLFs[x].deleteNativeResource();
// Items that are visible in the viewport
// should set their visibleInViewport flag to false and
// CustomItems should call app's hideNotify() as well
if (itemLFs[x].visibleInViewport) {
if (itemLFs[x] instanceof CustomItemLFImpl) {
// Remember it in temporary array
itemsCopy[count++] = itemLFs[x];
} else {
itemLFs[x].lCallHideNotify();
}
}
} catch (Throwable t) {
// do nothing... move on
}
}
} // synchronized
// Call CustomItem traverseOut outside LCDUILock
if (customItemToTraverseOut != null) {
customItemToTraverseOut.uCallTraverseOut();
}
// Call CustomItem hideNotify outside LCDUILock
for (count--; count >= 0; count--) {
itemsCopy[count].uCallHideNotify();
}
| boolean | uCallItemTraverse(ItemLFImpl item, int dir)Perform an internal traversal on the given item in
the given direction. The only assertion here is that
the item provided must be interactive (or otherwise
be a CustomItem). When this method returns, visRect[]
will hold the bounding box of the item's internal
traversal (in the Form's coordinate space).
boolean ret = false;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] uCallItemTraverse: dir=" + dir +
" traverseIndex=" + traverseIndex);
}
// The visRect is supposed to show the bounds of the Item
// currently visible on the screen
setVisRect(item, visRect);
// Whether the item performs an internal traversal or not,
// it has the current input focus
//item.hasFocus = true;
// Call traverse() outside LCDUILock
if (item.uCallTraverse(dir,
width, viewportHeight, visRect))
{
synchronized (Display.LCDUILock) {
// It's possible that this newFocus item has
// been just removed from this Form since we
// are outside LCDUILock. Check again.
if (item.nativeId != INVALID_NATIVE_ID) {
setCurrentItem0(nativeId, item.nativeId, visRect[Y]);
}
}
ret = true;
}
// Since visRect is sent to the Item in its own coordinate
// space, we translate it back into the overall Form's
// coordinate space
visRect[X] += item.bounds[X];
visRect[Y] += item.bounds[Y];
return ret;
| void | uCallKeyPressed(int keyCode)Handle a key press.
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"got callKeyPressed: " + keyCode);
}
int dir = KeyConverter.getGameAction(keyCode);
if (isNavigationKey(dir)) {
uTraverse(dir);
} else {
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
v = getItemInFocus();
}
// pass the keypress onto the current item
if (v != null && v instanceof CustomItemLFImpl) {
// NOTE: customItem.getInteractionModes() determines
// the supported events. The Zaurus platform implementation
// does not support traversal in any direction.
// if it is desired to support horizontal and/or vertical
// traversal, than the proper flags must be set accordingly.
// pass all key events to the CustomItem, including arrows
v.uCallKeyPressed(keyCode);
}
}
| void | uCallKeyReleased(int keyCode)Handle a key release event.
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"got callKeyReleased: " + keyCode);
}
if (!isNavigationKey(KeyConverter.getGameAction(keyCode))) {
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
v = getItemInFocus();
} // synchronized
// SYNC NOTE: formMode can only change as a result of a
// traversal, which can only occur serially on the event
// thread, so its safe to use it outside of the lock
if (v != null && v instanceof CustomItemLFImpl) {
v.uCallKeyReleased(keyCode);
}
}
| void | uCallKeyRepeated(int keyCode)Handle a key repeat.
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"got callKeyRepeated: " + keyCode);
}
if (isNavigationKey(KeyConverter.getGameAction(keyCode))) {
uCallKeyPressed(keyCode);
} else {
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
v = getItemInFocus();
} // synchronized
// SYNC NOTE: formMode can only change as a result of a
// traversal, which can only occur serially on the event
// thread, so its safe to use it outside of the lock
if (v != null && v instanceof CustomItemLFImpl) {
v.uCallKeyRepeated(keyCode);
}
}
| public void | uCallPaint(Graphics g, java.lang.Object target)Paint the contents of this Form .
int count;
synchronized (Display.LCDUILock) {
// super.lCallPaint(g, target); -- obsolete
if (numOfLFs == 0) {
return;
}
// SYNC NOTE: since we may call into CustomItem.paint(),
// we have to do it outside LCDUILock. So make a copy of the
// itemLFs array.
if (target instanceof Item) {
if (((Item)target).owner == this.owner) {
ensureDispatchItemArray(1);
dispatchItemLFs[0] = (ItemLFImpl)((Item)target).itemLF;
count = 1;
} else {
count = 0;
}
} else {
ensureDispatchItemArray(numOfLFs);
System.arraycopy(itemLFs, 0, dispatchItemLFs, 0, numOfLFs);
count = numOfLFs;
}
}
// Call paint on the copied itemLFs array
for (int i = 0; i < count; i++) {
uPaintItem(dispatchItemLFs[i], g);
}
// Dereference ItemLFImpl objects in dispatchItemLFs
// But leave the shrinking to uCallHide
resetDispatchItemArray(false);
| public void | uCallPeerStateChanged(int modelVersion, int peerId, int hint)Called by Display to notify an ItemLF
in current FormLF of a change in its peer state.
If the the peerId matches the nativeId of this FormLF ,
uViewportChanged() will be called to process the scroll
notification.
Otherwise, if there is an ItemLF that matches the peerId,
the ItemLF will be called to process this notification.
Otherwise, this is treated as a special notification to this
FormLF upon focus changed between items, and
parameter 'hint' will contain the index of the new current
ItemLF .
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"-=-=- FormLF: dsPeerStateChanged " +
peerId + "/" + hint);
}
int notifyType;
ItemLFImpl oldFocus = null, itemLFToNotify = null;
synchronized (Display.LCDUILock) {
if (modelVersion != super.modelVersion) {
return; // model version out of sync, ignore the event
}
// If not matching ItemLF, this is a focus changed notification
// 'hint' is the id of the new focused itemLF
if (peerId == INVALID_NATIVE_ID) {
notifyType = 1; // focus changed
oldFocus = getItemInFocus();
itemLFToNotify = id2Item(hint);
} else if (peerId == nativeId) {
// there is a scroll event from the native peer,
// we call show/hide Notify outside of the synchronized block
notifyType = 2; // viewport changed
} else {
// peerId identified the ItemLF, notify it
notifyType = 3; // item peer state changed
itemLFToNotify = id2Item(peerId);
}
}
// SYNC NOTE: Following calls may end in app code.
// So do it outside LCDUILock
switch (notifyType) {
case 1: // Focus notification
uFocusChanged(itemLFToNotify);
break;
case 2: // Scrolling notification
// 'hint' is the new viewport position
uViewportChanged(hint, hint + viewportHeight);
// Spec requires CustomItem's paint() to be called after
// its showNotify() is called and before hideNotify()
// it is safe to pass null as both parameters
// because only CustomItems will be repainted and they
// use their own Graphics
uCallPaint(null, null);
break;
case 3: // Item peer notification
if (itemLFToNotify != null &&
itemLFToNotify.uCallPeerStateChanged(hint)) {
// Notify the itemStateListener
owner.uCallItemStateChanged(itemLFToNotify.item);
}
break;
default:
// for safety/completeness.
Logging.report(Logging.WARNING, LogChannels.LC_HIGHUI_FORM_LAYOUT,
"FormLFImpl: notifyType=" + notifyType);
break;
}
| void | uCallPointerDragged(int x, int y)Handle a pointer dragged event.
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"got callPointerDragged: " + x + "," + y);
}
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
v = getItemInFocus();
// stop here if no current item to handle the key
if (v == null) {
return;
}
} // synchronized
// SYNC NOTE: formMode can only change as a result of a
// traversal, which can only occur serially on the event
// thread, so its safe to use it outside of the lock
if (v instanceof CustomItemLFImpl) {
v.uCallPointerDragged(x, y);
}
| void | uCallPointerPressed(int x, int y)Handle a pointer pressed event.
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"got callPointerPressed: " + x + "," + y);
}
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
v = getItemInFocus();
// stop here if no current item to handle the key
if (v == null) {
return;
}
} // synchronized
// SYNC NOTE: formMode can only change as a result of a
// traversal, which can only occur serially on the event
// thread, so its safe to use it outside of the lock
if (v instanceof CustomItemLFImpl) {
v.uCallPointerPressed(x, y);
}
| void | uCallPointerReleased(int x, int y)Handle a pointer released event.
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"got callPointerReleased: " + x + "," + y);
}
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
v = getItemInFocus();
// stop here if no current item to handle the key
if (v == null) {
return;
}
} // synchronized
// SYNC NOTE: formMode can only change as a result of a
// traversal, which can only occur serially on the event
// thread, so its safe to use it outside of the lock
if (v instanceof CustomItemLFImpl) {
v.uCallPointerReleased(x, y);
}
| public void | uCallShow()Notify this Form that it is being shown.
// Create native resources with title and ticker
super.uCallShow();
// Setup items and show form native resource
// SYNC NOTE: May call into app code to collect sizes.
// Call it outside LCDUILock
uShowContents(true);
synchronized (Display.LCDUILock) {
if (pendingCurrentItem != null) {
lScrollToItem(pendingCurrentItem);
pendingCurrentItem = null;
}
}
| private void | uEnsureResourceAndRequestedSizes()Make sure all items have native resource and
all CustomItem s have their minimum and preferred sizes
cached.
int i, count = 0;
ItemLFImpl[] itemsCopy = null;
synchronized (Display.LCDUILock) {
if (nativeId == INVALID_NATIVE_ID) {
return;
}
// Make a temporary copy of ItemLFs we need to collect sizes from
itemsCopy = new ItemLFImpl[numOfLFs];
// Make sure each Item has native resource
// and remember all the CustomItemLFImpls
for (i = 0; i < numOfLFs; i++) {
if (itemLFs[i].nativeId == INVALID_NATIVE_ID) {
itemLFs[i].createNativeResource(super.nativeId);
// layout(UPDATE_LAYOUT) later will not call
// setSize/setLocation on an ItemLF that has valid bounds
// already. But the native resource is recreated
// above, we make up these two calls here.
itemLFs[i].initNativeResource();
// Every native resource is default to be visible in
// viewport. It's up to the native container to maintain
// viewport.
itemLFs[i].lShowNativeResource();
}
if (itemLFs[i] instanceof CustomItemLFImpl) {
// Remember this in temporary array
itemsCopy[count++] = itemLFs[i];
}
}
} // synchronized
// Collect min and preferred sizes from CustomItems
// SYNC NOTE: This may call into app code like
// CustomItem.getPrefContentWidth(). So do it outside LCDUILock
for (i = 0; i < count; i++) {
((CustomItemLFImpl)itemsCopy[i]).uCallSizeRefresh();
}
| private void | uFocusChanged(ItemLFImpl newFocus)Update current item index and notify related item of the change.
Item specific abstract commands will also be shown.
ItemLFImpl oldFocus = null;
synchronized (Display.LCDUILock) {
pendingCurrentItem = null;
int focusIndex = item2Index(newFocus); // Could be -1
if (focusIndex == traverseIndex) {
oldFocus = newFocus;
} else {
oldFocus = traverseIndex > 0 ? itemLFs[traverseIndex] : null;
traverseIndex = focusIndex;
}
}
if (oldFocus != newFocus) {
if (oldFocus != null) {
oldFocus.uCallTraverseOut();
}
if (newFocus != null) {
itemTraverse =
uCallItemTraverse(newFocus, CustomItem.NONE);
}
updateCommandSet();
// call paint for custom items
uRequestPaint();
}
| void | uInitItemsInViewport(int dir, ItemLFImpl[] itemsCopy, int traverseIndexCopy)Initialize the current page of items, perform a traverse if possible.
This method is always called when a page is initially "shown".
This occurs when the form gains visibility for the very first
time as well as after every page up/page down occurs.
This method searches for the most appropriate item on the form
to receive the interaction focus.
// Create a copy of the current index for comparisons, below.
if (itemsCopy.length == 0) {
return;
}
// Hide & Show Items
int pos = getScrollPosition0();
uViewportChanged(pos, pos + viewportHeight);
// The result of an invalidate() call
if (traverseIndexCopy != -1 && dir == CustomItem.NONE) {
itemTraverse =
uCallItemTraverse(itemsCopy[traverseIndexCopy], dir);
uRequestPaint(); // request to paint contents area
return;
}
// Special case: It could be that no item in the current view
// is interactive, and thus the traverseIndexCopy is -1. If we
// are scrolling upwards, we artificially set it to be the last
// item on the form (+1) so that the getNextInteractiveItem()
// routine will subsequently reduce it by 1 and start searching
// for an interactive item from the bottom of the form upwards.
if (dir == Canvas.UP && traverseIndexCopy == -1) {
traverseIndexCopy = itemsCopy.length;
}
// If paging "down", we find the interactive item by moving
// left to right - this ensures we move line by line searching
// for an interactive item. When paging "up", we search from
// right to left.
int nextIndex = (dir == Canvas.DOWN || dir == CustomItem.NONE)
? getNextInteractiveItem(
itemsCopy, Canvas.RIGHT, traverseIndexCopy)
: getNextInteractiveItem(
itemsCopy, Canvas.LEFT, traverseIndexCopy);
if (traverseIndexCopy > -1 && traverseIndexCopy < itemsCopy.length) {
if (nextIndex != -1 ||
!itemCompletelyVisible(itemsCopy[traverseIndexCopy]))
{
// It could be we need to traverse out of a current
// item before paging
itemsCopy[traverseIndexCopy].uCallTraverseOut();
synchronized (Display.LCDUILock) {
traverseIndex = -1; // reset real index
traverseIndexCopy = traverseIndex;
}
}
}
/*
* NOTE: between these two sync sections itemLFs[] & traverseIndex
* can change again ...
*/
synchronized (Display.LCDUILock) {
if (itemsModified) {
// SYNCHRONIZE itemLFs & itemsCopy, update traverseIndex ...
itemsCopy = lRefreshItems(
itemsCopy, traverseIndexCopy, nextIndex);
} else if ((nextIndex > -1) && (nextIndex < numOfLFs)) {
traverseIndex = nextIndex;
}
traverseIndexCopy = traverseIndex;
}
if (traverseIndexCopy == -1 || traverseIndexCopy == itemsCopy.length) {
// If there is no traversable item on the current page,
// we simply return, and on the next 'traverse' we will
// perform a page scroll and repeat this method
} else {
// If there is a traversable item, we go ahead and traverse
// to it. We do *not* scroll at all under these circumstances
// because we have just performed a fresh page view (or scroll)
itemTraverse =
uCallItemTraverse(itemsCopy[traverseIndexCopy], dir);
}
uRequestPaint(); // request to paint contents area
| public boolean | uIsScrollNative()This method is used in repaint, in order to determine the translation
of the draw coordinates.
// only native form overrides this and returns true
return true;
| public void | uItemMakeVisible(Item i)Set the current traversal location to the given Item .
This call has no effect if the given Item is the
current traversal item, or if the given Item is not
part of this Form . Note that null can be passed in
clear the previously set current item.
synchronized (Display.LCDUILock) {
if (i == null) {
pendingCurrentItem = null;
}
/**
* Display could be made visible using display.setCurrentItem()
* call. In those cases foregroung will be granted after there
* there is a screen change event and after uItemMakeVisible()
* is called. In such cases we need to set pendingCurrentItem and
* call uItemMakeVisible() again when the FormLF changes its
* state to SHOWN.
*/
if (state != SHOWN) {
pendingCurrentItem = i;
return;
}
}
| void | uPaintItem(ItemLFImpl itemLF, Graphics g)Paint an item.
synchronized (Display.LCDUILock) {
// NOTE: Its possible, that an Item is in an invalid state
// during a requested repaint. Its ok to simply return,
// because it means there is a validation event coming on
// the event thread. When the form re-validates, the Item
// will be given a proper bounds and will be repainted
if (itemLF.actualBoundsInvalid[X]
|| itemLF.actualBoundsInvalid[Y]
|| itemLF.actualBoundsInvalid[WIDTH]
|| itemLF.actualBoundsInvalid[HEIGHT]
|| itemLF.nativeId == INVALID_NATIVE_ID) {
return;
}
}
// repaint only visible in viewport items
if (itemLF.visibleInViewport) {
// CustomItem uses its own off screen graphics for painting
// and the rest of the items do not need to repaint
itemLF.uCallPaint(null,
itemLF.bounds[WIDTH], itemLF.bounds[HEIGHT]);
}
| void | uScrollViewport(int dir, ItemLFImpl[] items)Perform a page flip in the given direction. This method will
attempt to scroll the view to show as much of the next page
as possible. It uses the locations and bounds of the items on
the page to best determine a new location - taking into account
items which may lie on page boundaries as well as items which
may span several pages.
int scrollPos = getScrollPosition0();
if (dir == Canvas.UP) {
int newY = scrollPos - (viewportHeight - PIXELS_LEFT_ON_PAGE);
if (newY < 0) {
newY = 0;
}
// We loop upwards until we find the first item which is
// currently at least partially visible
int firstVis = items.length;
for (int i = items.length - 1; i >= 0; i--) {
if (items[i].visibleInViewport) {
firstVis = i;
}
}
// case 1. We're at the top of the item so just
// traverse normally
if (items[firstVis].bounds[Y] >= scrollPos) {
scrollPos = newY;
setScrollPosition0(scrollPos);
return;
}
// case 2. We try to fit as much of the partially visible
// item onscreen as possible.
int fitY =
(items[firstVis].bounds[Y] + items[firstVis].bounds[HEIGHT]) -
viewportHeight;
if (fitY > newY && scrollPos > fitY) {
newY = fitY;
}
scrollPos = newY;
setScrollPosition0(scrollPos);
return;
} else if (dir == Canvas.DOWN) {
int newY = scrollPos + (viewportHeight - PIXELS_LEFT_ON_PAGE);
if (newY > viewable[HEIGHT] - viewportHeight) {
newY = viewable[HEIGHT] - viewportHeight;
}
// We loop downwards until we find the last item which is
// at least partially visible
int lastVis = -1;
for (int i = 0; i < items.length; i++) {
if (items[i].visibleInViewport) {
lastVis = i;
}
}
// case 1. We're at the bottom of the item so just
// traverse normally
if (items[lastVis].bounds[Y] + items[lastVis].bounds[HEIGHT] <=
scrollPos + viewportHeight)
{
scrollPos = newY;
setScrollPosition0(scrollPos);
return;
}
// case 2. We try to fit as much of the partially visible
// item onscreen as possible unless we're already at the top
// of the item from a previous scroll
if (newY > items[lastVis].bounds[Y] &&
scrollPos < items[lastVis].bounds[Y])
{
newY = items[lastVis].bounds[Y];
}
scrollPos = newY;
setScrollPosition0(scrollPos);
return;
}
| public boolean | uSetRotatedStatus(boolean newStatus)Set status of screen rotation
boolean status = super.uSetRotatedStatus(newStatus);
if (status) {
firstShown = true;
}
return status;
| private void | uShowContents(boolean initialTraverse)Show all items and give focus to current item.
SYNC NOTE: caller must NOT hold LCDUILock since this function may
call into app code like getPrefContentWidth(), sizeChanged or paint()
of CustomItem.
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"\nFormLFImpl: showContents()");
}
synchronized (Display.LCDUILock) {
if (firstShown) {
for (int i = 0; i < numOfLFs; i++) {
itemLFs[i].cachedWidth = ItemLFImpl.INVALID_SIZE;
}
}
}
// Ensure resources for all items and requested sizes for CustomItems
uEnsureResourceAndRequestedSizes();
ItemLFImpl[] itemsCopy = null;
int itemsCopyCount = 0;
int traverseIndexCopy = -1;
// Layout
synchronized (Display.LCDUILock) {
if (nativeId == INVALID_NATIVE_ID) {
return;
}
if (firstShown) {
LayoutManager.instance().lLayout(LayoutManager.FULL_LAYOUT,
itemLFs,
numOfLFs,
width,
height,
viewable);
firstShown = false;
} else {
LayoutManager.instance().lLayout(LayoutManager.UPDATE_LAYOUT,
itemLFs,
numOfLFs,
width,
height,
viewable);
}
if (resetToTop) {
traverseIndex = -1;
setScrollPosition0(0);
}
itemsCopy = new ItemLFImpl[numOfLFs];
itemsCopyCount = numOfLFs;
System.arraycopy(itemLFs, 0, itemsCopy, 0, numOfLFs);
traverseIndexCopy = traverseIndex;
itemsModified = false;
// Set native Form's window viewable size (logical Form size)
// and make it shown if not yet
showNativeResource0(nativeId, modelVersion, width,
viewable[HEIGHT]);
// update viewport height
viewportHeight = getViewportHeight0();
// correct scroll position if any
if (viewable[HEIGHT] <= viewportHeight) {
// if viewable height is less than viewport
// height just reset viewable y
setScrollPosition0(0);
} else if (getScrollPosition0() > (viewable[HEIGHT] - viewportHeight)) {
// if viewable y exceeds the max value set it to the max
// height just reset viewable y
setScrollPosition0(viewable[HEIGHT] - viewportHeight);
}
} // synchronized
uInitItemsInViewport(CustomItem.NONE, itemsCopy, traverseIndexCopy);
if (initialTraverse) {
updateCommandSet();
}
for (int index = 0; index < itemsCopyCount; index++) {
if (itemsCopy[index].sizeChanged) {
itemsCopy[index].uCallSizeChanged(itemsCopy[index].bounds[WIDTH],
itemsCopy[index].bounds[HEIGHT]);
itemsCopy[index].sizeChanged = false;
}
}
| void | uTraverse(int dir)Perform a traversal. This method handles traversal within a
"page" after the initial page has been shown via the
uInitItemsInViewport() routine. At the point this method is
called, the following conditions must be true:
1.) There are no interactive items at all on the current page
or
2.) There is at least one interactive item on the current page
and the traverseIndex is currently set to that item. In this
case, itemTraverse represents the return value of that item's
initial traverse() call.
Based on these conditions, this method will either:
1.) Continue the internal traversal on the current item (scrolling
as necessary to display the item's internal traversal location)
or
2.) Perform a traversal to the next interactive item on the page
or
3.) Perform a page flip (uScrollViewport()) and call the
uInitItemsInViewport() routine to select an appropriate
traversal item
SYNC NOTE: Maybe call into CustomItem.traverse().
So caller must not hold LCDUILock.
ItemLFImpl[] itemsCopy;
int traverseIndexCopy;
synchronized (Display.LCDUILock) {
itemsCopy = new ItemLFImpl[numOfLFs];
traverseIndexCopy = traverseIndex;
System.arraycopy(itemLFs, 0, itemsCopy, 0, numOfLFs);
itemsModified = false;
}
// itemTraverse indicates the return value of the
// last call to the current item's traverse method.
// 'true' indicates it is doing internal traversal,
// 'false' indicates we may traverse out of that item
// if we have something else to traverse to or scrolling
// that needs to be done
if (itemTraverse) {
if (traverseIndexCopy == -1) {
itemTraverse = false;
return;
}
itemTraverse =
uCallItemTraverse(itemsCopy[traverseIndexCopy], dir);
if (itemTraverse) {
// We may have to scroll to accommodate the new
// traversal location
if (scrollForBounds(dir, visRect)) {
uRequestPaint();
}
return;
}
}
// We are done with the traversal of the current item, so
// we look to see if another interactive item is available on
// current page
int nextIndex =
getNextInteractiveItem(itemsCopy, dir, traverseIndexCopy);
if (nextIndex != -1) {
// NOTE: In traverse(), if there is a "next" interactive
// item, there must have been a "first" interactive item
// (which was set initially in uInitItemsInViewport())
// so traverseIndex should always be valid
// We need to traverse out of the previous item, now that
// we've found a new item to traverse to
// NOTE WELL: traverseIndex (and thus traverseIndexCopy) may well
// be invalid if there is no currently focused item, the app adds
// a focusable item, and then the user traverses before the
// resulting invalidation can be processed. Thus, this value must
// be guarded anyway. See CR#6254765.
if (traverseIndexCopy != -1) {
itemsCopy[traverseIndexCopy].uCallTraverseOut();
synchronized (Display.LCDUILock) {
itemsCopy[traverseIndexCopy].lRequestPaint();
}
}
/*
* NOTE: Although we update traverseIndex in a synchronized block
* and call "lRefreshItems()" to update itemsCopy[] &
* traverseIndexCopy,
* original itemLFs[] & traverseIndex can change after sync block -
* so we still have a risk of referring to a non-existent item...
*/
synchronized (Display.LCDUILock) {
if (itemsModified) {
// SYNCHRONIZE itemLFs & itemsCopy ...
itemsCopy = lRefreshItems(
itemsCopy, traverseIndexCopy, nextIndex);
} else {
// Update our traverse index to the new item
traverseIndex = nextIndex;
}
traverseIndexCopy = traverseIndex;
}
if (traverseIndexCopy != -1) {
// We then need to traverse to the next item
itemTraverse =
uCallItemTraverse(itemsCopy[traverseIndexCopy], dir);
if (scrollForBounds(dir, visRect)) {
uRequestPaint(); // request to paint contents area
} else {
synchronized (Display.LCDUILock) {
itemsCopy[traverseIndexCopy].lRequestPaint();
}
}
}
int scrollPos = getScrollPosition0();
// There is a special case when traversing to the very last
// item on a Form
if (traverseIndexCopy == (itemsCopy.length - 1) &&
!itemCompletelyVisible(itemsCopy[traverseIndexCopy]))
{
// Since its the last item, we may need to
// perform a partial scroll to fit it.
if (scrollPos + viewportHeight !=
itemsCopy[traverseIndexCopy].bounds[Y] +
itemsCopy[traverseIndexCopy].bounds[HEIGHT])
{
scrollPos = viewable[HEIGHT] - viewportHeight;
// We make sure we don't go past the top of the
// item, as we must have been going down to reach
// the last item
if (scrollPos > itemsCopy[traverseIndexCopy].bounds[Y]) {
scrollPos = itemsCopy[traverseIndexCopy].bounds[Y];
}
uRequestPaint();
}
}
// Likewise, there is a special case when traversing up to
// the very first item on a Form
if (traverseIndexCopy == 0) {
// Since its the first item, we may need to
// perform a partial scroll to fit it.
if (scrollPos != itemsCopy[traverseIndexCopy].bounds[Y]) {
scrollPos = itemsCopy[traverseIndexCopy].bounds[Y];
// We make sure we don't go past the bottom of the
// item, as we must have been going up to get to
// the first item
if (itemsCopy[traverseIndexCopy].bounds[HEIGHT] >
viewportHeight)
{
scrollPos =
itemsCopy[traverseIndexCopy].bounds[HEIGHT] -
viewportHeight;
}
uRequestPaint();
}
}
setScrollPosition0(scrollPos);
updateCommandSet();
} else {
// There is no more interactive items wholly visible on
// the current page. We may need to scroll to the next page,
// if we do, then traverse out of the current item and
// scroll the page
int scrollPos = getScrollPosition0();
if ((dir == Canvas.LEFT || dir == Canvas.UP) && scrollPos > 0) {
// Special case. We're at the top-most interactive item, but
// its internal traversal doesn't allow the very top to be
// seen, we just scroll the view to show it
if (traverseIndexCopy != -1 &&
(scrollPos > itemsCopy[traverseIndexCopy].bounds[Y]))
{
scrollPos -= (viewportHeight - PIXELS_LEFT_ON_PAGE);
if (scrollPos < 0) {
scrollPos = 0;
}
setScrollPosition0(scrollPos);
uRequestPaint();
} else {
// page up
uScrollViewport(Canvas.UP, itemsCopy);
uInitItemsInViewport(
Canvas.UP, itemsCopy, traverseIndexCopy);
updateCommandSet();
return;
}
} else if ((dir == Canvas.RIGHT || dir == Canvas.DOWN) &&
(scrollPos + viewportHeight < viewable[HEIGHT]))
{
// Special case. We're at the bottom-most interactive item,
// but its internal traversal doesn't allow the very bottom
// to be seen, we just scroll the view to show it
if (traverseIndexCopy != -1 &&
((itemsCopy[traverseIndexCopy].bounds[Y] +
itemsCopy[traverseIndex].bounds[HEIGHT]) >
(scrollPos + viewportHeight)))
{
scrollPos += (viewportHeight - PIXELS_LEFT_ON_PAGE);
if (scrollPos > (viewable[HEIGHT] - viewportHeight))
{
scrollPos = viewable[HEIGHT] - viewportHeight;
}
setScrollPosition0(scrollPos);
uRequestPaint();
} else {
// page down
uScrollViewport(Canvas.DOWN, itemsCopy);
uInitItemsInViewport(
Canvas.DOWN, itemsCopy, traverseIndexCopy);
updateCommandSet();
return;
}
}
// If we don't need to scroll the page and there is nothing
// to traverse to, we reset the itemTraverse result as if
// the Item wishes to proceed with internal traversal (as long
// as there was some initial traverse in the first place, ie,
// traverseIndex != -1)
if (traverseIndexCopy != -1) {
itemTraverse = true;
}
updateCommandSet();
}
| private void | uViewportChanged(int vpY1, int vpY2)Called by the system to notify that viewport scroll location
or height has been changed.
int i, showCount, hideCount, size;
ItemLFImpl[] itemsCopy = null;
synchronized (Display.LCDUILock) {
itemsCopy = new ItemLFImpl[numOfLFs];
size = numOfLFs;
showCount = 0;
hideCount = numOfLFs;
for (i = 0; i < numOfLFs; i++) {
if (itemLFs[i].bounds[Y] +
itemLFs[i].bounds[HEIGHT]-1 > vpY1 &&
itemLFs[i].bounds[Y] < vpY2) {
// should become visible
if (itemLFs[i].visibleInViewport == false) {
itemsCopy[showCount++] = itemLFs[i];
}
} else {
// should not be visible
if (itemLFs[i].visibleInViewport) {
itemsCopy[--hideCount] = itemLFs[i];
}
}
}
} // synchronized (LCDUILock)
for (i = 0; i < showCount; i++) {
itemsCopy[i].uCallShowNotify();
}
for (i = hideCount; i < size; i++) {
itemsCopy[i].uCallHideNotify();
}
|
|