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: Dialog.cxx,v 1.43 2006/03/02 13:10:53 stephena Exp $
18
// Based on code from ScummVM - Scumm Interpreter
19
// Copyright (C) 2002-2004 The ScummVM project
20
//============================================================================
24
#include "OSystem.hxx"
25
#include "FrameBuffer.hxx"
29
#include "TabWidget.hxx"
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?
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),
52
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
55
for(unsigned int i = 0; i < _ourFocusList.size(); ++i)
56
_ourFocusList[i].focusList.clear();
62
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
70
// (Re)-build the focus list to use for the widgets which are currently
72
buildFocusWidgetList(_focusID);
75
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
80
_mouseWidget->handleMouseLeft(0);
85
parent()->removeDialog();
88
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
89
void Dialog::releaseFocus()
93
_focusedWidget->lostFocus();
98
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
99
void Dialog::addFocusWidget(Widget* w)
101
if(_ourFocusList.size() == 0)
105
_ourFocusList.push_back(f);
107
_ourFocusList[0].focusedWidget = w;
108
_ourFocusList[0].focusList.push_back(w);
111
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
112
void Dialog::addToFocusList(WidgetArray& list, int id)
114
id++; // Arrays start at 0, not -1.
116
// Make sure the array is large enough
117
while((int)_ourFocusList.size() <= id)
120
f.focusedWidget = NULL;
121
_ourFocusList.push_back(f);
124
_ourFocusList[id].focusList.push_back(list);
125
if(id == 0 && _ourFocusList.size() > 0)
126
_focusList = _ourFocusList[0].focusList;
128
if(list.size() > 0 && !(list[0]->getFlags() & WIDGET_NODRAW_FOCUS))
129
_ourFocusList[id].focusedWidget = list[0];
132
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
133
void Dialog::setFocus(Widget* w)
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())
139
// Redraw widgets for new focus
140
_focusedWidget = Widget::setFocusForChain(this, getFocusList(), w, 0);
144
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
145
void Dialog::buildFocusWidgetList(int id)
147
// Yes, this is hideously complex. That's the price we pay for
148
// tab navigation ...
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;
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())
164
_focusList.push_back(_ourFocusList[0].focusList);
166
// Append extra focus list
168
_focusList.push_back(_ourFocusList[_focusID].focusList);
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;
182
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
183
void Dialog::redrawFocus()
186
_focusedWidget = Widget::setFocusForChain(this, getFocusList(), _focusedWidget, 0);
189
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
190
bool Dialog::wantsEvents()
192
return _focusedWidget && _focusedWidget->wantsEvents();
195
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
200
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
201
void Dialog::drawDialog()
208
// cerr << "Dialog::drawDialog()\n";
209
FrameBuffer& fb = instance()->frameBuffer();
211
fb.fillRect(_x+1, _y+1, _w-2, _h-2, kBGColor);
212
fb.box(_x, _y, _w, _h, kColor, kShadowColor);
214
// Make all child widget dirty
215
Widget* w = _firstWidget;
216
Widget::setDirtyInChain(w);
226
// Draw outlines for focused widgets
229
// Tell the framebuffer this area is dirty
230
fb.addDirtyRect(_x, _y, _w, _h);
236
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
237
void Dialog::handleMouseDown(int x, int y, int button, int clickCount)
240
w = findWidget(x, y);
247
w->handleMouseDown(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button, clickCount);
250
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
251
void Dialog::handleMouseUp(int x, int y, int button, int clickCount)
257
// Lose focus on mouseup unless the widget requested to retain the focus
258
if(! (_focusedWidget->getFlags() & WIDGET_RETAIN_FOCUS ))
265
w->handleMouseUp(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button, clickCount);
270
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
271
void Dialog::handleMouseWheel(int x, int y, int direction)
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.
279
w = findWidget(x, y);
283
w->handleMouseWheel(x, y, direction);
286
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
287
void Dialog::handleKeyDown(int ascii, int keycode, int modifiers)
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
294
// Widgets are only cycled if currently focused key hasn't claimed
296
// TODO - figure out workaround for this
297
if(_ourTab && instance()->eventHandler().kbdShift(modifiers))
299
// these key-combos are never passed to the child widget
300
if(ascii == 256 + 20) // left arrow
302
_ourTab->cycleTab(-1);
305
else if(ascii == 256 + 19) // right arrow
307
_ourTab->cycleTab(+1);
312
if(keycode == 9) // tab key
314
if(_focusedWidget && !(_focusedWidget->getFlags() & WIDGET_WANTS_TAB))
316
if(instance()->eventHandler().kbdShift(modifiers))
317
_focusedWidget = Widget::setFocusForChain(this, getFocusList(),
320
_focusedWidget = Widget::setFocusForChain(this, getFocusList(),
322
return; // this key-combo is never passed to the child widget
327
_focusedWidget->handleKeyDown(ascii, keycode, modifiers);
330
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
331
void Dialog::handleKeyUp(int ascii, int keycode, int modifiers)
333
// Focused widget receives keyup events
335
_focusedWidget->handleKeyUp(ascii, keycode, modifiers);
338
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
339
void Dialog::handleMouseMoved(int x, int y, int button)
343
if(_focusedWidget && !_dragWidget)
346
int wx = w->getAbsX() - _x;
347
int wy = w->getAbsY() - _y;
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)
355
_mouseWidget->handleMouseLeft(button);
357
w->handleMouseEntered(button);
359
else if (!mouseInFocusedWidget && _mouseWidget == w)
362
w->handleMouseLeft(button);
365
w->handleMouseMoved(x - wx, y - wy, button);
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.
373
w = findWidget(x, y);
375
if (_mouseWidget != w)
378
_mouseWidget->handleMouseLeft(button);
380
w->handleMouseEntered(button);
384
if (w && (w->getFlags() & WIDGET_TRACK_MOUSE))
385
w->handleMouseMoved(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), button);
388
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
389
void Dialog::handleJoyDown(int stick, int button)
391
// Focused widget receives joystick events
393
_focusedWidget->handleJoyDown(stick, button);
396
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
397
void Dialog::handleJoyUp(int stick, int button)
399
// Focused widget receives joystick events
401
_focusedWidget->handleJoyUp(stick, button);
404
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
405
void Dialog::handleJoyAxis(int stick, int axis, int value)
407
// Focused widget receives joystick events
409
_focusedWidget->handleJoyAxis(stick, axis, value);
412
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
413
bool Dialog::handleJoyHat(int stick, int hat, int value)
415
// Focused widget receives joystick events
416
return (_focusedWidget && _focusedWidget->handleJoyHat(stick, hat, value));
419
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
420
void Dialog::handleCommand(CommandSender* sender, int cmd, int data, int id)
425
// Add this focus list for the given tab to the global focus list
426
buildFocusWidgetList(++data);
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.
439
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
440
Widget* Dialog::findWidget(int x, int y)
442
return Widget::findWidgetInChain(_firstWidget, x, y);
445
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
446
ButtonWidget* Dialog::addButton(const GUI::Font& font, int x, int y,
447
const string& label, int cmd, char hotkey)
450
const int w = 6 * font.getMaxCharWidth(),
451
h = font.getFontHeight() + 6;
453
return new ButtonWidget(this, font, x, y, w, h, label, cmd, hotkey);
455
return new ButtonWidget(this, font, x, y, kButtonWidth, 16, label, cmd, hotkey);