1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     GTK toolbar 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  11 #pragma implementation "tbargtk.h" 
  14 #include "wx/toolbar.h" 
  24 //----------------------------------------------------------------------------- 
  26 //----------------------------------------------------------------------------- 
  28 extern void wxapp_install_idle_handler(); 
  31 //----------------------------------------------------------------------------- 
  33 //----------------------------------------------------------------------------- 
  35 extern bool       g_blockEventsOnDrag
; 
  36 extern wxCursor   g_globalCursor
; 
  38 //----------------------------------------------------------------------------- 
  39 // "clicked" (internal from gtk_toolbar) 
  40 //----------------------------------------------------------------------------- 
  42 static void gtk_toolbar_callback( GtkWidget 
*WXUNUSED(widget
), wxToolBarTool 
*tool 
) 
  45         wxapp_install_idle_handler(); 
  47     if (tool
->m_owner
->m_blockNextEvent
) 
  49         tool
->m_owner
->m_blockNextEvent 
= FALSE
; 
  53     if (g_blockEventsOnDrag
) return; 
  54     if (!tool
->m_enabled
) return; 
  58         tool
->m_toggleState 
= !tool
->m_toggleState
; 
  60         if (tool
->m_bitmap2
.Ok()) 
  62             wxBitmap bitmap 
= tool
->m_bitmap1
; 
  63             if (tool
->m_toggleState
) bitmap 
= tool
->m_bitmap2
; 
  65             GtkPixmap 
*pixmap 
= GTK_PIXMAP( tool
->m_pixmap 
); 
  67             GdkBitmap 
*mask 
= (GdkBitmap 
*) NULL
; 
  68             if (bitmap
.GetMask()) mask 
= bitmap
.GetMask()->GetBitmap(); 
  70             gtk_pixmap_set( pixmap
, bitmap
.GetPixmap(), mask 
); 
  74     tool
->m_owner
->OnLeftClick( tool
->m_index
, tool
->m_toggleState 
); 
  77 //----------------------------------------------------------------------------- 
  78 // "enter_notify_event" 
  79 //----------------------------------------------------------------------------- 
  81 static gint 
gtk_toolbar_enter_callback( GtkWidget 
*WXUNUSED(widget
),  
  82   GdkEventCrossing 
*WXUNUSED(gdk_event
), wxToolBarTool 
*tool 
) 
  84     if (g_isIdle
) wxapp_install_idle_handler(); 
  86     if (g_blockEventsOnDrag
) return TRUE
; 
  89     wxToolBar 
*tb 
= tool
->m_owner
; 
  91 #if (GTK_MINOR_VERSION == 0) 
  92     /* we grey-out the tip text of disabled tool in GTK 1.0 */ 
  95         if (tb
->m_fg
->red 
!= 0) 
 100             gdk_color_alloc( gtk_widget_get_colormap( GTK_WIDGET(tb
->m_toolbar
) ), tb
->m_fg 
); 
 102             gtk_tooltips_set_colors( GTK_TOOLBAR(tb
->m_toolbar
)->tooltips
, tb
->m_bg
, tb
->m_fg 
); 
 107         if (tb
->m_fg
->red 
== 0) 
 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 
); 
 120     tb
->OnMouseEnter( tool
->m_index 
); 
 125 //----------------------------------------------------------------------------- 
 126 // InsertChild callback for wxToolBar 
 127 //----------------------------------------------------------------------------- 
 129 static void wxInsertChildInToolBar( wxToolBar
* WXUNUSED(parent
), wxWindow
* WXUNUSED(child
) ) 
 131     /* we don't do anything here but pray */ 
 134 //----------------------------------------------------------------------------- 
 136 //----------------------------------------------------------------------------- 
 138 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
