1 14 15 package org.gjt.sp.jedit.gui; 16 17 import java.awt.Component ; 18 import java.awt.Container ; 19 import java.awt.Dimension ; 20 import java.awt.Insets ; 21 import java.awt.LayoutManager2 ; 22 23 import java.util.Arrays ; 24 25 74 public class VariableGridLayout implements LayoutManager2 , java.io.Serializable 75 { 76 public static final int FIXED_NUM_ROWS = 1; 77 public static final int FIXED_NUM_COLUMNS = 2; 78 79 private static enum LayoutSize { MINIMUM, MAXIMUM, PREFERRED } 80 81 95 public VariableGridLayout(int mode, int size, int hgap, int vgap, boolean takeSizesIntoAccount, Insets distanceToBorders) 96 { 97 if (mode != FIXED_NUM_ROWS && mode != FIXED_NUM_COLUMNS) 98 { 99 throw new IllegalArgumentException ("illegal mode; value is " + mode); 100 } 101 if (size <= 0) 102 { 103 throw new IllegalArgumentException ("size cannot be zero or less; value is " + size); 104 } 105 if (hgap < 0) 106 { 107 throw new IllegalArgumentException ("hgap cannot be negative; value is " + hgap); 108 } 109 if (vgap < 0) 110 { 111 throw new IllegalArgumentException ("vgap cannot be negative; value is " + vgap); 112 } 113 this.mode = mode; 114 this.size = size; 115 this.hgap = hgap; 116 this.vgap = vgap; 117 this.takeSizesIntoAccount = takeSizesIntoAccount; 118 this.distanceToBorders = (Insets )distanceToBorders.clone(); 119 } 120 121 134 public VariableGridLayout(int mode, int size, int hgap, int vgap, boolean takeSizesIntoAccount) 135 { 136 this(mode, size, hgap, vgap, takeSizesIntoAccount, new Insets (0,0,0,0)); 137 } 138 139 151 public VariableGridLayout(int mode, int size, int hgap, int vgap) 152 { 153 this(mode, size, hgap, vgap, false, new Insets (0,0,0,0)); 154 } 155 156 166 public VariableGridLayout(int mode, int size) 167 { 168 this(mode, size, 0, 0, false, new Insets (0,0,0,0)); 169 } 170 171 177 public VariableGridLayout() 178 { 179 this(FIXED_NUM_ROWS, 1, 0, 0, false, new Insets (0,0,0,0)); 180 } 181 182 185 public void addLayoutComponent(String name, Component component) 186 { 187 } 188 189 192 public void addLayoutComponent(Component component, Object constraints) 193 { 194 } 195 196 199 public void removeLayoutComponent(Component component) 200 { 201 } 202 203 206 public float getLayoutAlignmentX(Container container) 207 { 208 return 0.5f; 209 } 210 211 214 public float getLayoutAlignmentY(Container container) 215 { 216 return 0.5f; 217 } 218 219 public Dimension preferredLayoutSize(Container parent) 220 { 221 return getLayoutSize(parent,LayoutSize.PREFERRED); 222 } 223 224 public Dimension minimumLayoutSize(Container parent) 225 { 226 return getLayoutSize(parent,LayoutSize.MINIMUM); 227 } 228 229 public Dimension maximumLayoutSize(Container parent) 230 { 231 return getLayoutSize(parent,LayoutSize.MAXIMUM); 232 } 233 234 public void layoutContainer(Container parent) 235 { 236 synchronized (parent.getTreeLock()) 237 { 238 update(parent); 239 240 int ncomponents = parent.getComponentCount(); 241 242 if (ncomponents == 0) 243 { 244 return; 245 } 246 247 int total_height = 0; 249 Arrays.fill(row_heights,0); 250 Arrays.fill(col_widths,0); 251 if (takeSizesIntoAccount) 252 { 253 Arrays.fill(minimum_row_heights,0); 254 Arrays.fill(minimum_col_widths,0); 255 Arrays.fill(maximum_row_heights,Integer.MAX_VALUE); 256 Arrays.fill(maximum_col_widths,Integer.MAX_VALUE); 257 } 258 for (int r = 0, i = 0; r < nrows; r++) 259 { 260 for (int c = 0; c < ncols; c++, i++) 261 { 262 if (i < ncomponents) 263 { 264 Component comp = parent.getComponent(i); 265 Dimension d = comp.getPreferredSize(); 266 row_heights[r] = Math.max(row_heights[r], d.height); 267 col_widths[c] = Math.max(col_widths[c], d.width); 268 if (takeSizesIntoAccount) 269 { 270 d = comp.getMinimumSize(); 271 minimum_row_heights[r] = Math.max(minimum_row_heights[r], d.height); 272 minimum_col_widths[c] = Math.max(minimum_col_widths[c], d.width); 273 d = comp.getMaximumSize(); 274 maximum_row_heights[r] = Math.min(maximum_row_heights[r], d.height); 275 maximum_col_widths[c] = Math.min(maximum_col_widths[c], d.width); 276 } 277 } 278 else 279 { 280 break; 281 } 282 } 283 if (takeSizesIntoAccount) 284 { 285 if (minimum_row_heights[r] >= maximum_row_heights[r]) 286 { 287 maximum_row_heights[r] = minimum_row_heights[r]; 288 row_heights[r] = minimum_row_heights[r]; 289 } 290 else if (row_heights[r] < minimum_row_heights[r]) 291 { 292 row_heights[r] = minimum_row_heights[r]; 293 } 294 else if (row_heights[r] > maximum_row_heights[r]) 295 { 296 row_heights[r] = maximum_row_heights[r]; 297 } 298 } 299 total_height += row_heights[r]; 300 } 301 302 int total_width = 0; 303 for (int c = 0; c < ncols; c++) 304 { 305 if (takeSizesIntoAccount) 306 { 307 if (minimum_col_widths[c] >= maximum_col_widths[c]) 308 { 309 maximum_col_widths[c] = minimum_col_widths[c]; 310 col_widths[c] = minimum_col_widths[c]; 311 } 312 else if (col_widths[c] < minimum_col_widths[c]) 313 { 314 col_widths[c] = minimum_col_widths[c]; 315 } 316 else if (col_widths[c] > maximum_col_widths[c]) 317 { 318 col_widths[c] = maximum_col_widths[c]; 319 } 320 } 321 total_width += col_widths[c]; 322 } 323 324 Dimension parent_size = parent.getSize(); 326 Insets insets = parent.getInsets(); 327 int free_height = parent_size.height 328 - insets.top - insets.bottom 329 - (nrows - 1) * vgap 330 - distanceToBorders.top - distanceToBorders.bottom; 331 int free_width = parent_size.width 332 - insets.left - insets.right 333 - (ncols - 1) * hgap 334 - distanceToBorders.left - distanceToBorders.right; 335 336 redistributeSpace(total_height,free_height, 337 takeSizesIntoAccount, 338 nrows,row_heights, 339 minimum_row_heights, 340 maximum_row_heights); 341 342 redistributeSpace(total_width,free_width, 343 takeSizesIntoAccount, 344 ncols,col_widths, 345 minimum_col_widths, 346 maximum_col_widths); 347 348 for (int r = 0, y = insets.top + distanceToBorders.top, i = 0; r < nrows; y += row_heights[r] + vgap, r++) 350 { 351 for (int c = 0, x = insets.left + distanceToBorders.left; c < ncols; x += col_widths[c] + hgap, c++, i++) 352 { 353 if (i < ncomponents) 354 { 355 Component comp = parent.getComponent(i); 356 Dimension d = comp.getMaximumSize(); 357 int width = col_widths[c]; 358 int height = row_heights[r]; 359 int xCorrection = 0; 360 int yCorrection = 0; 361 if (width > d.width) 362 { 363 xCorrection = (int)((width - d.width) * comp.getAlignmentX()); 364 width = d.width; 365 } 366 if (height > d.height) 367 { 368 yCorrection = (int)((height-d.height) * comp.getAlignmentY()); 369 height = d.height; 370 } 371 372 comp.setBounds(x + xCorrection, y + yCorrection, width, height); 373 } 374 } 375 } 376 } } 378 379 public void invalidateLayout(Container container) 380 { 381 } 382 383 387 public String toString() 388 { 389 return getClass().getName() + "[mode=" 390 + ((FIXED_NUM_ROWS == mode) ? "FIXED_NUM_ROWS" 391 : ((FIXED_NUM_COLUMNS == mode) ? "FIXED_NUM_COLUMNS" 392 : "UNKNOWN(" + mode + ")")) + ",size=" + size 393 + ",hgap=" + hgap + ",vgap=" + vgap 394 + ",takeSizesIntoAccount=" + takeSizesIntoAccount 395 + ",distanceToBorders=" + distanceToBorders + "]"; 396 } 397 398 403 private Dimension getLayoutSize(Container parent, LayoutSize which) 404 { 405 synchronized (parent.getTreeLock()) 406 { 407 update(parent); 408 409 int ncomponents = parent.getComponentCount(); 410 long h = 0; 411 long w = 0; 412 413 for (int r = 0, i = 0; r < nrows; r++) 414 { 415 int row_height = 0; 416 for (int c = 0; c < ncols; c++, i++) 417 { 418 if (i < ncomponents) 419 { 420 switch (which) 421 { 422 case MINIMUM: 423 row_height = Math.max(row_height, parent.getComponent(i).getMinimumSize().height); 424 break; 425 case MAXIMUM: 426 row_height = Math.max(row_height, parent.getComponent(i).getMaximumSize().height); 427 break; 428 case PREFERRED: 429 row_height = Math.max(row_height, parent.getComponent(i).getPreferredSize().height); 430 break; 431 default: 432 throw new InternalError ("missing case branch for LayoutSize " + which); 433 } 434 } 435 else 436 { 437 break; 438 } 439 } 440 h += row_height; 441 } 442 443 for (int c = 0; c < ncols; c++) 444 { 445 int col_width = 0; 446 for (int r = 0; r < nrows; r++) 447 { 448 int i = r * ncols + c; 449 if (i < ncomponents) 450 { 451 switch (which) 452 { 453 case MINIMUM: 454 col_width = Math.max(col_width, parent.getComponent(i).getMinimumSize().width); 455 break; 456 case MAXIMUM: 457 col_width = Math.max(col_width, parent.getComponent(i).getMaximumSize().width); 458 break; 459 case PREFERRED: 460 col_width = Math.max(col_width, parent.getComponent(i).getPreferredSize().width); 461 break; 462 default: 463 throw new InternalError ("missing case branch for LayoutSize " + which); 464 } 465 } 466 else 467 { 468 break; 469 } 470 } 471 w += col_width; 472 } 473 474 Insets insets = parent.getInsets(); 475 w += insets.left + insets.right + ((ncols - 1) * hgap) + distanceToBorders.left + distanceToBorders.right; 476 h += insets.top + insets.bottom + ((nrows - 1) * vgap) + distanceToBorders.top + distanceToBorders.bottom; 477 if (w > Integer.MAX_VALUE) { 478 w = Integer.MAX_VALUE; 479 } 480 if (h > Integer.MAX_VALUE) { 481 h = Integer.MAX_VALUE; 482 } 483 return new Dimension ((int)w,(int)h); 484 } 485 } 486 487 private void update(Container container) 488 { 489 int ncomponents = container.getComponentCount(); 490 int old_nrows = nrows; 491 int old_ncols = ncols; 492 if (this.mode == FIXED_NUM_ROWS) 493 { 494 nrows = this.size; 495 ncols = (ncomponents + nrows - 1) / nrows; 496 } 497 else 498 { 499 ncols = this.size; 500 nrows = (ncomponents + ncols - 1) / ncols; 501 } 502 if (old_nrows != nrows) 503 { 504 row_heights = new int[nrows]; 505 if (takeSizesIntoAccount) 506 { 507 minimum_row_heights = new int[nrows]; 508 maximum_row_heights = new int[nrows]; 509 } 510 } 511 if (old_ncols != ncols) 512 { 513 col_widths = new int[ncols]; 514 if (takeSizesIntoAccount) 515 { 516 minimum_col_widths = new int[ncols]; 517 maximum_col_widths = new int[ncols]; 518 } 519 } 520 } 521 522 private void redistributeSpace(int total_size, int free_size, boolean takeSizesIntoAccount, 523 int nelements, int[] element_sizes, 524 int[] minimum_element_sizes, int[] maximum_element_sizes) 525 { 526 if (total_size != free_size) 527 { 528 if (takeSizesIntoAccount) 529 { 530 boolean grow = total_size < free_size; 531 free_size = (free_size - total_size) * (grow ? 1 : -1); 532 while (free_size != 0) 533 { 534 int modifyableAmount = 0; 535 int modifySize = 0; 536 for (int i = 0 ; i < nelements ; i++) 537 { 538 if ((grow && (element_sizes[i] < maximum_element_sizes[i])) || 539 (!grow && (element_sizes[i] > minimum_element_sizes[i]))) 540 { 541 modifyableAmount++; 542 modifySize += element_sizes[i]; 543 } 544 } 545 boolean checkBounds = true; 546 if (0 == modifyableAmount) 547 { 548 for (int i = 0 ; i < nelements ; i++) 549 { 550 modifySize += element_sizes[i]; 551 } 552 checkBounds = false; 553 modifyableAmount = nelements; 554 } 555 if (free_size < modifyableAmount) 556 { 557 for (int i = 0 ; i < nelements ; i++) 558 { 559 if ((free_size != 0) && 560 (!checkBounds || 561 (checkBounds && 562 (grow && (element_sizes[i] < maximum_element_sizes[i])) || 563 (!grow && (element_sizes[i] > minimum_element_sizes[i]))))) 564 { 565 element_sizes[i] += (grow ? 1 : -1); 566 if (0 > element_sizes[i]) 567 { 568 element_sizes[i] = 0; 569 } 570 free_size--; 571 } 572 } 573 } 574 else 575 { 576 int modifySizeAddition = 0; 577 for (int i = 0 ; i < nelements ; i++) 578 { 579 int modifyableSize = (checkBounds ? (grow ? maximum_element_sizes[i] - element_sizes[i] : element_sizes[i] - minimum_element_sizes[i]) : Integer.MAX_VALUE - element_sizes[i]); 580 int elementModifySize = (int)((double)free_size / (double)modifySize * (double)element_sizes[i]); 581 if (elementModifySize <= modifyableSize) 582 { 583 element_sizes[i] += (grow ? elementModifySize : -elementModifySize); 584 modifySizeAddition += (grow ? elementModifySize : -elementModifySize); 585 free_size -= elementModifySize; 586 } 587 else 588 { 589 element_sizes[i] += (grow ? modifyableSize : -modifyableSize); 590 modifySizeAddition += (grow ? modifyableSize : -modifyableSize); 591 free_size -= modifyableSize; 592 } 593 if (0 > element_sizes[i]) 594 { 595 element_sizes[i] = 0; 596 } 597 } 598 modifySize += modifySizeAddition; 599 } 600 } 601 } 602 else 603 { 604 double d = (double)free_size / (double)total_size; 605 for (int i = 0; i < nelements; i++) 606 { 607 element_sizes[i] = (int)(element_sizes[i] * d); 608 } 609 } 610 } 611 } 612 613 private int mode; 614 private int size; 615 private int hgap; 616 private int vgap; 617 private boolean takeSizesIntoAccount; 618 private Insets distanceToBorders; 619 private transient int nrows = -1; 620 private transient int ncols = -1; 621 private transient int[] minimum_row_heights = null; 622 private transient int[] minimum_col_widths = null; 623 private transient int[] row_heights = null; 624 private transient int[] col_widths = null; 625 private transient int[] maximum_row_heights = null; 626 private transient int[] maximum_col_widths = null; 627 } 628 | Popular Tags |