Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
eventmanager.cpp
Go to the documentation of this file.
1 /*
2  * Vega Strike
3  * Copyright (C) 2003 Mike Byron
4  *
5  * http://vegastrike.sourceforge.net/
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include "vegastrike.h"
23 
24 #include "eventmanager.h"
25 
26 #include <algorithm>
27 
28 /* The EventManager class contains the basic event loop and the code
29  * to support the EventResponder chain. There should be only one
30  * instance of this class running in an application.
31  * You can get a pointer to it by using the static globalEventManager()
32  * function.
33  */
34 extern void ModifyMouseSensitivity( int &x, int &y );
35 //This is the one, unique event manager.
37 
38 //STATIC: Get the global instance of the event manager
40 {
41  if (globalEventManagerPtr == NULL) {
43  assert( globalEventManagerPtr != NULL ); //Make sure we got a manager!
44  }
45  return *globalEventManagerPtr;
46 }
47 
49 {
50  return globalEventManagerPtr != NULL;
51 }
52 
53 //STATIC: Initialize the event manager. This starts the event loop, etc.
54 //This may be called more than once -- it does nothing after the
55 //first call.
57 {
58  globalEventManagerPtr = new EventManager();
59  globalEventManagerPtr->takeOverEventManagement(); //FIXME -- EVENT HACK
60 }
61 
62 static std::vector< EventResponder* >deleteQueue;
63 
65 {
66  if ( controlToDelete == NULL || find( deleteQueue.begin(), deleteQueue.end(), controlToDelete ) != deleteQueue.end() ) {
67  bool DUPLICATE_DELETE_OF_OBJECT = true;
68  char tempstr[254];
69  sprintf( tempstr, "\nERROR: duplicate delete of object %lX.\n\n", (long unsigned int) controlToDelete );
70  fputs( tempstr, stderr );
71 #if defined (_MSC_VER) && defined (_DEBUG) && 0
72  if (DEBUG_ERROR_IN_MY_CODE)
73  _RPT0( _CRT_ERROR, tempstr );
74 #endif
75  printf( "Attach a debugger now!" );
76  while (DUPLICATE_DELETE_OF_OBJECT) {}
77  } else {
78  deleteQueue.push_back( controlToDelete );
79  }
80 }
81 
82 static void clearDeleteQueue()
83 {
84  while ( deleteQueue.size() ) {
85  std::vector< EventResponder* >queue( deleteQueue );
86  deleteQueue.clear();
87  for (size_t i = 0; i < queue.size(); i++)
88  delete queue[i];
89  }
90 }
91 
92 //Add a new event responder to the top of the chain.
93 //This responder will get events *first*.
95 {
96  m_responders.push_back( responder );
97 }
98 
99 //Remove an event responder from the chain.
100 void EventManager::removeResponder( EventResponder *responder, //The responder to get rid of.
101  bool top //True = only topmost, False = all.
102  )
103 {
104  bool found; //Whether we found one
105  do {
106  found = false;
107  //Start at the top, so that we only get the top if we only want the top.
108  //Can't use reverse_iterator easily -- erase() needs iterator.
109  for (int i = m_responders.size()-1; i >= 0; i--)
110  if (m_responders[i] == responder) {
111  m_responders.erase( m_responders.begin()+i );
112  found = true;
113  break;
114  }
115  //Do the loop again if we found one and we want all of them.
116  } while (found && !top);
117 //FIXME -- Calling this here causes the loop in processEvent to be b0rked by a deletion. We now must checkForShutdown at a later time...which is below checkForShutDownEventManager(); // FIXME mbyron -- EVENT HACK.
118 }
119 
120 //Send a command through the responder chain.
122 {
123  vector< EventResponder* >::reverse_iterator iter;
124  //Loop through the event chain, starting at the end.
125  for (iter = m_responders.rbegin(); iter != m_responders.rend(); iter++)
126  if ( (*iter)->processCommand( id, control ) )
127  //Somebody handled it!
128  break;
129 }
130 
131 //Send an input event through the responder chain.
133 {
134  //Record the mouse position.
135  //This is used (at least) to render the cursor.
136  switch (event.type)
137  {
138  case MOUSE_DOWN_EVENT:
139  case MOUSE_UP_EVENT:
140  case MOUSE_MOVE_EVENT:
141  case MOUSE_DRAG_EVENT:
142  m_mouseLoc = event.loc;
143  break;
144  default:
145  m_mouseLoc = event.loc;
146  break;
147  }
148  //Loop through the event chain, starting at the end.
149  //WARNING: The functions in this loop can change the responders list.
150  //Iterate through the list carefully!
151  for (size_t i = m_responders.size(); i > 0; i--) {
152  bool result = false;
153  if (i < m_responders.size()+1) {
154  //Check this in case responders get deleted.
155  switch (event.type)
156  {
157  case KEY_DOWN_EVENT:
158  result = m_responders[i-1]->processKeyDown( event );
159  break;
160  case KEY_UP_EVENT:
161  result = m_responders[i-1]->processKeyUp( event );
162  break;
163  case MOUSE_DOWN_EVENT:
164  result = m_responders[i-1]->processMouseDown( event );
165  break;
166  case MOUSE_UP_EVENT:
167  result = m_responders[i-1]->processMouseUp( event );
168  break;
169  case MOUSE_MOVE_EVENT:
170  result = m_responders[i-1]->processMouseMove( event );
171  break;
172  case MOUSE_DRAG_EVENT:
173  result = m_responders[i-1]->processMouseDrag( event );
174  break;
175  default:
176  //Event responder dispatch doesn't handle this type of input event!
177  assert( false );
178  break;
179  }
180  }
181  if (result)
182  //Somebody handled it!
183  break;
184  }
186 }
187 
188 //Constructor isn't public. Use initializeEventManager.
190  m_mouseLoc( 0.0, 0.0 )
191 {
192 }
193 
194 //Destructor.
196 
198 #include "cmd/base.h"
199 #include "gldrv/winsys.h"
200 
201 extern void InitCallbacks( void );
202 
203 //Called to revert to old event management.
205 {
206  if (m_responders.empty() && globalEventManagerPtr != NULL) {
207  //There are no more responders. We assume no more of our windows, and reset mouse callbacks.
208  //If we don't have a global event manager, we already did this.
209  InitCallbacks();
210 
211  //Get rid of global event manager object until we need it again.
212  delete globalEventManagerPtr;
213  globalEventManagerPtr = NULL;
214  }
215 }
216 
217 //Map mouse coord to Vegastrike 2d coord.
218 static float MouseXTo2dX( int x )
219 {
220  //2*(coord+.5)/res + 1.
221  //Puts origin in the middle of the screen, going -1 -> 1 left to right.
222  //Add .5 to put mouse in middle of pixel, rather than left side.
223  //Multiply by 2 first to reduce division error in the multiply.
224  //Do everything in double to minimize calc error and because it's faster.
225  //Result in float to round-off at the end. Gets prettier numbers. :-)
226  return ( 2.0*( (double) x+0.5 ) )/g_game.x_resolution-1.0;
227 }
228 
229 static float MouseYTo2dY( int y )
230 {
231  //See explanation of x.
232  //This is a bit different from x because the mouse coords increase top-
233  //to-bottom, and the drawing surface y increases bottom-to-top.
234  //So we need to reflect the mouse coords around the y origin.
235  return 1.0-( 2.0*( (double) y+0.5 ) )/g_game.y_resolution;
236 }
237 
238 void EventManager::ProcessMouseClick( int button, int state, int x, int y )
239 {
240  ModifyMouseSensitivity( x, y );
241  //Make sure we are working with the same "button" constants.
242  assert( LEFT_MOUSE_BUTTON == WS_LEFT_BUTTON );
243  assert( RIGHT_MOUSE_BUTTON == WS_RIGHT_BUTTON );
245  assert( WHEELUP_MOUSE_BUTTON == WS_WHEEL_UP );
247  if (state == WS_MOUSE_DOWN) {
248  InputEvent event( MOUSE_DOWN_EVENT, button, 0, Point( MouseXTo2dX( x ), MouseYTo2dY( y ) ) );
249  globalEventManager().sendInputEvent( (event) );
250  } else {
251  InputEvent event( MOUSE_UP_EVENT, button, 0, Point( MouseXTo2dX( x ), MouseYTo2dY( y ) ) );
252  globalEventManager().sendInputEvent( (event) );
253  }
255 }
256 
258 {
259  ModifyMouseSensitivity( x, y );
260  //FIXME mbyron -- Should provide info about which buttons are down.
261  InputEvent event( MOUSE_DRAG_EVENT, 0, 0, Point( MouseXTo2dX( x ), MouseYTo2dY( y ) ) );
262  globalEventManager().sendInputEvent( (event) );
264 }
265 
267 {
268  ModifyMouseSensitivity( x, y );
269  InputEvent event( MOUSE_MOVE_EVENT, 0, 0, Point( MouseXTo2dX( x ), MouseYTo2dY( y ) ) );
270  globalEventManager().sendInputEvent( (event) );
272 }
273 
274 //Called to grab event management from old system.
276 {
280 }
281