{==============================================================================

  Copyright (C) 2000-2001 by Evgeny Kryukov
  All rights reserved

  All contents of this file and all other files included in this archive
  are Copyright (C) 2001 Evgeny Kryukov. Use and/or distribution of
  them requires acceptance of the License Agreement.

  See License.txt for licence information

===============================================================================}

unit KsComboBoxs;
                                      
{$I KsCommonVer.Inc}
{$T-,W-,X+,P+}

interface

uses
  Windows, Classes, SysUtils, Messages, Graphics, Controls, Forms, StdCtrls, ExtCtrls,
  KsBitmap, KsUtils, KsControls, KsEdits, KsListBoxs;

type

  TKsComboButtonAlign = (cbaLeft, cbaRight);
  TKsComboStyle = (kcsDropDown, kcsDropDownList);

{ TKsCustomComboBox class }

  TKsCustomComboBox = class(TKsCustomEdit)
  private
    FListBox: TKsCustomListBox;
    FButtonAlign: TKsComboButtonAlign;
    FMouseOnButton: boolean;
    FButtonPressed: boolean;
    FDropDownCount: integer;
    FItemHeight: integer;
    FItemIndex: integer;
    FOnDrawItem: TDrawItemEvent;
    FOnMeasureItem: TMeasureItemEvent;
    FComboStyle: TKsComboStyle;
    FAutoComplete: boolean;
    FOldText: string;
    FWork: boolean;
    FTimer: TTimer;
    FOldReadOnly: boolean;
    procedure SetButtonAlign(const Value: TKsComboButtonAlign);
    procedure SetDropDownCount(const Value: integer);
    procedure SetItemHeight(const Value: integer);
    procedure SetItemIndex(const Value: integer);
    procedure SetItems(const Value: TStrings);
    function GetColorValue: TColor;
    function GetFontValue: TFont;
    procedure SetFlat(const Value: boolean);
    procedure SetFontDevice(const Value: TKsFontDevice);
    procedure SetFontType(const Value: TKsFontType);
    procedure SetListStyle(const Value: TKsListBoxStyle);
    procedure SetShowCheckBoxes(const Value: boolean);
    procedure SetSorted(const Value: Boolean);
    procedure SetWordWrap(const Value: boolean);
    procedure SetComboStyle(const Value: TKsComboStyle); 
    function GetFlat: boolean;
    function GetFontDevice: TKsFontDevice;
    function GetFontType: TKsFontType;
    function GetItems: TStrings;
    function GetListStyle: TKsListBoxStyle;
    function GetOnDrawItem: TDrawItemEvent;
    function GetOnMeasureItem: TMeasureItemEvent;
    function GetShowCheckBoxes: boolean;
    function GetSorted: Boolean;
    function GetWordWrap: boolean;
    procedure SetAutoComplete(const Value: boolean);
    function GetText: string;
    procedure SetText(Value: string);
    { Auto complete }
    procedure DoTimer(Sender: TObject);
  protected
    FComboWindow: TForm;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
    procedure WMNCLButtonDown(var Msg: TWMNCHitMessage); message WM_NCLBUTTONDOWN;
    procedure WMNCMouseMove(var Msg: TWMNCHitMessage); message WM_NCMOUSEMOVE;
    procedure WMMouseMove(var Msg: TWMMouse); message WM_MOUSEMOVE;
    procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
    procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
    procedure CMMouseWheel(var Msg: TCMMouseWheel); message CM_MOUSEWHEEL;
    procedure WMMouseWheel(var Msg: TWMMouseWheel); message WM_MOUSEWHEEL;
    procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
    { VCL }
    procedure KeyDown(var Key: word; Shift: TShiftState); override;
    procedure KeyUp(var Key: word; Shift: TShiftState); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; x, y: integer); override;
    procedure SetParent(AParent: TWinControl); override;
    { Edits }
    function GetEditRect: TRect; override;
    procedure PaintBorder(Buffer: TKsBitmap); override;
    procedure PaintBackground(Rect: TRect; Buffer: TKsBitmap); override;
    { Combo }
    procedure BeforeDropDown; virtual;
    procedure AfterDropDown; virtual;
    procedure DoListBoxClick(Sender: TObject);
    procedure ButtonClick; virtual;
    procedure PaintListItem(Rect: TRect; Buffer: TKsBitmap);
    function CreateListBox(AOwner: TComponent): TKsCustomListBox; virtual;
    function GetButtonRect: TRect;
    function GetButtonHeight: integer; virtual;
    property MouseOnButton: boolean read FMouseOnButton;
    property ListBox: TKsCustomListBox read FListBox;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Loaded; override;
    procedure Change; override;
    property ButtonPressed: boolean read FButtonPressed write FButtonPressed;
    property FontValue: TFont read GetFontValue;
    property ColorValue: TColor read GetColorValue;
  published
    property AutoComplete: boolean read FAutoComplete write SetAutoComplete;
    property ButtonAlign: TKsComboButtonAlign read FButtonAlign write SetButtonAlign default cbaRight;
    property ComboStyle: TKsComboStyle read FComboStyle write SetComboStyle;
    property DropDownCount: integer read FDropDownCount write SetDropDownCount;
    property ItemHeight: integer read FItemHeight write SetItemHeight;
    property Items: TStrings read GetItems write SetItems;
    property Flat: boolean read GetFlat write SetFlat;
    property FontDevice: TKsFontDevice read GetFontDevice write SetFontDevice default fdScreen;
    property FontType: TKsFontType read GetFontType write SetFontType default ftAll;
    property ItemIndex: integer read FItemIndex write SetItemIndex;
    property ListStyle: TKsListBoxStyle read GetListStyle write SetListStyle;
    property ShowCheckBoxes: boolean read GetShowCheckBoxes write SetShowCheckBoxes;
    property Sorted: Boolean read GetSorted write SetSorted default False;
    property Text: string read GetText write SetText;
    property WordWrap: boolean read GetWordWrap write SetWordWrap;
    property OnDrawItem: TDrawItemEvent read GetOnDrawItem write FOnDrawItem;
    property OnMeasureItem: TMeasureItemEvent read GetOnMeasureItem write FOnMeasureItem;
  end;

implementation {===============================================================}

uses KsForms;

type

  THackControl = class(TWinControl);
  THackListBox = class(TKsCustomListBox);

{ TKsComboWindow class }

  TKsComboWindow = class(TForm)
  private
    procedure CMShowingChanged(var Message: TMessage); //message CM_SHOWINGCHANGED;
    procedure WMActivate(var Msg: TWMActivate); message WM_ACTIVATE;
    procedure WMMouseActivate(var Msg: TWMMouseActivate); message WM_MOUSEACTIVATE;
  protected
    function GetForm: TWinControl;
    function GetKsForm: TKsCustomForm;
    procedure KeyDown(var Key: word; Shift: TShiftState); override;
  protected
    function CloseQuery: Boolean; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure CreateParams(var Params: TCreateParams); override;
  end;

{ TKsComboWindow ===============================================================}

constructor TKsComboWindow.Create(AOwner: TComponent);
begin
  inherited CreateNew(AOwner);
  BorderStyle := bsNone;
  KeyPreview := true;
end;

destructor TKsComboWindow.Destroy;
begin
  inherited Destroy;
end;

procedure TKsComboWindow.KeyDown(var Key: word; Shift: TShiftState);
begin
  inherited;
  if Key = VK_ESCAPE then
    Close;
  if (Key = VK_RETURN) or (Key = VK_SPACE) then
  begin
    if Owner is TKsCustomComboBox then
      (Owner as TKsCustomComboBox).ItemIndex := (Owner as TKsCustomComboBox).FListBox.ItemIndex;
    Close;
  end;
end;

procedure TKsComboWindow.CreateParams(var Params: TCreateParams);
begin
  inherited;
  with Params do
  begin
    ExStyle := ExStyle or WS_EX_TOPMOST or WS_EX_TOOLWINDOW;
    WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  end;
end;

function TKsComboWindow.GetForm: TWinControl;
begin
  if (Owner <> nil) and (Owner.Owner <> nil) and (Owner.Owner is TWinControl) then
    Result := Owner.Owner as TWinControl
  else
    Result := nil;
end;

