1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        panedrawpl.cpp
3 // Purpose:     cbPaneDrawPlugin implementation.
4 // Author:      Aleksandras Gluchovas
5 // Modified by:
6 // Created:     06/09/98
7 // RCS-ID:      $Id: panedrawpl.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 <math.h>
24 #include <stdlib.h>
25 
26 #include "wx/utils.h"     // import wxMin,wxMax macros
27 
28 #include "wx/fl/panedrawpl.h"
29 
30 // bitmap bits used by bar-resizing brush
31 
32 #define _IMG_A  0xAA    // Note: modified from _A to _IMG_A, _A was already defined (cygwin)
33 #define _IMG_B  0x00    // Note: modified from _B to _IMG_A, _B was already defined (cygwin)
34 #define _IMG_C  0x55    // Note: modified from _C to _IMG_C, for consistency reasons.
35 #define _IMG_D  0x00    // Note: modified from _D to _IMG_D, for consistency reasons.
36 
37 static const unsigned char _gCheckerImg[16] = { _IMG_A,_IMG_B,_IMG_C,_IMG_D,
38                                                 _IMG_A,_IMG_B,_IMG_C,_IMG_D,
39                                                 _IMG_A,_IMG_B,_IMG_C,_IMG_D,
40                                                 _IMG_A,_IMG_B,_IMG_C,_IMG_D
41                                               };
42 
43 // FIXME:: The below code somehow doesn't work - cursors remain unchanged
44 // Used: controlbar.cpp(1268):    set_cursor_bits( _gHorizCursorImg, bits, 32, 16 );
45 // Used: controlbar.cpp(1272):    set_cursor_bits( _gVertCursorImg, bits, 32, 16 );
46 /*
47 static void set_cursor_bits( const char** img, char* bits, int width, int height )
48 {
49     for( int i = 0; i != (width*height)/8; ++i )
50         bits[i] = 0;
51 
52     for( int y = 0; y != height; ++y )
53     {
54         const char* row = img[0];
55 
56         for( int x = 0; x != width; ++x )
57         {
58             int bitNo = y*width + x;
59 
60             char value = ( row[x] != '.' ) ? 1 : 0;
61 
62             bits[ bitNo / sizeof(char) ] |=
63                 ( ( bitNo %sizeof(char) ) << value );
64         }
65 
66         ++img;
67     }
68 }
69 */
70 
71 /***** Implementation for class cbPaneDrawPlugin *****/
72 
IMPLEMENT_DYNAMIC_CLASS(cbPaneDrawPlugin,cbPluginBase)73 IMPLEMENT_DYNAMIC_CLASS( cbPaneDrawPlugin, cbPluginBase )
74 
75 BEGIN_EVENT_TABLE( cbPaneDrawPlugin, cbPluginBase )
76 
77     EVT_PL_LEFT_DOWN           ( cbPaneDrawPlugin::OnLButtonDown         )
78     EVT_PL_LEFT_UP               ( cbPaneDrawPlugin::OnLButtonUp           )
79 //    EVT_PL_LEFT_DCLICK           ( cbPaneDrawPlugin::OnLDblClick           )
80     EVT_PL_RIGHT_UP               ( cbPaneDrawPlugin::OnRButtonUp           )
81     EVT_PL_MOTION               ( cbPaneDrawPlugin::OnMouseMove           )
82 
83 
84     EVT_PL_DRAW_PANE_BKGROUND  ( cbPaneDrawPlugin::OnDrawPaneBackground  )
85     EVT_PL_DRAW_PANE_DECOR     ( cbPaneDrawPlugin::OnDrawPaneDecorations )
86 
87     EVT_PL_DRAW_ROW_DECOR      ( cbPaneDrawPlugin::OnDrawRowDecorations  )
88     EVT_PL_DRAW_ROW_HANDLES    ( cbPaneDrawPlugin::OnDrawRowHandles      )
89     EVT_PL_DRAW_ROW_BKGROUND   ( cbPaneDrawPlugin::OnDrawRowBackground   )
90 
91     EVT_PL_SIZE_BAR_WND           ( cbPaneDrawPlugin::OnSizeBarWindow       )
92     EVT_PL_DRAW_BAR_DECOR       ( cbPaneDrawPlugin::OnDrawBarDecorations  )
93     EVT_PL_DRAW_BAR_HANDLES       ( cbPaneDrawPlugin::OnDrawBarHandles      )
94 
95     EVT_PL_START_DRAW_IN_AREA  ( cbPaneDrawPlugin::OnStartDrawInArea     )
96     EVT_PL_FINISH_DRAW_IN_AREA ( cbPaneDrawPlugin::OnFinishDrawInArea    )
97 
98 END_EVENT_TABLE()
99 
100 cbPaneDrawPlugin::cbPaneDrawPlugin(void)
101 
102     : mResizeStarted          ( false ),
103 
104       mResizeCursorOn         ( false ),
105       mpDraggedBar              ( NULL  ),
106       mpResizedRow            ( NULL  ),
107 
108       mRowHandleHitted        ( false ),
109       mIsUpperHandle          ( false ),
110       mBarHandleHitted        ( false ),
111       mIsLeftHandle           ( false ),
112       mBarContentHitted       ( false ),
113 
114       mpClntDc ( NULL ),
115       mpPane   ( NULL )
116 {}
117 
cbPaneDrawPlugin(wxFrameLayout * pPanel,int paneMask)118 cbPaneDrawPlugin::cbPaneDrawPlugin( wxFrameLayout* pPanel, int paneMask )
119 
120     : cbPluginBase( pPanel, paneMask ),
121 
122       // bar-row resizing state varaibles
123 
124       mResizeStarted          ( false ),
125 
126       mResizeCursorOn         ( false ),
127       mpDraggedBar              ( NULL ),
128       mpResizedRow            ( NULL ),
129 
130       mRowHandleHitted        ( false ),
131       mIsUpperHandle          ( false ),
132       mBarHandleHitted        ( false ),
133       mIsLeftHandle           ( false ),
134       mBarContentHitted       ( false ),
135 
136       mpClntDc ( NULL ),
137       mpPane   ( NULL )
138 {}
139 
~cbPaneDrawPlugin()140 cbPaneDrawPlugin::~cbPaneDrawPlugin()
141 {
142     // DBG::
143     wxASSERT( mpClntDc == NULL );
144 }
145 
DrawDraggedHandle(const wxPoint & pos,cbDockPane & pane)146 void cbPaneDrawPlugin::DrawDraggedHandle( const wxPoint& pos, cbDockPane& pane )
147 {
148     wxScreenDC dc;
149     int ofsX = 0;
150     int ofsY = 0;
151 
152     wxPoint fpos = pos;
153     pane.PaneToFrame( &fpos.x, &fpos.y );
154 
155     // short-cut
156     int resizeHndSize = pane.mProps.mResizeHandleSize;
157 
158     // "Required for X to specify that
159     // that we wish to draw on top of all windows
160     // - and we optimise by specifying the area
161     // for creating the overlap window." --J.S.
162 
163     wxScreenDC::StartDrawingOnTop(&mpLayout->GetParentFrame());
164 
165     mpLayout->GetParentFrame().ClientToScreen( &ofsX, &ofsY );
166 
167     int prevLF = dc.GetLogicalFunction();
168 
169     // BUG BUG BUG (wx):: somehow stippled brush works only
170     //                      when the bitmap created on stack, not
171     //                      as a member of the class
172 
173     wxBitmap checker( (const char*)_gCheckerImg, 8,8 );
174 
175     wxBrush checkerBrush( checker );
176 
177     dc.SetPen( mpLayout->mNullPen );
178     dc.SetBrush( checkerBrush );
179     dc.SetLogicalFunction( wxXOR );
180 
181     if ( mHandleIsVertical )
182     {
183         int delta = pos.x - mDragOrigin.x;
184 
185         if ( !pane.IsHorizontal() )
186 
187             delta = pos.y - mDragOrigin.y;
188 
189         int realHndOfs;
190         realHndOfs = pane.mBoundsInParent.x + pane.mLeftMargin + mHandleOfs;
191 
192         int newX = realHndOfs + delta;
193 
194         if ( newX + resizeHndSize > mHandleDragArea.x + mHandleDragArea.width )
195 
196             newX = mHandleDragArea.x + mHandleDragArea.width  - 1;
197 
198         if ( newX < mHandleDragArea.x )
199 
200             newX = mHandleDragArea.x;
201 
202         mDraggedDelta = newX - realHndOfs;
203 
204         dc.DrawRectangle( newX + ofsX, mHandleDragArea.y + ofsY,
205                           resizeHndSize + 1,
206                           mHandleDragArea.height+1 );
207     }
208     else
209     {
210         // otherwise, draw horizontal handle
211 
212         int delta = pos.y - mDragOrigin.y;
213 
214         if ( !pane.IsHorizontal() )
215 
216             delta = pos.x - mDragOrigin.x;
217 
218         int realHndOfs;
219         realHndOfs = pane.mBoundsInParent.y + pane.mTopMargin + mHandleOfs;
220 
221         int newY = realHndOfs + delta;
222 
223         if ( newY + resizeHndSize > mHandleDragArea.y + mHandleDragArea.height )
224 
225             newY = mHandleDragArea.y + mHandleDragArea.height - 1;
226 
227         if ( newY < mHandleDragArea.y )
228 
229             newY = mHandleDragArea.y;
230 
231         mDraggedDelta = newY - realHndOfs;
232 
233         dc.DrawRectangle( mHandleDragArea.x + ofsX, newY + ofsY,
234                           mHandleDragArea.width + 1,
235                           resizeHndSize + 1 );
236     }
237 
238     dc.SetLogicalFunction( prevLF );
239 
240     // "End drawing on top (frees the window used for drawing
241     // over the screen)" --J.S.
242     wxScreenDC::EndDrawingOnTop();
243 }
244 
OnMouseMove(cbMotionEvent & event)245 void cbPaneDrawPlugin::OnMouseMove( cbMotionEvent& event )
246 {
247     if ( !mResizeStarted )
248     {
249         // if nothing is started, do hit-tests
250 
251         bool prevWasRowHandle = mRowHandleHitted;
252 
253         mBarContentHitted = false;
254         mBarHandleHitted  = false;
255         mRowHandleHitted  = false;
256 
257         int testResult =
258             event.mpPane->HitTestPaneItems( event.mPos,        // in pane's coordiantes
259                                             &mpResizedRow,
260                                             &mpDraggedBar );
261 
262         if ( testResult != CB_NO_ITEMS_HITTED )
263         {
264             if ( testResult == CB_BAR_CONTENT_HITTED )
265             {
266                 // restore cursor, if non of the handles were hit
267                 if ( mResizeCursorOn )
268                 {
269                     // remove resizing hints
270 
271                     mpLayout->ReleaseEventsFromPane( event.mpPane );
272                     mpLayout->ReleaseEventsFromPlugin( this );
273 
274                     mResizeCursorOn = false;
275 
276                     mBarContentHitted = true;
277 
278                     // In Windows, at least, the frame needs to have a null cursor
279                     // else child windows (such as text windows) inherit the cursor
280 #if 1
281                     mpLayout->GetParentFrame().SetCursor( wxNullCursor );
282 #else
283                     mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
284 #endif
285                 }
286 
287                 // TBD:: fire something like "mouse-over-bar" event
288 
289                 event.Skip(); // pass event to the next handler in the chain
290                 return;
291             }
292 
293             wxCursor* pCurs;
294 
295             if ( testResult == CB_UPPER_ROW_HANDLE_HITTED ||
296                  testResult == CB_LOWER_ROW_HANDLE_HITTED)
297             {
298                 if ( event.mpPane->IsHorizontal() )
299 
300                     pCurs = mpLayout->mpVertCursor;
301                 else
302                     pCurs = mpLayout->mpHorizCursor;
303 
304                 mRowHandleHitted = true;
305                 mIsUpperHandle    = ( testResult == CB_UPPER_ROW_HANDLE_HITTED );
306             }
307             else
308             {
309                 // otherwise, if inter-bar handle was hitted
310 
311                 if ( event.mpPane->IsHorizontal() )
312 
313                     pCurs = mpLayout->mpHorizCursor;
314                 else
315                     pCurs = mpLayout->mpVertCursor;
316 
317                 mBarHandleHitted = true;
318                 mIsLeftHandle    = ( testResult == CB_LEFT_BAR_HANDLE_HITTED );
319             }
320 
321             // avoid setting the same cursor twice
322 
323             if ( !mResizeCursorOn || prevWasRowHandle != mRowHandleHitted )
324             {
325                 mpLayout->GetParentFrame().SetCursor( *pCurs );
326 
327                 if ( !mResizeCursorOn )
328                 {
329                     // caputre if not captured yet
330                     mpLayout->CaptureEventsForPane( event.mpPane );
331                     mpLayout->CaptureEventsForPlugin( this );
332                 }
333             }
334 
335             mResizeCursorOn = true;
336 
337             // handled is being dragged now, thus event is "eaten" by this plugin
338 
339             return;
340 
341         } // end of if (HitTestBarHandles())
342 
343         // restore cursor, if non of the handles were hit
344         if ( mResizeCursorOn )
345         {
346             mpLayout->ReleaseEventsFromPane( event.mpPane );
347             mpLayout->ReleaseEventsFromPlugin( this );
348 
349             // In Windows, at least, the frame needs to have a null cursor
350             // else child windows (such as text windows) inherit the cursor
351 #if 1
352             mpLayout->GetParentFrame().SetCursor( wxNullCursor );
353 #else
354             mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
355 #endif
356 
357             mResizeCursorOn = false;
358         }
359 
360         event.Skip(); // pass event to the next plugin
361     }
362 
363     // othewise series of actions, if something has already started
364 
365     else
366     if ( mResizeStarted )
367     {
368         // apply xor-mask twice
369         DrawDraggedHandle( mPrevPos,   *event.mpPane );
370 
371         // draw handle in the new position
372         DrawDraggedHandle( event.mPos, *event.mpPane );
373         mPrevPos = event.mPos;
374 
375         // handled is dragged, thus event is "eaten" by this plugin
376     }
377     else
378         event.Skip(); // pass event to the next plugin
379 }
380 
OnLDblClick(cbLeftDClickEvent & event)381 void cbPaneDrawPlugin::OnLDblClick( cbLeftDClickEvent& event )
382 {
383     if ( !mResizeCursorOn )
384     {
385         cbBarInfo* pBarToFloat;
386 
387         if ( event.mpPane->HitTestPaneItems( event.mPos,       // in pane's coordiantes
388                                              &mpResizedRow,
389                                              &pBarToFloat ) == CB_BAR_CONTENT_HITTED
390            )
391             {
392             return;
393             }
394 
395         event.Skip();
396     }
397 }
398 
OnLButtonDown(cbLeftDownEvent & event)399 void cbPaneDrawPlugin::OnLButtonDown( cbLeftDownEvent& event )
400 {
401     wxASSERT( !mResizeStarted );
402 
403     if ( mResizeCursorOn )
404     {
405         mResizeStarted = true;
406         mDragOrigin    = event.mPos;
407 
408         // setup constraints for the dragging handle
409 
410         int from, till;
411         mHandleOfs        = 0;
412         mHandleIsVertical = false;
413 
414         if ( mRowHandleHitted )
415 
416             event.mpPane->GetRowResizeRange( mpResizedRow, &from, &till, mIsUpperHandle );
417         else
418             // otherwise if bar handle was hitted
419             event.mpPane->GetBarResizeRange( mpDraggedBar, &from, &till, mIsLeftHandle );
420 
421         if ( mRowHandleHitted )
422         {
423             mHandleIsVertical = ( event.mpPane->IsHorizontal() ) ? false : true;
424 
425             mHandleDragArea.x      = 0;
426             mHandleDragArea.width  = event.mpPane->mPaneWidth;
427 
428             mHandleDragArea.y      = from;
429             mHandleDragArea.height = till - from;
430 
431             if ( mIsUpperHandle )
432 
433                 mHandleOfs = mpResizedRow->mRowY;
434             else
435                 mHandleOfs = mpResizedRow->mRowY +
436                              mpResizedRow->mRowHeight -
437                              event.mpPane->mProps.mResizeHandleSize;
438         }
439         else
440         {
441             // otehrwise if bar handle dragged
442 
443 //            cbRowInfo& rowInfo     = *mpDraggedBar->mpRow;
444             wxRect& bounds         = mpDraggedBar->mBounds;
445 
446             mHandleIsVertical = ( event.mpPane->IsHorizontal() ) ? true : false;
447 
448             mHandleDragArea.x      = from;
449             mHandleDragArea.width  = till - from;
450 
451 
452             mHandleDragArea.y      = bounds.y;
453             mHandleDragArea.height = bounds.height;
454 
455             // left-side-handle mBounds
456             if ( mIsLeftHandle )
457 
458                 mHandleOfs = bounds.x;
459             else
460                 mHandleOfs = bounds.x +
461                              bounds.width - event.mpPane->mProps.mResizeHandleSize;
462 
463         }
464 
465         event.mpPane->PaneToFrame( &mHandleDragArea );
466         DrawDraggedHandle(mDragOrigin, *event.mpPane);
467 
468         mPrevPos = mDragOrigin;
469 
470         return;
471         // handled is dragged, thus event is "eaten" by this plugin
472     }
473     else
474     {
475         cbBarInfo* pDraggedBar;
476 
477         if ( event.mpPane->HitTestPaneItems( event.mPos,       // in pane's coordiantes
478                                              &mpResizedRow,
479                                              &pDraggedBar ) == CB_BAR_CONTENT_HITTED
480            )
481         {
482             int x = event.mPos.x,
483                 y = event.mPos.y;
484 
485             event.mpPane->PaneToFrame( &x, &y );
486 
487             cbStartBarDraggingEvent dragEvt( pDraggedBar, wxPoint(x,y), event.mpPane );
488 
489             mpLayout->FirePluginEvent( dragEvt );
490 
491             return; // event is "eaten" by this plugin
492         }
493     }
494 
495     event.Skip(); // pass event to the next plugin in the chain
496 }
497 
OnLButtonUp(cbLeftUpEvent & event)498 void cbPaneDrawPlugin::OnLButtonUp( cbLeftUpEvent& event )
499 {
500     if ( mResizeStarted )
501     {
502         DrawDraggedHandle( event.mPos, *event.mpPane );
503 
504         mResizeStarted  = false;
505         mResizeCursorOn = false;
506 
507         mpLayout->ReleaseEventsFromPane( event.mpPane );
508         mpLayout->ReleaseEventsFromPlugin( this );
509 
510         // In Windows, at least, the frame needs to have a null cursor
511         // else child windows (such as text windows) inherit the cursor
512 #if 1
513         mpLayout->GetParentFrame().SetCursor( wxNullCursor );
514 #else
515         mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
516 #endif
517 
518         if ( mRowHandleHitted )
519         {
520             event.mpPane->ResizeRow( mpResizedRow,
521                                      mDraggedDelta,
522                                      mIsUpperHandle );
523         }
524         else
525         {
526             event.mpPane->ResizeBar( mpDraggedBar,
527                                      mDraggedDelta,
528                                      mIsLeftHandle );
529         }
530 
531         mpDraggedBar = NULL;
532         mpResizedRow = NULL;
533 
534         // handled dragging action was finished by this mouse-up,
535         // thus event is "eaten" by this plugin
536 
537         return;
538     }
539 
540     event.Skip(); // pass event to the next plugin
541 }
542 
OnRButtonUp(cbRightUpEvent & event)543 void cbPaneDrawPlugin::OnRButtonUp( cbRightUpEvent&   event )
544 {
545     wxPoint fpos = event.mPos;
546     event.mpPane->PaneToFrame( &fpos.x, &fpos.y );
547 
548     cbBarInfo* pDraggedBar;
549 
550     // user clicks inside the bar contnet, fire bar-customization event
551 
552     if ( event.mpPane->HitTestPaneItems( event.mPos,       // in pane's coordiantes
553                                          &mpResizedRow,
554                                          &pDraggedBar  ) == CB_BAR_CONTENT_HITTED
555        )
556     {
557         cbCustomizeBarEvent cbEvt( pDraggedBar, fpos, event.mpPane );
558 
559         mpLayout->FirePluginEvent( cbEvt );
560 
561         return; // event is "eaten" by this plugin
562     }
563 
564     // otherwise fire whole-layout customization event
565 
566     cbCustomizeLayoutEvent csEvt( fpos );
567 
568     mpLayout->FirePluginEvent( csEvt );
569 
570     // event is "eaten" by this plugin
571 }
572 
OnSizeBarWindow(cbSizeBarWndEvent & event)573 void cbPaneDrawPlugin::OnSizeBarWindow( cbSizeBarWndEvent& event )
574 {
575     cbBarInfo& bar = *event.mpBar;
576     mpPane         = event.mpPane;
577 
578     // it's possible that a bar does not have it's own window!
579     if ( !bar.mpBarWnd ) return;
580 
581     wxRect& bounds = event.mBoundsInParent;
582 
583     // check visibility
584     if ( bounds.height != 0 )
585     {
586         // size smaller than bounds, to leave space for shade lines
587 
588         // FIXME:: +/- 1s
589 
590         int nNewHeight = bounds.height - 2 - bar.mDimInfo.mVertGap *2;
591         if(nNewHeight < 0)
592            nNewHeight = 0;
593 
594         bar.mpBarWnd->wxWindow::SetSize( bounds.x      + 1 + bar.mDimInfo.mHorizGap,
595                                          bounds.y      + 1 + bar.mDimInfo.mVertGap,
596                                          bounds.width  - 2 - bar.mDimInfo.mHorizGap*2,
597                                          nNewHeight,
598                                          0
599                                        );
600 
601         if ( !bar.mpBarWnd->IsShown() )
602 
603             bar.mpBarWnd->Show( true );
604     }
605     else
606         // hide bar if not visible
607         bar.mpBarWnd->Show( false );
608 
609     event.Skip(); // pass event to the next plugin in the chain
610 }
611 
OnDrawRowDecorations(cbDrawRowDecorEvent & event)612 void cbPaneDrawPlugin::OnDrawRowDecorations( cbDrawRowDecorEvent& event )
613 {
614     DrawPaneShadeForRow( event.mpRow, *event.mpDc );
615 
616     event.Skip(); // pass event to the next plugin
617 }
618 
DrawUpperRowHandle(cbRowInfo * pRow,wxDC & dc)619 void cbPaneDrawPlugin::DrawUpperRowHandle( cbRowInfo* pRow, wxDC& dc )
620 {
621     wxRect& bounds = pRow->mBoundsInParent;
622 
623     if ( mpPane->IsHorizontal() )
624     {
625          if ( pRow->mHasUpperHandle )
626 
627             mpPane->DrawHorizHandle( dc, bounds.x,
628                                      bounds.y-1,
629                                       pRow->mRowWidth );
630     }
631     else
632     {
633         if ( pRow->mHasUpperHandle )
634 
635             mpPane->DrawVertHandle( dc, bounds.x-1,
636                                     bounds.y, pRow->mRowWidth );
637     }
638 }
639 
DrawLowerRowHandle(cbRowInfo * pRow,wxDC & dc)640 void cbPaneDrawPlugin::DrawLowerRowHandle( cbRowInfo* pRow, wxDC& dc )
641 {
642     wxRect& bounds = pRow->mBoundsInParent;
643 
644     // check if iter-row handles present
645 
646     if ( mpPane->IsHorizontal() )
647     {
648         if ( pRow->mHasLowerHandle )
649 
650             mpPane->DrawHorizHandle( dc, bounds.x, bounds.y + bounds.height - mpPane->mProps.mResizeHandleSize - 1,
651                                       pRow->mRowWidth );
652     }
653     else
654     {
655         if ( pRow->mHasLowerHandle )
656 
657             mpPane->DrawVertHandle( dc, bounds.x + bounds.width - mpPane->mProps.mResizeHandleSize - 1,
658                                      bounds.y, pRow->mRowWidth );
659     }
660 }
661 
OnDrawRowHandles(cbDrawRowHandlesEvent & event)662 void cbPaneDrawPlugin::OnDrawRowHandles( cbDrawRowHandlesEvent& event )
663 {
664     // short-cuts
665     cbRowInfo* pRow = event.mpRow;
666     wxDC&   dc      = *event.mpDc;
667     mpPane          = event.mpPane;
668 
669     // draw handles of surrounding rows first
670 
671     if ( pRow->mpPrev && pRow->mpPrev->mHasLowerHandle )
672 
673             DrawLowerRowHandle( pRow->mpPrev, dc );
674 
675     if ( pRow->mpNext && pRow->mpNext->mHasUpperHandle )
676 
677         DrawUpperRowHandle( pRow->mpNext, dc );
678 
679     // draw handles of the given row
680 
681     if ( pRow->mHasUpperHandle )
682 
683         DrawUpperRowHandle( pRow, dc );
684 
685     if ( pRow->mHasLowerHandle )
686 
687         DrawLowerRowHandle( pRow, dc );
688 
689     event.Skip(); // pass event to the next plugin
690 }
691 
OnDrawPaneBackground(cbDrawPaneBkGroundEvent & event)692 void cbPaneDrawPlugin::OnDrawPaneBackground ( cbDrawPaneBkGroundEvent& event )
693 {
694     wxDC& dc = *event.mpDc;
695     mpPane   = event.mpPane;
696 
697     // FOR NOW:: hard-coded
698     wxBrush bkBrush( mpLayout->mBorderPen.GetColour(), wxSOLID );
699 
700     dc.SetBrush( bkBrush );
701     dc.SetPen( mpLayout->mNullPen );
702 
703     wxRect& bounds = mpPane->mBoundsInParent;
704 
705     if ( mpPane->mTopMargin >= 1 )
706 
707         dc.DrawRectangle( bounds.x, bounds.y,
708                           bounds.width+1,
709                           mpPane->mTopMargin + 1);
710 
711 
712     if ( mpPane->mBottomMargin >= 1 )
713 
714         dc.DrawRectangle( bounds.x,
715                           bounds.y + bounds.height - mpPane->mBottomMargin,
716                           bounds.width + 1,
717                           mpPane->mBottomMargin + 1);
718 
719 
720     if ( mpPane->mLeftMargin >= 1 )
721 
722         dc.DrawRectangle( bounds.x,
723                           bounds.y + mpPane->mTopMargin - 1,
724                           mpPane->mLeftMargin + 1,
725                           bounds.height - mpPane->mTopMargin - mpPane->mBottomMargin + 2);
726 
727 
728     if ( mpPane->mRightMargin >= 1 )
729 
730         dc.DrawRectangle( bounds.x + bounds.width - mpPane->mRightMargin,
731                           bounds.y + mpPane->mTopMargin - 1,
732                           mpPane->mRightMargin + 1,
733                           bounds.height - mpPane->mTopMargin - mpPane->mBottomMargin + 2);
734 
735     event.Skip(); // pass event to the next plugin
736 }
737 
OnDrawRowBackground(cbDrawRowBkGroundEvent & event)738 void cbPaneDrawPlugin::OnDrawRowBackground ( cbDrawRowBkGroundEvent& event )
739 {
740     // short-cuts
741     cbRowInfo* pRow = event.mpRow;
742     wxDC&   dc      = *event.mpDc;
743     mpPane          = event.mpPane;
744 
745     // get ready
746     wxRect     rowBounds    = pRow->mBoundsInParent;
747     bool       isHorizontal    = event.mpPane->IsHorizontal();
748 
749 //    int prevPos;
750 
751     if ( isHorizontal )
752     {
753 //        prevPos = rowBounds.x;
754         // include one line above and below the row
755         --rowBounds.y;
756         rowBounds.height += 2;
757 
758         --rowBounds.x;
759         rowBounds.width  += 2;
760     }
761     else
762     {
763 //        prevPos = rowBounds.y;
764         // include one line above and below the row
765         --rowBounds.x;
766         rowBounds.width  += 2;
767 
768         --rowBounds.y;
769         rowBounds.height += 2;
770     }
771 
772 //#define TEST_BK_ERASING
773 
774 #ifdef TEST_BK_ERASING
775 
776     // DBG::
777     wxBrush br0( wxColour(0,160,160), wxSOLID );
778     dc.SetBrush(br0);
779     dc.SetPen  ( mpLayout->mNullPen );
780     dc.DrawRectangle( rowBounds.x, rowBounds.y,
781                       rowBounds.width  + 1,
782                       rowBounds.height + 1  );
783 #endif
784 
785     wxBrush bkBrush( mpLayout->mGrayPen.GetColour(), wxSOLID );
786 
787     dc.SetPen  ( mpLayout->mNullPen );
788     dc.SetBrush( bkBrush );
789 
790     // fill background-recatangle of entire row area
791     dc.DrawRectangle( rowBounds.x, rowBounds.y,
792                       rowBounds.width  + 1,
793                       rowBounds.height + 1  );
794 
795     dc.SetBrush( wxNullBrush );
796 
797     // draw "shaded-side-bars" for each bar
798     for( size_t i = 0; i != pRow->mBars.Count(); ++i )
799     {
800         wxRect& bounds = pRow->mBars[i]->mBoundsInParent;
801 
802         if ( isHorizontal )
803         {
804             DrawShade( 1, bounds, FL_ALIGN_LEFT, dc );
805             DrawShade( 1, bounds, FL_ALIGN_RIGHT, dc );
806         }
807         else
808         {
809             DrawShade( 1, bounds, FL_ALIGN_TOP, dc );
810             DrawShade( 1, bounds, FL_ALIGN_BOTTOM, dc );
811         }
812     }
813 
814     // draw extra shades to simulate "glued-bricks" effect
815 
816     // TBD:: reduce exessive drawing of shades, when the
817     //       row handle is present, and shades will be overr-drawn anyway
818 
819     DrawUpperRowShades( pRow, dc, 1 ); // outer shade
820 
821     if ( pRow->mpPrev )
822     {
823         DrawLowerRowShades( pRow->mpPrev, dc, 1 ); // outter shade
824         DrawLowerRowShades( pRow->mpPrev, dc, 0 ); // inner shade
825     }
826 
827     DrawLowerRowShades( pRow, dc, 1 );
828 
829     if ( pRow->mpNext )
830     {
831         DrawUpperRowShades( pRow->mpNext, dc, 1 );
832         DrawUpperRowShades( pRow->mpNext, dc, 0 );
833     }
834 
835     event.Skip(); // pass event to the next plugin
836 }
837 
DrawUpperRowShades(cbRowInfo * pRow,wxDC & dc,int level)838 void cbPaneDrawPlugin::DrawUpperRowShades( cbRowInfo* pRow, wxDC& dc, int level )
839 {
840     for( size_t i = 0; i != pRow->mBars.Count(); ++i )
841     {
842         wxRect& bounds = pRow->mBars[i]->mBoundsInParent;
843 
844         if ( mpPane->IsHorizontal() )
845         {
846             DrawShade( level, bounds, FL_ALIGN_TOP, dc );
847             if ( level == 1 )
848             {
849                 dc.SetPen( mpLayout->mDarkPen );
850                 dc.DrawPoint( bounds.x - 1, bounds.y );
851                 dc.SetPen( mpLayout->mLightPen );
852                 dc.DrawPoint( bounds.x + bounds.width , bounds.y );
853             }
854         }
855         else
856         {
857             DrawShade( level, bounds, FL_ALIGN_LEFT, dc );
858             if ( level == 1 )
859             {
860                 dc.SetPen( mpLayout->mDarkPen );
861                 dc.DrawPoint( bounds.x, bounds.y -1 );
862                 dc.SetPen( mpLayout->mLightPen );
863                 dc.DrawPoint( bounds.x, bounds.y + bounds.height );
864             }
865         }
866     }
867 }
868 
DrawLowerRowShades(cbRowInfo * pRow,wxDC & dc,int level)869 void cbPaneDrawPlugin::DrawLowerRowShades( cbRowInfo* pRow, wxDC& dc, int level )
870 {
871     for( size_t i = 0; i != pRow->mBars.Count(); ++i )
872     {
873         wxRect& bounds = pRow->mBars[i]->mBoundsInParent;
874 
875         if ( mpPane->IsHorizontal() )
876         {
877             DrawShade( level, bounds, FL_ALIGN_BOTTOM, dc );
878             if ( level == 1 )
879             {
880                 dc.SetPen( mpLayout->mDarkPen );
881                 dc.DrawPoint( bounds.x - 1, bounds.y + bounds.height -1 );
882                 dc.SetPen( mpLayout->mLightPen );
883                 dc.DrawPoint( bounds.x + bounds.width , bounds.y + bounds.height -1 );
884             }
885         }
886         else
887         {
888             DrawShade( level, bounds, FL_ALIGN_RIGHT, dc );
889             if ( level == 1 )
890             {
891                 dc.SetPen( mpLayout->mDarkPen );
892                 dc.DrawPoint( bounds.x + bounds.width - 1, bounds.y -1 );
893                 dc.SetPen( mpLayout->mLightPen );
894                 dc.DrawPoint( bounds.x + bounds.width - 1, bounds.y + bounds.height );
895             }
896         }
897     }
898 }
899 
DrawBarInnerShadeRect(cbBarInfo * pBar,wxDC & dc)900 void cbPaneDrawPlugin::DrawBarInnerShadeRect( cbBarInfo* pBar, wxDC& dc )
901 {
902     wxRect& bounds = pBar->mBoundsInParent;
903 
904     dc.SetPen( mpLayout->mDarkPen );
905 
906     dc.DrawLine( bounds.x + bounds.width - 1,
907                  bounds.y,
908                  bounds.x + bounds.width - 1,
909                  bounds.y + bounds.height );
910 
911     dc.DrawLine( bounds.x,
912                  bounds.y + bounds.height - 1,
913                  bounds.x + bounds.width,
914                  bounds.y + bounds.height -1  );
915 
916     dc.SetPen( mpLayout->mLightPen );
917 
918     dc.DrawLine( bounds.x,
919                  bounds.y,
920                  bounds.x + bounds.width - 1,
921                  bounds.y );
922 
923     dc.DrawLine( bounds.x,
924                  bounds.y,
925                  bounds.x,
926                  bounds.y + bounds.height - 1 );
927 }
928 
DrawShade(int level,wxRect & rect,int alignment,wxDC & dc)929 void cbPaneDrawPlugin::DrawShade( int level, wxRect& rect, int alignment, wxDC& dc )
930 {
931     // simulates "guled-bricks" appearence of control bars
932 
933     if ( ( alignment == FL_ALIGN_TOP    && level == 1 ) ||
934          ( alignment == FL_ALIGN_BOTTOM && level == 0 ) ||
935          ( alignment == FL_ALIGN_LEFT   && level == 1 ) ||
936          ( alignment == FL_ALIGN_RIGHT  && level == 0 )
937        )
938 
939         dc.SetPen( mpLayout->mDarkPen  );
940     else
941         dc.SetPen( mpLayout->mLightPen );
942 
943     if ( alignment == FL_ALIGN_TOP )
944     {
945         if ( level == 0 )
946 
947             dc.DrawLine( rect.x,
948                          rect.y,
949                          rect.x + rect.width - 1,
950                          rect.y );
951         else
952             dc.DrawLine( rect.x - 1,
953                          rect.y - 1,
954                          rect.x + rect.width + 0,
955                          rect.y - 1 );
956     }
957     else
958     if ( alignment == FL_ALIGN_BOTTOM )
959     {
960         if ( level == 0 )
961 
962             dc.DrawLine( rect.x,
963                          rect.y + rect.height - 1,
964                          rect.x + rect.width,
965                          rect.y + rect.height - 1 );
966         else
967             dc.DrawLine( rect.x - 1,
968                          rect.y + rect.height,
969                          rect.x + rect.width + 1,
970                          rect.y + rect.height );
971     }
972     else
973     if ( alignment == FL_ALIGN_LEFT )
974     {
975         if ( level == 0 )
976 
977             dc.DrawLine( rect.x,
978                          rect.y,
979                          rect.x,
980                          rect.y + rect.height - 1 );
981         else
982             dc.DrawLine( rect.x - 1,
983                          rect.y - 1,
984                          rect.x - 1,
985                          rect.y + rect.height );
986     }
987     else
988     if ( alignment == FL_ALIGN_RIGHT )
989     {
990         if ( level == 0 )
991 
992             dc.DrawLine( rect.x + rect.width - 1,
993                          rect.y,
994                          rect.x + rect.width - 1,
995                          rect.y + rect.height );
996         else
997         {
998             dc.DrawLine( rect.x + rect.width,
999                          rect.y - 1,
1000                          rect.x + rect.width,
1001                          rect.y + rect.height + 1  );
1002         }
1003     }
1004 }
1005 
DrawShade1(int level,wxRect & rect,int alignment,wxDC & dc)1006 void cbPaneDrawPlugin::DrawShade1( int level, wxRect& rect, int alignment, wxDC& dc )
1007 {
1008     // simulates "guled-bricks" appearence of control bars
1009 
1010     if ( ( alignment == FL_ALIGN_TOP    && level == 1 ) ||
1011          ( alignment == FL_ALIGN_BOTTOM && level == 0 ) ||
1012          ( alignment == FL_ALIGN_LEFT   && level == 1 ) ||
1013          ( alignment == FL_ALIGN_RIGHT  && level == 0 )
1014        )
1015 
1016         dc.SetPen( mpLayout->mDarkPen  );
1017     else
1018         dc.SetPen( mpLayout->mLightPen );
1019 
1020     if ( alignment == FL_ALIGN_TOP )
1021     {
1022         if ( level == 0 )
1023 
1024             dc.DrawLine( rect.x,
1025                          rect.y,
1026                          rect.x + rect.width,
1027                          rect.y );
1028         else
1029             dc.DrawLine( rect.x,
1030                          rect.y - 1,
1031                          rect.x + rect.width,
1032                          rect.y - 1 );
1033     }
1034     else
1035     if ( alignment == FL_ALIGN_BOTTOM )
1036     {
1037         if ( level == 0 )
1038 
1039             dc.DrawLine( rect.x,
1040                          rect.y + rect.height - 1,
1041                          rect.x + rect.width,
1042                          rect.y + rect.height - 1 );
1043         else
1044             dc.DrawLine( rect.x,
1045                          rect.y + rect.height,
1046                          rect.x + rect.width,
1047                          rect.y + rect.height );
1048     }
1049     else
1050     if ( alignment == FL_ALIGN_LEFT )
1051     {
1052         if ( level == 0 )
1053 
1054             dc.DrawLine( rect.x,
1055                          rect.y,
1056                          rect.x,
1057                          rect.y + rect.height );
1058         else
1059             dc.DrawLine( rect.x - 1,
1060                          rect.y,
1061                          rect.x - 1,
1062                          rect.y + rect.height );
1063     }
1064     else
1065     if ( alignment == FL_ALIGN_RIGHT )
1066     {
1067         if ( level == 0 )
1068 
1069             dc.DrawLine( rect.x + rect.width - 1,
1070                          rect.y,
1071                          rect.x + rect.width - 1,
1072                          rect.y + rect.height );
1073         else
1074         {
1075             dc.DrawLine( rect.x + rect.width,
1076                          rect.y ,
1077                          rect.x + rect.width,
1078                          rect.y + rect.height );
1079         }
1080     }
1081 }
1082 
DrawPaneShade(wxDC & dc,int alignment)1083 void cbPaneDrawPlugin::DrawPaneShade( wxDC& dc, int alignment )
1084 {
1085     if ( !mpPane->mProps.mShow3DPaneBorderOn ) return;
1086 
1087     wxRect bounds = mpPane->mBoundsInParent;
1088 
1089     bounds.x      += mpPane->mLeftMargin;
1090     bounds.y      += mpPane->mTopMargin;
1091     bounds.width  -= ( mpPane->mLeftMargin + mpPane->mRightMargin  );
1092     bounds.height -= ( mpPane->mTopMargin  + mpPane->mBottomMargin );
1093 
1094     DrawShade( 0, bounds, alignment, dc );
1095     DrawShade( 1, bounds, alignment, dc );
1096 }
1097 
DrawPaneShadeForRow(cbRowInfo * pRow,wxDC & dc)1098 void cbPaneDrawPlugin::DrawPaneShadeForRow( cbRowInfo* pRow, wxDC& dc )
1099 {
1100     if ( !mpPane->mProps.mShow3DPaneBorderOn ) return;
1101 
1102     // do not draw decoration, if pane has "vainished"
1103     if ( mpPane->mPaneWidth  < 0 ||
1104          mpPane->mPaneHeight < 0 )
1105 
1106          return;
1107 
1108     wxRect bounds = pRow->mBoundsInParent;
1109 
1110     if ( mpPane->mAlignment == FL_ALIGN_TOP ||
1111          mpPane->mAlignment == FL_ALIGN_BOTTOM )
1112     {
1113         --bounds.y;
1114         bounds.height += 2;
1115 
1116         DrawShade1( 0, bounds, FL_ALIGN_LEFT, dc );
1117         DrawShade1( 1, bounds, FL_ALIGN_LEFT, dc );
1118         DrawShade1( 0, bounds, FL_ALIGN_RIGHT, dc );
1119         DrawShade1( 1, bounds, FL_ALIGN_RIGHT, dc );
1120 
1121         if ( !pRow->mpNext )
1122             DrawPaneShade( dc, FL_ALIGN_BOTTOM );
1123 
1124         if ( !pRow->mpPrev )
1125             DrawPaneShade( dc, FL_ALIGN_TOP );
1126     }
1127     else
1128     {
1129         --bounds.x;
1130         bounds.width += 2;
1131 
1132         DrawShade1( 0, bounds, FL_ALIGN_TOP, dc );
1133         DrawShade1( 1, bounds, FL_ALIGN_TOP, dc );
1134         DrawShade1( 0, bounds, FL_ALIGN_BOTTOM, dc );
1135         DrawShade1( 1, bounds, FL_ALIGN_BOTTOM, dc );
1136 
1137         if ( !pRow->mpNext )
1138             DrawPaneShade( dc, FL_ALIGN_RIGHT );
1139 
1140         if ( !pRow->mpPrev )
1141             DrawPaneShade( dc, FL_ALIGN_LEFT );
1142     }
1143 }
1144 
OnDrawPaneDecorations(cbDrawPaneDecorEvent & event)1145 void cbPaneDrawPlugin::OnDrawPaneDecorations( cbDrawPaneDecorEvent& event )
1146 {
1147     wxDC& dc = *event.mpDc;
1148 
1149     cbDockPane* pPane = event.mpPane;
1150 
1151     RowArrayT& lst = pPane->GetRowList();
1152 
1153     // FIXME:: this is a workaround for some glitches
1154 
1155     if ( lst.Count() )
1156     {
1157         cbRowInfo* pLastRow = lst[ lst.Count() - 1 ];
1158 
1159         pPane->PaintRowBackground( pLastRow,  dc );
1160         pPane->PaintRowDecorations( pLastRow, dc );
1161         pPane->PaintRowHandles( pLastRow, dc );
1162     }
1163 
1164     if ( !pPane->mProps.mShow3DPaneBorderOn ) return;
1165 
1166     // do not draw decoration, if pane is completely hidden
1167     if ( event.mpPane->mPaneWidth  < 0 ||
1168          event.mpPane->mPaneHeight < 0 )
1169 
1170          return;
1171 
1172     DrawPaneShade( dc, FL_ALIGN_TOP    );
1173     DrawPaneShade( dc, FL_ALIGN_BOTTOM );
1174     DrawPaneShade( dc, FL_ALIGN_LEFT   );
1175     DrawPaneShade( dc, FL_ALIGN_RIGHT  );
1176 
1177     event.Skip(); // pass event to the next plugin
1178 }
1179 
1180 // bar decoration/sizing handlers
1181 
OnDrawBarDecorations(cbDrawBarDecorEvent & event)1182 void cbPaneDrawPlugin::OnDrawBarDecorations( cbDrawBarDecorEvent& event )
1183 {
1184 //    cbBarInfo* pBar = event.mpBar;
1185     wxDC&   dc      = *event.mpDc;
1186 
1187     // draw brick borders
1188 
1189     wxRect& rect = event.mBoundsInParent;
1190 
1191     dc.SetPen( mpLayout->mLightPen );
1192 
1193     // horiz
1194     dc.DrawLine( rect.x, rect.y,
1195                  rect.x + rect.width-1, rect.y );
1196 
1197     // vert
1198     dc.DrawLine( rect.x, rect.y,
1199                  rect.x, rect.y + rect.height-1 );
1200 
1201 
1202     dc.SetPen( mpLayout->mDarkPen );
1203 
1204     // vert
1205     dc.DrawLine( rect.x + rect.width-1, rect.y,
1206                  rect.x + rect.width-1, rect.y + rect.height-1 );
1207 
1208     // horiz
1209     dc.DrawLine( rect.x, rect.y + rect.height-1,
1210                  rect.x + rect.width, rect.y + rect.height-1 );
1211 
1212     event.Skip(); // pass event to the next plugin
1213 }
1214 
OnDrawBarHandles(cbDrawBarHandlesEvent & event)1215 void cbPaneDrawPlugin::OnDrawBarHandles( cbDrawBarHandlesEvent& event )
1216 {
1217     // short-cuts
1218     cbBarInfo* pBar = event.mpBar;
1219     wxDC&   dc      = *event.mpDc;
1220     mpPane          = event.mpPane;
1221 
1222     // draw handles around the bar if present
1223 
1224     if ( pBar->mHasLeftHandle ||
1225          pBar->mHasRightHandle )
1226     {
1227         wxRect& bounds = pBar->mBoundsInParent;
1228 
1229         if ( mpPane->IsHorizontal() )
1230         {
1231             if ( pBar->mHasLeftHandle )
1232 
1233                 mpPane->DrawVertHandle( dc, bounds.x - mpPane->mProps.mResizeHandleSize -1,
1234                                         bounds.y, bounds.height );
1235 
1236             if ( pBar->mHasRightHandle )
1237 
1238                 mpPane->DrawVertHandle( dc,
1239                                         bounds.x + bounds.width -1,
1240                                         bounds.y, bounds.height );
1241         }
1242         else
1243         {
1244             if ( pBar->mHasLeftHandle )
1245 
1246                 mpPane->DrawHorizHandle( dc, bounds.x,
1247                                          bounds.y  - mpPane->mProps.mResizeHandleSize - 1,
1248                                          bounds.width );
1249 
1250             if ( pBar->mHasRightHandle )
1251 
1252                 mpPane->DrawHorizHandle( dc, bounds.x,
1253                                          bounds.y + bounds.height - 1,
1254                                          bounds.width );
1255         }
1256     }
1257 
1258     event.Skip(); // pass event to the next plugin
1259 }
1260 
OnStartDrawInArea(cbStartDrawInAreaEvent & event)1261 void cbPaneDrawPlugin::OnStartDrawInArea( cbStartDrawInAreaEvent& event )
1262 {
1263     // DBG::
1264     wxASSERT( mpClntDc == NULL );
1265 
1266     // FOR NOW:: create/destroy client-dc upon each drawing
1267     mpClntDc = new wxClientDC( &mpLayout->GetParentFrame() );
1268 
1269     (*event.mppDc) = mpClntDc;
1270 
1271     mpClntDc->SetClippingRegion( event.mArea.x,     event.mArea.y,
1272                                  event.mArea.width, event.mArea.height );
1273 }
1274 
OnFinishDrawInArea(cbFinishDrawInAreaEvent & WXUNUSED (event))1275 void cbPaneDrawPlugin::OnFinishDrawInArea( cbFinishDrawInAreaEvent& WXUNUSED(event) )
1276 {
1277     // DBG::
1278     wxASSERT( mpClntDc );
1279 
1280     delete mpClntDc;
1281 
1282     mpClntDc = NULL;
1283 }
1284 
1285