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() 
  58 wxAuiTabArt
* wxAuiGtkTabArt::Clone() 
  60     wxAuiGtkTabArt
* clone 
= new wxAuiGtkTabArt(); 
  62     clone
->SetNormalFont(m_normalFont
); 
  63     clone
->SetSelectedFont(m_normalFont
); 
  64     clone
->SetMeasuringFont(m_normalFont
); 
  69 void wxAuiGtkTabArt::DrawBackground(wxDC
& dc
, wxWindow
* WXUNUSED(wnd
), const wxRect
& rect
) 
  71     wxGTKDCImpl 
*impldc 
= (wxGTKDCImpl
*) dc
.GetImpl(); 
  72     GdkWindow
* window 
= impldc
->GetGDKWindow(); 
  74     gtk_style_apply_default_background(gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget()), 
  79                                        rect
.x
, rect
.y
, rect
.width
, rect
.height
); 
  82 void wxAuiGtkTabArt::DrawBorder(wxDC
& WXUNUSED(dc
), wxWindow
* wnd
, const wxRect
& rect
) 
  84     int generic_border_width 
= wxAuiGenericTabArt::GetBorderWidth(wnd
); 
  87     if (!wnd
->m_wxwindow
) return; 
  88     if (!gtk_widget_is_drawable(wnd
->m_wxwindow
)) return; 
  90     GtkStyle 
*style_notebook 
= gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget()); 
  92     gtk_paint_box(style_notebook
, wnd
->GTKGetDrawingWindow(), GTK_STATE_NORMAL
, GTK_SHADOW_OUT
, 
  93                   NULL
, wnd
->m_wxwindow
, 
  94                   const_cast<char*>("notebook"), 
  95                   rect
.x 
+ generic_border_width 
+ 1, rect
.y 
+ generic_border_width 
+ 1, 
  96                   rect
.width 
- (generic_border_width 
+ 1), rect
.height 
- (generic_border_width 
+ 1)); 
  99 void ButtonStateAndShadow(int button_state
, GtkStateType 
&state
, GtkShadowType 
&shadow
) 
 102     if (button_state 
& wxAUI_BUTTON_STATE_DISABLED
) 
 104         state 
= GTK_STATE_INSENSITIVE
; 
 105         shadow 
= GTK_SHADOW_ETCHED_IN
; 
 107     else if (button_state 
& wxAUI_BUTTON_STATE_HOVER
) 
 109         state 
= GTK_STATE_PRELIGHT
; 
 110         shadow 
= GTK_SHADOW_OUT
; 
 112     else if (button_state 
& wxAUI_BUTTON_STATE_PRESSED
) 
 114         state 
= GTK_STATE_ACTIVE
; 
 115         shadow 
= GTK_SHADOW_IN
; 
 119         state 
= GTK_STATE_NORMAL
; 
 120         shadow 
= GTK_SHADOW_OUT
; 
 124 wxRect 
DrawCloseButton(wxDC
& dc
, 
 127                        wxRect 
const &in_rect
, 
 129                        GdkRectangle
* clipRect
) 
 131     GtkStyle 
*style_button 
= gtk_widget_get_style(wxGTKPrivate::GetButtonWidget()); 
 132     int xthickness 
= style_button
->xthickness
; 
 133     int ythickness 
= style_button
->ythickness
; 
 135     wxBitmap 
bmp(gtk_widget_render_icon(widget
, GTK_STOCK_CLOSE
, GTK_ICON_SIZE_SMALL_TOOLBAR
, "tab")); 
 137     if(bmp
.GetWidth() != s_CloseIconSize 
|| bmp
.GetHeight() != s_CloseIconSize
) 
 139         wxImage img 
= bmp
.ConvertToImage(); 
 140         img
.Rescale(s_CloseIconSize
, s_CloseIconSize
); 
 144     int button_size 
= s_CloseIconSize 
+ 2 * xthickness
; 
 148     if (orientation 
== wxLEFT
) 
 149         out_rect
.x 
= in_rect
.x 
- ythickness
; 
 151         out_rect
.x 
= in_rect
.x 
+ in_rect
.width 
- button_size 
- ythickness
; 
 153     out_rect
