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