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