]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/tbargtk.cpp
5c319548a45624435dbc9f8f6976441a824d2529
[wxWidgets.git] / src / gtk1 / tbargtk.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: tbargtk.cpp
3 // Purpose: GTK toolbar
4 // Author: Robert Roebling
5 // Modified: 13.12.99 by VZ to derive from wxToolBarBase
6 // RCS-ID: $Id$
7 // Copyright: (c) Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #ifdef __GNUG__
20 #pragma implementation "tbargtk.h"
21 #endif
22
23 #include "wx/toolbar.h"
24
25 #if wxUSE_TOOLBAR_NATIVE
26
27 #include "wx/frame.h"
28
29 #include <glib.h>
30 #include "wx/gtk/private.h"
31
32 extern GdkFont *GtkGetDefaultGuiFont();
33
34 // ----------------------------------------------------------------------------
35 // globals
36 // ----------------------------------------------------------------------------
37
38 // idle system
39 extern void wxapp_install_idle_handler();
40 extern bool g_isIdle;
41
42 // data
43 extern bool g_blockEventsOnDrag;
44 extern wxCursor g_globalCursor;
45
46 // ----------------------------------------------------------------------------
47 // private functions
48 // ----------------------------------------------------------------------------
49
50 // translate wxWindows toolbar style flags to GTK orientation and style
51 static void GetGtkStyle(long style,
52 GtkOrientation *orient, GtkToolbarStyle *gtkStyle)
53 {
54 *orient = style & wxTB_VERTICAL ? GTK_ORIENTATION_VERTICAL
55 : GTK_ORIENTATION_HORIZONTAL;
56
57
58 if ( style & wxTB_TEXT )
59 {
60 *gtkStyle = style & wxTB_NOICONS ? GTK_TOOLBAR_TEXT :
61 ( style & wxTB_HORZ_LAYOUT ? GTK_TOOLBAR_BOTH_HORIZ: GTK_TOOLBAR_BOTH );
62 }
63 else // no text, hence we must have the icons or what would we show?
64 {
65 *gtkStyle = GTK_TOOLBAR_ICONS;
66 }
67 }
68
69 // ----------------------------------------------------------------------------
70 // wxToolBarTool
71 // ----------------------------------------------------------------------------
72
73 class wxToolBarTool : public wxToolBarToolBase
74 {
75 public:
76 wxToolBarTool(wxToolBar *tbar,
77 int id,
78 const wxString& label,
79 const wxBitmap& bitmap1,
80 const wxBitmap& bitmap2,
81 wxItemKind kind,
82 wxObject *clientData,
83 const wxString& shortHelpString,
84 const wxString& longHelpString)
85 : wxToolBarToolBase(tbar, id, label, bitmap1, bitmap2, kind,
86 clientData, shortHelpString, longHelpString)
87 {
88 Init();
89 }
90
91 wxToolBarTool(wxToolBar *tbar, wxControl *control)
92 : wxToolBarToolBase(tbar, control)
93 {
94 Init();
95 }
96
97 // is this a radio button?
98 //
99 // unlike GetKind(), can be called for any kind of tools, not just buttons
100 bool IsRadio() const { return IsButton() && GetKind() == wxITEM_RADIO; }
101
102 // this is only called for the normal buttons, i.e. not separators nor
103 // controls
104 GtkToolbarChildType GetGtkChildType() const
105 {
106 switch ( GetKind() )
107 {
108 case wxITEM_CHECK:
109 return GTK_TOOLBAR_CHILD_TOGGLEBUTTON;
110
111 case wxITEM_RADIO:
112 return GTK_TOOLBAR_CHILD_RADIOBUTTON;
113
114 default:
115 wxFAIL_MSG( _T("unknown toolbar child type") );
116 // fall through
117
118 case wxITEM_NORMAL:
119 return GTK_TOOLBAR_CHILD_BUTTON;
120 }
121 }
122
123 GtkWidget *m_item;
124 GtkWidget *m_pixmap;
125
126 protected:
127 void Init();
128 };
129
130 // ----------------------------------------------------------------------------
131 // wxWin macros
132 // ----------------------------------------------------------------------------
133
134 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxToolBarBase)
135
136 // ============================================================================
137 // implementation
138 // ============================================================================
139
140 //-----------------------------------------------------------------------------
141 // "clicked" (internal from gtk_toolbar)
142 //-----------------------------------------------------------------------------
143
144 static void gtk_toolbar_callback( GtkWidget *WXUNUSED(widget),
145 wxToolBarTool *tool )
146 {
147 if (g_isIdle)
148 wxapp_install_idle_handler();
149
150 wxToolBar *tbar = (wxToolBar *)tool->GetToolBar();
151
152 if (tbar->m_blockEvent) return;
153
154 if (g_blockEventsOnDrag) return;
155 if (!tool->IsEnabled()) return;
156
157 if (tool->CanBeToggled())
158 {
159 tool->Toggle();
160
161 wxBitmap bitmap = tool->GetBitmap();
162 if ( bitmap.Ok() )
163 {
164 GtkPixmap *pixmap = GTK_PIXMAP( tool->m_pixmap );
165
166 GdkBitmap *mask = bitmap.GetMask() ? bitmap.GetMask()->GetBitmap()
167 : (GdkBitmap *)NULL;
168
169 gtk_pixmap_set( pixmap, bitmap.GetPixmap(), mask );
170 }
171
172 if ( tool->IsRadio() && !tool->IsToggled() )
173 {
174 // radio button went up, don't report this as a wxWin event
175 return;
176 }
177 }
178
179 tbar->OnLeftClick( tool->GetId(), tool->IsToggled() );
180 }
181
182 //-----------------------------------------------------------------------------
183 // "enter_notify_event" / "leave_notify_event"
184 //-----------------------------------------------------------------------------
185
186 static gint gtk_toolbar_tool_callback( GtkWidget *WXUNUSED(widget),
187 GdkEventCrossing *gdk_event,
188 wxToolBarTool *tool )
189 {
190 if (g_isIdle) wxapp_install_idle_handler();
191
192 if (g_blockEventsOnDrag) return TRUE;
193
194 wxToolBar *tb = (wxToolBar *)tool->GetToolBar();
195
196 // emit the event
197 if( gdk_event->type == GDK_ENTER_NOTIFY )
198 tb->OnMouseEnter( tool->GetId() );
199 else
200 tb->OnMouseEnter( -1 );
201
202 return FALSE;
203 }
204
205 //-----------------------------------------------------------------------------
206 // InsertChild callback for wxToolBar
207 //-----------------------------------------------------------------------------
208
209 static void wxInsertChildInToolBar( wxToolBar* WXUNUSED(parent),
210 wxWindow* WXUNUSED(child) )
211 {
212 // we don't do anything here
213 }
214
215 // ----------------------------------------------------------------------------
216 // wxToolBarTool
217 // ----------------------------------------------------------------------------
218
219 void wxToolBarTool::Init()
220 {
221 m_item =
222 m_pixmap = (GtkWidget *)NULL;
223 }
224
225 wxToolBarToolBase *wxToolBar::CreateTool(int id,
226 const wxString& text,
227 const wxBitmap& bitmap1,
228 const wxBitmap& bitmap2,
229 wxItemKind kind,
230 wxObject *clientData,
231 const wxString& shortHelpString,
232 const wxString& longHelpString)
233 {
234 return new wxToolBarTool(this, id, text, bitmap1, bitmap2, kind,
235 clientData, shortHelpString, longHelpString);
236 }
237
238 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
239 {
240 return new wxToolBarTool(this, control);
241 }
242
243 //-----------------------------------------------------------------------------
244 // wxToolBar construction
245 //-----------------------------------------------------------------------------
246
247 void wxToolBar::Init()
248 {
249 m_fg =
250 m_bg = (GdkColor *)NULL;
251 m_toolbar = (GtkToolbar *)NULL;
252 m_blockEvent = FALSE;
253 }
254
255 wxToolBar::~wxToolBar()
256 {
257 delete m_fg;
258 delete m_bg;
259 }
260
261 bool wxToolBar::Create( wxWindow *parent,
262 wxWindowID id,
263 const wxPoint& pos,
264 const wxSize& size,
265 long style,
266 const wxString& name )
267 {
268 m_needParent = TRUE;
269 m_insertCallback = (wxInsertChildFunction)wxInsertChildInToolBar;
270
271 if ( !PreCreation( parent, pos, size ) ||
272 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
273 {
274 wxFAIL_MSG( wxT("wxToolBar creation failed") );
275
276 return FALSE;
277 }
278
279 #ifdef __WXGTK20__
280 m_toolbar = GTK_TOOLBAR( gtk_toolbar_new() );
281 GtkSetStyle();
282
283 // Doesn't work this way.
284 // GtkToolbarSpaceStyle space_style = GTK_TOOLBAR_SPACE_EMPTY;
285 // gtk_widget_style_set (GTK_WIDGET (m_toolbar), "space_style", &space_style, NULL);
286 #else
287 GtkOrientation orient;
288 GtkToolbarStyle gtkStyle;
289 GetGtkStyle(style, &orient, &gtkStyle);
290
291 m_toolbar = GTK_TOOLBAR( gtk_toolbar_new(orient, gtkStyle) );
292 #endif
293
294 SetToolSeparation(7);
295
296 if (style & wxTB_DOCKABLE)
297 {
298 m_widget = gtk_handle_box_new();
299 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_toolbar) );
300 gtk_widget_show( GTK_WIDGET(m_toolbar) );
301
302 if (style & wxTB_FLAT)
303 gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(m_widget), GTK_SHADOW_NONE );
304 }
305 else
306 {
307 m_widget = gtk_event_box_new();
308 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_toolbar) );
309 ConnectWidget( m_widget );
310 gtk_widget_show(GTK_WIDGET(m_toolbar));
311 }
312
313 gtk_toolbar_set_tooltips( GTK_TOOLBAR(m_toolbar), TRUE );
314
315 // FIXME: there is no such function for toolbars in 2.0
316 #ifndef __WXGTK20__
317 if (style & wxTB_FLAT)
318 gtk_toolbar_set_button_relief( GTK_TOOLBAR(m_toolbar), GTK_RELIEF_NONE );
319 #endif
320
321
322 m_fg = new GdkColor;
323 m_fg->red = 0;
324 m_fg->green = 0;
325 m_fg->blue = 0;
326 wxColour fg(0,0,0);
327 fg.CalcPixel( gtk_widget_get_colormap( GTK_WIDGET(m_toolbar) ) );
328 m_fg->pixel = fg.GetPixel();
329
330 m_bg = new GdkColor;
331 m_bg->red = 65535;
332 m_bg->green = 65535;
333 m_bg->blue = 49980;
334 wxColour bg(255,255,196);
335 bg.CalcPixel( gtk_widget_get_colormap( GTK_WIDGET(m_toolbar) ) );
336 m_bg->pixel = bg.GetPixel();
337
338 gtk_tooltips_force_window( GTK_TOOLBAR(m_toolbar)->tooltips );
339
340 GtkStyle *g_style =
341 gtk_style_copy(
342 gtk_widget_get_style(
343 GTK_TOOLBAR(m_toolbar)->tooltips->tip_window ) );
344
345 g_style->bg[GTK_STATE_NORMAL] = *m_bg;
346
347 gtk_widget_set_style( GTK_TOOLBAR(m_toolbar)->tooltips->tip_window, g_style );
348
349 m_parent->DoAddChild( this );
350
351 PostCreation();
352
353 Show( TRUE );
354
355 return TRUE;
356 }
357
358 void wxToolBar::GtkSetStyle()
359 {
360 GtkOrientation orient;
361 GtkToolbarStyle style;
362 GetGtkStyle(GetWindowStyle(), &orient, &style);
363
364 gtk_toolbar_set_orientation(m_toolbar, orient);
365 gtk_toolbar_set_style(m_toolbar, style);
366 }
367
368 void wxToolBar::SetWindowStyleFlag( long style )
369 {
370 wxToolBarBase::SetWindowStyleFlag(style);
371
372 if ( m_toolbar )
373 GtkSetStyle();
374 }
375
376 bool wxToolBar::DoInsertTool(size_t pos, wxToolBarToolBase *toolBase)
377 {
378 wxToolBarTool *tool = (wxToolBarTool *)toolBase;
379
380 #ifndef __WXGTK20__
381 // if we have inserted a space before all the tools we must change the GTK
382 // index by 1
383 size_t posGtk = m_xMargin > 1 ? pos + 1 : pos;
384 #else
385 size_t posGtk = pos;
386 #endif
387
388 if ( tool->IsButton() )
389 {
390 if ( !HasFlag(wxTB_NOICONS) )
391 {
392 wxBitmap bitmap = tool->GetNormalBitmap();
393
394 wxCHECK_MSG( bitmap.Ok(), FALSE,
395 wxT("invalid bitmap for wxToolBar icon") );
396
397 wxCHECK_MSG( bitmap.GetBitmap() == NULL, FALSE,
398 wxT("wxToolBar doesn't support GdkBitmap") );
399
400 wxCHECK_MSG( bitmap.GetPixmap() != NULL, FALSE,
401 wxT("wxToolBar::Add needs a wxBitmap") );
402
403 GtkWidget *tool_pixmap = (GtkWidget *)NULL;
404
405 GdkPixmap *pixmap = bitmap.GetPixmap();
406
407 GdkBitmap *mask = (GdkBitmap *)NULL;
408 if ( bitmap.GetMask() )
409 mask = bitmap.GetMask()->GetBitmap();
410
411 tool_pixmap = gtk_pixmap_new( pixmap, mask );
412 gtk_pixmap_set_build_insensitive( GTK_PIXMAP(tool_pixmap), TRUE );
413
414 gtk_misc_set_alignment( GTK_MISC(tool_pixmap), 0.5, 0.5 );
415
416 tool->m_pixmap = tool_pixmap;
417 }
418 }
419
420 switch ( tool->GetStyle() )
421 {
422 case wxTOOL_STYLE_BUTTON:
423 // for a radio button we need the widget which starts the radio
424 // group it belongs to, i.e. the first radio button immediately
425 // preceding this one
426 {
427 GtkWidget *widget = NULL;
428
429 if ( tool->IsRadio() )
430 {
431 wxToolBarToolsList::Node *node = pos ? m_tools.Item(pos - 1)
432 : NULL;
433 while ( node )
434 {
435 wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
436 if ( !tool->IsRadio() )
437 break;
438
439 widget = tool->m_item;
440
441 node = node->GetPrevious();
442 }
443
444 if ( !widget )
445 {
446 // this is the first button in the radio button group,
447 // it will be toggled automatically by GTK so bring the
448 // internal flag in sync
449 tool->Toggle(TRUE);
450 }
451 }
452
453 tool->m_item = gtk_toolbar_insert_element
454 (
455 m_toolbar,
456 tool->GetGtkChildType(),
457 widget,
458 tool->GetLabel().empty()
459 ? NULL
460 : (const char*) wxGTK_CONV( tool->GetLabel() ),
461 tool->GetShortHelp().empty()
462 ? NULL
463 : (const char*) wxGTK_CONV( tool->GetShortHelp() ),
464 "", // tooltip_private_text (?)
465 tool->m_pixmap,
466 (GtkSignalFunc)gtk_toolbar_callback,
467 (gpointer)tool,
468 posGtk
469 );
470
471 if ( !tool->m_item )
472 {
473 wxFAIL_MSG( _T("gtk_toolbar_insert_element() failed") );
474
475 return FALSE;
476 }
477
478 gtk_signal_connect( GTK_OBJECT(tool->m_item),
479 "enter_notify_event",
480 GTK_SIGNAL_FUNC(gtk_toolbar_tool_callback),
481 (gpointer)tool );
482 gtk_signal_connect( GTK_OBJECT(tool->m_item),
483 "leave_notify_event",
484 GTK_SIGNAL_FUNC(gtk_toolbar_tool_callback),
485 (gpointer)tool );
486 }
487 break;
488
489 case wxTOOL_STYLE_SEPARATOR:
490 gtk_toolbar_insert_space( m_toolbar, posGtk );
491
492 // skip the rest
493 return TRUE;
494
495 case wxTOOL_STYLE_CONTROL:
496 gtk_toolbar_insert_widget(
497 m_toolbar,
498 tool->GetControl()->m_widget,
499 (const char *) NULL,
500 (const char *) NULL,
501 posGtk
502 );
503 break;
504 }
505
506 GtkRequisition req;
507 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_widget) )->size_request )
508 (m_widget, &req );
509 m_width = req.width + m_xMargin;
510 m_height = req.height + 2*m_yMargin;
511
512 return TRUE;
513 }
514
515 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
516 {
517 wxToolBarTool *tool = (wxToolBarTool *)toolBase;
518
519 switch ( tool->GetStyle() )
520 {
521 case wxTOOL_STYLE_CONTROL:
522 tool->GetControl()->Destroy();
523 break;
524
525 case wxTOOL_STYLE_BUTTON:
526 gtk_widget_destroy( tool->m_item );
527 break;
528
529 //case wxTOOL_STYLE_SEPARATOR: -- nothing to do
530 }
531
532 return TRUE;
533 }
534
535 // ----------------------------------------------------------------------------
536 // wxToolBar tools state
537 // ----------------------------------------------------------------------------
538
539 void wxToolBar::DoEnableTool(wxToolBarToolBase *toolBase, bool enable)
540 {
541 wxToolBarTool *tool = (wxToolBarTool *)toolBase;
542
543 if (tool->m_item)
544 {
545 gtk_widget_set_sensitive( tool->m_item, enable );
546 }
547 }
548
549 void wxToolBar::DoToggleTool( wxToolBarToolBase *toolBase, bool toggle )
550 {
551 wxToolBarTool *tool = (wxToolBarTool *)toolBase;
552
553 GtkWidget *item = tool->m_item;
554 if ( item && GTK_IS_TOGGLE_BUTTON(item) )
555 {
556 wxBitmap bitmap = tool->GetBitmap();
557 if ( bitmap.Ok() )
558 {
559 GtkPixmap *pixmap = GTK_PIXMAP( tool->m_pixmap );
560
561 GdkBitmap *mask = bitmap.GetMask() ? bitmap.GetMask()->GetBitmap()
562 : (GdkBitmap *)NULL;
563
564 gtk_pixmap_set( pixmap, bitmap.GetPixmap(), mask );
565 }
566
567 m_blockEvent = TRUE;
568
569 gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(item), toggle );
570
571 m_blockEvent = FALSE;
572 }
573 }
574
575 void wxToolBar::DoSetToggle(wxToolBarToolBase * WXUNUSED(tool),
576 bool WXUNUSED(toggle))
577 {
578 // VZ: absolutely no idea about how to do it
579 wxFAIL_MSG( _T("not implemented") );
580 }
581
582 // ----------------------------------------------------------------------------
583 // wxToolBar geometry
584 // ----------------------------------------------------------------------------
585
586 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord WXUNUSED(x),
587 wxCoord WXUNUSED(y)) const
588 {
589 // VZ: GTK+ doesn't seem to have such thing
590 wxFAIL_MSG( _T("wxToolBar::FindToolForPosition() not implemented") );
591
592 return (wxToolBarToolBase *)NULL;
593 }
594
595 void wxToolBar::SetMargins( int x, int y )
596 {
597 wxCHECK_RET( GetToolsCount() == 0,
598 wxT("wxToolBar::SetMargins must be called before adding tools.") );
599
600 #ifndef __WXGTK20__
601 if (x > 1)
602 gtk_toolbar_append_space( m_toolbar ); // oh well
603 #endif
604
605 m_xMargin = x;
606 m_yMargin = y;
607 }
608
609 void wxToolBar::SetToolSeparation( int separation )
610 {
611 // FIXME: this function disappeared
612 #ifndef __WXGTK20__
613 gtk_toolbar_set_space_size( m_toolbar, separation );
614 #endif
615
616 m_toolSeparation = separation;
617 }
618
619 void wxToolBar::SetToolShortHelp( int id, const wxString& helpString )
620 {
621 wxToolBarTool *tool = (wxToolBarTool *)FindById(id);
622
623 if ( tool )
624 {
625 (void)tool->SetShortHelp(helpString);
626 gtk_tooltips_set_tip(m_toolbar->tooltips, tool->m_item,
627 wxGTK_CONV( helpString ), "");
628 }
629 }
630
631 // ----------------------------------------------------------------------------
632 // wxToolBar idle handling
633 // ----------------------------------------------------------------------------
634
635 void wxToolBar::OnInternalIdle()
636 {
637 wxCursor cursor = m_cursor;
638 if (g_globalCursor.Ok()) cursor = g_globalCursor;
639
640 if (cursor.Ok())
641 {
642 /* I now set the cursor the anew in every OnInternalIdle call
643 as setting the cursor in a parent window also effects the
644 windows above so that checking for the current cursor is
645 not possible. */
646
647 if (HasFlag(wxTB_DOCKABLE) && (m_widget->window))
648 {
649 /* if the toolbar is dockable, then m_widget stands for the
650 GtkHandleBox widget, which uses its own window so that we
651 can set the cursor for it. if the toolbar is not dockable,
652 m_widget comes from m_toolbar which uses its parent's
653 window ("windowless windows") and thus we cannot set the
654 cursor. */
655 gdk_window_set_cursor( m_widget->window, cursor.GetCursor() );
656 }
657
658 wxToolBarToolsList::Node *node = m_tools.GetFirst();
659 while ( node )
660 {
661 wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
662 node = node->GetNext();
663
664 GtkWidget *item = tool->m_item;
665 if ( item )
666 {
667 GdkWindow *window = item->window;
668
669 if ( window )
670 {
671 gdk_window_set_cursor( window, cursor.GetCursor() );
672 }
673 }
674 }
675 }
676
677 if (wxUpdateUIEvent::CanUpdate(this))
678 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
679 }
680
681 #endif // wxUSE_TOOLBAR_NATIVE