RichMemo

From Lazarus wiki
Jump to navigationJump to search

Template:Translate

About

TRichMemo is a component to replace Delphi TRichEdit component. It's designed in cross-platform way, so implementation is possible for the following platforms: Win32, MacOSX, Linux. Since, being a cross-platform is the primary, most of windows RichEdit features are replaced, making RichMemo not compatible with Delphi's VCL or RX RichEdits.

Its main caracteristics are :

  • Text highlight
  • System based Unicode edit support

Planned: (patches are welcomed)

  • Adding images into text
  • Embedding LCL Controls?

The download contains the component, an installation package and a demo application, that illustrates the features of the component along with some instrumentation for evaluating the chart on a given system.

Screenshot

RichMemo macosx screenshot. Thanks to Dominique Louis

Bug reporting

Please add your Bugreports/Feature requests in Lazarus CCR project of the Lazarus bug tracker.

Author

Dmitry 'skalogryz' Boyarintsev

License

modified LGPL (same as the FPC RTL and the Lazarus LCL). You can contact the author if the modified LGPL doesn't work with your project licensing.

Download

The latest trunk is available here: https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/components/richmemo


note: Currently it's recommended to use the svn version. [1]

Change Log

  • Version 1.0.0 22th Jun 2009
  • Version 0.8.0 Jun 2009

Dependencies / System Requirements

  • Lazarus 1.0.0

Status: Released.

Issues:

Supported Widgetset

  • Win32
  • Gtk2
  • Carbon - support is limited due to inflexible Carbon APIs and deprecation of Carbon by Apple
  • Cocoa
  • Qt - support is very limited due to incomplete Qt4Pas support of QTextEdit related classes. QTextCharFormatH / QTextBlockFormatH are needed. The only thing that's currently working is the paragraph alignment.

Installation

  • Download the package
  • Open the package, and install it, rebuilding the IDE
  • TRichMemo is added to 'Common Controls' component page.

RichMemoPalette.PNG

TRichMemo

methods

SetTextAttributes

procedure SetTextAttributes(TextStart, TextLen: Integer; AFont: TFont);
  • TextStart : Integer - the first character to be modified
  • TextLen : Integer - number of characters to be modified
  • AFont : TFont - a font that should be applied to the part of the text


procedure SetTextAttributes(TextStart, TextLen: Integer; const TextParams: TFontParams);
  • TextStart : Integer - the first character to be modified
  • TextLen : Integer - number of characters to be modified
  • TextParams : TFontParams - font parameters to be set


SetTextureAttributes methods are changing specified text range style. Font parameters is passed in both methods, by AFont parameter (LCL TFont object) or by TFontParams (declared at RichMemo).

Setting text attributes does not change current selection. If it's necessary to modify the style of currently selected text, you should SelStart and SelLength as a text range values:

RichMemo1.SetTextAttributes(RichMemo1.SelStart, RichMemo1.SelLength, FontDialog1.Font);

GetTextAttributes

function GetTextAttributes(TextStart: Integer; var TextParams: TFontParams): Boolean; virtual;
  • TextStart : Integer - the character position to be queried for font parameters
  • var TextParams : TFontParams - output value, filled with charachter's font attributes. If the method fails and returns false, record's field values is undefined.

Fill font params of the character, at TextStart position. Method returns True if textstart is valid character position, and False overwise.

GetStyleRange

function GetStyleRange(CharPos: Integer; var RangeStart, RangeLen: Integer): Boolean; virtual;

Returns a range of characters that share the same font parameters, i.e. all characters in the range has the same font name, size, color and styles.

  • CharPos : Integer - a character that belongs to the style range. It's not necessary for this position to be at the begining on the style range. It can be in the middle on in the end of the style range. The first character position is returned by RangeStart parameter.
  • var RangeStart : Integer - the first character in the range
  • var RangeLen : Integer - number of characthers in the range

