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

« back to all changes in this revision

Viewing changes to src/gui/Dialog.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: Dialog.cxx,v 1.43 2006/03/02 13:10:53 stephena Exp $
 
17
//
 
18
//   Based on code from ScummVM - Scumm Interpreter
 
19
//   Copyright (C) 2002-2004 The ScummVM project
 
20
//============================================================================
 
21
 
 
22
#include <SDL.h>
 
23
 
 
24
#include "OSystem.hxx"
 
25
#include "FrameBuffer.hxx"
 
26
#include "Menu.hxx"
 
27
#include "Dialog.hxx"
 
28
#include "Widget.hxx"
 
29
#include "TabWidget.hxx"
 
30
 
 
31
/*
 
32
 * TODO list
 
33
 * - add some sense of the window being "active" (i.e. in front) or not. If it 
 
34
 *   was inactive and just became active, reset certain vars (like who is focused).
 
35
 *   Maybe we should just add lostFocus and receivedFocus methods to Dialog, just
 
36
 *   like we have for class Widget?
 
37
 * ...
 
38
 */
 
39
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
40
Dialog::Dialog(OSystem* instance, DialogContainer* parent,
 
41
               int x, int y, int w, int h)
 
42
  : GuiObject(instance, parent, x, y, w, h),
 
43
    _mouseWidget(0),
 
44
    _focusedWidget(0),
 
45
    _dragWidget(0),
 
46
    _visible(true),
 
47
    _ourTab(NULL),
 
48
    _focusID(0)
 
49
{
 
50
}
 
51
 
 
52
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
53
Dialog::~Dialog()
 
54
{
 
55
  for(unsigned int i = 0; i < _ourFocusList.size(); ++i)
 
56
    _ourFocusList[i].focusList.clear();
 
57
 
 
58
  delete _firstWidget;
 
59
  _firstWidget = NULL;
 
60
}
 
61
 
 
62
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
63
void Dialog::open()
 
64
{
 
65
  _result = 0;
 
66
  _visible = true;
 
67
 
 
68
  loadConfig();
 
69
 
 
70
  // (Re)-build the focus list to use for the widgets which are currently
 
71
  // onscreen
 
72
  buildFocusWidgetList(_focusID);
 
73
}
 
74
 
 
75
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
76
void Dialog::close()
 
77
{
 
78
  if (_mouseWidget)
 
79
  {
 
80
    _mouseWidget->handleMouseLeft(0);
 
81
    _mouseWidget = 0;
 
82
  }
 
83
 
 
84
  releaseFocus();
 
85
  parent()->removeDialog();
 
86
}
 
87
 
 
88
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
89
void Dialog::releaseFocus()
 
90
{
 
91
  if(_focusedWidget)
 
92
  {
 
93
    _focusedWidget->lostFocus();
 
94
    _focusedWidget = 0;
 
95
  }
 
96
}
 
97
 
 
98
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
99
void Dialog::addFocusWidget(Widget* w)
 
100
{
 
101
  if(_ourFocusList.size() == 0)
 
102
  {
 
103
        Focus f;
 
104
    f.focusedWidget = 0;
 
105
        _ourFocusList.push_back(f);
 
106
  }
 
107
  _ourFocusList[0].focusedWidget = w;
 
108
  _ourFocusList[0].focusList.push_back(w);
 
109
}
 
110
 
 
111
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
112
void Dialog::addToFocusList(WidgetArray& list, int id)
 
113
{
 
114
  id++;  // Arrays start at 0, not -1.
 
115
 
 
116
  // Make sure the array is large enough
 
117
  while((int)_ourFocusList.size() <= id)
 
118
  {
 
119
        Focus f;
 
120
        f.focusedWidget = NULL;
 
121
        _ourFocusList.push_back(f);
 
122
  }
 
123
 
 
124
  _ourFocusList[id].focusList.push_back(list);
 
125
  if(id == 0 && _ourFocusList.size() > 0)
 
126
    _focusList = _ourFocusList[0].focusList;
 
127
 
 
128
  if(list.size() > 0 && !(list[0]->getFlags() & WIDGET_NODRAW_FOCUS))
 
129
    _ourFocusList[id].focusedWidget = list[0];
 
130
}
 
