TB2ExtItems.pas 31 KB

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