The method returns true if successed. the method returns false, if CharPos is incorrect value - more than available characters or some other error.

SetRangeColor

procedure SetRangeColor(TextStart, TextLength: Integer; FontColor: TColor);

The method sets color of characters in the specified range to the FontColor. Other font parameters (name, size, styles) are left unchanged.

  • TextStart: Integer - the first character in the range
  • TextLength: Integer - number of characters in the range
  • FontColor: TColor - color that should be set

SetRangeParams

procedure SetRangeParams(TextStart, TextLength: Integer;
    ModifyMask: TTextModifyMask; const FontName: String; 
    FontSize: Integer; FontColor: TColor; 
    AddFontStyle, RemoveFontStyle: TFontStyles);

The method changes font parameters in the specified range.

GetParaAlignment

Gets paragraph alignment

function GetParaAlignment(TextStart: Integer; var AAlign: TParaAlignment): Boolean;
  • TextStart - the position of the character that's belongs to the paragraph
  • AAlign - gets alignment of a paragraph.

Note:

  • Win32 - full-width Justification doesn't work on Windows XP and earlier.
  • OSX - due to Carbon limitation, this is not working in Carbon, but works for Cocoa widgetset.

SetParaAlignment

Sets paragraph alignent

procedure SetParaAlignment(TextStart, TextLen: Integer; AAlign: TParaAlignment);

Note:

  • Win32 - full-width Justification doesn't work on Windows XP and earlier.
  • OSX - due to Carbon limitation, this is not working in Carbon, but works for Cocoa widgetset. It's also need to loaded that the correct alignment would be loaded from RTF file

GetParaMetric

Returns paragraph metrics for a given paragraph

richmemo parametric.PNG
  • FirstLine - an offset for the first line (in points), of the paragraph from the beginning of control
  • TailIndent - an offset for each line (in points), except for the first line, of the paragraph from the end of the control
  • HeadIndent - an offset for each line (in points) of the paragraph from the end of the control
  • SpaceBefore - additional space before paragraph (in points)
  • SpaceAfter - additional space after paragraph (in points)
  • LineSpacing - a factor used to calculate line spacing between lines in the paragraph. The factor is applied to Font size (tallest in the line), not the line height. Thus it's matching CSS's line-height property. Note that normal line-spacing is 1.2. I.e. font of 12 pt size, an actual lines spacing set to 1.2, would result in 14pt line height.
    • not supported in WinXP or earlier
    • most of the system would not allow if linespacing is set to less than 1.2. The value would be ignored and they'd default to 1.2

Note

  • RichEdit paragraph settings are specified in pixels, not points, so you'll need to either convert these sizes yourself or use RichMemoHelper methods
  • the notation of "Left"/"Right" offsets is avoided to prevent confusion for RTL.
function GetParaMetric(TextStart: Integer; var AMetric: TParaMetric): Boolean;

GetParaRange

Returns character range for a paragraph. The paragraph is identified by a character.

  function GetParaRange(CharOfs: Integer; var ParaRange: TParaRange): Boolean; virtual;
  function GetParaRange(CharOfs: Integer; var TextStart, TextLength: Integer): Boolean;

CharOfs - is a character that belongs to a paragraph which range is returned. TParaRange - is a structure that returns 3 fields

  • start - the first character in the paragraph
  • lengthNoBr - the length of the paragraph, excluding the line break character
  • length - the length of the paragrpah, including the line break, if present the last line in the control doesn't contain a line break character, thus length = lengthNoBr

function

GetParaRange(CharOfs: Integer; var TextStart, TextLength: Integer) 

returns "start" and "length" field of TParaRange

SetParaMetric

Sets paragraph metrics

procedure SetParaMetric(TextStart, TextLen: Integer; const AMetric: TParaMetric);

