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