LayoutManagerpublic class LayoutManager extends Object Layout management class for Form .
See DisplayableLF.java for naming convention. |
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. | private int[] | sizingBox'sizingBox' is a [x,y,w,h] array used for dynamic sizing of
Item s during the layout. It starts with the size of the
viewport, but can shrink or grow according to the Item
it tries to lay out.
It is used by layoutBlock and layoutRow. | static final int | FULL_LAYOUTDo a full layout. | static final int | UPDATE_LAYOUTOnly update layout. | static LayoutManager | singleInstanceSingle instance of the LayoutManager class. | static final int | XUsed as an index into the viewport[], for the x origin. | static final int | YUsed as an index into the viewport[], for the y origin. | static final int | WIDTHUsed as an index into the viewport[], for the width. | static final int | HEIGHTUsed as an index into the viewport[], for the height. | int | viewportWidthWidth of viewport, as passed to layout(). | int | viewportHeightHeight of viewport, as passed to layout(). |
Constructors Summary |
---|
LayoutManager()Singleton design pattern. Obtain access using instance() method.
sizingBox = new int[3]; // x,y,width
|
Methods Summary |
---|
private int | getCurHorAlignment(ItemLFImpl[] itemLFs, int index)Gets the current horizontal alignment of the item. If Item's
horizontal layout bits are not set its current horizontal
alignment is the same as of the previous Item.
for (int hAlign, i = index; i >= 0; i--) {
hAlign = itemLFs[i].getLayout() & LAYOUT_HMASK;
if (hAlign == 0) {
continue;
}
return hAlign;
}
// default layout is LAYOUT_LEFT
return Item.LAYOUT_LEFT;
| private int | getItemHeight(int index, int pW, ItemLFImpl[] itemLFs)Get item's height based on the width.
// SYNC NOTE: protected by the lock around calls to layout()
int pH;
// If the Item can be shrunken, we use its minimum height,
// and its preferred height if it is not
if (itemLFs[index].shouldVShrink()) {
pH = itemLFs[index].lGetAdornedMinimumHeight();
} else {
pH = itemLFs[index].lGetLockedHeight();
if (pH == -1) {
pH = itemLFs[index].lGetAdornedPreferredHeight(pW);
}
}
// If we can't scroll vertically, clip the item's height
// if it can't fit in the view. We would also enforce a
// notion of a "maximum vertical height" here if we had one
if (!Constants.SCROLLS_VERTICAL &&
pH > viewportHeight) {
pH = viewportHeight;
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" LayoutManager- getItemHeight("+index+","+pW+
") returns "+pH);
}
return pH;
| private int | inflateHExpandables(int rowStart, int rowEnd, int space, ItemLFImpl[] itemLFs)Inflate all the horizontally 'expandable' items on a row.
// SYNC NOTE: protected by the lock around calls to layout()
if (space == 0) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] inflateHExpandables -- " +
"returning (space == 0)");
}
return 0;
}
int numExp = 0;
// We first loop through and count the expandables
for (int i = rowStart; i <= rowEnd; i++) {
if (itemLFs[i].shouldHExpand()) {
numExp++;
}
}
if (numExp == 0 || space < numExp) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] inflateHExpandables -- returning " +
"(numExp == 0 || space < numExp) space = " +
space);
}
return space;
}
space = space / numExp;
// We then add the same amount to each Expandable
for (int i = rowStart; i <= rowEnd; i++) {
if (itemLFs[i].shouldHExpand()) {
itemLFs[i].lSetSize(itemLFs[i].bounds[WIDTH] + space,
getItemHeight(i,
itemLFs[i].bounds[WIDTH] +
space,
itemLFs));
// We right shift each subsequent item on the row
for (int j = i + 1; j <= rowEnd; j++) {
itemLFs[j].lMove(space, 0);
}
}
}
space = viewportWidth -
(itemLFs[rowEnd].bounds[X] + itemLFs[rowEnd].bounds[WIDTH]);
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] inflateHExpandables -- " +
"returning (end) space = " + space);
}
return space;
| private int | inflateHShrinkables(int rowStart, int rowEnd, int space, ItemLFImpl[] itemLFs)Inflate all the horizontally 'shrinkable' items on a row.
// SYNC NOTE: protected by the lock around calls to layout()
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] inflateHShrinkables -- rowStart=" +
rowStart + " rowEnd=" + rowEnd +
" space=" + space);
}
if (space == 0) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] inflateHShrinkables -- returning " +
"(space == 0)");
}
return 0;
}
// To inflate shrinkables, we make a first pass gathering
// the smallest proportion (the baseline)
int baseline = Integer.MAX_VALUE;
int pW, prop = 0;
for (int i = rowStart; i <= rowEnd; i++) {
if (itemLFs[i].shouldHShrink()) {
pW = itemLFs[i].lGetLockedWidth();
if (pW == -1) {
pW = itemLFs[i].lGetAdornedPreferredWidth(
itemLFs[i].lGetLockedHeight());
}
prop = pW - itemLFs[i].lGetAdornedMinimumWidth();
if (prop > 0 && prop < baseline) {
baseline = prop;
}
}
}
// If there are no shrinkables, return
if (baseline == Integer.MAX_VALUE) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] inflateHShrinkables -- returning " +
"(baseline == Integer.MAX_VALUE) space == " +
space);
}
return space;
}
prop = 0;
// Now we loop again, adding up all the proportions so
// we can find the adder
for (int i = rowStart; i <= rowEnd; i++) {
if (itemLFs[i].shouldHShrink()) {
pW = itemLFs[i].lGetLockedWidth();
if (pW == -1) {
pW = itemLFs[i].lGetAdornedPreferredWidth(
itemLFs[i].lGetLockedHeight());
}
prop += ((pW - itemLFs[i].lGetAdornedMinimumWidth()) /
baseline);
}
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] inflateHShrinkables -- prop == "+prop);
}
// Now we compute the adder, and add it to each of the
// shrinkables, times its proportion
int adder = space / prop;
for (int i = rowStart; i <= rowEnd; i++) {
if (itemLFs[i].shouldHShrink()) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"### item "+i+" before shrinking is:" +
itemLFs[i].bounds[WIDTH]);
}
pW = itemLFs[i].lGetLockedWidth();
if (pW == -1) {
pW = itemLFs[i].lGetAdornedPreferredWidth(
itemLFs[i].lGetLockedHeight());
}
space = pW - itemLFs[i].lGetAdornedMinimumWidth();
// The proportionate amount of space to add
prop = adder * (space / baseline);
// We only enlarge the item to its preferred width at
// a maximum
if (space > prop) {
space = prop;
}
itemLFs[i].lSetSize(itemLFs[i].bounds[WIDTH] + space,
getItemHeight(i,
itemLFs[i].bounds[WIDTH] +
space,
itemLFs));
// Now we have to shift the rest of the elements on the line
for (int j = i + 1; j <= rowEnd; j++) {
itemLFs[j].lMove(space, 0);
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"### item " + i + " shrank to:" +
itemLFs[i].bounds[WIDTH]);
}
}
}
space = viewportWidth -
(itemLFs[rowEnd].bounds[X] + itemLFs[rowEnd].bounds[WIDTH]);
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] inflateHShrinkables -- " +
"returning (end). space == " + space);
}
return space;
| static javax.microedition.lcdui.LayoutManager | instance()Singleton design pattern: obtain access to the single instance of
this class using this method.
return singleInstance;
| private boolean | isImplicitLineBreak(int curAlignment, int thisItem, ItemLFImpl[] itemLFs)This method checks if we need a new line due to change in
horizontal alignment. If horizontal alignment is not set on
Item with index thisItem then current horizontal
alignment is not changed and no row break is needed.
if (thisItem == 0) {
return false;
}
int hAlign = itemLFs[thisItem].getLayout() & LAYOUT_HMASK;
// alignment is not changed
if (hAlign == 0) {
return false;
}
return (hAlign != curAlignment);
| void | lLayout(int layoutMode, ItemLFImpl[] itemLFs, int numOfLFs, int inp_viewportWidth, int inp_viewportHeight, int[] viewable)Do layout.
SYNC NOTE: caller must hold LCDUILock around a call to this method
viewportWidth = inp_viewportWidth;
viewportHeight = inp_viewportHeight;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"\n<<<<<<<<<< Doing " +
(layoutMode == FULL_LAYOUT ?
"FULL_LAYOUT" :
"UPDATE_LAYOUT") +
"... >>>>>>>>>>");
}
if (layoutMode == FULL_LAYOUT) {
// first Layout
updateBlock(0, 0, true, itemLFs, numOfLFs, viewable);
} else {
// UPDATE_LAYOUT
// most of the time only one or two items are updated at a time.
// here we find the minimum items that needs a re-layout, and
// calling layout for them
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"UPDATE_LAYOUT - START");
}
// loop on all the items, and find which item needs an update
// If more than one Item needs update, they both will update,
// in their layout order.
// * we keep a "moving anchor" to use when we identify
// an invalid Item. This anchor is always at the beginning
// of the row above the current Item checked, or at the
// beginning of the row of the current Item, in case there
// was an explicit line break.
int anchorIndex = 0;
// this index is needed to identify new lines to be set as
// anchors later.
int newLineIndex = 0;
// find where to start the layout. It should be at the beginning
// of the line above the invalid item, or of the same line
// in case the line break is explicit.
// We loop on all the Items to find the first invalid, while
// keeping the anchorIndex up do date. When calling "updateBlock",
// the index will jump directly to the next block, because we laid
// out all the Items in that block.
for (int index = 0; index < numOfLFs; index++) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"\n["+itemLFs[index]+"]" +
"BEFORE: index: " +index +
"\t[" + itemLFs[index].bounds[X] +
"," + itemLFs[index].bounds[Y] +
"," + itemLFs[index].bounds[WIDTH] +
"," + itemLFs[index].bounds[HEIGHT] +
"]\t newLine?" + itemLFs[index].isNewLine +
" lineHeight=" + itemLFs[index].rowHeight +
"\t actualBoundsInvalid[" +
itemLFs[index].actualBoundsInvalid[X] + ","
+ itemLFs[index].actualBoundsInvalid[Y] +
"," +
itemLFs[index].actualBoundsInvalid[WIDTH] +
"," +
itemLFs[index].actualBoundsInvalid[HEIGHT] +
"]\t ** viewable: " + index +
"\t[" + viewportWidth + "," +
viewable[HEIGHT] +"]");
}
if (itemLFs[index].actualBoundsInvalid[WIDTH] ||
itemLFs[index].actualBoundsInvalid[X]) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"> WIDTH or X is invalid!");
}
// if width is changed, than we have to do a layout two
// a block of Items. So it covers the height as well call
// layout block. The index will jump to the first item on
// the next block.
// return the last item on the block:
index = updateBlock(anchorIndex, index, false,
itemLFs, numOfLFs, viewable);
// set the anchor on the next item, if there is one.
// if (i+1) is larger than the length of itemLFs, the for
// loop will end anyway so we don't have to check it here.
anchorIndex = index + 1;
} else if (itemLFs[index].actualBoundsInvalid[HEIGHT]) {
// item current height
int h = itemLFs[index].bounds[HEIGHT];
// item preferred height
int ph = itemLFs[index].lGetAdornedPreferredHeight(
itemLFs[index].bounds[WIDTH]);
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"> HEIGHT is invalid from:" + h +
" to:" + ph);
}
if (h != ph) {
itemLFs[index].lSetSize(itemLFs[index].bounds[WIDTH],
ph);
itemLFs[index].rowHeight += (ph-h);
// NOTE: We should check whole row height,
// instead of just this item.
itemLFs[index].actualBoundsInvalid[HEIGHT] = false;
if (numOfLFs > index+1) {
itemLFs[index+1].actualBoundsInvalid[Y] = true;
// NOTE: We should calculate new LineHeight,
// instead of just Item Height
updateVertically(index+1,
itemLFs,
numOfLFs,
viewable);
} else {
// only need to update the viewable
viewable[HEIGHT] += (ph - h);
}
}
} else if (itemLFs[index].actualBoundsInvalid[Y]) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"> *only* Y is invalid for #" +
index);
}
updateVertically(index, itemLFs, numOfLFs, viewable);
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"> Y - done");
}
} else {
// current item is valid.
// check if i can be a new anchor point
// (has an explicit line break before it,
// or after the previous Item).
if (itemLFs[index].isNewLine) {
if (itemLFs[index].equateNLB() ||
((index > 0) && (itemLFs[index-1].equateNLA()))) {
// explicit newline
anchorIndex = index;
newLineIndex = index;
} else {
// implicit newline
// we can move the anchor to the next line:
// set the anchorIndex to be the old newLineIndex
// (which is the first item on the row above the
// current item).
anchorIndex = newLineIndex;
// set i as the first in its line
newLineIndex = index;
}
}
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"AFTER: index: " + index +
"\t[" + itemLFs[index].bounds[X] +
"," + itemLFs[index].bounds[Y] +
"," + itemLFs[index].bounds[WIDTH] +
"," + itemLFs[index].bounds[HEIGHT] +
"]\t newLine?" + itemLFs[index].isNewLine +
" lineHeight=" +
itemLFs[index].rowHeight +
"\t actualBoundsInvalid[" +
itemLFs[index].actualBoundsInvalid[X] +
"," +
itemLFs[index].actualBoundsInvalid[Y] +
"," +
itemLFs[index].actualBoundsInvalid[WIDTH] +
"," +
itemLFs[index].actualBoundsInvalid[HEIGHT] +
"]\t ** viewable: " +index +
"\t[" + viewportWidth + "," +
viewable[HEIGHT] + "]");
}
} // for loop
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"UPDATE_LAYOUT - DONE");
}
}
// correct viewable area if required
// if there are no items in the form just reset viewable[HEIGHT]
if (numOfLFs == 0) {
viewable[HEIGHT] = 0;
}
| private int | layoutRowHorizontal(int rowStart, int rowEnd, int hSpace, int rowHeight, ItemLFImpl[] itemLFs)After the contents of a row have been determined, layout the
items on that row, taking into account the individual items'
horizontally oriented layout directives.
// SYNC NOTE: protected by the lock around calls to layout()
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] layoutRowHorizontal -- rowStart=" + rowStart
+ " rowEnd="+rowEnd + " hSpace=" + hSpace +
" rowHeight="+rowHeight);
}
hSpace = inflateHShrinkables(rowStart, rowEnd, hSpace, itemLFs);
hSpace = inflateHExpandables(rowStart, rowEnd, hSpace, itemLFs);
// if any of the items were inflated we have to recalculate
// the new row height for this row
rowHeight = 0;
for (int i = rowStart; i <= rowEnd; i++) {
if (rowHeight < itemLFs[i].bounds[HEIGHT]) {
rowHeight = itemLFs[i].bounds[HEIGHT];
}
}
if (hSpace == 0) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] layoutRowHorizontal -- done -- " +
"(hSpace == 0) -- returning "+rowHeight);
}
return rowHeight;
}
int curAlignment = getCurHorAlignment(itemLFs, rowStart);
switch (curAlignment) {
case Item.LAYOUT_CENTER:
hSpace = hSpace / 2;
/* fall through */
case Item.LAYOUT_RIGHT:
for (; rowStart <= rowEnd; rowStart++) {
itemLFs[rowEnd].lMove(hSpace, 0);
}
break;
case Item.LAYOUT_LEFT:
default:
break;
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] layoutRowHorizontal -- done " +
"-- returning "+rowHeight);
}
return rowHeight;
| private void | layoutRowVertical(int rowStart, int rowEnd, int lineHeight, ItemLFImpl[] itemLFs, int numOfLFs)After the contents of a row have been determined, layout the
items on that row, taking into account the individual items'
vertically oriented layout directives.
// SYNC NOTE: protected by the lock around calls to layout()
int space = 0;
int pH = 0;
for (int i = rowStart; i <= rowEnd; i++) {
// set the row height
itemLFs[i].rowHeight = lineHeight;
// Items that have the LAYOUT_VSHRINK directive are expanded
// to their preferred height or to the height of the row,
// whichever is smaller. Items that are still shorter than
// the row height and that have the LAYOUT_VEXPAND directive
// will expand to the height of the row.
if (itemLFs[i].shouldVExpand()) {
itemLFs[i].lSetSize(itemLFs[i].bounds[WIDTH], lineHeight);
} else if (itemLFs[i].shouldVShrink()) {
pH = itemLFs[i].lGetLockedHeight();
if (pH == -1) {
pH = itemLFs[i].
lGetAdornedPreferredHeight(itemLFs[i].bounds[WIDTH]);
}
if (pH > lineHeight) {
pH = lineHeight;
}
itemLFs[i].lSetSize(itemLFs[i].bounds[WIDTH], pH);
}
// initially the items are aligned at the top so we simply
// add on to the height
switch (itemLFs[i].getLayout() & LAYOUT_VMASK) {
case Item.LAYOUT_VCENTER:
space = lineHeight - itemLFs[i].bounds[HEIGHT];
if (space > 0) {
itemLFs[i].lMove(0, space / 2);
}
break;
case Item.LAYOUT_TOP:
// it's already there...
break;
case Item.LAYOUT_BOTTOM:
// the layout algorithm must align the Items along the bottom
// if there is no vertical directive specified.
default:
space = lineHeight - itemLFs[i].bounds[HEIGHT];
if (space > 0) {
itemLFs[i].lMove(0, space);
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"Default V layout -- space = " +
space +
" itemLFs[i].Y = " +
itemLFs[i].bounds[Y]);
}
}
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] layoutRowVertical -- done");
}
| private int | updateBlock(int startIndex, int invalidIndex, boolean fullLayout, ItemLFImpl[] itemLFs, int numOfLFs, int[] viewable)Used both to do a full layout or just update a layout.
assumptions: startIndex<=invalidIndex
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"\n - updateBlock(START="+startIndex
+", INVALID="+invalidIndex
+", Full Layout="+fullLayout+") {");
}
// SYNC NOTE: layout() is always called from within a hold
// on LCDUILock
int oldWidth = viewable[WIDTH];
int oldHeight = viewable[HEIGHT];
// If we don't have any Items, just return
if (numOfLFs == 0) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" we don't have any Items, just return }");
}
return 0;
}
int rowStart;
if (fullLayout) {
// The index of the first Item in the horizontal row
rowStart = 0;
} else {
rowStart = startIndex;
}
// The sizingBox starts out life with the size of the viewport,
// but gets whittled down as each Item gets laid out and occupies
// space in it. It effectively keeps a running total of what space
// is available due to the Items which have already been laid out
// We only allow space for the traversal indicator if we
// have more than one item - because we only draw the traversal
// indicator if we have more than one item to traverse to.
// LF's width is set to the maximum allowable width,
// while view's height is initialized with initial padding and
// and grows when new row is added.
sizingBox[X] = 0;
sizingBox[Y] = 0;
sizingBox[WIDTH] = viewportWidth;
viewable[WIDTH] = viewportWidth;
if (fullLayout) {
viewable[HEIGHT] = 0;
} else if (numOfLFs > 1 && startIndex > 0) {
sizingBox[Y] = itemLFs[startIndex-1].bounds[Y]
+ itemLFs[startIndex-1].rowHeight;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"sizingBox[Y]=" + sizingBox[Y]);
}
}
// A running variable which maintains the height of the
// tallest item on a line
int lineHeight = 0;
int pW, pH;
int curAlignment = Item.LAYOUT_LEFT;
// We loop through the Items starting in startIndex, until we reach
// the end of the block, and return the index of the next block,
// or just finishing the for loop if this is the last block.
for (int index = startIndex; index < numOfLFs; index++) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"..\n\tFOR LOOP: startIndex=" + startIndex +
" index=[" + index +
"] invalidIndex=" + invalidIndex);
}
// If the Item can be shrunken, get its minimum width,
// and its preferred if it is not
if (itemLFs[index].shouldHShrink()) {
pW = itemLFs[index].lGetAdornedMinimumWidth();
} else {
if (itemLFs[index].lGetLockedWidth() != -1) {
pW = itemLFs[index].lGetLockedWidth();
} else {
// if height is locked default preferred width
// will be used, otherwise width will be calculated
// based on lockedHeight
pW = itemLFs[index].lGetAdornedPreferredWidth(
itemLFs[index].lGetLockedHeight());
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" no shrink - locked w - pW=" + pW +
" viewable[width]=" + viewable[WIDTH]);
}
}
}
// We have a notion of the maximum allowable width an Item can
// have, so we enforce it first here:
if (!Constants.SCROLLS_HORIZONTAL && (pW > viewable[WIDTH])) {
pW = viewable[WIDTH];
}
// We use a separate boolean here to check for each case of
// requiring a new line (rather than the if() from hell)
boolean newLine = (index > 0 && itemLFs[index - 1].equateNLA() ||
itemLFs[index].equateNLB() ||
// no room for this item on the same row
pW > sizingBox[WIDTH]);
if (isImplicitLineBreak(curAlignment, index, itemLFs)) {
curAlignment = itemLFs[index].getLayout() & LAYOUT_HMASK;
newLine = true;
}
// We linebreak if there is an existing row;
// possible only when there is more than 1 item
if (newLine && (lineHeight > 0)) {
// index > 0, as the calculation of newLine guarantee
//
// ** NEW LINE **
//
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" --new line--");
}
// First, handle current row's layout directives
try {
// used for layout update
// int oldRowHeight = itemLFs[index-1].rowHeight;
boolean wasNewLine = itemLFs[index].isNewLine;
// now it's certainly first in line
itemLFs[index].isNewLine = true;
// layout items in previous row
lineHeight = layoutRowHorizontal(rowStart, index - 1,
sizingBox[WIDTH],
lineHeight,
itemLFs);
layoutRowVertical(rowStart, index - 1, lineHeight,
itemLFs, numOfLFs);
if (fullLayout) {
if (numOfLFs > 1) {
viewable[HEIGHT] += lineHeight;
} else {
viewable[HEIGHT] += lineHeight + 1;
}
} else { // UPDATE_LAYOUT
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"** 1 ** row height=" +
lineHeight);
}
// cases:
// 1. this item was first in row already
// > than update layout wouldn't be called for the
// > row above it unless there was a change in that
// > row.
// > Therefore we can finish the loop, and just update
// > the Y coordinates for the rest of the Items.
if (wasNewLine && index > invalidIndex) {
// we can call updateVertically by returning
// index-1 and marking next Y as invalid.
itemLFs[index].actualBoundsInvalid[Y] = true;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(
Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" returning index-1 and "+
"marking next Y as invalid. }");
}
return (index-1);
// (some Items after it may still be invalid,
// so the calling method will continue the layout).
}
// 2. this item wasn't first on its row
// > then we should continue a regular layout.
if (!wasNewLine) {
itemLFs[index].actualBoundsInvalid[X] = true;
}
}
} catch (Throwable t) {
Display.handleThrowable(t);
}
// Then, reset the sizingBox, lineHeight, and rowStart
sizingBox[X] = 0;
if (fullLayout) {
sizingBox[Y] = viewable[HEIGHT];
} else {
sizingBox[Y] = itemLFs[index-1].bounds[Y] +
itemLFs[index-1].rowHeight;
if (numOfLFs <= 1) {
sizingBox[Y] += 1;
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"** 2 ** sizingBox[Y]=" +
sizingBox[Y]);
}
}
sizingBox[WIDTH] = viewportWidth;
lineHeight = 0;
rowStart = index;
itemLFs[index].isNewLine = true;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" (new line end)");
}
//
// ** NEW LINE - END **
//
} else {
// keep isNewLine flag up to date
if (index == 0 || newLine) {
itemLFs[index].isNewLine = true;
} else {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"** " +index +" is not a new line **");
}
// this is not a new line
itemLFs[index].isNewLine = false;
}
}
pH = getItemHeight(index, pW, itemLFs);
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" updateBlock.. pH = " +pH);
}
// If the Item is changing size, set the flag so that callPaint()
// will call the Item's sizeChanged() method before painting
if (oldWidth != viewportWidth || oldHeight != viewportHeight ||
itemLFs[index].bounds[WIDTH] != pW || itemLFs[index].bounds[HEIGHT] != pH) {
itemLFs[index].sizeChanged = true;
}
if (!fullLayout && (index > invalidIndex)) {
// if we've reached the end of the block (explicit linebreak)
// than we can safely return
if (itemLFs[index].equateNLB() ||
((index > 0) && (itemLFs[index-1].equateNLA()))) {
// we can stop the loop, returning the last Item laid out
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"** stop layout, explicit lb **\n}");
}
itemLFs[index].actualBoundsInvalid[Y] = true;
return (index - 1);
// identify more occasions where only Y will change
} else if (itemLFs[index].bounds[X] == sizingBox[X] &&
// itemLFs[index].bounds[Y] == sizingBox[Y] &&
itemLFs[index].bounds[WIDTH] == pW &&
itemLFs[index].bounds[HEIGHT] == pH) {
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"\n** no need to layout **\n}");
}
itemLFs[index].actualBoundsInvalid[X] = false;
// notice the "true": (only the Y coordinate is invalid)
itemLFs[index].actualBoundsInvalid[Y] = true;
itemLFs[index].actualBoundsInvalid[WIDTH] = false;
itemLFs[index].actualBoundsInvalid[HEIGHT] = false;
return (index - 1);
}
}
// We assign bounds to the item, which is its pixel location,
// width, and height in coordinates which represent offsets
// of the viewport origin (that is, are in the viewport
// coordinate space)
itemLFs[index].lSetSize(pW, pH);
itemLFs[index].lSetLocation(sizingBox[X], sizingBox[Y]);
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"[F] index ("+ index +
" lineHeight == "+ lineHeight +
") set height to:" + pH);
}
itemLFs[index].actualBoundsInvalid[X] = false;
itemLFs[index].actualBoundsInvalid[Y] = false;
itemLFs[index].actualBoundsInvalid[WIDTH] = false;
itemLFs[index].actualBoundsInvalid[HEIGHT] = false;
// If this Item is currently the tallest on the line, its
// height becomes our prevailing lineheight
if (pH > lineHeight) {
lineHeight = pH;
}
// We whittle down the sizingBox by the Item's dimensions,
// effectively maintaining how much space is left for the
// remaining Items, if the item has some positive width
if (pW > 0) {
sizingBox[WIDTH] -= pW;
// we know that item fits on this row but padding
// might not fit
if (sizingBox[WIDTH] < 0) {
sizingBox[WIDTH] = 0;
}
sizingBox[X] += pW;
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"\t\tindex: " +index +
"\t[" + itemLFs[index].bounds[X] +
"," + itemLFs[index].bounds[Y] +
"," + itemLFs[index].bounds[WIDTH] +
"," + itemLFs[index].bounds[HEIGHT] + "]");
}
} // for
// Before we quit, layout the last row we did in the loop
try {
int oldRowHeight = itemLFs[rowStart].rowHeight;
lineHeight = layoutRowHorizontal(rowStart, numOfLFs - 1,
sizingBox[WIDTH], lineHeight,
itemLFs);
int rowY = itemLFs[rowStart].bounds[Y];
layoutRowVertical(rowStart, numOfLFs - 1, lineHeight,
itemLFs, numOfLFs);
viewable[HEIGHT] = rowY + lineHeight;
} catch (Throwable t) {
Display.handleThrowable(t);
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" returning invalidIndex:"+invalidIndex+" }");
}
return invalidIndex;
| private void | updateVertically(int startIndex, ItemLFImpl[] itemLFs, int numOfLFs, int[] viewable)Calculating how many pixels should the startIndex<> item move up
or down, and loop from this item until the end, adding the delta
to all these items.
We know where this startIndex should be, we know where it is
now, so we can know how much to move everything.
The viewable height is updated accordingly.
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"### in updateVertically for #" + startIndex +
".\t");
}
int deltaY = 0;
int newY = 0;
// loop on all the items, starting with this one,
// updating their Y, and unmark their flag
if (startIndex == 0) {
newY = 0;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
"newY=" + newY);
}
} else {
newY = itemLFs[startIndex-1].bounds[Y] +
itemLFs[startIndex-1].rowHeight;
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" itemLFs[si-1].bounds[Y]=" +
itemLFs[startIndex-1].bounds[Y] +
" itemLFs[si-1].rowHeight=" +
itemLFs[startIndex-1].rowHeight);
}
}
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
">>> CustomItemLFImpl -- lRepaint()" +
" itemLFs[si].bounds[Y]=" +
itemLFs[startIndex].bounds[Y] +
" newY=" + newY);
}
deltaY = newY - itemLFs[startIndex].bounds[Y];
if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
Logging.report(Logging.INFORMATION,
LogChannels.LC_HIGHUI_FORM_LAYOUT,
" delta= " + deltaY);
}
if (deltaY == 0) {
itemLFs[startIndex].actualBoundsInvalid[Y] = false;
return;
}
for (int i = startIndex; i < numOfLFs; i++) {
itemLFs[i].lMove(0, deltaY);
}
itemLFs[startIndex].actualBoundsInvalid[Y] = false;
// update viewable height
viewable[HEIGHT] += deltaY;
|
|