,wxControl
) 
 140 BEGIN_EVENT_TABLE(wxToolBar
, wxControl
) 
 141   EVT_IDLE(wxToolBar::OnIdle
) 
 144 wxToolBar::wxToolBar() 
 148 wxToolBar::wxToolBar( wxWindow 
*parent
, wxWindowID id
, 
 149   const wxPoint
& pos
, const wxSize
& size
, 
 150   long style
, const wxString
& name 
) 
 152     Create( parent
, id
, pos
, size
, style
, name 
); 
 155 wxToolBar::~wxToolBar() 
 161 bool wxToolBar::Create( wxWindow 
*parent
, wxWindowID id
, 
 162   const wxPoint
& pos
, const wxSize
& size
, 
 163   long style
, const wxString
& name 
) 
 166     m_blockNextEvent 
= FALSE
; 
 167     m_insertCallback 
= (wxInsertChildFunction
)wxInsertChildInToolBar
; 
 169     if (!PreCreation( parent
, pos
, size 
) || 
 170         !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name 
)) 
 172         wxFAIL_MSG( wxT("wxToolBar creation failed") ); 
 176     m_tools
.DeleteContents( TRUE 
); 
 178     m_toolbar 
= GTK_TOOLBAR( gtk_toolbar_new( GTK_ORIENTATION_HORIZONTAL
, 
 179                                               GTK_TOOLBAR_ICONS 
) ); 
 182     gtk_toolbar_set_space_size( m_toolbar
, m_separation 
); 
 183     m_hasToolAlready 
= FALSE
; 
 185     if (style 
& wxTB_DOCKABLE
) 
 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
) ); 
 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 
); 
 198         m_widget 
= GTK_WIDGET(m_toolbar
); 
 201     gtk_toolbar_set_tooltips( GTK_TOOLBAR(m_toolbar
), TRUE 
); 
 203 #if (GTK_MINOR_VERSION > 0) 
 204     if (style 
& wxTB_FLAT
) 
 205         gtk_toolbar_set_button_relief( GTK_TOOLBAR(m_toolbar
), GTK_RELIEF_NONE 
); 
 212     gdk_color_alloc( gtk_widget_get_colormap( GTK_WIDGET(m_toolbar
) ), m_fg 
); 
 218     gdk_color_alloc( gtk_widget_get_colormap( GTK_WIDGET(m_toolbar
) ), m_bg 
); 
 220 #if (GTK_MINOR_VERSION > 0) 
 221     gtk_tooltips_force_window( GTK_TOOLBAR(m_toolbar
)->tooltips 
); 
 225          gtk_widget_get_style(  
 226             GTK_TOOLBAR(m_toolbar
)->tooltips
->tip_window 
) ); 
 228     g_style
->bg
[GTK_STATE_NORMAL
] = *m_bg
; 
 229     gtk_widget_set_style( GTK_TOOLBAR(m_toolbar
)->tooltips
->tip_window
, g_style 
); 
 231     gtk_tooltips_set_colors( GTK_TOOLBAR(m_toolbar
)->tooltips
, m_bg
, m_fg 
); 
 237     m_parent
->DoAddChild( this ); 
 246 bool wxToolBar::OnLeftClick( int toolIndex
, bool toggleDown 
) 
 248     wxCommandEvent 
event( wxEVT_COMMAND_TOOL_CLICKED
, toolIndex 
); 
 249     event
.SetEventObject(this); 
 250     event
.SetInt( toolIndex 
); 
 251     event
.SetExtraLong((long) toggleDown
); 
 253     GetEventHandler()->ProcessEvent(event
); 
 258 void wxToolBar::OnRightClick( int toolIndex
, float WXUNUSED(x
), float WXUNUSED(y
) ) 
 260     wxCommandEvent 
event( wxEVT_COMMAND_TOOL_RCLICKED
, toolIndex 
); 
 261     event
.SetEventObject( this ); 
 262     event
.SetInt( toolIndex 
); 
 264     GetEventHandler()->ProcessEvent(event
); 
 267 void wxToolBar::OnMouseEnter( int toolIndex 
) 
 269     wxCommandEvent 
