FormLFImplpublic class FormLFImpl extends ScreenLFImpl implements FormLFLook and feel class for Form.
See DisplayableLF.java for naming convention. |
Fields Summary |
---|
static final boolean | TRAVERSE_HORIZONTALA boolean declaring whether the contents of the viewport
can be traversed using the horizontal traversal keys,
ie, left and right | static final boolean | TRAVERSE_VERTICALA boolean declaring whether the contents of the viewport
can be traversed using the vertical traversal keys,
ie, up and down | 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 | 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. | boolean | pointerPressedtrue if a callPointerPressed event has occurred without
a corresponding callPointerReleased. false otherwise | boolean | scrollInitializedA flag indicating if scroll has been initialized. When the form
is first shown, it can only set the scroll after it has become
current, which is after show() and before paint(), but there's
hard to set the scroll then until the paint() routine - which
is not the best place to do it. | 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 | ItemLFImpl[] | itemLFsArray of ItemLFs that correspond to the array of items in Form | static final int | DISPATCH_ITEM_ARRAY_BLOCKBlock size of the temporary array of ItemLFs used in dispatch. | static ItemLFImpl[] | dispatchItemLFsTemporary array of ItemLFs 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. | int | numOfLFsThe number of views present in this FormLF. | boolean | firstShownoptimization flag | Item | pendingCurrentItemItem that was made visible using display.setCurrentItem() call
while FormLF was in HIDDEN or FROZEN state. |
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];
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;
visRect = new int[4];
if (screen instanceof TextBox && item instanceof TextField) {
TextField textField = (TextField)item;
((TextFieldLFImpl)textField.textFieldLF).setBorder(false);
}
|
Methods Summary |
---|
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];
}
| private ItemLFImpl | findItemByPointer(int x, int y)Return the item containing the pointer {x, y}
ItemLFImpl item = null;
for (int i = 0; i < numOfLFs; i++) {
if (!itemLFs[i].shouldSkipTraverse()) {
if (itemLFs[i].itemContainsPointer(x + viewable[X], y + viewable[Y])) {
item = itemLFs[i];
break;
}
}
}
return item;
| int | findNearestNeighborDown(ItemLFImpl[] items, int index)Find the nearest neighbor to the given Item index
moving downward
// SYNC NOTE: see traverse()
if (index == -1) {
return 0;
}
int a1 = items[index].bounds[X];
int b1 = items[index].bounds[Y];
int a2 = a1 + items[index].bounds[WIDTH];
int b2 = b1 + items[index].bounds[HEIGHT] + 1;
int x1, y1, x2, y2;
int greatestY = -1;
while (true) {
for (int i = index + 1; i < items.length; i++) {
x1 = items[i].bounds[X];
y1 = items[i].bounds[Y];
x2 = x1 + items[i].bounds[WIDTH];
y2 = y1 + items[i].bounds[HEIGHT];
if (y2 > greatestY) {
greatestY = y2;
}
x1 = (a1 > x1) ? a1: x1;
y1 = (b1 > y1) ? b1: y1;
x2 = (a2 < x2) ? a2: x2;
y2 = (b2 < y2) ? b2: y2;
if (x2 >= x1 & y2 >= y1) {
return i;
}
}
if (b2 > greatestY) {
break;
}
}
return -1;
| int | findNearestNeighborUp(ItemLFImpl[] items, int index)Find the nearest neighbor to the given Item index
moving upward
// SYNC NOTE: see traverse()
if (index == 0) {
return -1;
}
int a1 = items[index].bounds[X];
int b1 = items[index].bounds[Y] - 1;
int a2 = a1 + items[index].bounds[WIDTH];
int b2 = b1 + items[index].bounds[HEIGHT] - 1;
int x1, y1, x2, y2;
int leastY = viewable[HEIGHT];
while (true) {
for (int i = index - 1; i >= 0; i--) {
x1 = items[i].bounds[X];
y1 = items[i].bounds[Y];
x2 = x1 + items[i].bounds[WIDTH];
y2 = y1 + items[i].bounds[HEIGHT];
if (y1 < leastY) {
leastY = y1;
}
x1 = (a1 > x1) ? a1: x1;
y1 = (b1 > y1) ? b1: y1;
x2 = (a2 < x2) ? a2: x2;
y2 = (b2 < y2) ? b2: y2;
if (x2 >= x1 & y2 >= y1) {
return i;
}
}
if (b1 < leastY) {
break;
}
}
return -1;
| public int | getDisplayableHeight()Calculate the height a displayable would occupy if it was to
be displayed.
int h = super.getDisplayableHeight();
if (traverseIndex != -1 && itemLFs != null &&
itemLFs[traverseIndex] instanceof TextFieldLFImpl) {
if (((TextFieldLFImpl)itemLFs[traverseIndex]).hasPTI()) {
h -= PTISkin.HEIGHT;
}
}
return h;
| 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 {
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].shouldSkipTraverse()) {
continue;
}
if (itemPartiallyVisible(items[index])) {
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;
| 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
return (item.bounds[Y] >= viewable[Y] &&
item.bounds[Y] + item.bounds[HEIGHT] <= (viewable[Y] + viewport[HEIGHT]));
| 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;
}
return !(item.bounds[Y] > viewable[Y] + viewport[HEIGHT] ||
item.bounds[Y] + item.bounds[HEIGHT] < viewable[Y]);
| public void | lCommitPendingInteraction()Called to commit any pending user interaction for the current item.
Override the no-op in Displayable.
if (traverseIndex >= 0) {
itemLFs[traverseIndex].lCommitPendingInteraction();
}
| public void | lDelete(int itemNum, Item deleteditem)Notifies look&feel object of an item deleted in the corresponding
Form.
// start optimization...
// 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,
"[F]setting actualBoundsInvalid[Y] #" +
(itemNum + 1));
if (itemNum > 0) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] | itemLFs[itemNum-1] = " +
itemLFs[itemNum-1]);
}
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] | itemLFs[itemNum] = " +
itemLFs[itemNum]);
if (itemNum < numOfLFs-1) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] | 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 of an item 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. This is will be only applicable to
Form. The rest of the subclasses will return null.
// SYNC NOTE: getCurrentItem is always called from within
// a hold on LCDUILock
return traverseIndex < 0 ? null : itemLFs[traverseIndex].item;
| public int | lGetHeight()Returns the height of the area available to the application.
int h = super.lGetHeight();
return (h > 2 * ScreenSkin.PAD_FORM_ITEMS ?
h - 2 * ScreenSkin.PAD_FORM_ITEMS : 0);
| public int | lGetWidth()Returns the width of the area available to the application.
int w = super.lGetWidth();
return (w > 2 * ScreenSkin.PAD_FORM_ITEMS ?
w - 2 * ScreenSkin.PAD_FORM_ITEMS : 0);
| 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)((Form)owner).items[itemNum].getLF();
numOfLFs++;
itemsModified = true;
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].shouldSkipTraverse())
/* (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 check that 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;
| 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)) {
viewable[Y] = itemLF.bounds[Y];
if (viewable[Y] + viewport[HEIGHT] > viewable[HEIGHT]) {
viewable[Y] = viewable[HEIGHT] - viewport[HEIGHT];
}
}
// 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.shouldSkipTraverse() ? -1 : index;
lRequestInvalidate();
} else {
// Ensure the item is visible
if (!itemPartiallyVisible(itemLF)) {
viewable[Y] = itemLF.bounds[Y];
if (viewable[Y] + viewport[HEIGHT] > viewable[HEIGHT]) {
viewable[Y] = viewable[HEIGHT] - viewport[HEIGHT];
}
}
}
| public void | lSet(int itemNum, Item item)Notifies look&feel object of an item deleted in the corresponding
Form.
itemLFs[itemNum] = (ItemLFImpl)item.itemLF;
itemsModified = true;
// current optimization: the new item is marked invalid, so when
// the callInvalidate arrives, we'll know to update it and
// the minimum set of neighbor Items.
lRequestInvalidate();
| 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;
}
}
| void | scrollChanged()Notify the form that the content has been scrolled
Form should notify all items.
ItemLFImpl[] itemsCopy = null;
int itemsCopyCount = 0;
int newX, newY;
synchronized (Display.LCDUILock) {
itemsCopy = new ItemLFImpl[numOfLFs];
itemsCopyCount = numOfLFs;
System.arraycopy(itemLFs, 0, itemsCopy, 0, numOfLFs);
newX = viewable[X];
newY = viewable[Y];
} // synchronized
for (int index = 0; index < itemsCopyCount; index++) {
itemsCopy[index].uCallScrollChanged(newX, newY);
}
| 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;
}
// 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] >= viewport[HEIGHT] &&
viewable[Y] != bounds[Y])
{
viewable[Y] = bounds[Y];
return true;
}
switch (dir) {
case Canvas.LEFT:
case Canvas.UP:
if (bounds[Y] >= viewable[Y]) {
return false;
}
viewable[Y] -= (viewport[HEIGHT] - PIXELS_LEFT_ON_PAGE);
if (viewable[Y] < 0) {
viewable[Y] = 0;
}
return true;
case Canvas.RIGHT:
case Canvas.DOWN:
if (bounds[Y] + bounds[HEIGHT] <=
viewable[Y] + viewport[HEIGHT])
{
return false;
}
viewable[Y] += (viewport[HEIGHT] - PIXELS_LEFT_ON_PAGE);
if (viewable[Y] > bounds[Y]) {
viewable[Y] = bounds[Y];
}
if (viewable[Y] + viewport[HEIGHT] > viewable[HEIGHT]) {
viewable[Y] = viewable[HEIGHT] - viewport[HEIGHT];
}
return true;
default:
// for safety/completeness, don't scroll.
Logging.report(Logging.WARNING,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"FormLFImpl: bounds, dir=" + dir);
break;
}
return false;
| void | setVerticalScroll()Set the vertical scroll indicators for this Screen
if (owner instanceof TextBox && itemLFs[0] instanceof TextBoxLFImpl) {
((TextBoxLFImpl)itemLFs[0]).setVerticalScroll();
} else {
super.setVerticalScroll();
}
scrollChanged();
| 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] = viewport[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 = viewable[Y];
// vpY2 the y coordinate of bottom left pixel
int vpY2 = vpY1 + viewport[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);
}
}
}
| public void | uCallFreeze()notify this Form it is being frozen on the given Display
int oldState = state;
super.uCallFreeze();
if (oldState == SHOWN) {
uCallItemHide();
}
| public void | uCallHide()notify this Form it is being hidden on the given Display
int oldState;
synchronized (Display.LCDUILock) {
oldState = state;
pendingCurrentItem = null;
}
super.uCallHide();
if (oldState == SHOWN) {
uCallItemHide();
}
| 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 Items
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] *-* FormLFImpl: dsInvalidate ");
}
synchronized (Display.LCDUILock) {
pendingInvalidate = false;
}
// 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;
}
// IMPL NOTES: Remove this line after UDPATE_LAYOUT is fixed
firstShown = true;
// Update contents
uShowContents(false);
// Request a repaint
uRequestPaint();
| private void | uCallItemHide()Calls uCallItemTraverseOut() and uCallHideNotify() when Form is
frozen or hidden
// SYNC NOTE: Rather than make a complete copy of the set
// of items on this form, we'll simply catch any exception
// that occurs and move on. The only problem that could occur
// would be items being deleted from the Form, which would
// mean the application was removing items from the Form
// while it was technically still visible.
if (traverseIndex != -1) {
try {
itemLFs[traverseIndex].uCallTraverseOut();
} catch (Throwable t) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_HIGHUI,
"Throwable while traversing out");
}
}
}
// We need to loop through our Items and call hideNotify
// on those that were visible
for (int x = 0; x < numOfLFs; x++) {
try {
if (itemLFs[x].visible) {
itemLFs[x].uCallHideNotify();
}
} catch (Throwable t) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_HIGHUI,
"Throwable while hideNotify");
}
}
}
| 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);
}
// Whether the item performs an internal traversal or not,
// it has the current input focus
item.hasFocus = true;
setVisRect(item, visRect);
// Call traverse() outside LCDUILock
if (item.uCallTraverse(dir,
viewport[WIDTH], viewport[HEIGHT], visRect)) {
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 (keyCode == Constants.KEYCODE_UP
|| keyCode == Constants.KEYCODE_DOWN
|| keyCode == Constants.KEYCODE_LEFT
|| keyCode == Constants.KEYCODE_RIGHT)
{
int dir = KeyConverter.getGameAction(keyCode);
// If 2D traversal is not enabled, we "direction-bend"
// and traverse in a typewriter-like fashion, line-by-line
// from left to right
if (!Constants.TRAVERSAL2D) {
if (dir == Canvas.DOWN) {
dir = Canvas.RIGHT;
} else if (dir == Canvas.UP) {
dir = Canvas.LEFT;
}
}
uTraverse(dir);
return;
} else {
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
if (numOfLFs == 0 || traverseIndex < 0) {
return;
}
v = itemLFs[traverseIndex];
} // synchronized
// SYNC NOTE: uCallKeyPressed may result in a call to the
// application, so we make sure we do this outside of the
// LCDUILock
if (v != null) {
// pass the keypress onto the current item
v.uCallKeyPressed(keyCode);
}
}
| void | uCallKeyReleased(int keyCode)Handle a key release event
if (keyCode == Constants.KEYCODE_UP
|| keyCode == Constants.KEYCODE_DOWN
|| keyCode == Constants.KEYCODE_LEFT
|| keyCode == Constants.KEYCODE_RIGHT)
{
return;
} else {
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
if (numOfLFs == 0 || traverseIndex < 0) {
return;
}
v = itemLFs[traverseIndex];
} // synchronized
// SYNC NOTE: uCallKeyPressed may result in a call to the
// application, so we make sure we do this outside of the
// LCDUILock
if (v != null) {
// pass the keypress onto the current item
v.uCallKeyReleased(keyCode);
}
}
| void | uCallKeyRepeated(int keyCode)Handle a key repeat
if (keyCode == Constants.KEYCODE_UP
|| keyCode == Constants.KEYCODE_DOWN
|| keyCode == Constants.KEYCODE_LEFT
|| keyCode == Constants.KEYCODE_RIGHT)
{
int dir = KeyConverter.getGameAction(keyCode);
// If 2D traversal is not enabled, we "direction-bend"
// and traverse in a typewriter-like fashion, line-by-line
// from left to right
if (!Constants.TRAVERSAL2D) {
if (dir == Canvas.DOWN) {
dir = Canvas.RIGHT;
} else if (dir == Canvas.UP) {
dir = Canvas.LEFT;
}
}
uTraverse(dir);
return;
} else {
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
if (numOfLFs == 0 || traverseIndex < 0) {
return;
}
v = itemLFs[traverseIndex];
} // synchronized
// SYNC NOTE: uCallKeyPressed may result in a call to the
// application, so we make sure we do this outside of the
// LCDUILock
if (v != null) {
// pass the keypress onto the current item
v.uCallKeyRepeated(keyCode);
}
}
| public void | uCallPaint(Graphics g, java.lang.Object target)Paint the contents of this Form
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] *-* FormLFImpl: dsPaint " +
target);
}
super.uCallPaint(g, target);
// IMPL_NOTE: Thread safety
// Cannot call paintItem inside this block
synchronized (Display.LCDUILock) {
// SYNC NOTE: We cannot hold any lock around a call into
// the application's paint() routine. Rather than copy
// the dataset and expend heap space, we simply protect
// this operation with try/catch. The only error condition
// would be if an insert/append/delete occurred in the middle
// of painting. This error condition would be quickly remedied
// by the pending validation of that change which causes a
// repaint automatically
try {
if (numOfLFs == 0) {
return;
}
int clip[] = new int[4];
clip[X] = g.getClipX();
clip[Y] = g.getClipY();
clip[WIDTH] = g.getClipWidth();
clip[HEIGHT] = g.getClipHeight();
// If the clip is an area above our viewport, just return
if (clip[Y] + clip[HEIGHT] <= 0) {
return;
}
if (!scrollInitialized) {
setVerticalScroll();
scrollInitialized = true;
}
if (target instanceof Item) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] FormLFImpl: dsPaint ONE Item " +
target);
}
if (((Item)target).owner == this.owner) {
((ItemLFImpl)((Item)target).getLF())
.paintItem(g, clip,
0 - viewable[X],
0 - viewable[Y]);
}
} else {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] FormLFImpl: dsPt. ALL Items ");
}
for (int i = 0; i < numOfLFs; i++) {
itemLFs[i].paintItem(g, clip,
0 - viewable[X],
0 - viewable[Y]);
}
}
} catch (Throwable t) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_HIGHUI,
"Throwable while paint item");
}
}
} // synchronized
| public void | uCallPeerStateChanged(int modelVersion, int itemPeerId, int hint)Called by Display to notify current FormLF of a change in its peer
state. For Java widgets, there is no peer for either Form or Items.
This implementation does nothing.
// No peer. Not expected to be called
| void | uCallPointerDragged(int x, int y)Handle a pointer dragged event
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
if (numOfLFs == 0 ||
traverseIndex < 0 || !pointerPressed) {
return;
}
v = itemLFs[traverseIndex];
x = (x + viewable[X]) - v.getInnerBounds(X);
y = (y + viewable[Y]) - v.getInnerBounds(Y);
}
// SYNC NOTE: this call may result in a call to the
// application, so we make sure we do this outside of the
// LCDUILock
v.uCallPointerDragged(x, y);
| void | uCallPointerPressed(int x, int y)Handle a pointer pressed event
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
if (numOfLFs == 0) {
return;
}
v = findItemByPointer(x, y);
pointerPressed = true;
}
// SYNC NOTE: this call may result in a call to the
// application, so we make sure we do this outside of the
// LCDUILock
if (v != null) {
x = (x + viewable[X]) - v.getInnerBounds(X);
y = (y + viewable[Y]) - v.getInnerBounds(Y);
v.uCallPointerPressed(x, y);
synchronized (Display.LCDUILock) {
lScrollToItem(v.item);
}
}
| void | uCallPointerReleased(int x, int y)Handle a pointer released event
ItemLFImpl v = null;
synchronized (Display.LCDUILock) {
if (numOfLFs == 0 ||
traverseIndex < 0 || !pointerPressed) {
return;
}
v = findItemByPointer(x, y);
pointerPressed = false;
}
// SYNC NOTE: this call may result in a call to the
// application, so we make sure we do this outside of the
// LCDUILock
if (v != null) {
x = (x + viewable[X]) - v.getInnerBounds(X);
y = (y + viewable[Y]) - v.getInnerBounds(Y);
v.uCallPointerReleased(x, y);
}
| public void | uCallScrollContent(int scrollType, int thumbPosition)Scroll content inside of the form.
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI,
"FormLF.uCallScrollContent scrollType=" + scrollType +
" thumbPosition=" + thumbPosition);
}
if (owner instanceof TextBox && itemLFs[0] instanceof TextBoxLFImpl) {
((TextBoxLFImpl)itemLFs[0]).uCallScrollContent(scrollType, thumbPosition);
} else {
super.uCallScrollContent(scrollType, thumbPosition);
}
| public void | uCallShow()notify this Form it is being shown on the given Display
super.uCallShow();
uShowContents(true);
synchronized (Display.LCDUILock) {
scrollInitialized = false;
if (pendingCurrentItem != null) {
lScrollToItem(pendingCurrentItem);
pendingCurrentItem = null;
}
}
| void | uEnsureRequestedSizes()Ensure CustomItems have their requested size cached.
int i, count = 0;
synchronized (Display.LCDUILock) {
// Make a temporary copy of ItemLFs we need to collect sizes from
ensureDispatchItemArray(numOfLFs);
// Make sure each Item has native resource
// and remember all the CustomItemLFImpls
for (i = 0; i < numOfLFs; i++) {
if (itemLFs[i] instanceof CustomItemLFImpl) {
// Remember this in temporary array
dispatchItemLFs[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)dispatchItemLFs[i]).uCallSizeRefresh();
}
// Dereference ItemLFImpl objects in dispatchItemLFs
resetDispatchItemArray(true);
| void | uHideShowItems(ItemLFImpl[] items)Loop through the set of items, making sure they have been
properly notified of their visibility via their show/hideNotify
methods.
// If an item is at least partially visible, it must have
// its showNotify() called (if not already done). If an
// item is completely offscreen, it must have its hideNotify()
// called (if not already done).
for (int i = 0; i < items.length; i++) {
if (items[i].visible != itemPartiallyVisible(items[i])) {
try {
if (items[i].visible) {
items[i].uCallHideNotify();
} else {
items[i].uCallShowNotify();
}
} catch (Throwable t) {
if (Logging.REPORT_LEVEL <= Logging.WARNING) {
Logging.report(Logging.WARNING, LogChannels.LC_HIGHUI,
"Throwable while hideNotify or showNotify");
}
}
}
}
| 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) {
setupScroll();
return;
}
uHideShowItems(itemsCopy);
// The result of an invalidate() call
if (traverseIndexCopy != -1 && dir == CustomItem.NONE) {
itemTraverse =
uCallItemTraverse(itemsCopy[traverseIndexCopy], dir);
uRequestPaint(); // request to paint contents area
synchronized (Display.LCDUILock) {
lScrollToItem(itemsCopy[traverseIndexCopy].item);
}
setupScroll();
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 (traverseIndexCopy > -1 && traverseIndexCopy < itemsCopy.length) {
// 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);
}
if (!itemTraverse) {
// 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 && nextIndex != 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
setupScroll();
| 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;
}
lScrollToItem(i);
}
| protected void | uScrollAt(int position)Perform a scrolling at the given position.
ItemLFImpl[] items = null;
synchronized (Display.LCDUILock) {
items = new ItemLFImpl[numOfLFs];
System.arraycopy(itemLFs, 0, items, 0, numOfLFs);
}
int oldY = viewable[Y];
super.uScrollAt(position);
if (oldY != viewable[Y]) {
uInitItemsInViewport(viewable[Y] > oldY ? Canvas.DOWN : Canvas.UP,
items, traverseIndex);
updateCommandSet();
}
| protected void | uScrollByLine(int dir)Perform a line scrolling in the given direction. This method will
attempt to scroll the view to show next/previous line.
ItemLFImpl[] items = null;
synchronized (Display.LCDUILock) {
items = new ItemLFImpl[numOfLFs];
System.arraycopy(itemLFs, 0, items, 0, numOfLFs);
}
int oldY = viewable[Y];
super.uScrollByLine(dir);
if (oldY != viewable[Y]) {
uInitItemsInViewport(dir, items, traverseIndex);
updateCommandSet();
}
| 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.
if (dir == Canvas.UP) {
int newY = viewable[Y] - (viewport[HEIGHT] - 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].visible) {
firstVis = i;
}
}
// case 1. We're at the top of the item so just
// traverse normally
if (items[firstVis].bounds[Y] >= viewable[Y]) {
viewable[Y] = newY;
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]) -
viewport[HEIGHT];
if (fitY > newY && viewable[Y] > fitY) {
newY = fitY;
}
viewable[Y] = newY;
return;
} else if (dir == Canvas.DOWN) {
int newY = viewable[Y] + (viewport[HEIGHT] - PIXELS_LEFT_ON_PAGE);
if (newY > viewable[HEIGHT] - viewport[HEIGHT]) {
newY = viewable[HEIGHT] - viewport[HEIGHT];
}
// 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].visible) {
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] <=
viewable[Y] + viewport[HEIGHT])
{
viewable[Y] = newY;
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] &&
viewable[Y] < items[lastVis].bounds[Y])
{
newY = items[lastVis].bounds[Y];
}
viewable[Y] = newY;
return;
}
| protected void | uScrollViewport(int dir)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.
ItemLFImpl[] items = null;
synchronized (Display.LCDUILock) {
items = new ItemLFImpl[numOfLFs];
System.arraycopy(itemLFs, 0, items, 0, numOfLFs);
}
int oldY = viewable[Y];
uScrollViewport(dir, items);
if (oldY != viewable[Y]) {
uInitItemsInViewport(dir, items, traverseIndex);
updateCommandSet();
}
| public boolean | uSetRotatedStatus(boolean newStatus)Set status of screen rotation
boolean status = super.uSetRotatedStatus(newStatus);
if (status) {
firstShown = true;
}
return status;
| 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: uShowContents()");
}
synchronized (Display.LCDUILock) {
if (firstShown) {
for (int i = 0; i < numOfLFs; i++) {
itemLFs[i].cachedWidth = ItemLFImpl.INVALID_SIZE;
}
}
}
// Collect CustomItem sizes outside LCDUILock
uEnsureRequestedSizes();
ItemLFImpl[] itemsCopy = null;
int itemsCopyCount = 0;
int traverseIndexCopy = -1;
synchronized (Display.LCDUILock) {
if (firstShown) {
super.layout(); // moved from LayoutManager
LayoutManager.instance().lLayout(LayoutManager.FULL_LAYOUT,
itemLFs, numOfLFs,
viewport[WIDTH],
viewport[HEIGHT],
viewable);
firstShown = false;
} else {
LayoutManager.instance().lLayout(LayoutManager.UPDATE_LAYOUT,
itemLFs, numOfLFs,
viewport[WIDTH],
viewport[HEIGHT],
viewable);
}
if (resetToTop) {
traverseIndex = -1;
viewable[Y] = 0;
viewable[X] = 0;
} else {
// correct scroll position if any
if (viewable[HEIGHT] <= viewport[HEIGHT] ||
viewable[Y] < 0) {
// if viewable height is less than viewport
// height just reset viewable y
// if viewable y is less than 0 set it to 0
viewable[Y] = 0;
} else if (viewable[Y] > (viewable[HEIGHT] - viewport[HEIGHT])) {
// if viewable y exceeds the max value set it to the max
// height just reset viewable y
viewable[Y] = viewable[HEIGHT] - viewport[HEIGHT];
}
}
itemsCopy = new ItemLFImpl[numOfLFs];
itemsCopyCount = numOfLFs;
System.arraycopy(itemLFs, 0, itemsCopy, 0, numOfLFs);
traverseIndexCopy = traverseIndex;
itemsModified = false;
} // synchronized
// We issue a default traverse to setup focus
//
// SYNC NOTE: Since this may call into CustomItem.traverse/traverseOut,
// call it outside LCDUILock
uInitItemsInViewport(CustomItem.NONE, itemsCopy, traverseIndexCopy);
if (initialTraverse) {
updateCommandSet();
}
for (int index = 0; index < itemsCopyCount; index++) {
if (itemsCopy[index].sizeChanged) {
itemsCopy[index].uCallSizeChanged(itemsCopy[index].getInnerBounds(WIDTH),
itemsCopy[index].getInnerBounds(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)) {
uHideShowItems(itemsCopy);
uRequestPaint(); // request to paint contents area
setupScroll();
}
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();
itemsCopy[traverseIndexCopy].uRequestPaint();
}
/*
* 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)) {
uHideShowItems(itemsCopy);
uRequestPaint(); // request to paint contents area
} else {
itemsCopy[traverseIndexCopy].uRequestPaint();
}
}
// 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 (viewable[Y] + viewport[HEIGHT] !=
itemsCopy[traverseIndexCopy].bounds[Y] +
itemsCopy[traverseIndexCopy].bounds[HEIGHT])
{
viewable[Y] = viewable[HEIGHT] -
viewport[HEIGHT];
// 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 (viewable[Y] > itemsCopy[traverseIndexCopy].bounds[Y]) {
viewable[Y] = itemsCopy[traverseIndexCopy].bounds[Y];
}
uHideShowItems(itemsCopy);
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 (viewable[Y] != itemsCopy[traverseIndexCopy].bounds[Y]) {
viewable[Y] = 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] >
viewport[HEIGHT])
{
viewable[Y] =
itemsCopy[traverseIndexCopy].bounds[HEIGHT] -
viewport[HEIGHT];
}
uHideShowItems(itemsCopy);
uRequestPaint();
}
}
setupScroll();
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
if ((dir == Canvas.LEFT || dir == Canvas.UP) && viewable[Y] > 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 &&
(viewable[Y] > itemsCopy[traverseIndexCopy].bounds[Y]))
{
viewable[Y] -= (viewport[HEIGHT] - PIXELS_LEFT_ON_PAGE);
if (viewable[Y] < 0) {
viewable[Y] = 0;
}
uHideShowItems(itemsCopy);
setupScroll();
uRequestPaint();
} else {
// page up
uScrollViewport(Canvas.UP, itemsCopy);
uInitItemsInViewport(
Canvas.UP, itemsCopy, traverseIndexCopy);
updateCommandSet();
return;
}
} else if ((dir == Canvas.RIGHT || dir == Canvas.DOWN) &&
(viewable[Y] + viewport[HEIGHT] < 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]) >
(viewable[Y] + viewport[HEIGHT])))
{
viewable[Y] += (viewport[HEIGHT] - PIXELS_LEFT_ON_PAGE);
if (viewable[Y] > (viewable[HEIGHT] - viewport[HEIGHT]))
{
viewable[Y] = viewable[HEIGHT] - viewport[HEIGHT];
}
uHideShowItems(itemsCopy);
setupScroll();
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();
}
| public void | updateCommandSet()Updates command set if this Displayable is visible
SYNC NOTE: Caller should hold LCDUILock.
if (state == SHOWN) {
currentDisplay.updateCommandSet();
}
|
|