Adjusting paragraph border, background and indents

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

Adjusting paragraph border, background and indents

Post by Sergey Tkachenko » Wed Jan 11, 2017 12:07 pm

For paragraphs in TRichView, offsets of borders, background, and indents are defined independently. All offsets are counted from contents.

On one hand, this approach allows making interesting effects, like
Image
On the other hand, if SpaceBefore, SpaceAfter, LeftIndent, RightIndent are not large enough, border and background may overlap adjacent paragraphs (if you use RichViewActions, they always assign spacing and indents large enough, but if you do it manually, this overlapping may happen).
Also, not all combinations are possible in HTML or Microsoft Word. In HTML, border is always drawn exactly inside background. In MS Word, border is drawn exactly outside background.
So, if your application is primarily designed for HTML/RTF/DocX export, you may wish to make the same border/background relation in TRichView.

The procedure below adjusts border, background, and intents of all paragraphs in existing documents. It always makes indents (SpaceBefore, SpaceAfter, LeftIndent, RightIndent) large enough to cover border and background.
Additionally, it adjusts borders and background; there are some options, see below.

Code: Select all

type
  TBorderMode = (bmFree, bmAroundBackground, bmBackgroundInBorder, bmAroundBackgroundNoSpacing);

procedure NormalizePara(ParaInfo: TParaInfo; BorderMode: TBorderMode);

  procedure NormalizeIndents(Offsets: TRVRect; w: Integer);
  begin
    if ParaInfo.LeftIndent < Offsets.Left + w then
      ParaInfo.LeftIndent := Offsets.Left + w;
    if ParaInfo.SpaceBefore < Offsets.Top + w then
      ParaInfo.SpaceBefore := Offsets.Top + w;
    if ParaInfo.RightIndent < Offsets.Right + w then
      ParaInfo.RightIndent := Offsets.Right + w;
    if ParaInfo.SpaceAfter < Offsets.Bottom + w then
      ParaInfo.SpaceAfter := Offsets.Bottom + w;
  end;

  procedure MakeNonNegative(Offsets: TRVRect);
  begin
    Offsets.Left := Max(Offsets.Left, 0);
    Offsets.Right := Max(Offsets.Right, 0);
    Offsets.Top := Max(Offsets.Top, 0);
    Offsets.Bottom := Max(Offsets.Bottom, 0);
  end;

  procedure MakeOffsetsAtLeast(Offsets, SampleOffsets: TRVRect);
  begin
    Offsets.Left := Max(Offsets.Left, SampleOffsets.Left);
    Offsets.Right := Max(Offsets.Right, SampleOffsets.Right);
    Offsets.Top := Max(Offsets.Top, SampleOffsets.Top);
    Offsets.Bottom := Max(Offsets.Bottom, SampleOffsets.Bottom);
  end;

  procedure MoveInside(Offsets, SampleOffsets: TRVRect; w: Integer);
  begin
    Offsets.Left := SampleOffsets.Left + w;
    Offsets.Right := SampleOffsets.Right + w;
    Offsets.Top := SampleOffsets.Top + w;
    Offsets.Bottom := SampleOffsets.Bottom + w;
  end;

begin
  MakeNonNegative(ParaInfo.Border.BorderOffsets);
  MakeNonNegative(ParaInfo.Background.BorderOffsets);
  if ParaInfo.Border.Style <> rvbNone then
  begin

    case BorderMode of
      bmAroundBackground:
        MakeOffsetsAtLeast(ParaInfo.Border.BorderOffsets,
          ParaInfo.Background.BorderOffsets);
      bmBackgroundInBorder:
        if ParaInfo.Background.Color <> clNone then
           MoveInside(ParaInfo.Background.BorderOffsets,
             ParaInfo.Border.BorderOffsets,
             ParaInfo.Border.GetTotalWidth);
      bmAroundBackgroundNoSpacing:
        ParaInfo.Border.BorderOffsets.Assign(ParaInfo.Background.BorderOffsets);
    end;
    NormalizeIndents(ParaInfo.Border.BorderOffsets,
      ParaInfo.Border.GetTotalWidth);
  end;
  if ParaInfo.Background.Color <> clNone then
    NormalizeIndents(ParaInfo.Background.BorderOffsets, 0);
end;

procedure NormalizeParagraphs(RVStyle: TRVStyle; BorderMode: TBorderMode);
var
  i: Integer;
begin
  for i := 0 to RVStyle.ParaStyles.Count - 1 do
    NormalizePara(RVStyle.ParaStyles[i], BorderMode);
end;
Test:

Code: Select all

procedure TForm3.ToolButton63Click(Sender: TObject);
begin
  NormalizeParagraphs(RichViewEdit1.Style, bmBackgroundInBorder);
  RichViewEdit1.Format;
end;
Options for BorderMode parameter:
* bmFree - border and background are not changed
* bmAroundBackground - border is changed so it is outside background (spacing between them is possible)
* bmBackgroundInBorder - background is changed to external side of border (this option corresponds to HTML)
* bmAroundBackgroundNoSpacing - border is changed so it is outside background (without spacing between them) (this option corresponds to Microsoft Word formats)

Update: MoveInside() corrected

Post Reply