]> git.saurik.com Git - wxWidgets.git/blob - utils/framelayout/src/controlarea.cpp
Cleaned up paint DC cache in ~wxPaintDC to avoid spurious memory warning
[wxWidgets.git] / utils / framelayout / src / controlarea.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: No names yet.
3 // Purpose: Contrib. demo
4 // Author: Aleksandras Gluchovas
5 // Modified by:
6 // Created: 07/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Aleksandras Gluchovas
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "controlarea.h"
14 // #pragma interface
15 #endif
16
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #ifndef WX_PRECOMP
25 #include "wx/wx.h"
26 #endif
27
28 #include <math.h>
29 #include <stdlib.h>
30
31 #include "wx/string.h"
32 #include "wx/utils.h" // import wxMin/wxMax macros and wxFileExist(..)
33
34 #include "controlarea.h"
35
36
37 /***** Implementation for class twTabInfo *****/
38
39 IMPLEMENT_DYNAMIC_CLASS( twTabInfo, wxObject )
40
41 twTabInfo::twTabInfo()
42 : mpContent( 0 )
43 {}
44
45 twTabInfo::~twTabInfo()
46 {
47 // FOR NOW:: nothing
48 }
49
50 int twTabInfo::ImgWidth()
51 {
52 if ( mBitMap.Ok() ) return mBitMap.GetWidth();
53 else return 0;
54 }
55
56 int twTabInfo::ImgHeight()
57 {
58 if ( mBitMap.Ok() ) return mBitMap.GetHeight();
59 else return 0;
60 }
61
62 int twTabInfo::ImageToTxtGap( int prefGap )
63 {
64 if ( mBitMap.Ok() ) return prefGap;
65 else return 0;
66 }
67
68 bool twTabInfo::HasImg()
69 {
70 return mBitMap.Ok();
71 }
72
73 bool twTabInfo::HasText()
74 {
75 return mText.Length();
76 }
77
78 wxBitmap& twTabInfo::GetImg()
79 {
80 return mBitMap;
81 }
82
83 wxString& twTabInfo::GetText()
84 {
85 return mText;
86 }
87
88 wxWindow& twTabInfo::GetContent()
89 {
90 return *mpContent;
91 }
92
93 /***** Implementation for class wxTabbedWindow *****/
94
95 IMPLEMENT_DYNAMIC_CLASS( wxTabbedWindow, wxPanel )
96
97 BEGIN_EVENT_TABLE( wxTabbedWindow, wxPanel )
98
99 EVT_SIZE ( wxTabbedWindow::OnSize )
100 EVT_PAINT( wxTabbedWindow::OnPaint )
101 EVT_LEFT_DOWN( wxTabbedWindow::OnLButtonDown )
102
103 // TDB:: filciker reduction
104 // EVT_ERASE_BACKGROUND( wxTabbedWindow::OnBkErase )
105
106 END_EVENT_TABLE()
107
108 wxTabbedWindow::wxTabbedWindow()
109
110 : mpTabScroll ( NULL ),
111 mpHorizScroll( NULL ),
112 mpVertScroll ( NULL ),
113
114 mVertGap ( 0 ),
115 mHorizGap( 0 ),
116
117 mTitleVertGap ( 3 ),
118 mTitleHorizGap( 4 ),
119 mImageTextGap ( 2 ),
120 mFirstTitleGap( 11 ),
121
122 mBorderOnlyWidth( 8 ),
123
124 mWhitePen( wxColour(255,255,255), 1, wxSOLID ),
125 mLightPen( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT), 1, wxSOLID),
126 mGrayPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE), 1, wxSOLID ),
127 mDarkPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID ),
128 mBlackPen( wxColour( 0, 0, 0), 1, wxSOLID ),
129
130 // state variables
131
132 mActiveTab ( 0 ),
133 mTitleHeight( 0 ),
134 mLayoutType( wxTITLE_IMG_AND_TEXT )
135 {}
136
137 wxTabbedWindow::~wxTabbedWindow()
138 {
139 wxNode* pTab = mTabs.First();
140
141 while( pTab )
142 {
143 delete ((twTabInfo*)pTab->Data());
144
145 pTab = pTab->Next();
146 }
147 }
148
149 void wxTabbedWindow::SizeTabs(int x,int y, int width, int height, bool repant)
150 {
151 wxNode* pTabNode = mTabs.First();
152 int n = 0;
153
154 while( pTabNode )
155 {
156 twTabInfo& info = *((twTabInfo*)pTabNode->Data());
157
158 if ( n == mActiveTab )
159 {
160 //wxSizeEvent evt;
161 //info.mpContent->GetEventHandler()->ProcessEvent( evt );
162
163 info.mpContent->SetSize( x, y, width, height, 0 );
164 info.mpContent->Show(TRUE);
165 info.mpContent->Refresh();
166
167 }
168 else
169 {
170 info.mpContent->Show(FALSE);
171 }
172
173 pTabNode = pTabNode->Next();
174 ++n;
175 }
176 }
177
178 void wxTabbedWindow::AddTab( wxWindow* pContent,
179 wxString tabText,
180 wxString imageFileName,
181 long imageType )
182 {
183 twTabInfo* pTab = new twTabInfo();
184
185 pTab->mpContent = pContent;
186 pTab->mText = tabText;
187
188 if ( wxFileExists( imageFileName ) &&
189
190 pTab->mBitMap.LoadFile( imageFileName, imageType ) )
191 {
192 pTab->mImageFile = imageFileName;
193 pTab->mImageType = imageType;
194 }
195
196 bool ok = pTab->mBitMap.Ok();
197
198 if ( pContent->GetParent() == NULL )
199
200 pContent->Create( this, -1 );
201
202 mTabs.Append( (wxObject*)pTab );
203
204 RecalcLayout(TRUE);
205
206 OnTabAdded( pTab );
207 }
208
209 void wxTabbedWindow::AddTab( wxWindow* pContent,
210 wxString tabText,
211 wxBitmap* pImage )
212 {
213 twTabInfo* pTab = new twTabInfo();
214
215 pTab->mpContent = pContent;
216 pTab->mText = tabText;
217
218 if ( pImage ) pTab->mBitMap = *pImage;
219
220 if ( pContent->GetParent() == NULL )
221
222 pContent->Create( this, -1 );
223
224 mTabs.Append( (wxObject*)pTab );
225
226 RecalcLayout(TRUE);
227
228 OnTabAdded( pTab );
229 }
230
231
232
233 void wxTabbedWindow::RemoveTab( int tabNo )
234 {
235 twTabInfo* pTab = ((twTabInfo*)(mTabs.Nth( tabNo )->Data()));
236
237 pTab->mpContent->Destroy();
238
239 delete pTab;
240
241 mTabs.DeleteNode( mTabs.Nth( tabNo ) );
242
243 if ( mActiveTab >= mTabs.Number() );
244
245 mActiveTab = mTabs.Number() - 1;
246
247 SetActiveTab( mActiveTab );
248 }
249
250 int wxTabbedWindow::GetTabCount()
251 {
252 return mTabs.Number();
253 }
254
255 wxWindow* wxTabbedWindow::GetTab( int tabNo )
256 {
257 return ((twTabInfo*)(mTabs.Nth( tabNo )->Data()))->mpContent;
258 }
259
260 wxWindow* wxTabbedWindow::GetActiveTab()
261 {
262 // FIMXE:: this is lame
263
264 return GetTab( mActiveTab );
265 }
266
267 void wxTabbedWindow::SetActiveTab( int tabNo )
268 {
269 mActiveTab = tabNo;
270
271 RecalcLayout(TRUE);
272
273 Refresh();
274 }
275
276 // width of the decorations border (4 shade-lines), should not be changed
277
278 #define BORDER_SZ 4
279
280 void wxTabbedWindow::DrawShadedRect( int x, int y, int width, int height,
281 wxPen& upperPen, wxPen& lowerPen, wxDC& dc
282 )
283 {
284 // darw the lightened upper-left sides of the rectangle
285
286 dc.SetPen( upperPen );
287 dc.DrawLine( x,y, x, y + height - 1 ); // vert
288 dc.DrawLine( x,y, x + width - 1, y ); // horiz
289
290 // draw the unenlightened lower-right sides of the rectangle
291
292 dc.SetPen( lowerPen );
293 dc.DrawLine( x + width - 1, y, x + width - 1, y + height - 1 ); // vert
294 dc.DrawLine( x, y + height - 1, x + width, y + height - 1 ); // horiz
295 }
296
297 void wxTabbedWindow::DrawDecorations( wxDC& dc )
298 {
299 // Protability NOTE::: DrawLine(..) draws a line from the first position,
300 // but not including the point specified by last position.
301 // This way Windows draws lines, not sure how Motif and Gtk
302 // prots behave...
303
304 int width, height;
305 GetClientSize( &width, &height );
306
307 // check if there's at least a bit of space to draw things
308
309 if ( width < mHorizGap*2 + BORDER_SZ*2+1 ||
310 height < mVertGap*2 + BORDER_SZ*2+1 + mTitleHeight
311 )
312 return;
313
314 // step #1 - draw border around the tab content area
315
316 // setup position for kind of "pencil"
317 int curX = mHorizGap;
318 int curY = mVertGap;
319
320 int xSize = width - mHorizGap*2;
321 int ySize = height - mVertGap *2 - mTitleHeight;
322
323 // layer 1 (upper white)
324 DrawShadedRect( curX+0, curY+0, xSize-0, ySize-0,
325 mLightPen, mBlackPen, dc );
326
327 // layer 2 (upper gray)
328 DrawShadedRect( curX+1, curY+1, xSize-2-1, ySize-2-1,
329 mGrayPen, mGrayPen, dc );
330
331 // layer 3 (upper darkGray)
332 DrawShadedRect( curX+2, curY+2, xSize-3-2, ySize-3-2,
333 mDarkPen, mLightPen, dc );
334
335 // layer 4 (upper black)
336 DrawShadedRect( curX+3, curY+3, xSize-4-3, ySize-4-3,
337 mBlackPen, mGrayPen, dc );
338
339 // add non-siemtric layer from the lower-right side (confroming to MFC-look)
340
341 dc.SetPen( mDarkPen );
342 dc.DrawLine( curX+1, curY + ySize - 2, curX + xSize - 1, curY + ySize - 2 ); // horiz
343 dc.DrawLine( curX + xSize - 2, curY + 1, curX + xSize - 2, curY + ySize - 2 ); // vert
344
345 // step #2 - draw tab title bars
346
347 curX = mFirstTitleGap;
348 curY = height - mVertGap - mTitleHeight;
349
350 int tabNo = 0;
351 wxNode* pNode = mTabs.First();
352
353 while( pNode )
354 {
355 // "hard-coded metafile" for decorations
356
357 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
358
359 xSize = tab.mDims.x;
360 ySize = mTitleHeight;
361
362 if ( tabNo == mActiveTab )
363 {
364 dc.SetPen( mGrayPen );
365 dc.DrawLine( curX+1, curY-2, curX+xSize-2, curY-2 );
366 dc.DrawLine( curX+1, curY-1, curX+xSize-2, curY-1 );
367 }
368
369 dc.SetPen( mLightPen );
370
371 if ( tabNo == mActiveTab )
372 dc.DrawLine( curX, curY-2, curX, curY+ySize-2 );
373 else
374 dc.DrawLine( curX, curY, curX, curY+ySize-2 );
375
376 dc.SetPen( mDarkPen );
377 dc.DrawLine( curX+1, curY+ySize-3, curX+1, curY+ySize-1 ); // to pix down
378 dc.DrawLine( curX+2, curY+ySize-2, curX+xSize-2, curY+ySize-2 );
379 dc.DrawLine( curX+xSize-3, curY+ySize-3, curX+xSize-2, curY+ySize-3 );
380 if ( tabNo == mActiveTab )
381 dc.DrawLine( curX+xSize-2, curY+ySize-3, curX+xSize-2, curY-3 );
382 else
383 dc.DrawLine( curX+xSize-2, curY+ySize-3, curX+xSize-2, curY-1 );
384
385 dc.SetPen( mBlackPen );
386 dc.DrawLine( curX+xSize-1, curY, curX+xSize-1, curY+ySize-2 );
387 dc.DrawLine( curX+xSize-2, curY+ySize-2, curX+xSize-3, curY+ySize-2 );
388 dc.DrawLine( curX+xSize-3, curY+ySize-1, curX+1, curY+ySize-1 );
389
390 pNode = pNode->Next();
391 ++tabNo;
392
393 // darw image and (or without) text centered within the
394 // title bar rectangle
395
396 if ( mLayoutType != wxTITLE_BORDER_ONLY && tab.HasImg() )
397 {
398 wxMemoryDC tmpDc;
399 tmpDc.SelectObject( tab.GetImg() );
400
401 dc.Blit( curX + mTitleHorizGap,
402 curY + ( ySize - tab.ImgHeight() ) / 2,
403 tab.ImgWidth(),
404 tab.ImgHeight(),
405 &tmpDc, 0, 0, wxCOPY,true
406 );
407 }
408
409 if ( mLayoutType == wxTITLE_IMG_AND_TEXT && tab.HasText() )
410 {
411 long x,w,h;
412
413 // set select default font of the window into it's device context
414 dc.SetFont( GetLabelingFont() );
415
416 dc.SetTextBackground( GetBackgroundColour() );
417
418 dc.GetTextExtent(tab.mText, &w, &h );
419
420 x = curX + mTitleHorizGap +
421 tab.ImgWidth() + tab.ImageToTxtGap(mImageTextGap);
422
423 dc.DrawText( tab.GetText(), x, curY + ( ySize - h ) / 2 );
424 }
425 curX += xSize;
426
427 } // end of `while (pNode)'
428 }
429
430 int wxTabbedWindow::HitTest( const wxPoint& pos )
431 {
432 int width, height;
433 GetClientSize( &width, &height );
434
435 int curX = mFirstTitleGap;
436 int curY = height - mVertGap - mTitleHeight;
437
438 int tabNo = 0;
439 wxNode* pNode = mTabs.First();
440
441 int x = pos.x;
442 int y = pos.y;
443
444 while( pNode )
445 {
446 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
447
448 int w,h;
449 w = tab.mDims.x;
450 h = tab.mDims.y;
451 // hit test rectangle of the currnet tab title bar
452 if ( pos.x >= curX && pos.x < curX + tab.mDims.x &&
453 pos.y >= curY && pos.y < curY + tab.mDims.y
454 )
455 {
456 return tabNo;
457 }
458
459 curX += tab.mDims.x;
460
461 pNode = pNode->Next();
462 ++tabNo;
463 }
464
465 return -1;
466 }
467
468 void wxTabbedWindow::HideInactiveTabs( bool andRepaint )
469 {
470 if ( !andRepaint )
471 return;
472
473 wxNode* pNode = mTabs.First();
474 int tabNo = 0;
475
476 while( pNode )
477 {
478 if ( tabNo != mActiveTab )
479 {
480 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
481 tab.mpContent->Show(FALSE);
482 }
483
484 pNode = pNode->Next();
485 ++tabNo;
486 }
487 }
488
489 wxFont wxTabbedWindow::GetLabelingFont()
490 {
491 #if 0
492 wxFont font;
493 #ifdef __WINDOWS__
494 font.SetFaceName("MS Sans Serif");
495 #else
496 font.SetFamily( wxDEFAULT );
497 #endif
498
499 font.SetStyle(wxNORMAL);
500 font.SetWeight(wxNORMAL);
501 font.SetPointSize( 8 );
502
503 #ifdef __WINDOWS__
504 font.RealizeResource();
505 #endif
506
507 return font;
508 #endif
509 return wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT);
510 }
511
512 void wxTabbedWindow::RecalcLayout(bool andRepaint)
513 {
514 HideInactiveTabs(andRepaint);
515
516 // resetup position of the active tab
517
518 int width, height;
519 GetClientSize( &width, &height );
520
521 int curX = mHorizGap + BORDER_SZ;
522 int curY = mVertGap + BORDER_SZ;
523
524 int xSize = width - mHorizGap*2 - BORDER_SZ*2-1;
525 int ySize = height - mVertGap*2 - BORDER_SZ*2-1 - mTitleHeight;
526
527 SizeTabs( curX, curY, xSize, ySize, andRepaint );
528
529 // pass #1 - try to layout assuming it's wxTITLE_IMG_AND_TEXT
530
531 mLayoutType = wxTITLE_IMG_AND_TEXT;
532
533 wxNode* pNode = mTabs.First();
534
535 curX = mFirstTitleGap; // the left-side gap
536 mTitleHeight = 0;
537
538 while( pNode )
539 {
540 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
541
542 wxWindowDC dc(this);
543
544 long w,h;
545
546 // set select default font of the window into it's device context
547 dc.SetFont( GetLabelingFont() );
548
549 dc.GetTextExtent(tab.mText, &w, &h );
550
551 tab.mDims.x = w + tab.ImageToTxtGap(mImageTextGap) +
552 tab.ImgWidth() + mTitleHorizGap*2;
553
554 tab.mDims.y = wxMax( h, tab.ImgHeight() ) + mTitleVertGap*2;
555 mTitleHeight = wxMax( mTitleHeight, tab.mDims.y );
556
557 curX += tab.mDims.x;
558
559 pNode = pNode->Next();
560 }
561
562 curX += mHorizGap; // the right-side gap
563
564 // make all title bars of equel height
565
566 pNode = mTabs.First();
567
568 while( pNode )
569 {
570 ((twTabInfo*)(pNode->Data()))->mDims.y = mTitleHeight;;
571 pNode = pNode->Next();
572 }
573
574 // if curX has'nt ran out of bounds, leave TITLE_IMG layout and return
575 if ( curX < width - mHorizGap )
576 return;
577
578 // pass #2 - try to layout assuming wxTITLE_IMG_ONLY
579
580 mLayoutType = wxTITLE_IMG_ONLY;
581
582 pNode = mTabs.First();
583
584 curX = mFirstTitleGap; // the left-side gap
585
586 int denomiator = mTabs.Number();
587 if ( denomiator == 0 ) ++denomiator;
588
589 mBorderOnlyWidth = (width - mFirstTitleGap - mHorizGap) / denomiator;
590
591 while( pNode )
592 {
593 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
594
595 if ( tab.HasImg() )
596 {
597 tab.mDims.x = tab.ImgWidth() + mTitleHorizGap*2;
598 tab.mDims.y = tab.ImgHeight() + mTitleVertGap*2;
599 }
600 else
601 {
602 tab.mDims.x = mBorderOnlyWidth;
603 tab.mDims.y = mTitleHeight;
604 }
605
606 curX += tab.mDims.x;
607
608 pNode = pNode->Next();
609 }
610
611 curX += mHorizGap; // the right-side gap
612
613 // if curX has'nt ran out of bounds, leave IMG_ONLY layout and return
614 if ( curX < width - mHorizGap )
615 return;
616
617 // pass #3 - set the narrowest layout wxTITLE_BORDER_ONLY
618
619 mLayoutType = wxTITLE_BORDER_ONLY;
620
621 pNode = mTabs.First();
622
623 while( pNode )
624 {
625 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
626
627 tab.mDims.x = mBorderOnlyWidth;
628 tab.mDims.y = mTitleHeight;
629
630 pNode = pNode->Next();
631 }
632 }
633
634 // wx event handlers
635
636 void wxTabbedWindow::OnPaint( wxPaintEvent& event )
637 {
638 wxPaintDC dc(this);
639 DrawDecorations( dc );
640 }
641
642 void wxTabbedWindow::OnSize ( wxSizeEvent& event )
643 {
644 SetBackgroundColour( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE) );
645 RecalcLayout(TRUE);
646 }
647
648 void wxTabbedWindow::OnBkErase( wxEraseEvent& event )
649 {
650 // do nothing
651 }
652
653 void wxTabbedWindow::OnLButtonDown( wxMouseEvent& event )
654 {
655 // floats, why?
656 int x = (int)event.m_x;
657 int y = (int)event.m_y;
658
659 int tabNo = HitTest( wxPoint(x,y) );
660
661 if ( tabNo != -1 )
662 {
663 SetActiveTab( tabNo );
664 }
665 }
666
667 /***** Implementation for class wxPaggedWindow *****/
668
669 IMPLEMENT_DYNAMIC_CLASS( wxPaggedWindow, wxTabbedWindow )
670
671 BEGIN_EVENT_TABLE( wxPaggedWindow, wxTabbedWindow )
672 EVT_SIZE ( wxPaggedWindow::OnSize )
673 EVT_PAINT ( wxPaggedWindow::OnPaint )
674 EVT_LEFT_DOWN( wxPaggedWindow::OnLButtonDown )
675 EVT_LEFT_UP ( wxPaggedWindow::OnLButtonUp )
676 EVT_MOTION ( wxPaggedWindow::OnMouseMove )
677 EVT_SCROLL ( wxPaggedWindow::OnScroll )
678 END_EVENT_TABLE()
679
680 // border for pagged-window is 2 shaded-lines
681
682 #undef BORDER_SZ
683 #define BORDER_SZ 2
684
685 wxPaggedWindow::wxPaggedWindow()
686
687 : mScrollEventInProgress( FALSE ),
688
689 mTabTrianGap(4),
690
691 mWhiteBrush( wxColour(255,255,255), wxSOLID ),
692 mGrayBrush ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE), wxSOLID ),
693
694 mCurentRowOfs( 0 ),
695 mAdjustableTitleRowLen( 300 ),
696
697 mIsDragged ( FALSE ),
698 mDagOrigin ( 0 ),
699 mCursorChanged( FALSE ),
700 mResizeCursor ( wxCURSOR_SIZEWE ),
701 mNormalCursor ( wxCURSOR_ARROW )
702 {
703 mTitleVertGap = 2;
704 mTitleHorizGap = 10;
705 }
706
707 wxPaggedWindow::~wxPaggedWindow()
708 {
709 // nothing (base class handles destruction)
710 }
711
712 wxFont wxPaggedWindow::GetLabelingFont()
713 {
714 #if 0
715 wxFont font;
716
717 #ifdef __WINDOWS__
718 font.SetFaceName("Arial");
719 #else
720 font.SetFamily( wxDEFAULT );
721 #endif
722
723 font.SetStyle(wxNORMAL);
724 font.SetWeight(wxNORMAL);
725 font.SetPointSize( 8 );
726
727 #ifdef __WINDOWS__
728 bool success = font.RealizeResource();
729 #endif
730
731 return font;
732 #endif
733 return wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT);
734 }
735
736 void wxPaggedWindow::OnTabAdded( twTabInfo* pInfo )
737 {
738 int units = GetWholeTabRowLen() / 20;
739
740 mpTabScroll->SetScrollbar( 0, 1, units, 1, FALSE );
741 }
742
743 wxScrollBar& wxPaggedWindow::GetVerticalScrollBar()
744 {
745 return *mpVertScroll;
746 }
747
748 wxScrollBar& wxPaggedWindow::GetHorizontalScrollBar()
749 {
750 return *mpHorizScroll;
751 }
752
753
754 int wxPaggedWindow::GetWholeTabRowLen()
755 {
756 wxNode* pNode = mTabs.First();
757
758 int len = 0;
759
760 while( pNode )
761 {
762 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
763
764 len += tab.mDims.x;
765 pNode = pNode->Next();
766 }
767
768 return len;
769 }
770
771 void wxPaggedWindow::DrawPaperBar( twTabInfo& tab, int x, int y,
772 wxBrush& brush, wxPen& pen, wxDC& dc )
773 {
774 wxPoint poly[4];
775
776 // draw organizer-style paper outlet
777
778 poly[0].x = x - mTabTrianGap;
779 poly[0].y = y;
780
781 poly[1].x = x + mTabTrianGap;
782 poly[1].y = y + tab.mDims.y-1;
783
784 poly[2].x = x + tab.mDims.x - mTabTrianGap;
785 poly[2].y = y + tab.mDims.y-1;
786
787 poly[3].x = x + tab.mDims.x + mTabTrianGap;
788 poly[3].y = y;
789
790 dc.SetPen( pen );
791 dc.SetBrush( brush );
792
793 dc.DrawPolygon( 4, poly );
794
795 long w,h;
796
797 // set select default font of the window into it's device context
798 dc.SetFont( GetLabelingFont() );
799
800 dc.SetTextBackground( brush.GetColour() );
801
802 dc.GetTextExtent(tab.mText, &w, &h );
803
804 if ( tab.HasImg() )
805 {
806 wxMemoryDC tmpDc;
807 tmpDc.SelectObject( tab.GetImg() );
808
809 dc.Blit( x + mTitleHorizGap,
810 y + ( tab.mDims.y - tab.ImgHeight() ) / 2,
811 tab.ImgWidth(),
812 tab.ImgHeight(),
813 &tmpDc, 0, 0, wxCOPY,true
814 );
815 }
816
817 if ( tab.HasText() )
818 {
819 int tx = x + mTitleHorizGap +
820 tab.ImgWidth() + tab.ImageToTxtGap(mImageTextGap);
821
822 dc.DrawText( tab.GetText(), tx, y + ( tab.mDims.y - h ) / 2 );
823 }
824 }
825
826 void wxPaggedWindow::DrawDecorations( wxDC& dc )
827 {
828 // FIXME:: the is big body have to be split!
829
830 int width, height;
831 GetClientSize( &width, &height );
832
833 int curX = mHorizGap;
834 int curY = mVertGap;
835
836 int xSize = width - mHorizGap*2;
837 int ySize = height - mVertGap*2;
838
839 DrawShadedRect( curX, curY, xSize, ySize,
840 mDarkPen, mLightPen, dc );
841
842 DrawShadedRect( curX+1, curY+1, xSize-2, ySize-2,
843 mBlackPen, mGrayPen, dc );
844
845 // draw inactive tab title bars frist (left-to-right)
846
847 wxNode* pNode = mTabs.First();
848 int tabNo = 0;
849
850 /* OLD STUFF::
851 curX = mTitleRowStart;
852 curY = height - mVertGap - BORDER_SZ - mTitleHeight;
853 */
854
855 curX = mTabTrianGap;
856 curY = 0;
857
858 // FOR NOW:: avoid creating bitmap with invalid dimensions
859
860 if ( mTitleRowLen < 1 || mTitleHeight < 1 ) return;
861
862 wxMemoryDC tmpDc;
863 wxBitmap tmpBmp( mTitleRowLen, mTitleHeight );
864
865 tmpDc.SelectObject( tmpBmp );
866 tmpDc.SetPen( mGrayPen );
867 tmpDc.SetBrush( mGrayBrush );
868 tmpDc.DrawRectangle( 0,0, mTitleRowLen, mTitleHeight );
869
870 tmpDc.SetDeviceOrigin( mCurentRowOfs, 0 );
871
872 while( pNode )
873 {
874 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
875
876 if ( tabNo != mActiveTab )
877
878 DrawPaperBar( tab, curX, curY, mGrayBrush, mBlackPen, tmpDc );
879
880 curX += tab.mDims.x;
881
882 pNode = pNode->Next();
883 ++tabNo;
884 }
885
886 // finally, draw the active tab (white-filled)
887
888 pNode = mTabs.First();
889 tabNo = 0;
890
891 curX = mTabTrianGap;
892
893 while( pNode )
894 {
895 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
896
897 if ( tabNo == mActiveTab )
898 {
899 DrawPaperBar( tab, curX, curY, mWhiteBrush, mBlackPen, tmpDc );
900
901 tmpDc.SetPen( mLightPen );
902
903 tmpDc.DrawLine( curX - mTabTrianGap+1, curY,
904 curX + tab.mDims.x + mTabTrianGap, curY );
905 break;
906 }
907 curX += tab.mDims.x;
908
909 pNode = pNode->Next();
910 ++tabNo;
911 }
912
913 // back to initial device origin
914
915 tmpDc.SetDeviceOrigin( 0, 0 );
916
917 // draw resize-hint-stick
918
919 curX = mTitleRowLen - 6;
920
921 DrawShadedRect( curX+0, 0+0, 6, mTitleHeight, mGrayPen, mBlackPen, tmpDc );
922 DrawShadedRect( curX+1, 0+1, 6-2, mTitleHeight-2, mLightPen, mDarkPen, tmpDc );
923 DrawShadedRect( curX+2, 0+2, 6-4, mTitleHeight-4, mGrayPen, mGrayPen, tmpDc );
924
925
926
927 dc.Blit( mTitleRowStart,
928 height - mVertGap - BORDER_SZ - mTitleHeight,
929 mTitleRowLen, mTitleHeight,
930 &tmpDc, 0,0, wxCOPY );
931 }
932
933 int wxPaggedWindow::HitTest( const wxPoint& pos )
934 {
935 return wxTabbedWindow::HitTest( pos );
936 }
937
938 void wxPaggedWindow::RecalcLayout(bool andRepaint)
939 {
940 mTitleRowLen = mAdjustableTitleRowLen;
941
942 if ( int(mpTabScroll) == -1 ) return;
943
944 // scroll bars should be created after Create() for this window is called
945 if ( !mpTabScroll )
946 {
947 mpTabScroll =
948 new wxScrollBar( this, -1, wxDefaultPosition, wxDefaultSize, wxSB_HORIZONTAL );
949
950 mpHorizScroll =
951 new wxScrollBar( this, -1, wxDefaultPosition, wxDefaultSize, wxSB_HORIZONTAL );
952
953 mpVertScroll =
954 new wxScrollBar( this, -1, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL );
955 }
956
957 {
958 int units = GetWholeTabRowLen() / 20;
959
960 mpTabScroll->SetScrollbar( 0, 1, units, 1, FALSE );
961 }
962
963 // resetup position of the active tab
964
965 int thumbLen = 16; // FOR NOW:: hardcoded
966
967 int width, height;
968 GetClientSize( &width, &height );
969
970 mTitleHeight = thumbLen;
971
972 int curX = mHorizGap + BORDER_SZ;
973 int curY = mVertGap + BORDER_SZ;
974
975 int xSize = width - mHorizGap*2 - BORDER_SZ*2 - thumbLen;
976
977 int ySize = height - mVertGap*2 - BORDER_SZ*2 - mTitleHeight;
978
979 SizeTabs( curX, curY, xSize, ySize, andRepaint );
980
981 // setup title bar LINES's horizontal scroll bar
982
983 curY = height - mVertGap - BORDER_SZ - thumbLen;
984
985 mpTabScroll->SetSize( curX, curY, thumbLen*2, thumbLen );
986
987 // setup view's HORIZONTAL scroll bar
988
989 curX += thumbLen*2;
990
991 mTitleRowStart = curX;
992 mFirstTitleGap = curX + mCurentRowOfs + mTabTrianGap;
993
994 mTitleRowLen = wxMin( mAdjustableTitleRowLen,
995 width - mHorizGap - BORDER_SZ - thumbLen*4 - curX );
996
997 curX += mTitleRowLen;
998
999 mpHorizScroll->SetSize( curX, curY,
1000 width - curX - mHorizGap - BORDER_SZ - thumbLen,
1001 thumbLen
1002 );
1003
1004 // setup view's VERTICAL scroll bar
1005
1006 curX = width - mHorizGap - BORDER_SZ - thumbLen;
1007
1008 curY = mVertGap + BORDER_SZ;
1009
1010 mpVertScroll->SetSize( curX, curY, thumbLen,
1011 height - curY - mVertGap - BORDER_SZ - thumbLen
1012 );
1013
1014 // layout tab title bars
1015
1016 mLayoutType = wxTITLE_IMG_AND_TEXT;
1017
1018 wxNode* pNode = mTabs.First();
1019
1020 while( pNode )
1021 {
1022 twTabInfo& tab = *((twTabInfo*)(pNode->Data()));
1023
1024 wxWindowDC dc(this);
1025
1026 long w,h;
1027
1028 // set select default font of the window into it's device context
1029 dc.SetFont( GetLabelingFont() );
1030 dc.GetTextExtent(tab.mText, &w, &h );
1031
1032 tab.mDims.x = w + tab.ImageToTxtGap(mImageTextGap) +
1033 tab.ImgWidth() + mTitleHorizGap*2;
1034
1035 tab.mDims.y = mTitleHeight;
1036
1037 pNode = pNode->Next();
1038 }
1039
1040 // disable title-bar scroller if there's nowhere to scroll to
1041
1042 mpTabScroll->Enable( mTitleRowLen < GetWholeTabRowLen() || mCurentRowOfs < 0 );
1043 }
1044
1045 // event handlers
1046
1047 void wxPaggedWindow::OnPaint( wxPaintEvent& event )
1048 {
1049 wxPaintDC dc(this);
1050 DrawDecorations( dc );
1051 }
1052
1053 void wxPaggedWindow::OnSize ( wxSizeEvent& event )
1054 {
1055 wxTabbedWindow::OnSize(event);
1056 }
1057
1058 void wxPaggedWindow::OnLButtonDown( wxMouseEvent& event )
1059 {
1060 if ( mCursorChanged )
1061 {
1062 mIsDragged = TRUE;
1063 mDagOrigin = event.m_x;
1064
1065 mOriginalTitleRowLen = mAdjustableTitleRowLen;
1066
1067 CaptureMouse();
1068 }
1069 else
1070 {
1071 wxTabbedWindow::OnLButtonDown( event );
1072 }
1073 }
1074
1075 void wxPaggedWindow::OnLButtonUp( wxMouseEvent& event )
1076 {
1077 if ( mIsDragged )
1078 {
1079 mIsDragged = FALSE;
1080 mCursorChanged = FALSE;
1081 SetCursor( mNormalCursor );
1082
1083 ReleaseMouse();
1084 }
1085 }
1086
1087 void wxPaggedWindow::OnMouseMove( wxMouseEvent& event )
1088 {
1089 int width, height;
1090 GetClientSize( &width, &height );
1091
1092 if ( !mIsDragged )
1093 {
1094 int y = height - mVertGap - BORDER_SZ - mTitleHeight;
1095 int x = mTitleRowStart + mTitleRowLen - 6;
1096
1097 if ( event.m_x >= x && event.m_y >= y &&
1098 event.m_x < x + 6 &&
1099 event.m_y < y + mTitleHeight
1100 )
1101 {
1102 if ( !mCursorChanged )
1103 {
1104 SetCursor( mResizeCursor );
1105
1106 mCursorChanged = TRUE;
1107 }
1108 }
1109 else
1110 if ( mCursorChanged )
1111 {
1112 SetCursor( mNormalCursor );
1113
1114 mCursorChanged = FALSE;
1115 }
1116 }
1117 else
1118 if ( mIsDragged )
1119 {
1120 mAdjustableTitleRowLen = mOriginalTitleRowLen + ( event.m_x - mDagOrigin );
1121
1122 // FOR NOW:: fixed
1123 if ( mAdjustableTitleRowLen < 6 ) mAdjustableTitleRowLen = 6;
1124
1125 wxWindowDC dc(this);
1126 DrawDecorations( dc );
1127
1128 RecalcLayout(FALSE);
1129
1130 //Refresh();
1131 }
1132 }
1133
1134 void wxPaggedWindow::OnScroll( wxScrollEvent& event )
1135 {
1136 int cmd = event.m_commandInt;
1137
1138 wxScrollBar* pSender = (wxScrollBar*)event.GetEventObject();
1139
1140 if ( pSender == mpTabScroll )
1141 {
1142 int maxLen = GetWholeTabRowLen();
1143
1144 int maxUnits = GetWholeTabRowLen() / 20;
1145
1146 mCurentRowOfs = -event.GetPosition()*maxUnits;
1147
1148 mFirstTitleGap = mTitleRowStart + mCurentRowOfs + mTabTrianGap;
1149
1150 // let' it automatically disable itself if it's time
1151 mpTabScroll->Enable( mTitleRowLen < GetWholeTabRowLen() || mCurentRowOfs < 0 );
1152
1153 // repaint title bars
1154 wxWindowDC dc(this);
1155 DrawDecorations( dc );
1156 }
1157 else
1158 if ( !mScrollEventInProgress )
1159 {
1160 mScrollEventInProgress = TRUE;
1161
1162 GetActiveTab()->GetEventHandler()->ProcessEvent( event );
1163 }
1164 else
1165 {
1166 // event bounced back to us, from here we
1167 // know that it has traveled the loop - thus it's processed!
1168
1169 mScrollEventInProgress = FALSE;
1170 }
1171 }