RVStyle.pas
上传用户:daoqigc
上传日期:2021-04-20
资源大小:2795k
文件大小:330k
源码类别:

RichEdit

开发平台:

Delphi

  1.                else
  2.                  Canvas.Font.Color  := clWhite;
  3.                end
  4.              else if RV_GetLuminance(RV_GetPrnColor(BackColor))>RV_GetLuminance(RV_GetPrnColor(Color)) then begin
  5.                Canvas.Brush.Color := clWhite;
  6.                Canvas.Font.Color := clBlack;
  7.                end
  8.              else begin
  9.                Canvas.Brush.Color := clBlack;
  10.                Canvas.Font.Color := clWhite;
  11.              end;
  12.            end;
  13.          rvcmBlackOnWhite:
  14.            begin
  15.              Canvas.Font.Color  := clBlack;
  16.              Canvas.Brush.Color := clNone;
  17.            end;
  18.        end;
  19.   end;
  20.   if Canvas.Brush.Color=clNone then
  21.     Canvas.Brush.Style := bsClear
  22.   else
  23.     Canvas.Brush.Style := bsSolid;
  24. end;
  25. {------------------------------------------------------------------------------}
  26. {$IFNDEF RVDONOTUSEINI}
  27. const IniProtectMask = $3FF;
  28. { Loads properties from the ini-file, from the section Section.
  29.   fs is a format string for keys, it is like 'Font%s1', 'Font%s2', etc.
  30.   DefName is a default style name.
  31.   JumpByDefault - for backward compatibility, defines if this style should be
  32.   hypertext if this is not explicitly specified in the ini-file.
  33.   DefJumpCursor - hypertext cursor assigned to this style if, if another
  34.   cursor is not specified in the ini-file explicitly.
  35. }
  36. procedure TCustomRVFontInfo.LoadFromINI(ini: TRVIniFile; const Section,
  37.   fs: String; JumpByDefault: Boolean; DefJumpCursor: TCursor);
  38. var s: String;
  39.     pr: Word;
  40. begin
  41.   inherited LoadFromINI(ini, Section, fs, RVDEFAULTTEXTSTYLENAME);
  42.   FontName   := ini.ReadString (Section, Format(fs,[RVINI_FONTNAME]),  RVDEFAULTSTYLEFONT);
  43.   s := UpperCase(ini.ReadString(Section, Format(fs,[RVINI_JUMP]),      RVINIUNKNOWN));
  44.   if (s=RVINIUNKNOWN) then begin // for compatibility with old saving format
  45.     Jump := JumpByDefault;
  46.     JumpCursor := DefJumpCursor;
  47.     end
  48.   else begin
  49.     Jump       := (s=RVINIFILEYESU);
  50.     JumpCursor := ini.ReadInteger(Section, Format(fs,[RVINI_JUMPCURSOR]), crJump);
  51.   end;
  52.   Size       := ini.ReadInteger(Section, Format(fs,[RVINI_SIZE]),        10);
  53.   Color      := ini.ReadInteger(Section, Format(fs,[RVINI_COLOR]),       clWindowText);
  54.   BackColor  := ini.ReadInteger(Section, Format(fs,[RVINI_BACKCOLOR]),   clNone);
  55.   HoverBackColor  := ini.ReadInteger(Section, Format(fs,[RVINI_HOVERBACKCOLOR]), clNone);
  56.   HoverColor := ini.ReadInteger(Section, Format(fs,[RVINI_HOVERCOLOR]), clNone);
  57.   {$IFDEF RICHVIEWCBDEF3}
  58.   Charset    := ini.ReadInteger(Section, Format(fs,[RVINI_CHARSET]),    DEFAULT_CHARSET);
  59.   {$ENDIF}
  60.   {$IFDEF RVLANGUAGEPROPERTY}
  61.   Language := ini.ReadInteger(Section, Format(fs,[RVINI_LANGUAGE]), 0);
  62.   {$ENDIF}
  63.   CharScale  := ini.ReadInteger(Section, Format(fs,[RVINI_CHARSCALE]),  100);
  64.   CharSpacing := ini.ReadInteger(Section, Format(fs,[RVINI_CHARSPACING]),  0);  
  65.   BiDiMode   := TRVBiDiMode(ini.ReadInteger(Section, Format(fs,[RVINI_BIDIMODE]),  0));
  66.   Style    := [];
  67.   if IniReadBool(ini, Section, Format(fs,[RVINI_BOLD]), False) then
  68.     Include(FStyle, fsBold);
  69.   if IniReadBool(ini, Section, Format(fs,[RVINI_UNDERLINE]), False) then
  70.     Include(FStyle, fsUnderline);
  71.   if IniReadBool(ini, Section, Format(fs,[RVINI_STRIKEOUT]), False) then
  72.     Include(FStyle, fsStrikeOut);
  73.   if IniReadBool(ini, Section, Format(fs,[RVINI_ITALIC]), False) then
  74.     Include(FStyle, fsItalic);
  75.   StyleEx  := [];
  76.   if IniReadBool(ini, Section, Format(fs,[RVINI_OVERLINE]), False) then
  77.     Include(FStyleEx, rvfsOverline);
  78.   if IniReadBool(ini, Section, Format(fs,[RVINI_ALLCAPS]), False) then
  79.     Include(FStyleEx, rvfsAllCaps);
  80.   FOptions  := [];
  81.   if IniReadBool(ini, Section, Format(fs,[RVINI_RTFCODE]), False) then
  82.     Include(FOptions, rvteoRTFCode);
  83.   if IniReadBool(ini, Section, Format(fs,[RVINI_HTMLCODE]), False) then
  84.     Include(FOptions, rvteoHTMLCode);
  85.   pr := ini.ReadInteger(Section, Format(fs,[RVINI_PROTECTION]), 0) and IniProtectMask;
  86.   Protection := TRVProtectOptions(pr);
  87.   if iniReadBool(ini, Section, Format(fs,[RVINI_SINGLESYMBOLS]), False) then begin
  88.     Include(FProtection, rvprStyleProtect);
  89.     Include(FProtection, rvprDoNotAutoSwitch);
  90.   end;
  91.   VShift        := ini.ReadInteger(Section, Format(fs,[RVINI_VSHIFT]),      0);
  92. end;
  93. {------------------------------------------------------------------------------}
  94. { Saves properties to the ini-file, to the section Section.
  95.   fs is a format string for keys, it is like 'Font%s1', 'Font%s2', etc. }
  96. procedure TCustomRVFontInfo.SaveToINI(ini: TRVIniFile; const Section, fs: String);
  97. begin
  98.   inherited SaveToINI(ini, Section, fs);
  99.   ini.WriteString(Section,  Format(fs,[RVINI_FONTNAME]),       FontName);
  100.   ini.WriteString(Section,  Format(fs,[RVINI_JUMP]),       arrNoYes[Jump]);
  101.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_SIZE]),       Size,       10);
  102.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_COLOR]),      Color,      clWindowText);
  103.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_BACKCOLOR]),  BackColor,  clNone);
  104.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_HOVERBACKCOLOR]), HoverBackColor, clNone);
  105.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_HOVERCOLOR]), HoverColor, clNone);
  106.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_JUMPCURSOR]), JumpCursor, crJump);
  107.   {$IFDEF RICHVIEWCBDEF3}
  108.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_CHARSET]),    Charset,    DEFAULT_CHARSET);
  109.   {$ENDIF}
  110.   WriteIntToIniIfNE(ini, Section,  Format(fs,[RVINI_CHARSCALE]),  CharScale,  100);
  111.   WriteIntToIniIfNE(ini, Section,  Format(fs,[RVINI_CHARSPACING]), CharSpacing,  0);  
  112.   WriteIntToIniIfNE(ini, Section,  Format(fs,[RVINI_BiDiMode]),  ord(BiDiMode),  0);
  113.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_BOLD]),      fsBold      in Style, False);
  114.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_UNDERLINE]), fsUnderline in Style, False);
  115.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_STRIKEOUT]), fsStrikeOut in Style, False);
  116.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_ITALIC]),    fsItalic    in Style, False);
  117.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_OVERLINE]),  rvfsOverline in StyleEx, False);
  118.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_ALLCAPS]),   rvfsAllCaps in StyleEx, False);
  119.   WriteIntToIniIfNE(ini, Section,  Format(fs,[RVINI_PROTECTION]), Word(Protection) and IniProtectMask, 0);
  120.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_RTFCODE]),    rvteoRTFCode  in Options, False);
  121.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_HTMLCODE]),   rvteoHTMLCode  in Options, False);
  122.   WriteIntToIniIfNE(ini, Section,  Format(fs,[RVINI_VSHIFT]),     VShift,     0);
  123.   {$IFDEF RVLANGUAGEPROPERTY}
  124.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_LANGUAGE]),Language,0);
  125.   {$ENDIF}
  126. end;
  127. {$ENDIF}
  128. {------------------------------------------------------------------------------}
  129. { Saves this text style as a part of CSS to the Stream.
  130.   if BaseStyle<>nil, only a difference between this style and BaseStyle is
  131.   saved.
  132.   If Multiline=False, all text will be written on a single line. }
  133. procedure TCustomRVFontInfo.SaveCSSToStream(Stream: TStream; BaseStyle: TCustomRVFontInfo;
  134.   Multiline, UTF8: Boolean);
  135. const
  136.     cssFontStyle  : array[Boolean] of String = ('normal','italic');
  137.     cssFontWeight : array[Boolean] of String = ('normal','bold');
  138.     {..................................................}
  139.     function GetTextDecoration(Style: TFontStyles; StyleEx: TRVFontStyles;
  140.                                Jump: Boolean): String;
  141.       {.................................}
  142.       procedure AddVal(Condition: Boolean; var s: String; const Value: String);
  143.       begin
  144.         if Condition then begin
  145.           if s<>'' then
  146.             s := s+' ';
  147.           s := s+Value;
  148.         end;
  149.       end;
  150.       {.................................}
  151.     begin
  152.       Result := '';
  153.       AddVal(fsUnderline in Style,    Result, 'underline');
  154.       AddVal(fsStrikeOut in Style,    Result, 'line-through');
  155.       AddVal(rvfsOverline in StyleEx, Result, 'overline');
  156.       if Result='' then
  157.         Result := 'none'
  158.     end;
  159.     {..................................................}
  160.     function GetTextVAlign(VShift: Integer): String;
  161.     begin
  162.       if VShift>0 then
  163.         Result := 'super'
  164.       else if VShift<0 then
  165.         Result := 'sub'
  166.       else
  167.         Result := '';
  168.     end;
  169.     {..................................................}
  170.     function GetHoverColor(Color: TColor): TColor;
  171.     begin
  172.       if Color=clNone then
  173.         Result := HoverColor
  174.       else
  175.         Result := Color;
  176.     end;
  177.     {..................................................}
  178. var s: String;
  179. begin
  180.   if (BaseStyle=nil) or (BaseStyle.Size<>Size) then
  181.     RVWriteX(Stream, Format(' font-size: %dpt;',[Size]), Multiline);
  182.   if (BaseStyle=nil) or (AnsiCompareText(BaseStyle.FontName, FontName)<>0) then begin
  183.     s := ''''+FontName+'''';
  184.     if UTF8 then
  185.       s := RVU_AnsiToUTF8(CP_ACP, s);
  186.     if AnsiCompareText(FontName, RVFONT_SYMBOL)=0 then
  187.       s := '''Arial Unicode MS'', ''Lucida Sans Unicode'', ''Arial''';
  188.     RVWriteX(Stream, Format(' font-family: %s;',[s]), Multiline);
  189.   end;
  190.   if (BaseStyle=nil) or ((fsItalic in BaseStyle.Style)<>(fsItalic in Style)) then
  191.     RVWriteX(Stream, Format(' font-style: %s;',[cssFontStyle[fsItalic in Style]]),
  192.       Multiline);
  193.   if (BaseStyle=nil) or ((fsBold in BaseStyle.Style)<>(fsBold in Style)) then
  194.     RVWriteX(Stream, Format(' font-weight: %s;',[cssFontWeight[fsBold in Style]]),
  195.       Multiline);
  196.   if (BaseStyle=nil) or (BaseStyle.Color<>Color) then
  197.     RVWriteX(Stream, Format(' color: %s;',[RV_GetHTMLRGBStr(Color, False)]), Multiline);
  198.   if ((BaseStyle=nil) and (CharSpacing<>0)) or
  199.      ((BaseStyle<>nil) and (BaseStyle.CharSpacing<>CharSpacing)) then
  200.      RVWriteX(Stream, Format(' letter-spacing: %dpx;',[CharSpacing]), Multiline);
  201.   if (rvfsAllCaps in StyleEx) then begin
  202.     if (BaseStyle=nil) or not (rvfsAllCaps in BaseStyle.StyleEx) then
  203.       RVWriteX(Stream, ' text-transform: uppercase;', Multiline);
  204.     end
  205.   else if (BaseStyle<>nil) and (rvfsAllCaps in BaseStyle.StyleEx) then
  206.       RVWriteX(Stream, ' text-transform: none;', Multiline);
  207.   if ((BaseStyle=nil) and ((BackColor<>clNone) or not Multiline)) or
  208.      ((BaseStyle<>nil) and (BaseStyle.BackColor<>BackColor)) then
  209.     RVWriteX(Stream, Format(' background-color: %s;',[RV_GetCSSBkColor(BackColor)]),
  210.       Multiline);
  211.   s := GetTextVAlign(VShift);
  212.   if ((BaseStyle=nil) and (s<>'')) or
  213.      ((BaseStyle<>nil) and (s<>GetTextVAlign(BaseStyle.VShift))) then
  214.     RVWriteX(Stream, Format(' vertical-align: %s;',[s]), Multiline);
  215.   s := GetTextDecoration(Style,StyleEx,Jump);
  216.     if (BaseStyle=nil) or
  217.      (s<>GetTextDecoration(BaseStyle.Style,BaseStyle.StyleEx,BaseStyle.Jump))
  218.      or (Jump and (s='none')) then
  219.     RVWriteX(Stream, Format(' text-decoration: %s;',[s]), Multiline);
  220. end;
  221. {------------------------------------------------------------------------------}
  222. { Method for backward compatibility:
  223.   allows loading the deleted SingleSymbols property. }
  224. procedure TCustomRVFontInfo.DefineProperties(Filer: TFiler);
  225. begin
  226.   Filer.DefineProperty(RVINI_SINGLESYMBOLS, SingleSymbolsReader, nil, False);
  227. end;
  228. {------------------------------------------------------------------------------}
  229. { Method for backward compatibility:
  230.   loads the deleted SingleSymbols property as [rvprStyleProtect, rvprDoNotAutoSwitch]
  231.   Protection options. }
  232. procedure TCustomRVFontInfo.SingleSymbolsReader(reader: TReader);
  233. var ss: Boolean;
  234. begin
  235.   ss := reader.ReadBoolean;
  236.   if ss then begin
  237.     Include(FProtection, rvprStyleProtect);
  238.     Include(FProtection, rvprDoNotAutoSwitch);
  239.   end;
  240. end;
  241. {================================= TFontInfo ==================================}
  242. { Constructor }
  243. constructor TFontInfo.Create(Collection: TCollection);
  244. begin
  245.   inherited Create(Collection);
  246.   FNextStyleNo := -1;
  247. end;
  248. {------------------------------------------------------------------------------}
  249. procedure TFontInfo.Assign(Source: TPersistent);
  250. begin
  251.   if Source is TFontInfo then begin
  252.     FNextStyleNo:= TFontInfo(Source).FNextStyleNo;
  253.     {$IFNDEF RVDONOTUSEUNICODE}
  254.     FUnicode    := TFontInfo(Source).FUnicode;
  255.     {$ENDIF}
  256.     {$IFNDEF RVDONOTUSESTYLETEMPLATES}
  257.     FModifiedProperties := TFontInfo(Source).FModifiedProperties;
  258.     {$ENDIF}
  259.   end;
  260.   inherited Assign(Source);
  261. end;
  262. {------------------------------------------------------------------------------}
  263. { Is this item equal to Value (all properties are equal)?
  264.   NextStyleNo property (adjusted using Mapping) is taken into account.
  265.   Mapping is from the Value's collection to this collection, see
  266.   TCustomRVInfos.MergeWith.
  267. }
  268. function TFontInfo.IsSimpleEqualEx(Value: TCustomRVInfo; Mapping: TRVIntegerList): Boolean;
  269. begin
  270.   Result := IsSimpleEqual(Value, True, False);
  271.   if not Result then
  272.     exit;
  273.   if Value is TFontInfo then begin
  274.     Result := False;
  275.     if (TFontInfo(Value).NextStyleNo>=0) then begin
  276.       if (TFontInfo(Value).NextStyleNo>=Mapping.Count) then
  277.         TFontInfo(Value).NextStyleNo := -1 // fix up
  278.       else if (Mapping[TFontInfo(Value).NextStyleNo]<>NextStyleNo) then
  279.         exit;
  280.     end;
  281.     Result := True;
  282.   end;
  283. end;
  284. {------------------------------------------------------------------------------}
  285. { Is this item equal to Value (all properties are equal)?
  286.   if IgnoreReferences=True, NextStyleNo property is ignored, otherwise they
  287.   must be equal.
  288.   IgnoreID is not used (used only in TRVListInfo). }
  289. function TFontInfo.IsSimpleEqual(Value: TCustomRVInfo; IgnoreReferences: Boolean;
  290.       IgnoreID: Boolean{$IFDEF RICHVIEWDEF4}=True{$ENDIF}): Boolean;
  291. begin
  292.   Result := inherited IsSimpleEqual(Value, IgnoreReferences, IgnoreID);
  293.   if Result and (Value is TFontInfo) then begin
  294.     Result :=
  295.     {$IFNDEF RVDONOTUSEUNICODE}
  296.     (Unicode = TFontInfo(Value).Unicode) and
  297.     {$ENDIF}
  298.     {$IFNDEF RVDONOTUSESTYLETEMPLATES}
  299.     (ModifiedProperties = TFontInfo(Value).ModifiedProperties) and
  300.     (StyleTemplateID = TFontInfo(Value).StyleTemplateID) and
  301.     {$ENDIF}
  302.     (IgnoreReferences or (NextStyleNo = TFontInfo(Value).NextStyleNo));
  303.   end;
  304. end;
  305. {------------------------------------------------------------------------------}
  306. {$IFNDEF RVDONOTUSESTYLETEMPLATES}
  307. { Checks all properties listed in PossibleProps. If they are equal in Self and
  308.   Source, exclude them in Self.ModifiedProperties }
  309. procedure TFontInfo.ExcludeUnmodifiedProperties(
  310.   Source: TCustomRVFontInfo; PossibleProps: TRVFontInfoProperties);
  311.    {.............................................................}
  312.    procedure ChangeFontStyle(FontStyle: TFontStyle; TextPropId: TRVFontInfoProperty);
  313.    begin
  314.      if (TextPropId in PossibleProps) and
  315.         ((FontStyle in Style)=(FontStyle in Source.Style)) then
  316.        Exclude(FModifiedProperties, TextPropId);
  317.    end;
  318.    {.............................................................}
  319.    procedure ChangeFontStyleEx(FontStyle: TRVFontStyle; TextPropId: TRVFontInfoProperty);
  320.    begin
  321.      if (TextPropId in PossibleProps) and
  322.         ((FontStyle in StyleEx)=(FontStyle in Source.StyleEx)) then
  323.        Exclude(FModifiedProperties, TextPropId);
  324.    end;
  325.    {.............................................................}
  326.    procedure ChangeTextOption(TextOption: TRVTextOption; TextOptionId: TRVFontInfoProperty);
  327.    begin
  328.      if (TextOptionId in PossibleProps) and
  329.         ((TextOption in Options)=(TextOption in Source.Options)) then
  330.        Exclude(FModifiedProperties, TextOptionId);
  331.    end;
  332.    {.............................................................}
  333. begin
  334.   if (rvfiFontName in PossibleProps) and not (rvfiFontName in ModifiedProperties) and
  335.     (CompareText(FontName , Source.FontName)=0) then
  336.     Exclude(FModifiedProperties, rvfiFontName);
  337.   if (rvfiSize in PossibleProps) and (Size=Source.Size) then
  338.     Exclude(FModifiedProperties, rvfiSize);
  339.   {$IFDEF RICHVIEWCBDEF3}
  340.   if (rvfiCharset in PossibleProps) and (Charset=Source.Charset) then
  341.     Exclude(FModifiedProperties, rvfiCharset);
  342.   {$ENDIF}
  343.   ChangeFontStyle(fsBold,      rvfiBold);
  344.   ChangeFontStyle(fsItalic,    rvfiItalic);
  345.   ChangeFontStyle(fsUnderline, rvfiUnderline);
  346.   ChangeFontStyle(fsStrikeOut, rvfiStrikeOut);
  347.   ChangeFontStyleEx(rvfsOverline, rvfiOverline);
  348.   ChangeFontStyleEx(rvfsAllCaps, rvfiAllCaps);
  349.   if (rvfiVShift in PossibleProps) and (VShift = Source.VShift) then
  350.     Exclude(FModifiedProperties, rvfiVShift);
  351.   if (rvfiColor in PossibleProps) and (Color = Source.Color) then
  352.     Exclude(FModifiedProperties, rvfiColor);
  353.   if (rvfiBackColor in PossibleProps) and (BackColor = Source.BackColor) then
  354.     Exclude(FModifiedProperties, rvfiBackColor);
  355.   if (rvfiHoverColor in PossibleProps) and (HoverColor = Source.HoverColor) then
  356.     Exclude(FModifiedProperties, rvfiHoverColor);
  357.   if (rvfiHoverBackColor in PossibleProps) and (HoverBackColor = Source.HoverBackColor) then
  358.     Exclude(FModifiedProperties, rvfiHoverBackColor);
  359.   if (rvfiJump in PossibleProps) and (Jump = Source.Jump) then
  360.     Exclude(FModifiedProperties, rvfiJump);
  361.   if (rvfiJumpCursor in PossibleProps) and (JumpCursor = Source.JumpCursor) then
  362.     Exclude(FModifiedProperties, rvfiJumpCursor);
  363.   if (rvfiProtection in PossibleProps) and (Protection = Source.Protection) then
  364.     Exclude(FModifiedProperties, rvfiProtection);
  365.   if (rvfiCharScale in PossibleProps) and (CharScale = Source.CharScale) then
  366.     Exclude(FModifiedProperties, rvfiCharScale);
  367.   if (rvfiBiDiMode in PossibleProps) and (BiDiMode = Source.BiDiMode) then
  368.     Exclude(FModifiedProperties, rvfiBiDiMode);
  369.   if (rvfiCharSpacing in PossibleProps) and (CharSpacing = Source.CharSpacing) then
  370.     Exclude(FModifiedProperties, rvfiCharSpacing);
  371.   ChangeTextOption(rvteoHTMLCode, rvfiHTMLCode);
  372.   ChangeTextOption(rvteoRTFCode,  rvfiRTFCode);
  373.   {$IFDEF RVLANGUAGEPROPERTY}
  374.   if (rvfiLanguage in PossibleProps) and (Language=Source.Language) then
  375.     Exclude(FModifiedProperties, rvfiLanguage);
  376.   {$ENDIF}
  377. end;
  378. {$ENDIF}
  379. {------------------------------------------------------------------------------}
  380. { Is this item equal to Value?
  381.   Equality is determined by comparing all properties NOT included in IgnoreList. }
  382. function TFontInfo.IsEqual(Value: TCustomRVFontInfo;
  383.   IgnoreList: TRVFontInfoProperties): Boolean;
  384. begin
  385.   Result := inherited IsEqual(Value, IgnoreList);
  386.   if Result and (Value is TFontInfo) then begin
  387.     Result :=
  388.       {$IFNDEF RVDONOTUSEUNICODE}
  389.       ((rvfiUnicode     in IgnoreList) or (Unicode = TFontInfo(Value).Unicode    )) and
  390.       {$ENDIF}
  391.       ((rvfiNextStyleNo in IgnoreList) or (NextStyleNo = TFontInfo(Value).NextStyleNo))
  392.       {$IFNDEF RVDONOTUSESTYLETEMPLATES}
  393.       and
  394.       (StyleTemplateId=Value.StyleTemplateId) and
  395.       (ModifiedProperties=TFontInfo(Value).ModifiedProperties)
  396.       {$ENDIF}
  397.       ;
  398.   end;
  399. end;
  400. {------------------------------------------------------------------------------}
  401. { Workaround for incorrect headers in D2-D6 }
  402. type
  403. {$IFDEF RICHVIEWDEF7}
  404.   {$IFDEF RICHVIEWDEF9}
  405.   TGetCharacterPlacementVal = LongBool;
  406.   {$ELSE}
  407.   TGetCharacterPlacementVal = Integer;
  408.   {$ENDIF}
  409. {$ELSE}
  410.   TGetCharacterPlacementVal = LongBool;
  411. {$ENDIF}
  412. const
  413.   GETCHARACTERPLACEMENTFLAGS = GCP_DIACRITIC or GCP_GLYPHSHAPE or {GCP_USEKERNING or }GCP_REORDER;
  414. { Draws the string s onto the Canvas.
  415.   For Unicode text, s contains "raw Unicode".
  416.   Item occupies the rectangle Bounds(Left, Top, Width, Height), text is started
  417.   at the position (Left+SpaceBefore, Top). SpaceBefore can be positive in
  418.   justify-aligned paragraphs.
  419.   This item is RVStyle.TextStyles[ThisStyleNo].
  420.   DefBiDiMode is a bi-di mode of the paragraph containing this item.
  421.   Printing is True if this is printing/print preview.
  422.   PreviewCorrection is True if this is a print preview requiring correction.
  423.   ColorMode is used to adjust colors.
  424.   Notes:
  425.   - if (BiDiMode is unspecified) and Printing and PreviewCorrection, a special
  426.     procedure is used: it adjusts character positions to fit the required text
  427.     width (Width-SpaceBefore), see PrintText(..., True);
  428.   - if (BiDiMode is unspecified) and Printing and not PreviewCorrection and
  429.     (CharExtra<>0) a special procedure is used to apply CharExtra (because
  430.     some printers ignore direct setting), see PrintText(..., False)
  431.   - this procedure draws dots (#$B7/#$B0) in place of spaces/nonbreaking spaces,
  432.     if rvtsSpecialCharacters is in DrawState, see DrawDots.
  433. }
  434. procedure TFontInfo.Draw(const s: String; Canvas: TCanvas; ThisStyleNo: Integer;
  435.   SpaceBefore, Left, Top, Width, Height: Integer; RVStyle: TRVStyle;
  436.   DrawState: TRVTextDrawStates; Printing, PreviewCorrection: Boolean;
  437.   ColorMode: TRVColorMode; DefBiDiMode: TRVBiDiMode);
  438.   {......................................................}
  439.   function PrintText(Spacing: Integer; AutoCalcSpacing: Boolean): Boolean;
  440.   var  PDx: PRVIntegerArray;
  441.       Dummy: Integer;
  442.       ItemOptions: TRVItemOptions;
  443.       i, Len, w,w2,l: Integer;
  444.   begin
  445.     Result := True;
  446.     {$IFNDEF RVDONOTUSEUNICODE}
  447.     if Unicode then begin
  448.       ItemOptions := [rvioUnicode];
  449.       Len := Length(s) div 2;
  450.       end
  451.     else
  452.     {$ENDIF}
  453.     begin
  454.       ItemOptions := [];
  455.       Len := Length(s);
  456.     end;
  457.     if Len<2 then begin
  458.       Result := False;
  459.       exit;
  460.     end;
  461.     GetMem(PDx, (Len+1)*sizeof(Integer));
  462.     try
  463.       RVU_GetTextExtentExPoint(Canvas, s, Width*2, Dummy, PDx, ItemOptions);
  464.       for i := Len-1 downto 1 do
  465.         dec(PDx[i], PDx[i-1]);
  466.       if not AutoCalcSpacing then begin
  467.         for i := 0 to Len-1 do
  468.           inc(PDx[i], Spacing);
  469.         end
  470.       else begin
  471.         w := RVU_TextWidth(s, Canvas, ItemOptions);
  472.         if w=Width-SpaceBefore then begin
  473.           Result := False;
  474.           exit;
  475.         end;
  476.         w := Width-SpaceBefore-w;
  477.         l := Len;
  478.         for i := 0 to Len-1 do begin
  479.           if w=0 then
  480.             break;
  481.           if l=0 then
  482.             w2 := w
  483.           else
  484.             w2 := w div l;
  485.           inc(PDx[i], w2);
  486.           dec(w,w2);
  487.           dec(l);
  488.         end;
  489.       end;
  490.       {$IFDEF RVDONOTUSEUNICODE}
  491.       ExtTextOutA(Canvas.Handle, Left+SpaceBefore, Top, 0, nil, Pointer(s), Len, Pointer(PDx));
  492.       {$ELSE}
  493.         if not Unicode then
  494.           ExtTextOutA(Canvas.Handle, Left+SpaceBefore, Top, 0, nil, Pointer(s), Len, Pointer(PDx))
  495.         else
  496.           ExtTextOutW(Canvas.Handle, Left+SpaceBefore, Top, 0, nil, Pointer(s), Len, Pointer(PDx));
  497.       {$ENDIF}
  498.     finally
  499.       FreeMem(PDx);
  500.     end;
  501.   end;
  502.   {......................................................}
  503.   procedure DrawDots;
  504.   var res: TGCPResults;
  505.     i, Len, Spacing, X: Integer;
  506.     POrder,POrderRev: PRVUnsignedArray;
  507.     PDX: PRVIntegerArray;
  508.     ok: Boolean;
  509.     ItemOptions: TRVItemOptions;
  510.     wb7,wb0, spshift, nbspshift: Integer;
  511.     {. . . . . . . . . . . . . . . . . . . . . . . . . . .}
  512.     procedure DrawDot(var w, shift: Integer; sp, dot: Char);
  513.     var BrushColor: TColor;
  514.         BrushStyle: TBrushStyle;
  515.     begin
  516.       if w=0 then begin
  517.         w := Canvas.TextWidth(dot);
  518.         shift := Round((Canvas.TextWidth(sp)-w)/2);
  519.       end;
  520.       BrushColor := Canvas.Brush.Color;
  521.       BrushStyle := Canvas.Brush.Style;
  522.       Canvas.Brush.Style := bsClear;
  523.       Canvas.TextOut(Left+shift, Top, dot);
  524.       Canvas.Brush.Style := BrushStyle;
  525.       Canvas.Brush.Color := BrushColor;
  526.     end;
  527.     {. . . . . . . . . . . . . . . . . . . . . . . . . . .}
  528.   begin
  529.     if Printing then
  530.       exit;
  531.     Len := Length(s);
  532.     if Len=0 then
  533.       exit;
  534.     wb7 := 0;
  535.     wb0 := 0;
  536.     spshift := 0;
  537.     nbspshift := 0;
  538.     {$IFNDEF RVDONOTUSEUNICODE}
  539.     if Unicode then
  540.       Len := Len div 2;
  541.     if Unicode and not RVNT then
  542.       ok := False
  543.     else {$ENDIF} begin
  544.       Spacing := GetTextCharacterExtra(Canvas.Handle);
  545.       FillChar(res, sizeof(TGCPResults), 0);
  546.       res.lStructSize := sizeof(TGCPResults);
  547.       GetMem(POrder,    Len*sizeof(Cardinal));
  548.       GetMem(POrderRev, Len*sizeof(Cardinal));
  549.       GetMem(PDX,       Len*sizeof(Integer));
  550.       try
  551.         FillChar(POrder^, Len*sizeof(Cardinal), 0);
  552.         res.lpOrder := @(POrder[0]);
  553.         res.lpDx    := @(PDX[0]);
  554.         res.nGlyphs := Len;
  555.         {$IFNDEF RVDONOTUSEUNICODE}
  556.         if Unicode then
  557.           ok := GetCharacterPlacementW(Canvas.Handle, Pointer(s),
  558.             TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  559.             GETCHARACTERPLACEMENTFLAGS)<>0
  560.         else
  561.         {$ENDIF}
  562.           ok := GetCharacterPlacementA(Canvas.Handle, PChar(s),
  563.             TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  564.             GETCHARACTERPLACEMENTFLAGS)<>0;
  565.         if ok then begin
  566.           for i := 0 to Len-1 do
  567.             POrderRev[POrder[i]] := i;
  568.           inc(Left, SpaceBefore);
  569.           {$IFNDEF RVDONOTUSEUNICODE}
  570.           if not Unicode then
  571.           {$ENDIF}
  572.             for i := 0 to Len-1 do begin
  573.               case s[POrderRev[i]+1] of
  574.                 ' ':
  575.                   if rvscSpace in RVVisibleSpecialCharacters then
  576.                     DrawDot(wb7, spshift, ' ', #$B7);
  577.                 #$A0:
  578.                   if rvscNBSP in RVVisibleSpecialCharacters then
  579.                     DrawDot(wb0, nbspshift, #$A0, #$B0);
  580.               end;
  581.               inc(Left, PDX[i]+Spacing);
  582.             end
  583.           {$IFNDEF RVDONOTUSEUNICODE}
  584.           else
  585.             for i := 0 to Len-1 do begin
  586.               case PRVWordArray(PChar(s))[POrderRev[i]] of
  587.                 ord(' '):
  588.                   if rvscSpace in RVVisibleSpecialCharacters then
  589.                     DrawDot(wb7, spshift, ' ', #$B7);
  590.                 $A0:
  591.                   if rvscNBSP in RVVisibleSpecialCharacters then
  592.                     DrawDot(wb0, nbspshift, #$A0, #$B0);
  593.               end;
  594.               inc(Left, PDX[i]+Spacing);
  595.             end;
  596.           {$ENDIF}
  597.         end;
  598.       finally
  599.         FreeMem(POrder);
  600.         FreeMem(POrderRev);
  601.         FreeMem(PDX);
  602.       end;
  603.     end;
  604.     if ok then
  605.       exit;
  606.     GetMem(PDX, (Len+2)*sizeof(Integer));
  607.     try
  608.       {$IFNDEF RVDONOTUSEUNICODE}
  609.       if Unicode then
  610.         ItemOptions := [rvioUnicode]
  611.       else
  612.       {$ENDIF}
  613.         ItemOptions := [];
  614.       RVU_GetTextExtentExPoint(Canvas, s, Width*2, X, PDX, ItemOptions);
  615.       inc(Left, SpaceBefore);
  616.       {$IFNDEF RVDONOTUSEUNICODE}
  617.       if not Unicode then
  618.       {$ENDIF}
  619.         for i := 0 to Len-1 do begin
  620.           if s[i+1]=' ' then begin
  621.             X := Left;
  622.             if i>0 then
  623.               inc(X, PDX[i-1]);
  624.             Canvas.TextOut(X, Top, chr($b7));
  625.           end;
  626.         end
  627.       {$IFNDEF RVDONOTUSEUNICODE}
  628.       else
  629.         for i := 0 to Len-1 do begin
  630.           if PRVWordArray(PChar(s))[i]=ord(' ') then begin
  631.             X := Left;
  632.             if i>0 then
  633.               inc(X, PDX[i-1]);
  634.             Canvas.TextOut(X, Top, chr($b7));
  635.           end;
  636.         end;
  637.       {$ENDIF}
  638.     finally
  639.       FreeMem(PDX);
  640.     end;
  641.   end;
  642.   {......................................................}
  643. var
  644.     potm: POutlineTextMetric;
  645.     sz: Integer;
  646.     CharExtra: Integer;
  647.     TextDone: Boolean;
  648. begin
  649.   TextDone := False;
  650.   if BiDiMode<>rvbdUnspecified then
  651.     DefBiDiMode := BiDiMode;
  652.   if Printing and (DefBiDiMode=rvbdUnspecified) then begin
  653.     if (Canvas.Brush.Style<>bsClear) then begin
  654.       Canvas.Pen.Style := psClear;
  655.       Canvas.FillRect(Bounds(Left,Top,Width,Height));
  656.       Canvas.Brush.Style := bsClear;
  657.       Canvas.Pen.Style := psSolid;
  658.     end;
  659.     if not PreviewCorrection then begin
  660.       CharExtra := GetTextCharacterExtra(Canvas.Handle);
  661.       if CharExtra<>0 then begin
  662.          SetTextCharacterExtra(Canvas.Handle, 0);
  663.          TextDone := PrintText(CharExtra, False);
  664.          SetTextCharacterExtra(Canvas.Handle, CharExtra);
  665.       end;
  666.       end
  667.     else begin
  668.       TextDone := PrintText(0, True);
  669.     end;
  670.   end;
  671.   {$IFNDEF RVDONOTUSEJUSTIFY};
  672.   if not TextDone then begin
  673.     {$IFDEF RVDONOTUSEUNICODE}
  674.     Canvas.TextOut(Left+SpaceBefore, Top, s);
  675.     {$ELSE}
  676.       if not Unicode then
  677.         TextOutA(Canvas.Handle, Left+SpaceBefore, Top, PChar(s), Length(s))
  678.       else
  679.         TextOutW(Canvas.Handle, Left+SpaceBefore, Top, Pointer(s), Length(s) div 2);
  680.     {$ENDIF}
  681.     if (rvtsSpecialCharacters in DrawState) and
  682.        (RVVisibleSpecialCharacters * [rvscSpace, rvscNBSP]<>[]) then
  683.       DrawDots;
  684.   end;
  685.   if (SpaceBefore<>0) and not Printing then begin
  686.     if (rvtsSelected in DrawState) and (Length(s)=0) then
  687.       RVStyle.ApplyStyleColor(Canvas, ThisStyleNo, DrawState-[rvtsSelected], Printing, ColorMode);
  688.     if Canvas.Brush.Style<>bsClear then
  689.     Canvas.FillRect(Bounds(Left,Top,SpaceBefore,Height));
  690.   end;
  691.   {$ELSE}
  692.   if not TextDone then begin
  693.     {$IFDEF RVDONOTUSEUNICODE}
  694.     Canvas.TextOut(Left, Top, s);
  695.     {$ELSE}
  696.       if not Unicode then
  697.         TextOutA(Canvas.Handle, Left, Top, PChar(s), Length(s))
  698.       else
  699.         TextOutW(Canvas.Handle, Left, Top, Pointer(s), Length(s) div 2);
  700.     {$ENDIF}
  701.   end;
  702.   {$ENDIF}
  703.   Canvas.Brush.Style := bsClear;
  704.   potm := nil;
  705.   try
  706.     {$IFNDEF RVDONOTUSEJUSTIFY}
  707.     if (SpaceBefore<>0) and (fsUnderline in Canvas.Font.Style) then begin
  708.       sz := GetOutlineTextMetrics(Canvas.Handle,0,nil);
  709.       if sz>0 then begin
  710.         GetMem(potm, sz);
  711.         FillChar(potm^, sz, 0);
  712.         sz := GetOutlineTextMetrics(Canvas.Handle,sz,potm);
  713.         if sz>0 then begin
  714.           Canvas.Pen.Color := Canvas.Font.Color;
  715.           Canvas.Pen.Width := potm.otmsUnderscoreSize;
  716.           Canvas.Pen.Style := psInsideFrame;
  717.           Canvas.MoveTo(Left,Top-potm.otmsUnderscorePosition+potm.otmTextMetrics.tmAscent+potm.otmsUnderscoreSize div 2);
  718.           Canvas.LineTo(Left+SpaceBefore+1,Top-potm.otmsUnderscorePosition+potm.otmTextMetrics.tmAscent+potm.otmsUnderscoreSize div 2);
  719.           Canvas.Pen.Style := psSolid;
  720.         end;
  721.       end;
  722.     end;
  723.     {$ENDIF}
  724.     if rvfsOverline in StyleEx then begin
  725.       if potm=nil then begin
  726.         sz := GetOutlineTextMetrics(Canvas.Handle,0,nil);
  727.         if sz>0 then begin
  728.           GetMem(potm, sz);
  729.           FillChar(potm^, sz, 0);
  730.           sz := GetOutlineTextMetrics(Canvas.Handle,sz,potm);
  731.           if sz>0 then
  732.             Canvas.Pen.Width := potm.otmsUnderscoreSize
  733.           else
  734.             Canvas.Pen.Width := 1;
  735.           end
  736.         else
  737.           Canvas.Pen.Width := 1;
  738.       end;
  739.       Canvas.Pen.Color := Canvas.Font.Color;
  740.       Canvas.MoveTo(Left, Top);
  741.       Canvas.LineTo(Left+Width, Top);
  742.     end;
  743.   finally
  744.     if potm<>nil then
  745.       FreeMem(potm);
  746.   end;
  747. end;
  748. {------------------------------------------------------------------------------}
  749. { You do not see this :) }
  750. procedure TFontInfo.DrawVertical(const s: String; Canvas: TCanvas;
  751.   ThisStyleNo, SpaceBefore, Left, Top, Width, Height: Integer;
  752.   RVStyle: TRVStyle; DrawState: TRVTextDrawStates);
  753. begin
  754.   {$IFNDEF RVDONOTUSEJUSTIFY};
  755.   {$IFDEF RVDONOTUSEUNICODE}
  756.   Canvas.TextOut(Left, Top+SpaceBefore, s);
  757.   {$ELSE}
  758.     if not Unicode then
  759.       TextOutA(Canvas.Handle, Left, Top+SpaceBefore, PChar(s), Length(s))
  760.     else
  761.       TextOutW(Canvas.Handle, Left, Top+SpaceBefore, Pointer(s), Length(s) div 2);
  762.   {$ENDIF}
  763.   if (SpaceBefore<>0) then begin
  764.     if (rvtsSelected in DrawState) and (Length(s)=0) then
  765.       RVStyle.ApplyStyleColor(Canvas, ThisStyleNo, DrawState-[rvtsSelected], False, rvcmColor);
  766.     if Canvas.Brush.Style<>bsClear then
  767.     Canvas.FillRect(Bounds(Left, Top, Height,SpaceBefore));
  768.   end;
  769.   {$ELSE}
  770.   {$IFDEF RVDONOTUSEUNICODE}
  771.   Canvas.TextOut(Left, Top, s);
  772.   {$ELSE}
  773.     if not Unicode then
  774.       TextOutA(Canvas.Handle, Left, Top, PChar(s), Length(s))
  775.     else
  776.       TextOutW(Canvas.Handle, Left, Top, Pointer(s), Length(s) div 2);
  777.   {$ENDIF}
  778.   {$ENDIF}
  779.   Canvas.Brush.Style := bsClear;
  780.   if rvfsOverline in StyleEx then begin
  781.     Canvas.Pen.Color := Canvas.Font.Color;
  782.     Canvas.MoveTo(Left, Top);
  783.     Canvas.LineTo(Left, Top+Width);
  784.   end;
  785. end;
  786. {------------------------------------------------------------------------------}
  787. {$IFNDEF RVDONOTUSEINI}
  788. { Loads properties from the ini-file, from the section Section.
  789.   fs is a format string for keys, it is like 'Font%s1', 'Font%s2', etc. }
  790. procedure TFontInfo.LoadFromINI(ini: TRVIniFile; const Section, fs: String;
  791.   JumpByDefault: Boolean; DefJumpCursor: TCursor);
  792. begin
  793.   inherited;
  794.   NextStyleNo   := ini.ReadInteger(Section, Format(fs,[RVINI_NEXTSTYLENO]), -1);
  795.   {$IFNDEF RVDONOTUSEUNICODE}
  796.   Unicode       := iniReadBool(ini, Section, Format(fs,[RVINI_UNICODE]), False);
  797.   {$ENDIF}
  798. end;
  799. {------------------------------------------------------------------------------}
  800. { Saves properties to the ini-file, to the section Section.
  801.   fs is a format string for keys, it is like 'Font%s1', 'Font%s2', etc. }
  802. procedure TFontInfo.SaveToINI(ini: TRVIniFile; const Section, fs: String);
  803. begin
  804.   inherited;
  805.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_NEXTSTYLENO]),NextStyleNo,-1);
  806.   {$IFNDEF RVDONOTUSEUNICODE}
  807.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_UNICODE]), Unicode, False);
  808.   {$ENDIF}
  809. end;
  810. {$ENDIF}
  811. {================================== TFontInfos ================================}
  812. { Destructor }
  813. destructor TFontInfos.Destroy;
  814. begin
  815.   FInvalidItem.Free;
  816.   inherited;
  817. end;
  818. {------------------------------------------------------------------------------}
  819. { Adds new item to the end (perfotms typecasting) }
  820. function TFontInfos.Add: TFontInfo;
  821. begin
  822.   Result := TFontInfo(inherited Add);
  823. end;
  824. {------------------------------------------------------------------------------}
  825. { Deprecated method }
  826. function TFontInfos.AddFont(Name: TFontName; Size: Integer;
  827.                    Color,BackColor: TColor; Style:TFontStyles): TFontInfo;
  828. begin
  829.    Result := Add;
  830.    Result.FontName  := Name;
  831.    Result.Size      := Size;
  832.    Result.Color     := Color;
  833.    Result.BackColor := BackColor;
  834.    Result.Style     := Style;
  835. end;
  836. {------------------------------------------------------------------------------}
  837. {$IFDEF RICHVIEWCBDEF3}
  838. { Deprecated method }
  839. function TFontInfos.AddFontEx(Name: TFontName; Size: Integer;
  840.                    Color, BackColor: TColor; Style:TFontStyles;
  841.                    Charset: TFontCharset): TFontInfo;
  842. begin
  843.    Result := AddFont(Name, Size, Color, BackColor, Style);
  844.    Result.Charset := Charset;
  845. end;
  846. {$ENDIF}
  847. {------------------------------------------------------------------------------}
  848. { READ method for the property Items[].
  849.   Returns the Index-th item. If the index is out of range (0..Count-1), returns
  850.   InvalidItem instead. This method never generates exceptions. }
  851. function TFontInfos.GetItem(Index: Integer): TFontInfo;
  852. begin
  853.   if (Index<0) or (Index>=Count) then
  854.     Result := InvalidItem
  855.   else
  856.     Result := TFontInfo(inherited GetItem(Index));
  857. end;
  858. {------------------------------------------------------------------------------}
  859. { WRITE method for the property Items[]. }
  860. procedure TFontInfos.SetItem(Index: Integer; Value: TFontInfo);
  861. begin
  862.   inherited SetItem(Index, Value);
  863. end;
  864. {------------------------------------------------------------------------------}
  865. { READ method for the property InvalidItem.
  866.   It's returned when accessing Items[] with invalid index.
  867.   By default it has all properties of Items[0], but white on red. }
  868. function TFontInfos.GetInvalidItem: TFontInfo;
  869. begin
  870.   if FInvalidItem=nil then begin
  871.     FInvalidItem := (FOwner as TRVStyle).GetTextStyleClass.Create(nil);
  872.     if Count>0 then
  873.       FInvalidItem.Assign(Items[0]);
  874.     FInvalidItem.BackColor := clRed;
  875.     FInvalidItem.Color := clWhite;
  876.   end;
  877.   Result := FInvalidItem;
  878. end;
  879. {------------------------------------------------------------------------------}
  880. { WRITE method for the property InvalidItem. }
  881. procedure TFontInfos.SetInvalidItem(const Value: TFontInfo);
  882. begin
  883.   if InvalidItem<>Value then
  884.     InvalidItem.Assign(Value);
  885. end;
  886. {------------------------------------------------------------------------------}
  887. {$IFNDEF RVDONOTUSEINI}
  888. { Loads itself from the ini-file, from the section Section. }
  889. procedure TFontInfos.LoadFromINI(ini: TRVIniFile; const Section: String;
  890.   DefJumpCursor: TCursor);
  891. var i, cnt: Integer;
  892. begin
  893.   // for compatibility with old versions, default count of styles is
  894.   // LAST_DEFAULT_STYLE_NO+1
  895.   cnt := ini.ReadInteger(Section, RVINI_TEXTSTYLECOUNT,   LAST_DEFAULT_STYLE_NO+1);
  896.   Clear;
  897.   for i := 0 to cnt-1 do begin
  898.     Add;
  899.     Items[i].LoadFromINI(ini, Section, RVINI_TEXTSTYLEPREFIX+IntToStr(i),
  900.       i in [rvsJump1, rvsJump2], DefJumpCursor);
  901.   end;
  902. end;
  903. {------------------------------------------------------------------------------}
  904. { Saves itself to the ini-file, to the section Section. }
  905. procedure TFontInfos.SaveToINI(ini: TRVIniFile; const Section: String);
  906. var i: Integer;
  907. begin
  908.   ini.WriteInteger(Section, RVINI_TEXTSTYLECOUNT, Count);
  909.   for i:=0 to Count-1 do
  910.     Items[i].SaveToINI(ini, Section, RVINI_TEXTSTYLEPREFIX+IntToStr(i));
  911. end;
  912. {$ENDIF}
  913. {------------------------------------------------------------------------------}
  914. { Returns the index of the style having all properties of Font.
  915.   Starts searching from Items[BaseStyle], then searches in other Items.
  916.   If not found, returns -1. }
  917. function TFontInfos.FindStyleWithFont(BaseStyle: Integer; Font: TFont): Integer;
  918. var i: Integer;
  919.     {........................................}
  920.     function Matched(fi: TFontInfo): Boolean;
  921.     begin
  922.       Result := (fi.Size=Font.Size) and
  923.                 (fi.Style=Font.Style) and
  924.                 (fi.FontName=Font.Name) and
  925.                 {$IFDEF RICHVIEWCBDEF3}
  926.                 (fi.Charset=Font.Charset) and
  927.                 {$ENDIF}
  928.                 (fi.Color=Font.Color);
  929.     end;
  930.     {........................................}
  931. begin
  932.   if Matched(Items[BaseStyle]) then begin
  933.     Result := BaseStyle;
  934.     exit;
  935.   end;
  936.   for i := 0 to Count-1 do
  937.     if (i<>BaseStyle) and Matched(Items[i]) and
  938.        Items[BaseStyle].IsEqual(Items[i], [rvfiFontName, rvfiSize, rvfiCharset,
  939.                                            rvfiBold, rvfiItalic, rvfiUnderline,
  940.                                            rvfiStrikeout, rvfiColor]) then begin
  941.       Result := i;
  942.       exit;
  943.     end;
  944.   Result := -1;
  945. end;
  946. {------------------------------------------------------------------------------}
  947. { Returns the index of the style having the specified font Size.
  948.   Starts searching from Items[BaseStyle], then searches in other Items.
  949.   If not found, returns -1. }
  950. function TFontInfos.FindStyleWithFontSize(BaseStyle, Size: Integer): Integer;
  951. var i: Integer;
  952. begin
  953.   if Items[BaseStyle].Size = Size then begin
  954.     Result := BaseStyle;
  955.     exit;
  956.   end;
  957.   for i := 0 to Count-1 do
  958.     if (i<>BaseStyle) and (Items[i].Size=Size) and
  959.        Items[BaseStyle].IsEqual(Items[i], [rvfiSize]) then begin
  960.       Result := i;
  961.       exit;
  962.     end;
  963.   Result := -1;
  964. end;
  965. {------------------------------------------------------------------------------}
  966. { Returns the index of the style having the specified values of Color and BackColor.
  967.   Starts searching from Items[BaseStyle], then searches in other Items.
  968.   If not found, returns -1. }
  969. function TFontInfos.FindStyleWithColor(BaseStyle: Integer; Color,
  970.   BackColor: TColor): Integer;
  971. var i: Integer;
  972. begin
  973.   if (Items[BaseStyle].Color     = Color) and
  974.      (Items[BaseStyle].BackColor = BackColor) then begin
  975.     Result := BaseStyle;
  976.     exit;
  977.   end;
  978.   for i := 0 to Count-1 do
  979.     if (i<>BaseStyle) and
  980.        (Items[i].Color     = Color) and
  981.        (Items[i].BackColor = BackColor) and
  982.        Items[BaseStyle].IsEqual(Items[i], [rvfiColor, rvfiBackColor]) then begin
  983.       Result := i;
  984.       exit;
  985.     end;
  986.   Result := -1;
  987. end;
  988. {------------------------------------------------------------------------------}
  989. { Returns the index of the style having the specified value of FontName.
  990.   Starts searching from Items[BaseStyle], then searches in other Items.
  991.   If not found, returns -1. }
  992. function TFontInfos.FindStyleWithFontName(BaseStyle: Integer;
  993.   const FontName: TFontName): Integer;
  994. var i: Integer;
  995. begin
  996.   if Items[BaseStyle].FontName = FontName then begin
  997.     Result := BaseStyle;
  998.     exit;
  999.   end;
  1000.   for i := 0 to Count-1 do
  1001.     if (i<>BaseStyle) and (Items[i].FontName=FontName) and
  1002.        Items[BaseStyle].IsEqual(Items[i], [rvfiFontName]) then begin
  1003.       Result := i;
  1004.       exit;
  1005.     end;
  1006.   Result := -1;
  1007. end;
  1008. {------------------------------------------------------------------------------}
  1009. { The most universal method for text style searching.
  1010.   Returns the index of the style having all properties of Style listed in Mask.
  1011.   Starts searching from Items[BaseStyle], then searches in other Items.
  1012.   If not found, returns -1. }
  1013. function TFontInfos.FindSuchStyle(BaseStyle: Integer; Style: TFontInfo;
  1014.   Mask: TRVFontInfoProperties): Integer;
  1015. var i: Integer;
  1016. begin
  1017.   Mask := RVAllFontInfoProperties - Mask;
  1018.   if Style.IsEqual(Items[BaseStyle], Mask) then begin
  1019.     Result := BaseStyle;
  1020.     exit;
  1021.   end;
  1022.   for i := 0 to Count-1 do
  1023.     if (i<>BaseStyle) and Style.IsEqual(Items[i], Mask) then begin
  1024.       Result := i;
  1025.       exit;
  1026.     end;
  1027.   Result := -1;
  1028. end;
  1029. {------------------------------------------------------------------------------}
  1030. {$IFDEF RICHVIEWCBDEF3}
  1031. { Returns the index of the style having the specified value of Charset.
  1032.   Starts searching from Items[BaseStyle], then searches in other Items.
  1033.   If not found, returns -1. }
  1034. function TFontInfos.FindStyleWithCharset(BaseStyle: Integer; Charset: TFontCharset): Integer;
  1035. var i: Integer;
  1036. begin
  1037.   if (Items[BaseStyle].Charset=Charset)
  1038.      {$IFNDEF RVDONOTUSEUNICODE}
  1039.      and not Items[BaseStyle].Unicode
  1040.      {$ENDIF}
  1041.      then begin
  1042.     Result := BaseStyle;
  1043.     exit;
  1044.   end;
  1045.   for i := 0 to Count-1 do
  1046.     if (i<>BaseStyle) and (Items[i].Charset=Charset) and
  1047.        {$IFNDEF RVDONOTUSEUNICODE}
  1048.        not Items[i].Unicode and
  1049.        {$ENDIF}
  1050.        Items[BaseStyle].IsEqual(Items[i], [rvfiCharset, rvfiUnicode]) then begin
  1051.       Result := i;
  1052.       exit;
  1053.     end;
  1054.   Result := -1;
  1055. end;
  1056. {$ENDIF}
  1057. {------------------------------------------------------------------------------}
  1058. { Returns the index of the style having the specified font styles.
  1059.   Mask defines which font styles to check. Value defines the required values
  1060.   of them.
  1061.   Starts searching from Items[BaseStyle], then searches in other Items.
  1062.   If not found, returns -1. }
  1063. function TFontInfos.FindStyleWithFontStyle(BaseStyle: Integer; Value,
  1064.   Mask: TFontStyles): Integer;
  1065. var i: Integer;
  1066.     IgnoreList: TRVFontInfoProperties;
  1067.     {........................................}
  1068.     function Matched(fi: TFontInfo): Boolean;
  1069.     var i: TFontStyle;
  1070.     begin
  1071.       for i := Low(TFontStyle) to High(TFontStyle) do
  1072.         if (i in Mask) and ((i in fi.Style)<>(i in Value)) then begin
  1073.           Result := False;
  1074.           exit;
  1075.         end;
  1076.       Result := True;
  1077.     end;
  1078.     {........................................}
  1079. begin
  1080.   if Matched(Items[BaseStyle]) then begin
  1081.     Result := BaseStyle;
  1082.     exit;
  1083.   end;
  1084.   IgnoreList := [];
  1085.   if fsBold in Mask then
  1086.     Include(IgnoreList, rvfiBold);
  1087.   if fsItalic in Mask then
  1088.     Include(IgnoreList, rvfiItalic);
  1089.   if fsUnderline in Mask then
  1090.     Include(IgnoreList, rvfiUnderline);
  1091.   if fsStrikeout in Mask then
  1092.     Include(IgnoreList, rvfiStrikeout);
  1093.   for i := 0 to Count-1 do
  1094.     if (i<>BaseStyle) and Matched(Items[i]) and
  1095.        Items[BaseStyle].IsEqual(Items[i], IgnoreList) then begin
  1096.       Result := i;
  1097.       exit;
  1098.     end;
  1099.   Result := -1;
  1100. end;
  1101. {================================== TRVRect ===================================}
  1102. { Assigns TRVRect (Source) to TRVRect (Self). }
  1103. procedure TRVRect.Assign(Source: TPersistent);
  1104. begin
  1105.   if Source is TRVRect then begin
  1106.     Left   := TRVRect(Source).Left;
  1107.     Right  := TRVRect(Source).Right;
  1108.     Top    := TRVRect(Source).Top;
  1109.     Bottom := TRVRect(Source).Bottom;
  1110.     end
  1111.   else
  1112.     inherited Assign(Source);
  1113. end;
  1114. {------------------------------------------------------------------------------}
  1115. { Assigns properties from value. Val* specify properties to assign. }
  1116. procedure TRVRect.AssignValidProperties(Source: TRVRect;
  1117.   ValL, ValT, ValR, ValB: Boolean);
  1118. begin
  1119.   if ValL then
  1120.     Left := Source.Left;
  1121.   if ValT then
  1122.     Top := Source.Top;
  1123.   if ValR then
  1124.     Right := Source.Right;
  1125.   if ValB then
  1126.     Bottom := Source.Bottom;
  1127. end;
  1128. {------------------------------------------------------------------------------}
  1129. { Assigns Value to all sides. }
  1130. procedure TRVRect.SetAll(Value: Integer);
  1131. begin
  1132.   Left   := Value;
  1133.   Top    := Value;
  1134.   Right  := Value;
  1135.   Bottom := Value;
  1136. end;
  1137. {------------------------------------------------------------------------------}
  1138. { Assigns itself to TRect. }
  1139. procedure TRVRect.AssignToRect(var Rect: TRect);
  1140. begin
  1141.   Rect.Left   := Left;
  1142.   Rect.Top    := Top;
  1143.   Rect.Right  := Right;
  1144.   Rect.Bottom := Bottom;
  1145. end;
  1146. {------------------------------------------------------------------------------}
  1147. { Assigns itself to TRect. Only sides having greater values are assigned. }
  1148. procedure TRVRect.AssignToRectIfGreater(var Rect: TRect);
  1149. begin
  1150.   if Left>Rect.Left then
  1151.     Rect.Left   := Left;
  1152.   if Top>Rect.Top then
  1153.     Rect.Top    := Top;
  1154.   if Right>Rect.Right then
  1155.     Rect.Right  := Right;
  1156.   if Bottom>Rect.Bottom then
  1157.     Rect.Bottom := Bottom;
  1158. end;
  1159. {------------------------------------------------------------------------------}
  1160. { Grows TRect by adding/subtracting sides. }
  1161. procedure TRVRect.InflateRect(var Rect: TRect);
  1162. begin
  1163.   dec(Rect.Left,   Left);
  1164.   dec(Rect.Top,    Top);
  1165.   inc(Rect.Right,  Right);
  1166.   inc(Rect.Bottom, Bottom);
  1167. end;
  1168. {------------------------------------------------------------------------------}
  1169. { Grows TRect by adding/subtracting sides adjusted to the resolution specified
  1170.   in sad. }
  1171. procedure TRVRect.InflateRectSaD(var Rect: TRect;
  1172.   const sad: TRVScreenAndDevice);
  1173. begin
  1174.   dec(Rect.Left,   RV_XToDevice(Left,   sad));
  1175.   dec(Rect.Top,    RV_YToDevice(Top,    sad));
  1176.   inc(Rect.Right,  RV_XToDevice(Right,  sad));
  1177.   inc(Rect.Bottom, RV_YToDevice(Bottom, sad));
  1178. end;
  1179. {------------------------------------------------------------------------------}
  1180. { Is this rectangle equal to Value? }
  1181. function TRVRect.IsEqual(Value: TRVRect): Boolean;
  1182. begin
  1183.   Result := (Left=Value.Left) and (Right=Value.Right) and
  1184.             (Top =Value.Top)  and (Bottom=Value.Bottom);
  1185. end;
  1186. {------------------------------------------------------------------------------}
  1187. { Are the specified sides equal to the sides of Value?
  1188.   Ign* specify sides to ignore when comparing. }
  1189. function TRVRect.IsEqualEx(Value: TRVRect; IgnL, IgnT, IgnR,
  1190.   IgnB: Boolean): Boolean;
  1191. begin
  1192.   Result := (IgnL or (Left=Value.Left)) and
  1193.             (IgnR or (Right=Value.Right)) and
  1194.             (IgnT or (Top =Value.Top)) and
  1195.             (ignB or (Bottom=Value.Bottom));
  1196. end;
  1197. {------------------------------------------------------------------------------}
  1198. { Returns the value of similarity between this rectangle and Value.
  1199.   The larger return value - the larger similarity.
  1200.   Result is proportional to Weight. }
  1201. function TRVRect.SimilarityValue(Value: TRVRect; Weight: Integer): Integer;
  1202. begin
  1203.   Result := RV_CompareInts(Left,   Value.Left,   Weight)+
  1204.             RV_CompareInts(Top,    Value.Top,    Weight)+
  1205.             RV_CompareInts(Right,  Value.Right,  Weight)+
  1206.             RV_CompareInts(Bottom, Value.Bottom, Weight);
  1207. end;
  1208. {------------------------------------------------------------------------------}
  1209. {$IFNDEF RVDONOTUSEINI}
  1210. { Loads itself from the ini-file, from the section Section.
  1211.   fs is a format string for ini keys. }
  1212. procedure TRVRect.LoadFromINI(ini: TRVIniFile; const Section, fs: String);
  1213. begin
  1214.   Left    := ini.ReadInteger(Section, Format(fs,[RVINI_LEFT]),   0);
  1215.   Right   := ini.ReadInteger(Section, Format(fs,[RVINI_RIGHT]),  0);
  1216.   Top     := ini.ReadInteger(Section, Format(fs,[RVINI_TOP]),    0);
  1217.   Bottom  := ini.ReadInteger(Section, Format(fs,[RVINI_BOTTOM]), 0);
  1218. end;
  1219. {------------------------------------------------------------------------------}
  1220. { Stores itself in the ini-file, in the section Section.
  1221.   fs is a format string for ini keys. }
  1222. procedure TRVRect.SaveToINI(ini: TRVIniFile; const Section, fs: String);
  1223. begin
  1224.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_LEFT]),   Left,   0);
  1225.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_RIGHT]),  Right,  0);
  1226.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_TOP]),    Top,    0);
  1227.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_BOTTOM]), Bottom, 0);
  1228. end;
  1229. {$ENDIF}
  1230. {================================ TRVBooleanRect ==============================}
  1231. { Constructor, assigns DefValue to all sides. }
  1232. constructor TRVBooleanRect.Create(DefValue: Boolean);
  1233. begin
  1234.   inherited Create;
  1235.   SetAll(DefValue);
  1236. end;
  1237. {------------------------------------------------------------------------------}
  1238. { Assigns Value to all sides. }
  1239. procedure TRVBooleanRect.SetAll(Value: Boolean);
  1240. begin
  1241.   Left   := Value;
  1242.   Top    := Value;
  1243.   Right  := Value;
  1244.   Bottom := Value;
  1245. end;
  1246. {------------------------------------------------------------------------------}
  1247. { Assigns parameters to sides. }
  1248. procedure TRVBooleanRect.SetValues(ALeft, ATop, ARight, ABottom: Boolean);
  1249. begin
  1250.   Left   := ALeft;
  1251.   Top    := ATop;
  1252.   Right  := ARight;
  1253.   Bottom := ABottom;
  1254. end;
  1255. {------------------------------------------------------------------------------}
  1256. { Assigns TRVBooleanRect (Source) to TRVBooleanRect (Self). }
  1257. procedure TRVBooleanRect.Assign(Source: TPersistent);
  1258. begin
  1259.   if Source is TRVBooleanRect then begin
  1260.     Left   := TRVBooleanRect(Source).Left;
  1261.     Right  := TRVBooleanRect(Source).Right;
  1262.     Top    := TRVBooleanRect(Source).Top;
  1263.     Bottom := TRVBooleanRect(Source).Bottom;
  1264.     end
  1265.   else
  1266.     inherited Assign(Source);
  1267. end;
  1268. {------------------------------------------------------------------------------}
  1269. { Assigns values from Source. Val* specify properties to assign. }
  1270. procedure TRVBooleanRect.AssignValidProperties(Source: TRVBooleanRect;
  1271.   ValL, ValT, ValR, ValB: Boolean);
  1272. begin
  1273.   if ValL then
  1274.     Left := Source.Left;
  1275.   if ValT then
  1276.     Top := Source.Top;
  1277.   if ValR then
  1278.     Right := Source.Right;
  1279.   if ValB then
  1280.     Bottom := Source.Bottom;
  1281. end;
  1282. {------------------------------------------------------------------------------}
  1283. { Is this boolean rectangle equal to Value? }
  1284. function TRVBooleanRect.IsEqual(Value: TRVBooleanRect): Boolean;
  1285. begin
  1286.   Result := (Left=Value.Left) and (Right=Value.Right) and
  1287.             (Top =Value.Top)  and (Bottom=Value.Bottom);
  1288. end;
  1289. {------------------------------------------------------------------------------}
  1290. { Are the sides equal to the parameters? }
  1291. function TRVBooleanRect.IsEqual2(ALeft, ATop, ARight, ABottom: Boolean): Boolean;
  1292. begin
  1293.   Result := (Left=ALeft) and (Right=ARight) and
  1294.             (Top =ATop)  and (Bottom=ABottom);
  1295. end;
  1296. {------------------------------------------------------------------------------}
  1297. { All all the sides equal to the Value? }
  1298. function TRVBooleanRect.IsAllEqual(Value: Boolean): Boolean;
  1299. begin
  1300.   Result := (Left=Value) and (Right=Value) and
  1301.             (Top =Value) and (Bottom=Value);
  1302. end;
  1303. {------------------------------------------------------------------------------}
  1304. { Are the specified sides equal to the sides of Value?
  1305.   Ign* specify sides to ignore when comparing. }
  1306. function TRVBooleanRect.IsEqualEx(Value: TRVBooleanRect; IgnL, IgnT, IgnR,
  1307.   IgnB: Boolean): Boolean;
  1308. begin
  1309.   Result := (IgnL or (Left=Value.Left)) and
  1310.             (IgnR or (Right=Value.Right)) and
  1311.             (IgnT or (Top =Value.Top)) and
  1312.             (ignB or (Bottom=Value.Bottom));
  1313. end;
  1314. {------------------------------------------------------------------------------}
  1315. {$IFNDEF RVDONOTUSEINI}
  1316. { Loads itself from the ini-file, from the section Section.
  1317.   fs is a format string for ini keys. }
  1318. procedure TRVBooleanRect.LoadFromINI(ini: TRVIniFile; const Section,
  1319.   fs: String);
  1320. begin
  1321.   Left    := IniReadBool(ini, Section, Format(fs,[RVINI_LEFT]),   True);
  1322.   Right   := IniReadBool(ini, Section, Format(fs,[RVINI_RIGHT]),  True);
  1323.   Top     := IniReadBool(ini, Section, Format(fs,[RVINI_TOP]),    True);
  1324.   Bottom  := IniReadBool(ini, Section, Format(fs,[RVINI_BOTTOM]), True);
  1325. end;
  1326. {------------------------------------------------------------------------------}
  1327. { Stores itself in the ini-file, in the section Section.
  1328.   fs is a format string for ini keys. }
  1329. procedure TRVBooleanRect.SaveToINI(ini: TRVIniFile; const Section,
  1330.   fs: String);
  1331. begin
  1332.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_LEFT]),   Left,   True);
  1333.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_RIGHT]),  Right,  True);
  1334.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_TOP]),    Top,    True);
  1335.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_BOTTOM]), Bottom, True);
  1336. end;
  1337. {$ENDIF}
  1338. {============================= TRVBorder ======================================}
  1339. { Constructor. Sets border style to "none", color to clWindowText, width to 1. }
  1340. constructor TRVBorder.Create;
  1341. begin
  1342.   inherited Create;
  1343.   FBorderOffsets := TRVRect.Create;
  1344.   FVisibleBorders := TRVBooleanRect.Create(True);
  1345.   Style := rvbNone;
  1346.   Color := clWindowText;
  1347.   Width := 1;
  1348.   InternalWidth := 1;
  1349. end;
  1350. {------------------------------------------------------------------------------}
  1351. { Destructor }
  1352. destructor TRVBorder.Destroy;
  1353. begin
  1354.   FBorderOffsets.Free;
  1355.   FVisibleBorders.Free;
  1356.   inherited Destroy;
  1357. end;
  1358. {------------------------------------------------------------------------------}
  1359. { Assigns TRVBorder (Source) to TRVBorder (Self). }
  1360. procedure TRVBorder.Assign(Source: TPersistent);
  1361. begin
  1362.   if Source is TRVBorder then begin
  1363.     Width := TRVBorder(Source).Width;
  1364.     Style := TRVBorder(Source).Style;
  1365.     Color := TRVBorder(Source).Color;
  1366.     InternalWidth := TRVBorder(Source).InternalWidth;
  1367.     VisibleBorders.Assign(TRVBorder(Source).VisibleBorders);
  1368.     BorderOffsets.Assign(TRVBorder(Source).BorderOffsets);
  1369.     end
  1370.   else
  1371.     inherited Assign(Source);
  1372. end;
  1373. {------------------------------------------------------------------------------}
  1374. { WRITE method for BorderOffsets property. }
  1375. procedure TRVBorder.SetBorderOffsets(const Value: TRVRect);
  1376. begin
  1377.   FBorderOffsets.Assign(Value);
  1378. end;
  1379. {------------------------------------------------------------------------------}
  1380. { WRITE method for VisibleBorders property. }
  1381. procedure TRVBorder.SetVisibleBorders(const Value: TRVBooleanRect);
  1382. begin
  1383.   FVisibleBorders.Assign(Value);
  1384. end;
  1385. {------------------------------------------------------------------------------}
  1386. { Draws border on Canvas at the rectangle Rect. Widths and offsets are adjusted
  1387.   according to the device resolution specified in sad.
  1388.   Colors are corrected according to ColorMode. }
  1389. procedure TRVBorder.DrawSaD(Rect: TRect; Canvas: TCanvas;
  1390.   const sad: TRVScreenAndDevice; ColorMode: TRVColorMode);
  1391. begin
  1392.   if Style = rvbNone then exit;
  1393.   ScaleRect(Rect, sad); // does nothing
  1394.   BorderOffsets.InflateRectSaD(Rect,sad);
  1395.   DoDraw(Rect, Canvas, RV_YToDevice(Width, sad),
  1396.     RV_YToDevice(InternalWidth, sad), RV_YToDevice(1, sad), ColorMode);
  1397. end;
  1398. {------------------------------------------------------------------------------}
  1399. { Draws border on Canvas at the rectangle Rect. }
  1400. procedure TRVBorder.Draw(Rect: TRect; Canvas: TCanvas);
  1401. begin
  1402.   if Style = rvbNone then exit;
  1403.   BorderOffsets.InflateRect(Rect);
  1404.   DoDraw(Rect, Canvas, Width, InternalWidth, 1, rvcmColor);
  1405. end;
  1406. {------------------------------------------------------------------------------}
  1407. { Draws border on Canvas at the rectangle Rect. This method is called by Draw
  1408.   and DrawSaD.
  1409.   Colors are corrected according to ColorMode. }
  1410. procedure TRVBorder.DoDraw(Rect: TRect; Canvas: TCanvas;
  1411.   Width, InternalWidth, OnePixelWidth: Integer; ColorMode: TRVColorMode);
  1412. var Count: Integer;
  1413. begin
  1414.   with Canvas.Pen do begin
  1415.     Width := Self.Width;
  1416.     Style := psInsideFrame;
  1417.     case ColorMode of
  1418.       rvcmColor:
  1419.         Color := Self.Color;
  1420.       rvcmPrinterColor:
  1421.         Color := RV_GetPrnColor(Self.Color);
  1422.       rvcmGrayScale:
  1423.         Color := RV_GetGray(RV_GetPrnColor(Self.Color));
  1424.       rvcmBlackAndWhite,  rvcmBlackOnWhite:
  1425.         Color := clBlack;
  1426.     end;
  1427.   end;
  1428.   case Style of
  1429.     rvbSingle:
  1430.       Count := 1;
  1431.     rvbDouble, rvbThickInside, rvbThickOutside:
  1432.       Count := 2;
  1433.     rvbTriple:
  1434.       Count := 3;
  1435.     else
  1436.       Count := 1;
  1437.   end;
  1438.   while Count>0 do begin
  1439.     if ((Count=1) and (Style=rvbThickOutside)) or
  1440.        ((Count=2) and (Style=rvbThickInside)) then
  1441.       Canvas.Pen.Width := Width*2
  1442.     else
  1443.       Canvas.Pen.Width := Width;
  1444.     if VisibleBorders.Top then begin
  1445.       Canvas.MoveTo(Rect.Left,Rect.Top);
  1446.       Canvas.LineTo(Rect.Right,Rect.Top);
  1447.       Canvas.MoveTo(Rect.Right,Rect.Top);
  1448.       Canvas.LineTo(Rect.Left,Rect.Top);
  1449.     end;
  1450.     if VisibleBorders.Right then begin
  1451.       Canvas.MoveTo(Rect.Right,Rect.Top);
  1452.       Canvas.LineTo(Rect.Right,Rect.Bottom);
  1453.       Canvas.MoveTo(Rect.Right,Rect.Bottom);
  1454.       Canvas.LineTo(Rect.Right,Rect.Top);
  1455.     end;
  1456.     if VisibleBorders.Bottom then begin
  1457.       Canvas.MoveTo(Rect.Right,Rect.Bottom);
  1458.       Canvas.LineTo(Rect.Left,Rect.Bottom);
  1459.       Canvas.MoveTo(Rect.Left,Rect.Bottom);
  1460.       Canvas.LineTo(Rect.Right,Rect.Bottom);
  1461.     end;
  1462.     if VisibleBorders.Left then begin
  1463.       Canvas.MoveTo(Rect.Left,Rect.Bottom);
  1464.       Canvas.LineTo(Rect.Left,Rect.Top);
  1465.       Canvas.MoveTo(Rect.Left,Rect.Top);
  1466.       Canvas.LineTo(Rect.Left,Rect.Bottom);
  1467.     end;
  1468.     InflateRect(Rect, InternalWidth+OnePixelWidth, InternalWidth+OnePixelWidth);
  1469.     if (Width=1) and (Style=rvbThickOutside) then begin
  1470.       inc(Rect.Bottom,OnePixelWidth);
  1471.       inc(Rect.Right,OnePixelWidth);
  1472.     end;
  1473.     if (Width=1) and (Style = rvbThickInside) then begin
  1474.       dec(Rect.Top,OnePixelWidth);
  1475.       dec(Rect.Left,OnePixelWidth);
  1476.     end;
  1477.     dec(Count);
  1478.   end;
  1479.   Canvas.Pen.Width := 1;
  1480. end;
  1481. {------------------------------------------------------------------------------}
  1482. { Is this border equal to Value? }
  1483. function TRVBorder.IsEqual(Value: TRVBorder): Boolean;
  1484. begin
  1485.   Result := (Style = Value.Style) and
  1486.             (Color = Value.Color) and
  1487.             (Width = Value.Width) and
  1488.             (InternalWidth = Value.InternalWidth) and
  1489.             BorderOffsets.IsEqual(Value.BorderOffsets) and
  1490.             VisibleBorders.IsEqual(Value.VisibleBorders);
  1491. end;
  1492. {------------------------------------------------------------------------------}
  1493. { Are the specified properties of this border equal to the properties of Value?
  1494.   IgnoreList specifies properties that must be ignored when comparing. }
  1495. function TRVBorder.IsEqual_Para(Value: TRVBorder; IgnoreList: TRVParaInfoProperties): Boolean;
  1496. begin
  1497.   Result := ((rvpiBorder_Style in IgnoreList) or (Style = Value.Style)) and
  1498.             ((rvpiBorder_Color in IgnoreList) or (Color = Value.Color)) and
  1499.             ((rvpiBorder_Width in IgnoreList) or (Width = Value.Width)) and
  1500.             ((rvpiBorder_InternalWidth in IgnoreList) or (InternalWidth = Value.InternalWidth)) and
  1501.             BorderOffsets.IsEqualEx(Value.BorderOffsets,
  1502.               rvpiBorder_BO_Left in IgnoreList,
  1503.               rvpiBorder_BO_Top in IgnoreList,
  1504.               rvpiBorder_BO_Right in IgnoreList,
  1505.               rvpiBorder_BO_Bottom in IgnoreList) and
  1506.             VisibleBorders.IsEqualEx(Value.VisibleBorders,
  1507.               rvpiBorder_Vis_Left in IgnoreList,
  1508.               rvpiBorder_Vis_Top in IgnoreList,
  1509.               rvpiBorder_Vis_Right in IgnoreList,
  1510.               rvpiBorder_Vis_Bottom in IgnoreList);
  1511. end;
  1512. {------------------------------------------------------------------------------}
  1513. { Assign properties from Source, listed in ValidProperties. }
  1514. procedure TRVBorder.AssignValidProperties(Source: TRVBorder;
  1515.   ValidProperties: TRVParaInfoProperties1);
  1516. begin
  1517.   if (rvpiBorder_Style in ValidProperties) then
  1518.     Style := Source.Style;
  1519.   if (rvpiBorder_Color in ValidProperties) then
  1520.     Color := Source.Color;
  1521.   if (rvpiBorder_Width in ValidProperties) then
  1522.     Width := Source.Width;
  1523.   if (rvpiBorder_InternalWidth in ValidProperties) then
  1524.     InternalWidth := Source.InternalWidth;
  1525.   BorderOffsets.AssignValidProperties(Source.BorderOffsets,
  1526.     rvpiBorder_BO_Left   in ValidProperties,
  1527.     rvpiBorder_BO_Top    in ValidProperties,
  1528.     rvpiBorder_BO_Right  in ValidProperties,
  1529.     rvpiBorder_BO_Bottom in ValidProperties);
  1530.   VisibleBorders.AssignValidProperties(Source.VisibleBorders,
  1531.     rvpiBorder_Vis_Left   in ValidProperties,
  1532.     rvpiBorder_Vis_Top    in ValidProperties,
  1533.     rvpiBorder_Vis_Right  in ValidProperties,
  1534.     rvpiBorder_Vis_Bottom in ValidProperties);
  1535. end;
  1536. {------------------------------------------------------------------------------}
  1537. { Returns a value of similarity between this border and Value.
  1538.   The larger value - the higher similarity. }
  1539. function TRVBorder.SimilarityValue(Value: TRVBorder): Integer;
  1540. var vis1,vis2: array[0..3] of Boolean;
  1541.     sum,i: Integer;
  1542. begin
  1543.   Result := 0;
  1544.   vis1[0] := ((Style<>rvbNone) and VisibleBorders.Left);
  1545.   vis2[0] := ((Value.Style<>rvbNone) and Value.VisibleBorders.Left);
  1546.   vis1[1] := ((Style<>rvbNone) and VisibleBorders.Top);
  1547.   vis2[1] := ((Value.Style<>rvbNone) and Value.VisibleBorders.Top);
  1548.   vis1[2] := ((Style<>rvbNone) and VisibleBorders.Right);
  1549.   vis2[2] := ((Value.Style<>rvbNone) and Value.VisibleBorders.Right);
  1550.   vis1[3] := ((Style<>rvbNone) and VisibleBorders.Bottom);
  1551.   vis2[3] := ((Value.Style<>rvbNone) and Value.VisibleBorders.Bottom);
  1552.   sum := 0;
  1553.   for i := 0 to 3 do begin
  1554.     inc(sum, ord(vis1[i] and vis2[i]));
  1555.   end;
  1556.   if sum>0 then begin
  1557.     Result := RV_CompareColors(Color, Value.Color, RVSMW_EACHRGBCOLOR, RVSMW_COLORSET)+
  1558.               RV_CompareInts(Width, Value.Width, RVSMW_WIDTH)+
  1559.               RV_CompareInts(InternalWidth, Value.InternalWidth, RVSMW_WIDTH);
  1560.     if Style = Value.Style then
  1561.       inc(Result, RVSMW_BORDERSTYLE);
  1562.     Result := Result * sum;
  1563.   end;
  1564.   for i := 0 to 3 do begin
  1565.     if not vis1[i] and not vis2[i] then
  1566.       inc(Result, RVSMW_BORDERNOSIDE);
  1567.     if vis1[i] <> vis2[i] then
  1568.       dec(Result, RVSMW_BORDERNOSIDE);
  1569.   end;
  1570.   if vis1[0] and vis2[0] then
  1571.     inc(Result, RV_CompareInts(BorderOffsets.Left, Value.BorderOffsets.Left, RVSMW_PADDING));
  1572.   if vis1[1] and vis2[1] then
  1573.     inc(Result, RV_CompareInts(BorderOffsets.Top, Value.BorderOffsets.Top, RVSMW_PADDING));
  1574.   if vis1[2] and vis2[2] then
  1575.     inc(Result, RV_CompareInts(BorderOffsets.Right, Value.BorderOffsets.Right, RVSMW_PADDING));
  1576.   if vis1[3] and vis2[3] then
  1577.     inc(Result, RV_CompareInts(BorderOffsets.Bottom, Value.BorderOffsets.Bottom, RVSMW_PADDING));
  1578. end;
  1579. {------------------------------------------------------------------------------}
  1580. { Returns the total width of border, including all line widths and gaps. }
  1581. function TRVBorder.GetTotalWidth: Integer;
  1582. begin
  1583.   case Style of
  1584.     rvbSingle:
  1585.       Result := Width;
  1586.     rvbDouble:
  1587.       Result := 2*Width+InternalWidth;
  1588.     rvbTriple:
  1589.       Result := 3*Width+2*InternalWidth;
  1590.     rvbThickInside, rvbThickOutside:
  1591.       Result := 3*Width+InternalWidth;
  1592.     else
  1593.       Result := 0;
  1594.   end;
  1595. end;
  1596. {------------------------------------------------------------------------------}
  1597. {$IFNDEF RVDONOTUSEINI}
  1598. { Loads itself from the ini-file, from the section Section.
  1599.   fs is a format string for ini keys. }
  1600. procedure TRVBorder.LoadFromINI(ini: TRVIniFile; const Section, fs: String);
  1601. begin
  1602.   Width := ini.ReadInteger(Section, Format(fs,[RVINI_WIDTH]), 1);
  1603.   Style := TRVBorderStyle(ini.ReadInteger(Section, Format(fs,[RVINI_STYLE]), ord(rvbNone)));
  1604.   Color := ini.ReadInteger(Section, Format(fs,[RVINI_COLOR]), clWindowText);
  1605.   InternalWidth := ini.ReadInteger(Section, Format(fs,[RVINI_INTERNALWIDTH]), 1);
  1606.   BorderOffsets.LoadFromINI(ini,  Section, Format(fs,[RVINI_BOFFSPREFIX]));
  1607.   VisibleBorders.LoadFromINI(ini, Section, Format(fs,[RVINI_VISBPREFIX]));
  1608. end;
  1609. {------------------------------------------------------------------------------}
  1610. { Stores itself in the ini-file, in the section Section.
  1611.   fs is a format string for ini keys. }
  1612. procedure TRVBorder.SaveToINI(ini: TRVIniFile; const Section, fs: String);
  1613. begin
  1614.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_WIDTH]), Width, 1);
  1615.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_STYLE]), ord(Style), ord(rvbNone));
  1616.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_COLOR]), Color, clWindowText);
  1617.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_INTERNALWIDTH]), InternalWidth, 1);
  1618.   BorderOffsets.SaveToINI(ini,    Section, Format(fs,[RVINI_BOFFSPREFIX]));
  1619.   VisibleBorders.SaveToINI(ini, Section, Format(fs,[RVINI_VISBPREFIX]));
  1620. end;
  1621. {$ENDIF}
  1622. {============================== TRVBackgroundRect =============================}
  1623. { Constructor, creates a transparent border with zero padding. }
  1624. constructor TRVBackgroundRect.Create;
  1625. begin
  1626.   inherited Create;
  1627.   FBorderOffsets := TRVRect.Create;
  1628.   Color := clNone
  1629. end;
  1630. {------------------------------------------------------------------------------}
  1631. { Destructor. }
  1632. destructor TRVBackgroundRect.Destroy;
  1633. begin
  1634.   FBorderOffsets.Free;
  1635.   inherited Destroy;
  1636. end;
  1637. {------------------------------------------------------------------------------}
  1638. { Assigns TRVBackgroundRect (Source) to TRVBackgroundRect (Self). }
  1639. procedure TRVBackgroundRect.Assign(Source: TPersistent);
  1640. begin
  1641.   if Source is TRVBackgroundRect then begin
  1642.     Color := TRVBackgroundRect(Source).Color;
  1643.     BorderOffsets := TRVBackgroundRect(Source).BorderOffsets;
  1644.     end
  1645.   else
  1646.     inherited Assign(Source);
  1647. end;
  1648. {------------------------------------------------------------------------------}
  1649. { Adds padding (BorderOffs) to Rect. }
  1650. procedure TRVBackgroundRect.PrepareDraw(var Rect: TRect);
  1651. begin
  1652.   BorderOffsets.InflateRect(Rect);
  1653. end;
  1654. {------------------------------------------------------------------------------}
  1655. { Adds corrected padding (BorderOffs) to Rect.
  1656.   Corrections is made according to the device resolution specified in sad. }
  1657. procedure TRVBackgroundRect.PrepareDrawSaD(var Rect: TRect;
  1658.   const sad: TRVScreenAndDevice);
  1659. begin
  1660.   BorderOffsets.InflateRectSaD(Rect,sad);
  1661. end;
  1662. {------------------------------------------------------------------------------}
  1663. { Draws background on the Canvas at the rectangle Rect.
  1664.   If Printing, this is a printing or print preview.
  1665.   Colors are corrected according to the ColorMode. }
  1666. procedure TRVBackgroundRect.Draw(Rect: TRect; Canvas: TCanvas;
  1667.   Printing: Boolean; ColorMode: TRVColorMode);
  1668. begin
  1669.   if (Color=clNone) or (ColorMode in [rvcmBlackAndWhite, rvcmBlackOnWhite]) then
  1670.     exit;
  1671.   Canvas.Brush.Style := bsSolid;
  1672.   case ColorMode of
  1673.     rvcmColor:
  1674.       Canvas.Brush.Color := Color;
  1675.     rvcmPrinterColor:
  1676.       Canvas.Brush.Color := RV_GetPrnColor(Color);
  1677.     rvcmGrayScale:
  1678.       Canvas.Brush.Color := RV_GetGray(RV_GetPrnColor(Color));
  1679.   end;
  1680.   Canvas.Pen.Style := psClear;
  1681.   inc(Rect.Right);
  1682.   inc(Rect.Bottom);
  1683.   Canvas.FillRect(Rect);
  1684.   Canvas.Pen.Style := psSolid;
  1685.   Canvas.Brush.Style := bsClear;
  1686. end;
  1687. {------------------------------------------------------------------------------}
  1688. { WRITE method for BorderOffsets property. }
  1689. procedure TRVBackgroundRect.SetBorderOffsets(const Value: TRVRect);
  1690. begin
  1691.   FBorderOffsets.Assign(Value);
  1692. end;
  1693. {------------------------------------------------------------------------------}
  1694. {$IFNDEF RVDONOTUSEINI}
  1695. { Loads itself from the ini-file, from the section Section.
  1696.   fs is a format string for ini keys. }
  1697. procedure TRVBackgroundRect.LoadFromINI(ini: TRVIniFile; const Section,
  1698.   fs: String);
  1699. begin
  1700.   Color := ini.ReadInteger(Section, Format(fs,[RVINI_COLOR]), clNone);
  1701.   BorderOffsets.LoadFromINI(ini,  Section, Format(fs,[RVINI_BOFFSPREFIX]));
  1702. end;
  1703. {------------------------------------------------------------------------------}
  1704. { Stores itself in the ini-file, in the section Section.
  1705.   fs is a format string for ini keys. }
  1706. procedure TRVBackgroundRect.SaveToINI(ini: TRVIniFile; const Section,
  1707.   fs: String);
  1708. begin
  1709.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_COLOR]), Color, clNone);
  1710.   BorderOffsets.SaveToINI(ini,    Section, Format(fs,[RVINI_BOFFSPREFIX]));
  1711. end;
  1712. {$ENDIF}
  1713. {------------------------------------------------------------------------------}
  1714. { Is this background equal to Value? }
  1715. function TRVBackgroundRect.IsEqual(Value: TRVBackgroundRect): Boolean;
  1716. begin
  1717.   Result := (Color = Value.Color) and
  1718.             BorderOffsets.IsEqual(Value.BorderOffsets);
  1719. end;
  1720. {------------------------------------------------------------------------------}
  1721. { Returns a value of similarity between this background and Value.
  1722.   The larger value - the higher similarity. }
  1723. function TRVBackgroundRect.SimilarityValue(
  1724.   Value: TRVBackgroundRect): Integer;
  1725. begin
  1726.   Result := RV_CompareColors(Color, Value.Color, RVSMW_EACHRGBBCOLOR, RVSMW_BCOLORSET)+
  1727.             BorderOffsets.SimilarityValue(Value.BorderOffsets, RVSMW_PADDING);
  1728. end;
  1729. {------------------------------------------------------------------------------}
  1730. { Are the specified properties of this background equal to the properties of Value?
  1731.   IgnoreList specifies properties that must be ignored when comparing. }
  1732. function TRVBackgroundRect.IsEqual_Para(Value: TRVBackgroundRect;
  1733.   IgnoreList: TRVParaInfoProperties): Boolean;
  1734. begin
  1735.   Result := ((rvpiBackground_Color in IgnoreList) or (Color = Value.Color)) and
  1736.             BorderOffsets.IsEqualEx(Value.BorderOffsets,
  1737.             rvpiBackground_BO_Left in IgnoreList,
  1738.             rvpiBackground_BO_Top in IgnoreList,
  1739.             rvpiBackground_BO_Right in IgnoreList,
  1740.             rvpiBackground_BO_Bottom in IgnoreList);
  1741. end;
  1742. {------------------------------------------------------------------------------}
  1743. { Assigns properties from Source, listed in ValidProperties }
  1744. procedure TRVBackgroundRect.AssignValidProperties(Source: TRVBackgroundRect;
  1745.   ValidProperties: TRVParaInfoProperties1);
  1746. begin
  1747.   if (rvpiBackground_Color in ValidProperties) then
  1748.     Color := Source.Color;
  1749.   BorderOffsets.AssignValidProperties(Source.BorderOffsets,
  1750.     rvpiBackground_BO_Left in ValidProperties,
  1751.     rvpiBackground_BO_Top in ValidProperties,
  1752.     rvpiBackground_BO_Right in ValidProperties,
  1753.     rvpiBackground_BO_Bottom in ValidProperties);
  1754. end;
  1755. {=========================== TRVTabInfo =======================================}
  1756. {$IFNDEF RVDONOTUSETABS}
  1757. {$IFDEF RICHVIEWCBDEF3}
  1758. { Designtime support. Returns a string to display for the tab in the collection
  1759.   editor.
  1760.   This string has format "<align> at <position>".
  1761.   If Leader is not empty, it's added to the end of the string. }
  1762. function TRVTabInfo.GetDisplayName: String;
  1763. begin
  1764.   Result := RVAlignStr[ord(Align)]+' at '+IntToStr(Position);
  1765.   if Leader<>'' then
  1766.     Result := Result+' ('+Leader+Leader+Leader+Leader+Leader+Leader+')';
  1767. end;
  1768. {$ENDIF}
  1769. {------------------------------------------------------------------------------}
  1770. { Is this tabstop equal to Value? }
  1771. function TRVTabInfo.IsEqual(Value: TRVTabInfo): Boolean;
  1772. begin
  1773.   Result := (Position=Value.Position) and
  1774.             (Align=Value.Align) and
  1775.             (Leader=Value.Leader);
  1776. end;
  1777. {------------------------------------------------------------------------------}
  1778. { Returns a value of similarity between this tabstop and Value.
  1779.   The larger value - the higher similarity. }
  1780. function TRVTabInfo.SimilarityValue(Value: TRVTabInfo): Integer;
  1781. begin
  1782.   Result := RV_CompareInts(Position, Value.Position, RVSMW_TABPOS);
  1783.   if Align=Value.Align then
  1784.     inc(Result, RVSMW_TABALIGN);
  1785.   if Leader=Value.Leader then
  1786.     inc(Result, RVSMW_LEADER);
  1787. end;
  1788. {------------------------------------------------------------------------------}
  1789. { WRITE method for Position property.
  1790.   Assigns the property value and resort the collection of tabstops. }
  1791. procedure TRVTabInfo.SetPosition(const Value: Integer);
  1792. begin
  1793.   if Value <> FPosition then begin
  1794.     FPosition := Value;
  1795.     if Collection<>nil then
  1796.       with TRVTabInfos(Collection) do begin
  1797.         BeginUpdate;
  1798.         try
  1799.           SortTabs;
  1800.         finally
  1801.           EndUpdate;
  1802.         end;
  1803.       end;
  1804.   end;
  1805. end;
  1806. {------------------------------------------------------------------------------}
  1807. { STORED method for Leader property.
  1808.   Should Leader value be stored? }
  1809. function TRVTabInfo.StoreLeader: Boolean;
  1810. begin
  1811.   Result := Leader<>'';
  1812. end;
  1813. {------------------------------------------------------------------------------}
  1814. { Assigns the tabstop Source to Self. }
  1815. procedure TRVTabInfo.Assign(Source: TPersistent);
  1816. begin
  1817.   if Source is TRVTabInfo then begin
  1818.     Position := TRVTabInfo(Source).Position;
  1819.     Align    := TRVTabInfo(Source).Align;
  1820.     Leader   := TRVTabInfo(Source).Leader;
  1821.     end
  1822.   else
  1823.     inherited Assign(Source);
  1824. end;
  1825. {------------------------------------------------------------------------------}
  1826. { Function for comparing position of tabstops. Used to sort the collection.    }
  1827. function CompareTabs(Item1, Item2: Pointer): Integer;
  1828. begin
  1829.   Result := TRVTabInfo(Item1).Position-TRVTabInfo(Item2).Position;
  1830. end;
  1831. {------------------------------------------------------------------------------}
  1832. {$IFNDEF RVDONOTUSEINI}
  1833. { Loads itself from the ini-file, from the section Section.
  1834.   fs is a format string for ini keys. }
  1835. procedure TRVTabInfo.LoadFromINI(ini: TRVIniFile; const Section,
  1836.   fs: String);
  1837. begin
  1838.   Position := ini.ReadInteger(Section, Format(fs,[RVINI_TABPOSITION]), 0);
  1839.   Align    := TRVTabAlign(ini.ReadInteger(Section, Format(fs,[RVINI_TABALIGN]), 0));
  1840.   Leader   := ini.ReadString(Section, Format(fs,[RVINI_TABLEADER]), '');
  1841. end;
  1842. {------------------------------------------------------------------------------}
  1843. { Stores itself in the ini-file, in the section Section.
  1844.   fs is a format string for ini keys. }
  1845. procedure TRVTabInfo.SaveToINI(ini: TRVIniFile; const Section, fs: String);
  1846. begin
  1847.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_TABPOSITION]), Position, 0);
  1848.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_TABALIGN]), ord(Align), 0);
  1849.   if Leader<>'' then
  1850.     ini.WriteString(Section, Format(fs,[RVINI_TABLEADER]), Leader);
  1851. end;
  1852. {$ENDIF}
  1853. {=============================== TRVTabInfos ==================================}
  1854. { Constructor. Creates empty collection of TRVTabInfo. }
  1855. constructor TRVTabInfos.Create(Owner: TPersistent);
  1856. begin
  1857.   inherited Create(TRVTabInfo);
  1858.   FOwner := Owner;
  1859. end;
  1860. {------------------------------------------------------------------------------}
  1861. {$IFDEF RICHVIEWCBDEF3}
  1862. { Designtime support. Required for the collection editor. }
  1863. function TRVTabInfos.GetOwner: TPersistent;
  1864. begin
  1865.   Result := FOwner;
  1866. end;
  1867. {$ENDIF}
  1868. {------------------------------------------------------------------------------}
  1869. { Sorts tabs by Position in ascending order.
  1870.   This method is called automatically when Items[].Position is changed         }
  1871. procedure TRVTabInfos.SortTabs;
  1872. var
  1873.   i: Integer;
  1874.   List: TList;
  1875. begin
  1876.   List := TList.Create;
  1877.   try
  1878.     for i := 0 to Count - 1 do
  1879.       List.Add(Items[i]);
  1880.     List.Sort(CompareTabs);
  1881.     for i := 0 to List.Count - 1 do
  1882.       TRVTabInfo(List.Items[i]).Index := i
  1883.   finally
  1884.     List.Free;
  1885.   end;
  1886. end;
  1887. {------------------------------------------------------------------------------}
  1888. {$IFNDEF RVDONOTUSEINI}
  1889. { Loads itself from the ini-file, from the section Section.
  1890.   fs is a format string for ini keys. }
  1891. procedure TRVTabInfos.LoadFromINI(ini: TRVIniFile; const Section,
  1892.   fs: String);
  1893. var i,c: Integer;
  1894. begin
  1895.   Clear;
  1896.   c := ini.ReadInteger(Section, Format(fs,[RVINI_TABCOUNT]), 0);
  1897.   for i := 0 to c-1 do
  1898.     Add.LoadFromINI(ini, Section, Format(fs,[''])+RVINI_TABPREFIX+IntToStr(i));
  1899. end;
  1900. {------------------------------------------------------------------------------}
  1901. { Stores itself in the ini-file, in the section Section.
  1902.   fs is a format string for ini keys. }
  1903. procedure TRVTabInfos.SaveToINI(ini: TRVIniFile; const Section,
  1904.   fs: String);
  1905. var i: Integer;
  1906. begin
  1907.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_TABCOUNT]), Count, 0);
  1908.   for i := 0 to Count-1 do
  1909.     Items[i].SaveToINI(ini, Section, Format(fs,[''])+RVINI_TABPREFIX+IntToStr(i));
  1910. end;
  1911. {$ENDIF}
  1912. {------------------------------------------------------------------------------}
  1913. { Adds a new item (added because of typecasting). }
  1914. function TRVTabInfos.Add: TRVTabInfo;
  1915. begin
  1916.   Result := TRVTabInfo(inherited Add);
  1917. end;
  1918. {------------------------------------------------------------------------------}
  1919. { READ method for Items[] property. }
  1920. function TRVTabInfos.GetItem(Index: Integer): TRVTabInfo;
  1921. begin
  1922.   Result := TRVTabInfo(inherited GetItem(Index));
  1923. end;
  1924. {------------------------------------------------------------------------------}
  1925. { WRITE method for Items[] property. }
  1926. procedure TRVTabInfos.SetItem(Index: Integer; Value: TRVTabInfo);
  1927. begin
  1928.   inherited SetItem(Index, Value);
  1929. end;
  1930. {------------------------------------------------------------------------------}
  1931. { Is this collection of tabstops equal to Value? }
  1932. function TRVTabInfos.IsEqual(Value: TRVTabInfos): Boolean;
  1933. var i: Integer;
  1934. begin
  1935.   Result := Count=Value.Count;
  1936.   if not Result then
  1937.     exit;
  1938.   for i := 0 to Count-1 do
  1939.     if not Items[i].IsEqual(Value[i]) then begin
  1940.       Result := False;
  1941.       exit;
  1942.     end;
  1943. end;
  1944. {------------------------------------------------------------------------------}
  1945. { Returns index of tab with the given Position (or -1 if not found).
  1946.   Collection must be sorted.                                                   }
  1947. function TRVTabInfos.Find(Position: Integer): Integer;
  1948. var a,b,c: Integer;
  1949. begin
  1950.   Result := -1;
  1951.   if Count=0 then
  1952.     exit;
  1953.   a := 0;
  1954.   b := Count-1;
  1955.   while (b-a)>1 do begin
  1956.      c := (a+b) div 2;
  1957.     if Items[c].Position<Position then
  1958.       a := c
  1959.     else
  1960.       b := c;
  1961.   end;
  1962.   if Items[a].Position=Position then
  1963.     Result := a
  1964.   else if Items[b].Position=Position then
  1965.     Result := b;
  1966. end;
  1967. {------------------------------------------------------------------------------}
  1968. { Deletes all tabs that not present in Value. Only tabs with all
  1969.   common properties are not deleted.                                           }
  1970. procedure TRVTabInfos.Intersect(Value: TRVTabInfos);
  1971. var i, Index: Integer;
  1972. begin
  1973.   for i := Count-1 downto 0 do begin
  1974.     Index := Value.Find(Items[i].Position);
  1975.     if (Index<0) or not Items[i].IsEqual(Value[Index]) then
  1976.       Items[i].Free;
  1977.   end;
  1978. end;
  1979. {------------------------------------------------------------------------------}
  1980. { Adds tabs from sources. New tabs are inserted, existing tabs are updated.    }
  1981. procedure TRVTabInfos.AddFrom(Source: TRVTabInfos);
  1982. var i, Index: Integer;
  1983. begin
  1984.   for i := 0 to Source.Count-1 do begin
  1985.     Index := Find(Source[i].Position);
  1986.     if Index<0 then begin
  1987.       Add;
  1988.       Index := Count-1;
  1989.     end;
  1990.     Items[Index].Assign(Source[i]);
  1991.   end;
  1992. end;
  1993. {------------------------------------------------------------------------------}
  1994. { Deletes tabs with the specified positions                                    }
  1995. procedure TRVTabInfos.DeleteList(Positions: TRVIntegerList);
  1996. var i, Index: Integer;
  1997. begin
  1998.   for i := 0 to Positions.Count-1 do begin
  1999.     Index := Find(Positions[i]);
  2000.     if Index>=0 then
  2001.       Items[Index].Free;
  2002.   end;
  2003. end;
  2004. {------------------------------------------------------------------------------}
  2005. { Returns a value of similarity between this collection of tabstops and Value.
  2006.   The greater value - the higher similarity. }
  2007. function TRVTabInfos.SimilarityValue(Value: TRVTabInfos): Integer;
  2008. var i, MinCount: Integer;
  2009. begin
  2010.   if Count<Value.Count then
  2011.     MinCount := Count
  2012.   else
  2013.     MinCount := Value.Count;
  2014.   Result := 0;
  2015.   for i := 0 to MinCount-1 do
  2016.     inc(Result, Items[i].SimilarityValue(Value[i]));
  2017.   dec(Result, (Count-MinCount)*RVSMW_NOTAB);
  2018.   dec(Result, (Value.Count-MinCount)*RVSMW_NOTAB);
  2019. end;
  2020. {$ENDIF}
  2021. {============================= TCustomRVParaInfo ==============================}
  2022. { Constructor. Creates left-aligned parameters with zero indents and spacing,
  2023.   without background, border and tabs.
  2024.   Default style name is 'Paragraph Style'. }
  2025. constructor TCustomRVParaInfo.Create(Collection: TCollection);
  2026. begin
  2027.   inherited Create(Collection);
  2028.   FirstIndent := 0;
  2029.   LeftIndent  := 0;
  2030.   RightIndent := 0;
  2031.   Alignment   := rvaLeft;
  2032.   FName       := RVDEFAULTPARASTYLENAME;
  2033.   FBorder     := TRVBorder.Create;
  2034.   FBackground := TRVBackgroundRect.Create;
  2035.   {$IFNDEF RVDONOTUSETABS}
  2036.   FTabs       := TRVTabInfos.Create(Self);
  2037.   {$ENDIF}
  2038.   LineSpacingType := rvlsPercent;
  2039.   LineSpacing := 100;
  2040. end;
  2041. {------------------------------------------------------------------------------}
  2042. { Destructor. }
  2043. destructor TCustomRVParaInfo.Destroy;
  2044. begin
  2045.   FBorder.Free;
  2046.   FBackground.Free;
  2047.   {$IFNDEF RVDONOTUSETABS}
  2048.   FTabs.Free;
  2049.   {$ENDIF}
  2050.   inherited Destroy;
  2051. end;
  2052. {------------------------------------------------------------------------------}
  2053. { WRITE method for Border property. }
  2054. procedure TCustomRVParaInfo.SetBorder(const Value: TRVBorder);
  2055. begin
  2056.   FBorder.Assign(Value);
  2057. end;
  2058. {------------------------------------------------------------------------------}
  2059. {$IFNDEF RVDONOTUSETABS}
  2060. { WRITE method for Tabs property. }
  2061. procedure TCustomRVParaInfo.SetTabs(const Value: TRVTabInfos);
  2062. begin
  2063.   FTabs.Assign(Value);
  2064. end;
  2065. {$ENDIF}
  2066. {------------------------------------------------------------------------------}
  2067. { WRITE method for Background property. }
  2068. procedure TCustomRVParaInfo.SetBackground(const Value: TRVBackgroundRect);
  2069. begin
  2070.   FBackground.Assign(Value);
  2071. end;
  2072. {------------------------------------------------------------------------------}
  2073. { Is there nondefault line spacing? }
  2074. function TCustomRVParaInfo.ExtraLineSpacing: Boolean;
  2075. begin
  2076.   case LineSpacingType of
  2077.     rvlsPercent:
  2078.       Result := LineSpacing<>100;
  2079.     rvlsSpaceBetween:
  2080.       Result := LineSpacing>0;
  2081.     else
  2082.       Result := False;
  2083.   end;
  2084. end;
  2085. {------------------------------------------------------------------------------}
  2086. { Assigns Source to Self, if Source is TCustomRVParaInfo. }
  2087. procedure TCustomRVParaInfo.Assign(Source: TPersistent);
  2088. begin
  2089.   if Source is TCustomRVParaInfo then begin
  2090.     FirstIndent := TCustomRVParaInfo(Source).FirstIndent;
  2091.     LeftIndent  := TCustomRVParaInfo(Source).LeftIndent;
  2092.     RightIndent := TCustomRVParaInfo(Source).RightIndent;
  2093.     Alignment   := TCustomRVParaInfo(Source).Alignment;
  2094.     SpaceBefore := TCustomRVParaInfo(Source).SpaceBefore;
  2095.     SpaceAfter  := TCustomRVParaInfo(Source).SpaceAfter;
  2096.     LineSpacing := TCustomRVParaInfo(Source).LineSpacing;
  2097.     LineSpacingType := TCustomRVParaInfo(Source).LineSpacingType;
  2098.     Background  := TCustomRVParaInfo(Source).Background;
  2099.     Border      := TCustomRVParaInfo(Source).Border;
  2100.     {$IFNDEF RVDONOTUSETABS}
  2101.     Tabs        := TCustomRVParaInfo(Source).Tabs;
  2102.     {$ENDIF}
  2103.     Options     := TCustomRVParaInfo(Source).Options;
  2104.     BiDiMode    := TCustomRVParaInfo(Source).BiDiMode;
  2105.   end;
  2106.   inherited Assign(Source);
  2107. end;
  2108. {------------------------------------------------------------------------------}
  2109. { Assigns properties listed in Props1 and Props2 from Source to Self. }
  2110. procedure TCustomRVParaInfo.AssignSelectedProperties(
  2111.   Source: TCustomRVParaInfo; Props: TRVParaInfoProperties);
  2112.    {.............................................................}
  2113.    procedure ChangeOption(Option: TRVParaOption; OptionId: TRVParaInfoProperty2);
  2114.    begin
  2115.      if OptionId in Props then
  2116.        if Option in Source.Options then
  2117.          Options := Options+[Option]
  2118.        else
  2119.          Options := Options-[Option];
  2120.    end;
  2121.    {.............................................................}
  2122. begin
  2123.   if (rvpiFirstIndent in Props) then
  2124.     FirstIndent := Source.FirstIndent;
  2125.   if (rvpiLeftIndent in Props) then
  2126.     LeftIndent := Source.LeftIndent;
  2127.   if (rvpiRightIndent in Props) then
  2128.     RightIndent := Source.RightIndent;
  2129.   if (rvpiSpaceBefore in Props) then
  2130.     SpaceBefore := Source.SpaceBefore;
  2131.   if (rvpiSpaceAfter in Props) then
  2132.     SpaceAfter := Source.SpaceAfter;
  2133.   if (rvpiAlignment in Props) then
  2134.     Alignment := Source.Alignment;
  2135.   if (rvpiLineSpacing in Props) then
  2136.     LineSpacing := Source.LineSpacing;
  2137.   if (rvpiLineSpacingType in Props) then
  2138.     LineSpacingType := Source.LineSpacingType;
  2139.   Background.AssignValidProperties(Source.Background, Props);
  2140.   Border.AssignValidProperties(Source.Border, Props);
  2141.   ChangeOption(rvpaoNoWrap, rvpiNoWrap);
  2142.   ChangeOption(rvpaoReadOnly, rvpiReadOnly);
  2143.   ChangeOption(rvpaoStyleProtect, rvpiStyleProtect);
  2144.   ChangeOption(rvpaoDoNotWantReturns, rvpiDoNotWantReturns);
  2145.   ChangeOption(rvpaoKeepLinesTogether, rvpiKeepLinesTogether);
  2146.   ChangeOption(rvpaoKeepWithNext, rvpiKeepWithNext);
  2147.   {$IFNDEF RVDONOTUSETABS}
  2148.   if (rvpiTabs in Props) then
  2149.     Tabs := Source.Tabs;
  2150.   {$ENDIF}
  2151.   if (rvpiBiDiMode in Props) then
  2152.     BiDiMode := Source.BiDiMode;
  2153.   { rvpiNextParaNo, rvpiDefStyleNo - not assigned }
  2154. end;
  2155. {------------------------------------------------------------------------------}
  2156. { Is this paragraph style equal to Value?
  2157.   IgnoreID parameter is not used.
  2158.   BaseStyleNo is ignored. }
  2159. function TCustomRVParaInfo.IsSimpleEqual(Value: TCustomRVInfo;
  2160.   IgnoreReferences, IgnoreID: Boolean): Boolean;
  2161. begin
  2162.   Result :=
  2163.     (Alignment       = TCustomRVParaInfo(Value).Alignment  ) and
  2164.     (FirstIndent     = TCustomRVParaInfo(Value).FirstIndent) and
  2165.     (LeftIndent      = TCustomRVParaInfo(Value).LeftIndent ) and
  2166.     (RightIndent     = TCustomRVParaInfo(Value).RightIndent) and
  2167.     (SpaceBefore     = TCustomRVParaInfo(Value).SpaceBefore) and
  2168.     (SpaceAfter      = TCustomRVParaInfo(Value).SpaceAfter) and
  2169.     (LineSpacing     = TCustomRVParaInfo(Value).LineSpacing) and
  2170.     (LineSpacingType = TCustomRVParaInfo(Value).LineSpacingType) and
  2171.     (Options         = TCustomRVParaInfo(Value).Options) and
  2172.     (BiDiMode        = TCustomRVParaInfo(Value).BiDiMode) and
  2173.     Background.IsEqual(TCustomRVParaInfo(Value).Background) and
  2174.     {$IFNDEF RVDONOTUSETABS}
  2175.     Tabs.IsEqual(TParaInfo(Value).Tabs) and
  2176.     {$ENDIF}
  2177.     Border.IsEqual(TParaInfo(Value).Border) and
  2178.     (not RichViewCompareStyleNames or (StyleName=TCustomRVParaInfo(Value).StyleName));
  2179. end;
  2180. {------------------------------------------------------------------------------}
  2181. { Returns a value of similarity between this paragraph style and Value.
  2182.   The greater value - the higher similarity.
  2183.   BaseStyleNo, NextParaNo, DefStyleNo are ignored. }
  2184. function TCustomRVParaInfo.SimilarityValue(Value: TCustomRVInfo): Integer;
  2185. begin
  2186.   Result :=
  2187.     RV_CompareInts(FirstIndent, TParaInfo(Value).FirstIndent, RVSMW_INDENT)+
  2188.     RV_CompareInts(LeftIndent,  TParaInfo(Value).LeftIndent,  RVSMW_INDENT)+
  2189.     RV_CompareInts(RightIndent, TParaInfo(Value).RightIndent, RVSMW_INDENT)+
  2190.     RV_CompareInts(SpaceBefore, TParaInfo(Value).SpaceBefore, RVSMW_INDENT)+
  2191.     RV_CompareInts(SpaceAfter, TParaInfo(Value).SpaceAfter, RVSMW_INDENT)+
  2192.     Background.SimilarityValue(TParaInfo(Value).Background)+
  2193.     {$IFNDEF RVDONOTUSETABS}
  2194.     Tabs.SimilarityValue(TParaInfo(Value).Tabs)+
  2195.     {$ENDIF}
  2196.     Border.SimilarityValue(TParaInfo(Value).Border);
  2197.   if (Alignment = TParaInfo(Value).Alignment) then
  2198.     inc(Result, RVSMW_ALIGNMENT);
  2199.   if (BiDiMode = TParaInfo(Value).BiDiMode) then
  2200.     inc(Result, RVSMW_BIDIMODE);
  2201.   if ((rvpaoNoWrap in Options) = (rvpaoNoWrap in TParaInfo(Value).Options)) then
  2202.     inc(Result, RVSMW_NOWRAP);
  2203.   if ((rvpaoReadOnly in Options) = (rvpaoReadOnly in TParaInfo(Value).Options)) then
  2204.     inc(Result, RVSMW_READONLY);
  2205.   if ((rvpaoStyleProtect in Options) = (rvpaoStyleProtect in TParaInfo(Value).Options)) then
  2206.     inc(Result, RVSMW_STYLEPROTECT);
  2207.   if ((rvpaoDoNotWantReturns in Options) = (rvpaoDoNotWantReturns in TParaInfo(Value).Options)) then
  2208.     inc(Result, RVSMW_DONOTWANTRETURNS);
  2209.   if ((rvpaoKeepLinesTogether in Options) = (rvpaoKeepLinesTogether in TParaInfo(Value).Options)) then
  2210.     inc(Result, RVSMW_KEEPLINESTOGETHER);
  2211.   if ((rvpaoKeepWithNext in Options) = (rvpaoKeepWithNext in TParaInfo(Value).Options)) then
  2212.     inc(Result, RVSMW_KEEPWITHNEXT);
  2213.   if (LineSpacingType=TParaInfo(Value).LineSpacingType) then
  2214.     inc(Result, RV_CompareInts(LineSpacing, TParaInfo(Value).LineSpacing, RVSMW_LINESPACING))
  2215.   else if ExtraLineSpacing<>TParaInfo(Value).ExtraLineSpacing then
  2216.     dec(Result, RVSMW_LINESPACING*4);
  2217. end;
  2218. {------------------------------------------------------------------------------}
  2219. { Is the specified properties of this paragraph style equal to the properties of
  2220.   Value. IgnoreList lists properties which will be ignored when comparing.
  2221.   BaseStyleNo is always ignored. }
  2222. function TCustomRVParaInfo.IsEqual(Value: TCustomRVParaInfo;
  2223.   IgnoreList: TRVParaInfoProperties): Boolean;
  2224. begin
  2225.   Result :=
  2226.     ((rvpiAlignment       in IgnoreList) or (Alignment       = Value.Alignment)) and
  2227.     ((rvpiFirstIndent     in IgnoreList) or (FirstIndent     = Value.FirstIndent)) and
  2228.     ((rvpiLeftIndent      in IgnoreList) or (LeftIndent      = Value.LeftIndent)) and
  2229.     ((rvpiRightIndent     in IgnoreList) or (RightIndent     = Value.RightIndent)) and
  2230.     ((rvpiSpaceBefore     in IgnoreList) or (SpaceBefore     = Value.SpaceBefore)) and
  2231.     ((rvpiSpaceAfter      in IgnoreList) or (SpaceAfter     = Value.SpaceAfter)) and
  2232.     ((rvpiLineSpacing     in IgnoreList) or (LineSpacing     = Value.LineSpacing)) and
  2233.     ((rvpiLineSpacingType in IgnoreList) or (LineSpacingType = Value.LineSpacingType)) and
  2234.     ((rvpiNoWrap          in IgnoreList) or ((rvpaoNoWrap in Options) = (rvpaoNoWrap in TParaInfo(Value).Options))) and
  2235.     ((rvpiReadOnly        in IgnoreList) or ((rvpaoReadOnly in Options) = (rvpaoReadOnly in TParaInfo(Value).Options))) and
  2236.     ((rvpiStyleProtect    in IgnoreList) or ((rvpaoStyleProtect in Options) = (rvpaoStyleProtect in TParaInfo(Value).Options))) and
  2237.     ((rvpiDoNotWantReturns in IgnoreList) or ((rvpaoDoNotWantReturns in Options) = (rvpaoDoNotWantReturns in TParaInfo(Value).Options))) and
  2238.     ((rvpiKeepLinesTogether in IgnoreList) or ((rvpaoKeepLinesTogether in Options) = (rvpaoKeepLinesTogether in TParaInfo(Value).Options))) and
  2239.     ((rvpiKeepWithNext    in IgnoreList) or ((rvpaoKeepWithNext in Options) = (rvpaoKeepWithNext in TParaInfo(Value).Options))) and
  2240.     ((rvpiBiDiMode        in IgnoreList) or (BiDiMode        = Value.BiDiMode)) and
  2241.     {$IFNDEF RVDONOTUSETABS}
  2242.     ((rvpiTabs            in IgnoreList) or Tabs.IsEqual(Value.Tabs)) and
  2243.     {$ENDIF}
  2244.     Background.IsEqual_Para(Value.Background, IgnoreList) and
  2245.     Border.IsEqual_Para(Value.Border, IgnoreList);
  2246.   if Result and RichViewCompareStyleNames then
  2247.     Result := StyleName=Value.StyleName;
  2248. end;
  2249. {------------------------------------------------------------------------------}
  2250. {$IFNDEF RVDONOTUSEINI}
  2251. { Loads itself from the ini-file, from the section Section.
  2252.   fs is a format string for ini keys. }
  2253. procedure TCustomRVParaInfo.LoadFromINI(ini: TRVIniFile; const Section, fs: String);
  2254. begin
  2255.   inherited LoadFromINI(ini, Section, fs, RVDEFAULTPARASTYLENAME);
  2256.   SpaceBefore := ini.ReadInteger(Section,  Format(fs,[RVINI_SPACEBEFORE]),  0);
  2257.   SpaceAfter  := ini.ReadInteger(Section,  Format(fs,[RVINI_SPACEAFTER]),  0);
  2258.   LeftIndent  := ini.ReadInteger(Section,  Format(fs,[RVINI_LEFTINDENT]),  0);
  2259.   RightIndent := ini.ReadInteger(Section,  Format(fs,[RVINI_RIGHTIDENT]),  0);
  2260.   FirstIndent := ini.ReadInteger(Section,  Format(fs,[RVINI_FIRSTINDENT]), 0);
  2261.   LineSpacing := ini.ReadInteger(Section,  Format(fs,[RVINI_LINESPACING]), 100);
  2262.   LineSpacingType := TRVLineSpacingType(ini.ReadInteger(Section,  Format(fs,[RVINI_LINESPACINGTYPE]), ord(rvlsPercent)));
  2263.   Alignment   := TRVAlignment(ini.ReadInteger(Section, Format(fs,[RVINI_ALIGNMENT]), ord(rvaLeft)));
  2264.   BiDiMode    := TRVBiDiMode(ini.ReadInteger(Section, Format(fs,[RVINI_BIDIMODE]), 0));
  2265.   Options := [];
  2266.   if IniReadBool(ini, Section, Format(fs,[RVINI_NOWRAP]), False) then
  2267.     Include(FOptions, rvpaoNoWrap);
  2268.   if IniReadBool(ini, Section, Format(fs,[RVINI_READONLY]), False) then
  2269.     Include(FOptions, rvpaoReadOnly);
  2270.   if IniReadBool(ini, Section, Format(fs,[RVINI_STYLEPROTECT]), False) then
  2271.     Include(FOptions, rvpaoStyleProtect);
  2272.   if IniReadBool(ini, Section, Format(fs,[RVINI_DONOTWANTRETURNS]), False) then
  2273.     Include(FOptions, rvpaoDoNotWantReturns);
  2274.   if IniReadBool(ini, Section, Format(fs,[RVINI_KEEPLINESTOGETHER]), False) then
  2275.     Include(FOptions, rvpaoKeepLinesTogether);
  2276.   if IniReadBool(ini, Section, Format(fs,[RVINI_KEEPWITHNEXT]), False) then
  2277.     Include(FOptions, rvpaoKeepWithNext);
  2278.   Border.LoadFromINI(ini,  Section, Format(fs,[RVINI_BORDERPREFIX]));
  2279.   Background.LoadFromINI(ini,  Section, Format(fs,[RVINI_BACKGROUNDPREFIX]));
  2280.   {$IFNDEF RVDONOTUSETABS}
  2281.   Tabs.LoadFromINI(ini, Section, Format(fs, [RVINI_TABPREFIX]));
  2282.   {$ENDIF}
  2283. end;
  2284. {------------------------------------------------------------------------------}
  2285. { Stores itself in the ini-file, in the section Section.
  2286.   fs is a format string for ini keys. }
  2287. procedure TCustomRVParaInfo.SaveToINI(ini: TRVIniFile; const Section, fs: String);
  2288. begin
  2289.   inherited SaveToINI(ini, Section, fs);
  2290.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_SPACEBEFORE]), SpaceBefore, 0);
  2291.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_SPACEAFTER]),  SpaceAfter,  0);
  2292.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_LEFTINDENT]),  LeftIndent,  0);
  2293.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_RIGHTIDENT]),  RightIndent, 0);
  2294.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_FIRSTINDENT]), FirstIndent, 0);
  2295.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_LINESPACING]), LineSpacing, 100);
  2296.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_LINESPACINGTYPE]), ord(LineSpacingType), ord(rvlsPercent));
  2297.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_ALIGNMENT]),   ord(Alignment), ord(rvaLeft));
  2298.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_BIDIMODE]),   ord(BiDiMode), 0);
  2299.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_NOWRAP]),  rvpaoNoWrap in Options, False);
  2300.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_READONLY]),  rvpaoReadOnly in Options, False);
  2301.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_STYLEPROTECT]),  rvpaoStyleProtect in Options, False);
  2302.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_DONOTWANTRETURNS]), rvpaoDoNotWantReturns in Options, False);
  2303.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_KEEPLINESTOGETHER]), rvpaoKeepLinesTogether in Options, False);
  2304.   WriteBoolToIniIfNE(ini, Section, Format(fs,[RVINI_KEEPWITHNEXT]), rvpaoKeepWithNext in Options, False);
  2305.   Border.SaveToINI(ini,  Section, Format(fs,[RVINI_BORDERPREFIX]));
  2306.   Background.SaveToINI(ini,  Section, Format(fs,[RVINI_BACKGROUNDPREFIX]));
  2307.   {$IFNDEF RVDONOTUSETABS}
  2308.   Tabs.SaveToINI(ini, Section, Format(fs, [RVINI_TABPREFIX]));
  2309.   {$ENDIF}
  2310. end;
  2311. {$ENDIF}
  2312. {------------------------------------------------------------------------------}
  2313. { Saves this paragraph style as a part of CSS to the Stream.
  2314.   if BaseStyle<>nil, only a difference between this style and BaseStyle is
  2315.   saved.
  2316.   If Multiline=False, all text will be written on a single line.
  2317.   If IgnoreLeftAlignment, left value of alignment is not saved.
  2318.   If IgnoreLeftIndents, left and first line indents are not saved. }
  2319. procedure TCustomRVParaInfo.SaveCSSToStream(Stream: TStream; BaseStyle: TParaInfo;
  2320.   Multiline, IgnoreLeftAlignment, IgnoreLeftIndents: Boolean);
  2321. const cssTextAlign  : array[TRVAlignment] of String =
  2322.   ('left', 'right', 'center', 'justify');
  2323.     {..................................................}
  2324.     function GetBorderStyle(bs: TRVBorderStyle): String;
  2325.     begin
  2326.       Result := '';
  2327.       case bs of
  2328.         rvbNone:
  2329.           Result := 'none';
  2330.         rvbSingle:
  2331.           Result := 'solid';
  2332.         rvbDouble, rvbTriple, rvbThickInside, rvbThickOutside:
  2333.           Result := 'double';
  2334.       end;
  2335.     end;
  2336.     {..................................................}
  2337.     function GetBorderWidth(Border: TRVBorder): Integer;
  2338.     begin
  2339.       Result := 0;
  2340.       case Border.Style of
  2341.         rvbSingle:
  2342.           Result := Border.Width;
  2343.         rvbDouble:
  2344.           Result := Border.Width+Border.InternalWidth;
  2345.         rvbThickInside, rvbThickOutside:
  2346.           Result := Border.Width*3 div 2+Border.InternalWidth;
  2347.         rvbTriple:
  2348.           Result := Border.Width+Border.InternalWidth*2;
  2349.       end;
  2350.     end;
  2351.     {..................................................}
  2352. var r, baser: TRect;
  2353. begin
  2354.   if ((BaseStyle=nil) and (not IgnoreLeftAlignment or (Alignment<>rvaLeft))) or
  2355.      ((BaseStyle<>nil) and (BaseStyle.Alignment<>Alignment)) then
  2356.     RVWriteX(Stream, ' text-align: '+cssTextAlign[Alignment]+';', Multiline);
  2357.   if not IgnoreLeftIndents and ((BaseStyle=nil) or (BaseStyle.FirstIndent<>FirstIndent)) then
  2358.     RVWriteX(Stream, Format(' text-indent: %dpx;', [FirstIndent]), Multiline);
  2359.   if ((BaseStyle=nil) and (LineSpacingType=rvlsPercent) and (LineSpacing<>100)) or
  2360.      ((BaseStyle<>nil) and (LineSpacingType=rvlsPercent) and
  2361.       (BaseStyle.LineSpacingType=rvlsPercent) and
  2362.       (LineSpacing<>BaseStyle.LineSpacing)) then
  2363.     RVWriteX(Stream, Format(' line-height: %d.%d;',[LineSpacing div 100, LineSpacing mod 100]), Multiline)
  2364.   else if (BaseStyle<>nil) and (BaseStyle.LineSpacingType=rvlsPercent) and
  2365.      (BaseStyle.LineSpacing<>100) and (LineSpacingType<>rvlsPercent) then
  2366.     RVWriteX(Stream, ' line-height: normal;', Multiline);
  2367.   if rvpaoNoWrap in Options then
  2368.     RVWriteX(Stream, ' white-space: nowrap;', Multiline)
  2369.   else if (BaseStyle<>nil) and (rvpaoNoWrap in BaseStyle.Options) then
  2370.     RVWriteX(Stream, ' white-space: normal;', Multiline);
  2371.   if rvpaoKeepLinesTogether in Options then
  2372.     RVWriteX(Stream, ' page-break-inside: avoid;', Multiline)
  2373.   else if (BaseStyle<>nil) and (rvpaoKeepLinesTogether in BaseStyle.Options) then
  2374.     RVWriteX(Stream, ' page-break-inside: auto;', Multiline);
  2375.   if rvpaoKeepWithNext in Options then
  2376.     RVWriteX(Stream, ' page-break-after: avoid;', Multiline)
  2377.   else if (BaseStyle<>nil) and (rvpaoKeepWithNext in BaseStyle.Options) then
  2378.     RVWriteX(Stream, ' page-break-after: auto;', Multiline);
  2379.   if (Border.Style <> rvbNone) and (Border.Color<>clNone) then begin
  2380.     RVWriteX(Stream, Format(' border-color: %s;', [RV_GetHTMLRGBStr(Border.Color, False)]),
  2381.       Multiline);
  2382.     RVWriteX(Stream, Format(' border-style: %s;', [GetBorderStyle(Border.Style)]),
  2383.       Multiline);
  2384.     RVWriteX(Stream, Format(' border-width: %dpx;', [GetBorderWidth(Border)]),
  2385.       Multiline);
  2386.     if not Border.VisibleBorders.Top then
  2387.       RVWriteX(Stream, ' border-top: none;', Multiline);
  2388.     if not Border.VisibleBorders.Right then
  2389.       RVWriteX(Stream, ' border-right: none;', Multiline);
  2390.     if not Border.VisibleBorders.Bottom then
  2391.       RVWriteX(Stream, ' border-bottom: none;', Multiline);
  2392.     if not Border.VisibleBorders.Left then
  2393.       RVWriteX(Stream, ' border-left: none;', Multiline);
  2394.     Border.BorderOffsets.AssignToRect(r);
  2395.     end
  2396.   else begin
  2397.     if (BaseStyle<>nil) and (BaseStyle.Border.Style <> rvbNone) and
  2398.        (BaseStyle.Border.Color<>clNone) then
  2399.       RVWriteX(Stream, ' border: none;', Multiline);
  2400.     r := Rect(0,0,0,0);
  2401.     //RVWriteX(Stream, ' border: none;', Multiline);
  2402.   end;
  2403.   if (BaseStyle<>nil) and (BaseStyle.Border.Style <> rvbNone) and
  2404.     (BaseStyle.Border.Color<>clNone) then
  2405.     BaseStyle.Border.BorderOffsets.AssignToRect(baser)
  2406.   else
  2407.     baser := Rect(0,0,0,0);
  2408.   if ((BaseStyle=nil) and (Background.Color<>clNone)) or
  2409.      ((BaseStyle<>nil) and (Background.Color<>BaseStyle.Background.Color)) then
  2410.     RVWriteX(Stream,
  2411.       Format(' background: %s;', [RV_GetCSSBkColor(Background.Color)]), Multiline);
  2412.   if Background.Color<>clNone then
  2413.     Background.BorderOffsets.AssignToRectIfGreater(r);
  2414.   if (BaseStyle=nil) or not AreRectsEqual(baser,r) then
  2415.     with r do
  2416.       RVWriteX(Stream, Format(' padding: %dpx %dpx %dpx %dpx;',
  2417.         [Top, Right, Bottom, Left]), Multiline);
  2418.   if (BaseStyle<>nil) then begin
  2419.     baser.Left   := BaseStyle.LeftIndent-baser.Left;
  2420.     baser.Right  := BaseStyle.RightIndent-baser.Right;
  2421.     baser.Top    := BaseStyle.SpaceBefore-baser.Top;
  2422.     baser.Bottom := BaseStyle.SpaceAfter-baser.Bottom;
  2423.   end;
  2424.   r.Left   := LeftIndent-r.Left;
  2425.   r.Right  := RightIndent-r.Right;
  2426.   r.Top    := SpaceBefore-r.Top;
  2427.   r.Bottom := SpaceAfter-r.Bottom;
  2428.   if (BaseStyle=nil) or not AreRectsEqual(baser,r) then
  2429.     with r do
  2430.       if not IgnoreLeftIndents then
  2431.         RVWriteX(Stream, Format(' margin: %dpx %dpx %dpx %dpx;',
  2432.           [Top, Right, Bottom, Left]), Multiline)
  2433.       else begin
  2434.         RVWriteX(Stream, Format(' margin-top: %dpx;', [Top]), Multiline);
  2435.         RVWriteX(Stream, Format(' margin-right: %dpx;', [Right]), Multiline);
  2436.         RVWriteX(Stream, Format(' margin-bottom: %dpx;', [Bottom]), Multiline);
  2437.       end;
  2438. end;
  2439. {=================================== TParaInfo ================================}
  2440. { Constructor }
  2441. constructor TParaInfo.Create(Collection: TCollection);
  2442. begin
  2443.   inherited Create(Collection);
  2444.   NextParaNo  := -1;
  2445.   DefStyleNo  := -1;
  2446. end;
  2447. {------------------------------------------------------------------------------}
  2448. { Assigns Source to Self, if Source is TCustomRVParaInfo }
  2449. procedure TParaInfo.Assign(Source: TPersistent);
  2450. begin
  2451.   if Source is TParaInfo then begin
  2452.     NextParaNo  := TParaInfo(Source).NextParaNo;
  2453.     DefStyleNo  := TParaInfo(Source).DefStyleNo;
  2454.     {$IFNDEF RVDONOTUSESTYLETEMPLATES}
  2455.     ModifiedProperties1 := TParaInfo(Source).ModifiedProperties1;
  2456.     ModifiedProperties2 := TParaInfo(Source).ModifiedProperties2;
  2457.     {$ENDIF}
  2458.   end;
  2459.   inherited Assign(Source);
  2460. end;
  2461. {------------------------------------------------------------------------------}
  2462. {$IFNDEF RVDONOTUSESTYLETEMPLATES}
  2463. procedure TParaInfo.ExcludeUnmodifiedProperties(Source: TCustomRVParaInfo;
  2464.   PossibleProps: TRVParaInfoProperties);
  2465.    {.............................................................}
  2466.    procedure ChangeOption(Option: TRVParaOption; OptionId: TRVParaInfoProperty2);
  2467.    begin
  2468.      if (OptionId in PossibleProps) and
  2469.         ((Option in Options)=(Option in Source.Options)) then
  2470.        Exclude(FModifiedProperties2, OptionId);
  2471.    end;
  2472.    {.............................................................}
  2473. begin
  2474.   if (rvpiFirstIndent in PossibleProps) and (FirstIndent=Source.FirstIndent) then
  2475.     Exclude(FModifiedProperties1, rvpiFirstIndent);
  2476.   if (rvpiLeftIndent in PossibleProps) and (LeftIndent=Source.LeftIndent) then
  2477.     Exclude(FModifiedProperties1, rvpiLeftIndent);
  2478.   if (rvpiRightIndent in PossibleProps) and (RightIndent=Source.RightIndent) then
  2479.     Exclude(FModifiedProperties1, rvpiRightIndent);
  2480.   if (rvpiSpaceBefore in PossibleProps) and (SpaceBefore=Source.SpaceBefore) then
  2481.     Exclude(FModifiedProperties1, rvpiSpaceBefore);
  2482.   if (rvpiSpaceAfter in PossibleProps) and (SpaceAfter=Source.SpaceAfter) then
  2483.     Exclude(FModifiedProperties1, rvpiSpaceAfter);
  2484.   if (rvpiAlignment in PossibleProps) and (Alignment=Source.Alignment) then
  2485.     Exclude(FModifiedProperties1, rvpiAlignment);
  2486.   if (rvpiLineSpacing in PossibleProps) and (LineSpacing=Source.LineSpacing) then
  2487.     Exclude(FModifiedProperties1, rvpiLineSpacing);
  2488.   if (rvpiLineSpacingType in PossibleProps) and (LineSpacingType=Source.LineSpacingType) then
  2489.     Exclude(FModifiedProperties1, rvpiLineSpacingType);
  2490.   if (rvpiBackground_Color in PossibleProps) and (Background.Color=Source.Background.Color) then
  2491.     Exclude(FModifiedProperties1, rvpiBackground_Color);
  2492.   if (rvpiBackground_BO_Left in PossibleProps) and
  2493.      (Background.BorderOffsets.Left=Source.Background.BorderOffsets.Left) then
  2494.     Exclude(FModifiedProperties1, rvpiBackground_BO_Left);
  2495.   if (rvpiBackground_BO_Top in PossibleProps) and
  2496.      (Background.BorderOffsets.Top=Source.Background.BorderOffsets.Top) then
  2497.     Exclude(FModifiedProperties1, rvpiBackground_BO_Top);
  2498.   if (rvpiBackground_BO_Right in PossibleProps) and
  2499.      (Background.BorderOffsets.Right=Source.Background.BorderOffsets.Right) then
  2500.     Exclude(FModifiedProperties1, rvpiBackground_BO_Right);
  2501.   if (rvpiBackground_BO_Bottom in PossibleProps) and
  2502.      (Background.BorderOffsets.Bottom=Source.Background.BorderOffsets.Bottom) then
  2503.     Exclude(FModifiedProperties1, rvpiBackground_BO_Bottom);
  2504.   if (rvpiBorder_Style in PossibleProps) and (Border.Style=Source.Border.Style) then
  2505.     Exclude(FModifiedProperties1, rvpiBorder_Style);
  2506.   if (rvpiBorder_Color in PossibleProps) and (Border.Color=Source.Border.Color) then
  2507.     Exclude(FModifiedProperties1, rvpiBorder_Color);
  2508.   if (rvpiBorder_Width in PossibleProps) and (Border.Width=Source.Border.Width) then
  2509.     Exclude(FModifiedProperties1, rvpiBorder_Width);
  2510.   if (rvpiBorder_InternalWidth in PossibleProps) and (Border.Width=Source.Border.InternalWidth) then
  2511.     Exclude(FModifiedProperties1, rvpiBorder_InternalWidth);
  2512.   if (rvpiBorder_BO_Left in PossibleProps) and
  2513.      (Border.BorderOffsets.Left=Source.Border.BorderOffsets.Left) then
  2514.     Exclude(FModifiedProperties1, rvpiBorder_BO_Left);
  2515.   if (rvpiBorder_BO_Top in PossibleProps) and
  2516.      (Border.BorderOffsets.Top=Source.Border.BorderOffsets.Top) then
  2517.     Exclude(FModifiedProperties1, rvpiBorder_BO_Top);
  2518.   if (rvpiBorder_BO_Right in PossibleProps) and
  2519.      (Border.BorderOffsets.Right=Source.Border.BorderOffsets.Right) then
  2520.     Exclude(FModifiedProperties1, rvpiBorder_BO_Right);
  2521.   if (rvpiBorder_BO_Bottom in PossibleProps) and
  2522.      (Border.BorderOffsets.Bottom=Source.Border.BorderOffsets.Bottom) then
  2523.     Exclude(FModifiedProperties1, rvpiBorder_BO_Bottom);
  2524.   if (rvpiBorder_Vis_Left in PossibleProps) and
  2525.      (Border.VisibleBorders.Left=Source.Border.VisibleBorders.Left) then
  2526.     Exclude(FModifiedProperties1, rvpiBorder_Vis_Left);
  2527.   if (rvpiBorder_Vis_Top in PossibleProps) and
  2528.      (Border.VisibleBorders.Top=Source.Border.VisibleBorders.Top) then
  2529.     Exclude(FModifiedProperties1, rvpiBorder_Vis_Top);
  2530.   if (rvpiBorder_Vis_Right in PossibleProps) and
  2531.      (Border.VisibleBorders.Right=Source.Border.VisibleBorders.Right) then
  2532.     Exclude(FModifiedProperties1, rvpiBorder_Vis_Right);
  2533.   if (rvpiBorder_Vis_Bottom in PossibleProps) and
  2534.      (Border.VisibleBorders.Bottom=Source.Border.VisibleBorders.Bottom) then
  2535.     Exclude(FModifiedProperties1, rvpiBorder_Vis_Bottom);
  2536.   ChangeOption(rvpaoNoWrap, rvpiNoWrap);
  2537.   ChangeOption(rvpaoReadOnly, rvpiReadOnly);
  2538.   ChangeOption(rvpaoStyleProtect, rvpiStyleProtect);
  2539.   ChangeOption(rvpaoDoNotWantReturns, rvpiDoNotWantReturns);
  2540.   ChangeOption(rvpaoKeepLinesTogether, rvpiKeepLinesTogether);
  2541.   ChangeOption(rvpaoKeepWithNext, rvpiKeepWithNext);
  2542.   if (rvpiTabs in PossibleProps) and Tabs.IsEqual(Source.Tabs) then
  2543.     Exclude(FModifiedProperties2, rvpiTabs);
  2544.   if (rvpiBiDiMode in PossibleProps) and (BiDiMode=Source.BiDiMode) then
  2545.     Exclude(FModifiedProperties2, rvpiBiDiMode);
  2546. end;
  2547. {$ENDIF}
  2548. {------------------------------------------------------------------------------}
  2549. {$IFNDEF RVDONOTUSEINI}
  2550. { Loads itself from the ini-file, from the section Section.
  2551.   fs is a format string for ini keys. }
  2552. procedure TParaInfo.LoadFromINI(ini: TRVIniFile; const Section,
  2553.   fs: String);
  2554. begin
  2555.   inherited LoadFromINI(ini, Section, fs);
  2556.   NextParaNo  := ini.ReadInteger(Section,  Format(fs,[RVINI_NEXTPARANO]), -1);
  2557.   DefStyleNo  := ini.ReadInteger(Section,  Format(fs,[RVINI_DEFSTYLENO]), -1);
  2558. end;
  2559. {------------------------------------------------------------------------------}
  2560. { Stores itself in the ini-file, in the section Section.
  2561.   fs is a format string for ini keys. }
  2562. procedure TParaInfo.SaveToINI(ini: TRVIniFile; const Section, fs: String);
  2563. begin
  2564.   inherited SaveToINI(ini, Section, fs);
  2565.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_NEXTPARANO]), NextParaNo, -1);
  2566.   WriteIntToIniIfNE(ini, Section, Format(fs,[RVINI_DEFSTYLENO]), DefStyleNo, -1);
  2567. end;
  2568. {$ENDIF}
  2569. {------------------------------------------------------------------------------}
  2570. { Is this paragraph style equal to Value?
  2571.   Mapping is used to compare NextParaNo.
  2572.   Mapping is from the Value's collection to this collection, see
  2573.   TCustomRVInfos.MergeWith.
  2574. }
  2575. function TParaInfo.IsSimpleEqualEx(Value: TCustomRVInfo;
  2576.   Mapping: TRVIntegerList): Boolean;
  2577. begin
  2578.   Result := IsSimpleEqual(Value, True, False);
  2579.   if not Result then
  2580.     exit;
  2581.   if Value is TParaInfo then begin
  2582.     Result := False;
  2583.     {
  2584.     if (Value.BaseStyleNo>=0) then begin
  2585.       if (Value.BaseStyleNo>=Mapping.Count) then
  2586.         Value.BaseStyleNo := -1 // fix up
  2587.       else if (Mapping[Value.BaseStyleNo]<>BaseStyleNo) then
  2588.         exit;
  2589.     end;
  2590.     }
  2591.     if (TParaInfo(Value).NextParaNo>=0) then begin
  2592.       if (TParaInfo(Value).NextParaNo>=Mapping.Count) then
  2593.         TParaInfo(Value).NextParaNo := -1 // fix up
  2594.       else if (Mapping[TParaInfo(Value).NextParaNo]<>NextParaNo) then
  2595.         exit;
  2596.     end;
  2597.     Result := True;
  2598.   end;
  2599. end;
  2600. {------------------------------------------------------------------------------}
  2601. { Is this paragraph style equal to Value?
  2602.   If IgnoreReferences, NextParaNo and DefStyleNo are ignored.
  2603.   IgnoreID parameter is not used.
  2604.   BaseStyleNo is ignored. }
  2605. function TParaInfo.IsSimpleEqual(Value: TCustomRVInfo; IgnoreReferences,
  2606.   IgnoreID: Boolean): Boolean;
  2607. begin
  2608.   Result := inherited IsSimpleEqual(Value, IgnoreReferences, IgnoreID);
  2609.   if not Result then
  2610.     exit;
  2611.   if Value is TParaInfo then
  2612.     Result :=
  2613.       {$IFNDEF RVDONOTUSESTYLETEMPLATES}
  2614.       (ModifiedProperties1 = TParaInfo(Value).ModifiedProperties1) and
  2615.       (ModifiedProperties2 = TParaInfo(Value).ModifiedProperties2) and
  2616.       (StyleTemplateID = TParaInfo(Value).StyleTemplateID) and
  2617.       {$ENDIF}
  2618.       (IgnoreReferences or (NextParaNo = TParaInfo(Value).NextParaNo)) and
  2619.       (IgnoreReferences or (DefStyleNo = TParaInfo(Value).DefStyleNo));
  2620. end;
  2621. {------------------------------------------------------------------------------}
  2622. { Is the specified properties of this paragraph style equal to the properties of
  2623.   Value. IgnoreList lists properties which will be ignored when comparing.
  2624.   BaseStyleNo is always ignored. }
  2625. function TParaInfo.IsEqual(Value: TCustomRVParaInfo;
  2626.   IgnoreList: TRVParaInfoProperties): Boolean;
  2627. begin
  2628.   Result := inherited IsEqual(Value, IgnoreList);
  2629.   if Result and (Value is TParaInfo) then begin
  2630.     Result := ((rvpiNextParaNo in IgnoreList) or (NextParaNo = TParaInfo(Value).NextParaNo)) and
  2631.               ((rvpiDefStyleNo in IgnoreList) or (DefStyleNo = TParaInfo(Value).DefStyleNo))
  2632.               {$IFNDEF RVDONOTUSESTYLETEMPLATES}
  2633.               and
  2634.               (StyleTemplateId=Value.StyleTemplateId) and
  2635.               (ModifiedProperties1=TParaInfo(Value).ModifiedProperties1) and
  2636.               (ModifiedProperties2=TParaInfo(Value).ModifiedProperties2)
  2637.               {$ENDIF}
  2638.               ;
  2639.   end
  2640. end;
  2641. {============================== TParaInfos ====================================}
  2642. destructor TParaInfos.Destroy; 
  2643. begin
  2644.   FInvalidItem.Free;
  2645.   inherited Destroy;
  2646. end;
  2647. {------------------------------------------------------------------------------}
  2648. { Assigns style names to TStrings. Called from TStrings.Assign. }
  2649. procedure TParaInfos.AssignTo(Dest: TPersistent);
  2650. var i: Integer;
  2651. begin
  2652.   if Dest is TStrings then begin
  2653.     TStrings(Dest).Clear;
  2654.     for i:=0 to Count-1 do
  2655.       TStrings(Dest).Add(Items[i].FName);
  2656.     end