Tulip.UI.EditBoxes.pas

Source Files

{******************************************************************************}
{                                                                              }
{                        Tulip - User Interface Library                        }
{                                                                              }
{         Copyright(c) 2012 - 2013 Marcos Gomes. All rights Reserved.          }
{                                                                              }
{  --------------------------------------------------------------------------  }
{                                                                              }
{  This product is based on Asphyre Sphinx (c) 2000 - 2012  Yuriy Kotsarenko.  }
{       All rights reserved. Official web site: http://www.afterwarp.net       }
{                                                                              }
{******************************************************************************}
{                                                                              }
{  Important Notice:                                                           }
{                                                                              }
{  If you modify/use this code or one of its parts either in original or       }
{  modified form, you must comply with Mozilla Public License Version 2.0,     }
{  including section 3, "Responsibilities". Failure to do so will result in    }
{  the license breach, which will be resolved in the court. Remember that      }
{  violating author's rights either accidentally or intentionally is           }
{  considered a serious crime in many countries. Thank you!                    }
{                                                                              }
{  !! Please *read* Mozilla Public License 2.0 document located at:            }
{  http://www.mozilla.org/MPL/                                                 }
{                                                                              }
{  --------------------------------------------------------------------------  }
{                                                                              }
{  The contents of this file are subject to the Mozilla Public License         }
{  Version 2.0 (the "License"); you may not use this file except in            }
{  compliance with the License. You may obtain a copy of the License at        }
{  http://www.mozilla.org/MPL/                                                 }
{                                                                              }
{  Software distributed under the License is distributed on an "AS IS"         }
{  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the     }
{  License for the specific language governing rights and limitations          }
{  under the License.                                                          }
{                                                                              }
{  The Original Code is Tulip.UI.EditBoxes.pas.                                }
{                                                                              }
{  The Initial Developer of the Original Code is Marcos Gomes.                 }
{  Portions created by Marcos Gomes are Copyright (C) 2012, Marcos Gomes.      }
{  All Rights Reserved.                                                        }
{                                                                              }
{******************************************************************************}
{                                                                              }
{  Tulip.UI.EditBoxes.pas                               Modified: 23-Mar-2013  }
{  --------------------------------------------------------------------------  }
{                                                                              }
{                   Base Implementations for EditBox Controls                  }
{                                                                              }
{                                Version 1.03                                  }
{                                                                              }
{******************************************************************************}

unit Tulip.UI.EditBoxes;

interface

uses
  Winapi.Windows, System.SysUtils, System.Classes, System.Math,
  // Asphyre Units
  AbstractCanvas, AsphyreFonts, AsphyreImages, AsphyreTypes, AsphyreUtils,
  Vectors2,
  // Tulip UI Units
  Tulip.UI.Types, Tulip.UI.Classes, Tulip.UI.Controls, Tulip.UI.Helpers,
  Tulip.UI.Utils;

type
{$REGION 'TCustomAEditBox'}
  TCustomAEditBox = class(TWControl)
  private
    FAntialiased: Boolean;
    FAutoSelect: Boolean;
    FBorder: TBorder;
    FColor: TFillColor;
    FFocusRect: TFocusRect;
    FFont: TEditFont;
    FImage: TImage;
    FMargin: Word;
    FMaxLength: Integer;
    FOnChange: TNotifyEvent;
    FReadOnly: Boolean;
    FSelection: TSelection;
    FText: String;
    FVirtualPosition: Integer;

    function GetTic: Integer;

    procedure SetAntialiased(Value: Boolean);
    procedure SetAutoSelect(Value: Boolean);
    procedure SetBorder(Value: TBorder);
    procedure SetColor(Value: TFillColor);
    procedure SetFocusRect(Value: TFocusRect);
    procedure SetFont(Value: TEditFont);
    procedure SetImage(Value: TImage);
    procedure SetMargin(Value: Word);
    procedure SetMaxLength(Value: Integer);
    procedure SetReadOnly(Value: Boolean);

    // procedure SetSelLength(Value: Integer);
    // procedure SetSelStart(Value: Integer);
    // procedure SetSelText(Value: String);

    procedure SetText(Value: String);
  protected
    procedure AssignTo(Dest: TPersistent); override;
    procedure Change; dynamic;
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    function GetSelLength: Integer;
    function GetSelStart: Integer;
    function GetSelText: string;

    procedure Clear;
    procedure ClearSelection;

    procedure CopyToClipboard;
    procedure CutToClipboard;
    procedure PasteFromClipboard;
    procedure SelectAll;

    procedure DoEnter; override;
    procedure DoExit; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
    procedure MouseEnter; override;
    procedure MouseLeave; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;

    property Antialiased: Boolean read FAntialiased write SetAntialiased;
    property AutoSelect: Boolean read FAutoSelect write SetAutoSelect;
    property Border: TBorder read FBorder write SetBorder;
    property Color: TFillColor read FColor write SetColor;
    property FocusRect: TFocusRect read FFocusRect write SetFocusRect;
    property Font: TEditFont read FFont write SetFont;
    property Image: TImage read FImage write SetImage;
    property Margin: Word read FMargin write SetMargin;
    property MaxLength: Integer read FMaxLength write SetMaxLength;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
    property ReadOnly: Boolean read FReadOnly write SetReadOnly;
    property Text: String read FText write SetText;
  end;
{$ENDREGION}

implementation

uses
  Tulip.UI;

var
  Tic: Byte;
  Counter: Cardinal;

{$REGION 'TCustomAEditBox'}
  { TCustomAEditBox }

procedure TCustomAEditBox.AssignTo(Dest: TPersistent);
begin
  ControlState := ControlState + [csReadingState];

  inherited AssignTo(Dest);

  if Dest is TCustomAEditBox then
    with TCustomAEditBox(Dest) do
    begin
      Antialiased := Self.Antialiased;
      AutoSelect := Self.AutoSelect;
      Border := Self.Border;
      Color := Self.Color;
      FocusRect := Self.FocusRect;
      Font := Self.Font;
      Image := Self.Image;
      MaxLength := Self.MaxLength;
      ReadOnly := Self.ReadOnly;
      Text := Self.Text;
    end;

  ControlState := ControlState - [csReadingState];
end;

procedure TCustomAEditBox.Change;
begin
  if Assigned(FOnChange) then
    FOnChange(Self);
end;

procedure TCustomAEditBox.Clear;
begin
  Text := '';
  Change;
end;

procedure TCustomAEditBox.ClearSelection;
begin
  FSelection.StartPos := 0;
  FSelection.EndPos := 0;
end;

procedure TCustomAEditBox.CopyToClipboard;
begin
  (ControlManager as TAControlManager).GetClipboard.SetTextBuf
    (PChar(GetSelText));
end;

constructor TCustomAEditBox.Create(AOwner: TComponent);
var
  Num: Integer;
begin
  ControlState := ControlState + [csCreating];

  inherited Create(AOwner);

  if (AOwner <> nil) and (AOwner <> Self) and (AOwner is TWControl) then
  begin
    // Auto generate name
    Num := 1;
    begin
      while AOwner.FindComponent('EditBox' + IntToStr(Num)) <> nil do
        Inc(Num);
      Name := 'EditBox' + IntToStr(Num);
    end;
  end;

  FAntialiased := True;
  FAutoSelect := True;
  FBorder := TBorder.Create;
  FBorder.Color := $B0FFFFFF;
  FBorder.Size := 1;
  FColor := TFillColor.Create($FF4090F0, $FF4090F0, $FF6EAAF4, $FF6EAAF4);
  FFocusRect := fDark;
  FFont := TEditFont.Create;
  FImage := TImage.Create;
  FMargin := 2;
  FMaxLength := 0;
  FReadOnly := False;
  FSelection.StartPos := 0;
  FSelection.EndPos := 0;
  FText := '';

  // Properties
  Left := 0;
  Top := 0;
  Width := 120;
  Height := 24;
  TabStop := True;
  Visible := True;

  Tic := 0;
  Counter := GetTickCount;

  ControlState := ControlState - [csCreating];
end;

procedure TCustomAEditBox.CutToClipboard;
var
  AText: String;
  AMin, AMax, ALength: Integer;
begin
  // Set initial values
  AText := Text;

  AMin := Min(FSelection.StartPos, FSelection.EndPos);
  AMax := Max(FSelection.StartPos, FSelection.EndPos);

  ALength := AMax - AMin;

  // Copy to Clipboard
  CopyToClipboard;

  Delete(AText, AMin + 1, ALength);
  Text := AText;
  // Execute OnChange Event
  Change;

  FSelection.StartPos := AMin;
  FSelection.EndPos := AMin;
end;

destructor TCustomAEditBox.Destroy;
begin
  FBorder.Free;
  FColor.Free;
  FFont.Free;
  FImage.Free;

  inherited;
end;

procedure TCustomAEditBox.DoEnter;
begin
  Tic := 0;

  if FAutoSelect then
    SelectAll;

  inherited;
end;

procedure TCustomAEditBox.DoExit;
begin
  ClearSelection;
  inherited;
end;

function TCustomAEditBox.GetSelLength: Integer;
var
  AMin, AMax: Integer;
begin
  AMin := Min(FSelection.StartPos, FSelection.EndPos);
  AMax := Max(FSelection.StartPos, FSelection.EndPos);

  Result := AMax - AMin;
end;

function TCustomAEditBox.GetSelStart: Integer;
var
  AMin: Integer;
begin
  AMin := Min(FSelection.StartPos, FSelection.EndPos);

  Result := AMin;
end;

function TCustomAEditBox.GetSelText: string;
var
  AMin, AMax, ALength: Integer;
begin
  AMin := Min(FSelection.StartPos, FSelection.EndPos);
  AMax := Max(FSelection.StartPos, FSelection.EndPos);
  ALength := AMax - AMin;

  Result := Copy(Text, AMin + 1, ALength);
end;

function TCustomAEditBox.GetTic: Integer;
begin
  // When the system run continuously for 49.7 days, GetTickCount=0
  if GetTickCount < Counter then
    Counter := GetTickCount;

  if (GetTickCount - Counter) >= 300 then
  begin
    Counter := GetTickCount;
    Tic := Tic + 1;
  end;

  if Tic = 4 then
    Tic := 0;

  Result := Tic;
end;

procedure TCustomAEditBox.KeyDown(var Key: Word; Shift: TShiftState);
var
  AText: String;
  AMin, AMax, ALength: Integer;
begin
  AText := Text;

  AMin := Min(FSelection.StartPos, FSelection.EndPos);
  AMax := Max(FSelection.StartPos, FSelection.EndPos);

  ALength := AMax - AMin;

  // shift pressed
  if Shift = [ssShift] then
  begin
    // user press right key
    if Key = vk_Right then
    begin
      if FSelection.EndPos < Length(Text) then
        Inc(FSelection.EndPos);
    end;

    // user press left key
    if Key = vk_Left then
    begin
      if FSelection.EndPos > 0 then
        Dec(FSelection.EndPos);
    end;

    // user press home key
    if Key = VK_Home then
    begin
      FSelection.EndPos := 0;
    end;

    // user press end key
    if Key = VK_End then
    begin
      FSelection.EndPos := Length(Text);
    end;
  end;

  // Shift not pressed
  if Shift <> [ssShift] then
  begin
    // User press left key
    if (Key = vk_Left) then
    begin
      if FSelection.StartPos = FSelection.EndPos then
      begin
        if FSelection.StartPos > 0 then
        begin
          Dec(FSelection.StartPos);
          FSelection.EndPos := FSelection.StartPos;
        end;
      end
      else if FSelection.StartPos > FSelection.EndPos then
      begin
        FSelection.StartPos := FSelection.EndPos;
      end
      else if FSelection.StartPos < FSelection.EndPos then
      begin
        FSelection.EndPos := FSelection.StartPos;
      end;
    end;

    // User press right key
    if (Key = vk_Right) then
    begin
      if FSelection.StartPos = FSelection.EndPos then
      begin
        if FSelection.EndPos < Length(Text) then
        begin
          Inc(FSelection.EndPos);
          FSelection.StartPos := FSelection.EndPos;
        end;
      end
      else if FSelection.StartPos > FSelection.EndPos then
      begin
        FSelection.EndPos := FSelection.StartPos;
      end
      else if FSelection.StartPos < FSelection.EndPos then
      begin
        FSelection.StartPos := FSelection.EndPos;
      end;
    end;

    // User press Delete or Backspace
    if ((Key = vk_Back) or (Key = vk_Delete)) and not(ReadOnly) then
    begin
      if ALength > 0 then
      begin
        case Key of
          vk_Back:
            Delete(AText, AMin + 1, ALength);
          vk_Delete:
            Delete(AText, AMin + 1, ALength);
        end;
      end
      else
      begin
        case Key of
          vk_Back:
            begin
              Delete(AText, AMin, 1);
              if AMin > 0 then
                Dec(AMin);
            end;
          vk_Delete:
            Delete(AText, AMin + 1, 1);
        end;
      end;

      Text := AText;
      // Execute OnChange Event
      Change;

      FSelection.StartPos := AMin;
      FSelection.EndPos := AMin;
    end;

    // user press home key
    if Key = VK_Home then
    begin
      FSelection.StartPos := 0;
      FSelection.EndPos := 0;
    end;

    // user press end key
    if Key = VK_End then
    begin
      FSelection.StartPos := Length(Text);
      FSelection.EndPos := Length(Text);
    end;
  end;

  Tic := 0;

  inherited KeyDown(Key, Shift);
end;

procedure TCustomAEditBox.KeyPress(var Key: Char);
var
  AText: String;
  AMin, AMax, ALength: Integer;
begin
  AText := Text;

  AMin := Min(FSelection.StartPos, FSelection.EndPos);
  AMax := Max(FSelection.StartPos, FSelection.EndPos);

  ALength := AMax - AMin;

  // Insert Key
  if (Key > #31) and not ReadOnly then
  begin
    Delete(AText, AMin + 1, ALength);

    Inc(AMin);
    Insert(Key, AText, AMin);

    Text := AText;
    // Execute OnChange Event
    Change;

    if AMin > Length(Text) then
      AMin := Length(Text);

    FSelection.StartPos := AMin;
    FSelection.EndPos := AMin;
  end;

  // Copy to Clipboard
  if Key = #3 then
    CopyToClipboard;

  // Paste from Clipboard
  if Key = #22 then
    PasteFromClipboard;

  // Cut to Clipboard
  if Key = #24 then
    CutToClipboard;

  inherited KeyPress(Key);
end;

procedure TCustomAEditBox.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
var
  Index, XPos, AVirtualCursor: Integer;
  AChars: TAChars;
  AFont: TAsphyreFont;
begin
  Self.SetFocus;

  AFont := ControlManager.Fonts.Font[FFont.Name];

  if ssDouble in Shift then
  begin
    SelectAll;
  end
  else if AFont <> nil then
  begin
    // Get chars from text
    Index := 0;
    SetLength(AChars, Length(Text) + 1);
    while Index < Length(Text) do
    begin
      AChars[Index].Char := Text[Index + 1];
      AChars[Index].Width := Round(AFont.TextWidth(Text[Index + 1]) +
        AFont.Kerning);
      Inc(Index);
    end;

    // Set position to 0
    FSelection.StartPos := 0;
    FSelection.EndPos := 0;

    // Get virtual Bounds
    XPos := ClientLeft + FBorder.Size + FMargin + FVirtualPosition;

    // Set virtual Pos
    AVirtualCursor := XPos;
    for Index := 0 to High(AChars) do
    begin
      if (X > AVirtualCursor) and (X <= AVirtualCursor + AChars[Index].Width)
      then
      begin
        if Index < Length(Text) then
        begin
          FSelection.StartPos := Index + 1;
          FSelection.EndPos := Index + 1;
        end;
        Break;
      end;
      AVirtualCursor := AVirtualCursor + AChars[Index].Width;

      if (Index = High(AChars)) and (X >= AVirtualCursor) then
      begin
        FSelection.StartPos := Index;
        FSelection.EndPos := Index;
      end;
    end;

  end;

  inherited MouseDown(Button, Shift, X, Y);
end;

procedure TCustomAEditBox.MouseEnter;
begin
  // Change the cursor
  if ControlManager.Parent <> nil then
    (ControlManager as TAControlManager).GetParentAsControl.Cursor := crIBeam;

  inherited MouseEnter;
end;

procedure TCustomAEditBox.MouseLeave;
begin
  // Change the cursor
  if ControlManager.Parent <> nil then
    (ControlManager as TAControlManager).GetParentAsControl.Cursor := crDefault;

  inherited MouseLeave;
end;

procedure TCustomAEditBox.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  Index, XPos, AVirtualCursor: Integer;
  AChars: TAChars;
  AFont: TAsphyreFont;
begin
  AFont := ControlManager.Fonts.Font[FFont.Name];

  if (AFont <> nil) and (Shift = [ssLeft]) then
  begin
    // Get chars from text
    Index := 0;
    SetLength(AChars, Length(Text) + 1);
    while Index < Length(Text) do
    begin
      AChars[Index].Char := Text[Index + 1];
      AChars[Index].Width := Round(AFont.TextWidth(Text[Index + 1]) +
        AFont.Kerning);
      Inc(Index);
    end;

    // Set position to 0
    FSelection.EndPos := 0;

    // Get virtual Bounds
    XPos := ClientLeft + Border.Size + Margin + FVirtualPosition;

    // Set virtual Pos
    AVirtualCursor := XPos;
    for Index := 0 to High(AChars) do
    begin
      if (X > AVirtualCursor) and (X <= AVirtualCursor + AChars[Index].Width)
      then
      begin
        if Index < Length(Text) then
        begin
          FSelection.EndPos := Index + 1;
        end;
        Break;
      end;
      AVirtualCursor := AVirtualCursor + AChars[Index].Width;

      if (Index = High(AChars)) and (X >= AVirtualCursor) then
      begin
        FSelection.EndPos := Index;
      end;
    end;
  end;

  inherited MouseMove(Shift, X, Y);
end;

procedure TCustomAEditBox.Paint;
var
  Index, X, Y, AWidth, AHeight, AVirtualCursor: Integer;
  AMin, AMax: Integer;
  AChars: TAChars;
  ARect: TRect;
  bTop, bBottom: TConstraintSize;
  AImage: TAsphyreImage;
  AFont: TAsphyreFont;
begin
  // Get size Canvas
  ARect := ControlManager.Canvas.ClipRect;

  // Set initial values
  X := ClientLeft;
  Y := ClientTop;

  ControlManager.Canvas.Antialias := FAntialiased;

  // Draw Background
  AImage := ControlManager.Images.Image[FImage.Image];
  if AImage <> nil then
  begin
    ControlManager.Canvas.UseImagePx(AImage, pRect4(FImage.Rect));
    ControlManager.Canvas.TexMap(pRect4(Rect(X, Y, X + Width, Y + Height)),
      cAlpha4(FColor), beNormal);
  end
  else
  begin
    ControlManager.Canvas.FillRect(Rect(X, Y, X + Width, Y + Height),
      cColor4(FColor), beNormal);
  end;

  // Draw Border
  if Border.Size > 0 then
  begin
    bTop := 0;
    bBottom := 0;

    if eTop in Border.Edges then
    begin
      ControlManager.Canvas.FillRect(Rect(X, Y, X + Width, Y + Border.Size),
        Border.Color, beNormal);
      bTop := Border.Size;
    end;

    if eBottom in Border.Edges then
    begin
      ControlManager.Canvas.FillRect(Rect(X, Y + Height - Border.Size,
        X + Width, Y + Height), Border.Color, beNormal);
      bBottom := Border.Size;
    end;

    if eLeft in Border.Edges then
      ControlManager.Canvas.FillRect(Rect(X, Y + bTop, X + Border.Size,
        Y + Height - bBottom), Border.Color, beNormal);

    if eRight in Border.Edges then
      ControlManager.Canvas.FillRect(Rect(X + Width - Border.Size, Y + bTop,
        X + Width, Y + Height - bBottom), Border.Color, beNormal);
  end;

  // Draw DisplayText
  AFont := ControlManager.Fonts.Font[FFont.Name];
  if (AFont <> nil) then
  begin
    // Set Bounds
    X := X + Margin + Border.Size;
    Y := Y + Margin + Border.Size;
    AWidth := Width - Margin * 2 - Border.Size * 2;
    AHeight := Height - Margin * 2 - Border.Size * 2;

    // Set Rect Canvas
    ControlManager.Canvas.ClipRect :=
      ShortRect(Rect(X - 1, Y, X + AWidth, Y + AHeight), ARect);

    // Get chars from text
    Index := 0;
    SetLength(AChars, Length(Text) + 1);
    while Index < Length(Text) do
    begin
      AChars[Index].Char := Text[Index + 1];
      AChars[Index].Width := Round(AFont.TextWidth(Text[Index + 1]) +
        AFont.Kerning);
      Inc(Index);
    end;

    // Set virtual Pos
    AVirtualCursor := 0;
    FVirtualPosition := 0;
    for Index := 0 to FSelection.EndPos - 1 do
    begin
      AVirtualCursor := AVirtualCursor + AChars[Index].Width;
    end;

    if AVirtualCursor > AWidth then
    begin
      FVirtualPosition := AWidth - AVirtualCursor;
      X := X + FVirtualPosition;
    end;

    AMin := Min(FSelection.StartPos, FSelection.EndPos);
    AMax := Max(FSelection.StartPos, FSelection.EndPos);

    // Draw Text char by char
    for Index := 0 to High(AChars) do
    begin
      // Draw Selection
      if (Index >= AMin) and (Index < AMax) then
      begin
        if Index = AMin then
          ControlManager.Canvas.FillRect(Rect(X - 1, Y, X + AChars[Index].Width,
            Y + AHeight), cColor4(FFont.SelectionColor), beNormal)
        else
          ControlManager.Canvas.FillRect(Rect(X, Y, X + AChars[Index].Width,
            Y + AHeight), cColor4(FFont.SelectionColor), beNormal);

        if (Index = AMin) and (Index = (AMax - 1)) then
          ControlManager.Canvas.FillRect
            (Rect(X, Y + 1, X + AChars[Index].Width - 1, Y + AHeight - 1),
            cColor4($25FFFFFF), beNormal)
        else if Index = AMin then
          ControlManager.Canvas.FillRect(Rect(X, Y + 1, X + AChars[Index].Width,
            Y + AHeight - 1), cColor4($25FFFFFF), beNormal)
        else if Index = (AMax - 1) then
          ControlManager.Canvas.FillRect
            (Rect(X, Y + 1, X + AChars[Index].Width - 1, Y + AHeight - 1),
            cColor4($25FFFFFF), beNormal)
        else
          ControlManager.Canvas.FillRect(Rect(X, Y + 1, X + AChars[Index].Width,
            Y + AHeight - 1), cColor4($25FFFFFF), beNormal);

        AFont.TextOut(Point2(X, Y + (AHeight div 2) - (AFont.FontSize.Y div 2) -
          1), AChars[Index].Char, cColor2($B0FFFFFF), 1.0);
      end
      else
      begin
        AFont.TextOut(Point2(X, Y + (AHeight div 2) - (AFont.FontSize.Y div 2) -
          1), AChars[Index].Char, cColor2(FFont.Color), 1.0);
      end;

      // Draw Tic
      if (GetTic <= 1) and (ControlManager.ActiveControl = Self) then
      begin
        if (Index = FSelection.StartPos) and (Index = FSelection.EndPos) then
          ControlManager.Canvas.Line(Point2(X, Y),
            Point2(X, Y + AHeight), clBlack1)
        else if Index = FSelection.EndPos then
          ControlManager.Canvas.Line(Point2(X - 1, Y),
            Point2(X - 1, Y + AHeight), clBlack1);
      end;

      // Set Next X position
      X := X + AChars[Index].Width;
    end;

    // Set Rect Canvas
    ControlManager.Canvas.ClipRect := ARect;
  end;

  // Set initial values
  X := ClientLeft;
  Y := ClientTop;

  // Draw Focus rect
  if (ControlManager.ActiveControl = Self) and (Self.FocusRect = fLight) then
  begin
    ControlManager.Canvas.FrameRect(Rect(X - 1, Y - 1, X + Width + 1,
      Y + Height + 1), cColor4($40FFFFFF), beNormal);
  end;
  if (ControlManager.ActiveControl = Self) and (Self.FocusRect = fDark) then
  begin
    ControlManager.Canvas.FrameRect(Rect(X - 1, Y - 1, X + Width + 1,
      Y + Height + 1), cColor4($20000000), beNormal);
  end;

end;

procedure TCustomAEditBox.PasteFromClipboard;
var
  AText, CText: String;
  AMin, AMax, ALength: Integer;
begin
  AText := Text;

  AMin := Min(FSelection.StartPos, FSelection.EndPos);
  AMax := Max(FSelection.StartPos, FSelection.EndPos);

  ALength := AMax - AMin;

  Delete(AText, AMin + 1, ALength);
  CText := (ControlManager as TAControlManager).GetClipboard.AsText;

  Inc(AMin);
  Insert(CText, AText, AMin);

  Text := AText;
  // Execute OnChange Event
  Change;

  Inc(AMin, Length(CText));

  if AMin > Length(Text) then
    AMin := Length(Text);

  FSelection.StartPos := AMin;
  FSelection.EndPos := AMin;
end;

procedure TCustomAEditBox.SelectAll;
begin
  if Enabled then
  begin
    FSelection.StartPos := 0;
    FSelection.EndPos := Length(Text);
  end;
end;

procedure TCustomAEditBox.SetAntialiased(Value: Boolean);
begin
  FAntialiased := Value;
end;

procedure TCustomAEditBox.SetAutoSelect(Value: Boolean);
begin
  FAutoSelect := Value;
end;

procedure TCustomAEditBox.SetBorder(Value: TBorder);
begin
  if Value <> nil then
    FBorder.Assign(Value);
end;

procedure TCustomAEditBox.SetColor(Value: TFillColor);
begin
  if Value <> nil then
    FColor.Assign(Value);
end;

procedure TCustomAEditBox.SetFocusRect(Value: TFocusRect);
begin
  FFocusRect := Value;
end;

procedure TCustomAEditBox.SetFont(Value: TEditFont);
begin
  if Value <> nil then
    FFont.Assign(Value);
end;

procedure TCustomAEditBox.SetImage(Value: TImage);
begin
  if Value <> nil then
    FImage.Assign(Value);
end;

procedure TCustomAEditBox.SetMargin(Value: Word);
begin
  FMargin := Value;
end;

procedure TCustomAEditBox.SetMaxLength(Value: Integer);
begin
  if FMaxLength <> Value then
  begin
    FMaxLength := Value;
    if (Value < Length(Text)) and (Value > 0) then
    begin
      Text := Copy(Text, 0, Value);
    end;
  end;
end;

procedure TCustomAEditBox.SetReadOnly(Value: Boolean);
begin
  FReadOnly := Value;
end;

// procedure TCustomAEditBox.SetSelLength(Value: Integer);
// begin
// FSelection.EndPos := FSelection.StartPos + Value;
//
// if FSelection.EndPos > Length(Text) then
// FSelection.EndPos := Length(Text);
//
// if FSelection.EndPos < 0 then
// FSelection.EndPos := 0;
// end;
//
// procedure TCustomAEditBox.SetSelStart(Value: Integer);
// begin
// if not((Value < 0) and (Value > Length(Text))) then
// begin
// FSelection.StartPos := Value;
// FSelection.EndPos := Value;
// end;
// end;
//
// procedure TCustomAEditBox.SetSelText(Value: String);
// var
// AText: String;
// AMin, AMax, ALength: Integer;
// begin
// AText := Text;
//
// AMin := Min(FSelection.StartPos, FSelection.EndPos);
// AMax := Max(FSelection.StartPos, FSelection.EndPos);
//
// ALength := AMax - AMin;
//
// // Insert Key
// Delete(AText, AMin + 1, ALength);
//
// Inc(AMin);
// Insert(Value, AText, AMin);
//
// Text := AText;
// Change;
//
// if AMin > Length(Text) then
// AMin := Length(Text);
//
// FSelection.StartPos := AMin;
// FSelection.EndPos := AMin + Length(Value);
// end;

procedure TCustomAEditBox.SetText(Value: String);
begin
  if (FMaxLength < Length(Value)) and (FMaxLength > 0) then
  begin
    Value := Copy(Value, 0, FMaxLength);
  end;

  FText := Value;
end;
{$ENDREGION}

end.