From 62a466e53cbb49c5338f8ea7f96b46e00d3b0bc4 Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Fri, 14 Dec 2012 01:18:59 +0300 Subject: Add popup list. Replace listbox in dropdown to popup list. --- src/CMakeLists.txt | 4 +- src/Makefile.am | 4 +- src/gui/gui.cpp | 10 + src/gui/gui.h | 7 + src/gui/itemamountwindow.cpp | 2 +- src/gui/popupmenu.cpp | 17 + src/gui/popupmenu.h | 3 + src/gui/widgets/dropdown.cpp | 244 +++++++++++---- src/gui/widgets/dropdown.h | 68 +++- src/gui/widgets/popuplist.cpp | 115 +++++++ src/gui/widgets/popuplist.h | 74 +++++ src/guichan/include/guichan/widgets/dropdown.hpp | 322 ------------------- src/guichan/widgets/dropdown.cpp | 383 ----------------------- 13 files changed, 476 insertions(+), 777 deletions(-) create mode 100644 src/gui/widgets/popuplist.cpp create mode 100644 src/gui/widgets/popuplist.h delete mode 100644 src/guichan/include/guichan/widgets/dropdown.hpp delete mode 100644 src/guichan/widgets/dropdown.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0b00f7143..7140fba7d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -172,6 +172,8 @@ SET(SRCS gui/widgets/playerbox.h gui/widgets/popup.cpp gui/widgets/popup.h + gui/widgets/popuplist.cpp + gui/widgets/popuplist.h gui/widgets/progressbar.cpp gui/widgets/progressbar.h gui/widgets/progressindicator.cpp @@ -699,7 +701,6 @@ SET(SRCS_GUICHAN guichan/include/guichan/widgets/button.hpp guichan/include/guichan/widgets/checkbox.hpp guichan/include/guichan/widgets/container.hpp - guichan/include/guichan/widgets/dropdown.hpp guichan/include/guichan/widgets/label.hpp guichan/include/guichan/widgets/listbox.hpp guichan/include/guichan/widgets/radiobutton.hpp @@ -732,7 +733,6 @@ SET(SRCS_GUICHAN guichan/widgets/button.cpp guichan/widgets/checkbox.cpp guichan/widgets/container.cpp - guichan/widgets/dropdown.cpp guichan/widgets/label.cpp guichan/widgets/listbox.cpp guichan/widgets/radiobutton.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 3af39acc2..32844edb8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,6 @@ manaplus_SOURCES += guichan/include/guichan/actionevent.hpp \ guichan/include/guichan/widgets/button.hpp \ guichan/include/guichan/widgets/checkbox.hpp \ guichan/include/guichan/widgets/container.hpp \ - guichan/include/guichan/widgets/dropdown.hpp \ guichan/include/guichan/widgets/label.hpp \ guichan/include/guichan/widgets/listbox.hpp \ guichan/include/guichan/widgets/radiobutton.hpp \ @@ -96,7 +95,6 @@ manaplus_SOURCES += guichan/actionevent.cpp \ guichan/widgets/button.cpp \ guichan/widgets/checkbox.cpp \ guichan/widgets/container.cpp \ - guichan/widgets/dropdown.cpp \ guichan/widgets/label.cpp \ guichan/widgets/listbox.cpp \ guichan/widgets/radiobutton.cpp \ @@ -174,6 +172,8 @@ manaplus_SOURCES += gui/widgets/avatarlistbox.cpp \ gui/widgets/playerbox.h \ gui/widgets/popup.cpp \ gui/widgets/popup.h \ + gui/widgets/popuplist.cpp \ + gui/widgets/popuplist.h \ gui/widgets/progressbar.cpp \ gui/widgets/progressbar.h \ gui/widgets/progressindicator.cpp \ diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 268f05fc1..7b2da4bff 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -696,3 +696,13 @@ void Gui::handleMouseInput() } BLOCK_END("Gui::handleMouseInput") } + +void Gui::addGlobalFocusListener(gcn::FocusListener* focusListener) +{ + mFocusListeners.push_back(focusListener); +} + +void Gui::removeGlobalFocusListener(gcn::FocusListener* focusListener) +{ + mFocusListeners.remove(focusListener); +} diff --git a/src/gui/gui.h b/src/gui/gui.h index db373193a..04b6ddba3 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -142,6 +142,10 @@ class Gui final : public gcn::Gui void getAbsolutePosition(gcn::Widget *widget, int &x, int &y); + void addGlobalFocusListener(gcn::FocusListener* focusListener); + + void removeGlobalFocusListener(gcn::FocusListener* focusListener); + protected: void handleMouseMoved(const gcn::MouseInput &mouseInput); @@ -163,6 +167,9 @@ class Gui final : public gcn::Gui float mMouseCursorAlpha; int mMouseInactivityTimer; int mCursorType; + + typedef std::list FocusListenerList; + FocusListenerList mFocusListeners; }; extern Gui *gui; /**< The GUI system */ diff --git a/src/gui/itemamountwindow.cpp b/src/gui/itemamountwindow.cpp index e25647436..82f85a2e7 100644 --- a/src/gui/itemamountwindow.cpp +++ b/src/gui/itemamountwindow.cpp @@ -137,7 +137,7 @@ void ItemAmountWindow::finish(Item *const item, const int amount, ItemAmountWindow::ItemAmountWindow(const Usage usage, Window *const parent, Item *const item, const int maxRange) : - Window("", true, parent, "amount.xml"), + Window("", false, parent, "amount.xml"), gcn::ActionListener(), gcn::KeyListener(), mItemAmountTextField(new IntTextField(this, 1)), diff --git a/src/gui/popupmenu.cpp b/src/gui/popupmenu.cpp index 4d781f5ac..5a75cb71d 100644 --- a/src/gui/popupmenu.cpp +++ b/src/gui/popupmenu.cpp @@ -70,6 +70,8 @@ #include "utils/gettext.h" +#include + #include "debug.h" extern int serverVersion; @@ -2187,6 +2189,21 @@ void PopupMenu::addPickupFilter(const std::string &name) } } +void PopupMenu::showPopup(const int x, const int y, gcn::ListModel *model) +{ + if (!model) + return; + + mBrowserBox->clearRows(); + for (int f = 0, sz = model->getNumberOfElements(); f < sz; f ++) + { + mBrowserBox->addRow(strprintf("dropdown_%d", f), + model->getElementAt(f).c_str()); + } + mBrowserBox->addRow("cancel", _("Cancel")); + showPopup(x, y); +} + RenameListener::RenameListener() : gcn::ActionListener(), mMapItem(nullptr), diff --git a/src/gui/popupmenu.h b/src/gui/popupmenu.h index 9ebf8d163..431d7e7de 100644 --- a/src/gui/popupmenu.h +++ b/src/gui/popupmenu.h @@ -29,6 +29,7 @@ #include "actorsprite.h" #include +#include #include "localconsts.h" @@ -165,6 +166,8 @@ class PopupMenu final : public Popup, public LinkHandler void showChangePos(const int x, const int y); + void showPopup(const int x, const int y, gcn::ListModel *model); + /** * Handles link action. */ diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp index bde16760b..6c3e3e9cc 100644 --- a/src/gui/widgets/dropdown.cpp +++ b/src/gui/widgets/dropdown.cpp @@ -28,8 +28,10 @@ #include "keyevent.h" #include "gui/sdlinput.h" +#include "gui/viewport.h" #include "gui/widgets/listbox.h" +#include "gui/widgets/popuplist.h" #include "gui/widgets/scrollarea.h" #include "resources/image.h" @@ -58,15 +60,27 @@ DropDown::DropDown(const Widget2 *const widget, gcn::ListModel *const listModel, gcn::ActionListener *const listener, const std::string &eventId): - gcn::DropDown::DropDown(listModel, - new ScrollArea, new ListBox(widget, listModel)), + gcn::ActionListener(), + gcn::BasicContainer(), + gcn::KeyListener(), + gcn::MouseListener(), + gcn::FocusListener(), + gcn::SelectionListener(), + Widget2(widget), + mPopup(new PopupList(this, listModel)), mShadowColor(getThemeColor(Theme::DROPDOWN_SHADOW)), mHighlightColor(getThemeColor(Theme::HIGHLIGHT)), mPadding(1), - mImagePadding(2) + mImagePadding(2), + mDroppedDown(false), + mPushed(false), + mFoldedUpHeight(0), + mIsDragged(false) { mFrameSize = 2; + mPopup->setHeight(100); + // Initialize graphics if (instances == 0) { @@ -113,7 +127,19 @@ DropDown::DropDown(const Widget2 *const widget, instances++; - mListBox->setForegroundColor(getThemeColor(Theme::DROPDOWN)); + setWidth(100); + setFocusable(true); + setListModel(listModel); + + if (mPopup->getSelected() < 0) + mPopup->setSelected(0); + + addMouseListener(this); + addKeyListener(this); + addFocusListener(this); + + adjustHeight(); + mPopup->setForegroundColor(getThemeColor(Theme::DROPDOWN)); setForegroundColor(getThemeColor(Theme::DROPDOWN)); if (!eventId.empty()) @@ -122,8 +148,8 @@ DropDown::DropDown(const Widget2 *const widget, if (listener) addActionListener(listener); - if (mListBox) - mListBox->adjustSize(); + if (mPopup) + mPopup->adjustSize(); if (mSkin) { @@ -154,8 +180,6 @@ DropDown::~DropDown() theme->unloadRect(skinRect); } } - delete mScrollArea; - mScrollArea = nullptr; } void DropDown::updateAlpha() @@ -201,12 +225,12 @@ void DropDown::draw(gcn::Graphics* graphics) mHighlightColor.a = alpha; mShadowColor.a = alpha; - if (mListBox->getListModel() && mListBox->getSelected() >= 0) + if (mPopup->getListModel() && mPopup->getSelected() >= 0) { graphics->setFont(getFont()); graphics->setColor(mForegroundColor); - graphics->drawText(mListBox->getListModel()->getElementAt( - mListBox->getSelected()), mPadding, mPadding); + graphics->drawText(mPopup->getListModel()->getElementAt( + mPopup->getSelected()), mPadding, mPadding); } if (isFocused()) @@ -220,7 +244,7 @@ void DropDown::draw(gcn::Graphics* graphics) if (mDroppedDown) { - drawChildren(graphics); +// drawChildren(graphics); // Draw two lines separating the ListBox with selected // element view. graphics->setColor(mHighlightColor); @@ -255,7 +279,6 @@ void DropDown::drawButton(gcn::Graphics *graphics) } } -// -- KeyListener notifications void DropDown::keyPressed(gcn::KeyEvent& keyEvent) { if (keyEvent.isConsumed()) @@ -283,9 +306,9 @@ void DropDown::keyPressed(gcn::KeyEvent& keyEvent) break; case Input::KEY_GUI_END: - if (mListBox->getListModel()) + if (mPopup->getListModel()) { - setSelected(mListBox->getListModel()-> + setSelected(mPopup->getListModel()-> getNumberOfElements() - 1); } break; @@ -297,26 +320,57 @@ void DropDown::keyPressed(gcn::KeyEvent& keyEvent) keyEvent.consume(); } -void DropDown::focusLost(const gcn::Event& event) +void DropDown::hideDrop() { - gcn::DropDown::focusLost(event); - releaseModalMouseInputFocus(); + distributeActionEvent(); + mPopup->setVisible(false); } void DropDown::mousePressed(gcn::MouseEvent& mouseEvent) { - gcn::DropDown::mousePressed(mouseEvent); - - if (0 <= mouseEvent.getY() && mouseEvent.getY() < getHeight() && - mouseEvent.getX() >= 0 && mouseEvent.getX() < getWidth() && - mouseEvent.getButton() == gcn::MouseEvent::LEFT && mDroppedDown && - mouseEvent.getSource() == mListBox) + // If we have a mouse press on the widget. + if (mouseEvent.getButton() == gcn::MouseEvent::LEFT + && !mDroppedDown && mouseEvent.getSource() == this) + { + mPushed = true; + dropDown(); + } + else { mPushed = false; foldUp(); - releaseModalMouseInputFocus(); - distributeActionEvent(); + hideDrop(); + } +} + +void DropDown::mouseReleased(gcn::MouseEvent &mouseEvent) +{ + if (mIsDragged) + mPushed = false; + + // Released outside of widget. Can happen when we have modal + // input focus. + if ((0 > mouseEvent.getY() + || mouseEvent.getY() >= getHeight() + || mouseEvent.getX() < 0 + || mouseEvent.getX() >= getWidth()) + && mouseEvent.getButton() == gcn::MouseEvent::LEFT) + { + if (mIsDragged) + foldUp(); } + else if (mouseEvent.getButton() == gcn::MouseEvent::LEFT) + { + mPushed = false; + } + + mIsDragged = false; +} + +void DropDown::mouseDragged(gcn::MouseEvent &mouseEvent) +{ + mIsDragged = true; + mouseEvent.consume(); } void DropDown::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent) @@ -333,7 +387,7 @@ void DropDown::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) void DropDown::setSelectedString(std::string str) { - gcn::ListModel *const listModel = mListBox->getListModel(); + gcn::ListModel *const listModel = mPopup->getListModel(); if (!listModel) return; @@ -349,7 +403,7 @@ void DropDown::setSelectedString(std::string str) std::string DropDown::getSelectedString() const { - gcn::ListModel *const listModel = mListBox->getListModel(); + gcn::ListModel *const listModel = mPopup->getListModel(); if (!listModel) return ""; @@ -358,48 +412,120 @@ std::string DropDown::getSelectedString() const void DropDown::adjustHeight() { - if (!mScrollArea || !mListBox) + setHeight(getFont()->getHeight() + 2 * mPadding); +} + +void DropDown::dropDown() +{ + if (!mPopup) return; - const int listBoxHeight = mListBox->getHeight(); - const int h2 = getFont()->getHeight() + 2 * mPadding; - int newHeight = h2; + if (!mDroppedDown) + { + mDroppedDown = true; + mFoldedUpHeight = getHeight(); + adjustHeight(); + +// if (getParent()) +// getParent()->moveToTop(this); + int x = 0; + int y = 0; + getAbsolutePosition(x, y); + const int frame = getParent()->getFrameSize(); + const int pad = mPopup->getPadding(); + const int pad2 = pad * 2; + + // here width should be adjusted on some other parameters + mPopup->setWidth(getWidth() - pad2 + 10); + mPopup->show(x - mPadding - frame - 1, y + getHeight()); + mPopup->requestMoveToTop(); + mPopup->requestFocus(); + } +} - if (mDroppedDown && getParent()) +void DropDown::foldUp() +{ + if (mDroppedDown) { - const int h = getParent()->getChildrenArea().height - getY(); - const int h0 = h - h2; - if (listBoxHeight > h0) - { - mScrollArea->setHeight(h0); - newHeight = h; - } - else - { - newHeight = listBoxHeight + h2; - mScrollArea->setHeight(listBoxHeight); - } + mDroppedDown = false; + adjustHeight(); +// mInternalFocusHandler.focusNone(); } +} - setHeight(newHeight); +int DropDown::getSelected() const +{ + return mPopup->getSelected(); +} - mScrollArea->setWidth(getWidth()); - mListBox->setWidth(mScrollArea->getChildrenArea().width); - mScrollArea->setPosition(0, 0); +void DropDown::setSelected(int selected) +{ + if (selected >= 0) + mPopup->setSelected(selected); } -void DropDown::dropDown() +void DropDown::setListModel(gcn::ListModel *listModel) { - const bool dropped = mDroppedDown; - gcn::DropDown::dropDown(); - if (!dropped) - adjustHeight(); + mPopup->setListModel(listModel); + + if (mPopup->getSelected() < 0) + mPopup->setSelected(0); + + adjustHeight(); } -void DropDown::foldUp() +gcn::ListModel *DropDown::getListModel() { - const bool dropped = mDroppedDown; - gcn::DropDown::foldUp(); - if (dropped) - adjustHeight(); + return mPopup->getListModel(); +} + +void DropDown::action(const gcn::ActionEvent &actionEvent A_UNUSED) +{ + foldUp(); + distributeActionEvent(); +} + +gcn::Rectangle DropDown::getChildrenArea() +{ + if (mDroppedDown) + { + // Calculate the children area (with the one pixel border in mind) + return gcn::Rectangle(1, mFoldedUpHeight + 1, + getWidth() - 2, getHeight() - mFoldedUpHeight - 2); + } + + return gcn::Rectangle(); +} + +void DropDown::valueChanged(const gcn::SelectionEvent& event A_UNUSED) +{ +} + +void DropDown::updateSelection() +{ + mDroppedDown = false; + mPushed = false; + distributeActionEvent(); + distributeValueChangedEvent(); +} + +void DropDown::addSelectionListener(SelectionListener* selectionListener) +{ + mSelectionListeners.push_back(selectionListener); +} + +void DropDown::removeSelectionListener(SelectionListener* listener) +{ + mSelectionListeners.remove(listener); +} + +void DropDown::distributeValueChangedEvent() +{ + for (SelectionListenerIterator iter = mSelectionListeners.begin(); + iter != mSelectionListeners.end(); + ++iter) + { + gcn::SelectionEvent event(this); + (*iter)->valueChanged(event); + } } diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h index d02b86672..6b3b6503a 100644 --- a/src/gui/widgets/dropdown.h +++ b/src/gui/widgets/dropdown.h @@ -25,12 +25,25 @@ #include "gui/widgets/widget2.h" -#include +#include "guichan/actionlistener.hpp" +#include "guichan/basiccontainer.hpp" +#include "guichan/focushandler.hpp" +#include "guichan/focuslistener.hpp" +#include "guichan/keylistener.hpp" +#include "guichan/listmodel.hpp" +#include "guichan/mouselistener.hpp" +#include "guichan/selectionlistener.hpp" + +#include "guichan/widgets/listbox.hpp" +#include "guichan/widgets/scrollarea.hpp" #include "localconsts.h" class Image; class ImageRect; +class ListBox; +class PopupList; +class ScrollArea; class Skin; /** @@ -40,7 +53,12 @@ class Skin; * DropDown you must give DropDown an implemented ListModel which represents * your list. */ -class DropDown final : public gcn::DropDown, +class DropDown final : public gcn::ActionListener, + public gcn::BasicContainer, + public gcn::KeyListener, + public gcn::MouseListener, + public gcn::FocusListener, + public gcn::SelectionListener, public Widget2 { public: @@ -70,10 +88,6 @@ class DropDown final : public gcn::DropDown, void drawFrame(gcn::Graphics *graphics) override; - // Inherited from FocusListener - - void focusLost(const gcn::Event& event) override; - // Inherited from KeyListener void keyPressed(gcn::KeyEvent& keyEvent) override; @@ -82,6 +96,10 @@ class DropDown final : public gcn::DropDown, void mousePressed(gcn::MouseEvent& mouseEvent) override; + void mouseReleased(gcn::MouseEvent& mouseEvent) override; + + void mouseDragged(gcn::MouseEvent& mouseEvent) override; + void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent) override; void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) override; @@ -90,11 +108,35 @@ class DropDown final : public gcn::DropDown, std::string getSelectedString() const A_WARN_UNUSED; + void valueChanged(const gcn::SelectionEvent& event); + + void updateSelection(); + void adjustHeight(); - void dropDown() override; + void dropDown(); + + void foldUp(); + + void hideDrop(); + + int getSelected() const; - void foldUp() override; + void setSelected(int selected); + + void setListModel(gcn::ListModel *listModel); + + gcn::ListModel *getListModel(); + + void addSelectionListener(SelectionListener* listener); + + void removeSelectionListener(SelectionListener* selectionListener); + + gcn::Rectangle getChildrenArea(); + + void action(const gcn::ActionEvent &actionEvent); + + void distributeValueChangedEvent(); protected: /** @@ -104,11 +146,21 @@ class DropDown final : public gcn::DropDown, */ void drawButton(gcn::Graphics *graphics); + PopupList *mPopup; gcn::Color mShadowColor; gcn::Color mHighlightColor; int mPadding; int mImagePadding; + bool mDroppedDown; + bool mPushed; + int mFoldedUpHeight; +// gcn::FocusHandler mInternalFocusHandler; + bool mIsDragged; + typedef std::list SelectionListenerList; + SelectionListenerList mSelectionListeners; + typedef SelectionListenerList::iterator SelectionListenerIterator; + // Add own Images. static int instances; static Image *buttons[2][2]; diff --git a/src/gui/widgets/popuplist.cpp b/src/gui/widgets/popuplist.cpp new file mode 100644 index 000000000..e32cd5b70 --- /dev/null +++ b/src/gui/widgets/popuplist.cpp @@ -0,0 +1,115 @@ +/* + * The ManaPlus Client + * Copyright (C) 2011-2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * 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 + * 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, see . + */ + +#include "gui/widgets/popuplist.h" + +#include "gui/widgets/dropdown.h" +#include "gui/widgets/listbox.h" +#include "gui/widgets/scrollarea.h" + +#include "utils/gettext.h" + +#include "debug.h" + +PopupList::PopupList(DropDown *const widget, + gcn::ListModel *const listModel): + Popup("PopupList", "popuplist.xml"), + gcn::FocusListener(), + mListModel(listModel), + mListBox(new ListBox(widget, listModel)), + mScrollArea(new ScrollArea), + mDropDown(widget) +{ + setFocusable(true); + + mListBox->setDistributeMousePressed(true); + mListBox->addSelectionListener(this); + mScrollArea->setContent(mListBox); + add(mScrollArea); + + if (getParent()) + getParent()->addFocusListener(this); +} + +void PopupList::show(int x, int y) +{ + int len = mListBox->getHeight() + 8; + if (len > 250) + len = 250; + setContentSize(mListBox->getWidth() + 8, len); + if (mainGraphics->mWidth < (x + getWidth() + 5)) + x = mainGraphics->mWidth - getWidth(); + if (mainGraphics->mHeight < (y + getHeight() + 5)) + y = mainGraphics->mHeight - getHeight(); + setPosition(x, y); + setVisible(true); + requestMoveToTop(); +} + +void PopupList::widgetResized(const gcn::Event &event) +{ + Popup::widgetResized(event); + adjustSize(); +} + +void PopupList::setSelected(int selected) +{ + if (!mListBox) + return; + + mListBox->setSelected(selected); +} + +int PopupList::getSelected() const +{ + if (!mListBox) + return -1; + + return mListBox->getSelected(); +} + +void PopupList::setListModel(gcn::ListModel *model) +{ + if (mListBox) + mListBox->setListModel(model); + mListModel = model; +} + +void PopupList::adjustSize() +{ + mScrollArea->setWidth(getWidth() - 8); + mScrollArea->setHeight(getHeight() - 8); + mListBox->adjustSize(); +} + +void PopupList::valueChanged(const gcn::SelectionEvent& event A_UNUSED) +{ + if (mDropDown) + mDropDown->updateSelection(); + setVisible(false); +} + +void PopupList::focusLost(const gcn::Event& event A_UNUSED) +{ + logger->log("lost focus"); + if (mDropDown) + mDropDown->updateSelection(); +// setVisible(false); +} diff --git a/src/gui/widgets/popuplist.h b/src/gui/widgets/popuplist.h new file mode 100644 index 000000000..f0b195a47 --- /dev/null +++ b/src/gui/widgets/popuplist.h @@ -0,0 +1,74 @@ +/* + * The ManaPlus Client + * Copyright (C) 2011-2012 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * 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 + * 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, see . + */ + +#ifndef POPUP_LIST_H +#define POPUP_LIST_H + +#include "gui/widgets/linkhandler.h" +#include "gui/widgets/popup.h" + +#include +#include "guichan/focuslistener.hpp" +#include +#include "guichan/selectionlistener.hpp" + +#include "localconsts.h" + +class DropDown; +class ListBox; +class ScrollArea; + +class PopupList final : public Popup, + public gcn::FocusListener, + public gcn::SelectionListener +{ + public: + PopupList(DropDown *const widget, + gcn::ListModel *const listModel); + + A_DELETE_COPY(PopupList) + + void show(int x, int y); + + void widgetResized(const gcn::Event &event) override; + + void setSelected(int selected); + + int getSelected() const; + + void setListModel(gcn::ListModel *model); + + gcn::ListModel *getListModel() const + { return mListModel; } + + void adjustSize(); + + void valueChanged(const gcn::SelectionEvent& event); + + void focusLost(const gcn::Event& event A_UNUSED); + + private: + gcn::ListModel *mListModel; + ListBox *mListBox; + ScrollArea *mScrollArea; + DropDown *mDropDown; +}; + +#endif diff --git a/src/guichan/include/guichan/widgets/dropdown.hpp b/src/guichan/include/guichan/widgets/dropdown.hpp deleted file mode 100644 index 0bdec632c..000000000 --- a/src/guichan/include/guichan/widgets/dropdown.hpp +++ /dev/null @@ -1,322 +0,0 @@ -/* _______ __ __ __ ______ __ __ _______ __ __ - * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ - * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / - * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / - * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / - * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / - * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ - * - * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson - * Copyright (C) 2011-2012 The ManaPlus Developers - * - * - * Per Larsson a.k.a finalman - * Olof Naessén a.k.a jansem/yakslem - * - * Visit: http://guichan.sourceforge.net - * - * License: (BSD) - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of Guichan nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef GCN_DROPDOWN_HPP -#define GCN_DROPDOWN_HPP - -#include "guichan/actionlistener.hpp" -#include "guichan/basiccontainer.hpp" -#include "guichan/deathlistener.hpp" -#include "guichan/focushandler.hpp" -#include "guichan/focuslistener.hpp" -#include "guichan/keylistener.hpp" -#include "guichan/listmodel.hpp" -#include "guichan/mouselistener.hpp" -#include "guichan/platform.hpp" -#include "guichan/selectionlistener.hpp" -#include "guichan/widgets/listbox.hpp" -#include "guichan/widgets/scrollarea.hpp" - -#include "localconsts.h" - -namespace gcn -{ - /** - * An implementation of a drop downable list from which an item can be - * selected. The drop down consists of an internal ScrollArea and an - * internal ListBox. The drop down also uses an internal FocusHandler to - * handle the focus of the internal ScollArea and the internal ListBox. The - * scroll area and the list box can be passed to the drop down if a custom - * scroll area and or a custom list box is preferable. - * - * To be able display a list the drop down uses a user provided list model. - * A list model can be any class that implements the ListModel interface. - * - * If an item is selected in the drop down a select event will be sent to - * all selection listeners of the drop down. If an item is selected by - * using a mouse click or by using the enter or space key an action event - * will be sent to all action listeners of the drop down. - */ - class GCN_CORE_DECLSPEC DropDown : - public ActionListener, - public BasicContainer, - public KeyListener, - public MouseListener, - public FocusListener, - public SelectionListener - { - public: - /** - * Contructor. - * - * @param listModel the ListModel to use. - * @param scrollArea the ScrollArea to use. - * @param listBox the listBox to use. - * @see ListModel, ScrollArea, ListBox. - */ - DropDown(ListModel *const listModel = nullptr, - ScrollArea *const scrollArea = nullptr, - ListBox *const listBox = nullptr); - - A_DELETE_COPY(DropDown) - - /** - * Destructor. - */ - virtual ~DropDown(); - - /** - * Gets the selected item as an index in the list model. - * - * @return the selected item as an index in the list model. - * @see setSelected - */ - int getSelected() const; - - /** - * Sets the selected item. The selected item is represented by - * an index from the list model. - * - * @param selected the selected item as an index from the list model. - * @see getSelected - */ - void setSelected(int selected); - - /** - * Sets the list model to use when displaying the list. - * - * @param listModel the list model to use. - * @see getListModel - */ - void setListModel(ListModel *listModel); - - /** - * Gets the list model used. - * - * @return the ListModel used. - * @see setListModel - */ - ListModel *getListModel(); - - /** - * Adjusts the height of the drop down to fit the height of the - * drop down's parent's height. It's used to not make the drop down - * draw itself outside of it's parent if folded down. - */ - void adjustHeight(); - - /** - * Adds a selection listener to the drop down. When the selection - * changes an event will be sent to all selection listeners of the - * drop down. - * - * If you delete your selection listener, be sure to also remove it - * using removeSelectionListener(). - * - * @param listener the selection listener to add. - * @since 0.8.0 - */ - void addSelectionListener(SelectionListener* listener); - - /** - * Removes a selection listener from the drop down. - * - * @param selectionListener the selection listener to remove. - * @since 0.8.0 - */ - void removeSelectionListener(SelectionListener* selectionListener); - - - // Inherited from Widget - - void setBaseColor(const Color& color); - - void setBackgroundColor(const Color& color); - - void setForegroundColor(const Color& color); - - void setFont(Font *font); - - void setSelectionColor(const Color& color); - - - // Inherited from BasicContainer - - virtual Rectangle getChildrenArea(); - - - // Inherited from FocusListener - - virtual void focusLost(const Event& event); - - - // Inherited from ActionListener - - virtual void action(const ActionEvent& actionEvent); - - - // Inherited from DeathListener - - virtual void death(const Event& event); - - - // Inherited from KeyListener - - virtual void keyPressed(KeyEvent& keyEvent) override = 0; - - - // Inherited from MouseListener - - virtual void mousePressed(MouseEvent& mouseEvent) override; - - virtual void mouseReleased(MouseEvent& mouseEvent) override; - - virtual void mouseWheelMovedUp(MouseEvent& mouseEvent) override; - - virtual void mouseWheelMovedDown(MouseEvent& mouseEvent) override; - - virtual void mouseDragged(MouseEvent& mouseEvent) override; - - - // Inherited from SelectionListener - - virtual void valueChanged(const SelectionEvent& event); - - protected: - /** - * Draws the button of the drop down. - * - * @param graphics a Graphics object to draw with. - */ - virtual void drawButton(Graphics *graphics) = 0; - - /** - * Sets the drop down to be dropped down. - */ - virtual void dropDown(); - - /** - * Sets the drop down to be folded up. - */ - virtual void foldUp(); - - /** - * Distributes a value changed event to all selection listeners - * of the drop down. - * - * @since 0.8.0 - */ - void distributeValueChangedEvent(); - - /** - * True if the drop down is dropped down, false otherwise. - */ - bool mDroppedDown; - - /** - * True if the drop down has been pushed with the mouse, false - * otherwise. - */ - bool mPushed; - - /** - * Holds what the height is if the drop down is folded up. Used when - * checking if the list of the drop down was clicked or if the upper - * part of the drop down was clicked on a mouse click. - */ - int mFoldedUpHeight; - - /** - * True if an internal scroll area is used, false if a scroll area - * has been passed to the drop down which the drop down should not - * deleted in it's destructor. - */ - bool mInternalScrollArea; - - /** - * The scroll area used. - */ - ScrollArea* mScrollArea; - - /** - * True if an internal list box is used, false if a list box - * has been passed to the drop down which the drop down should not - * deleted in it's destructor. - */ - bool mInternalListBox; - - /** - * The list box used. - */ - ListBox* mListBox; - - /** - * The internal focus handler used to keep track of focus for the - * internal list box. - */ - FocusHandler mInternalFocusHandler; - - /** - * True if the drop down is dragged. - */ - bool mIsDragged; - - /** - * Typedef. - */ - typedef std::list SelectionListenerList; - - /** - * The selection listener's of the drop down. - */ - SelectionListenerList mSelectionListeners; - - /** - * Typedef. - */ - typedef SelectionListenerList::iterator SelectionListenerIterator; - }; -} - -#endif // end GCN_DROPDOWN_HPP diff --git a/src/guichan/widgets/dropdown.cpp b/src/guichan/widgets/dropdown.cpp deleted file mode 100644 index fda433e51..000000000 --- a/src/guichan/widgets/dropdown.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* _______ __ __ __ ______ __ __ _______ __ __ - * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ - * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / - * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / - * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / - * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / - * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ - * - * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson - * Copyright (C) 2011-2012 The ManaPlus Developers - * - * - * Per Larsson a.k.a finalman - * Olof Naessén a.k.a jansem/yakslem - * - * Visit: http://guichan.sourceforge.net - * - * License: (BSD) - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of Guichan nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "guichan/widgets/dropdown.hpp" - -#include "guichan/exception.hpp" -#include "guichan/font.hpp" -#include "guichan/graphics.hpp" -#include "guichan/key.hpp" -#include "guichan/listmodel.hpp" -#include "guichan/mouseinput.hpp" -#include "guichan/widgets/listbox.hpp" -#include "guichan/widgets/scrollarea.hpp" - -#include "debug.h" - -namespace gcn -{ - DropDown::DropDown(ListModel *const listModel, - ScrollArea *const scrollArea, - ListBox *const listBox) : - gcn::ActionListener(), - gcn::BasicContainer(), - gcn::KeyListener(), - gcn::MouseListener(), - gcn::FocusListener(), - gcn::SelectionListener(), - mDroppedDown(false), - mPushed(false), - mFoldedUpHeight(0), - mInternalScrollArea(!scrollArea), - mScrollArea(mInternalScrollArea ? new ScrollArea : scrollArea), - mInternalListBox(!listBox), - mListBox(mInternalListBox ? new ListBox() : listBox), - mIsDragged(false) - { - setWidth(100); - setFocusable(true); - - setInternalFocusHandler(&mInternalFocusHandler); - mScrollArea->setContent(mListBox); - add(mScrollArea); - - mListBox->addActionListener(this); - mListBox->addSelectionListener(this); - - setListModel(listModel); - - if (mListBox->getSelected() < 0) - mListBox->setSelected(0); - - addMouseListener(this); - addKeyListener(this); - addFocusListener(this); - - adjustHeight(); - } - - DropDown::~DropDown() - { - if (widgetExists(mListBox)) - { - mListBox->removeActionListener(this); - mListBox->removeSelectionListener(this); - } - - if (mInternalScrollArea) - { - delete mScrollArea; - mScrollArea = nullptr; - } - - if (mInternalListBox) - { - delete mListBox; - mListBox = nullptr; - } - - setInternalFocusHandler(nullptr); - } - - int DropDown::getSelected() const - { - return mListBox->getSelected(); - } - - void DropDown::setSelected(int selected) - { - if (selected >= 0) - mListBox->setSelected(selected); - } - - void DropDown::mousePressed(MouseEvent& mouseEvent) - { - // If we have a mouse press on the widget. - if (0 <= mouseEvent.getY() - && mouseEvent.getY() < getHeight() - && mouseEvent.getX() >= 0 - && mouseEvent.getX() < getWidth() - && mouseEvent.getButton() == MouseEvent::LEFT - && !mDroppedDown - && mouseEvent.getSource() == this) - { - mPushed = true; - dropDown(); - requestModalMouseInputFocus(); - } - // Fold up the listbox if the upper part is clicked after fold down - else if (0 <= mouseEvent.getY() - && mouseEvent.getY() < mFoldedUpHeight - && mouseEvent.getX() >= 0 - && mouseEvent.getX() < getWidth() - && mouseEvent.getButton() == MouseEvent::LEFT - && mDroppedDown - && mouseEvent.getSource() == this) - { - mPushed = false; - foldUp(); - releaseModalMouseInputFocus(); - } - // If we have a mouse press outside the widget - else if (0 > mouseEvent.getY() - || mouseEvent.getY() >= getHeight() - || mouseEvent.getX() < 0 - || mouseEvent.getX() >= getWidth()) - { - mPushed = false; - foldUp(); - } - } - - void DropDown::mouseReleased(MouseEvent& mouseEvent) - { - if (mIsDragged) - mPushed = false; - - // Released outside of widget. Can happen when we have modal - // input focus. - if ((0 > mouseEvent.getY() - || mouseEvent.getY() >= getHeight() - || mouseEvent.getX() < 0 - || mouseEvent.getX() >= getWidth()) - && mouseEvent.getButton() == MouseEvent::LEFT - && isModalMouseInputFocused()) - { - releaseModalMouseInputFocus(); - - if (mIsDragged) - foldUp(); - } - else if (mouseEvent.getButton() == MouseEvent::LEFT) - { - mPushed = false; - } - - mIsDragged = false; - } - - void DropDown::mouseDragged(MouseEvent& mouseEvent) - { - mIsDragged = true; - - mouseEvent.consume(); - } - - void DropDown::setListModel(ListModel *listModel) - { - mListBox->setListModel(listModel); - - if (mListBox->getSelected() < 0) - mListBox->setSelected(0); - - adjustHeight(); - } - - ListModel *DropDown::getListModel() - { - return mListBox->getListModel(); - } - - void DropDown::adjustHeight() - { - } - - void DropDown::dropDown() - { - if (!mDroppedDown) - { - mDroppedDown = true; - mFoldedUpHeight = getHeight(); - adjustHeight(); - - if (getParent()) - getParent()->moveToTop(this); - } - - mListBox->requestFocus(); - } - - void DropDown::foldUp() - { - if (mDroppedDown) - { - mDroppedDown = false; - adjustHeight(); - mInternalFocusHandler.focusNone(); - } - } - - void DropDown::focusLost(const Event& event A_UNUSED) - { - foldUp(); - mInternalFocusHandler.focusNone(); - } - - - void DropDown::death(const Event& event) - { - if (event.getSource() == mScrollArea) - mScrollArea = nullptr; - - BasicContainer::death(event); - } - - void DropDown::action(const ActionEvent& actionEvent A_UNUSED) - { - foldUp(); - releaseModalMouseInputFocus(); - distributeActionEvent(); - } - - Rectangle DropDown::getChildrenArea() - { - if (mDroppedDown) - { - // Calculate the children area (with the one pixel border in mind) - return Rectangle(1, mFoldedUpHeight + 1, - getWidth() - 2, getHeight() - mFoldedUpHeight - 2); - } - - return Rectangle(); - } - - void DropDown::setBaseColor(const Color& color) - { - if (mInternalScrollArea) - mScrollArea->setBaseColor(color); - - if (mInternalListBox) - mListBox->setBaseColor(color); - - Widget::setBaseColor(color); - } - - void DropDown::setBackgroundColor(const Color& color) - { - if (mInternalScrollArea) - mScrollArea->setBackgroundColor(color); - - if (mInternalListBox) - mListBox->setBackgroundColor(color); - - Widget::setBackgroundColor(color); - } - - void DropDown::setForegroundColor(const Color& color) - { - if (mInternalScrollArea) - mScrollArea->setForegroundColor(color); - - if (mInternalListBox) - mListBox->setForegroundColor(color); - - Widget::setForegroundColor(color); - } - - void DropDown::setFont(Font *font) - { - if (mInternalScrollArea) - mScrollArea->setFont(font); - - if (mInternalListBox) - mListBox->setFont(font); - - Widget::setFont(font); - } - - void DropDown::mouseWheelMovedUp(MouseEvent& mouseEvent) - { - if (isFocused() && mouseEvent.getSource() == this) - { - mouseEvent.consume(); - - if (mListBox->getSelected() > 0) - mListBox->setSelected(mListBox->getSelected() - 1); - } - } - - void DropDown::mouseWheelMovedDown(MouseEvent& mouseEvent) - { - if (isFocused() && mouseEvent.getSource() == this) - { - mouseEvent.consume(); - - mListBox->setSelected(mListBox->getSelected() + 1); - } - } - - void DropDown::setSelectionColor(const Color& color) - { - Widget::setSelectionColor(color); - - if (mInternalListBox) - mListBox->setSelectionColor(color); - } - - void DropDown::valueChanged(const SelectionEvent& event A_UNUSED) - { - distributeValueChangedEvent(); - } - - void DropDown::addSelectionListener(SelectionListener* selectionListener) - { - mSelectionListeners.push_back(selectionListener); - } - - void DropDown::removeSelectionListener(SelectionListener* listener) - { - mSelectionListeners.remove(listener); - } - - void DropDown::distributeValueChangedEvent() - { - for (SelectionListenerIterator iter = mSelectionListeners.begin(); - iter != mSelectionListeners.end(); - ++iter) - { - SelectionEvent event(this); - (*iter)->valueChanged(event); - } - } -} -- cgit v1.2.3-70-g09d2