~ubuntu-branches/debian/squeeze/stella/squeeze

« back to all changes in this revision

Viewing changes to src/gui/DialogContainer.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Mario Iseli
  • Date: 2006-04-08 18:38:25 UTC
  • mfrom: (1.1.2 upstream) (2.1.1 etch)
  • Revision ID: james.westby@ubuntu.com-20060408183825-vu1jk57rk929derx
* New Maintainer (Closes: #361345)
* New upstream release (Closes: #349725)
* Build-Depend now on libslang2-dev (Closes: #325577)
* Complete rebuild of debian/, upgraded to policy-standards
  3.6.2 and compat-level 5.
* Removed stellarc since stella only reads ~/.stellarc and even
  works without a first config.
* New debian/watch file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//============================================================================
 
2
//
 
3
//   SSSS    tt          lll  lll       
 
4
//  SS  SS   tt           ll   ll        
 
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
 
10
//
 
11
// Copyright (c) 1995-2005 by Bradford W. Mott and the Stella team
 
12
//
 
13
// See the file "license" for information on usage and redistribution of
 
14
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
 
15
//
 
16
// $Id: DialogContainer.cxx,v 1.31 2006/03/02 13:10:53 stephena Exp $
 
17
//============================================================================
 
18
 
 
19
#include "OSystem.hxx"
 
20
#include "Dialog.hxx"
 
21
#include "Stack.hxx"
 
22
#include "EventHandler.hxx"
 
23
#include "bspf.hxx"
 
24
#include "DialogContainer.hxx"
 
25
 
 
26
#define JOY_DEADZONE 3200
 
27
 
 
28
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
29
DialogContainer::DialogContainer(OSystem* osystem)
 
30
  : myOSystem(osystem),
 
31
    myBaseDialog(NULL),
 
32
    myTime(0),
 
33
    myRefreshFlag(false)
 
34
{
 
35
  memset(&ourJoyMouse, 0, sizeof(JoyMouse));
 
36
  ourJoyMouse.delay_time = 25;
 
37
 
 
38
  ourEnableJoyMouseFlag = myOSystem->settings().getBool("joymouse");
 
39
  reset();
 
40
}
 
41
 
 
42
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
43
DialogContainer::~DialogContainer()
 
44
{
 
45
  if(myBaseDialog)
 
46
    delete myBaseDialog;
 
47
}
 
48
 
 
49
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
50
void DialogContainer::updateTime(uInt32 time)
 
51
{
 
52
  // We only need millisecond precision
 
53
  myTime = time / 1000;
 
54
 
 
55
  if(myDialogStack.empty())
 
56
    return;
 
57
 
 
58
  // Check for pending continuous events and send them to the active dialog box
 
59
  Dialog* activeDialog = myDialogStack.top();
 
60
 
 
61
  if(myCurrentKeyDown.keycode != 0 && myKeyRepeatTime < myTime)
 
62
  {
 
63
    activeDialog->handleKeyDown(myCurrentKeyDown.ascii, myCurrentKeyDown.keycode,
 
64
                                myCurrentKeyDown.flags);
 
65
    myKeyRepeatTime = myTime + kKeyRepeatSustainDelay;
 
66
  }
 
67
 
 
68
  if(myCurrentMouseDown.button != -1 && myClickRepeatTime < myTime)
 
69
  {
 
70
    activeDialog->handleMouseDown(myCurrentMouseDown.x - activeDialog->_x,
 
71
                                  myCurrentMouseDown.y - activeDialog->_y,
 
72
                                  myCurrentMouseDown.button, 1);
 
73
    myClickRepeatTime = myTime + kClickRepeatSustainDelay;
 
74
  }
 
75
 
 
76
  if(ourEnableJoyMouseFlag && myCurrentAxisDown.stick != -1 &&
 
77
     myAxisRepeatTime < myTime)
 
78
  {
 
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;
 
87
    if(interval > 3)
 
88
    {
 
89
      for(int i = 0; i < 10; ++i)
 
90
        activeDialog->handleJoyAxis(myCurrentAxisDown.stick, myCurrentAxisDown.axis,
 
91
                                    myCurrentAxisDown.value);
 
92
      myAxisRepeatTime = myTime + kAxisRepeatSustainDelay / 3;
 
93
    }
 
94
    else
 
95
    {
 
96
      activeDialog->handleJoyAxis(myCurrentAxisDown.stick, myCurrentAxisDown.axis,
 
97
                                  myCurrentAxisDown.value);
 
98
      myAxisRepeatTime = myTime + kAxisRepeatSustainDelay / interval;
 
99
    }
 
100
  }
 
101
 
 
102
  // Update joy to mouse events
 
103
  if(ourEnableJoyMouseFlag)
 
104
    handleJoyMouse(time);
 
105
}
 
106
 
 
107
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
108
void DialogContainer::draw()
 
109
{
 
110
  // Draw all the dialogs on the stack when we want a full refresh
 
111
  if(myRefreshFlag)
 
112
  {
 
113
    for(int i = 0; i < myDialogStack.size(); i++)
 
114
    {
 
115
      myDialogStack[i]->setDirty();
 
116
      myDialogStack[i]->drawDialog();
 
117
    }
 
118
    myRefreshFlag = false;
 
119
  }
 
120
  else if(!myDialogStack.empty())
 
121
  {
 
122
    myDialogStack.top()->drawDialog();
 
123
  }
 
124
}
 
125
 
 
126
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
127
void DialogContainer::addDialog(Dialog* d)
 
128
{
 
129
  myDialogStack.push(d);
 
130
 
 
131
  d->open();
 
132
  d->setDirty();  // Next update() will take care of drawing
 
133
}
 
134
 
 
135
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
136
void DialogContainer::removeDialog()
 
137
{
 
138
  if(!myDialogStack.empty())
 
139
  {
 
140
    myDialogStack.pop();
 
141
 
 
142
    // We need to redraw the entire screen contents, since we don't know
 
143
    // what was obscured
 
144
    myOSystem->eventHandler().refreshDisplay();
 
145
  }
 
146
}
 
147
 
 
148
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
149
void DialogContainer::reStack()
 
150
{
 
151
  // Pop all items from the stack, and then add the base menu
 
152
  while(!myDialogStack.empty())
 
153
    myDialogStack.pop();
 
154
  addDialog(myBaseDialog);
 
155
 
 
156
  // Erase any previous messages
 
157
  myOSystem->frameBuffer().hideMessage();
 
158
 
 
159
  // Reset all continuous events
 
160
  reset();
 
161
}
 
162
 
 
163
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
164
void DialogContainer::handleKeyEvent(int unicode, int key, int mod, uInt8 state)
 
165
{
 
166
  if(myDialogStack.empty())
 
167
    return;
 
168
 
 
169
  // Send the event to the dialog box on the top of the stack
 
170
  Dialog* activeDialog = myDialogStack.top();
 
171
  if(state == 1)
 
172
  {
 
173
    myCurrentKeyDown.ascii   = unicode;
 
174
    myCurrentKeyDown.keycode = key;
 
175
    myCurrentKeyDown.flags   = mod;
 
176
    myKeyRepeatTime = myTime + kKeyRepeatInitialDelay;
 
177
 
 
178
    activeDialog->handleKeyDown(unicode, key, mod);
 
179
  }
 
180
  else
 
181
  {
 
182
    activeDialog->handleKeyUp(unicode, key, mod);
 
183
 
 
184
    // Only stop firing events if it's the current key
 
185
    if (key == myCurrentKeyDown.keycode)
 
186
      myCurrentKeyDown.keycode = 0;
 
187
  }
 
188
}
 
189
 
 
190
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
191
void DialogContainer::handleMouseMotionEvent(int x, int y, int button)
 
192
{
 
193
  if(myDialogStack.empty())
 
194
    return;
 
195
 
 
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,
 
200
                                 button);
 
201
 
 
202
  // Turn off continuous click events as soon as the mouse moves
 
203
  myCurrentMouseDown.button = -1;
 
204
}
 
205
 
 
206
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
207
void DialogContainer::handleMouseButtonEvent(MouseButton b, int x, int y, uInt8 state)
 
208
{
 
209
  if(myDialogStack.empty())
 
210
    return;
 
211
 
 
212
  // Send the event to the dialog box on the top of the stack
 
213
  Dialog* activeDialog = myDialogStack.top();
 
214
 
 
215
  int button = (b == EVENT_LBUTTONDOWN || b == EVENT_LBUTTONUP) ? 1 : 2;
 
216
  switch(b)
 
217
  {
 
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)
 
222
      {
 
223
        myLastClick.x = myLastClick.y = 0;
 
224
        myLastClick.time = 0;
 
225
        myLastClick.count = 0;
 
226
      }
 
227
 
 
228
      if(myLastClick.count && (myTime < myLastClick.time + kDoubleClickDelay)
 
229
         && ABS(myLastClick.x - x) < 3
 
230
         && ABS(myLastClick.y - y) < 3)
 
231
      {
 
232
        myLastClick.count++;
 
233
      }
 
234
      else
 
235
      {
 
236
        myLastClick.x = x;
 
237
        myLastClick.y = y;
 
238
        myLastClick.count = 1;
 
239
      }
 
240
      myLastClick.time = myTime;
 
241
 
 
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;
 
247
 
 
248
      activeDialog->handleMouseDown(x - activeDialog->_x, y - activeDialog->_y,
 
249
                                    button, myLastClick.count);
 
250
      break;
 
251
 
 
252
    case EVENT_LBUTTONUP:
 
253
    case EVENT_RBUTTONUP:
 
254
      activeDialog->handleMouseUp(x - activeDialog->_x, y - activeDialog->_y,
 
255
                                  button, myLastClick.count);
 
256
 
 
257
      if(button == myCurrentMouseDown.button)
 
258
        myCurrentMouseDown.button = -1;
 
259
      break;
 
260
 
 
261
    case EVENT_WHEELUP:
 
262
      activeDialog->handleMouseWheel(x - activeDialog->_x, y - activeDialog->_y, -1);
 
263
      break;
 
264
 
 
265
    case EVENT_WHEELDOWN:
 
266
      activeDialog->handleMouseWheel(x - activeDialog->_x, y - activeDialog->_y, 1);
 
267
      break;
 
268
  }
 
269
}
 
270
 
 
271
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
272
void DialogContainer::handleJoyEvent(int stick, int button, uInt8 state)
 
273
{
 
274
  if(myDialogStack.empty())
 
275
    return;
 
276
 
 
277
  // Send the event to the dialog box on the top of the stack
 
278
  Dialog* activeDialog = myDialogStack.top();
 
279
 
 
280
  if(activeDialog->wantsEvents())
 
281
  {
 
282
    if(state == 1)
 
283
      activeDialog->handleJoyDown(stick, button);
 
284
    else
 
285
      activeDialog->handleJoyUp(stick, button);
 
286
  }
 
287
  else if(ourEnableJoyMouseFlag)
 
288
    myOSystem->eventHandler().createMouseButtonEvent(
 
289
      ourJoyMouse.x, ourJoyMouse.y, state);
 
290
}
 
291
 
 
292
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
293
void DialogContainer::handleJoyAxisEvent(int stick, int axis, int value)
 
294
{
 
295
  if(myDialogStack.empty())
 
296
    return;
 
297
 
 
298
  // Send the event to the dialog box on the top of the stack
 
299
  Dialog* activeDialog = myDialogStack.top();
 
300
 
 
301
  if(value > JOY_DEADZONE)
 
302
    value -= JOY_DEADZONE;
 
303
  else if(value < -JOY_DEADZONE )
 
304
    value += JOY_DEADZONE;
 
305
  else
 
306
    value = 0;
 
307
 
 
308
  if(activeDialog->wantsEvents())
 
309
  {
 
310
    // Only stop firing events if it's the current key
 
311
    if(myCurrentAxisDown.stick == stick && value == 0)
 
312
    {
 
313
      myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1;
 
314
      myCurrentAxisDown.count = 0;
 
315
    }
 
316
    else
 
317
    {
 
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;
 
323
    }
 
324
    activeDialog->handleJoyAxis(stick, axis, value);
 
325
  }
 
326
  else
 
327
  {
 
328
    if(axis % 2 == 0)  // x-direction
 
329
    {
 
330
      if(value != 0)
 
331
      {
 
332
        ourJoyMouse.x_vel = (value > 0) ? 1 : -1;
 
333
        ourJoyMouse.x_down_count = 1;
 
334
      }
 
335
      else
 
336
      {
 
337
        ourJoyMouse.x_vel = 0;
 
338
        ourJoyMouse.x_down_count = 0;
 
339
      }
 
340
    }
 
341
    else   // y-direction
 
342
    {
 
343
      value = -value;
 
344
 
 
345
      if(value != 0)
 
346
      {
 
347
        ourJoyMouse.y_vel = (-value > 0) ? 1 : -1;
 
348
        ourJoyMouse.y_down_count = 1;
 
349
      }
 
350
      else
 
351
      {
 
352
        ourJoyMouse.y_vel = 0;
 
353
        ourJoyMouse.y_down_count = 0;
 
354
      }
 
355
    }
 
356
    myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1;
 
357
    myCurrentAxisDown.count = 0;
 
358
  }
 
359
}
 
360
 
 
361
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
362
void DialogContainer::handleJoyHatEvent(int stick, int hat, int value)
 
363
{
 
364
  if(myDialogStack.empty())
 
365
    return;
 
366
 
 
367
  // Send the event to the dialog box on the top of the stack
 
368
  Dialog* activeDialog = myDialogStack.top();
 
369
 
 
370
  if(!(activeDialog->wantsEvents() &&
 
371
       activeDialog->handleJoyHat(stick, hat, value)))
 
372
  {
 
373
    bool handled = true;
 
374
    switch(value)
 
375
    {
 
376
      case kJHatCentered:
 
377
        handleJoyAxisEvent(stick, 0, 0);
 
378
        handleJoyAxisEvent(stick, 1, 0);       // axis 0 & 1, 0  ==> OFF
 
379
        break;
 
380
      case kJHatUp:
 
381
        handleJoyAxisEvent(stick, 1, -32767);  // axis 1, -value ==> UP
 
382
        break;
 
383
      case kJHatLeft:
 
384
        handleJoyAxisEvent(stick, 0, -32767);  // axis 0, -value ==> LEFT
 
385
        break;
 
386
      case kJHatDown:
 
387
        handleJoyAxisEvent(stick, 1, 32767);   // axis 1, +value ==> DOWN
 
388
        break;
 
389
      case kJHatRight:
 
390
        handleJoyAxisEvent(stick, 0, 32767);   // axis 0, +value ==> RIGHT
 
391
        break;
 
392
      default:
 
393
        handled = false;
 
394
    }
 
395
    if(handled)
 
396
      return;
 
397
  }
 
398
}
 
399
 
 
400
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
401
void DialogContainer::handleJoyMouse(uInt32 time)
 
402
{
 
403
  bool mouseAccel = true;//false;  // TODO - make this a commandline option
 
404
  int oldX = ourJoyMouse.x, oldY = ourJoyMouse.y;
 
405
 
 
406
  if(time >= ourJoyMouse.last_time + ourJoyMouse.delay_time)
 
407
  {
 
408
    ourJoyMouse.last_time = time;
 
409
    if(ourJoyMouse.x_down_count == 1)
 
410
    {
 
411
      ourJoyMouse.x_down_time = time;
 
412
      ourJoyMouse.x_down_count = 2;
 
413
    }
 
414
    if(ourJoyMouse.y_down_count == 1)
 
415
    {
 
416
      ourJoyMouse.y_down_time = time;
 
417
      ourJoyMouse.y_down_count = 2;
 
418
    }
 
419
 
 
420
    if(ourJoyMouse.x_vel || ourJoyMouse.y_vel)
 
421
    {
 
422
      if(ourJoyMouse.x_down_count)
 
423
      {
 
424
        if(mouseAccel && time > ourJoyMouse.x_down_time + ourJoyMouse.delay_time * 12)
 
425
        {
 
426
          if(ourJoyMouse.x_vel > 0)
 
427
            ourJoyMouse.x_vel++;
 
428
          else
 
429
            ourJoyMouse.x_vel--;
 
430
        }
 
431
        else if(time > ourJoyMouse.x_down_time + ourJoyMouse.delay_time * 8)
 
432
        {
 
433
          if(ourJoyMouse.x_vel > 0)
 
434
            ourJoyMouse.x_vel = ourJoyMouse.amt;
 
435
          else
 
436
            ourJoyMouse.x_vel = -ourJoyMouse.amt;
 
437
        }
 
438
      }
 
439
      if(ourJoyMouse.y_down_count)
 
440
      {
 
441
        if(mouseAccel && time > ourJoyMouse.y_down_time + ourJoyMouse.delay_time * 12)
 
442
        {
 
443
          if(ourJoyMouse.y_vel > 0)
 
444
            ourJoyMouse.y_vel++;
 
445
          else
 
446
            ourJoyMouse.y_vel--;
 
447
        }
 
448
        else if(time > ourJoyMouse.y_down_time + ourJoyMouse.delay_time * 8)
 
449
        {
 
450
          if(ourJoyMouse.y_vel > 0)
 
451
            ourJoyMouse.y_vel = ourJoyMouse.amt;
 
452
          else
 
453
            ourJoyMouse.y_vel = -ourJoyMouse.amt;
 
454
        }
 
455
      }
 
456
 
 
457
      ourJoyMouse.x += ourJoyMouse.x_vel;
 
458
      ourJoyMouse.y += ourJoyMouse.y_vel;
 
459
 
 
460
      if(ourJoyMouse.x < 0)
 
461
      {
 
462
        ourJoyMouse.x = 0;
 
463
        ourJoyMouse.x_vel = -1;
 
464
        ourJoyMouse.x_down_count = 1;
 
465
      }
 
466
      else if(ourJoyMouse.x > ourJoyMouse.x_max)
 
467
      {
 
468
        ourJoyMouse.x = ourJoyMouse.x_max;
 
469
        ourJoyMouse.x_vel = 1;
 
470
        ourJoyMouse.x_down_count = 1;
 
471
      }
 
472
 
 
473
      if(ourJoyMouse.y < 0)
 
474
      {
 
475
        ourJoyMouse.y = 0;
 
476
        ourJoyMouse.y_vel = -1;
 
477
        ourJoyMouse.y_down_count = 1;
 
478
      }
 
479
      else if(ourJoyMouse.y > ourJoyMouse.y_max)
 
480
      {
 
481
        ourJoyMouse.y = ourJoyMouse.y_max;
 
482
        ourJoyMouse.y_vel = 1;
 
483
        ourJoyMouse.y_down_count = 1;
 
484
      }
 
485
 
 
486
      if(oldX != ourJoyMouse.x || oldY != ourJoyMouse.y)
 
487
        myOSystem->eventHandler().createMouseMotionEvent(ourJoyMouse.x, ourJoyMouse.y);
 
488
    }
 
489
  }
 
490
}
 
491
 
 
492
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
493
void DialogContainer::reset()
 
494
{
 
495
  myCurrentKeyDown.keycode = 0;
 
496
  myCurrentMouseDown.button = -1;
 
497
  myLastClick.x = myLastClick.y = 0;
 
498
  myLastClick.time = 0;
 
499
  myLastClick.count = 0;
 
500
 
 
501
  myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1;
 
502
  myCurrentAxisDown.count = 0;
 
503
 
 
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;
 
509
 
 
510
  if(oldX != ourJoyMouse.x || oldY != ourJoyMouse.y)
 
511
    myOSystem->eventHandler().createMouseMotionEvent(ourJoyMouse.x, ourJoyMouse.y);
 
512
}
 
513
 
 
514
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
515
bool DialogContainer::ourEnableJoyMouseFlag;
 
516
 
 
517
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
518
JoyMouse DialogContainer::ourJoyMouse;