Use close button used in wxMiniFrame.
[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 #if defined( __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 #elif defined( __WXGTK__)
171 static unsigned char close_bits[]={
172 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfb, 0xef, 0xdb, 0xed, 0x8b, 0xe8,
173 0x1b, 0xec, 0x3b, 0xee, 0x1b, 0xec, 0x8b, 0xe8, 0xdb, 0xed, 0xfb, 0xef,
174 0x07, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
175 #else
176 static unsigned char close_bits[]={
177 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xcf,0xf9,
178 0x9f,0xfc,0x3f,0xfe,0x3f,0xfe,0x9f,0xfc,0xcf,0xf9,0xef,0xfb,
179 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
180 #endif
181
182 static unsigned char pin_bits[]={
183 0xff,0xff,0xff,0xff,0xff,0xff,0x1f,0xfc,0xdf,0xfc,0xdf,0xfc,
184 0xdf,0xfc,0xdf,0xfc,0xdf,0xfc,0x0f,0xf8,0x7f,0xff,0x7f,0xff,
185 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
186
187 #ifdef __WXMAC__
188 m_inactive_close_bitmap = BitmapFromBits(close_bits, 16, 16, *wxWHITE);
189 #else
190 m_inactive_close_bitmap = BitmapFromBits(close_bits, 16, 16, m_inactive_caption_text_colour);
191 #endif
192 m_inactive_pin_bitmap = BitmapFromBits(pin_bits, 16, 16, m_inactive_caption_text_colour);
193 #ifdef __WXMAC__
194 m_active_close_bitmap = BitmapFromBits(close_bits, 16, 16, *wxWHITE );
195 #else
196 m_active_close_bitmap = BitmapFromBits(close_bits, 16, 16, m_active_caption_text_colour);
197 #endif
198 m_active_pin_bitmap = BitmapFromBits(pin_bits, 16, 16, m_active_caption_text_colour);
199
200 // default metric values
201 #ifdef __WXMAC__
202 SInt32 height;
203 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight , &height );
204 m_sash_size = height;
205 #else
206 m_sash_size = 4;
207 #endif
208 m_caption_size = 17;
209 m_border_size = 1;
210 m_button_size = 14;
211 m_gripper_size = 9;
212 m_gradient_type = wxAUI_GRADIENT_VERTICAL;
213 }
214
215 int wxDefaultDockArt::GetMetric(int id)
216 {
217 switch (id)
218 {
219 case wxAUI_ART_SASH_SIZE: return m_sash_size;
220 case wxAUI_ART_CAPTION_SIZE: return m_caption_size;
221 case wxAUI_ART_GRIPPER_SIZE: return m_gripper_size;
222 case wxAUI_ART_PANE_BORDER_SIZE: return m_border_size;
223 case wxAUI_ART_PANE_BUTTON_SIZE: return m_button_size;
224 case wxAUI_ART_GRADIENT_TYPE: return m_gradient_type;
225 default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break;
226 }
227
228 return 0;
229 }
230
231 void wxDefaultDockArt::SetMetric(int id, int new_val)
232 {
233 switch (id)
234 {
235 case wxAUI_ART_SASH_SIZE: m_sash_size = new_val; break;
236 case wxAUI_ART_CAPTION_SIZE: m_caption_size = new_val; break;
237 case wxAUI_ART_GRIPPER_SIZE: m_gripper_size = new_val; break;
238 case wxAUI_ART_PANE_BORDER_SIZE: m_border_size = new_val; break;
239 case wxAUI_ART_PANE_BUTTON_SIZE: m_button_size = new_val; break;
240 case wxAUI_ART_GRADIENT_TYPE: m_gradient_type = new_val; break;
241 default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break;
242 }
243 }
244
245 wxColour wxDefaultDockArt::GetColour(int id)
246 {
247 switch (id)
248 {
249 case wxAUI_ART_BACKGROUND_COLOUR: return m_background_brush.GetColour();
250 case wxAUI_ART_SASH_COLOUR: return m_sash_brush.GetColour();
251 case wxAUI_ART_INACTIVE_CAPTION_COLOUR: return m_inactive_caption_colour;
252 case wxAUI_ART_INACTIVE_CAPTION_GRADIENT_COLOUR: return m_inactive_caption_gradient_colour;
253 case wxAUI_ART_INACTIVE_CAPTION_TEXT_COLOUR: return m_inactive_caption_text_colour;
254 case wxAUI_ART_ACTIVE_CAPTION_COLOUR: return m_active_caption_colour;
255 case wxAUI_ART_ACTIVE_CAPTION_GRADIENT_COLOUR: return m_active_caption_gradient_colour;
256 case wxAUI_ART_ACTIVE_CAPTION_TEXT_COLOUR: return m_active_caption_text_colour;
257 case wxAUI_ART_BORDER_COLOUR: return m_border_pen.GetColour();
258 case wxAUI_ART_GRIPPER_COLOUR: return m_gripper_brush.GetColour();
259 default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break;
260 }
261
262 return wxColour();
263 }
264
265 void wxDefaultDockArt::SetColour(int id, const wxColor& colour)
266 {
267 switch (id)
268 {
269 case wxAUI_ART_BACKGROUND_COLOUR: m_background_brush.SetColour(colour); break;
270 case wxAUI_ART_SASH_COLOUR: m_sash_brush.SetColour(colour); break;
271 case wxAUI_ART_INACTIVE_CAPTION_COLOUR: m_inactive_caption_colour = colour; break;
272 case wxAUI_ART_INACTIVE_CAPTION_GRADIENT_COLOUR: m_inactive_caption_gradient_colour = colour; break;
273 case wxAUI_ART_INACTIVE_CAPTION_TEXT_COLOUR: m_inactive_caption_text_colour = colour; break;
274 case wxAUI_ART_ACTIVE_CAPTION_COLOUR: m_active_caption_colour = colour; break;
275 case wxAUI_ART_ACTIVE_CAPTION_GRADIENT_COLOUR: m_active_caption_gradient_colour = colour; break;
276 case wxAUI_ART_ACTIVE_CAPTION_TEXT_COLOUR: m_active_caption_text_colour = colour; break;
277 case wxAUI_ART_BORDER_COLOUR: m_border_pen.SetColour(colour); break;
278 case wxAUI_ART_GRIPPER_COLOUR:
279 m_gripper_brush.SetColour(colour);
280 m_gripper_pen1.SetColour(StepColour(colour, 40));
281 m_gripper_pen2.SetColour(StepColour(colour, 60));
282 break;
283 default: wxFAIL_MSG(wxT("Invalid Metric Ordinal")); break;
284 }
285 }
286
287 void wxDefaultDockArt::SetFont(int id, const wxFont& font)
288 {
289 if (id == wxAUI_ART_CAPTION_FONT)
290 m_caption_font = font;
291 }
292
293 wxFont wxDefaultDockArt::GetFont(int id)
294 {
295 if (id == wxAUI_ART_CAPTION_FONT)
296 return m_caption_font;
297 return wxNullFont;
298 }
299
300 void wxDefaultDockArt::DrawSash(wxDC& dc, int, const wxRect& rect)
301 {
302 #ifdef __WXMAC__
303 HIRect splitterRect = CGRectMake( rect.x , rect.y , rect.width , rect.height );
304 CGContextRef cgContext ;
305 #if wxMAC_USE_CORE_GRAPHICS
306 cgContext = ((wxMacCGContext*)(dc.GetGraphicContext()))->GetNativeContext() ;
307 #else
308 Rect bounds ;
309 GetPortBounds( (CGrafPtr) dc.m_macPort , &bounds ) ;
310 QDBeginCGContext( (CGrafPtr) dc.m_macPort , &cgContext ) ;
311 CGContextTranslateCTM( cgContext , 0 , bounds.bottom - bounds.top ) ;
312 CGContextScaleCTM( cgContext , 1 , -1 ) ;
313 #endif
314
315 HIThemeSplitterDrawInfo drawInfo ;
316 drawInfo.version = 0 ;
317 drawInfo.state = kThemeStateActive ;
318 drawInfo.adornment = kHIThemeSplitterAdornmentNone ;
319 HIThemeDrawPaneSplitter( &splitterRect , &drawInfo , cgContext , kHIThemeOrientationNormal ) ;
320
321 #if wxMAC_USE_CORE_GRAPHICS
322 #else
323 QDEndCGContext( (CGrafPtr) dc.m_macPort , &cgContext ) ;
324 #endif
325
326 #else
327 dc.SetPen(*wxTRANSPARENT_PEN);
328 dc.SetBrush(m_sash_brush);
329 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
330 #endif
331 }
332
333
334 void wxDefaultDockArt::DrawBackground(wxDC& dc, int, const wxRect& rect)
335 {
336 dc.SetPen(*wxTRANSPARENT_PEN);
337 #ifdef __WXMAC__
338 // we have to clear first, otherwise we are drawing a light striped pattern
339 // over an already darker striped background
340 dc.SetBrush(*wxWHITE_BRUSH) ;
341 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
342 #endif
343 dc.SetBrush(m_background_brush);
344 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
345 }
346
347 void wxDefaultDockArt::DrawBorder(wxDC& dc, const wxRect& _rect,
348 wxPaneInfo& pane)
349 {
350 dc.SetPen(m_border_pen);
351 dc.SetBrush(*wxTRANSPARENT_BRUSH);
352
353 wxRect rect = _rect;
354 int i, border_width = GetMetric(wxAUI_ART_PANE_BORDER_SIZE);
355
356 if (pane.IsToolbar())
357 {
358 for (i = 0; i < border_width; ++i)
359 {
360 dc.SetPen(*wxWHITE_PEN);
361 dc.DrawLine(rect.x, rect.y, rect.x+rect.width, rect.y);
362 dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height);
363 dc.SetPen(m_border_pen);
364 dc.DrawLine(rect.x, rect.y+rect.height-1,
365 rect.x+rect.width, rect.y+rect.height-1);
366 dc.DrawLine(rect.x+rect.width-1, rect.y,
367 rect.x+rect.width-1, rect.y+rect.height);
368 rect.Deflate(1);
369 }
370 }
371 else
372 {
373 for (i = 0; i < border_width; ++i)
374 {
375 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
376 rect.Deflate(1);
377 }
378 }
379 }
380
381
382 void wxDefaultDockArt::DrawCaptionBackground(wxDC& dc, const wxRect& rect, bool active)
383 {
384 if (m_gradient_type == wxAUI_GRADIENT_NONE)
385 {
386 if (active)
387 dc.SetBrush(wxBrush(m_active_caption_colour));
388 else
389 dc.SetBrush(wxBrush(m_inactive_caption_colour));
390
391 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
392 }
393 else
394 {
395 if (active)
396 {
397 // on mac the gradients are expected to become darker from the top
398 #ifdef __WXMAC__
399 DrawGradientRectangle(dc, rect,
400 m_active_caption_gradient_colour,
401 m_active_caption_colour,
402 m_gradient_type);
403 #else
404 DrawGradientRectangle(dc, rect,
405 m_active_caption_colour,
406 m_active_caption_gradient_colour,
407 m_gradient_type);
408 #endif
409 }
410 else
411 {
412 // on mac the gradients are expected to become darker from the top
413 #ifdef __WXMAC__
414 DrawGradientRectangle(dc, rect,
415 m_inactive_caption_gradient_colour,
416 m_inactive_caption_colour,
417 m_gradient_type);
418 #else
419 DrawGradientRectangle(dc, rect,
420 m_inactive_caption_colour,
421 m_inactive_caption_gradient_colour,
422 m_gradient_type);
423 #endif
424 }
425 }
426 }
427
428
429 void wxDefaultDockArt::DrawCaption(wxDC& dc,
430 const wxString& text,
431 const wxRect& rect,
432 wxPaneInfo& pane)
433 {
434 dc.SetPen(*wxTRANSPARENT_PEN);
435 dc.SetFont(m_caption_font);
436
437 DrawCaptionBackground(dc, rect,
438 (pane.state & wxPaneInfo::optionActive)?true:false);
439
440 if (pane.state & wxPaneInfo::optionActive)
441 dc.SetTextForeground(m_active_caption_text_colour);
442 else
443 dc.SetTextForeground(m_inactive_caption_text_colour);
444
445
446 wxCoord w,h;
447 dc.GetTextExtent(wxT("ABCDEFHXfgkj"), &w, &h);
448
449 dc.SetClippingRegion(rect);
450 dc.DrawText(text, rect.x+3, rect.y+(rect.height/2)-(h/2)-1);
451 dc.DestroyClippingRegion();
452 }
453
454 void wxDefaultDockArt::DrawGripper(wxDC& dc,
455 const wxRect& rect,
456 wxPaneInfo& pane)
457 {
458 dc.SetPen(*wxTRANSPARENT_PEN);
459 dc.SetBrush(m_gripper_brush);
460
461 dc.DrawRectangle(rect.x, rect.y, rect.width,rect.height);
462
463 if (!pane.HasGripperTop())
464 {
465 int y = 5;
466 while (1)
467 {
468 dc.SetPen(m_gripper_pen1);
469 dc.DrawPoint(rect.x+3, rect.y+y);
470 dc.SetPen(m_gripper_pen2);
471 dc.DrawPoint(rect.x+3, rect.y+y+1);
472 dc.DrawPoint(rect.x+4, rect.y+y);
473 dc.SetPen(m_gripper_pen3);
474 dc.DrawPoint(rect.x+5, rect.y+y+1);
475 dc.DrawPoint(rect.x+5, rect.y+y+2);
476 dc.DrawPoint(rect.x+4, rect.y+y+2);
477
478 y += 4;
479 if (y > rect.GetHeight()-5)
480 break;
481 }
482 }
483 else
484 {
485 int x = 5;
486 while (1)
487 {
488 dc.SetPen(m_gripper_pen1);
489 dc.DrawPoint(rect.x+x, rect.y+3);
490 dc.SetPen(m_gripper_pen2);
491 dc.DrawPoint(rect.x+x+1, rect.y+3);
492 dc.DrawPoint(rect.x+x, rect.y+4);
493 dc.SetPen(m_gripper_pen3);
494 dc.DrawPoint(rect.x+x+1, rect.y+5);
495 dc.DrawPoint(rect.x+x+2, rect.y+5);
496 dc.DrawPoint(rect.x+x+2, rect.y+4);
497
498 x += 4;
499 if (x > rect.GetWidth()-5)
500 break;
501 }
502 }
503 }
504
505 void wxDefaultDockArt::DrawPaneButton(wxDC& dc,
506 int button,
507 int button_state,
508 const wxRect& _rect,
509 wxPaneInfo& pane)
510 {
511 wxRect rect = _rect;
512
513 if (button_state == wxAUI_BUTTON_STATE_PRESSED)
514 {
515 rect.x++;
516 rect.y++;
517 }
518
519 if (button_state == wxAUI_BUTTON_STATE_HOVER ||
520 button_state == wxAUI_BUTTON_STATE_PRESSED)
521 {
522 if (pane.state & wxPaneInfo::optionActive)
523 {
524 dc.SetBrush(wxBrush(StepColour(m_active_caption_colour, 120)));
525 dc.SetPen(wxPen(StepColour(m_active_caption_colour, 70)));
526 }
527 else
528 {
529 dc.SetBrush(wxBrush(StepColour(m_inactive_caption_colour, 120)));
530 dc.SetPen(wxPen(StepColour(m_inactive_caption_colour, 70)));
531 }
532
533 // draw the background behind the button
534 dc.DrawRectangle(rect.x, rect.y, 15, 15);
535 }
536
537 wxBitmap bmp;
538 switch (button)
539 {
540 default:
541 case wxPaneInfo::buttonClose:
542 if (pane.state & wxPaneInfo::optionActive)
543 bmp = m_active_close_bitmap;
544 else
545 bmp = m_inactive_close_bitmap;
546 break;
547 case wxPaneInfo::buttonPin:
548 if (pane.state & wxPaneInfo::optionActive)
549 bmp = m_active_pin_bitmap;
550 else
551 bmp = m_inactive_pin_bitmap;
552 break;
553 }
554
555 // draw the button itself
556 dc.DrawBitmap(bmp, rect.x, rect.y, true);
557 }
558
559
560 #endif // wxUSE_AUI