]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/fl/panedrawpl.cpp
Only support detection of "near the edge" coordinates, if dragging grid lines
[wxWidgets.git] / contrib / src / fl / panedrawpl.cpp
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$
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
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
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
140 cbPaneDrawPlugin::~cbPaneDrawPlugin()
141 {
142 // DBG::
143 wxASSERT( mpClntDc == NULL );
144 }
145
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
1275 void cbPaneDrawPlugin::OnFinishDrawInArea( cbFinishDrawInAreaEvent& WXUNUSED(event) )
1276 {
1277 // DBG::
1278 wxASSERT( mpClntDc );
1279
1280 delete mpClntDc;
1281
1282 mpClntDc = NULL;
1283 }
1284