.y 
= in_rect
.y 
+ (in_rect
.height 
- button_size
) / 2; 
 154     out_rect
.width 
= button_size
; 
 155     out_rect
.height 
= button_size
; 
 157     wxGTKDCImpl 
*impldc 
= (wxGTKDCImpl
*) dc
.GetImpl(); 
 158     GdkWindow
* window 
= impldc
->GetGDKWindow(); 
 160     if (button_state 
== wxAUI_BUTTON_STATE_HOVER
) 
 162         gtk_paint_box(style_button
, window
, 
 163                       GTK_STATE_PRELIGHT
, GTK_SHADOW_OUT
, clipRect
, widget
, "button", 
 164                      out_rect
.x
, out_rect
.y
, out_rect
.width
, out_rect
.height
); 
 166     else if (button_state 
== wxAUI_BUTTON_STATE_PRESSED
) 
 168         gtk_paint_box(style_button
, window
, 
 169                       GTK_STATE_ACTIVE
, GTK_SHADOW_IN
, clipRect
, widget
, "button", 
 170                       out_rect
.x
, out_rect
.y
, out_rect
.width
, out_rect
.height
); 
 174     dc
.DrawBitmap(bmp
, out_rect
.x 
+ xthickness
, out_rect
.y 
+ ythickness
, true); 
 179 void wxAuiGtkTabArt::DrawTab(wxDC
& dc
, wxWindow
* wnd
, const wxAuiNotebookPage
& page
, 
 180                              const wxRect
& in_rect
, int close_button_state
, wxRect
* out_tab_rect
, 
 181                              wxRect
* out_button_rect
, int* x_extent
) 
 183     GtkWidget 
*widget 
= wnd
->GetHandle(); 
 184     GtkStyle 
*style_notebook 
= gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget()); 
 186     wxRect 
const &window_rect 
= wnd
->GetRect(); 
 190     gtk_widget_style_get(wxGTKPrivate::GetNotebookWidget(), 
 191                          "focus-line-width", &focus_width
, 
 195     if (m_flags 
&wxAUI_NB_BOTTOM
) 
 196         tab_pos 
= wxAUI_NB_BOTTOM
; 
 197     else //if (m_flags & wxAUI_NB_TOP) {} 
 198         tab_pos 
= wxAUI_NB_TOP
; 
 200     // TODO: else if (m_flags &wxAUI_NB_LEFT) {} 
 201     // TODO: else if (m_flags &wxAUI_NB_RIGHT) {} 
 203     // figure out the size of the tab 
 204     wxSize tab_size 
= GetTabSize(dc
, wnd
, page
.caption
, page
.bitmap
, 
 205                                     page
.active
, close_button_state
, x_extent
); 
 207     wxRect tab_rect 
= in_rect
; 
 208     tab_rect
.width 
= tab_size
.x
; 
 209     tab_rect
.height 
= tab_size
.y
; 
 210     tab_rect
.y 
+= 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
; 
 213         tab_rect
.height 
+= 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
; 
 215     int gap_rect_height 
= 10 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
; 
 216     int gap_rect_x 
= 1, gap_start 
= 0, gap_width 
= 0; 
 217     int gap_rect_y 
= tab_rect
.y 
- gap_rect_height
; 
 218     int gap_rect_width 
= window_rect
.width
; 
 223             tab_rect
.y 
-= 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
; 
 225                 tab_rect
.y 
+= 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
; 
 226             gap_rect_y 
= tab_rect
.y 
+ tab_rect
.height 
- GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder 
/ 2; 
 228         case wxAUI_NB_BOTTOM
: 
 229             gap_start 
= tab_rect
.x 
- GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder 
/ 2; 
 230             gap_width 
= tab_rect
.width
; 
 232         // TODO: case wxAUI_NB_LEFT: break; 
 233         // TODO: case wxAUI_NB_RIGHT: break; 
 235     tab_rect
.y 
+= GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder 
/ 2; 
 236     gap_rect_y 
+= GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder 
/ 2; 
 238     int padding 
= focus_width 
+ GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
; 
 240     int clip_width 
= tab_rect
.width
; 
 241     if (tab_rect
.x 
+ tab_rect
.width 
> in_rect
.x 
+ in_rect
.width
) 
 242         clip_width 
= (in_rect
.x 
+ in_rect
.width
) - tab_rect
.x
; 
 244     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
); 
 247     area
