]> git.saurik.com Git - wxWidgets.git/blob - src/generic/drawerg.cpp
Fix for probably rare but potential refcount leak.
[wxWidgets.git] / src / generic / drawerg.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: drawer.cpp
3 // Purpose: Generic Drawer child window classes.
4 // Drawer windows appear under their parent window and
5 // behave like a drawer, opening and closing to reveal
6 // content that does not need to be visible at all times.
7 // Author: Ryan Norton
8 // Modified by:
9 // Created: 2004-30-01
10 // RCS-ID: $Id$
11 // Copyright: (c) Ryan Norton
12 // Licence: wxWindows licence
13 /////////////////////////////////////////////////////////////////////////////
14
15 #ifdef __GNUG__
16 #pragma implementation "drawerg.h"
17 #endif
18
19 #include "wx/defs.h"
20 #include "wx/generic/drawerg.h"
21 #include "wx/timer.h"
22
23 enum wxGenericDrawerConstants
24 {
25 wxGENERICDRAWER_INCREMENT = 1,
26 wxGENERICDRAWER_INTERVAL = 3
27 };
28
29 class wxGenericDrawerTimer : public wxTimer
30 {
31 public:
32
33 wxGenericDrawerTimer(wxGenericDrawerWindow* pWin, const int& nMult) :
34 m_pWin(pWin), m_nMult(nMult) {}
35
36 void Notify()
37 {
38 if ((m_nMult < 0 && !m_pWin->m_nOpenOffset) ||
39 (
40 m_nMult >= 0 &&
41 (( (m_pWin->m_nCurrentEdge == wxLEFT ||
42 m_pWin->m_nCurrentEdge == wxRIGHT) && m_pWin->m_nOpenOffset >= m_pWin->GetSize().GetWidth())
43
44 ||
45
46 ( (m_pWin->m_nCurrentEdge == wxTOP ||
47 m_pWin->m_nCurrentEdge == wxBOTTOM) && m_pWin->m_nOpenOffset >= m_pWin->GetSize().GetHeight())
48 ))
49 )
50 {
51 /*
52 wxFprintf(stderr, "shutdown - mult:%i off:%i tlr:%i ttb:%i\n", m_nMult, m_pWin->m_nOpenOffset,
53
54 (m_pWin->m_nCurrentEdge == wxLEFT ||
55 m_pWin->m_nCurrentEdge == wxRIGHT) && m_pWin->m_nOpenOffset >= m_pWin->GetSize().GetWidth(),
56
57 (m_pWin->m_nCurrentEdge == wxTOP ||
58 m_pWin->m_nCurrentEdge == wxBOTTOM) && m_pWin->m_nOpenOffset >= m_pWin->GetSize().GetHeight()
59 );
60 */
61
62 //clean up & shut down
63 Stop();
64 m_pWin->m_pTimer = NULL;
65
66 //reset current edge to preferred edge
67 if (m_nMult < 0)
68 {
69 m_pWin->m_nCurrentEdge = m_pWin->m_nPreferredEdge;
70 m_pWin->DoDrawerPosition();
71 }
72
73 //commit seppuku
74 delete this;
75 }
76 else
77 {
78 // wxFprintf(stderr, "continue\n");
79 wxPoint pos = m_pWin->GetPosition();
80 switch (m_pWin->m_nCurrentEdge)
81 {
82 case wxLEFT:
83 pos.x -= wxGENERICDRAWER_INCREMENT * m_nMult;
84 break;
85
86 case wxRIGHT:
87 pos.x += wxGENERICDRAWER_INCREMENT * m_nMult;
88 break;
89
90 case wxTOP:
91 pos.y -= wxGENERICDRAWER_INCREMENT * m_nMult;
92 break;
93
94 case wxBOTTOM:
95 default:
96 pos.y += wxGENERICDRAWER_INCREMENT * m_nMult;
97 break;
98 }
99 m_pWin->SetPosition(pos);
100 //wxFprintf(stderr, "tpos:%i,%i\n", pos.x, pos.y);
101 m_pWin->m_nOpenOffset += wxGENERICDRAWER_INCREMENT * m_nMult;
102 }
103 }
104
105 wxGenericDrawerWindow* m_pWin;
106 int m_nMult;
107 };
108
109 enum wxGenericDrawerOffsets
110 {
111 wxGENERICDRAWER_TOPOFFSET = 20,
112 wxGENERICDRAWER_BOTTOMOFFSET = 20
113 };
114
115 IMPLEMENT_DYNAMIC_CLASS(wxGenericDrawerWindow, wxWindow)
116
117 wxGenericDrawerWindow::wxGenericDrawerWindow() :
118 m_bOpen(false), m_nCurrentEdge(wxLEFT), m_nPreferredEdge(wxLEFT), m_nOpenOffset(0),
119 m_pTimer(NULL)
120 {
121 }
122
123 wxGenericDrawerWindow::~wxGenericDrawerWindow()
124 {
125 m_isBeingDeleted = true;
126 this->Show(false);
127 if (m_pTimer)
128 {
129 m_pTimer->Stop();
130 delete m_pTimer;
131 }
132 }
133
134 bool wxGenericDrawerWindow::Create(wxWindow *parent,
135 wxWindowID id, const wxString& title,
136 wxSize size, wxDirection edge, const wxString& name)
137 {
138 wxASSERT_MSG(NULL != parent, wxT("wxDrawerWindows must be attached to a parent window."));
139
140 wxASSERT_MSG(m_pTimer == NULL, wxT("Currently opening!!"));
141
142 wxASSERT_MSG(edge == wxLEFT ||
143 edge == wxRIGHT ||
144 edge == wxTOP ||
145 edge == wxBOTTOM, wxT("Invalid edge") );
146
147 // Create the drawer window.
148 const wxPoint pos(0, 0);
149 const long style = wxNO_BORDER || wxVSCROLL | wxHSCROLL;//wxFRAME_DRAWER;
150
151 bool success = wxTopLevelWindow::Create(parent, id, wxT(""), pos, size, style, name);
152
153 if (success)
154 {
155 // Set the drawers parent.
156
157
158 if (parent->IsTopLevel())
159 {
160 wxTopLevelWindow* tlwParent = (wxTopLevelWindow*) parent;
161
162 //connect to parent's events
163 tlwParent->Connect(tlwParent->GetId(), wxEVT_MOVE,
164 (wxObjectEventFunction) (wxEventFunction) (wxMoveEventFunction) &wxGenericDrawerWindow::OnDrawerMove,
165 NULL, //user data
166 this);
167
168 tlwParent->Connect(tlwParent->GetId(), wxEVT_SIZE,
169 (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxGenericDrawerWindow::OnDrawerSize,
170 NULL, //user data
171 this);
172
173 tlwParent->Connect(tlwParent->GetId(), wxEVT_KILL_FOCUS,
174 (wxObjectEventFunction) (wxEventFunction) (wxFocusEventFunction) &wxGenericDrawerWindow::OnDrawerFocus,
175 NULL, //user data
176 this);
177
178 m_LastParentSize = parent->GetSize();
179 DoDrawerPosition();
180 DoDrawerSize();
181 }
182 else
183 success = false;
184 }
185
186 m_nCurrentEdge = m_nPreferredEdge = edge;
187 Show(success);
188 if (success && parent->IsShown()) //bring parent on top
189 {
190 parent->Show(false);
191 parent->Show(true);
192 }
193 //wxFprintf(stderr,wxT("success==%i\n"), success);
194 return success;
195 }
196
197 wxDirection wxGenericDrawerWindow::GetCurrentEdge() const
198 {
199 return m_nCurrentEdge;
200 }
201
202 wxDirection wxGenericDrawerWindow::GetPreferredEdge() const
203 {
204 return m_nPreferredEdge;
205 }
206
207 bool wxGenericDrawerWindow::IsOpen() const
208 {
209 return m_bOpen;
210 }
211
212 bool wxGenericDrawerWindow::Open(const bool& show)
213 {
214 if(show)
215 {
216 if (m_pTimer)
217 delete m_pTimer;
218
219 m_pTimer = new wxGenericDrawerTimer(this, 1);
220 m_pTimer->Start(wxGENERICDRAWER_INTERVAL);
221 }
222 else
223 {
224 if (m_pTimer)
225 delete m_pTimer;
226
227 m_pTimer = new wxGenericDrawerTimer(this, -1);
228 m_pTimer->Start(wxGENERICDRAWER_INTERVAL);
229 }
230
231 return true;
232 }
233
234 bool wxGenericDrawerWindow::SetPreferredEdge(const wxDirection& edge)
235 {
236 wxASSERT(edge == wxLEFT ||
237 edge == wxRIGHT ||
238 edge == wxTOP ||
239 edge == wxBOTTOM );
240
241 if (!m_nOpenOffset)
242 {
243 m_nCurrentEdge = edge;
244 DoDrawerPosition();
245 }
246
247 m_nPreferredEdge = edge;
248 return true;
249 }
250
251 void wxGenericDrawerWindow::DoDrawerPosition()
252 {
253 const wxPoint parentPosition(GetParent()->GetPosition());
254 SetPosition(wxPoint(
255 parentPosition.x +
256 (m_nCurrentEdge == wxLEFT ?
257 -m_nOpenOffset : m_nCurrentEdge == wxRIGHT ? GetParent()->GetSize().GetWidth() + m_nOpenOffset - GetSize().GetWidth(): wxGENERICDRAWER_TOPOFFSET),
258 parentPosition.y +
259 (m_nCurrentEdge == wxTOP ?
260 -m_nOpenOffset : m_nCurrentEdge == wxBOTTOM ? GetParent()->GetSize().GetHeight() + m_nOpenOffset - GetSize().GetHeight() : wxGENERICDRAWER_TOPOFFSET)
261 ));
262 //wxFprintf(stderr,wxT("parentposition:%i,%i\n"), parentPosition.x, parentPosition.y);
263 //wxFprintf(stderr,wxT("offset:%i\nposition:%i,%i\n"), m_nOpenOffset, GetPosition().x, GetPosition().y);
264 }
265
266 void wxGenericDrawerWindow::DoDrawerSize()
267 {
268 // Constrain the drawer size to the parent window.
269 const wxSize parentSize(GetParent()->GetClientSize());
270 wxSize size = GetSize();
271
272 if (wxLEFT == m_nCurrentEdge || wxRIGHT == m_nCurrentEdge)
273 {
274 if (size.GetHeight() > parentSize.GetHeight())
275 size.SetHeight(parentSize.GetHeight() - (wxGENERICDRAWER_TOPOFFSET + wxGENERICDRAWER_BOTTOMOFFSET));
276
277 size.SetHeight(size.GetHeight() + (parentSize.GetHeight() - m_LastParentSize.GetHeight()));
278 }
279 else
280 {
281 if (size.GetWidth() > parentSize.GetWidth())
282 size.SetWidth(parentSize.GetWidth() - (wxGENERICDRAWER_TOPOFFSET + wxGENERICDRAWER_BOTTOMOFFSET));
283
284 size.SetWidth(size.GetWidth() + (parentSize.GetWidth() - m_LastParentSize.GetWidth()));
285 }
286
287 SetSize(size);
288 m_LastParentSize = parentSize;
289
290 //wxFprintf(stderr,wxT("size:%i,%i\n"), size.GetWidth(), size.GetHeight());
291 }
292
293 void wxGenericDrawerWindow::OnDrawerFocus(wxFocusEvent& evt)
294 {
295 // wxFprintf(stderr, wxT("focus\n"));
296
297 if (wxWindow::FindFocus() == this)
298 GetParent()->SetFocus();
299 }
300
301 void wxGenericDrawerWindow::OnDrawerMove(wxMoveEvent& evt)
302 {
303 DoDrawerPosition();
304 }
305
306 void wxGenericDrawerWindow::OnDrawerSize(wxSizeEvent& evt)
307 {
308 DoDrawerSize();
309 }
310