mwcustomedit.pas

来自「本人买的<<VC++项目开发实例>>源代码配套光盘.」· PAS 代码 · 共 1,920 行 · 第 1/5 页

PAS
1,920
字号
{+-----------------------------------------------------------------------------+
 | Class:       TmwCustomEdit
 | Created:     1998-11
 | Last change: 1999-11-18
 | Author:      Martin Waldenburg
 | Description: study on how to create a custom edit control without using
 |              a Windows edit control.
 | Version:     0.90 public beta (see VERSION.RTF for version history)
 | Copyright (c) 1998 Martin Waldenburg
 | All rights reserved.
 |
 | Thanks to : Woo Young Bum, Angus Johnson, Michael Trier, James Jacobson,
 |             Thomas Kurz, Primoz Gabrijelcic, Michael Beck, Andy Jeffries,
 |             Edward Kreis, Brad Stowers, Willo van der Merwe, Bernt Levinsson,
 |             Ted Berg, Michael Hieke, Dragan Grbic, Lucifer, Kees van Spelde,
 |             Hideo Koiso, Albert Research, Theodoros Bebekis, Heedong Lim,
 |             xyeyu, ArentJan Banck, Alexander Reiter, Tohru Hanai,
 |             Winfried Schoettler, Daniel Rodr韌uez Herrera, Hiep Ma,
 |             Nur Ismail, Milan Nikolic, Wynand Breytenbach
 |
 | LICENCE CONDITIONS
 |
 | USE OF THE ENCLOSED SOFTWARE
 | INDICATES YOUR ASSENT TO THE
 | FOLLOWING LICENCE CONDITIONS.
 |
 |
 |
 | These Licence Conditions are exlusively
 | governed by the Law and Rules of the
 | Federal Republic of Germany.
 |
 | Redistribution and use in source and binary form, with or without
 | modification, are permitted provided that the following conditions
 | are met:
 |
 | 1. Redistributions of source code must retain the above copyright
 |    notice, this list of conditions and the following disclaimer.
 |    If the source is modified, the complete original and unmodified
 |    source code has to distributed with the modified version.
 |
 | 2. Redistributions in binary form must reproduce the above
 |    copyright notice, these licence conditions and the disclaimer
 |    found at the end of this licence agreement in the documentation
 |    and/or other materials provided with the distribution.
 |
 | 3. Software using this code must contain a visible line of credit.
 |
 | 4. If my code is used in a "for profit" product, you have to donate
 |    to a registered charity in an amount that you feel is fair.
 |    You may use it in as many of your products as you like.
 |    Proof of this donation must be provided to the author of
 |    this software.
 |
 | 5. If you for some reasons don't want to give public credit to the
 |    author, you have to donate three times the price of your software
 |    product, or any other product including this component in any way,
 |    but no more than $500 US and not less than $200 US, or the
 |    equivalent thereof in other currency, to a registered charity.
 |    You have to do this for every of your products, which uses this
 |    code separately.
 |    Proof of this donations must be provided to the author of
 |    this software.
 |
 |
 | DISCLAIMER:
 |
 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS'.
 |
 | ALL EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 | PARTICULAR PURPOSE ARE DISCLAIMED.
 |
 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 |
 |  Martin.Waldenburg@T-Online.de
 |
 | Known problems:
 |   - dragging cannot be canceled with the chord clicking - don't know how to
 |     fix!
 |
 +----------------------------------------------------------------------------+}

{$I MWEDIT.INC}

unit mwCustomEdit;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, Graphics,
  mwKeyCmds,
  mwEditSearch,
  mwLocalStr, mwSupportProcs, mwSupportClasses,
  Printers,
  {$IFDEF MWE_MBCSSUPPORT}
  Imm,
  {$ENDIF}
  ExtCtrls, Forms, StdCtrls, Clipbrd, mwHighlighter,
  ShellAPI,
  uTextDrawer;

const
  DIGIT = ['0'..'9'];
// ALPHA            = ['A'..'Z', 'a'..'z'];
// break these up because we exceed the 4 byte limit when combined.
  ALPHA_UC = ['A'..'Z'];
  ALPHA_LC = ['a'..'z'];

   // not defined in all Delphi versions
  WM_MOUSEWHEEL = $020A;

   // maximum scroll range
  MAX_SCROLL = 32767;

// Max number of book/gutter marks returned from GetMarksForLine - that really
// should be enough.
  maxMarks = 16;

  MWEDIT_CLIPBOARD_FORMAT = 'mwEdit Control Block Type';

var
  mwEditClipboardFormat: UINT;

  {$IFDEF MWE_MBCSSUPPORT}
  {$IFNDEF MWE_COMPILER_4_UP}
{Windows.pas in D4}
const
  C3_NONSPACING = 1; { nonspacing character }
  C3_DIACRITIC = 2; { diacritic mark }
  C3_VOWELMARK = 4; { vowel mark }
  C3_SYMBOL = 8; { symbols }
  C3_KATAKANA = $0010; { katakana character }
  C3_HIRAGANA = $0020; { hiragana character }
  C3_HALFWIDTH = $0040; { half width character }
  C3_FULLWIDTH = $0080; { full width character }
  C3_IDEOGRAPH = $0100; { ideographic character }
  C3_KASHIDA = $0200; { Arabic kashida character }
  C3_LEXICAL = $0400; { lexical character }
  C3_ALPHA = $8000; { any linguistic char (C1_ALPHA) }
  C3_NOTAPPLICABLE = 0; { ctype 3 is not applicable }
  {$ENDIF}
  {$ENDIF}