event( wxEVT_COMMAND_TOOL_ENTER
, GetId() ); 
 270     event
.SetEventObject(this); 
 271     event
.SetInt( toolIndex 
); 
 273     GetEventHandler()->ProcessEvent(event
); 
 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 
) 
 281     m_hasToolAlready 
= TRUE
; 
 283     wxCHECK_MSG( bitmap
.Ok(), (wxToolBarTool 
*)NULL
, 
 284                  wxT("invalid bitmap for wxToolBar icon") ); 
 286     wxCHECK_MSG( bitmap
.GetBitmap() == NULL
, (wxToolBarTool 
*)NULL
, 
 287                  wxT("wxToolBar doesn't support GdkBitmap") ); 
 289     wxCHECK_MSG( bitmap
.GetPixmap() != NULL
, (wxToolBarTool 
*)NULL
, 
 290                  wxT("wxToolBar::Add needs a wxBitmap") ); 
 292     GtkWidget 
*tool_pixmap 
= (GtkWidget 
*)NULL
; 
 294     GdkPixmap 
*pixmap 
= bitmap
.GetPixmap(); 
 296     GdkBitmap 
*mask 
= (GdkBitmap 
*)NULL
; 
 297     if ( bitmap
.GetMask() ) 
 298       mask 
= bitmap
.GetMask()->GetBitmap(); 
 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 
); 
 305     gtk_misc_set_alignment( GTK_MISC(tool_pixmap
), 0.5, 0.5 ); 
 307     wxToolBarTool 
