1///////////////////////////////////////////////////////////////////////////// 2// Name: rowlayoutpl.cpp 3// Purpose: cbRowLayoutPlugin implementation. 4// Author: Aleksandras Gluchovas 5// Modified by: 6// Created: 09/09/98 7// RCS-ID: $Id: rowlayoutpl.cpp 35650 2005-09-23 12:56:45Z MR $ 8// Copyright: (c) Aleksandras Gluchovas 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// For compilers that support precompilation, includes "wx.h". 13#include "wx/wxprec.h" 14 15#ifdef __BORLANDC__ 16#pragma hdrstop 17#endif 18 19#ifndef WX_PRECOMP 20#include "wx/wx.h" 21#endif 22 23#include "wx/fl/rowlayoutpl.h" 24 25// exerimental "features" are still buggy 26#undef __EXPERIMENTAL 27 28/***** Implementation for class cbRowLayoutPlugin *****/ 29 30IMPLEMENT_DYNAMIC_CLASS( cbRowLayoutPlugin, cbPluginBase ) 31 32BEGIN_EVENT_TABLE( cbRowLayoutPlugin, cbPluginBase ) 33 34 EVT_PL_LAYOUT_ROW ( cbRowLayoutPlugin::OnLayoutRow ) 35 EVT_PL_LAYOUT_ROWS( cbRowLayoutPlugin::OnLayoutRows ) 36 EVT_PL_RESIZE_ROW ( cbRowLayoutPlugin::OnResizeRow ) 37 38 EVT_PL_INSERT_BAR ( cbRowLayoutPlugin::OnInsertBar ) 39 EVT_PL_REMOVE_BAR ( cbRowLayoutPlugin::OnRemoveBar ) 40 41END_EVENT_TABLE() 42 43cbRowLayoutPlugin::cbRowLayoutPlugin(void) 44 : mpPane( 0 ) 45{} 46 47cbRowLayoutPlugin::cbRowLayoutPlugin( wxFrameLayout* pPanel, int paneMask ) 48 49 : cbPluginBase( pPanel, paneMask ), 50 mpPane( 0 ) 51{} 52 53void cbRowLayoutPlugin::CheckIfAtTheBoundary( cbBarInfo* pTheBar, cbRowInfo& rowInfo ) 54{ 55 // this method handles situation, when fixed bar is inserted 56 // into the row, where among fixed bars not-fixed ones are present. 57 // In this case we need to check if the pBarNode appears to be inserted 58 // chain of fixed-bars on the very right or left side of the row, 59 // then all the white-space, such chain should be eliminated, 60 // and the resulting chain justified to the right or the left 61 // side of the row 62 63 if ( !pTheBar->IsFixed() || rowInfo.mHasOnlyFixedBars ) 64 65 return; 66 67 cbBarInfo* pBar = rowInfo.mBars[ rowInfo.mBars.Count() - 1 ]; 68 69 // slide fixed bars to the right on the right side relative to the pBarNode 70 71 int prevX = mpPane->mPaneWidth; 72 73 do 74 { 75 if ( !pBar->IsFixed() ) 76 break; 77 78 wxRect& bounds = pBar->mBounds; 79 80 bounds.x = prevX - bounds.width; 81 82 prevX = bounds.x; 83 84 if ( pBar == pTheBar ) break; 85 86 pBar = pBar->mpPrev; 87 } 88 while( 1 ); 89 90 // slide fixed bars to the left on the left side relative to the pBarNode 91 92 pBar = rowInfo.mBars[0]; 93 94 prevX = 0; 95 96 do 97 { 98 if ( pBar->IsFixed() ) 99 100 break; 101 102 wxRect& bounds = pBar->mBounds; 103 104 bounds.x = prevX; 105 106 prevX = bounds.x + bounds.width; 107 108 if ( pBar == pTheBar ) break; 109 110 pBar = pBar->mpNext; 111 } 112 while( 1 ); 113} 114 115void cbRowLayoutPlugin::ExpandNotFixedBars( cbRowInfo* pRow ) 116{ 117 ApplyLengthRatios( pRow ); 118 119 #if 1 120 121 // FIXME:: something's wrong? 122 return; 123 124 #else 125 126 double freeSpc = (double)GetRowFreeSpace( pRow ); 127 128 // calculate sum of precents 129 130 double pcntSum = 0.0; 131 132 size_t i; 133 for ( i = 0; i != pRow->mBars.Count(); ++i ) 134 { 135 if ( !pRow->mBars[i]->IsFixed() ) 136 pcntSum += pRow->mBars[i]->mLenRatio; 137 } 138 139 // setup bar lengths 140 141 int curX = 0; 142 143 for ( i = 0; i != pRow->mBars.Count(); ++i ) 144 { 145 cbBarInfo& bar = *pRow->mBars[i]; 146 147 if ( !bar.IsFixed() ) 148 { 149 bar.mLenRatio = bar.mLenRatio/(pcntSum); 150 151 bar.mBounds.width = 152 153 wxMax( mpPane->mProps.mMinCBarDim.x, int( freeSpc*bar.mLenRatio ) ); 154 } 155 156 bar.mBounds.x = curX; 157 curX = bar.mBounds.x + bar.mBounds.width; 158 } 159 #endif 160} 161 162void cbRowLayoutPlugin::AdjustLengthOfInserted( cbRowInfo* WXUNUSED(pRow), cbBarInfo* WXUNUSED(pTheBar) ) 163{ 164 return; 165 166#if 0 167 168 // TBD: Makes following code unreachable 169 170 // pTheBar is not-fixed 171 172 // FIXME:: what is this for?? 173 174#if 1 175 176 int totalLen = 0; 177 178 size_t i; 179 for ( i = 0; i != pRow->mBars.Count(); ++i ) 180 { 181 if ( !pRow->mBars[i]->IsFixed() ) 182 totalLen += pRow->mBars[i]->mBounds.width; 183 } 184 185 double curWidth = pTheBar->mBounds.width; 186 187 if ( pRow->mBars.Count() ) 188 189 pTheBar->mBounds.width = int( mpPane->mPaneWidth * (curWidth / double(totalLen)) ); 190#else 191 192 double freeSpc = (double)GetRowFreeSpace( pRow ); 193 194 double pcntSum = 0.0; 195 196 size_t i; 197 for ( i = 0; i != pRow->mBars.Count(); ++i ) 198 { 199 if ( !pRow->mBars[i]->IsFixed() ) 200 pcntSum += pRow->mBars[i]->mLenRatio; 201 } 202 203 // if no longer "balanced", assume that `pTheBar' was previously 204 // removed from this row (kind of AI...) 205 206 if ( pcntSum < 0.98 ) 207 208 pTheBar->mBounds.width = freeSpc * (1.0 - pcntSum); 209#endif 210 211#endif 212 213} 214 215void cbRowLayoutPlugin::FitBarsToRange( int from, int till, 216 cbBarInfo* pTheBar, cbRowInfo* pRow ) 217{ 218 cbBarInfo* pFromBar; 219 cbBarInfo* pTillBar; 220 221 if ( pTheBar->mBounds.x > from ) 222 { 223 // it's range from the left 224 pFromBar = pRow->mBars[0]; 225 pTillBar = pTheBar; 226 } 227 else 228 { 229 pFromBar = pTheBar->mpNext; 230 pTillBar = NULL; 231 } 232 233 // calc free space in the range 234 235 cbBarInfo* pBar = pFromBar; 236 int freeSpc = till-from; 237 double pcntSum = 0; 238 239 while( pBar != pTillBar ) 240 { 241 if ( pBar->IsFixed() ) 242 freeSpc -= pBar->mBounds.width; 243 else 244 pcntSum += pBar->mLenRatio; 245 246 pBar = pBar->mpNext; 247 } 248 249 // adjust not-fixed bar sizes in the range 250 251 pBar = pFromBar; 252 253 while ( pBar != pTillBar ) 254 { 255 if ( !pBar->IsFixed() ) 256 { 257 pBar->mBounds.width = 258 wxMax( mpPane->mProps.mMinCBarDim.x, 259 (int)( ((double)freeSpc) * (pBar->mLenRatio/pcntSum) ) 260 ); 261 } 262 pBar = pBar->mpNext; 263 } 264 265 // layout range, starting from the left-most bar 266 267 pBar = pFromBar; 268 int prevX = from; 269 bool hasNotFixedBars = false; 270 271 while ( pBar != pTillBar ) 272 { 273 wxRect& bounds = pBar->mBounds; 274 275 if ( !pBar->IsFixed() ) 276 { 277 hasNotFixedBars = true; 278 279 freeSpc -= bounds.width; 280 } 281 282 bounds.x = prevX; 283 284 prevX = bounds.x + bounds.width; 285 286 pBar = pBar->mpNext; 287 } 288 289 // make width adjustment for the right-most bar in the range, due to 290 // lost precision when seting widths using f.p. length-ratios 291 292 if ( hasNotFixedBars ) 293 { 294 if ( pTheBar->mBounds.x > from ) 295 { 296 if ( pTillBar->mpPrev ) 297 { 298 wxRect& tillBar = pTillBar->mpPrev->mBounds; 299 300 //tillBar.width = bar.mBounds.x - tillBar.x; 301 tillBar.width += freeSpc; 302 } 303 } 304 else 305 { 306 cbBarInfo* pLast = pRow->mBars[ pRow->mBars.Count() - 1 ]; 307 308 if ( pLast != pTheBar ) 309 { 310 pTheBar->mBounds.width += freeSpc; 311 312 SlideRightSideBars( pTheBar ); 313 } 314 } 315 } 316} 317 318void cbRowLayoutPlugin::MinimzeNotFixedBars( cbRowInfo* pRow, cbBarInfo* pBarToPreserve ) 319{ 320 size_t i; 321 for ( i = 0; i != pRow->mBars.Count(); ++i ) 322 { 323 if ( !pRow->mBars[i]->IsFixed() && pRow->mBars[i] != pBarToPreserve ) 324 pRow->mBars[i]->mBounds.width = mpPane->mProps.mMinCBarDim.x; 325 } 326} 327 328int cbRowLayoutPlugin::GetRowFreeSpace( cbRowInfo* pRow ) 329{ 330 int freeSpc = mpPane->mPaneWidth; 331 332 size_t i; 333 for ( i = 0; i != pRow->mBars.Count(); ++i ) 334 { 335 // not-fixed bars variable length, thus their 336 // dimensions are ignored 337 if ( pRow->mBars[i]->IsFixed() ) 338 freeSpc -= pRow->mBars[i]->mBounds.width; 339 } 340 341 return freeSpc; 342} 343 344void cbRowLayoutPlugin::RecalcLengthRatios( cbRowInfo* pRow ) 345{ 346 double freeSpc = double( GetRowFreeSpace( pRow ) ); 347 348 cbBarInfo* pBar = pRow->mBars[0]; 349 cbBarInfo* pLastNotFixed = NULL; 350 351 double pcntLeft = 1.0; // (100%) 352 353#ifdef __EXPERIMENTAL 354 355 int totalLen = 0; 356 357 size_t i; 358 for ( i = 0; i != pRow->mBars.Count(); ++i ) 359 { 360 if ( !pRow->mBars[i]->IsFixed() ) 361 totalLen += pRow->mBars[i]->mBounds.width; 362 } 363#endif 364 365 size_t i; 366 for ( i = 0; i != pRow->mBars.Count(); ++i ) 367 { 368 cbBarInfo& bar = *pRow->mBars[i]; 369 370 if ( !bar.IsFixed() ) 371 { 372 373#ifdef __EXPERIMENTAL 374 375 bar.mLenRatio = double(bar.mBounds.width)/double(totalLen); 376#else 377 bar.mLenRatio = double(bar.mBounds.width)/freeSpc; 378#endif 379 380 pcntLeft -= bar.mLenRatio; 381 pLastNotFixed = pBar; 382 } 383 } 384 385 // attach remainder (the result of lost precision) to the 386 // last not-fixed bar 387 388#if !defined(__EXPERIMENTAL) 389 390 if ( pLastNotFixed ) 391 392 pLastNotFixed->mLenRatio += pcntLeft; 393#endif 394 395} 396 397void cbRowLayoutPlugin::ApplyLengthRatios( cbRowInfo* pRow ) 398{ 399 size_t i; 400 double pcntSum = 0; 401 402 // FOR NOW:: all-in-one 403 404 for ( i = 0; i != pRow->mBars.Count(); ++i ) 405 { 406 if ( !pRow->mBars[i]->IsFixed() ) 407 pcntSum += pRow->mBars[i]->mLenRatio; 408 } 409 410 /* 411 pBar = node_to_first_bar_node( pRow ); 412 413 while( pBar ) 414 { 415 cbBarInfo& bar = node_to_bar( pBar ); 416 417 if ( !bar.IsFixed() ) 418 419 bar.mLenRatio = pcntSum / bar.mLenRatio; 420 421 pBar = pBar->Next(); 422 } 423 */ 424 425 int prevX = 0; 426 double freeSpc = GetRowFreeSpace( pRow ); 427 428 // tricky stuff (improtant!): 429 // when not-fixed bar is removed from the row and there are 430 // still some other not-fixed ones left in that row, then 431 // the sum of mLenRatio's is no longer 1.0 - this is left 432 // intintionally to handle the case when the removed bar 433 // is returned right back to the row - so that it would retain 434 // it's original dimensions in this row (this is kind of AI...) 435 // 436 // The problem is - when it's remvoed, the sum of 437 // mLenRatio's is not in "balance", i.e. is < 1.0, 438 // it's possible to restore balance, but instead of that 439 // we artifically ajdust freeSpc value in a way that it would 440 // look like total of mLetRatio's is 1.0, thus original 441 // len. ratios are _preserved_: 442 443 if (pcntSum == 0.0) 444 pcntSum = 1.0; 445 446 double unit = freeSpc / pcntSum; 447 448 bool haveSquished = false; 449 450 for ( i = 0; i != pRow->mBars.Count(); ++i ) 451 { 452 if ( !pRow->mBars[i]->IsFixed() ) 453 { 454 cbBarInfo& bar = *pRow->mBars[i]; 455 456 if ( int( unit * bar.mLenRatio ) < mpPane->mProps.mMinCBarDim.x ) 457 { 458 haveSquished = true; 459 460 bar.mBounds.width = -1; // mark as "squished" 461 462 pcntSum -= bar.mLenRatio; 463 464 freeSpc -= mpPane->mProps.mMinCBarDim.x; 465 } 466 } 467 } // for 468 469 if ( haveSquished ) 470 unit = freeSpc / pcntSum; 471 472 for ( i = 0; i != pRow->mBars.Count(); ++i ) 473 { 474 cbBarInfo& bar = *pRow->mBars[i]; 475 476 bar.mBounds.x = prevX; 477 478 if ( !bar.IsFixed() ) 479 { 480 if ( bar.mBounds.width == -1 ) 481 482 bar.mBounds.width = mpPane->mProps.mMinCBarDim.x; 483 else 484 bar.mBounds.width = int( unit * bar.mLenRatio ); 485 486 // a little bit of AI: 487 // memorize bar's height and width, when docked in 488 // the current orientation - by making the current 489 // dimensions to be "preffered" ones for this docking state 490 491 if ( !bar.IsFixed() ) 492 { 493 bar.mDimInfo.mSizes[ bar.mState ].x = bar.mBounds.width; 494 bar.mDimInfo.mSizes[ bar.mState ].y = bar.mBounds.height; 495 } 496 } 497 498 prevX = bar.mBounds.x + bar.mBounds.width; 499 } 500} 501 502void cbRowLayoutPlugin::DetectBarHandles( cbRowInfo* pRow ) 503{ 504 // first pass from left to right (detect left-side handles) 505 506 bool foundNotFixed = false; 507 508 size_t i; 509 for ( i = 0; i != pRow->mBars.Count(); ++i ) 510 { 511 cbBarInfo& bar = *pRow->mBars[i]; 512 513 bar.mHasLeftHandle = false; 514 515 if ( !bar.IsFixed() ) 516 { 517 if ( foundNotFixed ) 518 519 if ( bar.mpPrev && 520 bar.mpPrev->IsFixed() ) 521 522 bar.mHasLeftHandle = true; 523 524 foundNotFixed = true; 525 } 526 } 527 528 // pass from right to left (detect right-side handles) 529 530 foundNotFixed = false; 531 532 cbBarInfo* pBar = pRow->mBars[ pRow->mBars.Count() - 1 ]; 533 534 while( pBar ) 535 { 536 pBar->mHasRightHandle = false; 537 538 if ( !pBar->IsFixed() ) 539 { 540 if ( foundNotFixed ) 541 542 if ( pBar->mpNext ) 543 544 pBar->mHasRightHandle = true; 545 546 foundNotFixed = true; 547 } 548 549 pBar = pBar->mpPrev; 550 } 551} 552 553void cbRowLayoutPlugin::RelayoutNotFixedBarsAround( cbBarInfo* pTheBar, cbRowInfo* pRow ) 554{ 555 if ( !pTheBar->mpPrev ) 556 { 557 if ( !pTheBar->IsFixed() ) 558 { 559 // this bar the first in the row, move it's 560 // left edge to the very left 561 pTheBar->mBounds.width += pTheBar->mBounds.x; 562 pTheBar->mBounds.x = 0; 563 } 564 } 565 else 566 FitBarsToRange( 0, pTheBar->mBounds.x, pTheBar, pRow ); 567 568 if ( !pTheBar->mpNext ) 569 { 570 if ( !pTheBar->IsFixed() ) 571 { 572 // this bar is the last one, move it's 573 // right edge to the very right 574 575 pTheBar->mBounds.width = mpPane->mPaneWidth - pTheBar->mBounds.x; 576 } 577 } 578 else 579 FitBarsToRange( pTheBar->mBounds.x + pTheBar->mBounds.width, mpPane->mPaneWidth, 580 pTheBar, pRow 581 ); 582} 583 584void cbRowLayoutPlugin::LayoutItemsVertically( cbRowInfo& row ) 585{ 586 size_t i; 587 for ( i = 0; i != row.mBars.Count(); ++i ) 588 { 589 cbBarInfo& bar = *row.mBars[i]; 590 591 bar.mBounds.y = row.mRowY; 592 593 if ( !bar.IsFixed() ) 594 595 // make all not-fixed bars of equal height 596 bar.mBounds.height = row.mRowHeight; 597 598 if ( row.mHasUpperHandle ) 599 600 bar.mBounds.y += mpPane->mProps.mResizeHandleSize; 601 } 602} 603 604int cbRowLayoutPlugin::CalcRowHeight( cbRowInfo& row ) 605{ 606 int maxHeight = 0; 607 608 size_t i; 609 for ( i = 0; i != row.mBars.Count(); ++i ) 610 611 maxHeight = wxMax( maxHeight, row.mBars[i]->mBounds.height ); 612 613 return maxHeight; 614} 615 616void cbRowLayoutPlugin::StickRightSideBars( cbBarInfo* pToBar ) 617{ 618 cbBarInfo* pBar = pToBar->mpNext; 619 cbBarInfo* pPrev = pToBar; 620 621 while( pBar ) 622 { 623 wxRect& cur = pBar->mBounds; 624 wxRect& prev = pPrev->mBounds; 625 626 cur.x = prev.x + prev.width; 627 628 pPrev = pBar; 629 pBar = pBar->mpNext; 630 } 631} 632 633void cbRowLayoutPlugin::SlideLeftSideBars( cbBarInfo* pTheBar ) 634{ 635 // shift left-side-bars to the left (with respect to "theBar"), 636 // so that they would not obscured by each other 637 638 cbBarInfo* pBar = pTheBar->mpPrev; 639 cbBarInfo* pPrev = pTheBar; 640 641 while( pBar ) 642 { 643 wxRect& cur = pBar->mBounds; 644 wxRect& prev = pPrev->mBounds; 645 646 if ( cur.x + cur.width > prev.x ) 647 648 cur.x = prev.x - cur.width; 649 650 pPrev = pBar; 651 pBar = pBar->mpPrev; 652 } 653} 654 655void cbRowLayoutPlugin::SlideRightSideBars( cbBarInfo* pTheBar ) 656{ 657 // shift right-side-bars to the right (with respect to "theBar"), 658 // so that they would not be obscured by each other 659 660 cbBarInfo* pBar = pTheBar->mpNext; 661 cbBarInfo* pPrev = pTheBar; 662 663 while( pBar ) 664 { 665 wxRect& cur = pBar->mBounds; 666 wxRect& prev = pPrev->mBounds; 667 668 if ( cur.x < prev.x + prev.width ) 669 670 cur.x = prev.x + prev.width; 671 672 pPrev = pBar; 673 pBar = pBar->mpNext; 674 } 675} 676 677void cbRowLayoutPlugin::ShiftLeftTrashold( cbBarInfo* WXUNUSED(pTheBar), cbRowInfo& row ) 678{ 679 wxRect& first = row.mBars[0]->mBounds; 680 681 if ( first.x < 0 ) 682 { 683 row.mBars[0]->mBounds.x = 0; 684 685 SlideRightSideBars( row.mBars[0] ); 686 } 687} 688 689void cbRowLayoutPlugin::ShiftRightTrashold( cbBarInfo* pTheBar, cbRowInfo& row ) 690{ 691 wxRect& theBar = pTheBar->mBounds; 692 693 do 694 { 695 cbBarInfo* pBar = pTheBar; 696 697 // calculate free spece on the left side 698 699 int leftFreeSpc = 0; 700 701 while( pBar ) 702 { 703 wxRect& cur = pBar->mBounds; 704 705 if ( pBar->mpPrev ) 706 { 707 wxRect& prev = pBar->mpPrev->mBounds; 708 709 leftFreeSpc += cur.x - prev.x - prev.width; 710 } 711 else 712 leftFreeSpc += cur.x; 713 714 if ( cur.x < 0 ) 715 { 716 leftFreeSpc = 0; 717 break; 718 } 719 720 pBar = pBar->mpPrev; 721 } 722 723 pBar = pTheBar; 724 725 int rightOverflow = 0; 726 727 if ( pTheBar->IsFixed() ) 728 729 while( pBar ) 730 { 731 if ( !pBar->mpNext ) 732 { 733 wxRect& cur = pBar->mBounds; 734 735 if ( cur.x + cur.width > mpPane->mPaneWidth ) 736 737 rightOverflow = cur.x + cur.width - mpPane->mPaneWidth; 738 } 739 740 pBar = pBar->mpNext; 741 } 742 743 if ( rightOverflow > 0 ) 744 { 745 if ( leftFreeSpc <= 0 ) return; 746 747 if ( pTheBar->mpNext ) 748 { 749 wxRect& next = pTheBar->mpNext->mBounds; 750 751 // if there's enough space on the left, move over one half-obscured 752 // bar from the right to the left side with respect to "theBar" 753 754 if ( next.width < leftFreeSpc ) 755 { 756 cbBarInfo* pNext = pTheBar->mpNext; 757 758 row.mBars.Remove( pNext ); 759 760 row.mBars.Insert( pNext, row.mBars.Index( pTheBar ) ); 761 762 next.x = theBar.x - next.width; 763 764 // re-setup mpPrev/mpNext references after insertion 765 766 mpPane->InitLinksForRow( &row ); 767 768 // tighten things 769 770 StickRightSideBars( pTheBar ); 771 SlideLeftSideBars ( pTheBar ); 772 773 continue; 774 } 775 } 776 777 int leftShift = ( rightOverflow > leftFreeSpc ) 778 ? leftFreeSpc 779 : rightOverflow; 780 781 theBar.x -= leftShift; 782 783 StickRightSideBars( pTheBar ); 784 SlideLeftSideBars ( pTheBar ); 785 786 break; 787 788 } // end of if ( rightOverflow ) 789 else 790 break; 791 792 } while(1); 793} 794 795void cbRowLayoutPlugin::InsertBefore( cbBarInfo* pBeforeBar, 796 cbBarInfo* pTheBar, 797 cbRowInfo& row ) 798{ 799 if ( pBeforeBar ) 800 801 row.mBars.Insert( pTheBar, row.mBars.Index( pBeforeBar ) ); 802 else 803 row.mBars.Add( pTheBar ); 804 805 pTheBar->mpRow = &row; 806} 807 808void cbRowLayoutPlugin::DoInsertBar( cbBarInfo* pTheBar, cbRowInfo& row ) 809{ 810 wxRect& theBar = pTheBar->mBounds; 811 812 /* OLD STUFF:: 813 if ( theBar.x < 0 && !node_to_bar( pTheBar ).IsFixed() ) 814 { 815 // AI:: 816 theBar.width += theBar.x; 817 theBar.x = 0; 818 } */ 819 820 size_t i; 821 for ( i = 0; i != row.mBars.Count(); ++i ) 822 { 823 cbBarInfo& bar = *row.mBars[i]; 824 825 wxRect& cur = bar.mBounds; 826 827 // if bar hits the left edge 828 if ( theBar.x <= cur.x ) 829 { 830 InsertBefore( &bar, pTheBar, row ); 831 return; 832 } 833 834 else 835 // if bar hits the right edge 836 if ( theBar.x <= cur.x + cur.width ) 837 { 838 if ( theBar.x + theBar.width > cur.x + cur.width ) 839 { 840 InsertBefore( bar.mpNext, pTheBar, row ); 841 return; 842 } 843 844 // otherwise the bar lies within the bounds of current bar 845 846 int leftDist = theBar.x - cur.x; 847 int rightDist = cur.x + cur.width - (theBar.x + theBar.width); 848 849 if ( leftDist < rightDist ) 850 851 InsertBefore( &bar, pTheBar, row ); 852 else 853 InsertBefore( bar.mpNext, pTheBar, row ); 854 855 return; 856 } 857 } 858 859 InsertBefore( NULL, pTheBar, row ); // insert at the end 860} 861 862// evnet handlers 863 864void cbRowLayoutPlugin::OnInsertBar( cbInsertBarEvent& event ) 865{ 866 cbBarInfo* pBarToInsert = event.mpBar; 867 cbRowInfo* pIntoRow = event.mpRow; 868 mpPane = event.mpPane; 869 870 if ( !pBarToInsert->IsFixed() ) 871 872 AdjustLengthOfInserted( pIntoRow, pBarToInsert ); 873 874 DoInsertBar( pBarToInsert, *pIntoRow ); 875 876 mpPane->InitLinksForRow( pIntoRow ); // relink "mpNext/mpPrev"s 877 878 // perform relayouting of the bars after insertion 879 880 // init bar location info 881 pBarToInsert->mAlignment = event.mpPane->mAlignment; 882 pBarToInsert->mRowNo = event.mpPane->GetRowIndex( pIntoRow ); 883 884#ifdef __EXPERIMENTAL 885 886 if ( !pIntoRow->mHasOnlyFixedBars || !pBarToInsert->IsFixed() ) 887 888 RecalcLengthRatios( pIntoRow ); 889 890#endif 891 892 MinimzeNotFixedBars( pIntoRow, pBarToInsert ); 893 894 SlideLeftSideBars ( pBarToInsert ); 895 SlideRightSideBars( pBarToInsert ); 896 897 ShiftLeftTrashold ( pBarToInsert, *pIntoRow ); 898 ShiftRightTrashold( pBarToInsert, *pIntoRow ); 899 900 mpPane->SyncRowFlags( pIntoRow ); 901 902 CheckIfAtTheBoundary( pBarToInsert, *pIntoRow ); 903 904 if ( event.mpPane->IsHorizontal() ) 905 906 pBarToInsert->mState = wxCBAR_DOCKED_HORIZONTALLY; 907 else 908 pBarToInsert->mState = wxCBAR_DOCKED_VERTICALLY; 909 910 if ( !pIntoRow->mHasOnlyFixedBars ) 911 { 912 913#ifdef __EXPERIMENTAL 914 915 ExpandNotFixedBars( pIntoRow ); 916#else 917 918 RelayoutNotFixedBarsAround( pBarToInsert, pIntoRow ); 919 RecalcLengthRatios( pIntoRow ); 920 921#endif 922 923 DetectBarHandles( pIntoRow ); 924 925 // do proportional resizing of not-fixed bars 926 ApplyLengthRatios( pIntoRow ); 927 } 928 929 // adjust the bar's docking state 930 931 // a little bit of AI: 932 // memorize bar's height and width, when docked in 933 // the current orientation - by making the current 934 // dimensions to be "preferred" ones for this docking state 935 936 if ( !pBarToInsert->IsFixed() ) 937 { 938 cbBarInfo& bar = *pBarToInsert; 939 940 bar.mDimInfo.mSizes[ bar.mState ].x = bar.mBounds.width; 941 bar.mDimInfo.mSizes[ bar.mState ].y = bar.mBounds.height; 942 } 943} 944 945void cbRowLayoutPlugin::OnRemoveBar ( cbRemoveBarEvent& event ) 946{ 947 cbBarInfo* pBar = event.mpBar; 948 mpPane = event.mpPane; 949 950 cbRowInfo* pRow = pBar->mpRow; 951 952 mpLayout->GetUpdatesManager().OnBarWillChange( pBar, pRow, event.mpPane ); 953 954 // invalidate the whole row 955 //pFirst->mpRowInfo->mMgrData.mPrevBounds.x = -1; 956 957 pRow->mBars.Remove( pBar ); 958 959 // rest bar information after removing it from the row 960 pBar->mpRow = NULL; 961 pBar->mHasLeftHandle = false; 962 pBar->mHasRightHandle = false; 963 964 mpPane->InitLinksForRow( pRow ); // relink "mpNext/mpPrev"s 965 966 if ( pRow->mBars.Count() == 0 ) 967 { 968 // empty rows should not exist 969 970 event.mpPane->GetRowList().Remove( pRow ); 971 972 delete pRow; 973 974 mpPane->InitLinksForRows(); 975 } 976 else 977 { 978 // force repainting of bars, in the row, from which the bar was removed 979 980 // FIXME:: really needed? 981 pRow->mBars[0]->mUMgrData.SetDirty(true); 982 983 // re-setup mHasOnlyFixedBars flag for the row information 984 event.mpPane->SyncRowFlags( pRow ); 985 986 DetectBarHandles( pRow ); 987 988 if ( !pRow->mHasOnlyFixedBars ) 989 990 ExpandNotFixedBars( pRow ); 991 } 992} 993 994void cbRowLayoutPlugin::OnLayoutRow( cbLayoutRowEvent& event ) 995{ 996 cbRowInfo* pRow = event.mpRow; 997 mpPane = event.mpPane; 998 999 MinimzeNotFixedBars( pRow, NULL ); 1000 1001 if ( !pRow->mHasOnlyFixedBars ) 1002 { 1003 // do proportional resizing of not-fixed bars 1004 ApplyLengthRatios( pRow ); 1005 } 1006 1007 cbBarInfo& lastBar = *pRow->mBars[ pRow->mBars.Count() - 1 ]; 1008 cbBarInfo& firstBar = *pRow->mBars[ 0 ]; 1009 1010 // FIXME:: Next line not used 1011 // wxRect& bounds = lastBar.mBounds; 1012 1013 if ( lastBar.mBounds.x + lastBar.mBounds.width > mpPane->mPaneWidth ) 1014 { 1015 lastBar.mBounds.x = mpPane->mPaneWidth - lastBar.mBounds.width; 1016 1017 // first simulate left-row-edge friction 1018 1019 SlideLeftSideBars( &lastBar ); 1020 1021 if ( firstBar.mBounds.x < 0 ) 1022 firstBar.mBounds.x = 0; 1023 1024 // then left-row-edge function, though this 1025 // may cause some of the right-side bars going 1026 // out of row bounds, but left-side always 1027 // has the highest "priority" 1028 1029 SlideRightSideBars( &firstBar ); 1030 } 1031 1032 event.Skip(); // pass event to the next handler 1033} 1034 1035void cbRowLayoutPlugin::OnLayoutRows( cbLayoutRowsEvent& event ) 1036{ 1037 mpPane = event.mpPane; 1038 1039 int curY = 0; 1040 1041 // FIXME:: Next line not used. 1042 // RowArrayT& arr = mpPane->GetRowList(); 1043 1044 size_t i; 1045 for ( i = 0; i != mpPane->GetRowList().Count(); ++i ) 1046 { 1047 cbRowInfo& row = *mpPane->GetRowList()[ i ]; 1048 //mpPane->CalcLengthRatios(& row); 1049 1050 // setup "has-handle" flags for rows, which depend on the existence 1051 // of not-fixed bars in the row 1052 1053 if ( !row.mHasOnlyFixedBars ) 1054 { 1055 if ( mpPane->mAlignment == FL_ALIGN_TOP || 1056 mpPane->mAlignment == FL_ALIGN_LEFT ) 1057 { 1058 row.mHasLowerHandle = true; 1059 1060 row.mHasUpperHandle = false; 1061 } 1062 else 1063 { 1064 row.mHasUpperHandle = true; 1065 1066 row.mHasLowerHandle = false; 1067 } 1068 } 1069 else 1070 { 1071 // otherwise, rows with fixed-bars only, have no height-resizing handles 1072 row.mHasUpperHandle = false; 1073 row.mHasLowerHandle = false; 1074 } 1075 1076 // setup vertical positions for items in the row 1077 1078 row.mRowY = curY; 1079 1080 row.mRowWidth = mpPane->mPaneWidth; 1081 row.mRowHeight = CalcRowHeight( row ); 1082 1083 LayoutItemsVertically( row ); 1084 1085 if ( row.mHasUpperHandle ) 1086 row.mRowHeight += mpPane->mProps.mResizeHandleSize; 1087 if ( row.mHasLowerHandle ) 1088 row.mRowHeight += mpPane->mProps.mResizeHandleSize; 1089 1090 curY += row.mRowHeight; 1091 } 1092 1093 event.Skip(); // pass event to the next handler - other hookeds plugin 1094 // may also add some "refinements" to the layout now 1095} 1096 1097void cbRowLayoutPlugin::OnResizeRow( cbResizeRowEvent& event ) 1098{ 1099 // extract resize-event info 1100 int ofs = event.mHandleOfs; 1101 bool forUpperHandle = event.mForUpperHandle; 1102 cbRowInfo* pTheRow = event.mpRow; 1103 mpPane = event.mpPane; 1104 1105 // FIXME:: Next line not used. 1106 //int newHeight = pTheRow->mRowHeight; 1107 1108 if ( forUpperHandle ) 1109 { 1110 // calculate available free space from above, 1111 // which can be obtained by squeezing not-fixed height rows 1112 1113 cbRowInfo* pRow = pTheRow->mpPrev; 1114 1115 while( pRow ) 1116 { 1117 pRow = pRow->mpPrev; 1118 } 1119 } 1120 else 1121 { 1122 // calculate available free space from below, 1123 // which can be obtained by squeezing not-fixed height rows 1124 1125 cbRowInfo* pRow = pTheRow->mpNext; 1126 1127 while( pRow ) 1128 { 1129 pRow = pRow->mpNext; 1130 } 1131 } 1132 1133 mpLayout->GetUpdatesManager().OnStartChanges(); 1134 1135 int clientSize; 1136 1137 // allow user adjusting pane vs. client-area space, for upper-handle 1138 1139 if ( mpPane->IsHorizontal() ) 1140 1141 clientSize = mpLayout->GetClientHeight(); 1142 else 1143 clientSize = mpLayout->GetClientWidth(); 1144 1145 if ( forUpperHandle && ofs < -clientSize ) 1146 { 1147 int needed = -(ofs + clientSize); 1148 1149 cbRowInfo* pRow = mpPane->GetRowList()[ 0 ]; 1150 1151 // start squeezing rows from the top row towards bottom 1152 1153 while( pRow != pTheRow && needed ) 1154 { 1155 // only not-fixed rows can be squeezed 1156 1157 if ( !pRow->mHasOnlyFixedBars ) 1158 { 1159 int prevHeight = pRow->mRowHeight; 1160 1161 int newHeight = wxMax( event.mpPane->GetMinimalRowHeight( pRow ), 1162 prevHeight - needed ); 1163 1164 if ( newHeight != prevHeight ) 1165 { 1166 event.mpPane->SetRowHeight( pRow, newHeight ); 1167 1168 needed -= prevHeight - pRow->mRowHeight; 1169 } 1170 } 1171 1172 pRow = pRow->mpNext; 1173 } 1174 } 1175 1176 // allow user adjusting pane vs. client-area space, for lower-handle 1177 1178 if ( !forUpperHandle && ofs > clientSize ) 1179 { 1180 int needed = ofs - clientSize; 1181 1182 cbRowInfo* pRow = mpPane->GetRowList()[ mpPane->GetRowList().Count() - 1 ]; 1183 1184 // start squeezing rows from the bottom towards the top row 1185 1186 while( pRow && needed ) 1187 { 1188 // only not-fixed rows can be squeezed 1189 1190 if ( !pRow->mHasOnlyFixedBars ) 1191 { 1192 int prevHeight = pRow->mRowHeight; 1193 1194 int newHeight = wxMax( event.mpPane->GetMinimalRowHeight( pRow ), 1195 prevHeight - needed ); 1196 1197 if ( newHeight != prevHeight ) 1198 { 1199 event.mpPane->SetRowHeight( pRow, newHeight ); 1200 1201 needed -= prevHeight - pRow->mRowHeight; 1202 } 1203 } 1204 1205 pRow = pRow->mpPrev; 1206 } 1207 } 1208 1209 if ( forUpperHandle ) 1210 1211 event.mpPane->SetRowHeight( pTheRow, pTheRow->mRowHeight + (-ofs) ); 1212 else 1213 event.mpPane->SetRowHeight( pTheRow, pTheRow->mRowHeight + ofs ); 1214 1215 mpLayout->RecalcLayout(false); 1216 1217 mpLayout->GetUpdatesManager().OnFinishChanges(); 1218 mpLayout->GetUpdatesManager().UpdateNow(); 1219} 1220 1221