function TKsComboWindow.GetKsForm: TKsCustomForm;
var
  Form: TWinControl;
  i: integer;
begin
  Result := nil;

  Form := GetForm;
  if Form <> nil then
  begin
    for i := 0 to Form.ComponentCount - 1 do
      if Form.Components[i] is TKsCustomForm then
      begin
        Result := Form.Components[i] as TKsCustomForm;
        Exit;
      end;
  end
  else
    Result := nil;
end;

function TKsComboWindow.CloseQuery: Boolean;
begin
  Result := inherited CloseQuery;

  { Restore Button }
  if Owner is TKsCustomComboBox then
  begin
    (Owner as TKsCustomComboBox).ButtonPressed := false;
    (Owner as TKsCustomComboBox).Invalidate;
  end;
end;

procedure TKsComboWindow.CMShowingChanged(var Message: TMessage);
const
  ShowFlags: array[Boolean] of UINT = (
    SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW,
    SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW);
begin
  { Must override TCustomForm/TForm's CM_SHOWINGCHANGED handler so that the
    form doesn't get activated when Visible is set to True. }
  SetWindowPos(WindowHandle, 0, 0, 0, 0, 0, ShowFlags[Showing]);
end;

procedure TKsComboWindow.WMActivate(var Msg: TWMActivate);
var
  OwnerForm: TWinControl;
begin
  inherited ;
  OwnerForm := GetForm;

  if (Msg.Active = WA_ACTIVE) and (OwnerForm <> nil) then
    SendMessage(OwnerForm.Handle, WM_NCACTIVATE, 1, 0);
  if (Msg.Active = WA_INACTIVE) then
  begin
    (Owner as TKsCustomComboBox).AfterDropDown;                  
    Close;
  end;
end;

procedure TKsComboWindow.WMMouseActivate(var Msg: TWMMouseActivate);
begin

end;

{ TKsCustomComboBox ===========================================================}

constructor TKsCustomComboBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FItemIndex := -1;
  FListBox := CreateListBox(Self);
  FListBox.KeyboardClick := false;
  FListBox.Parent := Self;
  FListBox.Visible := false;
  FListBox.OnClick := DoListBoxClick;

  if csDesigning in ComponentState then
    FListBox.Align := alNone
  else
    FListBox.Align := alClient;

  FButtonAlign := cbaRight;
  FItemHeight := 15;
  FDropDownCount := 8;

  FWork := false;
  FTimer := TTimer.Create(Self);
  FTimer.Interval := 100;
  FTimer.OnTimer := DoTimer;
  FTimer.Enabled := false;
end;

destructor TKsCustomComboBox.Destroy;
begin
  if FListBox <> nil then
    AfterDropDown;

  if FComboWindow <> nil then FComboWindow.Free;
  inherited Destroy;
end;

procedure TKsCustomComboBox.Loaded;
begin
  FWork := true;
  inherited Loaded;
  FWork := false;
  FOldText := '';

  Realign;
end;

procedure TKsCustomComboBox.SetParent(AParent: TWinControl);
begin
  inherited SetParent(AParent);

  if (csDesigning in ComponentState) and (AParent <> nil) then
    FListBox.SetBounds(0, 1000, 10, 10);
end;

procedure TKsCustomComboBox.Change;
begin
  inherited;
  if not (csLoading in ComponentState) and not (csDesigning in ComponentState) then
    if FAutoComplete then
      if not FWork then
        FTimer.Enabled := true;
end;

procedure TKsCustomComboBox.DoTimer(Sender: TObject);
var
  i: integer;
  S1, S2: string;
begin
  FTimer.Enabled := false;
  if Length(Text) < Length(FOldText) then
  begin
    FOldText := Text;
    Exit;
  end;
  if (FOldText <> Text) and (not FWork) then
  begin
    FOldText := Text;
    FWork := true;
    for i := 0 to Items.Count-1 do
    begin
      S1 := Items[i];
      S2 := Text;
      S1 := LowerCase(S1);
      S2 := LowerCase(S2);
      if S2 = Copy(S1, 1, Length(S2)) then
      begin
        Text := Items[i];
        SelStart := Length(S2);
        SelLength := Length(S1);
        FWork := false;
        Exit;
      end;
    end;
    FWork := false;
  end;
end;

{ Combo }

procedure TKsCustomComboBox.DoListBoxClick;
begin
  if FComboWindow <> nil then
  begin
    ItemIndex := FListBox.ItemIndex;
    AfterDropDown;
    FComboWindow.Close;
  end;
end;

function TKsCustomComboBox.CreateListBox(AOwner: TComponent): TKsCustomListBox;
begin
  Result := TKsCustomListBox.Create(Self);
end;

procedure TKsCustomComboBox.AfterDropDown;
begin
  if (FListBox.Visible) or (FListBox.Parent <> Self) and (Handle <> 0) then
  begin
    FListBox.Visible := false;
    THackControl(FListBox).SetParent(Self);
    Windows.SetParent(FListBox.Handle, Handle);

    if ComboStyle = kcsDropDownList then Change;
    Invalidate;

    if Enabled then
      SetFocus;
  end;
end;

procedure TKsCustomComboBox.BeforeDropDown;
begin
  if not FListBox.Visible then
  begin
    FListBox.Visible := true;
    THackControl(FListBox).SetParent(FComboWindow);
    Windows.SetParent(FListBox.Handle, FComboWindow.Handle);
    FListBox.Realign;
  end;
end;

procedure TKsCustomComboBox.ButtonClick;
var
  P: TPoint;
  Form: TKsCustomForm;
  i: integer;
begin
  if FComboWindow <> nil then
  begin
    AfterDropDown;

    FComboWindow.Free;
    FComboWindow := nil;
  end;

  FComboWindow := TKsComboWindow.Create(Self);
  { Set bounds }
  P := ClientToScreen(Point(0, FHeight));
  FComboWindow.Left := P.X;
  FComboWindow.Top := P.Y;
  FComboWindow.Width := Width;
  FComboWindow.Height := FDropDownCount * FItemHeight;
  if P.Y + FDropDownCount * FItemHeight > Screen.Height then
    FComboWindow.Top := P.Y - Height - FDropDownCount * FItemHeight;
  if P.X + Width > Screen.Width then
    FComboWindow.Left := Screen.Width - Width;

  { Clear selections }
  if Items.Count > 0 then
    for i := 0 to Items.Count - 1 do
      FListBox.Selected[i] := false;

  { Set selection }
  if FItemIndex >= 0 then
    FListBox.Selected[FItemIndex] := true
  else
    if Items.Count > 0 then
      FListBox.Selected[0] := true;

  FListBox.Color := Color;
  { Show }
  Form := (FComboWindow as TKsComboWindow).GetKsForm;
  if Form <> nil then
  begin
    Form.DisableDrawing;
    try
      FComboWindow.Show;
      { Place ListBox }
      BeforeDropDown;

      FListBox.SetFocus;
      FListBox.Invalidate;
    finally
      Form.EnableDrawing;
    end;
  end
  else
  begin
    { With out KsForm }
    FComboWindow.Show;
    BeforeDropDown;
    FListBox.SetFocus;
    FListBox.Invalidate;
  end;
end;

function TKsCustomComboBox.GetButtonRect: TRect;
begin
  Result := GetEditRect;

  if not AutoSize then
    Result.Bottom := FHeight - Result.Top;

  InflateRect(Result, 2, 2);

  if FButtonAlign = cbaLeft then
  begin
    Result.Right := Result.Left + GetButtonHeight;
    OffsetRect(Result, -GetButtonHeight, 0);
  end
  else
  begin
    Result.Left := Result.Right - GetButtonHeight;
    OffsetRect(Result, GetButtonHeight, 0);
  end;
end;

function TKsCustomComboBox.GetButtonHeight: integer;
begin
  Result := 15;
end;

{ Edits }

procedure TKsCustomComboBox.PaintListItem(Rect: TRect; Buffer: TKsBitmap);
var
  SaveSelected: boolean;
begin
  if FComboStyle = kcsDropDownList then
  begin
    if (High(THackListBox(FListBox).FSelected) > 0) and (FItemIndex >= 0) then
    begin
      SaveSelected := THackListBox(FListBox).FSelected[FItemIndex];
      THackListBox(FListBox).FSelected[FItemIndex] := Focused;
      THackListBox(FListBox).DrawItem(Buffer, FItemIndex, Rect);
      THackListBox(FListBox).FSelected[FItemIndex] := SaveSelected;
    end
    else
      if (FItemIndex >= 0) and (Items.Count > 0) then
        THackListBox(FListBox).DrawItem(Buffer, FItemIndex, Rect);

    if Focused then
      Buffer.DrawFocusRect(Rect, ckWhite);
  end;
end;

procedure TKsCustomComboBox.PaintBackground(Rect: TRect; Buffer: TKsBitmap);
begin
  inherited PaintBackground(Rect, Buffer);
  PaintListItem(Rect, Buffer);
end;

procedure TKsCustomComboBox.PaintBorder(Buffer: TKsBitmap);
var
  R: TRect;
  B: TKsBitmap;
  Flags: Integer;
begin
  inherited PaintBorder(Buffer);
  { Draw Button }
  R := GetButtonRect;

  with Buffer do
  begin
    Flags := DFCS_SCROLLCOMBOBOX;
    if ButtonPressed then
      Flags := Flags or DFCS_PUSHED;

    DrawFrameControl(Buffer.DC, R, DFC_SCROLL, Flags);
  end;
end;

function TKsCustomComboBox.GetEditRect: TRect;
begin
  Result := Rect(0, 0, FWidth, FHeight);
  InflateRect(Result, -4, -4);

  if FButtonAlign = cbaRight then
    Dec(Result.Right, GetButtonHeight)
  else
    Inc(Result.Left, GetButtonHeight);

  Buffer.Font.Assign(Font);
  Result.Bottom := Result.Top + Buffer.TextHeight('Pq');
end;

procedure TKsCustomComboBox.KeyDown(var Key: word; Shift: TShiftState);
begin
  inherited;

  if (ssAlt in Shift) and (Key = VK_DOWN) then
  begin
    ButtonClick;
    Exit;
  end;

  case Key of
    VK_UP: ItemIndex := ItemIndex - 1;
    VK_DOWN: ItemIndex := ItemIndex + 1;
    VK_PRIOR: if not (FComboStyle = kcsDropDown) then ItemIndex := ItemIndex - 3;
    VK_NEXT: if not (FComboStyle = kcsDropDown) then ItemIndex := ItemIndex + 3;
    VK_END: if not (FComboStyle = kcsDropDown) then ItemIndex := Items.Count - 1;
    VK_HOME: if not (FComboStyle = kcsDropDown) then ItemIndex := 0;
  else
    Exit;
  end;

  if ItemIndex < 0 then ItemIndex := 0;  
  
  if ComboStyle = kcsDropDownList then Change;
  Invalidate;
end;

procedure TKsCustomComboBox.KeyUp(var Key: word; Shift: TShiftState);
begin
  inherited;

end;

procedure TKsCustomComboBox.MouseDown(Button: TMouseButton;
  Shift: TShiftState; x, y: integer);
begin
  inherited;

  if csDesigning in ComponentState then Exit;

  if FComboStyle = kcsDropDownList then
    ButtonClick;
end;

{ Windows Messages }

procedure TKsCustomComboBox.WMNCLButtonDown(var Msg: TWMNCHitMessage);
var
  P: TPoint;
begin
  inherited ;
  if csDesigning in ComponentState then Exit;
  
  P := Point(Msg.XCursor, Msg.YCursor);
  P := ScreenToClient(P);

  if not Focused then
    SetFocus;

  if PtInRect(GetButtonRect, P) then
  begin
    { Down }
    FButtonPressed := true;
    Invalidate;
    { ButtonClick }
    ButtonClick;
  end;
end;

procedure TKsCustomComboBox.WMMouseMove(var Msg: TWMMouse);
begin
  inherited ;

  if csDesigning in ComponentState then Exit;
  
  if FMouseOnButton then
  begin
    FMouseOnButton := false;
    Invalidate;
  end;
end;

procedure TKsCustomComboBox.WMNCMouseMove(var Msg: TWMNCHitMessage);
var
  P: TPoint;
begin
  inherited ;

  if csDesigning in ComponentState then Exit;
  
  P := Point(Msg.XCursor, Msg.YCursor);
  P := ScreenToClient(P);

  if not FMouseOnButton then
  begin
    if PtInRect(GetButtonRect, P) then
    begin
      FMouseOnButton := true;
      Invalidate;
    end
  end
  else
    if not PtInRect(GetButtonRect, P) then
    begin
      FMouseOnButton := false;
      Invalidate;
    end;
end;

{ Properties }

procedure TKsCustomComboBox.SetButtonAlign(const Value: TKsComboButtonAlign);
begin
  if FButtonAlign <> Value then
  begin
    FButtonAlign := Value;
    Invalidate;
  end;
end;

procedure TKsCustomComboBox.WMNCHitTest(var Msg: TWMNCHitTest);
var
  P: TPoint;
begin
  P := Point(Msg.XPos, Msg.YPos);
  P := ScreenToClient(P);

  if PtInRect(GetEditRect, P) then
    Msg.Result := HTCLIENT
  else
    Msg.Result := HTREDUCE;
end;

procedure TKsCustomComboBox.CMMouseLeave(var Message: TMessage);
begin
  inherited ;

  if FMouseOnButton then
  begin
    FMouseOnButton := false;
    Invalidate;
  end;
end;

procedure TKsCustomComboBox.CMMouseWheel(var Msg: TCMMouseWheel);
var
  Dy: integer;
  sl: integer;
begin
  if IsWinNT or IsWin98 then
    SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, @sl, SPIF_SENDCHANGE)
  else
    sl := 3;

  if sl = 0 then
    sl := 1;

  Dy := Msg.WheelDelta div (MOUSE_WHEEL_DELTA div sl);

  ItemIndex := ItemIndex - Dy;
  if ItemIndex < 0 then ItemIndex := 0;
  if ComboStyle = kcsDropDownList then Change;
  Invalidate;
