summaryrefslogtreecommitdiff
path: root/src/gui/widgets
diff options
context:
space:
mode:
authorAndrei Karas <akaras@inbox.ru>2012-12-14 01:18:59 +0300
committerAndrei Karas <akaras@inbox.ru>2012-12-15 22:26:03 +0300
commit62a466e53cbb49c5338f8ea7f96b46e00d3b0bc4 (patch)
tree9d69e63c1d2263aadd49afa551c23aff8ec51c2b /src/gui/widgets
parent1d290d6a54c2ea6e689446551a8d16025a179177 (diff)
downloadmv-62a466e53cbb49c5338f8ea7f96b46e00d3b0bc4.tar.gz
mv-62a466e53cbb49c5338f8ea7f96b46e00d3b0bc4.tar.bz2
mv-62a466e53cbb49c5338f8ea7f96b46e00d3b0bc4.tar.xz
mv-62a466e53cbb49c5338f8ea7f96b46e00d3b0bc4.zip
Add popup list. Replace listbox in dropdown to popup list.
Diffstat (limited to 'src/gui/widgets')
-rw-r--r--src/gui/widgets/dropdown.cpp244
-rw-r--r--src/gui/widgets/dropdown.h68
-rw-r--r--src/gui/widgets/popuplist.cpp115
-rw-r--r--src/gui/widgets/popuplist.h74
4 files changed, 434 insertions, 67 deletions
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 <guichan/widgets/dropdown.hpp>
+#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<SelectionListener*> 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef POPUP_LIST_H
+#define POPUP_LIST_H
+
+#include "gui/widgets/linkhandler.h"
+#include "gui/widgets/popup.h"
+
+#include <guichan/actionlistener.hpp>
+#include "guichan/focuslistener.hpp"
+#include <guichan/listmodel.hpp>
+#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