unit Unit1;

interface

{------------------------------------------------------------------------------
 Implementing "fields"
 The main property settings:
 - rvoTagsArePChars in RichViewEdit1.Options (so each item can have associated string)
 - RVStyle1.TextStyles collection has two styles (for static text and for fields)
   Especially look at Protection properties
 - RichViewEdit1 is set to "use predefined set of styles" (right click on
   RichViewEdit1 at design time, then choose "Settings")
 - AcceptDragDropFormats = []

------------------------------------------------------------------------------ }

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, RVStyle, RVScroll, RichView, RVEdit, Clipbrd, StdCtrls,
  CRVData, RVTable;

type
  TForm1 = class(TForm)
    RichViewEdit1: TRichViewEdit;
    rvs: TRVStyle;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure RichViewEdit1Paste(Sender: TCustomRichViewEdit;
      var DoDefault: Boolean);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function GetFieldLocation(RootRVData: TCustomRVData; const field: String;
  var RVData: TCustomRVData; var ItemNo: Integer): Boolean;
var i,r,c: Integer;
    table: TRVTableItemInfo;
begin
  Result := False;
  for i := 0 to RootRVData.ItemCount-1 do
    if RootRVData.GetItemStyle(i)=rvsTable then begin
      table := TRVTableItemInfo(RootRVData.GetItem(i));
      for r := 0 to table.Rows.Count-1 do
        for c := 0 to table.Rows[r].Count-1 do
          if table.Cells[r,c]<>nil then begin
            Result := GetFieldLocation(table.Cells[r,c].GetRVData,
              field, RVData, ItemNo);
            if Result then
              exit;
          end
      end
    else if PChar(RootRVData.GetItemTag(i)) = field then begin
      ItemNo := i;
      RVData := RootRVData.GetSourceRVData;
      Result := True;
      exit;
    end;
end;

function GetFieldValue(rv: TCustomRichView; const field: String): String;
var RVData: TCustomRVData;
    ItemNo: Integer;
begin
  if GetFieldLocation(rv.RVData, field, RVData, ItemNo) then
    Result := RVData.GetItemText(ItemNo)
  else
    Result := '';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  RichViewEdit1.Clear;
  RichViewEdit1.AddNL('2 + 2 =', 1,0);
  RichViewEdit1.AddNLTag('  ', 0,-1, Integer(StrNew('answer1')));
  RichViewEdit1.Add('?', 1);
  RichViewEdit1.AddNL('3 + 3 =', 1,0);
  RichViewEdit1.AddNLTag('  ', 0,-1, Integer(StrNew('answer2')));
  RichViewEdit1.Add('?', 1);
  RichViewEdit1.Format;
  RichViewEdit1.SetSelectionBounds(1,2,1,2);
end;

procedure TForm1.RichViewEdit1Paste(Sender: TCustomRichViewEdit;
  var DoDefault: Boolean);
var s: String;
begin
  // allowing to paste only one line text
  s := Clipboard.AsText;
  if (Pos(#10,s)=0) and (Pos(#13,s)=0) then
    RichViewEdit1.InsertText(s,False);
  DoDefault := False;
end;

procedure TForm1.Button1Click(Sender: TObject);
var s: String;
begin
  s := GetFieldValue(RichViewEdit1, 'answer1');
  if StrToIntDef(Trim(s), 0)<>4 then begin
    Application.MessageBox('Wrong! Try again','Test', 0);
    exit;
  end;
  s := GetFieldValue(RichViewEdit1, 'answer2');
  if StrToIntDef(Trim(s), 0)<>6 then begin
    Application.MessageBox('Wrong! Try again','Test', 0);
    exit;
  end;
  Application.MessageBox('Test is passed','Test', 0);
end;

end.
