X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9e691f46b2ec1b5dbbff2e51131e3c532e688a89..b5a7cdc076ec7a35990b2da37a4b7b81a9cc8f85:/src/gtk1/menu.cpp?ds=sidebyside diff --git a/src/gtk1/menu.cpp b/src/gtk1/menu.cpp index c41035bbc6..586b2ea034 100644 --- a/src/gtk1/menu.cpp +++ b/src/gtk1/menu.cpp @@ -110,7 +110,7 @@ void gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem *menu_item, static wxString wxReplaceUnderscore( const wxString& title ) { const wxChar *pc; - + /* GTK 1.2 wants to have "_" instead of "&" for accelerators */ wxString str; for ( pc = title; *pc != wxT('\0'); pc++ ) @@ -621,21 +621,25 @@ static void gtk_menu_clicked_callback( GtkWidget *widget, wxMenu *menu ) if (item->IsCheckable()) { - bool isReallyChecked = item->IsChecked(); - if ( item->wxMenuItemBase::IsChecked() == isReallyChecked ) + bool isReallyChecked = item->IsChecked(), + isInternallyChecked = item->wxMenuItemBase::IsChecked(); + + // ensure that the internal state is always consistent with what is + // shown on the screen + item->wxMenuItemBase::Check(isReallyChecked); + + // we must not report the events for the radio button going up nor the + // events resulting from the calls to wxMenuItem::Check() + if ( (item->GetKind() == wxITEM_RADIO && !isReallyChecked) || + (isInternallyChecked == isReallyChecked) ) { - /* the menu item has been checked by calling wxMenuItem->Check() */ return; } - else - { - /* the user pressed on the menu item -> report and make consistent - * again */ - item->wxMenuItemBase::Check(isReallyChecked); - } + + // the user pressed on the menu item: report the event below } - menu->SendEvent(item->GetId(), item->IsCheckable() ? item->IsChecked() : -1); + menu->SendEvent(id, item->IsCheckable() ? item->IsChecked() : -1); } //----------------------------------------------------------------------------- @@ -699,10 +703,21 @@ wxMenuItem *wxMenuItemBase::New(wxMenu *parentMenu, int id, const wxString& name, const wxString& help, - bool isCheckable, + wxItemKind kind, wxMenu *subMenu) { - return new wxMenuItem(parentMenu, id, name, help, isCheckable, subMenu); + return new wxMenuItem(parentMenu, id, name, help, kind, subMenu); +} + +wxMenuItem::wxMenuItem(wxMenu *parentMenu, + int id, + const wxString& text, + const wxString& help, + wxItemKind kind, + wxMenu *subMenu) + : wxMenuItemBase(parentMenu, id, text, help, kind, subMenu) +{ + Init(text); } wxMenuItem::wxMenuItem(wxMenu *parentMenu, @@ -711,15 +726,14 @@ wxMenuItem::wxMenuItem(wxMenu *parentMenu, const wxString& help, bool isCheckable, wxMenu *subMenu) + : wxMenuItemBase(parentMenu, id, text, help, + isCheckable ? wxITEM_CHECK : wxITEM_NORMAL, subMenu) { - m_id = id; - m_isCheckable = isCheckable; - m_isChecked = FALSE; - m_isEnabled = TRUE; - m_subMenu = subMenu; - m_parentMenu = parentMenu; - m_help = help; + Init(text); +} +void wxMenuItem::Init(const wxString& text) +{ m_labelWidget = (GtkWidget *) NULL; m_menuItem = (GtkWidget *) NULL; @@ -736,7 +750,7 @@ wxMenuItem::~wxMenuItem() wxString wxMenuItemBase::GetLabelFromText(const wxString& text) { wxString label; - + for ( const wxChar *pc = text.c_str(); *pc; pc++ ) { if ( *pc == wxT('_') ) @@ -746,7 +760,7 @@ wxString wxMenuItemBase::GetLabelFromText(const wxString& text) label += *pc; continue; } - + if ( *pc == wxT('&') ) { // wxMSW escapes & @@ -761,6 +775,14 @@ wxString wxMenuItemBase::GetLabelFromText(const wxString& text) void wxMenuItem::SetText( const wxString& str ) { + // Some optimization to avoid flicker + wxString oldLabel = m_text; + oldLabel = wxStripMenuCodes(oldLabel.BeforeFirst('\t')); + oldLabel.Replace(wxT("_"), wxT("")); + wxString label1 = wxStripMenuCodes(str.BeforeFirst('\t')); + if (oldLabel == label1) + return; + DoSetText(str); if (m_menuItem) @@ -841,13 +863,21 @@ void wxMenuItem::Check( bool check ) { wxCHECK_RET( m_menuItem, wxT("invalid menu item") ); - wxCHECK_RET( IsCheckable(), wxT("Can't check uncheckable item!") ) - if (check == m_isChecked) return; wxMenuItemBase::Check( check ); - gtk_check_menu_item_set_state( (GtkCheckMenuItem*)m_menuItem, (gint)check ); + + switch ( GetKind() ) + { + case wxITEM_CHECK: + case wxITEM_RADIO: + gtk_check_menu_item_set_state( (GtkCheckMenuItem*)m_menuItem, (gint)check ); + break; + + default: + wxFAIL_MSG( _T("can't check this item") ); + } } void wxMenuItem::Enable( bool enable ) @@ -881,10 +911,10 @@ wxString wxMenuItem::GetFactoryPath() const // remove '_' and '&' unconditionally continue; } - + path += *pc; } - + return path; } @@ -948,6 +978,11 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) bool appended = FALSE; #endif +#if GTK_CHECK_VERSION(1, 2, 0) + // does this item terminate the current radio group? + bool endOfRadioGroup = TRUE; +#endif // GTK+ >= 1.2 + if ( mitem->IsSeparator() ) { #if GTK_CHECK_VERSION(1, 2, 0) @@ -962,6 +997,9 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) /* this will be wrong for more than one separator. do we care? */ menuItem = gtk_item_factory_get_widget( m_factory, "
/sep" ); + + // we might have a separator inside a radio group + endOfRadioGroup = FALSE; #else // GTK+ 1.0 menuItem = gtk_menu_item_new(); #endif // GTK 1.2/1.0 @@ -1005,7 +1043,7 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) { wxString text( mitem->GetText() ); const wxBitmap *bitmap = &mitem->GetBitmap(); - + menuItem = gtk_pixmap_menu_item_new (); GtkWidget *label = gtk_accel_label_new (text.mb_str()); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); @@ -1046,16 +1084,51 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) /* local buffer in multibyte form */ char buf[200]; strcpy( buf, "/" ); - strcat( buf, text.mb_str() ); + strncat( buf, text.mb_str(), WXSIZEOF(buf) - 2 ); + buf[WXSIZEOF(buf) - 1] = '\0'; GtkItemFactoryEntry entry; entry.path = buf; entry.callback = (GtkItemFactoryCallback) gtk_menu_clicked_callback; entry.callback_action = 0; - if ( mitem->IsCheckable() ) - entry.item_type = (char *)""; - else - entry.item_type = (char *)""; + + wxString pathRadio; + const char *item_type; + switch ( mitem->GetKind() ) + { + case wxITEM_CHECK: + item_type = ""; + break; + + case wxITEM_RADIO: + if ( m_pathLastRadio.empty() ) + { + // start of a new radio group + item_type = ""; + m_pathLastRadio = buf + 1; + } + else // continue the radio group + { + pathRadio = m_pathLastRadio; + pathRadio.Replace("_", ""); + pathRadio.Prepend("
/"); + item_type = pathRadio; + } + + // continue the existing radio group, if any + endOfRadioGroup = FALSE; + break; + + default: + wxFAIL_MSG( _T("unexpected menu item kind") ); + // fall through + + case wxITEM_NORMAL: + item_type = ""; + break; + } + + entry.item_type = (char *)item_type; // cast needed for GTK+ entry.accelerator = (gchar*) NULL; #if wxUSE_ACCEL @@ -1105,6 +1178,13 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem) mitem->SetMenuItem(menuItem); +#if GTK_CHECK_VERSION(1, 2, 0) + if ( endOfRadioGroup ) + { + m_pathLastRadio.clear(); + } +#endif // GTK+ >= 1.2 + return TRUE; } @@ -1209,7 +1289,7 @@ static wxString GetHotKey( const wxMenuItem& item ) case WXK_F12: hotkey << wxT('F') << code - WXK_F1 + 1; break; - + // TODO: we should use gdk_keyval_name() (a.k.a. // XKeysymToString) here as well as hardcoding the keysym // names this might be not portable @@ -1343,7 +1423,7 @@ gtk_pixmap_menu_item_get_type (void) (GtkClassInitFunc) NULL, }; - pixmap_menu_item_type = gtk_type_unique (gtk_menu_item_get_type (), + pixmap_menu_item_type = gtk_type_unique (gtk_menu_item_get_type (), &pixmap_menu_item_info); } @@ -1353,7 +1433,7 @@ gtk_pixmap_menu_item_get_type (void) /** * gtk_pixmap_menu_item_new * - * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap() + * Creates a new pixmap menu item. Use gtk_pixmap_menu_item_set_pixmap() * to set the pixmap wich is displayed at the left side. * * Returns: @@ -1415,7 +1495,7 @@ gtk_pixmap_menu_item_draw (GtkWidget *widget, if (GTK_WIDGET_CLASS (parent_class)->draw) (* GTK_WIDGET_CLASS (parent_class)->draw) (widget, area); - if (GTK_WIDGET_DRAWABLE (widget) && + if (GTK_WIDGET_DRAWABLE (widget) && GTK_PIXMAP_MENU_ITEM(widget)->pixmap) { gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget)->pixmap),NULL); } @@ -1432,7 +1512,7 @@ gtk_pixmap_menu_item_expose (GtkWidget *widget, if (GTK_WIDGET_CLASS (parent_class)->expose_event) (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); - if (GTK_WIDGET_DRAWABLE (widget) && + if (GTK_WIDGET_DRAWABLE (widget) && GTK_PIXMAP_MENU_ITEM(widget)->pixmap) { gtk_widget_draw(GTK_WIDGET(GTK_PIXMAP_MENU_ITEM(widget)->pixmap),NULL); } @@ -1465,8 +1545,8 @@ gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem *menu_item, if (GTK_WIDGET_REALIZED (pixmap->parent) && !GTK_WIDGET_REALIZED (pixmap)) gtk_widget_realize (pixmap); - - if (GTK_WIDGET_VISIBLE (pixmap->parent)) { + + if (GTK_WIDGET_VISIBLE (pixmap->parent)) { if (GTK_WIDGET_MAPPED (pixmap->parent) && GTK_WIDGET_VISIBLE(pixmap) && !GTK_WIDGET_MAPPED (pixmap)) @@ -1474,7 +1554,7 @@ gtk_pixmap_menu_item_set_pixmap (GtkPixmapMenuItem *menu_item, } changed_have_pixmap_status(menu_item); - + if (GTK_WIDGET_VISIBLE (pixmap) && GTK_WIDGET_VISIBLE (menu_item)) gtk_widget_queue_resize (pixmap); } @@ -1560,7 +1640,7 @@ gtk_pixmap_menu_item_size_request (GtkWidget *widget, GTK_WIDGET_CLASS(parent_class)->size_request(widget,requisition); menu_item = GTK_PIXMAP_MENU_ITEM (widget); - + if (menu_item->pixmap) gtk_widget_size_request(menu_item->pixmap, &req); @@ -1581,19 +1661,19 @@ gtk_pixmap_menu_item_remove (GtkContainer *container, g_return_if_fail (GTK_IS_WIDGET (child)); bin = GTK_BIN (container); - g_return_if_fail ((bin->child == child || + g_return_if_fail ((bin->child == child || (GTK_PIXMAP_MENU_ITEM(container)->pixmap == child))); widget_was_visible = GTK_WIDGET_VISIBLE (child); - + gtk_widget_unparent (child); if (bin->child == child) - bin->child = NULL; + bin->child = NULL; else { GTK_PIXMAP_MENU_ITEM(container)->pixmap = NULL; changed_have_pixmap_status(GTK_PIXMAP_MENU_ITEM(container)); } - + if (widget_was_visible) gtk_widget_queue_resize (GTK_WIDGET (container)); } @@ -1615,7 +1695,7 @@ changed_have_pixmap_status (GtkPixmapMenuItem *menu_item) if (GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item)->have_pixmap_count == 0) { /* Install normal toggle size */ - GTK_MENU_ITEM_GET_CLASS(menu_item)->toggle_size = GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item)->orig_toggle_size; + GTK_MENU_ITEM_GET_CLASS(menu_item)->toggle_size = GTK_PIXMAP_MENU_ITEM_GET_CLASS(menu_item)->orig_toggle_size; } } @@ -1624,7 +1704,7 @@ changed_have_pixmap_status (GtkPixmapMenuItem *menu_item) this function is called, we get the same effect, just because of how the preferences option to show pixmaps works. Bogus, broken. */ - if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item))) + if (GTK_WIDGET_VISIBLE(GTK_WIDGET(menu_item))) gtk_widget_queue_resize(GTK_WIDGET(menu_item)); }