1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Robert Roebling 
   6 // Copyright:   (c) 1998 Robert Roebling 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  12 #pragma implementation "choice.h" 
  15 #include "wx/choice.h" 
  22 //----------------------------------------------------------------------------- 
  24 //----------------------------------------------------------------------------- 
  26 extern void wxapp_install_idle_handler(); 
  29 //----------------------------------------------------------------------------- 
  31 //----------------------------------------------------------------------------- 
  33 extern bool   g_blockEventsOnDrag
; 
  35 //----------------------------------------------------------------------------- 
  37 //----------------------------------------------------------------------------- 
  39 static void gtk_choice_clicked_callback( GtkWidget 
*WXUNUSED(widget
), wxChoice 
*choice 
) 
  42       wxapp_install_idle_handler(); 
  44     if (!choice
->m_hasVMT
) return; 
  46     if (g_blockEventsOnDrag
) return; 
  48     wxCommandEvent 
event(wxEVT_COMMAND_CHOICE_SELECTED
, choice
->GetId() ); 
  49     int n 
= choice
->GetSelection(); 
  52     event
.SetString( choice
->GetStringSelection() ); 
  53     event
.SetEventObject(choice
); 
  55     if ( choice
->HasClientObjectData() ) 
  56         event
.SetClientObject( choice
->GetClientObject(n
) ); 
  57     else if ( choice
->HasClientUntypedData() ) 
  58         event
.SetClientData( choice
->GetClientData(n
) ); 
  60     choice
->GetEventHandler()->ProcessEvent(event
); 
  63 //----------------------------------------------------------------------------- 
  65 //----------------------------------------------------------------------------- 
  67 IMPLEMENT_DYNAMIC_CLASS(wxChoice
,wxControl
) 
  71     m_strings 
= (wxSortedArrayString 
*)NULL
; 
  74 bool wxChoice::Create( wxWindow 
*parent
, wxWindowID id
, 
  75                        const wxPoint 
&pos
, const wxSize 
&size
, 
  76                        int n
, const wxString choices
[], 
  77                        long style
, const wxValidator
& validator
, const wxString 
&name 
) 
  80 #if (GTK_MINOR_VERSION > 0) 
  81     m_acceptsFocus 
= TRUE
; 
  84     if (!PreCreation( parent
, pos
, size 
) || 
  85         !CreateBase( parent
, id
, pos
, size
, style
, validator
, name 
)) 
  87         wxFAIL_MSG( wxT("wxChoice creation failed") ); 
  91     m_widget 
= gtk_option_menu_new(); 
  93     if ( style 
& wxCB_SORT 
) 
  95         // if our m_strings != NULL, DoAppend() will check for it and insert 
  96         // items in the correct order 
  97         m_strings 
= new wxSortedArrayString
; 
 100     GtkWidget 
*menu 
= gtk_menu_new(); 
 102     for (int i 
= 0; i 
< n
; i
++) 
 104         GtkAppendHelper(menu
, choices
[i
]); 
 107     gtk_option_menu_set_menu( GTK_OPTION_MENU(m_widget
), menu 
); 
 109     m_parent
->DoAddChild( this ); 
 113     SetFont( parent
->GetFont() ); 
 115     wxSize 
size_best( DoGetBestSize() ); 
 116     wxSize 
new_size( size 
); 
 117     if (new_size
.x 
== -1) 
 118         new_size
.x 
= size_best
.x
; 
 119     if (new_size
.y 
== -1) 
 120         new_size
.y 
= size_best
.y
; 
 121     if ((new_size
.x 
!= size
.x
) || (new_size
.y 
!= size
.y
)) 
 122         SetSize( new_size
.x
, new_size
.y 
); 
 124     SetBackgroundColour( parent
->GetBackgroundColour() ); 
 125     SetForegroundColour( parent
->GetForegroundColour() ); 
 132 wxChoice::~wxChoice() 
 139 int wxChoice::DoAppend( const wxString 
&item 
) 
 141     wxCHECK_MSG( m_widget 
!= NULL
, -1, wxT("invalid choice control") ); 
 143     GtkWidget 
