Added wxWakeUpIdle() to wxGTK,
[wxWidgets.git] / src / gtk1 / tbargtk.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: tbargtk.cpp
3 // Purpose: GTK toolbar
4 // Author: Robert Roebling
5 // RCS-ID: $Id$
6 // Copyright: (c) Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "tbargtk.h"
12 #endif
13
14 #include "wx/toolbar.h"
15
16 #if wxUSE_TOOLBAR
17
18 #include "wx/frame.h"
19
20 #include "glib.h"
21 #include "gdk/gdk.h"
22 #include "gtk/gtk.h"
23
24 //-----------------------------------------------------------------------------
25 // idle system
26 //-----------------------------------------------------------------------------
27
28 extern void wxapp_install_idle_handler();
29 extern bool g_isIdle;
30
31 //-----------------------------------------------------------------------------
32 // data
33 //-----------------------------------------------------------------------------
34
35 extern bool g_blockEventsOnDrag;
36 extern wxCursor g_globalCursor;
37
38 //-----------------------------------------------------------------------------
39 // "clicked" (internal from gtk_toolbar)
40 //-----------------------------------------------------------------------------
41
42 static void gtk_toolbar_callback( GtkWidget *WXUNUSED(widget), wxToolBarTool *tool )
43 {
44 if (g_isIdle)
45 wxapp_install_idle_handler();
46
47 if (tool->m_owner->m_blockNextEvent)
48 {
49 tool->m_owner->m_blockNextEvent = FALSE;
50 return;
51 }
52
53 if (g_blockEventsOnDrag) return;
54 if (!tool->m_enabled) return;
55
56 if (tool->m_isToggle)
57 {
58 tool->m_toggleState = !tool->m_toggleState;
59
60 if (tool->m_bitmap2.Ok())
61 {
62 wxBitmap bitmap = tool->m_bitmap1;
63 if (tool->m_toggleState) bitmap = tool->m_bitmap2;
64
65 GtkPixmap *pixmap = GTK_PIXMAP( tool->m_pixmap );
66
67 GdkBitmap *mask = (GdkBitmap *) NULL;
68 if (bitmap.GetMask()) mask = bitmap.GetMask()->GetBitmap();
69
70 gtk_pixmap_set( pixmap, bitmap.GetPixmap(), mask );
71 }
72 }
73
74 tool->m_owner->OnLeftClick( tool->m_index, tool->m_toggleState );
75 }
76
77 //-----------------------------------------------------------------------------
78 // "enter_notify_event"
79 //-----------------------------------------------------------------------------
80
81 static gint gtk_toolbar_enter_callback( GtkWidget *WXUNUSED(widget),
82 GdkEventCrossing *WXUNUSED(gdk_event), wxToolBarTool *tool )
83 {
84 if (g_isIdle) wxapp_install_idle_handler();
85
86 if (g_blockEventsOnDrag) return TRUE;
87
88
89 wxToolBar *tb = tool->m_owner;
90
91 #if (GTK_MINOR_VERSION == 0)
92 /* we grey-out the tip text of disabled tool in GTK 1.0 */
93 if (tool->m_enabled)
94 {
95 if (tb->m_fg->red != 0)
96 {
97 tb->m_fg->red = 0;
98 tb->m_fg->green = 0;
99 tb->m_fg->blue = 0;
100 gdk_color_alloc( gtk_widget_get_colormap( GTK_WIDGET(tb->m_toolbar) ), tb->m_fg );
101
102 gtk_tooltips_set_colors( GTK_TOOLBAR(tb->m_toolbar)->tooltips, tb->m_bg, tb->m_fg );
103 }
104 }
105 else
106 {
107 if (tb->m_fg->red == 0)
108 {
109 tb->m_fg->red = 33000;
110 tb->m_fg->green = 33000;
111 tb->m_fg->blue = 33000;
112 gdk_color_alloc( gtk_widget_get_colormap( GTK_WIDGET(tb->m_toolbar) ), tb->m_fg );
113 gtk_tooltips_set_colors( GTK_TOOLBAR(tb->m_toolbar)->tooltips, tb->m_bg, tb->m_fg );
114 }
115 }
116 #endif
117
118 /* emit the event */
119
120 tb->OnMouseEnter( tool->m_index );
121
122 return FALSE;
123 }
124
125 //-----------------------------------------------------------------------------
126 // InsertChild callback for wxToolBar
127 //-----------------------------------------------------------------------------
128
129 static void wxInsertChildInToolBar( wxToolBar* WXUNUSED(parent), wxWindow* WXUNUSED(child) )
130 {
131 /* we don't do anything here but pray */
132 }
133
134 //-----------------------------------------------------------------------------
135 // wxToolBar
136 //-----------------------------------------------------------------------------
137
138 IMPLEMENT_DYNAMIC_CLASS(wxToolBar,wxControl)
139
140 BEGIN_EVENT_TABLE(wxToolBar, wxControl)
141 EVT_IDLE(wxToolBar::OnIdle)
142 END_EVENT_TABLE()
143
144 wxToolBar::wxToolBar()
145 {
146 }
147
148 wxToolBar::wxToolBar( wxWindow *parent, wxWindowID id,
149 const wxPoint& pos, const wxSize& size,
150 long style, const wxString& name )
151 {
152 Create( parent, id, pos, size, style, name );
153 }
154
155 wxToolBar::~wxToolBar()
156 {
157 delete m_fg;
158 delete m_bg;
159 }
160
161 bool wxToolBar::Create( wxWindow *parent, wxWindowID id,
162 const wxPoint& pos, const wxSize& size,
163 long style, const wxString& name )
164 {
165 m_needParent = TRUE;
166 m_blockNextEvent = FALSE;
167 m_insertCallback = (wxInsertChildFunction)wxInsertChildInToolBar;
168
169 if (!PreCreation( parent, pos, size ) ||
170 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
171 {
172 wxFAIL_MSG( wxT("wxToolBar creation failed") );
173 return FALSE;
174 }
175
176 m_tools.DeleteContents( TRUE );
177
178 m_toolbar = GTK_TOOLBAR( gtk_toolbar_new( GTK_ORIENTATION_HORIZONTAL,
179 GTK_TOOLBAR_ICONS ) );
180
181 m_separation = 5;
182 gtk_toolbar_set_space_size( m_toolbar, m_separation );
183 m_hasToolAlready = FALSE;
184
185 if (style & wxTB_DOCKABLE)
186 {
187 m_widget = gtk_handle_box_new();
188 gtk_container_add( GTK_CONTAINER(m_widget), GTK_WIDGET(m_toolbar) );
189 gtk_widget_show( GTK_WIDGET(m_toolbar) );
190
191 #if (GTK_MINOR_VERSION > 0)
192 if (style & wxTB_FLAT)
193 gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(m_widget), GTK_SHADOW_NONE );
194 #endif
195 }
196 else
197 {
198 m_widget = GTK_WIDGET(m_toolbar);
199 }
200
201 gtk_toolbar_set_tooltips( GTK_TOOLBAR(m_toolbar), TRUE );
202
203 #if (GTK_MINOR_VERSION > 0)
204 if (style & wxTB_FLAT)
205 gtk_toolbar_set_button_relief( GTK_TOOLBAR(m_toolbar), GTK_RELIEF_NONE );
206 #endif
207
208 m_fg = new GdkColor;
209 m_fg->red = 0;
210 m_fg->green = 0;
211 m_fg->blue = 0;
212 gdk_color_alloc( gtk_widget_get_colormap( GTK_WIDGET(m_toolbar) ), m_fg );
213
214 m_bg = new GdkColor;
215 m_bg->red = 65535;
216 m_bg->green = 65535;
217 m_bg->blue = 50000;
218 gdk_color_alloc( gtk_widget_get_colormap( GTK_WIDGET(m_toolbar) ), m_bg );
219
220 #if (GTK_MINOR_VERSION > 0)
221 gtk_tooltips_force_window( GTK_TOOLBAR(m_toolbar)->tooltips );
222
223 GtkStyle *g_style =
224 gtk_style_copy(
225 gtk_widget_get_style(
226 GTK_TOOLBAR(m_toolbar)->tooltips->tip_window ) );
227
228 g_style->bg[GTK_STATE_NORMAL] = *m_bg;
229 gtk_widget_set_style( GTK_TOOLBAR(m_toolbar)->tooltips->tip_window, g_style );
230 #else
231 gtk_tooltips_set_colors( GTK_TOOLBAR(m_toolbar)->tooltips, m_bg, m_fg );
232 #endif
233
234 m_xMargin = 0;
235 m_yMargin = 0;
236
237 m_parent->DoAddChild( this );
238
239 PostCreation();
240
241 Show( TRUE );
242
243 return TRUE;
244 }
245
246 bool wxToolBar::OnLeftClick( int toolIndex, bool toggleDown )
247 {
248 wxCommandEvent event( wxEVT_COMMAND_TOOL_CLICKED, toolIndex );
249 event.SetEventObject(this);
250 event.SetInt( toolIndex );
251 event.SetExtraLong((long) toggleDown);
252
253 GetEventHandler()->ProcessEvent(event);
254
255 return TRUE;
256 }
257
258 void wxToolBar::OnRightClick( int toolIndex, float WXUNUSED(x), float WXUNUSED(y) )
259 {
260 wxCommandEvent event( wxEVT_COMMAND_TOOL_RCLICKED, toolIndex );
261 event.SetEventObject( this );
262 event.SetInt( toolIndex );
263
264 GetEventHandler()->ProcessEvent(event);
265 }
266
267 void wxToolBar::OnMouseEnter( int toolIndex )
268 {
269 wxCommandEvent event( wxEVT_COMMAND_TOOL_ENTER, GetId() );
270 event.SetEventObject(this);
271 event.SetInt( toolIndex );
272
273 GetEventHandler()->ProcessEvent(event);
274 }
275
276 wxToolBarTool *wxToolBar::AddTool( int toolIndex, const wxBitmap& bitmap,
277 const wxBitmap& pushedBitmap, bool toggle,
278 wxCoord WXUNUSED(xPos), wxCoord WXUNUSED(yPos), wxObject *clientData,
279 const wxString& helpString1, const wxString& helpString2 )
280 {
281 m_hasToolAlready = TRUE;
282
283 wxCHECK_MSG( bitmap.Ok(), (wxToolBarTool *)NULL,
284 wxT("invalid bitmap for wxToolBar icon") );
285
286 wxCHECK_MSG( bitmap.GetBitmap() == NULL, (wxToolBarTool *)NULL,
287 wxT("wxToolBar doesn't support GdkBitmap") );
288
289 wxCHECK_MSG( bitmap.GetPixmap() != NULL, (wxToolBarTool *)NULL,
290 wxT("wxToolBar::Add needs a wxBitmap") );
291
292 GtkWidget *tool_pixmap = (GtkWidget *)NULL;
293
294 GdkPixmap *pixmap = bitmap.GetPixmap();
295
296 GdkBitmap *mask = (GdkBitmap *)NULL;
297 if ( bitmap.GetMask() )
298 mask = bitmap.GetMask()->GetBitmap();
299
300 tool_pixmap = gtk_pixmap_new( pixmap, mask );
301 #if (GTK_MINOR_VERSION > 0)
302 gtk_pixmap_set_build_insensitive( GTK_PIXMAP(tool_pixmap), TRUE );
303 #endif
304
305 gtk_misc_set_alignment( GTK_MISC(tool_pixmap), 0.5, 0.5 );
306
307 wxToolBarTool *tool = new wxToolBarTool( this, toolIndex, bitmap, pushedBitmap,
308 toggle, clientData,
309 helpString1, helpString2,
310 tool_pixmap );
311
312 GtkToolbarChildType ctype = toggle ? GTK_TOOLBAR_CHILD_TOGGLEBUTTON
313 : GTK_TOOLBAR_CHILD_BUTTON;
314
315 GtkWidget *item = gtk_toolbar_append_element
316 (
317 m_toolbar,
318 ctype,
319 (GtkWidget *)NULL,
320 (const char *)NULL,
321 helpString1.mbc_str(),
322 "",
323 tool_pixmap,
324 (GtkSignalFunc)gtk_toolbar_callback,
325 (gpointer)tool
326 );
327
328 tool->m_item = item;
329
330 GtkRequisition req;
331 (* GTK_WIDGET_CLASS( GTK_OBJECT(m_widget)->klass )->size_request ) (m_widget, &req );
332 m_width = req.width;
333 m_height = req.height;
334
335 gtk_signal_connect( GTK_OBJECT(tool->m_item),
336 "enter_notify_event",
337 GTK_SIGNAL_FUNC(gtk_toolbar_enter_callback),
338 (gpointer)tool );
339
340 m_tools.Append( tool );
341
342 return tool;
343 }
344
345 bool wxToolBar::AddControl(wxControl *control)
346 {
347 wxCHECK_MSG( control, FALSE, wxT("toolbar: can't insert NULL control") );
348
349 wxCHECK_MSG( control->GetParent() == this, FALSE,
350 wxT("control must have toolbar as parent") );
351
352 m_hasToolAlready = TRUE;
353
354 wxToolBarTool *tool = new wxToolBarTool(control);
355
356 gtk_toolbar_append_widget( m_toolbar, control->m_widget, (const char *) NULL, (const char *) NULL );
357
358 GtkRequisition req;
359 (* GTK_WIDGET_CLASS( GTK_OBJECT(m_widget)->klass )->size_request ) (m_widget, &req );
360 m_width = req.width;
361 m_height = req.height;
362
363 m_tools.Append( tool );
364
365 return TRUE;
366 }
367
368 void wxToolBar::AddSeparator()
369 {
370 gtk_toolbar_append_space( m_toolbar );
371 }
372
373 void wxToolBar::ClearTools()
374 {
375 wxFAIL_MSG( wxT("wxToolBar::ClearTools not implemented") );
376 }
377
378 bool wxToolBar::Realize()
379 {
380 m_x = 0;
381 m_y = 0;
382 m_width = 100;
383 m_height = 0;
384
385 wxNode *node = m_tools.First();
386 while (node)
387 {
388 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
389 if (tool->m_bitmap1.Ok())
390 {
391 int tool_height = tool->m_bitmap1.GetHeight();
392 if (tool_height > m_height) m_height = tool_height;
393 }
394
395 node = node->Next();
396 }
397
398 m_height += 5 + 2*m_yMargin;
399
400 return TRUE;
401 }
402
403 void wxToolBar::EnableTool(int toolIndex, bool enable)
404 {
405 wxNode *node = m_tools.First();
406 while (node)
407 {
408 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
409 if (tool->m_index == toolIndex)
410 {
411 tool->m_enabled = enable;
412
413 #if (GTK_MINOR_VERSION > 0)
414 /* we don't disable the tools for GTK 1.0 as the bitmaps don't get
415 greyed anyway and this also disables tooltips */
416 if (tool->m_item)
417 gtk_widget_set_sensitive( tool->m_item, enable );
418 #endif
419
420 return;
421 }
422 node = node->Next();
423 }
424
425 wxFAIL_MSG( wxT("wrong toolbar index") );
426 }
427
428 void wxToolBar::ToggleTool( int toolIndex, bool toggle )
429 {
430 wxNode *node = m_tools.First();
431 while (node)
432 {
433 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
434 if (tool->m_index == toolIndex)
435 {
436 if ((tool->m_item) && (GTK_IS_TOGGLE_BUTTON(tool->m_item)))
437 {
438 tool->m_toggleState = toggle;
439
440 if (tool->m_bitmap2.Ok())
441 {
442 wxBitmap bitmap = tool->m_bitmap1;
443 if (tool->m_toggleState) bitmap = tool->m_bitmap2;
444
445 GtkPixmap *pixmap = GTK_PIXMAP( tool->m_pixmap );
446
447 GdkBitmap *mask = (GdkBitmap *) NULL;
448 if (bitmap.GetMask()) mask = bitmap.GetMask()->GetBitmap();
449
450 gtk_pixmap_set( pixmap, bitmap.GetPixmap(), mask );
451 }
452
453 m_blockNextEvent = TRUE; // we cannot use gtk_signal_disconnect here
454
455 gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(tool->m_item), toggle );
456 }
457
458 return;
459 }
460 node = node->Next();
461 }
462
463 wxFAIL_MSG( wxT("wrong toolbar index") );
464 }
465
466 wxObject *wxToolBar::GetToolClientData( int index ) const
467 {
468 wxNode *node = m_tools.First();
469 while (node)
470 {
471 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
472 if (tool->m_index == index) return tool->m_clientData;;
473 node = node->Next();
474 }
475
476 wxFAIL_MSG( wxT("wrong toolbar index") );
477
478 return (wxObject*)NULL;
479 }
480
481 bool wxToolBar::GetToolState(int toolIndex) const
482 {
483 wxNode *node = m_tools.First();
484 while (node)
485 {
486 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
487 if (tool->m_index == toolIndex) return tool->m_toggleState;
488 node = node->Next();
489 }
490
491 wxFAIL_MSG( wxT("wrong toolbar index") );
492
493 return FALSE;
494 }
495
496 bool wxToolBar::GetToolEnabled(int toolIndex) const
497 {
498 wxNode *node = m_tools.First();
499 while (node)
500 {
501 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
502 if (tool->m_index == toolIndex) return tool->m_enabled;
503 node = node->Next();
504 }
505
506 wxFAIL_MSG( wxT("wrong toolbar index") );
507
508 return FALSE;
509 }
510
511 void wxToolBar::SetMargins( int x, int y )
512 {
513 wxCHECK_RET( !m_hasToolAlready, wxT("wxToolBar::SetMargins must be called before adding tool.") );
514
515 if (x > 2) gtk_toolbar_append_space( m_toolbar ); // oh well
516
517 m_xMargin = x;
518 m_yMargin = y;
519 }
520
521 void wxToolBar::SetToolPacking( int WXUNUSED(packing) )
522 {
523 wxFAIL_MSG( wxT("wxToolBar::SetToolPacking not implemented") );
524 }
525
526 void wxToolBar::SetToolSeparation( int separation )
527 {
528 gtk_toolbar_set_space_size( m_toolbar, separation );
529 m_separation = separation;
530 }
531
532 int wxToolBar::GetToolPacking()
533 {
534 return 0;
535 }
536
537 int wxToolBar::GetToolSeparation()
538 {
539 return m_separation;
540 }
541
542 wxString wxToolBar::GetToolLongHelp(int toolIndex)
543 {
544 wxNode *node = m_tools.First();
545 while (node)
546 {
547 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
548 if (tool->m_index == toolIndex)
549 {
550 return tool->m_longHelpString;
551 }
552 node = node->Next();
553 }
554
555 wxFAIL_MSG( wxT("wrong toolbar index") );
556
557 return wxT("");
558 }
559
560 wxString wxToolBar::GetToolShortHelp(int toolIndex)
561 {
562 wxNode *node = m_tools.First();
563 while (node)
564 {
565 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
566 if (tool->m_index == toolIndex)
567 {
568 return tool->m_shortHelpString;
569 }
570 node = node->Next();
571 }
572
573 wxFAIL_MSG( wxT("wrong toolbar index") );
574
575 return wxT("");
576 }
577
578 void wxToolBar::SetToolLongHelp(int toolIndex, const wxString& helpString)
579 {
580 wxNode *node = m_tools.First();
581 while (node)
582 {
583 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
584 if (tool->m_index == toolIndex)
585 {
586 tool->m_longHelpString = helpString;
587 return;
588 }
589 node = node->Next();
590 }
591
592 wxFAIL_MSG( wxT("wrong toolbar index") );
593
594 return;
595 }
596
597 void wxToolBar::SetToolShortHelp(int toolIndex, const wxString& helpString)
598 {
599 wxNode *node = m_tools.First();
600 while (node)
601 {
602 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
603 if (tool->m_index == toolIndex)
604 {
605 tool->m_shortHelpString = helpString;
606 return;
607 }
608 node = node->Next();
609 }
610
611 wxFAIL_MSG( wxT("wrong toolbar index") );
612
613 return;
614 }
615
616 void wxToolBar::OnIdle( wxIdleEvent &WXUNUSED(ievent) )
617 {
618 wxEvtHandler* evtHandler = GetEventHandler();
619
620 wxNode* node = m_tools.First();
621 while (node)
622 {
623 wxToolBarTool* tool = (wxToolBarTool*) node->Data();
624
625 wxUpdateUIEvent event( tool->m_index );
626 event.SetEventObject(this);
627
628 if (evtHandler->ProcessEvent( event ))
629 {
630 if (event.GetSetEnabled())
631 EnableTool(tool->m_index, event.GetEnabled());
632 if (event.GetSetChecked())
633 ToggleTool(tool->m_index, event.GetChecked());
634 /*
635 if (event.GetSetText())
636 // Set tooltip?
637 */
638 }
639
640 node = node->Next();
641 }
642 }
643
644 void wxToolBar::OnInternalIdle()
645 {
646 wxCursor cursor = m_cursor;
647 if (g_globalCursor.Ok()) cursor = g_globalCursor;
648
649 if (cursor.Ok())
650 {
651 /* I now set the cursor the anew in every OnInternalIdle call
652 as setting the cursor in a parent window also effects the
653 windows above so that checking for the current cursor is
654 not possible. */
655
656 if (HasFlag(wxTB_DOCKABLE))
657 {
658 /* if the toolbar is dockable, then m_widget stands for the
659 GtkHandleBox widget, which uses its own window so that we
660 can set the cursor for it. if the toolbar is not dockable,
661 m_widget comes from m_toolbar which uses its parent's
662 window ("windowless windows") and thus we cannot set the
663 cursor. */
664 gdk_window_set_cursor( m_widget->window, cursor.GetCursor() );
665 }
666
667 wxNode *node = m_tools.First();
668 while (node)
669 {
670 wxToolBarTool *tool = (wxToolBarTool*)node->Data();
671 node = node->Next();
672
673 if (!tool->m_item || !tool->m_item->window)
674 continue;
675 else
676 gdk_window_set_cursor( tool->m_item->window, cursor.GetCursor() );
677 }
678 }
679
680 UpdateWindowUI();
681 }
682
683 #endif