1 /*
2 	This file is part of Warzone 2100.
3 	Copyright (C) 2020  Warzone 2100 Project
4 
5 	Warzone 2100 is free software; you can redistribute it and/or modify
6 	it under the terms of the GNU General Public License as published by
7 	the Free Software Foundation; either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	Warzone 2100 is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with Warzone 2100; if not, write to the Free Software
17 	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 /**
20  * @file
21  * Definitions for scroll bar functions.
22  */
23 
24 #ifndef __INCLUDED_LIB_WIDGET_DROPDOWN_H__
25 #define __INCLUDED_LIB_WIDGET_DROPDOWN_H__
26 
27 #include <optional-lite/optional.hpp>
28 #include "widget.h"
29 #include "scrollablelist.h"
30 
31 class DropdownItemWrapper;
32 typedef std::function<void(std::shared_ptr<DropdownItemWrapper> item)> DropdownOnSelectHandler;
33 
34 class DropdownItemWrapper: public WIDGET
35 {
36 protected:
DropdownItemWrapper()37 	DropdownItemWrapper() {}
38 
39 	void initialize(const std::shared_ptr<WIDGET> &newItem, DropdownOnSelectHandler newOnSelect);
40 
41 public:
make(const std::shared_ptr<WIDGET> & item,DropdownOnSelectHandler onSelect)42 	static std::shared_ptr<DropdownItemWrapper> make(const std::shared_ptr<WIDGET> &item, DropdownOnSelectHandler onSelect)
43 	{
44 		class make_shared_enabler: public DropdownItemWrapper {};
45 		auto widget = std::make_shared<make_shared_enabler>();
46 		widget->initialize(item, onSelect);
47 		return widget;
48 	}
49 
50 	bool processClickRecursive(W_CONTEXT *psContext, WIDGET_KEY key, bool wasPressed) override;
51 	void geometryChanged() override;
52 
getItem()53 	const std::shared_ptr<WIDGET>& getItem() const
54 	{
55 		return item;
56 	}
57 
setPadding(const Padding & value)58 	void setPadding(const Padding &value)
59 	{
60 		padding = value;
61 	}
62 
setSelected(bool value)63 	void setSelected(bool value)
64 	{
65 		selected = value;
66 	}
67 
68 protected:
69 	void display(int xOffset, int yOffset) override;
70 
71 private:
72 	std::shared_ptr<WIDGET> item;
73 	DropdownOnSelectHandler onSelect;
74 	Padding padding;
75 	bool selected = false;
76 };
77 
78 class DropdownWidget : public WIDGET
79 {
80 public:
81 	DropdownWidget();
82 
83 	void addItem(const std::shared_ptr<WIDGET> &widget);
84 	void display(int xOffset, int yOffset) override;
85 	void clicked(W_CONTEXT *psContext, WIDGET_KEY key) override;
86 	void run(W_CONTEXT *) override;
87 	void geometryChanged() override;
88 	void open();
89 	void close();
90 	bool processClickRecursive(W_CONTEXT *psContext, WIDGET_KEY key, bool wasPressed) override;
setListHeight(uint32_t value)91 	void setListHeight(uint32_t value)
92 	{
93 		itemsList->setGeometry(itemsList->x(), itemsList->y(), itemsList->width(), value);
94 	}
setItemPadding(const Padding & value)95 	void setItemPadding(const Padding &value)
96 	{
97 		itemPadding = value;
98 	}
setSelectedIndex(size_t index)99 	void setSelectedIndex(size_t index)
100 	{
101 		ASSERT_OR_RETURN(, index < items.size(), "Invalid dropdown item index");
102 		select(items[index]);
103 	}
setOnChange(std::function<void (DropdownWidget &)> value)104 	void setOnChange(std::function<void(DropdownWidget&)> value)
105 	{
106 		onChange = value;
107 	}
getSelectedItem()108 	std::shared_ptr<WIDGET> getSelectedItem() const
109 	{
110 		if (selectedItem == nullptr)
111 		{
112 			return nullptr;
113 		}
114 		return selectedItem->getItem();
115 	}
getSelectedIndex()116 	nonstd::optional<size_t> getSelectedIndex() const
117 	{
118 		if (selectedItem == nullptr)
119 		{
120 			return nonstd::nullopt;
121 		}
122 
123 		for (auto item = items.begin(); item != items.end(); item++)
124 		{
125 			if (*item == selectedItem)
126 			{
127 				return item - items.begin();
128 			}
129 		}
130 
131 		return nonstd::nullopt;
132 	}
getScrollbarWidth()133 	int getScrollbarWidth() const
134 	{
135 		ASSERT_OR_RETURN(0, itemsList != nullptr, "null itemsList");
136 		return itemsList->getScrollbarWidth();
137 	}
138 
139 private:
140 	std::vector<std::shared_ptr<DropdownItemWrapper>> items;
141 	std::shared_ptr<ScrollableListWidget> itemsList;
142 	std::shared_ptr<W_SCREEN> overlayScreen;
143 	std::shared_ptr<DropdownItemWrapper> selectedItem;
144 	Padding itemPadding = {0, 0, 0, 0};
145 	std::function<void(DropdownWidget&)> onChange;
146 
select(const std::shared_ptr<DropdownItemWrapper> & selected)147 	void select(const std::shared_ptr<DropdownItemWrapper> &selected)
148 	{
149 		if (selectedItem == selected)
150 		{
151 			return;
152 		}
153 
154 		if (selectedItem)
155 		{
156 			selectedItem->setSelected(false);
157 		}
158 		selectedItem = selected;
159 		selectedItem->setSelected(true);
160 
161 		if (onChange)
162 		{
163 			onChange(*this);
164 		}
165 	}
166 };
167 
168 #endif // __INCLUDED_LIB_WIDGET_DROPDOWN_H__
169