Sign in Join
Wiki copytemporary

RichMemo: what changed

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

OldNewLine
1-<figure>
2-<img src="richmemosample.png" title="RichMemo macOS screenshot (thanks to Dominique Louis)" />
3-<figcaption>RichMemo macOS screenshot (thanks to Dominique Louis)</figcaption>
4-</figure>
1+![](/wiki-images/5/54/Richmemosample.png)
52
63## Introduction
74
85**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.
96
107Its main characteristics are
118
129- Text highlight
1310- System based Unicode edit support
1411
1512Planned: (patches are welcomed)
1613
1714- Adding images into text
1815- Embedding LCL Controls?
1916
2017The 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.
2118
2219Please add your bugreports, feature requests, pull request on [GitHub](https://github.com/skalogryz/richmemo/issues).
2320
2421## Licensing
2522
2623Author: Dmitry 'skalogryz' Boyarintsev
2724
2825License: [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.
2926
3027## Download
3128
3229The easiest way to install the stable version of the component is via the [[Online Package Manager]] included in current Lazarus versions.
3330
3431The 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).
3532
3633## Installation
3734
3835- Download the package set.
3936- Open **richmemo_design.lpk** package, and install it, rebuilding the IDE.
4037- TRichMemo is added to the 'Common Controls' component page.
4138
42-<figure>
43-<img src="RichMemoPalette.PNG" title="RichMemoPalette.PNG" />
44-<figcaption>RichMemoPalette.PNG</figcaption>
45-</figure>
39+![](/wiki-images/8/80/RichMemoPalette.PNG)
4640
4741Originally **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:
4842
4943- richmemopackage - run-time rich memo component.
5044- richmemo_design - IDE extensions to support for RichMemo component.
5145
5246## Font Parameters
5347
5448Font 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).
5549
5650- Name - name of the font (family).
5751- Size - size of the font in points (passing a negative value might produce unexpected results).
5852- Color - color of the font.
5953- Style - font styles, including Bold, italic, strike-through, underline.
6054- 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.
6155- BkColor - background (aka highlight) color for the text.
6256- VScriptPos - vertical adjustment for the text ![](/wiki-images/c/c1/Richmemo_Subsuper.png).
6357 - vpNormal - no special position.
6458 - vpSubscript - the text is subscript.
6559 - vpSuperscript - the text is superscript.
6660
6761
6862The actual vertical offset of super/sub scripts depends on OS implementation and currently cannot be controlled.
6963
7064You 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).
7165
7266GetFontParams function resolves "Default" font name and returns the actual font family name.
7367
7468## Methods
7569
7670### SetTextAttributes
7771
7872```delphi
7973procedure SetTextAttributes(TextStart, TextLen: Integer; AFont: TFont);
8074```
8175
8276- TextStart : Integer - the first character to be modified
8377- TextLen : Integer - number of characters to be modified
8478- AFont : TFont - a font that should be applied to the part of the text
8579
8680```delphi
8781procedure SetTextAttributes(TextStart, TextLen: Integer; const TextParams: TFontParams);
8882```
8983
9084- TextStart : Integer - the first character to be modified
9185- TextLen : Integer - number of characters to be modified
9286- TextParams : TFontParams - font parameters to be set
9387
9488SetTextureAttributes 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).
9589
9690Setting 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:
9791
9892```delphi
9993RichMemo1.SetTextAttributes(RichMemo1.SelStart, RichMemo1.SelLength, FontDialog1.Font);
10094```
10195
10296### GetTextAttributes
10397
10498```delphi
10599function GetTextAttributes(TextStart: Integer; var TextParams: TFontParams): Boolean; virtual;
106100```
107101
108102- TextStart : Integer - the character position to be queried for font parameters
109103- var TextParams : TFontParams - output value, filled with charachter's font attributes. If the method fails and returns false, record's field values is undefined.
110104
111105Fill font params of the character, at TextStart position. Method returns True if textstart is valid character position, and False overwise.
112106
113107### GetStyleRange
114108
115109```delphi
116110function GetStyleRange(CharPos: Integer; var RangeStart, RangeLen: Integer): Boolean; virtual;
117111```
118112
119113Returns 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.
120114
121115- 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.
122116- var RangeStart : Integer - the first character in the range
123117- var RangeLen : Integer - number of characthers in the range
124118
125119The method returns true if successed. the method returns false, if CharPos is incorrect value - more than available characters or some other error.
126120
127121### CharAtPos
128122
129123```delphi
130124function CharAtPos(x,y: Integer): Integer; virtual;
131125```
132126
133127Returns zero-based character offset (not UTF8 position). Returns -1 if fails.
134128
135129- x, y - is a point in the client area of the RichMemo control.
136130
137131The 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.
138132
139133If 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.
140134
141135### SetRangeColor
142136
143137```delphi
144138procedure SetRangeColor(TextStart, TextLength: Integer; FontColor: TColor);
145139```
146140
147141The method sets color of characters in the specified range to the FontColor. Other font parameters (name, size, styles) are left unchanged.
148142
149143- TextStart: Integer - the first character in the range
150144- TextLength: Integer - number of characters in the range
151145- FontColor: TColor - color that should be set
152146
153147### SetRangeParams
154148
155149```delphi
156150 procedure SetRangeParams(TextStart, TextLength: Integer; ModifyMask: TTextModifyMask;
157151 const fnt: TFontParams; AddFontStyle, RemoveFontStyle: TFontStyles); overload;
158152```
159153
160154The method changes font parameters in the specified range.
161155
162156- TextStart - the first character in the range
163157- TextLength - number of characters in the range
164158- ModifyMask - shows what exact font attributes must be updated The mask accepts any combination of the following values:
165159 - tmm_Color - font color would be modified (fnt.Color field must be populated)
166160 - tmm_Name - font name would be modified (fnt.Name field must be populated)
167161 - tmm_Size - font size would be modified (fnt.Size field must be populated)
168162 - tmm_Styles - font styles would be modified as specified by AddFontStyle, RemoveFontStyle parameters
169163 - tmm_BackColor - text highlight (background) color would be modified. (fnt.HasBkClr and fnt.BkColor fields must be populated )
170164 - Sending an empty mask will cause the method to return without making any changes.
171165- fnt - font parameters that are going to be used, depending on the ModifyMask values.
172166- AddFontStyle - set of styles that should be applied to the range (used only if tmm_Styles in ModifyMask, otherwise ignored)
173167- RemoveFontStyle - set of font style should should be removed from the range (used only if tmm_Styles in ModifyMask, otherwise ignored)
174168
175169```delphi
176170procedure SetRangeParams(TextStart, TextLength: Integer;
177171 ModifyMask: TTextModifyMask; const FontName: String;
178172 FontSize: Integer; FontColor: TColor;
179173 AddFontStyle, RemoveFontStyle: TFontStyles);
180174```
181175
182176The 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
183177
184178- FontName - font name that should set (used only if tmm_Name in ModifyMask, otherwise ignored)
185179- FontColor - font color that should set (used only if tmm_Color in ModifyMask, otherwise ignored)
186180
187181For example, if the following code is used
188182
189183```delphi
190184 RichMemo1.SetRangeParams (
191185 RichMemo1.SelStart, RichMemo1.SelLength,
192186 [tmm_Styles, tmm_Color], // changing Color and Styles only
193187 '', // this is font name - it's not used, thus we can leave it empty
194188 0, // this is font size - it's font size, we can leave it empty
195189 clGreen, // making all the text in the selected region green color
196190 [fsBold, fsItalic], // adding Bold and Italic Styles
197191 []
198192 );
199193```
200194
201195### GetParaAlignment
202196
203197Gets paragraph alignment
204198
205199```delphi
206200function GetParaAlignment(TextStart: Integer; var AAlign: TParaAlignment): Boolean;
207201```
208202
209203- TextStart - the position of the character that's belongs to the paragraph
210204- AAlign - gets alignment of a paragraph.
211205
212206**Note**:
213207
214208- Win32 - full-width Justification doesn't work on Windows XP and earlier.
215209- OSX - due to Carbon limitation, this is not working in Carbon, but works for Cocoa widgetset.
216210
217211### SetParaAlignment
218212
219213Sets paragraph alignent
220214
221215```delphi
222216procedure SetParaAlignment(TextStart, TextLen: Integer; AAlign: TParaAlignment);
223217```
224218
225219**Note**:
226220
227221- Win32 - full-width Justification doesn't work on Windows XP and earlier.
228222- 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
229223
230224### GetParaMetric
231225
232226Returns paragraph metrics for a given paragraph ![](/wiki-images/b/be/Richmemo_parametric.PNG)
233227
234228- FirstLine - an offset for the first line (in points), of the paragraph from the beginning of control
235229- TailIndent - an offset for each line (in points), except for the first line, of the paragraph from the end of the control
236230- HeadIndent - an offset for each line (in points) of the paragraph from the end of the control
237231- SpaceBefore - additional space before paragraph (in points)
238232- SpaceAfter - additional space after paragraph (in points)
239233- 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.
240234 - not supported in WinXP or earlier
241235 - 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
242236
243237**Note**
244238
245239- RichEdit paragraph settings are specified in pixels, not points, so you'll need to either convert these sizes yourself or use RichMemoHelper methods
246240- the notation of "Left"/"Right" offsets is avoided to prevent confusion for RTL.
247241
248242```delphi
249243function GetParaMetric(TextStart: Integer; var AMetric: TParaMetric): Boolean;
250244```
251245
252246procedure SetParaMetric(TextStart, TextLen: Integer; const AMetric: TParaMetric);
253247
254-</source>
255-
256248It'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.
257249
258250### GetParaRange
259251
260252Returns character range for a paragraph. The paragraph is identified by a character.
261253
262254```delphi
263255 function GetParaRange(CharOfs: Integer; var ParaRange: TParaRange): Boolean;
264256 function GetParaRange(CharOfs: Integer; var TextStart, TextLength: Integer): Boolean;
265257```
266258
267259CharOfs - is a character that belongs to a paragraph which range is returned. TParaRange - is a structure that returns 3 fields
268260
269261- start - the first character in the paragraph
270262- lengthNoBr - the length of the paragraph, excluding the line break character
271263- 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.
272264
273265### SetParaTabs
274266
275267Sets the set of tab stops to paragraphs in the specified length.
276268
277269```delphi
278270 procedure SetParaTabs(TextStart, TextLen: Integer; const AStopList: TTabStopList);
279271```
280272
281273- TextStart
282274- TextLen
283275- AStopList - the structure that contains an array of tab stops.
284276 - Count - specifies the number of initialized elements.
285277 - Tabs - array contains the description of each tab stop, consisting of an Offset and Alignment.
286278 - Offset - the tab point offset in points (from the left side of the control)
287279 - Align - the alignment of the tab stop (tabLeft - default one, tabCenter, tabRight, tabDecimal).
288280
289281**Notes**
290282
291283Renamefest
292284Prior to r4140 TTabAlignment enum values were taLeft, taCenter, taRight, taDecimal,but it did collide with Classes.TAlignment declarations. Thus the suffix was changed.
293285
294286win32
295287allows no more that 32 tabs
296288
297289gtk2
298290only tabLeft align is supported
299291
300292carbon
301293not implemented
302294
303295### GetParaTabs
304296
305297Gets the tab stops array. If no specific tabs were specified (widget default tab stops) AStopList count would be set to 0.
306298
307299```delphi
308300 function GetParaTabs(CharOfs: Integer; var AStopList: TTabStopList): Boolean;
309301```
310302
311303### SetParaNumbering
312304
313305Sets paragraphs automatic numbering and styles, such as bullets
314306
315307```delphi
316308procedure SetParaNumbering(TextStart, TextLen: Integer; const ANumber: TParaNumbering); virtual;
317309```
318310
319311- **TextStart** - the character of the the first paragraph to apply the style too
320312- **TextLength** - the number of characters that paragraph properties should be modified
321313- **TParaNumbering** - the structure describing the paragraph numbering information
322314
323315:* **style** - the style of numbering
324316
325317
326318
327319Note: 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
328320
329321for initializing the structure you can use InitParaNumbering() or InitParaNumber() functions. Also using Default() would work too
330322
331323### SetRangeParaParams
332324
333325Sets paragraph metrics selectively
334326
335327```delphi
336328procedure SetRangeParaParams(TextStart, TextLength: Integer; ModifyMask: TParaModifyMask; const ParaMetric: TParaMetric);
337329```
338330
339331- TextStart - the character of the the first paragraph to apply the style too
340332- TextLength - the number of characters that paragraph properties should be modified
341333- 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
342334 - pmm_FirstLine - changes the first line indentation. FirstLine field of ParaMetric must be initialized
343335 - pmm_HeadIndent - changes the heading paragraph indentation. HeadIndent field of ParaMetric must be initialized
344336 - pmm_TailIndent - changes the trail paragraph indentation. TailIndent field of ParaMetric must be initialized
345337 - pmm_SpaceBefore - changes the space preceding . SpaceBefore field of ParaMetric must be initialized
346338 - pmm_SpaceAfter - changes the space after (below) the paragraph. SpaceAfter field of ParaMetric must be initialized
347339 - pmm_LineSpacing - line spacing within paragraph. LineSpace field of ParaMetric must be initialized
348340- ParaMetric - the structure containing the values to be set. Only fields specified by ModifyMask should be initialized
349341
350342### LoadRichText
351343
352344```delphi
353345function LoadRichText(Source: TStream): Boolean; virtual;
354346```
355347
356348- Source: TStream - a stream to read richtext data from
357349
358350The method loads RTF enocded data from the specified stream. Returns true if success, and false otherwise. If source is nil, the method returns false
359351
360352The content of TRichMemo is completely replaced by the content on the source stream. Current text selection is reset.
361353
362354### SaveRichText
363355
364356```delphi
365357function SaveRichText(Dest: TStream): Boolean; virtual;
366358```
367359
368360- Source: TStream - a stream to read richtext data from
369361
370362The method saves RTF enocded data to the specified stream. Returns true if success, and false otherwise. If source is nil, the method returns false
371363
372364Current state of TRichMemo is unchanged after the method returns
373365
374366### Search
375367
376368```delphi
377369function Search(const ANiddle: string; Start, Len: Integer; const SearchOpt: TSearchOptions): Integer;
378370```
379371
380372- ANiddle: string - a text to search for
381373- Start: Integer - a character position to start search from, if -1 or 0 search from the start
382374- Len: Integer - length (in characters, not bytes) of the text to search for the niddle.
383375- SearchOpt: TSearchOptions
384376 - soMatchCase - case sensitive search
385377 - soBackward - searching from the end of the document to the character identified by "Start" parameter
386378 - soWholeWord - searching for the whole word
387379
388380The 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.
389381
390382If the ANiddle was not found in the text, -1 is returned
391383
392384```delphi
393385function Search(const ANiddle: string; Start, Len: Integer; const SearchOpt: TSearchOptions;
394386 var TextStart, TextLength: Integer): Boolean;
395387```
396388
397389(The method is introduced with r5115)
398390
399391- ANiddle: string - a text to search for
400392- Start: Integer - a character position to start search from, if -1 or 0 search from the start
401393- Len: Integer - length (in characters, not bytes) of the text to search for the niddle.
402394- SearchOpt: TSearchOptions
403395 - soMatchCase - case sensitive search
404396 - soBackward - searching from the end of the document to the character identified by "Start" parameter
405397 - soWholeWord - searching for the whole word
406398- (output) ATextStart - a position of the text found (in characters)
407399- (output) ATextLength - length of the text found (in characters (cursor positions!))
408400
409401The method returns the true if searched sub-string is found, false otherwise.
410402
411403The returned ATextStart and ATextLength values are suitable for use in SelStart and SelLength properties.
412404
413405**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.
414406
415407If you need to extract the found text, you should use GetText() method (passing ATextStart and ATextLength values).
416408
417409### GetText, GetUText
418410
419411```delphi
420412 function GetText(TextStart, TextLength: Integer): String;
421413 function GetUText(TextStart, TextLength: Integer): UnicodeString;
422414```
423415
424416- TextStart: Integer - a character position to start extract from. (0 - is the first character in the text).
425417- TextLength: Integer - length (in characters, not bytes) of the text to extract
426418
427419GetText() returns UTF8 sub-string
428420
429421GetUText() returns UTF16 sub-string
430422
431423Current selection would not be affected by the operation. (If you see the selection affected, please report as an issue).
432424
433425You 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.
434426
435427### Redo
436428
437429```delphi
438430 procedure Redo;
439431```
440432
441433The method redos the last change [undone](http://lazarus-ccr.sourceforge.net/docs/lcl/stdctrls/tcustomedit.undo.html) previously.
442434
443435You can always call CanRedo to check, if there're any actions can be redone.
444436
445437## Properties
446438
447439### ZoomFactor
448440
449441```delphi
450442property ZoomFactor: double
451443```
452444
453445Read/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).
454446
455447### HideSelection
456448
457449```delphi
458450property HideSelection: Boolean default false
459451```
460452
461453Read/Write property. If True RichMemo selection is hidden if the control is not focused. If False, the selection is shown all the time.
462454
463455### CanRedo
464456
465457```delphi
466458property CanRedo: Boolean
467459```
468460
469461If 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.
470462
471463### Transparent
472464
473-<figure>
474465<img src="richmemo_transparent.png" title="richmemo_transparent.png" width="400" />
475-<figcaption>richmemo_transparent.png</figcaption>
476-</figure>
477466
478467```delphi
479468property Transparent: Boolean
480469```
481470
482471If 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
483472
484473Note 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)
485474
486475- Supported by Win32, Qt5 and Cocoa
487476
488477### Rtf
489478
490479```delphi
491480property Rtf: String
492481```
493482
494-<figure>
495483<img src="RtfEditor.PNG" title="RtfEditor.PNG" width="400" />
496-<figcaption>RtfEditor.PNG</figcaption>
497-</figure>
498484
499485Read/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.
500486
501487If then property value is an empty string then Lines property is used as a plain text to initialize control value in load-time.
502488
503489**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.
504490
505491**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.
506492
507493So 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)
508494
509495## Events
510496
511497### OnSelectionChange
512498
513499```delphi
514500property OnSelectionChange: TNotifyEvent
515501TNotifyEvent = procedure (Sender: TObject) of object;
516502```
517503
518504The event is fired whenever, selection is changed within RichMemo, either programmatically or due to the user action.
519505
520506## TRichEditForMemo
521507
522508The 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.
523509
524510### Methods
525511
526512#### FindText
527513
528514Searches a given range in the text for a target string
529515
530516### Properties
531517
532518#### SelAttributes
533519
534520Reads/Modifies character attributes of the current selection.
535521
536522### Paragraph
537523
538524Reads/Modifies paragraph attributes of the current selection.
539525
540526### RichMemoUtils
541527
542528The unit is introduced to add some useful OS-specific features for handling working with RichMemo
543529
544530#### InsertImageFromFile
545531
546532```delphi
547533function InsertImageFromFile (const ARichMemo: TCustomRichMemo; APos: Integer;
548534 const FileNameUTF8: string;
549535 const AImgSize: TSize
550536 ): Boolean = nil;
551537```
552538
553539*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).*
554540
555541- APos - position in the text
556542- 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.
557543
558544There's also an utility function **InsertImageFromFileNoResize** that calls InsertImageFromFile, passing size as 0.
559545
560546An example of use
561547
562548```delphi
563549 procedure TForm1.Button1Click(Sender: TObject);
564550 begin
565551 // running a dialog to select a picture to insert
566552 if OpenDialog1.Execute then
567553 // inserting the picture at the current RichMemo cursor position
568554 InsertImageFromFileNoResize(RichMemo1, RichMemo1.SelStart, OpenDialog1.FileName);
569555 end;
570556```
571557
572558### InsertStyledText,InsertColorStyledText,InsertFontText
573559
574560The 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.
575561
576562The 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.
577563
578564```delphi
579565procedure InsertStyledText(
580566 const ARichMemo: TCustomRichMemo;
581567 const TextUTF8: String;
582568 AStyle: TFontStyles;
583569 InsPos : Integer = -1 )
584570```
585571
586572InsertStyledText inserts the styled text at the specified position.
587573
588574```delphi
589575procedure InsertColorStyledText(
590576 const ARichMemo: TCustomRichMemo;
591577 const TextUTF8: String;
592578 AColor: TColor;
593579 AStyle: TFontStyles;
594580 InsPos : Integer = -1 )
595581```
596582
597583InsertColorStyledText inserts the text with specified style and color at the specified position. to the end of the RichMemo
598584
599585```delphi
600586procedure InsertFontText(
601587 const ARichMemo: TCustomRichMemo;
602588 const TextUTF8: String;
603589 const prms: TFontParams;
604590 InsPos : Integer = -1 )
605591```
606592
607593InsertFontText inserts the text and applies specified FontParams to it.
608594
609595You 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.
610596
611597## Frequently Asked Questions
612598
613599### Using RichMemo in Shared Libraries
614600
615601[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".
616602
617603## (Delphi) RichEdit like interface
618604
619605[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:
620606
621607- you can either create a sub-class from TCustomRichMemo (or RichMemo) and implement Delphi RichEdit methods;
622608- 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.
623609
624610`uses ... RichMemo, RichMemoHelpers;`\
625-\
611+
626612`TForm = class`\
627613`  RichMemo1 : TRichMemo;`\
628614`   `\
629615`  // SelAttributes property is not available in the base class`\
630616`  // but added by a helper defined at RichMemoHelpers unit`\
631617`RichMemo1.SelAttributes.Name := 'Courier New';`
632618
633619## Append mixed color text at the end of the RichMemo
634620
635621If you just need simple coloring then here is an example that will each time add a new line with random color (tested on Windows):
636622
637623```delphi
638624 procedure TForm1.Button1Click(Sender: TObject);
639625 var
640626 i, j: integer;
641627 str: string;
642628 begin
643629 with Richmemo1 do
644630 begin
645631 str := 'Newline text';
646632 i := Length(Lines.Text) - Lines.Count; // cr as #10#13 is counted only once so subtract it once
647633 j := Length(str) + 1; // +1 to make the cr the same format
648634 Lines.Add(str);
649635 SetRangeColor(i, j, Round(random * $FFFFFF));
650636 end;
651637 end;
652638```
653639
654-` `<span style="color:#0140FF">`Newline text`</span>\
655-` `<span style="color:#507FAF">`NewLine text`</span>\
656-` `<span style="color:#C04A90">`NewLine text`</span>
640+` ``Newline text`\
641+` ``NewLine text`\
642+` ``NewLine text`
657643
658644Alternative example for simple coloring (tested on Windows):
659645
660646```delphi
661647 procedure TForm1.Button2Click(Sender: TObject);
662648 begin
663649 with RichMemo1 do
664650 begin
665651 Lines.Add('Line in red');
666652 SetRangeColor(Length(Lines.Text) - Length(Lines[Lines.Count - 1]) - Lines.Count - 1, Length(Lines[Lines.Count - 1]), clRed);
667653
668654 Lines.Add('Line in blue');
669655 SetRangeColor(Length(Lines.Text) - Length(Lines[Lines.Count - 1]) - Lines.Count - 1, Length(Lines[Lines.Count - 1]), clBlue);
670656
671657 Lines.Add('Normal line.');
672658 Lines.Add('Normal line.');
673659
674660 Lines.Add('Line in green ');
675661 SetRangeColor(Length(Lines.Text) - Length(Lines[Lines.Count - 1]) - Lines.Count - 1, Length(Lines[Lines.Count - 1]), clGreen);
676662 end;
677663 end;
678664```
679665
680-` `<span style="color:#FF0000">`Line in red`</span>\
681-` `<span style="color:#0000FF">`Line in blue`</span>\
682-` `<span style="color:#000000">`Normal line.`</span>\
683-` `<span style="color:#000000">`Normal line.`</span>\
684-` `<span style="color:#008000">`Line in green`</span>
666+` ``Line in red`\
667+` ``Line in blue`\
668+` ``Normal line.`\
669+` ``Normal line.`\
670+` ``Line in green`
685671
686672If you need mixed coloring then this is an example that will add a new line with several different colored words (tested on Windows):
687673
688674```delphi
689675procedure TForm1.Button3Click(Sender: TObject);
690676 procedure AddColorStr(s: string; const col: TColor = clBlack; const NewLine: boolean = true);
691677 begin
692678 with RichMemo1 do
693679 begin
694680 if NewLine then
695681 begin
696682 Lines.Add('');
697683 Lines.Delete(Lines.Count - 1); // avoid double line spacing
698684 end;
699685
700686 SelStart := Length(Text);
701687 SelText := s;
702688 SelLength := Length(s);
703689 SetRangeColor(SelStart, SelLength, col);
704690
705691 // deselect inserted string and position cursor at the end of the text
706692 SelStart := Length(Text);
707693 SelText := '';
708694 end;
709695 end;
710696 begin
711697 AddColorStr('Black, ');
712698 AddColorStr('Green, ', clGReen, false);
713699 AddColorStr('Blue, ', clBlue, false);
714700 AddColorStr('Red', clRed, false);
715701 end;
716702```
717703
718-` `<span style="color:#000000">`Black, `</span><span style="color:#008000">`Green, `</span><span style="color:#0000FF">`Blue, `</span><span style="color:#FF0000">`Red`</span>\
719-` `<span style="color:#000000">`Black, `</span><span style="color:#008000">`Green, `</span><span style="color:#0000FF">`Blue, `</span><span style="color:#FF0000">`Red`</span>\
720-` `<span style="color:#000000">`Black, `</span><span style="color:#008000">`Green, `</span><span style="color:#0000FF">`Blue, `</span><span style="color:#FF0000">`Red`</span>
704+` ``Black, ``Green, ``Blue, ``Red`\
705+` ``Black, ``Green, ``Blue, ``Red`\
706+` ``Black, ``Green, ``Blue, ``Red`
721707
722708## Markup Language Parsing
723709
724710![mlparse example](/wiki-images/8/8c/Mlparse.png) The native rich-edit controls do not support a markup-language parsing.
725711
726712You'll need to write it yourself as shown in mlparse example
727713
728714## Internals
729715
730716### Platform Support Matrix
731717
732718Values in the matrix are not expected to be static (except for "carbon" column), each system is planned to support all features declared by RichMemo.
733719
734720Note 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.
735721
736722| Feature | Win32 | Gtk2 | Qt | Cocoa | Carbon |
737723|--------------------------------|-------|------------|-----|-------|-------------------|
738724| Font color and style selection | Yes | Yes | Yes | Yes | Yes |
739725| Font background color | Yes | Yes | Yes | Yes | No |
740726| Subscript,Superscript | Yes | Yes | No | No | No |
741727| GetStyleRange | Yes | Yes | No | Yes | Yes |
742728| Paragraph Alignment | Yes | Yes | Yes | Yes | Almost Impossible |
743729| Paragraph Metrics | Yes | Yes | No | Yes | Almost Impossible |
744730| Paragraph Tabs | Yes | Yes | No | Yes | No |
745731| Zoom | Yes | Incomplete | No | Yes | No |
746732| Printing | Yes | No | No | No | No |
747733| RTF Load/Save | OS | RichMemo | No | OS | OS |
748734| Insertables | Yes | Yes | No | No | No |
749735| Transparent | Yes | No | Yes | Yes | No |
750736
751737### Win32
752738
753739![RichMemo without Theme patch](/wiki-images/e/e9/Rm_win32_notheme.PNG) ![RichMemo with Theme](/wiki-images/1/19/Rm_win32_theme.PNG)
754740
755741- [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.
756742- 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.
757743- 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.
758744
759745Win32RichMemo 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.
760746
761747In 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
762748
763749`uses`\
764750`  RichMemo, ..{$ifdef WINDOWS}Win32RichMemo{$endif}`\
765-\
751+
766752`initialization`\
767753`  {$ifdef WINDOWS}`\
768754`  Win32RichMemo.NCPaint:=nil;`\
769755`  {$endif}`\
770756
771757You can also provide your own implementation of NCPaint. However, if you implement proper animated theme drawing, please provide patch.
772758
773759The behavior is Windows implementation specific and should not (and will not be) part of RichMemo interface.
774760
775761There's additional information about Windows RICHEDIT that can be found at:
776762
777763- MSDN blog by "Murray Sargent: Math in Office" (https://docs.microsoft.com/en-us/archive/blogs/murrays/).
778764
779765### Gtk2
780766
781767- [GtkTextView](https://developer.gnome.org/gtk2/stable/GtkTextView.html) is used as system widgetset
782768- Sub and Superscript are not supported natively, an extra code is implemented in gtk2richmemo in order to implement them.
783769- Bulletin and numbered lists are emulated.
784770
785771#### 2.1.0 (trunk/later)
786772
787773Gtk2 internal functions got changes. Specifically function GetWidgetInfo was modified, making RichMemo to fail on compilation.
788774
789775in order to adapt the change **RMLCLTRUNK** must be defined. It can be easily specified using **richmemopackage** compiler options.
790776
791-<figure>
792-<img src="rmlcltrunkdefine.png" title="rmlcltrunkdefine.png" />
793-<figcaption>rmlcltrunkdefine.png</figcaption>
794-</figure>
777+![](/wiki-images/0/05/Rmlcltrunkdefine.png)
795778
796779### Gtk3
797780
798781The 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.
799782
800783### Cocoa
801784
802785- [NSTextView](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSTextView_Class/index.html) is used for Cocoa as system widgetset
803786- Not every font-family provides *italic* font. Thus even if you pass fsItalic as part of Style for a font, it might be ignored.
804787
805788#### Lazarus 1.8 and earlier
806789
807790You need to add a define RMLCL18 for the package compilation.
808791
809792### Qt
810793
811794- [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.
812795- The following classes need to be mapped to C-functions:
813796 - [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.
814797 - [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.
815798
816799## See also
817800
818801- [[RichMemo/Features]] - Comments on some features in progress.
819802- [[RichMemo/WorkArounds]] - Some notes about features not yet complete.
820803- [[RichMemo/Defines]] - Additional package switches that allow to resolve compiling/runtime issues.
821804- [[RichMemo/Samples]] - More examples.
822805- [[RichMemo/FAQ]] - Frequently (Forum) Asked Questions
823806- [MyNotex](https://sites.google.com/site/mynotex/) - Application which uses modified by Massimo Nardello RichMemo package on Linux-Gtk2.
824807- [[TMemo]]
825808- [[KControls|KMemo control]]
826809
827810---
828811*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