From fc6557a6f5af68ed4a8da763216d0f375e29bd92 Mon Sep 17 00:00:00 2001
From: Robert Roebling <robert@roebling.de>
Date: Sat, 19 May 2007 23:21:47 +0000
Subject: [PATCH]  Implemented dropdown items in wxToolBar for wxGTK.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@46127 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/toolbar.tex |   2 +-
 src/gtk/tbargtk.cpp       | 154 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 153 insertions(+), 3 deletions(-)

diff --git a/docs/latex/wx/toolbar.tex b/docs/latex/wx/toolbar.tex
index 9d34c8d5f1..9179ae5086 100644
--- a/docs/latex/wx/toolbar.tex
+++ b/docs/latex/wx/toolbar.tex
@@ -121,7 +121,7 @@ values:
 next to it. Clicking the dropdown arrow sends a wxEVT\_COMMAND\_TOOL\_DROPDOWN\_CLICKED
 event and may also display the menu previously associated with the item with 
 \helpref{wxToolBar::SetDropdownMenu}{wxtoolbarsetdropdownmenu}. Currently this
-type of tools is only supported under MSW.}
+type of tools is supported under MSW and GTK.}
 \end{twocollist}
 
 \wxheading{See also}
diff --git a/src/gtk/tbargtk.cpp b/src/gtk/tbargtk.cpp
index 85a0268c51..55c3ba4f94 100644
--- a/src/gtk/tbargtk.cpp
+++ b/src/gtk/tbargtk.cpp
@@ -35,6 +35,26 @@
 #endif
 
 #include "wx/gtk/private.h"
+#include "wx/crt.h"
+#include "wx/menu.h"
+
+
+/* XPM */
+static const char *arrow_down_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"7 7 2 1",
+"  c None",
+". c Black",
+/* pixels */
+"       ",
+"       ",
+"       ",
+".......",
+" ..... ",
+"  ...  ",
+"   .   "
+};
+
 
 // ----------------------------------------------------------------------------
 // globals
@@ -211,6 +231,82 @@ static gboolean gtk_toolbar_tool_rclick_callback(GtkWidget *WXUNUSED(widget),
 }
 }
 
+//-----------------------------------------------------------------------------
+// "enter_notify_event" / "leave_notify_event" from dropdown
+//-----------------------------------------------------------------------------
+
+extern "C" {
+static gint gtk_toolbar_buddy_enter_callback( GtkWidget *WXUNUSED(widget),
+                                       GdkEventCrossing *WXUNUSED(gdk_event),
+                                       GtkWidget *tool )
+{
+    guint8 state = GTK_WIDGET_STATE( tool );
+    state |= GTK_STATE_PRELIGHT;
+    gtk_widget_set_state( tool, (GtkStateType) state );
+    return FALSE;
+}
+
+static gint gtk_toolbar_buddy_leave_callback( GtkWidget *WXUNUSED(widget),
+                                       GdkEventCrossing *WXUNUSED(gdk_event),
+                                       GtkWidget *tool )
+{
+    guint8 state = GTK_WIDGET_STATE( tool );
+    state &= ~GTK_STATE_PRELIGHT;
+    gtk_widget_set_state( tool, (GtkStateType) state );
+    return FALSE;
+}
+}
+
+//-----------------------------------------------------------------------------
+// "left-click" on dropdown 
+//-----------------------------------------------------------------------------
+
+extern "C"
+{
+static void gtk_pop_tb_hide_callback( GtkWidget *WXUNUSED(menu), GtkToggleButton *button  )
+{
+    gtk_toggle_button_set_active( button, FALSE );
+}
+
+static gboolean gtk_toolbar_dropdown_lclick_callback(GtkWidget *widget,
+                                                 GdkEventButton *event,
+                                                 wxToolBarToolBase *tool)
+{
+    if (event->button != 1)
+        return FALSE;
+
+    wxToolBar *tbar = (wxToolBar *)tool->GetToolBar();
+
+    if (tbar->m_blockEvent) return FALSE;
+
+    if (g_blockEventsOnDrag) return FALSE;
+    if (!tool->IsEnabled()) return FALSE;
+
+    wxCommandEvent evt(wxEVT_COMMAND_TOOL_DROPDOWN_CLICKED, tool->GetId() );
+    if ( tbar->GetEventHandler()->ProcessEvent(evt) )
+    {
+        return TRUE;
+    }
+    
+    wxMenu * const menu = tool->GetDropdownMenu();
+    if (!menu)
+        return TRUE;
+
+    // simulate press
+    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(widget), TRUE );
+    
+    g_signal_connect (menu->m_menu, "hide",
+                                    G_CALLBACK (gtk_pop_tb_hide_callback),
+                                    widget);
+    
+    tbar->PopupMenu( menu, widget->allocation.x, 
+                           widget->allocation.y + widget->allocation.height );
+                           
+    
+    return TRUE;
+}
+}
+
 //-----------------------------------------------------------------------------
 // "enter_notify_event" / "leave_notify_event"
 //-----------------------------------------------------------------------------
