2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* button.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "button.h"
2019-04-05 14:06:16 +02:00
2020-11-07 23:33:38 +01:00
# include "core/string/translation.h"
2023-09-08 21:00:10 +02:00
# include "scene/theme/theme_db.h"
2020-03-27 19:21:27 +01:00
# include "servers/rendering_server.h"
2014-02-10 02:10:30 +01:00
Size2 Button : : get_minimum_size ( ) const {
2022-08-12 13:39:22 +02:00
Ref < Texture2D > _icon = icon ;
if ( _icon . is_null ( ) & & has_theme_icon ( SNAME ( " icon " ) ) ) {
2022-08-31 14:02:40 +02:00
_icon = theme_cache . icon ;
2022-05-08 00:25:35 +02:00
}
2021-02-22 14:54:12 +01:00
2022-03-19 02:15:55 +01:00
return get_minimum_size_for_text_and_icon ( " " , _icon ) ;
2014-02-10 02:10:30 +01:00
}
2020-12-22 17:24:29 +01:00
void Button : : _set_internal_margin ( Side p_side , float p_value ) {
_internal_margin [ p_side ] = p_value ;
2017-12-11 06:03:32 +01:00
}
2023-04-12 03:34:00 +02:00
void Button : : _queue_update_size_cache ( ) {
}
2022-08-13 07:46:07 +02:00
Ref < StyleBox > Button : : _get_current_stylebox ( ) const {
Ref < StyleBox > stylebox = theme_cache . normal ;
const bool rtl = is_layout_rtl ( ) ;
switch ( get_draw_mode ( ) ) {
case DRAW_NORMAL : {
if ( rtl & & has_theme_stylebox ( SNAME ( " normal_mirrored " ) ) ) {
stylebox = theme_cache . normal_mirrored ;
} else {
stylebox = theme_cache . normal ;
}
} break ;
case DRAW_HOVER_PRESSED : {
// Edge case for CheckButton and CheckBox.
if ( has_theme_stylebox ( " hover_pressed " ) ) {
if ( rtl & & has_theme_stylebox ( SNAME ( " hover_pressed_mirrored " ) ) ) {
stylebox = theme_cache . hover_pressed_mirrored ;
} else {
stylebox = theme_cache . hover_pressed ;
}
break ;
}
}
[[fallthrough]] ;
case DRAW_PRESSED : {
if ( rtl & & has_theme_stylebox ( SNAME ( " pressed_mirrored " ) ) ) {
stylebox = theme_cache . pressed_mirrored ;
} else {
stylebox = theme_cache . pressed ;
}
} break ;
case DRAW_HOVER : {
if ( rtl & & has_theme_stylebox ( SNAME ( " hover_mirrored " ) ) ) {
stylebox = theme_cache . hover_mirrored ;
} else {
stylebox = theme_cache . hover ;
}
} break ;
case DRAW_DISABLED : {
if ( rtl & & has_theme_stylebox ( SNAME ( " disabled_mirrored " ) ) ) {
stylebox = theme_cache . disabled_mirrored ;
} else {
stylebox = theme_cache . disabled ;
}
} break ;
}
return stylebox ;
}
2014-02-10 02:10:30 +01:00
void Button : : _notification ( int p_what ) {
2019-08-20 18:41:14 +02:00
switch ( p_what ) {
2020-09-03 13:22:16 +02:00
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED : {
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
} break ;
2022-02-15 18:06:48 +01:00
2019-08-20 18:41:14 +02:00
case NOTIFICATION_TRANSLATION_CHANGED : {
2021-05-27 19:31:33 +02:00
xl_text = atr ( text ) ;
2020-09-03 13:22:16 +02:00
_shape ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
} break ;
2022-02-15 18:06:48 +01:00
2020-09-03 13:22:16 +02:00
case NOTIFICATION_THEME_CHANGED : {
_shape ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2019-08-20 18:41:14 +02:00
} break ;
2022-02-15 18:06:48 +01:00
2024-01-09 21:12:26 +01:00
case NOTIFICATION_RESIZED : {
if ( autowrap_mode ! = TextServer : : AUTOWRAP_OFF ) {
_shape ( ) ;
update_minimum_size ( ) ;
queue_redraw ( ) ;
}
} break ;
2019-08-20 18:41:14 +02:00
case NOTIFICATION_DRAW : {
2022-08-13 07:46:07 +02:00
const RID ci = get_canvas_item ( ) ;
const Size2 size = get_size ( ) ;
2016-03-09 00:00:52 +01:00
2022-08-13 07:46:07 +02:00
const Ref < StyleBox > style = _get_current_stylebox ( ) ;
{ // Draws the stylebox in the current state.
if ( ! flat ) {
style - > draw ( ci , Rect2 ( Point2 ( ) , size ) ) ;
}
2014-02-10 02:10:30 +01:00
2022-08-13 07:46:07 +02:00
if ( has_focus ( ) ) {
Ref < StyleBox > style2 = theme_cache . focus ;
style2 - > draw ( ci , Rect2 ( Point2 ( ) , size ) ) ;
}
}
Ref < Texture2D > _icon = icon ;
if ( _icon . is_null ( ) & & has_theme_icon ( SNAME ( " icon " ) ) ) {
_icon = theme_cache . icon ;
}
if ( xl_text . is_empty ( ) & & _icon . is_null ( ) ) {
break ;
}
const float style_margin_left = style - > get_margin ( SIDE_LEFT ) ;
const float style_margin_right = style - > get_margin ( SIDE_RIGHT ) ;
const float style_margin_top = style - > get_margin ( SIDE_TOP ) ;
const float style_margin_bottom = style - > get_margin ( SIDE_BOTTOM ) ;
Size2 drawable_size_remained = size ;
{ // The size after the stelybox is stripped.
drawable_size_remained . width - = style_margin_left + style_margin_right ;
drawable_size_remained . height - = style_margin_top + style_margin_bottom ;
}
const int h_separation = MAX ( 0 , theme_cache . h_separation ) ;
2024-01-22 15:16:24 +01:00
float left_internal_margin_with_h_separation = _internal_margin [ SIDE_LEFT ] ;
float right_internal_margin_with_h_separation = _internal_margin [ SIDE_RIGHT ] ;
2022-08-13 07:46:07 +02:00
{ // The width reserved for internal element in derived classes (and h_separation if need).
2024-02-21 02:32:04 +01:00
if ( _internal_margin [ SIDE_LEFT ] > 0.0f ) {
left_internal_margin_with_h_separation + = h_separation ;
}
2020-09-03 13:22:16 +02:00
2024-02-21 02:32:04 +01:00
if ( _internal_margin [ SIDE_RIGHT ] > 0.0f ) {
right_internal_margin_with_h_separation + = h_separation ;
2022-08-13 07:46:07 +02:00
}
2024-01-22 15:16:24 +01:00
drawable_size_remained . width - = left_internal_margin_with_h_separation + right_internal_margin_with_h_separation ; // The size after the internal element is stripped.
2022-08-13 07:46:07 +02:00
}
HorizontalAlignment icon_align_rtl_checked = horizontal_icon_alignment ;
HorizontalAlignment align_rtl_checked = alignment ;
// Swap icon and text alignment sides if right-to-left layout is set.
if ( is_layout_rtl ( ) ) {
if ( horizontal_icon_alignment = = HORIZONTAL_ALIGNMENT_RIGHT ) {
icon_align_rtl_checked = HORIZONTAL_ALIGNMENT_LEFT ;
} else if ( horizontal_icon_alignment = = HORIZONTAL_ALIGNMENT_LEFT ) {
icon_align_rtl_checked = HORIZONTAL_ALIGNMENT_RIGHT ;
}
if ( alignment = = HORIZONTAL_ALIGNMENT_RIGHT ) {
align_rtl_checked = HORIZONTAL_ALIGNMENT_LEFT ;
} else if ( alignment = = HORIZONTAL_ALIGNMENT_LEFT ) {
align_rtl_checked = HORIZONTAL_ALIGNMENT_RIGHT ;
}
}
2021-10-26 16:28:12 +02:00
2022-08-13 07:46:07 +02:00
Color font_color ;
Color icon_modulate_color ( 1 , 1 , 1 , 1 ) ;
// Get the font color and icon modulate color in the current state.
switch ( get_draw_mode ( ) ) {
case DRAW_NORMAL : {
2021-10-26 16:28:12 +02:00
// Focus colors only take precedence over normal state.
if ( has_focus ( ) ) {
2022-08-13 07:46:07 +02:00
font_color = theme_cache . font_focus_color ;
2021-10-26 16:28:12 +02:00
if ( has_theme_color ( SNAME ( " icon_focus_color " ) ) ) {
2022-08-13 07:46:07 +02:00
icon_modulate_color = theme_cache . icon_focus_color ;
2021-10-26 16:28:12 +02:00
}
} else {
2022-08-13 07:46:07 +02:00
font_color = theme_cache . font_color ;
2021-10-26 16:28:12 +02:00
if ( has_theme_color ( SNAME ( " icon_normal_color " ) ) ) {
2022-08-13 07:46:07 +02:00
icon_modulate_color = theme_cache . icon_normal_color ;
2021-10-26 16:28:12 +02:00
}
2020-05-14 16:41:43 +02:00
}
2019-08-20 18:41:14 +02:00
} break ;
case DRAW_HOVER_PRESSED : {
2021-10-31 02:10:45 +02:00
// Edge case for CheckButton and CheckBox.
2022-02-08 10:14:58 +01:00
if ( has_theme_stylebox ( " hover_pressed " ) ) {
2021-07-17 23:22:52 +02:00
if ( has_theme_color ( SNAME ( " font_hover_pressed_color " ) ) ) {
2022-08-13 07:46:07 +02:00
font_color = theme_cache . font_hover_pressed_color ;
2020-05-14 16:41:43 +02:00
}
2021-07-17 23:22:52 +02:00
if ( has_theme_color ( SNAME ( " icon_hover_pressed_color " ) ) ) {
2022-08-13 07:46:07 +02:00
icon_modulate_color = theme_cache . icon_hover_pressed_color ;
2020-05-14 16:41:43 +02:00
}
2019-08-20 18:41:14 +02:00
break ;
}
}
2022-08-13 07:46:07 +02:00
[[fallthrough]] ;
2019-08-20 18:41:14 +02:00
case DRAW_PRESSED : {
2021-07-17 23:22:52 +02:00
if ( has_theme_color ( SNAME ( " font_pressed_color " ) ) ) {
2022-08-13 07:46:07 +02:00
font_color = theme_cache . font_pressed_color ;
2020-05-14 16:41:43 +02:00
} else {
2022-08-13 07:46:07 +02:00
font_color = theme_cache . font_color ;
2020-05-14 16:41:43 +02:00
}
2021-07-17 23:22:52 +02:00
if ( has_theme_color ( SNAME ( " icon_pressed_color " ) ) ) {
2022-08-13 07:46:07 +02:00
icon_modulate_color = theme_cache . icon_pressed_color ;
2020-05-14 16:41:43 +02:00
}
2018-09-24 01:56:30 +02:00
2019-08-20 18:41:14 +02:00
} break ;
case DRAW_HOVER : {
2022-08-13 07:46:07 +02:00
font_color = theme_cache . font_hover_color ;
2021-07-17 23:22:52 +02:00
if ( has_theme_color ( SNAME ( " icon_hover_color " ) ) ) {
2022-08-13 07:46:07 +02:00
icon_modulate_color = theme_cache . icon_hover_color ;
2020-05-14 16:41:43 +02:00
}
2019-08-20 18:41:14 +02:00
} break ;
case DRAW_DISABLED : {
2022-08-13 07:46:07 +02:00
font_color = theme_cache . font_disabled_color ;
2021-07-17 23:22:52 +02:00
if ( has_theme_color ( SNAME ( " icon_disabled_color " ) ) ) {
2022-08-13 07:46:07 +02:00
icon_modulate_color = theme_cache . icon_disabled_color ;
2022-01-30 20:25:42 +01:00
} else {
2022-08-13 07:46:07 +02:00
icon_modulate_color . a = 0.4 ;
2020-05-14 16:41:43 +02:00
}
2019-08-20 18:41:14 +02:00
} break ;
2018-09-24 01:56:30 +02:00
}
2015-06-08 15:36:11 +02:00
2024-01-09 21:12:26 +01:00
const bool is_clipped = clip_text | | overrun_behavior ! = TextServer : : OVERRUN_NO_TRIMMING | | autowrap_mode ! = TextServer : : AUTOWRAP_OFF ;
2022-08-13 07:46:07 +02:00
const Size2 custom_element_size = drawable_size_remained ;
// Draw the icon.
if ( _icon . is_valid ( ) ) {
Size2 icon_size ;
{ // Calculate the drawing size of the icon.
icon_size = _icon - > get_size ( ) ;
if ( expand_icon ) {
const Size2 text_buf_size = text_buf - > get_size ( ) ;
Size2 _size = custom_element_size ;
if ( ! is_clipped & & icon_align_rtl_checked ! = HORIZONTAL_ALIGNMENT_CENTER & & text_buf_size . width > 0.0f ) {
// If there is not enough space for icon and h_separation, h_separation will occupy the space first,
// so the icon's width may be negative. Keep it negative to make it easier to calculate the space
// reserved for text later.
_size . width - = text_buf_size . width + h_separation ;
}
if ( vertical_icon_alignment ! = VERTICAL_ALIGNMENT_CENTER ) {
_size . height - = text_buf_size . height ;
}
2019-08-20 18:41:14 +02:00
2022-08-13 07:46:07 +02:00
float icon_width = icon_size . width * _size . height / icon_size . height ;
float icon_height = _size . height ;
2023-03-03 21:21:41 +01:00
2022-08-13 07:46:07 +02:00
if ( icon_width > _size . width ) {
icon_width = _size . width ;
icon_height = icon_size . height * icon_width / icon_size . width ;
}
2023-03-03 21:21:41 +01:00
2022-08-13 07:46:07 +02:00
icon_size = Size2 ( icon_width , icon_height ) ;
2019-10-25 05:29:10 +02:00
}
2022-08-13 07:46:07 +02:00
icon_size = _fit_icon_size ( icon_size ) ;
2019-08-29 04:12:22 +02:00
}
2019-08-20 18:41:14 +02:00
2022-08-13 07:46:07 +02:00
if ( icon_size . width > 0.0f ) {
// Calculate the drawing position of the icon.
Point2 icon_ofs ;
switch ( icon_align_rtl_checked ) {
case HORIZONTAL_ALIGNMENT_CENTER : {
icon_ofs . x = ( custom_element_size . width - icon_size . width ) / 2.0f ;
}
[[fallthrough]] ;
case HORIZONTAL_ALIGNMENT_FILL :
case HORIZONTAL_ALIGNMENT_LEFT : {
icon_ofs . x + = style_margin_left ;
2024-01-22 15:16:24 +01:00
icon_ofs . x + = left_internal_margin_with_h_separation ;
2022-08-13 07:46:07 +02:00
} break ;
case HORIZONTAL_ALIGNMENT_RIGHT : {
icon_ofs . x = size . x - style_margin_right ;
2024-01-22 15:16:24 +01:00
icon_ofs . x - = right_internal_margin_with_h_separation ;
2022-08-13 07:46:07 +02:00
icon_ofs . x - = icon_size . width ;
} break ;
2019-08-20 18:41:14 +02:00
}
2022-08-13 07:46:07 +02:00
switch ( vertical_icon_alignment ) {
case VERTICAL_ALIGNMENT_CENTER : {
icon_ofs . y = ( custom_element_size . height - icon_size . height ) / 2.0f ;
}
[[fallthrough]] ;
case VERTICAL_ALIGNMENT_FILL :
case VERTICAL_ALIGNMENT_TOP : {
icon_ofs . y + = style_margin_top ;
} break ;
case VERTICAL_ALIGNMENT_BOTTOM : {
icon_ofs . y = size . y - style_margin_bottom - icon_size . height ;
} break ;
}
2019-10-25 05:29:10 +02:00
2022-08-13 07:46:07 +02:00
Rect2 icon_region = Rect2 ( icon_ofs , icon_size ) ;
draw_texture_rect ( _icon , icon_region , false , icon_modulate_color ) ;
2023-03-03 21:21:41 +01:00
}
2022-08-13 07:46:07 +02:00
if ( ! xl_text . is_empty ( ) ) {
// Update the size after the icon is stripped. Stripping only when the icon alignments are not center.
if ( icon_align_rtl_checked ! = HORIZONTAL_ALIGNMENT_CENTER ) {
// Subtract the space's width occupied by icon and h_separation together.
drawable_size_remained . width - = icon_size . width + h_separation ;
}
2019-10-25 05:29:10 +02:00
2022-08-13 07:46:07 +02:00
if ( vertical_icon_alignment ! = VERTICAL_ALIGNMENT_CENTER ) {
drawable_size_remained . height - = icon_size . height ;
}
2017-12-11 07:37:29 +01:00
}
2019-08-20 18:41:14 +02:00
}
2014-02-10 02:10:30 +01:00
2022-08-13 07:46:07 +02:00
// Draw the text.
if ( ! xl_text . is_empty ( ) ) {
text_buf - > set_alignment ( align_rtl_checked ) ;
2023-07-14 07:59:16 +02:00
2022-08-13 07:46:07 +02:00
float text_buf_width = MAX ( 1.0f , drawable_size_remained . width ) ; // The space's width filled by the text_buf.
text_buf - > set_width ( text_buf_width ) ;
2023-07-14 07:59:16 +02:00
2022-08-13 07:46:07 +02:00
Point2 text_ofs ;
2023-03-03 21:21:41 +01:00
2022-08-13 07:46:07 +02:00
switch ( align_rtl_checked ) {
case HORIZONTAL_ALIGNMENT_CENTER : {
text_ofs . x = ( drawable_size_remained . width - text_buf_width ) / 2.0f ;
2019-10-25 05:29:10 +02:00
}
2022-08-13 07:46:07 +02:00
[[fallthrough]] ;
case HORIZONTAL_ALIGNMENT_FILL :
case HORIZONTAL_ALIGNMENT_LEFT :
case HORIZONTAL_ALIGNMENT_RIGHT : {
text_ofs . x + = style_margin_left ;
2024-01-22 15:16:24 +01:00
text_ofs . x + = left_internal_margin_with_h_separation ;
2022-08-13 07:46:07 +02:00
if ( icon_align_rtl_checked = = HORIZONTAL_ALIGNMENT_LEFT ) {
// Offset by the space's width that occupied by icon and h_separation together.
text_ofs . x + = custom_element_size . width - drawable_size_remained . width ;
}
} break ;
}
text_ofs . y = ( drawable_size_remained . height - text_buf - > get_size ( ) . height ) / 2.0f + style_margin_top ;
if ( vertical_icon_alignment = = VERTICAL_ALIGNMENT_TOP ) {
text_ofs . y + = custom_element_size . height - drawable_size_remained . height ; // Offset by the icon's height.
}
2019-08-20 18:41:14 +02:00
2022-08-13 07:46:07 +02:00
Color font_outline_color = theme_cache . font_outline_color ;
int outline_size = theme_cache . outline_size ;
if ( outline_size > 0 & & font_outline_color . a > 0.0f ) {
text_buf - > draw_outline ( ci , text_ofs , outline_size , font_outline_color ) ;
}
text_buf - > draw ( ci , text_ofs , font_color ) ;
2022-07-08 07:27:18 +02:00
}
2019-08-20 18:41:14 +02:00
} break ;
2014-02-10 02:10:30 +01:00
}
}
2023-03-31 21:17:59 +02:00
Size2 Button : : _fit_icon_size ( const Size2 & p_size ) const {
int max_width = theme_cache . icon_max_width ;
Size2 icon_size = p_size ;
if ( max_width > 0 & & icon_size . width > max_width ) {
icon_size . height = icon_size . height * max_width / icon_size . width ;
icon_size . width = max_width ;
}
return icon_size ;
}
2022-03-19 02:15:55 +01:00
Size2 Button : : get_minimum_size_for_text_and_icon ( const String & p_text , Ref < Texture2D > p_icon ) const {
Ref < TextParagraph > paragraph ;
if ( p_text . is_empty ( ) ) {
paragraph = text_buf ;
} else {
paragraph . instantiate ( ) ;
const_cast < Button * > ( this ) - > _shape ( paragraph , p_text ) ;
}
Size2 minsize = paragraph - > get_size ( ) ;
2024-01-09 21:12:26 +01:00
if ( clip_text | | overrun_behavior ! = TextServer : : OVERRUN_NO_TRIMMING | | autowrap_mode ! = TextServer : : AUTOWRAP_OFF ) {
2022-03-19 02:15:55 +01:00
minsize . width = 0 ;
}
2022-08-12 13:39:22 +02:00
if ( ! expand_icon & & p_icon . is_valid ( ) ) {
2023-03-31 21:17:59 +02:00
Size2 icon_size = _fit_icon_size ( p_icon - > get_size ( ) ) ;
2023-03-03 21:21:41 +01:00
if ( vertical_icon_alignment = = VERTICAL_ALIGNMENT_CENTER ) {
minsize . height = MAX ( minsize . height , icon_size . height ) ;
} else {
minsize . height + = icon_size . height ;
}
2022-03-19 02:15:55 +01:00
2023-03-03 21:21:41 +01:00
if ( horizontal_icon_alignment ! = HORIZONTAL_ALIGNMENT_CENTER ) {
2023-03-31 21:17:59 +02:00
minsize . width + = icon_size . width ;
2022-03-19 02:15:55 +01:00
if ( ! xl_text . is_empty ( ) | | ! p_text . is_empty ( ) ) {
2022-08-31 14:02:40 +02:00
minsize . width + = MAX ( 0 , theme_cache . h_separation ) ;
2022-03-19 02:15:55 +01:00
}
} else {
2023-03-31 21:17:59 +02:00
minsize . width = MAX ( minsize . width , icon_size . width ) ;
2022-03-19 02:15:55 +01:00
}
}
if ( ! xl_text . is_empty ( ) | | ! p_text . is_empty ( ) ) {
2022-08-31 14:02:40 +02:00
Ref < Font > font = theme_cache . font ;
float font_height = font - > get_height ( theme_cache . font_size ) ;
2023-03-03 21:21:41 +01:00
if ( vertical_icon_alignment = = VERTICAL_ALIGNMENT_CENTER ) {
minsize . height = MAX ( font_height , minsize . height ) ;
} else {
minsize . height + = font_height ;
}
2022-03-19 02:15:55 +01:00
}
2022-08-13 07:46:07 +02:00
return _get_current_stylebox ( ) - > get_minimum_size ( ) + minsize ;
2022-03-19 02:15:55 +01:00
}
void Button : : _shape ( Ref < TextParagraph > p_paragraph , String p_text ) {
if ( p_paragraph . is_null ( ) ) {
p_paragraph = text_buf ;
}
if ( p_text . is_empty ( ) ) {
p_text = xl_text ;
}
p_paragraph - > clear ( ) ;
2022-08-31 14:02:40 +02:00
Ref < Font > font = theme_cache . font ;
int font_size = theme_cache . font_size ;
if ( font . is_null ( ) | | font_size = = 0 ) {
// Can't shape without a valid font and a non-zero size.
return ;
}
2024-01-09 21:12:26 +01:00
BitField < TextServer : : LineBreakFlag > autowrap_flags = TextServer : : BREAK_MANDATORY ;
switch ( autowrap_mode ) {
case TextServer : : AUTOWRAP_WORD_SMART :
autowrap_flags = TextServer : : BREAK_WORD_BOUND | TextServer : : BREAK_ADAPTIVE | TextServer : : BREAK_MANDATORY ;
break ;
case TextServer : : AUTOWRAP_WORD :
autowrap_flags = TextServer : : BREAK_WORD_BOUND | TextServer : : BREAK_MANDATORY ;
break ;
case TextServer : : AUTOWRAP_ARBITRARY :
autowrap_flags = TextServer : : BREAK_GRAPHEME_BOUND | TextServer : : BREAK_MANDATORY ;
break ;
case TextServer : : AUTOWRAP_OFF :
break ;
}
autowrap_flags = autowrap_flags | TextServer : : BREAK_TRIM_EDGE_SPACES ;
p_paragraph - > set_break_flags ( autowrap_flags ) ;
2020-09-03 13:22:16 +02:00
if ( text_direction = = Control : : TEXT_DIRECTION_INHERITED ) {
2022-03-19 02:15:55 +01:00
p_paragraph - > set_direction ( is_layout_rtl ( ) ? TextServer : : DIRECTION_RTL : TextServer : : DIRECTION_LTR ) ;
2020-09-03 13:22:16 +02:00
} else {
2022-03-19 02:15:55 +01:00
p_paragraph - > set_direction ( ( TextServer : : Direction ) text_direction ) ;
2020-09-03 13:22:16 +02:00
}
2022-03-19 02:15:55 +01:00
p_paragraph - > add_string ( p_text , font , font_size , language ) ;
p_paragraph - > set_text_overrun_behavior ( overrun_behavior ) ;
2022-06-08 18:02:27 +02:00
}
2022-06-15 10:01:45 +02:00
void Button : : set_text_overrun_behavior ( TextServer : : OverrunBehavior p_behavior ) {
2022-06-08 18:02:27 +02:00
if ( overrun_behavior ! = p_behavior ) {
2022-08-13 07:46:07 +02:00
bool need_update_cache = overrun_behavior = = TextServer : : OVERRUN_NO_TRIMMING | | p_behavior = = TextServer : : OVERRUN_NO_TRIMMING ;
2022-06-08 18:02:27 +02:00
overrun_behavior = p_behavior ;
_shape ( ) ;
2022-08-13 07:46:07 +02:00
if ( need_update_cache ) {
_queue_update_size_cache ( ) ;
}
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2022-06-08 18:02:27 +02:00
update_minimum_size ( ) ;
}
}
2022-06-15 10:01:45 +02:00
TextServer : : OverrunBehavior Button : : get_text_overrun_behavior ( ) const {
2022-06-08 18:02:27 +02:00
return overrun_behavior ;
2020-09-03 13:22:16 +02:00
}
2017-03-05 16:44:50 +01:00
void Button : : set_text ( const String & p_text ) {
2020-09-03 13:22:16 +02:00
if ( text ! = p_text ) {
text = p_text ;
2021-05-27 19:31:33 +02:00
xl_text = atr ( text ) ;
2020-09-03 13:22:16 +02:00
_shape ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
String Button : : get_text ( ) const {
return text ;
}
2024-01-09 21:12:26 +01:00
void Button : : set_autowrap_mode ( TextServer : : AutowrapMode p_mode ) {
if ( autowrap_mode ! = p_mode ) {
autowrap_mode = p_mode ;
_shape ( ) ;
queue_redraw ( ) ;
update_minimum_size ( ) ;
}
}
TextServer : : AutowrapMode Button : : get_autowrap_mode ( ) const {
return autowrap_mode ;
}
2020-09-03 13:22:16 +02:00
void Button : : set_text_direction ( Control : : TextDirection p_text_direction ) {
ERR_FAIL_COND ( ( int ) p_text_direction < - 1 | | ( int ) p_text_direction > 3 ) ;
if ( text_direction ! = p_text_direction ) {
text_direction = p_text_direction ;
_shape ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-05-14 16:41:43 +02:00
}
2020-09-03 13:22:16 +02:00
}
Control : : TextDirection Button : : get_text_direction ( ) const {
return text_direction ;
}
void Button : : set_language ( const String & p_language ) {
if ( language ! = p_language ) {
language = p_language ;
_shape ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
}
String Button : : get_language ( ) const {
return language ;
}
void Button : : set_icon ( const Ref < Texture2D > & p_icon ) {
2023-05-17 14:49:59 +02:00
if ( icon = = p_icon ) {
return ;
}
if ( icon . is_valid ( ) ) {
2023-07-03 21:29:37 +02:00
icon - > disconnect_changed ( callable_mp ( this , & Button : : _texture_changed ) ) ;
2023-05-17 14:49:59 +02:00
}
icon = p_icon ;
if ( icon . is_valid ( ) ) {
2023-07-03 21:29:37 +02:00
icon - > connect_changed ( callable_mp ( this , & Button : : _texture_changed ) ) ;
2023-05-17 14:49:59 +02:00
}
queue_redraw ( ) ;
update_minimum_size ( ) ;
}
void Button : : _texture_changed ( ) {
2023-09-06 16:39:06 +02:00
queue_redraw ( ) ;
update_minimum_size ( ) ;
2014-02-10 02:10:30 +01:00
}
2019-06-11 20:43:37 +02:00
Ref < Texture2D > Button : : get_icon ( ) const {
2014-02-10 02:10:30 +01:00
return icon ;
}
2021-10-08 23:26:13 +02:00
void Button : : set_expand_icon ( bool p_enabled ) {
if ( expand_icon ! = p_enabled ) {
expand_icon = p_enabled ;
2023-04-12 03:34:00 +02:00
_queue_update_size_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2020-09-03 13:22:16 +02:00
}
2019-08-20 18:41:14 +02:00
}
bool Button : : is_expand_icon ( ) const {
return expand_icon ;
}
2021-10-08 23:26:13 +02:00
void Button : : set_flat ( bool p_enabled ) {
if ( flat ! = p_enabled ) {
flat = p_enabled ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
2014-02-10 02:10:30 +01:00
}
bool Button : : is_flat ( ) const {
return flat ;
}
2021-10-08 23:26:13 +02:00
void Button : : set_clip_text ( bool p_enabled ) {
if ( clip_text ! = p_enabled ) {
clip_text = p_enabled ;
2022-08-13 07:46:07 +02:00
_queue_update_size_cache ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2020-09-03 13:22:16 +02:00
}
2014-02-10 02:10:30 +01:00
}
bool Button : : get_clip_text ( ) const {
return clip_text ;
}
2021-11-25 03:58:47 +01:00
void Button : : set_text_alignment ( HorizontalAlignment p_alignment ) {
if ( alignment ! = p_alignment ) {
alignment = p_alignment ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2020-09-03 13:22:16 +02:00
}
2014-02-10 02:10:30 +01:00
}
2021-11-25 03:58:47 +01:00
HorizontalAlignment Button : : get_text_alignment ( ) const {
return alignment ;
2014-02-10 02:10:30 +01:00
}
2021-11-25 03:58:47 +01:00
void Button : : set_icon_alignment ( HorizontalAlignment p_alignment ) {
2022-08-13 07:46:07 +02:00
if ( horizontal_icon_alignment = = p_alignment ) {
return ;
}
2023-03-03 21:21:41 +01:00
horizontal_icon_alignment = p_alignment ;
update_minimum_size ( ) ;
queue_redraw ( ) ;
}
void Button : : set_vertical_icon_alignment ( VerticalAlignment p_alignment ) {
2022-08-13 07:46:07 +02:00
if ( vertical_icon_alignment = = p_alignment ) {
return ;
}
bool need_update_cache = vertical_icon_alignment = = VERTICAL_ALIGNMENT_CENTER | | p_alignment = = VERTICAL_ALIGNMENT_CENTER ;
2023-03-03 21:21:41 +01:00
vertical_icon_alignment = p_alignment ;
2022-08-13 07:46:07 +02:00
if ( need_update_cache ) {
_queue_update_size_cache ( ) ;
}
2021-12-06 14:02:34 +01:00
update_minimum_size ( ) ;
2022-08-13 23:21:24 +02:00
queue_redraw ( ) ;
2019-10-25 05:29:10 +02:00
}
2021-11-25 03:58:47 +01:00
HorizontalAlignment Button : : get_icon_alignment ( ) const {
2023-03-03 21:21:41 +01:00
return horizontal_icon_alignment ;
}
VerticalAlignment Button : : get_vertical_icon_alignment ( ) const {
return vertical_icon_alignment ;
2019-10-25 05:29:10 +02:00
}
2014-02-10 02:10:30 +01:00
void Button : : _bind_methods ( ) {
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_text " , " text " ) , & Button : : set_text ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text " ) , & Button : : get_text ) ;
2022-06-08 18:02:27 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_text_overrun_behavior " , " overrun_behavior " ) , & Button : : set_text_overrun_behavior ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text_overrun_behavior " ) , & Button : : get_text_overrun_behavior ) ;
2024-01-09 21:12:26 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_autowrap_mode " , " autowrap_mode " ) , & Button : : set_autowrap_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_autowrap_mode " ) , & Button : : get_autowrap_mode ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_text_direction " , " direction " ) , & Button : : set_text_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text_direction " ) , & Button : : get_text_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " set_language " , " language " ) , & Button : : set_language ) ;
ClassDB : : bind_method ( D_METHOD ( " get_language " ) , & Button : : get_language ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_button_icon " , " texture " ) , & Button : : set_icon ) ;
ClassDB : : bind_method ( D_METHOD ( " get_button_icon " ) , & Button : : get_icon ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_flat " , " enabled " ) , & Button : : set_flat ) ;
2019-10-25 05:29:10 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_flat " ) , & Button : : is_flat ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_clip_text " , " enabled " ) , & Button : : set_clip_text ) ;
ClassDB : : bind_method ( D_METHOD ( " get_clip_text " ) , & Button : : get_clip_text ) ;
2021-11-25 03:58:47 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_text_alignment " , " alignment " ) , & Button : : set_text_alignment ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text_alignment " ) , & Button : : get_text_alignment ) ;
ClassDB : : bind_method ( D_METHOD ( " set_icon_alignment " , " icon_alignment " ) , & Button : : set_icon_alignment ) ;
ClassDB : : bind_method ( D_METHOD ( " get_icon_alignment " ) , & Button : : get_icon_alignment ) ;
2023-03-03 21:21:41 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_vertical_icon_alignment " , " vertical_icon_alignment " ) , & Button : : set_vertical_icon_alignment ) ;
ClassDB : : bind_method ( D_METHOD ( " get_vertical_icon_alignment " ) , & Button : : get_vertical_icon_alignment ) ;
2021-10-08 23:26:13 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_expand_icon " , " enabled " ) , & Button : : set_expand_icon ) ;
2019-10-25 05:29:10 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_expand_icon " ) , & Button : : is_expand_icon ) ;
2017-03-05 16:44:50 +01:00
2023-01-09 15:31:44 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " text " , PROPERTY_HINT_MULTILINE_TEXT ) , " set_text " , " get_text " ) ;
2019-06-11 20:43:37 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " icon " , PROPERTY_HINT_RESOURCE_TYPE , " Texture2D " ) , " set_button_icon " , " get_button_icon " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " flat " ) , " set_flat " , " is_flat " ) ;
2023-01-25 15:39:02 +01:00
ADD_GROUP ( " Text Behavior " , " " ) ;
2021-11-25 03:58:47 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " alignment " , PROPERTY_HINT_ENUM , " Left,Center,Right " ) , " set_text_alignment " , " get_text_alignment " ) ;
2022-06-08 18:02:27 +02:00
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 " ) ;
2024-01-09 21:12:26 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " autowrap_mode " , PROPERTY_HINT_ENUM , " Off,Arbitrary,Word,Word (Smart) " ) , " set_autowrap_mode " , " get_autowrap_mode " ) ;
2023-01-25 15:39:02 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " clip_text " ) , " set_clip_text " , " get_clip_text " ) ;
ADD_GROUP ( " Icon Behavior " , " " ) ;
2021-11-25 03:58:47 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " icon_alignment " , PROPERTY_HINT_ENUM , " Left,Center,Right " ) , " set_icon_alignment " , " get_icon_alignment " ) ;
2023-03-03 21:21:41 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " vertical_icon_alignment " , PROPERTY_HINT_ENUM , " Top,Center,Bottom " ) , " set_vertical_icon_alignment " , " get_vertical_icon_alignment " ) ;
2019-08-20 18:41:14 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " expand_icon " ) , " set_expand_icon " , " is_expand_icon " ) ;
2022-05-09 11:47:10 +02:00
ADD_GROUP ( " BiDi " , " " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " text_direction " , PROPERTY_HINT_ENUM , " Auto,Left-to-Right,Right-to-Left,Inherited " ) , " set_text_direction " , " get_text_direction " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " language " , PROPERTY_HINT_LOCALE_ID , " " ) , " set_language " , " get_language " ) ;
2023-09-08 21:00:10 +02:00
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , normal ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , normal_mirrored ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , pressed ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , pressed_mirrored ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , hover ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , hover_mirrored ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , hover_pressed ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , hover_pressed_mirrored ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , disabled ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , disabled_mirrored ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_STYLEBOX , Button , focus ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , font_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , font_focus_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , font_pressed_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , font_hover_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , font_hover_pressed_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , font_disabled_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_FONT , Button , font ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_FONT_SIZE , Button , font_size ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Button , outline_size ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , font_outline_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , icon_normal_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , icon_focus_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , icon_pressed_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , icon_hover_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , icon_hover_pressed_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_COLOR , Button , icon_disabled_color ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_ICON , Button , icon ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Button , h_separation ) ;
BIND_THEME_ITEM ( Theme : : DATA_TYPE_CONSTANT , Button , icon_max_width ) ;
2014-02-10 02:10:30 +01:00
}
Button : : Button ( const String & p_text ) {
2021-06-18 00:03:09 +02:00
text_buf . instantiate ( ) ;
2022-08-30 10:56:17 +02:00
text_buf - > set_break_flags ( TextServer : : BREAK_MANDATORY | TextServer : : BREAK_TRIM_EDGE_SPACES ) ;
2017-01-08 23:54:19 +01:00
set_mouse_filter ( MOUSE_FILTER_STOP ) ;
2022-03-04 09:18:44 +01:00
2014-02-10 02:10:30 +01:00
set_text ( p_text ) ;
}
2017-03-05 16:44:50 +01:00
Button : : ~ Button ( ) {
2014-02-10 02:10:30 +01:00
}