Sorry, I went and removed consts as per the style guide :-)
[wxWidgets.git] / src / generic / tabg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: tabg.cpp
3 // Purpose: Generic tabbed dialogs
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c)
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "tabg.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 <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <math.h>
31
32 #include "wx/tab.h"
33
34 IMPLEMENT_DYNAMIC_CLASS(wxTabControl, wxObject)
35
36 IMPLEMENT_DYNAMIC_CLASS(wxTabLayer, wxList)
37
38 wxTabControl::wxTabControl(wxTabView *v)
39 {
40 m_view = v;
41 m_isSelected = FALSE;
42 m_labelFont = NULL;
43 m_offsetX = 0;
44 m_offsetY = 0;
45 m_width = 0;
46 m_height = 0;
47 m_id = 0;
48 m_rowPosition = 0;
49 m_colPosition = 0;
50 }
51
52 wxTabControl::~wxTabControl(void)
53 {
54 }
55
56 void wxTabControl::OnDraw(wxDC& dc, bool lastInRow)
57 {
58 // Old, but in some ways better (drawing opaque tabs)
59 #if 0
60 if (!m_view)
61 return;
62
63 // Top-left of tab view area
64 int viewX = m_view->GetViewRect().x;
65 int viewY = m_view->GetViewRect().y;
66
67 // Top-left of tab control
68 int tabX = GetX() + viewX;
69 int tabY = GetY() + viewY;
70 int tabHeightInc = 0;
71 if (m_isSelected)
72 {
73 tabHeightInc = (view->GetTabSelectionHeight() - view->GetTabHeight());
74 tabY -= tabHeightInc;
75 }
76
77 dc.SetPen(wxTRANSPARENT_PEN);
78
79 // Draw grey background
80 if (view->GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR)
81 {
82 dc.SetBrush(m_view->GetBackgroundBrush());
83
84 // Add 1 because the pen is transparent. Under Motif, may be different.
85 dc.DrawRectangle(tabX, tabY, (GetWidth()+1), (GetHeight() + 1 + tabHeightInc));
86 }
87
88 // Draw highlight and shadow
89 dc.SetPen(m_view->GetHighlightPen());
90
91 // Calculate the top of the tab beneath. It's the height of the tab, MINUS
92 // a bit if the tab below happens to be selected. Check.
93 wxTabControl *tabBeneath = NULL;
94 int subtractThis = 0;
95 if (GetColPosition() > 0)
96 tabBeneath = m_view->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition());
97 if (tabBeneath && tabBeneath->IsSelected())
98 subtractThis = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight());
99
100 // Vertical highlight: if first tab, draw to bottom of view
101 if (tabX == m_view->GetViewRect().x && (m_view->GetTabStyle() & wxTAB_STYLE_DRAW_BOX))
102 dc.DrawLine(tabX, tabY, tabX, (m_view->GetViewRect().y + m_view->GetViewRect().height));
103 else if (tabX == m_view->GetViewRect().x)
104 // Not box drawing, just to top of view.
105 dc.DrawLine(tabX, tabY, tabX, (m_view->GetViewRect().y));
106 else
107 dc.DrawLine(tabX, tabY, tabX, (tabY + GetHeight() + tabHeightInc - subtractThis));
108
109 dc.DrawLine(tabX, tabY, (tabX + GetWidth()), tabY);
110 dc.SetPen(m_view->GetShadowPen());
111
112 // Test if we're outside the right-hand edge of the view area
113 if (((tabX + GetWidth()) >= m_view->GetViewRect().x + m_view->GetViewRect().width) && (m_view->GetTabStyle() & wxTAB_STYLE_DRAW_BOX))
114 {
115 int bottomY = m_view->GetViewRect().y + m_view->GetViewRect().height + GetY() + m_view->GetTabHeight() + m_view->GetTopMargin();
116 // Add a tab height since we wish to draw to the bottom of the view.
117 dc.DrawLine((tabX + GetWidth()), tabY,
118 (tabX + GetWidth()), bottomY);
119
120 // Calculate the far-right of the view, since we don't wish to
121 // draw inside that
122 int rightOfView = m_view->GetViewRect().x + m_view->GetViewRect().width + 1;
123
124 // Draw the horizontal bit to connect to the view rectangle
125 dc.DrawLine((wxMax((tabX + GetWidth() - m_view->GetHorizontalTabOffset()), rightOfView)), (bottomY-1),
126 (tabX + GetWidth()), (bottomY-1));
127
128 // Draw black line to emphasize shadow
129 dc.SetPen(wxBLACK_PEN);
130 dc.DrawLine((tabX + GetWidth() + 1), (tabY+1),
131 (tabX + GetWidth() + 1), bottomY);
132
133 // Draw the horizontal bit to connect to the view rectangle
134 dc.DrawLine((wxMax((tabX + GetWidth() - m_view->GetHorizontalTabOffset()), rightOfView)), (bottomY),
135 (tabX + GetWidth() + 1), (bottomY));
136 }
137 else
138 {
139 if (lastInRow)
140 {
141 // 25/5/97 UNLESS it's less than the max number of positions in this row
142
143 int topY = m_view->GetViewRect().y - m_view->GetTopMargin();
144
145 int maxPositions = ((wxTabLayer *)m_view->GetLayers().Nth(0)->Data())->Number();
146
147 // Only down to the bottom of the tab, not to the top of the view
148 if ( GetColPosition() < maxPositions )
149 topY = tabY + GetHeight() + tabHeightInc;
150
151 // Shadow
152 dc.DrawLine((tabX + GetWidth()), tabY, (tabX + GetWidth()), topY);
153 // Draw black line to emphasize shadow
154 dc.SetPen(wxBLACK_PEN);
155 dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), (tabX + GetWidth() + 1),
156 topY);
157 }
158 else
159 {
160 // Calculate the top of the tab beneath. It's the height of the tab, MINUS
161 // a bit if the tab below (and next col along) happens to be selected. Check.
162 wxTabControl *tabBeneath = NULL;
163 int subtractThis = 0;
164 if (GetColPosition() > 0)
165 tabBeneath = m_view->FindTabControlForPosition(GetColPosition() - 1, GetRowPosition() + 1);
166 if (tabBeneath && tabBeneath->IsSelected())
167 subtractThis = (m_view->GetTabSelectionHeight() - m_view->GetTabHeight());
168
169 // Draw only to next tab down.
170 dc.DrawLine((tabX + GetWidth()), tabY,
171 (tabX + GetWidth()), (tabY + GetHeight() + tabHeightInc - subtractThis));
172
173 // Draw black line to emphasize shadow
174 dc.SetPen(wxBLACK_PEN);
175 dc.DrawLine((tabX + GetWidth() + 1), (tabY+1), (tabX + GetWidth() + 1),
176 (tabY + GetHeight() + tabHeightInc - subtractThis));
177 }
178 }
179
180 // Draw centered text
181 int textY = tabY + m_view->GetVerticalTabTextSpacing() + tabHeightInc;
182
183 if (m_isSelected)
184 dc.SetFont(m_view->GetSelectedTabFont());
185 else
186 dc.SetFont(GetFont());
187
188 wxColour col(m_view->GetTextColour());
189 dc.SetTextForeground(&col);
190 // dc.SetTextForeground(&(m_view->GetTextColour()));
191 dc.SetBackgroundMode(wxTRANSPARENT);
192 float textWidth, textHeight;
193 dc.GetTextExtent(GetLabel(), &textWidth, &textHeight);
194
195 int textX = (int)(tabX + (GetWidth() - textWidth)/2.0);
196 dc.DrawText(GetLabel(), textX, textY);
197
198 if (m_isSelected)
199 {
200 dc.SetPen(m_view->GetHighlightPen());
201
202 // Draw white highlight from the tab's left side to the left hand edge of the view
203 dc.DrawLine(m_view->GetViewRect().x, (tabY + GetHeight() + tabHeightInc),
204 tabX, (tabY + GetHeight() + tabHeightInc));
205
206 // Draw white highlight from the tab's right side to the right hand edge of the view
207 dc.DrawLine((tabX + GetWidth()), (tabY + GetHeight() + tabHeightInc),
208 m_view->GetViewRect().x + m_view->GetViewRect().width, (tabY + GetHeight() + tabHeightInc));
209 }
210 #endif
211
212 // New HEL version with rounder tabs
213 #if 1
214 if (!m_view) return;
215
216 int tabInc = 0;
217 if (m_isSelected)
218 {
219 tabInc = m_view->GetTabSelectionHeight() - m_view->GetTabHeight();
220 }
221 int tabLeft = GetX() + m_view->GetViewRect().x;
222 int tabTop = GetY() + m_view->GetViewRect().y - tabInc;
223 int tabRight = tabLeft + m_view->GetTabWidth();
224 int left = m_view->GetViewRect().x;
225 int top = tabTop + m_view->GetTabHeight() + tabInc;
226 int right = left + m_view->GetViewRect().width;
227 int bottom = top + m_view->GetViewRect().height;
228
229 if (m_isSelected)
230 {
231 // TAB is selected - draw TAB and the View's full outline
232
233 dc.SetPen(*(m_view->GetHighlightPen()));
234 wxPoint pnts[10];
235 int n = 0;
236 pnts[n].x = left; pnts[n++].y = bottom;
237 pnts[n].x = left; pnts[n++].y = top;
238 pnts[n].x = tabLeft; pnts[n++].y = top;
239 pnts[n].x = tabLeft; pnts[n++].y = tabTop + 2;
240 pnts[n].x = tabLeft + 2; pnts[n++].y = tabTop;
241 pnts[n].x = tabRight - 1; pnts[n++].y = tabTop;
242 dc.DrawLines(n, pnts);
243 if (!lastInRow)
244 {
245 dc.DrawLine(
246 (tabRight + 2),
247 top,
248 right,
249 top
250 );
251 }
252
253 dc.SetPen(*(m_view->GetShadowPen()));
254 dc.DrawLine(
255 tabRight,
256 tabTop + 2,
257 tabRight,
258 top
259 );
260 dc.DrawLine(
261 right,
262 top,
263 right,
264 bottom
265 );
266 dc.DrawLine(
267 right,
268 bottom,
269 left,
270 bottom
271 );
272
273 dc.SetPen(*wxBLACK_PEN);
274 dc.DrawPoint(
275 tabRight,
276 tabTop + 1
277 );
278 dc.DrawPoint(
279 tabRight + 1,
280 tabTop + 2
281 );
282 if (lastInRow)
283 {
284 dc.DrawLine(
285 tabRight + 1,
286 bottom,
287 tabRight + 1,
288 tabTop + 1
289 );
290 }
291 else
292 {
293 dc.DrawLine(
294 tabRight + 1,
295 tabTop + 2,
296 tabRight + 1,
297 top
298 );
299 dc.DrawLine(
300 right + 1,
301 top,
302 right + 1,
303 bottom + 1
304 );
305 }
306 dc.DrawLine(
307 right + 1,
308 bottom + 1,
309 left + 1,
310 bottom + 1
311 );
312 }
313 else
314 {
315 // TAB is not selected - just draw TAB outline and RH edge
316 // if the TAB is the last in the row
317
318 int maxPositions = ((wxTabLayer*)m_view->GetLayers().Nth(0)->Data())->Number();
319 wxTabControl* tabBelow = 0;
320 wxTabControl* tabBelowRight = 0;
321 if (GetColPosition() > 0)
322 {
323 tabBelow = m_view->FindTabControlForPosition(
324 GetColPosition() - 1,
325 GetRowPosition()
326 );
327 }
328 if (!lastInRow && GetColPosition() > 0)
329 {
330 tabBelowRight = m_view->FindTabControlForPosition(
331 GetColPosition() - 1,
332 GetRowPosition() + 1
333 );
334 }
335
336 float raisedTop = top - m_view->GetTabSelectionHeight() +
337 m_view->GetTabHeight();
338
339 dc.SetPen(*(m_view->GetHighlightPen()));
340 wxPoint pnts[10];
341 int n = 0;
342
343 pnts[n].x = tabLeft;
344
345 if (tabBelow && tabBelow->IsSelected())
346 {
347 pnts[n++].y = (long)raisedTop;
348 }
349 else
350 {
351 pnts[n++].y = top;
352 }
353 pnts[n].x = tabLeft; pnts[n++].y = tabTop + 2;
354 pnts[n].x = tabLeft + 2; pnts[n++].y = tabTop;
355 pnts[n].x = tabRight - 1; pnts[n++].y = tabTop;
356 dc.DrawLines(n, pnts);
357
358 dc.SetPen(*(m_view->GetShadowPen()));
359 if (GetRowPosition() >= maxPositions - 1)
360 {
361 dc.DrawLine(
362 tabRight,
363 (tabTop + 2),
364 tabRight,
365 bottom
366 );
367 dc.DrawLine(
368 tabRight,
369 bottom,
370 (tabRight - m_view->GetHorizontalTabOffset()),
371 bottom
372 );
373 }
374 else
375 {
376 if (tabBelowRight && tabBelowRight->IsSelected())
377 {
378 dc.DrawLine(
379 tabRight,
380 (long)raisedTop,
381 tabRight,
382 tabTop + 1
383 );
384 }
385 else
386 {
387 dc.DrawLine(
388 tabRight,
389 top - 1,
390 tabRight,
391 tabTop + 1
392 );
393 }
394 }
395
396 dc.SetPen(*wxBLACK_PEN);
397 dc.DrawPoint(
398 tabRight,
399 tabTop + 1
400 );
401 dc.DrawPoint(
402 tabRight + 1,
403 tabTop + 2
404 );
405 if (GetRowPosition() >= maxPositions - 1)
406 {
407 // draw right hand edge to bottom of view
408 dc.DrawLine(
409 tabRight + 1,
410 bottom + 1,
411 tabRight + 1,
412 tabTop + 2
413 );
414 dc.DrawLine(
415 tabRight + 1,
416 bottom + 1,
417 (tabRight - m_view->GetHorizontalTabOffset()),
418 bottom + 1
419 );
420 }
421 else
422 {
423 // draw right hand edge of TAB
424 if (tabBelowRight && tabBelowRight->IsSelected())
425 {
426 dc.DrawLine(
427 tabRight + 1,
428 (long)(raisedTop - 1),
429 tabRight + 1,
430 tabTop + 2
431 );
432 }
433 else
434 {
435 dc.DrawLine(
436 tabRight + 1,
437 top - 1,
438 tabRight + 1,
439 tabTop + 2
440 );
441 }
442 }
443 }
444
445 // Draw centered text
446 dc.SetPen(*wxBLACK_PEN);
447 if (m_isSelected)
448 {
449 dc.SetFont(*(m_view->GetSelectedTabFont()));
450 }
451 else
452 {
453 dc.SetFont(*(GetFont()));
454 }
455
456 wxColour col(m_view->GetTextColour());
457 dc.SetTextForeground(col);
458 dc.SetBackgroundMode(wxTRANSPARENT);
459 long textWidth, textHeight;
460 dc.GetTextExtent(GetLabel(), &textWidth, &textHeight);
461
462 float textX = (tabLeft + tabRight - textWidth) / 2;
463 float textY = (tabInc + tabTop + m_view->GetVerticalTabTextSpacing());
464
465 dc.DrawText(GetLabel(), (long)textX, (long)textY);
466 #endif
467 }
468
469 bool wxTabControl::HitTest(int x, int y) const
470 {
471 // Top-left of tab control
472 int tabX1 = GetX() + m_view->GetViewRect().x;
473 int tabY1 = GetY() + m_view->GetViewRect().y;
474
475 // Bottom-right
476 int tabX2 = tabX1 + GetWidth();
477 int tabY2 = tabY1 + GetHeight();
478
479 if (x >= tabX1 && y >= tabY1 && x <= tabX2 && y <= tabY2)
480 return TRUE;
481 else
482 return FALSE;
483 }
484
485 IMPLEMENT_DYNAMIC_CLASS(wxTabView, wxObject)
486
487 wxTabView::wxTabView(long style)
488 {
489 m_noTabs = 0;
490 m_tabStyle = style;
491 m_tabSelection = -1;
492 m_tabHeight = 20;
493 m_tabSelectionHeight = m_tabHeight + 2;
494 m_tabWidth = 80;
495 m_tabHorizontalOffset = 10;
496 m_tabHorizontalSpacing = 2;
497 m_tabVerticalTextSpacing = 3;
498 m_topMargin = 5;
499 m_tabViewRect.x = 20;
500 m_tabViewRect.y = 20;
501 m_tabViewRect.width = 300;
502 m_tabViewRect.x = 300;
503 m_highlightColour = *wxWHITE;
504 m_shadowColour = wxColour(128, 128, 128);
505 m_backgroundColour = *wxLIGHT_GREY;
506 m_textColour = *wxBLACK;
507 m_highlightPen = wxWHITE_PEN;
508 m_shadowPen = wxGREY_PEN;
509 m_backgroundPen = wxLIGHT_GREY_PEN;
510 m_backgroundBrush = wxLIGHT_GREY_BRUSH;
511 m_tabFont = wxTheFontList->FindOrCreateFont(9, wxSWISS, wxNORMAL, wxNORMAL);
512 m_tabSelectedFont = wxTheFontList->FindOrCreateFont(9, wxSWISS, wxNORMAL, wxBOLD);
513 m_window = NULL;
514 }
515
516 wxTabView::~wxTabView()
517 {
518 }
519
520 // Automatically positions tabs
521 wxTabControl *wxTabView::AddTab(int id, const wxString& label, wxTabControl *existingTab)
522 {
523 // First, find which layer we should be adding to.
524 wxNode *node = m_layers.Last();
525 if (!node)
526 {
527 wxTabLayer *newLayer = new wxTabLayer;
528 node = m_layers.Append(newLayer);
529 }
530 // Check if adding another tab control would go off the
531 // right-hand edge of the layer.
532 wxTabLayer *tabLayer = (wxTabLayer *)node->Data();
533 wxNode *lastTabNode = tabLayer->Last();
534 if (lastTabNode)
535 {
536 wxTabControl *lastTab = (wxTabControl *)lastTabNode->Data();
537 // Start another layer (row).
538 // Tricky choice: can't just check if will be overlapping the edge, because
539 // this happens anyway for 2nd and subsequent rows.
540 // Should check this for 1st row, and then subsequent rows should not exceed 1st
541 // in length.
542 if (((tabLayer == m_layers.First()->Data()) && ((lastTab->GetX() + 2*lastTab->GetWidth() + GetHorizontalTabSpacing())
543 > GetViewRect().width)) ||
544 ((tabLayer != m_layers.First()->Data()) && (tabLayer->Number() == ((wxTabLayer *)m_layers.First()->Data())->Number())))
545 {
546 tabLayer = new wxTabLayer;
547 m_layers.Append(tabLayer);
548 lastTabNode = NULL;
549 }
550 }
551 int layer = m_layers.Number() - 1;
552
553 wxTabControl *tabControl = existingTab;
554 if (!existingTab)
555 tabControl = OnCreateTabControl();
556 tabControl->SetRowPosition(tabLayer->Number());
557 tabControl->SetColPosition(layer);
558
559 wxTabControl *lastTab = NULL;
560 if (lastTabNode)
561 lastTab = (wxTabControl *)lastTabNode->Data();
562
563 // Top of new tab
564 int verticalOffset = (- GetTopMargin()) - ((layer+1)*GetTabHeight());
565 // Offset from view top-left
566 int horizontalOffset = 0;
567 if (!lastTab)
568 horizontalOffset = layer*GetHorizontalTabOffset();
569 else
570 horizontalOffset = lastTab->GetX() + GetTabWidth() + GetHorizontalTabSpacing();
571
572 tabControl->SetPosition(horizontalOffset, verticalOffset);
573 tabControl->SetSize(GetTabWidth(), GetTabHeight());
574 tabControl->SetId(id);
575 tabControl->SetLabel(label);
576 tabControl->SetFont(GetTabFont());
577
578 tabLayer->Append(tabControl);
579 m_noTabs ++;
580
581 return tabControl;
582 }
583
584 void wxTabView::ClearTabs(bool deleteTabs)
585 {
586 wxNode *layerNode = m_layers.First();
587 while (layerNode)
588 {
589 wxTabLayer *layer = (wxTabLayer *)layerNode->Data();
590 wxNode *tabNode = layer->First();
591 while (tabNode)
592 {
593 wxTabControl *tab = (wxTabControl *)tabNode->Data();
594 if (deleteTabs)
595 delete tab;
596 wxNode *next = tabNode->Next();
597 delete tabNode;
598 tabNode = next;
599 }
600 wxNode *nextLayerNode = layerNode->Next();
601 delete layer;
602 delete layerNode;
603 layerNode = nextLayerNode;
604 }
605 }
606
607 // Layout tabs (optional, e.g. if resizing window)
608 void wxTabView::Layout(void)
609 {
610 // Make a list of the tab controls, deleting the wxTabLayers.
611 wxList controls;
612
613 wxNode *layerNode = m_layers.First();
614 while (layerNode)
615 {
616 wxTabLayer *layer = (wxTabLayer *)layerNode->Data();
617 wxNode *tabNode = layer->First();
618 while (tabNode)
619 {
620 wxTabControl *tab = (wxTabControl *)tabNode->Data();
621 controls.Append(tab);
622 wxNode *next = tabNode->Next();
623 delete tabNode;
624 tabNode = next;
625 }
626 wxNode *nextLayerNode = layerNode->Next();
627 delete layer;
628 delete layerNode;
629 layerNode = nextLayerNode;
630 }
631
632 wxTabControl *lastTab = NULL;
633
634 wxTabLayer *currentLayer = new wxTabLayer;
635 m_layers.Append(currentLayer);
636
637 wxNode *node = controls.First();
638 while (node)
639 {
640 wxTabControl *tabControl = (wxTabControl *)node->Data();
641 if (lastTab)
642 {
643 // Start another layer (row).
644 // Tricky choice: can't just check if will be overlapping the edge, because
645 // this happens anyway for 2nd and subsequent rows.
646 // Should check this for 1st row, and then subsequent rows should not exceed 1st
647 // in length.
648 if (((currentLayer == m_layers.First()->Data()) && ((lastTab->GetX() + 2*lastTab->GetWidth() + GetHorizontalTabSpacing())
649 > GetViewRect().width)) ||
650 ((currentLayer != m_layers.First()->Data()) && (currentLayer->Number() == ((wxTabLayer *)m_layers.First()->Data())->Number())))
651 {
652 currentLayer = new wxTabLayer;
653 m_layers.Append(currentLayer);
654 lastTab = NULL;
655 }
656 }
657
658 int layer = m_layers.Number() - 1;
659
660 tabControl->SetRowPosition(currentLayer->Number());
661 tabControl->SetColPosition(layer);
662
663 // Top of new tab
664 int verticalOffset = (- GetTopMargin()) - ((layer+1)*GetTabHeight());
665 // Offset from view top-left
666 int horizontalOffset = 0;
667 if (!lastTab)
668 horizontalOffset = layer*GetHorizontalTabOffset();
669 else
670 horizontalOffset = lastTab->GetX() + GetTabWidth() + GetHorizontalTabSpacing();
671
672 tabControl->SetPosition(horizontalOffset, verticalOffset);
673 tabControl->SetSize(GetTabWidth(), GetTabHeight());
674
675 currentLayer->Append(tabControl);
676 lastTab = tabControl;
677
678 node = node->Next();
679 }
680
681 // Move the selected tab to the bottom
682 wxTabControl *control = FindTabControlForId(m_tabSelection);
683 if (control)
684 MoveSelectionTab(control);
685
686 }
687
688 // Draw all tabs
689 void wxTabView::Draw(wxDC& dc)
690 {
691 // Draw top margin area (beneath tabs and above view area)
692 if (GetTabStyle() & wxTAB_STYLE_COLOUR_INTERIOR)
693 {
694 dc.SetPen(*wxTRANSPARENT_PEN);
695 dc.SetBrush(*GetBackgroundBrush());
696
697 // Add 1 because the pen is transparent. Under Motif, may be different.
698 dc.DrawRectangle(
699 m_tabViewRect.x,
700 (m_tabViewRect.y - m_topMargin),
701 (m_tabViewRect.width + 1),
702 (m_topMargin + 1)
703 );
704 }
705
706 // Draw layers in reverse order
707 wxNode *node = m_layers.Last();
708 while (node)
709 {
710 wxTabLayer *layer = (wxTabLayer *)node->Data();
711 wxNode *node2 = layer->First();
712 while (node2)
713 {
714 wxTabControl *control = (wxTabControl *)node2->Data();
715 control->OnDraw(dc, (node2->Next() == NULL));
716 node2 = node2->Next();
717 }
718
719 node = node->Previous();
720 }
721
722
723 #if 0
724 if (GetTabStyle() & wxTAB_STYLE_DRAW_BOX)
725 {
726 dc.SetPen(GetShadowPen());
727
728 // Draw bottom line
729 dc.DrawLine(
730 (GetViewRect().x + 1),
731 (GetViewRect().y + GetViewRect().height),
732 (GetViewRect().x + GetViewRect().width),
733 (GetViewRect().y + GetViewRect().height)
734 );
735
736 // Draw right line
737 dc.DrawLine(
738 (GetViewRect().x + GetViewRect().width),
739 (GetViewRect().y - GetTopMargin() + 1),
740 (GetViewRect().x + GetViewRect().width),
741 (GetViewRect().y + GetViewRect().height)
742 );
743
744 dc.SetPen(wxBLACK_PEN);
745
746 // Draw bottom line
747 dc.DrawLine(
748 (GetViewRect().x),
749 (GetViewRect().y + GetViewRect().height + 1),
750 (GetViewRect().x + GetViewRect().width),
751 (GetViewRect().y + GetViewRect().height + 1)
752 );
753
754 // Draw right line
755 dc.DrawLine(
756 (GetViewRect().x + GetViewRect().width + 1),
757 (GetViewRect().y - GetTopMargin()),
758 (GetViewRect().x + GetViewRect().width + 1),
759 (GetViewRect().y + GetViewRect().height + 1)
760 );
761 }
762 #endif
763 }
764
765 // Process mouse event, return FALSE if we didn't process it
766 bool wxTabView::OnEvent(wxMouseEvent& event)
767 {
768 if (!event.LeftDown())
769 return FALSE;
770
771 float x, y;
772 event.Position(&x, &y);
773
774 wxTabControl *hitControl = NULL;
775
776 wxNode *node = m_layers.First();
777 while (node)
778 {
779 wxTabLayer *layer = (wxTabLayer *)node->Data();
780 wxNode *node2 = layer->First();
781 while (node2)
782 {
783 wxTabControl *control = (wxTabControl *)node2->Data();
784 if (control->HitTest((int)x, (int)y))
785 {
786 hitControl = control;
787 node = NULL;
788 node2 = NULL;
789 }
790 else
791 node2 = node2->Next();
792 }
793
794 if (node)
795 node = node->Next();
796 }
797
798 if (!hitControl)
799 return FALSE;
800
801 wxTabControl *currentTab = FindTabControlForId(m_tabSelection);
802
803 if (hitControl == currentTab)
804 return FALSE;
805
806 ChangeTab(hitControl);
807
808 return TRUE;
809 }
810
811 bool wxTabView::ChangeTab(wxTabControl *control)
812 {
813 wxTabControl *currentTab = FindTabControlForId(m_tabSelection);
814 int oldTab = -1;
815 if (currentTab)
816 oldTab = currentTab->GetId();
817
818 if (control == currentTab)
819 return TRUE;
820
821 if (m_layers.Number() == 0)
822 return FALSE;
823
824 if (!OnTabPreActivate(control->GetId(), oldTab))
825 return FALSE;
826
827 // Move the tab to the bottom
828 MoveSelectionTab(control);
829
830 if (currentTab)
831 currentTab->SetSelected(FALSE);
832
833 control->SetSelected(TRUE);
834 m_tabSelection = control->GetId();
835
836 OnTabActivate(control->GetId(), oldTab);
837
838 // Leave window refresh for the implementing window
839
840 return TRUE;
841 }
842
843 // Move the selected tab to the bottom layer, if necessary,
844 // without calling app activation code
845 bool wxTabView::MoveSelectionTab(wxTabControl *control)
846 {
847 if (m_layers.Number() == 0)
848 return FALSE;
849
850 wxTabLayer *firstLayer = (wxTabLayer *)m_layers.First()->Data();
851
852 // Find what column this tab is at, so we can swap with the one at the bottom.
853 // If we're on the bottom layer, then no need to swap.
854 if (!firstLayer->Member(control))
855 {
856 // Do a swap
857 int col = 0;
858 wxNode *thisNode = FindTabNodeAndColumn(control, &col);
859 if (!thisNode)
860 return FALSE;
861 wxNode *otherNode = firstLayer->Nth(col);
862 if (!otherNode)
863 return FALSE;
864
865 // If this is already in the bottom layer, return now
866 if (otherNode == thisNode)
867 return TRUE;
868
869 wxTabControl *otherTab = (wxTabControl *)otherNode->Data();
870
871 // We now have pointers to the tab to be changed to,
872 // and the tab on the first layer. Swap tab structures and
873 // position details.
874
875 int thisX = control->GetX();
876 int thisY = control->GetY();
877 int thisColPos = control->GetColPosition();
878 int otherX = otherTab->GetX();
879 int otherY = otherTab->GetY();
880 int otherColPos = otherTab->GetColPosition();
881
882 control->SetPosition(otherX, otherY);
883 control->SetColPosition(otherColPos);
884 otherTab->SetPosition(thisX, thisY);
885 otherTab->SetColPosition(thisColPos);
886
887 // Swap the data for the nodes
888 thisNode->SetData(otherTab);
889 otherNode->SetData(control);
890 }
891 return TRUE;
892 }
893
894 // Called when a tab is activated
895 void wxTabView::OnTabActivate(int /*activateId*/, int /*deactivateId*/)
896 {
897 }
898
899 void wxTabView::SetHighlightColour(const wxColour& col)
900 {
901 m_highlightColour = col;
902 m_highlightPen = wxThePenList->FindOrCreatePen(col, 1, wxSOLID);
903 }
904
905 void wxTabView::SetShadowColour(const wxColour& col)
906 {
907 m_shadowColour = col;
908 m_shadowPen = wxThePenList->FindOrCreatePen(col, 1, wxSOLID);
909 }
910
911 void wxTabView::SetBackgroundColour(const wxColour& col)
912 {
913 m_backgroundColour = col;
914 m_backgroundPen = wxThePenList->FindOrCreatePen(col, 1, wxSOLID);
915 m_backgroundBrush = wxTheBrushList->FindOrCreateBrush(col, wxSOLID);
916 }
917
918 void wxTabView::SetTabSelection(int sel, bool activateTool)
919 {
920 int oldSel = m_tabSelection;
921 wxTabControl *control = FindTabControlForId(sel);
922
923 if (!OnTabPreActivate(sel, oldSel))
924 return;
925
926 if (control)
927 control->SetSelected((sel != 0)); // TODO ??
928 else
929 {
930 wxMessageBox("Could not find tab for id", "Error", wxOK);
931 return;
932 }
933
934 m_tabSelection = sel;
935 MoveSelectionTab(control);
936
937 if (activateTool)
938 OnTabActivate(sel, oldSel);
939 }
940
941 // Find tab control for id
942 wxTabControl *wxTabView::FindTabControlForId(int id) const
943 {
944 wxNode *node1 = m_layers.First();
945 while (node1)
946 {
947 wxTabLayer *layer = (wxTabLayer *)node1->Data();
948 wxNode *node2 = layer->First();
949 while (node2)
950 {
951 wxTabControl *control = (wxTabControl *)node2->Data();
952 if (control->GetId() == id)
953 return control;
954 node2 = node2->Next();
955 }
956 node1 = node1->Next();
957 }
958 return NULL;
959 }
960
961 // Find tab control for layer, position (starting from zero)
962 wxTabControl *wxTabView::FindTabControlForPosition(int layer, int position) const
963 {
964 wxNode *node1 = m_layers.Nth(layer);
965 if (!node1)
966 return NULL;
967 wxTabLayer *tabLayer = (wxTabLayer *)node1->Data();
968 wxNode *node2 = tabLayer->Nth(position);
969 if (!node2)
970 return NULL;
971 return (wxTabControl *)node2->Data();
972 }
973
974 // Find the node and the column at which this control is positioned.
975 wxNode *wxTabView::FindTabNodeAndColumn(wxTabControl *control, int *col) const
976 {
977 wxNode *node1 = m_layers.First();
978 while (node1)
979 {
980 wxTabLayer *layer = (wxTabLayer *)node1->Data();
981 int c = 0;
982 wxNode *node2 = layer->First();
983 while (node2)
984 {
985 wxTabControl *cnt = (wxTabControl *)node2->Data();
986 if (cnt == control)
987 {
988 *col = c;
989 return node2;
990 }
991 node2 = node2->Next();
992 c ++;
993 }
994 node1 = node1->Next();
995 }
996 return NULL;
997 }
998
999 int wxTabView::CalculateTabWidth(int noTabs, bool adjustView)
1000 {
1001 m_tabWidth = (int)((m_tabViewRect.width - ((noTabs - 1)*GetHorizontalTabSpacing()))/noTabs);
1002 if (adjustView)
1003 {
1004 m_tabViewRect.width = noTabs*m_tabWidth + ((noTabs-1)*GetHorizontalTabSpacing());
1005 }
1006 return m_tabWidth;
1007 }
1008
1009 /*
1010 * wxTabbedDialog
1011 */
1012
1013 IMPLEMENT_CLASS(wxTabbedDialog, wxDialog)
1014
1015 BEGIN_EVENT_TABLE(wxTabbedDialog, wxDialog)
1016 EVT_CLOSE(wxTabbedDialog::OnCloseWindow)
1017 EVT_MOUSE_EVENTS(wxTabbedDialog::OnMouseEvent)
1018 EVT_PAINT(wxTabbedDialog::OnPaint)
1019 END_EVENT_TABLE()
1020
1021 wxTabbedDialog::wxTabbedDialog(wxWindow *parent, wxWindowID id,
1022 const wxString& title,
1023 const wxPoint& pos, const wxSize& size,
1024 long windowStyle, const wxString& name):
1025 wxDialog(parent, id, title, pos, size, windowStyle, name)
1026 {
1027 m_tabView = NULL;
1028 }
1029
1030 wxTabbedDialog::~wxTabbedDialog(void)
1031 {
1032 if (m_tabView)
1033 delete m_tabView;
1034 }
1035
1036 void wxTabbedDialog::OnCloseWindow(wxCloseEvent& WXUNUSED(event) )
1037 {
1038 Destroy();
1039 }
1040
1041 void wxTabbedDialog::OnMouseEvent(wxMouseEvent& event )
1042 {
1043 if (m_tabView)
1044 m_tabView->OnEvent(event);
1045 }
1046
1047 void wxTabbedDialog::OnPaint(wxPaintEvent& WXUNUSED(event) )
1048 {
1049 wxPaintDC dc(this);
1050 if (m_tabView)
1051 m_tabView->Draw(dc);
1052 }
1053
1054 /*
1055 * wxTabbedPanel
1056 */
1057
1058 IMPLEMENT_CLASS(wxTabbedPanel, wxPanel)
1059
1060 BEGIN_EVENT_TABLE(wxTabbedPanel, wxPanel)
1061 EVT_MOUSE_EVENTS(wxTabbedPanel::OnMouseEvent)
1062 EVT_PAINT(wxTabbedPanel::OnPaint)
1063 END_EVENT_TABLE()
1064
1065 wxTabbedPanel::wxTabbedPanel(wxWindow *parent, wxWindowID id, const wxPoint& pos,
1066 const wxSize& size, long windowStyle, const wxString& name):
1067 wxPanel(parent, id, pos, size, windowStyle, name)
1068 {
1069 m_tabView = NULL;
1070 }
1071
1072 wxTabbedPanel::~wxTabbedPanel(void)
1073 {
1074 delete m_tabView;
1075 }
1076
1077 void wxTabbedPanel::OnMouseEvent(wxMouseEvent& event)
1078 {
1079 if (m_tabView)
1080 m_tabView->OnEvent(event);
1081 }
1082
1083 void wxTabbedPanel::OnPaint(wxPaintEvent& WXUNUSED(event) )
1084 {
1085 wxPaintDC dc(this);
1086 if (m_tabView)
1087 m_tabView->Draw(dc);
1088 }
1089
1090 /*
1091 * wxDialogTabView
1092 */
1093
1094 IMPLEMENT_CLASS(wxPanelTabView, wxTabView)
1095
1096 wxPanelTabView::wxPanelTabView(wxPanel *pan, long style): wxTabView(style), m_tabWindows(wxKEY_INTEGER)
1097 {
1098 m_panel = pan;
1099 m_currentWindow = NULL;
1100
1101 if (m_panel->IsKindOf(CLASSINFO(wxTabbedDialog)))
1102 ((wxTabbedDialog *)m_panel)->SetTabView(this);
1103 else if (m_panel->IsKindOf(CLASSINFO(wxTabbedPanel)))
1104 ((wxTabbedPanel *)m_panel)->SetTabView(this);
1105
1106 SetWindow(m_panel);
1107 }
1108
1109 wxPanelTabView::~wxPanelTabView(void)
1110 {
1111 ClearWindows(TRUE);
1112 }
1113
1114 // Called when a tab is activated
1115 void wxPanelTabView::OnTabActivate(int activateId, int deactivateId)
1116 {
1117 if (!m_panel)
1118 return;
1119
1120 wxWindow *oldWindow = ((deactivateId == -1) ? 0 : GetTabWindow(deactivateId));
1121 wxWindow *newWindow = GetTabWindow(activateId);
1122
1123 if (oldWindow)
1124 oldWindow->Show(FALSE);
1125 if (newWindow)
1126 newWindow->Show(TRUE);
1127
1128 m_panel->Refresh();
1129 }
1130
1131
1132 void wxPanelTabView::AddTabWindow(int id, wxWindow *window)
1133 {
1134 m_tabWindows.Append((long)id, window);
1135 window->Show(FALSE);
1136 }
1137
1138 wxWindow *wxPanelTabView::GetTabWindow(int id) const
1139 {
1140 wxNode *node = m_tabWindows.Find((long)id);
1141 if (!node)
1142 return NULL;
1143 return (wxWindow *)node->Data();
1144 }
1145
1146 void wxPanelTabView::ClearWindows(bool deleteWindows)
1147 {
1148 if (deleteWindows)
1149 m_tabWindows.DeleteContents(TRUE);
1150 m_tabWindows.Clear();
1151 m_tabWindows.DeleteContents(FALSE);
1152 }
1153
1154 void wxPanelTabView::ShowWindowForTab(int id)
1155 {
1156 wxWindow *newWindow = GetTabWindow(id);
1157 if (newWindow == m_currentWindow)
1158 return;
1159 if (m_currentWindow)
1160 m_currentWindow->Show(FALSE);
1161 newWindow->Show(TRUE);
1162 newWindow->Refresh();
1163 }
1164