It's recommended to use InitParaMetric function in order to initialize TParaMetric structure. Otherwise zeroing structure out is by it size (i.e. FillChar(m, sizeof(TParaMetric), 0) is sufficient. If TParaMetric values are received from GetParaMetric call, then the structure is considered to be initialized properly.

SetRangeParaParams

Sets paragraph metrics selectively

 procedure SetRangeParaParams(TextStart, TextLength: Integer; ModifyMask: TParaModifyMask; const ParaMetric: TParaMetric);
  • TextStart - the character of the the first paragraph to apply the style too
  • TextLength - the number of characters that paragraph properties should be modified
  • ModifyMask - masks the identifies what para metric should be set for each paragraph within TextStart..TextLength block. Other characters will be left unmodified. Members of the set are
    • pmm_FirstLine - changes the first line indentation. FirstLine field of ParaMetric must be initialized
    • pmm_HeadIndent - changes the heading paragraph indentation. HeadIndent field of ParaMetric must be initialized
    • pmm_TailIndent - changes the trail paragraph indentation. TailIndent field of ParaMetric must be initialized
    • pmm_SpaceBefore - changes the space preceding . SpaceBefore field of ParaMetric must be initialized
    • pmm_SpaceAfter - changes the space after (below) the paragraph. SpaceAfter field of ParaMetric must be initialized
    • pmm_LineSpacing - line spacing within paragraph. LineSpace field of ParaMetric must be initialized
  • ParaMetric - the structure containing the values to be set. Only fields specified by ModifyMask should be initialized

LoadRichText

function LoadRichText(Source: TStream): Boolean; virtual;
  • Source: TStream - a stream to read richtext data from

The method loads RTF enocded data from the specified stream. Returns true if success, and false otherwise. If source is nil, the method returns false

The content of TRichMemo is completely replaced by the content on the source stream. Current text selection is reset.

SaveRichText

function SaveRichText(Dest: TStream): Boolean; virtual;
  • Source: TStream - a stream to read richtext data from

The method saves RTF enocded data to the specified stream. Returns true if success, and false otherwise. If source is nil, the method returns false

Current state of TRichMemo is unchanged after the method returns

properties

ZoomFactor

property ZoomFactor: double

Read/Write property. Controls zooming of the RichMemo content. 1.0 - is no-zoom. Less than < 1.0 - decrease zoom, more than 1.0 - increasing zooming. If 0 is set - value defaults to 1.0 zoom factor (no zoom).

HideSelection

property HideSelection: Boolean default false

Read/Write property. If True RichMemo selection is hidden if the control is not focused. If False, the selection is shown all the time.

Rtf

property Rtf: String
RtfEditor.PNG

Read/Write property that allows to read or write Rich-Text Formatted (RTF) text to the whole control. The intent of the property is to have an ability to set Rich-Text in design time, however the property would work in run-time as well.

If then property value is an empty string then Lines property is used as a plain text to initialize control value in load-time.

Note: The property is available in TRichMemo class only, it's not available (or even implemented in anyway) in TCustomRichMemo class. It is recommended to use LoadRichText/SaveRichText in order to modify the content of the page, just because they could consume less memory, than copying the whole rich-text into the memory.

Cross-platform and Forward Compatibility Note: - currently the property is implemented based on the widgetset providede Rich-text read/write routines. It is very likely that in near future it would be changed to used RichMemo read/write RTF stream code only. The issue is with older systems might not support the latest version of RTF.

So right now, you might run into an issue, If you create a project in Gtk2 and save the richmemo is design time containing Unicode characters. Then if you try to load it on the XP machine and would use widgetset native loader, you might see characters missing or rendered improperly. Changing to the usage of RichMemo RTF loader/saver will prevent this issue from happening. Currently you can also avoid it by registering RichMemo loaders (call RegisterRTFLoader, RegisterRTFSaver procedures in project initialization, before any RichMemo is loaded)

events

OnSelectionChange

