0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026:
0027: package javax.microedition.lcdui;
0028:
0029: import com.sun.midp.log.Logging;
0030: import com.sun.midp.log.LogChannels;
0031: import com.sun.midp.configurator.Constants;
0032:
0033: /**
0034: * Layout management class for <code>Form</code>.
0035: * See DisplayableLF.java for naming convention.
0036: */
0037: class LayoutManager {
0038:
0039: // Required test: multiple/simultaneous forms with different layout
0040:
0041: /**
0042: * Singleton design pattern. Obtain access using instance() method.
0043: */
0044: LayoutManager() {
0045: sizingBox = new int[3]; // x,y,width
0046: }
0047:
0048: /**
0049: * Do layout.
0050: * SYNC NOTE: caller must hold LCDUILock around a call to this method
0051: *
0052: * @param layoutMode one of <code>FULL_LAYOUT</code> or
0053: * <code>UPDATE_LAYOUT</code>
0054: * @param numOfLFs number of elements in the calling form
0055: * @param itemLFs reference to the items array of the calling form
0056: * @param inp_viewportWidth width of the screen area available for the form
0057: * @param inp_viewportHeight height of the screen area available
0058: * for the form
0059: * @param viewable area needed for the content of the form
0060: */
0061: void lLayout(int layoutMode, ItemLFImpl[] itemLFs, int numOfLFs,
0062: int inp_viewportWidth, int inp_viewportHeight,
0063: int[] viewable) {
0064:
0065: viewportWidth = inp_viewportWidth;
0066: viewportHeight = inp_viewportHeight;
0067:
0068: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0069: Logging
0070: .report(
0071: Logging.INFORMATION,
0072: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0073: "\n<<<<<<<<<< Doing "
0074: + (layoutMode == FULL_LAYOUT ? "FULL_LAYOUT"
0075: : "UPDATE_LAYOUT")
0076: + "... >>>>>>>>>>");
0077: }
0078:
0079: if (layoutMode == FULL_LAYOUT) {
0080: // first Layout
0081: updateBlock(0, 0, true, itemLFs, numOfLFs, viewable);
0082: } else {
0083: // UPDATE_LAYOUT
0084: // most of the time only one or two items are updated at a time.
0085: // here we find the minimum items that needs a re-layout, and
0086: // calling layout for them
0087:
0088: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0089: Logging.report(Logging.INFORMATION,
0090: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0091: "UPDATE_LAYOUT - START");
0092: }
0093: // loop on all the items, and find which item needs an update
0094: // If more than one Item needs update, they both will update,
0095: // in their layout order.
0096:
0097: // * we keep a "moving anchor" to use when we identify
0098: // an invalid Item. This anchor is always at the beginning
0099: // of the row above the current Item checked, or at the
0100: // beginning of the row of the current Item, in case there
0101: // was an explicit line break.
0102:
0103: int anchorIndex = 0;
0104:
0105: // this index is needed to identify new lines to be set as
0106: // anchors later.
0107: int newLineIndex = 0;
0108:
0109: // find where to start the layout. It should be at the beginning
0110: // of the line above the invalid item, or of the same line
0111: // in case the line break is explicit.
0112:
0113: // We loop on all the Items to find the first invalid, while
0114: // keeping the anchorIndex up do date. When calling "updateBlock",
0115: // the index will jump directly to the next block, because we laid
0116: // out all the Items in that block.
0117:
0118: for (int index = 0; index < numOfLFs; index++) {
0119:
0120: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0121: Logging
0122: .report(
0123: Logging.INFORMATION,
0124: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0125: "\n["
0126: + itemLFs[index]
0127: + "]"
0128: + "BEFORE: index: "
0129: + index
0130: + "\t["
0131: + itemLFs[index].bounds[X]
0132: + ","
0133: + itemLFs[index].bounds[Y]
0134: + ","
0135: + itemLFs[index].bounds[WIDTH]
0136: + ","
0137: + itemLFs[index].bounds[HEIGHT]
0138: + "]\t newLine?"
0139: + itemLFs[index].isNewLine
0140: + " lineHeight="
0141: + itemLFs[index].rowHeight
0142: + "\t actualBoundsInvalid["
0143: + itemLFs[index].actualBoundsInvalid[X]
0144: + ","
0145: + itemLFs[index].actualBoundsInvalid[Y]
0146: + ","
0147: + itemLFs[index].actualBoundsInvalid[WIDTH]
0148: + ","
0149: + itemLFs[index].actualBoundsInvalid[HEIGHT]
0150: + "]\t ** viewable: "
0151: + index + "\t["
0152: + viewportWidth + ","
0153: + viewable[HEIGHT] + "]");
0154: }
0155:
0156: if (itemLFs[index].actualBoundsInvalid[WIDTH]
0157: || itemLFs[index].actualBoundsInvalid[X]) {
0158:
0159: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0160: Logging.report(Logging.INFORMATION,
0161: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0162: "> WIDTH or X is invalid!");
0163: }
0164:
0165: // if width is changed, than we have to do a layout two
0166: // a block of Items. So it covers the height as well call
0167: // layout block. The index will jump to the first item on
0168: // the next block.
0169:
0170: // return the last item on the block:
0171: index = updateBlock(anchorIndex, index, false,
0172: itemLFs, numOfLFs, viewable);
0173:
0174: // set the anchor on the next item, if there is one.
0175: // if (i+1) is larger than the length of itemLFs, the for
0176: // loop will end anyway so we don't have to check it here.
0177:
0178: anchorIndex = index + 1;
0179:
0180: } else if (itemLFs[index].actualBoundsInvalid[HEIGHT]) {
0181:
0182: // item current height
0183: int h = itemLFs[index].bounds[HEIGHT];
0184:
0185: // item preferred height
0186: int ph = itemLFs[index]
0187: .lGetAdornedPreferredHeight(itemLFs[index].bounds[WIDTH]);
0188:
0189: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0190: Logging.report(Logging.INFORMATION,
0191: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0192: "> HEIGHT is invalid from:" + h
0193: + " to:" + ph);
0194: }
0195: if (h != ph) {
0196: itemLFs[index].lSetSize(
0197: itemLFs[index].bounds[WIDTH], ph);
0198: itemLFs[index].rowHeight += (ph - h);
0199:
0200: // NOTE: We should check whole row height,
0201: // instead of just this item.
0202:
0203: itemLFs[index].actualBoundsInvalid[HEIGHT] = false;
0204:
0205: if (numOfLFs > index + 1) {
0206:
0207: itemLFs[index + 1].actualBoundsInvalid[Y] = true;
0208:
0209: // NOTE: We should calculate new LineHeight,
0210: // instead of just Item Height
0211:
0212: updateVertically(index + 1, itemLFs,
0213: numOfLFs, viewable);
0214: } else {
0215: // only need to update the viewable
0216: viewable[HEIGHT] += (ph - h);
0217: }
0218: }
0219:
0220: } else if (itemLFs[index].actualBoundsInvalid[Y]) {
0221:
0222: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0223: Logging.report(Logging.INFORMATION,
0224: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0225: "> *only* Y is invalid for #" + index);
0226: }
0227:
0228: updateVertically(index, itemLFs, numOfLFs, viewable);
0229:
0230: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0231: Logging.report(Logging.INFORMATION,
0232: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0233: "> Y - done");
0234: }
0235:
0236: } else {
0237:
0238: // current item is valid.
0239:
0240: // check if i can be a new anchor point
0241: // (has an explicit line break before it,
0242: // or after the previous Item).
0243: if (itemLFs[index].isNewLine) {
0244:
0245: if (itemLFs[index].equateNLB()
0246: || ((index > 0) && (itemLFs[index - 1]
0247: .equateNLA()))) {
0248: // explicit newline
0249: anchorIndex = index;
0250: newLineIndex = index;
0251: } else {
0252: // implicit newline
0253:
0254: // we can move the anchor to the next line:
0255: // set the anchorIndex to be the old newLineIndex
0256: // (which is the first item on the row above the
0257: // current item).
0258: anchorIndex = newLineIndex;
0259:
0260: // set i as the first in its line
0261: newLineIndex = index;
0262: }
0263:
0264: }
0265:
0266: }
0267:
0268: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0269: Logging
0270: .report(
0271: Logging.INFORMATION,
0272: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0273: "AFTER: index: "
0274: + index
0275: + "\t["
0276: + itemLFs[index].bounds[X]
0277: + ","
0278: + itemLFs[index].bounds[Y]
0279: + ","
0280: + itemLFs[index].bounds[WIDTH]
0281: + ","
0282: + itemLFs[index].bounds[HEIGHT]
0283: + "]\t newLine?"
0284: + itemLFs[index].isNewLine
0285: + " lineHeight="
0286: + itemLFs[index].rowHeight
0287: + "\t actualBoundsInvalid["
0288: + itemLFs[index].actualBoundsInvalid[X]
0289: + ","
0290: + itemLFs[index].actualBoundsInvalid[Y]
0291: + ","
0292: + itemLFs[index].actualBoundsInvalid[WIDTH]
0293: + ","
0294: + itemLFs[index].actualBoundsInvalid[HEIGHT]
0295: + "]\t ** viewable: "
0296: + index + "\t["
0297: + viewportWidth + ","
0298: + viewable[HEIGHT] + "]");
0299: }
0300: } // for loop
0301: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0302: Logging.report(Logging.INFORMATION,
0303: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0304: "UPDATE_LAYOUT - DONE");
0305: }
0306: }
0307:
0308: // correct viewable area if required
0309:
0310: // if there are no items in the form just reset viewable[HEIGHT]
0311: if (numOfLFs == 0) {
0312: viewable[HEIGHT] = 0;
0313: }
0314: }
0315:
0316: /**
0317: * Used both to do a full layout or just update a layout.
0318: *
0319: * assumptions: startIndex<=invalidIndex
0320: *
0321: * @param startIndex The index to start the layout. Should start a row.
0322: * @param invalidIndex The index causing the re-layout, should
0323: * be equal or greater than startIndex
0324: * @param fullLayout if <code>true</code>, does a full layout and ignores
0325: * the rest of the parameters sent to this method.
0326: * @param itemLFs reference to the items array of the calling form
0327: * @param numOfLFs number of elements in the calling form
0328: * @param viewable area needed for the content of the form
0329: *
0330: * @return the index of the last <code>Item</code> laid out
0331: */
0332: private int updateBlock(int startIndex, int invalidIndex,
0333: boolean fullLayout, ItemLFImpl[] itemLFs, int numOfLFs,
0334: int[] viewable) {
0335: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0336: Logging.report(Logging.INFORMATION,
0337: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0338: "\n - updateBlock(START=" + startIndex
0339: + ", INVALID=" + invalidIndex
0340: + ", Full Layout=" + fullLayout + ") {");
0341: }
0342:
0343: // SYNC NOTE: layout() is always called from within a hold
0344: // on LCDUILock
0345:
0346: int oldWidth = viewable[WIDTH];
0347: int oldHeight = viewable[HEIGHT];
0348:
0349: // If we don't have any Items, just return
0350: if (numOfLFs == 0) {
0351:
0352: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0353: Logging.report(Logging.INFORMATION,
0354: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0355: " we don't have any Items, just return }");
0356: }
0357:
0358: return 0;
0359: }
0360:
0361: int rowStart;
0362:
0363: if (fullLayout) {
0364: // The index of the first Item in the horizontal row
0365: rowStart = 0;
0366: } else {
0367: rowStart = startIndex;
0368: }
0369:
0370: // The sizingBox starts out life with the size of the viewport,
0371: // but gets whittled down as each Item gets laid out and occupies
0372: // space in it. It effectively keeps a running total of what space
0373: // is available due to the Items which have already been laid out
0374:
0375: // We only allow space for the traversal indicator if we
0376: // have more than one item - because we only draw the traversal
0377: // indicator if we have more than one item to traverse to.
0378: // LF's width is set to the maximum allowable width,
0379: // while view's height is initialized with initial padding and
0380: // and grows when new row is added.
0381: sizingBox[X] = 0;
0382: sizingBox[Y] = 0;
0383: sizingBox[WIDTH] = viewportWidth;
0384: viewable[WIDTH] = viewportWidth;
0385:
0386: if (fullLayout) {
0387: viewable[HEIGHT] = 0;
0388: } else if (numOfLFs > 1 && startIndex > 0) {
0389: sizingBox[Y] = itemLFs[startIndex - 1].bounds[Y]
0390: + itemLFs[startIndex - 1].rowHeight;
0391:
0392: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0393: Logging.report(Logging.INFORMATION,
0394: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0395: "sizingBox[Y]=" + sizingBox[Y]);
0396: }
0397: }
0398:
0399: // A running variable which maintains the height of the
0400: // tallest item on a line
0401: int lineHeight = 0;
0402: int pW, pH;
0403: int curAlignment = Item.LAYOUT_LEFT;
0404:
0405: // We loop through the Items starting in startIndex, until we reach
0406: // the end of the block, and return the index of the next block,
0407: // or just finishing the for loop if this is the last block.
0408: for (int index = startIndex; index < numOfLFs; index++) {
0409:
0410: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0411: Logging.report(Logging.INFORMATION,
0412: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0413: "..\n\tFOR LOOP: startIndex=" + startIndex
0414: + " index=[" + index
0415: + "] invalidIndex=" + invalidIndex);
0416: }
0417:
0418: // If the Item can be shrunken, get its minimum width,
0419: // and its preferred if it is not
0420: if (itemLFs[index].shouldHShrink()) {
0421: pW = itemLFs[index].lGetAdornedMinimumWidth();
0422: } else {
0423: if (itemLFs[index].lGetLockedWidth() != -1) {
0424: pW = itemLFs[index].lGetLockedWidth();
0425: } else {
0426: // if height is locked default preferred width
0427: // will be used, otherwise width will be calculated
0428: // based on lockedHeight
0429: pW = itemLFs[index]
0430: .lGetAdornedPreferredWidth(itemLFs[index]
0431: .lGetLockedHeight());
0432:
0433: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0434: Logging.report(Logging.INFORMATION,
0435: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0436: " no shrink - locked w - pW=" + pW
0437: + " viewable[width]="
0438: + viewable[WIDTH]);
0439: }
0440: }
0441: }
0442:
0443: // We have a notion of the maximum allowable width an Item can
0444: // have, so we enforce it first here:
0445:
0446: if (!Constants.SCROLLS_HORIZONTAL && (pW > viewable[WIDTH])) {
0447: pW = viewable[WIDTH];
0448: }
0449:
0450: // We use a separate boolean here to check for each case of
0451: // requiring a new line (rather than the if() from hell)
0452: boolean newLine = (index > 0
0453: && itemLFs[index - 1].equateNLA()
0454: || itemLFs[index].equateNLB() ||
0455: // no room for this item on the same row
0456: pW > sizingBox[WIDTH]);
0457:
0458: if (isImplicitLineBreak(curAlignment, index, itemLFs)) {
0459: curAlignment = itemLFs[index].getLayout()
0460: & LAYOUT_HMASK;
0461: newLine = true;
0462: }
0463:
0464: // We linebreak if there is an existing row;
0465: // possible only when there is more than 1 item
0466: if (newLine && (lineHeight > 0)) {
0467: // index > 0, as the calculation of newLine guarantee
0468:
0469: //
0470: // ** NEW LINE **
0471: //
0472: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0473: Logging.report(Logging.INFORMATION,
0474: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0475: " --new line--");
0476: }
0477:
0478: // First, handle current row's layout directives
0479:
0480: try {
0481:
0482: // used for layout update
0483: // int oldRowHeight = itemLFs[index-1].rowHeight;
0484: boolean wasNewLine = itemLFs[index].isNewLine;
0485:
0486: // now it's certainly first in line
0487: itemLFs[index].isNewLine = true;
0488:
0489: // layout items in previous row
0490: lineHeight = layoutRowHorizontal(rowStart,
0491: index - 1, sizingBox[WIDTH], lineHeight,
0492: itemLFs);
0493: layoutRowVertical(rowStart, index - 1, lineHeight,
0494: itemLFs, numOfLFs);
0495:
0496: if (fullLayout) {
0497:
0498: if (numOfLFs > 1) {
0499: viewable[HEIGHT] += lineHeight;
0500: } else {
0501: viewable[HEIGHT] += lineHeight + 1;
0502: }
0503:
0504: } else { // UPDATE_LAYOUT
0505:
0506: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0507: Logging.report(Logging.INFORMATION,
0508: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0509: "** 1 ** row height=" + lineHeight);
0510: }
0511:
0512: // cases:
0513: // 1. this item was first in row already
0514: // > than update layout wouldn't be called for the
0515: // > row above it unless there was a change in that
0516: // > row.
0517: // > Therefore we can finish the loop, and just update
0518: // > the Y coordinates for the rest of the Items.
0519:
0520: if (wasNewLine && index > invalidIndex) {
0521: // we can call updateVertically by returning
0522: // index-1 and marking next Y as invalid.
0523: itemLFs[index].actualBoundsInvalid[Y] = true;
0524:
0525: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0526: Logging
0527: .report(
0528: Logging.INFORMATION,
0529: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0530: " returning index-1 and "
0531: + "marking next Y as invalid. }");
0532: }
0533:
0534: return (index - 1);
0535: // (some Items after it may still be invalid,
0536: // so the calling method will continue the layout).
0537:
0538: }
0539:
0540: // 2. this item wasn't first on its row
0541: // > then we should continue a regular layout.
0542:
0543: if (!wasNewLine) {
0544: itemLFs[index].actualBoundsInvalid[X] = true;
0545: }
0546: }
0547:
0548: } catch (Throwable t) {
0549: Display.handleThrowable(t);
0550: }
0551:
0552: // Then, reset the sizingBox, lineHeight, and rowStart
0553: sizingBox[X] = 0;
0554: if (fullLayout) {
0555: sizingBox[Y] = viewable[HEIGHT];
0556: } else {
0557: sizingBox[Y] = itemLFs[index - 1].bounds[Y]
0558: + itemLFs[index - 1].rowHeight;
0559: if (numOfLFs <= 1) {
0560: sizingBox[Y] += 1;
0561: }
0562: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0563: Logging.report(Logging.INFORMATION,
0564: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0565: "** 2 ** sizingBox[Y]="
0566: + sizingBox[Y]);
0567: }
0568: }
0569:
0570: sizingBox[WIDTH] = viewportWidth;
0571:
0572: lineHeight = 0;
0573: rowStart = index;
0574:
0575: itemLFs[index].isNewLine = true;
0576:
0577: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0578: Logging.report(Logging.INFORMATION,
0579: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0580: " (new line end)");
0581: }
0582: //
0583: // ** NEW LINE - END **
0584: //
0585:
0586: } else {
0587:
0588: // keep isNewLine flag up to date
0589:
0590: if (index == 0 || newLine) {
0591: itemLFs[index].isNewLine = true;
0592: } else {
0593:
0594: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0595: Logging
0596: .report(
0597: Logging.INFORMATION,
0598: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0599: "** "
0600: + index
0601: + " is not a new line **");
0602: }
0603:
0604: // this is not a new line
0605: itemLFs[index].isNewLine = false;
0606: }
0607:
0608: }
0609:
0610: pH = getItemHeight(index, pW, itemLFs);
0611:
0612: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0613: Logging.report(Logging.INFORMATION,
0614: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0615: " updateBlock.. pH = " + pH);
0616: }
0617:
0618: // If the Item is changing size, set the flag so that callPaint()
0619: // will call the Item's sizeChanged() method before painting
0620:
0621: if (oldWidth != viewportWidth
0622: || oldHeight != viewportHeight
0623: || itemLFs[index].bounds[WIDTH] != pW
0624: || itemLFs[index].bounds[HEIGHT] != pH) {
0625: itemLFs[index].sizeChanged = true;
0626: }
0627:
0628: if (!fullLayout && (index > invalidIndex)) {
0629:
0630: // if we've reached the end of the block (explicit linebreak)
0631: // than we can safely return
0632: if (itemLFs[index].equateNLB()
0633: || ((index > 0) && (itemLFs[index - 1]
0634: .equateNLA()))) {
0635:
0636: // we can stop the loop, returning the last Item laid out
0637: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0638: Logging.report(Logging.INFORMATION,
0639: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0640: "** stop layout, explicit lb **\n}");
0641: }
0642: itemLFs[index].actualBoundsInvalid[Y] = true;
0643: return (index - 1);
0644:
0645: // identify more occasions where only Y will change
0646: } else if (itemLFs[index].bounds[X] == sizingBox[X]
0647: &&
0648: // itemLFs[index].bounds[Y] == sizingBox[Y] &&
0649: itemLFs[index].bounds[WIDTH] == pW
0650: && itemLFs[index].bounds[HEIGHT] == pH) {
0651:
0652: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0653: Logging.report(Logging.INFORMATION,
0654: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0655: "\n** no need to layout **\n}");
0656: }
0657:
0658: itemLFs[index].actualBoundsInvalid[X] = false;
0659: // notice the "true": (only the Y coordinate is invalid)
0660: itemLFs[index].actualBoundsInvalid[Y] = true;
0661: itemLFs[index].actualBoundsInvalid[WIDTH] = false;
0662: itemLFs[index].actualBoundsInvalid[HEIGHT] = false;
0663:
0664: return (index - 1);
0665: }
0666: }
0667:
0668: // We assign bounds to the item, which is its pixel location,
0669: // width, and height in coordinates which represent offsets
0670: // of the viewport origin (that is, are in the viewport
0671: // coordinate space)
0672: itemLFs[index].lSetSize(pW, pH);
0673: itemLFs[index].lSetLocation(sizingBox[X], sizingBox[Y]);
0674:
0675: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0676: Logging.report(Logging.INFORMATION,
0677: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0678: "[F] index (" + index + " lineHeight == "
0679: + lineHeight + ") set height to:" + pH);
0680: }
0681:
0682: itemLFs[index].actualBoundsInvalid[X] = false;
0683: itemLFs[index].actualBoundsInvalid[Y] = false;
0684: itemLFs[index].actualBoundsInvalid[WIDTH] = false;
0685: itemLFs[index].actualBoundsInvalid[HEIGHT] = false;
0686:
0687: // If this Item is currently the tallest on the line, its
0688: // height becomes our prevailing lineheight
0689: if (pH > lineHeight) {
0690: lineHeight = pH;
0691: }
0692:
0693: // We whittle down the sizingBox by the Item's dimensions,
0694: // effectively maintaining how much space is left for the
0695: // remaining Items, if the item has some positive width
0696: if (pW > 0) {
0697: sizingBox[WIDTH] -= pW;
0698: // we know that item fits on this row but padding
0699: // might not fit
0700: if (sizingBox[WIDTH] < 0) {
0701: sizingBox[WIDTH] = 0;
0702: }
0703: sizingBox[X] += pW;
0704: }
0705:
0706: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0707: Logging.report(Logging.INFORMATION,
0708: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0709: "\t\tindex: " + index + "\t["
0710: + itemLFs[index].bounds[X] + ","
0711: + itemLFs[index].bounds[Y] + ","
0712: + itemLFs[index].bounds[WIDTH] + ","
0713: + itemLFs[index].bounds[HEIGHT] + "]");
0714: }
0715: } // for
0716:
0717: // Before we quit, layout the last row we did in the loop
0718: try {
0719:
0720: int oldRowHeight = itemLFs[rowStart].rowHeight;
0721:
0722: lineHeight = layoutRowHorizontal(rowStart, numOfLFs - 1,
0723: sizingBox[WIDTH], lineHeight, itemLFs);
0724:
0725: int rowY = itemLFs[rowStart].bounds[Y];
0726:
0727: layoutRowVertical(rowStart, numOfLFs - 1, lineHeight,
0728: itemLFs, numOfLFs);
0729:
0730: viewable[HEIGHT] = rowY + lineHeight;
0731:
0732: } catch (Throwable t) {
0733: Display.handleThrowable(t);
0734: }
0735:
0736: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0737: Logging.report(Logging.INFORMATION,
0738: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0739: " returning invalidIndex:" + invalidIndex + " }");
0740: }
0741:
0742: return invalidIndex;
0743: }
0744:
0745: /**
0746: * Calculating how many pixels should the <pre>startIndex<> item move up
0747: * or down, and loop from this item until the end, adding the delta
0748: * to all these items.
0749: * We know where this startIndex should be, we know where it is
0750: * now, so we can know how much to move everything.
0751: *
0752: * The viewable height is updated accordingly.
0753: *
0754: * @param startIndex the index of the first item that should move
0755: * up or down. It should be first in its row,
0756: * and the Item before it should be laid out
0757: * correctly, with rowHeight set up.
0758: * @param itemLFs reference to the items array of the calling form
0759: * @param numOfLFs number of elements in the calling form
0760: * @param viewable area needed for the content of the form
0761: */
0762: private void updateVertically(int startIndex, ItemLFImpl[] itemLFs,
0763: int numOfLFs, int[] viewable) {
0764:
0765: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0766: Logging.report(Logging.INFORMATION,
0767: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0768: "### in updateVertically for #" + startIndex
0769: + ".\t");
0770: }
0771:
0772: int deltaY = 0;
0773: int newY = 0;
0774: // loop on all the items, starting with this one,
0775: // updating their Y, and unmark their flag
0776: if (startIndex == 0) {
0777: newY = 0;
0778:
0779: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0780: Logging.report(Logging.INFORMATION,
0781: LogChannels.LC_HIGHUI_FORM_LAYOUT, "newY="
0782: + newY);
0783: }
0784:
0785: } else {
0786: newY = itemLFs[startIndex - 1].bounds[Y]
0787: + itemLFs[startIndex - 1].rowHeight;
0788:
0789: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0790: Logging.report(Logging.INFORMATION,
0791: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0792: " itemLFs[si-1].bounds[Y]="
0793: + itemLFs[startIndex - 1].bounds[Y]
0794: + " itemLFs[si-1].rowHeight="
0795: + itemLFs[startIndex - 1].rowHeight);
0796: }
0797: }
0798:
0799: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0800: Logging.report(Logging.INFORMATION,
0801: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0802: ">>> CustomItemLFImpl -- lRepaint()"
0803: + " itemLFs[si].bounds[Y]="
0804: + itemLFs[startIndex].bounds[Y] + " newY="
0805: + newY);
0806: }
0807:
0808: deltaY = newY - itemLFs[startIndex].bounds[Y];
0809:
0810: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0811: Logging.report(Logging.INFORMATION,
0812: LogChannels.LC_HIGHUI_FORM_LAYOUT, " delta= "
0813: + deltaY);
0814: }
0815:
0816: if (deltaY == 0) {
0817: itemLFs[startIndex].actualBoundsInvalid[Y] = false;
0818: return;
0819: }
0820:
0821: for (int i = startIndex; i < numOfLFs; i++) {
0822: itemLFs[i].lMove(0, deltaY);
0823: }
0824:
0825: itemLFs[startIndex].actualBoundsInvalid[Y] = false;
0826:
0827: // update viewable height
0828: viewable[HEIGHT] += deltaY;
0829: }
0830:
0831: /**
0832: * After the contents of a row have been determined, layout the
0833: * items on that row, taking into account the individual items'
0834: * horizontally oriented layout directives.
0835: *
0836: * @param rowStart the index of the first row element
0837: * @param rowEnd the index of the last row element
0838: * @param hSpace the amount of empty space in pixels in this row before
0839: * inflation
0840: * @param rowHeight the old row height
0841: * @param itemLFs reference to the items array of the calling form
0842: *
0843: * @return the new rowHeight for this row after all of the inflations
0844: */
0845: private int layoutRowHorizontal(int rowStart, int rowEnd,
0846: int hSpace, int rowHeight, ItemLFImpl[] itemLFs) {
0847: // SYNC NOTE: protected by the lock around calls to layout()
0848:
0849: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0850: Logging.report(Logging.INFORMATION,
0851: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0852: "[F] layoutRowHorizontal -- rowStart=" + rowStart
0853: + " rowEnd=" + rowEnd + " hSpace=" + hSpace
0854: + " rowHeight=" + rowHeight);
0855: }
0856:
0857: hSpace = inflateHShrinkables(rowStart, rowEnd, hSpace, itemLFs);
0858: hSpace = inflateHExpandables(rowStart, rowEnd, hSpace, itemLFs);
0859:
0860: // if any of the items were inflated we have to recalculate
0861: // the new row height for this row
0862: rowHeight = 0;
0863: for (int i = rowStart; i <= rowEnd; i++) {
0864: if (rowHeight < itemLFs[i].bounds[HEIGHT]) {
0865: rowHeight = itemLFs[i].bounds[HEIGHT];
0866: }
0867: }
0868:
0869: if (hSpace == 0) {
0870:
0871: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0872: Logging.report(Logging.INFORMATION,
0873: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0874: "[F] layoutRowHorizontal -- done -- "
0875: + "(hSpace == 0) -- returning "
0876: + rowHeight);
0877: }
0878: return rowHeight;
0879: }
0880:
0881: int curAlignment = getCurHorAlignment(itemLFs, rowStart);
0882:
0883: switch (curAlignment) {
0884: case Item.LAYOUT_CENTER:
0885: hSpace = hSpace / 2;
0886: /* fall through */
0887: case Item.LAYOUT_RIGHT:
0888: for (; rowStart <= rowEnd; rowStart++) {
0889: itemLFs[rowEnd].lMove(hSpace, 0);
0890: }
0891: break;
0892:
0893: case Item.LAYOUT_LEFT:
0894: default:
0895: break;
0896: }
0897:
0898: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0899: Logging.report(Logging.INFORMATION,
0900: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0901: "[F] layoutRowHorizontal -- done "
0902: + "-- returning " + rowHeight);
0903: }
0904:
0905: return rowHeight;
0906:
0907: }
0908:
0909: /**
0910: * Gets the current horizontal alignment of the item. If Item's
0911: * horizontal layout bits are not set its current horizontal
0912: * alignment is the same as of the previous Item.
0913: *
0914: * @param itemLFs reference to the items array of the calling form
0915: * @param index the index of an item in the itemLFs array which
0916: * current horizontal alignment needs to be found out
0917: * @return currentl horizontal alignment of an Item with passed in
0918: * index
0919: */
0920: private int getCurHorAlignment(ItemLFImpl[] itemLFs, int index) {
0921: for (int hAlign, i = index; i >= 0; i--) {
0922: hAlign = itemLFs[i].getLayout() & LAYOUT_HMASK;
0923:
0924: if (hAlign == 0) {
0925: continue;
0926: }
0927: return hAlign;
0928: }
0929:
0930: // default layout is LAYOUT_LEFT
0931: return Item.LAYOUT_LEFT;
0932: }
0933:
0934: /**
0935: * Inflate all the horizontally 'shrinkable' items on a row.
0936: *
0937: * @param rowStart the index of the first row element
0938: * @param rowEnd the index of the last row element
0939: * @param space the amount of empty space left in pixels in this row
0940: * @param itemLFs reference to the items array of the calling form
0941: *
0942: * @return the amount of empty space on this row after shinkage
0943: */
0944: private int inflateHShrinkables(int rowStart, int rowEnd,
0945: int space, ItemLFImpl[] itemLFs) {
0946: // SYNC NOTE: protected by the lock around calls to layout()
0947:
0948: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0949: Logging.report(Logging.INFORMATION,
0950: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0951: "[F] inflateHShrinkables -- rowStart=" + rowStart
0952: + " rowEnd=" + rowEnd + " space=" + space);
0953: }
0954:
0955: if (space == 0) {
0956: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0957: Logging.report(Logging.INFORMATION,
0958: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0959: "[F] inflateHShrinkables -- returning "
0960: + "(space == 0)");
0961: }
0962: return 0;
0963: }
0964:
0965: // To inflate shrinkables, we make a first pass gathering
0966: // the smallest proportion (the baseline)
0967: int baseline = Integer.MAX_VALUE;
0968: int pW, prop = 0;
0969:
0970: for (int i = rowStart; i <= rowEnd; i++) {
0971: if (itemLFs[i].shouldHShrink()) {
0972: pW = itemLFs[i].lGetLockedWidth();
0973: if (pW == -1) {
0974: pW = itemLFs[i]
0975: .lGetAdornedPreferredWidth(itemLFs[i]
0976: .lGetLockedHeight());
0977: }
0978: prop = pW - itemLFs[i].lGetAdornedMinimumWidth();
0979: if (prop > 0 && prop < baseline) {
0980: baseline = prop;
0981: }
0982: }
0983: }
0984:
0985: // If there are no shrinkables, return
0986: if (baseline == Integer.MAX_VALUE) {
0987: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
0988: Logging
0989: .report(
0990: Logging.INFORMATION,
0991: LogChannels.LC_HIGHUI_FORM_LAYOUT,
0992: "[F] inflateHShrinkables -- returning "
0993: + "(baseline == Integer.MAX_VALUE) space == "
0994: + space);
0995: }
0996: return space;
0997: }
0998:
0999: prop = 0;
1000:
1001: // Now we loop again, adding up all the proportions so
1002: // we can find the adder
1003: for (int i = rowStart; i <= rowEnd; i++) {
1004: if (itemLFs[i].shouldHShrink()) {
1005: pW = itemLFs[i].lGetLockedWidth();
1006: if (pW == -1) {
1007: pW = itemLFs[i]
1008: .lGetAdornedPreferredWidth(itemLFs[i]
1009: .lGetLockedHeight());
1010: }
1011: prop += ((pW - itemLFs[i].lGetAdornedMinimumWidth()) / baseline);
1012: }
1013: }
1014:
1015: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1016: Logging.report(Logging.INFORMATION,
1017: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1018: "[F] inflateHShrinkables -- prop == " + prop);
1019: }
1020:
1021: // Now we compute the adder, and add it to each of the
1022: // shrinkables, times its proportion
1023: int adder = space / prop;
1024:
1025: for (int i = rowStart; i <= rowEnd; i++) {
1026: if (itemLFs[i].shouldHShrink()) {
1027:
1028: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1029: Logging.report(Logging.INFORMATION,
1030: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1031: "### item " + i + " before shrinking is:"
1032: + itemLFs[i].bounds[WIDTH]);
1033: }
1034:
1035: pW = itemLFs[i].lGetLockedWidth();
1036: if (pW == -1) {
1037: pW = itemLFs[i]
1038: .lGetAdornedPreferredWidth(itemLFs[i]
1039: .lGetLockedHeight());
1040: }
1041: space = pW - itemLFs[i].lGetAdornedMinimumWidth();
1042:
1043: // The proportionate amount of space to add
1044: prop = adder * (space / baseline);
1045:
1046: // We only enlarge the item to its preferred width at
1047: // a maximum
1048: if (space > prop) {
1049: space = prop;
1050: }
1051: itemLFs[i].lSetSize(itemLFs[i].bounds[WIDTH] + space,
1052: getItemHeight(i, itemLFs[i].bounds[WIDTH]
1053: + space, itemLFs));
1054:
1055: // Now we have to shift the rest of the elements on the line
1056: for (int j = i + 1; j <= rowEnd; j++) {
1057: itemLFs[j].lMove(space, 0);
1058: }
1059: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1060: Logging.report(Logging.INFORMATION,
1061: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1062: "### item " + i + " shrank to:"
1063: + itemLFs[i].bounds[WIDTH]);
1064: }
1065: }
1066: }
1067:
1068: space = viewportWidth
1069: - (itemLFs[rowEnd].bounds[X] + itemLFs[rowEnd].bounds[WIDTH]);
1070:
1071: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1072: Logging.report(Logging.INFORMATION,
1073: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1074: "[F] inflateHShrinkables -- "
1075: + "returning (end). space == " + space);
1076: }
1077:
1078: return space;
1079: }
1080:
1081: /**
1082: * Inflate all the horizontally 'expandable' items on a row.
1083: *
1084: * @param rowStart the index of the first row element
1085: * @param rowEnd the index of the last row element
1086: * @param space the amount of empty space on this row
1087: * @param itemLFs reference to the items array of the calling form
1088: *
1089: * @return the amount of empty space after expansion
1090: */
1091: private int inflateHExpandables(int rowStart, int rowEnd,
1092: int space, ItemLFImpl[] itemLFs) {
1093: // SYNC NOTE: protected by the lock around calls to layout()
1094:
1095: if (space == 0) {
1096: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1097: Logging.report(Logging.INFORMATION,
1098: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1099: "[F] inflateHExpandables -- "
1100: + "returning (space == 0)");
1101: }
1102: return 0;
1103: }
1104:
1105: int numExp = 0;
1106: // We first loop through and count the expandables
1107: for (int i = rowStart; i <= rowEnd; i++) {
1108: if (itemLFs[i].shouldHExpand()) {
1109: numExp++;
1110: }
1111: }
1112:
1113: if (numExp == 0 || space < numExp) {
1114: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1115: Logging
1116: .report(
1117: Logging.INFORMATION,
1118: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1119: "[F] inflateHExpandables -- returning "
1120: + "(numExp == 0 || space < numExp) space = "
1121: + space);
1122: }
1123: return space;
1124: }
1125:
1126: space = space / numExp;
1127:
1128: // We then add the same amount to each Expandable
1129: for (int i = rowStart; i <= rowEnd; i++) {
1130: if (itemLFs[i].shouldHExpand()) {
1131: itemLFs[i].lSetSize(itemLFs[i].bounds[WIDTH] + space,
1132: getItemHeight(i, itemLFs[i].bounds[WIDTH]
1133: + space, itemLFs));
1134:
1135: // We right shift each subsequent item on the row
1136: for (int j = i + 1; j <= rowEnd; j++) {
1137: itemLFs[j].lMove(space, 0);
1138: }
1139: }
1140: }
1141:
1142: space = viewportWidth
1143: - (itemLFs[rowEnd].bounds[X] + itemLFs[rowEnd].bounds[WIDTH]);
1144:
1145: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1146: Logging.report(Logging.INFORMATION,
1147: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1148: "[F] inflateHExpandables -- "
1149: + "returning (end) space = " + space);
1150: }
1151:
1152: return space;
1153: }
1154:
1155: /**
1156: * After the contents of a row have been determined, layout the
1157: * items on that row, taking into account the individual items'
1158: * vertically oriented layout directives.
1159: *
1160: * @param rowStart the index of the first row element
1161: * @param rowEnd the index of the last row element
1162: * @param itemLFs reference to the items array of the calling form
1163: * @param lineHeight the overall height in pixels of the line
1164: * @param numOfLFs number of elements in the calling form
1165: */
1166: private void layoutRowVertical(int rowStart, int rowEnd,
1167: int lineHeight, ItemLFImpl[] itemLFs, int numOfLFs) {
1168: // SYNC NOTE: protected by the lock around calls to layout()
1169:
1170: int space = 0;
1171: int pH = 0;
1172:
1173: for (int i = rowStart; i <= rowEnd; i++) {
1174:
1175: // set the row height
1176: itemLFs[i].rowHeight = lineHeight;
1177:
1178: // Items that have the LAYOUT_VSHRINK directive are expanded
1179: // to their preferred height or to the height of the row,
1180: // whichever is smaller. Items that are still shorter than
1181: // the row height and that have the LAYOUT_VEXPAND directive
1182: // will expand to the height of the row.
1183: if (itemLFs[i].shouldVExpand()) {
1184: itemLFs[i].lSetSize(itemLFs[i].bounds[WIDTH],
1185: lineHeight);
1186:
1187: } else if (itemLFs[i].shouldVShrink()) {
1188: pH = itemLFs[i].lGetLockedHeight();
1189: if (pH == -1) {
1190: pH = itemLFs[i]
1191: .lGetAdornedPreferredHeight(itemLFs[i].bounds[WIDTH]);
1192: }
1193: if (pH > lineHeight) {
1194: pH = lineHeight;
1195: }
1196: itemLFs[i].lSetSize(itemLFs[i].bounds[WIDTH], pH);
1197: }
1198:
1199: // initially the items are aligned at the top so we simply
1200: // add on to the height
1201: switch (itemLFs[i].getLayout() & LAYOUT_VMASK) {
1202: case Item.LAYOUT_VCENTER:
1203: space = lineHeight - itemLFs[i].bounds[HEIGHT];
1204: if (space > 0) {
1205: itemLFs[i].lMove(0, space / 2);
1206: }
1207: break;
1208: case Item.LAYOUT_TOP:
1209: // it's already there...
1210: break;
1211: case Item.LAYOUT_BOTTOM:
1212: // the layout algorithm must align the Items along the bottom
1213: // if there is no vertical directive specified.
1214: default:
1215: space = lineHeight - itemLFs[i].bounds[HEIGHT];
1216: if (space > 0) {
1217: itemLFs[i].lMove(0, space);
1218: }
1219: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1220: Logging.report(Logging.INFORMATION,
1221: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1222: "Default V layout -- space = " + space
1223: + " itemLFs[i].Y = "
1224: + itemLFs[i].bounds[Y]);
1225: }
1226: }
1227: }
1228:
1229: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1230: Logging.report(Logging.INFORMATION,
1231: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1232: "[F] layoutRowVertical -- done");
1233: }
1234:
1235: }
1236:
1237: /**
1238: * This method checks if we need a new line due to change in
1239: * horizontal alignment. If horizontal alignment is not set on
1240: * <code>Item</code> with index thisItem then current horizontal
1241: * alignment is not changed and no row break is needed.
1242: *
1243: * @param curAlignment current horizontal alignment until this Item
1244: * @param thisItem index of the <code>Item</code> from which to start
1245: * the scan
1246: * @param itemLFs reference to the items array of the calling form
1247: *
1248: * @return <code>true</code> if a new line is needed
1249: */
1250: private boolean isImplicitLineBreak(int curAlignment, int this Item,
1251: ItemLFImpl[] itemLFs) {
1252:
1253: if (this Item == 0) {
1254: return false;
1255: }
1256:
1257: int hAlign = itemLFs[this Item].getLayout() & LAYOUT_HMASK;
1258:
1259: // alignment is not changed
1260: if (hAlign == 0) {
1261: return false;
1262: }
1263:
1264: return (hAlign != curAlignment);
1265: }
1266:
1267: /**
1268: * Get item's height based on the width.
1269: *
1270: * @param index the index of the item which height is being calculated
1271: * @param pW the width set for the item
1272: * @param itemLFs reference to the items array of the calling form
1273: *
1274: * @return the height of the item
1275: */
1276: private int getItemHeight(int index, int pW, ItemLFImpl[] itemLFs) {
1277: // SYNC NOTE: protected by the lock around calls to layout()
1278:
1279: int pH;
1280:
1281: // If the Item can be shrunken, we use its minimum height,
1282: // and its preferred height if it is not
1283: if (itemLFs[index].shouldVShrink()) {
1284: pH = itemLFs[index].lGetAdornedMinimumHeight();
1285: } else {
1286: pH = itemLFs[index].lGetLockedHeight();
1287: if (pH == -1) {
1288: pH = itemLFs[index].lGetAdornedPreferredHeight(pW);
1289: }
1290: }
1291:
1292: // If we can't scroll vertically, clip the item's height
1293: // if it can't fit in the view. We would also enforce a
1294: // notion of a "maximum vertical height" here if we had one
1295: if (!Constants.SCROLLS_VERTICAL && pH > viewportHeight) {
1296: pH = viewportHeight;
1297: }
1298:
1299: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
1300: Logging.report(Logging.INFORMATION,
1301: LogChannels.LC_HIGHUI_FORM_LAYOUT,
1302: " LayoutManager- getItemHeight(" + index + "," + pW
1303: + ") returns " + pH);
1304: }
1305:
1306: return pH;
1307: }
1308:
1309: /**
1310: * Singleton design pattern: obtain access to the single instance of
1311: * this class using this method.
1312: *
1313: * @return Single instance of LayoutManager
1314: */
1315: static LayoutManager instance() {
1316: return singleInstance;
1317: }
1318:
1319: /**
1320: * A bit mask to capture the horizontal layout directive of an item.
1321: */
1322: static final int LAYOUT_HMASK = 0x03;
1323:
1324: /**
1325: * A bit mask to capture the vertical layout directive of an item.
1326: */
1327: static final int LAYOUT_VMASK = 0x30;
1328:
1329: /**
1330: * 'sizingBox' is a [x,y,w,h] array used for dynamic sizing of
1331: * <code>Item</code>s during the layout. It starts with the size of the
1332: * viewport, but can shrink or grow according to the <code>Item</code>
1333: * it tries to lay out.
1334: *
1335: * It is used by layoutBlock and layoutRow.
1336: */
1337: private int[] sizingBox;
1338:
1339: /** Do a full layout. */
1340: final static int FULL_LAYOUT = -1;
1341:
1342: /** Only update layout. */
1343: final static int UPDATE_LAYOUT = -2;
1344:
1345: /**
1346: * Single instance of the LayoutManager class.
1347: */
1348: static LayoutManager singleInstance = new LayoutManager();
1349:
1350: /** Used as an index into the viewport[], for the x origin. */
1351: final static int X = DisplayableLFImpl.X;
1352:
1353: /** Used as an index into the viewport[], for the y origin. */
1354: final static int Y = DisplayableLFImpl.Y;
1355:
1356: /** Used as an index into the viewport[], for the width. */
1357: final static int WIDTH = DisplayableLFImpl.WIDTH;
1358:
1359: /** Used as an index into the viewport[], for the height. */
1360: final static int HEIGHT = DisplayableLFImpl.HEIGHT;
1361:
1362: /** Width of viewport, as passed to layout(). */
1363: int viewportWidth = 0;
1364:
1365: /** Height of viewport, as passed to layout(). */
1366: int viewportHeight = 0;
1367:
1368: }
|