From 57d8bb978f8808b5884a717a4d032b68eab4db76 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Thu, 12 Dec 2002 12:07:46 +0000 Subject: added PopUpWidget; hacked it into the edit game dialog just to show how to use it; note: this is NOT finished by any means, the look will change, the code will change, this is just an early preview :-) svn-id: r5914 --- gui/PopUpWidget.cpp | 262 ++++++++++++++++++++++++++++++++++++++++++++++++ gui/PopUpWidget.h | 78 ++++++++++++++ gui/ScrollBarWidget.cpp | 2 +- gui/launcher.cpp | 14 ++- gui/module.mk | 1 + gui/newgui.cpp | 47 ++++++--- gui/newgui.h | 6 +- 7 files changed, 392 insertions(+), 18 deletions(-) create mode 100644 gui/PopUpWidget.cpp create mode 100644 gui/PopUpWidget.h diff --git a/gui/PopUpWidget.cpp b/gui/PopUpWidget.cpp new file mode 100644 index 0000000000..966f3cc463 --- /dev/null +++ b/gui/PopUpWidget.cpp @@ -0,0 +1,262 @@ +/* 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" + +/* TODO: + * - draw an (unselectable) sepeator line for items that start with a '-' + * - handle looong lists by allowing scrolling (a lot of work if done right, + * so I will probably only implement if we really need it) + * - ... + */ + +#define UP_DOWN_BOX_HEIGHT 10 + +// Down arrow +static uint32 down_arrow[8] = { + 0x00000000, + 0x00000000, + 0x00100010, + 0x00110110, + 0x00011100, + 0x00011100, + 0x00001000, + 0x00001000, +}; + +const ScummVM::String PopUpWidget::emptyStr; + +class PopUpDialog : public Dialog { +protected: + PopUpWidget *_popUpBoss; + int _clickX, _clickY; + byte *_buffer; + int _selection; +public: + PopUpDialog(PopUpWidget *boss, int clickX, int clickY); + + void drawDialog(); + + void handleMouseDown(int x, int y, int button, int clickCount); + void handleMouseUp(int x, int y, int button, int clickCount); +// void handleMouseWheel(int x, int y, int direction); // Scroll through entries with scroll wheel + void handleMouseMoved(int x, int y, int button); // Redraw selections depending on mouse position +// bool handleKeyDown(uint16 ascii, int keycode, int modifiers); // Scroll through entries with arrow keys etc. +// void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); + +protected: +// void backupMenuBackground(); +// void restoreMenuBackground(); + + void drawMenuEntry(int entry, bool hilite); + + int findItem(int x, int y) const; +}; + +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; + _w = _popUpBoss->_w; + + // 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; +} + +void PopUpDialog::drawDialog() +{ + // Draw the menu border + _gui->box(_x, _y, _w, _h); + + // 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::handleMouseDown(int x, int y, int button, int clickCount) +{ +} + + +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); + if (dist > 3*3) { + setResult(_selection); + close(); + } + _clickX = -1; + _clickY = -1; +} + +void PopUpDialog::handleMouseMoved(int x, int y, int button) +{ + // Compute over which item + int item = findItem(x, y); + if (item != _selection) { + // Undraw old selection + if (_selection >= 0) + drawMenuEntry(_selection, false); + + // Change selection + _selection = item; + + // Draw new selection + if (item >= 0) + drawMenuEntry(item, true); + } +} + +int PopUpDialog::findItem(int x, int y) const +{ + if (x >= 0 && x < _w && y >= 0 && y < _h) { + return (y-2) / kLineHeight; + } + return _popUpBoss->_selectedItem; +} + +/* +void PopUpWidget::backupMenuBackground() +{ + NewGui *gui = _boss->getGui(); + + assert(_menu.buffer); + gui->blitToBuffer(_menu.x1, _menu.y1, _menu.w, _menu.h, _menu.buffer, _menu.w * 2); +} + +void PopUpWidget::restoreMenuBackground() +{ + NewGui *gui = _boss->getGui(); + + assert(_menu.buffer); + gui->blitFromBuffer(_menu.x1, _menu.y1, _menu.w, _menu.h, _menu.buffer, _menu.w * 2); + gui->addDirtyRect(_menu.x1, _menu.y1, _menu.w, _menu.h); + draw(); +} +*/ + +void PopUpDialog::drawMenuEntry(int entry, bool hilite) +{ + // Draw one entry of the popup menu, including selection + assert(entry >= 0); + int x = _x + 2; + int y = _y + 2 + kLineHeight * entry; + int w = _w - 4; + + _gui->fillRect(x, y, w, kLineHeight, + hilite ? _gui->_textcolorhi : _gui->_bgcolor); + _gui->drawString(_popUpBoss->_entries[entry].name, x+1, y+1, w-2, + hilite ? _gui->_bgcolor : _gui->_textcolor); + _gui->addDirtyRect(x, y, w, kLineHeight); +} + +// +// +// +// +// + + +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; + sendCommand(kPopUpItemSelectedCmd, _selectedItem); + } +} + +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 + gui->drawBitmap(down_arrow, _x+_w - 10, _y+1, hilite ? gui->_textcolorhi : gui->_textcolor); + + // 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); + } +} diff --git a/gui/PopUpWidget.h b/gui/PopUpWidget.h new file mode 100644 index 0000000000..c5901a2317 --- /dev/null +++ b/gui/PopUpWidget.h @@ -0,0 +1,78 @@ +/* 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$ + */ + +#ifndef POPUPWIDGET_H +#define POPUPWIDGET_H + +#include "widget.h" +#include "common/str.h" +#include "common/list.h" + +enum { + kPopUpItemSelectedCmd = 'POPs' +}; + +/* PopUpWidget + * A popup or dropdown widget which, when clicked, "pop up" a list of items and + * lets the user pick on of them. + * + * Implementation wise, when the user selects an item, then a kPopUpItemSelectedCmd + * is broadcast, with data being equal to the tag value of the selected entry. + */ +class PopUpWidget : public Widget, public CommandSender { + friend class PopUpDialog; + typedef ScummVM::String String; + + struct Entry { + String name; + uint32 tag; + }; + typedef ScummVM::List EntryList; +protected: + static const String emptyStr; + + EntryList _entries; + int _selectedItem; + +public: + PopUpWidget(Dialog *boss, int x, int y, int w, int h); + + void handleMouseDown(int x, int y, int button, int clickCount); +/* + void handleMouseUp(int x, int y, int button, int clickCount); +// void handleMouseWheel(int x, int y, int direction); // Scroll through entries with scroll wheel + void handleMouseMoved(int x, int y, int button); // Redraw selections depending on mouse position +// bool handleKeyDown(uint16 ascii, int keycode, int modifiers); // Scroll through entries with arrow keys etc. +// void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); +*/ + + void appendEntry(const String &entry, uint32 tag = (uint32)-1); +// void setEntries(const EntryList &entries); + void clearEntries(); + + void setSelected(int item); + int getSelected() const { return _selectedItem; } + const String& getSelectedString() const { return (_selectedItem >= 0) ? _entries[_selectedItem].name : emptyStr; } + +protected: + void drawWidget(bool hilite); +}; + +#endif diff --git a/gui/ScrollBarWidget.cpp b/gui/ScrollBarWidget.cpp index 9066c67291..232dbc8053 100644 --- a/gui/ScrollBarWidget.cpp +++ b/gui/ScrollBarWidget.cpp @@ -48,7 +48,7 @@ static uint32 up_arrow[8] = { 0x00100010, }; -// Up arrow +// Down arrow static uint32 down_arrow[8] = { 0x00000000, 0x00000000, diff --git a/gui/launcher.cpp b/gui/launcher.cpp index 0bfae7ca35..5d77021b6e 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -26,6 +26,7 @@ #include "message.h" #include "EditTextWidget.h" #include "ListWidget.h" +#include "PopUpWidget.h" #include "backends/fs/fs.h" #include "common/config-file.h" @@ -86,7 +87,8 @@ protected: }; EditGameDialog::EditGameDialog(NewGui *gui, Config &config, const String &domain) - : Dialog(gui, 8, 50, 320-2*8, 200-2*40), _config(config), _domain(domain) +// : Dialog(gui, 8, 50, 320-2*8, 200-2*40), _config(config), _domain(domain) + : Dialog(gui, 8, 30, 320-2*8, 200-2*30), _config(config), _domain(domain) { // Determine the description string String gameid(_config.get("gameid", _domain)); @@ -130,7 +132,15 @@ EditGameDialog::EditGameDialog(NewGui *gui, Config &config, const String &domain // Load in settings for the checkboxs _fullscreenCheckbox->setState(_config.getBool("fullscreen", false, _domain)); _AmigaPalCheckbox->setState(_config.getBool("amiga", false, _domain)); - + + // FIXME HACK - add a dummy popup widget here, for debugging. + // Note: this isn't useful at all right now... + PopUpWidget *foo; + foo = new PopUpWidget(this, 15, 102, 200, kLineHeight); + foo->appendEntry("Foo"); + foo->appendEntry("Bar"); + foo->appendEntry("Baz", 'QUUX'); + foo->setSelected(0); } void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) diff --git a/gui/module.mk b/gui/module.mk index bb024d180a..57bd3ff706 100644 --- a/gui/module.mk +++ b/gui/module.mk @@ -9,6 +9,7 @@ MODULE_OBJS = \ gui/ListWidget.o \ gui/message.o \ gui/newgui.o \ + gui/PopUpWidget.o \ gui/ScrollBarWidget.o \ gui/widget.o \ diff --git a/gui/newgui.cpp b/gui/newgui.cpp index a30be8ad10..4060fb0d56 100644 --- a/gui/newgui.cpp +++ b/gui/newgui.cpp @@ -157,7 +157,7 @@ void NewGui::runLoop() _system->set_mouse_pos(event.mouse.x, event.mouse.y); activeDialog->handleMouseMoved(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y, 0); break; - // We don'event distinguish between mousebuttons (for now at least) + // We don't distinguish between mousebuttons (for now at least) case OSystem::EVENT_LBUTTONDOWN: case OSystem::EVENT_RBUTTONDOWN: { if (_lastClick.count && (time < _lastClick.time + kDoubleClickDelay) @@ -297,9 +297,6 @@ void NewGui::line(int x, int y, int x2, int y2, int16 color) ptr = getBasePtr(x, y); - if (ptr == NULL) - return; - if (x == x2) { /* vertical line */ while (y++ <= y2) { @@ -320,8 +317,6 @@ void NewGui::blendRect(int x, int y, int w, int h, int16 color) int g = GREEN_FROM_16(color) * 3; int b = BLUE_FROM_16(color) * 3; int16 *ptr = getBasePtr(x, y); - if (ptr == NULL) - return; while (h--) { for (int i = 0; i < w; i++) { @@ -337,8 +332,6 @@ void NewGui::fillRect(int x, int y, int w, int h, int16 color) { int i; int16 *ptr = getBasePtr(x, y); - if (ptr == NULL) - return; while (h--) { for (i = 0; i < w; i++) { @@ -352,8 +345,6 @@ void NewGui::checkerRect(int x, int y, int w, int h, int16 color) { int i; int16 *ptr = getBasePtr(x, y); - if (ptr == NULL) - return; while (h--) { for (i = 0; i < w; i++) { @@ -402,8 +393,6 @@ void NewGui::drawChar(const byte chr, int xx, int yy, int16 color) tmp = guifont + 224 + (chr + 1) * 8; int16 *ptr = getBasePtr(xx, yy); - if (ptr == NULL) - return; for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) { @@ -453,14 +442,44 @@ void NewGui::drawString(const String &str, int x, int y, int w, int16 color, int } } +// +// Blit from a buffer to the display +// +void NewGui::blitFromBuffer(int x, int y, int w, int h, const byte *buf, int pitch) +{ + int16 *ptr = getBasePtr(x, y); + + assert(buf); + while (h--) { + memcpy(ptr, buf, w*2); + ptr += _screenPitch; + buf += pitch; + } +} + + +// +// Blit from the display to a buffer +// +void NewGui::blitToBuffer(int x, int y, int w, int h, byte *buf, int pitch) +{ + int16 *ptr = getBasePtr(x, y); + + assert(buf); + while (h--) { + memcpy(buf, ptr, w*2); + ptr += _screenPitch; + buf += pitch; + } +} + + // // Draw an 8x8 bitmap at location (x,y) // void NewGui::drawBitmap(uint32 bitmap[8], int x, int y, int16 color) { int16 *ptr = getBasePtr(x, y); - if (ptr == NULL) - return; for (int y2 = 0; y2 < 8; y2++) { uint32 mask = 0xF0000000; diff --git a/gui/newgui.h b/gui/newgui.h index 25c22b8147..648f8d34dd 100644 --- a/gui/newgui.h +++ b/gui/newgui.h @@ -132,13 +132,17 @@ public: void fillRect(int x, int y, int w, int h, int16 color); void checkerRect(int x, int y, int w, int h, int16 color); void frameRect(int x, int y, int w, int h, int16 color); - void addDirtyRect(int x, int y, int w, int h); void drawChar(byte c, int x, int y, int16 color); int getStringWidth(const String &str); int getCharWidth(byte c); void drawString(const String &str, int x, int y, int w, int16 color, int align = kTextAlignLeft); + void blitFromBuffer(int x, int y, int w, int h, const byte *buf, int pitch); + void blitToBuffer(int x, int y, int w, int h, byte *buf, int pitch); + void drawBitmap(uint32 bitmap[8], int x, int y, int16 color); + + void addDirtyRect(int x, int y, int w, int h); }; #endif -- cgit v1.2.3