X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ab73fe8d1dc54cb83e3a18868db770c96760fbb6..4913272f9cdead94a6d1470e51d6fb14946b50e0:/src/gtk/menu.cpp diff --git a/src/gtk/menu.cpp b/src/gtk/menu.cpp index f11a1571d5..ff7cac5e42 100644 --- a/src/gtk/menu.cpp +++ b/src/gtk/menu.cpp @@ -15,19 +15,15 @@ #ifndef WX_PRECOMP #include "wx/intl.h" #include "wx/log.h" - #include "wx/app.h" + #include "wx/frame.h" #include "wx/bitmap.h" + #include "wx/app.h" #endif -#if wxUSE_ACCEL - #include "wx/accel.h" -#endif // wxUSE_ACCEL - +#include "wx/accel.h" #include "wx/stockitem.h" #include "wx/gtk/private.h" -#include - // FIXME: is this right? somehow I don't think so (VZ) #define gtk_accel_group_attach(g, o) gtk_window_add_accel_group((o), (g)) @@ -260,6 +256,50 @@ void wxMenuBar::SetInvokingWindow( wxWindow *win ) } } +void wxMenuBar::SetLayoutDirection(wxLayoutDirection dir) +{ + if ( dir == wxLayout_Default ) + { + const wxWindow *const frame = GetFrame(); + if ( frame ) + { + // inherit layout from frame. + dir = frame->GetLayoutDirection(); + } + else // use global layout + { + dir = wxTheApp->GetLayoutDirection(); + } + } + + if ( dir == wxLayout_Default ) + return; + + GTKSetLayout(m_menubar, dir); + + // also set the layout of all menus we already have (new ones will inherit + // the current layout) + for ( wxMenuList::compatibility_iterator node = m_menus.GetFirst(); + node; + node = node->GetNext() ) + { + wxMenu *const menu = node->GetData(); + menu->SetLayoutDirection(dir); + } +} + +wxLayoutDirection wxMenuBar::GetLayoutDirection() const +{ + return GTKGetLayout(m_menubar); +} + +void wxMenuBar::Attach(wxFrame *frame) +{ + wxMenuBarBase::Attach(frame); + + SetLayoutDirection(wxLayout_Default); +} + void wxMenuBar::UnsetInvokingWindow( wxWindow *win ) { m_invokingWindow = (wxWindow*) NULL; @@ -293,6 +333,7 @@ bool wxMenuBar::GtkAppend(wxMenu *menu, const wxString& title, int pos) // The "m_owner" is the "menu item" menu->m_owner = gtk_menu_item_new_with_mnemonic( wxGTK_CONV( str ) ); + menu->SetLayoutDirection(GetLayoutDirection()); gtk_widget_show( menu->m_owner ); @@ -738,6 +779,12 @@ wxString wxMenuItemBase::GetLabelFromText(const wxString& text) void wxMenuItem::SetText( const wxString& str ) { + // cache some data which must be used later + bool isstock = wxIsStockID(GetId()); + const char *stockid = NULL; + if (isstock) + stockid = wxGetStockGtkID(GetId()); + // Some optimization to avoid flicker wxString oldLabel = m_text; oldLabel = wxStripMenuCodes(oldLabel); @@ -749,7 +796,7 @@ void wxMenuItem::SetText( const wxString& str ) DoSetText(str); if (oldLabel == label1 && - oldhotkey == GetHotKey()) // Make sure we can change a hotkey even if the label is unaltered + oldhotkey == GetHotKey()) // Make sure we can change a hotkey even if the label is unaltered return; if (m_menuItem) @@ -760,38 +807,78 @@ void wxMenuItem::SetText( const wxString& str ) else label = GTK_LABEL( GTK_BIN(m_menuItem)->child ); - gtk_label_set_text_with_mnemonic( GTK_LABEL(label), wxGTK_CONV_SYS(m_text) ); + // stock menu items can have empty labels: + wxString text = m_text; + if (text.IsEmpty() && !IsSeparator()) + { + wxASSERT_MSG(isstock, wxT("A non-stock menu item with an empty label?")); + text = wxGetStockLabel(GetId()); + + // need & => _ conversion + text = GTKProcessMenuItemLabel(text, NULL); + } + + gtk_label_set_text_with_mnemonic( GTK_LABEL(label), wxGTK_CONV_SYS(text) ); } + // remove old accelerator from our parent's accelerator group, if present guint accel_key; GdkModifierType accel_mods; - gtk_accelerator_parse( (const char*) oldbuf, &accel_key, &accel_mods); - if (accel_key != 0) + if (oldbuf[(size_t)0] != '\0') { - gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem), - m_parentMenu->m_accel, - accel_key, - accel_mods ); + gtk_accelerator_parse( (const char*) oldbuf, &accel_key, &accel_mods); + if (accel_key != 0) + { + gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem), + m_parentMenu->m_accel, + accel_key, + accel_mods ); + } + } + else if (isstock) + { + // if the accelerator was taken from a stock ID, just get it back from GTK+ stock + if (wxGetStockGtkAccelerator(stockid, &accel_mods, &accel_key)) + gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem), + m_parentMenu->m_accel, + accel_key, + accel_mods ); } + // add new accelerator to our parent's accelerator group wxCharBuffer buf = wxGTK_CONV_SYS( GetGtkHotKey(*this) ); - gtk_accelerator_parse( (const char*) buf, &accel_key, &accel_mods); - if (accel_key != 0) + if (buf[(size_t)0] != '\0') + { + gtk_accelerator_parse( (const char*) buf, &accel_key, &accel_mods); + if (accel_key != 0) + { + gtk_widget_add_accelerator( GTK_WIDGET(m_menuItem), + "activate", + m_parentMenu->m_accel, + accel_key, + accel_mods, + GTK_ACCEL_VISIBLE); + } + } + else if (isstock) { - gtk_widget_add_accelerator( GTK_WIDGET(m_menuItem), - "activate", - m_parentMenu->m_accel, - accel_key, - accel_mods, - GTK_ACCEL_VISIBLE); + // if the accelerator was taken from a stock ID, just get it back from GTK+ stock + if (wxGetStockGtkAccelerator(stockid, &accel_mods, &accel_key)) + gtk_widget_remove_accelerator( GTK_WIDGET(m_menuItem), + m_parentMenu->m_accel, + accel_key, + accel_mods ); } } -// it's valid for this function to be called even if m_menuItem == NULL -void wxMenuItem::DoSetText( const wxString& str ) +// NOTE: this function is different from the similar functions GTKProcessMnemonics() +// implemented in control.cpp and from wxMenuItemBase::GetLabelFromText... +// so there's no real code duplication +wxString wxMenuItem::GTKProcessMenuItemLabel(const wxString& str, wxString *hotKey) { + wxString text; + // '\t' is the deliminator indicating a hot key - m_text.Empty(); const wxChar *pc = str; while ( (*pc != wxT('\0')) && (*pc != wxT('\t')) ) { @@ -799,32 +886,41 @@ void wxMenuItem::DoSetText( const wxString& str ) { // "&" is doubled to indicate "&" instead of accelerator ++pc; - m_text << wxT('&'); + text << wxT('&'); } else if (*pc == wxT('&')) { - m_text << wxT('_'); + text << wxT('_'); } else if ( *pc == wxT('_') ) // escape underscores { - m_text << wxT("__"); + text << wxT("__"); } else { - m_text << *pc; + text << *pc; } ++pc; } - m_hotKey = wxT(""); - - if(*pc == wxT('\t')) + if (hotKey) { - pc++; - m_hotKey = pc; + hotKey->Empty(); + if(*pc == wxT('\t')) + { + pc++; + *hotKey = pc; + } } - // wxPrintf( wxT("DoSetText(): str %s m_text %s hotkey %s\n"), str.c_str(), m_text.c_str(), m_hotKey.c_str() ); + return text; +} + +// it's valid for this function to be called even if m_menuItem == NULL +void wxMenuItem::DoSetText( const wxString& str ) +{ + m_text.Empty(); + m_text = GTKProcessMenuItemLabel(str, &m_hotKey); } #if wxUSE_ACCEL @@ -834,14 +930,15 @@ wxAcceleratorEntry *wxMenuItem::GetAccel() const if ( !GetHotKey() ) { // nothing - return (wxAcceleratorEntry *)NULL; + return NULL; } - // as wxGetAccelFromString() looks for TAB, insert a dummy one here + // accelerator parsing code looks for them after a TAB, so insert a dummy + // one here wxString label; label << wxT('\t') << GetHotKey(); - return wxGetAccelFromString(label); + return wxAcceleratorEntry::Create(label); } #endif // wxUSE_ACCEL @@ -936,21 +1033,47 @@ wxMenu::~wxMenu() } } +void wxMenu::SetLayoutDirection(const wxLayoutDirection dir) +{ + if ( m_owner ) + wxWindow::GTKSetLayout(m_owner, dir); + //else: will be called later by wxMenuBar again +} + +wxLayoutDirection wxMenu::GetLayoutDirection() const +{ + return wxWindow::GTKGetLayout(m_owner); +} + bool wxMenu::GtkAppend(wxMenuItem *mitem, int pos) { GtkWidget *menuItem; - wxString text; + // cache some data used later + wxString text = mitem->GetText(); + int id = mitem->GetId(); + bool isstock = wxIsStockID(id); + const char *stockid = NULL; + if (isstock) + stockid = wxGetStockGtkID(mitem->GetId()); + + // stock menu items can have an empty label + if (text.IsEmpty() && !mitem->IsSeparator()) + { + wxASSERT_MSG(isstock, wxT("A non-stock menu item with an empty label?")); + text = wxGetStockLabel(id); + + // need & => _ conversion + text = wxMenuItem::GTKProcessMenuItemLabel(text, NULL); + } if ( mitem->IsSeparator() ) { menuItem = gtk_separator_menu_item_new(); } else if ( mitem->GetBitmap().Ok() || - (mitem->GetKind() == wxITEM_NORMAL && - wxIsStockID(mitem->GetId())) ) + (mitem->GetKind() == wxITEM_NORMAL && isstock) ) { - text = mitem->GetText(); wxBitmap bitmap(mitem->GetBitmap()); menuItem = gtk_image_menu_item_new_with_mnemonic( wxGTK_CONV_SYS( text ) ); @@ -960,9 +1083,8 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem, int pos) { // use stock bitmap for this item if available on the assumption // that it never hurts to follow GTK+ conventions more closely - const char *stock = wxGetStockGtkID(mitem->GetId()); - image = stock ? gtk_image_new_from_stock(stock, GTK_ICON_SIZE_MENU) - : NULL; + image = stockid ? gtk_image_new_from_stock(stockid, GTK_ICON_SIZE_MENU) + : NULL; } else // we have a custom bitmap { @@ -994,8 +1116,8 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem, int pos) } else // a normal item { - // text has "_" instead of "&" after mitem->SetText() so don't use it - text = mitem->GetText() ; + // NB: 'text' variable has "_" instead of "&" after mitem->SetText() + // so don't use it switch ( mitem->GetKind() ) { @@ -1043,15 +1165,29 @@ bool wxMenu::GtkAppend(wxMenuItem *mitem, int pos) wxCharBuffer buf = wxGTK_CONV_SYS( 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) + if (buf[(size_t)0] != '\0') + { + 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); + } + } + else if (isstock) { - gtk_widget_add_accelerator (GTK_WIDGET(menuItem), - "activate", - m_accel, - accel_key, - accel_mods, - GTK_ACCEL_VISIBLE); + // if the accelerator was taken from a stock ID, just get it back from GTK+ stock + if (wxGetStockGtkAccelerator(stockid, &accel_mods, &accel_key)) + gtk_widget_add_accelerator( GTK_WIDGET(menuItem), + "activate", + m_accel, + accel_key, + accel_mods, + GTK_ACCEL_VISIBLE); } if (pos == -1) @@ -1147,6 +1283,14 @@ int wxMenu::FindMenuIdByMenuItem( GtkWidget *menuItem ) const return wxNOT_FOUND; } +void wxMenu::Attach(wxMenuBarBase *menubar) +{ + wxMenuBase::Attach(menubar); + + // inherit layout direction from menubar. + SetLayoutDirection(menubar->GetLayoutDirection()); +} + // ---------------------------------------------------------------------------- // helpers // ---------------------------------------------------------------------------- @@ -1393,7 +1537,7 @@ static wxString GetGtkHotKey( const wxMenuItem& item ) hotkey += wxString::Format(wxT("Special%d"), code - WXK_SPECIAL1 + 1); break; */ - // if there are any other keys wxGetAccelFromString() may + // if there are any other keys wxAcceleratorEntry::Create() may // return, we should process them here default: