]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/fl/rowlayoutpl.cpp
glibc's vswprintf doesn't nul terminate on truncation.
[wxWidgets.git] / contrib / src / fl / rowlayoutpl.cpp
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$
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
30 IMPLEMENT_DYNAMIC_CLASS( cbRowLayoutPlugin, cbPluginBase )
31
32 BEGIN_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
41 END_EVENT_TABLE()
42
43 cbRowLayoutPlugin::cbRowLayoutPlugin(void)
44 : mpPane( 0 )
45 {}
46
47 cbRowLayoutPlugin::cbRowLayoutPlugin( wxFrameLayout* pPanel, int paneMask )
48
49 : cbPluginBase( pPanel, paneMask ),
50 mpPane( 0 )
51 {}
52
53 void 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
115 void 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
162 void 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
215 void 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
318 void 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
328 int 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
344 void 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
397 void 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
502 void 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
553 void 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
584 void 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
604 int 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
616 void 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
633 void 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
655 void 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
677 void 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
689 void 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
795 void 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
808 void 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
864 void 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
945 void 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
994 void 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
1035 void 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
1097 void 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