TB2ExtItems.pas 31 KB

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