unit TEMainFrm;

{------------------------------------------------------------------------------}
{
  TEMPLATE EDITOR (LABEL ITEM VERSION)
  This demo creates template and saves it in TEMPLATE.RVF.

  This demo shows how to:
  - use TRVLabelItemInfo as field;
  - use TRVSeqItemInfo (only one numbered sequence ("Num") is inserted in
    this demo, but you can paste RTF files with additional sequences).
  - use "smart popups" to edit item properties.

  See mail merging application in the same directory - MAILMERGELI.

  Main settings:
  - since field names are stored in tags (see the help topic about tags)
    as strings, rvoTagsArePChars is included in Options of rve.
  - this demo uses free formatting of template (right click richviews,
    choose "Settings" from the context menu, choose "Allow adding styles
    dynamically").
}
{------------------------------------------------------------------------------}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  StdCtrls, ExtCtrls, Menus,
  Dialogs, RVStyle, RVScroll, RichView, RVEdit,
  RVLabelItem, RVSeqItem, ImgList;

type
  TfrmTemplateEditor = class(TForm)
    rve: TRichViewEdit;
    RVStyle1: TRVStyle;
    MainMenu1: TMainMenu;
    mitFile: TMenuItem;
    mitSave: TMenuItem;
    N1: TMenuItem;
    mitExit: TMenuItem;
    mitInsert: TMenuItem;
    mitView: TMenuItem;
    mitShowNever: TMenuItem;
    mitShowCurrent: TMenuItem;
    mitShowAlways: TMenuItem;
    mitName: TMenuItem;
    mitCode: TMenuItem;
    N2: TMenuItem;
    mitNumber: TMenuItem;
    mitDate: TMenuItem;
    ImageList1: TImageList;
    pmField: TPopupMenu;
    pmSeq: TPopupMenu;
    mitDecimal: TMenuItem;
    mitLowerAlpha: TMenuItem;
    mitUpperAlpha: TMenuItem;
    mitLowerRoman: TMenuItem;
    mitUpperRoman: TMenuItem;
    N3: TMenuItem;
    mitContinue: TMenuItem;
    mitResetTo: TMenuItem;
    mitToName: TMenuItem;
    mitToCode: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure mitShowNeverClick(Sender: TObject);
    procedure mitShowCurrentClick(Sender: TObject);
    procedure mitShowAlwaysClick(Sender: TObject);
    procedure mitNameClick(Sender: TObject);
    procedure mitCodeClick(Sender: TObject);
    procedure mitSaveClick(Sender: TObject);
    procedure mitExitClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure mitDateClick(Sender: TObject);
    procedure mitNumberClick(Sender: TObject);
    procedure rveCaretMove(Sender: TObject);
    procedure mitNumberTypeClick(Sender: TObject);
    procedure pmSeqPopup(Sender: TObject);
    procedure mitResetToClick(Sender: TObject);
    procedure mitContinueClick(Sender: TObject);
    procedure mitToNameClick(Sender: TObject);
    procedure mitToCodeClick(Sender: TObject);
    procedure pmFieldPopup(Sender: TObject);
    procedure rveSmartPopupClick(Sender: TCustomRichView;
      Button: TCustomControl);
  private
    { Private declarations }
    procedure InsertField(const FieldCode, DisplayString: String);
    procedure SetNumberTypeToMenu(NumberType: TRVSeqType);
    procedure ResetCurrentSeqTo(Value: Integer; Reset: Boolean);
    procedure ChangeFieldTo(const FieldCode, DisplayString: String);
  public
    { Public declarations }
    procedure ChangeDate(Date: TDate);
  end;

var
  frmTemplateEditor: TfrmTemplateEditor;

implementation

uses PopupFrm;

{$R *.dfm}

procedure TfrmTemplateEditor.FormCreate(Sender: TObject);
begin
  rve.LoadRVF(ExtractFilePath(Application.ExeName)+'template.rvf');
  rve.Format;
end;
{============================= Menu "File" =====================================}
procedure TfrmTemplateEditor.mitSaveClick(Sender: TObject);
begin
  rve.SaveRVF(ExtractFilePath(Application.ExeName)+'template.rvf', False);
  rve.Modified := False;
end;
{------------------------------------------------------------------------------}
procedure TfrmTemplateEditor.mitExitClick(Sender: TObject);
begin
  Close;
end;
{------------------------------------------------------------------------------}
procedure TfrmTemplateEditor.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if rve.Modified then
    case Application.MessageBox('Template was modified'#13'Save?', 'Closing',
      MB_YESNOCANCEL or MB_ICONQUESTION) of
      ID_YES:
        mitSaveClick(Sender);
      ID_CANCEL:
        CanClose := False;
    end;
end;
{=========================== Menu "Insert" ====================================}
{ Inserting field.
  FieldCode - field code, saved in item's tag. Main application will search
    field by its code.
  DisplayString - will be displayed in place of field by default. Any string.  }
procedure TfrmTemplateEditor.InsertField(const FieldCode, DisplayString: String);
var li: TRVLabelItemInfo;
begin
  li := TRVLabelItemInfo.CreateEx(rve.RVData, rve.CurTextStyleNo, DisplayString);
  li.Tag := Integer(StrNew(PChar(FieldCode)));
  rve.InsertItem('', li);
end;
{------------------------------------------------------------------------------}
procedure TfrmTemplateEditor.mitNameClick(Sender: TObject);
begin
  InsertField('name', '<Name>');
end;
{------------------------------------------------------------------------------}
procedure TfrmTemplateEditor.mitCodeClick(Sender: TObject);
begin
  InsertField('code', '<Code>');
end;
{------------------------------------------------------------------------------}
procedure TfrmTemplateEditor.mitDateClick(Sender: TObject);
var LDate: TDate;
begin
  LDate := Date;
  InsertField('date:'+FloatToStr(LDate), '<'+DateToStr(LDate)+'>');
end;
{------------------------------------------------------------------------------}
procedure TfrmTemplateEditor.mitNumberClick(Sender: TObject);
var si: TRVSeqItemInfo;
begin
  si := TRVSeqItemInfo.CreateEx(rve.RVData, 'Num', rvseqDecimal,
    rve.CurTextStyleNo, 1, False);
  rve.InsertItem('', si);
end;
{========================== Menu "View" =======================================}
procedure TfrmTemplateEditor.mitShowNeverClick(Sender: TObject);
begin
  RVStyle1.FieldHighlightType := rvfhNever;
  rve.RefreshAll;
  mitShowNever.Checked   := True;
  mitShowCurrent.Checked := False;
  mitShowAlways.Checked  := False;
end;
{------------------------------------------------------------------------------}
procedure TfrmTemplateEditor.mitShowCurrentClick(Sender: TObject);
begin
  RVStyle1.FieldHighlightType := rvfhCurrent;
  rve.RefreshAll;
  mitShowNever.Checked   := False;
  mitShowCurrent.Checked := True;
  mitShowAlways.Checked  := False;
end;
{------------------------------------------------------------------------------}
procedure TfrmTemplateEditor.mitShowAlwaysClick(Sender: TObject);
begin
  RVStyle1.FieldHighlightType := rvfhAlways;
  rve.RefreshAll;
  mitShowNever.Checked   := False;
  mitShowCurrent.Checked := False;
  mitShowAlways.Checked  := True;
end;
{======================= Smart Popups =========================================}
procedure TfrmTemplateEditor.rveCaretMove(Sender: TObject);
var tle: TCustomRichViewEdit;
    FieldCode: String;
begin
  tle := rve.TopLevelEditor;
  case tle.GetItemStyle(tle.CurItemNo) of
    rvsLabel:
      begin
        FieldCode := PChar(tle.GetItemTag(tle.CurItemNo));
        if Copy(FieldCode, 1, 5)='date:' then begin
          rve.SmartPopupProperties.Hint := 'Change Date';
          rve.SmartPopupProperties.ImageIndex := 1;
          rve.SmartPopupProperties.Menu := nil;
          rve.OnSmartPopupClick := rveSmartPopupClick;
        end
        else begin
          rve.SmartPopupProperties.Hint := 'Change Field Code';
          rve.SmartPopupProperties.ImageIndex := 0;
          rve.SmartPopupProperties.Menu := pmField;
          rve.OnSmartPopupClick := nil;
        end;
        rve.SmartPopupVisible := True;
      end;
    rvsSequence:
      begin
        rve.SmartPopupProperties.Hint := 'Change Numbering';
        rve.SmartPopupProperties.ImageIndex := 2;
        rve.SmartPopupProperties.Menu := pmSeq;
        rve.SmartPopupVisible := True;
        rve.OnSmartPopupClick := nil;
      end;
    else
      rve.SmartPopupVisible := False;
  end;
end;
{------------------------------------------------------------------------------}
{ Sequences: checking appropriate numbering type in pmSeq }
procedure TfrmTemplateEditor.SetNumberTypeToMenu(NumberType: TRVSeqType);
var i: TRVSeqType;
begin
  for i := Low(TRVSeqType) to High(TRVSeqType) do
    pmSeq.Items[ord(i)].Checked := pmSeq.Items[ord(i)].Tag=ord(NumberType);

end;
{------------------------------------------------------------------------------}
{ Sequences: checking pmSeq items before it is displayed }
procedure TfrmTemplateEditor.pmSeqPopup(Sender: TObject);
begin
  if rve.CurItemStyle<>rvsSequence then begin
    Beep;
    abort;
  end;
  SetNumberTypeToMenu(TRVSeqItemInfo(rve.GetCurrentItem).NumberType);
  mitResetTo.Checked := TRVSeqItemInfo(rve.GetCurrentItem).Reset;
  mitContinue.Checked := not mitResetTo.Checked;
end;
{------------------------------------------------------------------------------}
{ Sequences: changing StartFrom and Reset properties of the current sequence
  item as an editing operation }
procedure TfrmTemplateEditor.ResetCurrentSeqTo(Value: Integer; Reset: Boolean);
var oldsi,si: TRVSeqItemInfo;
    tle: TCustomRichViewEdit;
begin
  if rve.CurItemStyle<>rvsSequence then begin
    Beep;
    exit;
  end;
  // creating a new item with the desired properties and inserting it
  // instead the old item
  oldsi := TRVSeqItemInfo(rve.GetCurrentItem);
  si := TRVSeqItemInfo.Create(rve.RVData);
  si.Assign(oldsi);
  if Reset then
    si.StartFrom := Value;
  si.Reset := Reset;
  tle := rve.TopLevelEditor;
  tle.SetSelectionBounds(tle.CurItemNo, 0, tle.CurItemNo, 1);
  rve.InsertItem('', si);
end;
{------------------------------------------------------------------------------}
{ Sequences: changing NumberType property of the current sequence
  item as an editing operation }
procedure TfrmTemplateEditor.mitNumberTypeClick(Sender: TObject);
var oldsi,si: TRVSeqItemInfo;
    tle: TCustomRichViewEdit;
begin
  if rve.CurItemStyle<>rvsSequence then begin
    Beep;
    exit;
  end;
  // creating a new item with the desired properties and inserting it
  // instead the old item
  oldsi := TRVSeqItemInfo(rve.GetCurrentItem);
  si := TRVSeqItemInfo.Create(rve.RVData);
  si.Assign(oldsi);
  si.NumberType := TRVSeqType(TMenuItem(Sender).Tag);
  tle := rve.TopLevelEditor;
  tle.SetSelectionBounds(tle.CurItemNo, 0, tle.CurItemNo, 1);
  rve.InsertItem('', si);
end;
{------------------------------------------------------------------------------}
{ Sequences: Reset to... }
procedure TfrmTemplateEditor.mitResetToClick(Sender: TObject);
var s,s2: String;
begin
  if rve.CurItemStyle<>rvsSequence then begin
    Beep;
    exit;
  end;
  s := IntToStr(TRVSeqItemInfo(rve.GetCurrentItem).StartFrom);
  s2 := s;
  if InputQuery('Reset','Reset &to:', s2) then begin
    if s=s2 then
      exit;
    ResetCurrentSeqTo(StrToIntDef(s2, 1), True);
  end;
end;
{------------------------------------------------------------------------------}
{ Sequences: Continue numbering }
procedure TfrmTemplateEditor.mitContinueClick(Sender: TObject);
begin
  ResetCurrentSeqTo(1{<-ignored}, False);
end;
{------------------------------------------------------------------------------}
{ Fields: changing field code and text as an editing operation}
procedure TfrmTemplateEditor.ChangeFieldTo(const FieldCode, DisplayString: String);
var oldli, li: TRVLabelItemInfo;
    tle: TCustomRichViewEdit;
begin
  if rve.CurItemStyle<>rvsLabel then begin
    Beep;
    exit;
  end;
  // creating a new item with the desired properties and inserting it
  // instead the old item
  oldli := TRVLabelItemInfo(rve.GetCurrentItem);
  li := TRVLabelItemInfo.Create(rve.RVData);
  li.Assign(oldli);
  li.Text := DisplayString;
  // assign does not copy tag,
  // so it's not necessary to call StrDispose(PChar(li.Tag))
  li.Tag := Integer(StrNew(PChar(FieldCode)));
  tle := rve.TopLevelEditor;
  tle.SetSelectionBounds(tle.CurItemNo, 0, tle.CurItemNo, 1);
  rve.InsertItem('', li);
end;
{------------------------------------------------------------------------------}
{ Fields: changing the current field to "name" }
procedure TfrmTemplateEditor.mitToNameClick(Sender: TObject);
begin
  ChangeFieldTo('name', '<Name>');
end;
{------------------------------------------------------------------------------}
{ Fields: changing the current field to "code" }
procedure TfrmTemplateEditor.mitToCodeClick(Sender: TObject);
begin
  ChangeFieldTo('code', '<Code>');
end;
{------------------------------------------------------------------------------}
{ Fields: checking items in pmFields before it is displayed }
procedure TfrmTemplateEditor.pmFieldPopup(Sender: TObject);
begin
  if rve.CurItemStyle<>rvsLabel then begin
    Beep;
    abort;
  end;
  mitToName.Checked := PChar(rve.GetCurrentTag)='name';
  mitToCode.Checked := PChar(rve.GetCurrentTag)='code';
end;
{------------------------------------------------------------------------------}
{ Date field: displaying calendar popup }
procedure TfrmTemplateEditor.rveSmartPopupClick(Sender: TCustomRichView;
  Button: TCustomControl);
var CalendarForm: TfrmPopup;
    pt: TPoint;
    FieldCode: String;
    li: TRVLabelItemInfo;
begin
  if rve.CurItemStyle<>rvsLabel then begin
    Beep;
    exit;
  end;
  li := TRVLabelItemInfo(rve.GetCurrentItem);
  FieldCode := PChar(li.Tag);
  if Copy(FieldCode, 1, 5)<>'date:' then begin
    Beep;
    exit;
  end;
  CalendarForm := TfrmPopup.Create(Application);
  CalendarForm.cal.Date := StrToInt(Copy(FieldCode, 6, Length(FieldCode)));
  pt.X := 0;
  pt.Y := Button.Height;
  pt := Button.ClientToScreen(pt);
  if pt.X+CalendarForm.Width>Screen.Width then
    pt.X := Screen.Width-CalendarForm.Width;
  if pt.Y+CalendarForm.Height>Screen.Height then
    pt.Y := Screen.Height-CalendarForm.Height;
  CalendarForm.Left := pt.X;
  CalendarForm.Top := pt.Y;
  CalendarForm.Show;
  rve.SmartPopupProperties.SetButtonState(True);
end;
{------------------------------------------------------------------------------}
{ Date field: this method is called by the calendar form }
procedure TfrmTemplateEditor.ChangeDate(Date: TDate);
begin
  ChangeFieldTo('date:'+FloatToStr(Date), '<'+DateToStr(Date)+'>');
end;

end.