type
  TmwEditExporter = (cfRTF, cfHTML);
  TmwEditExporters = set of TmwEditExporter;

  TmwSearchOption = (mwsoMatchCase, mwsoWholeWord, mwsoBackwards,
    mwsoEntireScope, mwsoSelectedOnly,
    mwsoReplace, mwsoReplaceAll, mwsoPrompt);
  TmwSearchOptions = set of TmwSearchOption;

  TmwReplaceAction = (mwraCancel, mwraSkip, mwraReplace, mwraReplaceAll);

  EmwEditError = class(Exception);

  PSelectionMode = ^TSelectionMode;
  TSelectionMode = (smNormal, smColumn, smLine);

  TIndexEvent = procedure(Index: Integer) of object;
  TPaintEvent = procedure(Sender: TObject; ACanvas: TCanvas) of object;
  TSpecialLineColorsEvent = procedure(Sender: TObject; Line: integer;
    var Special: boolean; var FG, BG: TColor) of object;
  TReplaceTextEvent = procedure(Sender: TObject; const ASearch, AReplace:
    string; Line, Column: integer; var Action: TmwReplaceAction) of object;

  TDropFilesEvent = procedure(Sender: TObject; X, Y: integer; Files: TStrings)
    of object;

  TProcessCommandEvent = procedure(Sender: TObject;
    var Command: TmwEditorCommand;
    var AChar: char; Data: pointer) of object;

  TCaretType = (ctVerticalLine, ctHorizontalLine, ctHalfBlock, ctBlock);

  // added mw as a prefix otherwise crNone conflicts with the
  // crNone cursor constant.
  TChangeReason = (mwcrInsert, mwcrPaste, mwcrDragDropInsert,
    mwcrDeleteAfterCursor, mwcrDelete, mwcrSelDelete,
    mwcrDragDropDelete, mwcrLineBreak, mwcrNone);

  TChangePtr = ^TChange;
  TChange = record
    ChangeStr: PChar;
    ChangeReason: TChangeReason;
    ChangeStartPos,
      ChangeEndPos: TPoint;
    ChangeSelMode: TSelectionMode;
  end;

  TmwPrintStatus = (psBegin, psNewPage, psEnd);
  TPrintStatusEvent = procedure(Sender: TObject; Status: TmwPrintStatus;
    PageNumber: integer; var Abort: boolean) of object;

  TmwMarginUnits = (muPixels, muThousandthsOfInches, muMillimeters);
  TmwPrintOptions = record
    SelectedOnly: boolean;
    Highlighted: boolean;
    WrapLongLines: boolean;
    IgnoreColors: boolean;
    Copies: integer;
    MarginUnits: TmwMarginUnits;
    Margins: TRect;
    PrintRange: TRect;
    Title: string;
    Header: TStringList;
    Footer: TStringList;
  end;

  TmwHeaderFooterAlign = (hfaLeft, hfaRight, hfaCenter);

  TmwStateFlag = (mwsfCaretChanged, mwsfScrollbarChanged,
    mwsfLinesChanging, mwsfInScrollLoop,
    mwsfCaretVisible, mwsfDblClicked, mwsfWaitForDragging);
  TmwStateFlags = set of TmwStateFlag;

  TmwEditorOption = (mweoAutoIndent, mweoDragDropEditing, mweoDropFiles,
    mweoHalfPageScroll, mweoScrollPastEol, mweoShowScrollHint,
    mweoTabsToSpaces, mweoSmartTabs);
  TmwEditorOptions = set of TmwEditorOption;

const
  MWEDIT_DEFAULT_OPTIONS = [mweoAutoIndent, mweoDragDropEditing,
    mweoScrollPastEol, mweoShowScrollHint,
    mweoSmartTabs, mweoTabsToSpaces];

