1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 #include "precompiled_sfx2.hxx" 23 #include "sfx2/sidebar/GridLayouter.hxx" 24 25 #include <vcl/window.hxx> 26 27 namespace sfx2 { namespace sidebar { 28 29 typedef std::vector<CellDescriptor> CellData; 30 typedef std::vector<CellData> ColumnData; 31 32 class GridLayouter::Implementation 33 { 34 public: 35 Implementation (Window& rParent); 36 ~Implementation (void); 37 38 CellDescriptor& GetCell ( 39 const sal_Int32 nRow, 40 const sal_Int32 nColumn, 41 const sal_Int32 nVariant); 42 43 void Layout (void); 44 void LayoutColumn( 45 ColumnData& rColumn, 46 const sal_Int32 nX, 47 const sal_Int32 nColumnIndex); 48 49 void DistributeWidth (const sal_Int32 nTotalWidth); 50 sal_Int32 GetMinimumColumnWidth ( 51 ColumnData& rColumn, 52 const ColumnDescriptor& rDescriptor) const; 53 54 void Paint (void); 55 56 Window& mrParent; 57 ::std::vector<ColumnData> maColumns; 58 ::std::vector<ColumnDescriptor> maColumnDescriptors; 59 }; 60 61 #define ForAllColumnDescriptors(I) \ 62 for (::std::vector<ColumnDescriptor>::iterator \ 63 I(maColumnDescriptors.begin()), \ 64 iEnd(maColumnDescriptors.end()); \ 65 I!=iEnd; \ 66 ++I) 67 68 #define ForAllColumns(I,N) \ 69 sal_Int32 N (0); \ 70 for (::std::vector<ColumnData>::iterator \ 71 I(maColumns.begin()), \ 72 iEnd(maColumns.end()); \ 73 I!=iEnd; \ 74 ++I,++N) 75 76 #define ForAllRows(ColumnData,I) \ 77 for (std::vector<CellData>::iterator \ 78 I((ColumnData).begin()), \ 79 iRowEnd((ColumnData).end()); \ 80 I!=iRowEnd; \ 81 ++I) 82 83 #define ForAllCells(CellData,I) \ 84 for (::std::vector<CellDescriptor>::iterator \ 85 I((CellData).begin()), \ 86 iCellEnd((CellData).end()); \ 87 I!=iCellEnd; \ 88 ++I) 89 90 91 //===== GridLayouter ========================================================== 92 93 GridLayouter::GridLayouter (Window& rParent) 94 : mpImplementation(new Implementation(rParent)) 95 { 96 } 97 98 99 100 101 GridLayouter::~GridLayouter (void) 102 { 103 } 104 105 106 107 108 CellDescriptor& GridLayouter::GetCell ( 109 const sal_Int32 nRow, 110 const sal_Int32 nColumn, 111 const sal_Int32 nVariant) 112 { 113 return mpImplementation->GetCell(nRow, nColumn, nVariant); 114 } 115 116 117 118 119 ColumnDescriptor& GridLayouter::GetColumn ( 120 const sal_Int32 nColumn) 121 { 122 // Make sure that the specified column exists. 123 mpImplementation->GetCell(0, nColumn, 0); 124 return mpImplementation->maColumnDescriptors[nColumn]; 125 } 126 127 128 129 130 void GridLayouter::Layout (void) 131 { 132 mpImplementation->Layout(); 133 } 134 135 136 137 138 void GridLayouter::Paint (const Rectangle& rBox) 139 { 140 (void)rBox; 141 142 mpImplementation->Paint(); 143 } 144 145 146 147 148 //===== CellDescriptor ======================================================== 149 150 CellDescriptor::CellDescriptor (void) 151 : mpControl(NULL), 152 mnGridWidth(1), 153 mnMinimumWidth(-1), 154 mnMaximumWidth(-1), 155 mnOffset(0) 156 { 157 } 158 159 160 161 162 CellDescriptor::~CellDescriptor (void) 163 { 164 } 165 166 167 168 169 CellDescriptor& CellDescriptor::SetGridWidth (const sal_Int32 nColumnCount) 170 { 171 mnGridWidth = nColumnCount; 172 return *this; 173 } 174 175 176 177 178 CellDescriptor& CellDescriptor::SetControl (Window& rControl) 179 { 180 mpControl = &rControl; 181 return *this; 182 } 183 184 185 186 187 CellDescriptor& CellDescriptor::SetFixedWidth (const sal_Int32 nWidth) 188 { 189 mnMinimumWidth = nWidth; 190 mnMaximumWidth = nWidth; 191 return *this; 192 } 193 194 195 196 CellDescriptor& CellDescriptor::SetOffset (const sal_Int32 nOffset) 197 { 198 mnOffset = nOffset; 199 return *this; 200 } 201 202 203 204 205 CellDescriptor& CellDescriptor::SetFixedWidth (void) 206 { 207 sal_Int32 nMaxControlWidth (0); 208 if (mpControl != NULL) 209 { 210 const sal_Int32 nControlWidth (mpControl->GetSizePixel().Width()); 211 if (nControlWidth > nMaxControlWidth) 212 nMaxControlWidth = nControlWidth; 213 } 214 mnMinimumWidth = nMaxControlWidth; 215 mnMaximumWidth = nMaxControlWidth; 216 217 return *this; 218 } 219 220 221 222 223 CellDescriptor& CellDescriptor::SetMinimumWidth (const sal_Int32 nWidth) 224 { 225 mnMinimumWidth = nWidth; 226 return *this; 227 } 228 229 230 231 sal_Int32 CellDescriptor::GetGridWidth (void) const 232 { 233 return mnGridWidth; 234 } 235 236 237 238 239 Window* CellDescriptor::GetControl (void) const 240 { 241 return mpControl; 242 } 243 244 245 246 247 sal_Int32 CellDescriptor::GetMinimumWidth (void) const 248 { 249 return mnMinimumWidth + mnOffset; 250 } 251 252 253 254 255 sal_Int32 CellDescriptor::GetMaximumWidth (void) const 256 { 257 return mnMaximumWidth; 258 } 259 260 261 262 sal_Int32 CellDescriptor::GetOffset (void) const 263 { 264 return mnOffset; 265 } 266 267 268 269 270 //===== GridLayouter::Implementation ========================================== 271 272 GridLayouter::Implementation::Implementation (Window& rParent) 273 : mrParent(rParent), 274 maColumns(), 275 maColumnDescriptors() 276 { 277 } 278 279 280 281 282 GridLayouter::Implementation::~Implementation (void) 283 { 284 } 285 286 287 288 289 CellDescriptor& GridLayouter::Implementation::GetCell ( 290 const sal_Int32 nRow, 291 const sal_Int32 nColumn, 292 const sal_Int32 nVariant) 293 { 294 if (nColumn<0 || nRow<0 || nVariant<0) 295 { 296 OSL_ASSERT(nColumn>=0); 297 OSL_ASSERT(nRow>=0); 298 OSL_ASSERT(nVariant>=0); 299 return GetCell(0,0,0); 300 } 301 302 // Provide missing columns. 303 if (maColumns.size() <= static_cast<size_t>(nColumn)) 304 { 305 maColumns.resize(nColumn+1); 306 maColumnDescriptors.resize(nColumn+1); 307 } 308 309 // Provide missing rows. 310 ColumnData& rColumn (maColumns[nColumn]); 311 if (rColumn.size() <= static_cast<size_t>(nRow)) 312 rColumn.resize(nRow+1); 313 314 // Provide missing variants. 315 CellData& rCellData (rColumn[nRow]); 316 if (rCellData.size() <= static_cast<size_t>(nVariant)) 317 rCellData.resize(nVariant+1); 318 319 return rCellData[nVariant]; 320 } 321 322 323 324 325 void GridLayouter::Implementation::Layout (void) 326 { 327 if (maColumns.empty()) 328 { 329 // There are no columns and therefore no controls => nothing 330 // to do. 331 return; 332 } 333 334 const Size aParentSize (mrParent.GetSizePixel()); 335 336 // Determine the total column weight. 337 sal_Int32 nTotalColumnWeight (0); 338 ForAllColumnDescriptors(iDescriptor) 339 nTotalColumnWeight += iDescriptor->GetWeight(); 340 if (nTotalColumnWeight <= 0) 341 { 342 OSL_ASSERT(nTotalColumnWeight>0); 343 return; 344 } 345 346 // Distribute the width of the parent window to the columns. 347 DistributeWidth(aParentSize.Width()); 348 349 // Set the new positions and widths. 350 sal_Int32 nX (0); 351 ForAllColumns(iColumn,nColumnIndex) 352 { 353 LayoutColumn( 354 *iColumn, 355 nX, 356 nColumnIndex); 357 358 nX += maColumnDescriptors[nColumnIndex].GetWidth(); 359 } 360 } 361 362 363 364 365 void GridLayouter::Implementation::LayoutColumn( 366 ColumnData& rColumn, 367 const sal_Int32 nX, 368 const sal_Int32 nColumnIndex) 369 { 370 ColumnDescriptor& rDescriptor (maColumnDescriptors[nColumnIndex]); 371 const sal_Int32 nLeft (nX + rDescriptor.GetLeftPadding()); 372 const sal_Int32 nWidth (rDescriptor.GetWidth() - rDescriptor.GetLeftPadding() - rDescriptor.GetRightPadding()); 373 374 sal_Int32 nRow (-1); 375 ForAllRows(rColumn, iCell) 376 { 377 ++nRow; 378 379 ForAllCells(*iCell, iCellDescriptor) 380 { 381 Window* pControl = iCellDescriptor->GetControl(); 382 if (pControl==NULL || ! pControl->IsVisible()) 383 continue; 384 385 sal_Int32 nCellWidth (nWidth); 386 const sal_Int32 nGridWidth (iCellDescriptor->GetGridWidth()); 387 if (nGridWidth < 0) 388 continue; 389 else if (nGridWidth > 1) 390 { 391 // Cell spans more than one column. Sum all their 392 // widths. 393 for (sal_Int32 nOffset=1; 394 nOffset<nGridWidth && static_cast<size_t>(nColumnIndex+nOffset)<maColumnDescriptors.size(); 395 ++nOffset) 396 { 397 nCellWidth += maColumnDescriptors[nColumnIndex+nOffset].GetWidth(); 398 } 399 nCellWidth -= maColumnDescriptors[nColumnIndex+nGridWidth-1].GetRightPadding(); 400 } 401 402 // Check width against valid range of cell. 403 if (iCellDescriptor->GetMinimumWidth() > 0) 404 if (nCellWidth < iCellDescriptor->GetMinimumWidth()) 405 nCellWidth = iCellDescriptor->GetMinimumWidth(); 406 if (iCellDescriptor->GetMaximumWidth() > 0) 407 if (nCellWidth > iCellDescriptor->GetMaximumWidth()) 408 nCellWidth = iCellDescriptor->GetMaximumWidth(); 409 410 pControl->SetPosSizePixel( 411 nLeft + iCellDescriptor->GetOffset(), 412 0, 413 nCellWidth, 414 0, 415 WINDOW_POSSIZE_X | WINDOW_POSSIZE_WIDTH); 416 } 417 } 418 } 419 420 421 422 423 void GridLayouter::Implementation::DistributeWidth (const sal_Int32 nTotalWidth) 424 { 425 // Prepare width distribution: 426 // a) Setup minimum widths for all columns. 427 // b) Sum up the width of columns that have zero weight. 428 // c) Sum up the non-zero weights. 429 sal_Int32 nZeroWeightWidth (0); 430 sal_Int32 nTotalColumnWeight (0); 431 for (sal_uInt32 nColumn=0; nColumn<maColumns.size(); ++nColumn) 432 { 433 ColumnDescriptor& rDescriptor (maColumnDescriptors[nColumn]); 434 ColumnData& rColumn (maColumns[nColumn]); 435 436 const sal_Int32 nWidth (GetMinimumColumnWidth(rColumn, rDescriptor)); 437 438 rDescriptor.SetWidth(nWidth); 439 440 if (rDescriptor.GetWeight() <= 0) 441 nZeroWeightWidth += nWidth; 442 else 443 nTotalColumnWeight += rDescriptor.GetWeight(); 444 } 445 446 sal_Int32 nRemainingWidth (nTotalWidth - nZeroWeightWidth); 447 if (nRemainingWidth < 0) 448 nRemainingWidth = 0; 449 450 451 // Distribute the remaining width between columns that have 452 // non-zero width. 453 const sal_Int32 nDistributableWidth (nRemainingWidth); 454 for (sal_uInt32 nColumn=0; nColumn<maColumns.size(); ++nColumn) 455 { 456 ColumnDescriptor& rDescriptor (maColumnDescriptors[nColumn]); 457 458 if (rDescriptor.GetWeight() > 0) 459 { 460 sal_Int32 nWidth (nDistributableWidth * rDescriptor.GetWeight() / nTotalColumnWeight); 461 // Make sure the width lies inside the valid range of 462 // column widths. 463 if (nWidth < rDescriptor.GetWidth()) 464 nWidth = rDescriptor.GetWidth(); 465 if (rDescriptor.GetMaximumWidth()>0) 466 if (nWidth > rDescriptor.GetTotalMaximumWidth()) 467 nWidth = rDescriptor.GetTotalMaximumWidth(); 468 469 rDescriptor.SetWidth(nWidth); 470 nRemainingWidth -= nWidth; 471 } 472 } 473 474 // If there are some pixels left (due to rounding errors), then 475 // give them to the first column that has non-zero weight. 476 if (nRemainingWidth > 0) 477 for (sal_uInt32 nColumn=0; nColumn<maColumns.size(); ++nColumn) 478 { 479 ColumnDescriptor& rDescriptor (maColumnDescriptors[nColumn]); 480 if (rDescriptor.GetWeight() > 0) 481 { 482 rDescriptor.SetWidth(rDescriptor.GetWidth() + nRemainingWidth); 483 break; 484 } 485 } 486 } 487 488 489 490 491 sal_Int32 GridLayouter::Implementation::GetMinimumColumnWidth ( 492 ColumnData& rColumn, 493 const ColumnDescriptor& rDescriptor) const 494 { 495 // Start with the minimum width of the whole column. 496 sal_Int32 nMinimumWidth (rDescriptor.GetMinimumWidth()); 497 498 // Take also into account the minimum widths of all cells in the column. 499 ForAllRows(rColumn, iCell) 500 ForAllCells(*iCell, iCellDescriptor) 501 { 502 if (iCellDescriptor->GetGridWidth() != 1) 503 continue; 504 const sal_Int32 nMinimumCellWidth (iCellDescriptor->GetMinimumWidth()); 505 if (nMinimumCellWidth > nMinimumWidth) 506 nMinimumWidth = nMinimumCellWidth; 507 } 508 509 // Make sure that the minimum width does not become larger than 510 // the maximum width of the column. 511 if (nMinimumWidth > rDescriptor.GetMaximumWidth() && rDescriptor.GetMaximumWidth()>0) 512 nMinimumWidth = rDescriptor.GetMaximumWidth(); 513 514 // Add the horizontal padding. 515 return nMinimumWidth 516 + rDescriptor.GetLeftPadding() 517 + rDescriptor.GetRightPadding(); 518 } 519 520 521 522 523 void GridLayouter::Implementation::Paint (void) 524 { 525 const Size aParentSize (mrParent.GetSizePixel()); 526 527 static const Color aSeparatorColor (0x66cdaa); 528 static const Color aLeftPaddingColor (0x98fb98); 529 static const Color aRightPaddingColor (0xff69b4); 530 static const Color aControlOverlayColor (0xffff00); 531 532 sal_Int32 nX (0); 533 mrParent.SetLineColor(); 534 mrParent.SetFillColor(aLeftPaddingColor); 535 ForAllColumnDescriptors(iColumn) 536 { 537 if (iColumn->GetLeftPadding() > 0) 538 { 539 mrParent.DrawRect(Rectangle( 540 nX,0, 541 nX+iColumn->GetLeftPadding(),aParentSize.Height())); 542 } 543 544 nX += iColumn->GetWidth(); 545 } 546 547 nX = 0; 548 mrParent.SetFillColor(aRightPaddingColor); 549 ForAllColumnDescriptors(iColumn) 550 { 551 if (iColumn->GetRightPadding() > 0) 552 { 553 const sal_Int32 nRight (nX + iColumn->GetWidth()); 554 const sal_Int32 nLeft (nRight - iColumn->GetRightPadding()); 555 mrParent.DrawRect(Rectangle( 556 nLeft,0, 557 nRight,aParentSize.Height())); 558 } 559 560 nX += iColumn->GetWidth(); 561 } 562 563 nX = 0; 564 mrParent.SetFillColor(); 565 mrParent.SetLineColor(aSeparatorColor); 566 ForAllColumnDescriptors(iColumn) 567 { 568 mrParent.DrawLine(Point(nX,0), Point(nX,aParentSize.Height())); 569 nX += iColumn->GetWidth(); 570 } 571 572 mrParent.SetFillColor(); 573 mrParent.SetLineColor(aControlOverlayColor); 574 ForAllColumns(iColumn,nColumnIndex) 575 ForAllRows(*iColumn, iCell) 576 ForAllCells(*iCell, iCellDescriptor) 577 { 578 Window* pControl (iCellDescriptor->GetControl()); 579 if (pControl!=NULL && pControl->IsVisible()) 580 { 581 Rectangle aBox ( 582 pControl->GetPosPixel(), 583 pControl->GetSizePixel()); 584 --aBox.Left(); 585 --aBox.Top(); 586 ++aBox.Right(); 587 ++aBox.Bottom(); 588 mrParent.DrawRect(aBox); 589 } 590 } 591 } 592 593 594 595 596 //===== ColumnDescriptor ====================================================== 597 598 ColumnDescriptor::ColumnDescriptor (void) 599 : mnWeight(1), 600 mnMinimumWidth(0), 601 mnMaximumWidth(-1), 602 mnLeftPadding(0), 603 mnRightPadding(0), 604 mnWidth(0) 605 { 606 } 607 608 609 610 611 ColumnDescriptor::~ColumnDescriptor (void) 612 { 613 } 614 615 616 617 618 ColumnDescriptor& ColumnDescriptor::SetWeight (const sal_Int32 nWeight) 619 { 620 mnWeight = nWeight; 621 622 return *this; 623 } 624 625 626 627 628 ColumnDescriptor& ColumnDescriptor::SetMinimumWidth (const sal_Int32 nWidth) 629 { 630 mnMinimumWidth = nWidth; 631 632 return *this; 633 } 634 635 636 637 ColumnDescriptor& ColumnDescriptor::SetFixedWidth (const sal_Int32 nWidth) 638 { 639 mnMinimumWidth = nWidth; 640 mnMaximumWidth = nWidth; 641 642 return *this; 643 } 644 645 646 647 ColumnDescriptor& ColumnDescriptor::SetLeftPadding (const sal_Int32 nPadding) 648 { 649 mnLeftPadding = nPadding; 650 651 return *this; 652 } 653 654 655 656 657 ColumnDescriptor& ColumnDescriptor::SetRightPadding (const sal_Int32 nPadding) 658 { 659 mnRightPadding = nPadding; 660 661 return *this; 662 } 663 664 665 666 667 sal_Int32 ColumnDescriptor::GetWeight (void) const 668 { 669 return mnWeight; 670 } 671 672 673 674 675 sal_Int32 ColumnDescriptor::GetMinimumWidth (void) const 676 { 677 return mnMinimumWidth; 678 } 679 680 681 682 683 sal_Int32 ColumnDescriptor::GetMaximumWidth (void) const 684 { 685 return mnMaximumWidth; 686 } 687 688 689 690 691 sal_Int32 ColumnDescriptor::GetTotalMaximumWidth (void) const 692 { 693 return mnMaximumWidth + mnLeftPadding + mnRightPadding; 694 } 695 696 697 698 699 sal_Int32 ColumnDescriptor::GetLeftPadding (void) const 700 { 701 return mnLeftPadding; 702 } 703 704 705 706 707 sal_Int32 ColumnDescriptor::GetRightPadding (void) const 708 { 709 return mnRightPadding; 710 } 711 712 713 714 715 void ColumnDescriptor::SetWidth (const sal_Int32 nWidth) 716 { 717 mnWidth = nWidth; 718 } 719 720 721 722 723 sal_Int32 ColumnDescriptor::GetWidth (void) const 724 { 725 return mnWidth; 726 } 727 728 } } // end of namespace sfx2::sidebar 729