property OnSelectionChange: TNotifyEvent
TNotifyEvent = procedure (Sender: TObject) of object;

The event is fired whenever, selection is changed within RichMemo, either programmatically or due to the user action.

TRichEditForMemo

The class helper that implements RichEdit programmatic interface. The helper is declared at RichEditHelpers unit, so you have to add it to the uses section. Helpers are available in FPC 2.6.0 or later.

methods

FindText

Searches a given range in the text for a target string

properties

SelAttributes

Reads/Modifies character attributes of the current selection.

Paragraph

Reads/Modifies paragraph attributes of the current selection.

RichMemoUtilities

The unit is introduced to add some useful OS-specific features for handling working with RichMemo

InsertImageFromFile

function InsertImageFromFile (const ARichMemo: TCustomRichMemo; APos: Integer;
    const FileNameUTF8: string;
    const AImgSize: TSize
): Boolean = nil;

Disclaimer: the function would insert an image file into RichMemo (if implemented by the widgetset) But in a very inefficient way. The image would be read again and the memory would be re-allocated for the image every time. So please, don't use it for smileys in your chat instant messaging. A better API (with data caching) is considered. (That's why this method is not part of TCustomRichMemo class).

  • APos - position in the text
  • AImgSize - size to be inserted in POINTS, not pixels!. If both cx and cy are 0, the image would not be resized at all. If only one cx, cy is zero results are undefined

Installation

  • Download the package Get the latest version from SVN
  • Open the package, and install it, rebuilding the IDE
  • TRichMemo is added to 'Common Controls' component page.

Frequently Asked Questions

Using RichMemo in Shared Libraries

Issue #17412 If you need to use the component in a shared library, you might need to add -fPIC key to the compiler option of "the package" and the "project".

(Delphi) RichEdit like interface

Issue #14632 A typical problem is porting an existing code that's using RichEdit from Delphi. RichMemo interface doesn't match RichEdit in many ways. But there're two ways to handle that:

  • you can either create a sub-class from TCustomRichMemo (or RichMemo) and implement Delphi RichEdit methods;
  • you can use RichMemoHelpers unit (fpc 2.6.0 or later required) and use methods provided by class Helpers that should; Currently SelAttributes and Paragraph properties are implemented.
uses ... RichMemo, RichMemoHelpers;

TForm = class
  RichMemo1 : TRichMemo;

  
// SelAttributes property is not available in the base class
// but added by a helper defined at RichMemoHelpers unit
RichMemo1.SelAttributes.Name := 'Courier New';

Append mixed color text at the end of the RichMemo

If you just need the basic coloring like this:

 word 1, word 2
 word 1, word 2
 word 1, word 2

then here is an example that will add a new line with just two words of different colors:

  procedure TForm1.Button1Click(Sender: TObject);
  begin
    // position cursor at the end of the text
    RichMemo1.SelStart := Length(RichMemo1.Text);
    RichMemo1.SelLength := 0;
  
    // insert new line with 1st word
    RichMemo1.SelText  := #13 + 'word 1, ';   //word 1 is red
    RichMemo1.SelLength := length(RichMemo1.SelText);
    RichMemo1.SetRangeColor(RichMemo1.selstart, RichMemo1.sellength, clBlue);
  
    // position cursor at the end of the text
    RichMemo1.SelStart  := Length(RichMemo1.Text);
    RichMemo1.SelLength := 0;
  
    // insert 2nd word
    RichMemo1.SelText   := 'word 2';   //word 1 is red
    RichMemo1.SelLength := length(RichMemo1.SelText);
    RichMemo1.SetRangeColor(RichMemo1.selstart, RichMemo1.sellength, clGreen);
  
    // position cursor at the end of the text
    RichMemo1.SelStart := Length(RichMemo1.Text);
    RichMemo1.SelLength := 0;
  end;

See Also

MyNotex application which uses modified by Massimo Nardello RichMemo package on Linux-Gtk2