unit vcl.wwdblook;
{
//
// Components : TwwDBLookupCombo
//
// Copyright (c) 1995-2001 by Woll2Woll Software
//
// 7/10/97 - Support non TwwTable lookup against a Linked or Lookup Field
// 7/21/97 - Added try/finally block to handle exceptions in EnableEdit
// 7/21/97 - ChangeFromLink now sets modified to True if just a plain calculated field
//           Previously would always be false in this case.
// 7/24/97 - Limit length to be up to field size
//
// 7/28/97 - If processing OnNotInList then ignore focus change since its
//           triggered by a message dialog by the user.  If we do call
//           UpdateRecord then the component incorrectly updates the tfield
//           even though the OnNotInList handler may indicate that it
//           it should not be updated.  Also select all text when
//           restoring back-values if user sets accept to false.
//
// 7/28/97   If modified then escape restores previous text.  Code added
//           to CnKeyDown.  UpdateData calls Closeup to handle NotInList.
//
// 7/30/97   Remove index switching on detail lookuptable when using a lookupfield
//
// 9/10/97 - Method UpdateFromCurrentSelection - Do not update active record if
//           its a TwwDBLookupComboDlg
//
// 9/18/97 - Reset backvalues when getting focus
//           Previously this code was in WMSetFocus, but that is fired also when
//           the form gets focus.  When the following code was placed in WMSetFocus,
//           the backvalues were incorrectly reset
//
// 9/18/97 - Escape updates FGrid.FDisplayValue instead of DisplayValue.
//           Previously in some cases could clear FDisplayValue to blank
//
// 9/18/97 - Don't beep when ShowMatchText is True
//
// 9/19/97 - Method KeyDown, Set ProcessingNotInList to True on escape so
//           validation is skipped in CMExit
//
// 9/28/97 - Assign TField.Text property intead of AsString property to fire
//           TField.OnSetText
//
// 10/5/97 - Method RefreshDisplay modifed to call DoLookup(False) to ensure
//           that lookuptable is positioned correctly before reading values.
//           Call this method to refresh the lookupcombo based on changes in
//           lookuptable.
//
// 10/12/97- Allows component to left-justify when exiting by setting selStart
//           to 0 in cmExit
// 10/16/97- When you have multiple combos on a form and the state changed from
//           Browse to Edit, then the combo would have its index changed while the
//           dropdown list was visible.  SetValue modified.
//
// 10/20/97- Use EnableEdit instead of FFieldLink.Edit so flag is set
// 10/20/97- Prevent the index from switching when delete key is pressed
// 10/21/97- Fix bug when drop-down grid remains visible after leaving column in
//           grid
//
// 10/27/97 - Fix for drawing text as disabled when control is dropdownlist style
//
// 10/29/97 - Search on calculated or lookup fields during incremental searching.
//            Previously used Locate method which did not support this.
//
// 11/6/97 -  Control was blank in some cases (i.e record-view dialog).  This
//            problem is now fixed.
//
// 11/15/97 - In Some Cases Quicken-Style would not work with autodropdown.
//            problem is now fixed.
//
// 11/19/97 - Fix - AllowClearKey when dropped down would change index order
// 11/25/97 - csDropDownList previosly did not update text when display field
//            differed from stored field in certain cases.
//
// 12/2/97 -  linked/lookup field use linked/lookup field value.
//            Optmization code now executed even when control is not visible
// 1/22/98 -  Don't allow clear key if csDropDownList
// 1/23/98 -  Clear FDisplayValue and hiliterow in AllowClearKey dropped-down case
//
// 2/5/98 -   Clear FDatalink.modified when encountering a vk_esc
//
// 2/20/98 - Don't clear tfield, so that esc can restore original contents
// 2/24/98 - Enable timer in KeyPress instead of KeyUp
//
// 3/1/98 -  Have NotInList event support for expression indexes
// 4/17/98 - Finish drawing down state in TwwComboButton MouseDown event
// 5/11/98 - Support Ctl3d=False
// 6/11/98 - Check for readonly flag when changing linked fields
// 8/24/98 - Support Delphi 4 ActionLists
// 8/25/98 - RefreshDisplay did not work properly with blank lookup values
// 8/25/98 - Update horzscrollbar property based on column widths.  This fixes
//           problem when have less rows than drop-down count.  The problem caused
//           the drop-down list to have the wrong active row when the last record
//           was selected.
// 8/26/98 - Adjust height more accurately as drop-down list was too tall when
//           titles were not shown in drop-down list
// 9/1/98 -  Don't call SetFocus unless CanFocus returns true in CMExit
// 9/2/98 -  Call FButton.Update in paint event so Delphi 4 paints icon correctly
//           in DBCtrlGrid
// 10/6/98 - Check dgTabs in cnKeyDown
// 10/8/98 - Fix problem with dgRowLines having the wrong number of records dropped down
// 10/16/98 - Drop-down grid created with height=0 for faster performance
// 11/15/98 - Calling closeup immediately would cause problems from hook
// 11/24/98 - Fix issues with pasting into control with respect to cs_DropDownList
// 1/20/99 -  Don't allow clear key if csDropDownList with AllowClearKey=False
// 1/21/99 -  Fix paint problem in situations where user invokess a dialog
              and when the dialog closes the focus returns to this control.
// 1/25/99 - Prevent grid's OnKeyDown from firing twice when encounter tab or cr
// 1/27/99 - Fixed problem with lookupfields where it was trying to assign a string
//           to the lookup field
// 3/9/99 -  Raise exception if exception raised in TField OnValidate.  Previously
//           the exception message would not be shown.  Also the focus could be lost without
//           this change.
// 3/14/99 - Remove flicker when shortening drop-down list (Delphi 4 problem only )
// 3/23/99 - Fix for 3/14/99 change
// 3/29/99 - RSW Don't clear unbound control if not in list
// 5/12/99 - Avoid exception by checking if semi-color exists in lookup field
// 5/27/99 - When clicking on a different combo dropdown controls edit area the
//           current combos text would be cleared after a delete.
// 6/16/99 - Fix problem where text didn't get cleared in tfield
// 7/25/99 - If entered text is not subset of current lookup record,
//           then set inlist to false.  This could happen if a trailing space
//           was in the entered text
// 10/20/99  Fixed alignment problem where it was using stored field's alignment
// 10/23/99 - Skip grid's hide controls when going into edit mode so
//            that focus does not move to the grid. Otherwise this could cause
//            the first character to be lost in some instances.
// 12/3/99 - Fix bug with button width not being used
// 12/11/99 - Fix problem of text not getting restored when OnNotInList sets
//            accept to false.
// 1/10/2000 -Fix problem of non TwwDatasets not recognizing control
//            information in drop-down list
// 3/7/00 - Use clGrayText for disabled color
// 3/9/00 - Fix problem when searching calculated field, as it was
//          not updating higlighted record.
// 3/14/00 - MDI forms should check ActiveControl instead of focused
//           to fix problem where 2nd button clicked was not recognized in MDI child
// 4/12/00 - Don't unselectall if showmatch text and partial selection from start already there
// 5/3/00 - Don't go into edit for readonly dataset
// 6/14/00 - RSW Fix problem with scroll thumb being too small as visiblerowcount is incorrect
// 7/31/00 - Makes sure modified is set in combo's change
// 8/17/00 - Add Option | loFixedDropDownHeight to support custom search
// 8/17/00 - Add OnPerformCustomSearch event for paramaterized query searching
// 9/13/00 - Workaround problem where locate ignores trailing spaces
// 10/17/00 - Height not accurate when multiple title lines are shown
// 11/28/2000 - PYW - Check based on actual work area.
// 8/8/01 - If auto-dropping down the item would not be highlighted in some cases.
// 9/7/2001 - Don't Clear unbound control if Accept was True.
// 3/12/02 - Support mousewheel
// 4/16/02 - Use AnsiUppercase instead.
// 12/12/02 - Don't unclear unbound control if accept is true
// 12/13/02 - Fix bug where still cleared even though AutoEdit=False
// 12/16/02 - Delphi 7 needs topmost so that hint window doesn't send the
//            listbox to the background
// 3/06/03 - Check for blank field name om timer event
// 4/9/03 - Fix bug with Navigator property causing Access violation
// 4/26/03 - Fix problem where hint for other control closing up dialog
// 5/17/03 - Call DropDown in cases where previously exited.  Otherwise AutoDropDown
//           does not always drop down if not found in list
// 6/10/03 - Respect bidi mode
// 8/16/04 - Update text to be same as lookupfield
// 10/24/06 - Performance issue - Remove extra unnecessary search
}
interface

{$i wwIfDef.pas}
uses Windows, Classes, StdCtrls, DB, Controls, Messages, SysUtils,
  Forms, Graphics, Menus, Buttons, Grids, dialogs,
  wwCommon, wwstr, wwdbigrd, extctrls, wwlocate, dbctrls,
  wwtypes, wwframe, wwdbedit, wwcombobutton, wwintl,
  system.Types, system.UITypes;
type

  TNotifyCloseUpEvent = procedure(Sender: TObject;
     LookupTable: TDataSet; FillTable: TDataSet; modified: boolean) of object;
  TNotInListEvent = procedure(Sender: TObject;
     LookupTable: TDataSet; NewValue: string; var Accept: boolean) of object;
  TwwPerformSearchEvent = procedure(Sender: TObject;
     LookupTable: TDataSet;
     SearchField: string;
     SearchValue: string;
     PerformLookup: boolean;
     var Found: boolean) of object;

  TwwPopupGrid = class;

  TwwDBLookupComboStyle = (csDropDown, csDropDownList);
  TwwDBLookupListOption = (loColLines, loRowLines, loTitles, loFixedDropDownHeight,
                           loSearchOnBackspace);
  TwwDBLookupListOptions = set of TwwDBLookupListOption;

  TwwCalcFieldType = (cftUnknown, cftCalculated, cftNotCalculated);

  TwwSeqSearchOption = (ssoEnabled, ssoCaseSensitive);
  TwwSeqSearchOptions = set of TwwSeqSearchOption;
  TwwLookupSearchType = (lstDefault, lstCustom);

//  TwwLookupComboButtonStyle = (lcbsEllipsis, lcbsDownArrow, lcbsCustom);

  TwwDropDownGridOptions = class(TPersistent)
  private
     FTitleLines: integer;
     FColor: TColor;
     FTitleAlignment: TAlignment;
  public
     constructor Create(AOwner: TComponent);
  published
     property TitleLines: integer read FTitleLines write FTitleLines default 1;
     property Color: TColor read FColor write FColor default clWindow;
     property TitleAlignment: TAlignment read FTitleAlignment write FTitleAlignment default taLeftJustify;
  end;

  TwwDBCustomLookupCombo= class(TCustomEdit)
  private
    {$ifndef GRIDESSENTIALS}
    FController: TwwController;
    {$endif}
    FPicture: TwwDBPicture;
    FDropDownAlignment: TLeftRight;
    FCanvas: TControlCanvas;
    FDropDownCount: Integer;
    FDropDownWidth: Integer;
    FBtnControl: TWinControl;
    FStyle: TwwDBLookupComboStyle;
    FOnDropDown: TNotifyEvent;
    FOnCloseUp: TNotifyCloseUpEvent;
    FOnNotInList: TNotInListEvent;
    FOnMouseEnter: TNotifyEvent;
    FOnMouseLeave: TNotifyEvent;
    FShowMatchText: boolean;
//    FLookupSearchType: TwwLookupSearchType;
    FOnPerformCustomSearch: TwwPerformSearchEvent;
    FOnBeforeDropDown: TNotifyEvent;
    FDropDownGridOptions: TwwDropDownGridOptions;
    FNavigator: boolean;

    ChangingFromLink: boolean;
    ProcessingNotInList: boolean;
    InCloseUpEvent: boolean;
    FSearchDelay: integer;
    FAutoDropDown: boolean;
    FSearchField: String;
    FSeqSearchOptions: TwwSeqSearchOptions;
    FOrderByDisplay: boolean;
    FItemCount: integer;
    FPreciseEditRegion: boolean;
    FAllowClearKey: boolean;
    FUseTFields: boolean;
    FImageList: TImageList;
    FButtonStyle: TwwComboButtonStyle;

    ExtraHeight: integer;     { Extra 1 pixel for height when in 16 bit }
    FControlInfoInDataset: boolean;
    FFrame: TwwEditFrame;
//    FUnboundAlignment: TAlignment;
    FButtonEffects: TwwButtonEffects;
//    FButtonGlyph: TBitmap;
    FButtonWidth: integer;
//    FFlatButton: boolean;
//    FFlatButtonTransparent: boolean;
//    FTransparent: boolean;
//    FCreateTransparent: boolean;

//    procedure SetTransparent(val: boolean);
    SkipUpdate: boolean;
    SetModifiedInChangeEvent: boolean;
//    InDropDownEvent, InCustomSearch: boolean;
    InDropDownEvent: boolean;
    InCustomSearch: boolean;
    FDisableThemes: boolean;
    OldShowHint: boolean;
    FMouseInControl: boolean;

    class constructor Create;
    function GetDataField: string;
    function GetDataSource: TDataSource;
    function GetLookupTable: TDataSet;
    function GetLookupField: string;
    function GetReadOnly: Boolean;
    function GetValue: string;
    function GetValue2: string;
    function GetValue3: string;

