[How to] How to make plain text editor

Demos, code samples. Only questions related to the existing topics are allowed here.
Post Reply
Sergey Tkachenko
Site Admin
Posts: 17566
Joined: Sat Aug 27, 2005 10:28 am
Contact:

[How to] How to make plain text editor

Post by Sergey Tkachenko »

:?: How to make a plain text editor based on TRichViewEdit
  • Exclude all but text from AcceptDragDropFormats property
  • Process OnPaste event (see below)
  • Disable all UI commands changing text and paragraph attributes

Code: Select all

procedure TForm1.rvePaste(Sender: TCustomRichViewEdit;
  var DoDefault: Boolean);
var s: String;
begin
  s := Clipboard.AsText;
  rve.InsertText(s, False);
  DoDefault := False;
end;
Update: In the new version, instead of using OnPaste, you can exclude all but text from AcceptPasteFormats property.
Last edited by Sergey Tkachenko on Thu Jun 06, 2013 3:21 pm, edited 3 times in total.
Sergey Tkachenko
Site Admin
Posts: 17566
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

:?: How to make ONE LINE plain text editor
  • Exclude all but text (rvddText for Delphi 3-2007, rvddUnicodeText for Delphi 2009+) from AcceptDragDropFormats property
  • Process OnPaste event (see below)
  • Process OnOleDrop event (see below)
  • Disable all UI commands changing text and paragraph attributes or inserting multiline text
  • Set WordWrap property = False (for RichView v1.9.27+), or include rvpaoNoWrap in property of paragraph style
  • Include rvoDoNotWantReturns in EditorOptions
  • Set VSmallStep property = 1, before calling Format
  • If you do not want tabulators as well, set RVStyle.SpacesInTab = 4

Code: Select all

uses Clipbrd, ActiveX, RVTypes;

{$I RV_Defs.inc}

