TB2ExtItems.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. unit TB2ExtItems;
  2. {
  3. Toolbar2000
  4. Copyright (C) 1998-2005 by Jordan Russell
  5. All rights reserved.
  6. The contents of this file are subject to the "Toolbar2000 License"; you may
  7. not use or distribute this file except in compliance with the
  8. "Toolbar2000 License". A copy of the "Toolbar2000 License" may be found in
  9. TB2k-LICENSE.txt or at:
  10. http://www.jrsoftware.org/files/tb2k/TB2k-LICENSE.txt
  11. Alternatively, the contents of this file may be used under the terms of the
  12. GNU General Public License (the "GPL"), in which case the provisions of the
  13. GPL are applicable instead of those in the "Toolbar2000 License". A copy of
  14. the GPL may be found in GPL-LICENSE.txt or at:
  15. http://www.jrsoftware.org/files/tb2k/GPL-LICENSE.txt
  16. If you wish to allow use of your version of this file only under the terms of
  17. the GPL and not to allow others to use your version of this file under the
  18. "Toolbar2000 License", indicate your decision by deleting the provisions
  19. above and replace them with the notice and other provisions required by the
  20. GPL. If you do not delete the provisions above, a recipient may use your
  21. version of this file under either the "Toolbar2000 License" or the GPL.
  22. $jrsoftware: tb2k/Source/TB2ExtItems.pas,v 1.63 2005/07/04 02:49:52 jr Exp $
  23. }
  24. interface
  25. {$I TB2Ver.inc}
  26. uses
  27. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  28. StdCtrls, CommCtrl, Menus, ActnList,
  29. TB2Item;
  30. type
  31. TTBEditItemOption = (tboUseEditWhenVertical);
  32. TTBEditItemOptions = set of TTBEditItemOption;
  33. const
  34. EditItemDefaultEditOptions = [];
  35. EditItemDefaultEditWidth = 64;
  36. { Change reasons for TTBEditItem.Text property }
  37. tcrSetProperty = 0; // direct assignment to TTBEditItem.Text property
  38. tcrActionLink = 1; // change comes from an action link
  39. tcrEditControl = 2; // change is caused by typing in edit area
  40. type
  41. TTBEditItem = class;
  42. TTBEditItemViewer = class;
  43. TTBAcceptTextEvent = procedure(Sender: TObject; var NewText: String;
  44. var Accept: Boolean) of object;
  45. TTBBeginEditEvent = procedure(Sender: TTBEditItem; Viewer: TTBEditItemViewer;
  46. EditControl: TEdit) of object;
  47. TTBEditAction = class(TAction)
  48. private
  49. FEditOptions: TTBEditItemOptions;
  50. FEditCaption: String;
  51. FEditWidth: Integer;
  52. FOnAcceptText: TTBAcceptTextEvent;
  53. FText: String;
  54. procedure SetEditCaption(Value: String);
  55. procedure SetEditOptions(Value: TTBEditItemOptions);
  56. procedure SetEditWidth(Value: Integer);
  57. procedure SetOnAcceptText(Value: TTBAcceptTextEvent);
  58. procedure SetText(Value: String);
  59. public
  60. constructor Create(AOwner: TComponent); override;
  61. published
  62. property EditCaption: String read FEditCaption write SetEditCaption;
  63. property EditOptions: TTBEditItemOptions read FEditOptions write SetEditOptions default EditItemDefaultEditOptions;
  64. property EditWidth: Integer read FEditWidth write SetEditWidth default EditItemDefaultEditWidth;
  65. property Text: String read FText write SetText;
  66. property OnAcceptText: TTBAcceptTextEvent read FOnAcceptText write SetOnAcceptText;
  67. end;
  68. TTBEditItemActionLink = class(TTBCustomItemActionLink)
  69. protected
  70. procedure AssignClient(AClient: TObject); override;
  71. function IsEditCaptionLinked: Boolean; virtual;
  72. function IsEditOptionsLinked: Boolean; virtual;
  73. function IsEditWidthLinked: Boolean; virtual;
  74. function IsOnAcceptTextLinked: Boolean; virtual;
  75. function IsTextLinked: Boolean; virtual;
  76. procedure SetEditCaption(const Value: String); virtual;
  77. procedure SetEditOptions(Value: TTBEditItemOptions); virtual;
  78. procedure SetEditWidth(const Value: Integer); virtual;
  79. procedure SetOnAcceptText(Value: TTBAcceptTextEvent); virtual;
  80. procedure SetText(const Value: String); virtual;
  81. end;
  82. TTBEditItem = class(TTBCustomItem)
  83. private
  84. FCharCase: TEditCharCase;
  85. FEditCaption: String;
  86. FEditOptions: TTBEditItemOptions;
  87. FEditWidth: Integer;
  88. FExtendedAccept: Boolean;
  89. FMaxLength: Integer;
  90. FOnAcceptText: TTBAcceptTextEvent;
  91. FOnBeginEdit: TTBBeginEditEvent;
  92. FText: String;
  93. function IsEditCaptionStored: Boolean;
  94. function IsEditOptionsStored: Boolean;
  95. function IsEditWidthStored: Boolean;
  96. function IsTextStored: Boolean;
  97. procedure SetCharCase(Value: TEditCharCase);
  98. procedure SetEditCaption(Value: String);
  99. procedure SetEditOptions(Value: TTBEditItemOptions);
  100. procedure SetEditWidth(Value: Integer);
  101. procedure SetMaxLength(Value: Integer);
  102. procedure SetText(Value: String);
  103. protected
  104. procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); override;
  105. function DoAcceptText(var NewText: string): Boolean; virtual;
  106. procedure DoBeginEdit(Viewer: TTBEditItemViewer); virtual;
  107. procedure DoTextChanging(const OldText: String; var NewText: String; Reason: Integer); virtual;
  108. procedure DoTextChanged(Reason: Integer); virtual;
  109. function GetActionLinkClass: TTBCustomItemActionLinkClass; override;
  110. function GetItemViewerClass(AView: TTBView): TTBItemViewerClass; override;
  111. function NeedToRecreateViewer(AViewer: TTBItemViewer): Boolean; override;
  112. property ExtendedAccept: Boolean read FExtendedAccept write FExtendedAccept default False;
  113. procedure SetTextEx(Value: String; Reason: Integer);
  114. public
  115. constructor Create(AOwner: TComponent); override;
  116. procedure Clear;
  117. procedure Click; override;
  118. published
  119. property Action;
  120. property AutoCheck;
  121. property Caption;
  122. property CharCase: TEditCharCase read FCharCase write SetCharCase default ecNormal;
  123. property Checked;
  124. property DisplayMode;
  125. property EditCaption: String read FEditCaption write SetEditCaption stored IsEditCaptionStored;
  126. property EditOptions: TTBEditItemOptions read FEditOptions write SetEditOptions stored IsEditOptionsStored;
  127. property EditWidth: Integer read FEditWidth write SetEditWidth stored IsEditWidthStored;
  128. property MaxLength: Integer read FMaxLength write SetMaxLength default 0;
  129. property Enabled;
  130. property GroupIndex;
  131. property HelpContext;
  132. property Hint;
  133. property ImageIndex;
  134. property RadioItem;
  135. property ShortCut;
  136. property Text: String read FText write SetText stored IsTextStored;
  137. property Visible;
  138. property OnAcceptText: TTBAcceptTextEvent read FOnAcceptText write FOnAcceptText;
  139. property OnBeginEdit: TTBBeginEditEvent read FOnBeginEdit write FOnBeginEdit;
  140. property OnClick;
  141. property OnSelect;
  142. end;
  143. TEditClass = class of TEdit;
  144. TTBEditItemViewer = class(TTBItemViewer)
  145. private
  146. FEditControl: TEdit;
  147. FEditControlStatus: set of (ecsContinueLoop, ecsAccept, ecsClose);
  148. function EditLoop(const CapHandle: HWND): Boolean;
  149. procedure EditWndProc(var Message: TMessage);
  150. procedure MouseBeginEdit;
  151. protected
  152. procedure CalcSize(const Canvas: TCanvas; var AWidth, AHeight: Integer);
  153. override;
  154. function CaptionShown: Boolean; override;
  155. function DoExecute: Boolean; override;
  156. function GetAccRole: Integer; override;
  157. function GetAccValue(var Value: WideString): Boolean; override;
  158. function GetCaptionText: String; override;
  159. procedure GetCursor(const Pt: TPoint; var ACursor: HCURSOR); override;
  160. function GetEditControlClass: TEditClass; virtual;
  161. procedure GetEditRect(var R: TRect); virtual;
  162. procedure MouseDown(Shift: TShiftState; X, Y: Integer;
  163. var MouseDownOnMenu: Boolean); override;
  164. procedure MouseUp(X, Y: Integer; MouseWasDownOnMenu: Boolean); override;
  165. procedure Paint(const Canvas: TCanvas; const ClientAreaRect: TRect;
  166. IsSelected, IsPushed, UseDisabledShadow: Boolean); override;
  167. function UsesSameWidth: Boolean; override;
  168. public
  169. property EditControl: TEdit read FEditControl;
  170. end;
  171. { TTBVisibilityToggleItem }
  172. TTBVisibilityToggleItem = class(TTBCustomItem)
  173. private
  174. FControl: TControl;
  175. procedure SetControl(Value: TControl);
  176. procedure UpdateProps;
  177. protected
  178. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  179. public
  180. procedure Click; override;
  181. procedure InitiateAction; override;
  182. published
  183. property Caption;
  184. property Control: TControl read FControl write SetControl;
  185. property DisplayMode;
  186. property Enabled;
  187. property HelpContext;
  188. property Hint;
  189. property ImageIndex;
  190. property Images;
  191. property InheritOptions;
  192. property MaskOptions;
  193. property Options;
  194. property ShortCut;
  195. property Visible;
  196. property OnClick;
  197. property OnSelect;
  198. end;
  199. implementation
  200. uses
  201. TB2Common, TB2Consts;
  202. const
  203. EditMenuTextMargin = 3;
  204. EditMenuMidWidth = 4;
  205. type
  206. TControlAccess = class(TControl);
  207. TEditAccess = class(TEdit);
  208. { TTBEditAction }
  209. constructor TTBEditAction.Create(AOwner: TComponent);
  210. begin
  211. inherited;
  212. FEditOptions := EditItemDefaultEditOptions;
  213. FEditWidth := EditItemDefaultEditWidth;
  214. DisableIfNoHandler := False;
  215. end;
  216. procedure TTBEditAction.SetEditCaption(Value: String);
  217. var
  218. I: Integer;
  219. begin
  220. if FEditCaption <> Value then begin
  221. for I := 0 to FClients.Count - 1 do
  222. if TBasicActionLink(FClients[I]) is TTBEditItemActionLink then
  223. TTBEditItemActionLink(FClients[I]).SetEditCaption(Value);
  224. FEditCaption := Value;
  225. Change;
  226. end;
  227. end;
  228. procedure TTBEditAction.SetEditOptions(Value: TTBEditItemOptions);
  229. var
  230. I: Integer;
  231. begin
  232. if FEditOptions <> Value then begin
  233. for I := 0 to FClients.Count - 1 do
  234. if TBasicActionLink(FClients[I]) is TTBEditItemActionLink then
  235. TTBEditItemActionLink(FClients[I]).SetEditOptions(Value);
  236. FEditOptions := Value;
  237. Change;
  238. end;
  239. end;
  240. procedure TTBEditAction.SetEditWidth(Value: Integer);
  241. var
  242. I: Integer;
  243. begin
  244. if FEditWidth <> Value then begin
  245. for I := 0 to FClients.Count - 1 do
  246. if TBasicActionLink(FClients[I]) is TTBEditItemActionLink then
  247. TTBEditItemActionLink(FClients[I]).SetEditWidth(Value);
  248. FEditWidth := Value;
  249. Change;
  250. end;
  251. end;
  252. procedure TTBEditAction.SetOnAcceptText(Value: TTBAcceptTextEvent);
  253. var
  254. I: Integer;
  255. begin
  256. if not MethodsEqual(TMethod(FOnAcceptText), TMethod(Value)) then begin
  257. for I := 0 to FClients.Count - 1 do
  258. if TBasicActionLink(FClients[I]) is TTBEditItemActionLink then
  259. TTBEditItemActionLink(FClients[I]).SetOnAcceptText(Value);
  260. FOnAcceptText := Value;
  261. Change;
  262. end;
  263. end;
  264. procedure TTBEditAction.SetText(Value: String);
  265. var
  266. I: Integer;
  267. begin
  268. if FText <> Value then begin
  269. for I := 0 to FClients.Count - 1 do
  270. if TBasicActionLink(FClients[I]) is TTBEditItemActionLink then
  271. TTBEditItemActionLink(FClients[I]).SetText(Value);
  272. FText := Value;
  273. Change;
  274. end;
  275. end;
  276. { TTBEditItemActionLink }
  277. procedure TTBEditItemActionLink.AssignClient(AClient: TObject);
  278. begin
  279. FClient := AClient as TTBEditItem;
  280. end;
  281. function TTBEditItemActionLink.IsEditCaptionLinked: Boolean;
  282. begin
  283. if Action is TTBEditAction then
  284. Result := TTBEditItem(FClient).EditCaption = TTBEditAction(Action).EditCaption
  285. else
  286. Result := False;
  287. end;
  288. function TTBEditItemActionLink.IsEditOptionsLinked: Boolean;
  289. begin
  290. if Action is TTBEditAction then
  291. Result := TTBEditItem(FClient).EditOptions = TTBEditAction(Action).EditOptions
  292. else
  293. Result := False;
  294. end;
  295. function TTBEditItemActionLink.IsEditWidthLinked: Boolean;
  296. begin
  297. if Action is TTBEditAction then
  298. Result := TTBEditItem(FClient).EditWidth = TTBEditAction(Action).EditWidth
  299. else
  300. Result := False;
  301. end;
  302. function TTBEditItemActionLink.IsOnAcceptTextLinked: Boolean;
  303. begin
  304. if Action is TTBEditAction then
  305. Result := MethodsEqual(TMethod(TTBEditItem(FClient).OnAcceptText),
  306. TMethod(TTBEditAction(Action).OnAcceptText))
  307. else
  308. Result := False;
  309. end;
  310. function TTBEditItemActionLink.IsTextLinked: Boolean;
  311. begin
  312. if Action is TTBEditAction then
  313. Result := TTBEditItem(FClient).Text = TTBEditAction(Action).Text
  314. else
  315. Result := False;
  316. end;
  317. procedure TTBEditItemActionLink.SetEditCaption(const Value: String);
  318. begin
  319. if IsEditCaptionLinked then TTBEditItem(FClient).EditCaption := Value;
  320. end;
  321. procedure TTBEditItemActionLink.SetEditOptions(Value: TTBEditItemOptions);
  322. begin
  323. if IsEditOptionsLinked then TTBEditItem(FClient).EditOptions := Value;
  324. end;
  325. procedure TTBEditItemActionLink.SetEditWidth(const Value: Integer);
  326. begin
  327. if IsEditWidthLinked then TTBEditItem(FClient).EditWidth := Value;
  328. end;
  329. procedure TTBEditItemActionLink.SetOnAcceptText(Value: TTBAcceptTextEvent);
  330. begin
  331. if IsOnAcceptTextLinked then TTBEditItem(FClient).OnAcceptText := Value;
  332. end;
  333. procedure TTBEditItemActionLink.SetText(const Value: String);
  334. begin
  335. if IsTextLinked then TTBEditItem(FClient).SetTextEx(Value , tcrActionLink);
  336. end;
  337. { TTBEditItem }
  338. constructor TTBEditItem.Create(AOwner: TComponent);
  339. begin
  340. inherited;
  341. FEditOptions := EditItemDefaultEditOptions;
  342. FEditWidth := EditItemDefaultEditWidth;
  343. end;
  344. procedure TTBEditItem.ActionChange(Sender: TObject; CheckDefaults: Boolean);
  345. begin
  346. inherited;
  347. if Action is TTBEditAction then
  348. with TTBEditAction(Sender) do
  349. begin
  350. if not CheckDefaults or (Self.EditCaption = '') then
  351. Self.EditCaption := EditCaption;
  352. if not CheckDefaults or (Self.EditOptions = []) then
  353. Self.EditOptions := EditOptions;
  354. if not CheckDefaults or (Self.Text = '') then
  355. Self.SetTextEx(Text, tcrActionLink);
  356. if not CheckDefaults or not Assigned(Self.OnAcceptText) then
  357. Self.OnAcceptText := OnAcceptText;
  358. end;
  359. end;
  360. function TTBEditItem.GetActionLinkClass: TTBCustomItemActionLinkClass;
  361. begin
  362. Result := TTBEditItemActionLink;
  363. end;
  364. function TTBEditItem.GetItemViewerClass(AView: TTBView): TTBItemViewerClass;
  365. begin
  366. if not(tboUseEditWhenVertical in EditOptions) and
  367. (AView.Orientation = tbvoVertical) then
  368. Result := inherited GetItemViewerClass(AView)
  369. else
  370. Result := TTBEditItemViewer;
  371. end;
  372. function TTBEditItem.NeedToRecreateViewer(AViewer: TTBItemViewer): Boolean;
  373. begin
  374. Result := GetItemViewerClass(AViewer.View) <> AViewer.ClassType;
  375. end;
  376. procedure TTBEditItem.Clear;
  377. begin
  378. Text := '';
  379. end;
  380. procedure TTBEditItem.Click;
  381. begin
  382. inherited;
  383. end;
  384. procedure TTBEditItem.DoBeginEdit(Viewer: TTBEditItemViewer);
  385. begin
  386. if Assigned(FOnBeginEdit) then
  387. FOnBeginEdit(Self, Viewer, Viewer.EditControl);
  388. end;
  389. function TTBEditItem.IsEditOptionsStored: Boolean;
  390. begin
  391. Result := (EditOptions <> EditItemDefaultEditOptions) and
  392. ((ActionLink = nil) or not(ActionLink is TTBEditItemActionLink) or
  393. not TTBEditItemActionLink(ActionLink).IsEditOptionsLinked);
  394. end;
  395. function TTBEditItem.IsEditCaptionStored: Boolean;
  396. begin
  397. Result := (ActionLink = nil) or not(ActionLink is TTBEditItemActionLink) or
  398. not TTBEditItemActionLink(ActionLink).IsEditCaptionLinked;
  399. end;
  400. function TTBEditItem.IsEditWidthStored: Boolean;
  401. begin
  402. Result := (EditWidth <> EditItemDefaultEditWidth) and
  403. ((ActionLink = nil) or not(ActionLink is TTBEditItemActionLink) or
  404. not TTBEditItemActionLink(ActionLink).IsEditWidthLinked);
  405. end;
  406. function TTBEditItem.IsTextStored: Boolean;
  407. begin
  408. Result := (ActionLink = nil) or not(ActionLink is TTBEditItemActionLink) or
  409. not TTBEditItemActionLink(ActionLink).IsTextLinked;
  410. end;
  411. procedure TTBEditItem.SetCharCase(Value: TEditCharCase);
  412. begin
  413. if FCharCase <> Value then begin
  414. FCharCase := Value;
  415. Text := Text; { update case }
  416. end;
  417. end;
  418. procedure TTBEditItem.SetEditOptions(Value: TTBEditItemOptions);
  419. begin
  420. if FEditOptions <> Value then begin
  421. FEditOptions := Value;
  422. Change(True);
  423. end;
  424. end;
  425. procedure TTBEditItem.SetEditCaption(Value: String);
  426. begin
  427. if FEditCaption <> Value then begin
  428. FEditCaption := Value;
  429. Change(True);
  430. end;
  431. end;
  432. procedure TTBEditItem.SetEditWidth(Value: Integer);
  433. begin
  434. if FEditWidth <> Value then begin
  435. FEditWidth := Value;
  436. Change(True);
  437. end;
  438. end;
  439. procedure TTBEditItem.SetMaxLength(Value: Integer);
  440. begin
  441. if FMaxLength <> Value then begin
  442. FMaxLength := Value;
  443. Change(False);
  444. end;
  445. end;
  446. function TTBEditItem.DoAcceptText(var NewText: string): Boolean;
  447. begin
  448. Result := True;
  449. if Assigned(FOnAcceptText) then FOnAcceptText(Self, NewText, Result);
  450. end;
  451. procedure TTBEditItem.DoTextChanging(const OldText: String; var NewText: String; Reason: Integer);
  452. begin
  453. case FCharCase of
  454. ecUpperCase: NewText := AnsiUpperCase(NewText);
  455. ecLowerCase: NewText := AnsiLowerCase(NewText);
  456. end;
  457. end;
  458. procedure TTBEditItem.DoTextChanged(Reason: Integer);
  459. begin
  460. end;
  461. procedure TTBEditItem.SetText(Value: String);
  462. begin
  463. DoTextChanging(FText, Value, tcrSetProperty);
  464. if FText <> Value then begin
  465. FText := Value;
  466. Change(False);
  467. DoTextChanged(tcrSetProperty);
  468. end;
  469. end;
  470. procedure TTBEditItem.SetTextEx(Value: String; Reason: Integer);
  471. begin
  472. DoTextChanging(FText, Value, Reason);
  473. if FText <> Value then begin
  474. FText := Value;
  475. Change(False);
  476. DoTextChanged(Reason);
  477. end;
  478. end;
  479. { TTBEditItemViewer }
  480. procedure TTBEditItemViewer.EditWndProc(var Message: TMessage);
  481. var
  482. Item: TTBEditItem;
  483. procedure AcceptText;
  484. var
  485. S: String;
  486. begin
  487. S := FEditControl.Text;
  488. if Item.DoAcceptText(S) then Item.SetTextEx(S, tcrEditControl);
  489. end;
  490. begin
  491. Item := TTBEditItem(Self.Item);
  492. if FEditControl = nil then
  493. Exit;
  494. if Message.Msg = WM_CHAR then
  495. case TWMChar(Message).CharCode of
  496. VK_TAB: begin
  497. FEditControlStatus := [ecsAccept];
  498. AcceptText;
  499. Exit;
  500. end;
  501. VK_RETURN: begin
  502. FEditControlStatus := [ecsAccept, ecsClose];
  503. AcceptText;
  504. Exit;
  505. end;
  506. VK_ESCAPE: begin
  507. FEditControlStatus := [];
  508. Exit;
  509. end;
  510. end;
  511. TEditAccess(FEditControl).WndProc(Message);
  512. if Message.Msg = WM_KILLFOCUS then begin
  513. { Someone has stolen the focus from us, so 'cancel mode'. (We have to
  514. handle WM_KILLFOCUS in addition to the upstream WM_CANCELMODE handling
  515. since we don't always hold the mouse capture.) }
  516. View.CancelMode;
  517. FEditControlStatus := [ecsClose];
  518. end;
  519. end;
  520. function TTBEditItemViewer.GetEditControlClass: TEditClass;
  521. begin
  522. Result := TEdit;
  523. end;
  524. procedure TTBEditItemViewer.GetEditRect(var R: TRect);
  525. var
  526. Item: TTBEditItem;
  527. DC: HDC;
  528. begin
  529. Item := TTBEditItem(Self.Item);
  530. DC := GetDC(0);
  531. try
  532. SelectObject(DC, View.GetFont.Handle);
  533. R := BoundsRect;
  534. if not View.IsToolbar and (Item.EditCaption <> '') then begin
  535. Inc(R.Left, GetTextWidth(DC, Item.EditCaption, True) +
  536. EditMenuMidWidth + EditMenuTextMargin * 2);
  537. end;
  538. finally
  539. ReleaseDC(0, DC);
  540. end;
  541. end;
  542. procedure TTBEditItemViewer.CalcSize(const Canvas: TCanvas;
  543. var AWidth, AHeight: Integer);
  544. var
  545. Item: TTBEditItem;
  546. DC: HDC;
  547. TextHeight, MinHeight: Integer;
  548. begin
  549. Item := TTBEditItem(Self.Item);
  550. DC := Canvas.Handle;
  551. TextHeight := GetTextHeight(DC);
  552. AWidth := Item.FEditWidth;
  553. AHeight := TextHeight;
  554. if not IsToolbarStyle and (Item.EditCaption <> '') then begin
  555. Inc(AWidth, GetTextWidth(DC, Item.EditCaption, True) + EditMenuMidWidth +
  556. EditMenuTextMargin * 2);
  557. end;
  558. MinHeight := AHeight + (EditMenuTextMargin * 2) + 1;
  559. if not IsToolbarStyle then
  560. Inc(AHeight, DivRoundUp(AHeight, 4));
  561. if AHeight < MinHeight then
  562. AHeight := MinHeight;
  563. end;
  564. function TTBEditItemViewer.CaptionShown: Boolean;
  565. begin
  566. Result := not IsToolbarStyle and inherited CaptionShown;
  567. end;
  568. function TTBEditItemViewer.GetCaptionText: String;
  569. begin
  570. Result := TTBEditItem(Item).EditCaption;
  571. end;
  572. procedure TTBEditItemViewer.Paint(const Canvas: TCanvas;
  573. const ClientAreaRect: TRect; IsSelected, IsPushed, UseDisabledShadow: Boolean);
  574. const
  575. FillColors: array[Boolean] of TColor = (clBtnFace, clWindow);
  576. TextColors: array[Boolean] of TColor = (clGrayText, clWindowText);
  577. var
  578. Item: TTBEditItem;
  579. S: String;
  580. R: TRect;
  581. W: Integer;
  582. begin
  583. Item := TTBEditItem(Self.Item);
  584. R := ClientAreaRect;
  585. { Caption }
  586. if not IsToolbarStyle and (Item.EditCaption <> '') then begin
  587. S := Item.EditCaption;
  588. W := GetTextWidth(Canvas.Handle, S, True) + EditMenuTextMargin * 2;
  589. R.Right := R.Left + W;
  590. if IsSelected then
  591. Canvas.FillRect(R);
  592. Inc(R.Left, EditMenuTextMargin);
  593. DrawItemCaption(Canvas, R, S, UseDisabledShadow, DT_SINGLELINE or
  594. DT_LEFT or DT_VCENTER);
  595. R := ClientAreaRect;
  596. Inc(R.Left, W + EditMenuMidWidth);
  597. end;
  598. { Border }
  599. if IsSelected and Item.Enabled then
  600. DrawEdge(Canvas.Handle, R, BDR_SUNKENOUTER, BF_RECT);
  601. InflateRect(R, -1, -1);
  602. Canvas.Brush.Color := FillColors[not Item.Enabled];
  603. Canvas.FrameRect(R);
  604. InflateRect(R, -1, -1);
  605. { Fill }
  606. Canvas.Brush.Color := FillColors[Item.Enabled];
  607. Canvas.FillRect(R);
  608. InflateRect(R, -1, -1);
  609. { Text }
  610. if Item.Text <> '' then begin
  611. S := Item.Text;
  612. Canvas.Brush.Style := bsClear; { speed optimization }
  613. Canvas.Font.Color := TextColors[Item.Enabled];
  614. DrawText(Canvas.Handle, PChar(S), Length(S), R, DT_SINGLELINE or DT_NOPREFIX);
  615. end;
  616. end;
  617. procedure TTBEditItemViewer.GetCursor(const Pt: TPoint; var ACursor: HCURSOR);
  618. var
  619. R: TRect;
  620. begin
  621. if not Item.Enabled then
  622. Exit;
  623. GetEditRect(R);
  624. OffsetRect(R, -BoundsRect.Left, -BoundsRect.Top);
  625. InflateRect(R, -2, -2);
  626. if PtInRect(R, Pt) then
  627. ACursor := LoadCursor(0, IDC_IBEAM);
  628. end;
  629. function TTBEditItemViewer.EditLoop(const CapHandle: HWND): Boolean;
  630. procedure ControlMessageLoop;
  631. function PointInWindow(const Wnd: HWND; const P: TPoint): Boolean;
  632. var
  633. W: HWND;
  634. begin
  635. Result := False;
  636. W := WindowFromPoint(P);
  637. if W = 0 then Exit;
  638. if W = Wnd then
  639. Result := True
  640. else
  641. if IsChild(Wnd, W) then
  642. Result := True;
  643. end;
  644. function ContinueLoop: Boolean;
  645. begin
  646. Result := (ecsContinueLoop in FEditControlStatus) and
  647. not View.IsModalEnding and FEditControl.Focused and Item.Enabled;
  648. { Note: View.IsModalEnding is checked since TTBView.CancelMode doesn't
  649. destroy popup windows; it merely hides them and calls EndModal. So if
  650. IsModalEnding returns True we can infer that CancelMode was likely
  651. called. }
  652. end;
  653. var
  654. Msg: TMsg;
  655. IsKeypadDigit: Boolean;
  656. V: Integer;
  657. begin
  658. try
  659. while ContinueLoop do begin
  660. { Examine the next message before popping it out of the queue }
  661. if not PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then begin
  662. WaitMessage;
  663. Continue;
  664. end;
  665. case Msg.message of
  666. WM_SYSKEYDOWN: begin
  667. { Exit immediately if Alt+[key] or F10 are pressed, but not
  668. Alt+Shift, Alt+`, or Alt+[keypad digit] }
  669. if (Msg.wParam <> VK_MENU) and (Msg.wParam <> VK_SHIFT) and
  670. (Msg.wParam <> VK_HANJA) then begin
  671. IsKeypadDigit := False;
  672. { This detect digits regardless of whether Num Lock is on: }
  673. if Lo(LongRec(Msg.lParam).Hi) <> 0 then
  674. for V := VK_NUMPAD0 to VK_NUMPAD9 do
  675. if MapVirtualKey(V, 0) = Lo(LongRec(Msg.lParam).Hi) then begin
  676. IsKeypadDigit := True;
  677. Break;
  678. end;
  679. if not IsKeypadDigit then begin
  680. FEditControlStatus := [ecsClose];
  681. Exit;
  682. end;
  683. end;
  684. end;
  685. WM_SYSKEYUP: begin
  686. { Exit when Alt is released by itself }
  687. if Msg.wParam = VK_MENU then begin
  688. FEditControlStatus := [ecsClose];
  689. Exit;
  690. end;
  691. end;
  692. WM_LBUTTONDOWN, WM_LBUTTONDBLCLK,
  693. WM_RBUTTONDOWN, WM_RBUTTONDBLCLK,
  694. WM_MBUTTONDOWN, WM_MBUTTONDBLCLK,
  695. WM_NCLBUTTONDOWN, WM_NCLBUTTONDBLCLK,
  696. WM_NCRBUTTONDOWN, WM_NCRBUTTONDBLCLK,
  697. WM_NCMBUTTONDOWN, WM_NCMBUTTONDBLCLK: begin
  698. { If a mouse click outside the edit control is in the queue,
  699. exit and let the upstream message loop deal with it }
  700. if Msg.hwnd <> FEditControl.Handle then
  701. Exit;
  702. end;
  703. WM_MOUSEMOVE, WM_NCMOUSEMOVE: begin
  704. if GetCapture = CapHandle then begin
  705. if PointInWindow(FEditControl.Handle, Msg.pt) then
  706. ReleaseCapture;
  707. end
  708. else if GetCapture = 0 then begin
  709. if not PointInWindow(FEditControl.Handle, Msg.pt) then
  710. SetCapture(CapHandle);
  711. end;
  712. if GetCapture = CapHandle then
  713. SetCursor(LoadCursor(0, IDC_ARROW));
  714. end;
  715. end;
  716. { Now pop the message out of the queue }
  717. if not PeekMessage(Msg, 0, Msg.message, Msg.message, PM_REMOVE or PM_NOYIELD) then
  718. Continue;
  719. if ((Msg.message >= WM_MOUSEFIRST) and (Msg.message <= WM_MOUSELAST)) and
  720. (Msg.hwnd = CapHandle) then
  721. { discard, so that the selection doesn't get changed }
  722. else begin
  723. TranslateMessage(Msg);
  724. DispatchMessage(Msg);
  725. end;
  726. end;
  727. finally
  728. { Make sure there are no outstanding WM_*CHAR messages }
  729. RemoveMessages(WM_CHAR, WM_DEADCHAR);
  730. RemoveMessages(WM_SYSCHAR, WM_SYSDEADCHAR);
  731. end;
  732. end;
  733. var
  734. Item: TTBEditItem;
  735. R: TRect;
  736. ActiveWnd, FocusWnd: HWND;
  737. S: string;
  738. begin
  739. Item := TTBEditItem(Self.Item);
  740. GetEditRect(R);
  741. if IsRectEmpty(R) then begin
  742. Result := False;
  743. Exit;
  744. end;
  745. ActiveWnd := GetActiveWindow;
  746. FocusWnd := GetFocus;
  747. { Create the edit control }
  748. InflateRect(R, -3, -3);
  749. //View.FreeNotification (Self);
  750. FEditControl := GetEditControlClass.Create(nil);
  751. try
  752. FEditControl.Name := Format('%s_edit_control_%p', [ClassName,
  753. Pointer(FEditControl)]);
  754. FEditControl.Visible := False;
  755. FEditControl.BorderStyle := bsNone;
  756. FEditControl.AutoSize := False;
  757. FEditControl.Font.Assign(View.GetFont);
  758. FEditControl.Text := Item.Text;
  759. FEditControl.CharCase := Item.FCharCase;
  760. FEditControl.MaxLength := Item.FMaxLength;
  761. FEditControl.BoundsRect := R;
  762. FEditControl.WindowProc := EditWndProc;
  763. FEditControl.ParentWindow := View.Window.Handle;
  764. FEditControl.SelectAll;
  765. Item.DoBeginEdit(Self);
  766. FEditControl.Visible := True;
  767. FEditControl.SetFocus;
  768. if GetActiveWindow <> ActiveWnd then
  769. { don't gray out title bar of old active window }
  770. SendMessage(ActiveWnd, WM_NCACTIVATE, 1, 0)
  771. else
  772. ActiveWnd := 0;
  773. FEditControlStatus := [ecsContinueLoop];
  774. ControlMessageLoop;
  775. finally
  776. S := FEditControl.Text;
  777. FreeAndNil(FEditControl);
  778. end;
  779. with TTBEditItem(Item) do
  780. if (FEditControlStatus = [ecsContinueLoop]) and ExtendedAccept then
  781. if DoAcceptText(S) then SetTextEx(S, tcrEditControl);
  782. { ensure the area underneath the edit control is repainted immediately }
  783. View.Window.Update;
  784. { If app is still active, set focus to previous control and restore capture
  785. to CapHandle if another control hasn't taken it }
  786. if GetActiveWindow <> 0 then begin
  787. SetFocus(FocusWnd);
  788. if GetCapture = 0 then
  789. SetCapture(CapHandle);
  790. end;
  791. if ActiveWnd <> 0 then
  792. SendMessage(ActiveWnd, WM_NCACTIVATE, Ord(GetActiveWindow = ActiveWnd), 0);
  793. { The SetFocus call above can change the Z order of windows. If the parent
  794. window is a popup window, reassert its topmostness. }
  795. if View.Window is TTBPopupWindow then
  796. SetWindowPos(View.Window.Handle, HWND_TOPMOST, 0, 0, 0, 0,
  797. SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
  798. { Send an MSAA "focus" event now that we're returning to the regular modal loop }
  799. View.NotifyFocusEvent;
  800. Result := ecsClose in FEditControlStatus;
  801. if not Result and (GetCapture = CapHandle) then begin
  802. if ecsAccept in FEditControlStatus then
  803. { if we are accepting but not closing, Tab must have been pressed }
  804. View.Selected := View.NextSelectable(View.Selected,
  805. GetKeyState(VK_SHIFT) >= 0);
  806. end;
  807. end;
  808. function TTBEditItemViewer.DoExecute: Boolean;
  809. begin
  810. { Close any delay-close popup menus before entering the edit loop }
  811. View.CancelChildPopups;
  812. Result := False;
  813. if EditLoop(View.GetCaptureWnd) then begin
  814. View.EndModal;
  815. if ecsAccept in FEditControlStatus then
  816. Result := True;
  817. end;
  818. end;
  819. procedure TTBEditItemViewer.MouseBeginEdit;
  820. begin
  821. if Item.Enabled then
  822. Execute(True)
  823. else begin
  824. if (View.ParentView = nil) and not View.IsPopup then
  825. View.EndModal;
  826. end;
  827. end;
  828. procedure TTBEditItemViewer.MouseDown(Shift: TShiftState; X, Y: Integer;
  829. var MouseDownOnMenu: Boolean);
  830. begin
  831. if IsPtInButtonPart(X, Y) then { for TBX... }
  832. MouseBeginEdit
  833. else
  834. inherited;
  835. end;
  836. procedure TTBEditItemViewer.MouseUp(X, Y: Integer; MouseWasDownOnMenu: Boolean);
  837. begin
  838. if IsPtInButtonPart(X, Y) then { for TBX... }
  839. MouseBeginEdit
  840. else
  841. inherited;
  842. end;
  843. function TTBEditItemViewer.UsesSameWidth: Boolean;
  844. begin
  845. Result := False;
  846. end;
  847. function TTBEditItemViewer.GetAccRole: Integer;
  848. const
  849. ROLE_SYSTEM_TEXT = $2a; { from OleAcc.h }
  850. begin
  851. Result := ROLE_SYSTEM_TEXT;
  852. end;
  853. function TTBEditItemViewer.GetAccValue(var Value: WideString): Boolean;
  854. begin
  855. Value := TTBEditItem(Item).Text;
  856. Result := True;
  857. end;
  858. { TTBToolbarVisibilityItem }
  859. procedure TTBVisibilityToggleItem.Click;
  860. begin
  861. if Assigned(FControl) then
  862. FControl.Visible := not FControl.Visible;
  863. inherited;
  864. end;
  865. procedure TTBVisibilityToggleItem.InitiateAction;
  866. begin
  867. UpdateProps;
  868. end;
  869. procedure TTBVisibilityToggleItem.Notification(AComponent: TComponent;
  870. Operation: TOperation);
  871. begin
  872. inherited;
  873. if (Operation = opRemove) and (AComponent = FControl) then
  874. Control := nil;
  875. end;
  876. procedure TTBVisibilityToggleItem.SetControl(Value: TControl);
  877. begin
  878. if FControl <> Value then begin
  879. FControl := Value;
  880. if Assigned(Value) then begin
  881. Value.FreeNotification(Self);
  882. if (Caption = '') and not(csLoading in ComponentState) then
  883. Caption := TControlAccess(Value).Caption;
  884. end;
  885. UpdateProps;
  886. end;
  887. end;
  888. procedure TTBVisibilityToggleItem.UpdateProps;
  889. begin
  890. if (ComponentState * [csDesigning, csLoading, csDestroying] = []) then
  891. Checked := Assigned(FControl) and FControl.Visible;
  892. end;
  893. end.