fctreecombo.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:48k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit fctreecombo;
  2. {
  3. //
  4. // Components : TfcTreeCombo
  5. //
  6. // Copyright (c) 2001 by Woll2Woll Software
  7. // 4/10/99 - PYW - When closed up ignore visible when getting the new node.
  8. // 7/24/99 - Publish Color and Text property for Delphi 4 and later
  9. // 11/17/99 - Clear selected so you can type in things not in the list when it is dropped down
  10. // 3/7/00 - Use clGrayText for disabled color
  11. // 7/31/00 - Makes sure modified is set in combo's change
  12. // 7/1/2001- Added mapping capabilites using new StoreDataUsing property.
  13. // 10/1/2001- Exposed OnMouseEnter and OnMouseLeave to be consistent with InfoPower.
  14. // 10/1/2001- Exposed PopupMenu property and OnContextPopup event.
  15. // 11/7/2001- Added method for requested capability to set the SelectedNode programmatically.
  16. // 3/1/2002-Added new function to handle painting in a TDBCtrlGrid
  17. // 3/15/2002 - Don't get new text if user hit Return/Enter key as this messes up Storedatausing path.
  18. // 3/18/2002 - Respect mapped value when framing enabled.
  19. }
  20. interface
  21. {$i fcIfDef.pas}
  22. uses
  23.   Forms, Graphics, Menus, SysUtils, Windows, Messages, Classes,
  24.   Controls, Buttons, fcCommon, fcCombo, fcTreeView, ExtCtrls, Dialogs, Grids,
  25.   db
  26.   {$ifdef fcDelphi4Up}
  27.   , ImgList
  28.   {$endif};
  29. const FCPOPUPTIMERID = 1000;
  30.       FCPOPUPINTERVAL = 50;
  31. type
  32.   TfcPopupPanel = class(TPanel)
  33.   protected
  34.     procedure CreateParams(var Params: TCreateParams); override;
  35.   public
  36.     constructor Create(AOwner: TComponent); override;
  37.   end;
  38.   TfcCustomTreeCombo = class;
  39.   TfcTreeComboTreeNode = class(TfcTreeNode)
  40.   private
  41.     FSelectable: Boolean;
  42.   protected
  43.     procedure ReadData(Stream: TStream; Info: PfcNodeInfo); override;
  44.     procedure WriteData(Stream: TStream; Info: PfcNodeInfo); override;
  45.     Function GetSizeOfNodeInfo: integer; override;
  46.   public
  47.     constructor Create(AOwner: TfcTreeNodes); override;
  48.   published
  49.     property Selectable: Boolean read FSelectable write FSelectable;
  50.   end;
  51.   TfcPopupTreeView = class(TfcTreeView)
  52.   private
  53.     FLastPoint: TPoint;
  54.     FTimerOn: Boolean;
  55.     FCheckChange: Boolean;
  56.     FTreeCombo: TfcCustomTreeCombo;
  57.     FCloseOnUp: Boolean;
  58.     FClickedInControl: Boolean;
  59.     procedure WMMouseActivate(var Message: TMessage); message WM_MOUSEACTIVATE;
  60.     procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
  61.     procedure WMTimer(var Message: TWMTimer); message WM_TIMER;
  62.   protected
  63.     procedure CalcNodeAttributes(Node: TfcTreeNode; AItemState: TfcItemStates); override;
  64.     procedure Change(Node: TfcTreeNode); override;
  65.     procedure KillTimer; virtual;
  66.     procedure SetTimer; virtual;
  67.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  68.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  69.     procedure WndProc(var Message: TMessage); override;
  70.     procedure Collapse(Node: TfcTreeNode); override;
  71.     property TreeCombo: TfcCustomTreeCombo read FTreeCombo;
  72.   public
  73.     constructor Create(AOwner: TComponent); override;
  74.     function ValidNode(Node: TfcTreeNode): Boolean;
  75.     function MovePage(Node: TfcTreeNode; Down: Boolean): TfcTreeNode;
  76.     function GetLastVisible: TfcTreeNode;
  77.     function GetLastNode: TfcTreeNode;
  78.     function SelectValidNode(StartingNode: TfcTreeNode; SelectedNode: TfcTreeNode; Key: Word): Boolean;
  79.     property Items;
  80.   end;
  81.   TfcImgComboOption = (icoExpanded, icoEndNodesOnly);
  82.   TfcImgComboOptions = set of TfcImgComboOption;
  83.   TfcCheckValidItemEvent = procedure(Sender: TObject; Node: TfcTreeNode; var Accept: Boolean) of object;
  84.   TfcCustomTreeCombo = class(TfcCustomCombo)
  85.   private
  86.     // Property Storage Variables
  87. //    FAlignmentVertical: TfcAlignVertical;
  88.     FOriginalNode: TfcTreeNode;
  89.     FOriginalText: String;
  90.     FSelectedNode: TfcTreeNode;
  91.     FPanel: TfcPopupPanel;
  92.     FShowMatchText: Boolean;
  93.     FOptions: TfcImgComboOptions;
  94.     FTreeView: TfcPopupTreeView;
  95.     FDropDownWidth: integer;
  96.     FOnCheckValidItem: TfcCheckValidItemEvent;
  97.     FOnSelectionChange: TNotifyEvent;
  98.     FItemsList: TStringList;
  99.     LastItemIndex: integer;
  100.     LastItemText: string;
  101.     SetModifiedInChangeEvent: boolean;
  102.     FStoreDataUsing: TwwStoreData;
  103.     function GetCalcNodeAttributes: TfcCalcNodeAttributesEvent;
  104.     function GetImageList: TCustomImageList;
  105.     function GetStateImageList: TCustomImageList;
  106.     function GetItems: TfcTreeNodes;
  107.     function GetSorted: Boolean;
  108.     function GetTreeOptions: TfcTreeViewOptions;
  109. //    procedure SetAlignmentVertical(Value: TfcAlignVertical);
  110.     procedure SetCalcNodeAttributes(Value: TfcCalcNodeAttributesEvent);
  111.     procedure SetItems(Value: TfcTreeNodes);
  112.     procedure SetImageList(Value: TCustomImageList);
  113.     procedure SetStateImageList(Value: TCustomImageList);
  114.     procedure SetSorted(Value: Boolean);
  115.     procedure SetTreeOptions(Value: TfcTreeViewOptions);
  116.     // Message Handlers
  117.     procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  118.     procedure InvalidateImage;
  119.     function CalcImageRect(Rect: TRect): TRect;
  120.   protected
  121.     // Virtual Methods
  122.     function CreatePopupTreeView: TfcPopupTreeView; virtual;
  123.     function GetStartingNode: TfcTreeNode; virtual;
  124.     procedure Change; override;
  125.     procedure ItemsChange(TreeView: TfcCustomTreeView; Node: TfcTreeNode;
  126.       Action: TfcItemChangeAction; NewValue: Variant); virtual;
  127.     procedure PaintToCanvas(Canvas: TCanvas; Rect: TRect; Highlight, GridPaint: Boolean;
  128.       Text: string); override;
  129.     procedure ResyncTreeSelected(LookupText: string); virtual;
  130.     procedure SelectionChange; virtual;
  131.     procedure SelectionChanging; virtual;
  132.     procedure DataChange(Sender: TObject); override;
  133.     procedure UpdateData(Sender: TObject); override;
  134.     // Overridden Methods
  135.     function GetDropDownControl: TWinControl; override;
  136.     function GetDropDownContainer: TWinControl; override;
  137.     function GetItemCount: Integer; override;
  138.     function GetItemSize: TSize; override;
  139.     function GetLeftIndent: Integer; override;
  140.     function GetEditRect: TRect; override;
  141.     procedure CreateWnd; override;
  142.     procedure KeyUp(var Key: WORD; Shift: TShiftState); override;
  143.     procedure KeyDown(var Key: WORD; Shift: TShiftState); override;
  144.     procedure KeyPress(var Key: Char); override;
  145.     procedure Loaded; override;
  146.     procedure Paint; override;
  147.     procedure WndProc(var Message: TMessage); override;
  148.     Function Editable: boolean; override;
  149.     procedure HideCaret; override;
  150.     property ItemsList: TStringList read FItemsList;
  151.   public
  152.     BasePatch: Variant;
  153.     constructor Create(AOwner: TComponent); override;
  154.     destructor Destroy; override;
  155.     function IsValidNode(Node: TfcTreeNode): Boolean; virtual;
  156.     procedure CloseUp(Accept: Boolean); override;
  157.     procedure DrawInGridCell(ACanvas: TCanvas; Rect: TRect;
  158.       State: TGridDrawState); override;
  159.     procedure DropDown; override;
  160.     function IsDroppedDown: Boolean; override;
  161.     procedure SetSelectedNode(Node:TfcTreeNode); virtual;
  162.     property DropDownWidth : integer read FDropDownWidth write FDropDownWidth default 0;
  163.     property Sorted: Boolean read GetSorted write SetSorted;
  164.     property TreeView: TfcPopupTreeView read FTreeView;
  165.     property Images: TCustomImageList read GetImageList write SetImageList;
  166.     property StateImages: TCustomImageList read GetStateImageList write SetStateImageList;
  167.     property Items: TfcTreeNodes read GetItems write SetItems;
  168.     property Options: TfcImgComboOptions read FOptions write FOptions;
  169.     property SelectedNode: TfcTreeNode read FSelectedNode;
  170.     property ShowMatchText: Boolean read FShowMatchText write FShowMatchText;
  171.     property TreeOptions: TfcTreeViewOptions read GetTreeOptions write SetTreeOptions default
  172.         [tvoShowButtons, tvoShowRoot, tvoShowLines, tvoHideSelection, tvoToolTips];
  173.     property StoreDataUsing: TwwStoreData read FStoreDataUsing write FStoreDataUsing default sdStoreText;
  174.     property OnCheckValidItem: TfcCheckValidItemEvent read FOnCheckValidItem write FOnCheckValidItem;
  175.     property OnCalcNodeAttributes: TfcCalcNodeAttributesEvent read GetCalcNodeAttributes write SetCalcNodeAttributes;
  176.     property OnSelectionChange: TNotifyEvent read FOnSelectionChange write FOnSelectionChange;
  177.   end;
  178.   TfcTreeCombo = class(TfcCustomTreeCombo)
  179.   published
  180.     property Controller;
  181.     property DisableThemes;
  182.     property AlignmentVertical;
  183.     {$ifdef fcDelphi4Up}
  184.     property Anchors;
  185.     property Constraints;
  186.     {$endif}
  187.     property AllowClearKey;
  188.     property AutoSelect;
  189.     property AutoSize;
  190.     property BorderStyle;
  191.     property ButtonStyle;
  192.     property ButtonEffects;
  193.     property ButtonGlyph;
  194.     property ButtonWidth;
  195.     property CharCase;
  196.     {$ifdef fcDelphi4Up}
  197.     property Color;
  198.     property Text;
  199.     {$endif}
  200.     property Frame;
  201.     property DataField;
  202.     property DataSource;
  203.     property DropDownCount;
  204.     property DropDownWidth;
  205.     property Enabled;
  206.     property Font;
  207.     property HideSelection;
  208.     property Images;
  209.     property InfoPower;
  210.     property MaxLength;
  211.     property Items;
  212.     property Options;
  213.     property PopupMenu;
  214.     property ReadOnly;
  215.     property ShowButton;
  216.     property ShowHint;
  217.     property ShowMatchText;
  218.     property Sorted;
  219.     property StateImages;
  220.     property StoreDataUsing;
  221.     property Style;
  222.     property TabOrder;
  223.     property TreeOptions;
  224.     property Visible;
  225.     property OnCalcNodeAttributes;
  226.     property OnClick;
  227.     property OnChange;
  228.     property OnCheckValidItem;
  229.     property OnCloseUp;
  230.     {$ifdef fcDelphi5Up}
  231.     property OnContextPopup;
  232.     {$endif}
  233.     property OnDblClick;
  234.     property OnDragDrop;
  235.     property OnDragOver;
  236.     property OnDropDown;
  237.     property OnAfterDropDown;
  238.     {$ifdef fcDelphi4up}
  239.     property OnEndDock;
  240.     property OnStartDock;
  241.     {$endif}
  242.     property OnEndDrag;
  243.     property OnEnter;
  244.     property OnExit;
  245.     property OnKeyDown;
  246.     property OnKeyPress;
  247.     property OnKeyUp;
  248.     property OnMouseEnter;
  249.     property OnMouseLeave;
  250.     property OnMouseDown;
  251.     property OnMouseMove;
  252.     property OnMouseUp;
  253.     property OnSelectionChange;
  254.     property OnStartDrag;
  255.   end;
  256. implementation
  257. uses
  258. {$ifdef fcdelphi6Up}
  259. variants,
  260. {$endif}
  261.  fcframe;
  262.  
  263. //type
  264. //  TwwCheatGridCast = class(TwwDBGrid);
  265. {$ifndef fcDelphi4Up}
  266. function fcIsInwwObjectView(control: TWinControl):boolean;
  267. begin
  268.   result := False;
  269. end;
  270. function fcIsInwwObjectViewPaint(control: TWinControl):boolean;
  271. begin
  272.   result := False;
  273. end;
  274. {$endif}
  275. procedure TfcPopupPanel.CreateParams(var Params: TCreateParams);
  276. begin
  277.   inherited;
  278.   with Params do
  279.   begin
  280.     Style := WS_POPUP or WS_BORDER;
  281.     ExStyle := WS_EX_TOOLWINDOW;
  282.     {$ifdef fcDelphi4up}
  283.     AddBiDiModeExStyle(ExStyle);
  284.     {$endif}
  285.     WindowClass.Style := CS_SAVEBITS;
  286.   end;
  287. end;
  288. constructor TfcPopupPanel.Create(AOwner: TComponent);
  289. begin
  290.   inherited;
  291.   ControlStyle := ControlStyle + [csNoDesignVisible, csReflector, csReplicatable];
  292.   BevelInner := bvNone;
  293.   BevelOuter := bvNone;
  294.   Height := 100;
  295. end;
  296. constructor TfcTreeComboTreeNode.Create(AOwner: TFCTreeNodes);
  297. begin
  298.   inherited Create(AOwner);
  299.   FSelectable := True;
  300.   SelectedIndex := -1;
  301. end;
  302. // Read/WriteData Methods overridden and implemented to support any
  303. // boolean properties added to TfcTreeComboTreeNode.  The Selectable
  304. // property, to be specific.
  305. Function TfcTreeComboTreeNode.GetSizeOfNodeInfo: integer;
  306. var BoolProps: TStringList;
  307. begin
  308.   BoolProps := TStringList.Create;
  309.   result:= inherited GetSizeOfNodeInfo;
  310.   fcGetBooleanProps(self, BoolProps);
  311.   result:= result + BoolProps.Count* SizeOf(boolean) + SizeOf(Integer);
  312.   BoolProps.Free;
  313. end;
  314. procedure TfcTreeComboTreeNode.ReadData(Stream: TStream; Info: PfcNodeInfo);
  315. var BoolProps: TStringList;
  316.     i: Integer;
  317.     CurBool: Boolean;
  318.     Count: Integer;
  319.     {$ifdef fcDelphi4Up}
  320.     L, Size: integer;
  321.     {$endif}
  322. begin
  323.   if TfcCustomTreeView(TreeView).StreamVersion=1 then inherited;
  324.   BoolProps := TStringList.Create;
  325.   fcGetBooleanProps(self, BoolProps);
  326.   if TfcCustomTreeView(TreeView).StreamVersion=1 then
  327.   begin
  328.      { If streaming from TfcTreeView then don't read in flags }
  329.      { ReadDataSize represents the size of the node written to the stream }
  330.      {$ifdef fcDelphi4Up}
  331.       L := Length(Text);
  332.      if L > 255 then L := 255;
  333.      Size := GetSizeOfNodeInfo + L - 255;
  334.      if (ReadDataSize<Size) then
  335.      begin
  336.         BoolProps.Free;
  337.         exit; { No more data to read so finished }
  338.      end
  339.      else
  340.      {$endif}
  341.      { Base class does not know about our structure so subtract the amount }
  342.      Stream.Position:= Stream.Position - (GetSizeOfNodeInfo - SizeOf(Info^));
  343.   end;
  344.   Stream.ReadBuffer(Count, SizeOf(Count));
  345.   for i := 0 to Count - 1 do
  346.   begin
  347.     Stream.ReadBuffer(CurBool, SizeOf(CurBool));
  348.     fcSetOrdProp(self, BoolProps[i], ord(CurBool));
  349.   end;
  350.   BoolProps.Free;
  351.   if TfcCustomTreeView(TreeView).StreamVersion=0 then inherited;
  352. end;
  353. procedure TfcTreeComboTreeNode.WriteData(Stream: TStream; Info: PfcNodeInfo);
  354. var BoolProps: TStringList;
  355.     i: Integer;
  356.     CurBool: Boolean;
  357.     Count: Integer;
  358. begin
  359.   inherited;
  360.   BoolProps := TStringList.Create;
  361.   fcGetBooleanProps(self, BoolProps);
  362.   Count := BoolProps.Count;
  363.   Stream.WriteBuffer(Count, SizeOf(Count));
  364.   for i := 0 to Count - 1 do
  365.   begin
  366.     CurBool := Boolean(fcGetOrdProp(self, BoolProps[i]));
  367.     Stream.WriteBuffer(CurBool, SizeOf(CurBool));
  368.   end;
  369.   BoolProps.Free;
  370. end;
  371. constructor TfcPopupTreeView.Create(AOwner: TComponent);
  372. begin
  373.   inherited;
  374.   ControlStyle := ControlStyle + [csReplicatable];
  375.   FCheckChange := False;
  376.   NodeClass := TfcTreeComboTreeNode;
  377.   FCloseOnUp := True;
  378.   Options:= [tvoShowButtons, tvoShowRoot,
  379.              tvoShowLines, tvoHideSelection, tvoToolTips];
  380. end;
  381. // Added so that PageDown/PageUp works properly with the Selectable property
  382. // of the TfcTreeComboTreeNode.
  383. function TfcPopupTreeView.MovePage(Node: TfcTreeNode; Down: Boolean): TfcTreeNode;
  384. var ItemsPerPage: Integer;
  385.     i: Integer;
  386. begin
  387.   result := nil;
  388.   ItemsPerPage := (Height div ItemHeight) + 1;
  389.   for i := 0 to ItemsPerPage - 1 do
  390.   begin
  391.     if Node = nil then Break;
  392.     result := Node;
  393.     if Down then Node := Node.GetNextVisible
  394.     else Node := Node.GetPrevVisible;
  395.   end;
  396.   if Node <> nil then result := Node;
  397. end;
  398. function TfcPopupTreeView.GetLastVisible: TfcTreeNode;
  399. var Node: TfcTreeNode;
  400. begin
  401.   result := nil;
  402.   Node := Items.GetFirstNode;
  403.   while Node <> nil do
  404.   begin
  405.     result := Node;
  406.     Node := Node.GetNextVisible;
  407.   end;
  408. end;
  409. // 4/10/99 - PYW - Get last node regardless of whether or not it is visible.
  410. function TfcPopupTreeView.GetLastNode: TfcTreeNode;
  411. var Node: TfcTreeNode;
  412. begin
  413.   result := nil;
  414.   Node := Items.GetFirstNode;
  415.   while Node <> nil do
  416.   begin
  417.     result := Node;
  418.     Node := Node.GetNext;
  419.   end;
  420. end;
  421. // Support methods for the Selectable property of the TfcTreeComboTreeNode.
  422. function TfcPopupTreeView.ValidNode(Node: TfcTreeNode): Boolean;
  423. begin
  424.   if (TreeCombo <> nil) and (icoEndNodesOnly in TreeCombo.Options) then result := Node.Count = 0
  425.   else result := True;
  426.   if not TfcTreeComboTreeNode(Node).Selectable then result := False;
  427. end;
  428. function TfcPopupTreeView.SelectValidNode(StartingNode, SelectedNode: TfcTreeNode; Key: Word): Boolean;
  429. begin
  430.   result := False;
  431.   if StartingNode = nil then
  432.   begin
  433.     StartingNode := Items.GetFirstNode;
  434.     if not (Key in [VK_NEXT, VK_END]) then Key := 0;
  435.   end;
  436.   if (SelectedNode <> nil) and (SelectedNode = Selected) then
  437.   begin
  438.     Selected := StartingNode;
  439.     Exit;
  440.   end;
  441.   if SelectedNode = nil then SelectedNode := StartingNode;
  442. { if Key in [vk_up, vk_down, vk_prior, vk_next, vk_home, vk_end] then
  443.   begin
  444.      if EditCanModify then begin
  445.         SetModified(True);
  446.      end
  447.      else exit;
  448.   end;
  449. }
  450.   if (TreeCombo.isDroppedDown) then begin
  451.     case Key of
  452.       VK_UP: SelectedNode := SelectedNode.GetPrevVisible;
  453.       VK_DOWN: SelectedNode := SelectedNode.GetNextVisible;
  454.       VK_PRIOR: SelectedNode := MovePage(SelectedNode, False);
  455.       VK_NEXT: SelectedNode := MovePage(SelectedNode, True);
  456.       VK_HOME: SelectedNode := Items.GetFirstNode;
  457.       VK_END: SelectedNode := GetLastVisible;
  458.     end;
  459.   end
  460.   else begin // 4/10/99 - PYW - When closed up ignore visible when getting the new node.
  461.     case Key of
  462.       VK_UP: SelectedNode := SelectedNode.GetPrev;
  463.       VK_DOWN: SelectedNode := SelectedNode.GetNext;
  464.       VK_PRIOR: SelectedNode := MovePage(SelectedNode, False);
  465.       VK_NEXT: SelectedNode := MovePage(SelectedNode, True);
  466.       VK_HOME: SelectedNode := Items.GetFirstNode;
  467.       VK_END: SelectedNode := GetLastNode;
  468.     end;
  469.   end;
  470.   if SelectedNode = nil then Exit;
  471.   if not TreeCombo.IsValidNode(SelectedNode) then
  472.   begin
  473.     if Key in [VK_UP, VK_PRIOR, VK_END] then Key := VK_UP else Key := VK_DOWN;
  474.     SelectValidNode(StartingNode, SelectedNode, Key);
  475.   end else Selected := SelectedNode;
  476.   result := True;
  477. end;
  478. procedure TfcPopupTreeView.WMLButtonDown(var Message: TWMLButtonDown);
  479. var HitTest: TfcHitTests;
  480.     Node: TfcTreeNode;
  481. begin
  482.   FClickedInControl := True;
  483.   if TreeCombo <> nil then TreeCombo.CheckCancelMode;
  484.   FCloseOnUp := False;
  485.   if PtInRect(Rect(0, 0, ClientWidth, ClientHeight), Point(Message.XPos, Message.YPos)) then
  486.     FCloseOnUp := True;
  487.   HitTest := GetHitTestInfoAt(Message.XPos, Message.YPos);
  488.   if fchtOnButton in HitTest then
  489.   begin
  490.     FCloseOnUp := False;
  491.     Node := GetNodeAt(Message.XPos, Message.YPos);
  492.     if Node <> nil then
  493.     begin
  494.       if Node.Expanded then Node.Collapse(False) else Node.Expand(False);
  495.     end;
  496.   end
  497.   else if fchtOnStateIcon in HitTest then begin { 1/31/2000 - Supports checkbox/radiobutton }
  498.      Node := GetNodeAt(Message.XPos, Message.YPos);
  499.      if Node <> nil then begin
  500.        if Node.CheckBoxType=tvctCheckBox then
  501.           node.checked:= not node.checked
  502.        else if Node.CheckBoxType=tvctRadioGroup then
  503.           node.checked:= true;
  504.      end
  505.   end
  506. end;
  507. procedure TfcPopupTreeView.WMTimer(var Message: TWMTimer);
  508. var p: TPoint;
  509. begin
  510.   inherited;
  511.   if GetKeyState(VK_LBUTTON) >= 0 then
  512.   begin
  513.     if TreeCombo <> nil then TreeCombo.CloseUp(True);
  514.     Exit;
  515.   end;
  516.   if Selected = nil then Exit;
  517.   GetCursorPos(p);
  518.   with ClientToScreen(Point(0, 0)) do
  519.   begin
  520.     if p.y < y then SelectValidNode(Selected, nil, VK_UP)
  521.     else if p.y > y + Height then SelectValidNode(Selected, nil, VK_DOWN);
  522.   end;
  523. end;
  524. procedure TfcPopupTreeView.Collapse(Node: TfcTreeNode);
  525. begin
  526.    inherited;
  527.    if (TreeCombo<>nil) and (icoEndNodesOnly in TreeCombo.Options) then
  528.       Selected:= nil;
  529. end;
  530. // Support hot-tracking of the iten in the drop-down treeview.
  531. procedure TfcPopupTreeView.MouseMove(Shift: TShiftState; X, Y: Integer);
  532. var Node: TfcTreeNode;
  533.     p: TPoint;
  534.     Msg: TWMTimer;
  535. begin
  536.   inherited;
  537.   if TreeCombo.EffectiveReadOnly then Exit;  // Prevent hot-tracking when readonly
  538.   if ((FLastPoint.x = x) and (FLastPoint.y = y)) or ((FLastPoint.x = -1) and (FLastPoint.y = -1)) then
  539.   begin
  540.     FLastPoint := Point(x, y);
  541.     Exit;
  542.   end;
  543.   Node := GetNodeAt(X, Y);
  544.   if (Node <> nil) and TreeCombo.IsValidNode(Node) then Selected := Node;
  545.   // Allow mouse to move selection down or up past window
  546.   if (TreeCombo <> nil) and (GetKeyState(VK_LBUTTON) < 0) then
  547.   begin
  548.     GetCursorPos(p);
  549.     with ClientToScreen(Point(0, 0)) do
  550.     begin
  551.       FillChar(Msg, SizeOf(Msg), 0);
  552.       if (p.y < y - TreeCombo.Height) or (p.y > y + Height) then
  553.       begin
  554.         WMTimer(Msg);
  555.         SetTimer;
  556.       end{ else
  557.         KillTimer; 4/5/99 - Leave timer on until MouseUP or CloseUp}
  558.     end;
  559.   end;
  560.   FLastPoint := Point(x, y);
  561. end;
  562. procedure TfcPopupTreeView.MouseUp(Button: TMouseButton;
  563.   Shift: TShiftState; X, Y: Integer);
  564. var hittest: TfcHitTests;
  565.     ClickedNode: TfcTreeNode;
  566. begin
  567.   if (TreeCombo <> nil) and (Button = mbLeft) and FCloseOnUp and
  568.      (FClickedInControl or PtInRect(ClientRect, Point(X, Y))) then
  569.   begin
  570.     hitTest:= GetHitTestInfoAt(X, Y);
  571.     if ([fchtOnButton,fchtOnStateIcon] * hittest=[]) then begin { 4/5/99 - RSW }
  572.        ClickedNode:= GetNodeAt(X, Y);
  573.        if (ClickedNode<>nil) and TreeCombo.IsValidNode(ClickedNode) then begin
  574.          TreeCombo.FSelectedNode:= Selected; { RSW }
  575.          TreeCombo.CloseUp(PtInRect(ClientRect, Point(X, Y)));
  576.        end
  577.     end
  578.   end;
  579.   KillTimer;
  580.   FCloseOnUp := True;
  581. end;
  582. procedure TfcPopupTreeView.WndProc(var Message: TMessage);
  583. begin
  584.   case Message.Msg of
  585.     WM_LBUTTONDBLCLK, WM_RBUTTONDOWN, WM_RBUTTONDBLCLK: ;
  586.   else
  587.     inherited;
  588.   end;
  589. end;
  590. procedure TfcPopupTreeView.WMMouseActivate(var Message: TMessage);
  591. begin
  592.   Message.Result := MA_NOACTIVATE;
  593. end;
  594. procedure TfcPopupTreeView.CalcNodeAttributes(Node: TfcTreeNode; AItemState: TfcItemStates);
  595. begin
  596.   if Node.Selected then
  597.   begin
  598.     Canvas.Brush.Color := clHighlight;
  599.     Canvas.Font.Color := clHighlightText;
  600.   end;
  601.   inherited;
  602. end;
  603. procedure TfcPopupTreeView.Change(Node: TfcTreeNode);
  604. begin
  605.   inherited;
  606.   if (TreeCombo <> nil) and FCheckChange and (Selected <> nil) then
  607.   begin
  608.     TreeCombo.FSelectedNode:= Selected; { RSW }
  609.     TreeCombo.Text := Selected.Text;
  610.   end;
  611. end;
  612. procedure TfcPopupTreeView.SetTimer;
  613. begin
  614.   Windows.SetTimer(Handle, FCPOPUPTIMERID, FCPOPUPINTERVAL, nil);
  615.   FTimerOn := True;
  616. end;
  617. procedure TfcPopupTreeView.KillTimer;
  618. begin
  619.   if HandleAllocated then Windows.KillTimer(Handle, FCPOPUPTIMERID);
  620.   FTimerOn := False;
  621. end;
  622. constructor TfcCustomTreeCombo.Create(AOwner: TComponent);
  623. begin
  624.   inherited;
  625.   ButtonStyle := cbsDownArrow;
  626.   ShowMatchText := True;
  627.   FOptions := [icoExpanded];
  628. //  FAlignmentVertical := fcavTop; { RSW - Used to be fcavCenter }
  629.   FPanel := TfcPopupPanel.Create(self);
  630.   FPanel.Visible := False;
  631.   FTreeView := CreatePopupTreeView;
  632.   FTreeView.FTreeCombo := self;
  633.   with FTreeView do
  634.   begin
  635.     BorderStyle := bsNone;
  636.     Parent := FPanel;
  637.     Visible := True;
  638.     Align := alClient;
  639.     OnItemChange := ItemsChange;
  640.   end;
  641.   FItemsList := TStringList.Create;
  642.   LastItemIndex:= -1;
  643.   LastItemText:='';
  644.   FStoreDataUsing:= sdStoreText;
  645. end;
  646. destructor TfcCustomTreeCombo.Destroy;
  647. begin
  648.   FItemsList.Free;
  649.   inherited;
  650. end;
  651. function TfcCustomTreeCombo.CreatePopupTreeView: TfcPopupTreeView;
  652. begin
  653.   result := TfcPopupTreeView.Create(self);
  654. end;
  655. function TfcCustomTreeCombo.GetStartingNode: TfcTreeNode;
  656. begin
  657.   result := TreeView.Items.GetFirstNode;
  658. end;
  659. procedure TfcCustomTreeCombo.InvalidateImage;
  660. var r: TRect;
  661. begin
  662.   if not HandleAllocated then exit;
  663.   { RSW - Clear image area }
  664.   r:= GetEditRect;
  665.   r:= Rect(1, 1, r.left-1, Height-1);
  666.   InvalidateRect(Handle, @r, True);
  667. end;
  668. procedure TfcCustomTreeCombo.Change;
  669. begin
  670.   if SetModifiedInChangeEvent then modified:=true; // 7/31/00
  671.   inherited;
  672.   if (TreeView.Selected = nil) or (TreeView.Selected.Text <> Text) then
  673.      InvalidateImage;
  674. end;
  675. procedure TfcCustomTreeCombo.ItemsChange(TreeView: TfcCustomTreeView; Node: TfcTreeNode;
  676.   Action: TfcItemChangeAction; NewValue: Variant);
  677. var Index: Integer;
  678. begin
  679.   if csDestroying in ComponentState then Exit;
  680.   if Action<>icaAdd then
  681.   begin
  682.      if (LastItemIndex<>-1) and (LastItemText=Node.Text) then
  683.      begin
  684.         Index:= LastItemIndex;
  685.      end
  686.      else
  687.         Index := FItemsList.IndexOf(Node.Text + '=' + InttoStr(Node.ImageIndex))
  688.   end
  689.   else begin
  690.      FItemsList.Add(Node.Text + '=' + InttoStr(Node.ImageIndex));
  691.      LastItemIndex:= FItemsList.count-1;
  692.      LastItemText:= Node.text;
  693.      exit;
  694.   end;
  695.   case Action of
  696.     icaDelete: begin
  697.        if Index <> -1 then FItemsList.Delete(Index);
  698.        LastItemText:= '';
  699.        LastItemIndex:= -1;
  700.     end;
  701.     icaText: begin { 12/5/99 - Optimization }
  702.        if (Index <> -1) and (NewValue <> NULL) then FItemsList[Index] := NewValue + '=' + InttoStr(Node.ImageIndex);
  703.        if NewValue=Null then LastItemText:= ''
  704.        else LastItemText:=  NewValue;
  705.        LastItemIndex:= Index;
  706.     end;
  707.     icaImageIndex: if Index <> -1 then FItemsList[Index] := Node.Text + '=' + InttoStr(NewValue);
  708.   end;
  709. end;
  710. function TfcCustomTreeCombo.CalcImageRect(Rect: TRect): TRect;
  711. var LineHeight, LineOffset: integer;
  712. begin
  713.    if Images=nil then  { RSW }
  714.    begin
  715.       result:= Rect;
  716.       exit;
  717.    end;
  718.   { 4/14/99 - Center icon with respect to the middle of the text's height  - RSW }
  719.   if AlignmentVertical = fcavTop then
  720.   begin
  721.      LineHeight:=
  722.              fcMax(Canvas.Textheight('A')+2, TImageList(Images).Height);
  723.      LineOffset:= (LineHeight-TImageList(Images).Height) div 2;
  724. //     if BorderStyle=bsNone then
  725. //        LineOffset:= LineOffset - 1;
  726.      LineOffset:= fcMax(-1, LineOffset);
  727.      result := Classes.Rect(Rect.Left + 1,  Rect.Top + 1 + LineOffset,
  728.              TImageList(Images).Width,
  729.              Rect.Top + 1 + LineOffset + TImageList(Images).Height);
  730.      if (Frame.isFrameEffective) then begin
  731.         if FFocused and (efLeftBorder in Frame.FocusBorders) then
  732.            result.left:= result.left +  1;
  733.         if FFocused and (efTopBorder in Frame.FocusBorders) then
  734.            result.top:= result.top +  1;
  735.         if not FFocused and (efLeftBorder in Frame.NonFocusBorders) then
  736.            result.left:= result.left +  1;
  737.         if not FFocused and (efTopBorder in Frame.NonFocusBorders) then
  738.            result.top:= result.top +  1;
  739.      end
  740.   end else
  741.   begin
  742.      result := Classes.Rect( Rect.Left + 1, Rect.Top + (Rect.Bottom-Rect.Top - TImageList(Images).Height) div 2 + 1,
  743.                  TImageList(Images).Width,TImageList(Images).Height);
  744. //     if Style = csDropDownList then OffsetRect(result, 1, 0); { 4/27/99 - RSW Remove this code as it makes image move to left unnecessarily}
  745.   end;
  746. end;
  747. procedure TfcCustomTreeCombo.PaintToCanvas(Canvas: TCanvas; Rect: TRect; Highlight,GridPaint: Boolean;
  748.   Text: string);
  749. var ImageIndex,OldBkMode: Integer;
  750.     s: String;
  751.     Flags: UINT;
  752.     TempRect:TRect;
  753.     OldBkColor:TColor;
  754.     SkipPaintImage: boolean;
  755.     TempNode: TfcTreeNode;
  756.     function GetTextRect:TRect;
  757.     begin
  758.        result := Classes.Rect(Rect.Left + GetLeftIndent + 2,
  759.                               Rect.Top + 2,
  760.                               Rect.Right,Rect.Bottom);
  761.        {$ifdef fcDelphi4Up}
  762.        if fcIsInwwObjectView(self) then begin
  763.           result.Top:= result.Top -1;
  764.           result.Left:= result.Left -1; // 1/29/01
  765.        end;
  766.        {$endif}
  767.       if (not fcIsInwwObjectView(self)) and
  768.          Frame.IsFrameEffective then
  769.       begin
  770.          Frame.GetFrameTextPosition(result.Left, result.top, FFocused);
  771.          result.left:= result.Left + GetLeftIndent + 1;
  772.          if AlignmentVertical = fcavCENTER then result.top:= result.Top -1;
  773.       end
  774.     end;
  775.   function DrawHighlight:boolean;
  776.   begin
  777.      result := ((not Editable and Focused) or fcParentGridFocused(Self));
  778.      if (not ShowMatchText) and (Style = csDropDownList) and Focused and not IsDroppedDown then result:= True; { RSW - 3/27/99 }
  779.      if csPaintCopy in ControlState then result:= False;
  780.   end;
  781.   procedure PaintText;
  782.   begin
  783.     // 2/25/99 - Added vertical alignment.
  784.     Flags := 0;
  785.     TempRect := GetTextRect;
  786.     if AlignmentVertical = fcavCENTER then flags := Flags or DT_VCENTER or DT_SINGLELINE
  787.     else flags := Flags or DT_TOP or DT_SINGLELINE;
  788.     if not fcIsInwwGrid(self) and { 4/27/99 - RSW, Adjust left,top in special case }
  789.       ((Style = csDropDownList) and not IsDroppedDown and not showmatchtext) then
  790.     begin
  791.        TempRect.left:= TempRect.left - 1;
  792.        TempRect.Top:= TempRect.Top - 1;
  793.     end
  794.     else if fcIsClass(parent.classtype, 'TwwDBGrid') then
  795.     begin
  796.        if not (dgRowLines in fcGetGridOptions(self)) then TempRect.Top:= TempRect.Top -1;
  797.     end;
  798.     if fcIsInwwObjectViewPaint(self) or
  799.        (IsTransparentEffective and not FFocused) or fcIsInwwGridPaint(self) then
  800.        SetBkMode(Canvas.Handle, TRANSPARENT)
  801.     else
  802.        SetBkMode(Canvas.Handle, OPAQUE);
  803.     if (not FFocused) and IsTransparentEffective and (Frame.NonFocusTransparentFontColor<>clNone) then
  804.         Canvas.Font.Color:= Frame.NonFocusTransparentFontColor;
  805.     // 8/1/02
  806.     if (not IsTransparentEffective) and (not fcIsInwwGridPaint(self)) then
  807.       if (not FFocused) and (Frame.Enabled) and (Frame.NonFocusColor<>clNone) then
  808.          Canvas.Brush.Color:= Frame.NonFocusColor;
  809.     DrawText(Canvas.Handle,PChar(Text),Length(Text),TempRect,Flags);
  810.   end;
  811.   procedure PaintImage;
  812.   var ImageRect: TRect;
  813.   begin
  814.      if Images=nil then exit; { 3/3/99 }
  815.      ImageRect := CalcImageRect(Rect);
  816.      if (Images <> nil) and (ImageIndex >= 0) and (ImageIndex < Images.Count) then
  817.      begin
  818.        fcImageListDraw(Images, ImageIndex, Canvas,
  819.          ImageRect.Left, ImageRect.Top,
  820.            0, Enabled)  // Changed calculation of y pos to ignore self's height.  Made it constant for now.  -ksw (2/24/99)
  821.      end
  822.   end;
  823.   //3/1/2002-Added new function to handle painting in a TDBCtrlGrid
  824.   function PaintCopyOutsideGrid: boolean;
  825.   begin
  826.      result:= not
  827.        ((not fcIsInwwGrid(self)) and (not (csPaintcopy in ControlState)))
  828.   end;
  829. begin
  830.   OldBkColor := GetBkColor(Canvas.Handle);
  831.   OldBkMode := GetBkMode(Canvas.Handle);
  832.   SkipPaintImage:= False;
  833.   Canvas.Font := Font; { 7/8/99 - Fixes problem where font not set for csPaintCopy }
  834.   if (not enabled) and (color<>clGrayText) then { 3/7/00 - Use disablec color }
  835.      Canvas.font.color:= clGrayText;
  836.   try
  837.      ImageIndex:= -1;
  838. //     if (not HandleAllocated) or (not TreeView.HandleAllocated) then
  839. //        if TreeView.Selected=nil then
  840. //           s:= 'abc';
  841.      if ((csPaintCopy in ControlState) and (DataLink.Field<>nil)) or // 12/11/01 - Respect mapped value and check for nil field
  842.         ((Frame.Enabled and not FFocused) and (Datalink.Field<>nil)) then // 3/18/2002 - Respect mapped value when framing enabled.
  843.      begin
  844.        if StoreDataUsing =sdStoreText then
  845.           Text := DataLink.Field.asString
  846.        else begin
  847.           tempNode := TreeView.Items.FindNodeInfo(
  848.              DataLink.Field.Text, False, StoreDataUsing);
  849.           if tempNode<>nil then
  850.              Text:= tempNode.Text
  851.           else Text:=DataLink.Field.asString;
  852.        end;
  853.      end;
  854.      if (not (csPaintCopy in ControlState)) and
  855.         (TreeView.Selected <> nil) and (TreeView.Selected.Text = Text) then
  856.         ImageIndex := TreeView.Selected.ImageIndex
  857.      else begin
  858.         s := FItemsList.Values[Text];
  859.         if s <> '' then ImageIndex := StrtoInt(s)
  860.         else ImageIndex := -1;
  861.      end;
  862.      // Draw Highlight rect with focus rect
  863.      if (csPaintCopy in ControlState) or // 1/31/01
  864.         (fcIsInwwGrid(self) and (not Focused or not Highlight)) or
  865.         ((Style = csDropDownList) and Focused and not IsDroppedDown and not showmatchtext) then
  866.      begin
  867.         if not fcIsInwwGrid(self) then
  868.         begin
  869.            Rect.Right := BtnParent.Left-1; { RSW, just set right and bottom}
  870.         end;
  871.         // Draw Background in the Highlight color and surround it with a focus rect
  872.         if (not fcIsInwwGrid(self)) or (not GridPaint) then
  873.            Canvas.Brush.Color :=
  874.              fcThisThat(Highlight and (DrawHighlight or Not PaintCopyOutsideGrid),
  875.              clHighlight, self.Color); { 7/8/99 - RSW - Use color of control }
  876.         if (not IsTransparentEffective) and not fcIsInwwObjectViewPaint(self) and
  877.            not (fcIsInwwGridPaint(self)) then Canvas.FillRect(Rect);
  878.         if (not GridPaint) and Highlight and (DrawHighlight or Not PaintCopyOutsideGrid) then
  879.         begin
  880.            SetBkColor(Canvas.Handle, ColorToRGB(clHighlightText));
  881.            SetTextColor(Canvas.Handle, ColorToRGB(clHighlight));
  882.            TempRect := Rect;
  883.            if fcIsInwwGrid(self) then begin
  884.               // 9/20/01 - don't subtract from temprect if its already been done
  885.               if TempRect.right > ClientRect.right - GetIconIndent then
  886.                  TempRect.Right := ClientRect.Right - GetIconIndent;
  887. //              if parent.focused then
  888. //                TwwCheatGridCast(Parent).DoCalcCellColors(FFieldLink.Field, [], True, Font, Brush);
  889.            end;
  890.            PaintImage;
  891.            SkipPaintImage:= True;
  892.            Canvas.DrawFocusRect(TempRect);
  893.         end;
  894.         // Draw the text
  895.         if not fcIsInwwGrid(self) or (not GridPaint) then begin
  896.            SetBkMode(Canvas.Handle, TRANSPARENT);
  897.            SetBkColor(Canvas.Handle, ColorToRGB(fcThisThat(Highlight and (DrawHighlight or Not PaintCopyOutsideGrid), clHighlight, clWindow)));
  898.            SetTextColor(Canvas.Handle, ColorToRGB(fcThisThat(Highlight and (DrawHighlight or not PaintCopyOutsideGrid), clWindow, Font.Color)));
  899.         end;
  900.         PaintText;
  901.      end
  902.      else if not fcisinwwGrid(Self) and
  903.        ((csPaintCopy in ControlState) or Frame.IsFrameEffective) and { 12/12/99 }
  904.        (not Focused) then begin { RSW - 3/17/99 }
  905.         PaintText;
  906.      end;
  907.      if not SkipPaintImage then PaintImage;
  908.      if Frame.IsFrameEffective then
  909.      begin
  910.        DrawFrame(Canvas);
  911.      end;
  912.   finally
  913.      SetBkMode(Canvas.Handle,OldBkMode);
  914.      SetBkColor(Canvas.Handle, OldBkColor);
  915.   end;
  916. end;
  917. procedure TfcCustomTreeCombo.ResyncTreeSelected(LookupText: string);
  918. begin
  919.   if ((TreeView.Selected = nil) or
  920.       (TreeView.Selected.Text <> LookupText)) then
  921.   begin
  922.      if (fcNameInList(Text, FItemsList) <> -1) then
  923.      begin
  924.         TreeView.Selected := TreeView.Items.FindNode(LookupText, False);
  925.         invalidate; { RSW - 2/24/99 }
  926.      end
  927.      else TreeView.Selected:= nil { RSW }
  928.   end
  929. end;
  930. procedure TfcCustomTreeCombo.SelectionChange;
  931. begin
  932.   if Assigned(FOnSelectionChange) then FOnSelectionChange(self);
  933.   TreeView.FCheckChange := False;
  934. end;
  935. procedure TfcCustomTreeCombo.SelectionChanging;
  936. begin
  937.   DataLink.Edit;
  938.   TreeView.FCheckChange := True;
  939. end;
  940. function TfcCustomTreeCombo.GetSorted: Boolean;
  941. begin
  942.   result := TreeView.SortType = fcstText;
  943. end;
  944. function TfcCustomTreeCombo.GetCalcNodeAttributes: TfcCalcNodeAttributesEvent;
  945. begin
  946.   result := TreeView.OnCalcNodeAttributes;
  947. end;
  948. function TfcCustomTreeCombo.GetImageList: TCustomImageList;
  949. begin
  950.   result := TreeView.Images;
  951. end;
  952. function TfcCustomTreeCombo.GetStateImageList: TCustomImageList;
  953. begin
  954.   result := TreeView.StateImages;
  955. end;
  956. function TfcCustomTreeCombo.GetItems: TfcTreeNodes;
  957. begin
  958.   result := TreeView.Items;
  959. end;
  960. function TfcCustomTreeCombo.GetTreeOptions: TfcTreeViewOptions;
  961. begin
  962.   result := TreeView.Options;
  963. end;
  964. {procedure TfcCustomTreeCombo.SetAlignmentVertical(Value: TfcAlignVertical);
  965. begin
  966.   if FAlignmentVertical <> Value then FAlignmentVertical := Value;
  967. end;
  968. }
  969. procedure TfcCustomTreeCombo.SetCalcNodeAttributes(Value: TfcCalcNodeAttributesEvent);
  970. begin
  971.   TreeView.OnCalcNodeAttributes := Value;
  972. end;
  973. procedure TfcCustomTreeCombo.SetItems(Value: TfcTreeNodes);
  974. begin
  975.   TreeView.Items := Value;
  976. end;
  977. procedure TfcCustomTreeCombo.SetImageList(Value: TCustomImageList);
  978. begin
  979.   TreeView.Images := Value;
  980.   if Value <> nil then Value.FreeNotification(self);
  981.   SetEditRect;
  982. end;
  983. procedure TfcCustomTreeCombo.SetStateImageList(Value: TCustomImageList);
  984. begin
  985.   TreeView.StateImages := Value;
  986.   if Value <> nil then Value.FreeNotification(self);
  987.   SetEditRect;
  988. end;
  989. procedure TfcCustomTreeCombo.SetSorted(Value: Boolean);
  990. begin
  991.   if Value then TreeView.SortType := fcstText else TreeView.SortType := fcstNone;
  992. end;
  993. procedure TfcCustomTreeCombo.SetTreeOptions(Value: TfcTreeViewOptions);
  994. begin
  995.   TreeView.Options := Value;
  996. end;
  997. function TfcCustomTreeCombo.GetDropDownControl: TWinControl;
  998. begin
  999.   result := TreeView;
  1000. end;
  1001. function TfcCustomTreeCombo.GetDropDownContainer: TWinControl;
  1002. begin
  1003.   result := FPanel;
  1004. end;
  1005. function TfcCustomTreeCombo.GetItemCount: Integer;
  1006. begin
  1007.   result := Items.Count;
  1008. end;
  1009. function TfcCustomTreeCombo.GetItemSize: TSize;
  1010.   function LargestRect: TSize;
  1011.   var Node: TfcTreeNode;
  1012.       i: Integer;
  1013.   begin
  1014.     result := fcSize(0, 0);
  1015.     Node := TreeView.Items.GetFirstNode;
  1016.     while Node <> nil do
  1017.     begin
  1018.       with Node.DisplayRect(True) do
  1019.       begin
  1020.         TreeView.Canvas.Font:= TreeView.Font; { 4/24/99 - RSW }
  1021.         i:= Left + TreeView.Canvas.TextWidth(Node.Text) + 6; { 4/5/99 - RSW }
  1022.         if (Node.ImageIndex=-2) and (TreeView.Images<>nil) then inc(i, TImageList(TreeView.Images).Width);
  1023.         result.cy := Bottom - Top;
  1024.       end;
  1025.       if i > result.cx then result.cx := i;
  1026.       Node := Node.GetNextVisible;
  1027.     end;
  1028.   end;
  1029. var Node: TfcTreeNode;
  1030. begin
  1031.   if DropDownWidth=0 then
  1032.   begin
  1033.      Node := Items.GetFirstNode;
  1034.      if Node <> nil then result := LargestRect
  1035.      else result := fcSize(0, 0);
  1036.   end
  1037.   else begin
  1038.      Node := Items.GetFirstNode;
  1039.      if Node <> nil then begin
  1040.        result.cx:= DropDownWidth;
  1041.        with Node.DisplayRect(True) do
  1042.           result.cy:= Bottom-Top
  1043.      end
  1044.      else result := fcSize(0, 0);
  1045.   end;
  1046. end;
  1047. procedure TfcCustomTreeCombo.CMTextChanged(var Message: TMessage);
  1048. begin
  1049.   inherited;
  1050. end;
  1051. procedure TfcCustomTreeCombo.DropDown;
  1052. begin
  1053.   // 2/25/99 - Make certain that combo does not dropdown if datasource is not enabled.
  1054.   if (Datalink.field=nil) and ((datasource<>nil) or (datafield<>'')) then exit;
  1055. //  ControlStyle := ControlStyle - [csNoDesignVisible];
  1056.   TreeView.FLastPoint := Point(-1, -1);
  1057.   TreeView.FClickedInControl := False;
  1058.   TreeView.FCloseOnUp := True;
  1059.   ResyncTreeSelected(Text);  { Move earlier }
  1060.   FOriginalNode := TreeView.Selected;
  1061.   FOriginalText:= Text;
  1062.   FSelectedNode:= FOriginalNode; { RSW }
  1063.   if icoExpanded in Options then begin
  1064.      TreeView.FullExpand;
  1065.      if ((Text='') or (FSelectedNode=nil)) and (TreeView.Items.GetFirstNode<>nil) then
  1066.      begin
  1067.         { 4/5/99 - Default to top of tree.  Don't use TopItem here as it has strange horizontal scrolling behavior}
  1068.         TreeView.selected:= TreeView.Items.GetFirstNode;
  1069.         TreeView.Selected:= nil;
  1070.      end
  1071.      else if FSelectedNode<>Nil then FSelectedNode.MakeVisible;
  1072.   end;
  1073.   if Style = csDropDownList then Invalidate;
  1074.   inherited;
  1075.   //2/25/99 - Removed from fcCombo so needs to be added here.
  1076.   Update;
  1077.   Selectall;
  1078. //  SetScrollPos(TreeView.Handle, sb_horz, 50, True);
  1079. end;
  1080. procedure TfcCustomTreeCombo.CloseUp(Accept: Boolean);
  1081. var IsDroppedDown: Boolean;
  1082. begin
  1083. //  ControlStyle := ControlStyle + [csNoDesignVisible];
  1084.   IsDroppedDown := self.IsDroppedDown;
  1085.   inherited;
  1086.   if IsDroppedDown then
  1087.   begin
  1088.     if Accept and (FOriginalNode<>FSelectedNode) and EditCanModify then { RSW }
  1089.     begin
  1090.       SelectionChanging;
  1091.       if FSelectedNode<>nil then begin
  1092.          SetModifiedInChangeEvent:=true;
  1093.          Text:= FSelectedNode.Text; { RSW }
  1094.          SetModifiedInChangeEvent:=False;
  1095.       end;
  1096. //      if TreeView.Selected <> nil then Text := TreeView.Selected.Text;
  1097.       SelectionChange;
  1098.       SetModified(True);
  1099.     end else begin
  1100.       TreeView.Selected := FOriginalNode;
  1101.       if TreeView.Selected <> nil then Text := TreeView.Selected.Text
  1102.       else Text:= FOriginalText; // if not fcIsInwwGrid(self) then Text := '';
  1103.     end;
  1104.     DoCloseUp(Accept);
  1105.   end;
  1106.   TreeView.KillTimer;
  1107.   if Editable then SelectAll; //(Style = csDropDown) then SelectAll;
  1108. end;
  1109. procedure TfcCustomTreeCombo.SetSelectedNode(Node:TfcTreeNode);
  1110. begin
  1111.    inherited;
  1112.    FSelectedNode := Node;
  1113. end;
  1114. function TfcCustomTreeCombo.IsDroppedDown: Boolean;
  1115. begin
  1116.   result := FPanel.Visible;
  1117. end;
  1118. procedure TfcCustomTreeCombo.DrawInGridCell(ACanvas: TCanvas; Rect: TRect;
  1119.   State: TGridDrawState);
  1120. begin
  1121.   PaintToCanvas(ACanvas, Rect, (gdSelected in State), True, DataLink.Field.Text);
  1122. end;
  1123. procedure TfcCustomTreeCombo.CreateWnd;
  1124. begin
  1125.   inherited;
  1126.   FPanel.Parent := self;
  1127. end;
  1128. procedure TfcCustomTreeCombo.KeyUp(var Key: WORD; Shift: TShiftState);
  1129. begin
  1130.   inherited;
  1131. {  if EffectiveReadOnly then Exit;  // Prevent selection change with keyboard when readonly
  1132.   case Key of
  1133.     VK_BACK:
  1134.        if (Style=csDropDownList) and (not isDroppedDown) then
  1135.        begin
  1136.          key:= 0;
  1137.        end;
  1138.   end;}
  1139. end;
  1140. procedure TfcCustomTreeCombo.KeyDown(var Key: WORD; Shift: TShiftState);
  1141. var r: TRect;
  1142. begin
  1143.   inherited;
  1144.   if EffectiveReadOnly then Exit;  // Prevent selection change with keyboard when readonly
  1145.   case Key of
  1146.     VK_BACK, VK_DELETE:
  1147.        if (Style=csDropDownList) {and (not isDroppedDown) }then
  1148.        begin
  1149.          //4/27/99 - Handle BackSpace Key as well.
  1150.          if (AllowClearKey) and
  1151.             ((selText=Text) or
  1152.              (not IsDroppedDown) and ((key=vk_delete) or ((key=vk_back) and (not ShowMatchText)))) then
  1153.          begin
  1154.             SelectionChanging;
  1155.             Text:= '';
  1156.             TreeView.Selected := nil;
  1157. //            SelectionChange;
  1158.             TreeView.FCheckChange := False;
  1159.             SetModified(True);
  1160.             key:= 0;
  1161.          end
  1162.          else begin
  1163.             if (selStart>0) and ShowMatchText then
  1164.             begin
  1165.                SendMessage(Handle, EM_SETSEL, length(Text), selStart-1);
  1166.                SendMessage(Handle, EM_SCROLLCARET, 0,0);
  1167.             end;
  1168.             key:= 0;
  1169.          end;
  1170.        end;
  1171.     VK_UP, VK_DOWN, VK_HOME, VK_END, VK_PRIOR, VK_NEXT:
  1172.     begin
  1173.       if (Key in [VK_HOME, VK_END]) and not (ssCtrl in Shift) and IsDroppedDown then Exit;
  1174.       if Items.Count > 0 then
  1175.         if (Style = csDropDownList) or (((Key = VK_UP) or (Key = VK_DOWN)) and not IsDroppedDown) then
  1176.         begin
  1177.           SelectionChanging;
  1178.           if not TreeView.SelectValidNode(TreeView.Selected, nil, Key) then
  1179.           begin
  1180.             r := GetEditRect;
  1181.             InvalidateRect(Handle, @r, False);
  1182.           end;
  1183.           SelectionChange;
  1184.           SetModified(True);
  1185.           Key := 0;
  1186.         end else if IsDroppedDown then begin
  1187.           SelectionChanging;
  1188.           TreeView.SelectValidNode(TreeView.Selected, nil, Key);
  1189.           SelectionChange;
  1190.           Key := 0;
  1191.         end;
  1192.       SelectAll;
  1193.     end;
  1194.   end;
  1195. end;
  1196. procedure TfcCustomTreeCombo.WndProc(var Message: TMessage);
  1197. begin
  1198.   inherited;
  1199. end;
  1200. procedure TfcCustomTreeCombo.KeyPress(var Key: Char);
  1201.   // This method occurs before the text has changed on the edit, so
  1202.   // this method returns what the text will be after the key has been
  1203.   // processed.
  1204.   function NewText: string;
  1205.   var CurStr: string;
  1206.   begin
  1207.     CurStr:= Text;
  1208.     result:= Copy(CurStr, 1, SelStart) + Char(Key) +
  1209.       Copy(CurStr, SelStart + 1 + Length(SelText), 32767);
  1210.   end;
  1211. var Text: string;
  1212.   // Return the first node whose beginning text matches the current
  1213.   // text of the combo.
  1214.   function FindNode: TfcTreeNode;
  1215.   var InitialNode: TfcTreeNode;
  1216.   begin
  1217.     InitialNode := TreeView.Selected;
  1218.     if InitialNode.Index < GetStartingNode.Index then InitialNode := GetStartingNode;
  1219.     result := InitialNode;
  1220.     repeat
  1221.       if IsValidNode(result) and (UpperCase(Copy(result.Text, 1, Length(Text))) = UpperCase(Text)) then Exit;
  1222.       result := result.GetNext;
  1223.       if result = nil then result := GetStartingNode;
  1224.     until result = InitialNode;
  1225.     result := nil;
  1226.   end;
  1227. var Node: TfcTreeNode;
  1228.     TextLen: Integer;
  1229.     HaveChangedText: boolean;
  1230. begin
  1231.   inherited;
  1232.   TreeView.HandleNeeded;  { Allows Items to be valid }
  1233.   if (key=#8) and (Style=csDropDownList) and ShowMatchText then
  1234.   begin
  1235.      key:= #0;
  1236.      if key=#0 then exit;
  1237.   end;
  1238.   if (Items.Count > 0) and (key<>#0) and
  1239.      (IsDroppedDown or (ShowMatchText {and (Style = csDropDown)})) and not (Key in [#8]) then
  1240.   begin
  1241.     // 3/15/2002 - Don't get new text if user hit Return/Enter key as this messes up Storedatausing path.
  1242.     if Key <> #13 then Text := NewText;
  1243.     Node := FindNode;
  1244.     if Node <> nil then
  1245.     begin
  1246.       TreeView.Selected := Node;
  1247.       FSelectedNode:= Node; { RSW }
  1248.       // Quicken-style highlighting
  1249.       if ShowMatchText then
  1250.       begin
  1251.         HaveChangedText:= self.text<>node.text;
  1252.         self.Text := Node.Text;
  1253.         TextLen := Length(Text);
  1254.         SelStart := Length(Node.Text);
  1255.         SelLength := - (Length(Node.Text) - TextLen);
  1256.       end else begin
  1257.         HaveChangedText:= self.text<>node.text;
  1258.         self.Text := Text;
  1259.         SelStart := Length(Text);
  1260.       end;
  1261. //      TreeView.Selected := Node;  { 4/22/99 RSW - Already set so redundant }
  1262.       if HaveChangedText then
  1263.       begin
  1264.          SelectionChange; { 4/22/99 - RSW }
  1265.          SetModified(True);
  1266.       end;
  1267.       Key := #0;
  1268.     end else begin
  1269. //      if IsDroppedDown and (Style = csDropDownList) then Key := #0  // If selection is not in list, but dropped down, then don't allow invalid entries
  1270.       if (Style = csDropDownList) then Key := #0  // If selection is not in list, but dropped down, then don't allow invalid entries
  1271.       else begin
  1272.         TreeView.Selected := nil; //4/27/99 - Clear selection only if dropdown style and not found.
  1273.         FSelectedNode:= Nil; { 11/17/99 - Clear selected so you can type
  1274.                                in things not in the list when it is dropped down}
  1275.       end;
  1276.     end;
  1277.   end;
  1278. {  if (key=#8) and (Style=csDropDownList) then
  1279.   begin
  1280.      if (not isDroppedDown) then key:= #0
  1281.      else if Text=SelText then key:= #0
  1282.   end;
  1283. }
  1284.   if (Key<>#0) and (Style=csDropDown) then SetModified(True) { RSW };
  1285.   if Key = #13 then Key := #0;
  1286. end;
  1287. procedure TfcCustomTreeCombo.Loaded;
  1288. begin
  1289.   inherited;
  1290.   if Sorted then TreeView.AlphaSort;
  1291. end;
  1292. procedure TfcCustomTreeCombo.Paint;
  1293. begin
  1294.    with ClientRect do PaintToCanvas(Canvas, Rect(0, 0, Right - Left, Bottom - Top), True, False, Text);
  1295. end;
  1296. function TfcCustomTreeCombo.GetLeftIndent: Integer;
  1297. begin
  1298.   result := inherited GetLeftIndent + 1;
  1299.   if fcIsInwwGrid(self) then Result:= Result -1; { 7/5/99 }
  1300.   if (Images <> nil) then inc(result, TImageList(Images).Width + 2);
  1301. end;
  1302. function TfcCustomTreeCombo.GetEditRect: TRect;
  1303. begin
  1304.   result:= inherited GetEditRect;
  1305.   if result.Right<=result.Left+10 then
  1306.      result.Right:= result.Left + 10; // 5/3/99 - RSW - Ensure edit rectangle is at least 10 pixels wide
  1307. end;
  1308. function TfcCustomTreeCombo.Editable: Boolean;
  1309. begin
  1310.    Result := (Style <> csDropDownList) or isDroppedDown or ShowMatchText;
  1311. end;
  1312. function TfcCustomTreeCombo.IsValidNode(Node: TfcTreeNode): Boolean;
  1313. begin
  1314.    result:= TreeView.ValidNode(Node);
  1315.    if Assigned(OnCheckValidItem) then OnCheckValidItem(Self, Node, result);
  1316. end;
  1317. procedure TfcCustomTreeCombo.HideCaret;
  1318. begin
  1319.   if (not showMatchText) then inherited;
  1320. end;
  1321. procedure TfcCustomTreeCombo.UpdateData(Sender: TObject);
  1322. var s: string;
  1323. begin
  1324.   if StoreDataUsing =sdStoreText then
  1325.      s:= Text
  1326.   else if StoreDataUsing = sdStoreData1 then
  1327.   begin
  1328.      if SelectedNode=nil then s:= ''
  1329.      else s:= SelectedNode.StringData;
  1330.   end
  1331.   else begin
  1332.      if SelectedNode=nil then s:= ''
  1333.      else s:= SelectedNode.StringData2
  1334.   end;
  1335.   if DataLink.Field.Text <> s then
  1336.     DataLink.Field.Text := s;
  1337. end;
  1338. procedure TfcCustomTreeCombo.DataChange(Sender: TObject);
  1339. var TempNode: TfcTreeNode;
  1340. begin
  1341.   if DataLink.Field <> nil then
  1342.   begin
  1343.     if not (csDesigning in ComponentState) then
  1344.     begin
  1345.       if (DataLink.Field.DataType = ftString) and (MaxLength = 0) then
  1346.         MaxLength := DataLink.Field.Size;
  1347.     end;
  1348.     if Focused and DataLink.CanModify then
  1349.     begin
  1350.        if StoreDataUsing =sdStoreText then
  1351.           Text := DataLink.Field.Text
  1352.        else begin
  1353.           tempNode := TreeView.Items.FindNodeInfo(
  1354.              DataLink.Field.Text, False, StoreDataUsing);
  1355.           if tempNode<>nil then
  1356.              Text:= tempNode.Text
  1357.           else Text:=DataLink.Field.Text;
  1358.        end
  1359.     end
  1360.     else begin
  1361.        if StoreDataUsing =sdStoreText then
  1362.           Text := DataLink.Field.DisplayText
  1363.        else begin
  1364.           tempNode := TreeView.Items.FindNodeInfo(
  1365.              DataLink.Field.Text, False, StoreDataUsing);
  1366.           if tempNode<>nil then
  1367.              Text:= tempNode.Text
  1368.           else Text:=DataLink.Field.Text;
  1369.        end
  1370.     end;
  1371.   end
  1372.   else begin
  1373.     if csDesigning in ComponentState then
  1374.       Text := Name
  1375.     else
  1376.       Text := '';
  1377.   end;
  1378. end;
  1379. end.