*menu 
= gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget
) ); 
 145     return GtkAppendHelper(menu
, item
); 
 148 void wxChoice::DoSetItemClientData( int n
, void* clientData 
) 
 150     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid choice control") ); 
 152     wxNode 
*node 
= m_clientList
.Nth( n 
); 
 153     wxCHECK_RET( node
, wxT("invalid index in wxChoice::DoSetItemClientData") ); 
 155     node
->SetData( (wxObject
*) clientData 
); 
 158 void* wxChoice::DoGetItemClientData( int n 
) const 
 160     wxCHECK_MSG( m_widget 
!= NULL
, NULL
, wxT("invalid choice control") ); 
 162     wxNode 
*node 
= m_clientList
.Nth( n 
); 
 163     wxCHECK_MSG( node
, NULL
, wxT("invalid index in wxChoice::DoGetItemClientData") ); 
 168 void wxChoice::DoSetItemClientObject( int n
, wxClientData
* clientData 
) 
 170     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid choice control") ); 
 172     wxNode 
*node 
= m_clientList
.Nth( n 
); 
 173     wxCHECK_RET( node
, wxT("invalid index in wxChoice::DoSetItemClientObject") ); 
 175     wxClientData 
*cd 
= (wxClientData
*) node
->Data(); 
 178     node
->SetData( (wxObject
*) clientData 
); 
 181 wxClientData
* wxChoice::DoGetItemClientObject( int n 
) const 
 183     wxCHECK_MSG( m_widget 
!= NULL
, (wxClientData
*) NULL
, wxT("invalid choice control") ); 
 185     wxNode 
*node 
= m_clientList
.Nth( n 
); 
 186     wxCHECK_MSG( node
, (wxClientData 
*)NULL
, 
 187                  wxT("invalid index in wxChoice::DoGetItemClientObject") ); 
 189     return (wxClientData
*) node
->Data(); 
 192 void wxChoice::Clear() 
 194     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid choice") ); 
 196     gtk_option_menu_remove_menu( GTK_OPTION_MENU(m_widget
) ); 
 197     GtkWidget 
*menu 
= gtk_menu_new(); 
 198     gtk_option_menu_set_menu( GTK_OPTION_MENU(m_widget
), menu 
); 
 200     if ( HasClientObjectData() ) 
 202         // destroy the data (due to Robert's idea of using wxList<wxObject> 
 203         // and not wxList<wxClientData> we can't just say 
 204         // m_clientList.DeleteContents(TRUE) - this would crash! 
 205         wxNode 
*node 
= m_clientList
.First(); 
 208             delete (wxClientData 
*)node
->Data(); 
 212     m_clientList
.Clear(); 
 218 void wxChoice::Delete( int WXUNUSED(n
) ) 
 220     wxFAIL_MSG( wxT("wxChoice:Delete not implemented") ); 
 223 int wxChoice::FindString( const wxString 
&string 
) const 
 225     wxCHECK_MSG( m_widget 
!= NULL
, -1, wxT("invalid choice") ); 
 227     // If you read this code once and you think you understand 
 228     // it, then you are very wrong. Robert Roebling. 
 230     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget
) ) ); 
 232     GList 
*child 
= menu_shell
->children
; 
 235         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 236         GtkLabel 
*label 
= (GtkLabel 
*) NULL
; 
 237         if (bin
->child
) label 
= GTK_LABEL(bin
->child
); 
 238         if (!label
) label 
= GTK_LABEL( GTK_BUTTON(m_widget
)->child 
); 
 240         wxASSERT_MSG( label 
!= NULL 
, wxT("wxChoice: invalid label") ); 
 242        if (string 
== wxString(label
->label
,*wxConvCurrent
)) 
 252 int wxChoice::GetSelection() const 
 254     wxCHECK_MSG( m_widget 
!= NULL
, -1, wxT("invalid choice") ); 
 256     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget
) ) ); 
 258     GList 
*child 
= menu_shell
->children
; 
 261         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 262         if (!bin
->child
) return count
; 
 270 void wxChoice::SetString( int WXUNUSED(n
), const wxString
& WXUNUSED(string
) ) 
 272     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid choice") ); 
 274     wxFAIL_MSG(wxT("not implemented")); 
 277 wxString 
