1 | /**************************************************************************/ |
2 | /* button.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
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 | |
31 | #include "button.h" |
32 | |
33 | #include "core/string/translation.h" |
34 | #include "scene/theme/theme_db.h" |
35 | #include "servers/rendering_server.h" |
36 | |
37 | Size2 Button::get_minimum_size() const { |
38 | Ref<Texture2D> _icon = icon; |
39 | if (_icon.is_null() && has_theme_icon(SNAME("icon" ))) { |
40 | _icon = theme_cache.icon; |
41 | } |
42 | |
43 | return get_minimum_size_for_text_and_icon("" , _icon); |
44 | } |
45 | |
46 | void Button::_set_internal_margin(Side p_side, float p_value) { |
47 | _internal_margin[p_side] = p_value; |
48 | } |
49 | |
50 | void Button::_queue_update_size_cache() { |
51 | } |
52 | |
53 | void Button::_notification(int p_what) { |
54 | switch (p_what) { |
55 | case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { |
56 | queue_redraw(); |
57 | } break; |
58 | |
59 | case NOTIFICATION_TRANSLATION_CHANGED: { |
60 | xl_text = atr(text); |
61 | _shape(); |
62 | |
63 | update_minimum_size(); |
64 | queue_redraw(); |
65 | } break; |
66 | |
67 | case NOTIFICATION_THEME_CHANGED: { |
68 | _shape(); |
69 | |
70 | update_minimum_size(); |
71 | queue_redraw(); |
72 | } break; |
73 | |
74 | case NOTIFICATION_DRAW: { |
75 | RID ci = get_canvas_item(); |
76 | Size2 size = get_size(); |
77 | Color color; |
78 | Color color_icon(1, 1, 1, 1); |
79 | |
80 | Ref<StyleBox> style = theme_cache.normal; |
81 | bool rtl = is_layout_rtl(); |
82 | const bool is_clipped = clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING; |
83 | |
84 | switch (get_draw_mode()) { |
85 | case DRAW_NORMAL: { |
86 | if (rtl && has_theme_stylebox(SNAME("normal_mirrored" ))) { |
87 | style = theme_cache.normal_mirrored; |
88 | } else { |
89 | style = theme_cache.normal; |
90 | } |
91 | |
92 | if (!flat) { |
93 | style->draw(ci, Rect2(Point2(0, 0), size)); |
94 | } |
95 | |
96 | // Focus colors only take precedence over normal state. |
97 | if (has_focus()) { |
98 | color = theme_cache.font_focus_color; |
99 | if (has_theme_color(SNAME("icon_focus_color" ))) { |
100 | color_icon = theme_cache.icon_focus_color; |
101 | } |
102 | } else { |
103 | color = theme_cache.font_color; |
104 | if (has_theme_color(SNAME("icon_normal_color" ))) { |
105 | color_icon = theme_cache.icon_normal_color; |
106 | } |
107 | } |
108 | } break; |
109 | case DRAW_HOVER_PRESSED: { |
110 | // Edge case for CheckButton and CheckBox. |
111 | if (has_theme_stylebox("hover_pressed" )) { |
112 | if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored" ))) { |
113 | style = theme_cache.hover_pressed_mirrored; |
114 | } else { |
115 | style = theme_cache.hover_pressed; |
116 | } |
117 | |
118 | if (!flat) { |
119 | style->draw(ci, Rect2(Point2(0, 0), size)); |
120 | } |
121 | if (has_theme_color(SNAME("font_hover_pressed_color" ))) { |
122 | color = theme_cache.font_hover_pressed_color; |
123 | } |
124 | if (has_theme_color(SNAME("icon_hover_pressed_color" ))) { |
125 | color_icon = theme_cache.icon_hover_pressed_color; |
126 | } |
127 | |
128 | break; |
129 | } |
130 | [[fallthrough]]; |
131 | } |
132 | case DRAW_PRESSED: { |
133 | if (rtl && has_theme_stylebox(SNAME("pressed_mirrored" ))) { |
134 | style = theme_cache.pressed_mirrored; |
135 | } else { |
136 | style = theme_cache.pressed; |
137 | } |
138 | |
139 | if (!flat) { |
140 | style->draw(ci, Rect2(Point2(0, 0), size)); |
141 | } |
142 | if (has_theme_color(SNAME("font_pressed_color" ))) { |
143 | color = theme_cache.font_pressed_color; |
144 | } else { |
145 | color = theme_cache.font_color; |
146 | } |
147 | if (has_theme_color(SNAME("icon_pressed_color" ))) { |
148 | color_icon = theme_cache.icon_pressed_color; |
149 | } |
150 | |
151 | } break; |
152 | case DRAW_HOVER: { |
153 | if (rtl && has_theme_stylebox(SNAME("hover_mirrored" ))) { |
154 | style = theme_cache.hover_mirrored; |
155 | } else { |
156 | style = theme_cache.hover; |
157 | } |
158 | |
159 | if (!flat) { |
160 | style->draw(ci, Rect2(Point2(0, 0), size)); |
161 | } |
162 | color = theme_cache.font_hover_color; |
163 | if (has_theme_color(SNAME("icon_hover_color" ))) { |
164 | color_icon = theme_cache.icon_hover_color; |
165 | } |
166 | |
167 | } break; |
168 | case DRAW_DISABLED: { |
169 | if (rtl && has_theme_stylebox(SNAME("disabled_mirrored" ))) { |
170 | style = theme_cache.disabled_mirrored; |
171 | } else { |
172 | style = theme_cache.disabled; |
173 | } |
174 | |
175 | if (!flat) { |
176 | style->draw(ci, Rect2(Point2(0, 0), size)); |
177 | } |
178 | color = theme_cache.font_disabled_color; |
179 | if (has_theme_color(SNAME("icon_disabled_color" ))) { |
180 | color_icon = theme_cache.icon_disabled_color; |
181 | } else { |
182 | color_icon.a = 0.4; |
183 | } |
184 | |
185 | } break; |
186 | } |
187 | |
188 | if (has_focus()) { |
189 | Ref<StyleBox> style2 = theme_cache.focus; |
190 | style2->draw(ci, Rect2(Point2(), size)); |
191 | } |
192 | |
193 | Ref<Texture2D> _icon; |
194 | if (icon.is_null() && has_theme_icon(SNAME("icon" ))) { |
195 | _icon = theme_cache.icon; |
196 | } else { |
197 | _icon = icon; |
198 | } |
199 | |
200 | Rect2 icon_region; |
201 | HorizontalAlignment icon_align_rtl_checked = horizontal_icon_alignment; |
202 | HorizontalAlignment align_rtl_checked = alignment; |
203 | // Swap icon and text alignment sides if right-to-left layout is set. |
204 | if (rtl) { |
205 | if (horizontal_icon_alignment == HORIZONTAL_ALIGNMENT_RIGHT) { |
206 | icon_align_rtl_checked = HORIZONTAL_ALIGNMENT_LEFT; |
207 | } else if (horizontal_icon_alignment == HORIZONTAL_ALIGNMENT_LEFT) { |
208 | icon_align_rtl_checked = HORIZONTAL_ALIGNMENT_RIGHT; |
209 | } |
210 | if (alignment == HORIZONTAL_ALIGNMENT_RIGHT) { |
211 | align_rtl_checked = HORIZONTAL_ALIGNMENT_LEFT; |
212 | } else if (alignment == HORIZONTAL_ALIGNMENT_LEFT) { |
213 | align_rtl_checked = HORIZONTAL_ALIGNMENT_RIGHT; |
214 | } |
215 | } |
216 | if (!_icon.is_null()) { |
217 | int valign = size.height - style->get_minimum_size().y; |
218 | |
219 | int voffset = 0; |
220 | Size2 icon_size = _icon->get_size(); |
221 | |
222 | // Fix vertical size. |
223 | if (vertical_icon_alignment != VERTICAL_ALIGNMENT_CENTER) { |
224 | valign -= text_buf->get_size().height; |
225 | } |
226 | |
227 | float icon_ofs_region = 0.0; |
228 | Point2 style_offset; |
229 | if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) { |
230 | style_offset.x = style->get_margin(SIDE_LEFT); |
231 | if (_internal_margin[SIDE_LEFT] > 0) { |
232 | icon_ofs_region = _internal_margin[SIDE_LEFT] + theme_cache.h_separation; |
233 | } |
234 | } else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) { |
235 | style_offset.x = 0.0; |
236 | } else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_RIGHT) { |
237 | style_offset.x = -style->get_margin(SIDE_RIGHT); |
238 | if (_internal_margin[SIDE_RIGHT] > 0) { |
239 | icon_ofs_region = -_internal_margin[SIDE_RIGHT] - theme_cache.h_separation; |
240 | } |
241 | } |
242 | style_offset.y = style->get_margin(SIDE_TOP); |
243 | |
244 | if (expand_icon) { |
245 | Size2 _size = get_size() - style->get_offset() * 2; |
246 | int icon_text_separation = text.is_empty() ? 0 : theme_cache.h_separation; |
247 | _size.width -= icon_text_separation + icon_ofs_region; |
248 | if (!is_clipped && icon_align_rtl_checked != HORIZONTAL_ALIGNMENT_CENTER) { |
249 | _size.width -= text_buf->get_size().width; |
250 | } |
251 | if (vertical_icon_alignment != VERTICAL_ALIGNMENT_CENTER) { |
252 | _size.height -= text_buf->get_size().height; |
253 | } |
254 | float icon_width = _icon->get_width() * _size.height / _icon->get_height(); |
255 | float icon_height = _size.height; |
256 | |
257 | if (icon_width > _size.width) { |
258 | icon_width = _size.width; |
259 | icon_height = _icon->get_height() * icon_width / _icon->get_width(); |
260 | } |
261 | |
262 | icon_size = Size2(icon_width, icon_height); |
263 | } |
264 | icon_size = _fit_icon_size(icon_size); |
265 | |
266 | if (vertical_icon_alignment == VERTICAL_ALIGNMENT_TOP) { |
267 | voffset = -(valign - icon_size.y) / 2; |
268 | } |
269 | if (vertical_icon_alignment == VERTICAL_ALIGNMENT_BOTTOM) { |
270 | voffset = (valign - icon_size.y) / 2 + text_buf->get_size().y; |
271 | } |
272 | |
273 | if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) { |
274 | icon_region = Rect2(style_offset + Point2(icon_ofs_region, voffset + Math::floor((valign - icon_size.y) * 0.5)), icon_size); |
275 | } else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) { |
276 | icon_region = Rect2(style_offset + Point2(icon_ofs_region + Math::floor((size.x - icon_size.x) * 0.5), voffset + Math::floor((valign - icon_size.y) * 0.5)), icon_size); |
277 | } else { |
278 | icon_region = Rect2(style_offset + Point2(icon_ofs_region + size.x - icon_size.x, voffset + Math::floor((valign - icon_size.y) * 0.5)), icon_size); |
279 | } |
280 | |
281 | if (icon_region.size.width > 0) { |
282 | Rect2 icon_region_rounded = Rect2(icon_region.position.round(), icon_region.size.round()); |
283 | draw_texture_rect(_icon, icon_region_rounded, false, color_icon); |
284 | } |
285 | } |
286 | |
287 | Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + theme_cache.h_separation, 0) : Point2(); |
288 | if (align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER && icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) { |
289 | icon_ofs.x = 0.0; |
290 | } |
291 | |
292 | int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width; |
293 | if (_internal_margin[SIDE_LEFT] > 0) { |
294 | text_clip -= _internal_margin[SIDE_LEFT] + theme_cache.h_separation; |
295 | } |
296 | if (_internal_margin[SIDE_RIGHT] > 0) { |
297 | text_clip -= _internal_margin[SIDE_RIGHT] + theme_cache.h_separation; |
298 | } |
299 | |
300 | text_buf->set_width(is_clipped ? text_clip : -1); |
301 | |
302 | int text_width = MAX(1, is_clipped ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x); |
303 | |
304 | Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_LEFT], 0)) / 2.0; |
305 | |
306 | if (vertical_icon_alignment == VERTICAL_ALIGNMENT_TOP) { |
307 | text_ofs.y += icon_region.size.height / 2; |
308 | } |
309 | if (vertical_icon_alignment == VERTICAL_ALIGNMENT_BOTTOM) { |
310 | text_ofs.y -= icon_region.size.height / 2; |
311 | } |
312 | |
313 | text_buf->set_alignment(align_rtl_checked); |
314 | text_buf->set_width(text_width); |
315 | switch (align_rtl_checked) { |
316 | case HORIZONTAL_ALIGNMENT_FILL: |
317 | case HORIZONTAL_ALIGNMENT_LEFT: { |
318 | if (icon_align_rtl_checked != HORIZONTAL_ALIGNMENT_LEFT) { |
319 | icon_ofs.x = 0.0; |
320 | } |
321 | if (_internal_margin[SIDE_LEFT] > 0) { |
322 | text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + theme_cache.h_separation; |
323 | } else { |
324 | text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x; |
325 | } |
326 | text_ofs.y += style->get_offset().y; |
327 | } break; |
328 | case HORIZONTAL_ALIGNMENT_CENTER: { |
329 | if (text_ofs.x < 0) { |
330 | text_ofs.x = 0; |
331 | } |
332 | if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) { |
333 | text_ofs += icon_ofs; |
334 | } |
335 | text_ofs += style->get_offset(); |
336 | } break; |
337 | case HORIZONTAL_ALIGNMENT_RIGHT: { |
338 | if (_internal_margin[SIDE_RIGHT] > 0) { |
339 | text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - theme_cache.h_separation; |
340 | } else { |
341 | text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width; |
342 | } |
343 | text_ofs.y += style->get_offset().y; |
344 | if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_RIGHT) { |
345 | text_ofs.x -= icon_ofs.x; |
346 | } |
347 | } break; |
348 | } |
349 | |
350 | Color font_outline_color = theme_cache.font_outline_color; |
351 | int outline_size = theme_cache.outline_size; |
352 | if (outline_size > 0 && font_outline_color.a > 0) { |
353 | text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color); |
354 | } |
355 | text_buf->draw(ci, text_ofs, color); |
356 | } break; |
357 | } |
358 | } |
359 | |
360 | Size2 Button::_fit_icon_size(const Size2 &p_size) const { |
361 | int max_width = theme_cache.icon_max_width; |
362 | Size2 icon_size = p_size; |
363 | |
364 | if (max_width > 0 && icon_size.width > max_width) { |
365 | icon_size.height = icon_size.height * max_width / icon_size.width; |
366 | icon_size.width = max_width; |
367 | } |
368 | |
369 | return icon_size; |
370 | } |
371 | |
372 | Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Texture2D> p_icon) const { |
373 | Ref<TextParagraph> paragraph; |
374 | if (p_text.is_empty()) { |
375 | paragraph = text_buf; |
376 | } else { |
377 | paragraph.instantiate(); |
378 | const_cast<Button *>(this)->_shape(paragraph, p_text); |
379 | } |
380 | |
381 | Size2 minsize = paragraph->get_size(); |
382 | if (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { |
383 | minsize.width = 0; |
384 | } |
385 | |
386 | if (!expand_icon && p_icon.is_valid()) { |
387 | Size2 icon_size = _fit_icon_size(p_icon->get_size()); |
388 | if (vertical_icon_alignment == VERTICAL_ALIGNMENT_CENTER) { |
389 | minsize.height = MAX(minsize.height, icon_size.height); |
390 | } else { |
391 | minsize.height += icon_size.height; |
392 | } |
393 | |
394 | if (horizontal_icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) { |
395 | minsize.width += icon_size.width; |
396 | if (!xl_text.is_empty() || !p_text.is_empty()) { |
397 | minsize.width += MAX(0, theme_cache.h_separation); |
398 | } |
399 | } else { |
400 | minsize.width = MAX(minsize.width, icon_size.width); |
401 | } |
402 | } |
403 | |
404 | if (!xl_text.is_empty() || !p_text.is_empty()) { |
405 | Ref<Font> font = theme_cache.font; |
406 | float font_height = font->get_height(theme_cache.font_size); |
407 | if (vertical_icon_alignment == VERTICAL_ALIGNMENT_CENTER) { |
408 | minsize.height = MAX(font_height, minsize.height); |
409 | } else { |
410 | minsize.height += font_height; |
411 | } |
412 | } |
413 | |
414 | return theme_cache.normal->get_minimum_size() + minsize; |
415 | } |
416 | |
417 | void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) { |
418 | if (p_paragraph.is_null()) { |
419 | p_paragraph = text_buf; |
420 | } |
421 | |
422 | if (p_text.is_empty()) { |
423 | p_text = xl_text; |
424 | } |
425 | |
426 | p_paragraph->clear(); |
427 | |
428 | Ref<Font> font = theme_cache.font; |
429 | int font_size = theme_cache.font_size; |
430 | if (font.is_null() || font_size == 0) { |
431 | // Can't shape without a valid font and a non-zero size. |
432 | return; |
433 | } |
434 | |
435 | if (text_direction == Control::TEXT_DIRECTION_INHERITED) { |
436 | p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); |
437 | } else { |
438 | p_paragraph->set_direction((TextServer::Direction)text_direction); |
439 | } |
440 | p_paragraph->add_string(p_text, font, font_size, language); |
441 | p_paragraph->set_text_overrun_behavior(overrun_behavior); |
442 | } |
443 | |
444 | void Button::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) { |
445 | if (overrun_behavior != p_behavior) { |
446 | overrun_behavior = p_behavior; |
447 | _shape(); |
448 | |
449 | queue_redraw(); |
450 | update_minimum_size(); |
451 | } |
452 | } |
453 | |
454 | TextServer::OverrunBehavior Button::get_text_overrun_behavior() const { |
455 | return overrun_behavior; |
456 | } |
457 | |
458 | void Button::set_text(const String &p_text) { |
459 | if (text != p_text) { |
460 | text = p_text; |
461 | xl_text = atr(text); |
462 | _shape(); |
463 | |
464 | queue_redraw(); |
465 | update_minimum_size(); |
466 | } |
467 | } |
468 | |
469 | String Button::get_text() const { |
470 | return text; |
471 | } |
472 | |
473 | void Button::set_text_direction(Control::TextDirection p_text_direction) { |
474 | ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); |
475 | if (text_direction != p_text_direction) { |
476 | text_direction = p_text_direction; |
477 | _shape(); |
478 | queue_redraw(); |
479 | } |
480 | } |
481 | |
482 | Control::TextDirection Button::get_text_direction() const { |
483 | return text_direction; |
484 | } |
485 | |
486 | void Button::set_language(const String &p_language) { |
487 | if (language != p_language) { |
488 | language = p_language; |
489 | _shape(); |
490 | queue_redraw(); |
491 | } |
492 | } |
493 | |
494 | String Button::get_language() const { |
495 | return language; |
496 | } |
497 | |
498 | void Button::set_icon(const Ref<Texture2D> &p_icon) { |
499 | if (icon == p_icon) { |
500 | return; |
501 | } |
502 | |
503 | if (icon.is_valid()) { |
504 | icon->disconnect_changed(callable_mp(this, &Button::_texture_changed)); |
505 | } |
506 | |
507 | icon = p_icon; |
508 | |
509 | if (icon.is_valid()) { |
510 | icon->connect_changed(callable_mp(this, &Button::_texture_changed)); |
511 | } |
512 | |
513 | queue_redraw(); |
514 | update_minimum_size(); |
515 | } |
516 | |
517 | void Button::_texture_changed() { |
518 | queue_redraw(); |
519 | update_minimum_size(); |
520 | } |
521 | |
522 | Ref<Texture2D> Button::get_icon() const { |
523 | return icon; |
524 | } |
525 | |
526 | void Button::set_expand_icon(bool p_enabled) { |
527 | if (expand_icon != p_enabled) { |
528 | expand_icon = p_enabled; |
529 | _queue_update_size_cache(); |
530 | queue_redraw(); |
531 | update_minimum_size(); |
532 | } |
533 | } |
534 | |
535 | bool Button::is_expand_icon() const { |
536 | return expand_icon; |
537 | } |
538 | |
539 | void Button::set_flat(bool p_enabled) { |
540 | if (flat != p_enabled) { |
541 | flat = p_enabled; |
542 | queue_redraw(); |
543 | } |
544 | } |
545 | |
546 | bool Button::is_flat() const { |
547 | return flat; |
548 | } |
549 | |
550 | void Button::set_clip_text(bool p_enabled) { |
551 | if (clip_text != p_enabled) { |
552 | clip_text = p_enabled; |
553 | queue_redraw(); |
554 | update_minimum_size(); |
555 | } |
556 | } |
557 | |
558 | bool Button::get_clip_text() const { |
559 | return clip_text; |
560 | } |
561 | |
562 | void Button::set_text_alignment(HorizontalAlignment p_alignment) { |
563 | if (alignment != p_alignment) { |
564 | alignment = p_alignment; |
565 | queue_redraw(); |
566 | } |
567 | } |
568 | |
569 | HorizontalAlignment Button::get_text_alignment() const { |
570 | return alignment; |
571 | } |
572 | |
573 | void Button::set_icon_alignment(HorizontalAlignment p_alignment) { |
574 | horizontal_icon_alignment = p_alignment; |
575 | update_minimum_size(); |
576 | queue_redraw(); |
577 | } |
578 | |
579 | void Button::set_vertical_icon_alignment(VerticalAlignment p_alignment) { |
580 | vertical_icon_alignment = p_alignment; |
581 | update_minimum_size(); |
582 | queue_redraw(); |
583 | } |
584 | |
585 | HorizontalAlignment Button::get_icon_alignment() const { |
586 | return horizontal_icon_alignment; |
587 | } |
588 | |
589 | VerticalAlignment Button::get_vertical_icon_alignment() const { |
590 | return vertical_icon_alignment; |
591 | } |
592 | |
593 | void Button::_bind_methods() { |
594 | ClassDB::bind_method(D_METHOD("set_text" , "text" ), &Button::set_text); |
595 | ClassDB::bind_method(D_METHOD("get_text" ), &Button::get_text); |
596 | ClassDB::bind_method(D_METHOD("set_text_overrun_behavior" , "overrun_behavior" ), &Button::set_text_overrun_behavior); |
597 | ClassDB::bind_method(D_METHOD("get_text_overrun_behavior" ), &Button::get_text_overrun_behavior); |
598 | ClassDB::bind_method(D_METHOD("set_text_direction" , "direction" ), &Button::set_text_direction); |
599 | ClassDB::bind_method(D_METHOD("get_text_direction" ), &Button::get_text_direction); |
600 | ClassDB::bind_method(D_METHOD("set_language" , "language" ), &Button::set_language); |
601 | ClassDB::bind_method(D_METHOD("get_language" ), &Button::get_language); |
602 | ClassDB::bind_method(D_METHOD("set_button_icon" , "texture" ), &Button::set_icon); |
603 | ClassDB::bind_method(D_METHOD("get_button_icon" ), &Button::get_icon); |
604 | ClassDB::bind_method(D_METHOD("set_flat" , "enabled" ), &Button::set_flat); |
605 | ClassDB::bind_method(D_METHOD("is_flat" ), &Button::is_flat); |
606 | ClassDB::bind_method(D_METHOD("set_clip_text" , "enabled" ), &Button::set_clip_text); |
607 | ClassDB::bind_method(D_METHOD("get_clip_text" ), &Button::get_clip_text); |
608 | ClassDB::bind_method(D_METHOD("set_text_alignment" , "alignment" ), &Button::set_text_alignment); |
609 | ClassDB::bind_method(D_METHOD("get_text_alignment" ), &Button::get_text_alignment); |
610 | ClassDB::bind_method(D_METHOD("set_icon_alignment" , "icon_alignment" ), &Button::set_icon_alignment); |
611 | ClassDB::bind_method(D_METHOD("get_icon_alignment" ), &Button::get_icon_alignment); |
612 | ClassDB::bind_method(D_METHOD("set_vertical_icon_alignment" , "vertical_icon_alignment" ), &Button::set_vertical_icon_alignment); |
613 | ClassDB::bind_method(D_METHOD("get_vertical_icon_alignment" ), &Button::get_vertical_icon_alignment); |
614 | ClassDB::bind_method(D_METHOD("set_expand_icon" , "enabled" ), &Button::set_expand_icon); |
615 | ClassDB::bind_method(D_METHOD("is_expand_icon" ), &Button::is_expand_icon); |
616 | |
617 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "text" , PROPERTY_HINT_MULTILINE_TEXT), "set_text" , "get_text" ); |
618 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "icon" , PROPERTY_HINT_RESOURCE_TYPE, "Texture2D" ), "set_button_icon" , "get_button_icon" ); |
619 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat" ), "set_flat" , "is_flat" ); |
620 | |
621 | ADD_GROUP("Text Behavior" , "" ); |
622 | ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment" , PROPERTY_HINT_ENUM, "Left,Center,Right" ), "set_text_alignment" , "get_text_alignment" ); |
623 | ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior" , PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis" ), "set_text_overrun_behavior" , "get_text_overrun_behavior" ); |
624 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text" ), "set_clip_text" , "get_clip_text" ); |
625 | |
626 | ADD_GROUP("Icon Behavior" , "" ); |
627 | ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_alignment" , PROPERTY_HINT_ENUM, "Left,Center,Right" ), "set_icon_alignment" , "get_icon_alignment" ); |
628 | ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_icon_alignment" , PROPERTY_HINT_ENUM, "Top,Center,Bottom" ), "set_vertical_icon_alignment" , "get_vertical_icon_alignment" ); |
629 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_icon" ), "set_expand_icon" , "is_expand_icon" ); |
630 | |
631 | ADD_GROUP("BiDi" , "" ); |
632 | ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction" , PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited" ), "set_text_direction" , "get_text_direction" ); |
633 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "language" , PROPERTY_HINT_LOCALE_ID, "" ), "set_language" , "get_language" ); |
634 | |
635 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, normal); |
636 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, normal_mirrored); |
637 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, pressed); |
638 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, pressed_mirrored); |
639 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, hover); |
640 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, hover_mirrored); |
641 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, hover_pressed); |
642 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, hover_pressed_mirrored); |
643 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, disabled); |
644 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, disabled_mirrored); |
645 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, focus); |
646 | |
647 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_color); |
648 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_focus_color); |
649 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_pressed_color); |
650 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_hover_color); |
651 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_hover_pressed_color); |
652 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_disabled_color); |
653 | |
654 | BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, Button, font); |
655 | BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, Button, font_size); |
656 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, outline_size); |
657 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_outline_color); |
658 | |
659 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_normal_color); |
660 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_focus_color); |
661 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_pressed_color); |
662 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_hover_color); |
663 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_hover_pressed_color); |
664 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_disabled_color); |
665 | |
666 | BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Button, icon); |
667 | |
668 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, h_separation); |
669 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, icon_max_width); |
670 | } |
671 | |
672 | Button::Button(const String &p_text) { |
673 | text_buf.instantiate(); |
674 | text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_TRIM_EDGE_SPACES); |
675 | set_mouse_filter(MOUSE_FILTER_STOP); |
676 | |
677 | set_text(p_text); |
678 | } |
679 | |
680 | Button::~Button() { |
681 | } |
682 | |