1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/gtk/collpane.cpp 
   3 // Purpose:     wxCollapsiblePane 
   4 // Author:      Francesco Montorsi 
   8 // Copyright:   (c) Francesco Montorsi 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 // ---------------------------------------------------------------------------- 
  15 // ---------------------------------------------------------------------------- 
  17 // For compilers that support precompilation, includes "wx.h". 
  18 #include "wx/wxprec.h" 
  22 #include "wx/collpane.h" 
  24 #include <gtk/gtkexpander.h> 
  27 const wxChar wxCollapsiblePaneNameStr
[] = wxT("CollapsiblePane"); 
  29 // ============================================================================ 
  31 // ============================================================================ 
  33 //----------------------------------------------------------------------------- 
  34 // "notify::expanded" signal 
  35 //----------------------------------------------------------------------------- 
  39 static void gtk_collapsiblepane_expanded_callback (GObject    
*object
, 
  40                                                     GParamSpec 
*param_spec
, 
  43     // NB: unlike for the "activate" signal, when this callback is called, if 
  44     //     we try to query the "collapsed" status through p->IsCollapsed(), we 
  45     //     get the right value. I.e. here p->IsCollapsed() will return false if 
  46     //     this callback has been called at the end of a collapsed->expanded 
  47     //     transition and viceversa. Inside the "activate" signal callback 
  48     //     p->IsCollapsed() would return the wrong value! 
  51     if ( p
->IsExpanded() ) 
  53         // unfortunately there's no clean way to retrieve the minimal size of 
  54         // the expanded pane in this handler or in other handlers for the 
  55         // signals generated by user clicks on the GtkExpander button: 
  56         // p->GetBestSize() or p->GetMinSize() would still return the size for 
  57         // the collapsed expander even if the collapsed->expanded transition 
  58         // has already been completed (this because GTK+ queues some resize 
  59         // calls which still must be processed). So, the only solution to 
  60         // correctly set the size hints for this window is to calculate the 
  61         // expanded size ourselves, without relying on p->Get[Best|Min]Size: 
  63         sz
.SetWidth(wxMax(sz
.x
, p
->GetPane()->GetMinSize().x
)); 
  64         sz
.SetHeight(sz
.y 
+ p
->GetPane()->GetMinSize().y 
+ 10); 
  68         // same problem described above: using p->Get[Best|Min]Size() here we 
  69         // would get the size of the control when it is expanded even if the 
  70         // expanded->collapsed transition should be complete now... 
  71         // So, we use the size cached at control-creation time... 
  72         sz 
= p
->m_szCollapsed
; 
  75     // minimal size has priority over the best size so set here our min size 
  79     wxWindow 
*top 
= p
->GetTopLevelParent(); 
  82         // we've changed our size, thus our top level parent needs to relayout 
  88             // force our parent to "fit", i.e. expand so that it can honour 
  95                 top
->GetSizer()->SetSizeHints(top
); 
  97             // use SetClientSize() and not SetSize() otherwise the size for 
  98             // e.g. a wxFrame with a menubar wouldn't be correctly set 
  99             top
->SetClientSize(sz
); 
 103     if ( p
->m_bIgnoreNextChange 
) 
 105         // change generated programmatically - do not send an event! 
 106         p
->m_bIgnoreNextChange 
= false; 
 111     wxCollapsiblePaneEvent 
ev(p
, p
->GetId(), p
->IsCollapsed()); 
 112     p
->GetEventHandler()->ProcessEvent(ev
); 
 117 gtk_collapsiblepane_insert_callback(wxWindowGTK
* parent
, wxWindowGTK
* child
) 
 119     // this callback should be used only once to insert the "pane" into the 
 120     // GtkExpander widget. wxGenericCollapsiblePane::DoAddChild() will check if 
 121     // it has been called only once (and in any case we would get a warning 
 122     // from the following call as GtkExpander is a GtkBin and can contain only 
 124     gtk_container_add (GTK_CONTAINER (parent
->m_widget
), child
->m_widget
); 
 127 //----------------------------------------------------------------------------- 
 129 //----------------------------------------------------------------------------- 
 131 IMPLEMENT_DYNAMIC_CLASS(wxCollapsiblePane
, wxGenericCollapsiblePane
) 
 133 BEGIN_EVENT_TABLE(wxCollapsiblePane
, wxGenericCollapsiblePane
) 
 134     EVT_SIZE(wxCollapsiblePane::OnSize
) 
 137 bool wxCollapsiblePane::Create(wxWindow 
*parent
, 
 139                                const wxString
& label
, 
 143                                const wxValidator
& val
, 
 144                                const wxString
& name
) 
 146     if (gtk_check_version(2,4,0)) 
 147         return wxGenericCollapsiblePane::Create(parent
, id
, label
, 
 148                                                 pos
, size
, style
, val
, name
); 
 151     m_acceptsFocus 
= true; 
 152     m_bIgnoreNextChange 
= false; 
 154     if ( !PreCreation( parent
, pos
, size 
) || 
 155           !wxControl::CreateBase(parent
, id
, pos
, size
, style
, val
, name
) ) 
 157         wxFAIL_MSG( wxT("wxCollapsiblePane creation failed") ); 
 162         gtk_expander_new_with_mnemonic(wxGTK_CONV(GTKConvertMnemonics(label
))); 
 164     // see the gtk_collapsiblepane_expanded_callback comments to understand why 
 165     // we connect to the "notify::expanded" signal instead of the more common 
 167     g_signal_connect(m_widget
, "notify::expanded", 
 168                      G_CALLBACK(gtk_collapsiblepane_expanded_callback
), this); 
 170     // before creating m_pPane, we need to makesure our own insert callback 
 172     m_insertCallback 
= gtk_collapsiblepane_insert_callback
; 
 174     // this the real "pane" 
 175     m_pPane 
= new wxWindow(this, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, 
 178     gtk_widget_show( GTK_WIDGET(m_widget
) ); 
 179     m_parent
->DoAddChild( this ); 
 183     // remember the size of this control when it's collapsed 
 184     m_szCollapsed 
= GetBestSize(); 
 189 wxSize 
wxCollapsiblePane::DoGetBestSize() const 
 191     if (!gtk_check_version(2,4,0)) 
 193         wxASSERT_MSG( m_widget
, wxT("DoGetBestSize called before creation") ); 
 198         (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) )->size_request 
) 
 201         // notice that we do not cache our best size here as it changes 
 202         return wxSize(req
.width
, req
.height
); 
 205     return wxGenericCollapsiblePane::DoGetBestSize(); 
 208 void wxCollapsiblePane::Collapse(bool collapse
) 
 210     if (!gtk_check_version(2,4,0)) 
 213         if (IsCollapsed() == collapse
) 
 216         // do not send event in next signal handler call 
 217         m_bIgnoreNextChange 