end;

procedure TKsCustomComboBox.WMMouseWheel(var Msg: TWMMouseWheel);
var
  Dy: integer;
begin
  Dy := Msg.WheelDelta div MOUSE_WHEEL_DELTA;

  ItemIndex := ItemIndex - Dy;
  if ItemIndex < 0 then ItemIndex := 0;  
  if ComboStyle = kcsDropDownList then Change;
  Invalidate;
end;

procedure TKsCustomComboBox.WMSetCursor(var Msg: TWMSetCursor);
begin
  if FComboStyle = kcsDropDown then
    inherited
  else
  begin
    if Smallint(Msg.HitTest) = HTCLIENT then
    begin
      Windows.SetCursor(Screen.Cursors[crDefault]);
      Msg.Result := 0
    end
    else
      inherited ;
  end;
end;

procedure TKsCustomComboBox.WMKillFocus(var Msg: TWMKillFocus);
begin
  inherited ;
  if FComboStyle = kcsDropDownList then
    Invalidate;
end;

procedure TKsCustomComboBox.WMSetFocus(var Msg: TWMSetFocus);
begin
  inherited ;
  if FComboStyle = kcsDropDownList then
  begin
    HideCaret;
    Invalidate;
  end;
end;

{ Properties }

function TKsCustomComboBox.GetColorValue: TColor;
begin
  if FListBox <> nil then
    Result := FListBox.ColorValue;
