Command Pattern
Posted: Mon Jul 12, 2010 3:19 pm
Coded and not tested much as an alternative to the
Demento from this thread:
http://www.purebasic.fr/english/viewtop ... 12&t=42867
This software pattern allows one to modularize and
implement a straight forward undo/redo mechanism.
You can read more about it under
http://en.wikipedia.org/wiki/Command_pattern
Actually, even if it obviously screams to be implemented
in OOP, this was made in a hurry and therefore is
straight forward procedural PB
have fun!
Demento from this thread:
http://www.purebasic.fr/english/viewtop ... 12&t=42867
This software pattern allows one to modularize and
implement a straight forward undo/redo mechanism.
You can read more about it under
http://en.wikipedia.org/wiki/Command_pattern
Actually, even if it obviously screams to be implemented
in OOP, this was made in a hurry and therefore is
straight forward procedural PB

have fun!
Code: Select all
Prototype command_do(*info)
Prototype command_undo(*info)
Prototype command_free_info(*info)
Structure COMMAND
do.command_do
undo.command_undo
free.command_free_info
*info
EndStructure
Structure UNDO_MANAGER
List undo_stack.COMMAND()
List redo_stack.COMMAND()
EndStructure
Procedure new_undo_manager()
*um.UNDO_MANAGER = AllocateMemory(SizeOf(UNDO_MANAGER))
InitializeStructure(*um, UNDO_MANAGER)
ProcedureReturn *um
EndProcedure
Procedure delete_undo_manager(*um.UNDO_MANAGER)
ClearStructure(*um, UNDO_MANAGER)
FreeMemory(*um)
EndProcedure
Procedure add_command(*um.UNDO_MANAGER, do.command_do, undo.command_undo, free_info.command_free_info, *info)
ForEach *um\redo_stack()
With *um\redo_stack()
\free(\info)
EndWith
Next
ClearList(*um\redo_stack())
AddElement(*um\undo_stack())
With *um\undo_stack()
\info = *info
\do = do
\undo = undo
\free = free_info
EndWith
EndProcedure
Procedure do(*um.UNDO_MANAGER)
*um\undo_stack()\do(*um\undo_stack()\info)
EndProcedure
Procedure undo(*um.UNDO_MANAGER)
If ListSize(*um\undo_stack()) > 0
*um\undo_stack()\undo(*um\undo_stack()\info)
AddElement(*um\redo_stack())
With *um\redo_stack()
\info = *um\undo_stack()\info
\do = *um\undo_stack()\do
\undo = *um\undo_stack()\undo
\free = *um\undo_stack()\free
EndWith
DeleteElement(*um\undo_stack())
EndIf
EndProcedure
Procedure redo(*um.UNDO_MANAGER)
If ListSize(*um\redo_stack()) > 0
*um\redo_stack()\do(*um\redo_stack()\info)
AddElement(*um\undo_stack())
With *um\undo_stack()
\info = *um\redo_stack()\info
\do = *um\redo_stack()\do
\undo = *um\redo_stack()\undo
\free = *um\redo_stack()\free
EndWith
DeleteElement(*um\redo_stack())
EndIf
EndProcedure
;------------------------------------------ here is one example command:
Structure REPLACE_CHAR
*pos.Character
char.c
old_char.c
EndStructure
Procedure.i replace_char_get_info(*pos.Character, char.c)
*info.REPLACE_CHAR = AllocateMemory(SizeOf (REPLACE_CHAR))
With *info
\pos = *pos
\char = char
\old_char = *pos\c
EndWith
ProcedureReturn *info
EndProcedure
Procedure replace_char_free_info(*info.REPLACE_CHAR)
FreeMemory(*info)
EndProcedure
Procedure replace_char_do(*info.REPLACE_CHAR)
*info\pos\c = *info\char
EndProcedure
Procedure replace_char_undo(*info.REPLACE_CHAR)
*info\pos\c = *info\old_char
EndProcedure
;------------------------------------------ example
string.s = "Hello World!"
um = new_undo_manager()
Debug string
add_command(um, @replace_char_do(), @replace_char_undo(), @replace_char_free_info(), replace_char_get_info(@string+4*SizeOf (Character), 'X'))
do(um)
Debug string
undo(um)
Debug string
redo(um)
Debug string