mwcompletionproposal.pas

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

PAS
989
字号
{-------------------------------------------------------------------------------
 | This unit is copyright Cyrille de Brebisson
 -------------------------------------------------------------------------------
 | Version history:
 |   0.50: source maintained by the autor, version history unknown
 |     - Better support of the completion form when embeded in an MDI
 |       application (thanks to Olivier Deckmyn)
 |     - Added Page up and Page down in the supported keys
 |     - The paint is now done through a bitmat to reduce flickering
 |   0.51: Stefan van As
 |     - Added Menus unit to the uses clause.
 |     - Added FShortCut, SetShortCut and published ShortCut property
 |       (defaults to Ctrl+Space) and ShortCut handling to EditorKeyDown.
 -------------------------------------------------------------------------------}

unit mwCompletionProposal;

interface

uses
  Forms, Classes, StdCtrls, Controls, SysUtils, mwCustomEdit, mwKeyCmds,
  Windows, Graphics, Menus;

type
  TCompletionProposalPaintItem = Function (Key: String; Canvas: TCanvas; x, y: integer): Boolean of object;

  TCompletionProposalForm = class (TForm)
  Protected
    FCurrentString: String;
    FOnKeyPress: TKeyPressEvent;
    FOnKeyDelete: TNotifyEvent;
    FOnPaintItem: TCompletionProposalPaintItem;
    FItemList: TStrings;
    FPosition: Integer;
    FNbLinesInWindow: Integer;
    FFontHeight: integer;
    Scroll: TScrollBar;
    FOnValidate: TNotifyEvent;
    FOnCancel: TNotifyEvent;
    FClSelect: TColor;
    FAnsi: boolean;
    procedure SetCurrentString(const Value: String);
    Procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: char); override;
    Procedure Paint; override;
    procedure ScrollGetFocus(Sender: TObject);
    Procedure Deactivate; override;
    procedure SelectPrec;
    procedure SelectNext;
    procedure ScrollChange(Sender: TObject);
    procedure SetItemList(const Value: TStrings);
    procedure SetPosition(const Value: Integer);
    procedure SetNbLinesInWindow(const Value: Integer);
    Procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    Procedure StringListChange(Sender: TObject);
  private
    Bitmap: TBitmap;  // used for drawing
    fCurrentEditor: TComponent;
  Public
    constructor Create(AOwner: Tcomponent); override;
    destructor destroy; override;
  Published
    Property CurrentString: String read FCurrentString write SetCurrentString;
    Property OnKeyPress: TKeyPressEvent read FOnKeyPress write FOnKeyPress;
    Property OnKeyDelete: TNotifyEvent read FOnKeyDelete write FOnKeyDelete;
    Property OnPaintItem: TCompletionProposalPaintItem read FOnPaintItem write FOnPaintItem;
    Property OnValidate: TNotifyEvent read FOnValidate write FOnValidate;
    Property OnCancel: TNotifyEvent read FOnCancel write FOnCancel;
    Property ItemList: TStrings read FItemList write SetItemList;
    Property Position: Integer read FPosition write SetPosition;
    Property NbLinesInWindow: Integer read FNbLinesInWindow write SetNbLinesInWindow;
    Property ClSelect: TColor read FClSelect write FClSelect;
    Property ffAnsi: boolean read fansi write fansi;
    Property CurrentEditor: tComponent read fCurrentEditor write fCurrentEditor;
  end;

  TCompletionProposal = Class (TComponent)
  private
    Form: TCompletionProposalForm;
    FOnExecute: TNotifyEvent;
    function GetClSelect: TColor;
    procedure SetClSelect(const Value: TColor);
    function GetCurrentString: String;
    function GetItemList: TStrings;
    function GetNbLinesInWindow: Integer;
    function GetOnCancel: TNotifyEvent;
    function GetOnKeyPress: TKeyPressEvent;
    function GetOnPaintItem: TCompletionProposalPaintItem;
    function GetOnValidate: TNotifyEvent;
    function GetPosition: Integer;
    procedure SetCurrentString(const Value: String);
    procedure SetItemList(const Value: TStrings);
    procedure SetNbLinesInWindow(const Value: Integer);
    procedure SetOnCancel(const Value: TNotifyEvent);
    procedure SetOnKeyPress(const Value: TKeyPressEvent);
    procedure SetOnPaintItem(const Value: TCompletionProposalPaintItem);
    procedure SetPosition(const Value: Integer);
    procedure SetOnValidate(const Value: TNotifyEvent);
    function GetOnKeyDelete: TNotifyEvent;
    procedure SetOnKeyDelete(const Value: TNotifyEvent);
    procedure RFAnsi(const Value: boolean);
    function SFAnsi: boolean;
  Public
    Constructor Create(Aowner: TComponent); override;
    Destructor Destroy; Override;
    Procedure Execute(s: string; x, y: integer);
    Property OnKeyPress: TKeyPressEvent read GetOnKeyPress write SetOnKeyPress;
    Property OnKeyDelete: TNotifyEvent read GetOnKeyDelete write SetOnKeyDelete;
    Property OnValidate: TNotifyEvent read GetOnValidate write SetOnValidate;
    Property OnCancel: TNotifyEvent read GetOnCancel write SetOnCancel;
    Property CurrentString: String read GetCurrentString write SetCurrentString;
  Published
    Property OnExecute: TNotifyEvent read FOnExecute Write FOnExecute;
    Property OnPaintItem: TCompletionProposalPaintItem read GetOnPaintItem write SetOnPaintItem;
    Property ItemList: TStrings read GetItemList write SetItemList;
    Property Position: Integer read GetPosition write SetPosition;
    Property NbLinesInWindow: Integer read GetNbLinesInWindow write SetNbLinesInWindow;
    Property ClSelect: TColor read GetClSelect Write SetClSelect;
    Property AnsiStrings: boolean read SFAnsi Write RFAnsi;
  End;

  TMwCompletionProposal = class (TCompletionProposal)
  private
    FShortCut: TShortCut;
    fEditors: TList;
    fEditstuffs: TList;
    FEndOfTokenChr: string;
    procedure SetEditor(const Value: TmwCustomEdit);
    procedure backspace(Senter: TObject);
    procedure Cancel(Senter: TObject);
    procedure Validate(Senter: TObject);
    procedure KeyPress(Sender: TObject; var Key: Char);
    Procedure EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    Procedure EditorKeyPress(Sender: TObject; var Key: char);
    Function GetPreviousToken(FEditor: TmwCustomEdit): string;
    function GetFEditor: TmwCustomEdit;
    function GetEditor(i: integer): TmwCustomEdit;
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure SetShortCut(Value: TShortCut);
  public
    Constructor Create(AOwner: TComponent); override;
    destructor destroy; override;
    Property Editors[i: integer]: TmwCustomEdit read GetEditor;
    Procedure AddEditor(Editor: TmwCustomEdit);
    Function RemoveEditor(Editor: TmwCustomEdit): boolean;
    Function EditorsCount: integer;
  published
    property ShortCut: TShortCut read FShortCut write SetShortCut;
    Property Editor: TmwCustomEdit read GetFEditor write SetEditor;
    Property EndOfTokenChr: string read FEndOfTokenChr write FEndOfTokenChr;
  end;

  TmwAutoComplete = class(TComponent)
  private
    FShortCut: TShortCut;
    fEditors: TList;
    fEditstuffs: TList;
    fAutoCompleteList: TStrings;
    FEndOfTokenChr: string;
    Procedure SetAutoCompleteList(List: TStrings);
    function GetEditor(i: integer): TmwCustomEdit;
    function GetEdit: TmwCustomEdit;
    procedure SetEdit(const Value: TmwCustomEdit);
  protected
    procedure SetShortCut(Value: TShortCut);
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    Procedure EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); virtual;
    Procedure EditorKeyPress(Sender: TObject; var Key: char); virtual;
    Function GetPreviousToken(Editor: tmwCustomEdit): string;
  public
    Constructor Create(AOwner: TComponent); override;
    Destructor destroy; override;
    Procedure Execute(token: string; Editor: TmwCustomEdit);
    Property Editors[i: integer]: TmwCustomEdit read GetEditor;
    Procedure AddEditor(Editor: TmwCustomEdit);
    Function RemoveEditor(Editor: TmwCustomEdit): boolean;
    Function EditorsCount: integer;
  published
    Property AutoCompleteList: TStrings read fAutoCompleteList write SetAutoCompleteList;
    Property EndOfTokenChr: string read FEndOfTokenChr write FEndOfTokenChr;
    Property Editor: TmwCustomEdit read GetEdit write SetEdit;
    property ShortCut: TShortCut read FShortCut write SetShortCut;
  end;

  Procedure PretyTextOut(c: TCanvas; x, y: integer; s: String);

  Procedure register;

implementation

uses
  mwLocalStr, mwSupportProcs;

{ TCompletionProposalForm }

constructor TCompletionProposalForm.Create(AOwner: Tcomponent);
begin
  CreateNew(AOwner);
  FItemList:= TStringList.Create;
  BorderStyle:= bsNone;
  width:=262;
  Scroll:= TScrollBar.Create(self);
  Scroll.Kind:= sbVertical;
  Scroll.OnChange:= ScrollChange;
  Scroll.Parent:= self;
  Scroll.OnEnter:= ScrollGetFocus;
  Visible:= false;
  FFontHeight:= Canvas.TextHeight('Cyrille de Brebisson');
  ClSelect:= clAqua;
  TStringList(FItemList).OnChange:= StringListChange;
  bitmap:= TBitmap.Create;
  NbLinesInWindow:= 6;
End;

procedure TCompletionProposalForm.Deactivate;
begin
  Visible:= False;
end;

destructor TCompletionProposalForm.destroy;
begin
  bitmap.free;
  Scroll.Free;
  FItemList.Free;
  inherited destroy;
end;

procedure TCompletionProposalForm.KeyDown(var Key: Word; Shift: TShiftState);
var
  i: integer;
begin
  case key of
    13: if Assigned(OnValidate) then
          OnValidate(Self);
    27,32: if Assigned(OnCancel) then
          OnCancel(Self);
    // I do not think there is a worst way to do this, but laziness rules :-)
    33: for i:=1 to NbLinesInWindow do SelectPrec;
    34: for i:=1 to NbLinesInWindow do SelectNext;
    38: if ssCtrl in Shift then
           Position:= 0
        else
          SelectPrec;
    40: if ssCtrl in Shift then
           Position:= ItemList.count-1
        else
          SelectNext;
    8:  if Shift=[] then
        Begin
          if Length(CurrentString)<>0 then
            begin
              CurrentString:= copy(CurrentString,1,Length(CurrentString)-1);
              if Assigned(OnKeyDelete) then OnKeyDelete(Self);
            end;
          end;
  end;
  paint;
end;

procedure TCompletionProposalForm.KeyPress(var Key: char);
begin
  case key of    //
    #33..'z': Begin
                CurrentString:= CurrentString+key;
                if Assigned(OnKeyPress) then
                  OnKeyPress(self, Key);
              end;
    #8: CurrentString:= CurrentString+key;
    else if Assigned(OnCancel) then OnCancel(Self);
  end;    // case
  paint;
end;

procedure TCompletionProposalForm.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  y:= (y-1) div FFontHeight;
  Position:= Scroll.Position+y;
end;

procedure TCompletionProposalForm.Paint;
var
  i: integer;
begin
  // update scrool bar
  if ItemList.Count-NbLinesInWindow<0 then
    Scroll.Max:= 0
  else
    Scroll.Max:= ItemList.Count-NbLinesInWindow;
  Position:= Position;
  Scroll.LargeChange:= NbLinesInWindow;

  // draw a rectangle around the window
  Canvas.Pen.Color:= ClBlack;
  Canvas.Moveto(0, 0);
  Canvas.LineTo(Width-1, 0);
  Canvas.LineTo(Width-1, Height-1);
  Canvas.LineTo(0, Height-1);
  Canvas.LineTo(0, 0);

  with bitmap do
  begin
    canvas.pen.color:= color;
    canvas.brush.color:= color;
    canvas.Rectangle(0,0,Width,Height);
    For i:= 0 to min(NbLinesInWindow-1,ItemList.Count-1) do
    Begin
      if i+Scroll.Position=Position then
      Begin
        Canvas.Brush.Color:= ClSelect;
        Canvas.Pen.Color:= ClSelect;
        Canvas.Rectangle(0, FFontHeight*i, width, FFontHeight*(i+1));
        Canvas.Pen.Color:= ClBlack;
      end else
        Canvas.Brush.Color:= Color;

      if not Assigned(OnPaintItem) or not OnPaintItem(ItemList[Scroll.Position+i], Canvas, 0, FFontHeight*i) then
        Canvas.TextOut(0, FFontHeight*i, ItemList[Scroll.Position+i]);
    end;
  end;
  canvas.Draw(1, 1, bitmap);
end;

procedure TCompletionProposalForm.ScrollChange(Sender: TObject);
begin
  if Position < Scroll.Position then
    Position:= Scroll.Position
  else if Position > Scroll.Position+NbLinesInWindow-1 then
    Position:= Scroll.Position+NbLinesInWindow-1;
  Paint;
