1 /*************************************************************************/
2 /* option_button.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #include "option_button.h"
31 #include "print_string.h"
32
get_minimum_size() const33 Size2 OptionButton::get_minimum_size() const {
34
35 Size2 minsize = Button::get_minimum_size();
36
37 if (has_icon("arrow"))
38 minsize.width += Control::get_icon("arrow")->get_width();
39
40 return minsize;
41 }
42
_notification(int p_what)43 void OptionButton::_notification(int p_what) {
44
45 switch (p_what) {
46
47 case NOTIFICATION_DRAW: {
48
49 if (!has_icon("arrow"))
50 return;
51
52 RID ci = get_canvas_item();
53 Ref<Texture> arrow = Control::get_icon("arrow");
54 Ref<StyleBox> normal = get_stylebox("normal");
55
56 Size2 size = get_size();
57
58 Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2)));
59 arrow->draw(ci, ofs);
60
61 } break;
62 }
63 }
64
_selected(int p_which)65 void OptionButton::_selected(int p_which) {
66
67 int selid = -1;
68 for (int i = 0; i < popup->get_item_count(); i++) {
69
70 bool is_clicked = popup->get_item_ID(i) == p_which;
71 if (is_clicked) {
72 selid = i;
73 break;
74 }
75 }
76
77 if (selid == -1 && p_which >= 0 && p_which < popup->get_item_count()) {
78 _select(p_which, true);
79 } else {
80
81 ERR_FAIL_COND(selid == -1);
82
83 _select(selid, true);
84 }
85 }
86
pressed()87 void OptionButton::pressed() {
88
89 Size2 size = get_size();
90 popup->set_global_pos(get_global_pos() + Size2(0, size.height));
91 popup->set_size(Size2(size.width, 0));
92
93 popup->popup();
94 }
95
add_icon_item(const Ref<Texture> & p_icon,const String & p_label,int p_ID)96 void OptionButton::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID) {
97
98 popup->add_icon_check_item(p_icon, p_label, p_ID);
99 if (popup->get_item_count() == 1)
100 select(0);
101 }
add_item(const String & p_label,int p_ID)102 void OptionButton::add_item(const String &p_label, int p_ID) {
103
104 popup->add_check_item(p_label, p_ID);
105 if (popup->get_item_count() == 1)
106 select(0);
107 }
108
set_item_text(int p_idx,const String & p_text)109 void OptionButton::set_item_text(int p_idx, const String &p_text) {
110
111 popup->set_item_text(p_idx, p_text);
112 }
set_item_icon(int p_idx,const Ref<Texture> & p_icon)113 void OptionButton::set_item_icon(int p_idx, const Ref<Texture> &p_icon) {
114
115 popup->set_item_icon(p_idx, p_icon);
116 }
set_item_ID(int p_idx,int p_ID)117 void OptionButton::set_item_ID(int p_idx, int p_ID) {
118
119 popup->set_item_ID(p_idx, p_ID);
120 }
121
set_item_metadata(int p_idx,const Variant & p_metadata)122 void OptionButton::set_item_metadata(int p_idx, const Variant &p_metadata) {
123
124 popup->set_item_metadata(p_idx, p_metadata);
125 }
126
set_item_disabled(int p_idx,bool p_disabled)127 void OptionButton::set_item_disabled(int p_idx, bool p_disabled) {
128
129 popup->set_item_disabled(p_idx, p_disabled);
130 }
131
get_item_text(int p_idx) const132 String OptionButton::get_item_text(int p_idx) const {
133
134 return popup->get_item_text(p_idx);
135 }
136
get_item_icon(int p_idx) const137 Ref<Texture> OptionButton::get_item_icon(int p_idx) const {
138
139 return popup->get_item_icon(p_idx);
140 }
141
get_item_ID(int p_idx) const142 int OptionButton::get_item_ID(int p_idx) const {
143
144 return popup->get_item_ID(p_idx);
145 }
get_item_metadata(int p_idx) const146 Variant OptionButton::get_item_metadata(int p_idx) const {
147
148 return popup->get_item_metadata(p_idx);
149 }
150
is_item_disabled(int p_idx) const151 bool OptionButton::is_item_disabled(int p_idx) const {
152
153 return popup->is_item_disabled(p_idx);
154 }
155
get_item_count() const156 int OptionButton::get_item_count() const {
157
158 return popup->get_item_count();
159 }
160
add_separator()161 void OptionButton::add_separator() {
162
163 popup->add_separator();
164 }
165
clear()166 void OptionButton::clear() {
167
168 popup->clear();
169 set_text("");
170 current = -1;
171 }
172
_select(int p_idx,bool p_emit)173 void OptionButton::_select(int p_idx, bool p_emit) {
174
175 if (p_idx < 0)
176 return;
177 if (p_idx == current)
178 return;
179
180 ERR_FAIL_INDEX(p_idx, popup->get_item_count());
181
182 for (int i = 0; i < popup->get_item_count(); i++) {
183
184 popup->set_item_checked(i, i == p_idx);
185 }
186
187 current = p_idx;
188 set_text(popup->get_item_text(current));
189 set_icon(popup->get_item_icon(current));
190
191 if (is_inside_tree() && p_emit)
192 emit_signal("item_selected", current);
193 }
194
_select_int(int p_which)195 void OptionButton::_select_int(int p_which) {
196
197 if (p_which < 0 || p_which >= popup->get_item_count())
198 return;
199 _select(p_which, false);
200 }
201
select(int p_idx)202 void OptionButton::select(int p_idx) {
203
204 _select(p_idx, false);
205 }
206
get_selected() const207 int OptionButton::get_selected() const {
208
209 return current;
210 }
211
get_selected_ID() const212 int OptionButton::get_selected_ID() const {
213
214 int idx = get_selected();
215 if (idx < 0)
216 return 0;
217 return get_item_ID(current);
218 }
get_selected_metadata() const219 Variant OptionButton::get_selected_metadata() const {
220
221 int idx = get_selected();
222 if (idx < 0)
223 return Variant();
224 return get_item_metadata(current);
225 }
226
remove_item(int p_idx)227 void OptionButton::remove_item(int p_idx) {
228
229 popup->remove_item(p_idx);
230 }
231
_get_items() const232 Array OptionButton::_get_items() const {
233
234 Array items;
235 for (int i = 0; i < get_item_count(); i++) {
236
237 items.push_back(get_item_text(i));
238 items.push_back(get_item_icon(i));
239 items.push_back(is_item_disabled(i));
240 items.push_back(get_item_ID(i));
241 items.push_back(get_item_metadata(i));
242 }
243
244 return items;
245 }
_set_items(const Array & p_items)246 void OptionButton::_set_items(const Array &p_items) {
247
248 ERR_FAIL_COND(p_items.size() % 5);
249 clear();
250
251 for (int i = 0; i < p_items.size(); i += 5) {
252
253 String text = p_items[i + 0];
254 Ref<Texture> icon = p_items[i + 1];
255 bool disabled = p_items[i + 2];
256 int id = p_items[i + 3];
257 Variant meta = p_items[i + 4];
258
259 int idx = get_item_count();
260 add_item(text, id);
261 set_item_icon(idx, icon);
262 set_item_disabled(idx, disabled);
263 set_item_metadata(idx, meta);
264 }
265 }
266
get_translatable_strings(List<String> * p_strings) const267 void OptionButton::get_translatable_strings(List<String> *p_strings) const {
268
269 return popup->get_translatable_strings(p_strings);
270 }
271
_bind_methods()272 void OptionButton::_bind_methods() {
273
274 ObjectTypeDB::bind_method(_MD("_selected"), &OptionButton::_selected);
275
276 ObjectTypeDB::bind_method(_MD("add_item", "label", "id"), &OptionButton::add_item, DEFVAL(-1));
277 ObjectTypeDB::bind_method(_MD("add_icon_item", "texture:Texture", "label", "id"), &OptionButton::add_icon_item);
278 ObjectTypeDB::bind_method(_MD("set_item_text", "idx", "text"), &OptionButton::set_item_text);
279 ObjectTypeDB::bind_method(_MD("set_item_icon", "idx", "texture:Texture"), &OptionButton::set_item_icon);
280 ObjectTypeDB::bind_method(_MD("set_item_disabled", "idx", "disabled"), &OptionButton::set_item_disabled);
281 ObjectTypeDB::bind_method(_MD("set_item_ID", "idx", "id"), &OptionButton::set_item_ID);
282 ObjectTypeDB::bind_method(_MD("set_item_metadata", "idx", "metadata"), &OptionButton::set_item_metadata);
283 ObjectTypeDB::bind_method(_MD("get_item_text", "idx"), &OptionButton::get_item_text);
284 ObjectTypeDB::bind_method(_MD("get_item_icon:Texture", "idx"), &OptionButton::get_item_icon);
285 ObjectTypeDB::bind_method(_MD("get_item_ID", "idx"), &OptionButton::get_item_ID);
286 ObjectTypeDB::bind_method(_MD("get_item_metadata", "idx"), &OptionButton::get_item_metadata);
287 ObjectTypeDB::bind_method(_MD("is_item_disabled", "idx"), &OptionButton::is_item_disabled);
288 ObjectTypeDB::bind_method(_MD("get_item_count"), &OptionButton::get_item_count);
289 ObjectTypeDB::bind_method(_MD("add_separator"), &OptionButton::add_separator);
290 ObjectTypeDB::bind_method(_MD("clear"), &OptionButton::clear);
291 ObjectTypeDB::bind_method(_MD("select", "idx"), &OptionButton::select);
292 ObjectTypeDB::bind_method(_MD("get_selected"), &OptionButton::get_selected);
293 ObjectTypeDB::bind_method(_MD("get_selected_ID"), &OptionButton::get_selected_ID);
294 ObjectTypeDB::bind_method(_MD("get_selected_metadata"), &OptionButton::get_selected_metadata);
295 ObjectTypeDB::bind_method(_MD("remove_item", "idx"), &OptionButton::remove_item);
296 ObjectTypeDB::bind_method(_MD("_select_int"), &OptionButton::_select_int);
297
298 ObjectTypeDB::bind_method(_MD("_set_items"), &OptionButton::_set_items);
299 ObjectTypeDB::bind_method(_MD("_get_items"), &OptionButton::_get_items);
300
301 ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), _SCS("_select_int"), _SCS("get_selected"));
302 ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), _SCS("_set_items"), _SCS("_get_items"));
303 ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "ID")));
304 }
305
OptionButton()306 OptionButton::OptionButton() {
307
308 popup = memnew(PopupMenu);
309 popup->hide();
310 popup->set_as_toplevel(true);
311 add_child(popup);
312 popup->connect("item_pressed", this, "_selected");
313
314 current = -1;
315 set_text_align(ALIGN_LEFT);
316 }
317
~OptionButton()318 OptionButton::~OptionButton() {
319 }
320