2002-12-12 12:07:46 +00:00
|
|
|
/* ScummVM - Scumm Interpreter
|
|
|
|
* Copyright (C) 2002 The ScummVM project
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* $Header$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "PopUpWidget.h"
|
|
|
|
#include "dialog.h"
|
|
|
|
#include "newgui.h"
|
2002-12-12 23:31:58 +00:00
|
|
|
#include "common/engine.h"
|
2002-12-12 12:07:46 +00:00
|
|
|
|
|
|
|
/* TODO:
|
|
|
|
* - draw an (unselectable) sepeator line for items that start with a '-'
|
2002-12-12 23:22:48 +00:00
|
|
|
* - handle long lists by allowing scrolling (a lot of work if done right,
|
2002-12-12 12:07:46 +00:00
|
|
|
* so I will probably only implement if we really need it)
|
|
|
|
* - ...
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define UP_DOWN_BOX_HEIGHT 10
|
|
|
|
|
2002-12-12 23:22:48 +00:00
|
|
|
// Little up/down arrow
|
|
|
|
static uint32 up_down_arrows[8] = {
|
2002-12-12 12:07:46 +00:00
|
|
|
0x00000000,
|
2002-12-12 23:22:48 +00:00
|
|
|
0x00001000,
|
2002-12-12 12:07:46 +00:00
|
|
|
0x00011100,
|
2002-12-12 23:22:48 +00:00
|
|
|
0x00111110,
|
|
|
|
0x00000000,
|
|
|
|
0x00111110,
|
2002-12-12 12:07:46 +00:00
|
|
|
0x00011100,
|
|
|
|
0x00001000,
|
|
|
|
};
|
|
|
|
|
|
|
|
const ScummVM::String PopUpWidget::emptyStr;
|
|
|
|
|
2002-12-13 21:35:04 +00:00
|
|
|
//
|
|
|
|
// PopUpDialog
|
|
|
|
//
|
|
|
|
|
2002-12-12 12:07:46 +00:00
|
|
|
class PopUpDialog : public Dialog {
|
|
|
|
protected:
|
|
|
|
PopUpWidget *_popUpBoss;
|
|
|
|
int _clickX, _clickY;
|
|
|
|
byte *_buffer;
|
|
|
|
int _selection;
|
2002-12-12 23:31:58 +00:00
|
|
|
uint32 _openTime;
|
2002-12-12 12:07:46 +00:00
|
|
|
public:
|
|
|
|
PopUpDialog(PopUpWidget *boss, int clickX, int clickY);
|
|
|
|
|
|
|
|
void drawDialog();
|
|
|
|
|
2002-12-13 21:35:04 +00:00
|
|
|
// void handleMouseDown(int x, int y, int button, int clickCount);
|
2002-12-12 12:07:46 +00:00
|
|
|
void handleMouseUp(int x, int y, int button, int clickCount);
|
2002-12-13 21:35:04 +00:00
|
|
|
void handleMouseWheel(int x, int y, int direction); // Scroll through entries with scroll wheel
|
2002-12-12 12:07:46 +00:00
|
|
|
void handleMouseMoved(int x, int y, int button); // Redraw selections depending on mouse position
|
2002-12-13 21:35:04 +00:00
|
|
|
void handleKeyDown(uint16 ascii, int keycode, int modifiers); // Scroll through entries with arrow keys etc.
|
2002-12-12 12:07:46 +00:00
|
|
|
// void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void drawMenuEntry(int entry, bool hilite);
|
|
|
|
|
|
|
|
int findItem(int x, int y) const;
|
2002-12-13 21:35:04 +00:00
|
|
|
void setSelection(int item);
|
|
|
|
bool isMouseDown();
|
2002-12-12 12:07:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY)
|
|
|
|
: Dialog(boss->_boss->getGui(), 0, 0, 16, 16),
|
|
|
|
_popUpBoss(boss)
|
|
|
|
{
|
|
|
|
// Calculate real popup dimensions
|
|
|
|
_x = _popUpBoss->_boss->getX() + _popUpBoss->_x;
|
|
|
|
_y = _popUpBoss->_boss->getY() + _popUpBoss->_y - _popUpBoss->_selectedItem * kLineHeight;
|
|
|
|
_h = _popUpBoss->_entries.size() * kLineHeight + 2;
|
2002-12-12 23:22:48 +00:00
|
|
|
_w = _popUpBoss->_w - 10;
|
2002-12-12 12:07:46 +00:00
|
|
|
|
|
|
|
// Copy the selection index
|
|
|
|
_selection = _popUpBoss->_selectedItem;
|
|
|
|
|
|
|
|
// TODO - perform clipping / switch to scrolling mode if we don't fit on the screen
|
|
|
|
|
|
|
|
// TODO - backup background here
|
|
|
|
|
|
|
|
// Remember original mouse position
|
|
|
|
_clickX = clickX - _x;
|
|
|
|
_clickY = clickY - _y;
|
2002-12-12 23:31:58 +00:00
|
|
|
|
|
|
|
// Time the popup was opened
|
|
|
|
_openTime = g_system->get_msecs();
|
2002-12-12 12:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PopUpDialog::drawDialog()
|
|
|
|
{
|
|
|
|
// Draw the menu border
|
2002-12-12 23:22:48 +00:00
|
|
|
// _gui->box(_x, _y, _w, _h);
|
|
|
|
_gui->hline(_x, _y, _x+_w-1, _gui->_color);
|
|
|
|
_gui->hline(_x, _y+_h-1, _x+_w-1, _gui->_shadowcolor);
|
|
|
|
_gui->vline(_x, _y, _y+_h-1, _gui->_color);
|
|
|
|
_gui->vline(_x+_w-1, _y, _y+_h-1, _gui->_shadowcolor);
|
2002-12-12 12:07:46 +00:00
|
|
|
|
|
|
|
// Draw the entries
|
|
|
|
int count = _popUpBoss->_entries.size();
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
drawMenuEntry(i, i == _selection);
|
|
|
|
}
|
|
|
|
|
|
|
|
_gui->addDirtyRect(_x, _y, _w, _h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PopUpDialog::handleMouseUp(int x, int y, int button, int clickCount)
|
|
|
|
{
|
|
|
|
// Mouse was released. If it wasn't moved much since the original mouse down,
|
|
|
|
// let the popup stay open. If it did move, assume the user made his selection.
|
|
|
|
int dist = (_clickX - x) * (_clickX - x) + (_clickY - y) * (_clickY - y);
|
2002-12-12 23:31:58 +00:00
|
|
|
if (dist > 3*3 || g_system->get_msecs() - _openTime > 300) {
|
2002-12-12 12:07:46 +00:00
|
|
|
setResult(_selection);
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
_clickX = -1;
|
|
|
|
_clickY = -1;
|
2002-12-12 23:31:58 +00:00
|
|
|
_openTime = (uint32)-1;
|
2002-12-12 12:07:46 +00:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:35:04 +00:00
|
|
|
void PopUpDialog::handleMouseWheel(int x, int y, int direction)
|
|
|
|
{
|
|
|
|
if (direction < 0) {
|
|
|
|
if (_selection > 0)
|
|
|
|
setSelection(_selection-1);
|
|
|
|
} else if (direction > 0) {
|
|
|
|
if (_selection < _popUpBoss->_entries.size()-1)
|
|
|
|
setSelection(_selection+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-12 12:07:46 +00:00
|
|
|
void PopUpDialog::handleMouseMoved(int x, int y, int button)
|
|
|
|
{
|
2002-12-13 21:35:04 +00:00
|
|
|
// Compute over which item the mouse is...
|
2002-12-12 12:07:46 +00:00
|
|
|
int item = findItem(x, y);
|
|
|
|
|
2002-12-13 21:35:04 +00:00
|
|
|
if (item == -1 && !isMouseDown())
|
|
|
|
return;
|
2002-12-12 12:07:46 +00:00
|
|
|
|
2002-12-13 21:35:04 +00:00
|
|
|
// ...and update the selection accordingly
|
|
|
|
setSelection(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PopUpDialog::handleKeyDown(uint16 ascii, int keycode, int modifiers)
|
|
|
|
{
|
|
|
|
if (keycode == 27) { // escape
|
|
|
|
close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isMouseDown())
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (keycode) {
|
|
|
|
case '\n': // enter/return
|
|
|
|
case '\r':
|
|
|
|
setResult(_selection);
|
|
|
|
close();
|
|
|
|
break;
|
|
|
|
case 256+17: // up arrow
|
|
|
|
if (_selection > 0)
|
|
|
|
setSelection(_selection-1);
|
|
|
|
break;
|
|
|
|
case 256+18: // down arrow
|
|
|
|
if (_selection < _popUpBoss->_entries.size()-1)
|
|
|
|
setSelection(_selection+1);
|
|
|
|
break;
|
|
|
|
case 256+22: // home
|
|
|
|
setSelection(0);
|
|
|
|
break;
|
|
|
|
case 256+23: // end
|
|
|
|
setSelection(_popUpBoss->_entries.size()-1);
|
|
|
|
break;
|
2002-12-12 12:07:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int PopUpDialog::findItem(int x, int y) const
|
|
|
|
{
|
|
|
|
if (x >= 0 && x < _w && y >= 0 && y < _h) {
|
|
|
|
return (y-2) / kLineHeight;
|
|
|
|
}
|
2002-12-13 21:35:04 +00:00
|
|
|
return -1;
|
2002-12-12 12:07:46 +00:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:35:04 +00:00
|
|
|
void PopUpDialog::setSelection(int item)
|
2002-12-12 12:07:46 +00:00
|
|
|
{
|
2002-12-13 21:35:04 +00:00
|
|
|
if (item != _selection) {
|
|
|
|
// Undraw old selection
|
|
|
|
if (_selection >= 0)
|
|
|
|
drawMenuEntry(_selection, false);
|
|
|
|
|
|
|
|
// Change selection
|
|
|
|
_selection = item;
|
2002-12-12 12:07:46 +00:00
|
|
|
|
2002-12-13 21:35:04 +00:00
|
|
|
// Draw new selection
|
|
|
|
if (item >= 0)
|
|
|
|
drawMenuEntry(item, true);
|
|
|
|
}
|
2002-12-12 12:07:46 +00:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:35:04 +00:00
|
|
|
bool PopUpDialog::isMouseDown()
|
2002-12-12 12:07:46 +00:00
|
|
|
{
|
2002-12-13 21:35:04 +00:00
|
|
|
// TODO/FIXME - need a way to determine whether any mouse buttons are pressed or not.
|
|
|
|
// Sure, we could just count mouse button up/down events, but that is cumbersome and
|
|
|
|
// error prone. Would be much nicer to add an API to OSystem for this...
|
|
|
|
|
|
|
|
return false;
|
2002-12-12 12:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PopUpDialog::drawMenuEntry(int entry, bool hilite)
|
|
|
|
{
|
|
|
|
// Draw one entry of the popup menu, including selection
|
|
|
|
assert(entry >= 0);
|
2002-12-12 23:22:48 +00:00
|
|
|
int x = _x + 1;
|
|
|
|
int y = _y + 1 + kLineHeight * entry;
|
|
|
|
int w = _w - 2;
|
2002-12-12 12:07:46 +00:00
|
|
|
|
|
|
|
_gui->fillRect(x, y, w, kLineHeight,
|
|
|
|
hilite ? _gui->_textcolorhi : _gui->_bgcolor);
|
2002-12-13 21:35:04 +00:00
|
|
|
_gui->drawString(_popUpBoss->_entries[entry].name, x+1, y+2, w-2,
|
2002-12-12 12:07:46 +00:00
|
|
|
hilite ? _gui->_bgcolor : _gui->_textcolor);
|
|
|
|
_gui->addDirtyRect(x, y, w, kLineHeight);
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:35:04 +00:00
|
|
|
|
2002-12-12 12:07:46 +00:00
|
|
|
//
|
2002-12-13 21:35:04 +00:00
|
|
|
// PopUpWidget
|
2002-12-12 12:07:46 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
PopUpWidget::PopUpWidget(Dialog *boss, int x, int y, int w, int h)
|
|
|
|
: Widget(boss, x, y-1, w, h+2), CommandSender(boss)
|
|
|
|
{
|
|
|
|
_flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS;
|
|
|
|
_type = 'POPU';
|
|
|
|
|
|
|
|
_selectedItem = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PopUpWidget::handleMouseDown(int x, int y, int button, int clickCount)
|
|
|
|
{
|
|
|
|
PopUpDialog popupDialog(this, x + _x + _boss->getX(), y + _y + _boss->getY());
|
|
|
|
int newSel = popupDialog.runModal();
|
|
|
|
if (newSel != -1 && _selectedItem != newSel) {
|
|
|
|
_selectedItem = newSel;
|
2002-12-12 23:31:58 +00:00
|
|
|
sendCommand(kPopUpItemSelectedCmd, _entries[_selectedItem].tag);
|
2002-12-12 12:07:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PopUpWidget::appendEntry(const String &entry, uint32 tag)
|
|
|
|
{
|
|
|
|
Entry e;
|
|
|
|
e.name = entry;
|
|
|
|
e.tag = tag;
|
|
|
|
_entries.push_back(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void PopUpWidget::clearEntries()
|
|
|
|
{
|
|
|
|
_entries.clear();
|
|
|
|
_selectedItem = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PopUpWidget::setSelected(int item)
|
|
|
|
{
|
|
|
|
// FIXME
|
|
|
|
if (item != _selectedItem) {
|
|
|
|
if (item >= 0 && item < _entries.size()) {
|
|
|
|
_selectedItem = item;
|
|
|
|
} else {
|
|
|
|
_selectedItem = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PopUpWidget::drawWidget(bool hilite)
|
|
|
|
{
|
|
|
|
NewGui *gui = _boss->getGui();
|
|
|
|
|
|
|
|
// Draw a thin frame around us.
|
|
|
|
// TODO - should look different than the EditTextWidget fram
|
|
|
|
gui->hline(_x, _y, _x+_w-1, gui->_color);
|
|
|
|
gui->hline(_x, _y+_h-1, _x+_w-1, gui->_shadowcolor);
|
|
|
|
gui->vline(_x, _y, _y+_h-1, gui->_color);
|
|
|
|
gui->vline(_x+_w-1, _y, _y+_h-1, gui->_shadowcolor);
|
|
|
|
|
|
|
|
// Draw an arrow pointing down at the right end to signal this is a dropdown/popup
|
2002-12-12 23:22:48 +00:00
|
|
|
gui->drawBitmap(up_down_arrows, _x+_w - 10, _y+2, hilite ? gui->_textcolorhi : gui->_textcolor);
|
2002-12-12 12:07:46 +00:00
|
|
|
|
|
|
|
// Draw the selected entry, if any
|
|
|
|
if (_selectedItem >= 0) {
|
|
|
|
int align = (gui->getStringWidth(_entries[_selectedItem].name) > _w-6) ? kTextAlignRight : kTextAlignLeft;
|
|
|
|
gui->drawString(_entries[_selectedItem].name, _x+2, _y+3, _w-6, gui->_textcolor, align);
|
|
|
|
}
|
|
|
|
}
|