~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to contrib/src/fl/rowlayoutpl.cpp

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

Show diffs side-by-side

added added

removed removed

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