end;

function TKsCustomComboBox.GetFontValue: TFont;
begin
  if FListBox <> nil then
    Result := FListBox.FontValue;
end;

function TKsCustomComboBox.GetFlat: boolean;
begin
  if FListBox <> nil then
    Result := FListBox.Flat;
end;

function TKsCustomComboBox.GetFontDevice: TKsFontDevice;
begin
  if FListBox <> nil then
    Result := FListBox.FontDevice;
end;

function TKsCustomComboBox.GetFontType: TKsFontType;
begin
  if FListBox <> nil then
    Result := FListBox.FontType;
end;

function TKsCustomComboBox.GetItems: TStrings;
begin
  if FListBox <> nil then
    Result := FListBox.Items;
end;

function TKsCustomComboBox.GetListStyle: TKsListBoxStyle;
begin
  if FListBox <> nil then
    Result := FListBox.ListStyle;
end;

function TKsCustomComboBox.GetOnDrawItem: TDrawItemEvent;
begin
  if FListBox <> nil then
    Result := FListBox.OnDrawItem;
end;

function TKsCustomComboBox.GetOnMeasureItem: TMeasureItemEvent;
begin
  if FListBox <> nil then
    Result := FListBox.OnMeasureItem;
end;

function TKsCustomComboBox.GetShowCheckBoxes: boolean;
begin
  if FListBox <> nil then
    Result := FListBox.ShowCheckBoxes;
