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