@@ -412,8 +508,25 @@ bool wxToolBar::DoInsertTool(size_t pos, wxToolBarToolBase *toolBase)
         }
     }
 
-    const int posGtk = int(pos);
-
+    int posGtk = 0;
+    if (pos > 0)
+    {    
+        size_t i;
+        for (i = 0; i < pos; i++)
+        {
+            posGtk++;
+            
+        
+            // if we have a dropdown menu, we use 2 GTK tools
+            // internally
+            wxToolBarToolsList::compatibility_iterator node = m_tools.Item( i );
+            wxToolBarTool *tool = (wxToolBarTool*) node->GetData();
+            if (tool->IsButton() && (tool->GetKind() == wxITEM_DROPDOWN))
+                posGtk++;
+        }
+    }
+    
+    
     switch ( tool->GetStyle() )
     {
         case wxTOOL_STYLE_BUTTON:
@@ -479,6 +592,43 @@ bool wxToolBar::DoInsertTool(size_t pos, wxToolBarToolBase *toolBase)
                 g_signal_connect(tool->m_item, "button-press-event",
                                   G_CALLBACK (gtk_toolbar_tool_rclick_callback),
                                   tool);
+
+                if (tool->GetKind() == wxITEM_DROPDOWN)
+                {
+                    GdkPixbuf *pixbuf = gdk_pixbuf_new_from_xpm_data( arrow_down_xpm );
+                    GtkWidget *dropdown = gtk_toggle_button_new();
+                    GtkWidget *image = gtk_image_new_from_pixbuf( pixbuf );
+                    gtk_widget_show( image );
+                    gtk_container_add( GTK_CONTAINER(dropdown), image );
+                    
+                    if (GetWindowStyle() & wxTB_FLAT)
+                        gtk_button_set_relief( GTK_BUTTON(dropdown), GTK_RELIEF_NONE );
+	                GTK_WIDGET_UNSET_FLAGS (dropdown, GTK_CAN_FOCUS);
+                    gtk_widget_show( dropdown );
+                
+                    g_signal_connect (dropdown, "enter_notify_event",
+                                  G_CALLBACK (gtk_toolbar_buddy_enter_callback),
+                                  tool->m_item);
+                    g_signal_connect (dropdown, "leave_notify_event",
+                                  G_CALLBACK (gtk_toolbar_buddy_leave_callback),
+                                  tool->m_item);
+                    g_signal_connect(dropdown, "button-press-event",
+                                  G_CALLBACK (gtk_toolbar_dropdown_lclick_callback),
+                                  tool);
+                                  
+                    GtkRequisition req;
+                    (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(tool->m_item) )->size_request )
+                        (tool->m_item, &req );
+                    gtk_widget_set_size_request( dropdown, -1, req.height );     
+                                  
+                    gtk_toolbar_insert_widget(
+                                       m_toolbar,
+                                       dropdown,
+                                       (const char *) NULL,
+                                       (const char *) NULL,
+                                       posGtk+1
+                                      );
+                }
             }
             break;
 
-- 
2.50.0