*tool 
= new wxToolBarTool( this, toolIndex
, bitmap
, pushedBitmap
, 
 309                                              helpString1
, helpString2
, 
 312     GtkToolbarChildType ctype 
= toggle 
? GTK_TOOLBAR_CHILD_TOGGLEBUTTON
 
 313                                        : GTK_TOOLBAR_CHILD_BUTTON
; 
 315     GtkWidget 
*item 
= gtk_toolbar_append_element
 
 321                       helpString1
.mbc_str(), 
 324                       (GtkSignalFunc
)gtk_toolbar_callback
, 
 331     (* GTK_WIDGET_CLASS( GTK_OBJECT(m_widget
)->klass 
)->size_request 
) (m_widget
, &req 
); 
 332     m_width 
= req
.width 
+ m_xMargin
; 
 333     m_height 
= req
.height 
+ 2*m_yMargin 
+ 4; 
 335     gtk_signal_connect( GTK_OBJECT(tool
->m_item
), 
 336                         "enter_notify_event",  
 337                         GTK_SIGNAL_FUNC(gtk_toolbar_enter_callback
), 
 340     m_tools
.Append( tool 
); 
 345 bool wxToolBar::AddControl(wxControl 
*control
) 
 347     wxCHECK_MSG( control
, FALSE
, wxT("toolbar: can't insert NULL control") ); 
 349     wxCHECK_MSG( control
->GetParent() == this, FALSE
, 
 350                  wxT("control must have toolbar as parent") ); 
 352     m_hasToolAlready 
= TRUE
; 
 354     wxToolBarTool 
*tool 
= new wxToolBarTool(control
); 
 356     tool 
-> m_item 
= NULL
; 
 357     gtk_toolbar_append_widget( m_toolbar
, control
->m_widget
, (const char *) NULL
, (const char *) NULL 
); 
 360     (* GTK_WIDGET_CLASS( GTK_OBJECT(m_widget
)->klass 
)->size_request 
) (m_widget
, &req 
); 
 361     m_width 
= req
.width 
+ m_xMargin
; 
 362     m_height 
= req
.height 
+ 2*m_yMargin 
+ 4; 
 364     m_tools
.Append( tool 
); 
 369 void wxToolBar::AddSeparator() 
 371     gtk_toolbar_append_space( m_toolbar 
); 
 374 bool wxToolBar::DeleteTool(int toolIndex
) 
 376     wxNode 
*node 
= m_tools
.First(); 
 379         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 380         if (tool
->m_index 
== toolIndex
) 
 383                 tool
->m_control
->Destroy(); 
 385                 gtk_widget_destroy( tool
->m_item 
); 
 386             m_tools
.DeleteNode( node 
); 
 396 void wxToolBar::ClearTools() 
 398     wxFAIL_MSG( wxT("wxToolBar::ClearTools not implemented") ); 
 401 bool wxToolBar::Realize() 
 406 void wxToolBar::EnableTool(int toolIndex
, bool enable
) 
 408     wxNode 
*node 
= m_tools
.First(); 
 411         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 412         if (tool
->m_index 
== toolIndex
) 
 414             tool
->m_enabled 
= enable
; 
 416 #if (GTK_MINOR_VERSION > 0) 
 417             /* we don't disable the tools for GTK 1.0 as the bitmaps don't get 
 418                greyed anyway and this also disables tooltips */ 
 420                 gtk_widget_set_sensitive( tool
->m_item
, enable 
); 
 428     wxFAIL_MSG( wxT("wrong toolbar index") ); 
 431 void wxToolBar::ToggleTool( int toolIndex
, bool toggle 
)  
 433     wxNode 
*node 
= m_tools
.First(); 
 436         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 437         if (tool
->m_index 
== toolIndex
) 
 439             if ((tool
->m_item
) && (GTK_IS_TOGGLE_BUTTON(tool
->m_item
))) 
 441                 tool
->m_toggleState 
= toggle
; 
 443                 if (tool
->m_bitmap2
.Ok()) 
 445                     wxBitmap bitmap 
= tool
->m_bitmap1
; 
 446                     if (tool
->m_toggleState
) bitmap 
= tool
->m_bitmap2
; 
 448                     GtkPixmap 
*pixmap 
= GTK_PIXMAP( tool
->m_pixmap 
); 
 450                     GdkBitmap 
*mask 
= (GdkBitmap 
*) NULL
; 
 451                     if (bitmap
.GetMask()) mask 
= bitmap
.GetMask()->GetBitmap(); 
 453                     gtk_pixmap_set( pixmap
, bitmap
.GetPixmap(), mask 
); 
 456                 m_blockNextEvent 
= TRUE
;  // we cannot use gtk_signal_disconnect here 
 458                 gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON(tool
->m_item
), toggle 
); 
 466     wxFAIL_MSG( wxT("wrong toolbar index") ); 
 469 wxObject 
*wxToolBar::GetToolClientData( int index 
) const 
 471     wxNode 
*node 
= m_tools
.First(); 
 474         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 475         if (tool
->m_index 
== index
) return tool
->m_clientData
;; 
 479     wxFAIL_MSG( wxT("wrong toolbar index") ); 
 481     return (wxObject
*)NULL
; 
 484 bool wxToolBar::GetToolState(int toolIndex
) const 
 486     wxNode 
*node 
= m_tools
.First(); 
 489         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 490         if (tool
->m_index 
== toolIndex
) return tool
->m_toggleState
; 
 494     wxFAIL_MSG( wxT("wrong toolbar index") ); 
 499 bool wxToolBar::GetToolEnabled(int toolIndex
) const 
 501     wxNode 
*node 
= m_tools
.First(); 
 504         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 505         if (tool
->m_index 
== toolIndex
) return tool
->m_enabled
; 
 509     wxFAIL_MSG( wxT("wrong toolbar index") ); 
 514 void wxToolBar::SetMargins( int x
, int y 
) 
 516     wxCHECK_RET( !m_hasToolAlready
, wxT("wxToolBar::SetMargins must be called before adding tool.") ); 
 518     if (x 
> 1) gtk_toolbar_append_space( m_toolbar 
);  // oh well 
 524 void wxToolBar::SetToolPacking( int WXUNUSED(packing
) ) 
 526     wxFAIL_MSG( wxT("wxToolBar::SetToolPacking not implemented") ); 
 529 void wxToolBar::SetToolSeparation( int separation 
) 
 531     gtk_toolbar_set_space_size( m_toolbar
, separation 
); 
 532     m_separation 
= separation
; 
 535 int wxToolBar::GetToolPacking() 
 540 int wxToolBar::GetToolSeparation() 
 545 wxString 
wxToolBar::GetToolLongHelp(int toolIndex
) 
 547     wxNode 
*node 
= m_tools
.First(); 
 550         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 551         if (tool
->m_index 
== toolIndex
) 
 553             return tool
->m_longHelpString
; 
 558     wxFAIL_MSG( wxT("wrong toolbar index") ); 
 563 wxString 
wxToolBar::GetToolShortHelp(int toolIndex
) 
 565     wxNode 
*node 
= m_tools
.First(); 
 568         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 569         if (tool
->m_index 
== toolIndex
) 
 571             return tool
->m_shortHelpString
; 
 576     wxFAIL_MSG( wxT("wrong toolbar index") ); 
 581 void wxToolBar::SetToolLongHelp(int toolIndex
, const wxString
& helpString
) 
 583     wxNode 
*node 
= m_tools
.First(); 
 586         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 587         if (tool
->m_index 
== toolIndex
) 
 589             tool
->m_longHelpString 
= helpString
; 
 595     wxFAIL_MSG( wxT("wrong toolbar index") ); 
 600 void wxToolBar::SetToolShortHelp(int toolIndex
, const wxString
& helpString
) 
 602     wxNode 
*node 
= m_tools
.First(); 
 605         wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 606         if (tool
->m_index 
== toolIndex
) 
 608             tool
->m_shortHelpString 
= helpString
; 
 614     wxFAIL_MSG( wxT("wrong toolbar index") ); 
 619 void wxToolBar::OnIdle( wxIdleEvent 
&WXUNUSED(ievent
) ) 
 621     wxEvtHandler
* evtHandler 
= GetEventHandler(); 
 623     wxNode
* node 
= m_tools
.First(); 
 626         wxToolBarTool
* tool 
= (wxToolBarTool
*) node
->Data(); 
 628         wxUpdateUIEvent 
event( tool
->m_index 
); 
 629         event
.SetEventObject(this); 
 631         if (evtHandler
->ProcessEvent( event 
)) 
 633             if (event
.GetSetEnabled()) 
 634                 EnableTool(tool
->m_index
, event
.GetEnabled()); 
 635             if (event
.GetSetChecked()) 
 636                 ToggleTool(tool
->m_index
, event
.GetChecked()); 
 638             if (event.GetSetText()) 
 647 void wxToolBar::OnInternalIdle() 
 649     wxCursor cursor 
= m_cursor
; 
 650     if (g_globalCursor
.Ok()) cursor 
= g_globalCursor
; 
 654         /* I now set the cursor the anew in every OnInternalIdle call 
 655            as setting the cursor in a parent window also effects the 
 656            windows above so that checking for the current cursor is 
 659         if (HasFlag(wxTB_DOCKABLE
)) 
 661             /* if the toolbar is dockable, then m_widget stands for the 
 662                GtkHandleBox widget, which uses its own window so that we 
 663                can set the cursor for it. if the toolbar is not dockable, 
 664                m_widget comes from m_toolbar which uses its parent's 
 665                window ("windowless windows") and thus we cannot set the 
 667             gdk_window_set_cursor( m_widget
->window
, cursor
.GetCursor() ); 
 670         wxNode 
*node 
= m_tools
.First(); 
 673             wxToolBarTool 
*tool 
= (wxToolBarTool
*)node
->Data(); 
 676             if (!tool
->m_item 
|| !tool
->m_item
->window
) 
 679                 gdk_window_set_cursor( tool
->m_item
->window
, cursor
.GetCursor() );