How to use Redo after TRVUndoList.AddInfo?

General TRichView support forum. Please post your questions here
Post Reply
Vitalii
Posts: 61
Joined: Sat Oct 20, 2018 2:55 pm

How to use Redo after TRVUndoList.AddInfo?

Post by Vitalii »

Hi, I have read other forum threads regarding "Custom Undo" operations, but I did not find an answer.
Based on this topic, I implemented a custom Undo class, and it works fine:

Code: Select all

  
class procedure TRVUndoModifyMathObject.AddUndo(RVData: TRichViewRVData;
  ItemInfo: TRVMathObjectItemInfo);
var
  Edit: TCustomRichViewEdit;
  UndoList: TRVUndoList;
  UndoItem: TRVUndoModifyMathObject;
begin
  if RVData = nil then Exit;
  Edit := TCustomRichViewEdit(RVData.GetAbsoluteRootData.GetParentControl);
  UndoList := TRVEditRVData(RVData).GetUndoList;
  if Assigned(UndoList) then
    begin
      UndoItem := TRVUndoModifyMathObject.Create;
      UndoItem.Action := rvuMisc;
      UndoItem.FInputExpression := ItemInfo.Expression;
      UndoItem.FOutputExpression := ItemInfo.OutputExpression;
      UndoItem.FOutputFormat := ItemInfo.OutputFormat;
      UndoItem.FTitle := ItemInfo.TextAlias;
      UndoItem.FItemNo := RVData.GetItemNo(ItemInfo);
      UndoList.AddInfo(UndoItem, Edit);
    end;
end;
The main code that applies the changes:

Code: Select all

  ...
  if AEdit.CanChange then
    begin
      AEdit.BeginUndoCustomGroup('Modify Math Object');
      TRVUndoModifyMathObject.AddUndo(AEdit.RVData, ItemInfo);
      ItemInfo.Expression := MemoInput.Lines.Text;
      ItemInfo.OutputExpression := EditOutput.Text;
      ItemInfo.OutputFormat := ComboBoxOutputFormat.Text;
      ItemInfo.TextAlias := EditTitle.Text;
      AEdit.Change;
      AEdit.RefreshAll;
    end;
  ...
Unfortunately, Redo does not respond... What should I change/add to make the Redo stack work properly?
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: How to use Redo after TRVUndoList.AddInfo?

Post by Sergey Tkachenko »

Is this main code inside TRVUndoModifyMathObject.Undo?
Can I see the full TRVUndoModifyMathObject implementation?

PS. If you need to modify integer and string properties of an item, there is an alternative solution. You do not need to implement custom undo object. Instead, you can implement extra item properties. Then you can use methods for setting these properties, and it can be undone/redone.
See https://www.trichview.com/forums/viewtopic.php?p=42899
Vitalii
Posts: 61
Joined: Sat Oct 20, 2018 2:55 pm

Re: How to use Redo after TRVUndoList.AddInfo?

Post by Vitalii »

Yes, implementation of the TRVUndoModifyMathObject.Undo is here:

Code: Select all

procedure TRVUndoModifyMathObject.Undo(RVData: TRichViewRVData);
var
  ItemInfo: TRVMathObjectItemInfo;
begin
  if FItemNo > -1 then
    begin
      ItemInfo := TRVMathObjectItemInfo(RVData.GetItem(FItemNo));
      if Assigned(ItemInfo) then
        begin
          ItemInfo.Expression := FInputExpression;
          ItemInfo.OutputExpression := FOutputExpression;
          ItemInfo.OutputFormat := FOutputFormat;
          ItemInfo.TextAlias := FTitle;
        end;
    end;
end;
As I said, this Undo method works correctly. Other methods are trivial:

Code: Select all

constructor TRVUndoModifyMathObject.Create;
begin
  inherited;
  FInputExpression := '';
  FOutputExpression := '';
  FOutputFormat := '';
  FTitle := '';
  FItemNo := -1;
end;

function TRVUndoModifyMathObject.RequiresFormat: Boolean;
begin
  Result := False;
end;
The "main code" is called through an external editor window (UI). This code is not part of the class TRVUndoModifyMathObject. My logic here is: before making changes, we create an Undo-object, make changes, and change/refresh editor. But I don't know if this Undo-object still works in Redo operations?
Sergey Tkachenko
Site Admin
Posts: 17557
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Re: How to use Redo after TRVUndoList.AddInfo?

Post by Sergey Tkachenko »

UndoItem.Undo must
1) save the current object state in a new undo item (when undoing, this new undo item will be inserted in the redo list; otherwise, in the undo list)
2) make changes in the object.

Let's see how a very simple undo item is implemented: TRVUndoChangeVAlignInfo, it changes VAlign property of an item.

Code: Select all

procedure TRVUndoChangeVAlignInfo.Undo(RVData: TRichViewRVData);
begin
  TRVEditRVData(RVData).Do_ChangeVAlign(ItemNo, VAlign);
end;
where

Code: Select all

procedure TRVEditRVData.Do_ChangeVAlign(ItemNo: Integer; VAlign: TRVVAlign);
var
  List: TRVUndoList;
  ui:   TRVUndoChangeVAlignInfo;
  item: TCustomRVItemInfo;
begin
  item := GetItem(ItemNo);
  if (item as TRVRectItemInfo).VAlign = VAlign then
    exit;
  // storing the old state in the new undo item 
  List := GetUndoList;
  if List <> nil then
  begin
    ui := TRVUndoChangeVAlignInfo.Create;
    ui.Action := rvuChangeText;
    ui.ItemNo := ItemNo;
    ui.VAlign := TRVRectItemInfo(item).VAlign;
    List.AddInfo(ui, TCustomRichViewEdit(OwnerRichView));
  end;
  // making changes
  TRVRectItemInfo(item).VAlign := VAlign;
end;
Vitalii
Posts: 61
Joined: Sat Oct 20, 2018 2:55 pm

Re: How to use Redo after TRVUndoList.AddInfo?

Post by Vitalii »

Yep, I need to add "AddUndo" to the Undo method. Thank you, Sergey)
Post Reply