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