1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/aui/tabartgtk.cpp
3 // Purpose: implementation of the wxAuiGTKTabArt
4 // Author: Jens Lody and Teodor Petrov
8 // Copyright: (c) 2012 Jens Lody <jens@codeblocks.org>
10 // Licence: wxWindows licence
11 ///////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
32 #include "wx/dcclient.h"
33 #include "wx/settings.h"
37 #include "wx/gtk/dc.h"
38 #include "wx/gtk/private.h"
42 #include "wx/aui/auibook.h"
43 #include "wx/aui/tabartgtk.h"
44 #include "wx/renderer.h"
49 static int s_CloseIconSize
= 16; // default size
53 wxAuiGtkTabArt::wxAuiGtkTabArt()//:
62 wxAuiTabArt
* wxAuiGtkTabArt::Clone()
64 wxAuiGtkTabArt
* clone
= new wxAuiGtkTabArt();
66 clone
->SetNormalFont(m_normalFont
);
67 clone
->SetSelectedFont(m_normalFont
);
68 clone
->SetMeasuringFont(m_normalFont
);
73 void wxAuiGtkTabArt::DrawBackground(wxDC
& dc
, wxWindow
* WXUNUSED(wnd
), const wxRect
& rect
)
75 wxGTKDCImpl
*impldc
= (wxGTKDCImpl
*) dc
.GetImpl();
76 GdkWindow
* window
= impldc
->GetGDKWindow();
78 gtk_style_apply_default_background(gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget()),
83 rect
.x
, rect
.y
, rect
.width
, rect
.height
);
86 void ButtonStateAndShadow(int button_state
, GtkStateType
&state
, GtkShadowType
&shadow
)
89 if (button_state
& wxAUI_BUTTON_STATE_DISABLED
)
91 state
= GTK_STATE_INSENSITIVE
;
92 shadow
= GTK_SHADOW_ETCHED_IN
;
94 else if (button_state
& wxAUI_BUTTON_STATE_HOVER
)
96 state
= GTK_STATE_PRELIGHT
;
97 shadow
= GTK_SHADOW_OUT
;
99 else if (button_state
& wxAUI_BUTTON_STATE_PRESSED
)
101 state
= GTK_STATE_ACTIVE
;
102 shadow
= GTK_SHADOW_IN
;
106 state
= GTK_STATE_NORMAL
;
107 shadow
= GTK_SHADOW_OUT
;
111 wxRect
DrawCloseButton(wxDC
& dc
,
114 wxRect
const &in_rect
,
116 GdkRectangle
* clipRect
)
118 GtkStyle
*style_button
= gtk_widget_get_style(wxGTKPrivate::GetButtonWidget());
119 int xthickness
= style_button
->xthickness
;
120 int ythickness
= style_button
->ythickness
;
123 bmp
.SetPixbuf(gtk_widget_render_icon(widget
, GTK_STOCK_CLOSE
, GTK_ICON_SIZE_SMALL_TOOLBAR
, "tab"));
125 if(bmp
.GetWidth() != s_CloseIconSize
|| bmp
.GetHeight() != s_CloseIconSize
)
127 wxImage img
= bmp
.ConvertToImage();
128 img
.Rescale(s_CloseIconSize
, s_CloseIconSize
);
132 int button_size
= s_CloseIconSize
+ 2 * xthickness
;
136 if (orientation
== wxLEFT
)
137 out_rect
.x
= in_rect
.x
- ythickness
;
139 out_rect
.x
= in_rect
.x
+ in_rect
.width
- button_size
- ythickness
;
141 out_rect
.y
= in_rect
.y
+ (in_rect
.height
- button_size
) / 2;
142 out_rect
.width
= button_size
;
143 out_rect
.height
= button_size
;
145 wxGTKDCImpl
*impldc
= (wxGTKDCImpl
*) dc
.GetImpl();
146 GdkWindow
* window
= impldc
->GetGDKWindow();
148 if (button_state
== wxAUI_BUTTON_STATE_HOVER
)
150 gtk_paint_box(style_button
, window
,
151 GTK_STATE_PRELIGHT
, GTK_SHADOW_OUT
, clipRect
, widget
, "button",
152 out_rect
.x
, out_rect
.y
, out_rect
.width
, out_rect
.height
);
154 else if (button_state
== wxAUI_BUTTON_STATE_PRESSED
)
156 gtk_paint_box(style_button
, window
,
157 GTK_STATE_ACTIVE
, GTK_SHADOW_IN
, clipRect
, widget
, "button",
158 out_rect
.x
, out_rect
.y
, out_rect
.width
, out_rect
.height
);
162 dc
.DrawBitmap(bmp
, out_rect
.x
+ xthickness
, out_rect
.y
+ ythickness
, true);
167 void wxAuiGtkTabArt::DrawTab(wxDC
& dc
, wxWindow
* wnd
, const wxAuiNotebookPage
& page
,
168 const wxRect
& in_rect
, int close_button_state
, wxRect
* out_tab_rect
,
169 wxRect
* out_button_rect
, int* x_extent
)
171 GtkWidget
*widget
= wnd
->GetHandle();
172 GtkStyle
*style_notebook
= gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget());
174 wxRect
const &window_rect
= wnd
->GetRect();
178 gtk_widget_style_get(wxGTKPrivate::GetNotebookWidget(),
179 "focus-line-width", &focus_width
,
182 int gap_x
= 0, gap_width
= 0;
184 if (m_flags
&wxAUI_NB_BOTTOM
)
185 tab_pos
= wxAUI_NB_BOTTOM
;
186 else //if (m_flags & wxAUI_NB_TOP) {}
187 tab_pos
= wxAUI_NB_TOP
;
189 // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
190 // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
192 // figure out the size of the tab
193 wxSize tab_size
= GetTabSize(dc
, wnd
, page
.caption
, page
.bitmap
,
194 page
.active
, close_button_state
, x_extent
);
196 wxRect tab_rect
= in_rect
;
197 tab_rect
.width
= tab_size
.x
;
198 tab_rect
.height
= tab_size
.y
;
199 tab_rect
.y
+= 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
;
202 tab_rect
.height
+= 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
;
203 // if no bitmap is set, we need a tiny correction
204 if (! page
.bitmap
.IsOk())
205 tab_rect
.height
+= 1;
207 int gap_height
= 6 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
;
208 int gap_y
= tab_rect
.y
- gap_height
;
213 tab_rect
.y
-= 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
;
215 tab_rect
.y
+= 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
;
216 gap_y
= tab_rect
.y
+ tab_rect
.height
;
218 case wxAUI_NB_BOTTOM
:
219 gap_x
= tab_rect
.x
- GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder
/ 2;
220 gap_width
= tab_rect
.width
;
223 tab_rect
.y
+= GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
/ 2;
224 gap_y
+= GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
/ 2;
226 int padding
= focus_width
+ GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
;
228 int clip_width
= tab_rect
.width
;
229 if (tab_rect
.x
+ tab_rect
.width
> in_rect
.x
+ in_rect
.width
)
230 clip_width
= (in_rect
.x
+ in_rect
.width
) - tab_rect
.x
;
232 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
);
235 area
.x
= tab_rect
.x
- GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder
;
236 area
.y
= tab_rect
.y
- 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
;
237 area
.width
= clip_width
+ GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder
;
238 area
.height
= tab_rect
.height
+ 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
;
240 wxGTKDCImpl
*impldc
= (wxGTKDCImpl
*) dc
.GetImpl();
241 GdkWindow
* window
= impldc
->GetGDKWindow();
243 if (tab_pos
== wxAUI_NB_BOTTOM
)
247 gtk_paint_box_gap(style_notebook
, window
, GTK_STATE_NORMAL
, GTK_SHADOW_OUT
,
249 const_cast<char*>("notebook"),
250 window_rect
.x
, gap_y
,
251 window_rect
.width
, gap_height
,
252 GTK_POS_BOTTOM
, gap_x
, gap_width
);
254 gtk_paint_extension(style_notebook
, window
,
255 page
.active
? GTK_STATE_NORMAL
: GTK_STATE_ACTIVE
, GTK_SHADOW_OUT
,
257 const_cast<char*>("tab"),
258 tab_rect
.x
, tab_rect
.y
,
259 tab_rect
.width
, tab_rect
.height
,
266 gtk_paint_box_gap(style_notebook
, window
, GTK_STATE_NORMAL
, GTK_SHADOW_OUT
,
268 const_cast<char*>("notebook"),
269 window_rect
.x
, gap_y
,
270 window_rect
.width
, gap_height
,
271 GTK_POS_TOP
, gap_x
, gap_width
);
273 gtk_paint_extension(style_notebook
, window
,
274 page
.active
? GTK_STATE_NORMAL
: GTK_STATE_ACTIVE
, GTK_SHADOW_OUT
,
276 const_cast<char*>("tab"),
277 tab_rect
.x
, tab_rect
.y
,
278 tab_rect
.width
, tab_rect
.height
,
282 wxCoord textX
= tab_rect
.x
+ padding
+ style_notebook
->xthickness
;
284 int bitmap_offset
= 0;
285 if (page
.bitmap
.IsOk())
287 bitmap_offset
= textX
;
290 int bitmapY
= tab_rect
.y
+(tab_rect
.height
- page
.bitmap
.GetHeight()) / 2;
293 if (tab_pos
== wxAUI_NB_TOP
)
294 bitmapY
+= style_notebook
->ythickness
/ 2;
296 bitmapY
-= style_notebook
->ythickness
/ 2;
298 dc
.DrawBitmap(page
.bitmap
,
303 textX
+= page
.bitmap
.GetWidth() + padding
;
306 wxCoord textW
, textH
, textY
;
308 dc
.SetFont(m_normalFont
);
309 dc
.GetTextExtent(page
.caption
, &textW
, &textH
);
310 textY
= tab_rect
.y
+ (tab_rect
.height
- textH
) / 2;
313 if (tab_pos
== wxAUI_NB_TOP
)
314 textY
+= style_notebook
->ythickness
/ 2;
316 textY
-= style_notebook
->ythickness
/ 2;
320 GdkColor text_colour
= page
.active
? style_notebook
->fg
[GTK_STATE_NORMAL
] : style_notebook
->fg
[GTK_STATE_ACTIVE
];
321 dc
.SetTextForeground(wxColor(text_colour
));
322 GdkRectangle focus_area
;
324 int padding_focus
= padding
- focus_width
;
325 focus_area
.x
= tab_rect
.x
+ padding_focus
;
326 focus_area
.y
= textY
- focus_width
;
327 focus_area
.width
= tab_rect
.width
- 2 * padding_focus
;
328 focus_area
.height
= textH
+ 2 * focus_width
;
330 if(page
.active
&& (wnd
->FindFocus() == wnd
) && focus_area
.x
<= (area
.x
+ area
.width
))
332 // clipping seems not to work here, so we we have to recalc the focus-area manually
333 if((focus_area
.x
+ focus_area
.width
) > (area
.x
+ area
.width
))
334 focus_area
.width
= area
.x
+ area
.width
- focus_area
.x
+ focus_width
- GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder
;
335 gtk_paint_focus (style_notebook
, window
,
336 GTK_STATE_ACTIVE
, NULL
, widget
, "tab",
337 focus_area
.x
, focus_area
.y
, focus_area
.width
, focus_area
.height
);
340 dc
.DrawText(page
.caption
, textX
, textY
);
342 // draw close-button on tab (if enabled)
343 if (close_button_state
!= wxAUI_BUTTON_STATE_HIDDEN
)
345 wxRect
rect(tab_rect
.x
, tab_rect
.y
, tab_rect
.width
- style_notebook
->xthickness
, tab_rect
.height
);
348 if (tab_pos
== wxAUI_NB_TOP
)
349 rect
.y
+= style_notebook
->ythickness
/ 2;
351 rect
.y
-= style_notebook
->ythickness
/ 2;
353 *out_button_rect
= DrawCloseButton(dc
, widget
, close_button_state
, rect
, wxRIGHT
, &area
);
356 tab_rect
.width
= std::min(tab_rect
.width
, clip_width
);
357 *out_tab_rect
= tab_rect
;
359 dc
.DestroyClippingRegion();
362 wxRect
DrawSimpleArrow(wxDC
& dc
,
365 wxRect
const &in_rect
,
367 GtkArrowType arrow_type
)
369 int scroll_arrow_hlength
, scroll_arrow_vlength
;
370 gtk_widget_style_get(widget
,
371 "scroll-arrow-hlength", &scroll_arrow_hlength
,
372 "scroll-arrow-vlength", &scroll_arrow_vlength
,
376 GtkShadowType shadow
;
377 ButtonStateAndShadow(button_state
, state
, shadow
);
381 if (orientation
== wxLEFT
)
382 out_rect
.x
= in_rect
.x
;
384 out_rect
.x
= in_rect
.x
+ in_rect
.width
- scroll_arrow_hlength
;
385 out_rect
.y
= (in_rect
.y
+ in_rect
.height
- 3 * gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget())->ythickness
- scroll_arrow_vlength
) / 2;
386 out_rect
.width
= scroll_arrow_hlength
;
387 out_rect
.height
= scroll_arrow_vlength
;
389 wxGTKDCImpl
*impldc
= (wxGTKDCImpl
*) dc
.GetImpl();
390 GdkWindow
* window
= impldc
->GetGDKWindow();
391 gtk_paint_arrow (gtk_widget_get_style(wxGTKPrivate::GetButtonWidget()), window
, state
, shadow
, NULL
, widget
, "notebook",
392 arrow_type
, TRUE
, out_rect
.x
, out_rect
.y
, out_rect
.width
, out_rect
.height
);
397 void wxAuiGtkTabArt::DrawButton(wxDC
& dc
, wxWindow
* wnd
,
398 const wxRect
& in_rect
,
404 GtkWidget
*widget
= wnd
->GetHandle();
405 wxRect rect
= in_rect
;
406 if (m_flags
&wxAUI_NB_BOTTOM
)
407 rect
.y
+= 2 * gtk_widget_get_style(wxGTKPrivate::GetButtonWidget())->ythickness
;
411 case wxAUI_BUTTON_CLOSE
:
412 rect
.y
-= 2 * gtk_widget_get_style(wxGTKPrivate::GetButtonWidget())->ythickness
;
413 rect
= DrawCloseButton(dc
, widget
, button_state
, rect
, orientation
, NULL
);
416 case wxAUI_BUTTON_LEFT
:
417 rect
= DrawSimpleArrow(dc
, widget
, button_state
, rect
, orientation
, GTK_ARROW_LEFT
);
420 case wxAUI_BUTTON_RIGHT
:
421 rect
= DrawSimpleArrow(dc
, widget
, button_state
, rect
, orientation
, GTK_ARROW_RIGHT
);
424 case wxAUI_BUTTON_WINDOWLIST
:
426 rect
.height
-= 4 * gtk_widget_get_style(wxGTKPrivate::GetButtonWidget())->ythickness
;
427 rect
.width
= rect
.height
;
428 rect
.x
= in_rect
.x
+ in_rect
.width
- rect
.width
;
430 if (button_state
== wxAUI_BUTTON_STATE_HOVER
)
431 wxRendererNative::Get().DrawComboBoxDropButton(wnd
, dc
, rect
, wxCONTROL_CURRENT
);
432 else if (button_state
== wxAUI_BUTTON_STATE_PRESSED
)
433 wxRendererNative::Get().DrawComboBoxDropButton(wnd
, dc
, rect
, wxCONTROL_PRESSED
);
435 wxRendererNative::Get().DrawDropArrow(wnd
, dc
, rect
);
444 int wxAuiGtkTabArt::GetBestTabCtrlSize(wxWindow
* wnd
,
445 const wxAuiNotebookPageArray
& pages
,
446 const wxSize
& required_bmp_size
)
448 SetMeasuringFont(m_normalFont
);
449 SetSelectedFont(m_normalFont
);
450 int tab_height
= 3 * gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget())->ythickness
+ wxAuiGenericTabArt::GetBestTabCtrlSize(wnd
, pages
, required_bmp_size
);
454 wxSize
wxAuiGtkTabArt::GetTabSize(wxDC
& dc
,
456 const wxString
& caption
,
457 const wxBitmap
& bitmap
,
459 int close_button_state
,
462 wxSize s
= wxAuiGenericTabArt::GetTabSize(dc
, wnd
, caption
, bitmap
, active
, close_button_state
, x_extent
);
465 gtk_widget_style_get (wnd
->GetHandle(),
466 "focus-line-width", &overlap
,
468 *x_extent
-= overlap
;