2014-02-10 09:10:30 +08:00
/**************************************************************************/
/* menu_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 07:50:27 +08:00
2014-02-10 09:10:30 +08:00
# include "menu_button.h"
2020-02-22 06:26:13 +08:00
2018-09-12 00:13:45 +08:00
# include "core/os/keyboard.h"
2020-03-04 09:51:12 +08:00
# include "scene/main/window.h"
2014-02-10 09:10:30 +08:00
2022-01-11 21:59:52 +08:00
void MenuButton : : shortcut_input ( const Ref < InputEvent > & p_event ) {
2021-04-05 14:52:21 +08:00
ERR_FAIL_COND ( p_event . is_null ( ) ) ;
2020-05-14 22:41:43 +08:00
if ( disable_shortcuts ) {
2017-12-19 22:29:55 +08:00
return ;
2020-05-14 22:41:43 +08:00
}
2017-12-19 22:29:55 +08:00
2020-02-24 05:23:34 +08:00
if ( p_event - > is_pressed ( ) & & ! is_disabled ( ) & & is_visible_in_tree ( ) & & popup - > activate_item_by_event ( p_event , false ) ) {
2022-10-02 14:46:37 +08:00
accept_event ( ) ;
return ;
2014-02-10 09:10:30 +08:00
}
2022-10-02 14:46:37 +08:00
Button : : shortcut_input ( p_event ) ;
2014-02-10 09:10:30 +08:00
}
2021-07-20 04:09:23 +08:00
void MenuButton : : _popup_visibility_changed ( bool p_visible ) {
set_pressed ( p_visible ) ;
2021-07-27 01:23:48 +08:00
if ( ! p_visible ) {
set_process_internal ( false ) ;
return ;
}
if ( switch_on_hover ) {
2023-12-19 00:07:34 +08:00
set_process_internal ( true ) ;
2021-07-27 01:23:48 +08:00
}
2021-07-20 04:09:23 +08:00
}
2014-02-10 09:10:30 +08:00
void MenuButton : : pressed ( ) {
2022-08-23 15:38:51 +08:00
if ( popup - > is_visible ( ) ) {
popup - > hide ( ) ;
return ;
}
2022-10-02 14:46:37 +08:00
show_popup ( ) ;
}
PopupMenu * MenuButton : : get_popup ( ) const {
return popup ;
}
void MenuButton : : show_popup ( ) {
if ( ! get_viewport ( ) ) {
return ;
}
2021-08-16 20:53:10 +08:00
emit_signal ( SNAME ( " about_to_popup " ) ) ;
2023-06-15 18:20:04 +08:00
Rect2 rect = get_screen_rect ( ) ;
rect . position . y + = rect . size . height ;
rect . size . height = 0 ;
popup - > set_size ( rect . size ) ;
2021-09-21 15:35:23 +08:00
if ( is_layout_rtl ( ) ) {
2023-06-15 18:20:04 +08:00
rect . position . x + = rect . size . width - popup - > get_size ( ) . width ;
2021-09-21 15:35:23 +08:00
}
2023-06-15 18:20:04 +08:00
popup - > set_position ( rect . position ) ;
2021-09-21 15:35:23 +08:00
2022-08-28 00:32:45 +08:00
// If not triggered by the mouse, start the popup with its first enabled item focused.
if ( ! _was_pressed_by_mouse ( ) ) {
for ( int i = 0 ; i < popup - > get_item_count ( ) ; i + + ) {
if ( ! popup - > is_item_disabled ( i ) ) {
2022-09-06 21:51:14 +08:00
popup - > set_focused_item ( i ) ;
2022-08-28 00:32:45 +08:00
break ;
}
}
2022-01-20 19:44:27 +08:00
}
2022-08-23 15:38:51 +08:00
popup - > popup ( ) ;
2014-02-10 09:10:30 +08:00
}
2018-07-30 06:26:43 +08:00
void MenuButton : : set_switch_on_hover ( bool p_enabled ) {
switch_on_hover = p_enabled ;
}
bool MenuButton : : is_switch_on_hover ( ) {
return switch_on_hover ;
2014-02-10 09:10:30 +08:00
}
2021-11-03 10:08:58 +08:00
void MenuButton : : set_item_count ( int p_count ) {
ERR_FAIL_COND ( p_count < 0 ) ;
2022-03-16 15:50:48 +08:00
if ( popup - > get_item_count ( ) = = p_count ) {
return ;
}
2021-11-03 10:08:58 +08:00
popup - > set_item_count ( p_count ) ;
notify_property_list_changed ( ) ;
}
int MenuButton : : get_item_count ( ) const {
return popup - > get_item_count ( ) ;
}
2019-04-19 06:50:35 +08:00
void MenuButton : : _notification ( int p_what ) {
2021-07-20 04:09:23 +08:00
switch ( p_what ) {
2022-02-07 10:07:08 +08:00
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED : {
popup - > set_layout_direction ( ( Window : : LayoutDirection ) get_layout_direction ( ) ) ;
} break ;
2022-02-16 01:06:48 +08:00
2021-07-20 04:09:23 +08:00
case NOTIFICATION_VISIBILITY_CHANGED : {
if ( ! is_visible_in_tree ( ) ) {
popup - > hide ( ) ;
}
} break ;
2022-02-16 01:06:48 +08:00
2021-07-20 04:09:23 +08:00
case NOTIFICATION_INTERNAL_PROCESS : {
2023-12-19 00:07:34 +08:00
MenuButton * menu_btn_other = Object : : cast_to < MenuButton > ( get_viewport ( ) - > gui_find_control ( get_viewport ( ) - > get_mouse_position ( ) ) ) ;
2021-07-27 01:23:48 +08:00
if ( menu_btn_other & & menu_btn_other ! = this & & menu_btn_other - > is_switch_on_hover ( ) & & ! menu_btn_other - > is_disabled ( ) & &
( get_parent ( ) - > is_ancestor_of ( menu_btn_other ) | | menu_btn_other - > get_parent ( ) - > is_ancestor_of ( popup ) ) ) {
popup - > hide ( ) ;
2022-08-28 00:32:45 +08:00
2021-07-27 01:23:48 +08:00
menu_btn_other - > pressed ( ) ;
2022-08-28 00:32:45 +08:00
// As the popup wasn't triggered by a mouse click, the item focus needs to be removed manually.
2022-09-06 21:51:14 +08:00
menu_btn_other - > get_popup ( ) - > set_focused_item ( - 1 ) ;
2021-07-20 04:09:23 +08:00
}
} break ;
2019-04-19 06:50:35 +08:00
}
}
2021-11-03 10:08:58 +08:00
bool MenuButton : : _set ( const StringName & p_name , const Variant & p_value ) {
2024-02-14 09:11:45 +08:00
const String sname = p_name ;
if ( property_helper . is_property_valid ( sname ) ) {
2021-11-03 10:08:58 +08:00
bool valid ;
2024-02-14 09:11:45 +08:00
popup - > set ( sname . trim_prefix ( " popup/ " ) , p_value , & valid ) ;
2021-11-03 10:08:58 +08:00
return valid ;
}
return false ;
}
bool MenuButton : : _get ( const StringName & p_name , Variant & r_ret ) const {
2024-02-14 09:11:45 +08:00
const String sname = p_name ;
if ( property_helper . is_property_valid ( sname ) ) {
2021-11-03 10:08:58 +08:00
bool valid ;
2024-02-14 09:11:45 +08:00
r_ret = popup - > get ( sname . trim_prefix ( " popup/ " ) , & valid ) ;
2021-11-03 10:08:58 +08:00
return valid ;
}
return false ;
}
2014-02-10 09:10:30 +08:00
void MenuButton : : _bind_methods ( ) {
2024-07-17 18:14:00 +08:00
// TODO: Properly handle popups when advanced GUI is disabled.
# ifndef ADVANCED_GUI_DISABLED
2017-08-09 19:19:41 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_popup " ) , & MenuButton : : get_popup ) ;
2024-07-17 18:14:00 +08:00
# endif // ADVANCED_GUI_DISABLED
2022-10-02 14:46:37 +08:00
ClassDB : : bind_method ( D_METHOD ( " show_popup " ) , & MenuButton : : show_popup ) ;
2018-07-30 06:26:43 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_switch_on_hover " , " enable " ) , & MenuButton : : set_switch_on_hover ) ;
ClassDB : : bind_method ( D_METHOD ( " is_switch_on_hover " ) , & MenuButton : : is_switch_on_hover ) ;
2017-12-19 22:29:55 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_disable_shortcuts " , " disabled " ) , & MenuButton : : set_disable_shortcuts ) ;
2014-02-10 09:10:30 +08:00
2021-11-04 22:27:23 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_item_count " , " count " ) , & MenuButton : : set_item_count ) ;
2021-11-03 10:08:58 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_item_count " ) , & MenuButton : : get_item_count ) ;
2018-07-30 06:26:43 +08:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " switch_on_hover " ) , " set_switch_on_hover " , " is_switch_on_hover " ) ;
2021-12-07 11:09:31 +08:00
ADD_ARRAY_COUNT ( " Items " , " item_count " , " set_item_count " , " get_item_count " , " popup/item_ " ) ;
2014-02-10 09:10:30 +08:00
2020-03-12 20:37:40 +08:00
ADD_SIGNAL ( MethodInfo ( " about_to_popup " ) ) ;
2024-02-14 09:11:45 +08:00
PopupMenu : : Item defaults ( true ) ;
base_property_helper . set_prefix ( " popup/item_ " ) ;
2024-05-09 20:19:16 +08:00
base_property_helper . set_array_length_getter ( & MenuButton : : get_item_count ) ;
2024-02-14 09:11:45 +08:00
base_property_helper . register_property ( PropertyInfo ( Variant : : STRING , " text " ) , defaults . text ) ;
base_property_helper . register_property ( PropertyInfo ( Variant : : OBJECT , " icon " , PROPERTY_HINT_RESOURCE_TYPE , " Texture2D " ) , defaults . icon ) ;
base_property_helper . register_property ( PropertyInfo ( Variant : : INT , " checkable " , PROPERTY_HINT_ENUM , " No,As Checkbox,As Radio Button " ) , defaults . checkable_type ) ;
base_property_helper . register_property ( PropertyInfo ( Variant : : BOOL , " checked " ) , defaults . checked ) ;
base_property_helper . register_property ( PropertyInfo ( Variant : : INT , " id " , PROPERTY_HINT_RANGE , " 0,10,1,or_greater " ) , defaults . id ) ;
base_property_helper . register_property ( PropertyInfo ( Variant : : BOOL , " disabled " ) , defaults . disabled ) ;
base_property_helper . register_property ( PropertyInfo ( Variant : : BOOL , " separator " ) , defaults . separator ) ;
2024-07-03 15:39:18 +08:00
PropertyListHelper : : register_base_helper ( & base_property_helper ) ;
2014-02-10 09:10:30 +08:00
}
2017-12-19 22:29:55 +08:00
void MenuButton : : set_disable_shortcuts ( bool p_disabled ) {
disable_shortcuts = p_disabled ;
}
2022-03-04 16:18:44 +08:00
MenuButton : : MenuButton ( const String & p_text ) :
Button ( p_text ) {
2014-02-10 09:10:30 +08:00
set_flat ( true ) ;
2018-09-21 13:18:40 +08:00
set_toggle_mode ( true ) ;
2017-12-19 22:29:55 +08:00
set_disable_shortcuts ( false ) ;
2022-01-11 21:59:52 +08:00
set_process_shortcut_input ( true ) ;
2020-09-17 09:46:04 +08:00
set_focus_mode ( FOCUS_NONE ) ;
2018-09-21 13:18:40 +08:00
set_action_mode ( ACTION_MODE_BUTTON_PRESS ) ;
2014-02-10 09:10:30 +08:00
popup = memnew ( PopupMenu ) ;
popup - > hide ( ) ;
2021-08-25 21:49:30 +08:00
add_child ( popup , false , INTERNAL_MODE_FRONT ) ;
2022-07-29 04:56:41 +08:00
popup - > connect ( " about_to_popup " , callable_mp ( this , & MenuButton : : _popup_visibility_changed ) . bind ( true ) ) ;
popup - > connect ( " popup_hide " , callable_mp ( this , & MenuButton : : _popup_visibility_changed ) . bind ( false ) ) ;
2024-02-14 09:11:45 +08:00
property_helper . setup_for_instance ( base_property_helper , this ) ;
2014-02-10 09:10:30 +08:00
}
MenuButton : : ~ MenuButton ( ) {
}