| 1 | /* |
| 2 | src/combobox.cpp -- simple combo box widget based on a popup button |
| 3 | |
| 4 | NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>. |
| 5 | The widget drawing code is based on the NanoVG demo application |
| 6 | by Mikko Mononen. |
| 7 | |
| 8 | All rights reserved. Use of this source code is governed by a |
| 9 | BSD-style license that can be found in the LICENSE.txt file. |
| 10 | */ |
| 11 | |
| 12 | #include <nanogui/combobox.h> |
| 13 | #include <nanogui/layout.h> |
| 14 | #include <nanogui/serializer/core.h> |
| 15 | #include <cassert> |
| 16 | |
| 17 | NAMESPACE_BEGIN(nanogui) |
| 18 | |
| 19 | ComboBox::ComboBox(Widget *parent) : PopupButton(parent), mSelectedIndex(0) { |
| 20 | } |
| 21 | |
| 22 | ComboBox::ComboBox(Widget *parent, const std::vector<std::string> &items) |
| 23 | : PopupButton(parent), mSelectedIndex(0) { |
| 24 | setItems(items); |
| 25 | } |
| 26 | |
| 27 | ComboBox::ComboBox(Widget *parent, const std::vector<std::string> &items, const std::vector<std::string> &itemsShort) |
| 28 | : PopupButton(parent), mSelectedIndex(0) { |
| 29 | setItems(items, itemsShort); |
| 30 | } |
| 31 | |
| 32 | void ComboBox::setSelectedIndex(int idx) { |
| 33 | if (mItemsShort.empty()) |
| 34 | return; |
| 35 | const std::vector<Widget *> &children = popup()->children(); |
| 36 | ((Button *) children[mSelectedIndex])->setPushed(false); |
| 37 | ((Button *) children[idx])->setPushed(true); |
| 38 | mSelectedIndex = idx; |
| 39 | setCaption(mItemsShort[idx]); |
| 40 | } |
| 41 | |
| 42 | void ComboBox::setItems(const std::vector<std::string> &items, const std::vector<std::string> &itemsShort) { |
| 43 | assert(items.size() == itemsShort.size()); |
| 44 | mItems = items; |
| 45 | mItemsShort = itemsShort; |
| 46 | if (mSelectedIndex < 0 || mSelectedIndex >= (int) items.size()) |
| 47 | mSelectedIndex = 0; |
| 48 | while (mPopup->childCount() != 0) |
| 49 | mPopup->removeChild(mPopup->childCount()-1); |
| 50 | mPopup->setLayout(new GroupLayout(10)); |
| 51 | int index = 0; |
| 52 | for (const auto &str: items) { |
| 53 | Button *button = new Button(mPopup, str); |
| 54 | button->setFlags(Button::RadioButton); |
| 55 | button->setCallback([&, index] { |
| 56 | mSelectedIndex = index; |
| 57 | setCaption(mItemsShort[index]); |
| 58 | setPushed(false); |
| 59 | popup()->setVisible(false); |
| 60 | if (mCallback) |
| 61 | mCallback(index); |
| 62 | }); |
| 63 | index++; |
| 64 | } |
| 65 | setSelectedIndex(mSelectedIndex); |
| 66 | } |
| 67 | |
| 68 | bool ComboBox::scrollEvent(const Vector2i &p, const Vector2f &rel) { |
| 69 | if (rel.y() < 0) { |
| 70 | setSelectedIndex(std::min(mSelectedIndex+1, (int)(items().size()-1))); |
| 71 | if (mCallback) |
| 72 | mCallback(mSelectedIndex); |
| 73 | return true; |
| 74 | } else if (rel.y() > 0) { |
| 75 | setSelectedIndex(std::max(mSelectedIndex-1, 0)); |
| 76 | if (mCallback) |
| 77 | mCallback(mSelectedIndex); |
| 78 | return true; |
| 79 | } |
| 80 | return Widget::scrollEvent(p, rel); |
| 81 | } |
| 82 | |
| 83 | void ComboBox::save(Serializer &s) const { |
| 84 | Widget::save(s); |
| 85 | s.set("items" , mItems); |
| 86 | s.set("itemsShort" , mItemsShort); |
| 87 | s.set("selectedIndex" , mSelectedIndex); |
| 88 | } |
| 89 | |
| 90 | bool ComboBox::load(Serializer &s) { |
| 91 | if (!Widget::load(s)) return false; |
| 92 | if (!s.get("items" , mItems)) return false; |
| 93 | if (!s.get("itemsShort" , mItemsShort)) return false; |
| 94 | if (!s.get("selectedIndex" , mSelectedIndex)) return false; |
| 95 | return true; |
| 96 | } |
| 97 | |
| 98 | NAMESPACE_END(nanogui) |
| 99 | |