-wxMenu::wxMenu( const wxString &title )
-{
- m_title = title;
- m_items.DeleteContents( TRUE );
- m_invokingWindow = NULL;
- m_menu = gtk_menu_new(); // Do not show!
-};
-
-void wxMenu::AppendSeparator()
-{
- wxMenuItem *mitem = new wxMenuItem();
- mitem->SetId(ID_SEPARATOR);
-
- GtkWidget *menuItem = gtk_menu_item_new();
- gtk_menu_append( GTK_MENU(m_menu), menuItem );
- gtk_widget_show( menuItem );
- mitem->SetMenuItem(menuItem);
- m_items.Append( mitem );
-};
-
-void wxMenu::Append( int id, const wxString &item, const wxString &helpStr, bool checkable )
-{
- wxMenuItem *mitem = new wxMenuItem();
- mitem->SetId(id);
- mitem->SetText(item);
- mitem->SetHelpString(helpStr);
- mitem->SetCheckable(checkable);
- const char *text = mitem->GetText();
- GtkWidget *menuItem = checkable ? gtk_check_menu_item_new_with_label(text)
- : gtk_menu_item_new_with_label(text);
- mitem->SetMenuItem(menuItem);
-
- gtk_signal_connect( GTK_OBJECT(menuItem), "activate",
- GTK_SIGNAL_FUNC(gtk_menu_clicked_callback),
- (gpointer*)this );
-
- gtk_menu_append( GTK_MENU(m_menu), menuItem );
- gtk_widget_show( menuItem );
- m_items.Append( mitem );
-};
-
-void wxMenu::Append( int id, const wxString &text, wxMenu *subMenu, const wxString &helpStr )
-{
- wxMenuItem *mitem = new wxMenuItem();
- mitem->SetId(id);
- mitem->SetText(text);
-
- GtkWidget *menuItem = gtk_menu_item_new_with_label(mitem->GetText());
- mitem->SetHelpString(helpStr);
- mitem->SetMenuItem(menuItem);
- mitem->SetSubMenu(subMenu);
-
- gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), subMenu->m_menu );
- gtk_menu_append( GTK_MENU(m_menu), menuItem );
- gtk_widget_show( menuItem );
- m_items.Append( mitem );
-};
-
-int wxMenu::FindItem( const wxString itemString ) const
-{
- wxString s( itemString );
-
- size_t pos;
- do {
- pos = s.First( '&' );
- if (pos != wxString::npos) s.Remove( pos, 1 );
- } while (pos != wxString::npos);
-
- wxNode *node = m_items.First();
- while (node)
- {
- wxMenuItem *item = (wxMenuItem*)node->Data();
- if (item->GetText() == s)
- return item->GetId();
- node = node->Next();
- };
-
- return -1;
-};
-
-void wxMenu::Enable( int id, bool enable )
-{
- wxMenuItem *item = FindItem(id);
- if ( item )
- item->Enable(enable);
-};
-
-bool wxMenu::IsEnabled( int id ) const
-{
- wxMenuItem *item = FindItem(id);
- if ( item )
- return item->IsEnabled();
- else
- return FALSE;
-};
-
-void wxMenu::Check( int id, bool enable )
-{
- wxMenuItem *item = FindItem(id);
- if ( item )
- item->Check(enable);
-};
-
-bool wxMenu::IsChecked( int id ) const
-{
- wxMenuItem *item = FindItem(id);
- if ( item )
- return item->IsChecked();
- else
- return FALSE;
-};
-
-void wxMenu::SetLabel( int id, const wxString &label )
-{
- wxMenuItem *item = FindItem(id);
- if ( item )
- item->SetText(label);
-};
+void wxMenu::Init()
+{
+ m_accel = gtk_accel_group_new();
+ m_menu = gtk_menu_new();
+ // NB: keep reference to the menu so that it is not destroyed behind
+ // our back by GTK+ e.g. when it is removed from menubar:
+ gtk_widget_ref(m_menu);
+
+ m_owner = (GtkWidget*) NULL;
+
+ // Tearoffs are entries, just like separators. So if we want this
+ // menu to be a tear-off one, we just append a tearoff entry
+ // immediately.
+ if ( m_style & wxMENU_TEAROFF )
+ {
+ GtkWidget *tearoff = gtk_tearoff_menu_item_new();
+
+ gtk_menu_append(GTK_MENU(m_menu), tearoff);
+ }
+
+ m_prevRadio = NULL;
+
+ // append the title as the very first entry if we have it
+ if ( !m_title.empty() )
+ {
+ Append(wxGTK_TITLE_ID, m_title);
+ AppendSeparator();
+ }
+}
+
+wxMenu::~wxMenu()
+{
+ WX_CLEAR_LIST(wxMenuItemList, m_items);
+
+ if ( GTK_IS_WIDGET( m_menu ))
+ {
+ // see wxMenu::Init
+ gtk_widget_unref( m_menu );
+ // if the menu is inserted in another menu at this time, there was
+ // one more reference to it:
+ if ( m_owner )
+ gtk_widget_destroy( m_menu );
+ }
+}
+
+bool wxMenu::GtkAppend(wxMenuItem *mitem, int pos)
+{
+ GtkWidget *menuItem;
+
+ wxString text;
+
+ if ( mitem->IsSeparator() )
+ {
+ menuItem = gtk_separator_menu_item_new();
+ }
+ else if (mitem->GetBitmap().Ok())
+ {
+ text = mitem->GetText();
+ const wxBitmap *bitmap = &mitem->GetBitmap();
+
+ menuItem = gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV( text ) );
+
+ GtkWidget *image;
+ if (bitmap->HasPixbuf())
+ {
+ image = gtk_image_new_from_pixbuf(bitmap->GetPixbuf());
+ }
+ else
+ {
+ GdkPixmap *gdk_pixmap = bitmap->GetPixmap();
+ GdkBitmap *gdk_bitmap = bitmap->GetMask() ?
+ bitmap->GetMask()->GetBitmap() :
+ (GdkBitmap*) NULL;
+ image = gtk_image_new_from_pixmap( gdk_pixmap, gdk_bitmap );
+ }
+
+ gtk_widget_show(image);
+
+ gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuItem), image );
+
+ m_prevRadio = NULL;
+ }
+ else // a normal item
+ {
+ // text has "_" instead of "&" after mitem->SetText() so don't use it
+ text = mitem->GetText() ;
+
+ switch ( mitem->GetKind() )
+ {
+ case wxITEM_CHECK:
+ {
+ menuItem = gtk_check_menu_item_new_with_mnemonic( wxGTK_CONV( text ) );
+ m_prevRadio = NULL;
+ break;
+ }
+
+ case wxITEM_RADIO:
+ {
+ GSList *group = NULL;
+ if ( m_prevRadio == NULL )
+ {
+ // start of a new radio group
+ m_prevRadio = menuItem = gtk_radio_menu_item_new_with_mnemonic( group, wxGTK_CONV( text ) );
+ }
+ else // continue the radio group
+ {
+ group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (m_prevRadio));
+ m_prevRadio = menuItem = gtk_radio_menu_item_new_with_mnemonic( group, wxGTK_CONV( text ) );
+ }
+ break;
+ }
+
+ default:
+ wxFAIL_MSG( _T("unexpected menu item kind") );
+ // fall through
+
+ case wxITEM_NORMAL:
+ {
+ menuItem = gtk_menu_item_new_with_mnemonic( wxGTK_CONV( text ) );
+ m_prevRadio = NULL;
+ break;
+ }
+ }
+
+ }
+
+ guint accel_key;
+ GdkModifierType accel_mods;
+ wxCharBuffer buf = wxGTK_CONV( GetGtkHotKey(*mitem) );
+
+ // wxPrintf( wxT("item: %s hotkey %s\n"), mitem->GetText().c_str(), GetGtkHotKey(*mitem).c_str() );
+ gtk_accelerator_parse( (const char*) buf, &accel_key, &accel_mods);
+ if (accel_key != 0)
+ {
+ gtk_widget_add_accelerator (GTK_WIDGET(menuItem),
+ "activate",
+ m_accel,
+ accel_key,
+ accel_mods,
+ GTK_ACCEL_VISIBLE);
+ }
+
+ if (pos == -1)
+ gtk_menu_shell_append(GTK_MENU_SHELL(m_menu), menuItem);
+ else
+ gtk_menu_shell_insert(GTK_MENU_SHELL(m_menu), menuItem, pos);
+
+ gtk_widget_show( menuItem );
+
+ if ( !mitem->IsSeparator() )
+ {
+ wxASSERT_MSG( menuItem, wxT("invalid menuitem") );
+
+ g_signal_connect (menuItem, "select",
+ G_CALLBACK (gtk_menu_hilight_callback), this);
+ g_signal_connect (menuItem, "deselect",
+ G_CALLBACK (gtk_menu_nolight_callback), this);
+
+ if ( mitem->IsSubMenu() && mitem->GetKind() != wxITEM_RADIO && mitem->GetKind() != wxITEM_CHECK )
+ {
+ gtk_menu_item_set_submenu( GTK_MENU_ITEM(menuItem), mitem->GetSubMenu()->m_menu );
+
+ gtk_widget_show( mitem->GetSubMenu()->m_menu );
+
+ // if adding a submenu to a menu already existing in the menu bar, we
+ // must set invoking window to allow processing events from this
+ // submenu
+ if ( m_invokingWindow )
+ wxMenubarSetInvokingWindow(mitem->GetSubMenu(), m_invokingWindow);
+ }
+ else
+ {
+ g_signal_connect (menuItem, "activate",
+ G_CALLBACK (gtk_menu_clicked_callback),
+ this);
+ }
+ }
+
+ mitem->SetMenuItem(menuItem);
+
+ if (ms_locked)
+ {
+ // This doesn't even exist!
+ // gtk_widget_lock_accelerators(mitem->GetMenuItem());
+ }
+
+ return TRUE;
+}
+
+wxMenuItem* wxMenu::DoAppend(wxMenuItem *mitem)
+{
+ if (!GtkAppend(mitem))
+ return NULL;
+
+ return wxMenuBase::DoAppend(mitem);
+}
+
+wxMenuItem* wxMenu::DoInsert(size_t pos, wxMenuItem *item)
+{
+ if ( !wxMenuBase::DoInsert(pos, item) )
+ return NULL;
+
+ // TODO
+ if ( !GtkAppend(item, (int)pos) )
+ return NULL;
+
+ return item;
+}
+
+wxMenuItem *wxMenu::DoRemove(wxMenuItem *item)
+{
+ if ( !wxMenuBase::DoRemove(item) )
+ return (wxMenuItem *)NULL;
+
+ // TODO: this code doesn't delete the item factory item and this seems
+ // impossible as of GTK 1.2.6.
+ gtk_widget_destroy( item->GetMenuItem() );
+
+ return item;
+}