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