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 
rect_hits_rect(const wxRect & r1,const wxRect & r2)29 static 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 
rect_contains_point(const wxRect & rect,int x,int y)39 static 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 
IMPLEMENT_DYNAMIC_CLASS(cbBarDragPlugin,cbPluginBase)49 IMPLEMENT_DYNAMIC_CLASS( cbBarDragPlugin, cbPluginBase )
50 
51 BEGIN_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 
60 END_EVENT_TABLE()
61 
62 cbBarDragPlugin::cbBarDragPlugin(void)
63 
64     : mBarDragStarted    ( false ),
65       mCanStick          ( true ),
66       mpScrDc            ( NULL ),
67       mpCurCursor        ( NULL ),
68       mpDraggedBar       ( NULL ),
69       mInClientHintBorder( 4 )
70 {}
71 
cbBarDragPlugin(wxFrameLayout * pPanel,int paneMask)72 cbBarDragPlugin::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 
~cbBarDragPlugin()84 cbBarDragPlugin::~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 
do_clip_edges(int len,int & rectPos,int & rectLen)93 void 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 
ClipRectInFrame(wxRect & rect)113 void 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 
ClipPosInFrame(wxPoint & pos)122 void 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 
AdjustHintRect(wxPoint & mousePos)137 void cbBarDragPlugin::AdjustHintRect( wxPoint& mousePos )
138 {
139     mHintRect.x = mousePos.x - mMouseInRectX;
140     mHintRect.y = mousePos.y - mMouseInRectY;
141 }
142 
HitTestPanes(wxRect & rect)143 cbDockPane* 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 
HitTestPanes(wxPoint & pos)158 cbDockPane* 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 
HitsPane(cbDockPane * pPane,wxRect & rect)173 bool cbBarDragPlugin::HitsPane( cbDockPane* pPane, wxRect& rect )
174 {
175     return rect_hits_rect( pPane->mBoundsInParent, rect );
176 }
177 
GetDistanceToPane(cbDockPane * pPane,wxPoint & mousePos)178 int 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 
IsInOtherPane(wxPoint & mousePos)194 bool cbBarDragPlugin::IsInOtherPane( wxPoint& mousePos )
195 {
196     cbDockPane* pPane = HitTestPanes( mousePos );
197 
198     if ( pPane && pPane != mpCurPane ) return true;
199     else return false;
200 }
201 
IsInClientArea(wxPoint & mousePos)202 bool cbBarDragPlugin::IsInClientArea( wxPoint& mousePos )
203 {
204     return  ( HitTestPanes( mousePos ) == NULL );
205 }
206 
IsInClientArea(wxRect & rect)207 bool cbBarDragPlugin::IsInClientArea( wxRect& rect )
208 {
209     return ( HitTestPanes( rect ) == NULL );
210 }
211 
CalcOnScreenDims(wxRect & rect)212 void 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 
check_upper_overrun(int & pos,int width,int mousePos)237 static inline void check_upper_overrun( int& pos, int width, int mousePos )
238 {
239     if ( mousePos >= pos + width )
240         pos = mousePos - width/2;
241 }
242 
check_lower_overrun(int & pos,int width,int mousePos)243 static inline void check_lower_overrun( int& pos, int width, int mousePos )
244 {
245     if ( mousePos <= pos )
246         pos = mousePos - width/2;
247 }
248 
StickToPane(cbDockPane * pPane,wxPoint & mousePos)249 void 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 
UnstickFromPane(cbDockPane * pPane,wxPoint & mousePos)324 void 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 
GetBarWidthInPane(cbDockPane * pPane)409 int 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 
GetBarHeightInPane(cbDockPane * pPane)422 int 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 
ShowHint(bool prevWasInClient)430 void 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 
OnMouseMove(cbMotionEvent & event)525 void 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 
OnLButtonDown(cbLeftDownEvent & event)642 void cbBarDragPlugin::OnLButtonDown( cbLeftDownEvent& event )
643 {
644     if ( mBarDragStarted  )
645     {
646         wxMessageBox(wxT("DblClick!"));
647     }
648 
649     event.Skip();
650 }
651 
OnLButtonUp(cbLeftUpEvent & event)652 void 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 
OnLDblClick(cbLeftDClickEvent & event)721 void 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 
OnStartBarDragging(cbStartBarDraggingEvent & event)749 void 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 
OnDrawHintRect(cbDrawHintRectEvent & event)814 void 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 
831 static 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 
StartTracking()837 void cbBarDragPlugin::StartTracking()
838 {
839     mpScrDc = new wxScreenDC;
840 
841     wxScreenDC::StartDrawingOnTop(&mpLayout->GetParentFrame());
842 }
843 
DoDrawHintRect(wxRect & rect,bool isInClientRect)844 void 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 
DrawHintRect(wxRect & rect,bool isInClientRect)904 void cbBarDragPlugin::DrawHintRect ( wxRect& rect, bool isInClientRect)
905 {
906     DoDrawHintRect( rect, isInClientRect );
907 }
908 
EraseHintRect(wxRect & rect,bool isInClientRect)909 void cbBarDragPlugin::EraseHintRect( wxRect& rect, bool isInClientRect)
910 {
911     DoDrawHintRect( rect, isInClientRect );
912 }
913 
FinishTracking()914 void cbBarDragPlugin::FinishTracking()
915 {
916     wxScreenDC::EndDrawingOnTop();
917 
918     delete mpScrDc;
919 
920     mpScrDc = NULL;
921 }
922 
RectToScr(wxRect & frameRect,wxRect & scrRect)923 void 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