Table of Contents

Ruler appearance and events

The horizontal ruler exposes separate appearance settings for the ruler body, page-margin fill, indent markers, tab stops, tick marks, and labels. It also raises live and committed change events so applications can update status text during a drag while deferring heavier work until the drag finishes.

Theme the ruler

Use Appearance when the ruler needs to match the editor surface or product theme. The fill, stroke, font, tab, and tick-mark settings can be changed independently.

procedure TForm1.ThemeRuler;
begin
  with TMSFNCRichEditorHorizontalRuler1.Appearance do
  begin
    // Ruler body and the shaded page-margin area.
    RulerFill.Kind   := gfkSolid;
    RulerFill.Color  := gcWhite;
    MarginFill.Kind  := gfkSolid;
    MarginFill.Color := gcLightgray;

    // Indent markers: fill plus outline stroke.
    IndentFill.Kind    := gfkSolid;
    IndentFill.Color   := gcSteelblue;
    IndentStroke.Kind  := gskSolid;
    IndentStroke.Color := gcDarkslategray;

    // Tab stops, tick marks, and the tick-label font.
    TabColor      := gcSteelblue;
    TabColorMoving := gcSilver;
    TickMarkColor := gcGray;
    Font.Name     := 'Segoe UI';
    Font.Color    := gcBlack;
  end;
end;

Track user changes

Margin and indent events come in live and committed forms. Use the live event for cheap feedback, such as a status-bar value, and the committed event for document state, persistence, or layout recalculation. Tab events report the affected tab index and indent.

procedure TForm1.FormCreate(Sender: TObject);
begin
  TMSFNCRichEditorHorizontalRuler1.RichEditor := TMSFNCRichEditor1;

  // *Change fires continuously while the user drags a marker; *Changed fires
  // once when the drag is committed. Use Changed for expensive work.
  TMSFNCRichEditorHorizontalRuler1.OnLeftMarginChange   := DoMarginDragging;
  TMSFNCRichEditorHorizontalRuler1.OnLeftMarginChanged  := DoMarginCommitted;

  // Tab events report the affected index and its indent position.
  TMSFNCRichEditorHorizontalRuler1.OnTabAdded := DoTabAdded;
end;

procedure TForm1.DoMarginDragging(Sender: TObject; Indent: Integer);
begin
  // Live preview while dragging - keep this handler cheap.
  StatusBar1.Panels[0].Text := Format('Left margin: %d', [Indent]);
end;

procedure TForm1.DoMarginCommitted(Sender: TObject; Indent: Integer);
begin
  // Final value once the user releases the marker.
  FDocumentDirty := True;
end;

procedure TForm1.DoTabAdded(Sender: TObject; Index: Integer; Indent: Integer);
begin
  StatusBar1.Panels[1].Text := Format('Tab %d at %d', [Index, Indent]);
end;

Custom drawing

Handle the before-draw events when a marker needs custom visuals. Set ADefaultDraw to False after drawing the replacement so the ruler does not paint the built-in marker on top.

procedure TForm1.FormCreate(Sender: TObject);
begin
  TMSFNCRichEditorHorizontalRuler1.OnBeforeDrawLeftMargin := DoDrawLeftMargin;
end;

procedure TForm1.DoDrawLeftMargin(Sender: TObject; AGraphics: TTMSFNCGraphics;
  AType: TTMSFNCRichEditorRulerTabType; AMargin: Integer; ARect: TRectF;
  var AAllow: Boolean; var ADefaultDraw: Boolean);
begin
  // Paint a soft highlight band for the left margin area, then tell the ruler
  // to skip its own default drawing for this marker.
  AGraphics.Fill.Kind  := gfkSolid;
  AGraphics.Fill.Color := gcLightyellow;
  AGraphics.Stroke.Kind := gskSolid;
  AGraphics.Stroke.Color := gcSteelblue;
  AGraphics.DrawRectangle(ARect);

  ADefaultDraw := False;   // replace the built-in marker drawing
end;

Pitfalls

  • Keep live-change handlers cheap. Drag events can fire many times while the pointer is moving.
  • Only suppress default drawing after rendering a replacement. Leaving both custom drawing and default drawing enabled can make markers look doubled or unclear.

See also