// Returning one line string made from s.
// This function replaces all linebreaks with ' | '.
// You can change this function, for example to return the first line
function MakeOneLineString(const s: String): String;
var p: Integer;
begin
  Result := AdjustLineBreaks(s);
  while True do begin
    p := Pos(#13#10, Result);
    if p=0 then
      break;
    Delete(Result, p, 2);
    Insert(' | ', Result, p);
 end;
end;

procedure TForm3.RichViewEdit1OleDrop(Sender: TCustomRichView;
  const DataObject: IDataObject; Shift: TShiftState; X, Y: Integer;
  PossibleDropEffects: TRVOleDropEffects; var DropEffect: TRVOleDropEffect;
  var DoDefault: Boolean);
var FmtEtc: TFormatEtc;
  StgMedium: TStgMedium;
  ptr: Pointer;
  s: String;
  p: Integer;
begin
  DoDefault := False;

  FillChar(StgMedium, sizeof(StgMedium), 0);
  FillChar(FmtEtc, sizeof(FmtEtc), 0);
  {$IFDEF RVUNICODESTR} // <-- Defined in RV_Defs.inc
  FmtEtc.cfFormat := CF_UNICODETEXT;
  {$ELSE}
  FmtEtc.cfFormat := CF_TEXT;
  {$ENDIF}
  FmtEtc.dwAspect := DVASPECT_CONTENT;
  FmtEtc.lindex := -1;
  FmtEtc.tymed := TYMED_HGLOBAL;
  if DataObject.GetData(FmtEtc, StgMedium)<>S_OK then
    exit;
  if StgMedium.tymed=TYMED_HGLOBAL then begin
    ptr := GlobalLock(StgMedium.HGlobal);
    try
      SetLength(s, GlobalSize(StgMedium.HGlobal) div sizeof(Char));
      Move(ptr^, PChar(s)^, Length(s)*sizeof(Char));
    finally
      GlobalUnlock(StgMedium.HGlobal);
    end;
    p := Pos(#0, s);
    if p>0 then
      s := Copy(s, 1, p-1);
    RichViewEdit1.InsertText(MakeOneLineString(s), False);
  end;
  ReleaseStgMedium(StgMedium);
end;

procedure TForm3.RichViewEdit1Paste(Sender: TCustomRichViewEdit;
  var DoDefault: Boolean);
var s: String;
begin
  s := Clipboard.AsText;
  RichViewEdit1.InsertText(MakeOneLineString(s), False);
  DoDefault := False;
end;
2008-Dec-11: updated for compatibility with TRichView 11 and Delphi 2009.
Last edited by Sergey Tkachenko on Thu Jul 22, 2010 7:27 pm, edited 2 times in total.
Sergey Tkachenko
Site Admin
Posts: 17566
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

How to make ONE LINE UNICODE plain text editor

In the example above, text is processed as ANSI in Delphi 4-2007 and as Unicode for Delphi 2009+. If you do not have Delphi 2009 but want to make a one line Unicode editor, the code for OnOleDrop and OnPaste events is below:

Code: Select all

// Returning one line string made from s.
// This function replaces all linebreaks with ' | '.
// You can change this function, for example to return the first line
function MakeOneLineString(const s: TRVUnicodeString): TRVUnicodeString;

  procedure ReplaceLB(const LB: TRVUnicodeString; var Res: TRVUnicodeString);
  var p: Integer;
  begin
    while True do begin
      p := Pos(LB, Res);
      if p=0 then
        break;
      Delete(Res, p, 2);
      Insert(' | ', Res, p);
    end;
  end;
begin
  Result := s;
  ReplaceLB(#13#10, Result);
  ReplaceLB(#10#13, Result);
  ReplaceLB(#10, Result);
  ReplaceLB(#13, Result);
end;

function GetUnicodeStringFromHandle(mem: Cardinal): TRVUnicodeString;
var ptr: Pointer;
  p: Integer;
begin
  ptr := GlobalLock(mem);
  try
    SetLength(Result, GlobalSize(mem) div 2);
    Move(ptr^, PRVUnicodeChar(Result)^, Length(Result)*2);
  finally
    GlobalUnlock(mem);
  end;
  p := Pos(TRVUnicodeString(#0), Result);
  if p>0 then
    Result := Copy(Result, 1, p-1);
end;

procedure TForm1.RichViewEdit1OleDrop(Sender: TCustomRichView; const DataObject: IDataObject;
  Shift: TShiftState; X, Y: Integer; PossibleDropEffects: TRVOleDropEffects;
  var DropEffect: TRVOleDropEffect; var DoDefault: Boolean);
var FmtEtc: TFormatEtc;
  StgMedium: TStgMedium;
  s: TRVUnicodeString;
begin
  DoDefault := False;
  FillChar(StgMedium, sizeof(StgMedium), 0);
  FillChar(FmtEtc, sizeof(FmtEtc), 0);
  FmtEtc.cfFormat := CF_UNICODETEXT;
  FmtEtc.dwAspect := DVASPECT_CONTENT;
  FmtEtc.lindex := -1;
  FmtEtc.tymed := TYMED_HGLOBAL;
  if DataObject.GetData(FmtEtc, StgMedium)<>S_OK then
    exit;
  if StgMedium.tymed=TYMED_HGLOBAL then begin
    s := GetUnicodeStringFromHandle(StgMedium.HGlobal);
    RichViewEdit1.InsertTextW(MakeOneLineString(s), False);
  end;
  ReleaseStgMedium(StgMedium);
end;

function GetUnicodeStringFromClipboard: TRVUnicodeString;
var mem: Cardinal;
begin
  if not Clipboard.HasFormat(CF_UNICODETEXT) then begin
    Result := '';
    exit;
  end;
  Clipboard.Open;
  try
    mem := Clipboard.GetAsHandle(CF_UNICODETEXT);
    Result := GetUnicodeStringFromHandle(mem);
  finally
    Clipboard.Close;
  end;
end;

procedure TForm1.RichViewEdit1Paste(Sender: TCustomRichViewEdit; var DoDefault: Boolean);
begin
  Sender.InsertTextW(MakeOneLineString(GetUnicodeStringFromClipboard));
  DoDefault := False;
end;
This code requires Unicode version of Pos function. As far as I remember, it was introduced in Delphi 2005. So for older versions of Delphi you need to replace Pos with a Unicode function.

(see http://www.trichview.com/forums/viewtopic.php?t=70 for making Unicode editors)
Sergey Tkachenko
Site Admin
Posts: 17566
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Additional info:
1) In RichViewActions, you can assign RVAControlPanel1.UserInterface = rvauiText to disable all formatting actions.
2) See also: How to disable insertion of images
Post Reply