1 19 20 package org.netbeans.modules.form.layoutdesign; 21 22 import java.awt.Graphics2D ; 23 import java.awt.Stroke ; 24 import java.awt.BasicStroke ; 25 import java.util.*; 26 27 52 53 class LayoutDragger implements LayoutConstants { 54 55 private VisualMapper visualMapper; 56 57 59 private int operation; 61 private static final int ADDING = 0; 62 private static final int MOVING = 1; 63 private static final int RESIZING = 2; 64 65 private LayoutComponent[] movingComponents; 67 68 private int movingEdges[]; 74 77 private LayoutRegion[] movingFormation; 79 80 private int[] startCursorPosition; 82 83 private SizeDef[] sizing; 84 85 87 private int[] lastCursorPosition = new int[] { LayoutRegion.UNKNOWN, LayoutRegion.UNKNOWN }; 89 90 private int[] moveDirection = new int[] { LEADING, LEADING }; 92 93 private int lockedDimension = -1; 95 96 private LayoutComponent targetContainer; 98 99 private LayoutRegion[] movingBounds; 101 102 private PositionDef[] bestPositions = new PositionDef[DIM_COUNT]; 104 105 private boolean canSnapToBaseline; 108 113 private LayoutRegion movingSpace; 114 private int dimension; 115 private boolean snapping; 116 117 private PositionDef[][] findingsNextTo; 119 private PositionDef[][] findingsAligned; 120 121 123 static final int[] ALL_EDGES = { LayoutRegion.ALL_POINTS, 124 LayoutRegion.ALL_POINTS }; 125 126 private static final int GL_TIP = 8; 128 129 private static final int SNAP_DISTANCE = 8; 131 132 private static final int ORT_DISTANCE = 8; 134 135 private static BasicStroke dashedStroke = new BasicStroke (1.0f, BasicStroke.CAP_BUTT, 136 BasicStroke.JOIN_MITER, 5.0f, new float[]{5.0f, 2.0f}, 0.0f); 137 138 141 LayoutDragger(LayoutComponent[] comps, 142 LayoutRegion[] compBounds, 143 int[] initialCursorPos, 144 int[] movingEdges, 145 VisualMapper mapper) 146 { 147 for (int i=0; i < DIM_COUNT; i++) { 148 if (movingEdges[i] == LEADING || movingEdges[i] == TRAILING) { 149 operation = RESIZING; 150 break; 151 } 152 } 153 if (operation != RESIZING) { 154 operation = comps[0].getParent() == null ? ADDING : MOVING; 155 } 156 157 this.movingComponents = comps; 158 this.movingFormation = compBounds; 159 this.startCursorPosition = initialCursorPos; 160 this.movingEdges = movingEdges; 161 visualMapper = mapper; 162 163 movingBounds = new LayoutRegion[compBounds.length]; 164 movingSpace = new LayoutRegion(); 165 for (int i=0; i < compBounds.length; i++) { 166 movingBounds[i] = new LayoutRegion(); 167 movingSpace.expand(compBounds[i]); 168 } 169 170 LayoutInterval parent = comps[0].getLayoutInterval(VERTICAL).getParent(); 172 for (int i=0; i < comps.length; i++) { 173 if (comps[i].getLayoutInterval(VERTICAL).getParent() != parent) { 174 parent = null; 175 break; 176 } 177 } 178 canSnapToBaseline = (comps.length == 1) || ((parent != null) && (parent.getGroupAlignment() == BASELINE)); 179 180 findingsNextTo = new PositionDef[DIM_COUNT][]; 181 findingsAligned = new PositionDef[DIM_COUNT][]; 182 for (int i=0; i < DIM_COUNT; i++) { 183 int n = LayoutRegion.POINT_COUNT[i]; 184 findingsNextTo[i] = new PositionDef[n]; 185 findingsAligned[i] = new PositionDef[n]; 186 for (int j=0; j < n; j++) { 187 findingsNextTo[i][j] = new PositionDef(); 188 findingsAligned[i][j] = new PositionDef(); 189 } 190 } 191 192 if (operation == RESIZING) { 193 prepareResizing(); 194 } 195 } 196 197 private void prepareResizing() { 198 sizing = new SizeDef[DIM_COUNT]; 199 LayoutComponent comp = movingComponents[0]; LayoutRegion space = movingFormation[0]; 201 java.awt.Dimension prefSize = null; 202 for (int i=0; i < DIM_COUNT; i++) { 203 if (isResizing(i)) { 204 SizeDef sizeDef = new SizeDef(); 205 sizing[i] = sizeDef; 206 sizeDef.originalSize = space.size(i); 207 if (comp.isLayoutContainer()) { 208 LayoutInterval resGap = findResizingGap(comp.getLayoutRoot(i)); 209 if (resGap != null) { 210 sizeDef.resizingGap = resGap; 211 sizeDef.originalGapSize = LayoutInterval.getIntervalCurrentSize(resGap, i); 212 sizeDef.preferredGapSize = LayoutUtils.getSizeOfDefaultGap(resGap, visualMapper); 213 sizeDef.preferredSize = sizeDef.originalSize 214 - sizeDef.originalGapSize + sizeDef.preferredGapSize; 215 sizeDef.zeroPreferredSize = isZeroResizingGap(resGap) ? 216 sizeDef.originalSize - sizeDef.originalGapSize : Short.MIN_VALUE; 217 } 218 else { 219 if (prefSize == null) { 220 prefSize = visualMapper.getComponentMinimumSize(comp.getId()); 221 } 222 sizeDef.preferredSize = i == HORIZONTAL ? prefSize.width : prefSize.height; 223 } 224 } 225 else { 226 if (prefSize == null) { 227 prefSize = visualMapper.getComponentPreferredSize(comp.getId()); 228 } 229 sizeDef.preferredSize = i == HORIZONTAL ? prefSize.width : prefSize.height; 230 } 231 } 232 } 233 } 234 235 private LayoutInterval findResizingGap(LayoutInterval group) { 236 for (Iterator it=group.getSubIntervals(); it.hasNext(); ) { 237 LayoutInterval li = (LayoutInterval) it.next(); 238 if (li.isEmptySpace() && li.hasAttribute(LayoutInterval.ATTR_DESIGN_CONTAINER_GAP)) { 239 return li; 240 } 241 else if (li.isGroup()) { 242 LayoutInterval gap = findResizingGap(li); 243 if (gap != null) { 244 return gap; 245 } 246 } 247 } 248 return null; 249 } 250 251 private static boolean isZeroResizingGap(LayoutInterval gap) { 252 return LayoutInterval.getNeighbor(gap, LEADING, false, true, false) == null 253 || LayoutInterval.getNeighbor(gap, TRAILING, false, true, false) == null; 254 } 255 256 void setTargetContainer(LayoutComponent container) { 257 targetContainer = container; 258 } 259 260 LayoutComponent getTargetContainer() { 261 return targetContainer; 262 } 263 264 boolean isResizing() { 265 return operation == RESIZING; 266 } 267 268 boolean isResizing(int dim) { 269 return movingEdges[dim] == LEADING || movingEdges[dim] == TRAILING; 270 } 271 272 int getResizingEdge(int dim) { 273 return movingEdges[dim]; 274 } 275 276 LayoutComponent[] getMovingComponents() { 277 return movingComponents; 278 } 279 280 VisualMapper getVisualMapper() { 281 return visualMapper; 282 } 283 284 287 LayoutRegion[] getMovingBounds() { 288 return movingBounds; 289 } 290 291 LayoutRegion getMovingSpace() { 292 return movingSpace; 293 } 294 295 PositionDef[] getPositions() { 296 305 return bestPositions; 306 } 307 308 SizeDef[] getSizes() { 309 return sizing; 310 } 311 312 boolean snappedToDefaultSize(int dimension) { 313 if (isResizing(dimension) && bestPositions[dimension] == null) { 314 int size = movingSpace.size(dimension); 315 return size == sizing[dimension].preferredSize 316 || size == sizing[dimension].zeroPreferredSize; 317 } 318 return false; 319 } 320 321 324 void move(int[] cursorPos, boolean autoPositioning, boolean lockDimension) { 325 int lockCandidate = -1; int minDelta = Integer.MAX_VALUE; 328 for (int i=0; i < DIM_COUNT; i++) { 329 cursorPos[i] -= startCursorPosition[i]; int currentPos = cursorPos[i]; 331 int lastPos = lastCursorPosition[i]; 332 lastCursorPosition[i] = currentPos; 333 if (lastPos == LayoutRegion.UNKNOWN) { lockDimension = false; } 336 else { 337 int delta = currentPos - lastPos; 338 if (delta != 0) { moveDirection[i] = delta > 0 ? TRAILING : LEADING; 340 } 341 if (movingEdges[i] != LayoutRegion.ALL_POINTS) { 342 lockDimension = false; } 344 else if (lockedDimension < 0) { PositionDef pos = bestPositions[i]; 346 if (pos != null && !pos.nextTo && delta < minDelta) { 347 lockCandidate = i; 348 minDelta = delta; 349 } 350 } 351 } 352 } 353 354 if (lockDimension) { 356 if (lockedDimension < 0) { lockedDimension = lockCandidate; 358 } 359 } 360 else lockedDimension = -1; 361 362 for (int i=0; i < movingBounds.length; i++) { 364 for (int j=0; j < DIM_COUNT; j++) { 365 if (j != lockedDimension) { 366 movingBounds[i].set(j, movingFormation[i]); 367 movingBounds[i].reshape(j, movingEdges[j], cursorPos[j]); 368 } 369 } 371 } 372 movingSpace = new LayoutRegion(); 373 for (int i=0; i<movingBounds.length; i++) { 374 movingSpace.expand(movingBounds[i]); 375 } 376 if (canSnapToBaseline) { movingSpace.positions[VERTICAL][BASELINE] = movingBounds[0].positions[VERTICAL][BASELINE]; 378 } 379 380 for (int i=0; i < DIM_COUNT; i++) { 382 if (i != lockedDimension) { 383 bestPositions[i] = null; 384 for (int j=0; j < LayoutRegion.POINT_COUNT[i]; j++) { 385 findingsNextTo[i][j].reset(); 386 findingsAligned[i][j].reset(); 387 } 388 } 389 } 390 391 snapping = autoPositioning; 393 if (autoPositioning) { 394 for (dimension=DIM_COUNT-1; dimension >= 0; dimension--) { 396 if (dimension != lockedDimension 397 && movingEdges[dimension] != LayoutRegion.NO_POINT) 398 { int snapDistance = findBestPosition(); 400 if (snapDistance != LayoutRegion.UNKNOWN) { 402 cursorPos[dimension] -= snapDistance; 403 for (int i=0; i<movingBounds.length; i++) { 404 movingBounds[i].reshape(dimension, 405 movingEdges[dimension], 406 -snapDistance); 407 } 408 movingSpace.reshape(dimension, 409 movingEdges[dimension], 410 -snapDistance); 411 } 412 } 413 } 414 } 415 416 for (int i=0; i < DIM_COUNT; i++) { 418 cursorPos[i] += startCursorPosition[i]; 419 } 420 } 421 422 void paintMoveFeedback(Graphics2D g) { 423 final int OVERLAP = 10; 424 for (int i=0; i < DIM_COUNT; i++) { 425 LayoutDragger.PositionDef position = bestPositions[i]; 426 if (position != null) { 427 boolean inRoot = (position.interval.getParent() == null); 428 int dir = 1-i; int align = position.alignment; 430 LayoutInterval interval = position.interval; 431 LayoutInterval parent = interval.getParent(); 432 boolean parentUsed; 433 do { 434 parentUsed = false; 435 if (parent != null && parent.isParallel()) { 436 if (align == LEADING || align == TRAILING) { 438 LayoutRegion parRegion = parent.getCurrentSpace(); 439 if (!position.nextTo 440 && LayoutRegion.distance(parRegion, movingSpace, i, align, align) == 0) 441 { 442 parentUsed = true; 443 } 444 } 445 else if (align == parent.getGroupAlignment()) { 446 parentUsed = true; 447 } 448 } 449 if (parentUsed) { 450 interval = parent; 451 parent = LayoutInterval.getFirstParent(parent, PARALLEL); 452 } 453 } while (parentUsed); 454 LayoutRegion posRegion = interval.getCurrentSpace(); 455 LayoutRegion contRegion = targetContainer.getLayoutRoot(0).getCurrentSpace(); 456 int conty1 = contRegion.positions[dir][LEADING]; 457 int conty2 = contRegion.positions[dir][TRAILING]; 458 int posx = posRegion.positions[i][(inRoot || !position.nextTo) ? align : 1-align]; 459 int posy1 = posRegion.positions[dir][LEADING]-OVERLAP; 460 posy1 = Math.max(posy1, conty1); 461 int posy2 = posRegion.positions[dir][TRAILING]+OVERLAP; 462 posy2 = Math.min(posy2, conty2); 463 int x = movingSpace.positions[i][align]; 464 int y1 = movingSpace.positions[dir][LEADING]-OVERLAP; 465 y1 = Math.max(y1, conty1); 466 int y2 = movingSpace.positions[dir][TRAILING]+OVERLAP; 467 y2 = Math.min(y2, conty2); 468 Stroke oldStroke = g.getStroke(); 469 g.setStroke(dashedStroke); 470 if (position.nextTo) { if (i == HORIZONTAL) { 472 g.drawLine(x, Math.min(y1, posy1), x, Math.max(y2, posy2)); 473 } else { 474 g.drawLine(Math.min(y1, posy1), x, Math.max(y2, posy2), x); 475 } 476 } else { if (x == posx) { 480 if (i == HORIZONTAL) { 481 g.drawLine(posx, Math.min(y1, posy1), posx, Math.max(y2, posy2)); 482 } else { 483 g.drawLine(Math.min(y1, posy1), posx, Math.max(y2, posy2), posx); 484 } 485 } 486 else { if (i == HORIZONTAL) { 488 g.drawLine(posx, posy1, posx, posy2); 489 g.drawLine(x, y1, x, y2); 490 } 491 else { 492 g.drawLine(posy1, posx, posy2, posx); 493 g.drawLine(y1, x, y2, x); 494 } 495 } 496 } 497 g.setStroke(oldStroke); 498 } 499 else if (snappedToDefaultSize(i)) { int align = movingEdges[i]; 501 int x1 = movingSpace.positions[i][align]; 502 int x2 = movingSpace.positions[i][align^1]; 503 int y = movingSpace.positions[i^1][CENTER]; 504 Stroke oldStroke = g.getStroke(); 505 g.setStroke(dashedStroke); 506 if (i == HORIZONTAL) { 507 g.drawLine(x1, y, x2, y); 508 } 509 else { 510 g.drawLine(y, x1, y, x2); 511 } 512 g.setStroke(oldStroke); 513 } 514 } 515 } 516 517 String [] positionCode() { 518 String [] code = new String [DIM_COUNT]; 519 for (int i=0; i < DIM_COUNT; i++) { 520 LayoutDragger.PositionDef position = bestPositions[i]; 521 if (position != null) { 522 int alignment = position.alignment; 523 if (position.nextTo) { code[i] = "nextTo" + dimensionCode(i) + alignmentCode(alignment); } else { int x = movingSpace.positions[i][alignment]; 527 int posx = position.interval.getCurrentSpace().positions[i][alignment]; 528 if (x == posx) { 529 code[i] = "align" + dimensionCode(i) + alignmentCode(alignment); } else { 531 code[i] = "indent"; } 533 } 534 } else if (snappedToDefaultSize(i)) { 535 code[i] = "snappedToDefault" + dimensionCode(i); } 537 } 538 if (code[0] == null) { 539 code[0] = code[1]; 540 code[1] = null; 541 } 542 if (code[0] == null) { 543 code[0] = isResizing() ? "generalResizing" : "generalPosition"; } 545 return code; 546 } 547 548 private static String dimensionCode(int dim) { 549 return (dim == HORIZONTAL) ? "Horizontal" : "Vertical"; } 551 552 private static String alignmentCode(int alignment) { 553 String code = null; 554 switch (alignment) { 555 case LEADING: code = "Leading"; break; case TRAILING: code = "Trailing"; break; case BASELINE: code = "Baseline"; break; } 559 return code; 560 } 561 562 565 570 private int findBestPosition() { 571 PositionDef best; 572 int snapDistance = LayoutRegion.UNKNOWN; 573 574 if (targetContainer != null) { 575 PositionDef bestNextTo; 576 PositionDef bestAligned; 577 LayoutInterval layoutRoot = targetContainer.getLayoutRoot(dimension); 578 int edges = movingEdges[dimension]; 579 580 checkRootForNextTo(layoutRoot, edges); 585 scanLayoutForNextTo(layoutRoot, edges); 586 bestNextTo = chooseBestNextTo(); 587 588 if (snapping) { checkRootForAligned(layoutRoot, edges); 590 scanLayoutForAligned(layoutRoot, edges); 591 bestAligned = chooseBestAligned(); 592 } 593 else bestAligned = null; 594 595 if (bestAligned == null) { 597 best = bestNextTo; 598 } 599 else if (bestNextTo == null) { 600 best = bestAligned; 601 } 602 else { boolean preferredNextTo = isPreferredNextTo(bestNextTo, bestAligned); 604 int nextToDst = smallestDistance(findingsNextTo[dimension]); 605 int alignedDst = smallestDistance(findingsAligned[dimension]); 606 if (!relatedPositions(bestNextTo, bestAligned)) { 607 int alignedOrtDst = Math.abs(LayoutRegion.nonOverlapDistance( 609 bestAligned.interval.getCurrentSpace(), movingSpace, dimension ^ 1)); 610 alignedDst = getDistanceScore(alignedDst, alignedOrtDst); 611 } 612 if (preferredNextTo) { 613 best = alignedDst*2 <= nextToDst && nextToDst - alignedDst >= SNAP_DISTANCE/2 ? 614 bestAligned : bestNextTo; 615 } 616 else { 617 best = nextToDst*2 <= alignedDst && alignedDst - nextToDst >= SNAP_DISTANCE/2 ? 618 bestNextTo : bestAligned; 619 } 620 if (best == bestNextTo) { 621 PositionDef equalAligned = getAlignedEqualToNextTo(bestNextTo); 622 if (equalAligned != null) 623 best = equalAligned; 624 } 625 } 626 } 627 else { 628 best = null; 629 } 630 631 if (snapping) { 632 if (isResizing(dimension)) { 633 int prefSizeDiff = movingSpace.size(dimension) - sizing[dimension].preferredSize; 634 int zeroSizeDiff = movingSpace.size(dimension) - sizing[dimension].zeroPreferredSize; 635 int sizeDiff = Math.abs(prefSizeDiff) <= Math.abs(zeroSizeDiff) ? 636 prefSizeDiff : zeroSizeDiff; 637 int absDiff = Math.abs(sizeDiff); 638 if (absDiff < SNAP_DISTANCE && (best == null || absDiff < Math.abs(best.distance))) { 639 best = null; snapDistance = movingEdges[dimension] == LEADING ? -sizeDiff : sizeDiff; 641 } 642 } 643 if (best != null) { 644 snapDistance = best.distance; 645 } 646 } 647 648 bestPositions[dimension] = best; 649 return snapDistance; 650 } 651 652 660 private void checkRootForNextTo(LayoutInterval layoutRoot, int alignment) { 661 assert alignment == LayoutRegion.ALL_POINTS || alignment == LEADING || alignment == TRAILING; 662 663 if (operation == RESIZING && isValidNextToResizing(layoutRoot, alignment) != 1) 664 return; 665 666 LayoutRegion rootSpace = layoutRoot.getCurrentSpace(); 667 668 for (int i = LEADING; i <= TRAILING; i++) { 669 if (alignment == LayoutRegion.ALL_POINTS || alignment == i) { 670 int distance = LayoutRegion.distance(rootSpace, movingSpace, 671 dimension, i, i); 672 assert distance != LayoutRegion.UNKNOWN; 673 if (snapping) { 674 int pad = findPadding(null, movingComponents[0].getLayoutInterval(dimension), 676 dimension, i); distance += (i == LEADING ? -pad : pad); 678 } 679 680 if (!snapping || Math.abs(distance) < SNAP_DISTANCE) { 681 PositionDef bestSoFar = findingsNextTo[dimension][i]; 682 assert !bestSoFar.isSet(); 683 bestSoFar.interval = layoutRoot; 684 bestSoFar.alignment = i; 685 bestSoFar.distance = distance; 686 bestSoFar.nextTo = true; 687 bestSoFar.snapped = snapping && Math.abs(distance) < SNAP_DISTANCE; 688 } 689 } 690 } 691 } 692 693 702 private int scanLayoutForNextTo(LayoutInterval interval, int alignment) { 703 assert alignment == LayoutRegion.ALL_POINTS || alignment == LEADING || alignment == TRAILING; 704 705 int groupOuterAlignment = DEFAULT; 706 707 for (int idx=0, count=interval.getSubIntervalCount(); idx < count; idx++) { 708 LayoutInterval sub = interval.getSubInterval(idx); 709 if (sub.isEmptySpace()) { 710 continue; 711 } 712 713 if (!orthogonalOverlap(interval, idx)) 714 continue; 715 716 int nextToAlignment = DEFAULT; 717 718 if (sub.isComponent()) { 719 if (isValidInterval(sub) 720 && (operation != RESIZING || isValidNextToResizing(sub, alignment) == 1)) 721 { nextToAlignment = checkNextToPosition(sub, alignment); 723 } 724 } 725 else if (sub.isSequential()) { 726 nextToAlignment = scanLayoutForNextTo(sub, alignment); 727 } 728 else { boolean validForRef = isValidInterval(sub); 731 int validResizing = validForRef && operation == RESIZING ? 732 isValidNextToResizing(sub, alignment) : 1; 733 int subGroupOuterAlign; 734 735 if (validResizing != -1 && canGoInsideForNextTo(sub, validForRef)) { 736 int align = alignment; 737 for (int i = LEADING; i <= TRAILING; i++) { 738 if (alignment != LayoutRegion.ALL_POINTS && i != alignment) { 739 continue; } 741 int insideDst = LayoutRegion.distance(sub.getCurrentSpace(), movingSpace, dimension, i, i) 742 * (i == LEADING ? 1 : -1); 743 if (insideDst < -SNAP_DISTANCE) { 744 if (align == LayoutRegion.ALL_POINTS) 746 align = i ^ 1; 747 else 748 align = LayoutRegion.NO_POINT; 749 } 750 } 751 if (align != LayoutRegion.NO_POINT) { 752 subGroupOuterAlign = scanLayoutForNextTo(sub, align); 753 } 754 else subGroupOuterAlign = DEFAULT; 755 } 756 else subGroupOuterAlign = alignment; 757 758 if (validForRef && validResizing == 1 && subGroupOuterAlign != DEFAULT) { 759 nextToAlignment = checkNextToPosition(sub, subGroupOuterAlign); 760 } 761 } 762 763 if (nextToAlignment != DEFAULT) { 764 if (interval.isSequential()) { 765 if (groupOuterAlignment == DEFAULT && (idx == 0 || idx+1 == count)) { 767 if (idx != 0) { 768 nextToAlignment = nextToAlignment == TRAILING ? DEFAULT : LEADING; 769 } 770 else if (idx+1 != count) { 771 nextToAlignment = nextToAlignment == LEADING ? DEFAULT : TRAILING; 772 } 773 groupOuterAlignment = nextToAlignment; 774 } 775 } 776 else { 777 if (LayoutInterval.wantResize(sub)) { 780 if (nextToAlignment == LayoutRegion.ALL_POINTS) { 781 groupOuterAlignment = LayoutRegion.ALL_POINTS; } 783 else if (groupOuterAlignment == DEFAULT) { 784 groupOuterAlignment = nextToAlignment; } 786 } 787 else if ((nextToAlignment == LayoutRegion.ALL_POINTS 788 || (nextToAlignment^1) == sub.getAlignment()) 789 && groupOuterAlignment == DEFAULT) 790 { groupOuterAlignment = sub.getAlignment() ^ 1; 792 } 793 } 794 } 795 } 796 797 return groupOuterAlignment; 798 } 799 800 805 private boolean orthogonalOverlap(LayoutInterval interval, int index) { 806 LayoutInterval sub = interval.getSubInterval(index); 807 LayoutRegion subSpace = sub.getCurrentSpace(); 808 if (LayoutRegion.overlap(movingSpace, subSpace, dimension^1, 0)) 809 return true; 810 811 if (dimension == VERTICAL) { if (sub.isSequential()) return true; 814 815 if (interval.getParent() != null && interval.getParent().getSubIntervalCount() > 1) 818 return false; 819 820 if (!LayoutRegion.overlap(movingSpace, interval.getCurrentSpace(), dimension, 0)) 821 return true; if (interval.isSequential()) { 823 if (LayoutRegion.distance(movingSpace, subSpace, dimension, TRAILING, LEADING) > 0) { 825 while (--index >= 0) { 827 LayoutInterval li = interval.getSubInterval(index); 828 if (!li.isEmptySpace() && isValidInterval(li)) 829 break; 830 } 831 if (index < 0) return true; 833 } 834 else if (LayoutRegion.distance(subSpace, movingSpace, dimension, TRAILING, LEADING) > 0) { 835 while (++index < interval.getSubIntervalCount()) { 837 LayoutInterval li = interval.getSubInterval(index); 838 if (!li.isEmptySpace() && isValidInterval(li)) 839 break; 840 } 841 if (index == interval.getSubIntervalCount()) return true; 843 } 844 } 845 } 846 847 return false; 848 } 849 850 private int checkNextToPosition(LayoutInterval sub, int alignment) { 851 int nextToAlignment = DEFAULT; 852 LayoutRegion subSpace = sub.getCurrentSpace(); 853 for (int i = LEADING; i <= TRAILING; i++) { 854 if (alignment != LayoutRegion.ALL_POINTS && i != alignment) 855 continue; 857 boolean validDistance; 858 int distance = LayoutRegion.distance(subSpace, movingSpace, 859 dimension, i^1, i); 860 if (snapping) { 861 int pad = findPadding(sub, movingComponents[0].getLayoutInterval(dimension), 863 dimension, i); distance += (i == LEADING ? -pad : pad); 865 validDistance = Math.abs(distance) < SNAP_DISTANCE; 866 } 867 else { 868 validDistance = (i == LEADING ? distance > 0 : distance < 0); 869 } 870 if (validDistance) { 871 nextToAlignment = nextToAlignment == DEFAULT ? i : LayoutRegion.ALL_POINTS; 872 873 PositionDef bestSoFar = findingsNextTo[dimension][i]; 874 if (!bestSoFar.isSet() || compareNextToPosition(sub, distance, bestSoFar) > 0) { 875 bestSoFar.interval = sub; 876 bestSoFar.alignment = i; 877 bestSoFar.distance = distance; 878 bestSoFar.nextTo = true; 879 bestSoFar.snapped = snapping; 880 } 881 } 882 } 883 return nextToAlignment; 884 } 885 886 893 private int compareNextToPosition(LayoutInterval newInterval, int newDistance, 894 PositionDef bestSoFar) 895 { 896 if (!bestSoFar.isSet()) 897 return 1; 899 LayoutRegion newSpace = newInterval.getCurrentSpace(); 900 LayoutRegion oldSpace = bestSoFar.interval.getCurrentSpace(); 901 int oldDistance = Math.abs(bestSoFar.distance); 902 903 if (newDistance < 0) 905 newDistance = -newDistance; 906 if (newDistance != oldDistance) { 907 return newDistance < oldDistance ? 1 : -1; 908 } 909 910 if (newInterval.isParentOf(bestSoFar.interval)) { 911 return 1; 912 } 913 914 int newOrtDst = Math.abs( 916 LayoutRegion.minDistance(newSpace, movingSpace, dimension ^ 1)); 917 int oldOrtDst = Math.abs( 918 LayoutRegion.minDistance(oldSpace, movingSpace, dimension ^ 1)); 919 if (newOrtDst != oldOrtDst) { 920 return newOrtDst < oldOrtDst ? 1 : -1; 921 } 922 923 return 0; 924 } 925 926 private static boolean canGoInsideForNextTo(LayoutInterval subGroup, boolean valid) { 927 return subGroup.isSequential() 931 || (subGroup.isParallel() 932 && (!valid 933 || (subGroup.getGroupAlignment() != CENTER 934 && subGroup.getGroupAlignment() != BASELINE))); 935 } 936 937 945 private void checkRootForAligned(LayoutInterval layoutRoot, int alignment) { 946 assert alignment == LayoutRegion.ALL_POINTS || alignment == LEADING || alignment == TRAILING; 947 948 if (operation == RESIZING && !isValidAlignedResizing(layoutRoot, alignment)) 949 return; 950 951 LayoutRegion rootSpace = layoutRoot.getCurrentSpace(); 952 953 for (int i = LEADING; i <= TRAILING; i++) { 954 if (alignment == LayoutRegion.ALL_POINTS || alignment == i) { 955 int distance = LayoutRegion.distance(rootSpace, movingSpace, 956 dimension, i, i); 957 if (distance != LayoutRegion.UNKNOWN 958 && Math.abs(distance) < SNAP_DISTANCE) 959 { PositionDef bestSoFar = findingsAligned[dimension][i]; 961 assert !bestSoFar.isSet(); 962 bestSoFar.interval = layoutRoot; 963 bestSoFar.alignment = i; 964 bestSoFar.distance = distance; 965 bestSoFar.nextTo = false; 966 bestSoFar.snapped = true; 967 } 968 } 969 } 970 } 971 972 978 private void scanLayoutForAligned(LayoutInterval interval, int alignment) { 979 assert alignment == LayoutRegion.ALL_POINTS || alignment == LEADING || alignment == TRAILING; 980 981 Iterator it = interval.getSubIntervals(); 982 while (it.hasNext()) { 983 LayoutInterval sub = (LayoutInterval) it.next(); 984 if (sub.isEmptySpace()) 985 continue; 986 987 if (sub.isComponent() 988 && isValidInterval(sub) 989 && (operation != RESIZING || isValidAlignedResizing(sub, alignment))) 990 { for (int i=0; i < LayoutRegion.POINT_COUNT[dimension]; i++) { 993 if (alignment == LayoutRegion.ALL_POINTS || i == alignment) { 994 int indentedDst = getIndentedDistance(sub, i); 995 int directDst = getDirectDistance(sub, i); 996 int distance = Math.abs(indentedDst) < Math.abs(directDst) ? 997 indentedDst : directDst; 998 if (checkAlignedDistance(distance, sub.getCurrentSpace(), i)) { 999 PositionDef bestSoFar = findingsAligned[dimension][i]; 1001 if (compareAlignedPosition(sub, distance, bestSoFar) >= 0) { 1002 bestSoFar.interval = sub; 1004 bestSoFar.alignment = i; 1005 bestSoFar.distance = distance; 1006 bestSoFar.nextTo = false; 1007 bestSoFar.snapped = true; 1008 } 1009 } 1010 } 1011 } 1012 } 1013 1014 if (sub.getSubIntervalCount() > 0 1015 && LayoutRegion.overlap(sub.getCurrentSpace(), movingSpace, dimension, SNAP_DISTANCE/2)) 1016 { scanLayoutForAligned(sub, alignment); 1018 } 1019 } 1020 } 1021 1022 private int getIndentedDistance(LayoutInterval interval, int alignment) { 1023 if (dimension == HORIZONTAL && alignment == LEADING) { 1024 LayoutRegion examinedSpace = interval.getCurrentSpace(); 1026 int verticalDst = LayoutRegion.distance(examinedSpace, movingSpace, 1027 VERTICAL, TRAILING, LEADING); 1028 if (verticalDst >= 0 && verticalDst < 2 * SNAP_DISTANCE) { 1029 int indent = findIndent(interval.getComponent(), movingComponents[0], 1031 dimension, alignment); 1032 if (indent > 0) { 1033 return LayoutRegion.distance(examinedSpace, movingSpace, 1034 dimension, alignment, alignment) 1035 - indent; 1036 } 1037 } 1038 } 1039 return Integer.MAX_VALUE; 1040 } 1041 1042 private int getDirectDistance(LayoutInterval interval, int alignment) { 1043 return checkValidAlignment(interval, alignment) ? 1044 LayoutRegion.distance(interval.getCurrentSpace(), movingSpace, 1045 dimension, alignment, alignment) : 1046 Integer.MAX_VALUE; 1047 } 1048 1049 private boolean checkValidAlignment(LayoutInterval interval, int alignment) { 1050 int presentAlign = interval.getAlignment(); 1051 if (presentAlign != DEFAULT) { 1053 boolean lastOne = true; 1054 Iterator it = interval.getParent().getSubIntervals(); 1055 while (it.hasNext()) { 1056 LayoutInterval li = (LayoutInterval) it.next(); 1057 if (li != interval && isValidInterval(li)) { 1058 lastOne = false; 1059 break; 1060 } 1061 } 1062 if (lastOne) { 1063 presentAlign = DEFAULT; 1064 } 1065 } 1066 1067 if (alignment == LEADING || alignment == TRAILING) { 1068 if (presentAlign == CENTER || presentAlign == BASELINE) 1070 return false; 1071 } 1072 else if (alignment == CENTER) { 1073 if (presentAlign != CENTER) 1076 return false; 1077 } 1078 else if (alignment == BASELINE) { 1079 if (presentAlign == CENTER) 1081 return false; 1082 } 1083 return true; 1084 } 1085 1086 private boolean checkAlignedDistance(int distance, LayoutRegion examinedSpace, int alignment) { 1087 if (distance != LayoutRegion.UNKNOWN && Math.abs(distance) < SNAP_DISTANCE) { 1088 int x1, x2, y1, y2; 1090 int indent = movingSpace.positions[dimension][alignment] 1091 - examinedSpace.positions[dimension][alignment] - distance; 1092 if (indent == 0) { 1093 x1 = examinedSpace.positions[dimension][alignment] - SNAP_DISTANCE/2; 1094 x2 = examinedSpace.positions[dimension][alignment] + SNAP_DISTANCE/2; 1095 y2 = movingSpace.positions[dimension^1][LEADING]; 1096 } 1097 else { 1098 x1 = examinedSpace.positions[dimension][alignment]; 1099 x2 = x1 + indent + SNAP_DISTANCE/2; 1100 y2 = movingSpace.positions[dimension^1][TRAILING]; 1101 } 1104 y1 = examinedSpace.positions[dimension^1][TRAILING]; 1105 if (y1 > y2) { 1106 y1 = movingSpace.positions[dimension^1][TRAILING]; 1107 y2 = examinedSpace.positions[dimension^1][LEADING]; 1108 if (y1 > y2) { return true; 1110 } 1111 } 1112 return !contentOverlap(targetContainer.getLayoutRoot(dimension), 1113 x1, x2, y1, y2, dimension); 1114 } 1115 return false; 1116 } 1117 1118 private boolean contentOverlap(LayoutInterval group, int x1, int x2, int y1, int y2, int dim) { 1119 int[][] groupPos = group.getCurrentSpace().positions; 1120 for (int i=0, n=group.getSubIntervalCount(); i < n; i++) { 1121 LayoutInterval li = group.getSubInterval(i); 1122 int _x1, _x2, _y1, _y2; 1123 if (li.isEmptySpace()) { 1124 if (group.isParallel()) 1125 continue; 1126 _x1 = i == 0 ? groupPos[dim][LEADING] : 1127 group.getSubInterval(i-1).getCurrentSpace().positions[dim][TRAILING]; 1128 _x2 = i+1 == n ? groupPos[dim][TRAILING] : 1129 group.getSubInterval(i+1).getCurrentSpace().positions[dim][LEADING]; 1130 _y1 = groupPos[dim^1][LEADING]; 1131 _y2 = groupPos[dim^1][TRAILING]; 1132 if (_y1 < y1) { 1133 _y2 = _y1; 1134 } 1135 else if (_y2 > y2) { 1136 _y1 = _y2; 1137 } 1138 } 1139 else { 1140 int[][] positions = li.getCurrentSpace().positions; 1141 _x1 = positions[dim][LEADING]; 1142 _x2 = positions[dim][TRAILING]; 1143 _y1 = positions[dim^1][LEADING]; 1144 _y2 = positions[dim^1][TRAILING]; 1145 } 1146 1147 if (_x1 < x2 && _x2 > x1 && _y1 < y2 && _y2 > y1) { if (li.isComponent()) { 1149 if (isValidInterval(li)) 1150 return true; 1151 } 1152 else if (li.isEmptySpace()) { 1153 if (i > 0 && i+1 < n && (li.getMinimumSize() == NOT_EXPLICITLY_DEFINED || li.getMinimumSize() == USE_PREFERRED_SIZE) 1155 && li.getPreferredSize() == NOT_EXPLICITLY_DEFINED 1156 && (li.getMaximumSize() == NOT_EXPLICITLY_DEFINED || li.getMaximumSize() == USE_PREFERRED_SIZE)) 1157 { LayoutInterval prev = group.getSubInterval(i-1); 1159 LayoutInterval next = group.getSubInterval(i+1); 1160 if ((!prev.isComponent() || isValidInterval(prev)) 1161 && (!next.isComponent() || isValidInterval(next))) 1162 { return true; 1164 } 1165 } 1166 if (_x1 >= x1 && _x2 <= x2) 1167 return false; } 1169 else if (li.isGroup() && contentOverlap(li, x1, x2, y1, y2, dim)) { 1170 return true; 1171 } 1172 } 1173 } 1174 return false; 1175 } 1176 1177 1182 private int compareAlignedPosition(LayoutInterval newInterval, 1183 int newDistance, 1184 PositionDef bestSoFar) 1185 { 1186 if (!bestSoFar.isSet()) 1187 return 1; 1189 if (newDistance < 0) 1191 newDistance = -newDistance; 1192 int oldDistance = Math.abs(bestSoFar.distance); 1193 1194 if (newInterval.getParent() == null) { 1195 return newDistance < oldDistance ? 1 : -1; 1196 } 1197 if (bestSoFar.interval.getParent() == null) { 1198 return oldDistance < newDistance ? -1 : 1; 1199 } 1200 1201 LayoutRegion newSpace = newInterval.getCurrentSpace(); 1203 LayoutRegion oldSpace = bestSoFar.interval.getCurrentSpace(); 1204 int newOrtDst = Math.abs( 1205 LayoutRegion.nonOverlapDistance(newSpace, movingSpace, dimension ^ 1)); 1206 int oldOrtDst = Math.abs( 1207 LayoutRegion.nonOverlapDistance(oldSpace, movingSpace, dimension ^ 1)); 1208 1209 int newScore = getDistanceScore(newDistance, newOrtDst); 1211 int oldScore = getDistanceScore(oldDistance, oldOrtDst); 1212 1213 if (newScore != oldScore) { 1214 return newScore < oldScore ? 1 : -1; 1215 } 1216 return 0; 1217 } 1218 1219 private static int getDistanceScore(int directDistance, int ortDistance) { 1220 return directDistance + ortDistance / SNAP_DISTANCE; 1222 } 1223 1224 private PositionDef chooseBestNextTo() { 1225 PositionDef[] positions = findingsNextTo[dimension]; 1226 PositionDef bestPos = null; 1227 int bestDst = 0; 1228 for (int i=0; i < positions.length; i++) { 1229 PositionDef pos = positions[i]; 1230 if (pos.isSet()) { 1231 int dst = Math.abs(pos.distance); 1232 if (bestPos == null || dst < bestDst 1233 || (dst == bestDst && moveDirection[dimension] == i)) { 1234 bestPos = pos; 1235 bestDst = dst; 1236 } 1237 } 1238 } 1239 return bestPos; 1240 } 1241 1242 private PositionDef chooseBestAligned() { 1243 PositionDef[] positions = findingsAligned[dimension]; 1244 PositionDef bestPos = null; 1245 for (int i=positions.length-1; i >= 0; i--) { 1246 PositionDef pos = positions[i]; 1247 if (pos.isSet()) { 1248 if (i == BASELINE || i == CENTER) { 1249 return pos; 1250 } 1251 if (bestPos == null) { 1252 bestPos = pos; 1253 } 1254 else { 1255 int c = compareAlignedPosition(pos.interval, pos.distance, bestPos); 1256 if (c == 0) { 1257 c = compareAlignedDirection(pos, bestPos); 1258 } 1259 if (c > 0) { bestPos = pos; 1261 } 1262 } 1263 } 1264 } 1265 return bestPos; 1266 } 1267 1268 private int compareAlignedDirection(PositionDef pos1, PositionDef pos2) { 1269 boolean p1 = isSuitableAlignment(pos1); 1270 boolean p2 = isSuitableAlignment(pos2); 1271 if (p1 == p2) { 1272 p1 = (pos1.alignment == moveDirection[dimension]); 1273 p2 = (pos2.alignment == moveDirection[dimension]); 1274 if (p1 == p2) 1275 return 0; 1276 } 1277 return p1 ? 1 : -1; 1278 } 1279 1280 private static boolean isSuitableAlignment(PositionDef pos) { 1281 assert pos.alignment == LEADING || pos.alignment == TRAILING; 1282 LayoutInterval parParent = LayoutInterval.getFirstParent(pos.interval, PARALLEL); 1283 return LayoutInterval.isAlignedAtBorder(pos.interval, parParent, pos.alignment) 1284 || !LayoutInterval.isAlignedAtBorder(pos.interval, parParent, pos.alignment^1); 1285 } 1286 1287 private static int smallestDistance(PositionDef[] positions) { 1288 int bestDst = -1; 1289 for (int i=0; i < positions.length; i++) { 1290 PositionDef pos = positions[i]; 1291 if (pos.isSet()) { 1292 int dst = Math.abs(pos.distance); 1293 if (bestDst < 0 || dst < bestDst) { 1294 bestDst = dst; 1295 } 1296 } 1297 } 1298 return bestDst; 1299 } 1300 1301 private boolean isPreferredNextTo(PositionDef bestNextTo, PositionDef bestAligned) { 1302 if (bestNextTo != null && bestAligned != null) { 1303 if (operation == RESIZING) { 1304 LayoutInterval resizing = movingComponents[0].getLayoutInterval(dimension); 1307 int fixedEdge = movingEdges[dimension] ^ 1; 1308 if (bestAligned.interval.isParentOf(resizing)) { 1309 if (LayoutInterval.isAlignedAtBorder(resizing, bestAligned.interval, fixedEdge)) { 1310 return false; 1311 } 1312 } 1313 else { 1314 LayoutInterval commonParent = LayoutInterval.getCommonParent(resizing, bestAligned.interval); 1315 if (LayoutInterval.isAlignedAtBorder(resizing, commonParent, fixedEdge) 1316 && LayoutInterval.isAlignedAtBorder(bestAligned.interval, commonParent, fixedEdge)) 1317 return false; 1318 } 1319 return true; 1320 } 1321 } 1322 return dimension == HORIZONTAL; 1323 } 1324 1325 private static boolean relatedPositions(PositionDef nextTo, PositionDef aligned) { 1326 if (nextTo.interval == null || aligned.interval == null) 1327 return false; 1328 1329 LayoutInterval neighbor = LayoutInterval.getNeighbor( 1330 aligned.interval, nextTo.alignment, true, true, false); 1331 return neighbor == nextTo.interval 1332 || (neighbor == null && nextTo.interval.getParent() == null); 1333 } 1334 1335 private PositionDef getAlignedEqualToNextTo(PositionDef bestNextTo) { 1336 if (operation == RESIZING || !bestNextTo.snapped) 1337 return null; 1338 1339 int alignment = bestNextTo.alignment; 1340 PositionDef alignedAlternative = findingsAligned[dimension][alignment]; 1341 if (alignedAlternative != null && alignedAlternative.distance == bestNextTo.distance) { 1342 LayoutInterval neighbor = LayoutInterval.getNeighbor( 1345 alignedAlternative.interval, alignment, true, true, false); 1346 if (neighbor != null 1347 && (neighbor == bestNextTo.interval || neighbor.isParentOf(bestNextTo.interval))) 1348 return alignedAlternative; 1349 } 1350 return null; 1351 } 1352 1353 1359 private boolean isValidInterval(LayoutInterval interval) { 1360 if (operation == ADDING) { 1361 return true; 1362 } 1363 1364 if (interval.isGroup()) { 1365 int count = 0; 1369 Iterator it = interval.getSubIntervals(); 1370 while (it.hasNext()) { 1371 LayoutInterval li = (LayoutInterval) it.next(); 1372 if ((!li.isEmptySpace() || interval.isSequential()) 1373 && isValidInterval(li)) 1374 { count++; 1376 if (count > 1) 1377 return true; 1378 } 1379 } 1380 return false; 1381 } 1382 else { 1383 for (int i=0; i < movingComponents.length; i++) { 1384 if (movingComponents[i].getLayoutInterval(dimension) == interval) { 1385 return false; 1386 } 1387 } 1388 return true; 1389 } 1390 } 1391 1392 1397 private int isValidNextToResizing(LayoutInterval interval, int alignment) { 1398 assert alignment == LEADING || alignment == TRAILING; 1399 LayoutInterval resizing = movingComponents[0].getLayoutInterval(dimension); 1400 if (interval.isParentOf(resizing)) { 1401 return interval.getParent() == null && clearWayToParent(resizing, interval, dimension, alignment) 1402 && (!toDeepToMerge(resizing, interval, alignment) 1403 || LayoutInterval.getNeighbor(resizing, alignment, true, true, false) == null) ? 1404 1 : 0; 1405 } 1406 1407 LayoutInterval commonParent = LayoutInterval.getCommonParent(interval, resizing); 1408 if (commonParent.isSequential()) { 1409 if (toDeepToMerge(resizing, commonParent, alignment) 1410 && LayoutInterval.getNeighbor(resizing, alignment, true, true, false) != interval) 1411 return -1; 1412 1413 resizing = getClearWayToParent(resizing, commonParent, dimension, alignment); 1414 if (resizing == null) 1415 return -1; 1416 1417 while (interval.getParent() != commonParent) { 1418 interval = interval.getParent(); 1419 } 1420 1421 int startIndex = commonParent.indexOf(alignment == LEADING ? interval : resizing) + 1; 1422 int endIndex = commonParent.indexOf(alignment == LEADING ? resizing : interval) - 1; 1423 return startIndex <= endIndex 1424 && !LayoutUtils.contentOverlap(movingSpace, commonParent, startIndex, endIndex, dimension^1) ? 1425 1 : -1; 1426 } 1427 return -1; 1428 } 1429 1430 private boolean isValidAlignedResizing(LayoutInterval interval, int alignment) { 1431 int dst = LayoutRegion.distance(movingSpace, interval.getCurrentSpace(), 1434 dimension, alignment^1, alignment); 1435 if ((alignment == LEADING && dst <= 0) || (alignment == TRAILING && dst >= 0)) { 1436 LayoutInterval resizing = movingComponents[0].getLayoutInterval(dimension); 1438 if (interval.isParentOf(resizing)) { 1439 if (!clearWayToParent(resizing, interval, dimension, alignment)) 1440 return false; 1441 if (toDeepToMerge(resizing, interval, alignment)) { 1442 LayoutInterval neighbor = LayoutInterval.getNeighbor(resizing, alignment, true, true, false); 1443 if (neighbor != null && interval.isParentOf(neighbor)) 1444 return false; 1445 } 1446 return true; 1447 } 1448 else { 1449 LayoutInterval commonParent = LayoutInterval.getCommonParent(interval, resizing); 1450 if (commonParent.isParallel()) 1451 return true; 1452 1453 if (toDeepToMerge(resizing, commonParent, alignment)) 1454 return false; 1455 1456 resizing = getClearWayToParent(resizing, commonParent, dimension, alignment); 1458 if (resizing == null) 1459 return false; 1460 1461 while (interval.getParent() != commonParent) { 1462 interval = interval.getParent(); 1463 } 1464 1465 int startIndex, endIndex; 1466 if (alignment == LEADING) { 1467 startIndex = commonParent.indexOf(interval); 1468 endIndex = commonParent.indexOf(resizing) - 1; 1469 } 1470 else { startIndex = commonParent.indexOf(resizing) + 1; 1472 endIndex = commonParent.indexOf(interval); 1473 } 1474 return startIndex <= endIndex 1475 && !LayoutUtils.contentOverlap(movingSpace, commonParent, startIndex, endIndex, dimension^1); 1476 } 1477 } 1478 return false; 1479 } 1480 1481 private static boolean clearWayToParent(LayoutInterval interval, LayoutInterval parent, int dimension, int alignment) { 1482 return getClearWayToParent(interval, parent, dimension, alignment) != null; 1483 } 1484 1485 private static LayoutInterval getClearWayToParent(LayoutInterval interval, 1486 LayoutInterval topParent, int dimension, int alignment) 1487 { 1488 LayoutRegion space = interval.getCurrentSpace(); 1489 LayoutInterval parent = interval.getParent(); 1490 while (parent != topParent) { 1491 if (parent.isSequential()) { 1492 int startIndex, endIndex; 1493 if (alignment == LEADING) { 1494 startIndex = 0; 1495 endIndex = parent.indexOf(interval) - 1; 1496 } 1497 else { 1498 startIndex = parent.indexOf(interval) + 1; 1499 endIndex = parent.getSubIntervalCount() - 1; 1500 } 1501 if (startIndex <= endIndex 1502 && LayoutUtils.contentOverlap(space, parent, startIndex, endIndex, dimension^1)) 1503 { return null; 1505 } 1506 } 1507 interval = parent; 1508 parent = interval.getParent(); 1509 } 1510 return interval; 1511 } 1512 1513 private static boolean toDeepToMerge(LayoutInterval interval, LayoutInterval parent, int alignment) { 1517 int level = 0; 1518 int a = DEFAULT; 1519 LayoutInterval prev = null; 1520 LayoutInterval p = interval.getParent(); 1521 while (p != parent) { 1522 if (p.isParallel()) { 1523 if (a == DEFAULT) { 1524 a = interval.getAlignment(); 1525 if (a != alignment) 1526 level++; 1527 } 1528 else if (!LayoutInterval.isAlignedAtBorder(prev, p, a)) { 1529 level++; 1530 if (level > 1) 1531 return true; 1532 } 1533 prev = p; 1534 } 1535 interval = p; 1536 p = interval.getParent(); 1537 } 1538 return level >= 2; 1539 } 1540 1541 1546 int findPadding(LayoutInterval interval, LayoutInterval moving, int dimension, int alignment) { 1547 int oppAlignment = (alignment == LEADING) ? TRAILING : LEADING; 1548 List movingComps = LayoutUtils.edgeSubComponents(moving, alignment); 1549 List fixedComps = LayoutUtils.edgeSubComponents(interval, oppAlignment); 1550 List sources = (alignment == LEADING) ? fixedComps : movingComps; 1551 List targets = (alignment == LEADING) ? movingComps : fixedComps; 1552 Map map = new HashMap(); 1553 for (int i=0; i<movingComponents.length; i++) { 1554 map.put(movingComponents[i].getId(), movingBounds[i]); 1555 } 1556 return LayoutUtils.getSizeOfDefaultGap(sources, targets, visualMapper, 1557 targetContainer.getId(), map); 1558 } 1559 1560 1563 int findIndent(LayoutComponent mainComp, LayoutComponent indentedComp, 1564 int dimension, int alignment) 1565 { 1566 return visualMapper.getPreferredPadding(mainComp.getId(), indentedComp.getId(), 1567 dimension, alignment, VisualMapper.INDENT); 1568 } 1569 1570 1573 static class PositionDef { 1574 private int distance = LayoutRegion.UNKNOWN; 1575 1576 LayoutInterval interval; 1577 int alignment = LayoutRegion.NO_POINT; 1578 boolean nextTo; 1579 boolean snapped; 1580 1582 private void reset() { 1583 distance = LayoutRegion.UNKNOWN; 1584 interval = null; 1585 alignment = LayoutRegion.NO_POINT; 1586 } 1587 1588 private boolean isSet() { 1589 return interval != null; 1590 } 1591 1592 public String toString() { 1593 StringBuffer sb = new StringBuffer (); 1594 sb.append("distance=").append(distance); sb.append(",alignment=").append(alignment); sb.append(",nextTo=").append(nextTo); sb.append(",snapped=").append(snapped); return sb.toString(); 1599 } 1600 } 1601 1602 static class SizeDef { 1603 private int originalSize; 1604 private int preferredSize; 1605 private int zeroPreferredSize; private LayoutInterval resizingGap; private int originalGapSize; 1608 private int preferredGapSize; 1609 1610 LayoutInterval getResizingGap() { 1611 return resizingGap; 1612 } 1613 1614 int getResizingGapSize(int currentSize) { 1615 if (resizingGap == null) 1616 return LayoutRegion.UNKNOWN; 1617 if (currentSize == zeroPreferredSize) 1618 return 0; 1619 int gapSize = originalGapSize - originalSize + currentSize; 1620 return currentSize == preferredSize || gapSize < 0 ? NOT_EXPLICITLY_DEFINED : gapSize; 1622 } 1623 } 1624} 1625 | Popular Tags |