]> git.saurik.com Git - wxWidgets.git/blob - src/common/event.cpp
small optimization in ProcessEvent() (IsKindOf(wxWindow) only called once)
[wxWidgets.git] / src / common / event.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: event.cpp
3 // Purpose: Event classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "event.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/defs.h"
25 #include "wx/control.h"
26 #include "wx/utils.h"
27 #include "wx/app.h"
28 #include "wx/dc.h"
29 #endif
30
31 #include "wx/event.h"
32 #include "wx/validate.h"
33
34 #if !USE_SHARED_LIBRARY
35 IMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject)
36 IMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject)
37 IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent)
38 IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent)
39 IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent)
40 IMPLEMENT_DYNAMIC_CLASS(wxMouseEvent, wxEvent)
41 IMPLEMENT_DYNAMIC_CLASS(wxKeyEvent, wxEvent)
42 IMPLEMENT_DYNAMIC_CLASS(wxSizeEvent, wxEvent)
43 IMPLEMENT_DYNAMIC_CLASS(wxPaintEvent, wxEvent)
44 IMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent)
45 IMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent)
46 IMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent)
47 IMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent)
48 IMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent)
49 IMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent)
50 IMPLEMENT_DYNAMIC_CLASS(wxIconizeEvent, wxEvent)
51 IMPLEMENT_DYNAMIC_CLASS(wxMenuEvent, wxEvent)
52 IMPLEMENT_DYNAMIC_CLASS(wxJoystickEvent, wxEvent)
53 IMPLEMENT_DYNAMIC_CLASS(wxDropFilesEvent, wxEvent)
54 IMPLEMENT_DYNAMIC_CLASS(wxActivateEvent, wxEvent)
55 IMPLEMENT_DYNAMIC_CLASS(wxInitDialogEvent, wxEvent)
56 IMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent)
57 IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent)
58 IMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent)
59 IMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxCommandEvent)
60 IMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent)
61 IMPLEMENT_DYNAMIC_CLASS(wxQueryNewPaletteEvent, wxEvent)
62
63 const wxEventTable *wxEvtHandler::GetEventTable() const
64 { return &wxEvtHandler::sm_eventTable; }
65
66 const wxEventTable wxEvtHandler::sm_eventTable =
67 { (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] };
68
69 const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] =
70 { { 0, 0, 0,
71 #ifdef __SGI_CC__
72 // stupid SGI compiler --- offer aug 98
73 0L }
74 #else // !SGI CC
75 NULL }
76 #endif // SGI/!SGI
77 };
78
79 #endif // !USE_SHARED_LIBRARY
80
81 /*
82 * General wxWindows events, covering
83 * all interesting things that might happen (button clicking, resizing,
84 * setting text in widgets, etc.).
85 *
86 * For each completely new event type, derive a new event class.
87 *
88 */
89
90 wxEvent::wxEvent(int theId)
91 {
92 m_eventType = wxEVT_NULL;
93 m_eventObject = (wxObject *) NULL;
94 m_eventHandle = (char *) NULL;
95 m_timeStamp = 0;
96 m_id = theId;
97 m_skipped = FALSE;
98 m_callbackUserData = (wxObject *) NULL;
99 }
100
101 /*
102 * Command events
103 *
104 */
105
106 wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId)
107 {
108 m_eventType = commandType;
109 m_clientData = (char *) NULL;
110 m_clientObject = (wxClientData *) NULL;
111 m_extraLong = 0;
112 m_commandInt = 0;
113 m_id = theId;
114 m_commandString = (char *) NULL;
115 }
116
117 /*
118 * Scroll events
119 */
120
121 wxScrollEvent::wxScrollEvent(wxEventType commandType,
122 int id,
123 int pos,
124 int orient)
125 : wxCommandEvent(commandType, id)
126 {
127 m_extraLong = orient;
128 m_commandInt = pos;
129 }
130
131
132 /*
133 * Mouse events
134 *
135 */
136
137 wxMouseEvent::wxMouseEvent(wxEventType commandType)
138 {
139 m_eventType = commandType;
140 m_metaDown = FALSE;
141 m_altDown = FALSE;
142 m_controlDown = FALSE;
143 m_shiftDown = FALSE;
144 m_leftDown = FALSE;
145 m_rightDown = FALSE;
146 m_middleDown = FALSE;
147 m_x = 0;
148 m_y = 0;
149 }
150
151 // True if was a button dclick event (1 = left, 2 = middle, 3 = right)
152 // or any button dclick event (but = -1)
153 bool wxMouseEvent::ButtonDClick(int but) const
154 {
155 switch (but)
156 {
157 case -1:
158 return (LeftDClick() || MiddleDClick() || RightDClick());
159 case 1:
160 return LeftDClick();
161 case 2:
162 return MiddleDClick();
163 case 3:
164 return RightDClick();
165 default:
166 wxFAIL_MSG("invalid parameter in wxMouseEvent::ButtonDClick");
167 }
168
169 return FALSE;
170 }
171
172 // True if was a button down event (1 = left, 2 = middle, 3 = right)
173 // or any button down event (but = -1)
174 bool wxMouseEvent::ButtonDown(int but) const
175 {
176 switch (but)
177 {
178 case -1:
179 return (LeftDown() || MiddleDown() || RightDown());
180 case 1:
181 return LeftDown();
182 case 2:
183 return MiddleDown();
184 case 3:
185 return RightDown();
186 default:
187 wxFAIL_MSG("invalid parameter in wxMouseEvent::ButtonDown");
188 }
189
190 return FALSE;
191 }
192
193 // True if was a button up event (1 = left, 2 = middle, 3 = right)
194 // or any button up event (but = -1)
195 bool wxMouseEvent::ButtonUp(int but) const
196 {
197 switch (but) {
198 case -1:
199 return (LeftUp() || MiddleUp() || RightUp());
200 case 1:
201 return LeftUp();
202 case 2:
203 return MiddleUp();
204 case 3:
205 return RightUp();
206 default:
207 wxFAIL_MSG("invalid parameter in wxMouseEvent::ButtonUp");
208 }
209
210 return FALSE;
211 }
212
213 // True if the given button is currently changing state
214 bool wxMouseEvent::Button(int but) const
215 {
216 switch (but) {
217 case -1:
218 return (ButtonUp(-1) || ButtonDown(-1) || ButtonDClick(-1)) ;
219 case 1:
220 return (LeftDown() || LeftUp() || LeftDClick());
221 case 2:
222 return (MiddleDown() || MiddleUp() || MiddleDClick());
223 case 3:
224 return (RightDown() || RightUp() || RightDClick());
225 default:
226 wxFAIL_MSG("invalid parameter in wxMouseEvent::Button");
227 }
228
229 return FALSE;
230 }
231
232 bool wxMouseEvent::ButtonIsDown(int but) const
233 {
234 switch (but) {
235 case -1:
236 return (LeftIsDown() || MiddleIsDown() || RightIsDown());
237 case 1:
238 return LeftIsDown();
239 case 2:
240 return MiddleIsDown();
241 case 3:
242 return RightIsDown();
243 default:
244 wxFAIL_MSG("invalid parameter in wxMouseEvent::ButtonIsDown");
245 }
246
247 return FALSE;
248 }
249
250 // Find the logical position of the event given the DC
251 wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const
252 {
253 wxPoint pt(dc.DeviceToLogicalX(m_x), dc.DeviceToLogicalY(m_y));
254 return pt;
255 }
256
257
258 /*
259 * Keyboard events
260 *
261 */
262
263 wxKeyEvent::wxKeyEvent(wxEventType type)
264 {
265 m_eventType = type;
266 m_shiftDown = FALSE;
267 m_controlDown = FALSE;
268 m_metaDown = FALSE;
269 m_altDown = FALSE;
270 m_keyCode = 0;
271 }
272
273 /*
274 * Event handler
275 */
276
277 wxEvtHandler::wxEvtHandler()
278 {
279 m_nextHandler = (wxEvtHandler *) NULL;
280 m_previousHandler = (wxEvtHandler *) NULL;
281 m_enabled = TRUE;
282 m_dynamicEvents = (wxList *) NULL;
283 }
284
285 wxEvtHandler::~wxEvtHandler()
286 {
287 // Takes itself out of the list of handlers
288 if (m_previousHandler)
289 m_previousHandler->m_nextHandler = m_nextHandler;
290
291 if (m_nextHandler)
292 m_nextHandler->m_previousHandler = m_previousHandler;
293
294 if (m_dynamicEvents)
295 {
296 wxNode *node = m_dynamicEvents->First();
297 while (node)
298 {
299 wxEventTableEntry *entry = (wxEventTableEntry*)node->Data();
300 if (entry->m_callbackUserData) delete entry->m_callbackUserData;
301 delete entry;
302 node = node->Next();
303 }
304 delete m_dynamicEvents;
305 };
306 }
307
308 /*
309 * Event table stuff
310 */
311
312 bool wxEvtHandler::ProcessEvent(wxEvent& event)
313 {
314 bool isWindow = IsKindOf(CLASSINFO(wxWindow));
315
316 // An event handler can be enabled or disabled
317 if ( GetEvtHandlerEnabled() )
318 {
319 // Handle per-instance dynamic event tables first
320
321 if (SearchDynamicEventTable( event ))
322 return TRUE;
323
324 // Then static per-class event tables
325
326 const wxEventTable *table = GetEventTable();
327
328 // Try the associated validator first, if this is a window.
329 // Problem: if the event handler of the window has been replaced,
330 // this wxEvtHandler may no longer be a window.
331 // Therefore validators won't be processed if the handler
332 // has been replaced with SetEventHandler.
333 // THIS CAN BE CURED if PushEventHandler is used instead of
334 // SetEventHandler, and then processing will be passed down the
335 // chain of event handlers.
336 if ( isWindow )
337 {
338 wxWindow *win = (wxWindow *)this;
339
340 // Can only use the validator of the window which
341 // is receiving the event
342 if ( (win == event.GetEventObject()) &&
343 win->GetValidator() &&
344 win->GetValidator()->ProcessEvent(event))
345 {
346 return TRUE;
347 }
348 }
349
350 // Search upwards through the inheritance hierarchy
351 while (table)
352 {
353 if (SearchEventTable((wxEventTable&)*table, event))
354 return TRUE;
355 table = table->baseTable;
356 }
357 }
358
359 // Try going down the event handler chain
360 if ( GetNextHandler() )
361 {
362 if ( GetNextHandler()->ProcessEvent(event) )
363 return TRUE;
364 }
365
366 // Carry on up the parent-child hierarchy,
367 // but only if event is a command event: it wouldn't
368 // make sense for a parent to receive a child's size event, for example
369 if ( isWindow && event.IsKindOf(CLASSINFO(wxCommandEvent)) )
370 {
371 wxWindow *win = (wxWindow *)this;
372 wxWindow *parent = win->GetParent();
373 if (parent && !parent->IsBeingDeleted())
374 return win->GetParent()->GetEventHandler()->ProcessEvent(event);
375 }
376
377 // Last try - application object.
378 // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always swallow
379 // it. wxEVT_IDLE is sent explicitly to wxApp so it will be processed
380 // appropriately via SearchEventTable.
381 if ( wxTheApp && (this != wxTheApp) && (event.GetEventType() != wxEVT_IDLE)
382 )
383 {
384 if ( wxTheApp->ProcessEvent(event) )
385 return TRUE;
386 }
387
388 return FALSE;
389 }
390
391 bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
392 {
393 int i = 0;
394 int commandId = event.GetId();
395
396 // BC++ doesn't like while (table.entries[i].m_fn)
397
398 while (table.entries[i].m_fn != 0L)
399 {
400 if ((event.GetEventType() == table.entries[i].m_eventType) &&
401 (table.entries[i].m_id == -1 || // Match, if event spec says any id will do (id == -1)
402 (table.entries[i].m_lastId == -1 && commandId == table.entries[i].m_id) ||
403 (table.entries[i].m_lastId != -1 &&
404 (commandId >= table.entries[i].m_id && commandId <= table.entries[i].m_lastId))))
405 {
406 event.Skip(FALSE);
407 event.m_callbackUserData = table.entries[i].m_callbackUserData;
408
409 (this->*((wxEventFunction) (table.entries[i].m_fn)))(event);
410
411 if ( event.GetSkipped() )
412 return FALSE;
413 else
414 return TRUE;
415 }
416 i++;
417 }
418 return FALSE;
419 }
420
421 void wxEvtHandler::Connect( int id, int lastId,
422 wxEventType eventType,
423 wxObjectEventFunction func,
424 wxObject *userData )
425 {
426 wxEventTableEntry *entry = new wxEventTableEntry;
427 entry->m_id = id;
428 entry->m_lastId = lastId;
429 entry->m_eventType = eventType;
430 entry->m_fn = func;
431 entry->m_callbackUserData = userData;
432
433 if (!m_dynamicEvents)
434 m_dynamicEvents = new wxList;
435
436 m_dynamicEvents->Append( (wxObject*) entry );
437 }
438
439 bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event )
440 {
441 if (!m_dynamicEvents) return FALSE;
442
443 int commandId = event.GetId();
444
445 wxNode *node = m_dynamicEvents->First();
446 while (node)
447 {
448 wxEventTableEntry *entry = (wxEventTableEntry*)node->Data();
449
450 if (entry->m_fn)
451 {
452 // Match, if event spec says any id will do (id == -1)
453 if ( (event.GetEventType() == entry->m_eventType) &&
454 (entry->m_id == -1 ||
455 (entry->m_lastId == -1 && commandId == entry->m_id) ||
456 (entry->m_lastId != -1 &&
457 (commandId >= entry->m_id && commandId <= entry->m_lastId))) )
458 {
459 event.Skip(FALSE);
460 event.m_callbackUserData = entry->m_callbackUserData;
461
462 (this->*((wxEventFunction) (entry->m_fn)))(event);
463
464 if (event.GetSkipped())
465 return FALSE;
466 else
467 return TRUE;
468 }
469 }
470 node = node->Next();
471 }
472 return FALSE;
473 };
474
475 bool wxEvtHandler::OnClose()
476 {
477 if (GetNextHandler())
478 return GetNextHandler()->OnClose();
479 else
480 return FALSE;
481 }