type

  TmwStatusChange = (mwscCaretX, mwscCaretY, mwscLeftChar, mwscTopLine,
    mwscInsertMode);
  TmwStatusChanges = set of TmwStatusChange;

  TStatusChangeEvent = procedure(Sender: TObject; Changes: TmwStatusChanges)
    of object;

  TmwCustomEdit = class;

  TMark = class
  protected
    fLine, fColumn, fImage: Integer;
    fEdit: TmwCustomEdit;
    fVisible: boolean;
    fInternalImage: boolean;
    fBookmarkNum: integer;
    function GetEdit: TmwCustomEdit; virtual;
    procedure SetColumn(const Value: Integer); virtual;
    procedure SetImage(const Value: Integer); virtual;
    procedure SetLine(const Value: Integer); virtual;
    procedure SetVisible(const Value: boolean);
    procedure SetInternalImage(const Value: boolean);
    function GetIsBookmark: boolean;
    procedure SetIsBookmark(const Value: boolean);
  public
    constructor Create(owner: TmwCustomEdit);
    property Line: integer read fLine write SetLine;
    property Column: integer read fColumn write SetColumn;
    property ImageIndex: integer read fImage write SetImage;
    property BookmarkNumber: integer read fBookmarkNum write fBookmarkNum;
    property Visible: boolean read fVisible write SetVisible;
    property InternalImage: boolean read fInternalImage write SetInternalImage;
    property IsBookmark: boolean read GetIsBookmark write SetIsBookmark;
  end;

  TPlaceMarkEvent = procedure(Sender: TObject; var mark: TMark) of object;

  TMarks = array[1..maxMarks] of TMark;

  { A list of mark objects. Each object cause a litle picture to be drawn in the
    gutter. }
  TMarkList = class(TList)
  protected
    fEdit: TmwCustomEdit;
    fOnChange: TNotifyEvent;
    function Get(Index: Integer): TMark;
    procedure Put(Index: Integer; Item: TMark);
    procedure DoChange;
  public
    constructor Create(owner: TmwCustomEdit);
    function Add(Item: TMark): Integer;
    function First: TMark;
    function Last: TMark;
    procedure Insert(Index: Integer; Item: TMark);
    function Remove(Item: TMark): Integer;
    procedure Delete(Index: Integer);
    procedure ClearLine(line: integer);
    procedure Place(mark: TMark);
    procedure GetMarksForLine(line: integer; var marks: TMarks);
    property Items[Index: Integer]: TMark read Get write Put; default;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

  TUndoList = class
  private
    fList: TList;
    fCanUndo: Integer;
    fMaxUndo: Integer;
    fOwner: TmwCustomEdit;
    fUndoLocked: Boolean;
    function GetCanUndo: Integer;
    procedure SetMaxUndo(const Value: Integer);
  protected
    procedure RemoveChange(index: Integer);
  public
    constructor Create(AOwner: TmwCustomEdit);
    destructor Destroy; override;
    procedure AddChange(ChangeReason: TChangeReason; ChangeStartPos,
      ChangeEndPos: TPoint; ChangeStr: PChar; ChangeSelMode: TSelectionMode);
    function GetChange(var ChangeStartPos, ChangeEndPos: TPoint;
      var ChangeStr: PChar; var ChangeSelMode: TSelectionMode): TChangeReason;
    {$IFDEF UNDO_DEBUG}
    function GetChange2(var ChangeStartPos, ChangeEndPos: TPoint;
      var ChangeStr: PChar; var ChangeSelMode: TSelectionMode; i: Integer):
        TChangeReason;
    {$ENDIF}
    function GetChangeReason: TChangeReason;
    procedure ClearList;
    procedure LockUndo;
    procedure UnLockUndo;
    property CanUndo: Integer read GetCanUndo;
    property MaxUndo: Integer read FMaxUndo write SetMaxUndo;
  end;

  TmwEditList = class(TStringList)
  private
    FOnAdded: TNotifyEvent;
    fOnCleared: TNotifyEvent;
    FOnDeleted: TIndexEvent;
    FOnInserted: TIndexEvent;
    FOnLoaded: TNotifyEvent;
    fOnPutted: TIndexEvent;
    fOnScanRanges: TNotifyEvent;
    nLoading: integer;
  protected
    procedure BeginLoading;
    procedure EndLoading;
    procedure Put(Index: Integer; const S: string); override;
  public
    function Add(const S: string): Integer; override;

    procedure AddStrings(Strings: TStrings); override;
    procedure Assign(Source: TPersistent); override;

    procedure Clear; override;
    procedure Delete(Index: Integer); override;
    procedure Insert(Index: Integer; const S: string); override;
    procedure SetTextStr(const Value: string); override;
    procedure LoadFromStream(Stream: TStream); override;
    property OnAdded: TNotifyEvent read FOnAdded write FOnAdded;
    property OnCleared: TNotifyEvent read fOnCleared write fOnCleared;
    property OnDeleted: TIndexEvent read FOnDeleted write FOnDeleted;
    property OnInserted: TIndexEvent read FOnInserted write FOnInserted;
    property OnLoaded: TNotifyEvent read FOnLoaded write FOnLoaded;
    property OnPutted: TIndexEvent read FOnPutted write FOnPutted;
    property OnScanRanges: TNotifyEvent read fOnScanRanges write fOnScanRanges;
  end;

  TmwCustomEdit = class(TCustomControl)
  private
    fBlockBegin: TPoint;
    fBlockEnd: TPoint;
    fCaretX: Integer;
    fCaretY: Integer;
    fCharsInWindow: Integer;
    fCharWidth: Integer;
    fFontDummy: TFont;
    fGutterWidth: Integer;
    {$IFDEF MWE_MBCSSUPPORT}
    fImeCount: Integer;
    fMBCSStepAside: Boolean;
    {$ENDIF}
    fInserting: Boolean;
    fLines: TStrings;
    fLinesInWindow: Integer;
    fLeftChar: Integer;
    fMaxLeftChar: Integer;
    fPaintLock: Integer;

⌨️ 快捷键说明

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