areruler.pas

来自「delphi编程控件」· PAS 代码 · 共 768 行 · 第 1/2 页

PAS
768
字号
unit ARERuler;

interface

uses
  Windows, Messages, Classes, Controls, Forms, ARichEd;

type
  TFirstIndentMark = class(TCustomControl)
  protected
    procedure CreateWnd; override;
    procedure Paint; override;
    procedure WndProc(var Message: TMessage); override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TLeftIndentMark = class(TCustomControl)
  protected
    procedure CreateWnd; override;
    procedure Paint; override;
    procedure WndProc(var Message: TMessage); override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TRightIndentMark = class(TCustomControl)
  protected
    procedure CreateWnd; override;
    procedure Paint; override;
    procedure WndProc(var Message: TMessage); override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TAutoRichEditRulerBorderStyle = (rbsNone, rbsRaised, rbsLowered);
  TAutoRichEditRulerDragType =
    (dtNone, dtFirstIndent, dtLeftIndent, dtRightIndent, dtOffset);

  TAutoRichEditRuler = class(TCustomControl)
  private
    FBorderStyle: TAutoRichEditRulerBorderStyle;
    FDragType: TAutoRichEditRulerDragType;
    FFirstIndentMark: TFirstIndentMark;
    FLeftIndentMark: TLeftIndentMark;
    FLockRichEditUpdate: Boolean;
    FPixelsPerInch: Integer;
    FPrevDragX: Integer;
    FRichEdit: TAutoRichEdit;
    FRightIndentMark: TRightIndentMark;

    function ClientToScreenX(Value: Integer): Integer;
    function CmToPixels(Value: Integer): Integer;
    function CmToTwips(Value: Integer): Integer;
    procedure DrawDragLine(X: Integer);
    procedure DrawInchMarks;
    function PixelsToCm(Value: Integer): Integer;
    function PixelsToTwips(Value: Integer): Integer;
    function TwipsToPixels(Value: Integer): Integer;

    function GetDraggingMark: TWinControl;
    function GetLeftMargin: Integer;
    function GetRightMargin: Integer;
    procedure SetBorderStyle(Value: TAutoRichEditRulerBorderStyle);
    procedure SetDragType(Value: TAutoRichEditRulerDragType);
    procedure SetRichEdit(Value: TAutoRichEdit);

    procedure WMEraseBkGnd(var Message: TWMEraseBkGnd); message WM_ERASEBKGND;
    procedure WMMove(var Message: TWMMove); message WM_MOVE;
    procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE;
    procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure Paint; override;

    property DraggingMark: TWinControl read GetDraggingMark;
    property DragType: TAutoRichEditRulerDragType read FDragType
      write SetDragType;
    property LeftMargin: Integer read GetLeftMargin;
    property RightMargin: Integer read GetRightMargin;
  public
    constructor Create(AOwner: TComponent); override;
    procedure RichEditChanged(Redraw: Boolean); virtual;
  published
    property Align;
    property AutoRichEdit: TAutoRichEdit read FRichEdit write SetRichEdit;
    property BorderStyle: TAutoRichEditRulerBorderStyle read FBorderStyle
      write SetBorderStyle default rbsNone;
  end;

implementation

uses
  SysUtils, Graphics;

const
  sAutoRichEditRulerFirstIndentHint = 'First Line Indent';
  sAutoRichEditRulerLeftIndentHint = 'Left Indent';
  sAutoRichEditRulerRightIndentHint = 'Right Indent';

{ TFirstIndentMark }

constructor TFirstIndentMark.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle + [csOpaque];
  Hint := sAutoRichEditRulerFirstIndentHint;
  ShowHint := True;
  Width := 9;
  Height := 8;
end;

procedure TFirstIndentMark.CreateWnd;
var
  P: array[1..6] of TPoint;
  FRegion: HRGN;
begin
  inherited;
  P[1] := Point(5, 8);
  P[2] := Point(0, 3);
  P[3] := Point(0, 0);
  P[4] := Point(9, 0);
  P[5] := Point(9, 3);
  P[6] := Point(4, 8);
  FRegion := CreatePolygonRgn(P, 6, WINDING);
  SetWindowRgn(Handle, FRegion, False);
end;

