From 2e1f50128a73bd61db8ee0077b631ada9486158a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 12 Mar 2006 14:21:19 +0000 Subject: [PATCH] support mnemonics for wxStatic/RadioBox and made it easier to add support for more controls by virtualizing the mnemonics support logic (patch 1448178) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@38027 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 5 ++++ include/wx/gtk/control.h | 5 +++- include/wx/gtk/radiobox.h | 3 +++ include/wx/gtk/statbox.h | 3 +++ include/wx/gtk/stattext.h | 3 +++ include/wx/gtk/window.h | 7 +++++ src/gtk/control.cpp | 43 ++++++++++++++++++++++++----- src/gtk/radiobox.cpp | 17 +++++++++--- src/gtk/statbox.cpp | 17 +++++++++--- src/gtk/stattext.cpp | 10 +++++++ src/gtk/window.cpp | 57 +++++++++++++++++++++++++-------------- 11 files changed, 135 insertions(+), 35 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index a89fa51c00..7e852f490f 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -151,6 +151,11 @@ wxGTK: --enable-gstreamer8 to force configure to check for GStreamer 0.8.\ - Fixed problem with choice editor in wxGrid whereby the editor lost focus when the combobox menu was shown. +- Fixed focusing with mnemonic accelerator keys on wxStaticText which + is now able to focus on wxComboBox and possibly other controls + previously unable to be focused upon before +- Enabled mnemonics and the corresponding accelerator keys for + wxStaticBox and wxRadioBox - Fixed problem trying to print from a preview, whereby wrong printer class was used. - Worked around pango crashes in strncmp on Solaris 10. diff --git a/include/wx/gtk/control.h b/include/wx/gtk/control.h index 42e48726bf..f2e5c6dc04 100644 --- a/include/wx/gtk/control.h +++ b/include/wx/gtk/control.h @@ -66,8 +66,11 @@ protected: // sets the label to the given string and also sets it for the given widget void GTKSetLabelForLabel(GtkLabel *w, const wxString& label); - // as GTKSetLabelForLabel() but for a GtkFrame widget + // GtkFrame helpers + GtkWidget* GTKCreateFrame(const wxString& label); void GTKSetLabelForFrame(GtkFrame *w, const wxString& label); + void GTKFrameApplyWidgetStyle(GtkFrame* w, GtkRcStyle* rc); + void GTKFrameSetMnemonicWidget(GtkFrame* w, GtkWidget* widget); // remove mnemonics ("&"s) from the label static wxString GTKRemoveMnemonics(const wxString& label); diff --git a/include/wx/gtk/radiobox.h b/include/wx/gtk/radiobox.h index fedb790c06..244dbab904 100644 --- a/include/wx/gtk/radiobox.h +++ b/include/wx/gtk/radiobox.h @@ -127,6 +127,9 @@ public: protected: void DoApplyWidgetStyle(GtkRcStyle *style); + virtual bool GTKWidgetNeedsMnemonic() const; + virtual void GTKWidgetDoSetMnemonic(GtkWidget* w); + // common part of all ctors void Init(); diff --git a/include/wx/gtk/statbox.h b/include/wx/gtk/statbox.h index 67e0a8e21d..90c5abc8c3 100644 --- a/include/wx/gtk/statbox.h +++ b/include/wx/gtk/statbox.h @@ -43,6 +43,9 @@ public: virtual bool IsTransparentForMouse() const { return TRUE; } protected: + virtual bool GTKWidgetNeedsMnemonic() const; + virtual void GTKWidgetDoSetMnemonic(GtkWidget* w); + void DoApplyWidgetStyle(GtkRcStyle *style); private: diff --git a/include/wx/gtk/stattext.h b/include/wx/gtk/stattext.h index c17c410591..dd12304984 100644 --- a/include/wx/gtk/stattext.h +++ b/include/wx/gtk/stattext.h @@ -65,6 +65,9 @@ public: // -------------- protected: + virtual bool GTKWidgetNeedsMnemonic() const; + virtual void GTKWidgetDoSetMnemonic(GtkWidget* w); + virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); diff --git a/include/wx/gtk/window.h b/include/wx/gtk/window.h index c14e0d836e..44b7940a8e 100644 --- a/include/wx/gtk/window.h +++ b/include/wx/gtk/window.h @@ -156,6 +156,13 @@ public: virtual bool IsOwnGtkWindow( GdkWindow *window ); void ConnectWidget( GtkWidget *widget ); + // Override GTKWidgetNeedsMnemonic and return true if your + // needs to set its mnemonic widget, such as for a + // GtkLabel for wxStaticText, then do the actual + // setting of the widget inside GTKWidgetDoSetMnemonic + virtual bool GTKWidgetNeedsMnemonic() const; + virtual void GTKWidgetDoSetMnemonic(GtkWidget* w); + // Returns the default context which usually is anti-aliased PangoContext *GtkGetPangoDefaultContext(); diff --git a/src/gtk/control.cpp b/src/gtk/control.cpp index 921820d427..4368959b6c 100644 --- a/src/gtk/control.cpp +++ b/src/gtk/control.cpp @@ -66,7 +66,6 @@ wxSize wxControl::DoGetBestSize() const return best; } - void wxControl::PostCreation(const wxSize& size) { wxWindow::PostCreation(); @@ -110,22 +109,54 @@ void wxControl::GTKSetLabelForLabel(GtkLabel *w, const wxString& label) gtk_label_set_text_with_mnemonic(w, wxGTK_CONV(labelGTK)); } +// ---------------------------------------------------------------------------- +// GtkFrame helpers +// +// GtkFrames do in fact support mnemonics in GTK2+ but not through +// gtk_frame_set_label, rather you need to use a custom label widget +// instead (idea gleaned from the native gtk font dialog code in GTK) +// ---------------------------------------------------------------------------- + +GtkWidget* wxControl::GTKCreateFrame(const wxString& label) +{ + const wxString labelGTK = GTKConvertMnemonics(label); + GtkWidget* labelwidget = gtk_label_new_with_mnemonic(wxGTK_CONV(labelGTK)); + gtk_widget_show(labelwidget); // without this it won't show... + + GtkWidget* framewidget = gtk_frame_new(NULL); + gtk_frame_set_label_widget(GTK_FRAME(framewidget), labelwidget); + + return framewidget; //note that the label is already set so you'll + //only need to call wxControl::SetLabel afterwards +} + void wxControl::GTKSetLabelForFrame(GtkFrame *w, const wxString& label) { - wxControl::SetLabel(label); + GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w)); + GTKSetLabelForLabel(labelwidget, label); +} + +void wxControl::GTKFrameApplyWidgetStyle(GtkFrame* w, GtkRcStyle* style) +{ + gtk_widget_modify_style(GTK_WIDGET(w), style); + gtk_widget_modify_style(gtk_frame_get_label_widget (w), style); +} - // frames don't support mnemonics even under GTK+ 2 - const wxString labelGTK = GTKRemoveMnemonics(label); +void wxControl::GTKFrameSetMnemonicWidget(GtkFrame* w, GtkWidget* widget) +{ + GtkLabel* labelwidget = GTK_LABEL(gtk_frame_get_label_widget(w)); - gtk_frame_set_label(w, labelGTK.empty() ? (char *)NULL - : wxGTK_CONV(labelGTK)); + gtk_label_set_mnemonic_widget(labelwidget, widget); } +// ---------------------------------------------------------------------------- // worker function implementing both GTKConvert/RemoveMnemonics() // // notice that under GTK+ 1 we only really need to support MNEMONICS_REMOVE as // it doesn't support mnemonics anyhow but this would make the code so ugly // that we do the same thing for GKT+ 1 and 2 +// ---------------------------------------------------------------------------- + enum MnemonicsFlag { MNEMONICS_REMOVE, diff --git a/src/gtk/radiobox.cpp b/src/gtk/radiobox.cpp index 686e8979ae..283027982e 100644 --- a/src/gtk/radiobox.cpp +++ b/src/gtk/radiobox.cpp @@ -205,8 +205,8 @@ bool wxRadioBox::Create( wxWindow *parent, wxWindowID id, const wxString& title, return false; } - m_widget = gtk_frame_new(NULL); - SetLabel(title); + m_widget = GTKCreateFrame(title); + wxControl::SetLabel(title); // majorDim may be 0 if all trailing parameters were omitted, so don't // assert here but just use the correct value for it @@ -530,8 +530,7 @@ void wxRadioBox::GtkEnableEvents() void wxRadioBox::DoApplyWidgetStyle(GtkRcStyle *style) { - gtk_widget_modify_style( m_widget, style ); - gtk_widget_modify_style(GTK_FRAME(m_widget)->label_widget, style); + GTKFrameApplyWidgetStyle(GTK_FRAME(m_widget), style); wxList::compatibility_iterator node = m_boxes.GetFirst(); while (node) @@ -545,6 +544,16 @@ void wxRadioBox::DoApplyWidgetStyle(GtkRcStyle *style) } } +bool wxRadioBox::GTKWidgetNeedsMnemonic() const +{ + return true; +} + +void wxRadioBox::GTKWidgetDoSetMnemonic(GtkWidget* w) +{ + GTKFrameSetMnemonicWidget(GTK_FRAME(m_widget), w); +} + #if wxUSE_TOOLTIPS void wxRadioBox::ApplyToolTip( GtkTooltips *tips, const wxChar *tip ) { diff --git a/src/gtk/statbox.cpp b/src/gtk/statbox.cpp index 89c9c8adc3..4d3feeb72b 100644 --- a/src/gtk/statbox.cpp +++ b/src/gtk/statbox.cpp @@ -56,8 +56,8 @@ bool wxStaticBox::Create( wxWindow *parent, return FALSE; } - m_widget = gtk_frame_new(NULL); - SetLabel(label); + m_widget = GTKCreateFrame(label); + wxControl::SetLabel(label); m_parent->DoAddChild( this ); @@ -87,8 +87,17 @@ void wxStaticBox::SetLabel( const wxString& label ) void wxStaticBox::DoApplyWidgetStyle(GtkRcStyle *style) { - gtk_widget_modify_style(m_widget, style); - gtk_widget_modify_style(GTK_FRAME(m_widget)->label_widget, style); + GTKFrameApplyWidgetStyle(GTK_FRAME(m_widget), style); +} + +bool wxStaticBox::GTKWidgetNeedsMnemonic() const +{ + return true; +} + +void wxStaticBox::GTKWidgetDoSetMnemonic(GtkWidget* w) +{ + GTKFrameSetMnemonicWidget(GTK_FRAME(m_widget), w); } // static diff --git a/src/gtk/stattext.cpp b/src/gtk/stattext.cpp index 1befdd1c89..2641ea02f3 100644 --- a/src/gtk/stattext.cpp +++ b/src/gtk/stattext.cpp @@ -166,6 +166,16 @@ bool wxStaticText::SetForegroundColour(const wxColour& colour) return true; } +bool wxStaticText::GTKWidgetNeedsMnemonic() const +{ + return true; +} + +void wxStaticText::GTKWidgetDoSetMnemonic(GtkWidget* w) +{ + gtk_label_set_mnemonic_widget(GTK_LABEL(m_widget), w); +} + // static wxVisualAttributes wxStaticText::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index b54d7239f1..95dd20fbcb 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -50,7 +50,6 @@ #include "wx/settings.h" #include "wx/log.h" #include "wx/fontutil.h" -#include "wx/stattext.h" #ifdef __WXDEBUG__ #include "wx/thread.h" @@ -1755,7 +1754,7 @@ gtk_window_motion_notify_callback( GtkWidget *widget, // Rewrite cursor handling here (away from idle). } } - + if (win->GetEventHandler()->ProcessEvent( event )) { g_signal_stop_emission_by_name (widget, "motion_notify_event"); @@ -2024,7 +2023,7 @@ gtk_window_enter_callback( GtkWidget *widget, // Rewrite cursor handling here (away from idle). } } - + if (win->GetEventHandler()->ProcessEvent( event )) { g_signal_stop_emission_by_name (widget, "enter_notify_event"); @@ -2943,7 +2942,7 @@ void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags if (GTK_WIDGET_VISIBLE (widget)) gtk_widget_queue_resize (widget); } - else + else #endif if (m_parent->m_wxwindow == NULL) // i.e. wxNotebook { @@ -3606,44 +3605,62 @@ void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move) wxapp_install_idle_handler(); } +bool wxWindowGTK::GTKWidgetNeedsMnemonic() const +{ + // none needed by default + return false; +} + +void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget* WXUNUSED(w)) +{ + // nothing to do by default since none is needed +} + void wxWindowGTK::RealizeTabOrder() { if (m_wxwindow) { if ( !m_children.empty() ) { -#if wxUSE_STATTEXT // we don't only construct the correct focus chain but also use - // this opportunity to update the mnemonic widgets for all labels - // - // it would be nice to extract this code from here and put it in - // stattext.cpp to reduce dependencies but there is no really easy - // way to do it unfortunately - wxStaticText *lastLabel = NULL; -#endif // wxUSE_STATTEXT + // this opportunity to update the mnemonic widgets for the widgets + // that need them GList *chain = NULL; + wxWindowGTK* mnemonicWindow = NULL; for ( wxWindowList::const_iterator i = m_children.begin(); i != m_children.end(); ++i ) { wxWindowGTK *win = *i; -#if wxUSE_STATTEXT - if ( lastLabel ) + + if ( mnemonicWindow ) { if ( win->AcceptsFocusFromKeyboard() ) { - GtkLabel *l = GTK_LABEL(lastLabel->m_widget); - gtk_label_set_mnemonic_widget(l, win->m_widget); - lastLabel = NULL; + // wxComboBox et al. needs to focus on on a different + // widget than m_widget, so if the main widget isn't + // focusable try the connect widget + GtkWidget* w = win->m_widget; + if ( !GTK_WIDGET_CAN_FOCUS(w) ) + { + w = win->GetConnectWidget(); + if ( !GTK_WIDGET_CAN_FOCUS(w) ) + w = NULL; + } + + if ( w ) + { + mnemonicWindow->GTKWidgetDoSetMnemonic(w); + mnemonicWindow = NULL; + } } } - else // check if this one is a label + else if ( win->GTKWidgetNeedsMnemonic() ) { - lastLabel = wxDynamicCast(win, wxStaticText); + mnemonicWindow = win; } -#endif // wxUSE_STATTEXT chain = g_list_prepend(chain, win->m_widget); } -- 2.45.2