X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fab591c5cceff41c0bedaa89af34cd039e2c44e1..a148cfb64451d6553cf66d1075b654e54e908210:/src/gtk1/menu.cpp?ds=sidebyside diff --git a/src/gtk1/menu.cpp b/src/gtk1/menu.cpp index 6250455059..d304c46a84 100644 --- a/src/gtk1/menu.cpp +++ b/src/gtk1/menu.cpp @@ -96,10 +96,10 @@ struct _GtkPixmapMenuItemClass }; -GtkType gtk_pixmap_menu_item_get_type (void); +GtkType gtk_pixmap_menu_item_get_type (void); GtkWidget* gtk_pixmap_menu_item_new (void); void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem *menu_item, - GtkWidget *pixmap); + GtkWidget *pixmap); #endif // USE_MENU_BITMAPS @@ -113,9 +113,16 @@ static wxString wxReplaceUnderscore( const wxString& title ) /* GTK 1.2 wants to have "_" instead of "&" for accelerators */ wxString str; - for ( pc = title; *pc != wxT('\0'); pc++ ) + pc = title; + while (*pc != wxT('\0')) { - if (*pc == wxT('&')) + if ((*pc == wxT('&')) && (*(pc+1) == wxT('&'))) + { + // "&" is doubled to indicate "&" instead of accelerator + ++pc; + str << wxT('&'); + } + else if (*pc == wxT('&')) { #if GTK_CHECK_VERSION(1, 2, 0) str << wxT('_'); @@ -149,6 +156,7 @@ static wxString wxReplaceUnderscore( const wxString& title ) str << *pc; } + ++pc; } return str; } @@ -385,10 +393,23 @@ bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title) #endif // m_invokingWindow is set after wxFrame::SetMenuBar(). This call enables - // adding menu later on. + // addings menu later on. if (m_invokingWindow) + { wxMenubarSetInvokingWindow( menu, m_invokingWindow ); + // OPTIMISE ME: we should probably cache this, or pass it + // directly, but for now this is a minimal + // change to validate the new dynamic sizing. + // see (and refactor :) similar code in Remove + // below. + + wxFrame *frame = wxDynamicCast( m_invokingWindow, wxFrame ); + + if( frame ) + frame->UpdateMenuBarSize(); + } + return TRUE; } @@ -427,6 +448,36 @@ wxMenu *wxMenuBar::Replace(size_t pos, wxMenu *menu, const wxString& title) return menuOld; } +static wxMenu *CopyMenu (wxMenu *menu) +{ + wxMenu *menucopy = new wxMenu (); + wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst(); + while (node) + { + wxMenuItem *item = node->GetData(); + int itemid = item->GetId(); + wxString text = item->GetText(); + text.Replace(wxT("_"), wxT("&")); + wxMenu *submenu = item->GetSubMenu(); + if (!submenu) + { + wxMenuItem* itemcopy = new wxMenuItem(menucopy, + itemid, text, + menu->GetHelpString(itemid)); + itemcopy->SetBitmap(item->GetBitmap()); + itemcopy->SetCheckable(item->IsCheckable()); + menucopy->Append(itemcopy); + } + else + menucopy->Append (itemid, text, CopyMenu(submenu), + menu->GetHelpString(itemid)); + + node = node->GetNext(); + } + + return menucopy; +} + wxMenu *wxMenuBar::Remove(size_t pos) { wxMenu *menu = wxMenuBarBase::Remove(pos); @@ -440,18 +491,32 @@ wxMenu *wxMenuBar::Remove(size_t pos) printf( "menu shell entries before %d\n", (int)g_list_length( menu_shell->children ) ); */ + wxMenu *menucopy = CopyMenu( menu ); + // unparent calls unref() and that would delete the widget so we raise // the ref count to 2 artificially before invoking unparent. gtk_widget_ref( menu->m_menu ); gtk_widget_unparent( menu->m_menu ); gtk_widget_destroy( menu->m_owner ); + delete menu; + menu = menucopy; /* printf( "factory entries after %d\n", (int)g_slist_length(m_factory->items) ); printf( "menu shell entries after %d\n", (int)g_list_length( menu_shell->children ) ); */ + if (m_invokingWindow) + { + // OPTIMISE ME: see comment in GtkAppend + + wxFrame *frame = wxDynamicCast( m_invokingWindow, wxFrame ); + + if( frame ) + frame->UpdateMenuBarSize(); + } + return menu; } @@ -554,13 +619,15 @@ wxString wxMenuBar::GetLabelTop( size_t pos ) const wxString text( menu->GetTitle() ); for ( const wxChar *pc = text.c_str(); *pc; pc++ ) { - if ( *pc == wxT('_') || *pc == wxT('&') ) + if ( *pc == wxT('_') ) { - // '_' is the escape character for GTK+ and '&' is the one for - // wxWindows - skip both of them + // '_' is the escape character for GTK+ continue; } + // don't remove ampersands '&' since if we have them in the menu title + // it means that they were doubled to indicate "&" instead of accelerator + label += *pc; } @@ -748,23 +815,33 @@ wxString wxMenuItemBase::GetLabelFromText(const wxString& text) for ( const wxChar *pc = text.c_str(); *pc; pc++ ) { - if ( *pc == wxT('_') ) + if ( *pc == wxT('_') ) { - // wxGTK escapes "xxx_xxx" to "xxx__xxx" + // GTK 1.2 escapes "xxx_xxx" to "xxx__xxx" pc++; label += *pc; continue; } - if ( *pc == wxT('&') ) +#if GTK_CHECK_VERSION(2, 0, 0) + if ( *pc == wxT('\\') ) { - // wxMSW escapes & + // GTK 2.0 escapes "xxx/xxx" to "xxx\/xxx" + pc++; + label += *pc; continue; } +#endif + if ( (*pc == wxT('&')) && (*(pc+1) != wxT('&')) ) + { + // wxMSW escapes "&" + // "&" is doubled to indicate "&" instead of accelerator + continue; + } + label += *pc; } - return label; } @@ -784,42 +861,54 @@ void wxMenuItem::SetText( const wxString& str ) { GtkLabel *label; if (m_labelWidget) - label = (GtkLabel*) m_labelWidget; + label = (GtkLabel*) m_labelWidget; else - label = GTK_LABEL( GTK_BIN(m_menuItem)->child ); + label = GTK_LABEL( GTK_BIN(m_menuItem)->child ); - /* set new text */ +#if GTK_CHECK_VERSION(2, 0, 0) + // We have to imitate item_factory_unescape_label here + wxString tmp; + for (size_t n = 0; n < m_text.Len(); n++) + { + if (m_text[n] != wxT('\\')) + tmp += m_text[n]; + } + + gtk_label_set_text_with_mnemonic( GTK_LABEL(label), wxGTK_CONV(tmp) ); +#else + // set new text gtk_label_set( label, wxGTK_CONV( m_text ) ); - /* reparse key accel */ - (void)gtk_label_parse_uline (GTK_LABEL(label), wxGTK_CONV( m_text ) ); + // reparse key accel + (void)gtk_label_parse_uline (GTK_LABEL(label), wxGTK_CONV(m_text) ); gtk_accel_label_refetch( GTK_ACCEL_LABEL(label) ); +#endif } } // it's valid for this function to be called even if m_menuItem == NULL void wxMenuItem::DoSetText( const wxString& str ) { - /* '\t' is the deliminator indicating a hot key */ + // '\t' is the deliminator indicating a hot key m_text.Empty(); const wxChar *pc = str; - for (; (*pc != wxT('\0')) && (*pc != wxT('\t')); pc++ ) + while ( (*pc != wxT('\0')) && (*pc != wxT('\t')) ) { -#if GTK_CHECK_VERSION(1, 2, 0) - if (*pc == wxT('&')) + if ((*pc == wxT('&')) && (*(pc+1) == wxT('&'))) { - m_text << wxT('_'); + // "&" is doubled to indicate "&" instead of accelerator + ++pc; + m_text << wxT('&'); } - else if ( *pc == wxT('_') ) // escape underscores + else if (*pc == wxT('&')) { - m_text << wxT("__"); + m_text << wxT('_'); } -#else // GTK+ < 1.2.0 - if (*pc == wxT('&')) +#if GTK_CHECK_VERSION(2, 0, 0) + else if ( *pc == wxT('_') ) // escape underscores { + // m_text << wxT("__"); doesn't work } -#endif -#if GTK_CHECK_VERSION(2, 0, 0) else if (*pc == wxT('/')) // we have to escape slashes { m_text << wxT("\\/"); @@ -828,16 +917,22 @@ void wxMenuItem::DoSetText( const wxString& str ) { m_text << wxT("\\\\"); } -#elif GTK_CHECK_VERSION(1, 2, 0) +#else + else if ( *pc == wxT('_') ) // escape underscores + { + m_text << wxT("__"); + } else if (*pc == wxT('/')) /* we have to filter out slashes ... */ { m_text << wxT('\\'); /* ... and replace them with back slashes */ } #endif - else + else { m_text << *pc; + } + ++pc; } - + m_hotKey = wxT(""); if(*pc == wxT('\t')) @@ -913,12 +1008,15 @@ wxString wxMenuItem::GetFactoryPath() const for ( const wxChar *pc = m_text.c_str(); *pc; pc++ ) { - if ( *pc == wxT('_') || *pc == wxT('&') ) + if ( *pc == wxT('_') ) { - // remove '_' and '&' unconditionally + // remove '_' unconditionally continue; } + // don't remove ampersands '&' since if we have them in the menu item title + // it means that they were doubled to indicate "&" instead of accelerator + path += *pc; } @@ -1042,12 +1140,12 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) guint accel_key = gtk_label_parse_uline (GTK_LABEL(label), wxGTK_CONV( text ) ); gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (label), menuItem); if (accel_key != GDK_VoidSymbol) - { + { gtk_widget_add_accelerator (menuItem, - "activate_item", - gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu)), - accel_key, 0, - GTK_ACCEL_LOCKED); + "activate_item", + gtk_menu_ensure_uline_accel_group (GTK_MENU (m_menu)), + accel_key, 0, + GTK_ACCEL_LOCKED); } gtk_widget_show (label); @@ -1060,6 +1158,7 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) 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 ); @@ -1068,22 +1167,23 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) #endif // USE_MENU_BITMAPS else // a normal item { - /* text has "_" instead of "&" after mitem->SetText() */ + // text has "_" instead of "&" after mitem->SetText() so don't use it wxString text( mitem->GetText() ); - /* local buffer in multibyte form */ - char buf[200]; - strcpy( buf, "/" ); - strncat( buf, wxGTK_CONV(text), WXSIZEOF(buf) - 2 ); - buf[WXSIZEOF(buf) - 1] = '\0'; + // buffers containing the menu item path and type in multibyte form + char bufPath[256], + bufType[256]; + + strcpy( bufPath, "/" ); + strncat( bufPath, wxGTK_CONV(text), WXSIZEOF(bufPath) - 2 ); + bufPath[WXSIZEOF(bufPath) - 1] = '\0'; GtkItemFactoryEntry entry; - entry.path = buf; + entry.path = bufPath; entry.callback = (GtkItemFactoryCallback) gtk_menu_clicked_callback; entry.callback_action = 0; wxString pathRadio; - char buf2[200]; const char *item_type; switch ( mitem->GetKind() ) { @@ -1096,16 +1196,19 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) { // start of a new radio group item_type = ""; - m_pathLastRadio = buf + 1; + wxString tmp( wxGTK_CONV_BACK( bufPath ) ); + tmp.Remove(0,1); + m_pathLastRadio = tmp; } else // continue the radio group { pathRadio = m_pathLastRadio; pathRadio.Replace(wxT("_"), wxT("")); pathRadio.Prepend(wxT("
/")); - strncat( buf2, wxGTK_CONV(pathRadio), WXSIZEOF(buf2) - 2 ); - buf2[WXSIZEOF(buf2) - 1] = '\0'; - item_type = buf2; + + strncpy(bufType, wxGTK_CONV(pathRadio), WXSIZEOF(bufType)); + bufType[WXSIZEOF(bufType) - 1] = '\0'; + item_type = bufType; } // continue the existing radio group, if any @@ -1128,9 +1231,10 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) // due to an apparent bug in GTK+, we have to use a static buffer here - // otherwise GTK+ 1.2.2 manages to override the memory we pass to it // somehow! (VZ) - static char s_accel[50]; // must be big enough + char s_accel[50]; // should be big enough, we check for overruns wxString tmp( GetHotKey(*mitem) ); strncpy(s_accel, wxGTK_CONV( tmp ), WXSIZEOF(s_accel)); + s_accel[WXSIZEOF(s_accel) - 1] = '\0'; entry.accelerator = s_accel; #else // !wxUSE_ACCEL entry.accelerator = (char*) NULL; @@ -1140,10 +1244,15 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) wxString path( mitem->GetFactoryPath() ); menuItem = gtk_item_factory_get_widget( m_factory, wxGTK_CONV( path ) ); + + if (!menuItem) + wxLogError( wxT("Wrong menu path: %s\n"), path.c_str() ); } if ( !mitem->IsSeparator() ) { + wxASSERT_MSG( menuItem, wxT("invalid menuitem") ); + gtk_signal_connect( GTK_OBJECT(menuItem), "select", GTK_SIGNAL_FUNC(gtk_menu_hilight_callback), (gpointer)this ); @@ -1214,13 +1323,13 @@ wxMenuItem *wxMenu::DoRemove(wxMenuItem *item) int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const { - wxNode *node = m_items.First(); + wxMenuItemList::Node *node = m_items.GetFirst(); while (node) { - wxMenuItem *item = (wxMenuItem*)node->Data(); + wxMenuItem *item = node->GetData(); if (item->GetMenuItem() == menuItem) return item->GetId(); - node = node->Next(); + node = node->GetNext(); } return wxNOT_FOUND; @@ -1280,6 +1389,33 @@ static wxString GetHotKey( const wxMenuItem& item ) case WXK_DELETE: hotkey << wxT("Delete" ); break; + case WXK_UP: + hotkey << wxT("Up" ); + break; + case WXK_DOWN: + hotkey << wxT("Down" ); + break; + case WXK_PAGEUP: + hotkey << wxT("Prior" ); + break; + case WXK_PAGEDOWN: + hotkey << wxT("Next" ); + break; + case WXK_LEFT: + hotkey << wxT("Left" ); + break; + case WXK_RIGHT: + hotkey << wxT("Right" ); + break; + case WXK_HOME: + hotkey << wxT("Home" ); + break; + case WXK_END: + hotkey << wxT("End" ); + break; + case WXK_RETURN: + hotkey << wxT("Return" ); + break; // if there are any other keys wxGetAccelFromString() may // return, we should process them here @@ -1287,7 +1423,7 @@ static wxString GetHotKey( const wxMenuItem& item ) default: if ( code < 127 ) { - gchar *name = gdk_keyval_name((guint)code); + wxString name = wxGTK_CONV_BACK( gdk_keyval_name((guint)code) ); if ( name ) { hotkey << name; @@ -1352,23 +1488,23 @@ extern "C" static void gtk_pixmap_menu_item_class_init (GtkPixmapMenuItemClass *klass); static void gtk_pixmap_menu_item_init (GtkPixmapMenuItem *menu_item); static void gtk_pixmap_menu_item_draw (GtkWidget *widget, - GdkRectangle *area); + GdkRectangle *area); static gint gtk_pixmap_menu_item_expose (GtkWidget *widget, - GdkEventExpose *event); + GdkEventExpose *event); /* we must override the following functions */ static void gtk_pixmap_menu_item_map (GtkWidget *widget); static void gtk_pixmap_menu_item_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); + GtkAllocation *allocation); static void gtk_pixmap_menu_item_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data); + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); static void gtk_pixmap_menu_item_size_request (GtkWidget *widget, - GtkRequisition *requisition); + GtkRequisition *requisition); static void gtk_pixmap_menu_item_remove (GtkContainer *container, - GtkWidget *child); + GtkWidget *child); static void changed_have_pixmap_status (GtkPixmapMenuItem *menu_item); @@ -1399,7 +1535,7 @@ gtk_pixmap_menu_item_get_type (void) }; pixmap_menu_item_type = gtk_type_unique (gtk_menu_item_get_type (), - &pixmap_menu_item_info); + &pixmap_menu_item_info); } return pixmap_menu_item_type; @@ -1461,7 +1597,7 @@ gtk_pixmap_menu_item_init (GtkPixmapMenuItem *menu_item) static void gtk_pixmap_menu_item_draw (GtkWidget *widget, - GdkRectangle *area) + GdkRectangle *area) { g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget)); @@ -1478,7 +1614,7 @@ gtk_pixmap_menu_item_draw (GtkWidget *widget, static gint gtk_pixmap_menu_item_expose (GtkWidget *widget, - GdkEventExpose *event) + GdkEventExpose *event) { g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_PIXMAP_MENU_ITEM (widget), FALSE); @@ -1506,7 +1642,7 @@ gtk_pixmap_menu_item_expose (GtkWidget *widget, void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem *menu_item, - GtkWidget *pixmap) + GtkWidget *pixmap) { g_return_if_fail (menu_item != NULL); g_return_if_fail (pixmap != NULL); @@ -1523,7 +1659,7 @@ gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem *menu_item, if (GTK_WIDGET_VISIBLE (pixmap->parent)) { if (GTK_WIDGET_MAPPED (pixmap->parent) && - GTK_WIDGET_VISIBLE(pixmap) && + GTK_WIDGET_VISIBLE(pixmap) && !GTK_WIDGET_MAPPED (pixmap)) gtk_widget_map (pixmap); } @@ -1554,7 +1690,7 @@ gtk_pixmap_menu_item_map (GtkWidget *widget) static void gtk_pixmap_menu_item_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) + GtkAllocation *allocation) { GtkPixmapMenuItem *pmenu_item; @@ -1571,8 +1707,8 @@ gtk_pixmap_menu_item_size_allocate (GtkWidget *widget, child_allocation.height = pmenu_item->pixmap->requisition.height; child_allocation.x = border_width + BORDER_SPACING; child_allocation.y = (border_width + BORDER_SPACING - + (((allocation->height - child_allocation.height) - child_allocation.x) - / 2)); /* center pixmaps vertically */ + + (((allocation->height - child_allocation.height) - child_allocation.x) + / 2)); /* center pixmaps vertically */ gtk_widget_size_allocate (pmenu_item->pixmap, &child_allocation); } @@ -1582,9 +1718,9 @@ gtk_pixmap_menu_item_size_allocate (GtkWidget *widget, static void gtk_pixmap_menu_item_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) { GtkPixmapMenuItem *menu_item; @@ -1598,12 +1734,12 @@ gtk_pixmap_menu_item_forall (GtkContainer *container, (* callback) (menu_item->pixmap, callback_data); GTK_CONTAINER_CLASS(parent_class)->forall(container,include_internals, - callback,callback_data); + callback,callback_data); } static void gtk_pixmap_menu_item_size_request (GtkWidget *widget, - GtkRequisition *requisition) + GtkRequisition *requisition) { GtkPixmapMenuItem *menu_item; GtkRequisition req = {0, 0}; @@ -1625,7 +1761,7 @@ gtk_pixmap_menu_item_size_request (GtkWidget *widget, static void gtk_pixmap_menu_item_remove (GtkContainer *container, - GtkWidget *child) + GtkWidget *child) { GtkBin *bin; gboolean widget_was_visible; @@ -1637,7 +1773,7 @@ gtk_pixmap_menu_item_remove (GtkContainer *container, bin = GTK_BIN (container); g_return_if_fail ((bin->child == child || - (GTK_PIXMAP_MENU_ITEM(container)->pixmap == child))); + (GTK_PIXMAP_MENU_ITEM(container)->pixmap == child))); widget_was_visible = GTK_WIDGET_VISIBLE (child);