Advertisement
snake5

sgs-ui - undo layer system

Sep 30th, 2014
405
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. global UndoLayer = {};
  2.  
  3. function UndoLayer.create()
  4. {
  5.     data =
  6.     {
  7.         object_types = {},
  8.         feedback_out = {},
  9.        
  10.         undo_states = [],
  11.         current_pos = 0,
  12.        
  13.         change = null,
  14.     };
  15.     class( data, UndoLayer );
  16.    
  17.     data.registerFeedbackOutput( "undolayer", this._registerChange );
  18.    
  19.     return data;
  20. }
  21.  
  22. //  S E T U P
  23.  
  24. function UndoLayer.registerObject( obj, fnobj, fn_add, fn_rem, fn_getstate, fn_getprop, fn_setprop )
  25. {
  26.     if( @this.object_types[ obj ] )
  27.         return WARNING( "object already registered: " $ obj );
  28.     this.object_types[ obj ] =
  29.     {
  30.         fnobj = fnobj,
  31.         add = fn_add,
  32.         rem = fn_rem,
  33.         getstate = fn_getstate,
  34.         getprop = fn_getprop,
  35.         setprop = fn_setprop
  36.     };
  37. }
  38.  
  39. function UndoLayer.registerFeedbackOutput( name, func )
  40. {
  41.     this.feedback_out[ name ] = func;
  42. }
  43.  
  44. function UndoLayer.unregisterFeedbackOutput( name )
  45. {
  46.     unset( this.feedback_out, name );
  47. }
  48.  
  49. //  U N D O - using
  50.  
  51. function UndoLayer.undo()
  52. {
  53.     if( this.current_pos == 0 )
  54.         return WARNING( "cannot undo - limit reached" );
  55.    
  56.     cp = --this.current_pos;
  57.     state = this.undo_states[ cp ];
  58.    
  59.     if( state.type == "add" )
  60.         this.doRemove( "undolayer", state.objtype, state.id );
  61.     else if( state.type == "remove" )
  62.     {
  63.         id = this.doAdd( "undolayer", state.objtype, state.state );
  64.         if( id != state.id )
  65.             return WARNING( "data link error: returned object ID mismatch" );
  66.     }
  67.     else if( state.type == "change" )
  68.         this.doChange( "undolayer", state.objtype, state.id, state.state_from );
  69. }
  70.  
  71. function UndoLayer.redo()
  72. {
  73.     if( this.current_pos == this.undo_states.size )
  74.         return WARNING( "cannot undo - limit reached" );
  75.    
  76.     cp = ++this.current_pos;
  77.     state = this.undo_states[ cp ];
  78.    
  79.     if( state.type == "add" )
  80.     {
  81.         id = this.doAdd( "undolayer", state.objtype, state.state );
  82.         if( id != state.id )
  83.             return WARNING( "data link error: returned object ID mismatch" );
  84.     }
  85.     else if( state.type == "remove" )
  86.         this.doRemove( "undolayer", state.objtype, state.id );
  87.     else if( state.type == "change" )
  88.         this.doChange( "undolayer", state.objtype, state.id, state.state_to );
  89. }
  90.  
  91. function UndoLayer.getCurrentPos(){ return this.current_pos; }
  92. function UndoLayer.getStateCount(){ return this.undo_states.size; }
  93. function UndoLayer.setCurrentPos( pos )
  94. {
  95.     if( pos < 0 || pos > this.undo_states.size )
  96.         return WARNING( "undo position out of bounds" );
  97.    
  98.     while( pos > this.current_pos )
  99.         this.redo();
  100.     while( pos < this.current_pos )
  101.         this.undo();
  102. }
  103.  
  104. //  U N D O - building
  105.  
  106. function UndoLayer.beginChange()
  107. {
  108.     if( this.change !== null )
  109.         return WARNING( "already making change" );
  110.     this.change = [];
  111. }
  112.  
  113. function UndoLayer.discardChange()
  114. {
  115.     if( this.change === null )
  116.         return WARNING( "not making change" );
  117.     this.change = null;
  118. }
  119.  
  120. function UndoLayer.revertDiscardChange()
  121. {
  122.     if( this.change === null )
  123.         return WARNING( "not making change" );
  124.    
  125.     this.commitChange( "__tmp__" );
  126.     this.undo();
  127.     this.pop();
  128. }
  129.  
  130. function UndoLayer.commitChange( name )
  131. {
  132.     if( this.change === null )
  133.         return WARNING( "not making change" );
  134.    
  135.     undo_states.push({ name = name, changes = this.change });
  136.     this.change = null;
  137. }
  138.  
  139. function UndoLayer.isMakingChange(){ return this.change !== null; }
  140.  
  141. //  E D I T I N G
  142.  
  143. function UndoLayer.doAdd( src, objtype, props )
  144. {
  145.     OT = @this.object_types[ objtype ];
  146.     if( !OT )
  147.         return WARNING( "object type not registered: " $ objtype );
  148.    
  149.     fnobj = OT.fnobj;
  150.     fn_add = OT.fn_add;
  151.     fn_getstate = OT.fn_getstate;
  152.     id = fnobj!fn_add( props );
  153.     state = fnobj!fn_getstate( id );
  154.    
  155.     this._invokeFeedback( src, "add", objtype, id, state );
  156.     return id;
  157. }
  158.  
  159. function UndoLayer.doRemove( src, objtype, id )
  160. {
  161.     OT = @this.object_types[ objtype ];
  162.     if( !OT )
  163.         return WARNING( "object type not registered: " $ objtype );
  164.    
  165.     fnobj = OT.fnobj;
  166.     fn_rem = OT.fn_rem;
  167.     fn_getstate = OT.fn_getstate;
  168.     state = fnobj!fn_getstate( id );
  169.     fnobj!fn_rem( id );
  170.    
  171.     this._invokeFeedback( src, "remove", objtype, id, state );
  172. }
  173.  
  174. function UndoLayer.doChange( src, objtype, id, changes )
  175. {
  176.     OT = @this.object_types[ objtype ];
  177.     if( !OT )
  178.         return WARNING( "object type not registered: " $ objtype );
  179.    
  180.     fnobj = OT.fnobj;
  181.     fn_setprops = OT.fn_setprops;
  182.     fn_getprops = OT.fn_getprops;
  183.     state = fnobj!fn_getprops( id, changes );
  184.     fnobj!fn_setprops( id, changes );
  185.    
  186.     this._invokeFeedback( src, "change", objtype, id, state, changes );
  187. }
  188.  
  189. //  L O O P B A C K
  190.  
  191. function UndoLayer._registerChange( src, action, objtype, id, state, state_to )
  192. {
  193.     if( src == "undolayer" )
  194.         return;
  195.     if( this.change === null )
  196.         return WARNING( "not making change" );
  197.    
  198.     if( action == "add" )
  199.     {
  200.         this.change.push({ objtype = objtype, type = "add", id = id, state = state });
  201.     }
  202.     else if( action == "remove" )
  203.     {
  204.         this.change.push({ objtype = objtype, type = "remove", id = id, state = state });
  205.     }
  206.     else if( action == "change" )
  207.     {
  208.         this.change.push({ objtype = objtype, type = "change", state_from = state, state_to = state_to });
  209.     }
  210. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement