Advanced Undo

Introduction

This topic describes advanced mechanisms for storing undo history. This is meant mostly for developers of custom user interfaces and libraries.

When Advanced Undo is Needed

In FlexSim, for the most part, undo/redo just works. You don't need to worry much about what is being recorded to the undo history, because it's all automatic. However, there are some instances where you might need to customize the undo history recording to suit your needs. Some examples of when you might want to customize undo history recording are:

  • When you have created a customized object, and that object changes certain variable values as the object is dragged around in the model, i.e. in its OnPreDraw or OnDrag functionality. You may want those values to go back to their original state before the object was dragged.
  • If you have custom functionality in a user library's drop script that you do NOT want recorded in the undo history. By default, whenever the user does a drag/drop operation from the library icon grid, FlexSim will automatically start an "aggregated undo" operation, which essentially retools several low-level commands to record changes that are made. We'll talk about this in more detail later, but for some dropscripts, you may need to temporarily "turn off" undo recording, then execute your functionality, then turn it back on. For example if you are performing functionality that opens a window.
  • If you create a tool window that is used to modify the model, like the Edit Selected Objects tool windows, then you'll need to add code to the buttons of those windows that explicitly does undo recording. In FlexSim, all things that are done in a 3D view, a tree view, or a table view, as well as all operations done in tool windows that focus around those views, are undo-able, so if you design a tool window that is used with one of these views, you'll need to make it undo-capable.

Creating an Undo Record Explicitly

To create an undo record before executing a piece of code, call beginaggregatedundo(). Pass in the view that this undo is associated with. If you pass in NULL as the view, then it will be associated with FlexSim's global undo history (MAIN:/project/undo/). Pass in a description of the operation being done ("ChangeColor"). The beginaggregatedundo() command will return back a unique id for the undo record that you've created. Then execute the code that you want to be undo-able, then call endaggregatedundo(), passing in the view and the undo id.

When you call beginaggregatedundo(), FlexSim will retool several low-level commands, so that subsequent calls that you make to those commands, or calls to those commands by other commands that you call, will record changes to the undo history. The commands that are retooled are as follows:

  • nodeadddata()
  • setnodenum()/set()
  • setnodestr()/sets()
  • nodedeldata()
  • nodeinsertinto()
  • nodeinsertafter()
  • nodejoin()
  • nodepoint()
  • nodebreak()
  • setname()
  • clearcontents()
  • createcopy()
  • createinstance()
  • switch_cppfunc(),switch_flexscript()... (all switch_... commands)
  • transfernode()
  • transfernodeobj()
  • moveobject()
  • setrank()
  • destroyobject()
  • destroynode()

Ignoring Undo

If you are inside of an aggregated undo and you want FlexSim to ignore a set of commands, call beginignoreundo(), execute the commands, then call endignoreundo(). This is especially useful in dropscripts of a user library. FlexSim automatically creates an aggregated undo record that applies to all functionality executed as part a drag/drop operation from the library icon grid, so all code that executes in a drop script is being recorded as part of an undo record. To bypass this for certain functionality, surround it with beginignoreundo() and endignoreundo()

Undo Tracking on a Custom Object's Drag

You may also want FlexSim to track changes to a custom object's variable value, or the location, rotation and scale of an object that the custom object changes as it is dragged. One example of this being used is in the Crane object in FlexSim's standard library. When you drag on one of the Crane's sizers, there are actually several objects behind the scenes that the Crane resizes as you drag. Also, the Crane has three variable values defining the x, y, and z location of the Crane's frame that change as you drag the Crane to a different position in the model. In order for undo functionality to work on the Crane, it must tell FlexSim to track undo information on those objects that it is changing as the user drags.

To add undo tracking to an object or number variable, call applicationcommand("addundotracking", view, obj_or_variable). The Crane performs this as part of its OnClick event, when the user clicks on the Crane.

Example

The following are snippets of example code using custom undo.

Simple Undo


		int undoId = beginaggregatedundo(c, "Set Object Rank");
		setrank(anObj, 5);
		endaggregatedundo(c, undoId);
		

Undo with an Ignore


		int undoId = beginaggregatedundo(c, "Change Object Shape");
		setnodestr(shape(anObj), shapePath);
		int index = getshapeindex(gets(shape(anObj)));
		beginignoreundo();
		if (getshapeindex(shapePath)==0) {
			autoloadallmedia(anObj);
			index = getshapeindex(gets(shape(anObj)));
		}
		endignoreundo();
		set(shapeindex(anObj), index);
		applyshapefactors(anObj);
		endaggregatedundo(c, undoId);