131
 
 
132
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
133
void Dialog::setFocus(Widget* w)
 
134
{
 
135
  // If the click occured inside a widget which is not the currently
 
136
  // focused one, change the focus to that widget.
 
137
  if(w && w != _focusedWidget && w->wantsFocus())
 
138
  {
 
139
    // Redraw widgets for new focus
 
140
    _focusedWidget = Widget::setFocusForChain(this, getFocusList(), w, 0);
 
141
  }
 
142
}
 
143
 
 
144
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
145
void Dialog::buildFocusWidgetList(int id)
 
146
{
 
147
  // Yes, this is hideously complex.  That's the price we pay for
 
148
  // tab navigation ...
 
149
 
 
150
  // Remember which item previously had focus, but only if it belongs
 
151
  // to this focus list
 
152
  if(_focusID < (int)_ourFocusList.size() &&
 
153
     Widget::isWidgetInChain(_ourFocusList[_focusID].focusList, _focusedWidget))
 
154
    _ourFocusList[_focusID].focusedWidget = _focusedWidget;
 
155
 
 
156
  _focusID = id;
 
157
 
 
158
  // Create a focuslist for items currently onscreen
 
159
  // We do this by starting with any dialog focus list (at index 0 in the
 
160
  // focus lists, then appending the list indicated by 'id'.
 
161
  if(_focusID < (int)_ourFocusList.size())
 
162
  {
 
163
    _focusList.clear();
 
164
    _focusList.push_back(_ourFocusList[0].focusList);
 
165
 
 
166
    // Append extra focus list
 
167
    if(_focusID > 0)
 
168
      _focusList.push_back(_ourFocusList[_focusID].focusList);
 
169
 
 
170
    // Only update _focusedWidget if it doesn't belong to the main focus list
 
171
    // HACK - figure out how to properly deal with only one focus-able widget
 
172
    // in a tab -- TabWidget is the spawn of the devil
 
173
    if(_focusList.size() == 1)
 
174
      _focusedWidget = _focusList[0];
 
175
    else if(!Widget::isWidgetInChain(_ourFocusList[0].focusList, _focusedWidget))
 
176
      _focusedWidget = _ourFocusList[_focusID].focusedWidget;
 
177
  }
 
178
  else
 
179
    _focusedWidget = 0;
 
180
}
 
181
 
 
182
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
183
void Dialog::redrawFocus()
 
184
{
 
185
  if(_focusedWidget)
 
186
    _focusedWidget = Widget::setFocusForChain(this, getFocusList(), _focusedWidget, 0);
 
187
}
 
188
 
 
189
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
190
bool Dialog::wantsEvents()
 
191
{
 
192
  return _focusedWidget && _focusedWidget->wantsEvents();
 
193
}
 
194
 
 
195
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
196
void Dialog::draw()
 
197
{
 
198
}
 
199
 
 
200
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
201
void Dialog::drawDialog()
 
202
{
 
203
  if(!isVisible())
 
204
    return;
 
205
 
 
206
  if(_dirty)
 
207
  {
 
208
//    cerr << "Dialog::drawDialog()\n";
 
209
    FrameBuffer& fb = instance()->frameBuffer();
 
210
 
 
211
    fb.fillRect(_x+1, _y+1, _w-2, _h-2, kBGColor);
 
212
    fb.box(_x, _y, _w, _h, kColor, kShadowColor);
 
213
 
 
214
    // Make all child widget dirty
 
215
    Widget* w = _firstWidget;
 
216
    Widget::setDirtyInChain(w);
 
217
 
 
218
    // Draw all children
 
219
    w = _firstWidget;
 
220
    while(w)
 
221
    {
 
222
      w->draw();
 
223
      w = w->_next;
 
224
    }
 
225
 
 
226
    // Draw outlines for focused widgets
 
227
    redrawFocus();
 
228
 
 
229
    // Tell the framebuffer this area is dirty
 
230
    fb.addDirtyRect(_x, _y, _w, _h);
 
231
 
 
232
    _dirty = false;
 
233
  }
 
234
}
 
235
 
 
236
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
237
void Dialog::handleMouseDown(int x, int y, int button, int clickCount)
 
