📄 form.java
字号:
// protect ourselves from unexpected errors using a try/catch in // the traverse() method itself. The only problem that could occur // would be if the application added or removed Items on the fly // while the user was traversing. This could lead to an error // condition, but it would be rectified immediately by the // pending validation caused by the append/delete. This seems // preferable to wasting a lot of heap or employing complicating // locking behavior if (traverseIndex == -1) { return false; } // If we need to scroll to fit the current internal traversal // bounds, just return if (formMode == ITEM_TRAVERSE && scrollForBounds(dir, visRect)) { validateVisibility = true; repaintContents(); return true; } visRect[X] = visRect[Y] = 0; visRect[WIDTH] = items[traverseIndex].bounds[WIDTH]; visRect[HEIGHT] = items[traverseIndex].bounds[HEIGHT]; if (items[traverseIndex].callTraverse(dir, viewport[WIDTH], viewport[HEIGHT], visRect)) { // 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] += items[traverseIndex].bounds[X]; visRect[Y] += items[traverseIndex].bounds[Y]; formMode = ITEM_TRAVERSE; if (scrollForTraversal(dir, visRect)) { validateVisibility = true; repaintContents(); } return true; } else { visRect[X] += items[traverseIndex].bounds[X]; visRect[Y] += items[traverseIndex].bounds[Y]; return false; } } /** * Find the nearest neighbor to the current traversed-to Item * moving upward * * @return the index of the nearest neighbor up */ int findNearestNeighborUp() { // SYNC NOTE: see traverse() if (traverseIndex == -1) { return 0; } int a1 = items[traverseIndex].bounds[X]; int b1 = items[traverseIndex].bounds[Y]; int a2 = a1 + items[traverseIndex].bounds[WIDTH]; int b2 = b1 + items[traverseIndex].bounds[HEIGHT]; b1--; b2--; int x1, y1, x2, y2; while (b1 >= 0) { for (int i = traverseIndex - 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]; 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; } } b1 = b1 - CELL_SPACING; } return -1; } /** * Find the nearest neighbor to the current traversed-to Item * moving downward * * @return the index of the nearest neighbor down */ int findNearestNeighborDown() { // SYNC NOTE: see traverse() if (traverseIndex == -1) { return 0; } int a1 = items[traverseIndex].bounds[X]; int b1 = items[traverseIndex].bounds[Y]; int a2 = a1 + items[traverseIndex].bounds[WIDTH]; int b2 = b1 + items[traverseIndex].bounds[HEIGHT]; b2++; int x1, y1, x2, y2; int greatestY = -1; while (true) { for (int i = traverseIndex + 1; i < numOfItems; 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; } } b2 = b2 + CELL_SPACING; if (b2 > greatestY) { break; } } return -1; } /** * Scroll the viewport to fit the bounds after an intial traversal * has been made * * @param dir the direction of traversal into the Item * @param bounds the bounding box of the traversal location * @return True if the viewport had to be scrolled to fit the item */ boolean scrollForBounds(int dir, int[] bounds) { // SYNC NOTE: see traverse() // We can just short circuit scrolling all together if // we know our view is smaller than the viewport if (view[HEIGHT] < viewport[HEIGHT]) { return false; } switch (dir) { case Canvas.UP: if (bounds[Y] >= view[Y]) { return false; } else { view[Y] -= Screen.CONTENT_HEIGHT; if (view[Y] < 0) { view[Y] = 0; } return true; } case Canvas.DOWN: if (bounds[Y] + bounds[HEIGHT] + CELL_SPACING <= view[Y] + viewport[HEIGHT]) { return false; } else { view[Y] += Screen.CONTENT_HEIGHT; if (view[Y] > view[HEIGHT] - viewport[HEIGHT]) { view[Y] = view[HEIGHT] - viewport[HEIGHT]; } return true; } case Canvas.LEFT: // we don't scroll horizontally just yet break; case Canvas.RIGHT: // we don't scroll horizontally just yet break; } return false; } /** * Scroll the viewport to fit the item when initially * traversing to the Item (or within the Item) in the given direction. * * @param dir the direction of traversal into the Item * @param bounds the bounding box of the traversal location * @return True if the viewport had to be scrolled to fit the item */ boolean scrollForTraversal(int dir, int[] bounds) { // SYNC NOTE: see traverse() // We can just short circuit scrolling all together if // we know our view is smaller than the viewport if (view[HEIGHT] < viewport[HEIGHT]) { if (view[Y] > 0) { view[Y] = 0; return true; } return false; } // If the bounds are fully in our view, just return false if (bounds[Y] > view[Y] && (bounds[Y] + bounds[HEIGHT] < view[Y] + viewport[HEIGHT])) { return false; } else { if (SCROLLS_VERTICAL) { if (bounds[HEIGHT] > viewport[HEIGHT]) { if (dir == Canvas.DOWN || dir == Canvas.LEFT || dir == CustomItem.NONE) { view[Y] = bounds[Y] - CELL_SPACING; } else if (dir == Canvas.UP || dir == Canvas.RIGHT) { view[Y] = bounds[Y] + bounds[HEIGHT] + CELL_SPACING - viewport[HEIGHT]; } } else { if (dir == Canvas.DOWN || dir == Canvas.LEFT || dir == CustomItem.NONE) { view[Y] = bounds[Y] + bounds[HEIGHT] + CELL_SPACING - viewport[HEIGHT]; } else if (dir == Canvas.UP || dir == Canvas.RIGHT) { view[Y] = bounds[Y] - CELL_SPACING; } } if ((view[Y] + viewport[HEIGHT]) > view[HEIGHT]) { view[Y] = view[HEIGHT] - viewport[HEIGHT]; } if (view[Y] < 0) { view[Y] = 0; } return true; } else if (SCROLLS_HORIZONTAL) { // Not supported } } return false; } /** * Layout the contents of this Form, and call super.layout() to layout * the contents of the parent Screen or Displayable */ void layout() { // SYNC NOTE: layout() is always called from within a hold // on LCDUILock super.layout(); // If we don't have any Items, just return if (numOfItems == 0) { return; } // The index of the first Item in the horizontal row int rowStart = 0; // The 'viewable' represents the viewpane. It starts out life 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 if (viewable == null) { viewable = new int[4]; } // 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. // View'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. if (numOfItems > 1) { viewable[X] = CELL_SPACING; viewable[Y] = CELL_SPACING; viewable[WIDTH] = viewport[WIDTH] - CELL_SPACING; viewable[HEIGHT] = viewport[HEIGHT] - CELL_SPACING; view[WIDTH] = viewable[WIDTH] - CELL_SPACING; view[HEIGHT] = CELL_SPACING; } else { viewable[X] = 1; viewable[Y] = 1; viewable[WIDTH] = viewport[WIDTH] - 1; viewable[HEIGHT] = viewport[HEIGHT] - 1; view[WIDTH] = viewable[WIDTH] - 1; view[HEIGHT] = 1; } // A running variable which maintains the height of the // tallest item on a line int lineHeight = 0; int pW, pH; // We loop through all the Items. NTS: we may be able to improve // this given we know which Item called invalidate()f; for (int index = 0; index < numOfItems; index++) { // If the Item can be shrunken, get its minimum width, // and its preferred if it is not if (items[index].shouldHShrink()) { pW = items[index].callMinimumWidth(); } else { if (items[index].lockedWidth != -1) { pW = items[index].lockedWidth; } else { // if height is locked default preferred width // will be used, otherwise width will be calculated // based on lockedHeight pW = items[index].callPreferredWidth( items[index].lockedHeight); } } // We have a notion of the maximum allowable width an Item can // have, so we enforce it first here: if (!SCROLLS_HORIZONTAL && (pW > view[WIDTH])) { pW = view[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 && items[index - 1].equateNLA()); newLine = (newLine || items[index].equateNLB()); newLine = (newLine || (pW > (viewable[WIDTH] - CELL_SPACING))); // We linebreak if there is an existing row if (newLine && (lineHeight > 0)) { // First, handle current row's layout directives try { lineHeight = layoutRowHorizontal(rowStart, index - 1,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -