]> git.saurik.com Git - wxWidgets.git/blob - src/aui/tabart.cpp
Fix crash in wxStaticBox::HandleEraseBkgnd() in wxMSW on closing.
[wxWidgets.git] / src / aui / tabart.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/aui/tabart.cpp
3 // Purpose: wxaui: wx advanced user interface - notebook-art
4 // Author: Benjamin I. Williams
5 // Modified by: Jens Lody (moved from auibook.cpp in extra file)
6 // Created: 2012-03-21
7 // RCS-ID: $Id:$
8 // Copyright: (C) Copyright 2006, Kirix Corporation, All Rights Reserved
9 // Licence: wxWindows Library Licence, Version 3.1
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ----------------------------------------------------------------------------
13 // headers
14 // ----------------------------------------------------------------------------
15
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #if wxUSE_AUI
23
24 #ifndef WX_PRECOMP
25 #include "wx/dc.h"
26 #include "wx/dcclient.h"
27 #include "wx/settings.h"
28 #include "wx/bitmap.h"
29 #include "wx/menu.h"
30 #endif
31
32 #include "wx/renderer.h"
33 #include "wx/aui/auibook.h"
34
35 #ifdef __WXMAC__
36 #include "wx/osx/private.h"
37 #endif
38
39
40 // -- GUI helper classes and functions --
41
42 class wxAuiCommandCapture : public wxEvtHandler
43 {
44 public:
45
46 wxAuiCommandCapture() { m_lastId = 0; }
47 int GetCommandId() const { return m_lastId; }
48
49 bool ProcessEvent(wxEvent& evt)
50 {
51 if (evt.GetEventType() == wxEVT_COMMAND_MENU_SELECTED)
52 {
53 m_lastId = evt.GetId();
54 return true;
55 }
56
57 if (GetNextHandler())
58 return GetNextHandler()->ProcessEvent(evt);
59
60 return false;
61 }
62
63 private:
64 int m_lastId;
65 };
66
67
68 // these functions live in dockart.cpp -- they'll eventually
69 // be moved to a new utility cpp file
70
71 wxBitmap wxAuiBitmapFromBits(const unsigned char bits[], int w, int h,
72 const wxColour& color);
73
74 wxString wxAuiChopText(wxDC& dc, const wxString& text, int max_size);
75
76 static void DrawButtons(wxDC& dc,
77 const wxRect& _rect,
78 const wxBitmap& bmp,
79 const wxColour& bkcolour,
80 int button_state)
81 {
82 wxRect rect = _rect;
83
84 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
85 {
86 rect.x++;
87 rect.y++;
88 }
89
90 if (button_state == wxAUI_BUTTON_STATE_HOVER ||
91 button_state == wxAUI_BUTTON_STATE_PRESSED)
92 {
93 dc.SetBrush(wxBrush(bkcolour.ChangeLightness(120)));
94 dc.SetPen(wxPen(bkcolour.ChangeLightness(75)));
95
96 // draw the background behind the button
97 dc.DrawRectangle(rect.x, rect.y, 15, 15);
98 }
99
100 // draw the button itself
101 dc.DrawBitmap(bmp, rect.x, rect.y, true);
102 }
103
104 static void IndentPressedBitmap(wxRect* rect, int button_state)
105 {
106 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
107 {
108 rect->x++;
109 rect->y++;
110 }
111 }
112
113 // -- bitmaps --
114
115 #if defined( __WXMAC__ )
116 static const unsigned char close_bits[]={
117 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
118 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
119 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
120 #elif defined( __WXGTK__)
121 static const unsigned char close_bits[]={
122 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
123 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
124 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
125 #else
126 static const unsigned char close_bits[]={
127 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xcf, 0xf9,
128 0x9f, 0xfc, 0x3f, 0xfe, 0x3f, 0xfe, 0x9f, 0xfc, 0xcf, 0xf9, 0xe7, 0xf3,
129 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
130 #endif
131
132 static const unsigned char left_bits[] = {
133 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0xfe,
134 0x1f, 0xfe, 0x0f, 0xfe, 0x1f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe,
135 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
136
137 static const unsigned char right_bits[] = {
138 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x9f, 0xff, 0x1f, 0xff,
139 0x1f, 0xfe, 0x1f, 0xfc, 0x1f, 0xfe, 0x1f, 0xff, 0x9f, 0xff, 0xdf, 0xff,
140 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
141
142 static const unsigned char list_bits[] = {
143 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
144 0x0f, 0xf8, 0xff, 0xff, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff,
145 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
146
147
148
149
150
151
152 // -- wxAuiGenericTabArt class implementation --
153
154 wxAuiGenericTabArt::wxAuiGenericTabArt()
155 {
156 m_normalFont = *wxNORMAL_FONT;
157 m_selectedFont = *wxNORMAL_FONT;
158 m_selectedFont.SetWeight(wxBOLD);
159 m_measuringFont = m_selectedFont;
160
161 m_fixedTabWidth = 100;
162 m_tabCtrlHeight = 0;
163
164 #if defined( __WXMAC__ ) && wxOSX_USE_COCOA_OR_CARBON
165 wxColor baseColour = wxColour( wxMacCreateCGColorFromHITheme(kThemeBrushToolbarBackground));
166 #else
167 wxColor baseColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
168 #endif
169
170 // the baseColour is too pale to use as our base colour,
171 // so darken it a bit --
172 if ((255-baseColour.Red()) +
173 (255-baseColour.Green()) +
174 (255-baseColour.Blue()) < 60)
175 {
176 baseColour = baseColour.ChangeLightness(92);
177 }
178
179 m_activeColour = baseColour;
180 m_baseColour = baseColour;
181 wxColor borderColour = baseColour.ChangeLightness(75);
182
183 m_borderPen = wxPen(borderColour);
184 m_baseColourPen = wxPen(m_baseColour);
185 m_baseColourBrush = wxBrush(m_baseColour);
186
187 m_activeCloseBmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
188 m_disabledCloseBmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
189
190 m_activeLeftBmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
191 m_disabledLeftBmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
192
193 m_activeRightBmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
194 m_disabledRightBmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
195
196 m_activeWindowListBmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
197 m_disabledWindowListBmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
198
199 m_flags = 0;
200 }
201
202 wxAuiGenericTabArt::~wxAuiGenericTabArt()
203 {
204 }
205
206 wxAuiTabArt* wxAuiGenericTabArt::Clone()
207 {
208 return new wxAuiGenericTabArt(*this);
209 }
210
211 void wxAuiGenericTabArt::SetFlags(unsigned int flags)
212 {
213 m_flags = flags;
214 }
215
216 void wxAuiGenericTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
217 size_t tab_count)
218 {
219 m_fixedTabWidth = 100;
220
221 int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
222
223 if (m_flags & wxAUI_NB_CLOSE_BUTTON)
224 tot_width -= m_activeCloseBmp.GetWidth();
225 if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
226 tot_width -= m_activeWindowListBmp.GetWidth();
227
228 if (tab_count > 0)
229 {
230 m_fixedTabWidth = tot_width/(int)tab_count;
231 }
232
233
234 if (m_fixedTabWidth < 100)
235 m_fixedTabWidth = 100;
236
237 if (m_fixedTabWidth > tot_width/2)
238 m_fixedTabWidth = tot_width/2;
239
240 if (m_fixedTabWidth > 220)
241 m_fixedTabWidth = 220;
242
243 m_tabCtrlHeight = tab_ctrl_size.y;
244 }
245
246
247 void wxAuiGenericTabArt::DrawBackground(wxDC& dc,
248 wxWindow* WXUNUSED(wnd),
249 const wxRect& rect)
250 {
251 // draw background
252
253 wxColor top_color = m_baseColour.ChangeLightness(90);
254 wxColor bottom_color = m_baseColour.ChangeLightness(170);
255 wxRect r;
256
257 if (m_flags &wxAUI_NB_BOTTOM)
258 r = wxRect(rect.x, rect.y, rect.width+2, rect.height);
259 // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
260 // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
261 else //for wxAUI_NB_TOP
262 r = wxRect(rect.x, rect.y, rect.width+2, rect.height-3);
263
264 dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
265
266
267 // draw base lines
268
269 dc.SetPen(m_borderPen);
270 int y = rect.GetHeight();
271 int w = rect.GetWidth();
272
273 if (m_flags &wxAUI_NB_BOTTOM)
274 {
275 dc.SetBrush(wxBrush(bottom_color));
276 dc.DrawRectangle(-1, 0, w+2, 4);
277 }
278 // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
279 // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
280 else //for wxAUI_NB_TOP
281 {
282 dc.SetBrush(m_baseColourBrush);
283 dc.DrawRectangle(-1, y-4, w+2, 4);
284 }
285 }
286
287
288 // DrawTab() draws an individual tab.
289 //
290 // dc - output dc
291 // in_rect - rectangle the tab should be confined to
292 // caption - tab's caption
293 // active - whether or not the tab is active
294 // out_rect - actual output rectangle
295 // x_extent - the advance x; where the next tab should start
296
297 void wxAuiGenericTabArt::DrawTab(wxDC& dc,
298 wxWindow* wnd,
299 const wxAuiNotebookPage& page,
300 const wxRect& in_rect,
301 int close_button_state,
302 wxRect* out_tab_rect,
303 wxRect* out_button_rect,
304 int* x_extent)
305 {
306 wxCoord normal_textx, normal_texty;
307 wxCoord selected_textx, selected_texty;
308 wxCoord texty;
309
310 // if the caption is empty, measure some temporary text
311 wxString caption = page.caption;
312 if (caption.empty())
313 caption = wxT("Xj");
314
315 dc.SetFont(m_selectedFont);
316 dc.GetTextExtent(caption, &selected_textx, &selected_texty);
317
318 dc.SetFont(m_normalFont);
319 dc.GetTextExtent(caption, &normal_textx, &normal_texty);
320
321 // figure out the size of the tab
322 wxSize tab_size = GetTabSize(dc,
323 wnd,
324 page.caption,
325 page.bitmap,
326 page.active,
327 close_button_state,
328 x_extent);
329
330 wxCoord tab_height = m_tabCtrlHeight - 3;
331 wxCoord tab_width = tab_size.x;
332 wxCoord tab_x = in_rect.x;
333 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
334
335
336 caption = page.caption;
337
338
339 // select pen, brush and font for the tab to be drawn
340
341 if (page.active)
342 {
343 dc.SetFont(m_selectedFont);
344 texty = selected_texty;
345 }
346 else
347 {
348 dc.SetFont(m_normalFont);
349 texty = normal_texty;
350 }
351
352
353 // create points that will make the tab outline
354
355 int clip_width = tab_width;
356 if (tab_x + clip_width > in_rect.x + in_rect.width)
357 clip_width = (in_rect.x + in_rect.width) - tab_x;
358
359 /*
360 wxPoint clip_points[6];
361 clip_points[0] = wxPoint(tab_x, tab_y+tab_height-3);
362 clip_points[1] = wxPoint(tab_x, tab_y+2);
363 clip_points[2] = wxPoint(tab_x+2, tab_y);
364 clip_points[3] = wxPoint(tab_x+clip_width-1, tab_y);
365 clip_points[4] = wxPoint(tab_x+clip_width+1, tab_y+2);
366 clip_points[5] = wxPoint(tab_x+clip_width+1, tab_y+tab_height-3);
367
368 // FIXME: these ports don't provide wxRegion ctor from array of points
369 #if !defined(__WXDFB__) && !defined(__WXCOCOA__)
370 // set the clipping region for the tab --
371 wxRegion clipping_region(WXSIZEOF(clip_points), clip_points);
372 dc.SetClippingRegion(clipping_region);
373 #endif // !wxDFB && !wxCocoa
374 */
375 // since the above code above doesn't play well with WXDFB or WXCOCOA,
376 // we'll just use a rectangle for the clipping region for now --
377 dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3);
378
379
380 wxPoint border_points[6];
381 if (m_flags &wxAUI_NB_BOTTOM)
382 {
383 border_points[0] = wxPoint(tab_x, tab_y);
384 border_points[1] = wxPoint(tab_x, tab_y+tab_height-6);
385 border_points[2] = wxPoint(tab_x+2, tab_y+tab_height-4);
386 border_points[3] = wxPoint(tab_x+tab_width-2, tab_y+tab_height-4);
387 border_points[4] = wxPoint(tab_x+tab_width, tab_y+tab_height-6);
388 border_points[5] = wxPoint(tab_x+tab_width, tab_y);
389 }
390 else //if (m_flags & wxAUI_NB_TOP) {}
391 {
392 border_points[0] = wxPoint(tab_x, tab_y+tab_height-4);
393 border_points[1] = wxPoint(tab_x, tab_y+2);
394 border_points[2] = wxPoint(tab_x+2, tab_y);
395 border_points[3] = wxPoint(tab_x+tab_width-2, tab_y);
396 border_points[4] = wxPoint(tab_x+tab_width, tab_y+2);
397 border_points[5] = wxPoint(tab_x+tab_width, tab_y+tab_height-4);
398 }
399 // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
400 // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
401
402 int drawn_tab_yoff = border_points[1].y;
403 int drawn_tab_height = border_points[0].y - border_points[1].y;
404
405
406 if (page.active)
407 {
408 // draw active tab
409
410 // draw base background color
411 wxRect r(tab_x, tab_y, tab_width, tab_height);
412 dc.SetPen(wxPen(m_activeColour));
413 dc.SetBrush(wxBrush(m_activeColour));
414 dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4);
415
416 // this white helps fill out the gradient at the top of the tab
417 dc.SetPen(*wxWHITE_PEN);
418 dc.SetBrush(*wxWHITE_BRUSH);
419 dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4);
420
421 // these two points help the rounded corners appear more antialiased
422 dc.SetPen(wxPen(m_activeColour));
423 dc.DrawPoint(r.x+2, r.y+1);
424 dc.DrawPoint(r.x+r.width-2, r.y+1);
425
426 // set rectangle down a bit for gradient drawing
427 r.SetHeight(r.GetHeight()/2);
428 r.x += 2;
429 r.width -= 3;
430 r.y += r.height;
431 r.y -= 2;
432
433 // draw gradient background
434 wxColor top_color = *wxWHITE;
435 wxColor bottom_color = m_activeColour;
436 dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
437 }
438 else
439 {
440 // draw inactive tab
441
442 wxRect r(tab_x, tab_y+1, tab_width, tab_height-3);
443
444 // start the gradent up a bit and leave the inside border inset
445 // by a pixel for a 3D look. Only the top half of the inactive
446 // tab will have a slight gradient
447 r.x += 3;
448 r.y++;
449 r.width -= 4;
450 r.height /= 2;
451 r.height--;
452
453 // -- draw top gradient fill for glossy look
454 wxColor top_color = m_baseColour;
455 wxColor bottom_color = top_color.ChangeLightness(160);
456 dc.GradientFillLinear(r, bottom_color, top_color, wxNORTH);
457
458 r.y += r.height;
459 r.y--;
460
461 // -- draw bottom fill for glossy look
462 top_color = m_baseColour;
463 bottom_color = m_baseColour;
464 dc.GradientFillLinear(r, top_color, bottom_color, wxSOUTH);
465 }
466
467 // draw tab outline
468 dc.SetPen(m_borderPen);
469 dc.SetBrush(*wxTRANSPARENT_BRUSH);
470 dc.DrawPolygon(WXSIZEOF(border_points), border_points);
471
472 // there are two horizontal grey lines at the bottom of the tab control,
473 // this gets rid of the top one of those lines in the tab control
474 if (page.active)
475 {
476 if (m_flags &wxAUI_NB_BOTTOM)
477 dc.SetPen(wxPen(m_baseColour.ChangeLightness(170)));
478 // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
479 // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
480 else //for wxAUI_NB_TOP
481 dc.SetPen(m_baseColourPen);
482 dc.DrawLine(border_points[0].x+1,
483 border_points[0].y,
484 border_points[5].x,
485 border_points[5].y);
486 }
487
488
489 int text_offset = tab_x + 8;
490 int close_button_width = 0;
491 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
492 {
493 close_button_width = m_activeCloseBmp.GetWidth();
494 }
495
496 int bitmap_offset = 0;
497 if (page.bitmap.IsOk())
498 {
499 bitmap_offset = tab_x + 8;
500
501 // draw bitmap
502 dc.DrawBitmap(page.bitmap,
503 bitmap_offset,
504 drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
505 true);
506
507 text_offset = bitmap_offset + page.bitmap.GetWidth();
508 text_offset += 3; // bitmap padding
509
510 }
511 else
512 {
513 text_offset = tab_x + 8;
514 }
515
516
517 wxString draw_text = wxAuiChopText(dc,
518 caption,
519 tab_width - (text_offset-tab_x) - close_button_width);
520
521 // draw tab text
522 dc.DrawText(draw_text,
523 text_offset,
524 drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1);
525
526 // draw focus rectangle
527 if (page.active && (wnd->FindFocus() == wnd))
528 {
529 wxRect focusRectText(text_offset, (drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1),
530 selected_textx, selected_texty);
531
532 wxRect focusRect;
533 wxRect focusRectBitmap;
534
535 if (page.bitmap.IsOk())
536 focusRectBitmap = wxRect(bitmap_offset, drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
537 page.bitmap.GetWidth(), page.bitmap.GetHeight());
538
539 if (page.bitmap.IsOk() && draw_text.IsEmpty())
540 focusRect = focusRectBitmap;
541 else if (!page.bitmap.IsOk() && !draw_text.IsEmpty())
542 focusRect = focusRectText;
543 else if (page.bitmap.IsOk() && !draw_text.IsEmpty())
544 focusRect = focusRectText.Union(focusRectBitmap);
545
546 focusRect.Inflate(2, 2);
547
548 wxRendererNative::Get().DrawFocusRect(wnd, dc, focusRect, 0);
549 }
550
551 // draw close button if necessary
552 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
553 {
554 wxBitmap bmp = m_disabledCloseBmp;
555
556 if (close_button_state == wxAUI_BUTTON_STATE_HOVER ||
557 close_button_state == wxAUI_BUTTON_STATE_PRESSED)
558 {
559 bmp = m_activeCloseBmp;
560 }
561
562 int offsetY = tab_y-1;
563 if (m_flags & wxAUI_NB_BOTTOM)
564 offsetY = 1;
565
566 wxRect rect(tab_x + tab_width - close_button_width - 1,
567 offsetY + (tab_height/2) - (bmp.GetHeight()/2),
568 close_button_width,
569 tab_height);
570
571 IndentPressedBitmap(&rect, close_button_state);
572 dc.DrawBitmap(bmp, rect.x, rect.y, true);
573
574 *out_button_rect = rect;
575 }
576
577 *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
578
579 dc.DestroyClippingRegion();
580 }
581
582 int wxAuiGenericTabArt::GetIndentSize()
583 {
584 return 5;
585 }
586
587 wxSize wxAuiGenericTabArt::GetTabSize(wxDC& dc,
588 wxWindow* WXUNUSED(wnd),
589 const wxString& caption,
590 const wxBitmap& bitmap,
591 bool WXUNUSED(active),
592 int close_button_state,
593 int* x_extent)
594 {
595 wxCoord measured_textx, measured_texty, tmp;
596
597 dc.SetFont(m_measuringFont);
598 dc.GetTextExtent(caption, &measured_textx, &measured_texty);
599
600 dc.GetTextExtent(wxT("ABCDEFXj"), &tmp, &measured_texty);
601
602 // add padding around the text
603 wxCoord tab_width = measured_textx;
604 wxCoord tab_height = measured_texty;
605
606 // if the close button is showing, add space for it
607 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
608 tab_width += m_activeCloseBmp.GetWidth() + 3;
609
610 // if there's a bitmap, add space for it
611 if (bitmap.IsOk())
612 {
613 tab_width += bitmap.GetWidth();
614 tab_width += 3; // right side bitmap padding
615 tab_height = wxMax(tab_height, bitmap.GetHeight());
616 }
617
618 // add padding
619 tab_width += 16;
620 tab_height += 10;
621
622 if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
623 {
624 tab_width = m_fixedTabWidth;
625 }
626
627 *x_extent = tab_width;
628
629 return wxSize(tab_width, tab_height);
630 }
631
632
633 void wxAuiGenericTabArt::DrawButton(wxDC& dc,
634 wxWindow* WXUNUSED(wnd),
635 const wxRect& in_rect,
636 int bitmap_id,
637 int button_state,
638 int orientation,
639 wxRect* out_rect)
640 {
641 wxBitmap bmp;
642 wxRect rect;
643
644 switch (bitmap_id)
645 {
646 case wxAUI_BUTTON_CLOSE:
647 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
648 bmp = m_disabledCloseBmp;
649 else
650 bmp = m_activeCloseBmp;
651 break;
652 case wxAUI_BUTTON_LEFT:
653 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
654 bmp = m_disabledLeftBmp;
655 else
656 bmp = m_activeLeftBmp;
657 break;
658 case wxAUI_BUTTON_RIGHT:
659 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
660 bmp = m_disabledRightBmp;
661 else
662 bmp = m_activeRightBmp;
663 break;
664 case wxAUI_BUTTON_WINDOWLIST:
665 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
666 bmp = m_disabledWindowListBmp;
667 else
668 bmp = m_activeWindowListBmp;
669 break;
670 }
671
672
673 if (!bmp.IsOk())
674 return;
675
676 rect = in_rect;
677
678 if (orientation == wxLEFT)
679 {
680 rect.SetX(in_rect.x);
681 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
682 rect.SetWidth(bmp.GetWidth());
683 rect.SetHeight(bmp.GetHeight());
684 }
685 else
686 {
687 rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
688 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
689 bmp.GetWidth(), bmp.GetHeight());
690 }
691
692 IndentPressedBitmap(&rect, button_state);
693 dc.DrawBitmap(bmp, rect.x, rect.y, true);
694
695 *out_rect = rect;
696 }
697
698 int wxAuiGenericTabArt::ShowDropDown(wxWindow* wnd,
699 const wxAuiNotebookPageArray& pages,
700 int /*active_idx*/)
701 {
702 wxMenu menuPopup;
703
704 size_t i, count = pages.GetCount();
705 for (i = 0; i < count; ++i)
706 {
707 const wxAuiNotebookPage& page = pages.Item(i);
708 wxString caption = page.caption;
709
710 // if there is no caption, make it a space. This will prevent
711 // an assert in the menu code.
712 if (caption.IsEmpty())
713 caption = wxT(" ");
714
715 wxMenuItem* item = new wxMenuItem(NULL, 1000+i, caption);
716 if (page.bitmap.IsOk())
717 item->SetBitmap(page.bitmap);
718 menuPopup.Append(item);
719 }
720
721 // find out where to put the popup menu of window items
722 wxPoint pt = ::wxGetMousePosition();
723 pt = wnd->ScreenToClient(pt);
724
725 // find out the screen coordinate at the bottom of the tab ctrl
726 wxRect cli_rect = wnd->GetClientRect();
727 pt.y = cli_rect.y + cli_rect.height;
728
729 wxAuiCommandCapture* cc = new wxAuiCommandCapture;
730 wnd->PushEventHandler(cc);
731 wnd->PopupMenu(&menuPopup, pt);
732 int command = cc->GetCommandId();
733 wnd->PopEventHandler(true);
734
735 if (command >= 1000)
736 return command-1000;
737
738 return -1;
739 }
740
741 int wxAuiGenericTabArt::GetBestTabCtrlSize(wxWindow* wnd,
742 const wxAuiNotebookPageArray& pages,
743 const wxSize& requiredBmp_size)
744 {
745 wxClientDC dc(wnd);
746 dc.SetFont(m_measuringFont);
747
748 // sometimes a standard bitmap size needs to be enforced, especially
749 // if some tabs have bitmaps and others don't. This is important because
750 // it prevents the tab control from resizing when tabs are added.
751 wxBitmap measureBmp;
752 if (requiredBmp_size.IsFullySpecified())
753 {
754 measureBmp.Create(requiredBmp_size.x,
755 requiredBmp_size.y);
756 }
757
758
759 int max_y = 0;
760 size_t i, page_count = pages.GetCount();
761 for (i = 0; i < page_count; ++i)
762 {
763 wxAuiNotebookPage& page = pages.Item(i);
764
765 wxBitmap bmp;
766 if (measureBmp.IsOk())
767 bmp = measureBmp;
768 else
769 bmp = page.bitmap;
770
771 // we don't use the caption text because we don't
772 // want tab heights to be different in the case
773 // of a very short piece of text on one tab and a very
774 // tall piece of text on another tab
775 int x_ext = 0;
776 wxSize s = GetTabSize(dc,
777 wnd,
778 wxT("ABCDEFGHIj"),
779 bmp,
780 true,
781 wxAUI_BUTTON_STATE_HIDDEN,
782 &x_ext);
783
784 max_y = wxMax(max_y, s.y);
785 }
786
787 return max_y+2;
788 }
789
790 void wxAuiGenericTabArt::SetNormalFont(const wxFont& font)
791 {
792 m_normalFont = font;
793 }
794
795 void wxAuiGenericTabArt::SetSelectedFont(const wxFont& font)
796 {
797 m_selectedFont = font;
798 }
799
800 void wxAuiGenericTabArt::SetMeasuringFont(const wxFont& font)
801 {
802 m_measuringFont = font;
803 }
804
805 void wxAuiGenericTabArt::SetColour(const wxColour& colour)
806 {
807 m_baseColour = colour;
808 m_borderPen = wxPen(m_baseColour.ChangeLightness(75));
809 m_baseColourPen = wxPen(m_baseColour);
810 m_baseColourBrush = wxBrush(m_baseColour);
811 }
812
813 void wxAuiGenericTabArt::SetActiveColour(const wxColour& colour)
814 {
815 m_activeColour = colour;
816 }
817
818 // -- wxAuiSimpleTabArt class implementation --
819
820 wxAuiSimpleTabArt::wxAuiSimpleTabArt()
821 {
822 m_normalFont = *wxNORMAL_FONT;
823 m_selectedFont = *wxNORMAL_FONT;
824 m_selectedFont.SetWeight(wxBOLD);
825 m_measuringFont = m_selectedFont;
826
827 m_flags = 0;
828 m_fixedTabWidth = 100;
829
830 wxColour baseColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
831
832 wxColour backgroundColour = baseColour;
833 wxColour normaltabColour = baseColour;
834 wxColour selectedtabColour = *wxWHITE;
835
836 m_bkBrush = wxBrush(backgroundColour);
837 m_normalBkBrush = wxBrush(normaltabColour);
838 m_normalBkPen = wxPen(normaltabColour);
839 m_selectedBkBrush = wxBrush(selectedtabColour);
840 m_selectedBkPen = wxPen(selectedtabColour);
841
842 m_activeCloseBmp = wxAuiBitmapFromBits(close_bits, 16, 16, *wxBLACK);
843 m_disabledCloseBmp = wxAuiBitmapFromBits(close_bits, 16, 16, wxColour(128,128,128));
844
845 m_activeLeftBmp = wxAuiBitmapFromBits(left_bits, 16, 16, *wxBLACK);
846 m_disabledLeftBmp = wxAuiBitmapFromBits(left_bits, 16, 16, wxColour(128,128,128));
847
848 m_activeRightBmp = wxAuiBitmapFromBits(right_bits, 16, 16, *wxBLACK);
849 m_disabledRightBmp = wxAuiBitmapFromBits(right_bits, 16, 16, wxColour(128,128,128));
850
851 m_activeWindowListBmp = wxAuiBitmapFromBits(list_bits, 16, 16, *wxBLACK);
852 m_disabledWindowListBmp = wxAuiBitmapFromBits(list_bits, 16, 16, wxColour(128,128,128));
853
854 }
855
856 wxAuiSimpleTabArt::~wxAuiSimpleTabArt()
857 {
858 }
859
860 wxAuiTabArt* wxAuiSimpleTabArt::Clone()
861 {
862 return new wxAuiSimpleTabArt(*this);
863 }
864
865 void wxAuiSimpleTabArt::SetFlags(unsigned int flags)
866 {
867 m_flags = flags;
868 }
869
870 void wxAuiSimpleTabArt::SetSizingInfo(const wxSize& tab_ctrl_size,
871 size_t tab_count)
872 {
873 m_fixedTabWidth = 100;
874
875 int tot_width = (int)tab_ctrl_size.x - GetIndentSize() - 4;
876
877 if (m_flags & wxAUI_NB_CLOSE_BUTTON)
878 tot_width -= m_activeCloseBmp.GetWidth();
879 if (m_flags & wxAUI_NB_WINDOWLIST_BUTTON)
880 tot_width -= m_activeWindowListBmp.GetWidth();
881
882 if (tab_count > 0)
883 {
884 m_fixedTabWidth = tot_width/(int)tab_count;
885 }
886
887
888 if (m_fixedTabWidth < 100)
889 m_fixedTabWidth = 100;
890
891 if (m_fixedTabWidth > tot_width/2)
892 m_fixedTabWidth = tot_width/2;
893
894 if (m_fixedTabWidth > 220)
895 m_fixedTabWidth = 220;
896 }
897
898 void wxAuiSimpleTabArt::SetColour(const wxColour& colour)
899 {
900 m_bkBrush = wxBrush(colour);
901 m_normalBkBrush = wxBrush(colour);
902 m_normalBkPen = wxPen(colour);
903 }
904
905 void wxAuiSimpleTabArt::SetActiveColour(const wxColour& colour)
906 {
907 m_selectedBkBrush = wxBrush(colour);
908 m_selectedBkPen = wxPen(colour);
909 }
910
911 void wxAuiSimpleTabArt::DrawBackground(wxDC& dc,
912 wxWindow* WXUNUSED(wnd),
913 const wxRect& rect)
914 {
915 // draw background
916 dc.SetBrush(m_bkBrush);
917 dc.SetPen(*wxTRANSPARENT_PEN);
918 dc.DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2);
919
920 // draw base line
921 dc.SetPen(*wxGREY_PEN);
922 dc.DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1);
923 }
924
925
926 // DrawTab() draws an individual tab.
927 //
928 // dc - output dc
929 // in_rect - rectangle the tab should be confined to
930 // caption - tab's caption
931 // active - whether or not the tab is active
932 // out_rect - actual output rectangle
933 // x_extent - the advance x; where the next tab should start
934
935 void wxAuiSimpleTabArt::DrawTab(wxDC& dc,
936 wxWindow* wnd,
937 const wxAuiNotebookPage& page,
938 const wxRect& in_rect,
939 int close_button_state,
940 wxRect* out_tab_rect,
941 wxRect* out_button_rect,
942 int* x_extent)
943 {
944 wxCoord normal_textx, normal_texty;
945 wxCoord selected_textx, selected_texty;
946 wxCoord textx, texty;
947
948 // if the caption is empty, measure some temporary text
949 wxString caption = page.caption;
950 if (caption.empty())
951 caption = wxT("Xj");
952
953 dc.SetFont(m_selectedFont);
954 dc.GetTextExtent(caption, &selected_textx, &selected_texty);
955
956 dc.SetFont(m_normalFont);
957 dc.GetTextExtent(caption, &normal_textx, &normal_texty);
958
959 // figure out the size of the tab
960 wxSize tab_size = GetTabSize(dc,
961 wnd,
962 page.caption,
963 page.bitmap,
964 page.active,
965 close_button_state,
966 x_extent);
967
968 wxCoord tab_height = tab_size.y;
969 wxCoord tab_width = tab_size.x;
970 wxCoord tab_x = in_rect.x;
971 wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
972
973 caption = page.caption;
974
975 // select pen, brush and font for the tab to be drawn
976
977 if (page.active)
978 {
979 dc.SetPen(m_selectedBkPen);
980 dc.SetBrush(m_selectedBkBrush);
981 dc.SetFont(m_selectedFont);
982 textx = selected_textx;
983 texty = selected_texty;
984 }
985 else
986 {
987 dc.SetPen(m_normalBkPen);
988 dc.SetBrush(m_normalBkBrush);
989 dc.SetFont(m_normalFont);
990 textx = normal_textx;
991 texty = normal_texty;
992 }
993
994
995 // -- draw line --
996
997 wxPoint points[7];
998 points[0].x = tab_x;
999 points[0].y = tab_y + tab_height - 1;
1000 points[1].x = tab_x + tab_height - 3;
1001 points[1].y = tab_y + 2;
1002 points[2].x = tab_x + tab_height + 3;
1003 points[2].y = tab_y;
1004 points[3].x = tab_x + tab_width - 2;
1005 points[3].y = tab_y;
1006 points[4].x = tab_x + tab_width;
1007 points[4].y = tab_y + 2;
1008 points[5].x = tab_x + tab_width;
1009 points[5].y = tab_y + tab_height - 1;
1010 points[6] = points[0];
1011
1012 dc.SetClippingRegion(in_rect);
1013
1014 dc.DrawPolygon(WXSIZEOF(points) - 1, points);
1015
1016 dc.SetPen(*wxGREY_PEN);
1017
1018 //dc.DrawLines(active ? WXSIZEOF(points) - 1 : WXSIZEOF(points), points);
1019 dc.DrawLines(WXSIZEOF(points), points);
1020
1021
1022 int text_offset;
1023
1024 int close_button_width = 0;
1025 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
1026 {
1027 close_button_width = m_activeCloseBmp.GetWidth();
1028 text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2);
1029 }
1030 else
1031 {
1032 text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2);
1033 }
1034
1035 // set minimum text offset
1036 if (text_offset < tab_x + tab_height)
1037 text_offset = tab_x + tab_height;
1038
1039 // chop text if necessary
1040 wxString draw_text = wxAuiChopText(dc,
1041 caption,
1042 tab_width - (text_offset-tab_x) - close_button_width);
1043
1044 // draw tab text
1045 dc.DrawText(draw_text,
1046 text_offset,
1047 (tab_y + tab_height)/2 - (texty/2) + 1);
1048
1049
1050 // draw focus rectangle
1051 if (page.active && (wnd->FindFocus() == wnd))
1052 {
1053 wxRect focusRect(text_offset, ((tab_y + tab_height)/2 - (texty/2) + 1),
1054 selected_textx, selected_texty);
1055
1056 focusRect.Inflate(2, 2);
1057
1058 wxRendererNative::Get().DrawFocusRect(wnd, dc, focusRect, 0);
1059 }
1060
1061 // draw close button if necessary
1062 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
1063 {
1064 wxBitmap bmp;
1065 if (page.active)
1066 bmp = m_activeCloseBmp;
1067 else
1068 bmp = m_disabledCloseBmp;
1069
1070 wxRect rect(tab_x + tab_width - close_button_width - 1,
1071 tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
1072 close_button_width,
1073 tab_height - 1);
1074 DrawButtons(dc, rect, bmp, *wxWHITE, close_button_state);
1075
1076 *out_button_rect = rect;
1077 }
1078
1079
1080 *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
1081
1082 dc.DestroyClippingRegion();
1083 }
1084
1085 int wxAuiSimpleTabArt::GetIndentSize()
1086 {
1087 return 0;
1088 }
1089
1090 wxSize wxAuiSimpleTabArt::GetTabSize(wxDC& dc,
1091 wxWindow* WXUNUSED(wnd),
1092 const wxString& caption,
1093 const wxBitmap& WXUNUSED(bitmap),
1094 bool WXUNUSED(active),
1095 int close_button_state,
1096 int* x_extent)
1097 {
1098 wxCoord measured_textx, measured_texty;
1099
1100 dc.SetFont(m_measuringFont);
1101 dc.GetTextExtent(caption, &measured_textx, &measured_texty);
1102
1103 wxCoord tab_height = measured_texty + 4;
1104 wxCoord tab_width = measured_textx + tab_height + 5;
1105
1106 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
1107 tab_width += m_activeCloseBmp.GetWidth();
1108
1109 if (m_flags & wxAUI_NB_TAB_FIXED_WIDTH)
1110 {
1111 tab_width = m_fixedTabWidth;
1112 }
1113
1114 *x_extent = tab_width - (tab_height/2) - 1;
1115
1116 return wxSize(tab_width, tab_height);
1117 }
1118
1119
1120 void wxAuiSimpleTabArt::DrawButton(wxDC& dc,
1121 wxWindow* WXUNUSED(wnd),
1122 const wxRect& in_rect,
1123 int bitmap_id,
1124 int button_state,
1125 int orientation,
1126 wxRect* out_rect)
1127 {
1128 wxBitmap bmp;
1129 wxRect rect;
1130
1131 switch (bitmap_id)
1132 {
1133 case wxAUI_BUTTON_CLOSE:
1134 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1135 bmp = m_disabledCloseBmp;
1136 else
1137 bmp = m_activeCloseBmp;
1138 break;
1139 case wxAUI_BUTTON_LEFT:
1140 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1141 bmp = m_disabledLeftBmp;
1142 else
1143 bmp = m_activeLeftBmp;
1144 break;
1145 case wxAUI_BUTTON_RIGHT:
1146 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1147 bmp = m_disabledRightBmp;
1148 else
1149 bmp = m_activeRightBmp;
1150 break;
1151 case wxAUI_BUTTON_WINDOWLIST:
1152 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
1153 bmp = m_disabledWindowListBmp;
1154 else
1155 bmp = m_activeWindowListBmp;
1156 break;
1157 }
1158
1159 if (!bmp.IsOk())
1160 return;
1161
1162 rect = in_rect;
1163
1164 if (orientation == wxLEFT)
1165 {
1166 rect.SetX(in_rect.x);
1167 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2));
1168 rect.SetWidth(bmp.GetWidth());
1169 rect.SetHeight(bmp.GetHeight());
1170 }
1171 else
1172 {
1173 rect = wxRect(in_rect.x + in_rect.width - bmp.GetWidth(),
1174 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
1175 bmp.GetWidth(), bmp.GetHeight());
1176 }
1177
1178
1179 DrawButtons(dc, rect, bmp, *wxWHITE, button_state);
1180
1181 *out_rect = rect;
1182 }
1183
1184 int wxAuiSimpleTabArt::ShowDropDown(wxWindow* wnd,
1185 const wxAuiNotebookPageArray& pages,
1186 int active_idx)
1187 {
1188 wxMenu menuPopup;
1189
1190 size_t i, count = pages.GetCount();
1191 for (i = 0; i < count; ++i)
1192 {
1193 const wxAuiNotebookPage& page = pages.Item(i);
1194 menuPopup.AppendCheckItem(1000+i, page.caption);
1195 }
1196
1197 if (active_idx != -1)
1198 {
1199 menuPopup.Check(1000+active_idx, true);
1200 }
1201
1202 // find out where to put the popup menu of window
1203 // items. Subtract 100 for now to center the menu
1204 // a bit, until a better mechanism can be implemented
1205 wxPoint pt = ::wxGetMousePosition();
1206 pt = wnd->ScreenToClient(pt);
1207 if (pt.x < 100)
1208 pt.x = 0;
1209 else
1210 pt.x -= 100;
1211
1212 // find out the screen coordinate at the bottom of the tab ctrl
1213 wxRect cli_rect = wnd->GetClientRect();
1214 pt.y = cli_rect.y + cli_rect.height;
1215
1216 wxAuiCommandCapture* cc = new wxAuiCommandCapture;
1217 wnd->PushEventHandler(cc);
1218 wnd->PopupMenu(&menuPopup, pt);
1219 int command = cc->GetCommandId();
1220 wnd->PopEventHandler(true);
1221
1222 if (command >= 1000)
1223 return command-1000;
1224
1225 return -1;
1226 }
1227
1228 int wxAuiSimpleTabArt::GetBestTabCtrlSize(wxWindow* wnd,
1229 const wxAuiNotebookPageArray& WXUNUSED(pages),
1230 const wxSize& WXUNUSED(requiredBmp_size))
1231 {
1232 wxClientDC dc(wnd);
1233 dc.SetFont(m_measuringFont);
1234 int x_ext = 0;
1235 wxSize s = GetTabSize(dc,
1236 wnd,
1237 wxT("ABCDEFGHIj"),
1238 wxNullBitmap,
1239 true,
1240 wxAUI_BUTTON_STATE_HIDDEN,
1241 &x_ext);
1242 return s.y+3;
1243 }
1244
1245 void wxAuiSimpleTabArt::SetNormalFont(const wxFont& font)
1246 {
1247 m_normalFont = font;
1248 }
1249
1250 void wxAuiSimpleTabArt::SetSelectedFont(const wxFont& font)
1251 {
1252 m_selectedFont = font;
1253 }
1254
1255 void wxAuiSimpleTabArt::SetMeasuringFont(const wxFont& font)
1256 {
1257 m_measuringFont = font;
1258 }
1259
1260 #endif // wxUSE_AUI