238
{
 
239
  Widget* w;
 
240
  w = findWidget(x, y);
 
241
 
 
242
  _dragWidget = w;
 
243
 
 
244
  setFocus(w);
 
245
 
 
246
  if(w)
 
247
    w->handleMouseDown(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button, clickCount);
 
248
}
 
249
 
 
250
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
251
void Dialog::handleMouseUp(int x, int y, int button, int clickCount)
 
252
{
 
253
  Widget* w;
 
254
 
 
255
  if(_focusedWidget)
 
256
  {
 
257
    // Lose focus on mouseup unless the widget requested to retain the focus
 
258
    if(! (_focusedWidget->getFlags() & WIDGET_RETAIN_FOCUS ))
 
259
      releaseFocus();
 
260
  }
 
261
 
 
262
  w = _dragWidget;
 
263
 
 
264
  if(w)
 
265
    w->handleMouseUp(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button, clickCount);
 
266
 
 
267
  _dragWidget = 0;
 
268
}
 
269
 
 
270
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
271
void Dialog::handleMouseWheel(int x, int y, int direction)
 
272
{
 
273
  Widget* w;
 
274
 
 
275
  // This may look a bit backwards, but I think it makes more sense for
 
276
  // the mouse wheel to primarily affect the widget the mouse is at than
 
277
  // the widget that happens to be focused.
 
278
 
 
279
  w = findWidget(x, y);
 
280
  if(!w)
 
281
    w = _focusedWidget;
 
282
  if (w)
 
283
    w->handleMouseWheel(x, y, direction);
 
284
}
 
285
 
 
286
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
287
void Dialog::handleKeyDown(int ascii, int keycode, int modifiers)
 
288
{
 
289
  // Test for TAB character
 
290
  // Shift-left/shift-right cursor selects next tab
 
291
  // Tab sets next widget in current tab
 
292
  // Shift-Tab sets previous widget in current tab
 
293
  //
 
294
  // Widgets are only cycled if currently focused key hasn't claimed
 
295
  // the TAB key
 
296
  // TODO - figure out workaround for this
 
297
  if(_ourTab && instance()->eventHandler().kbdShift(modifiers))
 
298
  {
 
299
    // these key-combos are never passed to the child widget
 
300
    if(ascii == 256 + 20)      // left arrow
 
301
    {
 
302
      _ourTab->cycleTab(-1);
 
303
      return;
 
304
    }
 
305
    else if(ascii == 256 + 19) // right arrow
 
306
    {
 
307
      _ourTab->cycleTab(+1);
 
308
      return;
 
309
    }
 
310
  }
 
311
 
 
312
  if(keycode == 9)  // tab key
 
313
  {
 
314
    if(_focusedWidget && !(_focusedWidget->getFlags() & WIDGET_WANTS_TAB))
 
315
    {
 
316
      if(instance()->eventHandler().kbdShift(modifiers))
 
317
        _focusedWidget = Widget::setFocusForChain(this, getFocusList(),
 
318
                                                  _focusedWidget, -1);
 
319
      else
 
320
        _focusedWidget = Widget::setFocusForChain(this, getFocusList(),
 
321
                                                  _focusedWidget, +1);
 
322
      return;  // this key-combo is never passed to the child widget
 
323
    }
 
324
  }
 
325
 
 
326
  if (_focusedWidget)
 
327
    _focusedWidget->handleKeyDown(ascii, keycode, modifiers);
 
328
}
 
329
 
 
330
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
331
void Dialog::handleKeyUp(int ascii, int keycode, int modifiers)
 
332
{
 
333
  // Focused widget receives keyup events
 
334
  if(_focusedWidget)
 
335
    _focusedWidget->handleKeyUp(ascii, keycode, modifiers);
 
336
}
 
337
 
 
338
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
339
void Dialog::handleMouseMoved(int x, int y, int button)
 
