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