//    procedure BtnMouseDown(Sender: TObject; Button: TMouseButton;
//       Shift: TShiftState; X, Y: Integer);
    procedure EnableEdit;
    function GetDisplayValue: string;
    function GetMinHeight: Integer;
    function GetOptions: TwwDBLookupListOptions;
    function CanEdit: Boolean;
    function Editable: Boolean;
    function MouseEditable: Boolean;
    procedure SetValue(const NewValue: string);
    procedure SetDisplayValue(const NewValue: string);
    procedure DataChange(Sender: TObject);
    procedure EditingChange(Sender: TObject);
    procedure SetDataField(const Value: string);
    procedure SetDataSource(Value: TDataSource);
{    procedure SetLookupSource(Value: TDataSource);} { 4/30/97 - Not used }
    procedure SetLookupTable(sel : TDataSet);
    procedure SetLookupField(const Value: string);
    procedure SetReadOnly(Value: Boolean);
    procedure SetOptions(Value: TwwDBLookupListOptions);
    procedure SetStyle(Value: TwwDBLookupComboStyle);
    Procedure SetPreciseEditRegion(val: boolean);
    procedure FieldLinkActive(Sender: TObject);
    procedure NonEditMouseDown(var Message: TWMLButtonDown);
    procedure DoSelectAll;
    procedure SetEditRect;
    procedure WMSetFont(var Message: TWMSetFont); message WM_SETFONT;
    procedure WMPaste (var Message: TMessage); message WM_PASTE;
    procedure WMCut (var Message: TMessage); message WM_CUT;
    procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
    procedure CMCancelMode(var Message: TCMCancelMode); message CM_CANCELMODE;
    procedure CMExit(var Message: TCMExit); message CM_EXIT;
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
    procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
    procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
    procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
    procedure CMEnter(var Message: TCMGotFocus); message CM_ENTER;
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
    procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
    procedure WMChar(var Msg: TWMChar); message WM_CHAR;
    procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBkgnd;
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
    procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK;
    procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT;    
    function getSelectedFields: TStrings;
    procedure setSelectedFields(sel : TStrings);

    function GetShowButton: boolean;
    procedure SetShowButton(sel: boolean);
    Function IsLookup: boolean;
    Procedure SetUseTFields(val: boolean);
    Function GetControlType: TStrings;
    Procedure SetControlType(val: TStrings);
    procedure SetButtonGlyph(Value: TBitmap);
    Function GetButtonGlyph: TBitmap;
    procedure SetButtonStyle(val: TwwComboButtonStyle);
    Procedure SetButtonWidth(val: integer);
    function GetButtonWidth: integer;
    procedure SetNavigator(Value: boolean);
    {$ifndef GRIDESSENTIALS}
    procedure SetController(Value: TwwController);
    {$endif}

  protected
    FFieldLink: TFieldDataLink;
    FTimer: TTimer;

    FGrid: TwwPopupGrid;
    FButton: TwwComboButton;
    FLastSearchKey: string;  { Last Incremental Search value }
    InList: Boolean;
    TypedInText: string;
    OldLookupValue, OldDisplayValue: string; { Restore backvalues for unbound case}
    InAutoDropDown: boolean;
    SkipDataChange: boolean;  { Skip DataChange event so index doesn't change }
    FMouseInButtonControl: boolean;
    FFocused: Boolean;

    function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
    function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
    Function HasMasterSource: boolean;
    Function UseSeqSearch: boolean;
    Function LTable: TDataSet;
    Function IsWWCalculatedField: boolean;
    Procedure DrawButton(Canvas: TCanvas; R: TRect; State: TButtonState;
       ControlState: TControlState; var DefaultPaint: boolean); virtual;

    Function SetValue2: string; { Set based on 2nd lookup field }
    Function SetValue3: string; { Set based on 3rd lookup field }
    procedure WwChangeFromLink(AlookupTable: TDataSet; var modified: boolean);
    procedure OnEditTimerEvent(Sender: TObject); virtual; { Delay before doing incremental search }
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    function GetLookupSource: TDataSource;

    procedure UpdateData(Sender: TObject); reintroduce; // 5/21/03 - Unicode

    procedure Notification(AComponent: TComponent;
      Operation: TOperation); override;
    procedure Change; override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure CreateWnd; override;
    procedure GridClick (Sender: TObject);
    procedure Loaded; override;
    Function GetLookupValue : string;
    procedure RedrawListGrid;
    Procedure UpdateButtonGlyph;
//    Function LoadComboGlyph: HBitmap; virtual;
    procedure CNKeyDown(var Message: TWMKeyDown); message CN_KEYDOWN; {handle tab}
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure UpdateFromCurrentSelection;
    procedure UpdateSearchIndex(useDisplayIndex: boolean);
    Function GetSearchIndex: integer;
    Procedure SetModified(val: boolean);
    Function IsValidChar(key: word): boolean;
    Function IsLookupDlg: boolean; virtual;
    Function IsLookupRequired: boolean;
    Function DoFindRecord(ASearchValue, ASearchField: string;  { For TwwTable finds }
                          matchType: TwwLocateMatchType): boolean; virtual;
    Procedure ComputeLookupFields;
    Procedure UpdateButtonPosition;
    function FindRecord(
       KeyValue: string;
       LookupField: string;
       MatchType: TwwLocateMatchType;
       CaseSensitive: boolean;
       PerformLookup: boolean = False): boolean; virtual;
//    procedure GetEditRectForFrame(var Loc: TRect); virtual;
    procedure DrawFrame(Canvas: TCanvas); virtual;
//    procedure GlyphChanged(Sender: TObject); virtual;
    function IsCustom: Boolean; virtual;
    function Is3DBorder: boolean;
    function GetEffectiveAlignment: TAlignment;
    procedure InvalidateTransparentButton;
    procedure PerformCustomSearch(
              SearchField: string;
              SearchValue: string;
              PerformLookup: boolean;
              var Found: boolean); virtual;
    procedure DoMouseEnter; virtual;
    procedure DoMouseLeave; virtual;
    function IsVistaComboNonEditable: boolean; virtual;

    // TwwTable specific methods
    Function UseExprIndex: boolean;
    Function IndexFields(index: integer): TField;
    procedure SetToIndexContainingField(fieldName: string);
    procedure SetToIndexContainingFields(fields: TStrings);

    function wwFindRecord(
      KeyValue: string;
      LookupField: string;
      MatchType: TwwLocateMatchType;
      caseSensitive: boolean): boolean;
    Function wwFindNearest(key: string; FieldNo: integer): boolean;
    Function wwFindKey(const KeyValues: array of Const): Boolean;

    property ControlCanvas:TControlCanvas read FCanvas;
    property MouseInControl: boolean read FMouseInControl;
  public
    wwDBCalcFieldType : TwwCalcFieldType;
    Patch: Variant;

    {$ifdef wwdelphi4up}
    function ExecuteAction(Action: TBasicAction): Boolean; override; { 8/24/98 }
    function UpdateAction(Action: TBasicAction): Boolean; override; {8/24/98}
    {$endif}

    function isTransparentEffective: boolean;
    procedure RefreshDisplay;  {Used only by property editor in design mode }
    procedure RefreshButton;
    procedure PerformSearch; { Call this from your onDropDown event if you apply a filter}

    procedure KeyPress(var Key: Char); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure DropDown; dynamic;
    procedure CloseUp (modified: boolean); dynamic;
    property Value: string read GetValue write SetValue;
    property Value2: string read GetValue2;
    property Value3: string read GetValue3;
    property LookupValue: string read GetLookupValue write SetValue;
    property DisplayValue: string read GetDisplayValue write SetDisplayValue;
    property SearchField: string read FSearchField write FSearchField;

    property DropDownAlignment: TLeftRight read FDropDownAlignment write FDropDownAlignment;
    property Selected : TStrings read getSelectedFields write setSelectedFields;
    property DataField: string read GetDataField write SetDataField;
    property DataSource: TDataSource read GetDataSource write SetDataSource;
    property ButtonStyle: TwwComboButtonStyle read FButtonStyle write SetButtonStyle;
    property ButtonEffects: TwwButtonEffects read FButtonEffects write FButtonEffects;
//    property ButtonFlat : boolean read GetFlatButton write SetFlatButton default False;
//    property ButtonTransparent: boolean read FFlatButtonTransparent write SetFlatButtonTransparent default false;
    property ButtonGlyph: TBitmap read GetButtonGlyph write SetButtonGlyph stored IsCustom;
    property ButtonWidth: integer read GetButtonWidth write SetButtonWidth default 0;
    property LookupTable : TDataSet read getLookupTable write setLookupTable;
    property LookupField: string read GetLookupField write SetLookupField;
    property Options: TwwDBLookupListOptions read GetOptions write SetOptions default [];
    property Style: TwwDBLookupComboStyle read FStyle write SetStyle default csDropDown;
    property DropDownCount: Integer read FDropDownCount write FDropDownCount default 8;
    property DropDownWidth: Integer read FDropDownWidth write FDropDownWidth default 0;
    property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
    property AutoDropDown: boolean read FAutoDropDown write FAutoDropDown;
    property OnDropDown: TNotifyEvent read FOnDropDown write FOnDropDown;
    property OnBeforeDropDown: TNotifyEvent read FOnBeforeDropDown write FOnBeforeDropDown;
    property OnCloseUp: TNotifyCloseUpEvent read FOnCloseUp write FOnCloseUp;
    property ShowButton: boolean read GetShowButton write SetShowButton;
    property SeqSearchOptions: TwwSeqSearchOptions read FSeqSearchOptions write FSeqSearchOptions
             default [ssoEnabled];
//    property Transparent: boolean read FTransparent write SetTransparent;
    property OnNotInList: TNotInListEvent read FOnNotInList write FOnNotInList;
    property Grid : TwwPopupGrid read FGrid write FGrid;
    property OrderByDisplay: boolean read FOrderByDisplay write FOrderByDisplay default True;
    property PreciseEditRegion: boolean read FPreciseEditRegion write SetPreciseEditRegion;
    property AllowClearKey: boolean read FAllowClearKey write FAllowClearKey;
    property ShowMatchText: boolean read FShowMatchText write FShowMatchText default False;
    property UseTFields: boolean read FUseTFields write SetUseTFields default True;
    property ImageList:TImageList read FImageList write FImageList;
    property ControlInfoInDataset: boolean
             read FControlInfoInDataset write FControlInfoInDataSet default True;
    property ControlType: TStrings read GetControlType write SetControlType;
    property Frame: TwwEditFrame read FFrame write FFrame;
    {$ifndef GRIDESSENTIALS}
    property Controller : TwwController read FController write SetController;
    {$endif}

//    property UnboundAlignment : TAlignment read FUnboundAlignment write FUnboundAlignment default taLeftJustify;
    property SearchDelay: integer read FSearchDelay write FSearchDelay default 0;
//    property LookupSearchType: TwwLookupSearchType read FLookupSearchType write FLookupSearchType default lstDefault;
    property DropDownGridOptions: TwwDropDownGridOptions read FDropDownGridOptions write FDropDownGridOptions;
    property OnPerformCustomSearch: TwwPerformSearchEvent read FOnPerformCustomSearch write FOnPerformCustomSearch;
    property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter;
    property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave;
    property Navigator : boolean read FNavigator write SetNavigator default False;
    property DisableThemes : boolean read FDisableThemes write FDisableThemes default False;
  published
    {$ifdef wwDelphi4Up}
    property Picture: TwwDBPicture read FPicture write FPicture;
    property Anchors;
    property BiDiMode;
    property Constraints;
    property ParentBiDiMode;  { 2/18/99 - Case sensitive name for Builder 4 }
    {$endif}
    property AutoSize;
    property Ctl3D;
    property Font;
    property CharCase;
    property BorderStyle;
  end;

  TwwDBLookupCombo= class(TwwDBCustomLookupCombo)
  strict private
    class constructor Create;

  published
    property Controller;
    property BevelEdges;
    property BevelInner;
    property BevelKind default bkNone;
    property BevelOuter;
    property DisableThemes;
    property ControlInfoInDataset;
    property ControlType;
    property DropDownAlignment;
    property Selected;
    property DataField;
    property DataSource;
    property LookupTable;
    property LookupField;
    property Options;
    property Style;
    property AutoSelect;
    property Color;
    property DragCursor;
    property DragMode;
    property DropDownCount;
    property DropDownWidth;
    property Enabled;
    property ButtonStyle default cbsDownArrow;
    property ButtonEffects;
    property Navigator;

    property Frame;
    property ButtonWidth;
    property ButtonGlyph;
    {$ifdef wwDelphi3Up}
    property ImeMode;
    property ImeName;
    {$endif}
    property ImageList;
    property MaxLength;
    property ParentColor;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Visible;
    property AutoDropDown;
    property ShowButton;
    property SeqSearchOptions;
    property OrderByDisplay;
    property SearchDelay;
    property UseTFields;
//    property LookupSearchType;
//    property UnboundAlignment;
//    property Transparent;

    property PreciseEditRegion;
    property AllowClearKey;
    property ShowMatchText;
    {$ifdef wwDELPHI2010Up}
    property Touch;
    {$endif}

    property OnChange;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnBeforeDropDown;
    property OnDropDown;
    property OnCloseUp;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnNotInList;
    property OnPerformCustomSearch;
    {$ifdef wwDELPHI2010Up}
    property OnGesture;
    {$endif}

    {$ifdef wwDELPHI2013Up}
    property Align;
    property StyleElements;
    property OEMConvert;
    property NumbersOnly;
    property DoubleBuffered;
    property ParentDoubleBuffered;
    {$endif}
  end;


  TwwDBLookupList = class(TwwCustomDBGrid)
  private
    FCombo: TwwDBCustomLookupCombo;
{    FSelected : TStrings;}

    FFieldLink: TFieldDataLink;
    FNavigatorLink: TFieldDataLink;
    FLookupField: String;
    FDisplayFld: TField;
    FValueFld: TField;  { Lookup Field - Should be unique }
    FValueFld2: TField; { If have 2 lookup fields }
    FValueFld3: TField; { If have 3 lookup fields }
    FValue: String;
    FValue2: String;
    FValue3: String;
    FDisplayValue: String;
    FHiliteRow: Integer;
    FOptions: TwwDBLookupListOptions;
    FTitleOffset: Integer;
    FFoundValue: Boolean;
    FInCellSelect: Boolean;
    FOnListClick: TNotifyEvent;
    BeAccurate: boolean;
    inDataChanged: integer;
    DummyString: string;  { Used so string is on heap instead of stack }

    function getSelectedFields: TStrings;
    procedure setSelectedFields(sel : TStrings);

    function GetDataField: string;
    function GetDataSource: TDataSource;
    function GetLookupSource: TDataSource;
    function GetLookupField: string;
    Function GetLookupTable: TDataSet;
    function GetValue: string;
    function GetValue2: string;
    function GetValue3: string;
    function GetDisplayValue: string;
    function GetReadOnly: Boolean;
    procedure FieldLinkActive(Sender: TObject);
    procedure DataChange(Sender: TObject);
    procedure NavigatorDataChange(Sender: TObject);
    procedure EditingChange(Sender: TObject);
    procedure SetDataField(const Value: string);
    procedure SetDataSource(Value: TDataSource);
    procedure SetLookupSource(Value: TDataSource);
    procedure SetLookupTable(value : TDataSet);
    procedure SetLookupField(const Value: string);
    procedure SetValue(const Value: string);
    procedure SetDisplayValue(const Value: string);
    procedure SetReadOnly(Value: Boolean);
    procedure SetOptions(Value: TwwDBLookupListOptions);
    procedure NewLayout;
    procedure FastLookup;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
    procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
    procedure CMExit(var Message: TCMExit); message CM_EXIT;
  protected
    procedure UpdateData(Sender: TObject); reintroduce;
//    Function LTable: TDataSet;
    Function isWWCalculatedField: boolean;
    function HighlightCell(DataCol, DataRow: Integer; const Value: string;
      AState: TGridDrawState): Boolean; override;
    function CanGridAcceptKey(Key: Word; Shift: TShiftState): Boolean; override;
    procedure DefineFieldMap; 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;

    function CanEdit: Boolean; virtual;
    procedure InitFields(showError: boolean);
    procedure CreateWnd; override;
    procedure KeyPress(var Key: Char); override;
    procedure LinkActive(Value: Boolean); override;
    procedure Scroll(Distance: Integer); override;
    procedure ListClick; dynamic;
    procedure Loaded; override;
    procedure Notification(AComponent: TComponent;
      Operation: TOperation); override;
    procedure Paint; override;
    procedure DataChanged; override;

    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
    procedure DrawCell(ACol, ARow: Longint; ARect: TRect;  AState: TGridDrawState); override;

  public
    lookupFieldCount: integer;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    property Value: string read GetValue write SetValue;
    property DisplayValue: string read GetDisplayValue write SetDisplayValue;
    property DisplayFld: TField read FDisplayFld;
    property VisibleRowCount;

    procedure SetColumnAttributes; override;
    procedure DoLookup(SetToDisplayIndex: boolean);

  published
    {$ifdef wwDelphi4Up}
    property Anchors;
    property Constraints;
    {$endif}
    property Selected : TStrings read getSelectedFields write setSelectedFields;
    property LookupTable : TDataSet read GetLookupTable write setLookupTable;

    property DataField: string read GetDataField write SetDataField;
    property DataSource: TDataSource read GetDataSource write SetDataSource;
    property LookupField: string read GetLookupField write SetLookupField;
    property Options: TwwDBLookupListOptions read FOptions write SetOptions default [];
    property OnClick: TNotifyEvent read FOnListClick write FOnListClick;
    property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
    property Align;
    property BorderStyle;
    property Color;
    property Ctl3D;
    property DragCursor;
    property DragMode;
    property Enabled;
    property Font;
    property ParentColor;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Visible;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
  end;


  TwwPopupGrid = class(TwwDBLookupList)
  private
    class constructor Create;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure CreateWnd; override;
    procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    function CanEdit: Boolean; override;
    procedure LinkActive(Value: Boolean); override;

  public
    firstPaint: boolean;
    property RowCount;
    property ColCount;
    constructor Create(AOwner: TComponent); override;
  published
    property ControlType; { 1/10/2000 }
  end;


  TwwLookupComboButton = class(TwwComboButton)
  protected
    function IsVistaTransparentButton: boolean; override;
    function IsVistaComboNonEditable: boolean; override;
    function ParentMouseInControl: boolean; override;
    function ParentDroppedDown: boolean; override;

    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure Paint; override;
  end;

  TwwLookupComboStyleHook = class(TEditStyleHook)
  strict private
    procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND;
  private
    Control: TWinControl;
  protected
    procedure PaintNC(Canvas: TCanvas); override;
  public
    constructor Create(AControl: TWinControl); override;
  end;

procedure Register;

implementation

uses DBConsts,

{$ifdef wwDelphi6Up}
variants,
{$endif}
{$ifdef wwDelphi7Up}
themes,
{$endif}
wwdbgrid;

{$R WWDBD32.RES}

type
  TCheatGridCast = class(TCustomGrid);
  TwwCheatGridCast = class(TwwDBGrid);

{$ifdef wwDelphi3Up}
procedure RaiseException(error: string);
{$else}
procedure RaiseException(error: word);
{$endif}
begin
  {$ifdef wwDelphi3Up}
   raise EInvalidOperation.Create (error);
  {$else}
   raise EInvalidOperation.Create (LoadStr (error));
  {$endif}
end;

constructor TwwDropDownGridOptions.Create(AOwner: TComponent);
begin
   FColor:= clWindow;
   FTitleLines:= 1;
   FTitleAlignment:= taLeftJustify;
end;

{ TwwDBCustomLookupCombo}

{ The following hook proc is a workaround for a delphi 4 bug
  where it no longer sends a CM_CANCELMODE message when the end-user
  clicks away from the dropped down list }
{$ifdef wwDelphi4up}
var wwLookupComboHook: HHOOK;

function wwLookupComboHookProc(nCode: Integer; wParam: Integer; lParam: Integer): LResult; stdcall;
var r1, r2: TRect;
begin
  result := CallNextHookEx(wwLookupComboHook, nCode, wParam, lParam);
  with PMouseHookStruct(lParam)^ do
  begin
    if (wParam = WM_LBUTTONDOWN) or (wParam = WM_NCLBUTTONDOWN) then
    begin
      if (Screen.ActiveControl <> nil) and (Screen.ActiveControl is TwwDBCustomLookupCombo) then
        with (Screen.ActiveControl as TwwDBCustomLookupCombo) do
      begin
        { Auto-closeup if clicked outside of drop-down area }
        if FGrid.visible then begin
           GetWindowRect(FGrid.Handle, r1);
           GetWindowRect(Handle, r2);
           if (not PtInRect(r1, pt)) and (not PtInRect(r2, pt)) then
             { 11/15/98 - Calling closeup immediately would cause problems
              if user's OnCloseUp aborted }
             PostMessage(Handle, CM_CANCELMODE, 0, 0);
//           CloseUp(True);
        end
      end;
    end;
  end;
end;
{$endif}

type
  TwwComboButtonEffects = class(TwwButtonEffects)
     protected
        procedure Refresh; override;
  end;

 TBtnWinControl = class(TWinControl)
 private
    EditControl: TwwDBCustomLookupCombo;
    procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBkgnd;
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  public
    constructor Create(AOwner: TComponent); override;
 end;

Procedure TwwComboButtonEffects.refresh;
begin
   (Control as TwwDBCustomLookupCombo).Updatebuttonglyph;
//   (Button as TSpeedButton).Glyph.Handle:=
//     TwwDBCustomLookupCombo(Control).LoadComboGlyph;
end;

procedure TBtnWinControl.WMEraseBkgnd(var Message: TWmEraseBkgnd);
var r: TRect;
    cc: TwwDBCustomLookupCombo;
begin

  // Remove parent clipping and don't paint background if styles enabled
  if wwIsCustomStyle(parent) or EditControl.IsVistaComboNonEditable then
  begin
     message.result:=1;
     exit;
  end;

  cc:= TwwDBCustomLookupCombo(parent);
  if cc.skipupdate then exit;

  if (IsInGridPaint(parent) or
     cc.isTransparentEffective)  then
  begin
     { Fixes paint problem when mouse is clicked in button and moved outside
       region, but it is not released }
     if (not IsInGridPaint(parent)) and
        (cc.ButtonEffects.Flat or cc.ButtonEffects.Transparent) and
        (csLButtonDown in cc.FButton.ControlState) then
     begin
        r:= Rect(parent.left + Left , parent.Top+top,
                 parent.left + left + Width, parent.top + Top + Height);
        InvalidateRect(parent.parent.handle, @r, False);
        cc.skipupdate:= true;
        parent.parent.update;
        cc.skipupdate:= False;
     end;
     message.result:= 1;
  end
  else inherited;
end;

constructor TBtnWinControl.Create(AOwner: TComponent);
begin
   inherited Create(AOwner);
   EditControl:= AOwner as TwwDBCustomLookupCombo;
end;

procedure TBtnWinControl.CMMouseEnter(var Message: TMessage);
begin
  inherited;
{  if EditControl.FButton.Flat then
  begin
     EditControl.UpdateButtonPosition;
     Invalidate;
  end}
end;

procedure TBtnWinControl.CMMouseLeave(var Message: TMessage);
var r: TRect;
    offset: integer;
begin
  inherited;

  if not EditControl.ButtonEffects.Flat then exit;

  if EditControl.BorderStyle=bsSingle then offset:=2 else offset:= 0;
  if not EditControl.FFocused then begin
     if EditControl.IsTransparentEffective then begin
        r:= Rect(parent.left + Left + offset, parent.Top+top+offset,
                 parent.left + left + offset + Width, parent.top + offset + Top + Height);
        if wwIsTransparentParent(self) then
          wwInvalidateTransparentArea(self, false) // just to be safer, but probably works in both cases
        else
          InvalidateRect(parent.parent.handle, @r, True);
        Invalidate;
     end;
     Invalidate;
  end
end;


constructor TwwLookupComboStyleHook.Create(AControl: TWinControl);
begin
  inherited;
  Control:= AControl;
//  OverridePaintNC := true;
//  OverrideEraseBkgnd := true;
end;

procedure TwwLookupComboStyleHook.PaintNC(Canvas: TCanvas);
begin
  if not (Control as TwwDBCustomLookupCombo).Frame.Enabled then
     if wwGetBorder(control) then
       inherited PaintNC(Canvas)
end;

procedure TwwLookupComboStyleHook.WMEraseBkgnd(var Message: TMessage);
begin
  // paint with style if have focus or if framing is not enabled - otherwise just use class behavior
  if Control.Focused or (not (Control as TwwDBCustomLookupCombo).Frame.Enabled) then
     inherited
end;

class constructor TwwDBCustomLookupCombo.Create;
begin
  TCustomStyleEngine.RegisterStyleHook(TwwDBCustomLookupCombo, TwwLookupComboStyleHook);
end;

class constructor TwwDBLookupCombo.Create;
begin
  TCustomStyleEngine.RegisterStyleHook(TwwDBLookupCombo, TwwLookupComboStyleHook);
end;

constructor TwwDBCustomLookupCombo.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FDropDownGridOptions := TwwDropDownGridOptions.Create(Self);
  FPicture:= TwwDBPicture.create(nil);

  FButtonStyle:= cbsDownArrow;
  FLastSearchKey:= '';
{  AutoSize := False; } { Removed 5/2/97 }

  ControlStyle := ControlStyle + [csReplicatable];
  ExtraHeight:= 0;
//  ControlStyle:= ControlStyle + [csOverrideStylePaint]; // Necessary so borders are not drawn by style - messes up framed controls without borderws

  FFieldLink := TFieldDataLink.Create;
  FFieldLink.Control := Self; {Release adds this }
  FFieldLink.OnDataChange := DataChange;
  FFieldLink.OnEditingChange := EditingChange;
  FFieldLink.OnUpdateData := UpdateData;
  FFieldLink.OnActiveChange := FieldLinkActive;

  FBtnControl := TBtnWinControl.Create (Self);
  FBtnControl.ControlStyle := FBtnControl.ControlStyle + [csReplicatable];
  FBtnControl.Width:= wwmax(GetSystemMetrics(SM_CXVSCROLL)+4, 17); {4/14/97}
  FBtnControl.Height := 17;
  FBtnControl.Visible := True;;
  FBtnControl.Parent := Self;

  FButton := TwwLookupComboButton.Create (Self);
  FButton.ControlStyle := FButton.ControlStyle + [csReplicatable];
  FButton.SetBounds (0, 0, FBtnControl.Width, FBtnControl.Height);
  FButton.Width:= wwmax(GetSystemMetrics(SM_CXVSCROLL), 15); {5/2/97 }
  FButton.Visible := True;
  FButton.Parent := FBtnControl;

  FGrid := TwwPopupGrid.Create(Self);
  FGrid.height:= 0; { 10/16/98 -Faster performance }
  FGrid.FCombo := Self;
  FGrid.Parent := Self;
  FGrid.Visible := False;
  FGrid.OnClick := GridClick;
  FGrid.Ctl3D:= self.Ctl3D;
  FGrid.PadColumnStyle:= pcsPlain;
  FGrid.Options:= [];

  Height := 25;
  FDropDownCount := 8;

  FTimer:= TTimer.create(self);
  FTimer.enabled:= False;
  FSearchDelay:= 0;
  FTimer.Interval:= 200;
  FTimer.OnTimer:= OnEditTimerEvent;

  wwDBCalcFieldType:=cftUnknown;
  ChangingFromLink:= False;
  InAutoDropDown:= False;
  AutoDropDown:= False;
  InList:= True;

  SeqSearchOptions:= [ssoEnabled];
  FOrderByDisplay:= True;
  FUseTFields:= True;

  FControlInfoInDataset:= True;
//  Transparent:= False;
  FFrame:= TwwEditFrame.create(self);

//  FButtonGlyph := TBitmap.Create;
//  FButtonGlyph.OnChange := GlyphChanged;

  FButtonEffects:= TwwComboButtonEffects.create(self, FButton);
//  FButton.Glyph.Handle := LoadComboGlyph;

//  FLookupSearchType:= lstDefault;

  Patch := VarArrayCreate([0, 1], varVariant);
  Patch[0] := False; // True when last character typed in was a backspace
  Patch[1] := False; // Internal use, set to true when processing backspace search (only when Patch[0]] is true)

end;

destructor TwwDBCustomLookupCombo.Destroy;
begin
  FPicture.Free;
  FDropDownGridOptions.Free;

  FFrame.Free;
  FButtonEffects.Free;
  FTimer.Free;
  FFieldLink.OnDataChange := nil;
  FFieldLink.Free;
  FFieldLink := nil;

  FButton.Free;
  FButton:= Nil;
  FCanvas.Free;
  FCanvas:= Nil;
  FGrid.Free;
  FGrid:= Nil;

  {$ifdef wwDelphi4up}
  if wwLookupComboHook<>0 then begin
     UnhookWindowsHookEx(wwLookupComboHook);
     wwLookupComboHook:= 0;
  end;
  {$endif}

//  FButtonGlyph.Free;
  inherited Destroy;
end;

Procedure TwwDBCustomLookupCombo.UpdatebuttonGlyph;
begin
//   FButton.Glyph.Handle:=0;  7/28/01 - Don't clear glyph
   if (FButtonStyle<>cbsCustom) and
      (ButtonEffects.Flat or ButtonEffects.Transparent) then
   begin
      if (FButtonStyle = cbsDownArrow) then
         FButton.Glyph.Handle:= LoadBitmap(HInstance, 'WWDROPDOWN')
   end;
end;

{Function TwwDBCustomLookupCombo.LoadComboGlyph: HBitmap;
begin
   result:= 0;
   if ButtonEffects.Flat or ButtonEffects.Transparent then
      result:= LoadBitmap(HInstance, 'WWDROPDOWN')
//   result:= LoadBitmap(0, PChar(32738));
end;
}
function TwwDBCustomLookupCombo.GetButtonGlyph: TBitmap;
begin
  result:= FButton.Glyph;
end;

procedure TwwDBCustomLookupCombo.SetButtonStyle(val: TwwComboButtonStyle);
begin
   if val<>FButtonStyle then begin
      FButtonStyle:= val;
      UpdateButtonGlyph;
//      FButton.Glyph.Handle:= LoadComboGlyph;
      FButton.Invalidate;
   end
end;

function TwwDBCustomLookupCombo.IsCustom: Boolean;
begin
  Result := ButtonStyle = cbsCustom;
end;

procedure TwwDBCustomLookupCombo.SetButtonGlyph(Value: TBitmap);
begin
  FButton.Glyph.Assign(Value);
  Invalidate;
end;
{
procedure TwwDBCustomLookupCombo.GlyphChanged(Sender: TObject);
begin
   FButton.Glyph.Handle:= LoadComboGlyph;
   Invalidate;
end;
}
Procedure TwwDBCustomLookupCombo.SetButtonWidth(val: integer);
begin
   if FButtonWidth<>val then
   begin
      FButtonWidth:= val;
      if val<>0 then FButton.Width:= val
      else FButton.Width:= wwmax(GetSystemMetrics(SM_CXVSCROLL), 15);
      UpdateButtonPosition;
   end
end;

function TwwDBCustomLookupCombo.GetButtonWidth: integer;
begin
   result:= FButtonWidth;
end;


function TwwDBCustomLookupCombo.GetShowButton: boolean;
begin
   result:= FBtnControl.visible;
end;

procedure TwwDBCustomLookupCombo.SetShowButton(sel: boolean);
begin
   if (FBtnControl.visible<> sel) then
   begin
      FBtnControl.visible:= sel;
      SetEditRect;
      self.invalidate;
   end
end;

Function TwwDBCustomLookupCombo.LTable: TDataSet;
begin
   if wwIsClass(LookupTable.classType, 'TwwTable') then
     result:= LookupTable
   else
     result:=nil;
end;

Function TwwDBCustomLookupCombo.UseExprIndex: boolean; // Only for TwwTable
var IndexDefs: TIndexDefs;
begin
   if wwGetIndexDefs(LookupTable, IndexDefs) and (lTable<>nil) then
     result:=
        (wwGetVariable(LookupTable, 'isDBaseTable')=True) and
        (SearchField<>'') and (IndexDefs.indexof(wwGetVariable(LookupTable, 'IndexName'))>=0) and
        (ixExpression in IndexDefs.Items[IndexDefs.indexof(wwGetVariable(LookupTable, 'IndexName'))].Options)
   else result:=false;
end;

Function TwwDBCustomLookupCombo.UseSeqSearch: boolean;
var IndexDefs: TIndexDefs;
begin
   if wwGetIndexDefs(LookupTable, IndexDefs) then
   begin
      result:= (not wwIsClass(LookupTable, 'TwwTable')) or
              (IndexDefs.count=0) or
               (wwGetVariable(LookupTable, 'IndexFieldCount')=0) or
                Assigned(FOnPerformCustomSearch); // 7/12/01

     { Still perform index search if xBASE expression index }
     if result and wwIsClass(LookupTable, 'TwwTable') then
     begin
         result:= not UseExprIndex
     end
   end
   else result:= True
end;

Function TwwDBCustomLookupCombo.wwFindNearest(key: string; FieldNo: integer): boolean;
var TempFieldValues: variant;
begin
   TempFieldValues:= VarArrayCreate([0, 1], varVariant);
   TempFieldValues[0]:= key;
   TempFieldValues[1]:= fieldNo;
   result := wwGetVariableWithParams(LookupTable, 'wwFindNearest', TempFieldValues)
end;

function TwwDBCustomLookupCombo.wwFindRecord(
   KeyValue: string;
   LookupField: string;
   MatchType: TwwLocateMatchType;
   caseSensitive: boolean): boolean;
   {
type
   TFindRecordFunction =
     function (
        KeyValue: string;
        LookupField: string;
        MatchType: TwwLocateMatchType;
        CaseSensitive: boolean): boolean of object;
var
    MethodFindRecord: TMethod;
    }
begin
   result:= wwTableFindRecord(LookupTable, KeyValue, LookupField, MatchType, caseSensitive);
//   TMethod(MethodFindRecord).Data := LookupTable; // object reference
//   TMethod(MethodFindRecord).Code := LookupTable.MethodAddress('wwFindRecord');
//   result:= TFindRecordFunction(MethodFindRecord)(KeyValue, LookupField, MatchType, caseSensitive)
end;

function TwwDBCustomLookupCombo.FindRecord(
       KeyValue: string;
       LookupField: string;
       MatchType: TwwLocateMatchType;
       CaseSensitive: boolean;
       PerformLookup: boolean = False): boolean;
type
   //TBoolFunction =function: boolean of object;
   TIsValidIndexFieldFunction = function(FieldName: string; caseSensitive: boolean): boolean of object;
   {
   TFindRecordFunction =
     function (
        KeyValue: string;
        LookupField: string;
        MatchType: TwwLocateMatchType;
        CaseSensitive: boolean): boolean of object;
    }
var curField: TField;
    SaveCursor: TCursor;
    //MethodIsLiveQuery: TMethod; //TBoolFunction;
    MethodIsValidIndexField: TMethod;
//    MethodFindRecord: TMethod;
begin
   if InCustomSearch then exit;
//   TMethod(MethodIsLiveQuery).Data := LookupTable; // object reference
//   TMethod(MethodIsLiveQuery).Code := LookupTable.MethodAddress('IsLiveQuery');
   TMethod(MethodIsValidIndexField).Data := LookupTable; // object reference
   TMethod(MethodIsValidIndexField).Code := LookupTable.MethodAddress('IsValidIndexField'); // 6/7/09 - Wrong method
//   TMethod(MethodFindRecord).Data := LookupTable; // object reference
//   TMethod(MethodFindRecord).Code := LookupTable.MethodAddress('wwFindRecord');

   // If event assigned then don't treat as TwwTable
   if wwIsClass(LookupTable, 'TwwTable') and not Assigned(FOnPerformCustomSearch) then
   begin
      result:= wwFindRecord(KeyValue, LookupField, MatchType, caseSensitive);
//      result:= TFindRecordFunction(MethodFindRecord)(KeyValue, LookupField, MatchType, caseSensitive)
//      result:= (LookupTable as TwwTable).wwFindRecord(KeyValue, LookupField, MatchType, CaseSensitive)
   end
   else begin
      { 5/12/99 - Avoid exception by checking if semi-colon exists in lookup field }
      curField:= LookupTable.FindField(LookupField);
      if (pos(';', LookupField)=0) and (curField<>nil) and (curField.asString=KeyValue) then begin
         result:= True;
         FGrid.invalidate;  { In case nothing was highlighted before }
      end
      else begin
         {7/24/97 - Limit length to be up to field size }
         if (curField is TStringField) and (curField.size>0) and (curField.size<length(Text)) then
            KeyValue:= copy(KeyValue, 1, curField.size);

         { If invalid value type or blank (blank lookup is slow) then skip search }
         if Assigned(FOnPerformCustomSearch) then begin
              if (KeyValue='') then // 1/6/07 - Event not firing before
              begin
                result:= False;
                FGrid.invalidate;
                exit;
             end;

             SkipDataChange:= True;
             InCustomSearch:= True;
             try
               PerformCustomSearch(LookupField, KeyValue, PerformLookup, Result);
             finally
               InCustomSearch:= False;
               SkipDataChange:= False;
             end;
         end
         else if
            (not wwFieldIsValidLocateValue(curField, KeyValue)) or
            (KeyValue='') then
         begin
            result:= False;
            FGrid.invalidate;
         end
         else if (not wwInternational.UseLocateMethodForSearch) then
             result:= wwDataSetFindRecord(LookupTable, KeyValue, LookupField, MatchType, caseSensitive)
         { 10/29/97 - Search on calculated or lookup fields }
         else if (curfield.calculated or curfield.lookup) then
             result:= wwDataSetFindRecord(LookupTable, KeyValue, LookupField, MatchType, False)
         else if not wwIsClass(LookupTable.classtype, 'TwwQuery') then
         begin                                                      { 9/20/97 - Replace wwDataSetFindRecord call with Locate to allow 3rd party engines
                        opportunity to take advantage of the index.  The end-user should set
                        SeqSearchOptions to the case sensitivity of the index so that the
                        index can be used }
            {$ifdef wwDelphi3Up}
            SaveCursor:= screen.cursor;
            Screen.cursor:= crHourGlass;
            if caseSensitive then begin
               if (MatchType=mtExactMatch) then result:= LookupTable.Locate(LookupField, KeyValue, [])
               else result:= LookupTable.Locate(LookupField, KeyValue, [loPartialKey]);
            end
            else begin
               if (MatchType=mtExactMatch) then result:= LookupTable.Locate(LookupField, KeyValue, [loCaseInsensitive])
               else result:= LookupTable.Locate(LookupField, KeyValue, [loPartialKey, loCaseInsensitive]);
            end;
            Screen.cursor:= SaveCursor;
            {$else}
            result:= wwDataSetFindRecord(LookupTable, KeyValue, LookupField, MatchType, caseSensitive)
            {$endif}
         end
         else if wwIsClass(LookupTable, 'TwwQuery') and wwGetVariable(LookupTable, 'IsLiveQuery') then
         //(MethodIsLiveQuery.code<>nil) and TBoolFunction(MethodIsLiveQuery) then
         //(LookupTable is TwwQuery) and TwwQuery(LookupTable).RequestLive and
         //          TwwQuery(LookupTable).CanModify then
         begin
             SaveCursor:= screen.cursor;
             Screen.cursor:= crHourGlass;
             { Require seq search on live parameterized query as Delphi Locate does not support this}
             if (wwGetDataSource(LookupTable)<>Nil) then
                result:= wwDataSetFindRecord(LookupTable, KeyValue, LookupField, MatchType, caseSensitive)
             else if (MatchType=mtExactMatch) then begin
                try
                  if TIsValidIndexFieldFunction(MethodIsValidIndexField)(LookupField, false) then
//                  if TwwQuery(LookupTable).isValidIndexField(LookupField, False) then
                     result:= LookupTable.Locate(LookupField, KeyValue, [loCaseInsensitive])
                  else if TIsValidIndexFieldFunction(MethodIsValidIndexField)(LookupField, True) then
//                  else if TwwQuery(LookupTable).isValidIndexField(LookupField, True) then
                     result:= LookupTable.Locate(LookupField, KeyValue, [])
                  else
                     result:= wwDataSetFindRecord(LookupTable, KeyValue,
                                                  LookupField, MatchType, caseSensitive);
                  Screen.cursor:= SaveCursor;
                except
                  result:= wwDataSetFindRecord(LookupTable, KeyValue, LookupField, MatchType, caseSensitive)
                end
             end
             else begin
                try
                  if TIsValidIndexFieldFunction(MethodIsValidIndexField)(LookupField, False) then
                  //if TwwQuery(LookupTable).isValidIndexField(LookupField, False) then
                     result:= LookupTable.Locate(LookupField, KeyValue, [loCaseInsensitive, loPartialKey])
                  else if TIsValidIndexFieldFunction(MethodIsValidIndexField)(LookupField, True) then
//                  else if TwwQuery(LookupTable).isValidIndexField(LookupField, True) then
                     result:= LookupTable.Locate(LookupField, KeyValue, [loPartialKey])
                  else
                     result:= wwDataSetFindRecord(LookupTable, KeyValue,
                                                  LookupField, MatchType, caseSensitive);
                  Screen.cursor:= SaveCursor;
                except
                  result:= wwDataSetFindRecord(LookupTable, KeyValue, LookupField, MatchType, caseSensitive)
                end;
             end
         end
         else begin
            SaveCursor:= screen.cursor;
            Screen.cursor:= crHourGlass;
            if (MatchType=mtExactMatch) then result:= LookupTable.Locate(LookupField, KeyValue, [])
            else result:= LookupTable.Locate(LookupField, KeyValue, [loPartialKey, loCaseInsensitive]);
            Screen.cursor:= SaveCursor;
         end
      end
   end;

   // 9/13/00 - Workaround problem where locate ignores trailing spaces
   if (not Assigned(FOnPerformCustomSearch)) and result then // 1/7/06 - Skip code if custom search
   begin
      if (pos(AnsiUpperCase(KeyValue),     //4/16/00 - Use AnsiUppercase instead.
          AnsiUpperCase(LookupTable.FieldByName(LookupField).asstring))<=0) then
         result:= false;
   end
end;

Function TwwDBCustomLookupCombo.IndexFields(index: integer): TField;
begin
   result:= TField(wwGetVariableObject(LookupTable, 'IndexFields', index));
end;

Function TwwDBCustomLookupCombo.wwFindKey(const KeyValues: array of Const): Boolean;
begin
   result:= wwGetVariableWithParams2(LookupTable, 'wwFindKey', KeyValues, [])
end;


procedure TwwDBCustomLookupCombo.OnEditTimerEvent(Sender: TObject);
var SearchIndex: integer;
    isFound: boolean;
    SearchText: string;
    TempSearchField: string;
    PerformDropDown: boolean;
//    TempFieldValues: variant;
begin

   PerformDropDown:= False;
   FTimer.enabled:= False;

   if (text <> FLastSearchKey) and (LookupTable<>Nil)
      and (LookupTable.active or Assigned(FOnPerformCustomSearch)) then begin
     try
      if FGrid.FNavigatorLink<>nil then
         FGrid.FNavigatorLink.OnDataChange:=nil;

      if (not FGrid.visible) and (not FAutoDropDown) and
         (FShowMatchText) and (Style<>csDropDownList) and { 6/6/98 }
         (Text<>'') {and (not skipSearch) }then
      begin
         UpdateSearchIndex(True);
//         InAutoDropDown:= True;
      end
       else if (not FGrid.visible) and FAutoDropDown and (Text<>'') then
      begin
         UpdateSearchIndex(True);
//         InAutoDropDown:= True;
         PerformDropDown:= True;
      end;

      if UseSeqSearch then begin
         if ((ssoEnabled in SeqSearchOptions) or Assigned(FOnPerformCustomSearch)) // 2/25/03
             and (FGrid.DisplayFld<>nil) and (FGrid.DisplayFld.FieldName<>'') then // 3/06/03 - Check for blank field name
         begin
            if FGrid.visible or InAutoDropDown or (CanEdit and ShowMatchText) then  { 8/17/96 - Execute code if inAutoDropDown }
            begin
               inList:= FindRecord(Value, FGrid.DisplayFld.FieldName,
                    mtPartialMatchStart, ssoCaseSensitive in SeqSearchOptions);

               if (not inList) and (FGrid.FDisplayFld=FGrid.FValueFld) then
               begin
{                  FGrid.FDisplayValue:= OldDisplayValue;
                  FGrid.FValue:= OldLookupValue;}
                  FGrid.FValue:= '';

                  // 5/17/03 - Call DropDown since AutoDropDown case
                  if PerformDropDown and InAutoDropDown then //InDropDownEvent then
                     try DropDown finally InAutoDropDown:= False end;
                  exit;
               end
            end
            else
               inList:= FindRecord(Value, FGrid.DisplayFld.FieldName,
                    mtExactMatch, ssoCaseSensitive in SeqSearchOptions);
            TypedInText:= Text;
            FGrid.FDisplayValue:= FGrid.FDisplayFld.asString;
            { 7/25/99 - If entered text is not subset of current lookup record,
              then set inlist to false.  This could happen if a trailing space
              was in the entered text }
            if inList and (length(FGrid.FDisplayValue)<length(Text)) then
            begin
              inList:= false;
            end;
            if (Patch[1]=true) and inList and (length(FGrid.FDisplayValue)>length(Text)) then
            begin
              inList:= false;
            end;
            isFound:= inList;
         end
         else begin
            // 5/17/03 - Call DropDown since AutoDropDown case
            if PerformDropDown and InAutoDropDown then //InDropDownEvent then
               try DropDown finally InAutoDropDown:= False end;
            exit;
         end
      end
      else with (LookupTable) do begin
         UpdateSearchIndex(True); // 2/14/03

         { Incrementally search on SearchField }
         { if dBASE then use expression index }
         if UseExprIndex then
         begin
            if not wwFieldIsValidValue(FieldbyName(SearchField), text) then exit;
            wwSetVariable(LookupTable, 'EditKey', null); //            EditKey;
            FieldByName(SearchField).asString:= text;
            wwSetVariable(LookupTable, 'GoToNearest', null); //            GoToNearest
            FGrid.FDisplayValue:= FieldByName(SearchField).asString;

            // 2/12/06 - Use AnsiUpperCase
            // isFound:= pos(Uppercase(Text), Uppercase(FieldByName(SearchField).asString))=1;
            isFound := AnsiPos(AnsiUppercase(Text), AnsiUppercase(FieldByName(SearchField).asString))=1;

            inList:= isFound; { 3/1/98 - For NotInList event }
         end
         else begin
            SearchIndex:= GetSearchIndex;

            { 8/27/99 - Don't search if index doesn't match search field }
            if (SearchIndex=0) and (FGrid.DisplayFld<>IndexFields(0)) then
            begin
               TempSearchField:= FGrid.DisplayFld.FieldName;
               if (ssoEnabled in SeqSearchOptions) then
               begin
                  if FGrid.visible or InAutoDropDown then
                     inList:= DoFindRecord(Text, TempSearchField, mtPartialMatchStart)
                  else
                     inList:= DoFindRecord(Text, TempSearchField, mtExactMatch)
               end;
//               exit; { 3/9/00 - Don't exit but do else if instead }
            end
            else if (SearchIndex>=0) and
               not ((SearchIndex=0) and (FGrid.DisplayFld<>IndexFields(0))) then
            begin
               if FGrid.visible or InAutoDropDown then begin
                  InList := wwFindNearest(text, SearchIndex)
               end
               else begin
                  case searchindex of { Use searchindex for lookup }
{                     1: begin
                          TempFieldValues:= VarArrayCreate([0, 1], varVariant);
                          TempFieldValues[0]:= IndexFields(0).AsString;
                          TempFieldValues[1]:= Text;
                          inList:= wwGetVariableWithParams(LookupTable, 'wwFindKey',  TempFieldValues);
                        end;}
                     1: inList:= wwFindKey([indexFields(0).asString, Text]);
{
                     2: begin
                          TempFieldValues:= VarArrayCreate([0, 2], varVariant);
                          TempFieldValues[0]:= IndexFields(0).AsString;
                          TempFieldValues[1]:= IndexFields(1).AsString;
                          TempFieldValues[2]:= Text;
                          inList:= wwGetVariableWithParams(LookupTable, 'wwFindKey', TempFieldValues);
                        end;
                        }
                     2: inList:= wwFindKey([indexFields(0).asString, indexFields(1).asString, Text]);
                     else begin
                     {
                          TempFieldValues:= VarArrayCreate([0, 0], varVariant);
                          TempFieldValues[0]:= Text;
                          inList:= wwGetVariableWithParams(LookupTable, 'wwFindKey', TempFieldValues);
                          }
                       InList:= wwFindKey([Text]);
                     end
                  end;
               end;
               TypedInText:= Text;
               FGrid.FDisplayValue:= IndexFields(SearchIndex).AsString;
//               FGrid.FDisplayValue:= IndexFields[SearchIndex].text;
            end
            else begin    {1/22/97}
                if FGrid.visible or InAutoDropDown then
                   inList:= DoFindRecord(Text, SearchField, mtPartialMatchStart)
                else
                   inList:= DoFindRecord(Text, SearchField, mtExactMatch)
            end;

            isFound:= inList;
         end
      end;

         FGrid.FValue:= FGrid.FValueFld.asString;
         if FGrid.FValueFld2<>Nil then
            FGrid.FValue2:= FGrid.FValueFld2.asString;
         if FGrid.FValueFld3<>Nil then
            FGrid.FValue3:= FGrid.FValueFld3.asString;

         if (not FGrid.visible) then FGrid.FHiliteRow:= -1;  { Reset to -1 for UpdateData method - 4/3/97 }

         if FShowMatchText and isFound and
            (FLastSearchKey<>'~~~~') then { vk_delete when dropped down so skip }
         begin
            if selStart>0 then SearchText:= copy(Text, 1, selStart)
            else SearchText:= Text;
            Text:= FGrid.DisplayFld.asString;
            modified:= True;
            selStart:= length(SearchText);
            selLength:= length(Text)-length(SearchText);
            if (not FGrid.visible) then FGrid.FHiliteRow:= 0; { 4/3/97}
         end;

         FLastSearchKey:= text;

         if PerformDropDown and InAutoDropDown then //InDropDownEvent then
            try DropDown finally InAutoDropDown:= False end;

{      end}
     finally
      if FGrid.FNavigatorLink<>nil then
         FGrid.FNavigatorLink.OnDataChange:=FGrid.NavigatorDataChange;
     end
   end;


end;

procedure TwwDBCustomLookupCombo.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (FFieldLink <> nil) then
  begin
    if (AComponent = DataSource) then
      DataSource := nil
    else if (FImageList=AComponent) then
       FImageList:= nil
  end;

  if (Operation = opRemove) then begin
     {$ifndef GRIDESSENTIALS}
     if (AComponent = FController) then FController:= nil;
     {$endif}
  end;
  
end;

function TwwDBCustomLookupCombo.Editable: Boolean;
begin
  if Fgrid.visible then begin
     Result:= True
  end
  else begin
     Result := (FStyle <> csDropDownList) or AutoDropDown;
  end
end;

function TwwDBCustomLookupCombo.MouseEditable: Boolean;
begin
  if Fgrid.visible then begin
     Result:= True
  end
  else begin
     Result := (FStyle <> csDropDownList);
  end
end;

Function TwwDBCustomLookupCombo.IsLookup: boolean;
begin
   result:= (FFieldLink.Field<>Nil) and FFieldLink.Field.Lookup;
end;

Function TwwDBCustomLookupCombo.IsWWCalculatedField: boolean;

  Function calcOrLookup: boolean;
  begin
     result:=
       (FFieldLink.dataSource.dataSet.fieldByName(dataField).calculated)
        or isLookup;
  end;

begin
     result:=
       ((FFieldLink.dataSource <>Nil) and (FFieldLink.dataSource.dataSet<>Nil) and
        (dataField<>'') and
        (wwDataSetIsValidField(FFieldLink.dataSource.dataSet, dataField)) and
        calcOrLookup);

     if (result and (wwDBCalcFieldType=cftUnknown)) then begin
        if wwDataSetGetLinks(dataSource.dataSet, dataField)='' then
        begin
           if isLookup then
             wwDBCalcFieldType:= cftCalculated
           else
             wwDBCalcFieldType:= cftNotCalculated
        end
        else wwDBCalcFieldType:= cftCalculated;
     end
end;

function TwwDBCustomLookupCombo.CanEdit: Boolean;
begin
  Result := (FFieldLink.DataSource = nil) or (DataField='') or
    (FFieldLink.Editing and Editable) or
     (isWWCalculatedField and
     ((datasource.state in [dsEdit, dsInsert]) or (dataSource.autoEdit)));

  { Calculated fields don't allow edit if csDropDownList style}
  if (not FGrid.Visible) and
     ((Style=csDropDownList) and not AutoDropDown) then
     Result:= False;

  if ReadOnly then Result:= False; {!!! Added 6/8/96}
end;

{ Over-ride tab if owned by a grid }
procedure TwwDBCustomLookupCombo.CNKeyDown(var Message: TWMKeyDown);
var shiftState: TShiftState;
    stat: integer;

    Function ReturnAsTab: boolean;
    var ParentGrid: TwwCustomDBGrid;
    begin
       if parent is TwwCustomDBGrid then
       begin
          parentGrid:= TwwCustomDBGrid(parent);
          result:= (dgEnterToTab in ParentGrid.KeyOptions) and
                   (Message.charcode = VK_RETURN);
       end
       else result:= False;
    end;

begin
  if not (csDesigning in ComponentState) then
  begin
    with Message do
    begin
       if (charcode = VK_ESCAPE) and not (parent is TwwCustomDBGrid) then begin
          if FGrid.visible then exit; { 6/4/97}

          { 7/28/97 -  If modified then escape restores previous text }
          if modified then begin
             FGrid.FDisplayValue:= OldDisplayValue; {9/18/97 - Use FGrid.FDisplayValue instead of DisplayValue }
             FGrid.FValue:= OldLookupValue;
             Text:= OldDisplayValue;
             if FFieldLink.Field<>nil then
                modified:= True   { Leave modified as True so RecordView does not close }
             else
                modified:= False;

             { 2/5/98 - Resets FFieldLink.modified flag }
             SkipDataChange:= True;
             FFieldLink.Reset;
             SkipDataChange:= False;

             exit;
          end;
       end;

       { Prevent tab from exiting if processing AutoDropDown character }
       if InAutoDropDown then exit;

       if (charcode = VK_TAB) or ReturnAsTab then
       begin
         if FGrid.visible then begin  { drop-down open, treat tab as CR + Tab }
            UpdateFromCurrentSelection;
            if InList then GridClick(self);  { InfoPower 2.0 addition}
            closeUp(True);
            DoSelectAll;
         end
       end;

       if (charcode = VK_TAB) or (charcode = VK_RETURN) then begin
         if not FGrid.Visible then begin
           if parent is TCustomGrid then begin
             if (charcode <> VK_TAB) or (goTabs in TCheatGridCast(parent).Options) then
             begin
               parent.setFocus;
               if parent.focused and
                 (IsInwwObjectView(self) or (charcode=vk_tab) or ReturnAsTab) then
               begin
                 shiftState:= KeyDataToShiftState(KeyData);
                 TCheatGridCast(parent).KeyDown(charcode, shiftState);
               end;
               exit;
             end
           end
         end
         else exit;
       end;

       { 1/4/2000 es_multiline style does not pass carriage return/line feed to form so
         we pass it ourselves }
       if ((charcode=vk_return) or (charcode=vk_escape)) then
       begin
          if (not modified) or (charcode = vk_return) then
            if (Windows.GetWindowLong(handle, GWL_STYLE) and es_multiline)<>0 then
            begin
              // 8/22/01 - Don't call inherited if parent processed keystroke.
              // Parent could process keystroke in case of popup menu with escape key assigned
              stat:= SendMessage(GetParent(Handle), TMessage(Message).Msg,
                TMessage(Message).wParam, TMessage(Message).lParam);
//              if (stat<>0) and (charcode = vk_escape) then exit;
              if (stat<>0) then
              begin
                 // 7/9/02 - set message.result to 1 if already processed
                 // Fixes problem with form events firing when they should not
                 if (charcode = vk_escape) or
                    (charcode = vk_return) then
                 begin
                    message.result:=1;
                    exit;
                 end
              end;
            end
       end;

    end
  end;
  inherited;
end;


procedure TwwDBCustomLookupCombo.KeyDown(var Key: Word; Shift: TShiftState);
type
  TSelection = record
    StartPos, EndPos: Integer;
  end;

var
  parentGrid: TCustomGrid;
  temp: boolean;

  procedure SendToParent;
  begin
    if ParentGrid.Visible then ParentGrid.setFocus;
    TwwDBGrid(ParentGrid).KeyDown(Key, Shift);
    Key := 0;
  end;

  procedure ParentEvent;
  var
    GridKeyDown: TKeyEvent;
  begin
    { 1/25/99 - Prevent grid's OnKeyDown from firing twice when encounter tab or cr }
    if (Screen.ActiveControl<>self) and ((key=13) or (key=9)) then exit;

    GridKeyDown := TwwDBGrid(ParentGrid).OnKeyDown;
    if Assigned(GridKeyDown) then GridKeyDown(ParentGrid, Key, Shift);
  end;

  function ForwardMovement: Boolean;
  var tempGrid: TwwDBGrid;
  begin
     if ParentGrid is TwwDBGrid then
     begin
       tempGrid:= ParentGrid as TwwDBGrid;
       Result := (dgAlwaysShowEditor in (tempGrid.Options));
     end
     else result:= False;
  end;

  function Ctrl: Boolean;
  begin
    Result := ssCtrl in Shift;
  end;

  function Alt: Boolean;
  begin
    Result := ssAlt in Shift;
  end;

  function Selection: TSelection;
  begin
    SendMessage(Handle, EM_GETSEL, Longint(@Result.StartPos), Longint(@Result.EndPos));
  end;

  function RightSide: Boolean;
  begin
    with Selection do
      Result := ((StartPos = 0) or (EndPos = StartPos)) and
        (EndPos = GetTextLen);
   end;

  function LeftSide: Boolean;
  begin
    with Selection do
      Result := (StartPos = 0) and ((EndPos = 0) or (EndPos = GetTextLen));
  end;

  procedure Deselect;
  begin
    SendMessage(Handle, EM_SETSEL, -1, 0);
  end;

begin
  if GetKeyState(VK_MENU) < 0 then Include(Shift, ssAlt);

  if (not FGrid.visible) and (parent is TCustomGrid) then
  begin
     parentGrid:=  (parent as TCustomGrid);

     case Key of
       { 9/19/97 - Set ProcessingNotInList to True so validation is skipped in CMExit}
       VK_ESCAPE:
          if not modified then begin
             Temp:= ProcessingNotInList;
             ProcessingNotInList:= True;
             SendToParent;
             ProcessingNotInList:= Temp;
          end;

       VK_UP, VK_DOWN, VK_NEXT, VK_PRIOR: if (not Alt) then SendToParent;
       VK_LEFT: if ForwardMovement and (Ctrl or LeftSide) then SendToParent;
       VK_RIGHT: if ForwardMovement and (Ctrl or RightSide) then SendToParent;
       VK_HOME: if ForwardMovement and (Ctrl or LeftSide) then SendToParent;
       VK_END: if ForwardMovement and (Ctrl or RightSide) then SendToParent;
       VK_INSERT: SendToParent;                {Fix - 8/12/96}
       VK_DELETE: if (Ctrl) then SendToParent; {Fix - 8/12/96}
       VK_F2:
         begin
           ParentEvent;
           if Key = VK_F2 then
           begin
             Deselect;
             Exit;
           end;
         end;
     end;
     if (not Editable) and (Key in [VK_LEFT, VK_RIGHT, VK_HOME, VK_END]) then SendToParent;

     if Key <> 0 then
       ParentEvent;
  end;

  { 1/20/99 - Don't allow clear key if csDropDownList regardless of ShowMatchText}
  if {FShowMatchText and }(key in [VK_BACK, VK_DELETE]) then begin
     if (style=csDropDownList) and (not AllowClearKey) and
        (not FGrid.visible) then
           Key:= 0;
  end;

  if Key <> 0 then begin
    { Prevent tab from exiting if processing AutoDropDown character }
    if isValidChar(Key) and FAutoDropDown and (not FGrid.visible) then
       InAutoDropDown:= True;
    inherited KeyDown(Key, Shift);

    if Key in [VK_BACK, VK_DELETE, VK_INSERT] then
    begin
      if Editable then EnableEdit;
      if not CanEdit then
        Key := 0;
    end
    else if not (Editable or isWWCalculatedfield) and (Key in [VK_HOME, VK_END, VK_LEFT, VK_RIGHT]) then
      Key := 0;

    if (Key in [VK_UP, VK_DOWN, VK_NEXT, VK_PRIOR, VK_F4] ) then
    begin
       if not FGrid.Visible then
       begin
         if ((ssAlt in Shift) and (Key in [VK_UP, VK_DOWN, VK_NEXT, VK_PRIOR]))
            or ((key=vk_f4) and not (ssAlt in Shift)) then begin
            DropDown;
            Key:= 0;
         end
       end
       else begin
         EnableEdit;
         if (FFieldLink.DataSource = nil) or FFieldLink.Editing or isWWCalculatedField then
           if (not ReadOnly) then FGrid.KeyDown (Key, Shift); { 6/11/98 - Check for readonly }
         Key := 0;
       end;
       {5/1/97 - Do not blindly set key:= 0, as key should remain - Necessary for support of
                 TwwRecordView's mapping of vk_down and vk_up to tab and shift-tab }
       {Key:= 0;}
    end
    else if (Key=vk_escape) and FGrid.visible then key:= 0; { 6/4/97 - RecordView ignores keystroke if 0 }

  end;


  if FShowMatchText and (key in [VK_BACK, VK_DELETE]) then begin
     if Grid.visible then FLastSearchKey:= '~~~~';
  end
  else begin
     FLastSearchKey:= '';
  end;


end;

Function TwwDBCustomLookupCombo.GetSearchIndex: integer;
var i, SearchIndex: integer;
begin
   if not wwHasIndex(LookupTable) then
   begin
      result:= -1;
      exit;
   end;
   SearchIndex:= 0;
   if SearchField<>'' then begin
      searchIndex:= -1; {1/22/97}
      if wwIsClass(LookupTable.classType, 'TwwTable') then
      begin
//
//      if (LookupTable is TwwTable) then with (LookupTable as TwwTable) do begin
         for i:= 0 to wwGetVariable(LookupTable, 'IndexFieldCount')-1 do
         if (lowercase(SearchField)=lowercase(IndexFields(i).FieldName)) then
//         indexFields[i].fieldName)) then
         begin
            SearchIndex:= i;
            break;
         end
      end
   end;
   result:= SearchIndex;
end;

procedure TwwDBCustomLookupCombo.SetToIndexContainingField(fieldName: string);
begin
   if lTable<>nil then begin
      wwSetToIndexContainingField(ltable, fieldName);
   end;
end;

procedure TwwDBCustomLookupCombo.SetToIndexContainingFields(fields: TStrings);
type
   TSetToIndexContainingFieldsFunc =
     function (
        fields: TStrings): boolean of object;
var
   method: TMethod;
begin
   if lTable<>nil then begin
      method.Data := LookupTable; // object reference
      method.Code := LookupTable.MethodAddress('setToIndexContainingFields');
      TSetToIndexContainingFieldsFunc(method)(fields);
   end;
end;

procedure TwwDBCustomLookupCombo.UpdateSearchIndex(useDisplayIndex: boolean);
var curpos: integer;
    curText: string;
    Field1Name, tempField: wwSmallString;
    lkupField: TField;                    {11/15/97}
begin
   if LookupTable=nil then exit;
   if not wwIsClass(LookupTable.classType, 'TTable') then
      if not wwIsClientCursor(LookupTable) then exit;
   if wwIsTableQuery(LookupTable) then exit;

   if useDisplayIndex then begin
      if not (FOrderByDisplay) then exit;
      if Selected.count>0 then begin
         curPos:= 1;
         Field1Name:= strGetToken(Selected[0], #9, curpos);
         curText:= LookupTable.fieldByname(Field1Name).asString;
      end
      else begin
         if (Selected.count=0) then begin {11/15/97 }
            curPos:= 1;
            field1Name:= strGetToken(lookupField, ';', curpos);
            if isWWCalculatedField then lkupField:= FGrid.FDisplayFld
            else lkupField:= lookupTable.findField(field1Name);
            if (lkupField<>Nil) then begin
               Selected.add(
                 lkupField.fieldName + #9 + inttostr(lkupField.displayWidth) + #9 +
                 lkupField.DisplayLabel);
            end
        end
      end;

      if lTable<>nil then
      begin
         setToIndexContainingFields(Selected) {Search using display key}
      end
      else begin
          // 4/7/09 - if have master source and are ttable then don't change index
          if wwGetControlMasterSource(LookupTable)=nil then
             wwSetTableIndex(LookupTable, Field1Name);
      end;
      if wwGetControlMasterSource(LookupTable)<>nil then begin
         curPos:= 1;
         if Selected.count>0 then begin
            SearchField:= strGetToken(Selected[0], #9, curpos);
            DoFindRecord(curText, SearchField, mtExactMatch); {1/22/97}
         end
      end;
   end
   else begin
      if wwGetControlMasterSource(LookupTable)<>nil then begin
         if LookupField<>'' then begin
            curPos:= 1;
            repeat
               TempField:= strGetToken(LookupField, ';', curpos);
               if TempField<>'' then SearchField:= TempField;
            until TempField='';
         end;
         curText:= LookupTable.fieldByname(SearchField).asString;
         if lTable<>nil then begin
            SetToIndexContainingField(LookupField);
         end;

         DoFindRecord(curText, SearchField, mtExactMatch); {1/22/97}
      end
      else begin
         if lTable<>nil then begin
            SetToIndexContainingField(LookupField);
         end
         else wwSetVariable(LookupTable, 'IndexFieldNames', LookupField);
      end
   end

end;

procedure TwwDBCustomLookupCombo.KeyUp(var Key: Word; Shift: TShiftState);
var tempModified: boolean;
    skipSearch: boolean;
    oldText : string;

  function AutoEditDisable: boolean;
  begin
     Result := (FFieldLink.DataSource = nil) or (DataField='') or
        (datasource.state in [dsEdit, dsInsert]) or (dataSource.autoEdit);
     Result:= Not Result;
  end;

begin

   if AllowClearKey and (not AutoEditDisable) then begin // 3/26/03 - Fix bug where still cleared even though AutoEdit=False
      if FGrid.Visible then begin
         if (not isWWCalculatedField) and
            ((key=vk_delete) or (key=vk_back)) and (Text='') then
         begin
            if (FFieldLink.Field<>Nil) then begin
               EnableEdit;{ 10/20/97 - Go through enableedit so flag is set}
                          {10/20/97 - Prevent the index from switching on delete.}
               FFieldLink.Modified; { 6/6/98 }
               FGrid.FValue:= '';
               FGrid.FDisplayValue:= '';  { 1/23/98 - Clear FDisplayValue and hiliterow }
               FGrid.FHiliteRow:= -1;
               FGrid.invalidate;
            end
            else begin
               FGrid.FValue:= '';
               FGrid.FDisplayValue:= ''; { 1/23/98 - Clear FDisplayValue and hiliterow }
               FGrid.FHiliteRow:= -1;
               FGrid.invalidate;
            end;
            Key:= 0;
         end
      end
      else begin
         if ((key=vk_delete) or (key=vk_back)) and
            ((SelText=Text) or ((Style=csDropDownList) and not FGrid.visible)) then
         begin
            if IsWWCalculatedField then begin
                Text:= '';
               Grid.Fvalue:= '';
               Grid.Fvalue2:= '';
               Grid.Fvalue3:= '';
               wwChangeFromLink(LookupTable, tempModified);
               Key:= 0;
            end
            else begin
               Text:= '';
               if (FFieldLink.Field<>Nil) then begin
                  EnableEdit;{ 10/20/97 - Go through enableedit so flag is set }
                             { 10/20/97 - Prevent the index from switching on delete.}
                  FFieldLink.modified; { 6/6/98 }
                  FGrid.FValue:= '';
               end
               else LookupValue:= '';
               Key:= 0;
            end
         end
      end;
   end;

  inherited KeyUp(Key, Shift);

  {3/11/97 - Still perform search if length is 1 }
  if (((FLastSearchKey<>Text) or (length(FLastSearchKey)=1)) and IsValidChar(Key)) then
  begin
     if FShowMatchText and (key in [VK_BACK, VK_DELETE]) then begin
        if (lTable<>nil) and
           (not wwIsTableQuery(LookupTable)) and
           (wwGetVariable(LookupTable, 'NarrowSearch')=true) and (Text = '') then
//           (LookupTable as TwwTable).narrowSearch and (Text = '') then
            wwSetVariable(LookupTable, 'FastCancelRange', null);
           //(LookupTable as TwwTable).FastCancelRange;
        skipSearch:= True;
     end
     else begin
        skipSearch:= False;
     end;

     { 1/20/99 - Skip clearing even when ShowMatchText is False }
     if (key in [VK_BACK, VK_DELETE]) then begin
        { 1/22/98 - Don't allow clear if csDropDownList and closed }
        if (not FGrid.visible) and (style=csDropDownList) and
           (not AllowClearKey) then begin
           Key:= 0;
           exit;
        end
     end;

     if (not FGrid.visible) and (not FAutoDropDown) and
        (FShowMatchText) and (Style<>csDropDownList) and { 6/6/98 }
        (Text<>'') and (not skipSearch) then
     begin
        UpdateSearchIndex(True);
        InAutoDropDown:= True;
        OnEditTimerEvent(Self);
        InAutoDropDown:= False;
     end
     else if (not FGrid.visible) and FAutoDropDown and (Text<>'') then
     begin
        UpdateSearchIndex(True);
        InAutoDropDown:= True;
        OnEditTimerEvent(Self);
//        try DropDown finally InAutoDropDown:= False end;
        InAutoDropDown:= False;
     end;

  end;
  InAutoDropDown:= False;

  { Update drop-down data connection when user is typing in box}
  if IsValidChar(Key) and not FGrid.visible then
  begin
     FFieldLink.Modified;
  end;

  // 2/9/11 - If backspace, then we update InList to be accurate.  This will slow
  // things down, but it can be important to be accurate.  Without this code
  // InList is not updated after a backspace and OnNotInList will not fire.
  // Developer must set Patch[0] to true to enable this undocumented feature
   if ((key=vk_back) or (key=vk_delete)) and (FGrid.Visible) then
   begin
     if Patch[0]=false then
     begin
        OldText:= Text;
        Patch[1]:=true;
        OnEditTimerEvent(Self);
        Patch[1]:=false;
        Text:= OldText;
     end

   end;

end;

Procedure TwwDBCustomLookupCombo.RefreshDisplay;
var OrigValue: string;
begin
   OrigValue:= LookupValue; {8/25/98}
   LookupValue:= ''; {10/5/97 }

   FGrid.DoLookup(False);
   if not FGrid.FFoundValue then { 8/25/98}
   begin
      FGrid.FDisplayValue:= '';
      Text:= '';
   end
   else begin
      if FGrid.FDisplayFld=Nil then exit;
      FGrid.FDisplayValue:= FGrid.FDisplayFld.asString;
      Text:= FGrid.FDisplayFld.AsString;
   end;
   FGrid.FValue:= OrigValue {8/25/98}
end;

Procedure TwwDBCustomLookupCombo.UpdateFromCurrentSelection;
begin
    if FTimer.enabled then begin
       FTimer.enabled:= False;
       OnEditTimerEvent(self);
    end
    else begin
       if FGrid.visible and (FGrid.FHiliteRow<0) then exit;  { Default to no selection if nothing selected }

       {9/10/97 - Do not update active record if its a TwwDBLookupComboDlg }
       if not wwIsClass(self.classType, 'TwwDBLookupComboDlg') then begin
          if FGrid.FHiliteRow>=0 then
             FGrid.DataLink.ActiveRecord:= FGrid.FHiliteRow;       { Make sure activerecord is on highlighted row }
       end;
       FGrid.FDisplayValue:= FGrid.FDisplayFld.AsString;
       if (FGrid.FValueFld <> FGrid.FDisplayFld) then begin
          FGrid.FValue:= FGrid.FValueFld.asString;
       end
       else begin
          FGrid.FValue:= FGrid.FDisplayValue;
       end;
       if FGrid.FValueFld2<>Nil then
          FGrid.FValue2:= FGrid.FValueFld2.asString;
       if FGrid.FValueFld3<>Nil then
          FGrid.FValue3:= FGrid.FValueFld3.asString;
    end;
end;

procedure TwwDBCustomLookupCombo.DoEnter;
begin
   FGrid.FDisplayValue:= Text;
   inherited doEnter;
   if Parent is TwwDBGrid then SelectAll;  { Fix - 8/15/96 Select all when focus set }

   { 7/28/97 - Don't clear modified flag when processing NotInList }
   if not ProcessingNotInList then SetModified(False);

   { 9/18/97 - Reset backvalues when getting focus }
   { Previously this code was in WMSetFocus, but that is fired also when
     the form gets focus.  When the following code was placed in WMSetFocus,
     the backvalues were incorrectly reset}
   if (not FGrid.visible) and (not ProcessingNotInList) then begin
      OldDisplayValue:= Text;
      OldLookupValue:= LookupValue;
   end;

end;

procedure TwwDBCustomLookupCombo.DoExit;
begin
   inherited doExit;
end;


procedure TwwDBCustomLookupCombo.KeyPress (var Key: Char);
var FGridWasVisible: boolean;
    TempAutoDropDown: boolean;
    parentform: TCustomForm;
   Function NewText: string;
   var curStr : string;
   begin
      curStr:= Text;
      if (ord(key)=vk_back) then begin
         if (length(curstr)>=1) then
            delete(curstr, selStart, 1);
         result:= curStr;
      end
      else
         result:= copy(curStr, 1, selStart+1-1) +
               char(Key) + copy(curStr, selStart + 1 + length(SelText), 32767);
   end;

   function IsValidKey(Key: Char): boolean;
   begin
      result:= (key>=#32) and (key<=#254) or
               (key>#255) and (Key<=High(Char));
   end;

   function IsValidKey2(Key: Char): boolean;
   begin
      result:= (key>=#32) and (Key<=High(Char));
   end;

begin
   if parent is TCustomGrid then TCheatGridCast(parent).KeyPress(Key);

           inherited KeyPress(Key);

   if (Picture.PictureMask<>'') and IsValidKey(Key) then
//   if (Picture.PictureMask<>'') and
//     (Key in [#32..#254]) then
   begin
     if Editable then EnableEdit; // Enable edit mode if picture mask assigned
     if CanEdit then
     begin
        if wwApplyPictureMask(self, Picture.PictureMask,
            True, Key) then
        begin
          selStart:= length(Text);
          if FGrid.Visible or ShowMatchText then
          begin
             TempAutoDropDown:= InAutoDropDown;
             InAutoDropDown:= True;
             OnEditTimerEvent(Self);
             InAutoDropDown:= TempAutoDropDown;
          end;
        end
     end
   end;

   { 1/20/99 - Don't allow clear key if csDropDownList }
   if (AutoDropDown=True) and ((key=#8) or (key=^X)) then begin
      if (style=csDropDownList) and (not AllowClearKey) and
         (not FGrid.visible) then
      begin
          Key:= #0;
      end
   end;

   { 2/24/98 - Enable timer in KeyPress instead of KeyUp }
   if (((FLastSearchKey<>NewText) or (length(FLastSearchKey)=1))
         and (ord(Key)>=32) or ((key=#8) and (loSearchOnBackspace in Options)))
         and (FGrid.visible or (ShowMatchText and CanEdit)) then
   begin
      if ShowMatchText and (ltable<>nil) and
         (not wwIsTablequery(LookupTable)) and (key=#8) and
//           ((LookupTable as TwwTable).Query.Count=0) and  (key=#8) and
           (loSearchOnBackSpace in Options) and
           (wwGetVariable(LookupTable, 'NarrowSearch')=true) and (NewText = '') then
//           (LookupTable as TwwTable).narrowSearch and (NewText = '') then
            wwSetVariable(LookupTable, 'FastCancelRange', null)
           //(LookupTable as TwwTable).FastCancelRange
      else begin
        if FSearchDelay>0 then begin
           FTimer.Interval:= FSearchDelay;
        end;
        FTimer.enabled:= True;
      end
   end;

   if (key = char(VK_RETURN)) then begin
      if FGrid.visible then begin
         UpdateFromCurrentSelection;
         if InList then GridClick(self);  { InfoPower 2.0 addition}
         closeUp(True);
         DoSelectAll;
         ShowCaret(Handle);
      end;
   end
   else if (key = char(VK_ESCAPE)) then begin
      if FGrid.Visible then begin
         closeup(False);
         FGridWasVisible:= True;
      end
      else FGridWasVisible:= False;

      if FFieldLink.Field<>Nil then begin
{         if FFieldLink.Editing then
            LookupValue:= '';
         FFieldLink.Reset;}
         FGrid.FDisplayValue:= OldDisplayValue; {9/18/97 - Use FGrid.FDisplayValue instead of DisplayValue }
         FGrid.FValue:= OldLookupValue;
         Text:= OldDisplayValue;
         modified:= False;  { 6/4/97}

         { 2/5/98 - Resets FFieldLink.modified flag }
         SkipDataChange:= True;
         FFieldLink.Reset;
         SkipDataChange:= False;

         DoSelectAll;

         if (not Editable) or (not FGridWasVisible) and
            (parent is TwwCustomDBGrid) then
         begin
//            if not (dgAlwaysShowEditor in TwwCustomDBGrid(parent).Options) then  { 6/6/98 }
             parentForm:= GetParentForm(self) as TCustomForm; { -ksw (6/22/98) }
             // 7/18/01 - Don't setfocus if parentform not visible (i.e. modal form that is auto-created has this issue }
             if (parentForm<>Nil) and parentform.visible then
                parent.setFocus;
         end

         // 7/28/01 - bottom line of parent grid not painting unless we invalidate row
         else if (parent is TwwCustomDBGrid) and useRightToLeftAlignment and
            FGridWasVisible then
            TwwCustomDBGrid(parent).InvalidateCurrentRow;

      end
      else begin
         DisplayValue:= OldDisplayValue;
         LookupValue:= OldLookupValue;
         if Navigator then FGrid.DoLookup(False); // 11/13/03 - Restore to original value
         DoSelectAll;
      end;
      key:= #0;
      exit;
   end;

  if (not FGrid.visible) and IsValidKey2(Key) and (FFieldLink.Field <> nil) and
//  if (not FGrid.visible) and (Key in [#32..#255]) and (FFieldLink.Field <> nil) and
      not FFieldLink.Field.IsValidChar(Key) and (not FAutoDropDown) and
      Editable and (not ShowMatchText) {9/18/97 - Don't beep when ShowMatchText is True} then
  begin
    Key := #0;
    MessageBeep(0)
  end;

  case Key of
    ^H, ^V, ^X, #32..#255:
      begin
        if Editable then EnableEdit;
        if not CanEdit then
        begin
          Key := #0;
        end
      end;

    Char (VK_RETURN):
      Key := #0;

    Char (VK_TAB):
      Key := #0;

  end;

end;

procedure TwwDBCustomLookupCombo.Change;
begin
  if FFieldLink.Editing then begin
    FFieldLink.Modified;
    if SetModifiedInChangeEvent then modified:=true; // 7/31/00
  end;
  inherited Change;
end;

function TwwDBCustomLookupCombo.GetDataSource: TDataSource;
begin
  if FFieldLink<>Nil then
     Result := FFieldLink.DataSource
  else Result:= Nil;
end;

procedure TwwDBCustomLookupCombo.SetDataSource(Value: TDataSource);
begin
  if (Value<>Nil) and (Value.dataSet <> nil) and (Value.dataSet = LookupTable) then
    RaiseException(wwSLookupSourceError);
  if (Value <> nil) and (LookupTable <> nil) and (Value.DataSet <> nil) and
    (Value.DataSet = LookupTable) then
    RaiseException(wwSLookupSourceError);
  FFieldLink.DataSource := Value;
end;

function TwwDBCustomLookupCombo.GetLookupTable: TDataSet;
begin
  Result := FGrid.getLookupTable;
end;

procedure TwwDBCustomLookupCombo.SetLookupTable(sel : TDataSet);
begin
    FGrid.setLookupTable(sel);
end;


function TwwDBCustomLookupCombo.GetLookupSource: TDataSource;
begin
  Result := FGrid.GetLookupSource;
end;

{ 4/30/97 - Not used }
{procedure TwwDBCustomLookupCombo.SetLookupSource(Value: TDataSource);
begin
  if (Value <> nil) and ((Value = DataSource) or
    ((Value.DataSet <> nil) and (Value.DataSet = FFieldLink.DataSet))) then
    RaiseException(SLookupSourceError);
  FGrid.SetLookupSource(Value);
  DataChange (Self);
end;
}

procedure TwwDBCustomLookupCombo.SetLookupField(const Value: string);
begin
  FGrid.LookupField := Value;
  FGrid.InitFields(True);
  DataChange (Self);
end;

function TwwDBCustomLookupCombo.GetLookupField: string;
begin
  Result := FGrid.LookupField;
end;

function TwwDBCustomLookupCombo.GetDataField: string;
begin
  Result := FFieldLink.FieldName;
end;

procedure TwwDBCustomLookupCombo.SetDataField(const Value: string);
begin
  FFieldLink.FieldName := Value;

  ComputeLookupFields;

end;

Function TwwDBCustomLookupCombo.SetValue2: string;
var
   tempFld: TField;
begin
   if (datasource=Nil) or (dataSource.dataSet=Nil) then tempFld:= Nil
   else tempFld:= dataSource.dataSet.FindField(FGrid.FValueFld2.fieldName);
   if tempFld<>Nil then begin
      if (FGrid.FValue2<>tempFld.asString) then
         if FGrid.FDisplayFld<>Nil then
         begin
            Text:= FGrid.FDisplayFld.asString;
            FGrid.FDisplayValue:= Text;
         end;
      FGrid.FValue2:= tempFld.asString;
   end;


   result:= FGrid.FValue2;
end;

Function TwwDBCustomLookupCombo.SetValue3: string;
var
   tempFld: TField;
begin
   if (datasource=Nil) or (dataSource.dataSet=Nil) then tempFld:= Nil
   else tempFld:= dataSource.dataSet.FindField(FGrid.FValueFld3.fieldName);
   if tempFld<>Nil then FGrid.FValue3:= tempFld.asString;
   result:= FGrid.FValue3;
end;

procedure TwwDBCustomLookupCombo.DataChange(Sender: TObject);
var APos: integer;
    TempLookupValue: string;
begin
  if SkipDataChange then exit;

  if (FFieldLink.Field <> nil) and not (csLoading in ComponentState) then begin

     { Update Text,  FFieldLink.Field.AsString is wrong if master record has moved }
     { However, LookupList.DataChanged calls this function later if master record }
     { has changed. }
     if HasMasterSource and (FGrid.inDataChanged=0) and
         IsWWCalculatedField then
     begin
       Text:= FFieldLink.Field.AsString;
       exit;
     end;

     { 4/5/97 - If masterfields have changed then skip rest of code since this will be called later by
       LookupList.DataChanged }
     if (FGrid.inDataChanged=0) and (LookupTable<>Nil) and (LookupTable.active) then
     begin
        if HasMasterSource and
           wwIsClass(lookupTable, 'TwwTable') and // 4/7/09
           (DataSource=wwGetControlMasterSource(LookupTable)) then
//           (DataSource=(LookupTable as TwwTable).MasterSource) then
        begin
           APos:= 1;
           TempLookupValue:=  DataSource.Dataset.FieldByName(
                strGetToken(wwGetVariable(LookupTable, 'MASTERFIELDS'), ';', APos)).asstring;
//                strGetToken((LookupTable as TwwTable).MasterFields, ';', APos)).asstring;
           if (IndexFields(0).AsString <> TempLookupValue) then
           begin
              if not FFieldLink.Field.isNull then exit;  { If null, then LookupList.datachanged not called }
           end
        end
     end;

     inc(FGrid.inDataChanged);
     try
        { 7/1/97 - Multiple lookup fields, always perform dolookup }
        if (FGrid.FValueFld2<>Nil) or (FGrid.FValueFld3<>Nil) then
        begin
           FGrid.DoLookup(False);
           Text:= FGrid.DisplayFld.asString;
           FGrid.FDisplayValue:= Text;
        end;

        Value := FFieldLink.Field.AsString; {? Not correct for calculated fields}

        { Initialize Fvalue2 according to current record - assume 2nd lookupfield
          has the same name in both tables }
        if (FGrid.FValueFld2<>Nil) then SetValue2;
        if (FGrid.FValueFld3<>Nil) then SetValue3;

        { 1/23/97 - Update back-values when change records }
        if datasource.state=dsBrowse then begin
           OldDisplayValue:= Text;
           OldLookupValue:= LookupValue;
        end;

        if HasMasterSource and IsWWCalculatedField then
          Text:= FFieldLink.Field.AsString;

     finally
        dec(FGrid.inDataChanged);
     end;
  end
  else if not Assigned(OnPerformCustomSearch) then
  begin
   // 5/6/03 Otherwise text is cleared when form containing lookupcombo is undocked
    if (csLoading in ComponentState) or (DataSource<>nil) then
      Text := EmptyStr;
  end;

  if Focused then DoSelectAll; {!!!!!}

end;

function TwwDBCustomLookupCombo.GetValue: String;
begin
  if Editable then
    Result := Text
  else
    Result := FGrid.Value;
end;

function TwwDBCustomLookupCombo.GetValue2: String;
begin
   Result := FGrid.FValue2;
end;
function TwwDBCustomLookupCombo.GetValue3: String;
begin
   Result := FGrid.FValue3;
end;

function TwwDBCustomLookupCombo.GetLookupValue: String;
begin
   Result := FGrid.Value;
end;

function TwwDBCustomLookupCombo.GetDisplayValue: String;
begin
  Result := Text;
end;

procedure TwwDBCustomLookupCombo.SetDisplayValue(const NewValue: String);
begin
  if FGrid.DisplayValue <> NewValue then
  begin
    if FGrid.DataLink.Active then
    begin
      FGrid.DisplayValue := NewValue;
      Text := FGrid.DisplayValue;
    end;
  end;
end;

procedure TwwDBCustomLookupCombo.SetValue(const NewValue: String);
var Found: boolean;
begin
  if FGrid.DataLink.Active and FFieldLink.Active and (DataSource<>Nil) and
      (DataSource.DataSet = LookupTable) and (LookupTable<>Nil) then
    RaiseException(wwSLookupSourceError);
  {10/16/97 - When you have multiple combos on a form and the state changed from
              Browse to Edit, then the combo would have its index changed while the
              dropdown list was visible.  Skip the following code in this case.}
  if (FGrid.Value <> NewValue) or
     { 11/6/97 - control not visible earlier, so need to re-enter,
                 or else control can be blank in some cases}
     ((Text='') and (NewValue<>'')) or
     ((FGrid.FValueFld=FGrid.FDisplayFld) and (Text <> NewValue)) then
  begin
    if FGrid.DataLink.Active then
    begin
      if (not ChangingFromLink) then FGrid.Value := NewValue;

      // 8/16/04 - Update text to be same as lookupfield
      if (FGrid.FValueFld=FGrid.FDisplayFld) then
      begin
         Text:= NewValue;
         // 10/24/06
         if (Navigator) then
            FGrid.DisplayValue:= NewValue  // Update table pointr
         else
            FGrid.FDisplayValue := NewValue;
         //FGrid.DisplayValue:= NewValue;
      end
      else
         Text:= FGrid.DisplayValue;
    end
    else if (LookupField='') and (lookupTable=Nil)  then begin
       Text:= NewValue;  {added for wwdotdot support }
    end
    else if (lookupTable<>Nil) and (not lookuptable.active) then {11/6/97 }
    begin
       if Assigned(FOnPerformCustomSearch) then
       begin
          SkipDataChange:= True;
          InCustomSearch:= True;
          try
             PerformCustomSearch(LookupField, NewValue, True, Found);
             if Found and (FGrid.FDisplayFld<>nil) then
             begin
                FGrid.FDisplayValue:= FGrid.FDisplayFld.asString;
             end
          finally
             InCustomSearch:= False;
             SkipDataChange:= False;
          end;
       end
       else
          Text:= NewValue;
    end
  end;

end;

function TwwDBCustomLookupCombo.GetReadOnly: Boolean;
begin
  Result := FFieldLink.ReadOnly;
end;

procedure TwwDBCustomLookupCombo.SetReadOnly(Value: Boolean);
begin
  FFieldLink.ReadOnly := Value;
  inherited ReadOnly := not CanEdit;
end;

procedure TwwDBCustomLookupCombo.EditingChange(Sender: TObject);
begin
  inherited ReadOnly := not CanEdit;
end;

Function TwwDBCustomLookupCombo.HasMasterSource: boolean;
begin
  if LookupTable=nil then result:=false
  else
    result:= wwIsClass(LookupTable, 'TwwTable') and
             (wwGetControlMasterSource(LookupTable)<>nil);
//   result:= (LookupTable<>Nil) and (LookupTable is TwwTable) and
//            ((LookupTable as TwwTable).MasterSource<>Nil);
end;

procedure TwwDBCustomLookupCombo.WwChangeFromLink(AlookupTable: TDataSet;
          var modified: boolean);
var fromlink: wwSmallString;
    fromlinks: string;
    fpos: integer;
    tempValue: string;
    i: integer;
    pos: integer;
    fromfield: TField;
    fromFieldNames: TStrings;
    ADataSet: TDataSet;
    startField: integer;
begin

   if changingFromLink then exit;

   changingFromLink:= True;

   fromFieldNames:= TStringList.create;

   try
     ADataSet:= datasource.dataSet;
     with ADataSet do begin
        if isLookup then begin
           fromLinks:= FFieldLink.Field.KeyFields;
           fpos:= 1;
           while True do begin
              fromLink:= strGetToken(fromlinks, ';', fpos);
              if (fromLink='') then break;
              fromFieldNames.add(fromLink);
           end
        end
        else begin
           TempValue:= wwDataSetGetLinks(ADataSet, dataField);
           pos:= 1;
           while True do begin
              fromLink:= strGetToken(TempValue, ';', pos);
              strGetToken(TempValue, ';', pos); { Skip }
              if (fromLink='') then break;
              fromFieldNames.add(fromLink);
           end
        end;

     end;

     modified:= False;

     if fromfieldnames.count=0 then modified:= true; { 7/21/97 - in case of calcuated field }

     for i:= 0 to fromFieldNames.count-1 do begin
        tempValue:= ADataSet.fieldByName(FromFieldNames[i]).Text;
        case i of
        0: if (tempValue <> FGrid.FValue) then modified:= True;
        1: if (FGrid.FValueFld2<>Nil) and (tempValue <> FGrid.FValue2) then modified:= True;
        2: if (FGrid.FValueFld3<>Nil) and (tempValue <> FGrid.FValue3) then modified:= True;
        else;
        end;
     end;

     if modified then begin
        skipDataChange:= True;  { Assigning fields will trigger OnDataChange }
        if wwIsClass(ADataSet, 'TTable') and (wwGetReadOnly(ADataSet)=true) then exit;        
//        if (ADataSet is TTable) and (ADataSet as TTable).readOnly then exit;
        if (ADataSet<>Nil) and not (ADataSet.canmodify) then exit; { 5/3/00 }
        if ReadOnly then exit; { 6/11/98 }

        self.datasource.edit; {Entering edit-mode clears looked up values so save them first }
        if (self.datasource.dataset.state=dsEdit) or (self.datasource.dataset.state=dsInsert) then
        begin
          { 2/10/97 - Only update last field for detail table}
          if HasMasterSource then startField:= fromFieldNames.count-1
          else startField:= 0;

          for i:= startField to fromFieldNames.count-1 do begin
             fromField := ADataSet.fieldByName(FromFieldNames[i]);
             case i of
               0: if (fromField.text<>FGrid.FValue) then fromField.text:= FGrid.FValue;
               1: if (FGrid.FValueFld2<>Nil) and (fromField.text<>FGrid.FValue2) then
                     fromField.text:= FGrid.FValue2;
               2: if (FGrid.FValueFld3<>Nil) and (fromField.text<>FGrid.FValue3) then
                     fromField.text:= FGrid.FValue3;
               else;
             end;
          end;
        end;
        modified:= True;
     end;

   finally
      fromFieldNames.free;
      skipDataChange:= False;

      repaint; { Necessary to repaint drop-down icon }
      changingFromLink:= False;
   end;

end;

procedure TwwDBCustomLookupCombo.UpdateData(Sender: TObject);
var tempFld: TField;
    modified: boolean;
begin
  if (FFieldLink.Field <> nil) then {and (FGrid.FHiliteRow>=0) then {debug}
  begin
    { 7/28/97 - Call CloseUp to handle NotInList event }
    if (not ProcessingNotInList) and (Text<>'') and (not FGrid.visible) then
       CloseUp(True);

    if isWWCalculatedField then begin
       if (FGrid.FHiliteRow>=0) then
          wwChangeFromLink(lookupTable, modified);
    end
    else begin
       if (FGrid.FValueFld = FGrid.FDisplayFld) then begin
         if (FFieldLink.Field.asString<>Text) then
{            FFieldLink.Field.AsString := Text;}
            FFieldLink.Field.Text := Text; { 9/28/97 - Assign Text property instead }

            // 5/21/01 - Update lookupvalue in case dropped down or exit
            // 8/8/01 - Don't update value if Auto dropping down
            if (FGrid.Value<>Text) and (not InAutoDropDown) then
               FGrid.Value:= Text;
       end
       else begin
         if (FFieldLink.Field.asString<>FGrid.Value) then
            FFieldLink.Field.AsString := FGrid.Value;
       end;

       if (FGrid.FHiliteRow>=0) or (isLookupDlg) then begin
          if (FGrid.FValueFld2<>Nil) then begin
             tempFld:= dataSource.dataSet.FindField(FGrid.FValueFld2.fieldName);
             if tempFld<>Nil then tempFld.assign(FGrid.FValueFld2);
          end;
          if (FGrid.FValueFld3<>Nil) then begin
             tempFld:= dataSource.dataSet.FindField(FGrid.FValueFld3.fieldName);
             if tempFld<>Nil then tempFld.assign(FGrid.FValueFld3);
          end;
       end;
    end
  end;
end;

procedure TwwDBCustomLookupCombo.FieldLinkActive(Sender: TObject);
begin
  if FFieldLink.dataSource=Nil then exit;

  if (csDesigning in ComponentState) and { don't reset datafield when running program }
    (not wwDataSetIsValidField(FFieldLink.dataSource.dataSet, dataField)) and
    (FFieldLink.Active) then dataField:= '';

  if FFieldLink.Active then ComputeLookupFields; {3/27/97}

  if FFieldLink.Active and (FGrid.DataLink.Active) then
  begin
//    if not Assigned(OnPerformCustomSearch) then
//    if (not InDropDownEvent) and (not InCustomSearch) then
    if (not InCustomSearch) then
    begin
      FGrid.SetValue ('');   {force a data update}
      DataChange (Self);
    end
  end;
end;

procedure TwwDBCustomLookupCombo.EnableEdit;
   { 8/16/96 Bypass parent HideControls in parent grid's dataChange}
   procedure SetHideControls(val: boolean);
   begin
//      if (Grid.visible) and (Parent is TwwDBGrid) then
     { 10/23/99 - Skip grid's hide controls when going into edit mode so
       that focus does not move to the grid }
      if (Parent is TwwDBGrid) then
         (Parent as TwwDBGrid).SkipHideControls:= val;
   end;

begin
   SkipDataChange:= True;
   SetHideControls(True);
   try {7/21/97 Added try/finally block to handle exceptions}
     FFieldLink.Edit;
   finally
     SetHideControls(False);
     SkipDataChange:= False;
   end
end;

procedure TwwDBCustomLookupCombo.WMPaste (var Message: TMessage);
begin
  if Editable then EnableEdit;
  if CanEdit then begin
     if AutoDropDown and (not Grid.visible) and (Style=csDropDownList) then exit; { 11/24/98}

     inherited;
     FFieldLink.modified;
     if Grid.visible then PerformSearch; { 11/24/98 }
  end
end;

procedure TwwDBCustomLookupCombo.WMCut (var Message: TMessage);
begin
  if Editable then EnableEdit;
  if CanEdit then inherited;
end;

Procedure TwwDBCustomLookupCombo.SetUseTFields(val: boolean);
begin
   FuseTFields:= val;
   FGrid.useTFields:= val;
{   FGrid.HandleNeeded;
   FGrid.LayoutChanged;}
end;

procedure TwwDBCustomLookupCombo.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);

  {ES_MULTILINE allows precise positioning of edit region, but it has the
   following side effects:
   1. Escape key no longer passed to form for closing of a modal dialog
   2. More resource consumption
   For this reason we have added another property - PreciseEditRegion
  }
  if PreciseEditRegion or (BorderStyle=bsNone) or self.IsVistaComboNonEditable then  // check IsVista so edit box is not cleared momentarily
     Params.Style := Params.Style or ES_MULTILINE or WS_CLIPCHILDREN
  else
     Params.Style := Params.Style or WS_CLIPCHILDREN;

  {$ifdef wwdelphi4up}
  if UseRightToLeftAlignment then
    Params.Style:= Params.Style or ES_MULTILINE;
  {$endif}

  if IsTransparentEffective and Frame.CreateTransparent then
  begin
     Params.ExStyle := Params.ExStyle or WS_EX_TRANSPARENT;
  end;

  // Remove parent clipping and don't paint background for button if styles enabled
  if wwIsCustomStyle(self) then
     Params.Style := Params.Style and not WS_CLIPCHILDREN;


end;

procedure TwwDBCustomLookupCombo.CreateWnd;
begin
  inherited CreateWnd;
  if (BorderStyle=bsNone) and AutoSize and
     not (parent is TCustomGrid) then Frame.AdjustHeight;
  SetEditRect;
  FGrid.HandleNeeded;
  DataChange (Self);  {update to current value}

  if IsTransparentEffective then
  begin
     wwDisableParentClipping(Parent);
  end
end;

procedure TwwDBCustomLookupCombo.SetEditRect;
var
  Loc: TRect;
begin
  Loc.Bottom := ClientHeight + 1; {+1 is workaround for windows paint bug}

  if UseRightToLeftAlignment then // Support bidimode for button - 8/26/08
    Loc.Right:= ClientWidth - 0
  else begin
    if ShowButton then Loc.Right := FBtnControl.Left - 2
    else Loc.Right:= ClientWidth - 2;
  end;

  if (BorderStyle = bsNone) and (Parent is TwwCustomDBGrid) then begin
     Loc.Top := 2;
     if (parent is TwwDBGrid) and not TwwDBGrid(parent).HaveAnyRowLines then
        Loc.Top:=1;
     Loc.Left := 2;
  end
  else if (Frame.IsFrameEffective) then
  begin
     Frame.GetEditRectForFrame(Loc);
  end
  else if (BorderStyle = bsNone) then
  begin
     Loc.Top := 1;
     Loc.Left := 1;
  end
  else begin
     Loc.Left := 0;
     Loc.Top:= 0;
  end;
  SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@Loc));
end;

type
 TCheatButton = class(TwwComboButton);

procedure TwwDBCustomLookupCombo.UpdateButtonPosition;
var
  MinHeight: Integer;
  offset :Integer;
begin
  if (csDesigning in ComponentState) then
    FGrid.SetBounds (0, Height + 1, 10, 10);

  if Frame.IsFrameEffective then
  begin
     offset:= 2;
  end
  else offset:= 0;

  MinHeight := GetMinHeight;
    { text edit bug: if size to less than minheight, then edit ctrl does
      not display the text }
  if Height < MinHeight then Height := MinHeight;

  if UseRightToLeftAlignment then // Support bidimode for button - 8/26/08
  begin
     //if ButtonStyle=cbsDownArrow then leftoffset:= leftoffset;
    if (not NewStyleControls) or (BorderStyle = bsNone) or (not Ctl3d) then
       FBtnControl.SetBounds (1, offset, FButton.Width+offset, ClientHeight-offset*2)
    else
       FBtnControl.SetBounds (0, offset, FButton.Width+4, ClientHeight-offset);
  end
  else begin
     if (not NewStyleControls) or (BorderStyle = bsNone) or (not Ctl3d) then
        FBtnControl.SetBounds (Width - FButton.Width - offset, offset, FButton.Width, ClientHeight-offset*2)
     else
        FBtnControl.SetBounds (Width - FButton.Width - 4, offset, FButton.Width, ClientHeight-offset);
  end;

  if BorderStyle = bsNone then begin
     FButton.Top:= -1; {Allows bitmap to be larger }
     FButton.Height := FBtnControl.Height+1;
  end
  else begin
     FButton.Top:= 0;
     FButton.Height := FBtnControl.Height;
  end;
  SetEditRect;
end;

procedure TwwDBCustomLookupCombo.WMSize(var Message: TWMSize);
begin
  inherited;
  UpdateButtonPosition;
end;

function TwwDBCustomLookupCombo.GetMinHeight: Integer;
var
  DC: HDC;
  SaveFont: HFont;
  SysMetrics, Metrics: TTextMetric;
begin
  result:= 0; { Don't have minheight }
  exit;

  DC := GetDC(0);
  GetTextMetrics(DC, SysMetrics);
  SaveFont := SelectObject(DC, Font.Handle);
  GetTextMetrics(DC, Metrics);
  SelectObject(DC, SaveFont);
  ReleaseDC(0, DC);
{  I := SysMetrics.tmHeight;
  if I > Metrics.tmHeight then I := Metrics.tmHeight;}
  Result := Metrics.tmHeight + 1 + GetSystemMetrics(SM_CYBORDER) * 2;
  if (bsSingle = BorderStyle) then Result:= Result + 2;
end;

procedure TwwDBLookupList.FastLookup;
var tempValue: string;
//    tempFieldValues: Variant;
begin
   FFoundValue := False;
   if not HandleAllocated then Exit;
   { 10/23/99 - optimization only for lookupcombo in grid }
   if (not FCombo.visible) and (parent is TwwCustomDBGrid) then exit;

   IF LookupField='' then exit;

   if (FCombo.FFieldLink=Nil) or (FCombo.FFieldLink.Field=Nil) then
      tempValue:= FCombo.LookupValue
   else tempValue:= FCombo.FFieldLink.Field.asString; {!!! Should be asString instead }

   if FCombo.UseSeqSearch then
   begin
       FFoundValue:= FCombo.FindRecord(tempValue, LookupField, mtExactMatch,
                                      ssoCaseSensitive in FCombo.SeqSearchOptions,
                                      True)
   end
   else if FValueFld2=Nil then begin
      if FCombo.HasMasterSource then begin
         FFoundValue:= FCombo.DoFindRecord(tempValue, LookupField, mtExactMatch); {1/22/97}
      end
      else begin
      {
         TempFieldValues:= VarArrayCreate([0, 0], varVariant);
         TempFieldValues[0]:= tempValue;
         FFoundValue:= wwGetVariableWithParams(LookupTable, 'wwFindKey',  tempFieldValues);
         }
         FFoundValue:= FCombo.wwFindKey([tempValue]);
      end;
   end
   else begin

      if FValueFld3=Nil then
      begin
      {
         TempFieldValues:= VarArrayCreate([0, 1], varVariant);
         TempFieldValues[0]:= tempValue;
         TempFieldValues[1]:= FCombo.SetValue2;
         FFoundValue:= wwGetVariableWithParams(LookupTable, 'wwFindKey', TempFieldValues);
         }
         FFoundValue:= FCombo.wwFindKey([tempValue, FCombo.SetValue2])
      end
      else begin
      {
         TempFieldValues:= VarArrayCreate([0, 2], varVariant);
         TempFieldValues[0]:= tempValue;
         TempFieldValues[1]:= FCombo.SetValue2;
         TempFieldValues[2]:= FCombo.SetValue3;
         FFoundValue:= wwGetVariableWithParams(LookupTable, 'wwFindKey', TempFieldValues);
         }
//         FFoundValue:= wwGetVariableWithParams(LookupTable, 'wwFindKey',  [tempValue, FCombo.SetValue2, FCombo.SetValue3])
         FFoundValue:= FCombo.wwFindKey([tempValue, FCombo.SetValue2, FCombo.SetValue3]);
      end
   end
end;

procedure TwwDBCustomLookupCombo.WMNCPaint(var Message: TMessage);
var Details: TThemedElementDetails;
  DC: HDC;
  R: TRect;
begin
  if IsVistaComboNonEditable then
  begin
    DC := GetWindowDC(Handle);
    try
       R := Rect(0, 0, Width, Height);
       InflateRect(R, 1, 1);
       if StyleServices.Enabled then begin
         if FGrid.Visible then
            Details := StyleServices.GetElementDetails(tbPushButtonPressed)
         else if (not FMouseInControl) then
            Details := StyleServices.GetElementDetails(tbPushButtonNormal)
         else
            Details := StyleServices.GetElementDetails(tbPushButtonHot);

         ExcludeClipRect(dc, 3, 3, R.Right-3, R.Bottom-3); // Don't paint inside borders
         StyleServices.DrawElement(dc, Details, R);
       end;
       message.Result:=1;
    finally
       ReleaseDC(Handle, DC);
    end;

  end
  else inherited;
end;

procedure TwwDBCustomLookupCombo.WMPaint(var Message: TWMPaint);
var
  PS: TPaintStruct;
  Indent, Left: Integer;
  ARect: TRect;
  S: array [0..255] of char;
  Focused: Boolean;
  DC: HDC;
  Win32: boolean;
  WriteOptions: TwwWriteTextOptions;
  ATextWidth: integer;
  UseVistaComboPaint: boolean;
  IsCustomStyle: boolean;

  Function ParentGridFocused: boolean;
  begin
     result:= False;
     if parent is TwwDBGrid then begin
        if parent.Focused then result:= True
     end
  end;

  Function DrawFocusControl: boolean;
  begin
      result:= (((Style=csDropDownList) and Focused) or ParentGridFocused)
                and not wwInPaintCopyState(ControlState)
  end;

  procedure CanvasNeeded;
  begin
    if FCanvas = nil then
    begin
      FCanvas := TControlCanvas.Create;
      FCanvas.Control := Self;
    end;
  end;

begin
  {
  FButton.invalidate;
  FButton.Update;
  }
  IsCustomStyle:= wwIsCustomStyle(self);

  { Don't use MouseEditable here }
  if ((GetEffectiveAlignment = taLeftJustify) and (not Frame.IsFrameEffective) or
     FFocused) and
     ((Editable and not ParentGridFocused and not wwInPaintCopyState(ControlState))) then
  begin
    if FGrid.visible then redrawListGrid;
    inherited;

    if Frame.IsFrameEffective then
    begin
      CanvasNeeded;
      FCanvas.Handle:= message.DC;
      DrawFrame(FCanvas);
      FCanvas.Handle:= 0;
    end;

    if FBtnControl.Visible then
    begin
      FButton.Invalidate;
      FButton.Update;
    end;

    Exit;
  end;

  CanvasNeeded;

  DC := Message.DC;

  if DC = 0 then DC := BeginPaint(Handle, PS);
  FCanvas.Handle := DC;
  try
    UseVistaComboPaint:=false;

    Focused := GetFocus = Handle;
    FCanvas.Font := Font;

    with FCanvas do
    begin
      ARect := ClientRect;

      if (not enabled) and (color<>clGrayText) then { 3/7/00 - Use clGrayText }
         font.color:= clGrayText
      else if IsInGridPaint(self) and (message.dc<>0) then
         Font.Color:= GetTextColor(message.dc)
      else if parent is TCustomGrid then
         font.Color:= TwwDBGrid(parent as TCustomGrid).Font.Color;
      Brush.Color:= clWhite;

      Win32:= True;

      { 8/25/96 - Fix for winNT }
      if (BorderStyle<>bsNone) then
      begin
          if (not NewStyleControls) or (not Ctl3d) or  { <-- This line changed }
            ( (not wwInPaintCopyState(ControlState)) and
              ((parent is TwwDBGrid) or (not Win32)) ) then
         begin
           Brush.Color := clWindowFrame;
           FrameRect(ARect);
         end
      end;

      Brush.Style := bsSolid;
      Brush.Color := Color;
      InflateRect(ARect, -1, -1);  {Added for csDropDownList style }
      // 4/15/01 - Back-color support
      if (not IsTransparentEffective) and (not IsInGridPaint(self)) then
      begin
         if Frame.Enabled and (not FFocused) and (Frame.NonFocusColor<>clNone) then
         begin
            Brush.Color:= Frame.NonFocusColor;
            ARect:= ClientRect;
            FillRect (ARect);
            InflateRect(ARect, -1, -1);  {Added for csDropDownList style }
         end
         else begin
            if wwUseThemes(self) then
            begin
               InflateRect(ARect, 1, 1);
               if IsVistaComboNonEditable then
               begin
                  wwFillEditThemeBackground(Grid.Visible, FMouseInControl, ARect, FCanvas);
                  UseVistaComboPaint:=true;
               end
               else if IsCustomStyle then begin
                 InflateRect(ARect, 1, 1);
                 if DrawFocusControl and (parent is TCustomGrid) then begin
                    wwPaintActiveGridCellBackgroundColor(self, FCanvas, ARect);
                 end
                 else begin
                   wwFillEditThemeBackgroundDefault(ARect, FCanvas);   // StyleServices
                 end;
                 InflateRect(ARect, -1, -1);
                 UseVistaComboPaint:=true;
               end
               else FillRect(ARect);

               InflateRect(ARect, -1, -1);
            end
            else
               FillRect (ARect);

         end;
      end;
      if Showbutton and not IsInGridPaint(self) then ARect.Right:= FBtnControl.Left;

      { Win 95 TGridRecord}
      if wwInPaintCopyState(ControlState) and (FFieldLink.Field <> nil) then
      begin
        if (FGrid.FValueFld = FGrid.FDisplayFld) or (FFieldLink.Field.isNull) or
           (FFieldLink.Field.Lookup) or (FFieldLink.Field.Calculated) then
        begin
           StrPCopy(S, Copy(FFieldLink.Field.DisplayText, 1, 255)) // 3/16/11 - Limit to 255 characters
        end
        else begin
           if wwIsClass(LookupTable, 'TwwTable') then
              SetToIndexContainingField(LookupField);
           FGrid.FastLookup;
           StrPCopy(S, Copy(FGrid.DisplayFld.asString, 1, 255)); // 3/16/11 - Limit to 255 characters
        end;
      end
      else StrPCopy (S, Copy(Text, 1, 255)); // 3/16/11 - Limit to 255 characters

      if DrawFocusControl then begin
         if not IsVistaComboNonEditable then
         begin
           Brush.Color := clHighlight;
           Font.Color := clHighlightText;
         end;
         // 3/4/00 - Honor grid calccellcolors
         if ParentGridFocused then
	          TwwCheatGridCast(Parent).DoCalcCellColors(FFieldLink.Field, [], True, Font, Brush);
      end;

{      Width := TextWidth(strpas(S));}

      if IsInwwObjectView(self) then Indent:= 1
      else if IsInGrid(self) then
      begin
         if wwIsClass(parent.classtype, 'TwwDBGrid')and
            (dgRowLines in TwwDBGrid(parent).Options) then
            Indent:=2
         else Indent:=1
      end
      else if ParentGridFocused then begin
         if BorderStyle=bsNone then
            Indent:= 2
         else
           Indent:= 3;
      end
      else Indent:= 1;

      if IsInGrid(self) then Left:= 2
      else if Frame.IsFrameEffective then
      begin
         Frame.GetFrameTextPosition(Left, Indent, FFocused);
      end
      else Left:= Indent + 1;

      if (FFieldLink.Field<>nil) and (not IsInwwObjectView(self)) then with FFieldLink.Field do
      begin
         ATextWidth := TextWidth(strpas(S));
         if (GetEffectiveAlignment = taRightJustify) then
         begin
            Left:= ARect.Right - ATextWidth - 2;
            if ShowButton and (not IsInwwObjectViewPaint(self)) then begin
               if not Frame.Transparent then Left:= Left + 1;
            end;
            if Frame.IsFrameEffective then Left:= Left - Frame.NonFocusTextOffsetX;
         end
         else if GetEffectiveAlignment = taCenter then
         begin
            Left := (ARect.Left + ARect.Right - ATextWidth) div 2;
         end
      end;

      WriteOptions:= [];
      if UseVistaCombopaint or IsInGridPaint(self) or
         (IsTransparentEffective and (not FFocused)) then
         WriteOptions:= WriteOptions + [wtoTransparent];

      if (not FFocused) and IsTransparentEffective and (Frame.NonFocusTransparentFontColor<>clNone) then
         FCanvas.Font.Color:= Frame.NonFocusTransparentFontColor
      // 4/15/01
      else if (not FFocused) and (Frame.Enabled) and
              (Frame.NonFocusFontColor<>clNone) then
         FCanvas.Font.Color:= Frame.NonFocusFontColor;

      // 6/10/03 - Respect bidi mode
      if UseRightToLeftAlignment and (GetEffectiveAlignment = taLeftJustify) then
      begin
         wwWriteTextLinesT(FCanvas, ARect, Left-1, Indent-1,
             s, taRightJustify, WriteOptions);
      end
      else
         wwWriteTextLinesT(FCanvas, ARect, Left-1, Indent-1,
             s, taLeftJustify, WriteOptions);

      if (not IsCustomStyle) and DrawFocusControl then
      begin
        ARect := ClientRect;
        if Showbutton then ARect.Right:= FBtnControl.Left;

        if (BorderStyle <> bsNone) then
        begin
          ARect.Top:= ARect.Top + 1;
          ARect.Bottom:= ARect.Bottom - 1;
          ARect.Left:= ARect.Left + 1;
        end
        else begin
        end;

        // Set colors in case they were changed earlier
        FCanvas.Pen.Color:= clHighlight;
        if not (self.IsVistaComboNonEditable) then
        begin
           FCanvas.FrameRect(ARect);
           SetTextColor(FCanvas.Handle, clBlack);
           SetBkColor(FCanvas.Handle, clWhite);
        end
        else begin
           SetTextColor(FCanvas.Handle, clBlack);
           SetBkColor(FCanvas.Handle, clWhite);
        end;

        DrawFocusRect (ARect);
      end

    end;

    if Frame.IsFrameEffective then
    begin
      DrawFrame(FCanvas);
    end;

  finally
    FCanvas.Handle := 0;
    if Message.DC = 0 then EndPaint(Handle, PS);

    if FBtnControl.Visible then
    begin
      FButton.Invalidate;
      FButton.Update;
    end;
  end

end;

procedure TwwDBCustomLookupCombo.CMFontChanged(var Message: TMessage);
begin
  inherited;
  GetMinHeight;
  if (Owner<>Nil) and (not (csLoading in Owner.ComponentState)) then SetEditRect;
end;

procedure TwwDBCustomLookupCombo.CMEnabledChanged(var Message: TMessage);
begin
  inherited;
  FButton.Enabled := Enabled;
end;

procedure TwwDBCustomLookupCombo.WMKillFocus(var Message: TWMKillFocus);
var tempNotInList: boolean;
begin
  tempNotInList:= (not InList) and (DisplayValue<>'');

{ 6/4/97
  if (not InList) then begin
     EnableEdit;
     if FFieldLink.Editing then FFieldLink.Modified;
  end;
}

  inherited;

  { 5/27/99 - When clicking on a different combo dropdown controls edit area the
            current combos text would be cleared after a delete.}
  if FGrid.visible and modified and (AllowClearKey=False) and (Text='') then
  begin
    UpdateFromCurrentSelection;
  end;
//  UpdateFromCurrentSelection;

  CloseUp(True);

  if tempNotInList then begin
    { Code to prevent MouseCapture by different component }
  end;
end;

procedure TwwDBCustomLookupCombo.CMCancelMode(var Message: TCMCancelMode);
begin

  if modified and (not InList) then begin
     EnableEdit;
     if FFieldLink.Editing then FFieldLink.Modified;
  end;

  { Comment out if want list to remain open until another control is activated }
  with Message do
    if (Sender <> Self) and (Sender <> FBtnControl) and
      (Sender <> FButton) and (Sender <> FGrid) then
    begin
      { In case user exits drop-down with mouse then force to enter from list }
      if FGrid.visible then begin
         UpdateFromCurrentSelection;
         if inList then GridClick(self);
      end;

      CloseUp(True);
    end
end;

procedure TwwDBCustomLookupCombo.RefreshButton;
begin
{
     FButton.enabled:= False;
     Repaint;
     FButton.enabled:= True;
     Repaint;    }
end;

  { 8/25/98 - Move outside scrope of RedrawListGrid so that its callable by
              the DropDown method }
  function GetWidthForGrid(Combo: TwwDBCustomLookupCombo;
     lessFields: integer): integer;
  var i: integer;
    CWidth: Integer;
    APos: integer;
    tempWidth: integer;
    TitleWidth: integer;
  begin
    cwidth:= GetSystemMetrics(SM_CXHThumb) + 1;  {Win95 fix }

    if Combo.useTFields then begin
      with Combo.FGrid do begin
        for I := 0 to FieldCount - (1 + lessFields) do begin
          Canvas.Font := Font;

          with Fields[I] do
          begin
            tempWidth:= DisplayWidth * Canvas.TextWidth('0') + GridLineWidth;

            { Width at least Title Size }
            if (loTitles in Options) then
            begin
               Canvas.Font := TitleFont;
               TitleWidth:= Canvas.TextWidth(DisplayLabel);
               if tempWidth < TitleWidth then tempWidth:= TitleWidth;
            end;
            CWidth := CWidth +  TempWidth;
          end;
        end
      end
    end
    else begin
      with Combo.FGrid do begin
        for I := 0 to Selected.count - (1 + lessFields) do begin
           Canvas.Font := Font;
           APos:= 1;
           strGetToken(selected[i], #9, APos); { Field Name }
           tempWidth:=  strtoint(strGetToken(selected[i], #9, APos)) * Canvas.TextWidth('0') +
                     GridLineWidth;

           { Width at least Title Size }
           if (loTitles in Options) then
           begin
              Canvas.Font := TitleFont;
              TitleWidth:= Canvas.TextWidth(strGetToken(selected[i], #9, APos));
              if tempWidth < TitleWidth then tempWidth:= TitleWidth;
           end;

            CWidth := CWidth +  TempWidth;
        end
      end
    end;

    result:= CWidth;
  end;


procedure TwwDBCustomLookupCombo.RedrawListGrid;
var
  P: TPoint;
  Y:  Integer;
  GridWidth, BorderWidth, BorderOffset: Integer;
  WinAttribute: HWnd;
  parentForm: TCustomForm;
  gridHeight: integer;

  function min(x,y: integer): integer;
  begin
     if x<y then result:= x else result:= y;
  end;

  function max(x,y: integer): integer;
  begin
     if x>y then result:= x else result:= y;
  end;
(*
  function getWidth(lessFields: integer): integer;
  var i: integer;
    CWidth: Integer;
    APos: integer;
    tempWidth: integer;
    TitleWidth: integer;
  begin
    cwidth:= GetSystemMetrics(SM_CXHThumb) + 1;  {Win95 fix }

    if useTFields then begin
      with FGrid do begin
        for I := 0 to FieldCount - (1 + lessFields) do begin
          Canvas.Font := Font;

          with Fields[I] do
          begin
            tempWidth:= DisplayWidth * Canvas.TextWidth('0') + GridLineWidth;

            { Width at least Title Size }
            if (loTitles in Grid.Options) then
            begin
               Canvas.Font := TitleFont;
               TitleWidth:= Canvas.TextWidth(DisplayLabel);
               if tempWidth < TitleWidth then tempWidth:= TitleWidth;
            end;
            CWidth := CWidth +  TempWidth;
          end;
        end
      end
    end
    else begin
      with FGrid do begin
        for I := 0 to Selected.count - (1 + lessFields) do begin
           Canvas.Font := Font;
           APos:= 1;
           strGetToken(selected[i], #9, APos); { Field Name }
           tempWidth:=  strtoint(strGetToken(selected[i], #9, APos)) * Canvas.TextWidth('0') +
                     GridLineWidth;

           { Width at least Title Size }
           if (loTitles in Grid.Options) then
           begin
              Canvas.Font := TitleFont;
              TitleWidth:= Canvas.TextWidth(strGetToken(selected[i], #9, APos));
              if tempWidth < TitleWidth then tempWidth:= TitleWidth;
           end;

            CWidth := CWidth +  TempWidth;
        end
      end
    end;

    result:= CWidth;
  end;

*)
   function GetDeskTopHeight:Integer;
   var Rect1:TRect;
   begin
      if SystemParametersInfo(SPI_GETWORKAREA,0,@Rect1,0) Then
         GetDeskTopHeight:=Rect1.Bottom-Rect1.Top
      else
         GetDeskTopHeight:=Screen.Height;
   end;
begin
  if (Width > 20) then
  begin

    P := ClientOrigin;
    Y := P.Y + Height - 1;
    if BorderStyle=bsNone then Y:= Y + 1;

    { Put dropdown list above or below drop-down control }
    { 11/28/2000 - PYW - Check based on actual work area. }
    if (Y + FGrid.Height) > GetDeskTopHeight then Y := P.Y - FGrid.Height + 1;
    if Y < 0 then Y := P.Y + Height - 1;

    GridWidth := DropDownWidth;

    if GridWidth = 0 then begin  { manually compute width }
       GridWidth:= getWidthForGrid(self, 0) + FGrid.ColCount * FGrid.GridLineWidth + FButton.Width;
    end;

    // 12/16/02 - Delphi 7 needs topmost so that hint window doesn't send the listbox to the background
    // Alternatively we can disable the hint while its dropped down, but we choose
    // not to do this at this time
    WinAttribute:= 0;
{    WinAttribute:= HWND_TOPMOST; } // Setting topmost disables messages from being on top.
                                    // This is unacceptable so we instead disable hints during drop-down
                                    // Alternatively we can consider providing the developer a property for this.

    parentForm:= GetParentForm(self) as TCustomForm; { -ksw (6/22/98) }

    if (parentForm<>Nil) and (TForm(parentForm).FormStyle=fsStayOnTop) then
       WinAttribute:= HWND_TOPMOST;

    BorderWidth := 0;
    if loRowLines in Options then BorderWidth := 1;

    GridHeight:= FGrid.height;
    BorderOffset:= 0;
    if loRowLines in Options then BorderOffset:= -2;
    if FDropDownAlignment = taLeftJustify then begin
       { 3/14/99 - Support multiple monitors }
       {$ifdef wwDelphi4Up}
       GridWidth:= min(Screen.DesktopWidth - P.X - 2, GridWidth);
       {$else}
       GridWidth:= min(Screen.Width - P.X - 2, GridWidth);
       {$endif}

       GridWidth:= max(Width-4, GridWidth);

       { Make room for scrollbar if present }
       if (GridWidth<=GetWidthForGrid(self, 1) + FGrid.ColCount * FGrid.GridLineWidth + FButton.Width + 1)
          and (FItemCount>0) then begin
          GridHeight := (FGrid.DefaultRowHeight + BorderWidth) *
            (FItemCount + FGrid.FTitleOffset) + 5 + BorderOffset + GetSystemMetrics(SM_CYHScroll) +
            ExtraHeight;
       end;

       SetWindowPos (FGrid.Handle, WinAttribute, P.X, Y, GridWidth, GridHeight,
             SWP_NOACTIVATE)
    end
    else begin
       GridWidth:= min(P.X + Width - 2, GridWidth);
       GridWidth:= max(Width-4, GridWidth);

       { Make room for scrollbar if present }
       if (GridWidth<=GetWidthForGrid(self, 1) + FGrid.ColCount * FGrid.GridLineWidth + FButton.Width + 1)
          and (FItemCount>0) then begin
          GridHeight := (FGrid.DefaultRowHeight + BorderWidth) *
            (FItemCount + FGrid.FTitleOffset) + 5 + BorderOffset + GetSystemMetrics(SM_CYHScroll) +
            ExtraHeight;
       end;

       SetWindowPos (FGrid.Handle, WinAttribute, P.X + 1 + Width - GridWidth, Y,
                    GridWidth, GridHeight, SWP_NOACTIVATE);
    end
  end
end;


procedure TwwDBCustomLookupCombo.DropDown;
var
  P: TPoint;
  BorderWidth, BorderOffset: Integer;
  curpos: integer;
  lkupField: TField;
  field1Name: string;
  PrevText: string;
  PrevSelStart, PrevSelLength:integer;   {11/13/97}
  WasInAutoDropDown: boolean; // 4/30/03 - Fix bug where InAutoDropDown state was cleared due to calling PerformSearch in one of the events.
                              // Thus we save this state before the events and refer to it in this method
  ShortenList: boolean;

  function min(x,y: integer): integer;
  begin
     if x<y then result:= x else result:= y;
  end;

  { 3/26/99 }
  procedure ClearHorzRange;
  begin
    if FGrid.ScrollBars in [ssHorizontal, ssBoth] then
      SetScrollRange(FGrid.Handle, SB_HORZ, 0, 0, True);
  end;

begin
 if InDropDownEvent then exit;

 try
  InDropDownEvent:= True;
  WasInAutoDropDown:= InAutoDropDown;

  // 5/21/01 - Flush typed in contents to variables before drop-down
   if {(not ShowMatchText) and}
      (FGrid.FValueFld = FGrid.FDisplayFld) and
      // 8/11/01 - Don't update tfield if autodropdown as then
      // modified flag comes out false when it should come out true
      not InAutoDropDown then
      FFieldLink.UpdateRecord;

  if Assigned(FOnPerformCustomSearch) then
  begin
     FFieldLink.UpdateRecord;
     OldDisplayValue:= Text;
     OldLookupValue:= LookupValue;
  end;

  if Assigned(FOnBeforeDropDown) then // 8/29/00 - New event
     FOnBeforeDropDown(self);

  if (LookupTable=Nil) then begin
     MessageDlg('No lookup table specified!', mtWarning, [mbok], 0);
     RefreshButton;
     exit;
  end;

{  if (not LookupTable.active) then begin
     MessageDlg('Lookup table is not active!', mtWarning, [mbok], 0);
     RefreshButton;
     exit;
  end;
}
  FGrid.Color:= DropDownGridOptions.Color;
  FGrid.TitleLines:= DropDownGridOptions.TitleLines;
  FGrid.TitleAlignment:= DropDownGridOptions.TitleAlignment;

  if not FGrid.Visible and (Width > 20) then
  begin

    FGrid.FHiliteRow:= -1;  { 8/30/96  - Reset HiliteRow when dropped down. }
                            { Otherwise HiliteRow could be out of range if records are deleted }

    { default to lookup field if no selection }
    if (Selected.count=0) then begin
       curPos:= 1;
       field1Name:= strGetToken(lookupField, ';', curpos);
       if isWWCalculatedField then lkupField:= FGrid.FDisplayFld
       else lkupField:= lookupTable.findField(field1Name);
       if (lkupField<>Nil) then begin
          Selected.add(
             lkupField.fieldName + #9 + inttostr(lkupField.displayWidth) + #9 +
             lkupField.DisplayLabel);
       end
    end;

    { 12/23/97 - Parameterized query moves dependent table when going into edit mode
      so go into edit-mode now instead of later }
    if (not WasInAutoDropDown) and wwIsClass(LookupTable.classType, 'TwwQuery') and
       (wwGetControlDataSource(LookupTable)<>Nil) then begin
       if (Datasource<>nil) and (DataSource.DataSet<>nil) and
          datasource.dataset.CanModify then { 5/3/00 }
           EnableEdit;
       FGrid.DoLookup(True); { Called in case lookupTable was moved by another control }
    end
    else if not WasInAutoDropDown then FGrid.DoLookup(True); { Called in case lookupTable was moved by another control }

    if useTFields then
       wwDataSetUpdateFieldProperties(FGrid.LookupTable, Selected)
    else begin
       FGrid.LayoutChanged;
    end;

    if Assigned(FOnDropDown) then
    begin
       FOnDropDown(Self);
    end;

    FItemCount := DropDownCount;
    if DropDownCount = 0 then FItemCount := 1;
    P := ClientOrigin;

    BorderWidth := 0;
    BorderOffset:= 0;
    if loRowLines in Options then begin
       BorderWidth := 1;
       BorderOffset:= 0;
    end;

    {8/26/98 - Height not accurate when titles are not shown }
    {10/17/00 - Height not accurate when multiple title lines are shown }
    FGrid.Height := (FGrid.DefaultRowHeight + BorderWidth) *
      (FItemCount + FGrid.FTitleOffset*FGrid.TitleLines) + 2 + 3*FGrid.FTitleOffset + BorderOffset + ExtraHeight;

//    FGrid.Height := (FGrid.DefaultRowHeight + BorderWidth) *
//      (FItemCount + FGrid.FTitleOffset) + 5 + BorderOffset + ExtraHeight;

    FGrid.BeAccurate:= True;
    {$ifdef wwDelphi4Up}
    ClearHorzRange;  {Necessary in Delphi 4 as it does not update scroll range if its not currently showing }
    {$endif}

    OldShowHint:= Application.ShowHint;
    Application.ShowHint := False;
    redrawListGrid;

    FGrid.UpdateRowCount;
    FGrid.beAccurate:= False;

    FGrid.ImageList:= ImageList;

    ShortenList:=true;
    if (loFixedDropDownHeight in Options) then ShortenList:= false;
    if (FItemCount <= FGrid.DataLink.RecordCount) then ShortenList:= false;
    if wwIsClass(LookupTable, 'TwwTable') then
    begin
       if wwGetVariable(LTable, 'SyncSQLByRange') then ShortenList:= false;
       if wwGetVariable(LTable, 'isSQLBased') then ShortenList:= false;
       if wwGetVariable(LTable, 'NarrowSearch') then ShortenList:= false;
    end;
{
    ShortenList:=
       not (loFixedDropDownHeight in Options) and
      (FItemCount > FGrid.DataLink.RecordCount) and
       ((ltable=nil) or
       ((LTable<>nil) and
         ((not wwGetVariable(LTable, 'SyncSQLByRange')) or (not wwGetVariable(LookupTable, 'isSQLBased')=True)) and
         (not wwGetVariable(LookupTable, 'NarrowSearch'))));
}
    { Shorten drop-down list size if have don't have enough records }
    if ShortenList then
    begin
      PrevText:= Text;
      FItemCount:= FGrid.DataLink.RecordCount;
      {8/26/98 - Height not accurate when titles are not shown }
      {10/17/00 - Height not accurate when multiple titles are shown }
      FGrid.Height := (FGrid.DefaultRowHeight + BorderWidth) *
         (FItemCount + FGrid.FTitleOffset*FGrid.TitleLines) + 2 + 3*FGrid.FTitleOffset + BorderOffset + ExtraHeight;
//      FGrid.Height := (FGrid.DefaultRowHeight + BorderWidth) *
//               (FItemCount + FGrid.FTitleOffset) + 5 + BorderOffset + ExtraHeight;
      SkipDataChange:= True;
      FGrid.ShowVertScrollBar:= False;
      {$ifdef wwdelphi4up} { 8/25/98 - Update horzscrollbar property based on column widths }
      FGrid.ShowHorzScrollBar:=
          GetWidthForGrid(self, 1) > Grid.Width;
      {$endif}
      FGrid.RecreateWnd;
      FGrid.HandleNeeded;  { Forces CreateWnd to be called }
      SkipDataChange:= False;

      redrawListGrid;
      {11/15/97 - Save and restore selStart and selLength }
      if ShowMatchText and WasInAutoDropDown then
      begin
         PrevSelStart:= selStart;
         PrevSelLength:= selLength;
         Text:= PrevText;     { Since recreating window, need to reset Text and SelStart }
         SelStart:= PrevSelStart;
         SelLength:= PrevSelLength;
      end
      else begin
         Text:= PrevText;     { Since recreating window, need to reset Text and SelStart }
         SelStart:= length(Text);
      end;
    end
    else if not FGrid.ShowVertScrollBar then begin  { Show scroll bar 9/4/96}
      SkipDataChange:= True;
      FGrid.ShowVertScrollBar:= True;
      FGrid.RecreateWnd;
      FGrid.HandleNeeded;
      SkipDataChange:= False;
    end;

    if Length (LookupField) = 0 then
      FGrid.FDisplayValue:= Text;
{      AssignStr(FGrid.FDisplayValue,Text);}
    FGrid.SetColumnAttributes;
    FGrid.UpdateRowCount;
    FGrid.UpdateScrollBar; // 6/14/00 - RSW Fix problem with scroll thumb being too small as visiblerowcount is incorrect
    FGrid.FirstPaint:=true;
    FGrid.Visible := True;

    FlastSearchKey := FGrid.DisplayValue;  { Reset each time drop down is called}
    Windows.SetFocus(Handle);

    inherited ReadOnly := not CanEdit;  { Refresh ReadOnly property - 6/6/95}
                                        { ReadOnly property gets reset by EditingChange }

    { 4/12/00 - Don't unselectall if showmatch text and partial selection from start already there }
//    if (not InAutoDropDown) and
    if (not WasInAutoDropDown) and
       not (ShowMatchText and (sellength>=1) and (selstart>0)) then DoSelectAll;       { If style = DropDownList, then doselectall and showcaret required }
    ShowCaret(Handle);

    Invalidate;  { Redraw this combo box for color changes in wmPaint }

    {$ifdef wwDelphi4up}
    if wwLookupComboHook=0 then
       wwLookupComboHook := SetWindowsHookEx(WH_MOUSE, @wwLookupComboHookProc, HINSTANCE, GetCurrentThreadID);
    {$endif}
  end;
 finally
   InDropDownEvent:= False;
 end
end;

procedure TwwDBCustomLookupCombo.PerformSearch;
begin
   FLastSearchKey:= '';
   OnEditTimerEvent(self);
end;

procedure TwwDBCustomLookupCombo.CloseUp (Modified: boolean);
var tempFld: TField;
    accept: boolean;
    tempInList: boolean;

  Function UnBoundCombo: boolean;
  begin
     result:=  (dataSource=Nil) or (dataSource.dataSet=Nil)
  end;

begin
  Accept:= False;           { OnNotInList not processed 9/5/96}
  if InCloseUpEvent then exit;
  if not FGrid.Visible then begin
     if FGrid.FDisplayFld=nil then exit;

     if Assigned(FOnNotInList) and (OldDisplayValue<>Text) and
      (not ProcessingNotInList) and
      {7/18/98 - OnNotInList does not work for calculated fields }
      (isWWCalculatedField or not FGrid.DisplayFld.calculated) then
     begin
        UpdateSearchIndex(True);  {2/10/97}
        if Text<>'' then OnEditTimerEvent(self) { 6/16/99 - Fix problem where text didn't get cleared in tfield }
        else inList:= False;

        if (not inList) then begin
           Accept:= True;
           ProcessingNotInList:= True;
           try
              if (Text<>'') then begin  { 2/10/97 - Don't call NotInList if blank}
                 OnNotInList(self, LookupTable, Text, Accept);
                 wwFixMouseDown;
              end;
              if not Accept then begin
                 DisplayValue:= OldDisplayValue;
                 FGrid.FValue:= OldLookupValue;
                 Text:= OldDisplayValue;
                 if Focused then SelectAll;  {7/28/97 - Select all of text }
              end;
           except
              ProcessingNotInList:= False;
              raise;
           end
        end;
        ProcessingNotInList:= False;
        OldDisplayValue:= Text;
     end
     else if (Style=csDropDown) and (FGrid.FDisplayFld<>FGrid.FValueFld) and
          (OldDisplayValue<>Text) then { 7/24/98 - Prevent's combo from accepting
                                                   display text that is not in lookup table }
     begin
        if (not ProcessingNotInList) and { 11/4/99 - Don't reset text during OnNotInList event }
           (not inList) then begin
           DisplayValue:= OldDisplayValue;
           FGrid.FValue:= OldLookupValue;
           Text:= OldDisplayValue;
           if Focused then SelectAll;
        end
     end
  end
  else try
     InCloseUpEvent:= True;

     tempInList:= inList;
     if Modified and (not InList) and  // 5/6/09 - Check readonly for unbound
        (FFieldLink.editing or isWWCalculatedField or (UnboundCombo and (not ReadOnly))) then  {6/10/97}
     begin
        FGrid.Visible := False;
        Invalidate;
        InList:= True;  { Reset flag }

        { 5/14/97 - If style is csDropDown, then allow change even though its not in the list }
        if (((Style=csDropDown) and (FGrid.FVAlueFld=FGrid.FDisplayFld))
           or Assigned(FOnNotInList))
           {and (OldDisplayValue<>Text) }then  { 5/23/97 - Call OnNotInList even when its the same, when dropped down }
        begin
           Accept:= True;
           if Assigned(FOnNotInList) and (Text<>'') then begin
              ProcessingNotInList:= True;
              OnNotInList(self, LookupTable, Text, Accept);
              wwFixMouseDown;
           end;
           if Accept then
              OldDisplayValue:= Text;

           ProcessingNotInList:= False;

           if Accept then begin
              if (FGrid.FValueFld=FGrid.DisplayFld) then begin
                 LookupValue:= Text;
                 DisplayValue:= Text;
                 if (FFieldLink.Field<>Nil) then begin
                    if FFieldLink.Field.asString<>Text then  { 6/7/97 - Only update if changed }
                       FFieldLink.Field.AsString := Text;
                 end
              end
              else if not isWWCalculatedField then begin
                 FGrid.FValue:= FGrid.FValueFld.asString;
                 if UnboundCombo then Text:= TypedInText;
              end;
           end
           else begin
              DisplayValue:= OldDisplayValue;
              if Text<>OldDisplayValue then { 12/11/99 - Fix problem of text not getting restored }
                 Text:= OldDisplayValue;
              LookupValue:= OldLookupValue;
              InCloseUpEvent:= False;
              exit
           end
        end
        else begin  { 7/24/98 - Prevent's combo from accepting display text that is not in lookup table }
           if (Style=csDropDown) and (FGrid.FDisplayFld<>FGrid.FValueFld) and
              (OldDisplayValue<>Text) then
           begin
              DisplayValue:= OldDisplayValue;
              { 1/27/99 - OldLookupValue is not reliable for calculated fields }
              if not IsWWCalculatedField then FGrid.FValue:= OldLookupValue;
              Text:= OldDisplayValue;
           end
        end
     end;

     if Modified and      // 5/6/09 - Check readonly for unbound
        (FFieldLink.editing or isWWCalculatedField or (UnboundCombo and (not ReadOnly))) then begin
        if UnboundCombo then begin
           if (not Accept) and TempInList then begin
              if (FGrid.FValueFld=FGrid.DisplayFld) then
                 Text:= LookupValue
              else Text:= FGrid.DisplayFld.asString;
           end;
           if tempInList then GridClick(self)  { InfoPower 2.0 addition}
           else if ((not Accept) and (Style=csDropDownList)) or   { 6/10/97}
                (FGrid.FValueFld<>FGrid.FDisplayFld) then
           begin
              if AllowClearKey then
              begin
                 if not Accept then begin  // 12/12/02 - Don't unclear unbound control if accept is true
                   Text:= '';   { Not in list so clear values }
                   FGrid.FValue:= '';
                 end
              end
              else begin { 3/29/99 - RSW Don't clear unbound control if not in list }
                 {9/7/2001 - Don't Clear unbound control if Accept was True.
                  This implies user set lookupvalue and text in OnNotInList event.
                  Before this would prevent the unbound case from selecting the new value}
                 if not Accept then begin
                   // 3/5/03 - Fix bug where unbound has value that is not in list
                   // with style=csDropDownList. This occurs after the user selects a value
                   // from the drop-down list, and then tries to type into the control
                   if UnboundCombo and (Style=csDropDownList) and (Text<>OldDisplayValue) then
                      Text:= OldDisplayValue;
                      
                   DisplayValue:= OldDisplayValue;
                   LookupValue:= OldLookupValue;
                 end
              end
           end
        end
        else if isWWCalculatedField then begin
           update;
           FGrid.Visible := False;
     SetWindowPos(FGrid.Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
      SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
           wwChangeFromLink(lookupTable, Modified);
           if FFieldLink.Field<>nil then // 6/26/02
              Text:= FFieldLink.Field.AsString; {7/9/97}
           SelectAll;
        end
        else begin
           Modified:= False;

           if (dataSource<>Nil) and (dataSource.dataSet<>Nil) then begin
              if (FGrid.FValueFld2<>Nil) then begin
                 tempFld:= dataSource.dataSet.FindField(FGrid.FValueFld2.fieldName);
                 if (tempFld<>Nil) and (fgrid.fhiliterow>=0) then begin { 10/14/96 Only change if have selection }
                    if tempFld.asString<>FGrid.FvalueFld2.asString then Modified:= True;
                    tempFld.asString:= FGrid.FValueFld2.asString;
                 end
              end;

              if (FGrid.FValueFld3<>Nil) then begin
                 tempFld:= dataSource.dataSet.FindField(FGrid.FValueFld3.fieldName);
                 if (tempFld<>Nil) and (fgrid.fhiliterow>=0) then begin  { 10/14/96 Only change if have selection }
                    if tempFld.asString<>FGrid.FvalueFld3.asString then Modified:= True;
                    tempFld.asString:= FGrid.FValueFld3.asString;
                 end
              end
           end;

           if (FFieldLink.Field<>Nil) then begin
              if FFieldLink.Field.asString<>FGrid.Value then Modified:= True;
              if Modified then begin
                 ChangingFromLink:= True; { Skip dolookup }
                 try  {4/23/97 - Use try/except block in case of abort in onValidate }

                    {11/25/97 - Update text to current record value in this special case }
                    if (style=csDropDownList) and (not TempInList) and
                       (FGrid.FValueFld<>FGrid.DisplayFld) then
                    begin
                       Text:= FGrid.FDisplayValue;
                    end;

                    FFieldLink.Field.AsString := FGrid.Value;

                 except
                    if not Focused then { 3/9/99 - RSW - If Not Focused then Restore previous value }
                    begin
                       FGrid.FDisplayValue:= OldDisplayValue;
                       FGrid.FValue:= OldLookupValue;
                       Text:= OldDisplayValue;
                    end;

                    { 3/9/99 - RSW - Call raise here }
                    Repaint;
                    Raise;
                 end
              end
              else if (style=csDropDownList) and (not tempinlist) then begin {7/4/97}
                 FGrid.FDisplayValue:= OldDisplayValue;
                 if Assigned(OnNotInList) and (not Accept) then { 2/24/99 - Don't update FValue if Accept }
                    FGrid.FValue:= OldLookupValue;
                 Text:= OldDisplayValue;
              end;
              ChangingFromLink:= False;
           end;
           repaint; { Necessary to repaint drop-down icon }

        end
     end
     else Modified:= False; {6/7/97}

     if not visible then begin  { 10/21/97- If control has somehow become hidden, }
                                { we need to make it visible again in order to }
                                { make the drop-down grid be invisible         }
        visible:= true;
     SetWindowPos(FGrid.Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
      SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
        FGrid.Visible := False;
        visible:= false;
     end
     else begin
     SetWindowPos(FGrid.Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
      SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
       FGrid.visible:= false
     end;
     Invalidate;

     if not editable then
        HideCaret(Handle); { Support csDropDownList style }

     if Modified then
     begin
        if wwIsClass(LookupTable, 'TwwTable') then
           wwSetVariable(lookupTable, 'INFINDRECORDCOUNT_INC', null);
        try
           if LookupTable.active then
           begin
             LookupTable.UpdateCursorPos;
             LookupTable.resync([]);
           end
        finally
           if wwIsClass(LookupTable, 'TwwTable') then
              wwSetVariable(lookupTable, 'INFINDRECORDCOUNT_DEC', null)
        end;
        OldDisplayValue:= Text;       {5/14/97}
        OldLookupValue:= LookupValue; {5/14/97}
     end;

     SetModified(Modified);

     if Assigned(FOnCloseUp) then begin
         if DataSource=Nil then FOnCloseUp(Self, LookupTable, Nil, Modified)
         else FOnCloseUp(Self, LookupTable, DataSource.dataSet, Modified);
(* 5/24/97 -  Remove disable controls in onCloseUp event - causes refresh of dataset *)
     end;

     InCloseupEvent:= False;
     {$ifdef wwDelphi4up}
     if wwLookupComboHook<>0 then UnhookWindowsHookEx(wwLookupComboHook);
     wwLookupComboHook:= 0;
     {$endif}
     Application.ShowHint := OldShowHint;
  except
     FGrid.visible:= False;
     ProcessingNotInList:= False;
     ChangingFromLink:= False; {3/11/97}
     Invalidate;
     InCloseupEvent:= False;
     {$ifdef wwDelphi4up}
     if wwLookupComboHook<>0 then begin
        UnhookWindowsHookEx(wwLookupComboHook);
        wwLookupComboHook:= 0;
     end;
     {$endif}
     Application.ShowHint := OldShowHint;
     raise;
  end
end;

procedure TwwDBCustomLookupCombo.GridClick (Sender: TObject);
begin
  inList:= True;
  if (FFieldLink.DataSource<>Nil) and (not FFieldLink.editing) and (not modified) then exit; { 6/7/97 }

  FFieldLink.Edit;
  if (FFieldLink.DataSource = nil) or FFieldLink.Editing or isWWCalculatedField then
  begin

    { Don't allow wwcalc field to be updated if table is readonly }
    if isWWCalculatedField then begin
       if wwIsClass(datasource.dataSet, 'TTable') and (wwGetReadOnly(datasource.dataSet)=true) then exit;
       //if (dataSource.dataSet is TTable) and (dataSource.dataSet as TTable).readOnly then exit;
       if ReadOnly then exit; { 6/11/98 }
    end;

    FFieldLink.Modified;
    SetModifiedInChangeEvent:=True; // 7/31/00 - Makes sure modified is set in combo's change
    Text := FGrid.DisplayValue;
    SetModifiedInChangeEvent:=False; // 7/31/00 - Makes sure modified is set in combo's change
    DoSelectAll;      { This added so text is highlighted when scrolling list }
    ShowCaret(Handle);

    FLastSearchKey:= Text;
  end
end;

procedure TwwDBCustomLookupCombo.SetStyle(Value: TwwDBLookupComboStyle);
begin
  if FStyle <> Value then
  begin
    FStyle := Value;
  end;
end;

procedure TwwDBCustomLookupCombo.WMLButtonDown(var Message: TWMLButtonDown);
begin
  if MouseEditable then
    inherited
  else
    NonEditMouseDown (Message);
end;

procedure TwwDBCustomLookupCombo.WMLButtonUp(var Message: TWMLButtonUp);
begin
  if not MouseEditable then MouseCapture := False;
  inherited;
end;

procedure TwwDBCustomLookupCombo.WMLButtonDblClk(var Message: TWMLButtonDblClk);
begin
  if MouseEditable then
    inherited
  else
    NonEditMouseDown (Message);
end;

procedure TwwDBCustomLookupCombo.NonEditMouseDown(var Message: TWMLButtonDown);
var
  CtrlState: TControlState;
begin
  SetFocus;
  if not Focused then exit; {2/28/97}
  HideCaret (Handle);

  if FGrid.Visible then
    CloseUp(True)
  else
    DropDown;

{  MouseCapture := True;}
  if csClickEvents in ControlStyle then
  begin
    CtrlState := ControlState;
    Include(CtrlState, csClicked);
    ControlState := CtrlState;
  end;
  with Message do
    MouseDown(mbLeft, KeysToShiftState(Keys), XPos, YPos);
end;

procedure MouseDragToGrid (Ctrl: TControl; Grid: TwwPopupGrid; X, Y: Integer);
var
  pt, clientPt: TPoint;
begin
  if (Grid.Visible) then
  begin
    pt.X := X;
    pt.Y := Y;
    pt := Ctrl.ClientToScreen (pt);
    clientPt := Grid.ClientOrigin;
    if (pt.X >= clientPt.X) and (pt.Y >= clientPt.Y) and
       (pt.X <= clientPt.X + Grid.ClientWidth) and
       (pt.Y <= clientPt.Y + Grid.ClientHeight) then
    begin
      Ctrl.Perform(WM_LBUTTONUP, 0, MakeLong (pt.x, pt.y)); {9/21/96 }
      pt := Grid.ScreenToClient(pt);
      Grid.Perform(WM_LBUTTONDOWN, 0, MakeLong (pt.x, pt.y));
    end;
  end;
end;

procedure TwwDBCustomLookupCombo.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited MouseMove (Shift, X, Y);
  if (ssLeft in Shift) and not Editable and (GetCapture = Handle) then
    MouseDragToGrid (Self, FGrid, X, Y);
end;

procedure TwwDBCustomLookupCombo.WMSetFocus(var Message: TWMSetFocus);
begin
  inherited;
  if wwIsCustomStyle(self) then
  begin
   if wwIsClass(self.ClassType, 'TwwDBLookupComboDlg') then // Otherwise button is not repainted
       Invalidate
  end
  else if not Editable then
  begin
    HideCaret (Handle);
    invalidate;  { 1/21/99 - Not repainted correctly otherwise in the following situation
                   User invokes a dialog, and when the dialog closes
                   the focus returns to this control. }
  end;
  if not Editable then
  begin
    HideCaret (Handle);
    invalidate;  { 1/21/99 - Not repainted correctly otherwise in the following situation
                   User invokes a dialog, and when the dialog closes
                   the focus returns to this control. }
  end;

{ 9/18/97 - Move to DoEnter }
{  if (not FGrid.visible) and (not ProcessingNotInList) then begin
     OldDisplayValue:= Text;
     OldLookupValue:= LookupValue;
  end;
}
end;

procedure TwwDBCustomLookupCombo.CMExit(var Message: TCMExit);
var OldText: string;
begin
  {7/28/97 - If processing OnNotInList then ignore focus change since its
             triggered by a message dialog by the user.  If we do call
             UpdateRecord then the component incorrectly updates the tfield
             even though the OnNotInList handler may indicate that it
             it should not be updated.
  }
  if ProcessingNotInList then
  begin
     exit;
  end;

  try
    FFieldLink.UpdateRecord;
    SelStart:= 0; { 10/12/97 - Allows component to left-justify when exiting }
  except
    DoSelectAll;
    ProcessingNotInList:= True; {10/1/97 - Don't reset backvalues in DoEnter }
    if CanFocus then SetFocus;  { 9/1/98 }
    ProcessingNotInList:= False; { 10/1/97 }
    raise;
  end;
  inherited;
  if not Editable then Invalidate;
  if ButtonEffects.Flat then FButton.invalidate;

  FFocused:= False;
  Invalidate;

  if IsTransparentEffective then begin
     Frame.CreateTransparent:= True;
     OldText:= Text;  { Text is cleared when recreating window }
     RecreateWnd;
     Text:= OldText;
     SetEditRect;
  end;

  if Frame.enabled then begin
//     invalidate; { See if this causes any flicker }
     wwInvalidateTransparentArea(self, True);
  end;


end;

procedure TwwDBCustomLookupCombo.CMEnter(var Message: TCMGotFocus);
var exStyle, origStyle: longint;
begin
  if wwGridEssentials and not (IsInGrid(self)) then
  begin
      DisplayProfessionalVersionOnlyMessage(self, '');
  end;

  SetEditRect;
  if AutoSelect and not (csLButtonDown in ControlState) then DoSelectAll;
  inherited;
  if not Editable then Invalidate;
  if ButtonEffects.Flat then FButton.invalidate;

  if IsTransparentEffective then begin
     Frame.CreateTransparent:= False;
     OrigStyle:= Windows.GetWindowLong(handle, GWL_EXSTYLE);
     exStyle:= OrigStyle and not WS_EX_TRANSPARENT;
     Windows.SetWindowLong(handle, GWL_EXSTYLE, exStyle);
     invalidate;
  end;

  FFocused:= True;
  Invalidate;
end;

procedure TwwDBCustomLookupCombo.DoSelectAll;
begin
  if Editable then
    SelectAll;
end;

procedure TwwDBCustomLookupCombo.SetOptions(Value: TwwDBLookupListOptions);
begin
  FGrid.Options := Value;
end;

function TwwDBCustomLookupCombo.GetOptions: TwwDBLookupListOptions;
begin
  Result := FGrid.Options;
end;

procedure TwwDBCustomLookupCombo.Loaded;
begin
  if FButtonWidth=0 then { 12/3/99 - Fix bug with button width not being used }
     FButton.Width:= wwmax(GetSystemMetrics(SM_CXVSCROLL), 15); {4/14/97}
  if (parent<>Nil) or (owner<>nil) then  { 11/17/97 - parent=nil causes runtime error }
     UpdateButtonPosition;
  inherited Loaded;
  DataChange(Self);
end;

function TwwDBCustomLookupCombo.GetSelectedFields: TStrings;
begin
    result:= FGrid.getSelectedFields;
end;

procedure TwwDBCustomLookupCombo.SetSelectedFields(sel : TStrings);
begin
    FGrid.setSelectedFields(sel);
end;

{ Map scrolling to keystrokes, otherwise current highlight doesn't update properly }
procedure TwwDBLookupList.WMVScroll(var Message: TWMVScroll);
  Function Sequencable: boolean;
  begin
     if wwIsClass(Datalink.Dataset, 'TwwTable') then
        result:= wwGetVariable(DataLink.DataSet, 'isSequencable')
     else result:= False;
  end;

begin
  if not visible then exit;

{  key:= 0;}

  if Datalink.Active then
    with Message, DataLink.DataSet, Datalink do
      case ScrollCode of
        SB_LINEUP: MoveBy(-ActiveRecord - 1);
        SB_LINEDOWN: MoveBy(RecordCount - ActiveRecord);
        SB_THUMBPOSITION:
          begin
            if FHiliteRow >= 0 then FHiliteRow := -1;
            inherited;
          end;
        else inherited;
      end;
{
        SB_PAGEUP: key:= VK_PRIOR;
        SB_PAGEDOWN: key:= VK_NEXT;
        SB_THUMBPOSITION:
          begin
            if Sequencable then inherited
            else begin
               case Pos of
                 0: key:= VK_HOME;
                 1: key:= VK_PRIOR;
                 2: Exit;
                 3: key:= VK_NEXT;
                 4: key:= VK_END;
               end;
            end
          end;

        SB_BOTTOM: key:= VK_END;
        SB_TOP: key:= VK_HOME;
      end;

   if key<>0 then KeyDown(key, []);
}
end;


{ TLookupList }

constructor TwwDBLookupList.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FFieldLink := TFieldDataLink.Create;
 
  FFieldLink.Control := Self;
  FFieldLink.OnDataChange := DataChange;
  FFieldLink.OnEditingChange := EditingChange;
  FFieldLink.OnUpdateData := UpdateData;
  FFieldLink.OnActiveChange := FieldLinkActive;

  FTitleOffset := 0;

  FInCellSelect:= False;
  FUpdateFields := False;
  FValue := '';
  FValue2 := '';
  FValue3 := '';
  FDisplayValue := '';
  FLookupField := '';
  FHiliteRow := -1;
  inherited Options := [dgRowSelect,dgRowLinesDisableFixed];
  FixedCols := 0;
  FixedRows := 0;
  Width := 121;
  Height := 97;

  SetLookupSource(TDataSource.create(Self));
{  FSelected:= TStringList.create;}
  LookupFieldCount:= 0;
end;

destructor TwwDBLookupList.Destroy;
begin
  FFieldLink.OnDataChange := nil;
  FFieldLink.Free;
  FFieldLink := nil;
{  FSelected.Free;
  FSelected := Nil;}

  if FNavigatorLink<>nil then
  begin
    FNavigatorLink.OnDataChange := nil;
    FNavigatorLink.Free;
    FNavigatorLink:=nil;
  end;

  inherited Destroy;
end;

function TwwDBLookupList.getSelectedFields: TStrings;
begin
    result:= inherited Selected;
end;

procedure TwwDBLookupList.setSelectedFields(sel : TStrings);
begin
   (inherited Selected).assign(sel);
end;

procedure TwwDBLookupList.CreateWnd;
begin
  inherited CreateWnd;
  DataChange (Self);  {update to current value}
end;

procedure TwwDBLookupList.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (FFieldLink <> nil) and
     (AComponent = DataSource) then
    DataSource := nil;
end;

function TwwDBLookupList.GetDataSource: TDataSource;
begin
  if FFieldLink<>Nil then
     Result := FFieldLink.DataSource
  else Result:= Nil;
end;

procedure TwwDBLookupList.SetDataSource(Value: TDataSource);
begin
  if (Value <> nil) and ((Value = GetLookupSource) or ((Value.DataSet <> nil)
    and (Value.DataSet = DataLink.DataSet))) then
    RaiseException(wwSLookupSourceError);
  FFieldLink.DataSource := Value;
end;

function TwwDBLookupList.GetLookupSource: TDataSource;
begin
  Result := inherited DataSource;
end;

procedure TwwDBLookupList.NewLayout;
begin
  InitFields(True); { Release versin adds this }
  LayoutChanged;
  FValue:= '';
  FValue2:= '';
  FValue3:= '';
  DataChange (Self);
end;

Function TwwDBLookupList.GetLookupTable: TDataSet;
begin
   result:= Nil;
   if (inherited DataSource) = Nil then exit;
   result:= ((inherited DataSource).dataSet);
end;

procedure TwwDBLookupList.SetLookupTable(Value: TDataSet);
begin
   if (GetLookupSource = Nil) then begin
     MessageDlg('Lookup Source is not created', mtinformation, [mbok], 0);
     exit;
   end;

   if ((DataSource<>Nil) and (Value = DataSource.DataSet)) or
      ((Value<>Nil) and (Value = FFieldLink.DataSet)) then
     RaiseException(wwSLookupSourceError);

   if (Value <> nil) and
      not (Value.InheritsFrom(TDataSet)) then
     RaiseException(wwSLookupTableError);

   (inherited DataSource).dataSet:= Value;

   NewLayout;
end;

procedure TwwDBLookupList.SetLookupSource(Value: TDataSource);
begin
  if (Value <> nil) and ((Value = DataSource) or
    ((Value.DataSet <> nil) and (Value.DataSet = FFieldLink.DataSet))) then
     RaiseException(wwSLookupSourceError);
  if (Value <> nil) and (Value.DataSet <> nil) and
      not (Value.DataSet.InheritsFrom(TDataSet)) then
     RaiseException(wwSLookupTableError);
  inherited DataSource := Value;
  NewLayout;
end;

procedure TwwDBLookupList.SetLookupField(const Value: string);
begin
  if Value <> LookupField then
  begin
    FLookupField:= Value;
    NewLayout;
  end;
end;

procedure TwwDBLookupList.SetValue(const Value: string);
var parentForm: TCustomForm;
begin
  parentForm := GetParentForm(self); // 9/28/06
  if (parentForm<>nil) then HandleNeeded;
//  HandleNeeded;  {Added 5/19/96 so initialization of Text property works right away}

  if DataLink.Active and FFieldLink.Active and
      ((DataSource = GetLookupSource) or
      ((DataSource<>Nil) and (DataSource.DataSet = GetLookupSource.DataSet))) then
     RaiseException(wwSLookupSourceError);

  if (FValue <> Value) or (Row = FTitleOffset) then
  begin
    if DataLink.Active and (FValueFld <> nil) then
    begin
      FValue:= Value;
      FHiliteRow := -1;     { to be reset in .HighlightCell }

      {5/28/97 - Optimize of display when displayed field is a lookup or linked field }
      {12/2/97 - Move optimization code before test for FCombo.visible }
      if (inDataChanged>0) and isWWCalculatedField then
      begin
         FDisplayValue:= FCombo.DataSource.DataSet.FieldByName(FCombo.datafield).asstring;
         exit;
      end;

      {Optimize of display and stored field are the same }
      if (FValueFld=FDisplayFld) then begin
         FDisplayValue:= FValue;
         exit;
      end;

      if FCombo.visible or not (parent is TwwCustomDBGrid) then
//         or (IsInwwObjectView(FCombo)) then
      begin
         DoLookup(False);
         if FFoundValue and (FValueFld <> FDisplayFld) then
           FDisplayValue:= FDisplayFld.asString
         else if (FValueFld = FDisplayFld) then
           FDisplayValue:= FValue
         else
            FDisplayValue:= '';
      end
    end;
  end;
end;

procedure TwwDBLookupList.SetDisplayValue(const Value: string);
//var TempFieldValues: variant;
begin
  if (FDisplayValue <> Value) or (Row = FTitleOffset) then
  begin
    FFoundValue := False;
    if DataLink.Active and (FDisplayFld <> nil) then
    begin
      FHiliteRow := -1;     { to be reset in .HighlightCell }
      FFoundValue := False;

      if FCombo.UseSeqSearch then
      begin
          with self as TwwPopupGrid do begin
              FFoundValue:= FCombo.FindRecord(Value, LookupField, mtExactMatch,
                      ssoCaseSensitive in TwwPopupGrid(self).FCombo.SeqSearchOptions)
          end
      end
      else with inherited DataSource.DataSet do
      begin
           if FValueFld2=Nil then begin
              with self as TwwPopupGrid do begin
                 if wwGetControlMasterSource(inherited DataSource.DataSet)<>nil then
//                 if MasterSource<>Nil then
                    FFoundValue:= FCombo.DoFindRecord(Value, LookupField, mtExactMatch) {1/22/97}
                 else begin
                    if wwGetVariable((inherited Datasource.dataset), 'IndexFieldCount')=0 then
//                    if IndexFieldCount=0 then
                       FFoundValue:= FCombo.wwFindRecord(Value, LookupField, mtExactMatch,
                           ssoCaseSensitive in TwwPopupGrid(self).FCombo.SeqSearchOptions)
//                       FFoundValue:= wwFindRecord(Value, LookupField, mtExactMatch,
//                           ssoCaseSensitive in TwwPopupGrid(self).FCombo.SeqSearchOptions)

                    else begin
                    {
                          TempFieldValues:= VarArrayCreate([0, 0], varVariant);
                          TempFieldValues[0]:= Value;
                          FFoundValue:= wwGetVariableWithParams(inherited Datasource.dataset, 'wwFindKey', TempFieldValues);
                     }
                         FFoundValue:= FCombo.wwFindKey([Value]);
                    end;
                 end
              end
           end
           else begin
              if FValueFld3=Nil then begin
                 with self as TwwPopupGrid do begin
                 {
                   TempFieldValues:= VarArrayCreate([0, 1], varVariant);
                   TempFieldValues[0]:= Value;
                   TempFieldValues[1]:= FCombo.SetValue2;
                   FFoundValue:= wwGetVariableWithParams(inherited Datasource.dataset, 'wwFindKey', TempFieldValues);
                   }
                   FFoundValue:= FCombo.wwFindKey([Value, FCombo.SetValue2]);
                 end
              end
              else begin
                 with self as TwwPopupGrid do begin
                 {
                   TempFieldValues:= VarArrayCreate([0, 2], varVariant);
                   TempFieldValues[0]:= Value;
                   TempFieldValues[1]:= FCombo.SetValue2;
                   TempFieldValues[2]:= FCombo.SetValue3;
                   FFoundValue:= wwGetVariableWithParams(inherited Datasource.dataset, 'wwFindKey', TempFieldValues);
                  }
                   FFoundValue:=
                      FCombo.wwFindKey([Value, FCombo.SetValue2, FCombo.SetValue3])
                 end
              end
           end;
      end;

      with TwwPopupGrid(self).FCombo do begin
         inList:= FFoundValue;  { !!!! Added InfoPower 2.0}
         TypedInText:= Text;
         if Value='' then inList:= True;
      end;

      FDisplayValue:= Value;
      if (FValueFld = FDisplayFld) then
        FValue:= FDisplayValue
      else if not FFoundValue then
      begin
        FDisplayValue:= '';
        FValue:= '';
      end
      else
        FValue:= FValueFld.asString;
    end;
  end;
end;

Function TwwDBLookupList.isWWCalculatedField: boolean;
begin
   with TwwPopupGrid(self) do result:= FCombo.isWWCalculatedField;
end;

Procedure TwwDBCustomLookupCombo.ComputeLookupFields;
var tempValue, toLink, tolinks: string;
    pos: integer;
begin
    if DataField='' then exit;

    if FFieldLink.Field=nil then exit;
    if isLookup then begin
       toLinks:= FFieldLink.Field.LookupKeyFields
    end
    else begin
       toLinks:= '';
       TempValue:= wwDataSetGetLinks(DataSource.DataSet, dataField);
       if TempValue='' then exit;

       pos:= 1;
       while True do begin
          strGetToken(TempValue, ';', pos); { Skip }
          toLink:= strGetToken(TempValue, ';', pos);
          if (toLink='') then break;
          if toLinks<>'' then
             toLinks:= toLinks + ';' + toLink
          else toLinks:= toLink;
       end;
    end;

    if (tolinks<>'') then begin
       LookupField:= tolinks;
       FGrid.InitFields(True);
    end

end;

{Function TwwDBLookupList.LTable: TwwTable;
begin
   result:= LookupTable as TwwTable;
end;
}

procedure TwwDBLookupList.DoLookup(SetToDisplayIndex: boolean);
var curTable: TDataSet;
    links: TStrings;
    fpos: integer;
    fromlink, toLink: wwSmallString;
    fromLinks: string;
    toLinks: string;
    tpos: integer;

  Function UnBoundCombo: boolean;
  begin
      with (self as TwwPopupGrid) do begin
         result:=  (FCombo.dataSource=Nil) or (FCombo.dataSource.dataSet=Nil)
      end
  end;

  // 7/9/02 - Support multi-field lookup for TTable and .lookup field
  function MultiFieldLookup: boolean;
  var i: integer;
      TempFieldValues: Variant;
  begin
     TempFieldValues:= VarArrayCreate([0, links.count div 2 -1], varVariant);
     for i:= 1 to links.count div 2 do
       TempFieldValues[i-1]:= curTable.FieldByName(links[i * 2-1]).asString;
     result:= LookupTable.Locate(
          FCombo.FFieldLink.Field.KeyFields, TempFieldValues, []);
  end;

begin

  FFoundValue := False;
  if not HandleAllocated then Exit;
    with (self as TwwPopupGrid) do
      if (not FCombo.visible) and (parent is TwwCustomDBGrid) then exit; {Optimization }

  if wwIsClass(LookupTable, 'TwwTable') then
     wwSetVariable(lookupTable, 'INFINDRECORDCOUNT_INC', null);

  //if (LookupTable is TwwTable) then inc(LTable.InFindRecordCount);

  try with LookupTable do begin
    if isWWCalculatedField then begin
       with self as TwwPopupGrid do begin
          curTable:= (FCombo.dataSource.dataSet);
          if FCombo.isLookup then begin
             links:= TStringlist.create;

             fromLinks:= FCombo.FFieldLink.Field.KeyFields;
             toLinks:= FCombo.FFieldLink.Field.LookupKeyFields;
             fpos:= 1; tpos:= 1;
             while True do begin
                fromLink:= strGetToken(fromlinks, ';', fpos);
                toLink:= strGetToken(tolinks, ';', tpos);
                if (fromLink='') or (toLink='') then break;
                links.add(fromLink );
                links.add(toLink);
             end;

             if (wwIsClass(LookupTable, 'TwwTable') and FCombo.HasMasterSource) then begin
                { 7/30/97 - Remove index switching on detail lookuptable when using a lookupfield }
                FFoundValue:= FCombo.DoFindRecord(curTable.FieldByName(links[links.count-2]).asString,
                    links[links.count-1], mtExactMatch);
             end
             else begin
                if wwIsClass(LookupTable, 'TwwTable') then begin  {7/10/97 - Support Non TwwTable against lookup field }
                   FCombo.UpdateSearchIndex(False);
                   if links.count>=4 then
                      FFoundValue:= MultiFieldLookup
                   else
                      FFoundValue:= FCombo.DoFindRecord(curTable.FieldByName(links[links.count-2]).asString,
                          links[links.count-1], mtExactMatch);
                end
                else begin
                   FFoundValue:= FCombo.FindRecord(curTable.FieldByName(links[links.count-2]).asString,
                    links[links.count-1], mtExactMatch, False);
                end
             end;
             links.free;
          end
          else begin
             { Move lookupTable to match curTable's lookup value }
             if wwIsClass(LookupTable, 'TwwTable') and (not FCombo.HasMasterSource) then
             begin
                wwSetVariable(FCombo.LookupTable, 'inLookupLink', True);
                FFoundValue:= wwDataSetSyncLookupTable(curTable, lookupTable, FCombo.dataField, DummyString);
                wwSetVariable(FCombo.LookupTable, 'inLookupLink', false);
             end
             else begin
                { Sequential search using lookupfield since its the detail table}
                links:= TStringlist.create;
                fpos:= 1;
                fromLinks:= wwDataSetGetLinks(curTable, FCombo.DataField); { From and to links }
                while True do begin
                   fromLink:= strGetToken(fromLinks, ';', fpos);
                   toLink:= strGetToken(fromLinks, ';', fpos);
                   if (fromLink='') or (toLink='') then break;
                   links.add(fromLink);
                   links.add(toLink);
                end;
                if wwIsClass(LookupTable, 'TwwTable') then begin  {7/10/97 - Support Non TwwTable against lookup field }
                   FCombo.UpdateSearchIndex(False);
                   if links.Count>0 then
                     FFoundValue:= FCombo.DoFindRecord(curTable.FieldByName(links[links.count-2]).asString,
                       links[links.count-1], mtExactMatch);
                end
                else begin
                   if links.Count>0 then // 3/16/09 - Make sure do not generate index out of range for calculated fields
                     FFoundValue:= FCombo.FindRecord(curTable.FieldByName(links[links.count-2]).asString,
                       links[links.count-1], mtExactMatch, False);
                end;
                links.free;
             end;
          end;

          { Switch index to left-most column }
          if setToDisplayIndex then  {12/4/96}
             FCombo.UpdateSearchIndex(True);

          if not FFoundValue then begin
             First;
             { Clear so nothing is highlighted }
             FCombo.FGrid.FValue:= '';
             if FCombo.FGrid.FValueFld2<>Nil then
                FCombo.FGrid.FValue2:= '';
             if FCombo.FGrid.FValueFld3<>Nil then
                FCombo.FGrid.FValue3:= '';
             Update;
          end
          else begin
             FCombo.FGrid.FValue:= FCombo.FGrid.FValueFld.asString;
             if FCombo.FGrid.FValueFld2<>Nil then
                FCombo.FGrid.FValue2:= FCombo.FGrid.FValueFld2.asString;
             if FCombo.FGrid.FValueFld3<>Nil then
                FCombo.FGrid.FValue3:= FCombo.FGrid.FValueFld3.asString;
          end
       end
    end
    else begin

      {Switch index to lookupfield being used }
      with self as TwwPopupGrid do
         if Lookupfield<>'' then
         begin
            FCombo.UpdateSearchIndex(False);
         end;

      if State = dsSetKey then Exit;

      if UnBoundCombo then begin

         if FValueFld = DisplayFld then begin
            FValue:= (self as TwwPopupGrid).FCombo.DisplayValue;
            FDisplayValue:= FValue;
         end;

      end;

      FastLookup;
      if not setToDisplayIndex then exit;  { Optimization}

      with TwwPopupGrid(self).FCombo do begin
         inList:= FFoundValue;  { !!!! Added InfoPower 2.0}
         TypedInText:= Text;
         if Value='' then inList:= True;
      end;

      {Switch index to left most column for display purposes}
      with self as TwwPopupGrid do
      begin
         FCombo.UpdateSearchIndex(True);
      end;

      if not FFoundValue then
      begin
         First;
      end
    end;

  end
  finally
    if wwIsClass(LookupTable, 'TwwTable') then
       wwSetVariable(lookupTable, 'INFINDRECORDCOUNT_DEC', null)
//    if (LookupTable is TwwTable) then dec(LTable.InFindRecordCount);
  end;

end;

function TwwDBLookupList.GetLookupField: string;
begin
  Result := FLookupField;
end;

function TwwDBLookupList.GetValue: string;
begin
  Result := FValue;
end;

function TwwDBLookupList.GetValue2: string;
begin
  Result := FValue2;
end;

function TwwDBLookupList.GetValue3: string;
begin
  Result := FValue3;
end;

function TwwDBLookupList.GetDisplayValue: string;
begin
  Result := FDisplayValue;
end;

function TwwDBLookupList.GetDataField: string;
begin
  Result := FFieldLink.FieldName;
end;

procedure TwwDBLookupList.SetDataField(const Value: string);
begin
  FFieldLink.FieldName := Value;
end;

function TwwDBLookupList.GetReadOnly: Boolean;
begin
  Result := FFieldLink.ReadOnly;
end;

function TwwDBLookupList.CanEdit: Boolean;
begin
  Result := (FFieldLink.DataSource = nil) or FFieldLink.Editing
end;

procedure TwwDBLookupList.SetReadOnly(Value: Boolean);
begin
  FFieldLink.ReadOnly := Value;
end;

procedure TwwDBLookupList.DataChange(Sender: TObject);
begin
  if (FFieldLink.Field <> nil) and not (csLoading in ComponentState) then
  begin
    Value := FFieldLink.Field.AsString;
  end
end;

procedure TwwDBLookupList.EditingChange(Sender: TObject);
begin
end;

procedure TwwDBLookupList.UpdateData(Sender: TObject);
begin
  if FFieldLink.Field <> nil then
    FFieldLink.Field.AsString := Value;
end;

procedure TwwDBLookupList.InitFields(showError: boolean);
var thispos: integer;
    links, fromlink, toLink: string;
    APos: integer;
    curPos: integer;
    field1Name, field2Name, field3Name: string;
begin
  FDisplayFld:= nil;
  FValueFld:= nil;
  FValueFld2:= nil;
  FValueFld3:= nil;
  if (not DataLink.active) or(length(LookupField)=0) then exit;

  if (Datalink.Datasource = nil) or (Datalink.Dataset = nil) then Exit;
  with Datalink.DataSet do
  begin
    curPos:= 1;
    field1Name:= strGetToken(lookupField, ';', curpos);
    field2Name:= strGetToken(lookupField, ';', curpos);
    field3Name:= strGetToken(lookupField, ';', curpos);
    FValueFld := FindField(field1Name);
    if (FValueFld=Nil) and ShowError then
    {$ifdef wwDelphi3Up}
      {$ifdef wwDelphi3}
      raise EInvalidOperation.create(Format(SFieldNotFound, ['Error', lookupField]));
      {$else}
      raise EInvalidOperation.create(Format(SFieldNotFound, [lookupField]));
      {$endif}
    {$else}
      raise EInvalidOperation.create(FmtLoadStr(SFieldNotFound, [lookupField]));
    {$endif}
    if field2Name<>'' then FValueFld2 := FindField(field2name);
    if field3Name<>'' then FValueFld3 := FindField(field3name);

    { compute # of lookup fields }
    if FValueFld3<>Nil then LookupFieldCount:= 3
    else if FValueFld2<>Nil then LookupFieldCount:= 2
    else if FValueFld<>Nil then LookupFieldCount:= 1;

    { Set lookup field to match calculated field }
    if isWWCalculatedField then begin
       with self as TwwPopupGrid do begin
          links:= wwDataSetGetLinks(FCombo.dataSource.dataSet, FCombo.dataField);
          if selected.count=0 then
             FDisplayFld:= FindField(wwDataSetGetDisplayField(FCombo.dataSource.dataSet,
                                     FCombo.dataField));
       end;
       APos:= 1;
       fromLink:= strGetToken(links, ';', APos);
       toLink:= strGetToken(links, ';', APos);
       if (fromLink<>'') and (toLink<>'') then begin
          FValueFld:= FindField(toLink);
          fromLink:= strGetToken(links, ';', APos);
          toLink:= strGetToken(links, ';', APos);
          if (fromLink<>'') and (toLink<>'') then begin
             FValueFld2:= FindField(toLink);
             fromLink:= strGetToken(links, ';', APos);
             toLink:= strGetToken(links, ';', APos);
             if (fromLink<>'') and (toLink<>'') then
                FValueFld3:= FindField(toLink);
          end
       end
    end;

    if FValueFld <> nil then
    begin
      { Set DisplayFld to first field }
      if (Selected.count) > 0 then
      begin
        thisPos:= pos(#9, selected[0]);
        if (thisPos>=0) then FDisplayFld:= FindField(copy(selected[0], 1, thisPos-1));
      end;
      if FDisplayFld = nil then begin
         FDisplayFld := FValueFld;
      end
    end;
  end;

  if FCombo.Navigator and (FDisplayFld<>nil) then
  begin
//     FFieldLink.FieldName:= FDisplayFld.FieldName;
//     FFieldLink.DataSource:=GetLookupSource;
     FNavigatorLink.FieldName:= FDisplayFld.FieldName;
     FNavigatorLink.DataSource:= GetLookupSource;
  end;

end;

procedure TwwDBLookupList.DefineFieldMap;
var
  i: integer;
begin
  InitFields(False);
  if FValueFld <> nil then
  begin
     if not useTFields then inherited DefineFieldMap
     else with LookupTable do begin
        if fieldCount = 0 then DataLink.AddMapping(FValueFld.FieldName)
        else begin
           for i:= 0 to fieldCount-1 do begin
              if (fields[i].visible) then begin
                 Datalink.AddMapping (Fields[i].FieldName)
              end;
           end
        end
     end
  end
end;

procedure TwwDBLookupList.SetColumnAttributes;
var
  I: Integer;
  TotalWidth, BorderWidth: Integer;
begin
  inherited SetColumnAttributes;

  if FieldCount > 0 then
  begin
    BorderWidth := 0;
    if loColLines in FOptions then BorderWidth := 1;
    TotalWidth := 0;
    for I := 0 to ColCount -2 do
      TotalWidth := TotalWidth + ColWidths[I] + BorderWidth;
    if (ColCount = 1) or (TotalWidth < (ClientWidth - 15)) then
      ColWidths[ColCount-1] := ClientWidth - TotalWidth;
  end;
end;

procedure TwwDBLookupList.WMSize(var Message: TWMSize);
begin
  if csDestroying in ComponentState then exit;
  if not BeAccurate and not visible then exit;
  inherited;
  SetColumnAttributes;
end;

function TwwDBLookupList.CanGridAcceptKey(Key: Word; Shift: TShiftState): Boolean;
var
  MyOnKeyDown: TKeyEvent;
begin
  Result := True;
  if Key = VK_INSERT then Result := False
  else if Key in [VK_UP, VK_DOWN, VK_NEXT, VK_RIGHT, VK_LEFT, VK_PRIOR,
    VK_HOME, VK_END] then
  begin
    FFieldLink.Edit;
    FCombo.Modified:= True;  { 6/4/97 - Allows GridClick to change text }
    if (Key in [VK_UP, VK_DOWN, VK_RIGHT, VK_LEFT]) and not CanEdit then
      Result := False
    else if (inherited DataSource <> nil) and
        (inherited DataSource.State <> dsInactive) then
    begin
      if (FHiliteRow >= 0) and (FHiliteRow <> DataLink.ActiveRecord) then
      begin
        Row := FTitleOffset + FHiliteRow;
        Datalink.ActiveRecord := FHiliteRow;
      end
      else if (FHiliteRow < 0) then
      begin
        if FFoundValue then
          DoLookup(True)
        else
        begin
          DataLink.DataSource.DataSet.First;
          Row := FTitleOffset;
          Key := 0;
          MyOnKeyDown := OnKeyDown;
          if Assigned(MyOnKeyDown) then MyOnKeyDown(Self, Key, Shift);
          InvalidateRow (FTitleOffset);
          ListClick;
          Result := False;
        end;
      end;
    end;
  end;
end;

procedure TwwDBLookupList.KeyDown(var Key: Word; Shift: TShiftState);
begin
  try
     FInCellSelect := True;
{     LookupTable.DisableControls;}
     inherited KeyDown (Key, Shift);
  finally
    FInCellSelect := False;
  end;

  if (Key in [VK_UP, VK_DOWN, VK_NEXT, VK_PRIOR, VK_HOME, VK_END]) and
      CanEdit then
  begin
    Invalidate;
    ListClick;
  end;
{  LookupTable.enableControls;}
end;


procedure TwwDBLookupList.KeyPress(var Key: Char);
begin
  inherited KeyPress (Key);
  case Key of
    #32..#255:
      DataLink.Edit;
    Char (VK_ESCAPE):
      begin
        FFieldLink.Reset;
        Key := #0;
      end;
  end;
end;

procedure TwwDBLookupList.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
var
  CellHit: TGridCoord;
  MyOnMouseDown: TMouseEvent;
begin
  if not (csDesigning in ComponentState) and CanFocus and TabStop then
  begin
    SetFocus;
    if ValidParentForm(Self).ActiveControl <> Self then
    begin
      MouseCapture := False;
      Exit;
    end;
  end;
  if ssDouble in Shift then
  begin
    DblClick;
    Exit;
  end;
  if (Button = mbLeft) and (DataLink.DataSource <> nil) and
    (FDisplayFld <> nil)  then
  begin
    CellHit := MouseCoord (X, Y);
    if (CellHit.Y >= FTitleOffset) then
    begin
      FFieldLink.Edit;
      FGridState := gsSelecting;
      SetTimer(Handle, 1, 60, nil);
      if (CellHit.Y <> (FHiliteRow + FTitleOffset)) then
      begin
        InvalidateRow (FHiliteRow + FTitleOffset);
        InvalidateRow (CellHit.Y);
      end;
      Row := CellHit.Y;
      Datalink.ActiveRecord := Row - FTitleOffset;
    end;
  end;
  MyOnMouseDown := OnMouseDown;
  if Assigned(MyOnMouseDown) then MyOnMouseDown(Self, Button, Shift, X, Y);
end;

procedure TwwDBLookupList.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited MouseMove (Shift, X, Y);
  if FGridState = gsSelecting then
    if (Row >= FTitleOffset) then Datalink.ActiveRecord := Row - FTitleOffset;
end;

procedure TwwDBLookupList.MouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
var
  OldState: TGridState;
begin
  OldState := FGridState;
  inherited MouseUp(Button, Shift, X, Y);
  if OldState = gsSelecting then
  begin
    if (Row >= FTitleOffset) then Datalink.ActiveRecord := Row - FTitleOffset;
    ListClick;
  end;
end;

procedure TwwDBLookupList.ListClick;
begin
  { 11/12/98 -  Check readonly flag }
  if (CanEdit and not FCombo.ReadOnly) and (FDisplayFld <> nil) then
  begin
    if FFieldLink.Editing then
      FFieldLink.Modified;
    FDisplayValue:= FDisplayFld.asString;
    if (FValueFld <> FDisplayFld)then begin
      FValue:= FValueFld.asString;
      if FValueFld2<>Nil then FValue2:= FValueFld2.AsString;
      if FValueFld3<>Nil then FValue3:=FValueFld3.AsString;

    end
    else begin
      FValue:= FDisplayValue;
      if FValueFld2<>Nil then FValue2:= FValueFld2.AsString;
      if FValueFld3<>Nil then FValue3:= FValueFld3.AsString;
    end
  end;
  if Assigned (FOnListClick) then FOnListClick(Self);
end;

function TwwDBLookupList.HighlightCell(DataCol, DataRow: Integer; const Value: string;
      AState: TGridDrawState): Boolean;
var
  OldActive: Integer;
begin
  Result := False;
  if not DataLink.Active or (FValueFld = nil) then Exit;
  if (CanEdit) and ((FGridState = gsSelecting) or FInCellSelect) then
  begin
    if Row = (DataRow + FTitleOffset) then
    begin
      Result := True;
      FHiliteRow := DataRow;
    end;
  end
  else
  begin
    OldActive := DataLink.ActiveRecord;
    try
      DataLink.ActiveRecord := DataRow;
      if (GetValue = FValueFld.AsString) then begin
         if (FValueFld2<>Nil) then begin
            if (GetValue2 = FValueFld2.asString) then
            begin
              if (FValueFld3=Nil) then begin
                 Result := True;
                 FHiliteRow := DataRow;
              end
              else begin
                 if (GetValue3 = FValueFld3.asString) then begin
                    Result := True;
                    FHiliteRow := DataRow;
                 end
              end
            end
         end
         else begin
           Result := True;
           FHiliteRow := DataRow;
         end
      end;
    finally
      DataLink.ActiveRecord := OldActive;
    end;
  end;
end;

procedure TwwDBLookupList.Paint;
begin
{  FHiliteRow := -1;}
  inherited Paint;
  if Focused and (FHiliteRow <> -1) then
    Canvas.DrawFocusRect(BoxRect(0, FHiliteRow, MaxInt, FHiliteRow));
end;

procedure TwwDBLookupList.Scroll(Distance: Integer);
begin
  if not visible then exit;

  if FHiliteRow >= 0 then
  begin
    FHiliteRow := FHiliteRow - Distance;
    if FHiliteRow >= VisibleRowCount then
      FHiliteRow := -1;
  end;
  inherited Scroll(Distance);
end;

procedure TwwDBLookupList.LinkActive(Value: Boolean);
begin
  inherited LinkActive (Value);
  if DataLink.Active then
  begin
{    if not (GetLookupSource.DataSet.InheritsFrom(TTable)) then
      RaiseException(SLookupTableError);}
//    if not Assigned(FCombo.OnPerformCustomSearch) then
//    (not FCombo.InDropDownEvent) and (not FCombo.InCustomSearch) then
    if (not FCombo.InCustomSearch) and (not FCombo.Navigator) then // 11/13/03 - Don't update for navigator mode then
    begin
      SetValue ('');   {force a data update}
      DataChange(Self);
    end
  end;
end;

procedure TwwDBLookupList.FieldLinkActive(Sender: TObject);
begin
  if FFieldLink.Active and DataLink.Active then
  begin
    DataChange(Self);
  end
end;

procedure TwwDBLookupList.CMEnter(var Message: TCMEnter);
begin
  inherited;
  if FHiliteRow <> -1 then InvalidateRow(FHiliteRow);
end;

procedure TwwDBLookupList.CMExit(var Message: TCMExit);
begin
  try
    FFieldLink.UpdateRecord;
  except
    SetFocus;
    raise;
  end;
  inherited;
  if FHiliteRow <> -1 then InvalidateRow(FHiliteRow);
end;

procedure TwwDBLookupList.SetOptions(Value: TwwDBLookupListOptions);
var
  NewGridOptions: TwwDBGridOptions;
begin
  if FOptions <> Value then
  begin
    FOptions := Value;
    FTitleOffset := 0;
    NewGridOptions := [dgRowSelect, dgRowLinesDisableFixed];
    if loColLines in Value then
      NewGridOptions := NewGridOptions + [dgColLines];
    if loRowLines in Value then
      NewGridOptions := NewGridOptions + [dgRowLines];
    if loTitles in Value then
    begin
      FTitleOffset := 1;
      NewGridOptions := NewGridOptions + [dgTitles];
    end;
    inherited Options := NewGridOptions;

  end;
end;

procedure TwwDBLookupList.Loaded;
begin
  inherited Loaded;
  DataChange(Self);
end;

{ TwwPopupGrid }

constructor TwwPopupGrid.Create(AOwner: TComponent);
begin
  FCombo:= AOwner as TwwDBCustomLookupCombo;

  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csNoDesignVisible, csReplicatable];
  FAcquireFocus := False;
  TabStop := False;
end;

procedure TwwPopupGrid.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do
  begin
    Style := Style or WS_BORDER;
    ExStyle := WS_EX_TOOLWINDOW;
    AddBiDiModeExStyle(ExStyle);  // Support bidi mode
    WindowClass.Style := CS_SAVEBITS;
  end;
end;

procedure TwwPopupGrid.CreateWnd;
begin
  inherited CreateWnd;
  if not (csDesigning in ComponentState) then
    Windows.SetParent(Handle, 0);
  CallWindowProc(DefWndProc, Handle, WM_SETFOCUS, 0, 0);
  FCombo.DataChange (Self);  {update to current value}
end;

procedure TwwPopupGrid.WMLButtonUp(var Message: TWMLButtonUp);
begin
  inherited;
  with Message do
    FCombo.CloseUp(True);
end;

function TwwPopupGrid.CanEdit: Boolean;
begin
  Result := (FCombo.FFieldLink.DataSource = nil) or FCombo.FFieldLink.Editing
    or (FCombo.isWWCalculatedField and
     ((FCombo.datasource.state in [dsEdit, dsInsert]) or (FCombo.dataSource.autoEdit)))

end;

procedure TwwPopupGrid.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  FCombo.EnableEdit; { 10/20/97 - Go through enableedit so flag is set }
{  FCombo.FFieldLink.Edit;}
  inherited MouseDown(Button, Shift, X, Y);
end;

procedure TwwPopupGrid.LinkActive(Value: Boolean);
begin
  if Parent = nil then Exit;   {grid being destroyed}
  inherited LinkActive (Value);

  if DataLink.Active then
  begin
    if FValueFld = nil then InitFields(True);
//    if not Assigned(FCombo.OnPerformCustomSearch) then
//    if (not FCombo.InDropDownEvent) and (not FCombo.InCustomSearch) then
    if (not FCombo.InCustomSearch) and (not FCombo.Navigator) then // 11/13/03 - Don't update for navigator mode then
    begin
      SetValue ('');   {force a data update}
      FCombo.DataChange (Self);
    end
  end;
end;

{ TwwLookupComboButton }

procedure TwwLookupComboButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
begin
  inherited MouseUp (Button, Shift, X, Y);

  TwwDBCustomLookupCombo(parent.parent).InvalidateTransparentButton;
end;

procedure TwwLookupComboButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
var dropDownListVisible: boolean;
    parentForm: TCustomForm;
begin
  with TwwDBCustomLookupCombo(Parent.Parent) do
  begin
    dropDownListVisible:= FGrid.visible;

    if not FGrid.Visible then
    begin
      if (Handle <> GetFocus) and CanFocus then
      begin
        SetFocus;
        // 6/16/01 - Fix problem when using WebBrowse and it has text selected
        // 6/29/02 - Don't reset focus or onenter/onexits can fire more than once
//        if Handle<>GetFocus then
//           windows.SetFocus(Handle);

        { 3/14/00 - MDI forms should check ActiveControl instead of focused}
        parentForm:= GetParentForm(FGrid.FCombo);
        if (parentForm<>nil) and
           (TForm(parentForm).formstyle = fsMDIChild) then
        begin
           if (GetFocus <> Handle) and
              (parentForm.ActiveControl<>FGrid.FCombo) then exit;
        end
        else if (GetFocus <> Handle) then Exit;
      end;
    end;
  end;
  inherited MouseDown (Button, Shift, X, Y);

  if not wwIsTransparentParent(Parent.Parent) then
     Update;  { 4/17/98 - Finish drawing down state }

  TwwDBCustomLookupCombo(parent.parent).InvalidateTransparentButton;

  with TwwDBCustomLookupCombo(Parent.Parent) do
  begin
    if not dropDownListVisible and FGrid.Visible then exit; {skip remaining code }

    if FGrid.Visible then begin
      if InList then GridClick(self);  {Now hiding drop down so select current selection } {5/14/97 - if InList}
      CloseUp(True)
    end
    else
    begin
      DropDown;
    end;
  end;

end;

procedure TwwLookupComboButton.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited MouseMove (Shift, X, Y);
  if (ssLeft in Shift) and (GetCapture = Parent.Handle) then
    MouseDragToGrid (Self, TwwDBCustomLookupCombo(Parent.Parent).FGrid, X, Y);
end;

function TwwLookupComboButton.IsVistaTransparentButton: boolean;
var combo: TwwDBCustomLookupCombo;
begin
   combo:= TwwDBCustomLookupCombo(parent.parent);
   if wwUseThemes(self) and IsVista and
     ((not IsVistaComboNonEditable) {or (IsVistaComboNonEditable and combo.Grid.Visible)} ) and
      not (combo.Frame.Enabled and combo.Frame.Transparent) then
      result:= true
   else
      result:=false;
end;

function TwwLookupComboButton.IsVistaComboNonEditable: boolean;
begin
   result:= TwwDBCustomLookupCombo(parent.parent).IsVistaComboNonEditable;
end;

function TwwLookupComboButton.ParentMouseInControl: boolean;
begin
   result:= TwwDBCustomLookupCombo(parent.parent).MouseInControl;
end;

function TwwLookupComboButton.ParentDroppedDown: boolean;
begin
   result:= TwwDBCustomLookupCombo(parent.parent).Grid.Visible;
end;



function TwwDBCustomLookupCombo.IsVistaComboNonEditable: boolean;
begin
  result:= wwUseThemes(self) and IsVista and
            ((FStyle = csDropDownList) and not AutoDropDown);
//          not Editable;
end;

Procedure TwwDBCustomLookupCombo.DrawButton(Canvas: TCanvas; R: TRect;
          State: TButtonState; ControlState: TControlState; var DefaultPaint: boolean);
var Transparent: boolean;
begin
  if ButtonStyle=cbsCustom then exit;

  DefaultPaint:= False;
  Transparent:=  FButton.Flat and
      (not FMouseInButtonControl) and not (FFocused);
  if ButtonStyle=cbsDownArrow then
     wwDrawDropDownArrow(Canvas, R, State, Enabled, ControlState)
  else
      wwDrawEllipsis(Canvas, R, State, Enabled, Transparent,
         ButtonEffects.Transparent {and ButtonEffects.Flat},
         ControlState)
end;

procedure TwwLookupComboButton.paint;
var R : TRect;
    DefaultPaint: boolean;
begin
   { 7/2/99 }
   if twwdbCustomLookupCombo(parent.parent).SkipUpdate then exit;
   if (csPaintCopy in ControlState) and
      not (csDesigning in ComponentState) and IsInGrid(parent.parent) then exit;
   SetRect(R, 0, 0, ClientWidth, ClientHeight);
   with TwwDBCustomLookupCombo(Parent.Parent) do
   begin
      DefaultPaint:= True;
      FMouseInButtonControl:= self.MouseInControl;
      if (FButton.Glyph.Handle=0) or self.MouseInControl or
         FFocused or wwisClass(Parent.classType, 'TwwDBGrid') then
          if not (ButtonEffects.Transparent and (ButtonStyle=cbsDownArrow)) then
            if not wwUseThemes(self.parent.parent) then
            begin
               DrawButton(Canvas, R, FState, ControlState, DefaultPaint);
            end;

      if DefaultPaint then begin
         Ellipsis:= ButtonStyle = cbsEllipsis;
         inherited Paint;
      end;

      { Draw edges  }
      if self.MouseInControl or (not ButtonEffects.Flat) or
         FFocused or wwisClass(Parent.classType, 'TwwDBGrid') then
      begin
         if not wwUseThemes(self.parent.parent) then
         begin
           if FState=bsDown then
              DrawEdge(Canvas.Handle, R, EDGE_SUNKEN, BF_RECT)
           else
              DrawEdge(Canvas.Handle, R, EDGE_RAISED, BF_RECT)
         end
      end
   end
end;

{ Win95 Addition to support TGridRecord }
procedure TwwDBCustomLookupCombo.CMGetDataLink(var Message: TMessage);
begin
  Message.Result := Integer(FFieldLink);
end;

Procedure TwwDBCustomLookupCombo.SetModified(val: boolean);
begin
   Modified:= val;
end;

Function TwwDBCustomLookupCombo.isValidChar(key: word): boolean;
begin
   result:= (key = VK_BACK) or (key=VK_SPACE) or (key=VK_DELETE) or
            ((key >= ord('0')) and (key<=VK_DIVIDE)) or
            (key>VK_SCROLL); { Support international characters }
end;

{ Prevent tab from exiting if processing AutoDropDown character }
procedure TwwDBCustomLookupCombo.WMChar(var Msg: TWMChar);
begin
   if isValidChar(Msg.charcode) and FAutoDropDown and (not FGrid.visible) and
      (Parent is TwwCustomDBGrid) then
      InAutoDropDown:= True;
   inherited;
end;

Procedure TwwDBCustomLookupCombo.SetPreciseEditRegion(val: boolean);
begin
   if (val<>FPreciseEditRegion) then begin
     FPreciseEditRegion:= val;
     RecreateWnd;
   end
end;


Function TwwDBCustomLookupCombo.IsLookupDlg: boolean;
begin
   result:= False;
end;

Function TwwDBCustomLookupCombo.IsLookupRequired: boolean;
begin
   result:= False;
   with FGrid do begin
      if (FValueFld.asString <> LookupValue) then result:= True;
      if (FValueFld2<>Nil) and (FValueFld2.asString <> FValue) then result:= True;
      if (FValueFld3<>Nil) and (FValueFld3.asString <> FValue) then result:= True;
   end
end;

Function TwwDBCustomLookupCombo.DoFindRecord(ASearchValue, ASearchField: string;
   matchType: TwwLocateMatchType): boolean;
var searchIndex: integer;
    doSeqSearch: boolean;
//    TempFieldValues: Variant;
//    table: TTable;
begin
//   table:= LookupTable as TTable;
   doSeqSearch:= False;
   if HasMasterSource then begin
      if wwGetVariable(LookupTable, 'masterFields')=null then // 4/3/09
         doSeqSearch:=true
      else begin
        searchIndex:= strCount(wwGetVariable(LookupTable, 'masterFields'), ';')+1;
        if searchIndex >= wwGetVariable(LookupTable, 'indexFieldCount') then
           doSeqSearch:= True { Changed > to >=, 3/27/97}
        else if not wwEqualStr(IndexFields(searchIndex).fieldName,ASearchField) then
           doSeqSearch:= True;
      end
   end;

   if (matchType=mtExactMatch) and
      wwEqualStr(ASearchValue, LookupTable.FieldByName(ASearchField).asString) then
      result:= True    {6/10/97 - Optimization}
   else if doSeqSearch then
      result:= wwFindRecord(ASearchValue, ASearchField, matchType,
            ssoCaseSensitive in SeqSearchOptions)
   else if HasMasterSource then
   begin
      result:= wwFindNearest(ASearchValue,
         strCount(wwGetVariable(LookupTable, 'masterFields'), ';')+1);
   end
   else begin
      searchIndex:= GetSearchIndex;
      if searchIndex>=0 then
      begin
         result:= wwFindNearest(ASearchValue, searchIndex)
      end
      else
         result:= FindRecord(ASearchValue, ASearchField, matchType,
            ssoCaseSensitive in SeqSearchOptions)
   end
end;

procedure TwwDBLookupList.DataChanged;
begin
   inherited DataChanged;
   if FCombo.HasMasterSource and (wwGetVariable(FCombo.LookupTable, 'MASTERFIELDS')<>'') and
      (LookupTable.state=dsBrowse) and
      (FCombo.FFieldLink.Field <> nil) and not (csLoading in ComponentState) then
   begin
      if not wwIsClass(lookupTable, 'TwwTable') then exit; // 4/7/09
      {
      if not wwIsClass(lookupTable, 'TwwTable') then begin
         MessageDlg('LookupTable on a detail table is only supported when using a TwwTable as the LookupTable!',
                    mtWarning, [mbok], 0);
         exit;
      end;
      }
      if (wwGetVariable(LookupTable, 'inFindRecordCount')>0) then exit;
      if inDataChanged>0 then exit;

      inc(inDataChanged);
      try
         FValue:= '';    { Forces lookup to be performed }
         FCombo.DataChange(FCombo);
      finally
         dec(inDataChanged);
      end;

   end

end;

procedure TwwDBLookupList.DrawCell(ACol, ARow: Longint;
   ARect: TRect;  AState: TGridDrawState);
begin
   { Make cells 3D style }
   inherited;
//   Draw3DLines(ARect, ACol, ARow, AState);
end;

{$ifdef wwdelphi4up}
function TwwDBCustomLookupCombo.ExecuteAction(Action: TBasicAction): Boolean;
begin
  Result := inherited ExecuteAction(Action) or (FFieldLink <> nil) and
    FFieldLink.ExecuteAction(Action);
end;

function TwwDBCustomLookupCombo.UpdateAction(Action: TBasicAction): Boolean;
begin
  Result := inherited UpdateAction(Action) or (FFieldLink <> nil) and
    FFieldLink.UpdateAction(Action);
end;
{$endif}

Function TwwDBCustomLookupCombo.GetControlType: TStrings;
begin
   result:= Grid.controltype;
end;

Procedure TwwDBCustomLookupCombo.SetControlType(val: TStrings);
begin
   Grid.controltype.assign(val);
end;

procedure TwwDBCustomLookupCombo.WMEraseBkgnd(var Message: TWmEraseBkgnd);
//var r: TRect;
begin
  if IsInwwObjectViewPaint(self) or   IsVistaComboNonEditable or
    (IsTransparentEffective and not FFocused) then
  begin
     Message.result:= 1;
  end
{  else if false and StyleServices.ThemesEnabled and
      (parent is TCustomGrid) then
  begin
     r:= ClientRect;
     if FCanvas<>nil then
        Windows.FillRect(message.dc, r, FCanvas.brush.handle );
     message.result:=1
  end  }
  else
     inherited;
end;
{
procedure TwwDBCustomLookupCombo.SetFlatButton(val: boolean);
begin
   if FFlatButton<>val then
   begin
      FFlatButton:= val;
      FButton.Flat:= FFlatButton or FFlatButtonTransparent;
      FButton.Glyph.Handle:= LoadComboGlyph;
      FButton.Invalidate;
   end;
end;

procedure TwwDBCustomLookupCombo.SetFlatButtonTransparent(val: boolean);
begin
   if FFlatButtonTransparent<>val then
   begin
      FFlatButtonTransparent:= val;
      FButton.Flat:= FFlatButton or FFlatButtonTransparent;
      FButton.Glyph.Handle:= LoadComboGlyph;
      FButton.Invalidate;
   end;
end;

function TwwDBCustomLookupCombo.GetFlatButton: boolean;
begin
   result:= FFlatButton;
end;


{procedure TwwDBCustomLookupCombo.SetFlatButton(val: boolean);
begin
   if FButton.Flat<>val then
   begin
      FButton.Flat:= val;
      FButton.Glyph.Handle:= LoadComboGlyph;
      FButton.Invalidate;
   end;
end;


function TwwDBCustomLookupCombo.GetFlatButton: boolean;
begin
   result:= FButton.Flat;
end;
}

{procedure TwwDBCustomLookupCombo.GetEditRectForFrame(var Loc: TRect);
begin
     if (Frame.FocusStyle = efsFrameBox) then
     begin
        Loc.Top := 2;
        Loc.Left := 2;
     end
     else if is3DBorder then
     begin
        Loc.Top := 3;
        if Frame.FocusStyle in [efsFrameSunken, efsFrameBump] then
           Loc.Left := 3
        else Loc.Left:= 2;
        Loc.Right:= Loc.Right -2
     end
     else begin
        Loc.Top:= 1;
        Loc.Left:= 1;
     end
end;
}
function TwwDBCustomLookupCombo.Is3DBorder: boolean;
begin
//   result:=
//     Frame.FocusStyle in [efsFrameSunken, efsFrameRaised, efsFrameEtched, efsFrameBump]
   result:= true;
end;

procedure TwwDBCustomLookupCombo.DrawFrame(Canvas: TCanvas);
begin
    wwDrawEdge(self, Frame, Canvas, FFocused);
end;

function TwwDBCustomLookupCombo.isTransparentEffective: boolean;
begin
   result:= Frame.Transparent and Frame.IsFrameEffective and
            not wwIsDesigning(self)
end;

{
procedure TwwDBCustomLookupCombo.SetTransparent(val: boolean);
begin
   if val<>FTransparent then
   begin
     FCreateTransparent:= val;
     FTransparent:= val;
   end
end;
}

procedure TwwDBCustomLookupCombo.CMTextChanged(var Message: TMessage);
begin
  if IsTransparentEffective and (not FFocused) then
     Frame.RefreshTransparentText;

  inherited;
end;


function TwwDBCustomLookupCombo.GetEffectiveAlignment: TAlignment;
begin
//   if FFieldLink.Field=nil then result:= FUnboundAlignment
//   else begin
//      result:= FFieldLink.Field.Alignment;
      if FGrid.DisplayFld<>nil then
        result:= FGrid.DisplayFld.Alignment
      else result:= taLeftJustify
//   end
end;

{procedure TwwDBCustomLookupCombo.BtnMouseDown(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
//var r: TRect;
begin
   exit;
   if ButtonFlat and ButtonTransparent then begin
     with FBtnControl do begin
         r:= Rect(parent.left + Left, parent.Top+top,
                 parent.left + left+ Width, parent.top + Top + Height);
         InvalidateRect(parent.parent.handle, @r, True);
         parent.parent.Update;
     end
   end;
end;
}
procedure TwwDBCustomLookupCombo.InvalidateTransparentButton;
var r: TRect;
begin
   if ButtonEffects.Flat or ButtonEffects.Transparent then begin
     with FBtnControl do begin
         r:= Rect(parent.left + Left, parent.Top+top,
               parent.left + left+ Width, parent.top + Top + Height);
        { Calling with True causes flicker for any control that is invalidated.
          Test with False to see if any side effects  }
         InvalidateRect(parent.parent.handle, @r, False);
      end
   end;
   FButton.invalidate;
end;

procedure TwwDBCustomLookupCombo.DoMouseEnter;
begin
  try
    if Assigned(FOnMouseEnter) then FOnMouseEnter(self);
  except
    exit;
  end;
  if Frame.IsFrameEffective and (not FFocused) and
     Frame.MouseEnterSameAsFocus then
     wwDrawEdge(self, Frame, ControlCanvas, True)
  else begin
     FMouseInControl:=true;
     if IsVistaComboNonEditable then
        invalidate;
  end;
end;

procedure TwwDBCustomLookupCombo.DoMouseLeave;
var    oldtext:string;
begin
  try
     if Assigned(FOnMouseLeave) then FOnMouseLeave(self);
  except
     exit;
  end;

  if Frame.IsFrameEffective and (not FFocused) and
     Frame.MouseEnterSameAsFocus then begin
     wwDrawEdge(self, Frame, ControlCanvas, False);
     if IsTransparentEffective then
        Frame.CreateTransparent:= True;
     OldText:= Text;  { Text is cleared when recreating window }
     RecreateWnd;
     Text:= OldText;
     SetEditRect;
  end
  else begin
     FMouseInControl:= false;
     if IsVistaComboNonEditable then
        invalidate;
  end;
end;

procedure TwwDBCustomLookupCombo.CMMouseEnter(var Message: TMessage);
begin
  inherited;
  DoMouseEnter;
end;

procedure TwwDBCustomLookupCombo.CMMouseLeave(var Message: TMessage);
var r:TRect;
   pt:TPoint;
//   oldtext:string;
begin
  GetCursorPos(pt);
  pt := ScreenToClient(pt);
  r := ClientRect;
  if (PtInRect(r,pt)) then exit;

  inherited;
  DoMouseLeave;
end;

procedure TwwDBCustomLookupCombo.PerformCustomSearch(
   SearchField: string; SearchValue: string;
   PerformLookup: boolean; var Found: boolean);
begin
   if Assigned(FOnPerformCustomSearch) then
      FOnPerformCustomSearch(self, LookupTable,
          SearchField, SearchValue, PerformLookup, Found);
end;

procedure Register;
begin
{  RegisterComponents('InfoPower', [TwwDBCustomLookupCombo]);
  RegisterComponents('InfoPower', [TwwDBLookupList]);
}
end;


// 11/9/01 - Some fonts change the margin, so let us reset back to 0 so that
// borders will be ok
procedure TwwDBCustomLookupCombo.WMSetFont(var Message: TWMSetFont);
begin
  inherited;
  if Frame.Enabled and NewStyleControls then
     SendMessage(Handle, EM_SETMARGINS, EC_LEFTMARGIN or EC_RIGHTMARGIN, 0);
end;

// 3/12/02 - Support mousewheel
function TwwDBCustomLookupCombo.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean;
var key: word;
begin
  result := False;
  if not FGrid.Visible then exit;
  key:= vk_down;
  if (GetLookupSource <> nil) and (GetLookupSource.DataSet <> nil) then
     if (GetLookupSource.DataSet.Active) then
     begin
         EnableEdit;
         FGrid.KeyDown (key, Shift);
     end;
  result := True;
end;

function TwwDBCustomLookupCombo.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean;
var key: word;
begin
  result := False;
  if not FGrid.Visible then exit;
  key:= vk_up;

  if (GetLookupSource <> nil) and (GetLookupSource.DataSet <> nil) then
     if (GetLookupSource.DataSet.Active) then
     begin
         EnableEdit;
         FGrid.KeyDown (key, Shift);
     end;
  result := True;
end;

Procedure TwwDBCustomLookupCombo.SetNavigator(Value: boolean);
begin
  if Navigator <> Value then
  begin
     FNavigator:=Value;
     if Value then with FGrid do begin
       if FNavigatorLink=nil then  // 4/9/03 - Always initiailze
       begin
          FNavigatorLink:= TFieldDataLink.Create;
          FNavigatorLink.Control:= FCombo;
       end;
       FNavigatorLink.OnDataChange := NavigatorDataChange;
       if (FDisplayFld<>nil) then
       begin
         FNavigatorLink.FieldName:= FDisplayFld.FieldName;
         FNavigatorLink.DataSource:= GetLookupSource;
       end
     end
     else begin
        FGrid.FNavigatorLink.OnDataChange:=nil;
     end
  end
end;

procedure TwwDBLookupList.NavigatorDataChange(Sender: TObject);
begin
  if not (csLoading in ComponentState) and FCombo.Navigator and
     (FDisplayFld<>nil) and (FDisplayFld.DataSet<>nil) then    // 6/10/03 - Don't execute code if no associated dataset (other gpf)
  begin
     FCombo.text:= FDisplayFld.DisplayText;
     FCombo.FGrid.Value:= FValueFld.asString;
     FCombo.SelectAll;
  end
end;


{$ifndef GRIDESSENTIALS}
procedure TwwDBCustomLookupCombo.SetController(Value: TwwController);
begin
   if wwGridEssentials then
   begin
       DisplayProfessionalVersionOnlyMessage(self, 'TwwDBEdit Controller Property only supported in professional version');
   end;
   
   if FController<>Value then
   begin
      wwUpdateController(TComponent(FController), Value, self);
      if FController<>nil then
      begin
         FFrame.Assign(FController.Frame);
         if HandleAllocated then RecreateWnd;
      end
   end
end;
{$endif}

class constructor TwwPopupGrid.Create;
begin
  TCustomStyleEngine.RegisterStyleHook(TwwPopupGrid, TwwDBGridStyleHook);
end;

end.

