]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/collpane.cpp
updated setup.h for OpenVMS
[wxWidgets.git] / src / gtk / collpane.cpp
CommitLineData
3c1f8cb1
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/gtk/collpane.cpp
3// Purpose: wxCollapsiblePane
4// Author: Francesco Montorsi
5// Modified By:
6// Created: 8/10/2006
7// Id: $Id$
8// Copyright: (c) Francesco Montorsi
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
16
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
19
ff654490 20#if wxUSE_COLLPANE && !defined(__WXUNIVERSAL__)
3c1f8cb1
VZ
21
22#include "wx/collpane.h"
0ccf0043
RR
23#include "wx/toplevel.h"
24#include "wx/sizer.h"
4c79f9c1 25#include "wx/panel.h"
0ccf0043 26
9dc44eff 27#include <gtk/gtk.h>
2cbf7014 28#include "wx/gtk/private.h"
9dc44eff 29#include "wx/gtk/private/gtk2-compat.h"
3c1f8cb1 30
ff654490
VZ
31// the lines below duplicate the same definitions in collpaneg.cpp, if we have
32// another implementation of this class we should extract them to a common file
33
23318a53 34const char wxCollapsiblePaneNameStr[] = "collapsiblePane";
ff654490 35
9b11752c 36wxDEFINE_EVENT( wxEVT_COMMAND_COLLPANE_CHANGED, wxCollapsiblePaneEvent );
ff654490
VZ
37
38IMPLEMENT_DYNAMIC_CLASS(wxCollapsiblePaneEvent, wxCommandEvent)
39
3c1f8cb1
VZ
40// ============================================================================
41// implementation
42// ============================================================================
43
3c1f8cb1
VZ
44//-----------------------------------------------------------------------------
45// "notify::expanded" signal
46//-----------------------------------------------------------------------------
47
48extern "C" {
49
e4161a2a
VZ
50static void
51gtk_collapsiblepane_expanded_callback(GObject * WXUNUSED(object),
52 GParamSpec * WXUNUSED(param_spec),
53 wxCollapsiblePane *p)
3c1f8cb1 54{
4f5dc9aa
FM
55 // NB: unlike for the "activate" signal, when this callback is called, if
56 // we try to query the "collapsed" status through p->IsCollapsed(), we
57 // get the right value. I.e. here p->IsCollapsed() will return false if
58 // this callback has been called at the end of a collapsed->expanded
59 // transition and viceversa. Inside the "activate" signal callback
60 // p->IsCollapsed() would return the wrong value!
61
62 wxSize sz;
63 if ( p->IsExpanded() )
3c1f8cb1 64 {
4f5dc9aa
FM
65 // NB: we cannot use the p->GetBestSize() or p->GetMinSize() functions
66 // here as they would return the size for the collapsed expander
67 // even if the collapsed->expanded transition has already been
68 // completed; we solve this problem doing:
69
70 sz = p->m_szCollapsed;
71
72 wxSize panesz = p->GetPane()->GetBestSize();
73 sz.x = wxMax(sz.x, panesz.x);
74 sz.y += gtk_expander_get_spacing(GTK_EXPANDER(p->m_widget)) + panesz.y;
75 }
76 else // collapsed
77 {
78 // same problem described above: using p->Get[Best|Min]Size() here we
79 // would get the size of the control when it is expanded even if the
80 // expanded->collapsed transition should be complete now...
81 // So, we use the size cached at control-creation time...
82 sz = p->m_szCollapsed;
3c1f8cb1
VZ
83 }
84
4f5dc9aa
FM
85 // VERY IMPORTANT:
86 // just calling
87 // p->OnStateChange(sz);
88 // here would work work BUT:
89 // 1) in the expanded->collapsed transition it provokes a lot of flickering
90 // 2) in the collapsed->expanded transition using the "Change status" wxButton
91 // in samples/collpane application some strange warnings would be generated
92 // by the "clearlooks" theme, if that's your theme.
93 //
94 // So we prefer to use some GTK+ native optimized calls, which prevent too many resize
95 // calculations to happen. Note that the following code has been very carefully designed
96 // and tested - be VERY careful when changing it!
97
98 // 1) need to update our size hints
99 // NB: this function call won't actually do any long operation
d13b34d3 100 // (redraw/relayout/resize) so that it's flicker-free
4f5dc9aa
FM
101 p->SetMinSize(sz);
102
912c3932
VZ
103 if (p->HasFlag(wxCP_NO_TLW_RESIZE))
104 {
0514c6a2
RD
105 // fire an event
106 wxCollapsiblePaneEvent ev(p, p->GetId(), p->IsCollapsed());
937013e0 107 p->HandleWindowEvent(ev);
74ab5f5b 108
4c51a665 109 // the user asked to explicitly handle the resizing itself...
912c3932
VZ
110 return;
111 }
5c234706 112
912c3932
VZ
113 wxTopLevelWindow *
114 top = wxDynamicCast(wxGetTopLevelParent(p), wxTopLevelWindow);
115 if ( top && top->GetSizer() )
116 {
0ccf0043 117 // 2) recalculate minimal size of the top window
4f5dc9aa 118 sz = top->GetSizer()->CalcMin();
912c3932 119
912c3932
VZ
120 if (top->m_mainWidget)
121 {
2e10110a
VS
122 // 3) MAGIC HACK: if you ever used GtkExpander in a GTK+ program
123 // you know that this magic call is required to make it possible
124 // to shrink the top level window in the expanded->collapsed
125 // transition. This may be sometimes undesired but *is*
126 // necessary and if you look carefully, all GTK+ programs using
127 // GtkExpander perform this trick (e.g. the standard "open file"
d13b34d3 128 // dialog of GTK+>=2.4 is not resizable when the expander is
2e10110a 129 // collapsed!)
0ccf0043
RR
130 gtk_window_set_resizable (GTK_WINDOW (top->m_widget), p->IsExpanded());
131
cca410b3 132 // 4) set size hints
2e10110a 133 top->SetMinClientSize(sz);
912c3932 134
cca410b3
PC
135 // 5) set size
136 top->SetClientSize(sz);
912c3932
VZ
137 }
138 }
0ccf0043 139
550d433e 140 if ( p->m_bIgnoreNextChange )
3c1f8cb1
VZ
141 {
142 // change generated programmatically - do not send an event!
143 p->m_bIgnoreNextChange = false;
144 return;
145 }
146
147 // fire an event
148 wxCollapsiblePaneEvent ev(p, p->GetId(), p->IsCollapsed());
937013e0 149 p->HandleWindowEvent(ev);
3c1f8cb1
VZ
150}
151}
152
48200154 153void wxCollapsiblePane::AddChildGTK(wxWindowGTK* child)
3c1f8cb1 154{
48200154 155 // should be used only once to insert the "pane" into the
550d433e
VZ
156 // GtkExpander widget. wxGenericCollapsiblePane::DoAddChild() will check if
157 // it has been called only once (and in any case we would get a warning
158 // from the following call as GtkExpander is a GtkBin and can contain only
159 // a single child!).
48200154 160 gtk_container_add(GTK_CONTAINER(m_widget), child->m_widget);
3c1f8cb1
VZ
161}
162
3c1f8cb1
VZ
163//-----------------------------------------------------------------------------
164// wxCollapsiblePane
165//-----------------------------------------------------------------------------
166
ff654490 167IMPLEMENT_DYNAMIC_CLASS(wxCollapsiblePane, wxControl)
3c1f8cb1 168
ff654490 169BEGIN_EVENT_TABLE(wxCollapsiblePane, wxCollapsiblePaneBase)
3c1f8cb1
VZ
170 EVT_SIZE(wxCollapsiblePane::OnSize)
171END_EVENT_TABLE()
172
550d433e
VZ
173bool wxCollapsiblePane::Create(wxWindow *parent,
174 wxWindowID id,
175 const wxString& label,
176 const wxPoint& pos,
177 const wxSize& size,
178 long style,
179 const wxValidator& val,
180 const wxString& name)
3c1f8cb1 181{
3c1f8cb1
VZ
182 m_bIgnoreNextChange = false;
183
550d433e
VZ
184 if ( !PreCreation( parent, pos, size ) ||
185 !wxControl::CreateBase(parent, id, pos, size, style, val, name) )
3c1f8cb1
VZ
186 {
187 wxFAIL_MSG( wxT("wxCollapsiblePane creation failed") );
188 return false;
189 }
190
ff928a27
VZ
191 m_widget =
192 gtk_expander_new_with_mnemonic(wxGTK_CONV(GTKConvertMnemonics(label)));
9ff9d30c 193 g_object_ref(m_widget);
3c1f8cb1 194
4f5dc9aa
FM
195 // see the gtk_collapsiblepane_expanded_callback comments to understand why
196 // we connect to the "notify::expanded" signal instead of the more common
197 // "activate" one
198 g_signal_connect(m_widget, "notify::expanded",
3c1f8cb1 199 G_CALLBACK(gtk_collapsiblepane_expanded_callback), this);
5c234706 200
3c1f8cb1 201 // this the real "pane"
037c7b4c 202 m_pPane = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
4f5dc9aa 203 wxTAB_TRAVERSAL|wxNO_BORDER, wxS("wxCollapsiblePanePane"));
3c1f8cb1 204
3c1f8cb1 205 m_parent->DoAddChild( this );
5c234706 206
3c1f8cb1 207 PostCreation(size);
ce00f59b 208
5c234706
VZ
209 // we should blend into our parent background
210 const wxColour bg = parent->GetBackgroundColour();
211 SetBackgroundColour(bg);
212 m_pPane->SetBackgroundColour(bg);
213
3c1f8cb1 214 // remember the size of this control when it's collapsed
4f5dc9aa 215 m_szCollapsed = GetBestSize();
3c1f8cb1 216
3c1f8cb1
VZ
217 return true;
218}
219
220wxSize wxCollapsiblePane::DoGetBestSize() const
221{
ff654490 222 wxASSERT_MSG( m_widget, wxT("DoGetBestSize called before creation") );
3c1f8cb1 223
4f5dc9aa 224 GtkRequisition req;
9dc44eff
PC
225#ifdef __WXGTK3__
226 gtk_widget_get_preferred_width(m_widget, NULL, &req.width);
227 gtk_widget_get_preferred_height_for_width(m_widget, req.width, NULL, &req.height);
228#else
229 GTK_WIDGET_GET_CLASS(m_widget)->size_request(m_widget, &req);
230#endif
5c234706 231
4f5dc9aa
FM
232 // notice that we do not cache our best size here as it changes
233 // all times the user expands/hide our pane
234 return wxSize(req.width, req.height);
69d32caf
RR
235}
236
3c1f8cb1
VZ
237void wxCollapsiblePane::Collapse(bool collapse)
238{
ff654490
VZ
239 // optimization
240 if (IsCollapsed() == collapse)
241 return;
3c1f8cb1 242
ff654490
VZ
243 // do not send event in next signal handler call
244 m_bIgnoreNextChange = true;
245 gtk_expander_set_expanded(GTK_EXPANDER(m_widget), !collapse);
3c1f8cb1
VZ
246}
247
248bool wxCollapsiblePane::IsCollapsed() const
249{
ff654490 250 return !gtk_expander_get_expanded(GTK_EXPANDER(m_widget));
3c1f8cb1
VZ
251}
252
253void wxCollapsiblePane::SetLabel(const wxString &str)
254{
5a607f8b
VZ
255 gtk_expander_set_label(GTK_EXPANDER(m_widget),
256 wxGTK_CONV(GTKConvertMnemonics(str)));
912c3932 257
ff654490
VZ
258 // FIXME: we need to update our collapsed width in some way but using GetBestSize()
259 // we may get the size of the control with the pane size summed up if we are expanded!
260 //m_szCollapsed.x = GetBestSize().x;
3c1f8cb1
VZ
261}
262
263void wxCollapsiblePane::OnSize(wxSizeEvent &ev)
264{
265#if 0 // for debug only
266 wxClientDC dc(this);
267 dc.SetPen(*wxBLACK_PEN);
268 dc.SetBrush(*wxTRANSPARENT_BRUSH);
269 dc.DrawRectangle(wxPoint(0,0), GetSize());
270 dc.SetPen(*wxRED_PEN);
271 dc.DrawRectangle(wxPoint(0,0), GetBestSize());
272#endif
273
3c1f8cb1 274 // here we need to resize the pane window otherwise, even if the GtkExpander container
5c234706 275 // is expanded or shrunk, the pane window won't be updated!
912c3932 276 m_pPane->SetSize(ev.GetSize().x, ev.GetSize().y - m_szCollapsed.y);
3c1f8cb1 277
4c51a665 278 // we need to explicitly call m_pPane->Layout() or else it won't correctly relayout
3c1f8cb1
VZ
279 // (even if SetAutoLayout(true) has been called on it!)
280 m_pPane->Layout();
281}
282
4f5dc9aa
FM
283
284GdkWindow *wxCollapsiblePane::GTKGetWindow(wxArrayGdkWindows& windows) const
285{
286 GtkWidget *label = gtk_expander_get_label_widget( GTK_EXPANDER(m_widget) );
385e8575
PC
287 windows.Add(gtk_widget_get_window(label));
288 windows.Add(gtk_widget_get_window(m_widget));
4f5dc9aa
FM
289
290 return NULL;
ce00f59b 291}
4f5dc9aa 292
ff654490 293#endif // wxUSE_COLLPANE && !defined(__WXUNIVERSAL__)
3c1f8cb1 294