2023-01-05 20:25:55 +08:00
/**************************************************************************/
/* action_map_editor.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. */
/**************************************************************************/
2020-10-01 21:04:57 +08:00
2022-10-05 20:42:12 +08:00
# include "editor/action_map_editor.h"
2022-11-04 18:36:13 +08:00
2023-08-22 15:44:20 +08:00
# include "editor/editor_settings.h"
2023-08-13 08:33:39 +08:00
# include "editor/editor_string_names.h"
2022-10-05 20:42:12 +08:00
# include "editor/event_listener_line_edit.h"
# include "editor/input_event_configuration_dialog.h"
2024-01-15 20:14:55 +08:00
# include "editor/themes/editor_scale.h"
2022-10-05 20:42:12 +08:00
# include "scene/gui/check_button.h"
2024-01-12 04:13:23 +08:00
# include "scene/gui/separator.h"
2022-10-05 20:42:12 +08:00
# include "scene/gui/tree.h"
2020-10-01 21:04:57 +08:00
static bool _is_action_name_valid ( const String & p_name ) {
const char32_t * cstr = p_name . get_data ( ) ;
for ( int i = 0 ; cstr [ i ] ; i + + ) {
if ( cstr [ i ] = = ' / ' | | cstr [ i ] = = ' : ' | | cstr [ i ] = = ' " ' | |
cstr [ i ] = = ' = ' | | cstr [ i ] = = ' \\ ' | | cstr [ i ] < 32 ) {
return false ;
}
}
return true ;
}
void ActionMapEditor : : _event_config_confirmed ( ) {
Ref < InputEvent > ev = event_config_dialog - > get_event ( ) ;
Dictionary new_action = current_action . duplicate ( ) ;
2021-12-24 12:19:24 +08:00
Array events = new_action [ " events " ] . duplicate ( ) ;
2020-10-01 21:04:57 +08:00
if ( current_action_event_index = = - 1 ) {
// Add new event
events . push_back ( ev ) ;
} else {
// Edit existing event
events [ current_action_event_index ] = ev ;
}
new_action [ " events " ] = events ;
2021-07-18 05:22:52 +08:00
emit_signal ( SNAME ( " action_edited " ) , current_action_name , new_action ) ;
2020-10-01 21:04:57 +08:00
}
void ActionMapEditor : : _add_action_pressed ( ) {
_add_action ( add_edit - > get_text ( ) ) ;
}
2022-05-04 07:47:29 +08:00
String ActionMapEditor : : _check_new_action_name ( const String & p_name ) {
if ( p_name . is_empty ( ) | | ! _is_action_name_valid ( p_name ) ) {
return TTR ( " Invalid action name. It cannot be empty nor contain '/', ':', '=', ' \\ ' or ' \" ' " ) ;
}
if ( _has_action ( p_name ) ) {
return vformat ( TTR ( " An action with the name '%s' already exists. " ) , p_name ) ;
}
return " " ;
}
void ActionMapEditor : : _add_edit_text_changed ( const String & p_name ) {
String error = _check_new_action_name ( p_name ) ;
2022-08-25 18:42:17 +08:00
add_button - > set_tooltip_text ( error ) ;
2022-05-04 07:47:29 +08:00
add_button - > set_disabled ( ! error . is_empty ( ) ) ;
}
2021-12-29 01:08:06 +08:00
bool ActionMapEditor : : _has_action ( const String & p_name ) const {
for ( const ActionInfo & action_info : actions_cache ) {
if ( p_name = = action_info . name ) {
return true ;
}
}
return false ;
}
2020-10-01 21:04:57 +08:00
void ActionMapEditor : : _add_action ( const String & p_name ) {
2022-05-04 07:47:29 +08:00
String error = _check_new_action_name ( p_name ) ;
if ( ! error . is_empty ( ) ) {
show_message ( error ) ;
2021-12-29 01:08:06 +08:00
return ;
}
2020-10-01 21:04:57 +08:00
add_edit - > clear ( ) ;
2021-07-18 05:22:52 +08:00
emit_signal ( SNAME ( " action_added " ) , p_name ) ;
2020-10-01 21:04:57 +08:00
}
void ActionMapEditor : : _action_edited ( ) {
TreeItem * ti = action_tree - > get_edited ( ) ;
if ( ! ti ) {
return ;
}
if ( action_tree - > get_selected_column ( ) = = 0 ) {
// Name Edited
String new_name = ti - > get_text ( 0 ) ;
String old_name = ti - > get_meta ( " __name " ) ;
if ( new_name = = old_name ) {
return ;
}
2021-12-09 17:42:46 +08:00
if ( new_name . is_empty ( ) | | ! _is_action_name_valid ( new_name ) ) {
2020-10-01 21:04:57 +08:00
ti - > set_text ( 0 , old_name ) ;
2021-05-20 18:07:26 +08:00
show_message ( TTR ( " Invalid action name. It cannot be empty nor contain '/', ':', '=', ' \\ ' or ' \" ' " ) ) ;
2020-10-01 21:04:57 +08:00
return ;
}
2021-12-29 01:08:06 +08:00
if ( _has_action ( new_name ) ) {
ti - > set_text ( 0 , old_name ) ;
show_message ( vformat ( TTR ( " An action with the name '%s' already exists. " ) , new_name ) ) ;
return ;
}
2021-07-18 05:22:52 +08:00
emit_signal ( SNAME ( " action_renamed " ) , old_name , new_name ) ;
2020-10-01 21:04:57 +08:00
} else if ( action_tree - > get_selected_column ( ) = = 1 ) {
// Deadzone Edited
String name = ti - > get_meta ( " __name " ) ;
Dictionary old_action = ti - > get_meta ( " __action " ) ;
Dictionary new_action = old_action . duplicate ( ) ;
new_action [ " deadzone " ] = ti - > get_range ( 1 ) ;
// Call deferred so that input can finish propagating through tree, allowing re-making of tree to occur.
2021-07-18 05:22:52 +08:00
call_deferred ( SNAME ( " emit_signal " ) , " action_edited " , name , new_action ) ;
2020-10-01 21:04:57 +08:00
}
}
2021-09-18 15:33:18 +08:00
void ActionMapEditor : : _tree_button_pressed ( Object * p_item , int p_column , int p_id , MouseButton p_button ) {
if ( p_button ! = MouseButton : : LEFT ) {
return ;
}
2020-10-01 21:04:57 +08:00
ItemButton option = ( ItemButton ) p_id ;
TreeItem * item = Object : : cast_to < TreeItem > ( p_item ) ;
if ( ! item ) {
return ;
}
switch ( option ) {
case ActionMapEditor : : BUTTON_ADD_EVENT : {
current_action = item - > get_meta ( " __action " ) ;
current_action_name = item - > get_meta ( " __name " ) ;
current_action_event_index = - 1 ;
2023-12-18 05:56:26 +08:00
event_config_dialog - > popup_and_configure ( Ref < InputEvent > ( ) , current_action_name ) ;
2020-10-01 21:04:57 +08:00
} break ;
case ActionMapEditor : : BUTTON_EDIT_EVENT : {
// Action and Action name is located on the parent of the event.
current_action = item - > get_parent ( ) - > get_meta ( " __action " ) ;
current_action_name = item - > get_parent ( ) - > get_meta ( " __name " ) ;
current_action_event_index = item - > get_meta ( " __index " ) ;
Ref < InputEvent > ie = item - > get_meta ( " __event " ) ;
if ( ie . is_valid ( ) ) {
2023-12-18 05:56:26 +08:00
event_config_dialog - > popup_and_configure ( ie , current_action_name ) ;
2020-10-01 21:04:57 +08:00
}
} break ;
case ActionMapEditor : : BUTTON_REMOVE_ACTION : {
// Send removed action name
String name = item - > get_meta ( " __name " ) ;
2021-07-18 05:22:52 +08:00
emit_signal ( SNAME ( " action_removed " ) , name ) ;
2020-10-01 21:04:57 +08:00
} break ;
case ActionMapEditor : : BUTTON_REMOVE_EVENT : {
// Remove event and send updated action
2021-12-24 12:19:24 +08:00
Dictionary action = item - > get_parent ( ) - > get_meta ( " __action " ) . duplicate ( ) ;
2020-10-01 21:04:57 +08:00
String action_name = item - > get_parent ( ) - > get_meta ( " __name " ) ;
int event_index = item - > get_meta ( " __index " ) ;
2021-12-24 12:19:24 +08:00
Array events = action [ " events " ] . duplicate ( ) ;
2021-07-04 06:17:03 +08:00
events . remove_at ( event_index ) ;
2020-10-01 21:04:57 +08:00
action [ " events " ] = events ;
2021-07-18 05:22:52 +08:00
emit_signal ( SNAME ( " action_edited " ) , action_name , action ) ;
2020-10-01 21:04:57 +08:00
} break ;
2023-01-13 19:36:44 +08:00
case ActionMapEditor : : BUTTON_REVERT_ACTION : {
ERR_FAIL_COND_MSG ( ! item - > has_meta ( " __action_initial " ) , " Tree Item for action which can be reverted is expected to have meta value with initial value of action. " ) ;
Dictionary action = item - > get_meta ( " __action_initial " ) . duplicate ( ) ;
String action_name = item - > get_meta ( " __name " ) ;
emit_signal ( SNAME ( " action_edited " ) , action_name , action ) ;
} break ;
2020-10-01 21:04:57 +08:00
default :
break ;
}
}
void ActionMapEditor : : _tree_item_activated ( ) {
TreeItem * item = action_tree - > get_selected ( ) ;
if ( ! item | | ! item - > has_meta ( " __event " ) ) {
return ;
}
2021-09-18 15:33:18 +08:00
_tree_button_pressed ( item , 2 , BUTTON_EDIT_EVENT , MouseButton : : LEFT ) ;
2020-10-01 21:04:57 +08:00
}
2021-05-06 03:49:35 +08:00
void ActionMapEditor : : set_show_builtin_actions ( bool p_show ) {
show_builtin_actions = p_show ;
show_builtin_actions_checkbutton - > set_pressed ( p_show ) ;
2023-08-22 15:44:20 +08:00
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " project_settings " , " show_builtin_actions " , show_builtin_actions ) ;
2020-10-01 21:04:57 +08:00
2021-05-06 03:49:35 +08:00
// Prevent unnecessary updates of action list when cache is empty.
2020-10-01 21:04:57 +08:00
if ( ! actions_cache . is_empty ( ) ) {
update_action_list ( ) ;
}
}
void ActionMapEditor : : _search_term_updated ( const String & ) {
update_action_list ( ) ;
}
2022-10-02 22:50:05 +08:00
void ActionMapEditor : : _search_by_event ( const Ref < InputEvent > & p_event ) {
if ( p_event . is_null ( ) | | ( p_event - > is_pressed ( ) & & ! p_event - > is_echo ( ) ) ) {
update_action_list ( ) ;
}
}
2020-10-01 21:04:57 +08:00
Variant ActionMapEditor : : get_drag_data_fw ( const Point2 & p_point , Control * p_from ) {
TreeItem * selected = action_tree - > get_selected ( ) ;
if ( ! selected ) {
return Variant ( ) ;
}
String name = selected - > get_text ( 0 ) ;
Label * label = memnew ( Label ( name ) ) ;
2021-07-08 21:29:15 +08:00
label - > set_theme_type_variation ( " HeaderSmall " ) ;
2020-10-01 21:04:57 +08:00
label - > set_modulate ( Color ( 1 , 1 , 1 , 1.0f ) ) ;
action_tree - > set_drag_preview ( label ) ;
Dictionary drag_data ;
if ( selected - > has_meta ( " __action " ) ) {
drag_data [ " input_type " ] = " action " ;
}
if ( selected - > has_meta ( " __event " ) ) {
drag_data [ " input_type " ] = " event " ;
}
action_tree - > set_drop_mode_flags ( Tree : : DROP_MODE_INBETWEEN ) ;
return drag_data ;
}
bool ActionMapEditor : : can_drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) const {
Dictionary d = p_data ;
if ( ! d . has ( " input_type " ) ) {
return false ;
}
TreeItem * selected = action_tree - > get_selected ( ) ;
TreeItem * item = action_tree - > get_item_at_position ( p_point ) ;
if ( ! selected | | ! item | | item = = selected ) {
return false ;
}
// Don't allow moving an action in-between events.
if ( d [ " input_type " ] = = " action " & & item - > has_meta ( " __event " ) ) {
return false ;
}
// Don't allow moving an event to a different action.
if ( d [ " input_type " ] = = " event " & & item - > get_parent ( ) ! = selected - > get_parent ( ) ) {
return false ;
}
return true ;
}
void ActionMapEditor : : drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) {
if ( ! can_drop_data_fw ( p_point , p_data , p_from ) ) {
return ;
}
TreeItem * selected = action_tree - > get_selected ( ) ;
TreeItem * target = action_tree - > get_item_at_position ( p_point ) ;
bool drop_above = action_tree - > get_drop_section_at_position ( p_point ) = = - 1 ;
if ( ! target ) {
return ;
}
Dictionary d = p_data ;
if ( d [ " input_type " ] = = " action " ) {
// Change action order.
String relative_to = target - > get_meta ( " __name " ) ;
String action_name = selected - > get_meta ( " __name " ) ;
2021-07-18 05:22:52 +08:00
emit_signal ( SNAME ( " action_reordered " ) , action_name , relative_to , drop_above ) ;
2020-10-01 21:04:57 +08:00
} else if ( d [ " input_type " ] = = " event " ) {
// Change event order
int current_index = selected - > get_meta ( " __index " ) ;
int target_index = target - > get_meta ( " __index " ) ;
// Construct new events array.
Dictionary new_action = selected - > get_parent ( ) - > get_meta ( " __action " ) ;
Array events = new_action [ " events " ] ;
Array new_events ;
// The following method was used to perform the array changes since `remove` followed by `insert` was not working properly at time of writing.
// Loop thought existing events
for ( int i = 0 ; i < events . size ( ) ; i + + ) {
// If you come across the current index, just skip it, as it has been moved.
if ( i = = current_index ) {
continue ;
} else if ( i = = target_index ) {
// We are at the target index. If drop above, add selected event there first, then target, so moved event goes on top.
if ( drop_above ) {
new_events . push_back ( events [ current_index ] ) ;
new_events . push_back ( events [ target_index ] ) ;
} else {
new_events . push_back ( events [ target_index ] ) ;
new_events . push_back ( events [ current_index ] ) ;
}
} else {
new_events . push_back ( events [ i ] ) ;
}
}
new_action [ " events " ] = new_events ;
2021-07-18 05:22:52 +08:00
emit_signal ( SNAME ( " action_edited " ) , selected - > get_parent ( ) - > get_meta ( " __name " ) , new_action ) ;
2020-10-01 21:04:57 +08:00
}
}
void ActionMapEditor : : _notification ( int p_what ) {
switch ( p_what ) {
2022-08-29 17:04:31 +08:00
case NOTIFICATION_ENTER_TREE :
2020-10-01 21:04:57 +08:00
case NOTIFICATION_THEME_CHANGED : {
2023-08-13 08:33:39 +08:00
action_list_search - > set_right_icon ( get_editor_theme_icon ( SNAME ( " Search " ) ) ) ;
2024-01-12 04:13:23 +08:00
add_button - > set_icon ( get_editor_theme_icon ( SNAME ( " Add " ) ) ) ;
2022-08-25 14:11:39 +08:00
if ( ! actions_cache . is_empty ( ) ) {
update_action_list ( ) ;
}
2020-10-01 21:04:57 +08:00
} break ;
}
}
void ActionMapEditor : : _bind_methods ( ) {
ADD_SIGNAL ( MethodInfo ( " action_added " , PropertyInfo ( Variant : : STRING , " name " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " action_edited " , PropertyInfo ( Variant : : STRING , " name " ) , PropertyInfo ( Variant : : DICTIONARY , " new_action " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " action_removed " , PropertyInfo ( Variant : : STRING , " name " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " action_renamed " , PropertyInfo ( Variant : : STRING , " old_name " ) , PropertyInfo ( Variant : : STRING , " new_name " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " action_reordered " , PropertyInfo ( Variant : : STRING , " action_name " ) , PropertyInfo ( Variant : : STRING , " relative_to " ) , PropertyInfo ( Variant : : BOOL , " before " ) ) ) ;
2022-12-21 19:48:59 +08:00
ADD_SIGNAL ( MethodInfo ( SNAME ( " filter_focused " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( SNAME ( " filter_unfocused " ) ) ) ;
2020-10-01 21:04:57 +08:00
}
LineEdit * ActionMapEditor : : get_search_box ( ) const {
return action_list_search ;
}
2023-08-31 02:11:21 +08:00
LineEdit * ActionMapEditor : : get_path_box ( ) const {
return add_edit ;
}
2020-10-01 21:04:57 +08:00
InputEventConfigurationDialog * ActionMapEditor : : get_configuration_dialog ( ) {
return event_config_dialog ;
}
2022-10-02 22:50:05 +08:00
bool ActionMapEditor : : _should_display_action ( const String & p_name , const Array & p_events ) const {
const Ref < InputEvent > search_ev = action_list_search_by_event - > get_event ( ) ;
bool event_match = true ;
if ( search_ev . is_valid ( ) ) {
event_match = false ;
for ( int i = 0 ; i < p_events . size ( ) ; + + i ) {
const Ref < InputEvent > ev = p_events [ i ] ;
if ( ev . is_valid ( ) & & ev - > is_match ( search_ev , true ) ) {
event_match = true ;
}
}
}
return event_match & & action_list_search - > get_text ( ) . is_subsequence_ofn ( p_name ) ;
}
2020-10-01 21:04:57 +08:00
void ActionMapEditor : : update_action_list ( const Vector < ActionInfo > & p_action_infos ) {
if ( ! p_action_infos . is_empty ( ) ) {
actions_cache = p_action_infos ;
}
action_tree - > clear ( ) ;
TreeItem * root = action_tree - > create_item ( ) ;
for ( int i = 0 ; i < actions_cache . size ( ) ; i + + ) {
ActionInfo action_info = actions_cache [ i ] ;
2022-10-02 22:50:05 +08:00
const Array events = action_info . action [ " events " ] ;
if ( ! _should_display_action ( action_info . name , events ) ) {
2020-10-01 21:04:57 +08:00
continue ;
}
2021-05-06 03:49:35 +08:00
if ( ! action_info . editable & & ! show_builtin_actions ) {
2020-10-01 21:04:57 +08:00
continue ;
}
const Variant deadzone = action_info . action [ " deadzone " ] ;
// Update Tree...
TreeItem * action_item = action_tree - > create_item ( root ) ;
2024-03-10 16:35:18 +08:00
ERR_FAIL_NULL ( action_item ) ;
2020-10-01 21:04:57 +08:00
action_item - > set_meta ( " __action " , action_info . action ) ;
action_item - > set_meta ( " __name " , action_info . name ) ;
// First Column - Action Name
action_item - > set_text ( 0 , action_info . name ) ;
action_item - > set_editable ( 0 , action_info . editable ) ;
action_item - > set_icon ( 0 , action_info . icon ) ;
// Second Column - Deadzone
action_item - > set_editable ( 1 , true ) ;
action_item - > set_cell_mode ( 1 , TreeItem : : CELL_MODE_RANGE ) ;
action_item - > set_range_config ( 1 , 0.0 , 1.0 , 0.01 ) ;
action_item - > set_range ( 1 , deadzone ) ;
// Third column - buttons
2023-01-13 19:36:44 +08:00
if ( action_info . has_initial ) {
bool deadzone_eq = action_info . action_initial [ " deadzone " ] = = action_info . action [ " deadzone " ] ;
bool events_eq = Shortcut : : is_event_array_equal ( action_info . action_initial [ " events " ] , action_info . action [ " events " ] ) ;
bool action_eq = deadzone_eq & & events_eq ;
action_item - > set_meta ( " __action_initial " , action_info . action_initial ) ;
2023-08-13 08:33:39 +08:00
action_item - > add_button ( 2 , action_tree - > get_editor_theme_icon ( SNAME ( " ReloadSmall " ) ) , BUTTON_REVERT_ACTION , action_eq , action_eq ? TTR ( " Cannot Revert - Action is same as initial " ) : TTR ( " Revert Action " ) ) ;
2023-01-13 19:36:44 +08:00
}
2023-08-13 08:33:39 +08:00
action_item - > add_button ( 2 , action_tree - > get_editor_theme_icon ( SNAME ( " Add " ) ) , BUTTON_ADD_EVENT , false , TTR ( " Add Event " ) ) ;
action_item - > add_button ( 2 , action_tree - > get_editor_theme_icon ( SNAME ( " Remove " ) ) , BUTTON_REMOVE_ACTION , ! action_info . editable , action_info . editable ? TTR ( " Remove Action " ) : TTR ( " Cannot Remove Action " ) ) ;
2020-10-01 21:04:57 +08:00
2023-08-13 08:33:39 +08:00
action_item - > set_custom_bg_color ( 0 , action_tree - > get_theme_color ( SNAME ( " prop_subsection " ) , EditorStringName ( Editor ) ) ) ;
action_item - > set_custom_bg_color ( 1 , action_tree - > get_theme_color ( SNAME ( " prop_subsection " ) , EditorStringName ( Editor ) ) ) ;
2020-10-01 21:04:57 +08:00
for ( int evnt_idx = 0 ; evnt_idx < events . size ( ) ; evnt_idx + + ) {
Ref < InputEvent > event = events [ evnt_idx ] ;
if ( event . is_null ( ) ) {
continue ;
}
TreeItem * event_item = action_tree - > create_item ( action_item ) ;
// First Column - Text
2022-11-18 16:18:31 +08:00
event_item - > set_text ( 0 , EventListenerLineEdit : : get_event_text ( event , true ) ) ;
2020-10-01 21:04:57 +08:00
event_item - > set_meta ( " __event " , event ) ;
event_item - > set_meta ( " __index " , evnt_idx ) ;
2021-10-13 00:49:13 +08:00
// First Column - Icon
Ref < InputEventKey > k = event ;
if ( k . is_valid ( ) ) {
2022-12-11 07:21:22 +08:00
if ( k - > get_physical_keycode ( ) = = Key : : NONE & & k - > get_keycode ( ) = = Key : : NONE & & k - > get_key_label ( ) ! = Key : : NONE ) {
2023-08-13 08:33:39 +08:00
event_item - > set_icon ( 0 , action_tree - > get_editor_theme_icon ( SNAME ( " KeyboardLabel " ) ) ) ;
2022-12-11 07:21:22 +08:00
} else if ( k - > get_keycode ( ) ! = Key : : NONE ) {
2023-08-13 08:33:39 +08:00
event_item - > set_icon ( 0 , action_tree - > get_editor_theme_icon ( SNAME ( " Keyboard " ) ) ) ;
2022-12-11 07:21:22 +08:00
} else if ( k - > get_physical_keycode ( ) ! = Key : : NONE ) {
2023-08-13 08:33:39 +08:00
event_item - > set_icon ( 0 , action_tree - > get_editor_theme_icon ( SNAME ( " KeyboardPhysical " ) ) ) ;
2022-12-11 07:21:22 +08:00
} else {
2023-08-13 08:33:39 +08:00
event_item - > set_icon ( 0 , action_tree - > get_editor_theme_icon ( SNAME ( " KeyboardError " ) ) ) ;
2021-10-13 00:49:13 +08:00
}
}
Ref < InputEventMouseButton > mb = event ;
if ( mb . is_valid ( ) ) {
2023-08-13 08:33:39 +08:00
event_item - > set_icon ( 0 , action_tree - > get_editor_theme_icon ( SNAME ( " Mouse " ) ) ) ;
2021-10-13 00:49:13 +08:00
}
Ref < InputEventJoypadButton > jb = event ;
if ( jb . is_valid ( ) ) {
2023-08-13 08:33:39 +08:00
event_item - > set_icon ( 0 , action_tree - > get_editor_theme_icon ( SNAME ( " JoyButton " ) ) ) ;
2021-10-13 00:49:13 +08:00
}
Ref < InputEventJoypadMotion > jm = event ;
if ( jm . is_valid ( ) ) {
2023-08-13 08:33:39 +08:00
event_item - > set_icon ( 0 , action_tree - > get_editor_theme_icon ( SNAME ( " JoyAxis " ) ) ) ;
2021-10-13 00:49:13 +08:00
}
2020-10-01 21:04:57 +08:00
// Third Column - Buttons
2023-08-13 08:33:39 +08:00
event_item - > add_button ( 2 , action_tree - > get_editor_theme_icon ( SNAME ( " Edit " ) ) , BUTTON_EDIT_EVENT , false , TTR ( " Edit Event " ) ) ;
event_item - > add_button ( 2 , action_tree - > get_editor_theme_icon ( SNAME ( " Remove " ) ) , BUTTON_REMOVE_EVENT , false , TTR ( " Remove Event " ) ) ;
2020-10-01 21:04:57 +08:00
event_item - > set_button_color ( 2 , 0 , Color ( 1 , 1 , 1 , 0.75 ) ) ;
event_item - > set_button_color ( 2 , 1 , Color ( 1 , 1 , 1 , 0.75 ) ) ;
}
}
2024-03-23 17:49:40 +08:00
// Update UI.
clear_all_search - > set_disabled ( action_list_search - > get_text ( ) . is_empty ( ) & & action_list_search_by_event - > get_event ( ) . is_null ( ) ) ;
2020-10-01 21:04:57 +08:00
}
void ActionMapEditor : : show_message ( const String & p_message ) {
message - > set_text ( p_message ) ;
2022-04-08 06:46:49 +08:00
message - > popup_centered ( ) ;
2020-10-01 21:04:57 +08:00
}
void ActionMapEditor : : use_external_search_box ( LineEdit * p_searchbox ) {
memdelete ( action_list_search ) ;
action_list_search = p_searchbox ;
2024-05-14 17:42:00 +08:00
action_list_search - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & ActionMapEditor : : _search_term_updated ) ) ;
2020-10-01 21:04:57 +08:00
}
2022-12-21 19:48:59 +08:00
void ActionMapEditor : : _on_filter_focused ( ) {
emit_signal ( SNAME ( " filter_focused " ) ) ;
}
void ActionMapEditor : : _on_filter_unfocused ( ) {
emit_signal ( SNAME ( " filter_unfocused " ) ) ;
}
2020-10-01 21:04:57 +08:00
ActionMapEditor : : ActionMapEditor ( ) {
// Main Vbox Container
VBoxContainer * main_vbox = memnew ( VBoxContainer ) ;
2022-03-19 08:02:57 +08:00
main_vbox - > set_anchors_and_offsets_preset ( PRESET_FULL_RECT ) ;
2020-10-01 21:04:57 +08:00
add_child ( main_vbox ) ;
HBoxContainer * top_hbox = memnew ( HBoxContainer ) ;
main_vbox - > add_child ( top_hbox ) ;
action_list_search = memnew ( LineEdit ) ;
action_list_search - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2023-09-25 12:09:29 +08:00
action_list_search - > set_placeholder ( TTR ( " Filter by Name " ) ) ;
2020-10-01 21:04:57 +08:00
action_list_search - > set_clear_button_enabled ( true ) ;
2024-05-14 17:42:00 +08:00
action_list_search - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & ActionMapEditor : : _search_term_updated ) ) ;
2020-10-01 21:04:57 +08:00
top_hbox - > add_child ( action_list_search ) ;
2022-10-02 22:50:05 +08:00
action_list_search_by_event = memnew ( EventListenerLineEdit ) ;
action_list_search_by_event - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
action_list_search_by_event - > set_stretch_ratio ( 0.75 ) ;
action_list_search_by_event - > connect ( " event_changed " , callable_mp ( this , & ActionMapEditor : : _search_by_event ) ) ;
2023-09-04 23:01:33 +08:00
action_list_search_by_event - > connect ( SceneStringName ( focus_entered ) , callable_mp ( this , & ActionMapEditor : : _on_filter_focused ) ) ;
action_list_search_by_event - > connect ( SceneStringName ( focus_exited ) , callable_mp ( this , & ActionMapEditor : : _on_filter_unfocused ) ) ;
2022-10-02 22:50:05 +08:00
top_hbox - > add_child ( action_list_search_by_event ) ;
2024-03-23 17:49:40 +08:00
clear_all_search = memnew ( Button ) ;
2022-10-02 22:50:05 +08:00
clear_all_search - > set_text ( TTR ( " Clear All " ) ) ;
2024-03-23 17:49:40 +08:00
clear_all_search - > set_tooltip_text ( TTR ( " Clear all search filters. " ) ) ;
2024-05-14 15:40:21 +08:00
clear_all_search - > connect ( SceneStringName ( pressed ) , callable_mp ( action_list_search_by_event , & EventListenerLineEdit : : clear_event ) ) ;
clear_all_search - > connect ( SceneStringName ( pressed ) , callable_mp ( action_list_search , & LineEdit : : clear ) ) ;
2022-10-02 22:50:05 +08:00
top_hbox - > add_child ( clear_all_search ) ;
2020-10-01 21:04:57 +08:00
// Adding Action line edit + button
add_hbox = memnew ( HBoxContainer ) ;
add_hbox - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
add_edit = memnew ( LineEdit ) ;
add_edit - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
add_edit - > set_placeholder ( TTR ( " Add New Action " ) ) ;
add_edit - > set_clear_button_enabled ( true ) ;
2024-05-14 17:42:00 +08:00
add_edit - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & ActionMapEditor : : _add_edit_text_changed ) ) ;
2021-06-17 00:43:34 +08:00
add_edit - > connect ( " text_submitted " , callable_mp ( this , & ActionMapEditor : : _add_action ) ) ;
2020-10-01 21:04:57 +08:00
add_hbox - > add_child ( add_edit ) ;
2022-05-04 07:47:29 +08:00
add_button = memnew ( Button ) ;
2021-05-06 03:49:35 +08:00
add_button - > set_text ( TTR ( " Add " ) ) ;
2024-05-14 15:40:21 +08:00
add_button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ActionMapEditor : : _add_action_pressed ) ) ;
2020-10-01 21:04:57 +08:00
add_hbox - > add_child ( add_button ) ;
2022-05-04 07:47:29 +08:00
// Disable the button and set its tooltip.
_add_edit_text_changed ( add_edit - > get_text ( ) ) ;
2020-10-01 21:04:57 +08:00
2024-01-12 04:13:23 +08:00
add_hbox - > add_child ( memnew ( VSeparator ) ) ;
2022-10-02 22:50:05 +08:00
show_builtin_actions_checkbutton = memnew ( CheckButton ) ;
show_builtin_actions_checkbutton - > set_text ( TTR ( " Show Built-in Actions " ) ) ;
show_builtin_actions_checkbutton - > connect ( " toggled " , callable_mp ( this , & ActionMapEditor : : set_show_builtin_actions ) ) ;
add_hbox - > add_child ( show_builtin_actions_checkbutton ) ;
2023-08-22 15:44:20 +08:00
show_builtin_actions = EditorSettings : : get_singleton ( ) - > get_project_metadata ( " project_settings " , " show_builtin_actions " , false ) ;
show_builtin_actions_checkbutton - > set_pressed ( show_builtin_actions ) ;
2020-10-01 21:04:57 +08:00
main_vbox - > add_child ( add_hbox ) ;
// Action Editor Tree
action_tree = memnew ( Tree ) ;
action_tree - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
action_tree - > set_columns ( 3 ) ;
action_tree - > set_hide_root ( true ) ;
action_tree - > set_column_titles_visible ( true ) ;
action_tree - > set_column_title ( 0 , TTR ( " Action " ) ) ;
2021-07-04 11:13:28 +08:00
action_tree - > set_column_clip_content ( 0 , true ) ;
2020-10-01 21:04:57 +08:00
action_tree - > set_column_title ( 1 , TTR ( " Deadzone " ) ) ;
action_tree - > set_column_expand ( 1 , false ) ;
2021-06-28 21:40:56 +08:00
action_tree - > set_column_custom_minimum_width ( 1 , 80 * EDSCALE ) ;
2020-10-01 21:04:57 +08:00
action_tree - > set_column_expand ( 2 , false ) ;
2021-06-28 21:40:56 +08:00
action_tree - > set_column_custom_minimum_width ( 2 , 50 * EDSCALE ) ;
2024-03-10 16:35:18 +08:00
action_tree - > connect ( " item_edited " , callable_mp ( this , & ActionMapEditor : : _action_edited ) , CONNECT_DEFERRED ) ;
2020-10-01 21:04:57 +08:00
action_tree - > connect ( " item_activated " , callable_mp ( this , & ActionMapEditor : : _tree_item_activated ) ) ;
2021-09-18 15:33:18 +08:00
action_tree - > connect ( " button_clicked " , callable_mp ( this , & ActionMapEditor : : _tree_button_pressed ) ) ;
2020-10-01 21:04:57 +08:00
main_vbox - > add_child ( action_tree ) ;
2023-01-14 10:37:19 +08:00
SET_DRAG_FORWARDING_GCD ( action_tree , ActionMapEditor ) ;
2020-10-01 21:04:57 +08:00
// Adding event dialog
event_config_dialog = memnew ( InputEventConfigurationDialog ) ;
2024-05-14 20:28:18 +08:00
event_config_dialog - > connect ( SceneStringName ( confirmed ) , callable_mp ( this , & ActionMapEditor : : _event_config_confirmed ) ) ;
2020-10-01 21:04:57 +08:00
add_child ( event_config_dialog ) ;
message = memnew ( AcceptDialog ) ;
add_child ( message ) ;
}