.x 
= tab_rect
.x 
- GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder
; 
 248     area
.y 
= tab_rect
.y 
- 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
; 
 249     area
.width 
= clip_width 
+ GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder
; 
 250     area
.height 
= tab_rect
.height 
+ 2 * GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
; 
 252     wxGTKDCImpl 
*impldc 
= (wxGTKDCImpl
*) dc
.GetImpl(); 
 253     GdkWindow
* window 
= impldc
->GetGDKWindow(); 
 255     // Before drawing the active tab itself, draw a box without border, because some themes 
 256     // have transparent gaps and a line would be visible at the bottom of the tab 
 258         gtk_paint_box(style_notebook
, window
, GTK_STATE_NORMAL
, GTK_SHADOW_NONE
, 
 260                       const_cast<char*>("notebook"), 
 261                       gap_rect_x
, gap_rect_y
, 
 262                       gap_rect_width
, gap_rect_height
); 
 264     if (tab_pos 
== wxAUI_NB_BOTTOM
) 
 268             gtk_paint_box_gap(style_notebook
, window
, GTK_STATE_NORMAL
, GTK_SHADOW_OUT
, 
 270                               const_cast<char*>("notebook"), 
 271                               gap_rect_x
, gap_rect_y
, 
 272                               gap_rect_width
, gap_rect_height
, 
 273                               GTK_POS_BOTTOM
, gap_start 
, gap_width
); 
 275         gtk_paint_extension(style_notebook
, window
, 
 276                            page
.active 
? GTK_STATE_NORMAL 
: GTK_STATE_ACTIVE
, GTK_SHADOW_OUT
, 
 278                            const_cast<char*>("tab"), 
 279                            tab_rect
.x
, tab_rect
.y
, 
 280                            tab_rect
.width
, tab_rect
.height
, 
 287             gtk_paint_box_gap(style_notebook
, window
, GTK_STATE_NORMAL
, GTK_SHADOW_OUT
, 
 289                               const_cast<char*>("notebook"), 
 290                               gap_rect_x
, gap_rect_y
, 
 291                               gap_rect_width
, gap_rect_height
, 
 292                               GTK_POS_TOP
, gap_start 
, gap_width
); 
 294         gtk_paint_extension(style_notebook
, window
, 
 295                            page
.active 
? GTK_STATE_NORMAL 
: GTK_STATE_ACTIVE
, GTK_SHADOW_OUT
, 
 297                            const_cast<char*>("tab"), 
 298                            tab_rect
.x
, tab_rect
.y
, 
 299                            tab_rect
.width
, tab_rect
.height
, 
 303     // After drawing the inactive tab itself, draw a box with the same dimensions as the gap-box, 
 304     // otherwise we don't get a gap-box, if the active tab is invisible 
 306         gtk_paint_box(style_notebook
, window
, GTK_STATE_NORMAL
, GTK_SHADOW_OUT
, 
 308                       const_cast<char*>("notebook"), 
 309                       gap_rect_x
, gap_rect_y
, 
 310                       gap_rect_width
, gap_rect_height
); 
 312     wxCoord textX 
= tab_rect
.x 
+ padding 
+ style_notebook
->xthickness
; 
 314     int bitmap_offset 
= 0; 
 315     if (page
.bitmap
.IsOk()) 
 317         bitmap_offset 
= textX
; 
 320         int bitmapY 
= tab_rect
.y 
+(tab_rect
.height 
- page
.bitmap
.GetHeight()) / 2; 
 323             if (tab_pos 
== wxAUI_NB_TOP
) 
 324                 bitmapY 
+= style_notebook
->ythickness 
/ 2; 
 326                 bitmapY 
-= style_notebook
->ythickness 
/ 2; 
 328         dc
.DrawBitmap(page
.bitmap
, 
 333         textX 
+= page
.bitmap
.GetWidth() + padding
; 
 336     wxCoord textW
, textH
, textY
; 
 338     dc
.SetFont(m_normalFont
); 
 339     dc
.GetTextExtent(page
.caption
, &textW
, &textH
); 
 340     textY 
= tab_rect
.y 
+ (tab_rect
.height 
- textH
) / 2; 
 343         if (tab_pos 
== wxAUI_NB_TOP
) 
 344             textY 
+= style_notebook
->ythickness 
/ 2; 
 346             textY 
-= style_notebook
->ythickness 
/ 2; 
 350     GdkColor text_colour 
= page
.active 
? style_notebook
->fg
[GTK_STATE_NORMAL
] : style_notebook
->fg
[GTK_STATE_ACTIVE
]; 
 351     dc
.SetTextForeground(wxColor(text_colour
)); 
 352     GdkRectangle focus_area
; 
 354     int padding_focus 
= padding 
- focus_width
; 
 355     focus_area
.x 
= tab_rect
.x 
+ padding_focus
; 
 356     focus_area
.y 
= textY 
- focus_width
; 
 357     focus_area
.width 
= tab_rect
.width 
- 2 * padding_focus
; 
 358     focus_area
.height 
= textH 
+ 2 * focus_width
; 
 360     if(page
.active 
&& (wnd
->FindFocus() == wnd
) && focus_area
.x 
<= (area
.x 
+ area
.width
)) 
 362         // clipping seems not to work here, so we we have to recalc the focus-area manually 
 363         if((focus_area
.x 
+ focus_area
.width
) > (area
.x 
+ area
.width
)) 
 364             focus_area
.width 
= area
.x 
+ area
.width 
- focus_area
.x 
+ focus_width 
- GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder
; 
 365         gtk_paint_focus (style_notebook
, window
, 
 366                          GTK_STATE_ACTIVE
, NULL
, widget
, "tab", 
 367                          focus_area
.x
, focus_area
.y
, focus_area
.width
, focus_area
.height
); 
 370     dc
.DrawText(page
.caption
, textX
, textY
); 
 372     // draw close-button on tab (if enabled) 
 373     if (close_button_state 
!= wxAUI_BUTTON_STATE_HIDDEN
) 
 375         wxRect 
rect(tab_rect
.x
, tab_rect
.y
, tab_rect
.width 
- style_notebook
->xthickness
, tab_rect
.height
); 
 378             if (tab_pos 
== wxAUI_NB_TOP
) 
 379                 rect
.y 
+= style_notebook
->ythickness 
/ 2; 
 381                 rect
.y 
-= style_notebook
->ythickness 
/ 2; 
 383         *out_button_rect 
= DrawCloseButton(dc
, widget
, close_button_state
, rect
, wxRIGHT
, &area
); 
 386     if ( clip_width 
< tab_rect
.width 
) 
 387         tab_rect
.width 
= clip_width
; 
 388     *out_tab_rect 
= tab_rect
; 
 390     dc
.DestroyClippingRegion(); 
 393 wxRect 
DrawSimpleArrow(wxDC
& dc
, 
 396                        wxRect 
const &in_rect
, 
 398                        GtkArrowType arrow_type
) 
 400     int scroll_arrow_hlength
, scroll_arrow_vlength
; 
 401     gtk_widget_style_get(widget
, 
 402                          "scroll-arrow-hlength", &scroll_arrow_hlength
, 
 403                          "scroll-arrow-vlength", &scroll_arrow_vlength
, 
 407     GtkShadowType shadow
; 
 408     ButtonStateAndShadow(button_state
, state
, shadow
); 
 412     if (orientation 
== wxLEFT
) 
 413         out_rect
.x 
= in_rect
.x
; 
 415         out_rect
.x 
= in_rect
.x 
+ in_rect
.width 
- scroll_arrow_hlength
; 
 416     out_rect
.y 
= (in_rect
.y 
+ in_rect
.height 
- 3 * gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget())->ythickness 
- scroll_arrow_vlength
) / 2; 
 417     out_rect
.width 
= scroll_arrow_hlength
; 
 418     out_rect
.height 
= scroll_arrow_vlength
; 
 420     wxGTKDCImpl 
*impldc 
= (wxGTKDCImpl
*) dc
.GetImpl(); 
 421     GdkWindow
* window 
= impldc
->GetGDKWindow(); 
 422     gtk_paint_arrow (gtk_widget_get_style(wxGTKPrivate::GetButtonWidget()), window
, state
, shadow
, NULL
, widget
, "notebook", 
 423                      arrow_type
, TRUE
, out_rect
.x
, out_rect
.y
, out_rect
.width
, out_rect
.height
); 
 428 void wxAuiGtkTabArt::DrawButton(wxDC
& dc
, wxWindow
* wnd
, 
 429                             const wxRect
& in_rect
, 
 435     GtkWidget 
*widget 
= wnd
->GetHandle(); 
 436     wxRect rect 
= in_rect
; 
 437     if (m_flags 
&wxAUI_NB_BOTTOM
) 
 438         rect
.y 
+= 2 * gtk_widget_get_style(wxGTKPrivate::GetButtonWidget())->ythickness
; 
 442         case wxAUI_BUTTON_CLOSE
: 
 443             rect
.y 
-= 2 * gtk_widget_get_style(wxGTKPrivate::GetButtonWidget())->ythickness
; 
 444             rect 
= DrawCloseButton(dc
, widget
, button_state
, rect
, orientation
, NULL
); 
 447         case wxAUI_BUTTON_LEFT
: 
 448             rect 
= DrawSimpleArrow(dc
, widget
, button_state
, rect
, orientation
, GTK_ARROW_LEFT
); 
 451         case wxAUI_BUTTON_RIGHT
: 
 452             rect 
= DrawSimpleArrow(dc
, widget
, button_state
, rect
, orientation
, GTK_ARROW_RIGHT
); 
 455         case wxAUI_BUTTON_WINDOWLIST
: 
 457                 rect
.height 
-= 4 * gtk_widget_get_style(wxGTKPrivate::GetButtonWidget())->ythickness
; 
 458                 rect
.width 
= rect
.height
; 
 459                 rect
.x 
= in_rect
.x 
+ in_rect
.width 
- rect
.width
; 
 461                 if (button_state 
== wxAUI_BUTTON_STATE_HOVER
) 
 462                     wxRendererNative::Get().DrawComboBoxDropButton(wnd
, dc
, rect
, wxCONTROL_CURRENT
); 
 463                 else if (button_state 
== wxAUI_BUTTON_STATE_PRESSED
) 
 464                     wxRendererNative::Get().DrawComboBoxDropButton(wnd
, dc
, rect
, wxCONTROL_PRESSED
); 
 466                     wxRendererNative::Get().DrawDropArrow(wnd
, dc
, rect
); 
 475 int wxAuiGtkTabArt::GetBestTabCtrlSize(wxWindow
* wnd
, 
 476                                    const wxAuiNotebookPageArray
& pages
, 
 477                                    const wxSize
& required_bmp_size
) 
 479     SetMeasuringFont(m_normalFont
); 
 480     SetSelectedFont(m_normalFont
); 
 481     int tab_height 
= 3 * gtk_widget_get_style(wxGTKPrivate::GetNotebookWidget())->ythickness 
+ wxAuiGenericTabArt::GetBestTabCtrlSize(wnd
, pages
, required_bmp_size
); 
 485 int wxAuiGtkTabArt::GetBorderWidth(wxWindow
* wnd
) 
 487     return wxAuiGenericTabArt::GetBorderWidth(wnd
) + wxMax(GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_hborder
, 
 488                                                            GTK_NOTEBOOK (wxGTKPrivate::GetNotebookWidget())->tab_vborder
); 
 491 int wxAuiGtkTabArt::GetAdditionalBorderSpace(wxWindow
* wnd
) 
 493     return 2 * GetBorderWidth(wnd
); 
 496 wxSize 
wxAuiGtkTabArt::GetTabSize(wxDC
& dc
, 
 498                               const wxString
& caption
, 
 499                               const wxBitmap
& bitmap
, 
 501                               int close_button_state
, 
 504     wxSize s 
= wxAuiGenericTabArt::GetTabSize(dc
, wnd
, caption
, bitmap
, active
, close_button_state
, x_extent
); 
 507     gtk_widget_style_get (wnd
->GetHandle(), 
 508         "focus-line-width", &overlap
, 
 510     *x_extent 
-= overlap
;