]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/fl/rowlayoutpl.cpp
Updated version and other minor tweaks
[wxWidgets.git] / contrib / src / fl / rowlayoutpl.cpp
CommitLineData
8e08b761 1/////////////////////////////////////////////////////////////////////////////
4cbc57f0
JS
2// Name: rowlayoutpl.cpp
3// Purpose: cbRowLayoutPlugin implementation.
8e08b761
JS
4// Author: Aleksandras Gluchovas
5// Modified by:
6// Created: 09/09/98
7// RCS-ID: $Id$
8// Copyright: (c) Aleksandras Gluchovas
4cbc57f0 9// Licence: wxWindows licence
8e08b761
JS
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
34IMPLEMENT_DYNAMIC_CLASS( cbRowLayoutPlugin, cbPluginBase )
35
36BEGIN_EVENT_TABLE( cbRowLayoutPlugin, cbPluginBase )
37
11a68fa3
GT
38 EVT_PL_LAYOUT_ROW ( cbRowLayoutPlugin::OnLayoutRow )
39 EVT_PL_LAYOUT_ROWS( cbRowLayoutPlugin::OnLayoutRows )
40 EVT_PL_RESIZE_ROW ( cbRowLayoutPlugin::OnResizeRow )
8e08b761 41
11a68fa3
GT
42 EVT_PL_INSERT_BAR ( cbRowLayoutPlugin::OnInsertBar )
43 EVT_PL_REMOVE_BAR ( cbRowLayoutPlugin::OnRemoveBar )
8e08b761
JS
44
45END_EVENT_TABLE()
46
47cbRowLayoutPlugin::cbRowLayoutPlugin(void)
11a68fa3 48 : mpPane( 0 )
8e08b761
JS
49{}
50
51cbRowLayoutPlugin::cbRowLayoutPlugin( wxFrameLayout* pPanel, int paneMask )
52
11a68fa3
GT
53 : cbPluginBase( pPanel, paneMask ),
54 mpPane( 0 )
8e08b761
JS
55{}
56
57void cbRowLayoutPlugin::CheckIfAtTheBoundary( cbBarInfo* pTheBar, cbRowInfo& rowInfo )
58{
11a68fa3
GT
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
8e08b761 66
11a68fa3 67 if ( !pTheBar->IsFixed() || rowInfo.mHasOnlyFixedBars )
8e08b761 68
11a68fa3 69 return;
8e08b761 70
11a68fa3 71 cbBarInfo* pBar = rowInfo.mBars[ rowInfo.mBars.Count() - 1 ];
8e08b761 72
11a68fa3 73 // slide fixed bars to the right on the right side relative to the pBarNode
8e08b761 74
11a68fa3 75 int prevX = mpPane->mPaneWidth;
8e08b761 76
11a68fa3
GT
77 do
78 {
79 if ( !pBar->IsFixed() )
80 break;
8e08b761 81
11a68fa3 82 wxRect& bounds = pBar->mBounds;
8e08b761 83
11a68fa3 84 bounds.x = prevX - bounds.width;
8e08b761 85
11a68fa3 86 prevX = bounds.x;
8e08b761 87
11a68fa3 88 if ( pBar == pTheBar ) break;
8e08b761 89
11a68fa3
GT
90 pBar = pBar->mpPrev;
91 }
92 while( 1 );
8e08b761 93
11a68fa3 94 // slide fixed bars to the left on the left side relative to the pBarNode
8e08b761 95
11a68fa3 96 pBar = rowInfo.mBars[0];
8e08b761 97
11a68fa3
GT
98 prevX = 0;
99
100 do
101 {
102 if ( pBar->IsFixed() )
8e08b761 103
11a68fa3 104 break;
8e08b761 105
11a68fa3 106 wxRect& bounds = pBar->mBounds;
8e08b761 107
11a68fa3 108 bounds.x = prevX;
8e08b761 109
11a68fa3 110 prevX = bounds.x + bounds.width;
8e08b761 111
11a68fa3 112 if ( pBar == pTheBar ) break;
8e08b761 113
11a68fa3
GT
114 pBar = pBar->mpNext;
115 }
116 while( 1 );
8e08b761
JS
117}
118
119void cbRowLayoutPlugin::ExpandNotFixedBars( cbRowInfo* pRow )
120{
11a68fa3 121 ApplyLengthRatios( pRow );
8e08b761 122
11a68fa3
GT
123 // FIXME:: something's wrong?
124 return;
8e08b761 125
11a68fa3 126 double freeSpc = (double)GetRowFreeSpace( pRow );
8e08b761 127
11a68fa3 128 // calculate sum of precents
8e08b761 129
11a68fa3 130 double pcntSum = 0.0;
8e08b761 131
11a68fa3
GT
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 }
8e08b761 138
11a68fa3 139 // setup bar lengths
8e08b761 140
11a68fa3 141 int curX = 0;
8e08b761 142
11a68fa3
GT
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 }
8e08b761
JS
159}
160
161void cbRowLayoutPlugin::AdjustLengthOfInserted( cbRowInfo* pRow, cbBarInfo* pTheBar )
162{
11a68fa3 163 return; // TBD: Makes following code unreachable
8e08b761 164
11a68fa3 165 // pTheBar is not-fixed
8e08b761
JS
166
167
11a68fa3 168 // FIXME:: what is this for??
8e08b761
JS
169
170#if 1
171
11a68fa3 172 int totalLen = 0;
8e08b761
JS
173
174 size_t i;
11a68fa3 175 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 176 {
11a68fa3
GT
177 if ( !pRow->mBars[i]->IsFixed() )
178 totalLen += pRow->mBars[i]->mBounds.width;
8e08b761
JS
179 }
180
11a68fa3 181 double curWidth = pTheBar->mBounds.width;
8e08b761 182
11a68fa3 183 if ( pRow->mBars.Count() )
8e08b761 184
11a68fa3 185 pTheBar->mBounds.width = int( mpPane->mPaneWidth * (curWidth / double(totalLen)) );
8e08b761
JS
186#else
187
11a68fa3 188 double freeSpc = (double)GetRowFreeSpace( pRow );
8e08b761 189
11a68fa3 190 double pcntSum = 0.0;
8e08b761 191
11a68fa3
GT
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 }
8e08b761 198
11a68fa3
GT
199 // if no longer "balanced", assume that `pTheBar' was previously
200 // removed from this row (kind of AI...)
8e08b761 201
11a68fa3
GT
202 if ( pcntSum < 0.98 )
203
204 pTheBar->mBounds.width = freeSpc * (1.0 - pcntSum);
8e08b761
JS
205#endif
206}
207
11a68fa3
GT
208void cbRowLayoutPlugin::FitBarsToRange( int from, int till,
209 cbBarInfo* pTheBar, cbRowInfo* pRow )
8e08b761 210{
11a68fa3
GT
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 }
8e08b761
JS
309}
310
311void cbRowLayoutPlugin::MinimzeNotFixedBars( cbRowInfo* pRow, cbBarInfo* pBarToPreserve )
312{
313 size_t i;
11a68fa3 314 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 315 {
11a68fa3
GT
316 if ( !pRow->mBars[i]->IsFixed() && pRow->mBars[i] != pBarToPreserve )
317 pRow->mBars[i]->mBounds.width = mpPane->mProps.mMinCBarDim.x;
8e08b761
JS
318 }
319}
320
321int cbRowLayoutPlugin::GetRowFreeSpace( cbRowInfo* pRow )
322{
11a68fa3 323 int freeSpc = mpPane->mPaneWidth;
8e08b761
JS
324
325 size_t i;
11a68fa3 326 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 327 {
11a68fa3
GT
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;
8e08b761
JS
332 }
333
11a68fa3 334 return freeSpc;
8e08b761
JS
335}
336
337void cbRowLayoutPlugin::RecalcLengthRatios( cbRowInfo* pRow )
338{
11a68fa3 339 double freeSpc = double( GetRowFreeSpace( pRow ) );
8e08b761 340
11a68fa3
GT
341 cbBarInfo* pBar = pRow->mBars[0];
342 cbBarInfo* pLastNotFixed = NULL;
8e08b761 343
11a68fa3 344 double pcntLeft = 1.0; // (100%)
8e08b761
JS
345
346#ifdef __EXPERIMENTAL
347
11a68fa3 348 int totalLen = 0;
8e08b761
JS
349
350 size_t i;
11a68fa3 351 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 352 {
11a68fa3
GT
353 if ( !pRow->mBars[i]->IsFixed() )
354 totalLen += pRow->mBars[i]->mBounds.width;
8e08b761
JS
355 }
356#endif
357
358 size_t i;
11a68fa3
GT
359 for ( i = 0; i != pRow->mBars.Count(); ++i )
360 {
361 cbBarInfo& bar = *pRow->mBars[i];
8e08b761 362
11a68fa3
GT
363 if ( !bar.IsFixed() )
364 {
8e08b761
JS
365
366#ifdef __EXPERIMENTAL
367
11a68fa3 368 bar.mLenRatio = double(bar.mBounds.width)/double(totalLen);
8e08b761 369#else
11a68fa3 370 bar.mLenRatio = double(bar.mBounds.width)/freeSpc;
8e08b761
JS
371#endif
372
11a68fa3
GT
373 pcntLeft -= bar.mLenRatio;
374 pLastNotFixed = pBar;
375 }
376 }
8e08b761 377
11a68fa3
GT
378 // attach remainder (the result of lost precision) to the
379 // last not-fixed bar
8e08b761 380
11a68fa3 381#if !defined(__EXPERIMENTAL)
8e08b761 382
11a68fa3
GT
383 if ( pLastNotFixed )
384
385 pLastNotFixed->mLenRatio += pcntLeft;
8e08b761
JS
386#endif
387
388}
389
390void cbRowLayoutPlugin::ApplyLengthRatios( cbRowInfo* pRow )
391{
11a68fa3 392 double pcntSum = 0;
8e08b761 393
11a68fa3 394 // FOR NOW:: all-in-one
8e08b761 395
11a68fa3
GT
396 size_t i = 0;
397 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 398 {
11a68fa3
GT
399 if ( !pRow->mBars[i]->IsFixed() )
400 pcntSum += pRow->mBars[i]->mLenRatio;
8e08b761
JS
401 }
402
11a68fa3
GT
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 )
8e08b761 441 {
11a68fa3
GT
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;
8e08b761 449
11a68fa3 450 bar.mBounds.width = -1; // mark as "squished"
8e08b761 451
11a68fa3 452 pcntSum -= bar.mLenRatio;
8e08b761 453
11a68fa3
GT
454 freeSpc -= mpPane->mProps.mMinCBarDim.x;
455 }
456 }
8e08b761
JS
457 } // for
458
11a68fa3
GT
459 if ( haveSquished )
460 unit = freeSpc / pcntSum;
8e08b761 461
11a68fa3
GT
462 for ( i = 0; i != pRow->mBars.Count(); ++i )
463 {
464 cbBarInfo& bar = *pRow->mBars[i];
8e08b761 465
11a68fa3 466 bar.mBounds.x = prevX;
8e08b761 467
11a68fa3
GT
468 if ( !bar.IsFixed() )
469 {
470 if ( bar.mBounds.width == -1 )
8e08b761 471
11a68fa3
GT
472 bar.mBounds.width = mpPane->mProps.mMinCBarDim.x;
473 else
474 bar.mBounds.width = int( unit * bar.mLenRatio );
8e08b761 475
11a68fa3
GT
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
8e08b761 480
11a68fa3
GT
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 }
8e08b761 487
11a68fa3
GT
488 prevX = bar.mBounds.x + bar.mBounds.width;
489 }
8e08b761
JS
490}
491
492void cbRowLayoutPlugin::DetectBarHandles( cbRowInfo* pRow )
493{
11a68fa3 494 // first pass from left to right (detect left-side handles)
8e08b761 495
11a68fa3 496 bool foundNotFixed = FALSE;
8e08b761
JS
497
498 size_t i;
11a68fa3
GT
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 }
8e08b761 517
11a68fa3 518 // pass from right to left (detect right-side handles)
8e08b761 519
11a68fa3 520 foundNotFixed = FALSE;
8e08b761 521
11a68fa3 522 cbBarInfo* pBar = pRow->mBars[ pRow->mBars.Count() - 1 ];
8e08b761 523
11a68fa3
GT
524 while( pBar )
525 {
526 pBar->mHasRightHandle = FALSE;
8e08b761 527
11a68fa3
GT
528 if ( !pBar->IsFixed() )
529 {
530 if ( foundNotFixed )
8e08b761 531
11a68fa3 532 if ( pBar->mpNext )
8e08b761 533
11a68fa3 534 pBar->mHasRightHandle = TRUE;
8e08b761 535
11a68fa3
GT
536 foundNotFixed = TRUE;
537 }
8e08b761 538
11a68fa3
GT
539 pBar = pBar->mpPrev;
540 }
8e08b761
JS
541}
542
543void cbRowLayoutPlugin::RelayoutNotFixedBarsAround( cbBarInfo* pTheBar, cbRowInfo* pRow )
544{
11a68fa3
GT
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 );
8e08b761
JS
572}
573
574void cbRowLayoutPlugin::LayoutItemsVertically( cbRowInfo& row )
575{
576 size_t i;
11a68fa3
GT
577 for ( i = 0; i != row.mBars.Count(); ++i )
578 {
579 cbBarInfo& bar = *row.mBars[i];
8e08b761 580
11a68fa3 581 bar.mBounds.y = row.mRowY;
8e08b761 582
11a68fa3 583 if ( !bar.IsFixed() )
8e08b761 584
11a68fa3
GT
585 // make all not-fixed bars of equal height
586 bar.mBounds.height = row.mRowHeight;
8e08b761 587
11a68fa3 588 if ( row.mHasUpperHandle )
8e08b761 589
11a68fa3
GT
590 bar.mBounds.y += mpPane->mProps.mResizeHandleSize;
591 }
8e08b761
JS
592}
593
594int cbRowLayoutPlugin::CalcRowHeight( cbRowInfo& row )
595{
11a68fa3 596 int maxHeight = 0;
8e08b761
JS
597
598 size_t i;
11a68fa3
GT
599 for ( i = 0; i != row.mBars.Count(); ++i )
600
601 maxHeight = wxMax( maxHeight, row.mBars[i]->mBounds.height );
8e08b761 602
11a68fa3 603 return maxHeight;
8e08b761
JS
604}
605
606void cbRowLayoutPlugin::StickRightSideBars( cbBarInfo* pToBar )
607{
11a68fa3
GT
608 cbBarInfo* pBar = pToBar->mpNext;
609 cbBarInfo* pPrev = pToBar;
8e08b761 610
11a68fa3
GT
611 while( pBar )
612 {
613 wxRect& cur = pBar->mBounds;
614 wxRect& prev = pPrev->mBounds;
8e08b761 615
11a68fa3 616 cur.x = prev.x + prev.width;
8e08b761 617
11a68fa3
GT
618 pPrev = pBar;
619 pBar = pBar->mpNext;
620 }
8e08b761
JS
621}
622
623void cbRowLayoutPlugin::SlideLeftSideBars( cbBarInfo* pTheBar )
624{
11a68fa3
GT
625 // shift left-side-bars to the left (with respect to "theBar"),
626 // so that they would not obscured by each other
8e08b761 627
11a68fa3
GT
628 cbBarInfo* pBar = pTheBar->mpPrev;
629 cbBarInfo* pPrev = pTheBar;
8e08b761 630
11a68fa3
GT
631 while( pBar )
632 {
633 wxRect& cur = pBar->mBounds;
634 wxRect& prev = pPrev->mBounds;
8e08b761 635
11a68fa3 636 if ( cur.x + cur.width > prev.x )
8e08b761 637
11a68fa3 638 cur.x = prev.x - cur.width;
8e08b761 639
11a68fa3
GT
640 pPrev = pBar;
641 pBar = pBar->mpPrev;
642 }
8e08b761
JS
643}
644
645void cbRowLayoutPlugin::SlideRightSideBars( cbBarInfo* pTheBar )
646{
11a68fa3
GT
647 // shift right-side-bars to the right (with respect to "theBar"),
648 // so that they would not be obscured by each other
8e08b761 649
11a68fa3
GT
650 cbBarInfo* pBar = pTheBar->mpNext;
651 cbBarInfo* pPrev = pTheBar;
8e08b761 652
11a68fa3
GT
653 while( pBar )
654 {
655 wxRect& cur = pBar->mBounds;
656 wxRect& prev = pPrev->mBounds;
8e08b761 657
11a68fa3 658 if ( cur.x < prev.x + prev.width )
8e08b761 659
11a68fa3 660 cur.x = prev.x + prev.width;
8e08b761 661
11a68fa3
GT
662 pPrev = pBar;
663 pBar = pBar->mpNext;
664 }
8e08b761
JS
665}
666
667void cbRowLayoutPlugin::ShiftLeftTrashold( cbBarInfo* pTheBar, cbRowInfo& row )
668{
11a68fa3 669 wxRect& first = row.mBars[0]->mBounds;
8e08b761 670
11a68fa3
GT
671 if ( first.x < 0 )
672 {
673 row.mBars[0]->mBounds.x = 0;
8e08b761 674
11a68fa3
GT
675 SlideRightSideBars( row.mBars[0] );
676 }
8e08b761
JS
677}
678
679void cbRowLayoutPlugin::ShiftRightTrashold( cbBarInfo* pTheBar, cbRowInfo& row )
680{
11a68fa3 681 wxRect& theBar = pTheBar->mBounds;
8e08b761 682
11a68fa3
GT
683 do
684 {
685 cbBarInfo* pBar = pTheBar;
8e08b761 686
11a68fa3 687 // calculate free spece on the left side
8e08b761 688
11a68fa3 689 int leftFreeSpc = 0;
8e08b761 690
11a68fa3
GT
691 while( pBar )
692 {
693 wxRect& cur = pBar->mBounds;
8e08b761 694
11a68fa3
GT
695 if ( pBar->mpPrev )
696 {
697 wxRect& prev = pBar->mpPrev->mBounds;
8e08b761 698
11a68fa3
GT
699 leftFreeSpc += cur.x - prev.x - prev.width;
700 }
701 else
702 leftFreeSpc += cur.x;
8e08b761 703
11a68fa3
GT
704 if ( cur.x < 0 )
705 {
706 leftFreeSpc = 0;
707 break;
708 }
8e08b761 709
11a68fa3
GT
710 pBar = pBar->mpPrev;
711 }
8e08b761 712
11a68fa3 713 pBar = pTheBar;
8e08b761 714
11a68fa3 715 int rightOverflow = 0;
8e08b761 716
11a68fa3 717 if ( pTheBar->IsFixed() )
8e08b761 718
11a68fa3
GT
719 while( pBar )
720 {
721 if ( !pBar->mpNext )
722 {
723 wxRect& cur = pBar->mBounds;
8e08b761 724
11a68fa3 725 if ( cur.x + cur.width > mpPane->mPaneWidth )
8e08b761 726
11a68fa3
GT
727 rightOverflow = cur.x + cur.width - mpPane->mPaneWidth;
728 }
8e08b761 729
11a68fa3
GT
730 pBar = pBar->mpNext;
731 }
8e08b761 732
11a68fa3
GT
733 if ( rightOverflow > 0 )
734 {
735 if ( leftFreeSpc <= 0 ) return;
8e08b761 736
11a68fa3
GT
737 if ( pTheBar->mpNext )
738 {
739 wxRect& next = pTheBar->mpNext->mBounds;
8e08b761 740
11a68fa3
GT
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"
8e08b761 743
11a68fa3
GT
744 if ( next.width < leftFreeSpc )
745 {
746 cbBarInfo* pNext = pTheBar->mpNext;
8e08b761 747
11a68fa3 748 row.mBars.Remove( pNext );
8e08b761 749
11a68fa3 750 row.mBars.Insert( pNext, row.mBars.Index( pTheBar ) );
8e08b761 751
11a68fa3 752 next.x = theBar.x - next.width;
8e08b761 753
11a68fa3 754 // re-setup mpPrev/mpNext references after insertion
8e08b761 755
11a68fa3 756 mpPane->InitLinksForRow( &row );
8e08b761 757
11a68fa3 758 // tighten things
8e08b761 759
11a68fa3
GT
760 StickRightSideBars( pTheBar );
761 SlideLeftSideBars ( pTheBar );
8e08b761 762
11a68fa3
GT
763 continue;
764 }
765 }
8e08b761 766
11a68fa3
GT
767 int leftShift = ( rightOverflow > leftFreeSpc )
768 ? leftFreeSpc
769 : rightOverflow;
8e08b761 770
11a68fa3 771 theBar.x -= leftShift;
8e08b761 772
11a68fa3
GT
773 StickRightSideBars( pTheBar );
774 SlideLeftSideBars ( pTheBar );
8e08b761 775
11a68fa3 776 break;
8e08b761 777
11a68fa3
GT
778 } // end of if ( rightOverflow )
779 else
780 break;
8e08b761 781
11a68fa3 782 } while(1);
8e08b761
JS
783}
784
785void cbRowLayoutPlugin::InsertBefore( cbBarInfo* pBeforeBar,
11a68fa3
GT
786 cbBarInfo* pTheBar,
787 cbRowInfo& row )
8e08b761 788{
11a68fa3 789 if ( pBeforeBar )
8e08b761 790
11a68fa3
GT
791 row.mBars.Insert( pTheBar, row.mBars.Index( pBeforeBar ) );
792 else
793 row.mBars.Add( pTheBar );
8e08b761 794
11a68fa3 795 pTheBar->mpRow = &row;
8e08b761
JS
796}
797
798void cbRowLayoutPlugin::DoInsertBar( cbBarInfo* pTheBar, cbRowInfo& row )
799{
11a68fa3 800 wxRect& theBar = pTheBar->mBounds;
8e08b761 801
11a68fa3
GT
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 } */
8e08b761
JS
809
810 size_t i;
11a68fa3
GT
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
8e08b761
JS
850}
851
852// evnet handlers
853
854void cbRowLayoutPlugin::OnInsertBar( cbInsertBarEvent& event )
855{
11a68fa3
GT
856 cbBarInfo* pBarToInsert = event.mpBar;
857 cbRowInfo* pIntoRow = event.mpRow;
858 mpPane = event.mpPane;
8e08b761 859
11a68fa3 860 if ( !pBarToInsert->IsFixed() )
8e08b761 861
11a68fa3 862 AdjustLengthOfInserted( pIntoRow, pBarToInsert );
8e08b761 863
11a68fa3 864 DoInsertBar( pBarToInsert, *pIntoRow );
8e08b761 865
11a68fa3 866 mpPane->InitLinksForRow( pIntoRow ); // relink "mpNext/mpPrev"s
8e08b761 867
11a68fa3 868 // perform relayouting of the bars after insertion
8e08b761 869
11a68fa3
GT
870 // init bar location info
871 pBarToInsert->mAlignment = event.mpPane->mAlignment;
872 pBarToInsert->mRowNo = event.mpPane->GetRowIndex( pIntoRow );
8e08b761
JS
873
874#ifdef __EXPERIMENTAL
875
11a68fa3 876 if ( !pIntoRow->mHasOnlyFixedBars || !pBarToInsert->IsFixed() )
8e08b761 877
11a68fa3 878 RecalcLengthRatios( pIntoRow );
8e08b761
JS
879
880#endif
881
11a68fa3 882 MinimzeNotFixedBars( pIntoRow, pBarToInsert );
8e08b761 883
11a68fa3
GT
884 SlideLeftSideBars ( pBarToInsert );
885 SlideRightSideBars( pBarToInsert );
8e08b761 886
11a68fa3
GT
887 ShiftLeftTrashold ( pBarToInsert, *pIntoRow );
888 ShiftRightTrashold( pBarToInsert, *pIntoRow );
8e08b761 889
11a68fa3 890 mpPane->SyncRowFlags( pIntoRow );
8e08b761 891
11a68fa3 892 CheckIfAtTheBoundary( pBarToInsert, *pIntoRow );
8e08b761 893
11a68fa3 894 if ( event.mpPane->IsHorizontal() )
8e08b761 895
11a68fa3
GT
896 pBarToInsert->mState = wxCBAR_DOCKED_HORIZONTALLY;
897 else
898 pBarToInsert->mState = wxCBAR_DOCKED_VERTICALLY;
8e08b761 899
11a68fa3
GT
900 if ( !pIntoRow->mHasOnlyFixedBars )
901 {
8e08b761
JS
902
903#ifdef __EXPERIMENTAL
904
11a68fa3 905 ExpandNotFixedBars( pIntoRow );
8e08b761
JS
906#else
907
11a68fa3
GT
908 RelayoutNotFixedBarsAround( pBarToInsert, pIntoRow );
909 RecalcLengthRatios( pIntoRow );
8e08b761
JS
910
911#endif
912
11a68fa3 913 DetectBarHandles( pIntoRow );
8e08b761 914
11a68fa3
GT
915 // do proportional resizing of not-fixed bars
916 ApplyLengthRatios( pIntoRow );
917 }
8e08b761 918
11a68fa3 919 // adjust the bar's docking state
8e08b761 920
11a68fa3
GT
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
8e08b761 925
11a68fa3
GT
926 if ( !pBarToInsert->IsFixed() )
927 {
928 cbBarInfo& bar = *pBarToInsert;
8e08b761 929
11a68fa3
GT
930 bar.mDimInfo.mSizes[ bar.mState ].x = bar.mBounds.width;
931 bar.mDimInfo.mSizes[ bar.mState ].y = bar.mBounds.height;
932 }
8e08b761
JS
933}
934
935void cbRowLayoutPlugin::OnRemoveBar ( cbRemoveBarEvent& event )
936{
11a68fa3
GT
937 cbBarInfo* pBar = event.mpBar;
938 mpPane = event.mpPane;
8e08b761 939
11a68fa3 940 cbRowInfo* pRow = pBar->mpRow;
8e08b761 941
11a68fa3 942 mpLayout->GetUpdatesManager().OnBarWillChange( pBar, pRow, event.mpPane );
8e08b761 943
11a68fa3
GT
944 // invalidate the whole row
945 //pFirst->mpRowInfo->mMgrData.mPrevBounds.x = -1;
8e08b761 946
11a68fa3 947 pRow->mBars.Remove( pBar );
8e08b761 948
11a68fa3
GT
949 // rest bar information after removing it from the row
950 pBar->mpRow = NULL;
951 pBar->mHasLeftHandle = FALSE;
952 pBar->mHasRightHandle = FALSE;
8e08b761 953
11a68fa3 954 mpPane->InitLinksForRow( pRow ); // relink "mpNext/mpPrev"s
8e08b761 955
11a68fa3
GT
956 if ( pRow->mBars.Count() == 0 )
957 {
958 // empty rows should not exist
8e08b761 959
11a68fa3 960 event.mpPane->GetRowList().Remove( pRow );
8e08b761 961
11a68fa3 962 delete pRow;
8e08b761 963
11a68fa3
GT
964 mpPane->InitLinksForRows();
965 }
966 else
967 {
968 // force repainting of bars, in the row, from which the bar was removed
8e08b761 969
11a68fa3
GT
970 // FIXME:: really needed?
971 pRow->mBars[0]->mUMgrData.SetDirty(TRUE);
8e08b761 972
11a68fa3
GT
973 // re-setup mHasOnlyFixedBars flag for the row information
974 event.mpPane->SyncRowFlags( pRow );
8e08b761 975
11a68fa3 976 DetectBarHandles( pRow );
8e08b761 977
11a68fa3 978 if ( !pRow->mHasOnlyFixedBars )
8e08b761 979
11a68fa3
GT
980 ExpandNotFixedBars( pRow );
981 }
8e08b761
JS
982}
983
984void cbRowLayoutPlugin::OnLayoutRow( cbLayoutRowEvent& event )
985{
11a68fa3
GT
986 cbRowInfo* pRow = event.mpRow;
987 mpPane = event.mpPane;
8e08b761 988
11a68fa3 989 MinimzeNotFixedBars( pRow, NULL );
8e08b761 990
11a68fa3
GT
991 if ( !pRow->mHasOnlyFixedBars )
992 {
993 // do proportional resizing of not-fixed bars
994 ApplyLengthRatios( pRow );
995 }
8e08b761 996
11a68fa3
GT
997 cbBarInfo& lastBar = *pRow->mBars[ pRow->mBars.Count() - 1 ];
998 cbBarInfo& firstBar = *pRow->mBars[ 0 ];
8e08b761 999
11a68fa3 1000 // FIXME:: Next line not used
8e08b761
JS
1001 // wxRect& bounds = lastBar.mBounds;
1002
11a68fa3
GT
1003 if ( lastBar.mBounds.x + lastBar.mBounds.width > mpPane->mPaneWidth )
1004 {
1005 lastBar.mBounds.x = mpPane->mPaneWidth - lastBar.mBounds.width;
8e08b761 1006
11a68fa3 1007 // first simulate left-row-edge friction
8e08b761 1008
11a68fa3 1009 SlideLeftSideBars( &lastBar );
8e08b761 1010
11a68fa3 1011 if ( firstBar.mBounds.x < 0 )
8e08b761
JS
1012 firstBar.mBounds.x = 0;
1013
11a68fa3
GT
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"
8e08b761 1018
11a68fa3
GT
1019 SlideRightSideBars( &firstBar );
1020 }
8e08b761 1021
11a68fa3 1022 event.Skip(); // pass event to the next handler
8e08b761
JS
1023}
1024
1025void cbRowLayoutPlugin::OnLayoutRows( cbLayoutRowsEvent& event )
1026{
11a68fa3 1027 mpPane = event.mpPane;
8e08b761 1028
11a68fa3 1029 int curY = 0;
8e08b761
JS
1030
1031 // FIXME:: Next line not used.
11a68fa3 1032 // RowArrayT& arr = mpPane->GetRowList();
8e08b761
JS
1033
1034 size_t i;
11a68fa3
GT
1035 for ( i = 0; i != mpPane->GetRowList().Count(); ++i )
1036 {
1037 cbRowInfo& row = *mpPane->GetRowList()[ i ];
a570d5b3 1038 //mpPane->CalcLengthRatios(& row);
11a68fa3
GT
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 )
8e08b761 1076 row.mRowHeight += mpPane->mProps.mResizeHandleSize;
11a68fa3 1077 if ( row.mHasLowerHandle )
8e08b761
JS
1078 row.mRowHeight += mpPane->mProps.mResizeHandleSize;
1079
11a68fa3
GT
1080 curY += row.mRowHeight;
1081 }
8e08b761 1082
11a68fa3
GT
1083 event.Skip(); // pass event to the next handler - other hookeds plugin
1084 // may also add some "refinements" to the layout now
8e08b761
JS
1085}
1086
1087void cbRowLayoutPlugin::OnResizeRow( cbResizeRowEvent& event )
1088{
11a68fa3
GT
1089 // extract resize-event info
1090 int ofs = event.mHandleOfs;
1091 bool forUpperHandle = event.mForUpperHandle;
1092 cbRowInfo* pTheRow = event.mpRow;
1093 mpPane = event.mpPane;
8e08b761
JS
1094
1095 // FIXME:: Next line not used.
11a68fa3 1096 //int newHeight = pTheRow->mRowHeight;
8e08b761 1097
11a68fa3 1098 int freeSpc = 0;
8e08b761 1099
11a68fa3
GT
1100 if ( forUpperHandle )
1101 {
1102 // calculate available free space from above,
1103 // which can be obtained by squeezing not-fixed height rows
8e08b761 1104
11a68fa3 1105 cbRowInfo* pRow = pTheRow->mpPrev;
8e08b761 1106
11a68fa3
GT
1107 while( pRow )
1108 {
1109 freeSpc += pRow->mRowHeight - event.mpPane->GetMinimalRowHeight( pRow );
8e08b761 1110
11a68fa3
GT
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
8e08b761 1118
11a68fa3 1119 cbRowInfo* pRow = pTheRow->mpNext;
8e08b761 1120
11a68fa3
GT
1121 while( pRow )
1122 {
1123 freeSpc += pRow->mRowHeight - mpPane->GetMinimalRowHeight( pRow );
8e08b761 1124
11a68fa3
GT
1125 pRow = pRow->mpNext;
1126 }
1127 }
8e08b761 1128
11a68fa3 1129 mpLayout->GetUpdatesManager().OnStartChanges();
8e08b761 1130
11a68fa3 1131 int clientSize;
8e08b761 1132
11a68fa3 1133 // allow user adjusting pane vs. client-area space, for upper-handle
8e08b761 1134
11a68fa3 1135 if ( mpPane->IsHorizontal() )
8e08b761 1136
11a68fa3
GT
1137 clientSize = mpLayout->GetClientHeight();
1138 else
1139 clientSize = mpLayout->GetClientWidth();
8e08b761 1140
11a68fa3
GT
1141 if ( forUpperHandle && ofs < -clientSize )
1142 {
1143 int needed = -(ofs + clientSize);
8e08b761 1144
11a68fa3 1145 cbRowInfo* pRow = mpPane->GetRowList()[ 0 ];
8e08b761 1146
11a68fa3 1147 // start squeezing rows from the top row towards bottom
8e08b761 1148
11a68fa3
GT
1149 while( pRow != pTheRow && needed )
1150 {
1151 // only not-fixed rows can be squeezed
8e08b761 1152
11a68fa3
GT
1153 if ( !pRow->mHasOnlyFixedBars )
1154 {
1155 int prevHeight = pRow->mRowHeight;
8e08b761 1156
11a68fa3
GT
1157 int newHeight = wxMax( event.mpPane->GetMinimalRowHeight( pRow ),
1158 prevHeight - needed );
8e08b761 1159
11a68fa3
GT
1160 if ( newHeight != prevHeight )
1161 {
1162 event.mpPane->SetRowHeight( pRow, newHeight );
8e08b761 1163
11a68fa3
GT
1164 needed -= prevHeight - pRow->mRowHeight;
1165 }
1166 }
8e08b761 1167
11a68fa3
GT
1168 pRow = pRow->mpNext;
1169 }
1170 }
8e08b761 1171
11a68fa3 1172 // allow user adjusting pane vs. client-area space, for lower-handle
8e08b761 1173
11a68fa3
GT
1174 if ( !forUpperHandle && ofs > clientSize )
1175 {
1176 int needed = ofs - clientSize;
8e08b761 1177
11a68fa3 1178 cbRowInfo* pRow = mpPane->GetRowList()[ mpPane->GetRowList().Count() - 1 ];
8e08b761 1179
11a68fa3 1180 // start squeezing rows from the bottom towards the top row
8e08b761 1181
11a68fa3
GT
1182 while( pRow && needed )
1183 {
1184 // only not-fixed rows can be squeezed
8e08b761 1185
11a68fa3
GT
1186 if ( !pRow->mHasOnlyFixedBars )
1187 {
1188 int prevHeight = pRow->mRowHeight;
8e08b761 1189
11a68fa3
GT
1190 int newHeight = wxMax( event.mpPane->GetMinimalRowHeight( pRow ),
1191 prevHeight - needed );
8e08b761 1192
11a68fa3
GT
1193 if ( newHeight != prevHeight )
1194 {
1195 event.mpPane->SetRowHeight( pRow, newHeight );
8e08b761 1196
11a68fa3
GT
1197 needed -= prevHeight - pRow->mRowHeight;
1198 }
1199 }
8e08b761 1200
11a68fa3
GT
1201 pRow = pRow->mpPrev;
1202 }
1203 }
8e08b761 1204
11a68fa3
GT
1205 if ( forUpperHandle )
1206
1207 event.mpPane->SetRowHeight( pTheRow, pTheRow->mRowHeight + (-ofs) );
1208 else
1209 event.mpPane->SetRowHeight( pTheRow, pTheRow->mRowHeight + ofs );
8e08b761 1210
11a68fa3 1211 mpLayout->RecalcLayout(FALSE);
8e08b761 1212
11a68fa3
GT
1213 mpLayout->GetUpdatesManager().OnFinishChanges();
1214 mpLayout->GetUpdatesManager().UpdateNow();
8e08b761
JS
1215}
1216