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