procedure TFirstIndentMark.Paint;
var
  P: array[1..6] of TPoint;
begin
  inherited Paint;
  with Canvas do
  begin
    P[1] := Point(4, 7);
    P[2] := Point(0, 3);
    P[3] := Point(0, 0);
    P[4] := Point(8, 0);
    P[5] := Point(8, 3);
    P[6] := P[1];
    Pen.Color := clBlack;
    Polyline(P);
    // draw highlight parts
    P[1] := Point(3, 5);
    P[2] := Point(1, 3);
    P[3] := Point(1, 1);
    P[4] := Point(7, 1);
    Pen.Color := clBtnHighlight;
    Polyline(Slice(P, 4));
  end;
end;

procedure TFirstIndentMark.WndProc(var Message: TMessage);
begin
  with TWMMouse(Message) do
    if (Msg = WM_LBUTTONDOWN) or (Msg = WM_MOUSEMOVE) then
    begin
      if Msg = WM_LBUTTONDOWN then
        TAutoRichEditRuler(Parent).DragType := dtFirstIndent;
      Pos := PointToSmallPoint(
        Parent.ScreenToClient(ClientToScreen(SmallPointToPoint(Pos))));
      Result := SendMessage(Parent.Handle, Msg, Keys, Longint(Pos));
    end
    else
      if (Msg = WM_LBUTTONDBLCLK) and
        (TAutoRichEditRuler(Parent).AutoRichEdit <> nil) then
        TAutoRichEditRuler(Parent).AutoRichEdit.ParagraphDialog
      else inherited;
  if Message.Msg = WM_MOVE then Top := 2;
end;

{ TLeftIndentMark }

constructor TLeftIndentMark.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle + [csOpaque];
  Hint := sAutoRichEditRulerLeftIndentHint;
  ShowHint := True;
  Width := 9;
  Height := 14;
end;

procedure TLeftIndentMark.CreateWnd;
var
  P: array[1..6] of TPoint;
  FRegion: HRGN;
begin
  inherited;
  P[1] := Point(4, 0);
  P[2] := Point(0, 4);
  P[3] := Point(0, 14);
  P[4] := Point(9, 14);
  P[5] := Point(9, 4);
  P[6] := Point(5, 0);
  FRegion := CreatePolygonRgn(P, 6, WINDING);
  SetWindowRgn(Handle, FRegion, False);
end;

procedure TLeftIndentMark.Paint;
var
  P: array[1..6] of TPoint;
begin
  inherited Paint;
  with Canvas do
  begin
    P[1] := Point(4, 0);
    P[2] := Point(0, 4);
    P[3] := Point(0, 13);
    P[4] := Point(8, 13);
    P[5] := Point(8, 4);
    P[6] := P[1];
    Pen.Color := clBlack;
    Polyline(P);
    MoveTo(1, 7);
    LineTo(8, 7);
    // draw highlight parts
    P[1] := Point(4, 1);
    P[2] := Point(1, 4);
    P[3] := Point(1, 6);
    Pen.Color := clBtnHighlight;
    Polyline(Slice(P, 3));
    P[1] := Point(1, 11);
    P[2] := Point(1, 8);
    P[3] := Point(7, 8);
    Polyline(Slice(P, 3));
  end;
end;

procedure TLeftIndentMark.WndProc(var Message: TMessage);
begin
  with TWMMouse(Message) do
    if (Msg = WM_LBUTTONDOWN) or (Msg = WM_MOUSEMOVE) then
    begin
      if Msg = WM_LBUTTONDOWN then
        with TAutoRichEditRuler(Parent) do
          if HiWord(Message.lParam) < 7 then DragType := dtOffset
          else DragType := dtLeftIndent;
      Pos := PointToSmallPoint(
        Parent.ScreenToClient(ClientToScreen(SmallPointToPoint(Pos))));
      Result := SendMessage(Parent.Handle, Msg, Keys, Longint(Pos));
    end
    else
      if (Msg = WM_LBUTTONDBLCLK) and
        (TAutoRichEditRuler(Parent).AutoRichEdit <> nil) then
        TAutoRichEditRuler(Parent).AutoRichEdit.ParagraphDialog
      else inherited;
  if Message.Msg = WM_MOVE then Top := 10;
end;

