Sign in Join
Wiki copytemporary

RichMemo: what changed

Revision 2 to 3. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11![](/wiki-images/5/54/Richmemosample.png)
22
33## Introduction
44
55**RichMemo** is a package that includes a component to replace the Delphi TRichEdit component. It's designed in cross-platform way, so implementation is possible for the following platforms: Win32, MacOSX and Linux. Since, being cross-platform is the primary target, the native RichMemo API can be extended to make it Delphi's RichEdit compatible.
66
77Its main characteristics are
88
99- Text highlight
1010- System based Unicode edit support
1111
1212Planned: (patches are welcomed)
1313
1414- Adding images into text
1515- Embedding LCL Controls?
1616
1717The 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.
1818
1919Please add your bugreports, feature requests, pull request on [GitHub](https://github.com/skalogryz/richmemo/issues).
2020
2121## Licensing
2222
2323Author: Dmitry 'skalogryz' Boyarintsev
2424
2525License: [modified](http://svn.freepascal.org/svn/lazarus/trunk/COPYING.modifiedLGPL) [LGPL](http://svn.freepascal.org/svn/lazarus/trunk/COPYING.LGPL) (the 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.
2626
2727## Download
2828
2929The easiest way to install the stable version of the component is via the [[Online Package Manager]] included in current Lazarus versions.
3030
3131The latest trunk is available on GitHub: <https://github.com/skalogryz/richmemo/> . The latest sources can be downloaded by [this GitHub link](https://github.com/skalogryz/richmemo/archive/refs/heads/master.zip).
3232
3333## Installation
3434
3535- Download the package set.
3636- Open **richmemo_design.lpk** package, and install it, rebuilding the IDE.
3737- TRichMemo is added to the 'Common Controls' component page.
3838
3939![](/wiki-images/8/80/RichMemoPalette.PNG)
4040
4141Originally **richmemopackage** was a single file, containing IDE specific and run-time needed classes. However, that meant that IDEIntf package would be a requirement for any project using RichMemo. In order to mitigate that the package was split into to separate packages:
4242
4343- richmemopackage - run-time rich memo component.
4444- richmemo_design - IDE extensions to support for RichMemo component.
4545
4646## Font Parameters
4747
4848Font parameters are generally represented by TFontParams record. The type is used to describe **rich** attributes of the font. Some attributes goes beyond the scope of TFont class, thus an extra type was necessary. However, most of the TFont related data types are reused (i.e. TFontStyles).
4949
5050- Name - name of the font (family).
5151- Size - size of the font in points (passing a negative value might produce unexpected results).
5252- Color - color of the font.
5353- Style - font styles, including Bold, italic, strike-through, underline.
5454- HasBkClr - boolean flag, if the text for the should have background color (if true, BkColor field is used, otherwise BkColor is ignored). Transparency is not supported.
5555- BkColor - background (aka highlight) color for the text.
5656- VScriptPos - vertical adjustment for the text ![](/wiki-images/c/c1/Richmemo_Subsuper.png).
5757 - vpNormal - no special position.
5858 - vpSubscript - the text is subscript.
5959 - vpSuperscript - the text is superscript.
6060
6161
6262The actual vertical offset of super/sub scripts depends on OS implementation and currently cannot be controlled.
6363
6464You can assign FontParams from TFont structure. For that you'll need to use `GetFontParams(afont: TFont)` function. Note, most of LCL controls have TFont set to "default" values. These are not actual values, but rather an indication that control's default font should be used (similar to crDefault for TColor).
6565
6666GetFontParams function resolves "Default" font name and returns the actual font family name.
6767
6868## Methods
6969
7070### SetTextAttributes
7171
7272```delphi
7373procedure SetTextAttributes(TextStart, TextLen: Integer; AFont: TFont);
7474```
7575
7676- TextStart : Integer - the first character to be modified
7777- TextLen : Integer - number of characters to be modified
7878- AFont : TFont - a font that should be applied to the part of the text
7979
8080```delphi
8181procedure SetTextAttributes(TextStart, TextLen: Integer; const TextParams: TFontParams);
8282```
8383
8484- TextStart : Integer - the first character to be modified
8585- TextLen : Integer - number of characters to be modified
8686- TextParams : TFontParams - font parameters to be set
8787
8888SetTextureAttributes 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).
8989
9090Setting 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:
9191
9292```delphi
9393RichMemo1.SetTextAttributes(RichMemo1.SelStart, RichMemo1.SelLength, FontDialog1.Font);
9494```
9595
9696### GetTextAttributes
9797
9898```delphi
9999function GetTextAttributes(TextStart: Integer; var TextParams: TFontParams): Boolean; virtual;
100100```
101101
102102- TextStart : Integer - the character position to be queried for font parameters
103103- var TextParams : TFontParams - output value, filled with charachter's font attributes. If the method fails and returns false, record's field values is undefined.
104104
105105Fill font params of the character, at TextStart position. Method returns True if textstart is valid character position, and False overwise.
106106
107107### GetStyleRange
108108
109109```delphi
110110function GetStyleRange(CharPos: Integer; var RangeStart, RangeLen: Integer): Boolean; virtual;
111111```
112112
113113Returns 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.
114114
115115- 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.
116116- var RangeStart : Integer - the first character in the range
117117- var RangeLen : Integer - number of characthers in the range
118118
119119The method returns true if successed. the method returns false, if CharPos is incorrect value - more than available characters or some other error.
120120
121121### CharAtPos
122122
123123```delphi
124124function CharAtPos(x,y: Integer): Integer; virtual;
125125```
126126
127127Returns zero-based character offset (not UTF8 position). Returns -1 if fails.
128128
129129- x, y - is a point in the client area of the RichMemo control.
130130
131131The method is aware of scrolling state of the control. Thus two calls to CharAtPos(0,0) might return different values if scroll positions is changed between calls. See "examples/hittest" for the sample of usage.
132132
133133If specified x,y would be out of the content of RichMemo the return value is undefined. It is left up to widgetset to either return -1 or closes character available.
134134
135135### SetRangeColor
136136
137137```delphi
138138procedure SetRangeColor(TextStart, TextLength: Integer; FontColor: TColor);
139139```
140140
141141The method sets color of characters in the specified range to the FontColor. Other font parameters (name, size, styles) are left unchanged.
142142
143143- TextStart: Integer - the first character in the range
144144- TextLength: Integer - number of characters in the range
145145- FontColor: TColor - color that should be set
146146
147147### SetRangeParams
148148
149149```delphi
150150 procedure SetRangeParams(TextStart, TextLength: Integer; ModifyMask: TTextModifyMask;
151151 const fnt: TFontParams; AddFontStyle, RemoveFontStyle: TFontStyles); overload;
152152```
153153
154154The method changes font parameters in the specified range.
155155
156156- TextStart - the first character in the range
157157- TextLength - number of characters in the range
158158- ModifyMask - shows what exact font attributes must be updated The mask accepts any combination of the following values:
159159 - tmm_Color - font color would be modified (fnt.Color field must be populated)
160160 - tmm_Name - font name would be modified (fnt.Name field must be populated)
161161 - tmm_Size - font size would be modified (fnt.Size field must be populated)
162162 - tmm_Styles - font styles would be modified as specified by AddFontStyle, RemoveFontStyle parameters
163163 - tmm_BackColor - text highlight (background) color would be modified. (fnt.HasBkClr and fnt.BkColor fields must be populated )
164164 - Sending an empty mask will cause the method to return without making any changes.
165165- fnt - font parameters that are going to be used, depending on the ModifyMask values.
166166- AddFontStyle - set of styles that should be applied to the range (used only if tmm_Styles in ModifyMask, otherwise ignored)
167167- RemoveFontStyle - set of font style should should be removed from the range (used only if tmm_Styles in ModifyMask, otherwise ignored)
168168
169169```delphi
170170procedure SetRangeParams(TextStart, TextLength: Integer;
171171 ModifyMask: TTextModifyMask; const FontName: String;
172172 FontSize: Integer; FontColor: TColor;
173173 AddFontStyle, RemoveFontStyle: TFontStyles);
174174```
175175
176176The overloaded version of the method. It's just a wrapper around the parameter using TFontParams structure. The method doesn't support changing of background color, you should use the TFontParams version
177177
178178- FontName - font name that should set (used only if tmm_Name in ModifyMask, otherwise ignored)
179179- FontColor - font color that should set (used only if tmm_Color in ModifyMask, otherwise ignored)
180180
181181For example, if the following code is used
182182
183183```delphi
184184 RichMemo1.SetRangeParams (
185185 RichMemo1.SelStart, RichMemo1.SelLength,
186186 [tmm_Styles, tmm_Color], // changing Color and Styles only
187187 '', // this is font name - it's not used, thus we can leave it empty
188188 0, // this is font size - it's font size, we can leave it empty
189189 clGreen, // making all the text in the selected region green color
190190 [fsBold, fsItalic], // adding Bold and Italic Styles
191191 []
192192 );
193193```
194194
195195### GetParaAlignment
196196
197197Gets paragraph alignment
198198
199199```delphi
200200function GetParaAlignment(TextStart: Integer; var AAlign: TParaAlignment): Boolean;
201201```
202202
203203- TextStart - the position of the character that's belongs to the paragraph
204204- AAlign - gets alignment of a paragraph.
205205
206206**Note**:
207207
208208- Win32 - full-width Justification doesn't work on Windows XP and earlier.
209209- OSX - due to Carbon limitation, this is not working in Carbon, but works for Cocoa widgetset.
210210
211211### SetParaAlignment
212212
213213Sets paragraph alignent
214214
215215```delphi
216216procedure SetParaAlignment(TextStart, TextLen: Integer; AAlign: TParaAlignment);
217217```
218218
219219**Note**:
220220
221221- Win32 - full-width Justification doesn't work on Windows XP and earlier.
222222- 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
223223
224224### GetParaMetric
225225
226226Returns paragraph metrics for a given paragraph ![](/wiki-images/b/be/Richmemo_parametric.PNG)
227227
228228- FirstLine - an offset for the first line (in points), of the paragraph from the beginning of control
229229- TailIndent - an offset for each line (in points), except for the first line, of the paragraph from the end of the control
230230- HeadIndent - an offset for each line (in points) of the paragraph from the end of the control
231231- SpaceBefore - additional space before paragraph (in points)
232232- SpaceAfter - additional space after paragraph (in points)
233233- 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.
234234 - not supported in WinXP or earlier
235235 - 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
236236
237237**Note**
238238
239239- RichEdit paragraph settings are specified in pixels, not points, so you'll need to either convert these sizes yourself or use RichMemoHelper methods
240240- the notation of "Left"/"Right" offsets is avoided to prevent confusion for RTL.
241241
242242```delphi
243243function GetParaMetric(TextStart: Integer; var AMetric: TParaMetric): Boolean;
244244```
245245
246246procedure SetParaMetric(TextStart, TextLen: Integer; const AMetric: TParaMetric);
247247
248248It'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.
249249
250250### GetParaRange
251251
252252Returns character range for a paragraph. The paragraph is identified by a character.
253253
254254```delphi
255255 function GetParaRange(CharOfs: Integer; var ParaRange: TParaRange): Boolean;
256256 function GetParaRange(CharOfs: Integer; var TextStart, TextLength: Integer): Boolean;
257257```
258258
259259CharOfs - is a character that belongs to a paragraph which range is returned. TParaRange - is a structure that returns 3 fields
260260
261261- start - the first character in the paragraph
262262- lengthNoBr - the length of the paragraph, excluding the line break character
263263- 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 value.
264264
265265### SetParaTabs
266266
267267Sets the set of tab stops to paragraphs in the specified length.
268268
269269```delphi
270270 procedure SetParaTabs(TextStart, TextLen: Integer; const AStopList: TTabStopList);
271271```
272272
273273- TextStart
274274- TextLen
275275- AStopList - the structure that contains an array of tab stops.
276276 - Count - specifies the number of initialized elements.
277277 - Tabs - array contains the description of each tab stop, consisting of an Offset and Alignment.
278278 - Offset - the tab point offset in points (from the left side of the control)
279279 - Align - the alignment of the tab stop (tabLeft - default one, tabCenter, tabRight, tabDecimal).
280280
281281**Notes**
282282
283283Renamefest
284284Prior to r4140 TTabAlignment enum values were taLeft, taCenter, taRight, taDecimal,but it did collide with Classes.TAlignment declarations. Thus the suffix was changed.
285285
286286win32
287287allows no more that 32 tabs
288288
289289gtk2
290290only tabLeft align is supported
291291
292292carbon
293293not implemented
294294
295295### GetParaTabs
296296
297297Gets the tab stops array. If no specific tabs were specified (widget default tab stops) AStopList count would be set to 0.
298298
299299```delphi
300300 function GetParaTabs(CharOfs: Integer; var AStopList: TTabStopList): Boolean;
301301```
302302
303303### SetParaNumbering
304304
305305Sets paragraphs automatic numbering and styles, such as bullets
306306
307307```delphi
308308procedure SetParaNumbering(TextStart, TextLen: Integer; const ANumber: TParaNumbering); virtual;
309309```
310310
311311- **TextStart** - the character of the the first paragraph to apply the style too
312312- **TextLength** - the number of characters that paragraph properties should be modified
313313- **TParaNumbering** - the structure describing the paragraph numbering information
314314
315315:* **style** - the style of numbering
316316
317317
318318
319319Note: for cross-platform compatibility, it's recommended to use either **pnNone**, **pnBullet**, **pnNumber** or **pnCustomChar**. RTF provides more support for numbering, yet not every platform rich-text widgetset supports them
320320
321321for initializing the structure you can use InitParaNumbering() or InitParaNumber() functions. Also using Default() would work too
322322
323323### SetRangeParaParams
324324
325325Sets paragraph metrics selectively
326326
327327```delphi
328328procedure SetRangeParaParams(TextStart, TextLength: Integer; ModifyMask: TParaModifyMask; const ParaMetric: TParaMetric);
329329```
330330
331331- TextStart - the character of the the first paragraph to apply the style too
332332- TextLength - the number of characters that paragraph properties should be modified
333333- 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
334334 - pmm_FirstLine - changes the first line indentation. FirstLine field of ParaMetric must be initialized
335335 - pmm_HeadIndent - changes the heading paragraph indentation. HeadIndent field of ParaMetric must be initialized
336336 - pmm_TailIndent - changes the trail paragraph indentation. TailIndent field of ParaMetric must be initialized
337337 - pmm_SpaceBefore - changes the space preceding . SpaceBefore field of ParaMetric must be initialized
338338 - pmm_SpaceAfter - changes the space after (below) the paragraph. SpaceAfter field of ParaMetric must be initialized
339339 - pmm_LineSpacing - line spacing within paragraph. LineSpace field of ParaMetric must be initialized
340340- ParaMetric - the structure containing the values to be set. Only fields specified by ModifyMask should be initialized
341341
342342### LoadRichText
343343
344344```delphi
345345function LoadRichText(Source: TStream): Boolean; virtual;
346346```
347347
348348- Source: TStream - a stream to read richtext data from
349349
350350The method loads RTF enocded data from the specified stream. Returns true if success, and false otherwise. If source is nil, the method returns false
351351
352352The content of TRichMemo is completely replaced by the content on the source stream. Current text selection is reset.
353353
354354### SaveRichText
355355
356356```delphi
357357function SaveRichText(Dest: TStream): Boolean; virtual;
358358```
359359
360360- Source: TStream - a stream to read richtext data from
361361
362362The method saves RTF enocded data to the specified stream. Returns true if success, and false otherwise. If source is nil, the method returns false
363363
364364Current state of TRichMemo is unchanged after the method returns
365365
366366### Search
367367
368368```delphi
369369function Search(const ANiddle: string; Start, Len: Integer; const SearchOpt: TSearchOptions): Integer;
370370```
371371
372372- ANiddle: string - a text to search for
373373- Start: Integer - a character position to start search from, if -1 or 0 search from the start
374374- Len: Integer - length (in characters, not bytes) of the text to search for the niddle.
375375- SearchOpt: TSearchOptions
376376 - soMatchCase - case sensitive search
377377 - soBackward - searching from the end of the document to the character identified by "Start" parameter
378378 - soWholeWord - searching for the whole word
379379
380380The method returns the character position of the found sub-string. The position is suitable for use in SelStart property. However, might not be usable for the direct Copy operation, if Unicode characters are present in the code. Instead UTF8Copy should be used.
381381
382382If the ANiddle was not found in the text, -1 is returned
383383
384384```delphi
385385function Search(const ANiddle: string; Start, Len: Integer; const SearchOpt: TSearchOptions;
386386 var TextStart, TextLength: Integer): Boolean;
387387```
388388
389389(The method is introduced with r5115)
390390
391391- ANiddle: string - a text to search for
392392- Start: Integer - a character position to start search from, if -1 or 0 search from the start
393393- Len: Integer - length (in characters, not bytes) of the text to search for the niddle.
394394- SearchOpt: TSearchOptions
395395 - soMatchCase - case sensitive search
396396 - soBackward - searching from the end of the document to the character identified by "Start" parameter
397397 - soWholeWord - searching for the whole word
398398- (output) ATextStart - a position of the text found (in characters)
399399- (output) ATextLength - length of the text found (in characters (cursor positions!))
400400
401401The method returns the true if searched sub-string is found, false otherwise.
402402
403403The returned ATextStart and ATextLength values are suitable for use in SelStart and SelLength properties.
404404
405405**Note**: for complex scripts, the found text might be exactly the same as the sub-string searched. The search behavior (on complex scripts) is widgetset specific. Thus searching for the same string on different widgetsets (i.e. win32 or gtk2) might produce different results. If you need the same results and don't get them, please create a bug report.
406406
407407If you need to extract the found text, you should use GetText() method (passing ATextStart and ATextLength values).
408408
409409### GetText, GetUText
410410
411411```delphi
412412 function GetText(TextStart, TextLength: Integer): String;
413413 function GetUText(TextStart, TextLength: Integer): UnicodeString;
414414```
415415
416416- TextStart: Integer - a character position to start extract from. (0 - is the first character in the text).
417417- TextLength: Integer - length (in characters, not bytes) of the text to extract
418418
419419GetText() returns UTF8 sub-string
420420
421421GetUText() returns UTF16 sub-string
422422
423423Current selection would not be affected by the operation. (If you see the selection affected, please report as an issue).
424424
425425You should not consider the efficiency of either method. For example, WinAPI internally operates with UTF16 characters, thus GetUText() **might** be more efficient for it. While Gtk2 operates UTF8 and calling GetText() **might** be more efficient for it. Instead of thinking about underlying system, you should be considering the needs of your task.
426426
427427### Redo
428428
429429```delphi
430430 procedure Redo;
431431```
432432
433433The method redos the last change [undone](http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tcustomedit.undo.html) previously.
434434
435435You can always call CanRedo to check, if there're any actions can be redone.
436436
437437## Properties
438438
439439### ZoomFactor
440440
441441```delphi
442442property ZoomFactor: double
443443```
444444
445445Read/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).
446446
447447### HideSelection
448448
449449```delphi
450450property HideSelection: Boolean default false
451451```
452452
453453Read/Write property. If True RichMemo selection is hidden if the control is not focused. If False, the selection is shown all the time.
454454
455455### CanRedo
456456
457457```delphi
458458property CanRedo: Boolean
459459```
460460
461461If True, there're actions in Undo queue that can be redone. If False, there are no actions in Undo queue that can be redone. Calling to Redo won't have any effect.
462462
463463### Transparent
464464
465-<img src="richmemo_transparent.png" title="richmemo_transparent.png" width="400" />
465+![](/wiki-images/4/40/Richmemo_transparent.png)
466466
467467```delphi
468468property Transparent: Boolean
469469```
470470
471471If True, the background of richmemo is not filled with any color, leaving any underlying controls or windows to be visible. (Suggested to be used with TImage that would provide the background) If False, (default) the background is filled with a solid color
472472
473473Note that the property might not affect "border" style of the the richmemo. You need to set BorderStyle to bsNone in order to disable it. For macOS this also hides the focus ring (when the control is focused)
474474
475475- Supported by Win32, Qt5 and Cocoa
476476
477477### Rtf
478478
479479```delphi
480480property Rtf: String
481481```
482482
483-<img src="RtfEditor.PNG" title="RtfEditor.PNG" width="400" />
483+![](/wiki-images/b/b8/RtfEditor.PNG)
484484
485485Read/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.
486486
487487If then property value is an empty string then Lines property is used as a plain text to initialize control value in load-time.
488488
489489**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.
490490
491491**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.
492492
493493So 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)
494494
495495## Events
496496
497497### OnSelectionChange
498498
499499```delphi
500500property OnSelectionChange: TNotifyEvent
501501TNotifyEvent = procedure (Sender: TObject) of object;
502502```
503503
504504The event is fired whenever, selection is changed within RichMemo, either programmatically or due to the user action.
505505
506506## TRichEditForMemo
507507
508508The 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.
509509
510510### Methods
511511
512512#### FindText
513513
514514Searches a given range in the text for a target string
515515
516516### Properties
517517
518518#### SelAttributes
519519
520520Reads/Modifies character attributes of the current selection.
521521
522522### Paragraph
523523
524524Reads/Modifies paragraph attributes of the current selection.
525525
526526### RichMemoUtils
527527
528528The unit is introduced to add some useful OS-specific features for handling working with RichMemo
529529
530530#### InsertImageFromFile
531531
532532```delphi
533533function InsertImageFromFile (const ARichMemo: TCustomRichMemo; APos: Integer;
534534 const FileNameUTF8: string;
535535 const AImgSize: TSize
536536 ): Boolean = nil;
537537```
538538
539539*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).*
540540
541541- APos - position in the text
542542- 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.
543543
544544There's also an utility function **InsertImageFromFileNoResize** that calls InsertImageFromFile, passing size as 0.
545545
546546An example of use
547547
548548```delphi
549549 procedure TForm1.Button1Click(Sender: TObject);
550550 begin
551551 // running a dialog to select a picture to insert
552552 if OpenDialog1.Execute then
553553 // inserting the picture at the current RichMemo cursor position
554554 InsertImageFromFileNoResize(RichMemo1, RichMemo1.SelStart, OpenDialog1.FileName);
555555 end;
556556```
557557
558558### InsertStyledText,InsertColorStyledText,InsertFontText
559559
560560The set of functions that simplify appending and replacing of styled text. The specified style of the text is applied on the insertion. The common rule for all functions, if InsPos (insertion position) is negative - the text is appended to the end. In order to insert the text in the beginning of the test InsPos should set to 0.
561561
562562The inserted text is not forced to be on a new line or add a new line. You might want to add LineFeed character to TestUTF8 parameter, if you want the inserted text to cause a new line to be started.
563563
564564```delphi
565565procedure InsertStyledText(
566566 const ARichMemo: TCustomRichMemo;
567567 const TextUTF8: String;
568568 AStyle: TFontStyles;
569569 InsPos : Integer = -1 )
570570```
571571
572572InsertStyledText inserts the styled text at the specified position.
573573
574574```delphi
575575procedure InsertColorStyledText(
576576 const ARichMemo: TCustomRichMemo;
577577 const TextUTF8: String;
578578 AColor: TColor;
579579 AStyle: TFontStyles;
580580 InsPos : Integer = -1 )
581581```
582582
583583InsertColorStyledText inserts the text with specified style and color at the specified position. to the end of the RichMemo
584584
585585```delphi
586586procedure InsertFontText(
587587 const ARichMemo: TCustomRichMemo;
588588 const TextUTF8: String;
589589 const prms: TFontParams;
590590 InsPos : Integer = -1 )
591591```
592592
593593InsertFontText inserts the text and applies specified FontParams to it.
594594
595595You might want to create a class helper to implement these functions as methods for RichMemo. Beware, if you're using Delphi-compatibility helper - you might right into a conflict.
596596
597597## Frequently Asked Questions
598598
599599### Using RichMemo in Shared Libraries
600600
601601[Issue \#17412](http://bugs.freepascal.org/view.php?id=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".
602602
603603## (Delphi) RichEdit like interface
604604
605605[Issue \#14632](http://bugs.freepascal.org/view.php?id=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:
606606
607607- you can either create a sub-class from TCustomRichMemo (or RichMemo) and implement Delphi RichEdit methods;
608608- 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.
609609
610610`uses ... RichMemo, RichMemoHelpers;`\
611611
612612`TForm = class`\
613613`  RichMemo1 : TRichMemo;`\
614614`   `\
615615`  // SelAttributes property is not available in the base class`\
616616`  // but added by a helper defined at RichMemoHelpers unit`\
617617`RichMemo1.SelAttributes.Name := 'Courier New';`
618618
619619## Append mixed color text at the end of the RichMemo
620620
621621If you just need simple coloring then here is an example that will each time add a new line with random color (tested on Windows):
622622
623623```delphi
624624 procedure TForm1.Button1Click(Sender: TObject);
625625 var
626626 i, j: integer;
627627 str: string;
628628 begin
629629 with Richmemo1 do
630630 begin
631631 str := 'Newline text';
632632 i := Length(Lines.Text) - Lines.Count; // cr as #10#13 is counted only once so subtract it once
633633 j := Length(str) + 1; // +1 to make the cr the same format
634634 Lines.Add(str);
635635 SetRangeColor(i, j, Round(random * $FFFFFF));
636636 end;
637637 end;
638638```
639639
640640` ``Newline text`\
641641` ``NewLine text`\
642642` ``NewLine text`
643643
644644Alternative example for simple coloring (tested on Windows):
645645
646646```delphi
647647 procedure TForm1.Button2Click(Sender: TObject);
648648 begin
649649 with RichMemo1 do
650650 begin
651651 Lines.Add('Line in red');
652652 SetRangeColor(Length(Lines.Text) - Length(Lines[Lines.Count - 1]) - Lines.Count - 1, Length(Lines[Lines.Count - 1]), clRed);
653653
654654 Lines.Add('Line in blue');
655655 SetRangeColor(Length(Lines.Text) - Length(Lines[Lines.Count - 1]) - Lines.Count - 1, Length(Lines[Lines.Count - 1]), clBlue);
656656
657657 Lines.Add('Normal line.');
658658 Lines.Add('Normal line.');
659659
660660 Lines.Add('Line in green ');
661661 SetRangeColor(Length(Lines.Text) - Length(Lines[Lines.Count - 1]) - Lines.Count - 1, Length(Lines[Lines.Count - 1]), clGreen);
662662 end;
663663 end;
664664```
665665
666666` ``Line in red`\
667667` ``Line in blue`\
668668` ``Normal line.`\
669669` ``Normal line.`\
670670` ``Line in green`
671671
672672If you need mixed coloring then this is an example that will add a new line with several different colored words (tested on Windows):
673673
674674```delphi
675675procedure TForm1.Button3Click(Sender: TObject);
676676 procedure AddColorStr(s: string; const col: TColor = clBlack; const NewLine: boolean = true);
677677 begin
678678 with RichMemo1 do
679679 begin
680680 if NewLine then
681681 begin
682682 Lines.Add('');
683683 Lines.Delete(Lines.Count - 1); // avoid double line spacing
684684 end;
685685
686686 SelStart := Length(Text);
687687 SelText := s;
688688 SelLength := Length(s);
689689 SetRangeColor(SelStart, SelLength, col);
690690
691691 // deselect inserted string and position cursor at the end of the text
692692 SelStart := Length(Text);
693693 SelText := '';
694694 end;
695695 end;
696696 begin
697697 AddColorStr('Black, ');
698698 AddColorStr('Green, ', clGReen, false);
699699 AddColorStr('Blue, ', clBlue, false);
700700 AddColorStr('Red', clRed, false);
701701 end;
702702```
703703
704704` ``Black, ``Green, ``Blue, ``Red`\
705705` ``Black, ``Green, ``Blue, ``Red`\
706706` ``Black, ``Green, ``Blue, ``Red`
707707
708708## Markup Language Parsing
709709
710710![mlparse example](/wiki-images/8/8c/Mlparse.png) The native rich-edit controls do not support a markup-language parsing.
711711
712712You'll need to write it yourself as shown in mlparse example
713713
714714## Internals
715715
716716### Platform Support Matrix
717717
718718Values in the matrix are not expected to be static (except for "carbon" column), each system is planned to support all features declared by RichMemo.
719719
720720Note that the table contains more features than published above. That means that the APIs are already available in RichMemo, but since they're unstable (on some platforms) it's considered "experimental" rather than promised.
721721
722722| Feature | Win32 | Gtk2 | Qt | Cocoa | Carbon |
723723|--------------------------------|-------|------------|-----|-------|-------------------|
724724| Font color and style selection | Yes | Yes | Yes | Yes | Yes |
725725| Font background color | Yes | Yes | Yes | Yes | No |
726726| Subscript,Superscript | Yes | Yes | No | No | No |
727727| GetStyleRange | Yes | Yes | No | Yes | Yes |
728728| Paragraph Alignment | Yes | Yes | Yes | Yes | Almost Impossible |
729729| Paragraph Metrics | Yes | Yes | No | Yes | Almost Impossible |
730730| Paragraph Tabs | Yes | Yes | No | Yes | No |
731731| Zoom | Yes | Incomplete | No | Yes | No |
732732| Printing | Yes | No | No | No | No |
733733| RTF Load/Save | OS | RichMemo | No | OS | OS |
734734| Insertables | Yes | Yes | No | No | No |
735735| Transparent | Yes | No | Yes | Yes | No |
736736
737737### Win32
738738
739739![RichMemo without Theme patch](/wiki-images/e/e9/Rm_win32_notheme.PNG) ![RichMemo with Theme](/wiki-images/1/19/Rm_win32_theme.PNG)
740740
741741- [RichEdit](https://msdn.microsoft.com/en-us/library/windows/desktop/bb787605%28v=vs.85%29.aspx) is used as system widgetset. The latest known .dll is loaded and initialized on start. Please note that RichEdit 1.0 would not support most of the features.
742742- The internal wrapper of RichEditManager is provided in order to be compatible with Win 9x. However, it was never tried or tested. It's also expected that TOM object could be wrapped as one of the RichEditManager implementation. However, having the "manager" in place could be removed completely.
743743- According to the internet, RichEdit control was not updated by Microsoft to support Theme drawing (since XP and up to Windows 8.1). Thus, RichEdit might always look like an old Win9x 3d-framed control. Based on the patch provided at the [issue](http://bugs.freepascal.org/view.php?id=25111%7Creported) a way to override [WM_NCPAINT](https://msdn.microsoft.com/en-us/library/windows/desktop/dd145212%28v=vs.85%29.aspx) method was introduced in r4153.
744744
745745Win32RichMemo provides a global variable NCPaint. It's a handler of non-client area drawing. By default, it attempts to draw themed border (see Win32RichMemo.ThemedNCPaint for implementation). It provides good results on Windows XP themes, but later themes (where animations are used), the results are not so great and should be updated.
746746
747747In order to let system do NCPaint only (i.e. LCL implementation is causing issues or new windows updated RichEdit to draw borders properly), you can change NCPaint value at runtime, resetting it to nil
748748
749749`uses`\
750750`  RichMemo, ..{$ifdef WINDOWS}Win32RichMemo{$endif}`\
751751
752752`initialization`\
753753`  {$ifdef WINDOWS}`\
754754`  Win32RichMemo.NCPaint:=nil;`\
755755`  {$endif}`\
756756
757757You can also provide your own implementation of NCPaint. However, if you implement proper animated theme drawing, please provide patch.
758758
759759The behavior is Windows implementation specific and should not (and will not be) part of RichMemo interface.
760760
761761There's additional information about Windows RICHEDIT that can be found at:
762762
763763- MSDN blog by "Murray Sargent: Math in Office" (https://docs.microsoft.com/en-us/archive/blogs/murrays/).
764764
765765### Gtk2
766766
767767- [GtkTextView](https://developer.gnome.org/gtk2/stable/GtkTextView.html) is used as system widgetset
768768- Sub and Superscript are not supported natively, an extra code is implemented in gtk2richmemo in order to implement them.
769769- Bulletin and numbered lists are emulated.
770770
771771#### 2.1.0 (trunk/later)
772772
773773Gtk2 internal functions got changes. Specifically function GetWidgetInfo was modified, making RichMemo to fail on compilation.
774774
775775in order to adapt the change **RMLCLTRUNK** must be defined. It can be easily specified using **richmemopackage** compiler options.
776776
777777![](/wiki-images/0/05/Rmlcltrunkdefine.png)
778778
779779### Gtk3
780780
781781The APIs between Gtk2 and [Gtk3](https://developer.gnome.org/gtk3/stable/GtkTextView.html) are not really different. The major difference is in painting. For Gtk3 Cairo canvas is heavily used. The only area it affects is "Internals". IF any one wants to contribute Gtk2 implementation - please create separate gtk3richmemoXXX units. No {\$ifdefs} should be created in gtk2 units.
782782
783783### Cocoa
784784
785785- [NSTextView](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSTextView_Class/index.html) is used for Cocoa as system widgetset
786786- Not every font-family provides *italic* font. Thus even if you pass fsItalic as part of Style for a font, it might be ignored.
787787
788788#### Lazarus 1.8 and earlier
789789
790790You need to add a define RMLCL18 for the package compilation.
791791
792792### Qt
793793
794794- [QTextEdit](http://doc.qt.io/qt-4.8/qtextedit.html) widget is used. Current C-mappings for Qt are missing a lot of RichText APIs, thus full implementation is currently impossible.
795795- The following classes need to be mapped to C-functions:
796796 - [QTextBlockFormatH](http://doc.qt.io/qt-4.8/qtextblockformat.html) needed for paragraphs alignments (such as paragraph indents, line spacing and tabs). QTextEdit only exposes paragraph alignment.
797797 - [QTextCharFormatH](http://doc.qt.io/qt-4.8/qtextcharformat.html) needed for additional character formatting (i.e. vertical alignment, links support). QTextEdit only exposes font styles.
798798
799799## See also
800800
801801- [[RichMemo/Features]] - Comments on some features in progress.
802802- [[RichMemo/WorkArounds]] - Some notes about features not yet complete.
803803- [[RichMemo/Defines]] - Additional package switches that allow to resolve compiling/runtime issues.
804804- [[RichMemo/Samples]] - More examples.
805805- [[RichMemo/FAQ]] - Frequently (Forum) Asked Questions
806806- [MyNotex](https://sites.google.com/site/mynotex/) - Application which uses modified by Massimo Nardello RichMemo package on Linux-Gtk2.
807807- [[TMemo]]
808808- [[KControls|KMemo control]]
809809
810810---
811811*From the Free Pascal wiki, page "RichMemo", as it stood on 2022-09-29 after a change by Skalogryz, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history