1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/toolbar.cpp
3 // Purpose:     GTK toolbar
4 // Author:      Robert Roebling
5 // Modified:    13.12.99 by VZ to derive from wxToolBarBase
6 // Copyright:   (c) Robert Roebling
7 // Licence:     wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12 
13 #if wxUSE_TOOLBAR_NATIVE
14 
15 #include "wx/toolbar.h"
16 
17 #include <gtk/gtk.h>
18 #include "wx/gtk/private.h"
19 #include "wx/gtk/private/gtk2-compat.h"
20 
21 // ----------------------------------------------------------------------------
22 // globals
23 // ----------------------------------------------------------------------------
24 
25 // data
26 extern bool       g_blockEventsOnDrag;
27 
28 // ----------------------------------------------------------------------------
29 // wxToolBarTool
30 // ----------------------------------------------------------------------------
31 
32 class wxToolBarTool : public wxToolBarToolBase
33 {
34 public:
wxToolBarTool(wxToolBar * tbar,int id,const wxString & label,const wxBitmap & bitmap1,const wxBitmap & bitmap2,wxItemKind kind,wxObject * clientData,const wxString & shortHelpString,const wxString & longHelpString)35     wxToolBarTool(wxToolBar *tbar,
36                   int id,
37                   const wxString& label,
38                   const wxBitmap& bitmap1,
39                   const wxBitmap& bitmap2,
40                   wxItemKind kind,
41                   wxObject *clientData,
42                   const wxString& shortHelpString,
43                   const wxString& longHelpString)
44         : wxToolBarToolBase(tbar, id, label, bitmap1, bitmap2, kind,
45                             clientData, shortHelpString, longHelpString)
46     {
47         m_item = NULL;
48     }
49 
wxToolBarTool(wxToolBar * tbar,wxControl * control,const wxString & label)50     wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label)
51         : wxToolBarToolBase(tbar, control, label)
52     {
53         m_item = NULL;
54     }
55 
56     void SetImage();
57     void CreateDropDown();
58     void ShowDropdown(GtkToggleButton* button);
59 
60     GtkToolItem* m_item;
61 };
62 
63 // ----------------------------------------------------------------------------
64 // wxWin macros
65 // ----------------------------------------------------------------------------
66 
IMPLEMENT_DYNAMIC_CLASS(wxToolBar,wxControl)67 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
68 
69 // ============================================================================
70 // implementation
71 // ============================================================================
72 
73 //-----------------------------------------------------------------------------
74 // "clicked" from m_item
75 //-----------------------------------------------------------------------------
76 
77 extern "C" {
78 static void item_clicked(GtkToolButton*, wxToolBarTool* tool)
79 {
80     if (g_blockEventsOnDrag) return;
81 
82     tool->GetToolBar()->OnLeftClick(tool->GetId(), false);
83 }
84 }
85 
86 //-----------------------------------------------------------------------------
87 // "toggled" from m_item
88 //-----------------------------------------------------------------------------
89 
90 extern "C" {
item_toggled(GtkToggleToolButton * button,wxToolBarTool * tool)91 static void item_toggled(GtkToggleToolButton* button, wxToolBarTool* tool)
92 {
93     if (g_blockEventsOnDrag) return;
94 
95     const bool active = gtk_toggle_tool_button_get_active(button) != 0;
96     tool->Toggle(active);
97     if (!active && tool->GetKind() == wxITEM_RADIO)
98         return;
99 
100     if (!tool->GetToolBar()->OnLeftClick(tool->GetId(), active))
101     {
102         // revert back
103         tool->Toggle();
104     }
105 }
106 }
107 
108 //-----------------------------------------------------------------------------
109 // "button_press_event" from m_item child
110 //-----------------------------------------------------------------------------
111 
112 extern "C" {
113 static gboolean
button_press_event(GtkWidget *,GdkEventButton * event,wxToolBarTool * tool)114 button_press_event(GtkWidget*, GdkEventButton* event, wxToolBarTool* tool)
115 {
116     if (event->button != 3)
117         return FALSE;
118 
119     if (g_blockEventsOnDrag) return TRUE;
120 
121     tool->GetToolBar()->OnRightClick(
122         tool->GetId(), int(event->x), int(event->y));
123 
124     return TRUE;
125 }
126 }
127 
128 //-----------------------------------------------------------------------------
129 // "child_detached" from m_widget
130 //-----------------------------------------------------------------------------
131 
132 extern "C" {
child_detached(GtkWidget *,GtkToolbar * toolbar,void *)133 static void child_detached(GtkWidget*, GtkToolbar* toolbar, void*)
134 {
135     // disable showing overflow arrow when toolbar is detached,
136     // otherwise toolbar collapses to just an arrow
137     gtk_toolbar_set_show_arrow(toolbar, false);
138 }
139 }
140 
141 //-----------------------------------------------------------------------------
142 // "child_attached" from m_widget
143 //-----------------------------------------------------------------------------
144 
145 extern "C" {
child_attached(GtkWidget *,GtkToolbar * toolbar,void *)146 static void child_attached(GtkWidget*, GtkToolbar* toolbar, void*)
147 {
148     gtk_toolbar_set_show_arrow(toolbar, true);
149 }
150 }
151 
152 //-----------------------------------------------------------------------------
153 // "enter_notify_event" / "leave_notify_event" from m_item
154 //-----------------------------------------------------------------------------
155 
156 extern "C" {
157 static gboolean
enter_notify_event(GtkWidget *,GdkEventCrossing * event,wxToolBarTool * tool)158 enter_notify_event(GtkWidget*, GdkEventCrossing* event, wxToolBarTool* tool)
159 {
160     if (g_blockEventsOnDrag) return TRUE;
161 
162     int id = -1;
163     if (event->type == GDK_ENTER_NOTIFY)
164         id = tool->GetId();
165     tool->GetToolBar()->OnMouseEnter(id);
166 
167     return FALSE;
168 }
169 }
170 
171 //-----------------------------------------------------------------------------
172 // "expose_event" from GtkImage inside m_item
173 //-----------------------------------------------------------------------------
174 
175 extern "C" {
176 static gboolean
177 #ifdef __WXGTK3__
image_draw(GtkWidget * widget,cairo_t * cr,wxToolBarTool * tool)178 image_draw(GtkWidget* widget, cairo_t* cr, wxToolBarTool* tool)
179 #else
180 image_expose_event(GtkWidget* widget, GdkEventExpose*, wxToolBarTool* tool)
181 #endif
182 {
183     const wxBitmap& bitmap = tool->GetDisabledBitmap();
184     if (tool->IsEnabled() || !bitmap.IsOk())
185         return false;
186 
187     // draw disabled bitmap ourselves, GtkImage has no way to specify it
188     GtkAllocation alloc;
189     gtk_widget_get_allocation(widget, &alloc);
190     GtkRequisition req;
191     gtk_widget_get_requisition(widget, &req);
192 #ifdef __WXGTK3__
193     const int x = (alloc.width - req.width) / 2;
194     const int y = (alloc.height - req.height) / 2;
195     bitmap.Draw(cr, x, y);
196 #else
197     const int x = alloc.x + (alloc.width - req.width) / 2;
198     const int y = alloc.y + (alloc.height - req.height) / 2;
199     gdk_draw_pixbuf(
200         gtk_widget_get_window(widget), gtk_widget_get_style(widget)->black_gc, bitmap.GetPixbuf(),
201         0, 0, x, y,
202         -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0);
203 #endif
204     return true;
205 }
206 }
207 
208 //-----------------------------------------------------------------------------
209 // "toggled" from dropdown menu button
210 //-----------------------------------------------------------------------------
211 
212 extern "C" {
arrow_toggled(GtkToggleButton * button,wxToolBarTool * tool)213 static void arrow_toggled(GtkToggleButton* button, wxToolBarTool* tool)
214 {
215     if (gtk_toggle_button_get_active(button))
216     {
217         tool->ShowDropdown(button);
218         gtk_toggle_button_set_active(button, false);
219     }
220 }
221 }
222 
223 //-----------------------------------------------------------------------------
224 // "button_press_event" from dropdown menu button
225 //-----------------------------------------------------------------------------
226 
227 extern "C" {
228 static gboolean
arrow_button_press_event(GtkToggleButton * button,GdkEventButton * event,wxToolBarTool * tool)229 arrow_button_press_event(GtkToggleButton* button, GdkEventButton* event, wxToolBarTool* tool)
230 {
231     if (event->button == 1)
232     {
233         g_signal_handlers_block_by_func(button, (void*)arrow_toggled, tool);
234         gtk_toggle_button_set_active(button, true);
235         tool->ShowDropdown(button);
236         gtk_toggle_button_set_active(button, false);
237         g_signal_handlers_unblock_by_func(button, (void*)arrow_toggled, tool);
238         return true;
239     }
240     return false;
241 }
242 }
243 
AddChildGTK(wxWindowGTK * child)244 void wxToolBar::AddChildGTK(wxWindowGTK* child)
245 {
246     GtkWidget* align = gtk_alignment_new(0.5, 0.5, 0, 0);
247     gtk_widget_show(align);
248     gtk_container_add(GTK_CONTAINER(align), child->m_widget);
249     GtkToolItem* item = gtk_tool_item_new();
250     gtk_container_add(GTK_CONTAINER(item), align);
251     // position will be corrected in DoInsertTool if necessary
252     gtk_toolbar_insert(GTK_TOOLBAR(gtk_bin_get_child(GTK_BIN(m_widget))), item, -1);
253 }
254 
255 // ----------------------------------------------------------------------------
256 // wxToolBarTool
257 // ----------------------------------------------------------------------------
258 
SetImage()259 void wxToolBarTool::SetImage()
260 {
261     const wxBitmap& bitmap = GetNormalBitmap();
262     wxCHECK_RET(bitmap.IsOk(), "invalid bitmap for wxToolBar icon");
263 
264     GtkWidget* image = gtk_tool_button_get_icon_widget(GTK_TOOL_BUTTON(m_item));
265     // always use pixbuf, because pixmap mask does not
266     // work with disabled images in some themes
267     gtk_image_set_from_pixbuf(GTK_IMAGE(image), bitmap.GetPixbuf());
268 }
269 
270 // helper to create a dropdown menu item
CreateDropDown()271 void wxToolBarTool::CreateDropDown()
272 {
273     gtk_tool_item_set_homogeneous(m_item, false);
274     GtkOrientation orient = GTK_ORIENTATION_HORIZONTAL;
275     GtkArrowType arrowType = GTK_ARROW_DOWN;
276     if (GetToolBar()->HasFlag(wxTB_LEFT | wxTB_RIGHT))
277     {
278         orient = GTK_ORIENTATION_VERTICAL;
279         arrowType = GTK_ARROW_RIGHT;
280     }
281     GtkWidget* box = gtk_box_new(orient, 0);
282     GtkWidget* arrow = gtk_arrow_new(arrowType, GTK_SHADOW_NONE);
283     GtkWidget* tool_button = gtk_bin_get_child(GTK_BIN(m_item));
284     g_object_ref(tool_button);
285     gtk_container_remove(GTK_CONTAINER(m_item), tool_button);
286     gtk_container_add(GTK_CONTAINER(box), tool_button);
287     g_object_unref(tool_button);
288     GtkWidget* arrow_button = gtk_toggle_button_new();
289     gtk_button_set_relief(GTK_BUTTON(arrow_button),
290         gtk_tool_item_get_relief_style(GTK_TOOL_ITEM(m_item)));
291     gtk_container_add(GTK_CONTAINER(arrow_button), arrow);
292     gtk_container_add(GTK_CONTAINER(box), arrow_button);
293     gtk_widget_show_all(box);
294     gtk_container_add(GTK_CONTAINER(m_item), box);
295 
296     g_signal_connect(arrow_button, "toggled", G_CALLBACK(arrow_toggled), this);
297     g_signal_connect(arrow_button, "button_press_event",
298         G_CALLBACK(arrow_button_press_event), this);
299 }
300 
ShowDropdown(GtkToggleButton * button)301 void wxToolBarTool::ShowDropdown(GtkToggleButton* button)
302 {
303     wxToolBarBase* toolbar = GetToolBar();
304     wxCommandEvent event(wxEVT_TOOL_DROPDOWN, GetId());
305     if (!toolbar->HandleWindowEvent(event))
306     {
307         wxMenu* menu = GetDropdownMenu();
308         if (menu)
309         {
310             GtkAllocation alloc;
311             gtk_widget_get_allocation(GTK_WIDGET(button), &alloc);
312             int x = alloc.x;
313             int y = alloc.y;
314             if (toolbar->HasFlag(wxTB_LEFT | wxTB_RIGHT))
315                 x += alloc.width;
316             else
317                 y += alloc.height;
318             toolbar->PopupMenu(menu, x, y);
319         }
320     }
321 }
322 
CreateTool(int id,const wxString & text,const wxBitmap & bitmap1,const wxBitmap & bitmap2,wxItemKind kind,wxObject * clientData,const wxString & shortHelpString,const wxString & longHelpString)323 wxToolBarToolBase *wxToolBar::CreateTool(int id,
324                                          const wxString& text,
325                                          const wxBitmap& bitmap1,
326                                          const wxBitmap& bitmap2,
327                                          wxItemKind kind,
328                                          wxObject *clientData,
329                                          const wxString& shortHelpString,
330                                          const wxString& longHelpString)
331 {
332     return new wxToolBarTool(this, id, text, bitmap1, bitmap2, kind,
333                              clientData, shortHelpString, longHelpString);
334 }
335 
336 wxToolBarToolBase *
CreateTool(wxControl * control,const wxString & label)337 wxToolBar::CreateTool(wxControl *control, const wxString& label)
338 {
339     return new wxToolBarTool(this, control, label);
340 }
341 
342 //-----------------------------------------------------------------------------
343 // wxToolBar construction
344 //-----------------------------------------------------------------------------
345 
Init()346 void wxToolBar::Init()
347 {
348     m_toolbar = NULL;
349     m_tooltips = NULL;
350 }
351 
~wxToolBar()352 wxToolBar::~wxToolBar()
353 {
354 #ifndef __WXGTK3__
355     if (m_tooltips) // always NULL if GTK >= 2.12
356     {
357         gtk_object_destroy(GTK_OBJECT(m_tooltips));
358         g_object_unref(m_tooltips);
359     }
360 #endif
361 }
362 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)363 bool wxToolBar::Create( wxWindow *parent,
364                         wxWindowID id,
365                         const wxPoint& pos,
366                         const wxSize& size,
367                         long style,
368                         const wxString& name )
369 {
370     if ( !PreCreation( parent, pos, size ) ||
371          !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
372     {
373         wxFAIL_MSG( wxT("wxToolBar creation failed") );
374 
375         return false;
376     }
377 
378     FixupStyle();
379 
380     m_toolbar = GTK_TOOLBAR( gtk_toolbar_new() );
381 #ifndef __WXGTK3__
382     if (gtk_check_version(2, 12, 0))
383     {
384         m_tooltips = gtk_tooltips_new();
385         g_object_ref(m_tooltips);
386         gtk_object_sink(GTK_OBJECT(m_tooltips));
387     }
388 #endif
389     GtkSetStyle();
390 
391     if ((style & wxTB_DOCKABLE)
392 #ifdef __WXGTK3__
393         // using GtkHandleBox prevents toolbar from drawing with GTK+ >= 3.19.7
394         && gtk_check_version(3,19,7)
395 #endif
396         )
397     {
398         m_widget = gtk_handle_box_new();
399 
400         g_signal_connect(m_widget, "child_detached",
401             G_CALLBACK(child_detached), NULL);
402         g_signal_connect(m_widget, "child_attached",
403             G_CALLBACK(child_attached), NULL);
404 
405         if (style & wxTB_FLAT)
406             gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(m_widget), GTK_SHADOW_NONE );
407     }
408     else
409     {
410         m_widget = gtk_event_box_new();
411         ConnectWidget( m_widget );
412     }
413     g_object_ref(m_widget);
414     gtk_container_add(GTK_CONTAINER(m_widget), GTK_WIDGET(m_toolbar));
415     gtk_widget_show(GTK_WIDGET(m_toolbar));
416 
417     m_parent->DoAddChild( this );
418 
419     PostCreation(size);
420 
421     return true;
422 }
423 
GTKGetWindow(wxArrayGdkWindows & WXUNUSED (windows)) const424 GdkWindow *wxToolBar::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
425 {
426     return gtk_widget_get_window(GTK_WIDGET(m_toolbar));
427 }
428 
GtkSetStyle()429 void wxToolBar::GtkSetStyle()
430 {
431     GtkOrientation orient = GTK_ORIENTATION_HORIZONTAL;
432     if (HasFlag(wxTB_LEFT | wxTB_RIGHT))
433         orient = GTK_ORIENTATION_VERTICAL;
434 
435     GtkToolbarStyle style = GTK_TOOLBAR_ICONS;
436     if (HasFlag(wxTB_NOICONS))
437         style = GTK_TOOLBAR_TEXT;
438     else if (HasFlag(wxTB_TEXT))
439     {
440         style = GTK_TOOLBAR_BOTH;
441         if (HasFlag(wxTB_HORZ_LAYOUT))
442             style = GTK_TOOLBAR_BOTH_HORIZ;
443     }
444 
445 #ifdef __WXGTK3__
446     gtk_orientable_set_orientation(GTK_ORIENTABLE(m_toolbar), orient);
447 #else
448     gtk_toolbar_set_orientation(m_toolbar, orient);
449 #endif
450     gtk_toolbar_set_style(m_toolbar, style);
451 }
452 
SetWindowStyleFlag(long style)453 void wxToolBar::SetWindowStyleFlag( long style )
454 {
455     wxToolBarBase::SetWindowStyleFlag(style);
456 
457     if ( m_toolbar )
458         GtkSetStyle();
459 }
460 
Realize()461 bool wxToolBar::Realize()
462 {
463     if ( !wxToolBarBase::Realize() )
464         return false;
465 
466     // bring the initial state of all the toolbar items in line with the
467     // internal state if the latter was changed by calling wxToolBarTool::
468     // Enable(): this works under MSW, where the toolbar items are only created
469     // in Realize() which uses the internal state to determine the initial
470     // button state, so make it work under GTK too
471     for ( wxToolBarToolsList::const_iterator i = m_tools.begin();
472           i != m_tools.end();
473           ++i )
474     {
475         // by default the toolbar items are enabled and not toggled, so we only
476         // have to do something if their internal state doesn't correspond to
477         // this
478         if ( !(*i)->IsEnabled() )
479             DoEnableTool(*i, false);
480         if ( (*i)->IsToggled() )
481             DoToggleTool(*i, true);
482     }
483 
484     return true;
485 }
486 
DoInsertTool(size_t pos,wxToolBarToolBase * toolBase)487 bool wxToolBar::DoInsertTool(size_t pos, wxToolBarToolBase *toolBase)
488 {
489     wxToolBarTool* tool = static_cast<wxToolBarTool*>(toolBase);
490 
491     GSList* radioGroup;
492     GtkWidget* bin_child;
493     switch ( tool->GetStyle() )
494     {
495         case wxTOOL_STYLE_BUTTON:
496             switch (tool->GetKind())
497             {
498                 case wxITEM_CHECK:
499                     tool->m_item = gtk_toggle_tool_button_new();
500                     g_signal_connect(tool->m_item, "toggled",
501                         G_CALLBACK(item_toggled), tool);
502                     break;
503                 case wxITEM_RADIO:
504                     radioGroup = GetRadioGroup(pos);
505                     if (!radioGroup)
506                     {
507                         // this is the first button in the radio button group,
508                         // it will be toggled automatically by GTK so bring the
509                         // internal flag in sync
510                         tool->Toggle(true);
511                     }
512                     tool->m_item = gtk_radio_tool_button_new(radioGroup);
513                     g_signal_connect(tool->m_item, "toggled",
514                         G_CALLBACK(item_toggled), tool);
515                     break;
516                 default:
517                     wxFAIL_MSG("unknown toolbar child type");
518                     // fall through
519                 case wxITEM_DROPDOWN:
520                 case wxITEM_NORMAL:
521                     tool->m_item = gtk_tool_button_new(NULL, "");
522                     g_signal_connect(tool->m_item, "clicked",
523                         G_CALLBACK(item_clicked), tool);
524                     break;
525             }
526             if (!HasFlag(wxTB_NOICONS))
527             {
528                 GtkWidget* image = gtk_image_new();
529                 gtk_tool_button_set_icon_widget(
530                     GTK_TOOL_BUTTON(tool->m_item), image);
531                 tool->SetImage();
532                 gtk_widget_show(image);
533 #ifdef __WXGTK3__
534                 g_signal_connect(image, "draw",
535                     G_CALLBACK(image_draw), tool);
536 #else
537                 g_signal_connect(image, "expose_event",
538                     G_CALLBACK(image_expose_event), tool);
539 #endif
540             }
541             if (!tool->GetLabel().empty())
542             {
543                 gtk_tool_button_set_label(
544                     GTK_TOOL_BUTTON(tool->m_item), wxGTK_CONV(tool->GetLabel()));
545                 // needed for labels in horizontal toolbar with wxTB_HORZ_LAYOUT
546                 gtk_tool_item_set_is_important(tool->m_item, true);
547             }
548             if (!HasFlag(wxTB_NO_TOOLTIPS) && !tool->GetShortHelp().empty())
549             {
550 #if GTK_CHECK_VERSION(2, 12, 0)
551                 if (GTK_CHECK_VERSION(3,0,0) || gtk_check_version(2,12,0) == NULL)
552                 {
553                     gtk_tool_item_set_tooltip_text(tool->m_item,
554                         wxGTK_CONV(tool->GetShortHelp()));
555                 }
556                 else
557 #endif
558                 {
559 #ifndef __WXGTK3__
560                     gtk_tool_item_set_tooltip(tool->m_item,
561                         m_tooltips, wxGTK_CONV(tool->GetShortHelp()), "");
562 #endif
563                 }
564             }
565             bin_child = gtk_bin_get_child(GTK_BIN(tool->m_item));
566             g_signal_connect(bin_child, "button_press_event",
567                 G_CALLBACK(button_press_event), tool);
568             g_signal_connect(bin_child, "enter_notify_event",
569                 G_CALLBACK(enter_notify_event), tool);
570             g_signal_connect(bin_child, "leave_notify_event",
571                 G_CALLBACK(enter_notify_event), tool);
572 
573             if (tool->GetKind() == wxITEM_DROPDOWN)
574                 tool->CreateDropDown();
575             gtk_toolbar_insert(m_toolbar, tool->m_item, int(pos));
576             break;
577 
578         case wxTOOL_STYLE_SEPARATOR:
579             tool->m_item = gtk_separator_tool_item_new();
580             if ( tool->IsStretchable() )
581             {
582                 gtk_separator_tool_item_set_draw
583                 (
584                     GTK_SEPARATOR_TOOL_ITEM(tool->m_item),
585                     FALSE
586                 );
587                 gtk_tool_item_set_expand(tool->m_item, TRUE);
588             }
589             gtk_toolbar_insert(m_toolbar, tool->m_item, int(pos));
590             break;
591 
592         case wxTOOL_STYLE_CONTROL:
593             wxWindow* control = tool->GetControl();
594             if (gtk_widget_get_parent(control->m_widget) == NULL)
595                 AddChildGTK(control);
596             tool->m_item = GTK_TOOL_ITEM(gtk_widget_get_parent(gtk_widget_get_parent(control->m_widget)));
597             if (gtk_toolbar_get_item_index(m_toolbar, tool->m_item) != int(pos))
598             {
599                 g_object_ref(tool->m_item);
600                 gtk_container_remove(
601                     GTK_CONTAINER(m_toolbar), GTK_WIDGET(tool->m_item));
602                 gtk_toolbar_insert(m_toolbar, tool->m_item, int(pos));
603                 g_object_unref(tool->m_item);
604             }
605             break;
606     }
607     gtk_widget_show(GTK_WIDGET(tool->m_item));
608 
609     InvalidateBestSize();
610 
611     return true;
612 }
613 
DoDeleteTool(size_t,wxToolBarToolBase * toolBase)614 bool wxToolBar::DoDeleteTool(size_t /* pos */, wxToolBarToolBase* toolBase)
615 {
616     wxToolBarTool* tool = static_cast<wxToolBarTool*>(toolBase);
617 
618     if (tool->GetStyle() == wxTOOL_STYLE_CONTROL)
619     {
620         // don't destroy the control here as we can be called from
621         // RemoveTool() and then we need to keep the control alive;
622         // while if we're called from DeleteTool() the control will
623         // be destroyed when wxToolBarToolBase itself is deleted
624         GtkWidget* widget = tool->GetControl()->m_widget;
625         gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(widget)), widget);
626     }
627     gtk_widget_destroy(GTK_WIDGET(tool->m_item));
628     tool->m_item = NULL;
629 
630     InvalidateBestSize();
631     return true;
632 }
633 
GetRadioGroup(size_t pos)634 GSList* wxToolBar::GetRadioGroup(size_t pos)
635 {
636     GSList* radioGroup = NULL;
637     GtkToolItem* item = NULL;
638     if (pos > 0)
639     {
640         item = gtk_toolbar_get_nth_item(m_toolbar, int(pos) - 1);
641         if (!GTK_IS_RADIO_TOOL_BUTTON(item))
642             item = NULL;
643     }
644     if (item == NULL && pos < m_tools.size())
645     {
646         item = gtk_toolbar_get_nth_item(m_toolbar, int(pos));
647         if (!GTK_IS_RADIO_TOOL_BUTTON(item))
648             item = NULL;
649     }
650     if (item)
651         radioGroup = gtk_radio_tool_button_get_group((GtkRadioToolButton*)item);
652     return radioGroup;
653 }
654 
655 // ----------------------------------------------------------------------------
656 // wxToolBar tools state
657 // ----------------------------------------------------------------------------
658 
DoEnableTool(wxToolBarToolBase * toolBase,bool enable)659 void wxToolBar::DoEnableTool(wxToolBarToolBase *toolBase, bool enable)
660 {
661     wxToolBarTool* tool = static_cast<wxToolBarTool*>(toolBase);
662 
663     if (tool->m_item)
664         gtk_widget_set_sensitive(GTK_WIDGET(tool->m_item), enable);
665 }
666 
DoToggleTool(wxToolBarToolBase * toolBase,bool toggle)667 void wxToolBar::DoToggleTool( wxToolBarToolBase *toolBase, bool toggle )
668 {
669     wxToolBarTool* tool = static_cast<wxToolBarTool*>(toolBase);
670 
671     if (tool->m_item)
672     {
673         g_signal_handlers_block_by_func(tool->m_item, (void*)item_toggled, tool);
674 
675         gtk_toggle_tool_button_set_active(
676             GTK_TOGGLE_TOOL_BUTTON(tool->m_item), toggle);
677 
678         g_signal_handlers_unblock_by_func(tool->m_item, (void*)item_toggled, tool);
679     }
680 }
681 
DoSetToggle(wxToolBarToolBase * WXUNUSED (tool),bool WXUNUSED (toggle))682 void wxToolBar::DoSetToggle(wxToolBarToolBase * WXUNUSED(tool),
683                             bool WXUNUSED(toggle))
684 {
685     // VZ: absolutely no idea about how to do it
686     wxFAIL_MSG( wxT("not implemented") );
687 }
688 
689 // ----------------------------------------------------------------------------
690 // wxToolBar geometry
691 // ----------------------------------------------------------------------------
692 
DoGetBestSize() const693 wxSize wxToolBar::DoGetBestSize() const
694 {
695     // Unfortunately, if overflow arrow is enabled GtkToolbar only reports size
696     // of arrow. To get the real size, the arrow is temporarily disabled here.
697     // This is gross, since it will cause a queue_resize, and could potentially
698     // lead to an infinite loop. But there seems to be no alternative, short of
699     // disabling the arrow entirely.
700     gtk_toolbar_set_show_arrow(m_toolbar, false);
701     const wxSize size = wxToolBarBase::DoGetBestSize();
702     gtk_toolbar_set_show_arrow(m_toolbar, true);
703     return size;
704 }
705 
FindToolForPosition(wxCoord WXUNUSED (x),wxCoord WXUNUSED (y)) const706 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord WXUNUSED(x),
707                                                   wxCoord WXUNUSED(y)) const
708 {
709     // VZ: GTK+ doesn't seem to have such thing
710     wxFAIL_MSG( wxT("wxToolBar::FindToolForPosition() not implemented") );
711 
712     return NULL;
713 }
714 
SetToolShortHelp(int id,const wxString & helpString)715 void wxToolBar::SetToolShortHelp( int id, const wxString& helpString )
716 {
717     wxToolBarTool* tool = static_cast<wxToolBarTool*>(FindById(id));
718 
719     if ( tool )
720     {
721         (void)tool->SetShortHelp(helpString);
722         if (tool->m_item)
723         {
724 #if GTK_CHECK_VERSION(2, 12, 0)
725             if (GTK_CHECK_VERSION(3,0,0) || gtk_check_version(2,12,0) == NULL)
726             {
727                 gtk_tool_item_set_tooltip_text(tool->m_item,
728                     wxGTK_CONV(helpString));
729             }
730             else
731 #endif
732             {
733 #ifndef __WXGTK3__
734                 gtk_tool_item_set_tooltip(tool->m_item,
735                     m_tooltips, wxGTK_CONV(helpString), "");
736 #endif
737             }
738         }
739     }
740 }
741 
SetToolNormalBitmap(int id,const wxBitmap & bitmap)742 void wxToolBar::SetToolNormalBitmap( int id, const wxBitmap& bitmap )
743 {
744     wxToolBarTool* tool = static_cast<wxToolBarTool*>(FindById(id));
745     if ( tool )
746     {
747         wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
748 
749         tool->SetNormalBitmap(bitmap);
750         tool->SetImage();
751     }
752 }
753 
SetToolDisabledBitmap(int id,const wxBitmap & bitmap)754 void wxToolBar::SetToolDisabledBitmap( int id, const wxBitmap& bitmap )
755 {
756     wxToolBarTool* tool = static_cast<wxToolBarTool*>(FindById(id));
757     if ( tool )
758     {
759         wxCHECK_RET( tool->IsButton(), wxT("Can only set bitmap on button tools."));
760 
761         tool->SetDisabledBitmap(bitmap);
762     }
763 }
764 
765 // ----------------------------------------------------------------------------
766 
767 // static
768 wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant WXUNUSED (variant))769 wxToolBar::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
770 {
771     return GetDefaultAttributesFromGTKWidget(gtk_toolbar_new());
772 }
773 
774 #endif // wxUSE_TOOLBAR_NATIVE
775