47
45
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
48
PopUpDialog::PopUpDialog(PopUpWidget* boss, int clickX, int clickY)
49
: Dialog(boss->instance(), boss->parent(), 0, 0, 16, 16),
52
// Copy the selection index
53
_selection = _popUpBoss->_selectedItem;
55
// Calculate real popup dimensions
56
_x = _popUpBoss->getAbsX() + _popUpBoss->_labelWidth;
57
_y = _popUpBoss->getAbsY() - _popUpBoss->_selectedItem * _popUpBoss->_fontHeight;
58
_w = _popUpBoss->_w - _popUpBoss->_labelWidth - 10;
62
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
63
void PopUpDialog::drawDialog()
65
// Normally we add widgets and let Dialog::draw() take care of this
66
// logic. But for some reason, this Dialog was written differently
67
// by the ScummVM guys, so I'm not going to mess with it.
70
FrameBuffer& fb = instance()->frameBuffer();
72
// Draw the menu border
73
fb.hLine(_x, _y, _x + _w - 1, kColor);
74
fb.hLine(_x, _y + _h - 1, _x + _w - 1, kShadowColor);
75
fb.vLine(_x, _y, _y + _h - 1, kColor);
76
fb.vLine(_x + _w - 1, _y, _y + _h - 1, kShadowColor);
78
// If necessary, draw dividing line
80
fb.vLine(_x + _w / 2, _y, _y + _h - 2, kColor);
83
int count = _popUpBoss->_entries.size();
84
for(int i = 0; i < count; i++)
85
drawMenuEntry(i, i == _selection);
87
// The last entry may be empty. Fill it with black.
88
if(_twoColumns && (count & 1))
89
fb.fillRect(_x + 1 + _w / 2, _y + 1 + _popUpBoss->_fontHeight * (_entriesPerColumn - 1),
90
_w / 2 - 1, _popUpBoss->_fontHeight, kWidColor);
93
fb.addDirtyRect(_x, _y, _w, _h);
97
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
98
void PopUpDialog::handleMouseDown(int x, int y, int button, int clickCount)
100
// Only make a selection if we're in the dialog area
101
if(x >= 0 && x < _w && y >= 0 && y < _h)
107
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
108
void PopUpDialog::handleMouseWheel(int x, int y, int direction)
112
else if(direction > 0)
116
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
117
void PopUpDialog::handleMouseMoved(int x, int y, int button)
119
// Compute over which item the mouse is...
120
int item = findItem(x, y);
122
if(item >= 0 && _popUpBoss->_entries[item].name.size() == 0)
125
if(item == -1 && !isMouseDown())
128
// ...and update the selection accordingly
132
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
133
void PopUpDialog::handleKeyDown(int ascii, int keycode, int modifiers)
138
Event::Type e = instance()->eventHandler().eventForKey(keycode, kMenuMode);
142
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
143
void PopUpDialog::handleJoyDown(int stick, int button)
146
instance()->eventHandler().eventForJoyButton(stick, button, kMenuMode);
150
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
151
void PopUpDialog::handleJoyAxis(int stick, int axis, int value)
153
if(value != 0) // we don't care about 'axis up' events
156
instance()->eventHandler().eventForJoyAxis(stick, axis, value, kMenuMode);
161
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
162
bool PopUpDialog::handleJoyHat(int stick, int hat, int value)
165
instance()->eventHandler().eventForJoyHat(stick, hat, value, kMenuMode);
170
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
171
void PopUpDialog::handleEvent(Event::Type e)
175
case Event::UISelect:
190
setSelection(_popUpBoss->_entries.size()-1);
192
case Event::UICancel:
200
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
201
void PopUpDialog::drawMenuEntry(int entry, bool hilite)
203
FrameBuffer& fb = instance()->frameBuffer();
205
// Draw one entry of the popup menu, including selection
210
int n = _popUpBoss->_entries.size() / 2;
212
if(_popUpBoss->_entries.size() & 1)
218
y = _y + 1 + _popUpBoss->_fontHeight * (entry - n);
223
y = _y + 1 + _popUpBoss->_fontHeight * entry;
231
y = _y + 1 + _popUpBoss->_fontHeight * entry;
235
string& name = _popUpBoss->_entries[entry].name;
236
fb.fillRect(x, y, w, _popUpBoss->_fontHeight, hilite ? kTextColorHi : kWidColor);
241
fb.hLine(x - 1, y + _popUpBoss->_fontHeight / 2, x + w, kShadowColor);
242
fb.hLine(x, y + 1 + _popUpBoss->_fontHeight / 2, x + w, kColor);
245
fb.drawString(_popUpBoss->font(), name, x + 1, y + 2, w - 2,
246
hilite ? _popUpBoss->_textcolorhi : _popUpBoss->_textcolor);
249
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
250
void PopUpDialog::recalc()
252
// Perform clipping / switch to scrolling mode if we don't fit on the screen
253
const int height = instance()->frameBuffer().baseHeight();
255
_x = _popUpBoss->getAbsX() + _popUpBoss->_labelWidth;
256
_y = _popUpBoss->getAbsY() + _popUpBoss->getHeight();
258
_h = _popUpBoss->_entries.size() * _popUpBoss->_fontHeight + 2;
260
// HACK: For now, we do not do scrolling. Instead, we draw the dialog
261
// in two columns if it's too tall.
264
const int width = instance()->frameBuffer().baseWidth();
267
_entriesPerColumn = _popUpBoss->_entries.size() / 2;
269
if(_popUpBoss->_entries.size() & 1)
272
_h = _entriesPerColumn * _popUpBoss->_fontHeight + 2;
275
// Find width of largest item
276
for(unsigned int i = 0; i < _popUpBoss->_entries.size(); i++)
278
int width = _popUpBoss->_font->getStringWidth(_popUpBoss->_entries[i].name);
289
if(_popUpBoss->_selectedItem >= _entriesPerColumn)
292
_y = _popUpBoss->getAbsY() - (_popUpBoss->_selectedItem - _entriesPerColumn) *
293
_popUpBoss->_fontHeight;
310
else if(_y + _h >= height)
311
_y = height - 1 - _h;
313
// TODO - implement scrolling if we had to move the menu, or if there are too many entries
316
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
317
int PopUpDialog::findItem(int x, int y) const
319
if(x >= 0 && x < _w && y >= 0 && y < _h)
323
unsigned int entry = (y - 2) / _popUpBoss->_fontHeight;
326
entry += _entriesPerColumn;
328
if(entry >= _popUpBoss->_entries.size())
333
return (y - 2) / _popUpBoss->_fontHeight;
339
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
340
void PopUpDialog::setSelection(int item)
342
if(item != _selection)
346
_popUpBoss->_selectedItem = item;
348
setDirty(); _popUpBoss->setDirty(); _popUpBoss->draw();
352
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
353
void PopUpDialog::sendSelection()
356
_popUpBoss->sendCommand(_popUpBoss->_cmd,
357
_popUpBoss->_entries[_selection].tag,
360
// We remove the dialog when the user has selected an item
361
parent()->removeDialog();
364
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
365
void PopUpDialog::cancelSelection()
367
setSelection(_oldSelection);
368
parent()->removeDialog();
371
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
372
bool PopUpDialog::isMouseDown()
374
// TODO - need a way to determine whether any mouse buttons are pressed or not.
375
// Sure, we could just count mouse button up/down events, but that is cumbersome and
376
// error prone. Would be much nicer to add an API to OSystem for this...
381
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
382
void PopUpDialog::moveUp()
386
setSelection(_popUpBoss->_entries.size() - 1);
388
else if(_selection > 0)
390
int item = _selection;
393
} while (item >= 0 && _popUpBoss->_entries[item].name.size() == 0);
399
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
400
void PopUpDialog::moveDown()
402
int lastItem = _popUpBoss->_entries.size() - 1;
408
else if(_selection < lastItem)
410
int item = _selection;
413
} while (item <= lastItem && _popUpBoss->_entries[item].name.size() == 0);
422
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
423
46
PopUpWidget::PopUpWidget(GuiObject* boss, const GUI::Font& font,
424
int x, int y, int w, int h,
47
int x, int y, int w, int h, const StringMap& list,
425
48
const string& label, int labelWidth, int cmd)
426
49
: Widget(boss, font, x, y - 1, w, h + 2),
427
50
CommandSender(boss),
429
_labelWidth(labelWidth),
52
_labelWidth(labelWidth)
432
54
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
433
55
_type = kPopUpWidget;
486
110
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
487
void PopUpWidget::appendEntry(const string& entry, int tag)
492
_entries.push_back(e);
495
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
496
void PopUpWidget::clearEntries()
501
// Reset the height of the popup dialog to be empty
502
myPopUpDialog->setHeight(2);
505
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
506
void PopUpWidget::setSelected(int item)
508
if(item != _selectedItem)
510
if(item >= 0 && item < (int)_entries.size())
511
_selectedItem = item;
517
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
518
void PopUpWidget::setSelectedName(const string& name)
520
for(unsigned int item = 0; item < _entries.size(); ++item)
522
if(_entries[item].name == name)
530
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
531
void PopUpWidget::setSelectedTag(int tag)
533
for(unsigned int item = 0; item < _entries.size(); ++item)
535
if(_entries[item].tag == tag)
543
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
544
void PopUpWidget::setSelectedMax()
546
setSelected(_entries.size() - 1);
111
void PopUpWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
113
// Intercept all events sent through the PromptWidget
114
// They're likely from our ContextMenu, indicating a redraw is required
117
// Pass the cmd on to our parent
118
sendCommand(cmd, data, id);
549
121
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
550
122
void PopUpWidget::drawWidget(bool hilite)
552
124
//cerr << "PopUpWidget::drawWidget\n";
553
FrameBuffer& fb = instance()->frameBuffer();
125
FBSurface& s = dialog().surface();
555
127
int x = _x + _labelWidth;
556
128
int w = _w - _labelWidth;
558
130
// Draw the label, if any
559
131
if (_labelWidth > 0)
560
fb.drawString(_font, _label, _x, _y + myTextY, _labelWidth,
561
isEnabled() ? _textcolor : kColor, kTextAlignRight);
132
s.drawString(_font, _label, _x, _y + myTextY, _labelWidth,
133
isEnabled() ? _textcolor : kColor, kTextAlignRight);
563
135
// Draw a thin frame around us.
564
fb.hLine(x, _y, x + w - 1, kColor);
565
fb.hLine(x, _y +_h-1, x + w - 1, kShadowColor);
566
fb.vLine(x, _y, _y+_h-1, kColor);
567
fb.vLine(x + w - 1, _y, _y +_h - 1, kShadowColor);
136
s.hLine(x, _y, x + w - 1, kColor);
137
s.hLine(x, _y +_h-1, x + w - 1, kShadowColor);
138
s.vLine(x, _y, _y+_h-1, kColor);
139
s.vLine(x + w - 1, _y, _y +_h - 1, kShadowColor);
569
141
// Fill the background
570
fb.fillRect(x + 1, _y + 1, w - 2, _h - 2, kWidColor);
142
s.fillRect(x + 1, _y + 1, w - 2, _h - 2, kWidColor);
572
144
// Draw an arrow pointing down at the right end to signal this is a dropdown/popup
573
fb.drawBitmap(up_down_arrows, x+w - 10, _y + myArrowsY,
574
!isEnabled() ? kColor : hilite ? kTextColorHi : kTextColor);
145
s.drawBitmap(up_down_arrows, x+w - 10, _y + myArrowsY,
146
!isEnabled() ? kColor : hilite ? kTextColorHi : kTextColor);
576
148
// Draw the selected entry, if any
577
if(_selectedItem >= 0)
579
TextAlignment align = (_font->getStringWidth(_entries[_selectedItem].name) > w-6) ?
580
kTextAlignRight : kTextAlignLeft;
581
fb.drawString(_font, _entries[_selectedItem].name, x+2, _y+myTextY, w-6,
582
!isEnabled() ? kColor : kTextColor, align);
149
const string& name = myMenu->getSelectedName();
150
TextAlignment align = (_font->getStringWidth(name) > w-6) ?
151
kTextAlignRight : kTextAlignLeft;
152
s.drawString(_font, name, x+2, _y+myTextY, w-6,
153
!isEnabled() ? kColor : kTextColor, align);