]> git.saurik.com Git - wxWidgets.git/blob - src/common/event.cpp
wxString::Scanf() removed because can't be implemented portably
[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(wxScrollEvent, wxCommandEvent)
39 IMPLEMENT_DYNAMIC_CLASS(wxMouseEvent, wxEvent)
40 IMPLEMENT_DYNAMIC_CLASS(wxKeyEvent, wxEvent)
41 IMPLEMENT_DYNAMIC_CLASS(wxSizeEvent, wxEvent)
42 IMPLEMENT_DYNAMIC_CLASS(wxPaintEvent, wxEvent)
43 IMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent)
44 IMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent)
45 IMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent)
46 IMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent)
47 IMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent)
48 IMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent)
49 IMPLEMENT_DYNAMIC_CLASS(wxIconizeEvent, wxEvent)
50 IMPLEMENT_DYNAMIC_CLASS(wxMenuEvent, wxEvent)
51 IMPLEMENT_DYNAMIC_CLASS(wxJoystickEvent, wxEvent)
52 IMPLEMENT_DYNAMIC_CLASS(wxDropFilesEvent, wxEvent)
53 IMPLEMENT_DYNAMIC_CLASS(wxActivateEvent, wxEvent)
54 IMPLEMENT_DYNAMIC_CLASS(wxInitDialogEvent, wxEvent)
55 IMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent)
56 IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent)
57 IMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxEvent)
58
59 const wxEventTable *wxEvtHandler::GetEventTable() const { return &wxEvtHandler::sm_eventTable; }
60
61 const wxEventTable wxEvtHandler::sm_eventTable =
62 { NULL, &wxEvtHandler::sm_eventTableEntries[0] };
63
64 const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] = { { 0, 0, 0, NULL } };
65
66 #endif
67
68 /*
69 * General wxWindows events, covering
70 * all interesting things that might happen (button clicking, resizing,
71 * setting text in widgets, etc.).
72 *
73 * For each completely new event type, derive a new event class.
74 *
75 */
76
77 wxEvent::wxEvent(int theId)
78 {
79 m_eventType = 0;
80 m_eventObject = NULL;
81 m_eventHandle = NULL;
82 m_timeStamp = 0;
83 m_id = theId;
84 m_skipped = FALSE;
85 m_callbackUserData = NULL;
86 }
87
88 /*
89 * Command events
90 *
91 */
92
93 wxCommandEvent::wxCommandEvent(WXTYPE commandType, int theId)
94 {
95 m_eventType = commandType;
96 m_clientData = NULL;
97 m_extraLong = 0;
98 m_commandInt = 0;
99 m_id = theId;
100 m_commandString = NULL;
101 }
102
103 /*
104 * Scroll events
105 */
106
107 wxScrollEvent::wxScrollEvent(WXTYPE commandType, int id, int pos, int orient):
108 wxCommandEvent(commandType, id)
109 {
110 m_extraLong = orient;
111 m_commandInt = pos;
112 }
113
114
115 /*
116 * Mouse events
117 *
118 */
119
120 wxMouseEvent::wxMouseEvent(WXTYPE commandType)
121 {
122 m_eventType = commandType;
123 m_metaDown = FALSE;
124 m_altDown = FALSE;
125 m_controlDown = FALSE;
126 m_shiftDown = FALSE;
127 }
128
129 // True if was a button dclick event (1 = left, 2 = middle, 3 = right)
130 // or any button dclick event (but = -1)
131 bool wxMouseEvent::ButtonDClick(int but) const
132 {
133 switch (but) {
134 case -1:
135 return (LeftDClick() || MiddleDClick() || RightDClick());
136 case 1:
137 return LeftDClick();
138 case 2:
139 return MiddleDClick();
140 case 3:
141 return RightDClick();
142 default:
143 return FALSE;
144 }
145 // NOTREACHED
146 }
147
148 // True if was a button down event (1 = left, 2 = middle, 3 = right)
149 // or any button down event (but = -1)
150 bool wxMouseEvent::ButtonDown(int but) const
151 {
152 switch (but) {
153 case -1:
154 return (LeftDown() || MiddleDown() || RightDown());
155 case 1:
156 return LeftDown();
157 case 2:
158 return MiddleDown();
159 case 3:
160 return RightDown();
161 default:
162 return FALSE;
163 }
164 // NOTREACHED
165 }
166
167 // True if was a button up event (1 = left, 2 = middle, 3 = right)
168 // or any button up event (but = -1)
169 bool wxMouseEvent::ButtonUp(int but) const
170 {
171 switch (but) {
172 case -1:
173 return (LeftUp() || MiddleUp() || RightUp());
174 case 1:
175 return LeftUp();
176 case 2:
177 return MiddleUp();
178 case 3:
179 return RightUp();
180 default:
181 return FALSE;
182 }
183 // NOTREACHED
184 }
185
186 // True if the given button is currently changing state
187 bool wxMouseEvent::Button(int but) const
188 {
189 switch (but) {
190 case -1:
191 return (ButtonUp(-1) || ButtonDown(-1) || ButtonDClick(-1)) ;
192 case 1:
193 return (LeftDown() || LeftUp() || LeftDClick());
194 case 2:
195 return (MiddleDown() || MiddleUp() || MiddleDClick());
196 case 3:
197 return (RightDown() || RightUp() || RightDClick());
198 default:
199 return FALSE;
200 }
201 // NOTREACHED
202 }
203
204 bool wxMouseEvent::ButtonIsDown(int but) const
205 {
206 switch (but) {
207 case -1:
208 return (LeftIsDown() || MiddleIsDown() || RightIsDown());
209 case 1:
210 return LeftIsDown();
211 case 2:
212 return MiddleIsDown();
213 case 3:
214 return RightIsDown();
215 default:
216 return FALSE;
217 }
218 // NOTREACHED
219 }
220
221 // Find the logical position of the event given the DC
222 wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const
223 {
224 wxPoint pt(dc.DeviceToLogicalX(m_x), dc.DeviceToLogicalY(m_y));
225 return pt;
226 }
227
228
229 /*
230 * Keyboard events
231 *
232 */
233
234 wxKeyEvent::wxKeyEvent(WXTYPE type)
235 {
236 m_eventType = type;
237 m_shiftDown = FALSE;
238 m_controlDown = FALSE;
239 m_metaDown = FALSE;
240 m_altDown = FALSE;
241 m_keyCode = 0;
242 }
243
244 /*
245 * Event handler
246 */
247
248 wxEvtHandler::wxEvtHandler(void)
249 {
250 m_clientData = NULL;
251 m_nextHandler = NULL;
252 m_previousHandler = NULL;
253 m_enabled = TRUE;
254 m_dynamicEvents = NULL;
255 }
256
257 wxEvtHandler::~wxEvtHandler(void)
258 {
259 // Takes itself out of the list of handlers
260 if (m_previousHandler)
261 m_previousHandler->m_nextHandler = m_nextHandler;
262
263 if (m_nextHandler)
264 m_nextHandler->m_previousHandler = m_previousHandler;
265
266 if (m_dynamicEvents)
267 {
268 wxNode *node = m_dynamicEvents->First();
269 while (node)
270 {
271 wxEventTableEntry *entry = (wxEventTableEntry*)node->Data();
272 if (entry->m_callbackUserData) delete entry->m_callbackUserData;
273 delete entry;
274 node = node->Next();
275 }
276 delete m_dynamicEvents;
277 };
278 }
279
280 /*
281 * Event table stuff
282 */
283
284 bool wxEvtHandler::ProcessEvent(wxEvent& event)
285 {
286 // An event handler can be enabled or disabled
287 if ( GetEvtHandlerEnabled() )
288 {
289 // Handle per-instance dynamic event tables first
290
291 if (SearchDynamicEventTable( event )) return TRUE;
292
293 // Then static per-class event tables
294
295 const wxEventTable *table = GetEventTable();
296
297 // Try the associated validator first, if this is a window.
298 // Problem: if the event handler of the window has been replaced,
299 // this wxEvtHandler may no longer be a window.
300 // Therefore validators won't be processed if the handler
301 // has been replaced with SetEventHandler.
302 // THIS CAN BE CURED if PushEventHandler is used instead of
303 // SetEventHandler, and then processing will be passed down the
304 // chain of event handlers.
305 if (IsKindOf(CLASSINFO(wxWindow)))
306 {
307 wxWindow *win = (wxWindow *)this;
308
309 // Can only use the validator of the window which
310 // is receiving the event
311 if ( (win == event.GetEventObject()) &&
312 win->GetValidator() &&
313 win->GetValidator()->ProcessEvent(event))
314 return TRUE;
315 }
316
317 // Search upwards through the inheritance hierarchy
318 while (table)
319 {
320 if (SearchEventTable((wxEventTable&)*table, event))
321 return TRUE;
322 table = table->baseTable;
323 }
324 }
325
326 // Try going down the event handler chain
327 if ( GetNextHandler() )
328 {
329 if ( GetNextHandler()->ProcessEvent(event) )
330 return TRUE;
331 }
332
333 // Carry on up the parent-child hierarchy,
334 // but only if event is a command event: it wouldn't
335 // make sense for a parent to receive a child's size event, for example
336 if (IsKindOf(CLASSINFO(wxWindow)) && event.IsKindOf(CLASSINFO(wxCommandEvent)))
337 {
338 wxWindow *win = (wxWindow *)this;
339 wxWindow *parent = win->GetParent();
340 if (parent && !parent->IsBeingDeleted())
341 return win->GetParent()->GetEventHandler()->ProcessEvent(event);
342 }
343
344 // Last try - application object
345 if (wxTheApp && this != wxTheApp && wxTheApp->ProcessEvent(event))
346 return TRUE;
347 else
348 return FALSE;
349 }
350
351 bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event)
352 {
353 int i = 0;
354 int commandId = event.GetId();
355
356 while (table.entries[i].m_fn != NULL)
357 {
358 if ((event.GetEventType() == table.entries[i].m_eventType) &&
359 (table.entries[i].m_id == -1 || // Match, if event spec says any id will do (id == -1)
360 (table.entries[i].m_lastId == -1 && commandId == table.entries[i].m_id) ||
361 (table.entries[i].m_lastId != -1 &&
362 (commandId >= table.entries[i].m_id && commandId <= table.entries[i].m_lastId))))
363 {
364 event.Skip(FALSE);
365 event.m_callbackUserData = table.entries[i].m_callbackUserData;
366
367 (this->*((wxEventFunction) (table.entries[i].m_fn)))(event);
368
369 if ( event.GetSkipped() )
370 return FALSE;
371 else
372 return TRUE;
373 }
374 i ++;
375 }
376 return FALSE;
377 }
378
379 void wxEvtHandler::Connect( const int id, const int lastId,
380 const int eventType,
381 wxObjectEventFunction func,
382 wxObject *userData )
383 {
384 wxEventTableEntry *entry = new wxEventTableEntry;
385 entry->m_id = id;
386 entry->m_lastId = lastId;
387 entry->m_eventType = eventType;
388 entry->m_fn = func;
389 entry->m_callbackUserData = userData;
390
391 if (!m_dynamicEvents)
392 m_dynamicEvents = new wxList;
393
394 m_dynamicEvents->Append( (wxObject*) entry );
395 }
396
397 bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event )
398 {
399 if (!m_dynamicEvents) return FALSE;
400
401 int commandId = event.GetId();
402
403 wxNode *node = m_dynamicEvents->First();
404 while (node)
405 {
406 wxEventTableEntry *entry = (wxEventTableEntry*)node->Data();
407 if (entry->m_fn)
408 {
409 if ((event.GetEventType() == entry->m_eventType) &&
410 (entry->m_id == -1 || // Match, if event spec says any id will do (id == -1)
411 (entry->m_lastId == -1 && commandId == entry->m_id) ||
412 (entry->m_lastId != -1 &&
413 (commandId >= entry->m_id && commandId <= entry->m_lastId))))
414 {
415 event.Skip(FALSE);
416 event.m_callbackUserData = entry->m_callbackUserData;
417
418 (this->*((wxEventFunction) (entry->m_fn)))(event);
419
420 if (event.GetSkipped())
421 return FALSE;
422 else
423 return TRUE;
424 }
425 };
426 node = node->Next();
427 }
428 return FALSE;
429 };
430
431 #if WXWIN_COMPATIBILITY
432 void wxEvtHandler::OldOnMenuCommand(int cmd)
433 {
434 if (GetNextHandler()) GetNextHandler()->OldOnMenuCommand(cmd);
435 }
436
437 void wxEvtHandler::OldOnMenuSelect(int cmd)
438 {
439 if (GetNextHandler()) GetNextHandler()->OldOnMenuSelect(cmd);
440 }
441
442 void wxEvtHandler::OldOnInitMenuPopup(int pos)
443 {
444 if (GetNextHandler()) GetNextHandler()->OldOnInitMenuPopup(pos);
445 }
446
447 void wxEvtHandler::OldOnScroll(wxCommandEvent& event)
448 {
449 if (GetNextHandler()) GetNextHandler()->OldOnScroll(event);
450 }
451
452 void wxEvtHandler::OldOnPaint(void)
453 {
454 if (GetNextHandler()) GetNextHandler()->OldOnPaint();
455 }
456 void wxEvtHandler::OldOnSize(int width, int height)
457 {
458 if (GetNextHandler()) GetNextHandler()->OldOnSize(width, height);
459 }
460
461 void wxEvtHandler::OldOnMove(int x, int y)
462 {
463 if (GetNextHandler()) GetNextHandler()->OldOnMove(x, y);
464 }
465
466 void wxEvtHandler::OldOnMouseEvent(wxMouseEvent& event)
467 {
468 if (GetNextHandler()) GetNextHandler()->OldOnMouseEvent(event);
469 }
470
471 void wxEvtHandler::OldOnChar(wxKeyEvent& event)
472 {
473 if (GetNextHandler()) GetNextHandler()->OldOnChar(event);
474 }
475
476 // Under Windows, we can intercept character input per dialog or frame
477 bool wxEvtHandler::OldOnCharHook(wxKeyEvent& event)
478 {
479 if (GetNextHandler()) return GetNextHandler()->OldOnCharHook(event);
480 else return FALSE;
481 }
482
483 void wxEvtHandler::OldOnActivate(bool active)
484 {
485 if (GetNextHandler()) GetNextHandler()->OldOnActivate(active);
486 }
487
488 void wxEvtHandler::OldOnSetFocus(void)
489 {
490 if (GetNextHandler()) GetNextHandler()->OldOnSetFocus();
491 }
492
493 void wxEvtHandler::OldOnKillFocus(void)
494 {
495 if (GetNextHandler()) GetNextHandler()->OldOnKillFocus();
496 }
497
498 bool wxEvtHandler::OldOnSysColourChange(void)
499 {
500 if (GetNextHandler()) return GetNextHandler()->OldOnSysColourChange();
501 return FALSE;
502 }
503
504 void wxEvtHandler::OldOnDropFiles(int n, char *files[], int x, int y)
505 {
506 if (GetNextHandler()) GetNextHandler()->OldOnDropFiles(n, files, x, y);
507 }
508 #endif
509
510 bool wxEvtHandler::OnClose(void)
511 {
512 if (GetNextHandler()) return GetNextHandler()->OnClose();
513 else return FALSE;
514 }
515
516