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