]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/fl/panedrawpl.cpp
Fixed bug with SetValue on read-only combobox; don't call ::SetWindowText,
[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 #ifdef __GNUG__
13 #pragma implementation "panedrawpl.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/wx.h"
25 #endif
26
27 #include <math.h>
28 #include <stdlib.h>
29
30 #include "wx/utils.h" // import wxMin,wxMax macros
31
32 #include "wx/fl/panedrawpl.h"
33
34 // bitmap bits used by bar-resizing brush
35
36 #define _IMG_A 0xAA // Note: modified from _A to _IMG_A, _A was already defined (cygwin)
37 #define _IMG_B 0x00 // Note: modified from _B to _IMG_A, _B was already defined (cygwin)
38 #define _IMG_C 0x55 // Note: modified from _C to _IMG_C, for consistency reasons.
39 #define _IMG_D 0x00 // Note: modified from _D to _IMG_D, for consistency reasons.
40
41 static const unsigned char _gCheckerImg[16] = { _IMG_A,_IMG_B,_IMG_C,_IMG_D,
42 _IMG_A,_IMG_B,_IMG_C,_IMG_D,
43 _IMG_A,_IMG_B,_IMG_C,_IMG_D,
44 _IMG_A,_IMG_B,_IMG_C,_IMG_D
45 };
46
47 // FIXME:: The below code somehow doesn't work - cursors remain unchanged
48 // Used: controlbar.cpp(1268): set_cursor_bits( _gHorizCursorImg, bits, 32, 16 );
49 // Used: controlbar.cpp(1272): set_cursor_bits( _gVertCursorImg, bits, 32, 16 );
50 /*
51 static void set_cursor_bits( const char** img, char* bits, int width, int height )
52 {
53 for( int i = 0; i != (width*height)/8; ++i )
54 bits[i] = 0;
55
56 for( int y = 0; y != height; ++y )
57 {
58 const char* row = img[0];
59
60 for( int x = 0; x != width; ++x )
61 {
62 int bitNo = y*width + x;
63
64 char value = ( row[x] != '.' ) ? 1 : 0;
65
66 bits[ bitNo / sizeof(char) ] |=
67 ( ( bitNo %sizeof(char) ) << value );
68 }
69
70 ++img;
71 }
72 }
73 */
74
75 /***** Implementation for class cbPaneDrawPlugin *****/
76
77 IMPLEMENT_DYNAMIC_CLASS( cbPaneDrawPlugin, cbPluginBase )
78
79 BEGIN_EVENT_TABLE( cbPaneDrawPlugin, cbPluginBase )
80
81 EVT_PL_LEFT_DOWN ( cbPaneDrawPlugin::OnLButtonDown )
82 EVT_PL_LEFT_UP ( cbPaneDrawPlugin::OnLButtonUp )
83 // EVT_PL_LEFT_DCLICK ( cbPaneDrawPlugin::OnLDblClick )
84 EVT_PL_RIGHT_UP ( cbPaneDrawPlugin::OnRButtonUp )
85 EVT_PL_MOTION ( cbPaneDrawPlugin::OnMouseMove )
86
87
88 EVT_PL_DRAW_PANE_BKGROUND ( cbPaneDrawPlugin::OnDrawPaneBackground )
89 EVT_PL_DRAW_PANE_DECOR ( cbPaneDrawPlugin::OnDrawPaneDecorations )
90
91 EVT_PL_DRAW_ROW_DECOR ( cbPaneDrawPlugin::OnDrawRowDecorations )
92 EVT_PL_DRAW_ROW_HANDLES ( cbPaneDrawPlugin::OnDrawRowHandles )
93 EVT_PL_DRAW_ROW_BKGROUND ( cbPaneDrawPlugin::OnDrawRowBackground )
94
95 EVT_PL_SIZE_BAR_WND ( cbPaneDrawPlugin::OnSizeBarWindow )
96 EVT_PL_DRAW_BAR_DECOR ( cbPaneDrawPlugin::OnDrawBarDecorations )
97 EVT_PL_DRAW_BAR_HANDLES ( cbPaneDrawPlugin::OnDrawBarHandles )
98
99 EVT_PL_START_DRAW_IN_AREA ( cbPaneDrawPlugin::OnStartDrawInArea )
100 EVT_PL_FINISH_DRAW_IN_AREA ( cbPaneDrawPlugin::OnFinishDrawInArea )
101
102 END_EVENT_TABLE()
103
104 cbPaneDrawPlugin::cbPaneDrawPlugin(void)
105
106 : mResizeStarted ( FALSE ),
107
108 mResizeCursorOn ( FALSE ),
109 mpDraggedBar ( NULL ),
110 mpResizedRow ( NULL ),
111
112 mRowHandleHitted ( FALSE ),
113 mIsUpperHandle ( FALSE ),
114 mBarHandleHitted ( FALSE ),
115 mIsLeftHandle ( FALSE ),
116 mBarContentHitted ( FALSE ),
117
118 mpClntDc ( NULL ),
119 mpPane ( NULL )
120 {}
121
122 cbPaneDrawPlugin::cbPaneDrawPlugin( wxFrameLayout* pPanel, int paneMask )
123
124 : cbPluginBase( pPanel, paneMask ),
125
126 // bar-row resizing state varaibles
127
128 mResizeStarted ( FALSE ),
129
130 mResizeCursorOn ( FALSE ),
131 mpDraggedBar ( NULL ),
132 mpResizedRow ( NULL ),
133
134 mRowHandleHitted ( FALSE ),
135 mIsUpperHandle ( FALSE ),
136 mBarHandleHitted ( FALSE ),
137 mIsLeftHandle ( FALSE ),
138 mBarContentHitted ( FALSE ),
139
140 mpClntDc ( NULL ),
141 mpPane ( NULL )
142 {}
143
144 cbPaneDrawPlugin::~cbPaneDrawPlugin()
145 {
146 // DBG::
147 wxASSERT( mpClntDc == NULL );
148 }
149
150 void cbPaneDrawPlugin::DrawDraggedHandle( const wxPoint& pos, cbDockPane& pane )
151 {
152 wxScreenDC dc;
153 int ofsX = 0;
154 int ofsY = 0;
155
156 wxPoint fpos = pos;
157 pane.PaneToFrame( &fpos.x, &fpos.y );
158
159 // short-cut
160 int resizeHndSize = pane.mProps.mResizeHandleSize;
161
162 // "Required for X to specify that
163 // that we wish to draw on top of all windows
164 // - and we optimise by specifying the area
165 // for creating the overlap window." --J.S.
166
167 wxScreenDC::StartDrawingOnTop(&mpLayout->GetParentFrame());
168
169 mpLayout->GetParentFrame().ClientToScreen( &ofsX, &ofsY );
170
171 int prevLF = dc.GetLogicalFunction();
172
173 // BUG BUG BUG (wx):: somehow stippled brush works only
174 // when the bitmap created on stack, not
175 // as a member of the class
176
177 wxBitmap checker( (const char*)_gCheckerImg, 8,8 );
178
179 wxBrush checkerBrush( checker );
180
181 dc.SetPen( mpLayout->mNullPen );
182 dc.SetBrush( checkerBrush );
183 dc.SetLogicalFunction( wxXOR );
184
185 if ( mHandleIsVertical )
186 {
187 int delta = pos.x - mDragOrigin.x;
188
189 if ( !pane.IsHorizontal() )
190
191 delta = pos.y - mDragOrigin.y;
192
193 int realHndOfs;
194 realHndOfs = pane.mBoundsInParent.x + pane.mLeftMargin + mHandleOfs;
195
196 int newX = realHndOfs + delta;
197
198 if ( newX + resizeHndSize > mHandleDragArea.x + mHandleDragArea.width )
199
200 newX = mHandleDragArea.x + mHandleDragArea.width - 1;
201
202 if ( newX < mHandleDragArea.x )
203
204 newX = mHandleDragArea.x;
205
206 mDraggedDelta = newX - realHndOfs;
207
208 dc.DrawRectangle( newX + ofsX, mHandleDragArea.y + ofsY,
209 resizeHndSize + 1,
210 mHandleDragArea.height+1 );
211 }
212 else
213 {
214 // otherwise, draw horizontal handle
215
216 int delta = pos.y - mDragOrigin.y;
217
218 if ( !pane.IsHorizontal() )
219
220 delta = pos.x - mDragOrigin.x;
221
222 int realHndOfs;
223 realHndOfs = pane.mBoundsInParent.y + pane.mTopMargin + mHandleOfs;
224
225 int newY = realHndOfs + delta;
226
227 if ( newY + resizeHndSize > mHandleDragArea.y + mHandleDragArea.height )
228
229 newY = mHandleDragArea.y + mHandleDragArea.height - 1;
230
231 if ( newY < mHandleDragArea.y )
232
233 newY = mHandleDragArea.y;
234
235 mDraggedDelta = newY - realHndOfs;
236
237 dc.DrawRectangle( mHandleDragArea.x + ofsX, newY + ofsY,
238 mHandleDragArea.width + 1,
239 resizeHndSize + 1 );
240 }
241
242 dc.SetLogicalFunction( prevLF );
243
244 // "End drawing on top (frees the window used for drawing
245 // over the screen)" --J.S.
246 wxScreenDC::EndDrawingOnTop();
247 }
248
249 void cbPaneDrawPlugin::OnMouseMove( cbMotionEvent& event )
250 {
251 if ( !mResizeStarted )
252 {
253 // if nothing is started, do hit-tests
254
255 bool prevWasRowHandle = mRowHandleHitted;
256
257 mBarContentHitted = FALSE;
258 mBarHandleHitted = FALSE;
259 mRowHandleHitted = FALSE;
260
261 int testResult =
262 event.mpPane->HitTestPaneItems( event.mPos, // in pane's coordiantes
263 &mpResizedRow,
264 &mpDraggedBar );
265
266 if ( testResult != CB_NO_ITEMS_HITTED )
267 {
268 if ( testResult == CB_BAR_CONTENT_HITTED )
269 {
270 // restore cursor, if non of the handles were hit
271 if ( mResizeCursorOn )
272 {
273 // remove resizing hints
274
275 mpLayout->ReleaseEventsFromPane( event.mpPane );
276 mpLayout->ReleaseEventsFromPlugin( this );
277
278 mResizeCursorOn = FALSE;
279
280 mBarContentHitted = TRUE;
281
282 // In Windows, at least, the frame needs to have a null cursor
283 // else child windows (such as text windows) inherit the cursor
284 #if 1
285 mpLayout->GetParentFrame().SetCursor( wxNullCursor );
286 #else
287 mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
288 #endif
289 }
290
291 // TBD:: fire something like "mouse-over-bar" event
292
293 event.Skip(); // pass event to the next handler in the chain
294 return;
295 }
296
297 wxCursor* pCurs = NULL;
298
299 if ( testResult == CB_UPPER_ROW_HANDLE_HITTED ||
300 testResult == CB_LOWER_ROW_HANDLE_HITTED)
301 {
302 if ( event.mpPane->IsHorizontal() )
303
304 pCurs = mpLayout->mpVertCursor;
305 else
306 pCurs = mpLayout->mpHorizCursor;
307
308 mRowHandleHitted = TRUE;
309 mIsUpperHandle = ( testResult == CB_UPPER_ROW_HANDLE_HITTED );
310 }
311 else
312 {
313 // otherwise, if inter-bar handle was hitted
314
315 if ( event.mpPane->IsHorizontal() )
316
317 pCurs = mpLayout->mpHorizCursor;
318 else
319 pCurs = mpLayout->mpVertCursor;
320
321 mBarHandleHitted = TRUE;
322 mIsLeftHandle = ( testResult == CB_LEFT_BAR_HANDLE_HITTED );
323 }
324
325 // avoid setting the same cursor twice
326
327 if ( !mResizeCursorOn || prevWasRowHandle != mRowHandleHitted )
328 {
329 if ( !mResizeCursorOn )
330 {
331 // caputre if not captured yet
332 mpLayout->CaptureEventsForPane( event.mpPane );
333 mpLayout->CaptureEventsForPlugin( this );
334 }
335
336 mpLayout->GetParentFrame().SetCursor( *pCurs );
337 }
338
339 mResizeCursorOn = TRUE;
340
341 // handled is being dragged now, thus event is "eaten" by this plugin
342
343 return;
344
345 } // end of if (HitTestBarHandles())
346
347 // restore cursor, if non of the handles were hit
348 if ( mResizeCursorOn )
349 {
350 mpLayout->ReleaseEventsFromPane( event.mpPane );
351 mpLayout->ReleaseEventsFromPlugin( this );
352
353 // In Windows, at least, the frame needs to have a null cursor
354 // else child windows (such as text windows) inherit the cursor
355 #if 1
356 mpLayout->GetParentFrame().SetCursor( wxNullCursor );
357 #else
358 mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
359 #endif
360
361 mResizeCursorOn = FALSE;
362 }
363
364 event.Skip(); // pass event to the next plugin
365 }
366
367 // othewise series of actions, if something has already started
368
369 else
370 if ( mResizeStarted )
371 {
372 // apply xor-mask twice
373 DrawDraggedHandle( mPrevPos, *event.mpPane );
374
375 // draw handle in the new position
376 DrawDraggedHandle( event.mPos, *event.mpPane );
377 mPrevPos = event.mPos;
378
379 // handled is dragged, thus event is "eaten" by this plugin
380 }
381 else
382 event.Skip(); // pass event to the next plugin
383 }
384
385 void cbPaneDrawPlugin::OnLDblClick( cbLeftDClickEvent& event )
386 {
387 if ( !mResizeCursorOn )
388 {
389 cbBarInfo* pBarToFloat;
390
391 if ( event.mpPane->HitTestPaneItems( event.mPos, // in pane's coordiantes
392 &mpResizedRow,
393 &pBarToFloat ) == CB_BAR_CONTENT_HITTED
394 )
395 {
396 return;
397 }
398
399 event.Skip();
400 }
401 }
402
403 void cbPaneDrawPlugin::OnLButtonDown( cbLeftDownEvent& event )
404 {
405 wxASSERT( !mResizeStarted );
406
407 if ( mResizeCursorOn )
408 {
409 mResizeStarted = TRUE;
410 mDragOrigin = event.mPos;
411
412 // setup constraints for the dragging handle
413
414 int from, till;
415 mHandleOfs = 0;
416 mHandleIsVertical = FALSE;
417
418 if ( mRowHandleHitted )
419
420 event.mpPane->GetRowResizeRange( mpResizedRow, &from, &till, mIsUpperHandle );
421 else
422 // otherwise if bar handle was hitted
423 event.mpPane->GetBarResizeRange( mpDraggedBar, &from, &till, mIsLeftHandle );
424
425 if ( mRowHandleHitted )
426 {
427 mHandleIsVertical = ( event.mpPane->IsHorizontal() ) ? FALSE : TRUE;
428
429 mHandleDragArea.x = 0;
430 mHandleDragArea.width = event.mpPane->mPaneWidth;
431
432 mHandleDragArea.y = from;
433 mHandleDragArea.height = till - from;
434
435 if ( mIsUpperHandle )
436
437 mHandleOfs = mpResizedRow->mRowY;
438 else
439 mHandleOfs = mpResizedRow->mRowY +
440 mpResizedRow->mRowHeight -
441 event.mpPane->mProps.mResizeHandleSize;
442 }
443 else
444 {
445 // otehrwise if bar handle dragged
446
447 // cbRowInfo& rowInfo = *mpDraggedBar->mpRow;
448 wxRect& bounds = mpDraggedBar->mBounds;
449
450 mHandleIsVertical = ( event.mpPane->IsHorizontal() ) ? TRUE : FALSE;
451
452 mHandleDragArea.x = from;
453 mHandleDragArea.width = till - from;
454
455
456 mHandleDragArea.y = bounds.y;
457 mHandleDragArea.height = bounds.height;
458
459 // left-side-handle mBounds
460 if ( mIsLeftHandle )
461
462 mHandleOfs = bounds.x;
463 else
464 mHandleOfs = bounds.x +
465 bounds.width - event.mpPane->mProps.mResizeHandleSize;
466
467 }
468
469 event.mpPane->PaneToFrame( &mHandleDragArea );
470 DrawDraggedHandle(mDragOrigin, *event.mpPane);
471
472 mPrevPos = mDragOrigin;
473
474 return;
475 // handled is dragged, thus event is "eaten" by this plugin
476 }
477 else
478 {
479 cbBarInfo* pDraggedBar;
480
481 if ( event.mpPane->HitTestPaneItems( event.mPos, // in pane's coordiantes
482 &mpResizedRow,
483 &pDraggedBar ) == CB_BAR_CONTENT_HITTED
484 )
485 {
486 int x = event.mPos.x,
487 y = event.mPos.y;
488
489 event.mpPane->PaneToFrame( &x, &y );
490
491 cbStartBarDraggingEvent dragEvt( pDraggedBar, wxPoint(x,y), event.mpPane );
492
493 mpLayout->FirePluginEvent( dragEvt );
494
495 return; // event is "eaten" by this plugin
496 }
497 }
498
499 event.Skip(); // pass event to the next plugin in the chain
500 }
501
502 void cbPaneDrawPlugin::OnLButtonUp( cbLeftUpEvent& event )
503 {
504 if ( mResizeStarted )
505 {
506 DrawDraggedHandle( event.mPos, *event.mpPane );
507
508 mResizeStarted = FALSE;
509 mResizeCursorOn = FALSE;
510
511 mpLayout->ReleaseEventsFromPane( event.mpPane );
512 mpLayout->ReleaseEventsFromPlugin( this );
513
514 // In Windows, at least, the frame needs to have a null cursor
515 // else child windows (such as text windows) inherit the cursor
516 #if 1
517 mpLayout->GetParentFrame().SetCursor( wxNullCursor );
518 #else
519 mpLayout->GetParentFrame().SetCursor( *mpLayout->mpNormalCursor );
520 #endif
521
522 if ( mRowHandleHitted )
523 {
524 event.mpPane->ResizeRow( mpResizedRow,
525 mDraggedDelta,
526 mIsUpperHandle );
527 }
528 else
529 {
530 event.mpPane->ResizeBar( mpDraggedBar,
531 mDraggedDelta,
532 mIsLeftHandle );
533 }
534
535 mpDraggedBar = NULL;
536 mpResizedRow = NULL;
537
538 // handled dragging action was finished by this mouse-up,
539 // thus event is "eaten" by this plugin
540
541 return;
542 }
543
544 event.Skip(); // pass event to the next plugin
545 }
546
547 void cbPaneDrawPlugin::OnRButtonUp( cbRightUpEvent& event )
548 {
549 wxPoint fpos = event.mPos;
550 event.mpPane->PaneToFrame( &fpos.x, &fpos.y );
551
552 cbBarInfo* pDraggedBar;
553
554 // user clicks inside the bar contnet, fire bar-customization event
555
556 if ( event.mpPane->HitTestPaneItems( event.mPos, // in pane's coordiantes
557 &mpResizedRow,
558 &pDraggedBar ) == CB_BAR_CONTENT_HITTED
559 )
560 {
561 cbCustomizeBarEvent cbEvt( pDraggedBar, fpos, event.mpPane );
562
563 mpLayout->FirePluginEvent( cbEvt );
564
565 return; // event is "eaten" by this plugin
566 }
567
568 // otherwise fire whole-layout customization event
569
570 cbCustomizeLayoutEvent csEvt( fpos );
571
572 mpLayout->FirePluginEvent( csEvt );
573
574 // event is "eaten" by this plugin
575 }
576
577 void cbPaneDrawPlugin::OnSizeBarWindow( cbSizeBarWndEvent& event )
578 {
579 cbBarInfo& bar = *event.mpBar;
580 mpPane = event.mpPane;
581
582 // it's possible that a bar does not have it's own window!
583 if ( !bar.mpBarWnd ) return;
584
585 wxRect& bounds = event.mBoundsInParent;
586
587 // check visibility
588 if ( bounds.height != 0 )
589 {
590 // size smaller than bounds, to leave space for shade lines
591
592 // FIXME:: +/- 1s
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 bounds.height - 2 - bar.mDimInfo.mVertGap *2 ,
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& event )
1276 {
1277 // DBG::
1278 wxASSERT( mpClntDc );
1279
1280 delete mpClntDc;
1281
1282 mpClntDc = NULL;
1283 }
1284