340
{
 
341
  Widget* w;
 
342
        
 
343
  if(_focusedWidget && !_dragWidget)
 
344
  {
 
345
    w = _focusedWidget;
 
346
    int wx = w->getAbsX() - _x;
 
347
    int wy = w->getAbsY() - _y;
 
348
                
 
349
    // We still send mouseEntered/Left messages to the focused item
 
350
    // (but to no other items).
 
351
    bool mouseInFocusedWidget = (x >= wx && x < wx + w->_w && y >= wy && y < wy + w->_h);
 
352
    if(mouseInFocusedWidget && _mouseWidget != w)
 
353
    {
 
354
      if(_mouseWidget)
 
355
        _mouseWidget->handleMouseLeft(button);
 
356
      _mouseWidget = w;
 
357
      w->handleMouseEntered(button);
 
358
    }
 
359
    else if (!mouseInFocusedWidget && _mouseWidget == w)
 
360
    {
 
361
      _mouseWidget = 0;
 
362
      w->handleMouseLeft(button);
 
363
    }
 
364
 
 
365
    w->handleMouseMoved(x - wx, y - wy, button);
 
366
  }
 
367
 
 
368
  // While a "drag" is in process (i.e. mouse is moved while a button is pressed),
 
369
  // only deal with the widget in which the click originated.
 
370
  if (_dragWidget)
 
371
    w = _dragWidget;
 
372
  else
 
373
    w = findWidget(x, y);
 
374
 
 
375
  if (_mouseWidget != w)
 
376
  {
 
377
    if (_mouseWidget)
 
378
      _mouseWidget->handleMouseLeft(button);
 
379
    if (w)
 
380
      w->handleMouseEntered(button);
 
381
    _mouseWidget = w;
 
382
  } 
 
383
 
 
384
  if (w && (w->getFlags() & WIDGET_TRACK_MOUSE))
 
385
    w->handleMouseMoved(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button);
 
386
}
 
387
 
 
388
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
389
void Dialog::handleJoyDown(int stick, int button)
 
390
{
 
391
  // Focused widget receives joystick events
 
392
  if(_focusedWidget)
 
393
    _focusedWidget->handleJoyDown(stick, button);
 
394
}
 
395
 
 
396
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
397
void Dialog::handleJoyUp(int stick, int button)
 
398
{
 
399
  // Focused widget receives joystick events
 
400
  if(_focusedWidget)
 
401
    _focusedWidget->handleJoyUp(stick, button);
 
402
}
 
403
 
 
404
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
405
void Dialog::handleJoyAxis(int stick, int axis, int value)
 
406
{
 
407
  // Focused widget receives joystick events
 
408
  if(_focusedWidget)
 
409
    _focusedWidget->handleJoyAxis(stick, axis, value);
 
410
}
 
411
 
 
412
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
413
bool Dialog::handleJoyHat(int stick, int hat, int value)
 
414
{
 
415
  // Focused widget receives joystick events
 
416
  return (_focusedWidget && _focusedWidget->handleJoyHat(stick, hat, value));
 
417
}
 
418
 
 
419
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
420
void Dialog::handleCommand(CommandSender* sender, int cmd, int data, int id)
 
421
{
 
422
  switch(cmd)
 
423
  {
 
424
    case kTabChangedCmd:
 
425
      // Add this focus list for the given tab to the global focus list
 
426
      buildFocusWidgetList(++data);
 
427
      break;
 
428
 
 
429
    case kCloseCmd:
 
430
      close();
 
431
      break;
 
432
  }
 
433
}
 
434
 
 
435
/*
 
436
 * Determine the widget at location (x,y) if any. Assumes the coordinates are
 
437
 * in the local coordinate system, i.e. relative to the top left of the dialog.
 
438
 */
 
439
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
440
Widget* Dialog::findWidget(int x, int y)
 
441
{
 
442
  return Widget::findWidgetInChain(_firstWidget, x, y);
 
443
}
 
444
 
 
445
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
446
ButtonWidget* Dialog::addButton(const GUI::Font& font, int x, int y,
 
447
                                const string& label, int cmd, char hotkey)
 
448
{
 
449
#if 0
 
450
  const int w = 6 * font.getMaxCharWidth(),
 
451
            h = font.getFontHeight() + 6;
 
452
 
 
453
  return new ButtonWidget(this, font, x, y, w, h, label, cmd, hotkey);
 
454
#else
 
455
  return new ButtonWidget(this, font, x, y, kButtonWidth, 16, label, cmd, hotkey);
 
456
#endif
 
457
}