diff options
author | Bastien Bouclet | 2019-11-13 21:09:21 +0100 |
---|---|---|
committer | Bastien Bouclet | 2019-11-24 14:06:25 +0100 |
commit | 2c812a6b7a0b24b9012379118867fb4f64f32c14 (patch) | |
tree | 6f4225127305dbdae8f3a0dc7dfe61e51af51b1a /gui/widgets | |
parent | 3db6aed4e474d5b16639ee4958d1cd13504d12fb (diff) | |
download | scummvm-rg350-2c812a6b7a0b24b9012379118867fb4f64f32c14.tar.gz scummvm-rg350-2c812a6b7a0b24b9012379118867fb4f64f32c14.tar.bz2 scummvm-rg350-2c812a6b7a0b24b9012379118867fb4f64f32c14.zip |
GUI: Add DropdownButtonWidget and use it in the launcher for mass add
DropdownButtonWidget is a button split in two parts vertically. Clicking
the left part triggers a default action. Clicking the right part shows a
list of other actions the user can choose from.
Using this widget on the launcher lets 'Mass add' be a secondary action
of the 'Add' button, removing the necessity of pressing the shift key to
access the feature.
Diffstat (limited to 'gui/widgets')
-rw-r--r-- | gui/widgets/popup.cpp | 187 | ||||
-rw-r--r-- | gui/widgets/popup.h | 59 |
2 files changed, 155 insertions, 91 deletions
diff --git a/gui/widgets/popup.cpp b/gui/widgets/popup.cpp index 970e35ab23..351d0fe559 100644 --- a/gui/widgets/popup.cpp +++ b/gui/widgets/popup.cpp @@ -21,7 +21,6 @@ */ #include "common/system.h" -#include "gui/dialog.h" #include "gui/gui-manager.h" #include "gui/widgets/popup.h" @@ -33,62 +32,35 @@ namespace GUI { // PopUpDialog // -class PopUpDialog : public Dialog { -protected: - PopUpWidget *_popUpBoss; - int _clickX, _clickY; - int _selection; - uint32 _openTime; - bool _twoColumns; - int _entriesPerColumn; - - int _leftPadding; - int _rightPadding; - - int _lastRead; - -public: - PopUpDialog(PopUpWidget *boss, int clickX, int clickY); - - void drawDialog(DrawLayer layerToDraw) override; - - void handleMouseUp(int x, int y, int button, int clickCount) override; - void handleMouseWheel(int x, int y, int direction) override; // Scroll through entries with scroll wheel - void handleMouseMoved(int x, int y, int button) override; // Redraw selections depending on mouse position - void handleMouseLeft(int button) override; - void handleKeyDown(Common::KeyState state) override; // Scroll through entries with arrow keys etc. - -protected: - void drawMenuEntry(int entry, bool hilite); - - int findItem(int x, int y) const; - void setSelection(int item); - bool isMouseDown(); - - void moveUp(); - void moveDown(); - void read(Common::String); -}; - -PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY) - : Dialog(0, 0, 16, 16), - _popUpBoss(boss) { +PopUpDialog::PopUpDialog(Widget *boss, const Common::String &name, int clickX, int clickY): + Dialog(name), + _boss(boss), + // Remember original mouse position + _clickX(clickX), + _clickY(clickY), + _selection(-1), + _initialSelection(-1), + _openTime(0), + _twoColumns(false), + _entriesPerColumn(1), + _leftPadding(0), + _rightPadding(0), + _lineHeight(kLineHeight), + _lastRead(-1) { _backgroundType = ThemeEngine::kDialogBackgroundNone; + _w = _boss->getWidth(); +} - _openTime = 0; - _entriesPerColumn = 1; +void PopUpDialog::open() { + // Time the popup was opened + _openTime = g_system->getMillis(); - // Copy the selection index - _selection = _popUpBoss->_selectedItem; + _initialSelection = _selection; // Calculate real popup dimensions - _x = _popUpBoss->getAbsX(); - _y = _popUpBoss->getAbsY() - _popUpBoss->_selectedItem * kLineHeight; - _h = _popUpBoss->_entries.size() * kLineHeight + 2; - _w = _popUpBoss->_w - kLineHeight + 2; + _h = _entries.size() * _lineHeight + 2; - _leftPadding = _popUpBoss->_leftPadding; - _rightPadding = _popUpBoss->_rightPadding; + _entriesPerColumn = 1; // Perform clipping / switch to scrolling mode if we don't fit on the screen // FIXME - OSystem should send out notification messages when the screen @@ -103,16 +75,16 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY) const int screenW = g_system->getOverlayWidth(); _twoColumns = true; - _entriesPerColumn = _popUpBoss->_entries.size() / 2; + _entriesPerColumn = _entries.size() / 2; - if (_popUpBoss->_entries.size() & 1) + if (_entries.size() & 1) _entriesPerColumn++; - _h = _entriesPerColumn * kLineHeight + 2; + _h = _entriesPerColumn * _lineHeight + 2; _w = 0; - for (uint i = 0; i < _popUpBoss->_entries.size(); i++) { - int width = g_gui.getStringWidth(_popUpBoss->_entries[i].name); + for (uint i = 0; i < _entries.size(); i++) { + int width = g_gui.getStringWidth(_entries[i]); if (width > _w) _w = width; @@ -123,9 +95,9 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY) if (!(_w & 1)) _w++; - if (_popUpBoss->_selectedItem >= _entriesPerColumn) { + if (_selection >= _entriesPerColumn) { _x -= _w / 2; - _y = _popUpBoss->getAbsY() - (_popUpBoss->_selectedItem - _entriesPerColumn) * kLineHeight; + _y = _boss->getAbsY() - (_selection - _entriesPerColumn) * _lineHeight; } if (_w >= screenW) @@ -146,11 +118,12 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY) // TODO - implement scrolling if we had to move the menu, or if there are too many entries - // Remember original mouse position - _clickX = clickX - _x; - _clickY = clickY - _y; - _lastRead = -1; + + Dialog::open(); +} + +void PopUpDialog::reflowLayout() { } void PopUpDialog::drawDialog(DrawLayer layerToDraw) { @@ -163,7 +136,7 @@ void PopUpDialog::drawDialog(DrawLayer layerToDraw) { g_gui.vLine(_x + _w / 2, _y, _y + _h - 2, g_gui._color);*/ // Draw the entries - int count = _popUpBoss->_entries.size(); + int count = _entries.size(); for (int i = 0; i < count; i++) { drawMenuEntry(i, i == _selection); } @@ -172,17 +145,15 @@ void PopUpDialog::drawDialog(DrawLayer layerToDraw) { /*if (_twoColumns && (count & 1)) { g_gui.fillRect(_x + 1 + _w / 2, _y + 1 + kLineHeight * (_entriesPerColumn - 1), _w / 2 - 1, kLineHeight, g_gui._bgcolor); }*/ - - if (_openTime == 0) { - // Time the popup was opened - _openTime = g_system->getMillis(); - } } void PopUpDialog::handleMouseUp(int x, int y, int button, int clickCount) { + int absX = x + getAbsX(); + int absY = y + getAbsY(); + // 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); + int dist = (_clickX - absX) * (_clickX - absX) + (_clickY - absY) * (_clickY - absY); if (dist > 3 * 3 || g_system->getMillis() - _openTime > 300) { setResult(_selection); close(); @@ -203,18 +174,18 @@ void PopUpDialog::handleMouseMoved(int x, int y, int button) { // Compute over which item the mouse is... int item = findItem(x, y); - if (item >= 0 && _popUpBoss->_entries[item].name.size() == 0) + if (item >= 0 && _entries[item].size() == 0) item = -1; if (item == -1 && !isMouseDown()) { - setSelection(_popUpBoss->_selectedItem); + setSelection(_initialSelection); return; } // ...and update the selection accordingly setSelection(item); - if (_lastRead != item && _popUpBoss->_entries.size() > 0 && item != -1) { - read(_popUpBoss->_entries[item].name); + if (_lastRead != item && _entries.size() > 0 && item != -1) { + read(_entries[item]); _lastRead = item; } } @@ -261,7 +232,7 @@ void PopUpDialog::handleKeyDown(Common::KeyState state) { break; // fall through case Common::KEYCODE_END: - setSelection(_popUpBoss->_entries.size()-1); + setSelection(_entries.size()-1); break; case Common::KEYCODE_KP2: @@ -293,19 +264,45 @@ void PopUpDialog::handleKeyDown(Common::KeyState state) { } } +void PopUpDialog::setPosition(int x, int y) { + _x = x; + _y = y; +} + +void PopUpDialog::setPadding(int left, int right) { + _leftPadding = left; + _rightPadding = right; +} + +void PopUpDialog::setLineHeight(int lineHeight) { + _lineHeight = lineHeight; +} + +void PopUpDialog::setWidth(uint16 width) { + _w = width; +} + +void PopUpDialog::appendEntry(const Common::String &entry) { + _entries.push_back(entry); +} + +void PopUpDialog::clearEntries() { + _entries.clear(); +} + int PopUpDialog::findItem(int x, int y) const { if (x >= 0 && x < _w && y >= 0 && y < _h) { if (_twoColumns) { - uint entry = (y - 2) / kLineHeight; + uint entry = (y - 2) / _lineHeight; if (x > _w / 2) { entry += _entriesPerColumn; - if (entry >= _popUpBoss->_entries.size()) + if (entry >= _entries.size()) return -1; } return entry; } - return (y - 2) / kLineHeight; + return (y - 2) / _lineHeight; } return -1; } @@ -335,19 +332,19 @@ bool PopUpDialog::isMouseDown() { void PopUpDialog::moveUp() { if (_selection < 0) { - setSelection(_popUpBoss->_entries.size() - 1); + setSelection(_entries.size() - 1); } else if (_selection > 0) { int item = _selection; do { item--; - } while (item >= 0 && _popUpBoss->_entries[item].name.size() == 0); + } while (item >= 0 && _entries[item].size() == 0); if (item >= 0) setSelection(item); } } void PopUpDialog::moveDown() { - int lastItem = _popUpBoss->_entries.size() - 1; + int lastItem = _entries.size() - 1; if (_selection < 0) { setSelection(0); @@ -355,7 +352,7 @@ void PopUpDialog::moveDown() { int item = _selection; do { item++; - } while (item <= lastItem && _popUpBoss->_entries[item].name.size() == 0); + } while (item <= lastItem && _entries[item].size() == 0); if (item <= lastItem) setSelection(item); } @@ -367,34 +364,34 @@ void PopUpDialog::drawMenuEntry(int entry, bool hilite) { int x, y, w; if (_twoColumns) { - int n = _popUpBoss->_entries.size() / 2; + int n = _entries.size() / 2; - if (_popUpBoss->_entries.size() & 1) + if (_entries.size() & 1) n++; if (entry >= n) { x = _x + 1 + _w / 2; - y = _y + 1 + kLineHeight * (entry - n); + y = _y + 1 + _lineHeight * (entry - n); } else { x = _x + 1; - y = _y + 1 + kLineHeight * entry; + y = _y + 1 + _lineHeight * entry; } w = _w / 2 - 1; } else { x = _x + 1; - y = _y + 1 + kLineHeight * entry; + y = _y + 1 + _lineHeight * entry; w = _w - 2; } - Common::String &name(_popUpBoss->_entries[entry].name); + Common::String &name(_entries[entry]); if (name.size() == 0) { // Draw a separator - g_gui.theme()->drawLineSeparator(Common::Rect(x, y, x + w, y + kLineHeight)); + g_gui.theme()->drawLineSeparator(Common::Rect(x, y, x + w, y + _lineHeight)); } else { g_gui.theme()->drawText( - Common::Rect(x + 1, y + 2, x + w, y + 2 + kLineHeight), + Common::Rect(x + 1, y + 2, x + w, y + 2 + _lineHeight), name, hilite ? ThemeEngine::kStateHighlight : ThemeEngine::kStateEnabled, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, _leftPadding ); @@ -429,7 +426,17 @@ PopUpWidget::PopUpWidget(GuiObject *boss, int x, int y, int w, int h, const char void PopUpWidget::handleMouseDown(int x, int y, int button, int clickCount) { if (isEnabled()) { - PopUpDialog popupDialog(this, x + getAbsX(), y + getAbsY()); + PopUpDialog popupDialog(this, "", x + getAbsX(), y + getAbsY()); + popupDialog.setPosition(getAbsX(), getAbsY() - _selectedItem * kLineHeight); + popupDialog.setPadding(_leftPadding, _rightPadding); + popupDialog.setWidth(getWidth() - kLineHeight + 2); + + + for (uint i = 0; i < _entries.size(); i++) { + popupDialog.appendEntry(_entries[i].name); + } + popupDialog.setSelection(_selectedItem); + int newSel = popupDialog.runModal(); if (newSel != -1 && _selectedItem != newSel) { _selectedItem = newSel; diff --git a/gui/widgets/popup.h b/gui/widgets/popup.h index 3ccf8787d5..d7c218f2d3 100644 --- a/gui/widgets/popup.h +++ b/gui/widgets/popup.h @@ -23,6 +23,7 @@ #ifndef GUI_WIDGETS_POPUP_H #define GUI_WIDGETS_POPUP_H +#include "gui/dialog.h" #include "gui/widget.h" #include "common/str.h" #include "common/array.h" @@ -41,7 +42,6 @@ enum { * is broadcast, with data being equal to the tag value of the selected entry. */ class PopUpWidget : public Widget, public CommandSender { - friend class PopUpDialog; typedef Common::String String; struct Entry { @@ -85,6 +85,63 @@ protected: void drawWidget(); }; +/** + * A small dialog showing a list of items and allowing the user to chose one of them + * + * Used by PopUpWidget and DropdownButtonWidget. + */ +class PopUpDialog : public Dialog { +protected: + Widget *_boss; + int _clickX, _clickY; + int _selection; + int _initialSelection; + uint32 _openTime; + bool _twoColumns; + int _entriesPerColumn; + + int _leftPadding; + int _rightPadding; + int _lineHeight; + + int _lastRead; + + typedef Common::Array<Common::String> EntryList; + EntryList _entries; + +public: + PopUpDialog(Widget *boss, const Common::String &name, int clickX, int clickY); + + void open() override; + void reflowLayout() override; + void drawDialog(DrawLayer layerToDraw) override; + + void handleMouseUp(int x, int y, int button, int clickCount) override; + void handleMouseWheel(int x, int y, int direction) override; // Scroll through entries with scroll wheel + void handleMouseMoved(int x, int y, int button) override; // Redraw selections depending on mouse position + void handleMouseLeft(int button) override; + void handleKeyDown(Common::KeyState state) override; // Scroll through entries with arrow keys etc. + + void setPosition(int x, int y); + void setPadding(int left, int right); + void setLineHeight(int lineHeight); + void setWidth(uint16 width); + + void appendEntry(const Common::String &entry); + void clearEntries(); + void setSelection(int item); + +protected: + void drawMenuEntry(int entry, bool hilite); + + int findItem(int x, int y) const; + bool isMouseDown(); + + void moveUp(); + void moveDown(); + void read(Common::String); +}; + } // End of namespace GUI #endif |