]> git.saurik.com Git - wxWidgets.git/blob - src/aui/dockart.cpp
prevent some obscure wxAUI crashes after DetachPane() is used (crashes only happen...
[wxWidgets.git] / src / aui / dockart.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/aui/dockart.cpp
3 // Purpose: wxaui: wx advanced user interface - docking window manager
4 // Author: Benjamin I. Williams
5 // Modified by:
6 // Created: 2005-05-17
7 // RCS-ID: $Id$
8 // Copyright: (C) Copyright 2005-2006, Kirix Corporation, All Rights Reserved
9 // Licence: wxWindows Library Licence, Version 3.1
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #if wxUSE_AUI
27
28 #include "wx/aui/framemanager.h"
29 #include "wx/aui/dockart.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/settings.h"
33 #include "wx/dcclient.h"
34 #include "wx/image.h"
35 #endif
36
37 #ifdef __WXMAC__
38 #include "wx/mac/private.h"
39 #endif
40
41 // -- wxDefaultDockArt class implementation --
42
43 // wxDefaultDockArt is an art provider class which does all of the drawing for
44 // wxFrameManager. This allows the library caller to customize the dock art
45 // (probably by deriving from this class), or to completely replace all drawing
46 // with custom dock art (probably by writing a new stand-alone class derived
47 // from the wxDockArt base class). The active dock art class can be set via
48 // wxFrameManager::SetDockArt()
49
50
51 // StepColour() it a utility function that simply darkens
52 // or lightens a color, based on the specified percentage
53 static wxColor StepColour(const wxColor& c, int percent)
54 {
55 int r = c.Red(), g = c.Green(), b = c.Blue();
56 return wxColour((unsigned char)wxMin((r*percent)/100,255),
57 (unsigned char)wxMin((g*percent)/100,255),
58 (unsigned char)wxMin((b*percent)/100,255));
59 }
60
61 static wxColor LightContrastColour(const wxColour& c)
62 {
63 int amount = 120;
64
65 // if the color is especially dark, then
66 // make the contrast even lighter
67 if (c.Red() < 128 && c.Green() < 128 && c.Blue() < 128)
68 amount = 160;
69
70 return StepColour(c, amount);
71 }
72
73 // BitmapFromBits() is a utility function that creates a
74 // masked bitmap from raw bits (XBM format)
75 static wxBitmap BitmapFromBits(const unsigned char bits[], int w, int h,
76 const wxColour& color)
77 {
78 wxImage img = wxBitmap((const char*)bits, w, h).ConvertToImage();
79 img.Replace(255,255,255,123,123,123);
80 img.Replace(0,0,0,color.Red(),color.Green(),color.Blue());
81 img.SetMaskColour(123,123,123);
82 return wxBitmap(img);
83 }
84
85
86 static void DrawGradientRectangle(wxDC& dc,
87 const wxRect& rect,
88 const wxColour& start_color,
89 const wxColour& end_color,
90 int direction)
91 {
92 int rd, gd, bd, high = 0;
93 rd = end_color.Red() - start_color.Red();
94 gd = end_color.Green() - start_color.Green();
95 bd = end_color.Blue() - start_color.Blue();
96
97 if (direction == wxAUI_GRADIENT_VERTICAL)
98 high = rect.GetHeight()-1;
99 else
100 high = rect.GetWidth()-1;
101
102 for (int i = 0; i <= high; ++i)
103 {
104 int r = start_color.Red() + ((i*rd*100)/high)/100;
105 int g = start_color.Green() + ((i*gd*100)/high)/100;
106 int b = start_color.Blue() + ((i*bd*100)/high)/100;
107
108 wxPen p(wxColor((unsigned char)r,
109 (unsigned char)g,
110 (unsigned char)b));
111 dc.SetPen(p);
112
113 if (direction == wxAUI_GRADIENT_VERTICAL)
114 dc.DrawLine(rect.x, rect.y+i, rect.x+rect.width, rect.y+i);
115 else
116 dc.DrawLine(rect.x+i, rect.y, rect.x+i, rect.y+rect.height);
117 }
118
119 }
120
121 wxDefaultDockArt::wxDefaultDockArt()
122 {
123 #ifdef __WXMAC__
124 wxBrush toolbarbrush;
125 toolbarbrush.MacSetTheme( kThemeBrushToolbarBackground );
126 wxColor base_color = toolbarbrush.GetColour();
127 #else
128 wxColor base_color = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
129 #endif
130
131 wxColor darker1_color = StepColour(base_color, 85);
132 wxColor darker2_color = StepColour(base_color, 70);
133 wxColor darker3_color = StepColour(base_color, 60);
134 wxColor darker4_color = StepColour(base_color, 50);
135 wxColor darker5_color = StepColour(base_color, 40);
136
137 m_active_caption_colour = LightContrastColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
138 m_active_caption_gradient_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT);
139 m_active_caption_text_colour = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
140 m_inactive_caption_colour = StepColour(darker1_color, 80);
141 m_inactive_caption_gradient_colour = darker1_color;
142 m_inactive_caption_text_colour = *wxBLACK;
143
144 #ifdef __WXMAC__
145 m_sash_brush = toolbarbrush;
146 m_background_brush = toolbarbrush;
147 m_gripper_brush = toolbarbrush;
148 #else
149 m_sash_brush = wxBrush(base_color);
150 m_background_brush = wxBrush(base_color);
151 m_gripper_brush = wxBrush(base_color);
152 #endif
153 m_border_pen = wxPen(darker2_color);
154 m_gripper_pen1 = wxPen(darker5_color);
155 m_gripper_pen2 = wxPen(darker3_color);
156 m_gripper_pen3 = *wxWHITE_PEN;
157
158 #ifdef __WXMAC__
159 m_caption_font = *wxSMALL_FONT;
160 #else
161 m_caption_font = wxFont(8, wxDEFAULT, wxNORMAL, wxNORMAL, FALSE);
162 #endif
163
164 // some built in bitmaps
165 #ifdef __WXMAC__
166 static unsigned char close_bits[]={
167 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x03, 0xF8, 0x01, 0xF0, 0x19, 0xF3,
168 0xB8, 0xE3, 0xF0, 0xE1, 0xE0, 0xE0, 0xF0, 0xE1, 0xB8, 0xE3, 0x19, 0xF3,
169 0x01, 0xF0, 0x03, 0xF8, 0x0F, 0xFE, 0xFF, 0xFF };
170 #else
171 static unsigned char close_bits[]={
172 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xcf,0xf9,
173 0x9f,0xfc,0x3f,0xfe,0x3f,0xfe,0x9f,0xfc,0xcf,0xf9,0xef,0xfb,
174 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
175 #endif
176
177 static unsigned char pin_bits[]={
178 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xfc,0xdf,0xfc,0xdf,0xfc,
179 0xdf,0xfc,0xdf,0xfc,0xdf,0xfc,0x0f,0xf8,0x7f,0xff,0x7f,0xff,
180 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
181
182 #ifdef __WXMAC__
183 m_inactive_close_bitmap = BitmapFromBits(close_bits, 16, 16, *wxWHITE);
184 #else
185 m_inactive_close_bitmap = BitmapFromBits(close_bits, 16, 16, m_inactive_caption_text_colour);
186 #endif
187 m_inactive_pin_bitmap = BitmapFromBits(pin_bits, 16, 16, m_inactive_caption_text_colour);
188 #ifdef __WXMAC__
189 m_active_close_bitmap = BitmapFromBits(close_bits, 16, 16, *wxWHITE );
190 #else
191 m_active_close_bitmap = BitmapFromBits(close_bits, 16, 16, m_active_caption_text_colour);
192 #endif
193 m_active_pin_bitmap = BitmapFromBits(pin_bits, 16, 16, m_active_caption_text_colour);
194
195 // default metric values
196 #ifdef __WXMAC__
197 SInt32 height;
198 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight , &height );
199 m_sash_size = height;
200 #else
201 m_sash_size = 4;
202 #endif
203 m_caption_size = 17;
204 m_border_size = 1;
205 m_button_size = 14;
206 m_gripper_size = 9;
207 m_gradient_type = wxAUI_GRADIENT_VERTICAL;
208 }
209
210 int wxDefaultDockArt::GetMetric(int id)
211 {
212 switch (id)
213 {
214 case wxAUI_ART_SASH_SIZE: return m_sash_size;
215 case wxAUI_ART_CAPTION_SIZE: return m_caption_size;
216 case wxAUI_ART_GRIPPER_SIZE: return m_gripper_size;
217 case wxAUI_ART_PANE_BORDER_SIZE: return m_border_size;
218 case wxAUI_ART_PANE_BUTTON_SIZE: return m_button_size;
219 case wxAUI_ART_GRADIENT_TYPE: return m_gradient_type;
220 default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break;
221 }
222
223 return 0;
224 }
225
226 void wxDefaultDockArt::SetMetric(int id, int new_val)
227 {
228 switch (id)
229 {
230 case wxAUI_ART_SASH_SIZE: m_sash_size = new_val; break;
231 case wxAUI_ART_CAPTION_SIZE: m_caption_size = new_val; break;
232 case wxAUI_ART_GRIPPER_SIZE: m_gripper_size = new_val; break;
233 case wxAUI_ART_PANE_BORDER_SIZE: m_border_size = new_val; break;
234 case wxAUI_ART_PANE_BUTTON_SIZE: m_button_size = new_val; break;
235 case wxAUI_ART_GRADIENT_TYPE: m_gradient_type = new_val; break;
236 default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break;
237 }
238 }
239
240 wxColour wxDefaultDockArt::GetColour(int id)
241 {
242 switch (id)
243 {
244 case wxAUI_ART_BACKGROUND_COLOUR: return m_background_brush.GetColour();
245 case wxAUI_ART_SASH_COLOUR: return m_sash_brush.GetColour();
246 case wxAUI_ART_INACTIVE_CAPTION_COLOUR: return m_inactive_caption_colour;
247 case wxAUI_ART_INACTIVE_CAPTION_GRADIENT_COLOUR: return m_inactive_caption_gradient_colour;
248 case wxAUI_ART_INACTIVE_CAPTION_TEXT_COLOUR: return m_inactive_caption_text_colour;
249 case wxAUI_ART_ACTIVE_CAPTION_COLOUR: return m_active_caption_colour;
250 case wxAUI_ART_ACTIVE_CAPTION_GRADIENT_COLOUR: return m_active_caption_gradient_colour;
251 case wxAUI_ART_ACTIVE_CAPTION_TEXT_COLOUR: return m_active_caption_text_colour;
252 case wxAUI_ART_BORDER_COLOUR: return m_border_pen.GetColour();
253 case wxAUI_ART_GRIPPER_COLOUR: return m_gripper_brush.GetColour();
254 default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break;
255 }
256
257 return wxColour();
258 }
259
260 void wxDefaultDockArt::SetColour(int id, const wxColor& colour)
261 {
262 switch (id)
263 {
264 case wxAUI_ART_BACKGROUND_COLOUR: m_background_brush.SetColour(colour); break;
265 case wxAUI_ART_SASH_COLOUR: m_sash_brush.SetColour(colour); break;
266 case wxAUI_ART_INACTIVE_CAPTION_COLOUR: m_inactive_caption_colour = colour; break;
267 case wxAUI_ART_INACTIVE_CAPTION_GRADIENT_COLOUR: m_inactive_caption_gradient_colour = colour; break;
268 case wxAUI_ART_INACTIVE_CAPTION_TEXT_COLOUR: m_inactive_caption_text_colour = colour; break;
269 case wxAUI_ART_ACTIVE_CAPTION_COLOUR: m_active_caption_colour = colour; break;
270 case wxAUI_ART_ACTIVE_CAPTION_GRADIENT_COLOUR: m_active_caption_gradient_colour = colour; break;
271 case wxAUI_ART_ACTIVE_CAPTION_TEXT_COLOUR: m_active_caption_text_colour = colour; break;
272 case wxAUI_ART_BORDER_COLOUR: m_border_pen.SetColour(colour); break;
273 case wxAUI_ART_GRIPPER_COLOUR:
274 m_gripper_brush.SetColour(colour);
275 m_gripper_pen1.SetColour(StepColour(colour, 40));
276 m_gripper_pen2.SetColour(StepColour(colour, 60));
277 break;
278 default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break;
279 }
280 }
281
282 void wxDefaultDockArt::SetFont(int id, const wxFont& font)
283 {
284 if (id == wxAUI_ART_CAPTION_FONT)
285 m_caption_font = font;
286 }
287
288 wxFont wxDefaultDockArt::GetFont(int id)
289 {
290 if (id == wxAUI_ART_CAPTION_FONT)
291 return m_caption_font;
292 return wxNullFont;
293 }
294
295 void wxDefaultDockArt::DrawSash(wxDC& dc, int, const wxRect& rect)
296 {
297 #ifdef __WXMAC__
298 HIRect splitterRect = CGRectMake( rect.x , rect.y , rect.width , rect.height );
299 CGContextRef cgContext ;
300 #if wxMAC_USE_CORE_GRAPHICS
301 cgContext = ((wxMacCGContext*)(dc.GetGraphicContext()))->GetNativeContext() ;
302 #else
303 Rect bounds ;
304 GetPortBounds( (CGrafPtr) dc.m_macPort , &bounds ) ;
305 QDBeginCGContext( (CGrafPtr) dc.m_macPort , &cgContext ) ;
306 CGContextTranslateCTM( cgContext , 0 , bounds.bottom - bounds.top ) ;
307 CGContextScaleCTM( cgContext , 1 , -1 ) ;
308 #endif
309
310 HIThemeSplitterDrawInfo drawInfo ;
311 drawInfo.version = 0 ;
312 drawInfo.state = kThemeStateActive ;
313 drawInfo.adornment = kHIThemeSplitterAdornmentNone ;
314 HIThemeDrawPaneSplitter( &splitterRect , &drawInfo , cgContext , kHIThemeOrientationNormal ) ;
315
316 #if wxMAC_USE_CORE_GRAPHICS
317 #else
318 QDEndCGContext( (CGrafPtr) dc.m_macPort , &cgContext ) ;
319 #endif
320
321 #else
322 dc.SetPen(*wxTRANSPARENT_PEN);
323 dc.SetBrush(m_sash_brush);
324 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
325 #endif
326 }
327
328
329 void wxDefaultDockArt::DrawBackground(wxDC& dc, int, const wxRect& rect)
330 {
331 dc.SetPen(*wxTRANSPARENT_PEN);
332 #ifdef __WXMAC__
333 // we have to clear first, otherwise we are drawing a light striped pattern
334 // over an already darker striped background
335 dc.SetBrush(*wxWHITE_BRUSH) ;
336 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
337 #endif
338 dc.SetBrush(m_background_brush);
339 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
340 }
341
342 void wxDefaultDockArt::DrawBorder(wxDC& dc, const wxRect& _rect,
343 wxPaneInfo& pane)
344 {
345 dc.SetPen(m_border_pen);
346 dc.SetBrush(*wxTRANSPARENT_BRUSH);
347
348 wxRect rect = _rect;
349 int i, border_width = GetMetric(wxAUI_ART_PANE_BORDER_SIZE);
350
351 if (pane.IsToolbar())
352 {
353 for (i = 0; i < border_width; ++i)
354 {
355 dc.SetPen(*wxWHITE_PEN);
356 dc.DrawLine(rect.x, rect.y, rect.x+rect.width, rect.y);
357 dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height);
358 dc.SetPen(m_border_pen);
359 dc.DrawLine(rect.x, rect.y+rect.height-1,
360 rect.x+rect.width, rect.y+rect.height-1);
361 dc.DrawLine(rect.x+rect.width-1, rect.y,
362 rect.x+rect.width-1, rect.y+rect.height);
363 rect.Deflate(1);
364 }
365 }
366 else
367 {
368 for (i = 0; i < border_width; ++i)
369 {
370 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
371 rect.Deflate(1);
372 }
373 }
374 }
375
376
377 void wxDefaultDockArt::DrawCaptionBackground(wxDC& dc, const wxRect& rect, bool active)
378 {
379 if (m_gradient_type == wxAUI_GRADIENT_NONE)
380 {
381 if (active)
382 dc.SetBrush(wxBrush(m_active_caption_colour));
383 else
384 dc.SetBrush(wxBrush(m_inactive_caption_colour));
385
386 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
387 }
388 else
389 {
390 if (active)
391 {
392 // on mac the gradients are expected to become darker from the top
393 #ifdef __WXMAC__
394 DrawGradientRectangle(dc, rect,
395 m_active_caption_gradient_colour,
396 m_active_caption_colour,
397 m_gradient_type);
398 #else
399 DrawGradientRectangle(dc, rect,
400 m_active_caption_colour,
401 m_active_caption_gradient_colour,
402 m_gradient_type);
403 #endif
404 }
405 else
406 {
407 // on mac the gradients are expected to become darker from the top
408 #ifdef __WXMAC__
409 DrawGradientRectangle(dc, rect,
410 m_inactive_caption_gradient_colour,
411 m_inactive_caption_colour,
412 m_gradient_type);
413 #else
414 DrawGradientRectangle(dc, rect,
415 m_inactive_caption_colour,
416 m_inactive_caption_gradient_colour,
417 m_gradient_type);
418 #endif
419 }
420 }
421 }
422
423
424 void wxDefaultDockArt::DrawCaption(wxDC& dc,
425 const wxString& text,
426 const wxRect& rect,
427 wxPaneInfo& pane)
428 {
429 dc.SetPen(*wxTRANSPARENT_PEN);
430 dc.SetFont(m_caption_font);
431
432 DrawCaptionBackground(dc, rect,
433 (pane.state & wxPaneInfo::optionActive)?true:false);
434
435 if (pane.state & wxPaneInfo::optionActive)
436 dc.SetTextForeground(m_active_caption_text_colour);
437 else
438 dc.SetTextForeground(m_inactive_caption_text_colour);
439
440
441 wxCoord w,h;
442 dc.GetTextExtent(wxT("ABCDEFHXfgkj"), &w, &h);
443
444 dc.SetClippingRegion(rect);
445 dc.DrawText(text, rect.x+3, rect.y+(rect.height/2)-(h/2)-1);
446 dc.DestroyClippingRegion();
447 }
448
449 void wxDefaultDockArt::DrawGripper(wxDC& dc,
450 const wxRect& rect,
451 wxPaneInfo& pane)
452 {
453 dc.SetPen(*wxTRANSPARENT_PEN);
454 dc.SetBrush(m_gripper_brush);
455
456 dc.DrawRectangle(rect.x, rect.y, rect.width,rect.height);
457
458 if (!pane.HasGripperTop())
459 {
460 int y = 5;
461 while (1)
462 {
463 dc.SetPen(m_gripper_pen1);
464 dc.DrawPoint(rect.x+3, rect.y+y);
465 dc.SetPen(m_gripper_pen2);
466 dc.DrawPoint(rect.x+3, rect.y+y+1);
467 dc.DrawPoint(rect.x+4, rect.y+y);
468 dc.SetPen(m_gripper_pen3);
469 dc.DrawPoint(rect.x+5, rect.y+y+1);
470 dc.DrawPoint(rect.x+5, rect.y+y+2);
471 dc.DrawPoint(rect.x+4, rect.y+y+2);
472
473 y += 4;
474 if (y > rect.GetHeight()-5)
475 break;
476 }
477 }
478 else
479 {
480 int x = 5;
481 while (1)
482 {
483 dc.SetPen(m_gripper_pen1);
484 dc.DrawPoint(rect.x+x, rect.y+3);
485 dc.SetPen(m_gripper_pen2);
486 dc.DrawPoint(rect.x+x+1, rect.y+3);
487 dc.DrawPoint(rect.x+x, rect.y+4);
488 dc.SetPen(m_gripper_pen3);
489 dc.DrawPoint(rect.x+x+1, rect.y+5);
490 dc.DrawPoint(rect.x+x+2, rect.y+5);
491 dc.DrawPoint(rect.x+x+2, rect.y+4);
492
493 x += 4;
494 if (x > rect.GetWidth()-5)
495 break;
496 }
497 }
498 }
499
500 void wxDefaultDockArt::DrawPaneButton(wxDC& dc,
501 int button,
502 int button_state,
503 const wxRect& _rect,
504 wxPaneInfo& pane)
505 {
506 wxRect rect = _rect;
507
508 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
509 {
510 rect.x++;
511 rect.y++;
512 }
513
514 if (button_state == wxAUI_BUTTON_STATE_HOVER ||
515 button_state == wxAUI_BUTTON_STATE_PRESSED)
516 {
517 if (pane.state & wxPaneInfo::optionActive)
518 {
519 dc.SetBrush(wxBrush(StepColour(m_active_caption_colour, 120)));
520 dc.SetPen(wxPen(StepColour(m_active_caption_colour, 70)));
521 }
522 else
523 {
524 dc.SetBrush(wxBrush(StepColour(m_inactive_caption_colour, 120)));
525 dc.SetPen(wxPen(StepColour(m_inactive_caption_colour, 70)));
526 }
527
528 // draw the background behind the button
529 dc.DrawRectangle(rect.x, rect.y, 15, 15);
530 }
531
532 wxBitmap bmp;
533 switch (button)
534 {
535 default:
536 case wxPaneInfo::buttonClose:
537 if (pane.state & wxPaneInfo::optionActive)
538 bmp = m_active_close_bitmap;
539 else
540 bmp = m_inactive_close_bitmap;
541 break;
542 case wxPaneInfo::buttonPin:
543 if (pane.state & wxPaneInfo::optionActive)
544 bmp = m_active_pin_bitmap;
545 else
546 bmp = m_inactive_pin_bitmap;
547 break;
548 }
549
550 // draw the button itself
551 dc.DrawBitmap(bmp, rect.x, rect.y, true);
552 }
553
554
555 #endif // wxUSE_AUI