1/////////////////////////////////////////////////////////////////////////////
2// Name:        bardragpl.cpp
3// Purpose:     cbBarDragPlugin implementation
4// Author:      Aleksandras Gluchovas
5// Modified by:
6// Created:     23/09/98
7// RCS-ID:      $Id: bardragpl.cpp 35650 2005-09-23 12:56:45Z MR $
8// Copyright:   (c) Aleksandras Gluchovas
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
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/bardragpl.h"
24
25#define POS_UNDEFINED -32768
26
27// helpers, FOR NOW:: static
28
29static inline bool rect_hits_rect( const wxRect& r1, const wxRect& r2 )
30{
31    if ( ( r2.x >= r1.x && r2.x <= r1.x + r1.width ) ||
32         ( r1.x >= r2.x && r1.x <= r2.x + r2.width ) )
33        if ( ( r2.y >= r1.y && r2.y <= r1.y + r1.height ) ||
34             ( r1.y >= r2.y && r1.y <= r2.y + r2.height ) )
35            return true;
36    return false;
37}
38
39static inline bool rect_contains_point( const wxRect& rect, int x, int y )
40{
41    return ( x >= rect.x &&
42             y >= rect.y &&
43             x <  rect.x + rect.width  &&
44             y <  rect.y + rect.height );
45}
46
47/***** Implementation for class cbBarDragPlugin *****/
48
49IMPLEMENT_DYNAMIC_CLASS( cbBarDragPlugin, cbPluginBase )
50
51BEGIN_EVENT_TABLE( cbBarDragPlugin, cbPluginBase )
52
53    //EVT_PL_LEFT_DOWN        ( cbBarDragPlugin::OnLButtonDown      )
54    EVT_PL_LEFT_UP            ( cbBarDragPlugin::OnLButtonUp        )
55    EVT_PL_MOTION             ( cbBarDragPlugin::OnMouseMove        )
56    EVT_PL_DRAW_HINT_RECT     ( cbBarDragPlugin::OnDrawHintRect     )
57    EVT_PL_START_BAR_DRAGGING ( cbBarDragPlugin::OnStartBarDragging )
58    EVT_PL_LEFT_DCLICK        ( cbBarDragPlugin::OnLDblClick        )
59
60END_EVENT_TABLE()
61
62cbBarDragPlugin::cbBarDragPlugin(void)
63
64    : mBarDragStarted    ( false ),
65      mCanStick          ( true ),
66      mpScrDc            ( NULL ),
67      mpCurCursor        ( NULL ),
68      mpDraggedBar       ( NULL ),
69      mInClientHintBorder( 4 )
70{}
71
72cbBarDragPlugin::cbBarDragPlugin( wxFrameLayout* pPanel, int paneMask )
73
74    : cbPluginBase( pPanel, paneMask ),
75
76      mBarDragStarted    ( false ),
77      mCanStick          ( true ),
78      mpScrDc            ( NULL ),
79      mpCurCursor        ( NULL ),
80      mpDraggedBar       ( NULL ),
81      mInClientHintBorder( 4 )
82{}
83
84cbBarDragPlugin::~cbBarDragPlugin()
85{
86    // nothing
87}
88
89// helper methods (protected)
90
91// clips (top/bottom) or (right/left) edges against the frame's bounding rect.
92
93void do_clip_edges( int len, int& rectPos, int& rectLen )
94{
95    if ( rectPos < 0 )
96    {
97        rectLen += rectPos;
98        rectPos = 0;
99        if ( rectLen < 0 )
100            rectLen = 1;
101    }
102    else
103        if ( rectPos > len-1 )
104        {
105            rectPos = len-1;
106            rectLen = 1;
107        }
108        else
109            if ( rectPos + rectLen - 1 > len )
110                 rectLen -= (rectPos + rectLen) - len + 1;
111}
112
113void cbBarDragPlugin::ClipRectInFrame( wxRect& rect )
114{
115    int w, h;
116    mpLayout->GetParentFrame().GetClientSize( &w, &h );
117
118    do_clip_edges( w, rect.x, rect.width  );
119    do_clip_edges( h, rect.y, rect.height );
120}
121
122void cbBarDragPlugin::ClipPosInFrame( wxPoint& pos )
123{
124    int w, h;
125    mpLayout->GetParentFrame().GetClientSize( &w, &h );
126
127    if ( pos.x < 0 )
128        pos.x = 0;
129    if ( pos.y < 0 )
130        pos.y = 0;
131    if ( pos.x > w )
132        pos.x = w-1;
133    if ( pos.y > h )
134        pos.y = h-1;
135}
136
137void cbBarDragPlugin::AdjustHintRect( wxPoint& mousePos )
138{
139    mHintRect.x = mousePos.x - mMouseInRectX;
140    mHintRect.y = mousePos.y - mMouseInRectY;
141}
142
143cbDockPane* cbBarDragPlugin::HitTestPanes( wxRect& rect )
144{
145    //wxRect clipped = rect;
146
147    //ClipRectInFrame( clipped );
148
149    cbDockPane** pPanes = mpLayout->GetPanesArray();
150
151    for( int i = 0; i != MAX_PANES; ++i )
152        if ( rect_hits_rect( pPanes[i]->mBoundsInParent, rect ) )
153            return pPanes[i];
154
155    return NULL;
156}
157
158cbDockPane* cbBarDragPlugin::HitTestPanes( wxPoint& pos )
159{
160    wxPoint clipped = pos;
161
162    //ClipPosInFrame( pos );
163
164    cbDockPane** pPanes = mpLayout->GetPanesArray();
165
166    for( int i = 0; i != MAX_PANES; ++i )
167        if ( rect_contains_point( pPanes[i]->mBoundsInParent, clipped.x, clipped.y ) )
168            return pPanes[i];
169
170    return NULL;
171}
172
173bool cbBarDragPlugin::HitsPane( cbDockPane* pPane, wxRect& rect )
174{
175    return rect_hits_rect( pPane->mBoundsInParent, rect );
176}
177
178int cbBarDragPlugin::GetDistanceToPane( cbDockPane* pPane, wxPoint& mousePos )
179{
180    wxRect& bounds = pPane->mBoundsInParent;
181
182    switch( pPane->mAlignment )
183    {
184        case FL_ALIGN_TOP    : return mousePos.y - ( bounds.y + bounds.height );
185        case FL_ALIGN_BOTTOM : return bounds.y - mousePos.y;
186        case FL_ALIGN_LEFT   : return mousePos.x - ( bounds.x + bounds.width  );
187        case FL_ALIGN_RIGHT  : return bounds.x - mousePos.x;
188        default : return 0; // never reached
189    }
190
191//    return 0;
192}
193
194bool cbBarDragPlugin::IsInOtherPane( wxPoint& mousePos )
195{
196    cbDockPane* pPane = HitTestPanes( mousePos );
197
198    if ( pPane && pPane != mpCurPane ) return true;
199    else return false;
200}
201
202bool cbBarDragPlugin::IsInClientArea( wxPoint& mousePos )
203{
204    return  ( HitTestPanes( mousePos ) == NULL );
205}
206
207bool cbBarDragPlugin::IsInClientArea( wxRect& rect )
208{
209    return ( HitTestPanes( rect ) == NULL );
210}
211
212void cbBarDragPlugin::CalcOnScreenDims( wxRect& rect )
213{
214    if ( !mpCurPane || mpDraggedBar->IsFixed() ) return;
215
216    wxRect inPane = rect;
217
218    mpCurPane->FrameToPane( &inPane );
219
220    int rowNo = mpCurPane->GetRowAt( inPane.y, inPane.y + inPane.height );
221
222    bool isMaximized = ( rowNo >= (int)mpCurPane->GetRowList().Count() || rowNo < 0 );
223
224    if ( isMaximized )
225    {
226        inPane.x = 0;
227        inPane.width = mpCurPane->mPaneWidth;
228
229        mpCurPane->PaneToFrame( &inPane );
230
231        rect = inPane;
232    }
233}
234
235// helpers
236
237static inline void check_upper_overrun( int& pos, int width, int mousePos )
238{
239    if ( mousePos >= pos + width )
240        pos = mousePos - width/2;
241}
242
243static inline void check_lower_overrun( int& pos, int width, int mousePos )
244{
245    if ( mousePos <= pos )
246        pos = mousePos - width/2;
247}
248
249void cbBarDragPlugin::StickToPane( cbDockPane* pPane, wxPoint& mousePos )
250{
251    int wInPane = GetBarWidthInPane ( pPane );
252    int hInPane = GetBarHeightInPane( pPane );
253
254    // adjsut hint-rect horizontally (in pane's orientation)
255
256    if ( pPane->IsHorizontal() )
257    {
258        mHintRect.width  = wInPane;
259        mHintRect.height = hInPane;
260    }
261    else
262    {
263        mHintRect.height = wInPane;
264        mHintRect.width  = hInPane;
265    }
266
267    // adjsut hint-rect vertically (in pane's orientation)
268
269    wxRect& bounds = pPane->mBoundsInParent;
270
271    // true, if hint enters the pane through it's lower edge
272
273    bool fromLowerEdge = ( pPane->IsHorizontal() )
274                           ? mousePos.y > bounds.y
275                           : mousePos.x > bounds.x;
276
277    // NOTE:: about all the below min/max things: they are meant to ensure
278    //        that the mouse pointer doesn't overrun (leave) the hint-rectangle
279    //        when its dimensions are recalculated upon sticking it to the pane
280
281    if ( pPane->IsHorizontal() && fromLowerEdge )
282    {
283        int paneBottomEdgeY = bounds.y + bounds.height;
284
285        mHintRect.y = wxMin( paneBottomEdgeY, mousePos.y );
286
287        check_lower_overrun( mHintRect.y, hInPane, mousePos.y );
288
289    }
290    else
291        if ( pPane->IsHorizontal() && !fromLowerEdge )
292        {
293            int paneTopEdgeY = bounds.y;
294
295            mHintRect.y = wxMax( paneTopEdgeY - hInPane, mousePos.y - hInPane );
296
297            check_upper_overrun( mHintRect.y, hInPane, mousePos.y );
298        }
299        else
300            if ( !pPane->IsHorizontal() && fromLowerEdge )
301            {
302                int paneRightEdgeX = bounds.x + bounds.width;
303
304                mHintRect.x = wxMin( paneRightEdgeX, mousePos.x );
305
306                check_lower_overrun( mHintRect.x, hInPane, mousePos.x );
307            }
308            else
309                if ( !pPane->IsHorizontal() && !fromLowerEdge )
310                {
311                    int paneLeftEdgeX = bounds.x;
312
313                    mHintRect.x = wxMax( paneLeftEdgeX - hInPane, mousePos.x - hInPane );
314
315                    check_upper_overrun( mHintRect.x, hInPane, mousePos.x );
316                }
317
318    mMouseInRectX = mousePos.x - mHintRect.x;
319    mMouseInRectY = mousePos.y - mHintRect.y;
320
321    mpCurPane = pPane; // memorize pane to which the hint is currently sticked
322}
323
324void cbBarDragPlugin::UnstickFromPane( cbDockPane* pPane, wxPoint& mousePos )
325{
326    // unsticking causes rectangle to get the shape in which
327    // dragged control-bar would be when floated
328
329    int newWidth  = mpDraggedBar->mDimInfo.mSizes[wxCBAR_FLOATING].x;
330    int newHeight = mpDraggedBar->mDimInfo.mSizes[wxCBAR_FLOATING].y;
331
332    wxRect& flBounds = mpDraggedBar->mDimInfo.mBounds[wxCBAR_FLOATING];
333
334    if ( flBounds.width != -1 )
335    {
336        newWidth  = flBounds.width;
337        newHeight = flBounds.height;
338    }
339
340    mHintRect.width  = newWidth;
341    mHintRect.height = newHeight;
342
343    wxRect& bounds = pPane->mBoundsInParent;
344
345    // true, if hint leaves the pane through it's lower edge
346
347    bool fromLowerEdge = ( pPane->IsHorizontal() )
348                           ? mousePos.y > bounds.y
349                           : mousePos.x > bounds.x;
350
351    // NOTE:: ...all the below min/max things - see comments about it in StickToPane(..)
352
353    if ( pPane->IsHorizontal() && fromLowerEdge )
354    {
355        // bool fromLowerEdge = mousePos.y > bounds.y;
356
357        mHintRect.y = wxMax( bounds.y + bounds.height + 1, mousePos.y - newHeight );
358
359        check_upper_overrun( mHintRect.y, newHeight, mousePos.y );
360
361        // this is how MFC's hint behaves:
362
363        if ( mMouseInRectX > newWidth )
364            mHintRect.x = mousePos.x - ( newWidth / 2 );
365    }
366    else
367        if ( pPane->IsHorizontal() && !fromLowerEdge )
368        {
369            mHintRect.y = wxMin( bounds.y - newHeight - 1, mousePos.y );
370
371            // -/-
372
373            if ( mMouseInRectX > newWidth )
374                mHintRect.x = mousePos.x - ( newWidth / 2 );
375
376            check_lower_overrun( mHintRect.y, newHeight, mousePos.y );
377        }
378        else
379            if ( !pPane->IsHorizontal() && fromLowerEdge )
380            {
381                mHintRect.x = wxMax( bounds.x + bounds.width, mousePos.x - newWidth );
382
383                // -/-
384
385                if ( mMouseInRectY > newHeight )
386                    mHintRect.y = mousePos.y - ( newHeight / 2 );
387
388                check_upper_overrun( mHintRect.x, newWidth, mousePos.x );
389            }
390            else
391                if ( !pPane->IsHorizontal() && !fromLowerEdge )
392                {
393                    mHintRect.x = wxMin( bounds.x - newWidth - 1, mousePos.x );
394
395                    // -/-
396
397                    if ( mMouseInRectY > newHeight )
398                        mHintRect.y = mousePos.y - ( newHeight / 2 );
399
400                    check_lower_overrun( mHintRect.x, newWidth, mousePos.x );
401                }
402
403    mMouseInRectX = mousePos.x - mHintRect.x;
404    mMouseInRectY = mousePos.y - mHintRect.y;
405
406    mpCurPane = NULL;
407}
408
409int cbBarDragPlugin::GetBarWidthInPane( cbDockPane* pPane )
410{
411    if ( pPane == mpSrcPane )
412        return mBarWidthInSrcPane;
413
414    // this is how MFC's bars behave:
415
416    if ( pPane->IsHorizontal() )
417        return mpDraggedBar->mDimInfo.mSizes[wxCBAR_DOCKED_HORIZONTALLY].x;
418    else
419        return mpDraggedBar->mDimInfo.mSizes[wxCBAR_DOCKED_VERTICALLY  ].x;
420}
421
422int cbBarDragPlugin::GetBarHeightInPane( cbDockPane* pPane )
423{
424    if ( pPane->IsHorizontal() )
425        return mpDraggedBar->mDimInfo.mSizes[wxCBAR_DOCKED_HORIZONTALLY].y;
426    else
427        return mpDraggedBar->mDimInfo.mSizes[wxCBAR_DOCKED_VERTICALLY  ].y;
428}
429
430void cbBarDragPlugin::ShowHint( bool prevWasInClient )
431{
432    bool wasDocked = false;
433
434    if ( mpSrcPane->mProps.mRealTimeUpdatesOn == false )
435    {
436        // do heavy calculations first
437
438        wxRect actualRect = mHintRect; // will be adjusted depending on drag-settings
439
440        if ( mpSrcPane->mProps.mExactDockPredictionOn && mpCurPane )
441        {
442#ifdef  __WXDEBUG__
443            bool success =
444#endif
445                           mpLayout->RedockBar( mpDraggedBar, mHintRect, mpCurPane, false );
446
447            wxASSERT( success ); // DBG::
448
449            actualRect = mpDraggedBar->mBounds;
450
451            mpCurPane->PaneToFrame( &actualRect );
452        }
453        else
454            CalcOnScreenDims( actualRect );
455
456        // release previous hint
457
458        if ( mPrevHintRect.x != POS_UNDEFINED )
459        {
460            // erase previous rectangle
461
462            cbDrawHintRectEvent evt( mPrevHintRect, prevWasInClient, true, false );
463
464            mpLayout->FirePluginEvent( evt );
465        }
466
467        // draw new hint
468
469        cbDrawHintRectEvent evt( actualRect, mpCurPane == NULL, false, false );
470
471        mpLayout->FirePluginEvent( evt );
472
473        mPrevHintRect = actualRect;
474    }
475    else
476    {
477        // otherwise, if real-time updates option is ON
478
479        if ( mpDraggedBar->mState != wxCBAR_FLOATING && !mpCurPane )
480        {
481            mpLayout->SetBarState( mpDraggedBar, wxCBAR_FLOATING, true );
482        }
483        else
484            if ( mpDraggedBar->mState == wxCBAR_FLOATING && mpCurPane )
485            {
486                mpLayout->SetBarState( mpDraggedBar, wxCBAR_DOCKED_HORIZONTALLY, false );
487
488                wasDocked = true;
489            }
490
491        if ( mpCurPane )
492        {
493            mpLayout->GetUpdatesManager().OnStartChanges();
494
495            if ( wasDocked )
496
497            mpDraggedBar->mUMgrData.SetDirty( true );
498
499#ifdef  __WXDEBUG__
500            bool success =
501#endif
502                           mpLayout->RedockBar( mpDraggedBar, mHintRect, mpCurPane, false );
503
504            wxASSERT( success ); // DBG ::
505
506            mpLayout->GetUpdatesManager().OnFinishChanges();
507            mpLayout->GetUpdatesManager().UpdateNow();
508        }
509        else
510        {
511            if ( mpLayout->mFloatingOn )
512            {
513                // move the top-most floated bar around as user drags the hint
514
515                mpDraggedBar->mDimInfo.mBounds[ wxCBAR_FLOATING ] = mHintRect;
516
517                mpLayout->ApplyBarProperties( mpDraggedBar );
518            }
519        }
520    }
521}
522
523/*** event handlers ***/
524
525void cbBarDragPlugin::OnMouseMove( cbMotionEvent& event )
526{
527    // calculate postion in frame's coordiantes
528
529    if ( !mBarDragStarted )
530    {
531        event.Skip(); // pass event to the next plugin
532        return;
533    }
534
535    wxPoint mousePos = event.mPos;
536
537    event.mpPane->PaneToFrame( &mousePos.x, &mousePos.y );
538
539    bool   prevIsInClient = ( mpCurPane == 0 );
540
541    AdjustHintRect( mousePos );
542
543    // if the hint-rect is not "tempted" to any pane yet
544
545    if ( mpCurPane == NULL )
546    {
547        cbDockPane* pPane = HitTestPanes( mHintRect );
548
549        // enable sticking again, if we've left the pane completely
550        if ( !pPane )
551            mCanStick = true;
552
553        if ( mCanStick && pPane &&
554             GetDistanceToPane( pPane, mousePos ) < GetBarHeightInPane( pPane ) )
555            StickToPane( pPane, mousePos );
556        else
557            if ( pPane && HitTestPanes( mousePos ) == pPane && 0 ) // FOR NOW:: disabled
558
559        StickToPane( pPane, mousePos );
560    }
561    else
562    {
563        // otherwise, when rect is now sticked to some of the panes
564        // check if it should still remain in this pane
565
566        mCanStick = true;
567
568        bool mouseInOther = IsInOtherPane( mousePos );
569
570        if ( mouseInOther )
571        {
572            cbDockPane* pPane = HitTestPanes( mousePos );
573
574            StickToPane( pPane, mousePos );
575        }
576        else
577        {
578            if ( IsInClientArea( mousePos ) )
579            {
580                cbDockPane* pPane = HitTestPanes( mHintRect );
581
582                if ( pPane &&
583                     pPane != mpCurPane &&
584                     GetDistanceToPane( pPane, mousePos ) < GetBarHeightInPane( pPane ) )
585                    StickToPane( pPane, mousePos );
586                else
587                    if ( !pPane )
588                    {
589                        UnstickFromPane( mpCurPane, mousePos );
590
591                        // FOR NOW:: disabled, would cause some mess
592                        // mCanStick = false; // prevents from sticking to this
593                        // pane again, flag is reset when hint-rect
594                        // leaves the pane completely
595                    }
596                    else
597                        if ( GetDistanceToPane( pPane, mousePos ) > GetBarHeightInPane( pPane ) )
598                        {
599                            if ( !HitsPane( mpCurPane, mHintRect ) )
600                            {
601                                UnstickFromPane( mpCurPane, mousePos );
602
603                                // FOR NOW:: disabled, would cause some mess
604                                // mCanStick = false; // prevents from sticking to this
605                                // pane again, flag is reset when hint-rect
606                                // leaves the pane completely
607                            }
608                        }
609
610            }
611        }
612    }
613
614    ShowHint( prevIsInClient );
615
616    wxCursor* pPrevCurs = mpCurCursor;
617
618    if ( mpCurPane )
619    {
620        mpCurCursor = mpLayout->mpNormalCursor;
621    }
622    else
623    {
624        // if floating is off, and we are in the client
625        // area, the cursor will be invalid, otherwise
626        // it will be the normal cursor
627
628        if (mpLayout->mFloatingOn)
629        {
630            mpCurCursor = mpLayout->mpNormalCursor;
631        }
632        else
633        {
634            mpCurCursor = mpLayout->mpNECursor;
635        }
636
637    }
638    if ( pPrevCurs != mpCurCursor )
639        mpLayout->GetParentFrame().SetCursor( *mpCurCursor );
640}
641
642void cbBarDragPlugin::OnLButtonDown( cbLeftDownEvent& event )
643{
644    if ( mBarDragStarted  )
645    {
646        wxMessageBox(wxT("DblClick!"));
647    }
648
649    event.Skip();
650}
651
652void cbBarDragPlugin::OnLButtonUp( cbLeftUpEvent& event )
653{
654    if ( mBarDragStarted  )
655    {
656        if ( mpSrcPane->mProps.mRealTimeUpdatesOn == false )
657        {
658            // erase current rectangle, and finsih on-screen drawing session
659
660            cbDrawHintRectEvent evt( mPrevHintRect, mpCurPane == NULL, true, true );
661
662            mpLayout->FirePluginEvent( evt );
663
664            if ( mpCurPane != NULL )
665            {
666                if ( mpSrcPane->mProps.mExactDockPredictionOn )
667                {
668                    mpLayout->RedockBar( mpDraggedBar, mHintRect, mpCurPane, false );
669
670                    mpLayout->GetUpdatesManager().OnFinishChanges();
671                    mpLayout->GetUpdatesManager().UpdateNow();
672                }
673                else
674                {
675                    if (mpDraggedBar->mState == wxCBAR_FLOATING)
676                    {
677                        mpLayout->SetBarState( mpDraggedBar, wxCBAR_DOCKED_HORIZONTALLY, true);
678                    }
679
680                    mpLayout->RedockBar( mpDraggedBar, mHintRect, mpCurPane );
681                }
682            }
683            else
684            {
685                if (mpDraggedBar->mState != wxCBAR_FLOATING)
686                {
687                    mpLayout->SetBarState(mpDraggedBar, wxCBAR_FLOATING, true);
688                }
689
690                mpDraggedBar->mDimInfo.mBounds[ wxCBAR_FLOATING ] = mHintRect;
691                mpLayout->ApplyBarProperties( mpDraggedBar );
692            }
693        }
694
695        mHintRect.width = -1;
696
697        // In Windows, at least, the frame needs to have a null cursor
698        // else child windows (such as text windows) inherit the cursor
699#if 1
700        mpLayout->GetParentFrame().SetCursor( wxNullCursor );
701#else
702        mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
703#endif
704
705        mpLayout->ReleaseEventsFromPane( event.mpPane );
706        mpLayout->ReleaseEventsFromPlugin( this );
707
708        mBarDragStarted = false;
709
710        if ( mBarWasFloating && mpDraggedBar->mState != wxCBAR_FLOATING )
711        {
712            // save bar's floating position before it was docked
713
714            mpDraggedBar->mDimInfo.mBounds[ wxCBAR_FLOATING ] = mFloatedBarBounds;
715        }
716    }
717    else
718        event.Skip(); // pass event to the next plugin
719}
720
721void cbBarDragPlugin::OnLDblClick( cbLeftDClickEvent& event )
722{
723    int avoidCompilerWarning = 1;
724    if ( avoidCompilerWarning )
725    {
726        cbBarInfo* pHittedBar;
727        cbRowInfo* pRow;
728
729        if ( event.mpPane->HitTestPaneItems( event.mPos,   // in pane's coordiantes
730                                             &pRow,
731                                             &pHittedBar ) == CB_BAR_CONTENT_HITTED
732           )
733        {
734            mpLayout->SetBarState( pHittedBar, wxCBAR_FLOATING, true );
735
736            mpLayout->RepositionFloatedBar( pHittedBar );
737
738            return; // event is "eaten" by this plugin
739        }
740
741        mBarDragStarted = false;
742
743        event.Skip();
744    }
745
746    //wxMessageBox("Hi, dblclick arrived!");
747}
748
749void cbBarDragPlugin::OnStartBarDragging( cbStartBarDraggingEvent& event )
750{
751    mpDraggedBar = event.mpBar;
752    mpSrcPane    = event.mpPane;
753
754    mpLayout->CaptureEventsForPane( event.mpPane );
755    mpLayout->CaptureEventsForPlugin( this );
756
757    mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
758
759    mBarDragStarted = true;
760
761    wxRect inParent = mpDraggedBar->mBounds;
762
763    mBarWasFloating = mpDraggedBar->mState == wxCBAR_FLOATING;
764
765    if ( mBarWasFloating )
766    {
767        inParent = mpDraggedBar->mDimInfo.mBounds[ wxCBAR_FLOATING ];
768        mFloatedBarBounds = inParent;
769    }
770    else
771        event.mpPane->PaneToFrame( &inParent );
772
773    mHintRect.x = POS_UNDEFINED;
774
775    mHintRect.width  = inParent.width;
776    mHintRect.height = inParent.height;
777
778    mMouseInRectX = event.mPos.x - inParent.x;
779    mMouseInRectY = event.mPos.y - inParent.y;
780
781    mpSrcPane = event.mpPane;
782
783    if ( mpDraggedBar->mState == wxCBAR_FLOATING )
784
785        mpCurPane = NULL;
786    else
787        mpCurPane = event.mpPane;
788
789    mPrevHintRect.x = POS_UNDEFINED;
790
791    mCanStick = false; // we're not stuck into any pane now -
792                       // there's nowhere to "stick-twice"
793
794    mBarWidthInSrcPane = mpDraggedBar->mDimInfo.mSizes[ mpDraggedBar->mState ].x;
795
796    if ( mpSrcPane->mProps.mRealTimeUpdatesOn == false &&
797         mpSrcPane->mProps.mExactDockPredictionOn  )
798        mpLayout->GetUpdatesManager().OnStartChanges(); // capture initial state of layout
799
800    // simulate the first mouse movement
801
802    int x = event.mPos.x, y = event.mPos.y;
803    mpSrcPane->FrameToPane( &x, &y );
804
805    wxPoint pt(x,y);
806    cbMotionEvent motionEvt( pt, event.mpPane );
807    this->OnMouseMove( motionEvt );
808
809    return; // event is "eaten" by this plugin
810}
811
812/*** on-screen hint-tracking related methods ***/
813
814void cbBarDragPlugin::OnDrawHintRect( cbDrawHintRectEvent& event )
815{
816    if ( !mpScrDc ) StartTracking();
817
818    DoDrawHintRect( event.mRect, event.mIsInClient );
819
820    if ( event.mLastTime )
821        FinishTracking();
822}
823
824#define _IMG_A  0xAA    // Note: modified from _A to _IMG_A, _A was already defined (cygwin)
825#define _IMG_B  0x00    // Note: modified from _B to _IMG_A, _B was already defined (cygwin)
826#define _IMG_C  0x55    // Note: modified from _C to _IMG_C, for consistency reasons.
827#define _IMG_D  0x00    // Note: modified from _D to _IMG_D, for consistency reasons.
828
829// FOR NOW:: static
830
831static const unsigned char _gCheckerImg[16] = { _IMG_A,_IMG_B,_IMG_C,_IMG_D,
832                                                _IMG_A,_IMG_B,_IMG_C,_IMG_D,
833                                                _IMG_A,_IMG_B,_IMG_C,_IMG_D,
834                                                _IMG_A,_IMG_B,_IMG_C,_IMG_D
835                                              };
836
837void cbBarDragPlugin::StartTracking()
838{
839    mpScrDc = new wxScreenDC;
840
841    wxScreenDC::StartDrawingOnTop(&mpLayout->GetParentFrame());
842}
843
844void cbBarDragPlugin::DoDrawHintRect( wxRect& rect, bool isInClientRect)
845{
846    wxRect scrRect;
847
848    RectToScr( rect, scrRect );
849
850    int prevLF = mpScrDc->GetLogicalFunction();
851
852    mpScrDc->SetLogicalFunction( wxINVERT );
853
854    if ( isInClientRect )
855    {
856        // BUG BUG BUG (wx):: somehow stippled brush works only
857        // when the bitmap created on stack, not
858        // as a member of the class
859
860        wxBitmap checker( (const char*)_gCheckerImg, 8,8 );
861
862        wxBrush checkerBrush( checker );
863
864        mpScrDc->SetPen( mpLayout->mNullPen );
865        mpScrDc->SetBrush( checkerBrush );
866
867        int half = mInClientHintBorder / 2;
868
869        mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y - half,
870                                scrRect.width + 2*half, mInClientHintBorder );
871
872        mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y + scrRect.height - half,
873                                scrRect.width + 2*half, mInClientHintBorder );
874
875        mpScrDc->DrawRectangle( scrRect.x - half, scrRect.y + half - 1,
876                                mInClientHintBorder, scrRect.height - 2*half + 2);
877
878        mpScrDc->DrawRectangle( scrRect.x + scrRect.width - half,
879                                scrRect.y + half - 1,
880                                mInClientHintBorder, scrRect.height - 2*half + 2);
881
882        mpScrDc->SetBrush( wxNullBrush );
883    }
884    else
885    {
886        mpScrDc->SetPen( mpLayout->mBlackPen );
887
888        mpScrDc->DrawLine( scrRect.x, scrRect.y,
889                           scrRect.x + scrRect.width, scrRect.y );
890
891        mpScrDc->DrawLine( scrRect.x, scrRect.y + 1,
892                           scrRect.x, scrRect.y + scrRect.height );
893
894        mpScrDc->DrawLine( scrRect.x+1, scrRect.y + scrRect.height,
895                           scrRect.x + scrRect.width, scrRect.y + scrRect.height );
896
897        mpScrDc->DrawLine( scrRect.x + scrRect.width , scrRect.y,
898                           scrRect.x + scrRect.width, scrRect.y + scrRect.height + 1);
899    }
900
901    mpScrDc->SetLogicalFunction( prevLF );
902}
903
904void cbBarDragPlugin::DrawHintRect ( wxRect& rect, bool isInClientRect)
905{
906    DoDrawHintRect( rect, isInClientRect );
907}
908
909void cbBarDragPlugin::EraseHintRect( wxRect& rect, bool isInClientRect)
910{
911    DoDrawHintRect( rect, isInClientRect );
912}
913
914void cbBarDragPlugin::FinishTracking()
915{
916    wxScreenDC::EndDrawingOnTop();
917
918    delete mpScrDc;
919
920    mpScrDc = NULL;
921}
922
923void cbBarDragPlugin::RectToScr( wxRect& frameRect, wxRect& scrRect )
924{
925    scrRect = frameRect;
926
927    int x = frameRect.x, y = frameRect.y;
928
929    mpLayout->GetParentFrame().ClientToScreen( &x, &y );
930
931    scrRect.x = x;
932    scrRect.y = y;
933}
934
935