end;

function TKsCustomComboBox.GetSorted: Boolean;
begin
  if FListBox <> nil then
    Result := FListBox.Sorted;
end;

function TKsCustomComboBox.GetWordWrap: boolean;
begin
  if FListBox <> nil then
    Result := FListBox.WordWrap;
end;

procedure TKsCustomComboBox.SetDropDownCount(const Value: integer);
begin
  FDropDownCount := Value;
end;

procedure TKsCustomComboBox.SetItemHeight(const Value: integer);
begin
  FItemHeight := Value;
end;

procedure TKsCustomComboBox.SetItemIndex(const Value: integer);
begin
  FItemIndex := Value;

  if (FComboStyle = kcsDropDown) and (csLoading in ComponentState) then Exit;

  if FItemIndex < -1 then FItemIndex := 0;
  if FItemIndex > Items.Count - 1 then FItemIndex := Items.Count - 1;

  if FComboStyle = kcsDropDownList then
    if FItemIndex < -1 then FItemIndex := 0;

  if FComboStyle = kcsDropDown then
    if (FItemIndex >= 0) and (FItemIndex < FListBox.Items.Count) then
      Text := Items[FItemIndex];

  if (FComboStyle = kcsDropDownList) and not (csLoading in ComponentState) then
  begin
    if Assigned(OnChange) then
      OnChange(Self);
  end;

  Invalidate;