{ TRightIndentMark }

constructor TRightIndentMark.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle + [csOpaque];
  Hint := sAutoRichEditRulerRightIndentHint;
  ShowHint := True;
  Width := 9;
  Height := 8;
end;

procedure TRightIndentMark.CreateWnd;
var
  P: array[1..6] of TPoint;
  FRegion: HRGN;
begin
  inherited;
  P[1] := Point(4, 0);
  P[2] := Point(0, 4);
  P[3] := Point(0, 8);
  P[4] := Point(9, 8);
  P[5] := Point(9, 4);
  P[6] := Point(5, 0);
  FRegion := CreatePolygonRgn(P, 6, WINDING);
  SetWindowRgn(Handle, FRegion, False);
end;

procedure TRightIndentMark.Paint;
var
  P: array[1..6] of TPoint;
begin
  inherited Paint;
  with Canvas do
  begin
    P[1] := Point(4, 0);
    P[2] := Point(0, 4);
    P[3] := Point(0, 7);
    P[4] := Point(8, 7);
    P[5] := Point(8, 4);
    P[6] := P[1];
    Pen.Color := clBlack;
    Polyline(P);
    // draw highlight parts
    P[1] := Point(4, 1);
    P[2] := Point(1, 4);
    P[3] := Point(1, 6);
    Pen.Color := clBtnHighlight;
    Polyline(Slice(P, 3));
  end;
end;

procedure TRightIndentMark.WndProc(var Message: TMessage);
begin
  with TWMMouse(Message) do
    if (Msg = WM_LBUTTONDOWN) or (Msg = WM_MOUSEMOVE) then
    begin
      if Msg = WM_LBUTTONDOWN then
        TAutoRichEditRuler(Parent).DragType := dtRightIndent;
      Pos := PointToSmallPoint(
        Parent.ScreenToClient(ClientToScreen(SmallPointToPoint(Pos))));
      Result := SendMessage(Parent.Handle, Msg, Keys, Longint(Pos));
    end
    else
      if (Msg = WM_LBUTTONDBLCLK) and
        (TAutoRichEditRuler(Parent).AutoRichEdit <> nil) then
        TAutoRichEditRuler(Parent).AutoRichEdit.ParagraphDialog
      else inherited;
  if Message.Msg = WM_MOVE then Top := 10;
end;

{ TAutoRichEditRuler }

constructor TAutoRichEditRuler.Create(AOwner: TComponent);
var
  DC: HDC;
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csOpaque];
  FBorderStyle := rbsNone;
  FFirstIndentMark := TFirstIndentMark.Create(Self);
  FFirstIndentMark.Parent := Self;
  FLeftIndentMark := TLeftIndentMark.Create(Self);
  FLeftIndentMark.Parent := Self;
  FPrevDragX := -1;
  FRightIndentMark := TRightIndentMark.Create(Self);
  FRightIndentMark.Parent := Self;
  Width := 220;
  DC := GetDC(0);
  FPixelsPerInch := GetDeviceCaps(DC, LOGPIXELSX);
  ReleaseDC(0, DC);
end;

function TAutoRichEditRuler.ClientToScreenX(Value: Integer): Integer;
begin
  Result := ClientToScreen(Point(Value, 0)).X;
end;

// Value is in hundredth of centimetre
function TAutoRichEditRuler.CmToPixels(Value: Integer): Integer;
begin
  Result := MulDiv(Value, FPixelsPerInch, 254);
end;

// Value is in hundredth of centimetre
function TAutoRichEditRuler.CmToTwips(Value: Integer): Integer;
begin
  Result := MulDiv(Value, 1440, 254);
end;

procedure TAutoRichEditRuler.DrawDragLine(X: Integer);
var
  Y1, Y2: Integer;
  DC: HDC;
  Pen: HPEN;
begin
  with FRichEdit do
  begin
    Y1 := ClientToScreen(Point(0, 0)).Y;
    Y2 := Y1 + ClientHeight;
  end;
  DC := GetWindowDC(0);
  SetROP2(DC, R2_NOTXORPEN);
  Pen := CreatePen(PS_DOT, 1, COLOR_WINDOWTEXT);
  SelectObject(DC, Pen);
  MoveToEx(DC, X, Y1, nil);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?