2014-02-10 09:10:30 +08:00
/*************************************************************************/
/* undo_redo.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 20:16:55 +08:00
/* https://godotengine.org */
2014-02-10 09:10:30 +08:00
/*************************************************************************/
2019-01-01 19:53:14 +08:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 09:10:30 +08:00
/* */
/* 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 "undo_redo.h"
2017-01-16 15:04:19 +08:00
2018-09-12 00:13:45 +08:00
# include "core/os/os.h"
2014-02-10 09:10:30 +08:00
void UndoRedo : : _discard_redo ( ) {
2017-03-05 23:44:50 +08:00
if ( current_action = = actions . size ( ) - 1 )
2014-02-10 09:10:30 +08:00
return ;
2017-03-05 23:44:50 +08:00
for ( int i = current_action + 1 ; i < actions . size ( ) ; i + + ) {
2014-02-10 09:10:30 +08:00
2018-07-25 09:11:03 +08:00
for ( List < Operation > : : Element * E = actions . write [ i ] . do_ops . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
if ( E - > get ( ) . type = = Operation : : TYPE_REFERENCE ) {
2014-02-10 09:10:30 +08:00
Object * obj = ObjectDB : : get_instance ( E - > get ( ) . object ) ;
if ( obj )
memdelete ( obj ) ;
}
}
//ERASE do data
}
2017-03-05 23:44:50 +08:00
actions . resize ( current_action + 1 ) ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
void UndoRedo : : create_action ( const String & p_name , MergeMode p_mode ) {
2014-02-10 09:10:30 +08:00
2017-01-05 20:16:00 +08:00
uint32_t ticks = OS : : get_singleton ( ) - > get_ticks_msec ( ) ;
2017-03-05 23:44:50 +08:00
if ( action_level = = 0 ) {
2014-02-10 09:10:30 +08:00
_discard_redo ( ) ;
2016-08-18 04:14:51 +08:00
// Check if the merge operation is valid
2019-02-26 01:09:33 +08:00
if ( p_mode ! = MERGE_DISABLE & & actions . size ( ) & & actions [ actions . size ( ) - 1 ] . name = = p_name & & actions [ actions . size ( ) - 1 ] . last_tick + 800 > ticks ) {
2016-08-18 04:14:51 +08:00
2017-03-05 23:44:50 +08:00
current_action = actions . size ( ) - 2 ;
2016-08-18 04:14:51 +08:00
2019-02-26 01:09:33 +08:00
if ( p_mode = = MERGE_ENDS ) {
2016-08-18 04:14:51 +08:00
2019-02-26 01:09:33 +08:00
// Clear all do ops from last action, and delete all object references
List < Operation > : : Element * E = actions . write [ current_action + 1 ] . do_ops . front ( ) ;
2016-08-18 04:14:51 +08:00
2019-02-26 01:09:33 +08:00
while ( E ) {
2016-08-18 04:14:51 +08:00
2019-02-26 01:09:33 +08:00
if ( E - > get ( ) . type = = Operation : : TYPE_REFERENCE ) {
2016-08-18 04:14:51 +08:00
2019-02-26 01:09:33 +08:00
Object * obj = ObjectDB : : get_instance ( E - > get ( ) . object ) ;
if ( obj )
memdelete ( obj ) ;
}
2019-02-22 02:29:57 +08:00
2019-02-26 01:09:33 +08:00
E = E - > next ( ) ;
actions . write [ current_action + 1 ] . do_ops . pop_front ( ) ;
}
2016-08-18 04:14:51 +08:00
}
2018-07-25 09:11:03 +08:00
actions . write [ actions . size ( ) - 1 ] . last_tick = ticks ;
2019-02-26 01:09:33 +08:00
merge_mode = p_mode ;
2019-03-23 09:06:01 +08:00
merging = true ;
2014-02-10 09:10:30 +08:00
} else {
2016-08-18 04:14:51 +08:00
2014-02-10 09:10:30 +08:00
Action new_action ;
2017-03-05 23:44:50 +08:00
new_action . name = p_name ;
new_action . last_tick = ticks ;
2014-02-10 09:10:30 +08:00
actions . push_back ( new_action ) ;
2019-02-22 02:29:57 +08:00
2019-02-26 01:09:33 +08:00
merge_mode = MERGE_DISABLE ;
}
2014-02-10 09:10:30 +08:00
}
action_level + + ;
}
2017-03-05 23:44:50 +08:00
void UndoRedo : : add_do_method ( Object * p_object , const String & p_method , VARIANT_ARG_DECLARE ) {
2014-02-10 09:10:30 +08:00
VARIANT_ARGPTRS
2018-01-07 18:47:55 +08:00
ERR_FAIL_COND ( p_object = = NULL ) ;
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND ( action_level < = 0 ) ;
ERR_FAIL_COND ( ( current_action + 1 ) > = actions . size ( ) ) ;
2014-02-10 09:10:30 +08:00
Operation do_op ;
2017-08-07 18:17:31 +08:00
do_op . object = p_object - > get_instance_id ( ) ;
2017-08-25 04:58:51 +08:00
if ( Object : : cast_to < Resource > ( p_object ) )
do_op . resref = Ref < Resource > ( Object : : cast_to < Resource > ( p_object ) ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
do_op . type = Operation : : TYPE_METHOD ;
do_op . name = p_method ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
do_op . args [ i ] = * argptr [ i ] ;
2014-02-10 09:10:30 +08:00
}
2018-07-25 09:11:03 +08:00
actions . write [ current_action + 1 ] . do_ops . push_back ( do_op ) ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
void UndoRedo : : add_undo_method ( Object * p_object , const String & p_method , VARIANT_ARG_DECLARE ) {
2014-02-10 09:10:30 +08:00
VARIANT_ARGPTRS
2018-01-07 18:47:55 +08:00
ERR_FAIL_COND ( p_object = = NULL ) ;
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND ( action_level < = 0 ) ;
ERR_FAIL_COND ( ( current_action + 1 ) > = actions . size ( ) ) ;
2016-08-18 04:14:51 +08:00
// No undo if the merge mode is MERGE_ENDS
2017-03-05 23:44:50 +08:00
if ( merge_mode = = MERGE_ENDS )
2016-08-18 04:14:51 +08:00
return ;
2014-02-10 09:10:30 +08:00
Operation undo_op ;
2017-08-07 18:17:31 +08:00
undo_op . object = p_object - > get_instance_id ( ) ;
2017-08-25 04:58:51 +08:00
if ( Object : : cast_to < Resource > ( p_object ) )
undo_op . resref = Ref < Resource > ( Object : : cast_to < Resource > ( p_object ) ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
undo_op . type = Operation : : TYPE_METHOD ;
undo_op . name = p_method ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
undo_op . args [ i ] = * argptr [ i ] ;
2014-02-10 09:10:30 +08:00
}
2018-07-25 09:11:03 +08:00
actions . write [ current_action + 1 ] . undo_ops . push_back ( undo_op ) ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
void UndoRedo : : add_do_property ( Object * p_object , const String & p_property , const Variant & p_value ) {
2014-02-10 09:10:30 +08:00
2018-01-07 18:47:55 +08:00
ERR_FAIL_COND ( p_object = = NULL ) ;
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND ( action_level < = 0 ) ;
ERR_FAIL_COND ( ( current_action + 1 ) > = actions . size ( ) ) ;
2014-02-10 09:10:30 +08:00
Operation do_op ;
2017-08-07 18:17:31 +08:00
do_op . object = p_object - > get_instance_id ( ) ;
2017-08-25 04:58:51 +08:00
if ( Object : : cast_to < Resource > ( p_object ) )
do_op . resref = Ref < Resource > ( Object : : cast_to < Resource > ( p_object ) ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
do_op . type = Operation : : TYPE_PROPERTY ;
do_op . name = p_property ;
do_op . args [ 0 ] = p_value ;
2018-07-25 09:11:03 +08:00
actions . write [ current_action + 1 ] . do_ops . push_back ( do_op ) ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
void UndoRedo : : add_undo_property ( Object * p_object , const String & p_property , const Variant & p_value ) {
2014-02-10 09:10:30 +08:00
2018-01-07 18:47:55 +08:00
ERR_FAIL_COND ( p_object = = NULL ) ;
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND ( action_level < = 0 ) ;
ERR_FAIL_COND ( ( current_action + 1 ) > = actions . size ( ) ) ;
2014-02-10 09:10:30 +08:00
2016-08-18 04:14:51 +08:00
// No undo if the merge mode is MERGE_ENDS
2017-03-05 23:44:50 +08:00
if ( merge_mode = = MERGE_ENDS )
2016-08-18 04:14:51 +08:00
return ;
2014-02-10 09:10:30 +08:00
Operation undo_op ;
2017-08-07 18:17:31 +08:00
undo_op . object = p_object - > get_instance_id ( ) ;
2017-08-25 04:58:51 +08:00
if ( Object : : cast_to < Resource > ( p_object ) )
undo_op . resref = Ref < Resource > ( Object : : cast_to < Resource > ( p_object ) ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
undo_op . type = Operation : : TYPE_PROPERTY ;
undo_op . name = p_property ;
undo_op . args [ 0 ] = p_value ;
2018-07-25 09:11:03 +08:00
actions . write [ current_action + 1 ] . undo_ops . push_back ( undo_op ) ;
2014-02-10 09:10:30 +08:00
}
void UndoRedo : : add_do_reference ( Object * p_object ) {
2018-01-07 18:47:55 +08:00
ERR_FAIL_COND ( p_object = = NULL ) ;
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND ( action_level < = 0 ) ;
ERR_FAIL_COND ( ( current_action + 1 ) > = actions . size ( ) ) ;
2014-02-10 09:10:30 +08:00
Operation do_op ;
2017-08-07 18:17:31 +08:00
do_op . object = p_object - > get_instance_id ( ) ;
2017-08-25 04:58:51 +08:00
if ( Object : : cast_to < Resource > ( p_object ) )
do_op . resref = Ref < Resource > ( Object : : cast_to < Resource > ( p_object ) ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
do_op . type = Operation : : TYPE_REFERENCE ;
2018-07-25 09:11:03 +08:00
actions . write [ current_action + 1 ] . do_ops . push_back ( do_op ) ;
2014-02-10 09:10:30 +08:00
}
void UndoRedo : : add_undo_reference ( Object * p_object ) {
2018-01-07 18:47:55 +08:00
ERR_FAIL_COND ( p_object = = NULL ) ;
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND ( action_level < = 0 ) ;
ERR_FAIL_COND ( ( current_action + 1 ) > = actions . size ( ) ) ;
2016-08-18 04:14:51 +08:00
// No undo if the merge mode is MERGE_ENDS
2017-03-05 23:44:50 +08:00
if ( merge_mode = = MERGE_ENDS )
2016-08-18 04:14:51 +08:00
return ;
2014-02-10 09:10:30 +08:00
Operation undo_op ;
2017-08-07 18:17:31 +08:00
undo_op . object = p_object - > get_instance_id ( ) ;
2017-08-25 04:58:51 +08:00
if ( Object : : cast_to < Resource > ( p_object ) )
undo_op . resref = Ref < Resource > ( Object : : cast_to < Resource > ( p_object ) ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
undo_op . type = Operation : : TYPE_REFERENCE ;
2018-07-25 09:11:03 +08:00
actions . write [ current_action + 1 ] . undo_ops . push_back ( undo_op ) ;
2014-02-10 09:10:30 +08:00
}
void UndoRedo : : _pop_history_tail ( ) {
_discard_redo ( ) ;
if ( ! actions . size ( ) )
return ;
2018-07-25 09:11:03 +08:00
for ( List < Operation > : : Element * E = actions . write [ 0 ] . undo_ops . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
if ( E - > get ( ) . type = = Operation : : TYPE_REFERENCE ) {
2014-02-10 09:10:30 +08:00
Object * obj = ObjectDB : : get_instance ( E - > get ( ) . object ) ;
if ( obj )
memdelete ( obj ) ;
}
}
actions . remove ( 0 ) ;
2019-02-14 21:19:03 +08:00
if ( current_action > = 0 ) {
current_action - - ;
}
2014-02-10 09:10:30 +08:00
}
2019-05-19 18:34:40 +08:00
bool UndoRedo : : is_committing_action ( ) const {
return committing > 0 ;
2019-03-04 04:53:59 +08:00
}
2014-02-10 09:10:30 +08:00
void UndoRedo : : commit_action ( ) {
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND ( action_level < = 0 ) ;
2014-02-10 09:10:30 +08:00
action_level - - ;
2017-03-05 23:44:50 +08:00
if ( action_level > 0 )
2014-02-10 09:10:30 +08:00
return ; //still nested
2019-03-23 09:06:01 +08:00
if ( merging ) {
version - - ;
merging = false ;
}
2019-05-19 18:34:40 +08:00
committing + + ;
2014-02-10 09:10:30 +08:00
redo ( ) ; // perform action
2019-05-19 18:34:40 +08:00
committing - - ;
2017-03-05 23:44:50 +08:00
if ( callback & & actions . size ( ) > 0 ) {
callback ( callback_ud , actions [ actions . size ( ) - 1 ] . name ) ;
2014-02-10 09:10:30 +08:00
}
}
void UndoRedo : : _process_operation_list ( List < Operation > : : Element * E ) {
2017-03-05 23:44:50 +08:00
for ( ; E ; E = E - > next ( ) ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
Operation & op = E - > get ( ) ;
2014-02-10 09:10:30 +08:00
Object * obj = ObjectDB : : get_instance ( op . object ) ;
2019-02-14 21:19:03 +08:00
if ( ! obj ) //may have been deleted and this is fine
continue ;
2015-05-12 08:36:29 +08:00
2017-03-05 23:44:50 +08:00
switch ( op . type ) {
2014-02-10 09:10:30 +08:00
case Operation : : TYPE_METHOD : {
2018-09-08 09:14:13 +08:00
Vector < const Variant * > argptrs ;
argptrs . resize ( VARIANT_ARG_MAX ) ;
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( op . args [ i ] . get_type ( ) = = Variant : : NIL ) {
break ;
}
argptrs . write [ i ] = & op . args [ i ] ;
argc + + ;
}
argptrs . resize ( argc ) ;
Variant : : CallError ce ;
obj - > call ( op . name , ( const Variant * * ) argptrs . ptr ( ) , argc , ce ) ;
if ( ce . error ! = Variant : : CallError : : CALL_OK ) {
ERR_PRINTS ( " Error calling method from signal ' " + String ( op . name ) + " ': " + Variant : : get_call_error_text ( obj , op . name , ( const Variant * * ) argptrs . ptr ( ) , argc , ce ) ) ;
}
2015-05-12 08:36:29 +08:00
# ifdef TOOLS_ENABLED
2017-08-25 04:58:51 +08:00
Resource * res = Object : : cast_to < Resource > ( obj ) ;
2015-05-12 08:36:29 +08:00
if ( res )
res - > set_edited ( true ) ;
2015-08-02 23:29:37 +08:00
2015-05-12 08:36:29 +08:00
# endif
2015-08-02 23:29:37 +08:00
if ( method_callback ) {
2017-03-05 23:44:50 +08:00
method_callback ( method_callbck_ud , obj , op . name , VARIANT_ARGS_FROM_ARRAY ( op . args ) ) ;
2015-08-02 23:29:37 +08:00
}
2014-02-10 09:10:30 +08:00
} break ;
case Operation : : TYPE_PROPERTY : {
2017-03-05 23:44:50 +08:00
obj - > set ( op . name , op . args [ 0 ] ) ;
2014-11-02 22:31:01 +08:00
# ifdef TOOLS_ENABLED
2017-08-25 04:58:51 +08:00
Resource * res = Object : : cast_to < Resource > ( obj ) ;
2014-11-02 22:31:01 +08:00
if ( res )
res - > set_edited ( true ) ;
# endif
2015-08-02 23:29:37 +08:00
if ( property_callback ) {
2017-03-05 23:44:50 +08:00
property_callback ( prop_callback_ud , obj , op . name , op . args [ 0 ] ) ;
2015-08-02 23:29:37 +08:00
}
2014-02-10 09:10:30 +08:00
} break ;
case Operation : : TYPE_REFERENCE : {
//do nothing
} break ;
}
}
}
2018-05-27 10:41:19 +08:00
bool UndoRedo : : redo ( ) {
2014-02-10 09:10:30 +08:00
2018-05-27 10:41:19 +08:00
ERR_FAIL_COND_V ( action_level > 0 , false ) ;
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
if ( ( current_action + 1 ) > = actions . size ( ) )
2018-05-27 10:41:19 +08:00
return false ; //nothing to redo
2019-03-04 04:53:59 +08:00
2014-02-10 09:10:30 +08:00
current_action + + ;
2018-07-25 09:11:03 +08:00
_process_operation_list ( actions . write [ current_action ] . do_ops . front ( ) ) ;
2014-02-10 09:10:30 +08:00
version + + ;
2019-02-14 07:52:51 +08:00
emit_signal ( " version_changed " ) ;
2018-05-27 10:41:19 +08:00
return true ;
2014-02-10 09:10:30 +08:00
}
2018-05-27 10:41:19 +08:00
bool UndoRedo : : undo ( ) {
2014-02-10 09:10:30 +08:00
2018-05-27 10:41:19 +08:00
ERR_FAIL_COND_V ( action_level > 0 , false ) ;
2017-03-05 23:44:50 +08:00
if ( current_action < 0 )
2018-05-27 10:41:19 +08:00
return false ; //nothing to redo
2018-07-25 09:11:03 +08:00
_process_operation_list ( actions . write [ current_action ] . undo_ops . front ( ) ) ;
2014-02-10 09:10:30 +08:00
current_action - - ;
2015-06-22 11:03:19 +08:00
version - - ;
2019-02-14 07:52:51 +08:00
emit_signal ( " version_changed " ) ;
2018-05-27 10:41:19 +08:00
return true ;
2014-02-10 09:10:30 +08:00
}
2018-11-19 04:07:38 +08:00
void UndoRedo : : clear_history ( bool p_increase_version ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND ( action_level > 0 ) ;
2014-02-10 09:10:30 +08:00
_discard_redo ( ) ;
2017-03-05 23:44:50 +08:00
while ( actions . size ( ) )
2014-02-10 09:10:30 +08:00
_pop_history_tail ( ) ;
2019-02-14 07:52:51 +08:00
if ( p_increase_version ) {
2018-11-19 04:07:38 +08:00
version + + ;
2019-02-14 07:52:51 +08:00
emit_signal ( " version_changed " ) ;
}
2014-02-10 09:10:30 +08:00
}
String UndoRedo : : get_current_action_name ( ) const {
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND_V ( action_level > 0 , " " ) ;
if ( current_action < 0 )
2019-02-14 07:52:51 +08:00
return " " ;
2014-02-10 09:10:30 +08:00
return actions [ current_action ] . name ;
}
2019-02-14 07:52:51 +08:00
bool UndoRedo : : has_undo ( ) {
return current_action > = 0 ;
}
bool UndoRedo : : has_redo ( ) {
return ( current_action + 1 ) < actions . size ( ) ;
}
2014-02-10 09:10:30 +08:00
uint64_t UndoRedo : : get_version ( ) const {
return version ;
}
2017-03-05 23:44:50 +08:00
void UndoRedo : : set_commit_notify_callback ( CommitNotifyCallback p_callback , void * p_ud ) {
2014-02-10 09:10:30 +08:00
2017-03-05 23:44:50 +08:00
callback = p_callback ;
callback_ud = p_ud ;
2014-02-10 09:10:30 +08:00
}
2017-03-05 23:44:50 +08:00
void UndoRedo : : set_method_notify_callback ( MethodNotifyCallback p_method_callback , void * p_ud ) {
2015-08-02 23:29:37 +08:00
2017-03-05 23:44:50 +08:00
method_callback = p_method_callback ;
method_callbck_ud = p_ud ;
2015-08-02 23:29:37 +08:00
}
2017-03-05 23:44:50 +08:00
void UndoRedo : : set_property_notify_callback ( PropertyNotifyCallback p_property_callback , void * p_ud ) {
2015-08-02 23:29:37 +08:00
2017-03-05 23:44:50 +08:00
property_callback = p_property_callback ;
prop_callback_ud = p_ud ;
2015-08-02 23:29:37 +08:00
}
2014-02-10 09:10:30 +08:00
UndoRedo : : UndoRedo ( ) {
2019-05-19 18:34:40 +08:00
committing = 0 ;
2017-03-05 23:44:50 +08:00
version = 1 ;
action_level = 0 ;
current_action = - 1 ;
merge_mode = MERGE_DISABLE ;
2019-03-23 09:06:01 +08:00
merging = false ;
2017-03-05 23:44:50 +08:00
callback = NULL ;
callback_ud = NULL ;
method_callbck_ud = NULL ;
prop_callback_ud = NULL ;
method_callback = NULL ;
property_callback = NULL ;
2014-02-10 09:10:30 +08:00
}
UndoRedo : : ~ UndoRedo ( ) {
clear_history ( ) ;
}
2015-06-22 03:55:47 +08:00
2017-03-05 23:44:50 +08:00
Variant UndoRedo : : _add_do_method ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2015-06-22 03:55:47 +08:00
2017-03-05 23:44:50 +08:00
if ( p_argcount < 2 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 0 ;
2015-06-22 03:55:47 +08:00
return Variant ( ) ;
}
2017-03-05 23:44:50 +08:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : OBJECT ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : OBJECT ;
2015-06-22 03:55:47 +08:00
return Variant ( ) ;
}
2017-03-05 23:44:50 +08:00
if ( p_args [ 1 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 1 ;
r_error . expected = Variant : : STRING ;
2015-06-22 03:55:47 +08:00
return Variant ( ) ;
}
2017-03-05 23:44:50 +08:00
r_error . error = Variant : : CallError : : CALL_OK ;
2015-06-22 03:55:47 +08:00
2017-03-05 23:44:50 +08:00
Object * object = * p_args [ 0 ] ;
2015-06-22 03:55:47 +08:00
String method = * p_args [ 1 ] ;
Variant v [ VARIANT_ARG_MAX ] ;
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < MIN ( VARIANT_ARG_MAX , p_argcount - 2 ) ; + + i ) {
2015-06-22 03:55:47 +08:00
2017-03-05 23:44:50 +08:00
v [ i ] = * p_args [ i + 2 ] ;
2015-06-22 03:55:47 +08:00
}
2017-03-05 23:44:50 +08:00
add_do_method ( object , method , v [ 0 ] , v [ 1 ] , v [ 2 ] , v [ 3 ] , v [ 4 ] ) ;
2015-06-22 03:55:47 +08:00
return Variant ( ) ;
}
2017-03-05 23:44:50 +08:00
Variant UndoRedo : : _add_undo_method ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2015-06-22 03:55:47 +08:00
2017-03-05 23:44:50 +08:00
if ( p_argcount < 2 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 0 ;
2015-06-22 03:55:47 +08:00
return Variant ( ) ;
}
2017-03-05 23:44:50 +08:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : OBJECT ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : OBJECT ;
2015-06-22 03:55:47 +08:00
return Variant ( ) ;
}
2017-03-05 23:44:50 +08:00
if ( p_args [ 1 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 1 ;
r_error . expected = Variant : : STRING ;
2015-06-22 03:55:47 +08:00
return Variant ( ) ;
}
2017-03-05 23:44:50 +08:00
r_error . error = Variant : : CallError : : CALL_OK ;
2015-06-22 03:55:47 +08:00
2017-03-05 23:44:50 +08:00
Object * object = * p_args [ 0 ] ;
2015-06-22 03:55:47 +08:00
String method = * p_args [ 1 ] ;
Variant v [ VARIANT_ARG_MAX ] ;
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < MIN ( VARIANT_ARG_MAX , p_argcount - 2 ) ; + + i ) {
2015-06-22 03:55:47 +08:00
2017-03-05 23:44:50 +08:00
v [ i ] = * p_args [ i + 2 ] ;
2015-06-22 03:55:47 +08:00
}
2017-03-05 23:44:50 +08:00
add_undo_method ( object , method , v [ 0 ] , v [ 1 ] , v [ 2 ] , v [ 3 ] , v [ 4 ] ) ;
2015-06-22 03:55:47 +08:00
return Variant ( ) ;
}
void UndoRedo : : _bind_methods ( ) {
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " create_action " , " name " , " merge_mode " ) , & UndoRedo : : create_action , DEFVAL ( MERGE_DISABLE ) ) ;
ClassDB : : bind_method ( D_METHOD ( " commit_action " ) , & UndoRedo : : commit_action ) ;
2019-05-19 18:34:40 +08:00
// FIXME: Typo in "commiting", fix in 4.0 when breaking compat.
ClassDB : : bind_method ( D_METHOD ( " is_commiting_action " ) , & UndoRedo : : is_committing_action ) ;
2016-03-09 07:00:52 +08:00
2015-06-22 03:55:47 +08:00
{
MethodInfo mi ;
2017-03-05 23:44:50 +08:00
mi . name = " add_do_method " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : OBJECT , " object " ) ) ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING , " method " ) ) ;
2015-06-22 03:55:47 +08:00
2017-03-05 23:44:50 +08:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " add_do_method " , & UndoRedo : : _add_do_method , mi ) ;
2015-06-22 03:55:47 +08:00
}
{
MethodInfo mi ;
2017-03-05 23:44:50 +08:00
mi . name = " add_undo_method " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : OBJECT , " object " ) ) ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING , " method " ) ) ;
2016-09-08 06:39:02 +08:00
2017-03-05 23:44:50 +08:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " add_undo_method " , & UndoRedo : : _add_undo_method , mi ) ;
2015-06-22 03:55:47 +08:00
}
2017-08-09 19:19:41 +08:00
ClassDB : : bind_method ( D_METHOD ( " add_do_property " , " object " , " property " , " value " ) , & UndoRedo : : add_do_property ) ;
ClassDB : : bind_method ( D_METHOD ( " add_undo_property " , " object " , " property " , " value " ) , & UndoRedo : : add_undo_property ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " add_do_reference " , " object " ) , & UndoRedo : : add_do_reference ) ;
ClassDB : : bind_method ( D_METHOD ( " add_undo_reference " , " object " ) , & UndoRedo : : add_undo_reference ) ;
2018-11-19 04:07:38 +08:00
ClassDB : : bind_method ( D_METHOD ( " clear_history " , " increase_version " ) , & UndoRedo : : clear_history , DEFVAL ( true ) ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_current_action_name " ) , & UndoRedo : : get_current_action_name ) ;
2019-02-14 07:52:51 +08:00
ClassDB : : bind_method ( D_METHOD ( " has_undo " ) , & UndoRedo : : has_undo ) ;
ClassDB : : bind_method ( D_METHOD ( " has_redo " ) , & UndoRedo : : has_redo ) ;
2017-03-05 23:44:50 +08:00
ClassDB : : bind_method ( D_METHOD ( " get_version " ) , & UndoRedo : : get_version ) ;
2017-09-13 11:37:01 +08:00
ClassDB : : bind_method ( D_METHOD ( " redo " ) , & UndoRedo : : redo ) ;
ClassDB : : bind_method ( D_METHOD ( " undo " ) , & UndoRedo : : undo ) ;
2016-08-18 04:14:51 +08:00
2019-02-14 07:52:51 +08:00
ADD_SIGNAL ( MethodInfo ( " version_changed " ) ) ;
2017-08-20 23:45:01 +08:00
BIND_ENUM_CONSTANT ( MERGE_DISABLE ) ;
BIND_ENUM_CONSTANT ( MERGE_ENDS ) ;
BIND_ENUM_CONSTANT ( MERGE_ALL ) ;
2015-06-23 10:44:13 +08:00
}