end;

procedure TKsCustomComboBox.SetItems(const Value: TStrings);
begin
  if (FListBox <> nil) then
    FListBox.Items.Assign(Value);
end;

procedure TKsCustomComboBox.SetFlat(const Value: boolean);
begin
  if (FListBox <> nil) then
    FListBox.Flat := Value;
end;

procedure TKsCustomComboBox.SetFontDevice(const Value: TKsFontDevice);
begin
  if (FListBox <> nil) then
    FListBox.FontDevice := Value;
end;

procedure TKsCustomComboBox.SetFontType(const Value: TKsFontType);
begin
  if (FListBox <> nil) then
    FListBox.FontType := Value;
end;

procedure TKsCustomComboBox.SetListStyle(const Value: TKsListBoxStyle);
begin
  if (FListBox <> nil) then
    FListBox.ListStyle := Value;
end;

procedure TKsCustomComboBox.SetShowCheckBoxes(const Value: boolean);
begin
  if (FListBox <> nil) then
    FListBox.ShowCheckBoxes := Value;
end;

procedure TKsCustomComboBox.SetSorted(const Value: Boolean);
begin
  if (FListBox <> nil) then
    FListBox.Sorted := Value;
end;

procedure TKsCustomComboBox.SetWordWrap(const Value: boolean);
begin
  if (FListBox <> nil) then
    FListBox.WordWrap := Value;
end;

procedure TKsCustomComboBox.SetComboStyle(const Value: TKsComboStyle);
begin
  FComboStyle := Value;

  case FComboStyle of
    kcsDropDown: begin
      ReadOnly := FOldReadOnly;
      ShowCaret;
    end;
    kcsDropDownList: begin
      ItemIndex := 0;
      FOldReadOnly := ReadOnly;
      ReadOnly := true;
      Text := '';
      HideCaret;
    end;
  end;
end;

procedure TKsCustomComboBox.SetAutoComplete(const Value: boolean);
begin
  FAutoComplete := Value;
end;

function TKsCustomComboBox.GetText: string;
begin
  if (FComboStyle = kcsDropDownList) and ((ItemIndex >= 0) and (ItemIndex < Items.Count)) then
    Result := Items[ItemIndex]
  else
    Result := inherited Text;  
end;

procedure TKsCustomComboBox.SetText(Value: string);
begin
  inherited Text := Value;
end;

end.
