1. We don't need GetTopLevelParent() here, we already have wxGetTopLevelParent()
[wxWidgets.git] / src / generic / collpaneg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/collpaneg.cpp
3 // Purpose: wxGenericCollapsiblePane
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
20 #ifndef WX_PRECOMP
21 #include "wx/button.h"
22 #endif // !WX_PRECOMP
23
24 #include "wx/collpane.h"
25 #include "wx/statline.h"
26
27 // ----------------------------------------------------------------------------
28 // constants
29 // ----------------------------------------------------------------------------
30
31 // the number of pixels to leave between the button and the static line and
32 // between the button and the pane
33 #define wxCP_MARGIN 10
34
35 // ============================================================================
36 // implementation
37 // ============================================================================
38
39 const wxChar wxGenericCollapsiblePaneNameStr[] = wxT("genericCollapsiblePane");
40
41 //-----------------------------------------------------------------------------
42 // wxGenericCollapsiblePane
43 //-----------------------------------------------------------------------------
44
45 DEFINE_EVENT_TYPE(wxEVT_COMMAND_COLLPANE_CHANGED)
46 IMPLEMENT_DYNAMIC_CLASS(wxGenericCollapsiblePane, wxControl)
47 IMPLEMENT_DYNAMIC_CLASS(wxCollapsiblePaneEvent, wxCommandEvent)
48
49 BEGIN_EVENT_TABLE(wxGenericCollapsiblePane, wxControl)
50 EVT_BUTTON(wxID_ANY, wxGenericCollapsiblePane::OnButton)
51 EVT_SIZE(wxGenericCollapsiblePane::OnSize)
52 END_EVENT_TABLE()
53
54
55 bool wxGenericCollapsiblePane::Create(wxWindow *parent,
56 wxWindowID id,
57 const wxString& label,
58 const wxPoint& pos,
59 const wxSize& size,
60 long style,
61 const wxValidator& val,
62 const wxString& name)
63 {
64 if ( !wxControl::Create(parent, id, pos, size, style, val, name) )
65 return false;
66
67 m_strLabel = label;
68
69 // create children; their size & position is set in OnSize()
70 m_pButton = new wxButton(this, wxID_ANY, GetBtnLabel(), wxPoint(0, 0),
71 wxDefaultSize, wxBU_EXACTFIT);
72 m_pStatLine = new wxStaticLine(this, wxID_ANY);
73 m_pPane = new wxWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
74 wxNO_BORDER);
75
76 // start as collapsed:
77 m_pPane->Hide();
78
79 //CacheBestSize(GetBestSize());
80 return true;
81 }
82
83 wxSize wxGenericCollapsiblePane::DoGetBestSize() const
84 {
85 wxSize sz = m_pButton->GetBestSize();
86
87 // set width
88 sz.SetWidth(sz.x + wxCP_MARGIN + m_pStatLine->GetBestSize().x);
89 const wxCoord paneWidth = m_pPane->GetBestSize().x;
90 if ( sz.x < paneWidth )
91 sz.x = paneWidth;
92
93 // when expanded, we need more vertical space
94 if ( IsExpanded() )
95 sz.SetHeight(sz.y + wxCP_MARGIN + m_pPane->GetBestSize().y);
96
97 return sz;
98 }
99
100 wxString wxGenericCollapsiblePane::GetBtnLabel() const
101 {
102 return m_strLabel + (IsCollapsed() ? wxT(" >>") : wxT(" <<"));
103 }
104
105 void wxGenericCollapsiblePane::Collapse(bool collapse)
106 {
107 // optimization
108 if ( IsCollapsed() == collapse )
109 return;
110
111 // update our state
112 m_pPane->Show(!collapse);
113
114 // update button label
115 // NB: this must be done after updating our "state"
116 m_pButton->SetLabel(GetBtnLabel());
117
118 // minimal size has priority over the best size so set here our min size
119 wxSize sz = GetBestSize();
120 SetMinSize(sz);
121 SetSize(sz);
122
123 wxWindow *top = wxGetTopLevelParent(this);
124 if (top)
125 {
126 // we've changed our size, thus our top level parent needs to relayout
127 // itself
128 top->Layout();
129
130 // FIXME: this makes wxGenericCollapsiblePane behave as the user expect
131 // but maybe there are cases where this is unwanted!
132 if (top->GetSizer())
133 #ifdef __WXGTK__
134 // FIXME: the SetSizeHints() call would be required also for GTK+ for
135 // the expanded->collapsed transition. Unfortunately if we
136 // enable this line, then the GTK+ top window won't always be
137 // resized by the SetClientSize() call below! As a side effect
138 // of this dirty fix, the minimal size for the pane window is
139 // not set in GTK+ and the user can hide it shrinking the "top"
140 // window...
141 if (IsCollapsed())
142 #endif
143 top->GetSizer()->SetSizeHints(top);
144
145 if (IsCollapsed())
146 {
147 // use SetClientSize() and not SetSize() otherwise the size for
148 // e.g. a wxFrame with a menubar wouldn't be correctly set
149 top->SetClientSize(sz);
150 }
151 else
152 {
153 // force our parent to "fit", i.e. expand so that it can honour
154 // our minimal size
155 top->Fit();
156 }
157 }
158 }
159
160 void wxGenericCollapsiblePane::SetLabel(const wxString &label)
161 {
162 m_strLabel = label;
163 m_pButton->SetLabel(GetBtnLabel());
164 m_pButton->SetBestFittingSize();
165
166 LayoutChildren();
167 }
168
169 void wxGenericCollapsiblePane::LayoutChildren()
170 {
171 wxSize btnSz = m_pButton->GetSize();
172
173 // the button position & size are always ok...
174
175 // move & resize the static line
176 m_pStatLine->SetSize(btnSz.x + wxCP_MARGIN, btnSz.y/2,
177 GetSize().x - btnSz.x - wxCP_MARGIN, -1,
178 wxSIZE_USE_EXISTING);
179
180 // move & resize the container window
181 m_pPane->SetSize(0, btnSz.y + wxCP_MARGIN,
182 GetSize().x, GetSize().y - btnSz.y - wxCP_MARGIN);
183 }
184
185
186
187 //-----------------------------------------------------------------------------
188 // wxGenericCollapsiblePane - event handlers
189 //-----------------------------------------------------------------------------
190
191 void wxGenericCollapsiblePane::OnButton(wxCommandEvent& event)
192 {
193 if ( event.GetEventObject() != m_pButton )
194 {
195 event.Skip();
196 return;
197 }
198
199 Collapse(!IsCollapsed());
200
201 // this change was generated by the user - send the event
202 wxCollapsiblePaneEvent ev(this, GetId(), IsCollapsed());
203 GetEventHandler()->ProcessEvent(ev);
204 }
205
206 void wxGenericCollapsiblePane::OnSize(wxSizeEvent& WXUNUSED(event))
207 {
208 #if 0 // for debug only
209 wxClientDC dc(this);
210 dc.SetPen(*wxBLACK_PEN);
211 dc.SetBrush(*wxTRANSPARENT_BRUSH);
212 dc.DrawRectangle(wxPoint(0,0), GetSize());
213 dc.SetPen(*wxRED_PEN);
214 dc.DrawRectangle(wxPoint(0,0), GetBestSize());
215 #endif
216
217
218 if (!m_pButton || !m_pStatLine || !m_pPane)
219 return; // we need to complete the creation first!
220
221 LayoutChildren();
222
223 // this is very important to make the pane window layout show correctly
224 m_pPane->Layout();
225 }
226