wxChoice::GetString( int n 
) const 
 279     wxCHECK_MSG( m_widget 
!= NULL
, wxT(""), wxT("invalid choice") ); 
 281     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget
) ) ); 
 283     GList 
*child 
= menu_shell
->children
; 
 286         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 289             GtkLabel 
*label 
= (GtkLabel 
*) NULL
; 
 290             if (bin
->child
) label 
= GTK_LABEL(bin
->child
); 
 291             if (!label
) label 
= GTK_LABEL( GTK_BUTTON(m_widget
)->child 
); 
 293             wxASSERT_MSG( label 
!= NULL 
, wxT("wxChoice: invalid label") ); 
 295             return wxString(label
->label
,*wxConvCurrent
); 
 301     wxFAIL_MSG( wxT("wxChoice: invalid index in GetString()") ); 
 306 int wxChoice::GetCount() const 
 308     wxCHECK_MSG( m_widget 
!= NULL
, 0, wxT("invalid choice") ); 
 310     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget
) ) ); 
 312     GList 
*child 
= menu_shell
->children
; 
 321 void wxChoice::SetSelection( int n 
) 
 323     wxCHECK_RET( m_widget 
!= NULL
, wxT("invalid choice") ); 
 326     gtk_option_menu_set_history( GTK_OPTION_MENU(m_widget
), (gint
)tmp 
); 
 329 void wxChoice::ApplyWidgetStyle() 
 333     GtkMenuShell 
*menu_shell 
= GTK_MENU_SHELL( gtk_option_menu_get_menu( GTK_OPTION_MENU(m_widget
) ) ); 
 335     gtk_widget_set_style( m_widget
, m_widgetStyle 
); 
 336     gtk_widget_set_style( GTK_WIDGET( menu_shell 
), m_widgetStyle 
); 
 338     GList 
*child 
= menu_shell
->children
; 
 341         gtk_widget_set_style( GTK_WIDGET( child
->data 
), m_widgetStyle 
); 
 343         GtkBin 
*bin 
= GTK_BIN( child
->data 
); 
 344         GtkWidget 
*label 
= (GtkWidget 
*) NULL
; 
 345         if (bin
->child
) label 
= bin
->child
; 
 346         if (!label
) label 
= GTK_BUTTON(m_widget
)->child
; 
 348         gtk_widget_set_style( label
, m_widgetStyle 
); 
 354 size_t wxChoice::GtkAppendHelper(GtkWidget 
*menu
, const wxString
& item
) 
 356     GtkWidget 
*menu_item 
= gtk_menu_item_new_with_label( item
.mbc_str() ); 
 361         // sorted control, need to insert at the correct index 
 362         index 
= m_strings
->Add(item
); 
 364         gtk_menu_insert( GTK_MENU(menu
), menu_item
, index 
); 
 368             m_clientList
.Insert( m_clientList
.Item(index 
- 1), 
 373             m_clientList
.Insert( (wxObject
*) NULL 
); 
 378         // normal control, just append 
 379         gtk_menu_append( GTK_MENU(menu
), menu_item 
); 
 381         m_clientList
.Append( (wxObject
*) NULL 
); 
 383         // don't call wxChoice::GetCount() from here because it doesn't work 
 384         // if we're called from ctor (and GtkMenuShell is still NULL) 
 385         index 
= m_clientList
.GetCount() - 1; 
 388     if (GTK_WIDGET_REALIZED(m_widget
)) 
 390         gtk_widget_realize( menu_item 
); 
 391         gtk_widget_realize( GTK_BIN(menu_item
)->child 
); 
 393         if (m_widgetStyle
) ApplyWidgetStyle(); 
 396     gtk_signal_connect( GTK_OBJECT( menu_item 
), "activate", 
 397       GTK_SIGNAL_FUNC(gtk_choice_clicked_callback
), (gpointer
*)this ); 
 399     gtk_widget_show( menu_item 
); 
 401     // return the index of the item in the control 
 405 wxSize 
wxChoice::DoGetBestSize() const 
 407     wxSize 
ret( wxControl::DoGetBestSize() ); 
 408     if (ret
.x 
< 80) ret
.x 
= 80; 
 409     ret
.y 
= 16 + gdk_char_height( m_widget
->style
->font
, 'H' );