Custom commands

GrafEdit provides two utility classes to simplify the development of most custom commands.

TChangeCanvasGraphicCmd is a base class that can be used to write commands that change all, or a subset of the canvas graphics in the current selection. Custom commands derived from TChangeCanvasGraphicCmd support undo and redo, and can change graphics incrementally or in a single call.

TCanvasGraphicAssociationsWith<> is a helper class for saving and retrieving undo and redo information in a custom command.

Change canvas graphic command

TChangeCanvasGraphicCmd implements HandleDoBegin, HandleDoIncrement, HandleDoEnd, HandleUndo, and HandleRedo. All these functions except HandleDoEnd iterate over all canvas graphics in the current selection and call BeginChange, ContinueChange, UndoChange, and RedoChange, respectively, which are all implemented in the TChangeCanvasGraphicCmd derived classes.


The default implementations for BeginChange, ContinueChange, UndoChange, and RedoChange do nothing. In your custom derived classes, you implement only the functions that apply. For example, a non-incremental command would not implement ContinueChange.

These functions have the following two parameters shown in the following function declaration for BeginChange:

    virtual void BeginChange( MCanvasRepresentation&, MCanvasGraphic& );
MCanvasRepresentation is the canvas representation and MCanvasGraphic is the graphic being examined in the selection during iteration.

BeginChange and ContinueChange

Typically, your custom command implements BeginChange to save the current state of the graphic and then change the graphic. If the custom command is incremental, ContinueChange is implemented to apply the change to the next increment, but not to save undo information because BeginChange has already done this.

Most custom commands introduce their own functions and data to represent the change and the undo and redo information. For example, TScaleCanvasGraphicCmd is constructed from a TGPoint scale factor and a TGPoint center of scale. There is a SetScaleFactor function to set the scale factor before each increment, and data for the scale factor, center of scale, and undo and redo data. The implementation of BeginChange and ContinueChange scales each graphic passed in by the scale factor around the center of scale.

UndoChange and RedoChange

UndoChange restores the canvas graphic to its state before BeginChange was called. The implementation for UndoChange saves the current changed state of the graphic in case there is a future call to Redo, and uses the data that BeginChange saved to restore the graphic to its original state. Your implementation for UndoChange recalls the part of the canvas graphic that was saved by BeginChange and replaces the changed part with the recalled part.

RedoChange restores the canvas graphic to its state before Undo was called. The implementation of RedoChange uses the data that UndoChange saved to restore the graphic to its changed state. Your implementation for RedoChange recalls the part of the canvas graphic that UndoChange saved and replaces the changed part with the recalled part.

In a TChangeCanvasGraphicCmd, the BeginChange and ContinueChange functions are called for each canvas graphic in the selection. In many cases, only the attribute bundle or the matrix of the graphic are changed at one time. In some cases, both the attribute bundle and the matrix are changed.

Because all canvas graphics have unique identifiers to distinguish them from other canvas graphics, the BeginChange command can copy or orphan the part to be changed and save it in association with the unique ID of the canvas graphic. When UndoChange is called to process a graphic, it gets the graphic ID and finds the saved part.

Associations with template

The implementations for UndoChange and RedoChange use the template TCanvasGraphicAssociationsWith to save only the part of the canvas graphic that changed.

The following code uses the TCanvasGraphicAssociationsWith template to implement a custom command by saving the entire graphic. You can model your own custom commands after this. This is the best approach when the canvas graphics your command changes were developed by someone else and you do not know whether these canvas graphics have hidden relationships between seemingly distinct parts. For example, scaling a canvas graphic might change the line width.

You want the UndoChange and RedoChange commands to restore the canvas graphic to its correct size and line width. However, saving and restoring the matrix only does not restore the correct line width, but saving and restoring the entire graphic does.

      // Copyright (C) 1995 Taligent, Inc. All rights reserved.
      //Construct a TCanvasGraphicAssociationsWith instance for the part to save.
      TCustomCommand::TCustomCommand ()
      {
          fMemory = new TCanvasGraphicAssociationsWith< MCanvasGraphic >;
      }
      
      //The BeginChange function saves the part to be changed, and
      //associates it with the ID of the canvas graphic from which it comes.
      void
      TYourCommand::BeginChange( MCanvasRepresentation&, MCanvasGraphic& graphic )
      {
          fMemory->AdoptAssociation( graphic.GetID(), ::Copy( &graphic ) );
      
          //Code to change the graphic comes next
      
      }
      
      //The UndoChange function restores the part that was changed and 
      //retrieves the original part from the associations instance.
      //This implementation saves the state before undo for redo.
      void
      TCustomCommand::UndoChange( MCanvasRepresentation& rep, MCanvasGraphic& graphic )
      {
          TCanvasGraphicID id = graphic.GetID();
          MCanvasGraphic* undo = fMemory->OrphanAssociation( id );
          MCanvasGraphic* redo = rep.Swap( id, undo );
          fMemory->AdoptAssociation( id, redo );
      }
      
      void
      TCustomCommand::RedoChange( MCanvasRepresentation& rep, MCanvasGraphic& graphic )
      {
          TCanvasGraphicID id = graphic.GetID();
          MCanvasGraphic* redo = fMemory->OrphanAssociation( id );
          MCanvasGraphic* undo = rep.Swap( id, redo );
          fMemory->AdoptAssociation( id, undo );
      }

[Contents] [Previous] [Next]
Click the icon to mail questions or corrections about this material to Taligent personnel.
Copyright©1995 Taligent,Inc. All rights reserved.

Generated with WebMaker