1
//============================================================================
5
// SS tttttt eeee ll ll aaaa
6
// SSSS tt ee ee ll ll aa
7
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8
// SS SS tt ee ll ll aa aa
9
// SSSS ttt eeeee llll llll aaaaa
11
// Copyright (c) 1995-2005 by Bradford W. Mott and the Stella team
13
// See the file "license" for information on usage and redistribution of
14
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16
// $Id: DialogContainer.cxx,v 1.31 2006/03/02 13:10:53 stephena Exp $
17
//============================================================================
19
#include "OSystem.hxx"
22
#include "EventHandler.hxx"
24
#include "DialogContainer.hxx"
26
#define JOY_DEADZONE 3200
28
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
29
DialogContainer::DialogContainer(OSystem* osystem)
35
memset(&ourJoyMouse, 0, sizeof(JoyMouse));
36
ourJoyMouse.delay_time = 25;
38
ourEnableJoyMouseFlag = myOSystem->settings().getBool("joymouse");
42
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
43
DialogContainer::~DialogContainer()
49
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
50
void DialogContainer::updateTime(uInt32 time)
52
// We only need millisecond precision
55
if(myDialogStack.empty())
58
// Check for pending continuous events and send them to the active dialog box
59
Dialog* activeDialog = myDialogStack.top();
61
if(myCurrentKeyDown.keycode != 0 && myKeyRepeatTime < myTime)
63
activeDialog->handleKeyDown(myCurrentKeyDown.ascii, myCurrentKeyDown.keycode,
64
myCurrentKeyDown.flags);
65
myKeyRepeatTime = myTime + kKeyRepeatSustainDelay;
68
if(myCurrentMouseDown.button != -1 && myClickRepeatTime < myTime)
70
activeDialog->handleMouseDown(myCurrentMouseDown.x - activeDialog->_x,
71
myCurrentMouseDown.y - activeDialog->_y,
72
myCurrentMouseDown.button, 1);
73
myClickRepeatTime = myTime + kClickRepeatSustainDelay;
76
if(ourEnableJoyMouseFlag && myCurrentAxisDown.stick != -1 &&
77
myAxisRepeatTime < myTime)
79
// The longer an axis event is enabled, the faster it should change
80
// We do this by decreasing the amount of time between consecutive axis events
81
// After a certain threshold, send 10 events at a time (this is necessary
82
// since at some point, we'd like to process more eventss than the
83
// current framerate allows)
84
myCurrentAxisDown.count++;
85
int interval = myCurrentAxisDown.count / 40 + 1;
86
myAxisRepeatTime = myTime + kAxisRepeatSustainDelay / interval;
89
for(int i = 0; i < 10; ++i)
90
activeDialog->handleJoyAxis(myCurrentAxisDown.stick, myCurrentAxisDown.axis,
91
myCurrentAxisDown.value);
92
myAxisRepeatTime = myTime + kAxisRepeatSustainDelay / 3;
96
activeDialog->handleJoyAxis(myCurrentAxisDown.stick, myCurrentAxisDown.axis,
97
myCurrentAxisDown.value);
98
myAxisRepeatTime = myTime + kAxisRepeatSustainDelay / interval;
102
// Update joy to mouse events
103
if(ourEnableJoyMouseFlag)
104
handleJoyMouse(time);
107
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
108
void DialogContainer::draw()
110
// Draw all the dialogs on the stack when we want a full refresh
113
for(int i = 0; i < myDialogStack.size(); i++)
115
myDialogStack[i]->setDirty();
116
myDialogStack[i]->drawDialog();
118
myRefreshFlag = false;
120
else if(!myDialogStack.empty())
122
myDialogStack.top()->drawDialog();
126
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
127
void DialogContainer::addDialog(Dialog* d)
129
myDialogStack.push(d);
132
d->setDirty(); // Next update() will take care of drawing
135
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
136
void DialogContainer::removeDialog()
138
if(!myDialogStack.empty())
142
// We need to redraw the entire screen contents, since we don't know
144
myOSystem->eventHandler().refreshDisplay();
148
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
149
void DialogContainer::reStack()
151
// Pop all items from the stack, and then add the base menu
152
while(!myDialogStack.empty())
154
addDialog(myBaseDialog);
156
// Erase any previous messages
157
myOSystem->frameBuffer().hideMessage();
159
// Reset all continuous events
163
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
164
void DialogContainer::handleKeyEvent(int unicode, int key, int mod, uInt8 state)
166
if(myDialogStack.empty())
169
// Send the event to the dialog box on the top of the stack
170
Dialog* activeDialog = myDialogStack.top();
173
myCurrentKeyDown.ascii = unicode;
174
myCurrentKeyDown.keycode = key;
175
myCurrentKeyDown.flags = mod;
176
myKeyRepeatTime = myTime + kKeyRepeatInitialDelay;
178
activeDialog->handleKeyDown(unicode, key, mod);
182
activeDialog->handleKeyUp(unicode, key, mod);
184
// Only stop firing events if it's the current key
185
if (key == myCurrentKeyDown.keycode)
186
myCurrentKeyDown.keycode = 0;
190
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
191
void DialogContainer::handleMouseMotionEvent(int x, int y, int button)
193
if(myDialogStack.empty())
196
// Send the event to the dialog box on the top of the stack
197
Dialog* activeDialog = myDialogStack.top();
198
activeDialog->handleMouseMoved(x - activeDialog->_x,
199
y - activeDialog->_y,
202
// Turn off continuous click events as soon as the mouse moves
203
myCurrentMouseDown.button = -1;
206
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
207
void DialogContainer::handleMouseButtonEvent(MouseButton b, int x, int y, uInt8 state)
209
if(myDialogStack.empty())
212
// Send the event to the dialog box on the top of the stack
213
Dialog* activeDialog = myDialogStack.top();
215
int button = (b == EVENT_LBUTTONDOWN || b == EVENT_LBUTTONUP) ? 1 : 2;
218
case EVENT_LBUTTONDOWN:
219
case EVENT_RBUTTONDOWN:
220
// If more than two clicks have been recorded, we start over
221
if(myLastClick.count == 2)
223
myLastClick.x = myLastClick.y = 0;
224
myLastClick.time = 0;
225
myLastClick.count = 0;
228
if(myLastClick.count && (myTime < myLastClick.time + kDoubleClickDelay)
229
&& ABS(myLastClick.x - x) < 3
230
&& ABS(myLastClick.y - y) < 3)
238
myLastClick.count = 1;
240
myLastClick.time = myTime;
242
// Now account for repeated mouse events (click and hold)
243
myCurrentMouseDown.x = x;
244
myCurrentMouseDown.y = y;
245
myCurrentMouseDown.button = button;
246
myClickRepeatTime = myTime + kClickRepeatInitialDelay;
248
activeDialog->handleMouseDown(x - activeDialog->_x, y - activeDialog->_y,
249
button, myLastClick.count);
252
case EVENT_LBUTTONUP:
253
case EVENT_RBUTTONUP:
254
activeDialog->handleMouseUp(x - activeDialog->_x, y - activeDialog->_y,
255
button, myLastClick.count);
257
if(button == myCurrentMouseDown.button)
258
myCurrentMouseDown.button = -1;
262
activeDialog->handleMouseWheel(x - activeDialog->_x, y - activeDialog->_y, -1);
265
case EVENT_WHEELDOWN:
266
activeDialog->handleMouseWheel(x - activeDialog->_x, y - activeDialog->_y, 1);
271
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
272
void DialogContainer::handleJoyEvent(int stick, int button, uInt8 state)
274
if(myDialogStack.empty())
277
// Send the event to the dialog box on the top of the stack
278
Dialog* activeDialog = myDialogStack.top();
280
if(activeDialog->wantsEvents())
283
activeDialog->handleJoyDown(stick, button);
285
activeDialog->handleJoyUp(stick, button);
287
else if(ourEnableJoyMouseFlag)
288
myOSystem->eventHandler().createMouseButtonEvent(
289
ourJoyMouse.x, ourJoyMouse.y, state);
292
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
293
void DialogContainer::handleJoyAxisEvent(int stick, int axis, int value)
295
if(myDialogStack.empty())
298
// Send the event to the dialog box on the top of the stack
299
Dialog* activeDialog = myDialogStack.top();
301
if(value > JOY_DEADZONE)
302
value -= JOY_DEADZONE;
303
else if(value < -JOY_DEADZONE )
304
value += JOY_DEADZONE;
308
if(activeDialog->wantsEvents())
310
// Only stop firing events if it's the current key
311
if(myCurrentAxisDown.stick == stick && value == 0)
313
myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1;
314
myCurrentAxisDown.count = 0;
318
// Now account for repeated axis events (press and hold)
319
myCurrentAxisDown.stick = stick;
320
myCurrentAxisDown.axis = axis;
321
myCurrentAxisDown.value = value;
322
myAxisRepeatTime = myTime + kAxisRepeatInitialDelay;
324
activeDialog->handleJoyAxis(stick, axis, value);
328
if(axis % 2 == 0) // x-direction
332
ourJoyMouse.x_vel = (value > 0) ? 1 : -1;
333
ourJoyMouse.x_down_count = 1;
337
ourJoyMouse.x_vel = 0;
338
ourJoyMouse.x_down_count = 0;
347
ourJoyMouse.y_vel = (-value > 0) ? 1 : -1;
348
ourJoyMouse.y_down_count = 1;
352
ourJoyMouse.y_vel = 0;
353
ourJoyMouse.y_down_count = 0;
356
myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1;
357
myCurrentAxisDown.count = 0;
361
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
362
void DialogContainer::handleJoyHatEvent(int stick, int hat, int value)
364
if(myDialogStack.empty())
367
// Send the event to the dialog box on the top of the stack
368
Dialog* activeDialog = myDialogStack.top();
370
if(!(activeDialog->wantsEvents() &&
371
activeDialog->handleJoyHat(stick, hat, value)))
377
handleJoyAxisEvent(stick, 0, 0);
378
handleJoyAxisEvent(stick, 1, 0); // axis 0 & 1, 0 ==> OFF
381
handleJoyAxisEvent(stick, 1, -32767); // axis 1, -value ==> UP
384
handleJoyAxisEvent(stick, 0, -32767); // axis 0, -value ==> LEFT
387
handleJoyAxisEvent(stick, 1, 32767); // axis 1, +value ==> DOWN
390
handleJoyAxisEvent(stick, 0, 32767); // axis 0, +value ==> RIGHT
400
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
401
void DialogContainer::handleJoyMouse(uInt32 time)
403
bool mouseAccel = true;//false; // TODO - make this a commandline option
404
int oldX = ourJoyMouse.x, oldY = ourJoyMouse.y;
406
if(time >= ourJoyMouse.last_time + ourJoyMouse.delay_time)
408
ourJoyMouse.last_time = time;
409
if(ourJoyMouse.x_down_count == 1)
411
ourJoyMouse.x_down_time = time;
412
ourJoyMouse.x_down_count = 2;
414
if(ourJoyMouse.y_down_count == 1)
416
ourJoyMouse.y_down_time = time;
417
ourJoyMouse.y_down_count = 2;
420
if(ourJoyMouse.x_vel || ourJoyMouse.y_vel)
422
if(ourJoyMouse.x_down_count)
424
if(mouseAccel && time > ourJoyMouse.x_down_time + ourJoyMouse.delay_time * 12)
426
if(ourJoyMouse.x_vel > 0)
431
else if(time > ourJoyMouse.x_down_time + ourJoyMouse.delay_time * 8)
433
if(ourJoyMouse.x_vel > 0)
434
ourJoyMouse.x_vel = ourJoyMouse.amt;
436
ourJoyMouse.x_vel = -ourJoyMouse.amt;
439
if(ourJoyMouse.y_down_count)
441
if(mouseAccel && time > ourJoyMouse.y_down_time + ourJoyMouse.delay_time * 12)
443
if(ourJoyMouse.y_vel > 0)
448
else if(time > ourJoyMouse.y_down_time + ourJoyMouse.delay_time * 8)
450
if(ourJoyMouse.y_vel > 0)
451
ourJoyMouse.y_vel = ourJoyMouse.amt;
453
ourJoyMouse.y_vel = -ourJoyMouse.amt;
457
ourJoyMouse.x += ourJoyMouse.x_vel;
458
ourJoyMouse.y += ourJoyMouse.y_vel;
460
if(ourJoyMouse.x < 0)
463
ourJoyMouse.x_vel = -1;
464
ourJoyMouse.x_down_count = 1;
466
else if(ourJoyMouse.x > ourJoyMouse.x_max)
468
ourJoyMouse.x = ourJoyMouse.x_max;
469
ourJoyMouse.x_vel = 1;
470
ourJoyMouse.x_down_count = 1;
473
if(ourJoyMouse.y < 0)
476
ourJoyMouse.y_vel = -1;
477
ourJoyMouse.y_down_count = 1;
479
else if(ourJoyMouse.y > ourJoyMouse.y_max)
481
ourJoyMouse.y = ourJoyMouse.y_max;
482
ourJoyMouse.y_vel = 1;
483
ourJoyMouse.y_down_count = 1;
486
if(oldX != ourJoyMouse.x || oldY != ourJoyMouse.y)
487
myOSystem->eventHandler().createMouseMotionEvent(ourJoyMouse.x, ourJoyMouse.y);
492
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
493
void DialogContainer::reset()
495
myCurrentKeyDown.keycode = 0;
496
myCurrentMouseDown.button = -1;
497
myLastClick.x = myLastClick.y = 0;
498
myLastClick.time = 0;
499
myLastClick.count = 0;
501
myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1;
502
myCurrentAxisDown.count = 0;
504
int oldX = ourJoyMouse.x, oldY = ourJoyMouse.y;
505
if(ourJoyMouse.x > ourJoyMouse.x_max)
506
ourJoyMouse.x = ourJoyMouse.x_max;
507
if(ourJoyMouse.y > ourJoyMouse.y_max)
508
ourJoyMouse.y = ourJoyMouse.y_max;
510
if(oldX != ourJoyMouse.x || oldY != ourJoyMouse.y)
511
myOSystem->eventHandler().createMouseMotionEvent(ourJoyMouse.x, ourJoyMouse.y);
514
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
515
bool DialogContainer::ourEnableJoyMouseFlag;
517
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
518
JoyMouse DialogContainer::ourJoyMouse;