end;

procedure TCompletionProposalForm.ScrollGetFocus(Sender: TObject);
begin
  ActiveControl:= nil;
end;

procedure TCompletionProposalForm.SelectNext;
begin
  if Position<ItemList.Count-1 then
    Position:= Position+1;
end;

procedure TCompletionProposalForm.SelectPrec;
begin
  if Position>0 then
    Position:= Position-1;
end;

procedure TCompletionProposalForm.SetCurrentString(const Value: String);
var
  i: integer;
begin
  FCurrentString := Value;
  i:= 0;
  if ffansi then
    while (i<=ItemList.count-1) and (AnsiCompareText(ItemList[i],Value)<0) do
      inc(i)
  else
    while (i<=ItemList.count-1) and (ItemList[i]<Value) do
      inc(i);
  if i<=ItemList.Count-1 then
    Position:= i;
end;

procedure TCompletionProposalForm.SetItemList(const Value: TStrings);
begin
  FItemList.Assign(Value);
end;

procedure TCompletionProposalForm.SetNbLinesInWindow(const Value: Integer);
begin
  FNbLinesInWindow := Value;
  Height:= fFontHeight * NbLinesInWindow + 2;
  Scroll.top:= 2;
  Scroll.left:= ClientWidth-Scroll.Width-2;
  Scroll.Height:= Height-4;
  bitmap.Width:= Scroll.left-2;
  bitmap.height:= Height-2;
end;

procedure TCompletionProposalForm.SetPosition(const Value: Integer);
begin
  if Value<=ItemList.Count-1 then
  Begin
    if FPosition<>Value then
    Begin
      FPosition := Value;
      if Position<Scroll.Position then
        Scroll.Position:= Position
      else
        if Scroll.Position < Position-NbLinesInWindow+1 then
          Scroll.Position:= Position-NbLinesInWindow+1;
      invalidate;
    end;
  end;
end;

procedure TCompletionProposalForm.StringListChange(Sender: TObject);
begin
  if ItemList.Count-NbLinesInWindow<0 then
    Scroll.Max:= 0
  else
    Scroll.Max:= ItemList.Count-NbLinesInWindow;
  Position:= Position;
end;

{ TCompletionProposal }

constructor TCompletionProposal.Create(Aowner: TComponent);
begin
  Inherited Create(AOwner);
  Form:= TCompletionProposalForm.Create(Self);
end;

destructor TCompletionProposal.Destroy;
begin
  form.Free;
  Inherited Destroy;
end;

procedure TCompletionProposal.Execute(s: string; x, y: integer);
begin
  form.top:= y;
  form.left:= x;
  CurrentString:= s;
  if assigned(OnExecute) then
    OnExecute(Self);
  form.Show;
end;

function TCompletionProposal.GetCurrentString: String;
begin
  result:= Form.CurrentString;
end;

function TCompletionProposal.GetItemList: TStrings;
begin
  result:= Form.ItemList;
end;

function TCompletionProposal.GetNbLinesInWindow: Integer;
begin
  Result:= Form.NbLinesInWindow;
end;

function TCompletionProposal.GetOnCancel: TNotifyEvent;
begin
  Result:= Form.OnCancel;
end;

function TCompletionProposal.GetOnKeyPress: TKeyPressEvent;
begin
  Result:= Form.OnKeyPress;
end;

function TCompletionProposal.GetOnPaintItem: TCompletionProposalPaintItem;
begin
  Result:= Form.OnPaintItem;
end;

function TCompletionProposal.GetOnValidate: TNotifyEvent;
begin
  Result:= Form.OnValidate;
end;

function TCompletionProposal.GetPosition: Integer;
begin
  Result:= Form.Position;
end;

procedure TCompletionProposal.SetCurrentString(const Value: String);
begin
  form.CurrentString:= Value;
end;

procedure TCompletionProposal.SetItemList(const Value: TStrings);
begin
  form.ItemList:= Value;
end;

procedure TCompletionProposal.SetNbLinesInWindow(const Value: Integer);
begin
  form.NbLinesInWindow:= Value;
end;

procedure TCompletionProposal.SetOnCancel(const Value: TNotifyEvent);
begin
  form.OnCancel:= Value;
end;

procedure TCompletionProposal.SetOnKeyPress(const Value: TKeyPressEvent);
begin
  form.OnKeyPress:= Value;
end;

⌨️ 快捷键说明

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