Remove obsolete VisualAge-related files.
[wxWidgets.git] / src / aui / tabartgtk.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/aui/tabartgtk.cpp
3 // Purpose: implementation of the wxAuiGTKTabArt
4 // Author: Jens Lody and Teodor Petrov
5 // Modified by:
6 // Created: 2012-03-23
7 // Copyright: (c) 2012 Jens Lody <jens@codeblocks.org>
8 // and Teodor Petrov
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_AUI
28
29 #ifndef WX_PRECOMP
30 #include "wx/dc.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33 #include "wx/image.h"
34 #endif
35
36 #include "wx/gtk/dc.h"
37 #include "wx/gtk/private.h"
38
39 #include <gtk/gtk.h>
40
41 #include "wx/aui/auibook.h"
42 #include "wx/aui/tabartgtk.h"
43 #include "wx/renderer.h"
44
45 namespace
46 {
47
48 static int s_CloseIconSize = 16; // default size
49
50 }
51
52 wxAuiGtkTabArt::wxAuiGtkTabArt()
53
54 {
55 }
56
57 wxAuiTabArt* wxAuiGtkTabArt::Clone()
58 {
59 wxAuiGtkTabArt* clone = new wxAuiGtkTabArt();
60
61 clone->SetNormalFont(m_normalFont);
62 clone->SetSelectedFont(m_normalFont);
63 clone->SetMeasuringFont(m_normalFont);
64
65 return clone;
66 }
67
68 void wxAuiGtkTabArt::DrawBackground(wxDC& dc, wxWindow* WXUNUSED(wnd), const wxRect& rect)
69 {
70 wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
71 GdkWindow* window = impldc->GetGDKWindow();
72
73 gtk_style_apply_default_background(gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget()),
74 window,
75 true,
76 GTK_STATE_NORMAL,
77 NULL,
78 rect.x, rect.y, rect.width, rect.height);
79 }
80
81 void wxAuiGtkTabArt::DrawBorder(wxDC& WXUNUSED(dc), wxWindow* wnd, const wxRect& rect)
82 {
83 int generic_border_width = wxAuiGenericTabArt::GetBorderWidth(wnd);
84
85 if (!wnd) return;
86 if (!wnd->m_wxwindow) return;
87 if (!gtk_widget_is_drawable(wnd->m_wxwindow)) return;
88
89 GtkStyle *style_notebook = gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget());
90
91 gtk_paint_box(style_notebook, wnd->GTKGetDrawingWindow(), GTK_STATE_NORMAL, GTK_SHADOW_OUT,
92 NULL, wnd->m_wxwindow,
93 const_cast<char*>("notebook"),
94 rect.x + generic_border_width + 1, rect.y + generic_border_width + 1,
95 rect.width - (generic_border_width + 1), rect.height - (generic_border_width + 1));
96 }
97
98 void ButtonStateAndShadow(int button_state, GtkStateType &state, GtkShadowType &shadow)
99 {
100
101 if (button_state & wxAUI_BUTTON_STATE_DISABLED)
102 {
103 state = GTK_STATE_INSENSITIVE;
104 shadow = GTK_SHADOW_ETCHED_IN;
105 }
106 else if (button_state & wxAUI_BUTTON_STATE_HOVER)
107 {
108 state = GTK_STATE_PRELIGHT;
109 shadow = GTK_SHADOW_OUT;
110 }
111 else if (button_state & wxAUI_BUTTON_STATE_PRESSED)
112 {
113 state = GTK_STATE_ACTIVE;
114 shadow = GTK_SHADOW_IN;
115 }
116 else
117 {
118 state = GTK_STATE_NORMAL;
119 shadow = GTK_SHADOW_OUT;
120 }
121 }
122
123 wxRect DrawCloseButton(wxDC& dc,
124 GtkWidget *widget,
125 int button_state,
126 wxRect const &in_rect,
127 int orientation,
128 GdkRectangle* clipRect)
129 {
130 GtkStyle *style_button = gtk_widget_get_style(wxGTKPrivate::GetButtonWidget());
131 int xthickness = style_button->xthickness;
132 int ythickness = style_button->ythickness;
133
134 wxBitmap bmp(gtk_widget_render_icon(widget, GTK_STOCK_CLOSE, GTK_ICON_SIZE_SMALL_TOOLBAR, "tab"));
135
136 if(bmp.GetWidth() != s_CloseIconSize || bmp.GetHeight() != s_CloseIconSize)
137 {
138 wxImage img = bmp.ConvertToImage();
139 img.Rescale(s_CloseIconSize, s_CloseIconSize);
140 bmp = img;
141 }
142
143 int button_size = s_CloseIconSize + 2 * xthickness;
144
145 wxRect out_rect;
146
147 if (orientation == wxLEFT)
148 out_rect.x = in_rect.x - ythickness;
149 else
150 out_rect.x = in_rect.x + in_rect.width - button_size - ythickness;
151
152 out_rect.y = in_rect.y + (in_rect.height - button_size) / 2;
153 out_rect.width = button_size;
154 out_rect.height = button_size;
155
156 wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
157 GdkWindow* window = impldc->GetGDKWindow();
158
159 if (button_state == wxAUI_BUTTON_STATE_HOVER)
160 {
161 gtk_paint_box(style_button, window,
162 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, clipRect, widget, "button",
163 out_rect.x, out_rect.y, out_rect.width, out_rect.height);
164 }
165 else if (button_state == wxAUI_BUTTON_STATE_PRESSED)
166 {
167 gtk_paint_box(style_button, window,
168 GTK_STATE_ACTIVE, GTK_SHADOW_IN, clipRect, widget, "button",
169 out_rect.x, out_rect.y, out_rect.width, out_rect.height);
170 }
171
172
173 dc.DrawBitmap(bmp, out_rect.x + xthickness, out_rect.y + ythickness, true);
174
175 return out_rect;
176 }
177
178 void wxAuiGtkTabArt::DrawTab(wxDC& dc, wxWindow* wnd, const wxAuiNotebookPage& page,
179 const wxRect& in_rect, int close_button_state, wxRect* out_tab_rect,
180 wxRect* out_button_rect, int* x_extent)
181 {
182 GtkWidget *widget = wnd->GetHandle();
183 GtkStyle *style_notebook = gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget());
184
185 wxRect const &window_rect = wnd->GetRect();
186
187 int focus_width = 0;
188
189 gtk_widget_style_get(wxGTKPrivate::GetNotebookWidget(),
190 "focus-line-width", &focus_width,
191 NULL);
192
193 int tab_pos;
194 if (m_flags &wxAUI_NB_BOTTOM)
195 tab_pos = wxAUI_NB_BOTTOM;
196 else //if (m_flags & wxAUI_NB_TOP) {}
197 tab_pos = wxAUI_NB_TOP;
198
199 // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
200 // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
201
202 // figure out the size of the tab
203 wxSize tab_size = GetTabSize(dc, wnd, page.caption, page.bitmap,
204 page.active, close_button_state, x_extent);
205
206 wxRect tab_rect = in_rect;
207 tab_rect.width = tab_size.x;
208 tab_rect.height = tab_size.y;
209 tab_rect.y += 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder;
210
211 if (page.active)
212 tab_rect.height += 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder;
213
214 int gap_rect_height = 10 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder;
215 int gap_rect_x = 1, gap_start = 0, gap_width = 0;
216 int gap_rect_y = tab_rect.y - gap_rect_height;
217 int gap_rect_width = window_rect.width;
218
219 switch (tab_pos)
220 {
221 case wxAUI_NB_TOP:
222 tab_rect.y -= 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder;
223 if (!page.active)
224 tab_rect.y += 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder;
225 gap_rect_y = tab_rect.y + tab_rect.height - GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder / 2;
226 // fall through
227 case wxAUI_NB_BOTTOM:
228 gap_start = tab_rect.x - GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder / 2;
229 gap_width = tab_rect.width;
230 break;
231 // TODO: case wxAUI_NB_LEFT: break;
232 // TODO: case wxAUI_NB_RIGHT: break;
233 }
234 tab_rect.y += GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder / 2;
235 gap_rect_y += GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder / 2;
236
237 int padding = focus_width + GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder;
238
239 int clip_width = tab_rect.width;
240 if (tab_rect.x + tab_rect.width > in_rect.x + in_rect.width)
241 clip_width = (in_rect.x + in_rect.width) - tab_rect.x;
242
243 dc.SetClippingRegion(tab_rect.x, tab_rect.y - GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder, clip_width, tab_rect.height + GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder);
244
245 GdkRectangle area;
246 area.x = tab_rect.x - GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder;
247 area.y = tab_rect.y - 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder;
248 area.width = clip_width + GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder;
249 area.height = tab_rect.height + 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder;
250
251 wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
252 GdkWindow* window = impldc->GetGDKWindow();
253
254 // Before drawing the active tab itself, draw a box without border, because some themes
255 // have transparent gaps and a line would be visible at the bottom of the tab
256 if (page.active)
257 gtk_paint_box(style_notebook, window, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
258 NULL, widget,
259 const_cast<char*>("notebook"),
260 gap_rect_x, gap_rect_y,
261 gap_rect_width, gap_rect_height);
262
263 if (tab_pos == wxAUI_NB_BOTTOM)
264 {
265 if (page.active)
266 {
267 gtk_paint_box_gap(style_notebook, window, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
268 NULL, widget,
269 const_cast<char*>("notebook"),
270 gap_rect_x, gap_rect_y,
271 gap_rect_width, gap_rect_height,
272 GTK_POS_BOTTOM, gap_start , gap_width);
273 }
274 gtk_paint_extension(style_notebook, window,
275 page.active ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE, GTK_SHADOW_OUT,
276 &area, widget,
277 const_cast<char*>("tab"),
278 tab_rect.x, tab_rect.y,
279 tab_rect.width, tab_rect.height,
280 GTK_POS_TOP);
281 }
282 else
283 {
284 if (page.active)
285 {
286 gtk_paint_box_gap(style_notebook, window, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
287 NULL, widget,
288 const_cast<char*>("notebook"),
289 gap_rect_x, gap_rect_y,
290 gap_rect_width, gap_rect_height,
291 GTK_POS_TOP, gap_start , gap_width);
292 }
293 gtk_paint_extension(style_notebook, window,
294 page.active ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE, GTK_SHADOW_OUT,
295 &area, widget,
296 const_cast<char*>("tab"),
297 tab_rect.x, tab_rect.y,
298 tab_rect.width, tab_rect.height,
299 GTK_POS_BOTTOM);
300 }
301
302 // After drawing the inactive tab itself, draw a box with the same dimensions as the gap-box,
303 // otherwise we don't get a gap-box, if the active tab is invisible
304 if (!page.active)
305 gtk_paint_box(style_notebook, window, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
306 NULL, widget,
307 const_cast<char*>("notebook"),
308 gap_rect_x, gap_rect_y,
309 gap_rect_width, gap_rect_height);
310
311 wxCoord textX = tab_rect.x + padding + style_notebook->xthickness;
312
313 int bitmap_offset = 0;
314 if (page.bitmap.IsOk())
315 {
316 bitmap_offset = textX;
317
318 // draw bitmap
319 int bitmapY = tab_rect.y +(tab_rect.height - page.bitmap.GetHeight()) / 2;
320 if(!page.active)
321 {
322 if (tab_pos == wxAUI_NB_TOP)
323 bitmapY += style_notebook->ythickness / 2;
324 else
325 bitmapY -= style_notebook->ythickness / 2;
326 }
327 dc.DrawBitmap(page.bitmap,
328 bitmap_offset,
329 bitmapY,
330 true);
331
332 textX += page.bitmap.GetWidth() + padding;
333 }
334
335 wxCoord textW, textH, textY;
336
337 dc.SetFont(m_normalFont);
338 dc.GetTextExtent(page.caption, &textW, &textH);
339 textY = tab_rect.y + (tab_rect.height - textH) / 2;
340 if(!page.active)
341 {
342 if (tab_pos == wxAUI_NB_TOP)
343 textY += style_notebook->ythickness / 2;
344 else
345 textY -= style_notebook->ythickness / 2;
346 }
347
348 // draw tab text
349 GdkColor text_colour = page.active ? style_notebook->fg[GTK_STATE_NORMAL] : style_notebook->fg[GTK_STATE_ACTIVE];
350 dc.SetTextForeground(wxColor(text_colour));
351 GdkRectangle focus_area;
352
353 int padding_focus = padding - focus_width;
354 focus_area.x = tab_rect.x + padding_focus;
355 focus_area.y = textY - focus_width;
356 focus_area.width = tab_rect.width - 2 * padding_focus;
357 focus_area.height = textH + 2 * focus_width;
358
359 if(page.active && (wnd->FindFocus() == wnd) && focus_area.x <= (area.x + area.width))
360 {
361 // clipping seems not to work here, so we we have to recalc the focus-area manually
362 if((focus_area.x + focus_area.width) > (area.x + area.width))
363 focus_area.width = area.x + area.width - focus_area.x + focus_width - GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder;
364 gtk_paint_focus (style_notebook, window,
365 GTK_STATE_ACTIVE, NULL, widget, "tab",
366 focus_area.x, focus_area.y, focus_area.width, focus_area.height);
367 }
368
369 dc.DrawText(page.caption, textX, textY);
370
371 // draw close-button on tab (if enabled)
372 if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
373 {
374 wxRect rect(tab_rect.x, tab_rect.y, tab_rect.width - style_notebook->xthickness, tab_rect.height);
375 if(!page.active)
376 {
377 if (tab_pos == wxAUI_NB_TOP)
378 rect.y += style_notebook->ythickness / 2;
379 else
380 rect.y -= style_notebook->ythickness / 2;
381 }
382 *out_button_rect = DrawCloseButton(dc, widget, close_button_state, rect, wxRIGHT, &area);
383 }
384
385 if ( clip_width < tab_rect.width )
386 tab_rect.width = clip_width;
387 *out_tab_rect = tab_rect;
388
389 dc.DestroyClippingRegion();
390 }
391
392 wxRect DrawSimpleArrow(wxDC& dc,
393 GtkWidget *widget,
394 int button_state,
395 wxRect const &in_rect,
396 int orientation,
397 GtkArrowType arrow_type)
398 {
399 int scroll_arrow_hlength, scroll_arrow_vlength;
400 gtk_widget_style_get(widget,
401 "scroll-arrow-hlength", &scroll_arrow_hlength,
402 "scroll-arrow-vlength", &scroll_arrow_vlength,
403 NULL);
404
405 GtkStateType state;
406 GtkShadowType shadow;
407 ButtonStateAndShadow(button_state, state, shadow);
408
409 wxRect out_rect;
410
411 if (orientation == wxLEFT)
412 out_rect.x = in_rect.x;
413 else
414 out_rect.x = in_rect.x + in_rect.width - scroll_arrow_hlength;
415 out_rect.y = (in_rect.y + in_rect.height - 3 * gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget())->ythickness - scroll_arrow_vlength) / 2;
416 out_rect.width = scroll_arrow_hlength;
417 out_rect.height = scroll_arrow_vlength;
418
419 wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
420 GdkWindow* window = impldc->GetGDKWindow();
421 gtk_paint_arrow (gtk_widget_get_style(wxGTKPrivate::GetButtonWidget()), window, state, shadow, NULL, widget, "notebook",
422 arrow_type, TRUE, out_rect.x, out_rect.y, out_rect.width, out_rect.height);
423
424 return out_rect;
425 }
426
427 void wxAuiGtkTabArt::DrawButton(wxDC& dc, wxWindow* wnd,
428 const wxRect& in_rect,
429 int bitmap_id,
430 int button_state,
431 int orientation,
432 wxRect* out_rect)
433 {
434 GtkWidget *widget = wnd->GetHandle();
435 wxRect rect = in_rect;
436 if (m_flags &wxAUI_NB_BOTTOM)
437 rect.y += 2 * gtk_widget_get_style(wxGTKPrivate::GetButtonWidget())->ythickness;
438
439 switch (bitmap_id)
440 {
441 case wxAUI_BUTTON_CLOSE:
442 rect.y -= 2 * gtk_widget_get_style(wxGTKPrivate::GetButtonWidget())->ythickness;
443 rect = DrawCloseButton(dc, widget, button_state, rect, orientation, NULL);
444 break;
445
446 case wxAUI_BUTTON_LEFT:
447 rect = DrawSimpleArrow(dc, widget, button_state, rect, orientation, GTK_ARROW_LEFT);
448 break;
449
450 case wxAUI_BUTTON_RIGHT:
451 rect = DrawSimpleArrow(dc, widget, button_state, rect, orientation, GTK_ARROW_RIGHT);
452 break;
453
454 case wxAUI_BUTTON_WINDOWLIST:
455 {
456 rect.height -= 4 * gtk_widget_get_style(wxGTKPrivate::GetButtonWidget())->ythickness;
457 rect.width = rect.height;
458 rect.x = in_rect.x + in_rect.width - rect.width;
459
460 if (button_state == wxAUI_BUTTON_STATE_HOVER)
461 wxRendererNative::Get().DrawComboBoxDropButton(wnd, dc, rect, wxCONTROL_CURRENT);
462 else if (button_state == wxAUI_BUTTON_STATE_PRESSED)
463 wxRendererNative::Get().DrawComboBoxDropButton(wnd, dc, rect, wxCONTROL_PRESSED);
464 else
465 wxRendererNative::Get().DrawDropArrow(wnd, dc, rect);
466 }
467 break;
468 }
469
470 *out_rect = rect;
471 }
472
473
474 int wxAuiGtkTabArt::GetBestTabCtrlSize(wxWindow* wnd,
475 const wxAuiNotebookPageArray& pages,
476 const wxSize& required_bmp_size)
477 {
478 SetMeasuringFont(m_normalFont);
479 SetSelectedFont(m_normalFont);
480 int tab_height = 3 * gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget())->ythickness + wxAuiGenericTabArt::GetBestTabCtrlSize(wnd, pages, required_bmp_size);
481 return tab_height;
482 }
483
484 int wxAuiGtkTabArt::GetBorderWidth(wxWindow* wnd)
485 {
486 return wxAuiGenericTabArt::GetBorderWidth(wnd) + wxMax(GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder,
487 GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder);
488 }
489
490 int wxAuiGtkTabArt::GetAdditionalBorderSpace(wxWindow* wnd)
491 {
492 return 2 * GetBorderWidth(wnd);
493 }
494
495 wxSize wxAuiGtkTabArt::GetTabSize(wxDC& dc,
496 wxWindow* wnd,
497 const wxString& caption,
498 const wxBitmap& bitmap,
499 bool active,
500 int close_button_state,
501 int* x_extent)
502 {
503 wxSize s = wxAuiGenericTabArt::GetTabSize(dc, wnd, caption, bitmap, active, close_button_state, x_extent);
504
505 int overlap = 0;
506 gtk_widget_style_get (wnd->GetHandle(),
507 "focus-line-width", &overlap,
508 NULL);
509 *x_extent -= overlap;
510 return s;
511 }
512 #endif // wxUSE_AUI