1 /*
2  * This file is part of the Code::Blocks IDE and licensed under the GNU General Public License, version 3
3  * http://www.gnu.org/licenses/gpl-3.0.html
4  */
5 
6 
7 #include <wx/window.h>
8 #include <wx/gdicmn.h>
9 #include <wx/string.h>
10 #include <wx/settings.h>
11 #include <wx/image.h>
12 #include "cbauibook.h"
13 #include "prep.h"
14 #include "notebookstyles.h"
15 
16 #if defined(__WXGTK__) && (USE_GTK_NOTEBOOK) && !wxCHECK_VERSION(3, 0, 0)
17     #define GSocket GLibSocket
18     #include <gtk/gtk.h>
19     #undef GSocket
20     #include <wx/artprov.h>
21     #include <wx/renderer.h>
22 #endif
23 
24 #include <wx/dc.h>
25 #include <wx/dcclient.h>
26 
27 // Some general constants:
28 namespace
29 {
30     const int c_vertical_border_padding = 4;
31 }
32 
33 /******************************************************************************
34 * Renderer for Microsoft (tm) Visual Studio 7.1 like tabs                     *
35 ******************************************************************************/
36 
NbStyleVC71()37 NbStyleVC71::NbStyleVC71() : wxAuiDefaultTabArt()
38 {
39 }
40 
Clone()41 wxAuiTabArt* NbStyleVC71::Clone()
42 {
43     NbStyleVC71* clone = new NbStyleVC71();
44 
45 #if wxCHECK_VERSION(3, 0, 0)
46     clone->SetNormalFont(m_normalFont);
47     clone->SetSelectedFont(m_selectedFont);
48     clone->SetMeasuringFont(m_measuringFont);
49 #else
50     clone->SetNormalFont(m_normal_font);
51     clone->SetSelectedFont(m_selected_font);
52     clone->SetMeasuringFont(m_measuring_font);
53 #endif
54 
55     return clone;
56 }
57 
DrawTab(wxDC & dc,wxWindow * wnd,const wxAuiNotebookPage & page,const wxRect & in_rect,int close_button_state,wxRect * out_tab_rect,wxRect * out_button_rect,int * x_extent)58 void NbStyleVC71::DrawTab(wxDC& dc, wxWindow* wnd,
59                             const wxAuiNotebookPage& page,
60                             const wxRect& in_rect, int close_button_state,
61                             wxRect* out_tab_rect, wxRect* out_button_rect,
62                             int* x_extent)
63 {
64     // Visual studio 7.1 style
65     // This code is based on the renderer included in wxFlatNotebook:
66     // http://svn.berlios.de/wsvn/codeblocks/trunk/src/sdk/wxFlatNotebook/src/wxFlatNotebook/renderer.cpp?rev=5106
67 
68     // figure out the size of the tab
69 
70     wxSize tab_size = GetTabSize(dc,
71                                  wnd,
72                                  page.caption,
73                                  page.bitmap,
74                                  page.active,
75                                  close_button_state,
76                                  x_extent);
77 
78 #if wxCHECK_VERSION(3, 0, 0)
79     wxCoord tab_height = m_tabCtrlHeight - 3;
80 #else
81     wxCoord tab_height = m_tab_ctrl_height - 3;
82 #endif
83     wxCoord tab_width = tab_size.x;
84     wxCoord tab_x = in_rect.x;
85     wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
86     int clip_width = tab_width;
87     if (tab_x + clip_width > in_rect.x + in_rect.width - 4)
88         clip_width = (in_rect.x + in_rect.width) - tab_x - 4;
89     dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3);
90     if(m_flags & wxAUI_NB_BOTTOM)
91         tab_y--;
92 
93     dc.SetPen((page.active) ? wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT)) : wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)));
94     dc.SetBrush((page.active) ? wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)) : wxBrush(*wxTRANSPARENT_BRUSH));
95 
96     if (page.active)
97     {
98 //        int tabH = (m_flags & wxAUI_NB_BOTTOM) ? tab_height - 5 : tab_height - 2;
99         int tabH = tab_height - 2;
100 
101         dc.DrawRectangle(tab_x, tab_y, tab_width, tabH);
102 
103         int rightLineY1 = (m_flags & wxAUI_NB_BOTTOM) ? c_vertical_border_padding - 2 : c_vertical_border_padding - 1;
104         int rightLineY2 = tabH + 3;
105         dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)));
106         dc.DrawLine(tab_x + tab_width - 1, rightLineY1 + 1, tab_x + tab_width - 1, rightLineY2);
107         if(m_flags & wxAUI_NB_BOTTOM)
108             dc.DrawLine(tab_x + 1, rightLineY2 - 3 , tab_x + tab_width - 1, rightLineY2 - 3);
109         dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW)));
110         dc.DrawLine(tab_x + tab_width , rightLineY1 , tab_x + tab_width, rightLineY2);
111         if(m_flags & wxAUI_NB_BOTTOM)
112             dc.DrawLine(tab_x , rightLineY2 - 2 , tab_x + tab_width, rightLineY2 - 2);
113 
114     }
115     else
116     {
117         // We dont draw a rectangle for non selected tabs, but only
118         // vertical line on the right
119         int blackLineY1 = (m_flags & wxAUI_NB_BOTTOM) ? c_vertical_border_padding + 2 : c_vertical_border_padding + 1;
120         int blackLineY2 = tab_height - 5;
121         dc.DrawLine(tab_x + tab_width, blackLineY1, tab_x + tab_width, blackLineY2);
122     }
123 
124     wxPoint border_points[2];
125     if (m_flags & wxAUI_NB_BOTTOM)
126     {
127         border_points[0] = wxPoint(tab_x, tab_y);
128         border_points[1] = wxPoint(tab_x, tab_y + tab_height - 6);
129     }
130     else // if (m_flags & wxAUI_NB_TOP)
131     {
132         border_points[0] = wxPoint(tab_x, tab_y + tab_height - 4);
133         border_points[1] = wxPoint(tab_x, tab_y + 2);
134     }
135 
136     int drawn_tab_yoff = border_points[1].y;
137     int drawn_tab_height = border_points[0].y - border_points[1].y;
138 
139     int text_offset = tab_x + 8;
140 
141     int bitmap_offset = 0;
142     if (page.bitmap.IsOk())
143     {
144         bitmap_offset = tab_x + 8;
145 
146         // draw bitmap
147         dc.DrawBitmap(page.bitmap,
148                       bitmap_offset,
149                       drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
150                       true);
151 
152         text_offset = bitmap_offset + page.bitmap.GetWidth();
153         text_offset += 3; // bitmap padding
154     }
155      else
156     {
157         text_offset = tab_x + 8;
158     }
159 
160 
161     // if the caption is empty, measure some temporary text
162     wxString caption = page.caption;
163     if (caption.empty())
164         caption = wxT("Xj");
165 
166     wxCoord textx;
167     wxCoord texty;
168     if (page.active)
169 #if wxCHECK_VERSION(3, 0, 0)
170         dc.SetFont(m_selectedFont);
171 #else
172         dc.SetFont(m_selected_font);
173 #endif
174     else
175 #if wxCHECK_VERSION(3, 0, 0)
176         dc.SetFont(m_normalFont);
177 #else
178         dc.SetFont(m_normal_font);
179 #endif
180     dc.GetTextExtent(caption, &textx, &texty);
181     // draw tab text
182     dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
183     dc.DrawText(page.caption, text_offset,
184                 drawn_tab_yoff + drawn_tab_height / 2 - texty / 2 - 1);
185 
186     // draw 'x' on tab (if enabled)
187     if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
188     {
189 #if wxCHECK_VERSION(3, 0, 0)
190         int close_button_width = m_activeCloseBmp.GetWidth();
191         wxBitmap bmp = m_disabledCloseBmp;
192 #else
193         int close_button_width = m_active_close_bmp.GetWidth();
194         wxBitmap bmp = m_disabled_close_bmp;
195 #endif
196 
197         if ((close_button_state == wxAUI_BUTTON_STATE_HOVER) ||
198                     (close_button_state == wxAUI_BUTTON_STATE_PRESSED))
199 #if wxCHECK_VERSION(3, 0, 0)
200             bmp = m_activeCloseBmp;
201 #else
202             bmp = m_active_close_bmp;
203 #endif
204 
205         wxRect rect(tab_x + tab_width - close_button_width - 3,
206                     drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2),
207                     close_button_width, tab_height);
208 
209         // Indent the button if it is pressed down:
210         if (close_button_state == wxAUI_BUTTON_STATE_PRESSED)
211         {
212             rect.x++;
213             rect.y++;
214         }
215         dc.DrawBitmap(bmp, rect.x, rect.y, true);
216         *out_button_rect = rect;
217     }
218 
219     *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
220     dc.DestroyClippingRegion();
221 }
222 
GetBestTabCtrlSize(wxWindow * wnd,const wxAuiNotebookPageArray & WXUNUSED (pages),const wxSize & WXUNUSED (required_bmp_size))223 int NbStyleVC71::GetBestTabCtrlSize(wxWindow* wnd,
224                                     const wxAuiNotebookPageArray& WXUNUSED(pages),
225                                     const wxSize& WXUNUSED(required_bmp_size))
226 {
227 //    m_requested_tabctrl_height = -1;
228 //    m_tab_ctrl_height = -1;
229     wxClientDC dc(wnd);
230 #if wxCHECK_VERSION(3, 0, 0)
231     dc.SetFont(m_measuringFont);
232 #else
233     dc.SetFont(m_measuring_font);
234 #endif
235     int x_ext = 0;
236     wxSize s = GetTabSize(dc, wnd, wxT("ABCDEFGHIj"), wxNullBitmap, true,
237                             wxAUI_BUTTON_STATE_HIDDEN, &x_ext);
238     return s.y + 4;
239 }
240 
NbStyleFF2()241 NbStyleFF2::NbStyleFF2() : wxAuiDefaultTabArt()
242 {
243 }
244 
Clone()245 wxAuiTabArt* NbStyleFF2::Clone()
246 {
247     NbStyleFF2* clone = new NbStyleFF2();
248 
249 #if wxCHECK_VERSION(3, 0, 0)
250     clone->SetNormalFont(m_normalFont);
251     clone->SetSelectedFont(m_selectedFont);
252     clone->SetMeasuringFont(m_measuringFont);
253 #else
254     clone->SetNormalFont(m_normal_font);
255     clone->SetSelectedFont(m_selected_font);
256     clone->SetMeasuringFont(m_measuring_font);
257 #endif
258 
259     return clone;
260 }
261 
DrawTab(wxDC & dc,wxWindow * wnd,const wxAuiNotebookPage & page,const wxRect & in_rect,int close_button_state,wxRect * out_tab_rect,wxRect * out_button_rect,int * x_extent)262 void NbStyleFF2::DrawTab(wxDC& dc, wxWindow* wnd,
263                             const wxAuiNotebookPage& page,
264                             const wxRect& in_rect, int close_button_state,
265                             wxRect* out_tab_rect, wxRect* out_button_rect,
266                             int* x_extent)
267 {
268 
269     // Firefox 2 style
270 
271     // figure out the size of the tab
272     wxSize tab_size = GetTabSize(dc, wnd, page.caption, page.bitmap,
273                                     page.active, close_button_state, x_extent);
274 
275 #if wxCHECK_VERSION(3, 0, 0)
276     wxCoord tab_height = m_tabCtrlHeight - 2;
277 #else
278     wxCoord tab_height = m_tab_ctrl_height - 2;
279 #endif
280     wxCoord tab_width = tab_size.x;
281     wxCoord tab_x = in_rect.x;
282     wxCoord tab_y = in_rect.y + in_rect.height - tab_height;
283 
284     int clip_width = tab_width;
285     if (tab_x + clip_width > in_rect.x + in_rect.width - 4)
286         clip_width = (in_rect.x + in_rect.width) - tab_x - 4;
287     dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3);
288 
289 	wxPoint tabPoints[7];
290 	int adjust = 0;
291     if (!page.active)
292     {
293         adjust = 1;
294     }
295 
296     tabPoints[0].x = tab_x + 3;
297     tabPoints[0].y = (m_flags & wxAUI_NB_BOTTOM) ? 3 : tab_height - 2;
298 
299     tabPoints[1].x = tabPoints[0].x;
300     tabPoints[1].y = (m_flags & wxAUI_NB_BOTTOM) ? tab_height - (c_vertical_border_padding + 2) - adjust : (c_vertical_border_padding + 2) + adjust;
301 
302     tabPoints[2].x = tabPoints[1].x+2;
303     tabPoints[2].y = (m_flags & wxAUI_NB_BOTTOM) ? tab_height - c_vertical_border_padding - adjust: c_vertical_border_padding + adjust;
304 
305     tabPoints[3].x = tab_x +tab_width - 2;
306     tabPoints[3].y = tabPoints[2].y;
307 
308     tabPoints[4].x = tabPoints[3].x + 2;
309     tabPoints[4].y = tabPoints[1].y;
310 
311     tabPoints[5].x = tabPoints[4].x;
312     tabPoints[5].y = tabPoints[0].y;
313 
314     tabPoints[6].x = tabPoints[0].x;
315     tabPoints[6].y = tabPoints[0].y;
316 
317 //    dc.SetBrush((page.active) ? wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)) : wxBrush(wxAuiStepColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE),85)));
318     dc.SetBrush((page.active) ? wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)) : wxBrush(*wxTRANSPARENT_BRUSH));
319 
320 	dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW)));
321 
322 	dc.DrawPolygon(7, tabPoints);
323 
324     dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)));
325     if (page.active)
326     {
327         dc.DrawLine(tabPoints[0].x + 1, tabPoints[0].y, tabPoints[5].x , tabPoints[0].y);
328     }
329 
330     int drawn_tab_yoff = tabPoints[1].y;
331     int drawn_tab_height = tabPoints[0].y - tabPoints[2].y;
332 
333     int text_offset = tab_x + 8;
334 
335     int bitmap_offset = 0;
336     if (page.bitmap.IsOk())
337     {
338         bitmap_offset = tab_x + 8;
339 
340         // draw bitmap
341         dc.DrawBitmap(page.bitmap,
342                       bitmap_offset,
343                       drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
344                       true);
345 
346         text_offset = bitmap_offset + page.bitmap.GetWidth();
347         text_offset += 3; // bitmap padding
348     }
349      else
350     {
351         text_offset = tab_x + 8;
352     }
353 
354 
355     // if the caption is empty, measure some temporary text
356     wxString caption = page.caption;
357     if (caption.empty())
358         caption = wxT("Xj");
359 
360     wxCoord textx;
361     wxCoord texty;
362     if (page.active)
363 #if wxCHECK_VERSION(3, 0, 0)
364         dc.SetFont(m_selectedFont);
365 #else
366         dc.SetFont(m_selected_font);
367 #endif
368     else
369 #if wxCHECK_VERSION(3, 0, 0)
370         dc.SetFont(m_normalFont);
371 #else
372         dc.SetFont(m_normal_font);
373 #endif
374     dc.GetTextExtent(caption, &textx, &texty);
375     // draw tab text
376     dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
377     dc.DrawText(page.caption, text_offset,
378                 drawn_tab_yoff + drawn_tab_height / 2 - texty / 2 - 1);
379 
380     // draw 'x' on tab (if enabled)
381     if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
382     {
383 #if wxCHECK_VERSION(3, 0, 0)
384         int close_button_width = m_activeCloseBmp.GetWidth();
385         wxBitmap bmp = m_disabledCloseBmp;
386 #else
387         int close_button_width = m_active_close_bmp.GetWidth();
388         wxBitmap bmp = m_disabled_close_bmp;
389 #endif
390 
391         if ((close_button_state == wxAUI_BUTTON_STATE_HOVER) ||
392                     (close_button_state == wxAUI_BUTTON_STATE_PRESSED))
393 #if wxCHECK_VERSION(3, 0, 0)
394             bmp = m_activeCloseBmp;
395 #else
396             bmp = m_active_close_bmp;
397 #endif
398 
399         wxRect rect(tab_x + tab_width - close_button_width - 3,
400                     drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2),
401                     close_button_width, tab_height);
402 
403         // Indent the button if it is pressed down:
404         if (close_button_state == wxAUI_BUTTON_STATE_PRESSED)
405         {
406             rect.x++;
407             rect.y++;
408         }
409         dc.DrawBitmap(bmp, rect.x, rect.y, true);
410         *out_button_rect = rect;
411     }
412 
413     *out_tab_rect = wxRect(tab_x, tab_y, tab_width, tab_height);
414     dc.DestroyClippingRegion();
415 }
416 
GetBestTabCtrlSize(wxWindow * wnd,const wxAuiNotebookPageArray & WXUNUSED (pages),const wxSize & WXUNUSED (required_bmp_size))417 int NbStyleFF2::GetBestTabCtrlSize(wxWindow* wnd,
418                                     const wxAuiNotebookPageArray& WXUNUSED(pages),
419                                     const wxSize& WXUNUSED(required_bmp_size))
420 {
421 //    m_requested_tabctrl_height = -1;
422 //    m_tab_ctrl_height = -1;
423     wxClientDC dc(wnd);
424 #if wxCHECK_VERSION(3, 0, 0)
425     dc.SetFont(m_measuringFont);
426 #else
427     dc.SetFont(m_measuring_font);
428 #endif
429     int x_ext = 0;
430     wxSize s = GetTabSize(dc, wnd, wxT("ABCDEFGHIj"), wxNullBitmap, true,
431                             wxAUI_BUTTON_STATE_HIDDEN, &x_ext);
432     return s.y + 6;
433 }
434 
435 #if defined(__WXGTK__) && (USE_GTK_NOTEBOOK) && !wxCHECK_VERSION(3, 0, 0)
436 
437 namespace
438 {
439 
440 static GtkWidget *g_window = nullptr;
441 static GtkWidget *g_container = nullptr;
442 static GtkWidget *g_notebook = nullptr;
443 static GtkWidget *g_button = nullptr;
444 static int s_CloseIconSize = 16; // default size
445 
setup_widget_prototype(GtkWidget * widget)446 static void setup_widget_prototype(GtkWidget* widget)
447 {
448     if (!g_window)
449     {
450         g_window = gtk_window_new(GTK_WINDOW_POPUP);
451         gtk_widget_realize(g_window);
452     }
453     if (!g_container)
454     {
455         g_container = gtk_fixed_new();
456         gtk_container_add(GTK_CONTAINER(g_window), g_container);
457     }
458 
459     gtk_container_add(GTK_CONTAINER(g_container), widget);
460     gtk_widget_realize(widget);
461 }
462 
get_style_button()463 static GtkStyle * get_style_button()
464 {
465     if (!g_button)
466     {
467         g_button = gtk_button_new();
468         setup_widget_prototype(g_button);
469     }
470     return gtk_widget_get_style(g_button);
471 }
472 
get_style_notebook()473 static GtkStyle * get_style_notebook()
474 {
475     if (!g_notebook)
476     {
477         g_notebook = gtk_notebook_new();
478         setup_widget_prototype(g_notebook);
479     }
480     return gtk_widget_get_style(g_notebook);
481 }
482 
483 }
484 
NbStyleGTK()485 NbStyleGTK::NbStyleGTK():
486     m_Xthickness(0),
487     m_Ythickness(0),
488     m_TabHBorder(0),
489     m_TabVBorder(0)
490 
491 {
492 }
493 
Clone()494 wxAuiTabArt* NbStyleGTK::Clone()
495 {
496     NbStyleGTK* clone = new NbStyleGTK();
497 
498 #if wxCHECK_VERSION(3, 0, 0)
499     clone->SetNormalFont(m_normalFont);
500     clone->SetSelectedFont(m_normalFont);
501     clone->SetMeasuringFont(m_normalFont);
502 #else
503     clone->SetNormalFont(m_normal_font);
504     clone->SetSelectedFont(m_normal_font);
505     clone->SetMeasuringFont(m_normal_font);
506 #endif
507 
508     return clone;
509 }
510 
DrawBackground(wxDC & dc,wxWindow * wnd,const wxRect & rect)511 void NbStyleGTK::DrawBackground(wxDC& dc, wxWindow* wnd, const wxRect& rect)
512 {
513     GtkStyle* style_notebook = get_style_notebook();
514     GtkNotebook* notebook = GTK_NOTEBOOK (g_notebook);
515 
516     // if one of the parameters have changed, the height needs to be recalculated, so we force it,
517     if(m_Xthickness  != style_notebook->xthickness ||
518        m_Ythickness  != style_notebook->ythickness ||
519        m_TabVBorder != notebook->tab_vborder ||
520        m_TabHBorder != notebook->tab_hborder)
521     {
522         m_Xthickness  = style_notebook->xthickness;
523         m_Ythickness  = style_notebook->ythickness;
524         m_TabVBorder = notebook->tab_vborder;
525         m_TabHBorder = notebook->tab_hborder;
526         wxAuiNotebook* nb = nullptr;
527         if(wnd)
528              nb = (cbAuiNotebook*)wnd->GetParent();
529         if(nb)
530             nb->SetTabCtrlHeight(-1);
531     }
532 #if wxCHECK_VERSION(3, 0, 0)
533     wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
534     GdkWindow* pWin = impldc->GetGDKWindow();
535 #else
536     GdkWindow* pWin = dc.GetGDKWindow();
537 #endif
538     gtk_style_apply_default_background(style_notebook, pWin, 1, GTK_STATE_NORMAL, nullptr,
539                                        rect.x, rect.y, rect.width, rect.height);
540 }
541 
ButtonStateAndShadow(int button_state,GtkStateType & state,GtkShadowType & shadow)542 void ButtonStateAndShadow(int button_state, GtkStateType &state, GtkShadowType &shadow)
543 {
544 
545     if (button_state & wxAUI_BUTTON_STATE_DISABLED)
546     {
547         state = GTK_STATE_INSENSITIVE;
548         shadow = GTK_SHADOW_ETCHED_IN;
549     }
550     else if (button_state & wxAUI_BUTTON_STATE_HOVER)
551     {
552         state = GTK_STATE_PRELIGHT;
553         shadow = GTK_SHADOW_OUT;
554     }
555     else if (button_state & wxAUI_BUTTON_STATE_PRESSED)
556     {
557         state = GTK_STATE_ACTIVE;
558         shadow = GTK_SHADOW_IN;
559     }
560     else
561     {
562         state = GTK_STATE_NORMAL;
563         shadow = GTK_SHADOW_OUT;
564     }
565 }
566 
DrawCloseButton(wxDC & dc,GtkWidget * widget,int button_state,wxRect const & in_rect,int orientation,GdkRectangle * clipRect)567 wxRect DrawCloseButton(wxDC& dc,
568                        GtkWidget *widget,
569                        int button_state,
570                        wxRect const &in_rect,
571                        int orientation,
572                        GdkRectangle* clipRect)
573 {
574     GtkStyle *style_button = get_style_button();
575     int xthickness = style_button->xthickness;
576     int ythickness = style_button->ythickness;
577 
578     wxBitmap bmp;
579     bmp.SetPixbuf(gtk_widget_render_icon(widget, GTK_STOCK_CLOSE, GTK_ICON_SIZE_SMALL_TOOLBAR, "tab"));
580 
581     if(bmp.GetWidth() != s_CloseIconSize || bmp.GetHeight() != s_CloseIconSize)
582     {
583         wxImage img = bmp.ConvertToImage();
584         img.Rescale(s_CloseIconSize, s_CloseIconSize);
585         bmp = img;
586     }
587 
588     int button_size = s_CloseIconSize + 2 * xthickness;
589 
590     wxRect out_rect;
591 
592     if (orientation == wxLEFT)
593         out_rect.x = in_rect.x - ythickness;
594     else
595         out_rect.x = in_rect.x + in_rect.width - button_size - ythickness;
596 
597     out_rect.y = in_rect.y + (in_rect.height - button_size) / 2;
598     out_rect.width = button_size;
599     out_rect.height = button_size;
600 
601 #if wxCHECK_VERSION(3, 0, 0)
602     wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
603     GdkWindow* pWin = impldc->GetGDKWindow();
604 #else
605     GdkWindow* pWin = dc.GetGDKWindow();
606 #endif
607 
608     if (button_state == wxAUI_BUTTON_STATE_HOVER)
609     {
610         gtk_paint_box(style_button, pWin,
611                       GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, clipRect, widget, "button",
612                       out_rect.x, out_rect.y, out_rect.width, out_rect.height);
613     }
614     else if (button_state == wxAUI_BUTTON_STATE_PRESSED)
615     {
616         gtk_paint_box(style_button, pWin,
617                       GTK_STATE_ACTIVE, GTK_SHADOW_IN, clipRect, widget, "button",
618                       out_rect.x, out_rect.y, out_rect.width, out_rect.height);
619     }
620 
621 
622     dc.DrawBitmap(bmp, out_rect.x + xthickness, out_rect.y + ythickness, true);
623 
624     return out_rect;
625 }
626 
DrawTab(wxDC & dc,wxWindow * wnd,const wxAuiNotebookPage & page,const wxRect & in_rect,int close_button_state,wxRect * out_tab_rect,wxRect * out_button_rect,int * x_extent)627 void NbStyleGTK::DrawTab(wxDC& dc, wxWindow* wnd, const wxAuiNotebookPage& page,
628                              const wxRect& in_rect, int close_button_state, wxRect* out_tab_rect,
629                              wxRect* out_button_rect, int* x_extent)
630 {
631     GtkWidget *widget = wnd->GetHandle();
632     GtkStyle *style_notebook = get_style_notebook();
633 
634     wxRect const &window_rect = wnd->GetRect();
635 
636     int focus_width = 0;
637 
638     gtk_widget_style_get(g_notebook,
639                          "focus-line-width", &focus_width,
640                          NULL);
641 
642     int tab_pos;
643     if (m_flags &wxAUI_NB_BOTTOM)
644         tab_pos = wxAUI_NB_BOTTOM;
645     else //if (m_flags & wxAUI_NB_TOP) {}
646         tab_pos = wxAUI_NB_TOP;
647 
648     // TODO: else if (m_flags &wxAUI_NB_LEFT) {}
649     // TODO: else if (m_flags &wxAUI_NB_RIGHT) {}
650 
651     // figure out the size of the tab
652     wxSize tab_size = GetTabSize(dc, wnd, page.caption, page.bitmap,
653                                     page.active, close_button_state, x_extent);
654 
655     wxRect tab_rect = in_rect;
656     tab_rect.width = tab_size.x;
657     tab_rect.height = tab_size.y;
658     tab_rect.y += 2 * m_TabHBorder;
659 
660     if (page.active)
661         tab_rect.height += 2 * m_TabHBorder;
662 #if wxCHECK_VERSION(3, 0, 0)
663     // if no bitmap is set, we need a tiny correction
664     if (! page.bitmap.IsOk())
665         tab_rect.height += 1;
666 #endif
667 
668     int gap_rect_height = 6 * m_TabHBorder;
669     int gap_rect_x = 1, gap_start = 0, gap_width = 0;
670     int gap_rect_y = tab_rect.y - gap_rect_height;
671     int gap_rect_width = window_rect.width;
672 
673     switch (tab_pos)
674     {
675         case wxAUI_NB_TOP:
676             tab_rect.y -= 2 * m_TabHBorder;
677             if (!page.active)
678                 tab_rect.y += 2 * m_TabHBorder;
679             gap_rect_y = tab_rect.y + tab_rect.height - m_TabHBorder / 2;
680             // fall through
681         case wxAUI_NB_BOTTOM:
682             gap_start = tab_rect.x - m_TabVBorder / 2;
683             gap_width = tab_rect.width;
684             break;
685         default:
686             break;
687     }
688     tab_rect.y += m_TabHBorder / 2;
689     gap_rect_y += m_TabHBorder / 2;
690 
691     int padding = focus_width + m_TabHBorder;
692 
693     int clip_width = tab_rect.width;
694     if (tab_rect.x + tab_rect.width > in_rect.x + in_rect.width)
695         clip_width = (in_rect.x + in_rect.width) - tab_rect.x;
696 
697     dc.SetClippingRegion(tab_rect.x, tab_rect.y - m_TabVBorder, clip_width, tab_rect.height + m_TabVBorder);
698 
699     GdkRectangle area;
700     area.x = tab_rect.x - m_TabVBorder;
701     area.y = tab_rect.y - 2 * m_TabHBorder;
702     area.width = clip_width + m_TabVBorder;
703     area.height = tab_rect.height + 2 * m_TabHBorder;
704 
705 #if wxCHECK_VERSION(3, 0, 0)
706     wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
707     GdkWindow* pWin = impldc->GetGDKWindow();
708 #else
709     GdkWindow* pWin = dc.GetGDKWindow();
710 #endif
711 
712     if (tab_pos == wxAUI_NB_BOTTOM)
713     {
714         if (page.active)
715         {
716             gtk_paint_box_gap(style_notebook, pWin, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
717                               NULL, widget, "notebook",
718                               gap_rect_x, gap_rect_y,
719                               gap_rect_width, gap_rect_height,
720                               GTK_POS_BOTTOM, gap_start , gap_width);
721         }
722         gtk_paint_extension(style_notebook, pWin,
723                            page.active ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE, GTK_SHADOW_OUT,
724                            &area, widget, "tab",
725                            tab_rect.x, tab_rect.y,
726                            tab_rect.width, tab_rect.height,
727                            GTK_POS_TOP);
728     }
729     else
730     {
731         if (page.active)
732         {
733             gtk_paint_box_gap(style_notebook, pWin, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
734                               NULL, widget, "notebook",
735                               gap_rect_x, gap_rect_y,
736                               gap_rect_width, gap_rect_height,
737                               GTK_POS_TOP, gap_start , gap_width);
738         }
739         gtk_paint_extension(style_notebook, pWin,
740                            page.active ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE, GTK_SHADOW_OUT,
741                            &area, widget, "tab",
742                            tab_rect.x, tab_rect.y,
743                            tab_rect.width, tab_rect.height,
744                            GTK_POS_BOTTOM);
745     }
746 
747     wxCoord textX = tab_rect.x + padding + m_Xthickness;
748 
749     int bitmap_offset = 0;
750     if (page.bitmap.IsOk())
751     {
752         bitmap_offset = textX;
753 
754         // draw bitmap
755         int bitmapY = tab_rect.y +(tab_rect.height - page.bitmap.GetHeight()) / 2;
756         if(!page.active)
757         {
758             if (tab_pos == wxAUI_NB_TOP)
759                 bitmapY += m_Ythickness / 2;
760             else
761                 bitmapY -= m_Ythickness / 2;
762         }
763         dc.DrawBitmap(page.bitmap,
764                       bitmap_offset,
765                       bitmapY,
766                       true);
767 
768         textX += page.bitmap.GetWidth() + padding;
769     }
770 
771     wxCoord textW, textH, textY;
772 
773 #if wxCHECK_VERSION(3, 0, 0)
774     dc.SetFont(m_normalFont);
775 #else
776     dc.SetFont(m_normal_font);
777 #endif
778     dc.GetTextExtent(page.caption, &textW, &textH);
779     textY = tab_rect.y + (tab_rect.height - textH) / 2;
780     if(!page.active)
781     {
782         if (tab_pos == wxAUI_NB_TOP)
783             textY += m_Ythickness / 2;
784         else
785             textY -= m_Ythickness / 2;
786     }
787 
788     // draw tab text
789     GdkColor text_colour = page.active ? style_notebook->fg[GTK_STATE_NORMAL] : style_notebook->fg[GTK_STATE_ACTIVE];
790     dc.SetTextForeground(wxColor(text_colour));
791     GdkRectangle focus_area;
792 
793     int padding_focus = padding - focus_width;
794     focus_area.x = tab_rect.x + padding_focus;
795     focus_area.y = textY - focus_width;
796     focus_area.width = tab_rect.width - 2 * padding_focus;
797     focus_area.height = textH + 2 * focus_width;
798 
799     if(page.active && (wnd->FindFocus() == wnd) && focus_area.x <= (area.x + area.width))
800     {
801         // clipping seems not to work here, so we we have to recalc the focus-area manually
802         if((focus_area.x + focus_area.width) > (area.x + area.width))
803             focus_area.width = area.x + area.width - focus_area.x + focus_width - m_TabVBorder;
804         gtk_paint_focus (style_notebook, pWin,
805                          GTK_STATE_ACTIVE, NULL, widget, "tab",
806                          focus_area.x, focus_area.y, focus_area.width, focus_area.height);
807     }
808 
809     dc.DrawText(page.caption, textX, textY);
810 
811     // draw close-button on tab (if enabled)
812     if (close_button_state != wxAUI_BUTTON_STATE_HIDDEN)
813     {
814         wxRect rect(tab_rect.x, tab_rect.y, tab_rect.width - m_Xthickness, tab_rect.height);
815         if(!page.active)
816         {
817             if (tab_pos == wxAUI_NB_TOP)
818                 rect.y += m_Ythickness / 2;
819             else
820                 rect.y -= m_Ythickness / 2;
821         }
822         *out_button_rect = DrawCloseButton(dc, widget, close_button_state, rect, wxRIGHT, &area);
823     }
824 
825     tab_rect.width = std::min(tab_rect.width, clip_width);
826     *out_tab_rect = tab_rect;
827 
828     dc.DestroyClippingRegion();
829 }
830 
DrawSimpleArrow(wxDC & dc,GtkWidget * widget,int button_state,wxRect const & in_rect,int orientation,GtkArrowType arrow_type)831 wxRect DrawSimpleArrow(wxDC& dc,
832                        GtkWidget *widget,
833                        int button_state,
834                        wxRect const &in_rect,
835                        int orientation,
836                        GtkArrowType arrow_type)
837 {
838     int scroll_arrow_hlength, scroll_arrow_vlength;
839     gtk_widget_style_get(widget,
840                          "scroll-arrow-hlength", &scroll_arrow_hlength,
841                          "scroll-arrow-vlength", &scroll_arrow_vlength,
842                          NULL);
843 
844     GtkStateType state;
845     GtkShadowType shadow;
846     ButtonStateAndShadow(button_state, state, shadow);
847 
848     wxRect out_rect;
849 
850     if (orientation == wxLEFT)
851         out_rect.x = in_rect.x;
852     else
853         out_rect.x = in_rect.x + in_rect.width - scroll_arrow_hlength;
854     out_rect.y = (in_rect.y + in_rect.height - 3 * get_style_notebook()->ythickness - scroll_arrow_vlength) / 2;
855     out_rect.width = scroll_arrow_hlength;
856     out_rect.height = scroll_arrow_vlength;
857 
858 #if wxCHECK_VERSION(3, 0, 0)
859     wxGTKDCImpl *impldc = (wxGTKDCImpl*) dc.GetImpl();
860     GdkWindow* pWin = impldc->GetGDKWindow();
861 #else
862     GdkWindow* pWin = dc.GetGDKWindow();
863 #endif
864     gtk_paint_arrow (get_style_button(), pWin, state, shadow, nullptr, widget, "notebook",
865                      arrow_type, TRUE, out_rect.x, out_rect.y, out_rect.width, out_rect.height);
866 
867     return out_rect;
868 }
869 
DrawButton(wxDC & dc,wxWindow * wnd,const wxRect & in_rect,int bitmap_id,int button_state,int orientation,wxRect * out_rect)870 void NbStyleGTK::DrawButton(wxDC& dc, wxWindow* wnd,
871                             const wxRect& in_rect,
872                             int bitmap_id,
873                             int button_state,
874                             int orientation,
875                             wxRect* out_rect)
876 {
877     GtkWidget *widget = wnd->GetHandle();
878     wxRect rect = in_rect;
879     if (m_flags &wxAUI_NB_BOTTOM)
880         rect.y += 2 * get_style_button()->ythickness;
881 
882     switch (bitmap_id)
883     {
884         case wxAUI_BUTTON_CLOSE:
885             rect.y -= 2 * get_style_button()->ythickness;
886             rect = DrawCloseButton(dc, widget, button_state, rect, orientation, NULL);
887             break;
888 
889         case wxAUI_BUTTON_LEFT:
890             rect = DrawSimpleArrow(dc, widget, button_state, rect, orientation, GTK_ARROW_LEFT);
891             break;
892 
893         case wxAUI_BUTTON_RIGHT:
894             rect = DrawSimpleArrow(dc, widget, button_state, rect, orientation, GTK_ARROW_RIGHT);
895             break;
896 
897         case wxAUI_BUTTON_WINDOWLIST:
898             {
899                 rect.height -= 4 * get_style_button()->ythickness;
900                 rect.width = rect.height;
901                 rect.x = in_rect.x + in_rect.width - rect.width;
902 
903                 if (button_state == wxAUI_BUTTON_STATE_HOVER)
904                     wxRendererNative::Get().DrawComboBoxDropButton(wnd, dc, rect, wxCONTROL_CURRENT);
905                 else if (button_state == wxAUI_BUTTON_STATE_PRESSED)
906                     wxRendererNative::Get().DrawComboBoxDropButton(wnd, dc, rect, wxCONTROL_PRESSED);
907                 else
908                     wxRendererNative::Get().DrawDropArrow(wnd, dc, rect);
909             }
910             break;
911 
912         default:
913             break;
914     }
915 
916     *out_rect = rect;
917 }
918 
919 
GetBestTabCtrlSize(wxWindow * wnd,const wxAuiNotebookPageArray & pages,const wxSize & required_bmp_size)920 int NbStyleGTK::GetBestTabCtrlSize(wxWindow* wnd,
921                                    const wxAuiNotebookPageArray& pages,
922                                    const wxSize& required_bmp_size)
923 {
924 #if wxCHECK_VERSION(3, 0, 0)
925     SetMeasuringFont(m_normalFont);
926     SetSelectedFont(m_normalFont);
927 #else
928     SetMeasuringFont(m_normal_font);
929     SetSelectedFont(m_normal_font);
930 #endif
931     int tab_height = 3 * get_style_notebook()->ythickness + wxAuiDefaultTabArt::GetBestTabCtrlSize(wnd, pages, required_bmp_size);
932     return tab_height;
933 }
934 
GetTabSize(wxDC & dc,wxWindow * wnd,const wxString & caption,const wxBitmap & bitmap,bool active,int close_button_state,int * x_extent)935 wxSize NbStyleGTK::GetTabSize(wxDC& dc,
936                               wxWindow* wnd,
937                               const wxString& caption,
938                               const wxBitmap& bitmap,
939                               bool active,
940                               int close_button_state,
941                               int* x_extent)
942 {
943     wxSize s = wxAuiDefaultTabArt::GetTabSize(dc, wnd, caption, bitmap, active, close_button_state, x_extent);
944 
945     int overlap = 0;
946     gtk_widget_style_get (wnd->GetHandle(),
947         "focus-line-width", &overlap,
948         NULL);
949     *x_extent -= overlap;
950     return s;
951 }
952 
953 #endif // #if defined(__WXGTK__) && (USE_GTK_NOTEBOOK) && !wxCHECK_VERSION(3, 0, 0)
954