= true; 
 218         gtk_expander_set_expanded(GTK_EXPANDER(m_widget
), !collapse
); 
 221         wxGenericCollapsiblePane::Collapse(collapse
); 
 224 bool wxCollapsiblePane::IsCollapsed() const 
 226     if (!gtk_check_version(2,4,0)) 
 227         return !gtk_expander_get_expanded(GTK_EXPANDER(m_widget
)); 
 229     return wxGenericCollapsiblePane::IsCollapsed(); 
 232 void wxCollapsiblePane::SetLabel(const wxString 
&str
) 
 234     if (!gtk_check_version(2,4,0)) 
 235         gtk_expander_set_label(GTK_EXPANDER(m_widget
), str
.c_str()); 
 237         wxGenericCollapsiblePane::SetLabel(str
); 
 240 void wxCollapsiblePane::OnSize(wxSizeEvent 
&ev
) 
 242 #if 0       // for debug only 
 244     dc
.SetPen(*wxBLACK_PEN
); 
 245     dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
 246     dc
.DrawRectangle(wxPoint(0,0), GetSize()); 
 247     dc
.SetPen(*wxRED_PEN
); 
 248     dc
.DrawRectangle(wxPoint(0,0), GetBestSize()); 
 251     // here we need to resize the pane window otherwise, even if the GtkExpander container 
 252     // is expanded or shrinked, the pane window won't be updated! 
 253     m_pPane
->SetSize(ev
.GetSize()); 
 255     // we need to explicitely call m_pPane->Layout() or else it won't correctly relayout 
 256     // (even if SetAutoLayout(true) has been called on it!) 
 260 #endif //  __WXGTK24__