]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/tbargtk.cpp
applied patch 528960 (a few minor bug fixes)
[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 // wxToolBarTool
48 // ----------------------------------------------------------------------------
49
50 class wxToolBarTool : public wxToolBarToolBase
51 {
52 public:
53 wxToolBarTool(wxToolBar *tbar,
54 int id,
55 const wxBitmap& bitmap1,
56 const wxBitmap& bitmap2,
57 bool toggle,
58 wxObject *clientData,
59 const wxString& shortHelpString,
60 const wxString& longHelpString)
61 : wxToolBarToolBase(tbar, id, bitmap1, bitmap2, toggle,
62 clientData, shortHelpString, longHelpString)
63 {
64 Init();
65 }
66
67 wxToolBarTool(wxToolBar *tbar, wxControl *control)
68 : wxToolBarToolBase(tbar, control)
69 {
70 Init();
71 }
72
73 GtkWidget *m_item;
74 GtkWidget *m_pixmap;
75
76 protected:
77 void Init();
78 };
79
80 // ----------------------------------------------------------------------------
81 // wxWin macros
82 // ----------------------------------------------------------------------------
83
84 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxToolBarBase)
85
86 // ============================================================================
87 // implementation
88 // ============================================================================
89
90 //-----------------------------------------------------------------------------
91 // "clicked" (internal from gtk_toolbar)
92 //-----------------------------------------------------------------------------
93
94 static void gtk_toolbar_callback( GtkWidget *WXUNUSED(widget),
95 wxToolBarTool *tool )
96 {
97 if (g_isIdle)
98 wxapp_install_idle_handler();
99
100 wxToolBar *tbar = (wxToolBar *)tool->GetToolBar();
101
102 if (tbar->m_blockEvent) return;
103
104 if (g_blockEventsOnDrag) return;
105 if (!tool->IsEnabled()) return;
106
107 if (tool->CanBeToggled())
108 {
109 tool->Toggle();
110
111 wxBitmap bitmap = tool->GetBitmap();
112 if ( bitmap.Ok() )
113 {
114 GtkPixmap *pixmap = GTK_PIXMAP( tool->m_pixmap );
115
116 GdkBitmap *mask = bitmap.GetMask() ? bitmap.GetMask()->GetBitmap()
117 : (GdkBitmap *)NULL;
118
119 gtk_pixmap_set( pixmap, bitmap.GetPixmap(), mask );
120 }
121 }
122
123 tbar->OnLeftClick( tool->GetId(), tool->IsToggled() );
124 }
125
126 //-----------------------------------------------------------------------------
127 // "enter_notify_event" / "leave_notify_event"
128 //-----------------------------------------------------------------------------
129
130 static gint gtk_toolbar_tool_callback( GtkWidget *WXUNUSED(widget),
131 GdkEventCrossing *gdk_event,
132 wxToolBarTool *tool )
133 {
134 if (g_isIdle) wxapp_install_idle_handler();
135
136 if (g_blockEventsOnDrag) return TRUE;
137
138 wxToolBar *tb = (wxToolBar *)tool->GetToolBar();
139
140 // emit the event
141 if( gdk_event->type == GDK_ENTER_NOTIFY )
142 tb->OnMouseEnter( tool->GetId() );
143 else
144 tb->OnMouseEnter( -1 );
145
146 return FALSE;
147 }
148
149 //-----------------------------------------------------------------------------
150 // InsertChild callback for wxToolBar
151 //-----------------------------------------------------------------------------
152
153 static void wxInsertChildInToolBar( wxToolBar* WXUNUSED(parent),
154 wxWindow* WXUNUSED(child) )
155 {
156 // we don't do anything here
157 }
158
159 // ----------------------------------------------------------------------------
160 // wxToolBarTool
161 // ----------------------------------------------------------------------------
162
163 void wxToolBarTool::Init()
164 {
165 m_item =
166 m_pixmap = (GtkWidget *)NULL;
167 }
168
169 wxToolBarToolBase *wxToolBar::CreateTool(int id,
170 const wxBitmap& bitmap1,
171 const wxBitmap& bitmap2,
172 bool toggle,
173 wxObject *clientData,
174 const wxString& shortHelpString,
175 const wxString& longHelpString)
176 {
177 return new wxToolBarTool(this, id, bitmap1, bitmap2, toggle,
178 clientData, shortHelpString, longHelpString);
179 }
180
181 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
182 {
183 return new wxToolBarTool(this, control);
184 }
185
186 //-----------------------------------------------------------------------------
187 // wxToolBar construction
188 //-----------------------------------------------------------------------------
189
190 void wxToolBar::Init()
191 {
192 m_fg =
193 m_bg = (GdkColor *)NULL;
194 m_toolbar = (GtkToolbar *)NULL;
195 m_blockEvent = FALSE;
196 }
197
198 wxToolBar::~wxToolBar()
199 {
200 delete m_fg;
201 delete m_bg;
202 }
203
204 bool wxToolBar::Create( wxWindow *parent,
205 wxWindowID id,
206 const wxPoint& pos,
207 const wxSize& size,
208 long style,
209 const wxString& name )
210 {
211 m_needParent = TRUE;
212 m_insertCallback = (wxInsertChildFunction)wxInsertChildInToolBar;
213
214 if ( !PreCreation( parent, pos, size ) ||
215 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
216 {
217 wxFAIL_MSG( wxT("wxToolBar creation failed") );
218
219 return FALSE;
220 }
221
222 GtkOrientation orient = style & wxTB_VERTICAL ? GTK_ORIENTATION_VERTICAL
223 : GTK_ORIENTATION_HORIZONTAL;
224
225 #ifdef __WXGTK20__
226 m_toolbar = GTK_TOOLBAR( gtk_toolbar_new() );
227 gtk_toolbar_set_orientation(m_toolbar, orient);
228 gtk_toolbar_set_style(m_toolbar, GTK_TOOLBAR_ICONS);
229 #else
230 m_toolbar = GTK_TOOLBAR( gtk_toolbar_new( orient, GTK_TOOLBAR_ICONS ) );
231 #endif
232
233 SetToolSeparation(7);
234
235 if (style & wxTB_DOCKABLE)
236 {
237 m_widget = gtk_handle_box_new();
238 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_toolbar) );
239 gtk_widget_show( GTK_WIDGET(m_toolbar) );
240
241 if (style & wxTB_FLAT)
242 gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(m_widget), GTK_SHADOW_NONE );
243 }
244 else
245 {
246 m_widget = GTK_WIDGET(m_toolbar);
247 }
248
249 gtk_toolbar_set_tooltips( GTK_TOOLBAR(m_toolbar), TRUE );
250
251 // FIXME: there is no such function for toolbars in 2.0
252 #ifndef __WXGTK20__
253 if (style & wxTB_FLAT)
254 gtk_toolbar_set_button_relief( GTK_TOOLBAR(m_toolbar), GTK_RELIEF_NONE );
255 #endif
256
257
258 m_fg = new GdkColor;
259 m_fg->red = 0;
260 m_fg->green = 0;
261 m_fg->blue = 0;
262 wxColour fg(0,0,0);
263 fg.CalcPixel( gtk_widget_get_colormap( GTK_WIDGET(m_toolbar) ) );
264 m_fg->pixel = fg.GetPixel();
265
266 m_bg = new GdkColor;
267 m_bg->red = 65535;
268 m_bg->green = 65535;
269 m_bg->blue = 49980;
270 wxColour bg(255,255,196);
271 bg.CalcPixel( gtk_widget_get_colormap( GTK_WIDGET(m_toolbar) ) );
272 m_bg->pixel = bg.GetPixel();
273
274 gtk_tooltips_force_window( GTK_TOOLBAR(m_toolbar)->tooltips );
275
276 GtkStyle *g_style =
277 gtk_style_copy(
278 gtk_widget_get_style(
279 GTK_TOOLBAR(m_toolbar)->tooltips->tip_window ) );
280
281 g_style->bg[GTK_STATE_NORMAL] = *m_bg;
282
283 SET_STYLE_FONT(g_style, GtkGetDefaultGuiFont());
284
285 gtk_widget_set_style( GTK_TOOLBAR(m_toolbar)->tooltips->tip_window, g_style );
286
287 m_parent->DoAddChild( this );
288
289 PostCreation();
290
291 Show( TRUE );
292
293 return TRUE;
294 }
295
296 bool wxToolBar::DoInsertTool(size_t pos, wxToolBarToolBase *toolBase)
297 {
298 wxToolBarTool *tool = (wxToolBarTool *)toolBase;
299
300 // we have inserted a space before all the tools
301 if (m_xMargin > 1) pos++;
302
303 if ( tool->IsButton() )
304 {
305 wxBitmap bitmap = tool->GetBitmap1();
306
307 wxCHECK_MSG( bitmap.Ok(), FALSE,
308 wxT("invalid bitmap for wxToolBar icon") );
309
310 wxCHECK_MSG( bitmap.GetBitmap() == NULL, FALSE,
311 wxT("wxToolBar doesn't support GdkBitmap") );
312
313 wxCHECK_MSG( bitmap.GetPixmap() != NULL, FALSE,
314 wxT("wxToolBar::Add needs a wxBitmap") );
315
316 GtkWidget *tool_pixmap = (GtkWidget *)NULL;
317
318 GdkPixmap *pixmap = bitmap.GetPixmap();
319
320 GdkBitmap *mask = (GdkBitmap *)NULL;
321 if ( bitmap.GetMask() )
322 mask = bitmap.GetMask()->GetBitmap();
323
324 tool_pixmap = gtk_pixmap_new( pixmap, mask );
325 #if (GTK_MINOR_VERSION > 0)
326 gtk_pixmap_set_build_insensitive( GTK_PIXMAP(tool_pixmap), TRUE );
327 #endif
328
329 gtk_misc_set_alignment( GTK_MISC(tool_pixmap), 0.5, 0.5 );
330
331 tool->m_pixmap = tool_pixmap;
332 }
333
334 switch ( tool->GetStyle() )
335 {
336 case wxTOOL_STYLE_BUTTON:
337 tool->m_item = gtk_toolbar_insert_element
338 (
339 m_toolbar,
340 tool->CanBeToggled()
341 ? GTK_TOOLBAR_CHILD_TOGGLEBUTTON
342 : GTK_TOOLBAR_CHILD_BUTTON,
343 (GtkWidget *)NULL,
344 (const char *)NULL,
345 tool->GetShortHelp().mbc_str(),
346 "", // tooltip_private_text (?)
347 tool->m_pixmap,
348 (GtkSignalFunc)gtk_toolbar_callback,
349 (gpointer)tool,
350 pos
351 );
352
353 if ( !tool->m_item )
354 {
355 wxFAIL_MSG( _T("gtk_toolbar_insert_element() failed") );
356
357 return FALSE;
358 }
359
360 gtk_signal_connect( GTK_OBJECT(tool->m_item),
361 "enter_notify_event",
362 GTK_SIGNAL_FUNC(gtk_toolbar_tool_callback),
363 (gpointer)tool );
364 gtk_signal_connect( GTK_OBJECT(tool->m_item),
365 "leave_notify_event",
366 GTK_SIGNAL_FUNC(gtk_toolbar_tool_callback),
367 (gpointer)tool );
368 break;
369
370 case wxTOOL_STYLE_SEPARATOR:
371 gtk_toolbar_insert_space( m_toolbar, pos );
372
373 // skip the rest
374 return TRUE;
375
376 case wxTOOL_STYLE_CONTROL:
377 gtk_toolbar_insert_widget(
378 m_toolbar,
379 tool->GetControl()->m_widget,
380 (const char *) NULL,
381 (const char *) NULL,
382 pos
383 );
384 break;
385 }
386
387 GtkRequisition req;
388 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_widget) )->size_request )
389 (m_widget, &req );
390 m_width = req.width + m_xMargin;
391 m_height = req.height + 2*m_yMargin;
392
393 return TRUE;
394 }
395
396 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
397 {
398 wxToolBarTool *tool = (wxToolBarTool *)toolBase;
399
400 switch ( tool->GetStyle() )
401 {
402 case wxTOOL_STYLE_CONTROL:
403 tool->GetControl()->Destroy();
404 break;
405
406 case wxTOOL_STYLE_BUTTON:
407 gtk_widget_destroy( tool->m_item );
408 break;
409
410 //case wxTOOL_STYLE_SEPARATOR: -- nothing to do
411 }
412
413 return TRUE;
414 }
415
416 // ----------------------------------------------------------------------------
417 // wxToolBar tools state
418 // ----------------------------------------------------------------------------
419
420 void wxToolBar::DoEnableTool(wxToolBarToolBase *toolBase, bool enable)
421 {
422 #if (GTK_MINOR_VERSION > 0)
423 wxToolBarTool *tool = (wxToolBarTool *)toolBase;
424
425 /* we don't disable the tools for GTK 1.0 as the bitmaps don't get
426 greyed anyway and this also disables tooltips */
427 if (tool->m_item)
428 gtk_widget_set_sensitive( tool->m_item, enable );
429 #endif
430 }
431
432 void wxToolBar::DoToggleTool( wxToolBarToolBase *toolBase, bool toggle )
433 {
434 wxToolBarTool *tool = (wxToolBarTool *)toolBase;
435
436 GtkWidget *item = tool->m_item;
437 if ( item && GTK_IS_TOGGLE_BUTTON(item) )
438 {
439 wxBitmap bitmap = tool->GetBitmap();
440 if ( bitmap.Ok() )
441 {
442 GtkPixmap *pixmap = GTK_PIXMAP( tool->m_pixmap );
443
444 GdkBitmap *mask = bitmap.GetMask() ? bitmap.GetMask()->GetBitmap()
445 : (GdkBitmap *)NULL;
446
447 gtk_pixmap_set( pixmap, bitmap.GetPixmap(), mask );
448 }
449
450 m_blockEvent = TRUE;
451
452 gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(item), toggle );
453
454 m_blockEvent = FALSE;
455 }
456 }
457
458 void wxToolBar::DoSetToggle(wxToolBarToolBase * WXUNUSED(tool),
459 bool WXUNUSED(toggle))
460 {
461 // VZ: absolutely no idea about how to do it
462 wxFAIL_MSG( _T("not implemented") );
463 }
464
465 // ----------------------------------------------------------------------------
466 // wxToolBar geometry
467 // ----------------------------------------------------------------------------
468
469 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord WXUNUSED(x),
470 wxCoord WXUNUSED(y)) const
471 {
472 // VZ: GTK+ doesn't seem to have such thing
473 wxFAIL_MSG( _T("wxToolBar::FindToolForPosition() not implemented") );
474
475 return (wxToolBarToolBase *)NULL;
476 }
477
478 void wxToolBar::SetMargins( int x, int y )
479 {
480 wxCHECK_RET( GetToolsCount() == 0,
481 wxT("wxToolBar::SetMargins must be called before adding tools.") );
482
483 if (x > 1) gtk_toolbar_append_space( m_toolbar ); // oh well
484
485 m_xMargin = x;
486 m_yMargin = y;
487 }
488
489 void wxToolBar::SetToolSeparation( int separation )
490 {
491 // FIXME: this function disappeared
492 #ifndef __WXGTK20__
493 gtk_toolbar_set_space_size( m_toolbar, separation );
494 #endif
495
496 m_toolSeparation = separation;
497 }
498
499 void wxToolBar::SetToolShortHelp( int id, const wxString& helpString )
500 {
501 wxToolBarTool *tool = (wxToolBarTool *)FindById(id);
502
503 if ( tool )
504 {
505 (void)tool->SetShortHelp(helpString);
506 gtk_tooltips_set_tip(m_toolbar->tooltips, tool->m_item,
507 helpString.mbc_str(), "");
508 }
509 }
510
511 // ----------------------------------------------------------------------------
512 // wxToolBar idle handling
513 // ----------------------------------------------------------------------------
514
515 void wxToolBar::OnInternalIdle()
516 {
517 wxCursor cursor = m_cursor;
518 if (g_globalCursor.Ok()) cursor = g_globalCursor;
519
520 if (cursor.Ok())
521 {
522 /* I now set the cursor the anew in every OnInternalIdle call
523 as setting the cursor in a parent window also effects the
524 windows above so that checking for the current cursor is
525 not possible. */
526
527 if (HasFlag(wxTB_DOCKABLE) && (m_widget->window))
528 {
529 /* if the toolbar is dockable, then m_widget stands for the
530 GtkHandleBox widget, which uses its own window so that we
531 can set the cursor for it. if the toolbar is not dockable,
532 m_widget comes from m_toolbar which uses its parent's
533 window ("windowless windows") and thus we cannot set the
534 cursor. */
535 gdk_window_set_cursor( m_widget->window, cursor.GetCursor() );
536 }
537
538 wxToolBarToolsList::Node *node = m_tools.GetFirst();
539 while ( node )
540 {
541 wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
542 node = node->GetNext();
543
544 GtkWidget *item = tool->m_item;
545 if ( item )
546 {
547 GdkWindow *window = item->window;
548
549 if ( window )
550 {
551 gdk_window_set_cursor( window, cursor.GetCursor() );
552 }
553 }
554 }
555 }
556
557 UpdateWindowUI();
558 }
559
560 #endif // wxUSE_TOOLBAR_NATIVE