]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/fl/rowlayoutpl.cpp
Don't use a saved label size incase the size changes. Patch from Hong Yuan.
[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 10/////////////////////////////////////////////////////////////////////////////
18c45cd6 11
8e08b761
JS
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16#pragma hdrstop
17#endif
18
19#ifndef WX_PRECOMP
20#include "wx/wx.h"
21#endif
22
23#include "wx/fl/rowlayoutpl.h"
24
25// exerimental "features" are still buggy
26#undef __EXPERIMENTAL
27
28/***** Implementation for class cbRowLayoutPlugin *****/
29
30IMPLEMENT_DYNAMIC_CLASS( cbRowLayoutPlugin, cbPluginBase )
31
32BEGIN_EVENT_TABLE( cbRowLayoutPlugin, cbPluginBase )
33
11a68fa3
GT
34 EVT_PL_LAYOUT_ROW ( cbRowLayoutPlugin::OnLayoutRow )
35 EVT_PL_LAYOUT_ROWS( cbRowLayoutPlugin::OnLayoutRows )
36 EVT_PL_RESIZE_ROW ( cbRowLayoutPlugin::OnResizeRow )
8e08b761 37
11a68fa3
GT
38 EVT_PL_INSERT_BAR ( cbRowLayoutPlugin::OnInsertBar )
39 EVT_PL_REMOVE_BAR ( cbRowLayoutPlugin::OnRemoveBar )
8e08b761
JS
40
41END_EVENT_TABLE()
42
43cbRowLayoutPlugin::cbRowLayoutPlugin(void)
11a68fa3 44 : mpPane( 0 )
8e08b761
JS
45{}
46
47cbRowLayoutPlugin::cbRowLayoutPlugin( wxFrameLayout* pPanel, int paneMask )
48
11a68fa3
GT
49 : cbPluginBase( pPanel, paneMask ),
50 mpPane( 0 )
8e08b761
JS
51{}
52
53void cbRowLayoutPlugin::CheckIfAtTheBoundary( cbBarInfo* pTheBar, cbRowInfo& rowInfo )
54{
11a68fa3
GT
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,
18c45cd6 60 // and the resulting chain justified to the right or the left
11a68fa3 61 // side of the row
8e08b761 62
18c45cd6 63 if ( !pTheBar->IsFixed() || rowInfo.mHasOnlyFixedBars )
8e08b761 64
11a68fa3 65 return;
8e08b761 66
11a68fa3 67 cbBarInfo* pBar = rowInfo.mBars[ rowInfo.mBars.Count() - 1 ];
8e08b761 68
11a68fa3 69 // slide fixed bars to the right on the right side relative to the pBarNode
8e08b761 70
11a68fa3 71 int prevX = mpPane->mPaneWidth;
8e08b761 72
11a68fa3
GT
73 do
74 {
18c45cd6 75 if ( !pBar->IsFixed() )
11a68fa3 76 break;
8e08b761 77
11a68fa3 78 wxRect& bounds = pBar->mBounds;
8e08b761 79
11a68fa3 80 bounds.x = prevX - bounds.width;
8e08b761 81
11a68fa3 82 prevX = bounds.x;
8e08b761 83
11a68fa3 84 if ( pBar == pTheBar ) break;
8e08b761 85
11a68fa3
GT
86 pBar = pBar->mpPrev;
87 }
88 while( 1 );
8e08b761 89
18c45cd6 90 // slide fixed bars to the left on the left side relative to the pBarNode
8e08b761 91
11a68fa3 92 pBar = rowInfo.mBars[0];
8e08b761 93
11a68fa3 94 prevX = 0;
18c45cd6 95
11a68fa3
GT
96 do
97 {
18c45cd6 98 if ( pBar->IsFixed() )
8e08b761 99
11a68fa3 100 break;
8e08b761 101
11a68fa3 102 wxRect& bounds = pBar->mBounds;
8e08b761 103
11a68fa3 104 bounds.x = prevX;
8e08b761 105
11a68fa3 106 prevX = bounds.x + bounds.width;
8e08b761 107
11a68fa3 108 if ( pBar == pTheBar ) break;
8e08b761 109
11a68fa3
GT
110 pBar = pBar->mpNext;
111 }
112 while( 1 );
8e08b761
JS
113}
114
115void cbRowLayoutPlugin::ExpandNotFixedBars( cbRowInfo* pRow )
116{
11a68fa3 117 ApplyLengthRatios( pRow );
8e08b761 118
196be0f1
JS
119 #if 1
120
11a68fa3
GT
121 // FIXME:: something's wrong?
122 return;
8e08b761 123
196be0f1
JS
124 #else
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
18c45cd6
WS
151 bar.mBounds.width =
152
11a68fa3
GT
153 wxMax( mpPane->mProps.mMinCBarDim.x, int( freeSpc*bar.mLenRatio ) );
154 }
18c45cd6 155
11a68fa3
GT
156 bar.mBounds.x = curX;
157 curX = bar.mBounds.x + bar.mBounds.width;
158 }
196be0f1 159 #endif
8e08b761
JS
160}
161
196be0f1 162void cbRowLayoutPlugin::AdjustLengthOfInserted( cbRowInfo* WXUNUSED(pRow), cbBarInfo* WXUNUSED(pTheBar) )
8e08b761 163{
196be0f1 164 return;
8e08b761 165
196be0f1
JS
166#if 0
167
168 // TBD: Makes following code unreachable
8e08b761 169
196be0f1 170 // pTheBar is not-fixed
8e08b761 171
11a68fa3 172 // FIXME:: what is this for??
8e08b761
JS
173
174#if 1
175
11a68fa3 176 int totalLen = 0;
8e08b761
JS
177
178 size_t i;
11a68fa3 179 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 180 {
11a68fa3
GT
181 if ( !pRow->mBars[i]->IsFixed() )
182 totalLen += pRow->mBars[i]->mBounds.width;
8e08b761
JS
183 }
184
11a68fa3 185 double curWidth = pTheBar->mBounds.width;
8e08b761 186
11a68fa3 187 if ( pRow->mBars.Count() )
8e08b761 188
11a68fa3 189 pTheBar->mBounds.width = int( mpPane->mPaneWidth * (curWidth / double(totalLen)) );
8e08b761
JS
190#else
191
11a68fa3 192 double freeSpc = (double)GetRowFreeSpace( pRow );
8e08b761 193
11a68fa3 194 double pcntSum = 0.0;
8e08b761 195
11a68fa3
GT
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 }
8e08b761 202
11a68fa3
GT
203 // if no longer "balanced", assume that `pTheBar' was previously
204 // removed from this row (kind of AI...)
8e08b761 205
11a68fa3
GT
206 if ( pcntSum < 0.98 )
207
208 pTheBar->mBounds.width = freeSpc * (1.0 - pcntSum);
8e08b761 209#endif
196be0f1
JS
210
211#endif
212
8e08b761
JS
213}
214
11a68fa3
GT
215void cbRowLayoutPlugin::FitBarsToRange( int from, int till,
216 cbBarInfo* pTheBar, cbRowInfo* pRow )
8e08b761 217{
8552e6f0
MB
218 cbBarInfo* pFromBar;
219 cbBarInfo* pTillBar;
11a68fa3
GT
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,
18c45cd6 259 (int)( ((double)freeSpc) * (pBar->mLenRatio/pcntSum) )
11a68fa3
GT
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;
c82c42d4 269 bool hasNotFixedBars = false;
11a68fa3
GT
270
271 while ( pBar != pTillBar )
272 {
273 wxRect& bounds = pBar->mBounds;
274
275 if ( !pBar->IsFixed() )
276 {
c82c42d4 277 hasNotFixedBars = true;
11a68fa3
GT
278
279 freeSpc -= bounds.width;
280 }
281
282 bounds.x = prevX;
283
284 prevX = bounds.x + bounds.width;
18c45cd6 285
11a68fa3
GT
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 }
8e08b761
JS
316}
317
318void cbRowLayoutPlugin::MinimzeNotFixedBars( cbRowInfo* pRow, cbBarInfo* pBarToPreserve )
319{
320 size_t i;
11a68fa3 321 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 322 {
11a68fa3
GT
323 if ( !pRow->mBars[i]->IsFixed() && pRow->mBars[i] != pBarToPreserve )
324 pRow->mBars[i]->mBounds.width = mpPane->mProps.mMinCBarDim.x;
8e08b761
JS
325 }
326}
327
328int cbRowLayoutPlugin::GetRowFreeSpace( cbRowInfo* pRow )
329{
11a68fa3 330 int freeSpc = mpPane->mPaneWidth;
8e08b761
JS
331
332 size_t i;
11a68fa3 333 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 334 {
11a68fa3
GT
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;
8e08b761
JS
339 }
340
11a68fa3 341 return freeSpc;
8e08b761
JS
342}
343
344void cbRowLayoutPlugin::RecalcLengthRatios( cbRowInfo* pRow )
345{
11a68fa3 346 double freeSpc = double( GetRowFreeSpace( pRow ) );
8e08b761 347
11a68fa3
GT
348 cbBarInfo* pBar = pRow->mBars[0];
349 cbBarInfo* pLastNotFixed = NULL;
8e08b761 350
11a68fa3 351 double pcntLeft = 1.0; // (100%)
8e08b761
JS
352
353#ifdef __EXPERIMENTAL
354
11a68fa3 355 int totalLen = 0;
8e08b761
JS
356
357 size_t i;
11a68fa3 358 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 359 {
11a68fa3
GT
360 if ( !pRow->mBars[i]->IsFixed() )
361 totalLen += pRow->mBars[i]->mBounds.width;
8e08b761
JS
362 }
363#endif
364
365 size_t i;
11a68fa3
GT
366 for ( i = 0; i != pRow->mBars.Count(); ++i )
367 {
368 cbBarInfo& bar = *pRow->mBars[i];
8e08b761 369
11a68fa3
GT
370 if ( !bar.IsFixed() )
371 {
8e08b761
JS
372
373#ifdef __EXPERIMENTAL
374
11a68fa3 375 bar.mLenRatio = double(bar.mBounds.width)/double(totalLen);
8e08b761 376#else
11a68fa3 377 bar.mLenRatio = double(bar.mBounds.width)/freeSpc;
8e08b761
JS
378#endif
379
11a68fa3
GT
380 pcntLeft -= bar.mLenRatio;
381 pLastNotFixed = pBar;
382 }
383 }
8e08b761 384
11a68fa3
GT
385 // attach remainder (the result of lost precision) to the
386 // last not-fixed bar
8e08b761 387
18c45cd6 388#if !defined(__EXPERIMENTAL)
8e08b761 389
11a68fa3 390 if ( pLastNotFixed )
18c45cd6 391
11a68fa3 392 pLastNotFixed->mLenRatio += pcntLeft;
8e08b761
JS
393#endif
394
395}
396
397void cbRowLayoutPlugin::ApplyLengthRatios( cbRowInfo* pRow )
398{
8552e6f0 399 size_t i;
11a68fa3 400 double pcntSum = 0;
8e08b761 401
11a68fa3 402 // FOR NOW:: all-in-one
8e08b761 403
11a68fa3 404 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 405 {
11a68fa3
GT
406 if ( !pRow->mBars[i]->IsFixed() )
407 pcntSum += pRow->mBars[i]->mLenRatio;
8e08b761
JS
408 }
409
11a68fa3
GT
410 /*
411 pBar = node_to_first_bar_node( pRow );
18c45cd6 412
11a68fa3
GT
413 while( pBar )
414 {
415 cbBarInfo& bar = node_to_bar( pBar );
416
417 if ( !bar.IsFixed() )
18c45cd6 418
11a68fa3
GT
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 //
18c45cd6 436 // The problem is - when it's remvoed, the sum of
11a68fa3
GT
437 // mLenRatio's is not in "balance", i.e. is < 1.0,
438 // it's possible to restore balance, but instead of that
18c45cd6 439 // we artifically ajdust freeSpc value in a way that it would
11a68fa3
GT
440 // look like total of mLetRatio's is 1.0, thus original
441 // len. ratios are _preserved_:
442
8ca3dfcd
JS
443 if (pcntSum == 0.0)
444 pcntSum = 1.0;
445
11a68fa3
GT
446 double unit = freeSpc / pcntSum;
447
c82c42d4 448 bool haveSquished = false;
11a68fa3
GT
449
450 for ( i = 0; i != pRow->mBars.Count(); ++i )
8e08b761 451 {
11a68fa3
GT
452 if ( !pRow->mBars[i]->IsFixed() )
453 {
18c45cd6
WS
454 cbBarInfo& bar = *pRow->mBars[i];
455
11a68fa3
GT
456 if ( int( unit * bar.mLenRatio ) < mpPane->mProps.mMinCBarDim.x )
457 {
c82c42d4 458 haveSquished = true;
8e08b761 459
11a68fa3 460 bar.mBounds.width = -1; // mark as "squished"
8e08b761 461
11a68fa3 462 pcntSum -= bar.mLenRatio;
8e08b761 463
11a68fa3
GT
464 freeSpc -= mpPane->mProps.mMinCBarDim.x;
465 }
466 }
8e08b761
JS
467 } // for
468
11a68fa3
GT
469 if ( haveSquished )
470 unit = freeSpc / pcntSum;
8e08b761 471
11a68fa3
GT
472 for ( i = 0; i != pRow->mBars.Count(); ++i )
473 {
474 cbBarInfo& bar = *pRow->mBars[i];
8e08b761 475
11a68fa3 476 bar.mBounds.x = prevX;
8e08b761 477
11a68fa3
GT
478 if ( !bar.IsFixed() )
479 {
480 if ( bar.mBounds.width == -1 )
8e08b761 481
11a68fa3
GT
482 bar.mBounds.width = mpPane->mProps.mMinCBarDim.x;
483 else
484 bar.mBounds.width = int( unit * bar.mLenRatio );
8e08b761 485
18c45cd6
WS
486 // a little bit of AI:
487 // memorize bar's height and width, when docked in
11a68fa3
GT
488 // the current orientation - by making the current
489 // dimensions to be "preffered" ones for this docking state
8e08b761 490
11a68fa3
GT
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 }
8e08b761 497
11a68fa3
GT
498 prevX = bar.mBounds.x + bar.mBounds.width;
499 }
8e08b761
JS
500}
501
502void cbRowLayoutPlugin::DetectBarHandles( cbRowInfo* pRow )
503{
11a68fa3 504 // first pass from left to right (detect left-side handles)
8e08b761 505
c82c42d4 506 bool foundNotFixed = false;
8e08b761
JS
507
508 size_t i;
11a68fa3
GT
509 for ( i = 0; i != pRow->mBars.Count(); ++i )
510 {
511 cbBarInfo& bar = *pRow->mBars[i];
18c45cd6 512
c82c42d4 513 bar.mHasLeftHandle = false;
11a68fa3
GT
514
515 if ( !bar.IsFixed() )
516 {
517 if ( foundNotFixed )
18c45cd6 518
11a68fa3
GT
519 if ( bar.mpPrev &&
520 bar.mpPrev->IsFixed() )
18c45cd6 521
c82c42d4 522 bar.mHasLeftHandle = true;
11a68fa3 523
c82c42d4 524 foundNotFixed = true;
11a68fa3
GT
525 }
526 }
8e08b761 527
11a68fa3 528 // pass from right to left (detect right-side handles)
8e08b761 529
c82c42d4 530 foundNotFixed = false;
8e08b761 531
11a68fa3 532 cbBarInfo* pBar = pRow->mBars[ pRow->mBars.Count() - 1 ];
8e08b761 533
11a68fa3
GT
534 while( pBar )
535 {
c82c42d4 536 pBar->mHasRightHandle = false;
8e08b761 537
11a68fa3
GT
538 if ( !pBar->IsFixed() )
539 {
540 if ( foundNotFixed )
8e08b761 541
11a68fa3 542 if ( pBar->mpNext )
8e08b761 543
c82c42d4 544 pBar->mHasRightHandle = true;
8e08b761 545
c82c42d4 546 foundNotFixed = true;
11a68fa3 547 }
8e08b761 548
11a68fa3
GT
549 pBar = pBar->mpPrev;
550 }
8e08b761
JS
551}
552
553void cbRowLayoutPlugin::RelayoutNotFixedBarsAround( cbBarInfo* pTheBar, cbRowInfo* pRow )
554{
11a68fa3
GT
555 if ( !pTheBar->mpPrev )
556 {
557 if ( !pTheBar->IsFixed() )
558 {
18c45cd6 559 // this bar the first in the row, move it's
11a68fa3
GT
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 {
18c45cd6 572 // this bar is the last one, move it's
11a68fa3
GT
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 );
8e08b761
JS
582}
583
584void cbRowLayoutPlugin::LayoutItemsVertically( cbRowInfo& row )
585{
586 size_t i;
11a68fa3
GT
587 for ( i = 0; i != row.mBars.Count(); ++i )
588 {
589 cbBarInfo& bar = *row.mBars[i];
8e08b761 590
11a68fa3 591 bar.mBounds.y = row.mRowY;
8e08b761 592
11a68fa3 593 if ( !bar.IsFixed() )
8e08b761 594
11a68fa3
GT
595 // make all not-fixed bars of equal height
596 bar.mBounds.height = row.mRowHeight;
8e08b761 597
11a68fa3 598 if ( row.mHasUpperHandle )
8e08b761 599
11a68fa3
GT
600 bar.mBounds.y += mpPane->mProps.mResizeHandleSize;
601 }
8e08b761
JS
602}
603
604int cbRowLayoutPlugin::CalcRowHeight( cbRowInfo& row )
605{
11a68fa3 606 int maxHeight = 0;
8e08b761
JS
607
608 size_t i;
11a68fa3 609 for ( i = 0; i != row.mBars.Count(); ++i )
18c45cd6 610
11a68fa3 611 maxHeight = wxMax( maxHeight, row.mBars[i]->mBounds.height );
8e08b761 612
11a68fa3 613 return maxHeight;
8e08b761
JS
614}
615
616void cbRowLayoutPlugin::StickRightSideBars( cbBarInfo* pToBar )
617{
11a68fa3
GT
618 cbBarInfo* pBar = pToBar->mpNext;
619 cbBarInfo* pPrev = pToBar;
8e08b761 620
11a68fa3
GT
621 while( pBar )
622 {
623 wxRect& cur = pBar->mBounds;
624 wxRect& prev = pPrev->mBounds;
8e08b761 625
11a68fa3 626 cur.x = prev.x + prev.width;
8e08b761 627
11a68fa3
GT
628 pPrev = pBar;
629 pBar = pBar->mpNext;
630 }
8e08b761
JS
631}
632
633void cbRowLayoutPlugin::SlideLeftSideBars( cbBarInfo* pTheBar )
634{
11a68fa3
GT
635 // shift left-side-bars to the left (with respect to "theBar"),
636 // so that they would not obscured by each other
8e08b761 637
11a68fa3
GT
638 cbBarInfo* pBar = pTheBar->mpPrev;
639 cbBarInfo* pPrev = pTheBar;
8e08b761 640
11a68fa3
GT
641 while( pBar )
642 {
643 wxRect& cur = pBar->mBounds;
644 wxRect& prev = pPrev->mBounds;
8e08b761 645
11a68fa3 646 if ( cur.x + cur.width > prev.x )
8e08b761 647
11a68fa3 648 cur.x = prev.x - cur.width;
8e08b761 649
11a68fa3
GT
650 pPrev = pBar;
651 pBar = pBar->mpPrev;
652 }
8e08b761
JS
653}
654
655void cbRowLayoutPlugin::SlideRightSideBars( cbBarInfo* pTheBar )
656{
11a68fa3
GT
657 // shift right-side-bars to the right (with respect to "theBar"),
658 // so that they would not be obscured by each other
8e08b761 659
11a68fa3
GT
660 cbBarInfo* pBar = pTheBar->mpNext;
661 cbBarInfo* pPrev = pTheBar;
8e08b761 662
11a68fa3
GT
663 while( pBar )
664 {
665 wxRect& cur = pBar->mBounds;
666 wxRect& prev = pPrev->mBounds;
8e08b761 667
11a68fa3 668 if ( cur.x < prev.x + prev.width )
8e08b761 669
11a68fa3 670 cur.x = prev.x + prev.width;
8e08b761 671
11a68fa3
GT
672 pPrev = pBar;
673 pBar = pBar->mpNext;
674 }
8e08b761
JS
675}
676
196be0f1 677void cbRowLayoutPlugin::ShiftLeftTrashold( cbBarInfo* WXUNUSED(pTheBar), cbRowInfo& row )
8e08b761 678{
11a68fa3 679 wxRect& first = row.mBars[0]->mBounds;
8e08b761 680
11a68fa3
GT
681 if ( first.x < 0 )
682 {
683 row.mBars[0]->mBounds.x = 0;
8e08b761 684
11a68fa3
GT
685 SlideRightSideBars( row.mBars[0] );
686 }
8e08b761
JS
687}
688
689void cbRowLayoutPlugin::ShiftRightTrashold( cbBarInfo* pTheBar, cbRowInfo& row )
690{
11a68fa3 691 wxRect& theBar = pTheBar->mBounds;
8e08b761 692
11a68fa3
GT
693 do
694 {
695 cbBarInfo* pBar = pTheBar;
8e08b761 696
11a68fa3 697 // calculate free spece on the left side
8e08b761 698
11a68fa3 699 int leftFreeSpc = 0;
8e08b761 700
11a68fa3
GT
701 while( pBar )
702 {
703 wxRect& cur = pBar->mBounds;
8e08b761 704
11a68fa3
GT
705 if ( pBar->mpPrev )
706 {
707 wxRect& prev = pBar->mpPrev->mBounds;
8e08b761 708
11a68fa3
GT
709 leftFreeSpc += cur.x - prev.x - prev.width;
710 }
711 else
712 leftFreeSpc += cur.x;
8e08b761 713
11a68fa3
GT
714 if ( cur.x < 0 )
715 {
716 leftFreeSpc = 0;
717 break;
718 }
8e08b761 719
11a68fa3
GT
720 pBar = pBar->mpPrev;
721 }
8e08b761 722
11a68fa3 723 pBar = pTheBar;
8e08b761 724
11a68fa3 725 int rightOverflow = 0;
8e08b761 726
11a68fa3 727 if ( pTheBar->IsFixed() )
8e08b761 728
11a68fa3
GT
729 while( pBar )
730 {
731 if ( !pBar->mpNext )
732 {
733 wxRect& cur = pBar->mBounds;
8e08b761 734
11a68fa3 735 if ( cur.x + cur.width > mpPane->mPaneWidth )
8e08b761 736
11a68fa3
GT
737 rightOverflow = cur.x + cur.width - mpPane->mPaneWidth;
738 }
8e08b761 739
11a68fa3
GT
740 pBar = pBar->mpNext;
741 }
8e08b761 742
11a68fa3
GT
743 if ( rightOverflow > 0 )
744 {
745 if ( leftFreeSpc <= 0 ) return;
8e08b761 746
11a68fa3
GT
747 if ( pTheBar->mpNext )
748 {
749 wxRect& next = pTheBar->mpNext->mBounds;
8e08b761 750
11a68fa3
GT
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"
8e08b761 753
11a68fa3
GT
754 if ( next.width < leftFreeSpc )
755 {
756 cbBarInfo* pNext = pTheBar->mpNext;
8e08b761 757
11a68fa3 758 row.mBars.Remove( pNext );
8e08b761 759
11a68fa3 760 row.mBars.Insert( pNext, row.mBars.Index( pTheBar ) );
8e08b761 761
11a68fa3 762 next.x = theBar.x - next.width;
8e08b761 763
11a68fa3 764 // re-setup mpPrev/mpNext references after insertion
8e08b761 765
11a68fa3 766 mpPane->InitLinksForRow( &row );
8e08b761 767
11a68fa3 768 // tighten things
8e08b761 769
11a68fa3
GT
770 StickRightSideBars( pTheBar );
771 SlideLeftSideBars ( pTheBar );
8e08b761 772
11a68fa3
GT
773 continue;
774 }
775 }
8e08b761 776
18c45cd6
WS
777 int leftShift = ( rightOverflow > leftFreeSpc )
778 ? leftFreeSpc
11a68fa3 779 : rightOverflow;
8e08b761 780
11a68fa3 781 theBar.x -= leftShift;
8e08b761 782
11a68fa3
GT
783 StickRightSideBars( pTheBar );
784 SlideLeftSideBars ( pTheBar );
8e08b761 785
11a68fa3 786 break;
8e08b761 787
11a68fa3
GT
788 } // end of if ( rightOverflow )
789 else
790 break;
8e08b761 791
11a68fa3 792 } while(1);
8e08b761
JS
793}
794
18c45cd6 795void cbRowLayoutPlugin::InsertBefore( cbBarInfo* pBeforeBar,
11a68fa3
GT
796 cbBarInfo* pTheBar,
797 cbRowInfo& row )
8e08b761 798{
11a68fa3 799 if ( pBeforeBar )
8e08b761 800
11a68fa3
GT
801 row.mBars.Insert( pTheBar, row.mBars.Index( pBeforeBar ) );
802 else
803 row.mBars.Add( pTheBar );
8e08b761 804
11a68fa3 805 pTheBar->mpRow = &row;
8e08b761
JS
806}
807
808void cbRowLayoutPlugin::DoInsertBar( cbBarInfo* pTheBar, cbRowInfo& row )
809{
11a68fa3 810 wxRect& theBar = pTheBar->mBounds;
8e08b761 811
11a68fa3
GT
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 } */
8e08b761
JS
819
820 size_t i;
11a68fa3
GT
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 }
18c45cd6 833
11a68fa3
GT
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
8e08b761
JS
860}
861
862// evnet handlers
863
864void cbRowLayoutPlugin::OnInsertBar( cbInsertBarEvent& event )
865{
11a68fa3
GT
866 cbBarInfo* pBarToInsert = event.mpBar;
867 cbRowInfo* pIntoRow = event.mpRow;
868 mpPane = event.mpPane;
8e08b761 869
11a68fa3 870 if ( !pBarToInsert->IsFixed() )
8e08b761 871
11a68fa3 872 AdjustLengthOfInserted( pIntoRow, pBarToInsert );
8e08b761 873
11a68fa3 874 DoInsertBar( pBarToInsert, *pIntoRow );
8e08b761 875
11a68fa3 876 mpPane->InitLinksForRow( pIntoRow ); // relink "mpNext/mpPrev"s
8e08b761 877
11a68fa3 878 // perform relayouting of the bars after insertion
8e08b761 879
11a68fa3
GT
880 // init bar location info
881 pBarToInsert->mAlignment = event.mpPane->mAlignment;
882 pBarToInsert->mRowNo = event.mpPane->GetRowIndex( pIntoRow );
8e08b761
JS
883
884#ifdef __EXPERIMENTAL
885
11a68fa3 886 if ( !pIntoRow->mHasOnlyFixedBars || !pBarToInsert->IsFixed() )
8e08b761 887
11a68fa3 888 RecalcLengthRatios( pIntoRow );
8e08b761
JS
889
890#endif
891
11a68fa3 892 MinimzeNotFixedBars( pIntoRow, pBarToInsert );
8e08b761 893
11a68fa3
GT
894 SlideLeftSideBars ( pBarToInsert );
895 SlideRightSideBars( pBarToInsert );
8e08b761 896
11a68fa3
GT
897 ShiftLeftTrashold ( pBarToInsert, *pIntoRow );
898 ShiftRightTrashold( pBarToInsert, *pIntoRow );
8e08b761 899
11a68fa3 900 mpPane->SyncRowFlags( pIntoRow );
8e08b761 901
11a68fa3 902 CheckIfAtTheBoundary( pBarToInsert, *pIntoRow );
8e08b761 903
11a68fa3 904 if ( event.mpPane->IsHorizontal() )
8e08b761 905
11a68fa3
GT
906 pBarToInsert->mState = wxCBAR_DOCKED_HORIZONTALLY;
907 else
908 pBarToInsert->mState = wxCBAR_DOCKED_VERTICALLY;
8e08b761 909
11a68fa3
GT
910 if ( !pIntoRow->mHasOnlyFixedBars )
911 {
8e08b761
JS
912
913#ifdef __EXPERIMENTAL
914
11a68fa3 915 ExpandNotFixedBars( pIntoRow );
8e08b761
JS
916#else
917
11a68fa3
GT
918 RelayoutNotFixedBarsAround( pBarToInsert, pIntoRow );
919 RecalcLengthRatios( pIntoRow );
8e08b761
JS
920
921#endif
922
11a68fa3 923 DetectBarHandles( pIntoRow );
8e08b761 924
18c45cd6 925 // do proportional resizing of not-fixed bars
11a68fa3
GT
926 ApplyLengthRatios( pIntoRow );
927 }
8e08b761 928
11a68fa3 929 // adjust the bar's docking state
8e08b761 930
18c45cd6
WS
931 // a little bit of AI:
932 // memorize bar's height and width, when docked in
11a68fa3
GT
933 // the current orientation - by making the current
934 // dimensions to be "preferred" ones for this docking state
8e08b761 935
11a68fa3
GT
936 if ( !pBarToInsert->IsFixed() )
937 {
938 cbBarInfo& bar = *pBarToInsert;
8e08b761 939
11a68fa3
GT
940 bar.mDimInfo.mSizes[ bar.mState ].x = bar.mBounds.width;
941 bar.mDimInfo.mSizes[ bar.mState ].y = bar.mBounds.height;
942 }
8e08b761
JS
943}
944
945void cbRowLayoutPlugin::OnRemoveBar ( cbRemoveBarEvent& event )
946{
11a68fa3
GT
947 cbBarInfo* pBar = event.mpBar;
948 mpPane = event.mpPane;
8e08b761 949
11a68fa3 950 cbRowInfo* pRow = pBar->mpRow;
8e08b761 951
11a68fa3 952 mpLayout->GetUpdatesManager().OnBarWillChange( pBar, pRow, event.mpPane );
8e08b761 953
11a68fa3
GT
954 // invalidate the whole row
955 //pFirst->mpRowInfo->mMgrData.mPrevBounds.x = -1;
8e08b761 956
11a68fa3 957 pRow->mBars.Remove( pBar );
8e08b761 958
11a68fa3
GT
959 // rest bar information after removing it from the row
960 pBar->mpRow = NULL;
c82c42d4
WS
961 pBar->mHasLeftHandle = false;
962 pBar->mHasRightHandle = false;
8e08b761 963
11a68fa3 964 mpPane->InitLinksForRow( pRow ); // relink "mpNext/mpPrev"s
8e08b761 965
11a68fa3
GT
966 if ( pRow->mBars.Count() == 0 )
967 {
968 // empty rows should not exist
8e08b761 969
11a68fa3 970 event.mpPane->GetRowList().Remove( pRow );
8e08b761 971
11a68fa3 972 delete pRow;
8e08b761 973
11a68fa3
GT
974 mpPane->InitLinksForRows();
975 }
976 else
977 {
978 // force repainting of bars, in the row, from which the bar was removed
8e08b761 979
11a68fa3 980 // FIXME:: really needed?
c82c42d4 981 pRow->mBars[0]->mUMgrData.SetDirty(true);
8e08b761 982
11a68fa3
GT
983 // re-setup mHasOnlyFixedBars flag for the row information
984 event.mpPane->SyncRowFlags( pRow );
8e08b761 985
11a68fa3 986 DetectBarHandles( pRow );
8e08b761 987
11a68fa3 988 if ( !pRow->mHasOnlyFixedBars )
8e08b761 989
11a68fa3
GT
990 ExpandNotFixedBars( pRow );
991 }
8e08b761
JS
992}
993
994void cbRowLayoutPlugin::OnLayoutRow( cbLayoutRowEvent& event )
995{
11a68fa3
GT
996 cbRowInfo* pRow = event.mpRow;
997 mpPane = event.mpPane;
8e08b761 998
11a68fa3 999 MinimzeNotFixedBars( pRow, NULL );
8e08b761 1000
11a68fa3
GT
1001 if ( !pRow->mHasOnlyFixedBars )
1002 {
18c45cd6 1003 // do proportional resizing of not-fixed bars
11a68fa3
GT
1004 ApplyLengthRatios( pRow );
1005 }
8e08b761 1006
11a68fa3
GT
1007 cbBarInfo& lastBar = *pRow->mBars[ pRow->mBars.Count() - 1 ];
1008 cbBarInfo& firstBar = *pRow->mBars[ 0 ];
8e08b761 1009
11a68fa3 1010 // FIXME:: Next line not used
8e08b761
JS
1011 // wxRect& bounds = lastBar.mBounds;
1012
11a68fa3
GT
1013 if ( lastBar.mBounds.x + lastBar.mBounds.width > mpPane->mPaneWidth )
1014 {
1015 lastBar.mBounds.x = mpPane->mPaneWidth - lastBar.mBounds.width;
8e08b761 1016
11a68fa3 1017 // first simulate left-row-edge friction
8e08b761 1018
11a68fa3 1019 SlideLeftSideBars( &lastBar );
8e08b761 1020
11a68fa3 1021 if ( firstBar.mBounds.x < 0 )
8e08b761
JS
1022 firstBar.mBounds.x = 0;
1023
11a68fa3
GT
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"
8e08b761 1028
11a68fa3
GT
1029 SlideRightSideBars( &firstBar );
1030 }
8e08b761 1031
11a68fa3 1032 event.Skip(); // pass event to the next handler
8e08b761
JS
1033}
1034
1035void cbRowLayoutPlugin::OnLayoutRows( cbLayoutRowsEvent& event )
1036{
11a68fa3 1037 mpPane = event.mpPane;
8e08b761 1038
11a68fa3 1039 int curY = 0;
8e08b761
JS
1040
1041 // FIXME:: Next line not used.
11a68fa3 1042 // RowArrayT& arr = mpPane->GetRowList();
8e08b761
JS
1043
1044 size_t i;
11a68fa3
GT
1045 for ( i = 0; i != mpPane->GetRowList().Count(); ++i )
1046 {
1047 cbRowInfo& row = *mpPane->GetRowList()[ i ];
a570d5b3 1048 //mpPane->CalcLengthRatios(& row);
11a68fa3 1049
18c45cd6 1050 // setup "has-handle" flags for rows, which depend on the existence
11a68fa3
GT
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 {
c82c42d4 1058 row.mHasLowerHandle = true;
11a68fa3 1059
18c45cd6 1060 row.mHasUpperHandle = false;
11a68fa3
GT
1061 }
1062 else
1063 {
c82c42d4 1064 row.mHasUpperHandle = true;
11a68fa3 1065
18c45cd6 1066 row.mHasLowerHandle = false;
11a68fa3
GT
1067 }
1068 }
1069 else
1070 {
1071 // otherwise, rows with fixed-bars only, have no height-resizing handles
18c45cd6
WS
1072 row.mHasUpperHandle = false;
1073 row.mHasLowerHandle = false;
11a68fa3
GT
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 )
8e08b761 1086 row.mRowHeight += mpPane->mProps.mResizeHandleSize;
11a68fa3 1087 if ( row.mHasLowerHandle )
8e08b761
JS
1088 row.mRowHeight += mpPane->mProps.mResizeHandleSize;
1089
11a68fa3
GT
1090 curY += row.mRowHeight;
1091 }
8e08b761 1092
11a68fa3
GT
1093 event.Skip(); // pass event to the next handler - other hookeds plugin
1094 // may also add some "refinements" to the layout now
8e08b761
JS
1095}
1096
1097void cbRowLayoutPlugin::OnResizeRow( cbResizeRowEvent& event )
1098{
11a68fa3
GT
1099 // extract resize-event info
1100 int ofs = event.mHandleOfs;
1101 bool forUpperHandle = event.mForUpperHandle;
1102 cbRowInfo* pTheRow = event.mpRow;
1103 mpPane = event.mpPane;
8e08b761
JS
1104
1105 // FIXME:: Next line not used.
11a68fa3 1106 //int newHeight = pTheRow->mRowHeight;
8e08b761 1107
11a68fa3
GT
1108 if ( forUpperHandle )
1109 {
1110 // calculate available free space from above,
1111 // which can be obtained by squeezing not-fixed height rows
8e08b761 1112
11a68fa3 1113 cbRowInfo* pRow = pTheRow->mpPrev;
8e08b761 1114
18c45cd6 1115 while( pRow )
11a68fa3 1116 {
11a68fa3
GT
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
8e08b761 1124
11a68fa3 1125 cbRowInfo* pRow = pTheRow->mpNext;
8e08b761 1126
18c45cd6 1127 while( pRow )
11a68fa3 1128 {
11a68fa3
GT
1129 pRow = pRow->mpNext;
1130 }
1131 }
8e08b761 1132
11a68fa3 1133 mpLayout->GetUpdatesManager().OnStartChanges();
8e08b761 1134
11a68fa3 1135 int clientSize;
8e08b761 1136
11a68fa3 1137 // allow user adjusting pane vs. client-area space, for upper-handle
8e08b761 1138
11a68fa3 1139 if ( mpPane->IsHorizontal() )
8e08b761 1140
11a68fa3
GT
1141 clientSize = mpLayout->GetClientHeight();
1142 else
1143 clientSize = mpLayout->GetClientWidth();
8e08b761 1144
11a68fa3
GT
1145 if ( forUpperHandle && ofs < -clientSize )
1146 {
1147 int needed = -(ofs + clientSize);
8e08b761 1148
11a68fa3 1149 cbRowInfo* pRow = mpPane->GetRowList()[ 0 ];
8e08b761 1150
11a68fa3 1151 // start squeezing rows from the top row towards bottom
8e08b761 1152
11a68fa3
GT
1153 while( pRow != pTheRow && needed )
1154 {
1155 // only not-fixed rows can be squeezed
8e08b761 1156
11a68fa3
GT
1157 if ( !pRow->mHasOnlyFixedBars )
1158 {
1159 int prevHeight = pRow->mRowHeight;
8e08b761 1160
18c45cd6 1161 int newHeight = wxMax( event.mpPane->GetMinimalRowHeight( pRow ),
11a68fa3 1162 prevHeight - needed );
8e08b761 1163
11a68fa3
GT
1164 if ( newHeight != prevHeight )
1165 {
1166 event.mpPane->SetRowHeight( pRow, newHeight );
8e08b761 1167
11a68fa3
GT
1168 needed -= prevHeight - pRow->mRowHeight;
1169 }
1170 }
8e08b761 1171
11a68fa3
GT
1172 pRow = pRow->mpNext;
1173 }
1174 }
8e08b761 1175
11a68fa3 1176 // allow user adjusting pane vs. client-area space, for lower-handle
8e08b761 1177
11a68fa3
GT
1178 if ( !forUpperHandle && ofs > clientSize )
1179 {
1180 int needed = ofs - clientSize;
8e08b761 1181
11a68fa3 1182 cbRowInfo* pRow = mpPane->GetRowList()[ mpPane->GetRowList().Count() - 1 ];
8e08b761 1183
11a68fa3 1184 // start squeezing rows from the bottom towards the top row
8e08b761 1185
11a68fa3
GT
1186 while( pRow && needed )
1187 {
1188 // only not-fixed rows can be squeezed
8e08b761 1189
11a68fa3
GT
1190 if ( !pRow->mHasOnlyFixedBars )
1191 {
1192 int prevHeight = pRow->mRowHeight;
8e08b761 1193
18c45cd6 1194 int newHeight = wxMax( event.mpPane->GetMinimalRowHeight( pRow ),
11a68fa3 1195 prevHeight - needed );
8e08b761 1196
11a68fa3
GT
1197 if ( newHeight != prevHeight )
1198 {
1199 event.mpPane->SetRowHeight( pRow, newHeight );
8e08b761 1200
11a68fa3
GT
1201 needed -= prevHeight - pRow->mRowHeight;
1202 }
1203 }
8e08b761 1204
11a68fa3
GT
1205 pRow = pRow->mpPrev;
1206 }
1207 }
8e08b761 1208
11a68fa3 1209 if ( forUpperHandle )
18c45cd6 1210
11a68fa3
GT
1211 event.mpPane->SetRowHeight( pTheRow, pTheRow->mRowHeight + (-ofs) );
1212 else
1213 event.mpPane->SetRowHeight( pTheRow, pTheRow->mRowHeight + ofs );
8e08b761 1214
c82c42d4 1215 mpLayout->RecalcLayout(false);
8e08b761 1216
11a68fa3
GT
1217 mpLayout->GetUpdatesManager().OnFinishChanges();
1218 mpLayout->GetUpdatesManager().UpdateNow();
8e08b761
JS
1219}
1220