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__