SimplePropEdit.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. unit SimplePropEdit;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * The Original Code is Nested Sampling Example
  16. *
  17. * The Initial Developer of the Original Code is
  18. * Mattias Andersson <[email protected]>
  19. *
  20. * Portions created by the Initial Developer are Copyright (C) 2000-2005
  21. * the Initial Developer. All Rights Reserved.
  22. *
  23. * Contributor(s):
  24. * Michael Hansen <[email protected]>
  25. * Andre Beckedorf <[email protected]>
  26. *
  27. * ***** END LICENSE BLOCK ***** *)
  28. interface
  29. uses
  30. {$IFDEF FPC} LCLIntf, LResources, {$ELSE} Windows, {$ENDIF}
  31. Forms, Controls, StdCtrls, ExtCtrls, ComCtrls, Grids, Messages, Classes,
  32. Graphics, TypInfo, GR32_OrdinalMaps;
  33. const
  34. WM_SELECTOBJECT = WM_USER + 2000;
  35. type
  36. TWMSelectObject = packed record
  37. Msg: Cardinal;
  38. Unused: Longint;
  39. Obj: TPersistent;
  40. Result: Longint;
  41. end;
  42. PPropertyRangeEntry = ^TPropertyRangeEntry;
  43. TPropertyRangeEntry = record
  44. AClass: TClass;
  45. PropName: string;
  46. LoValue: Single;
  47. HiValue: Single;
  48. end;
  49. TSimplePropertyEditor = class(TCustomPanel)
  50. private
  51. FLabels: TList;
  52. FPropertyControls: TList;
  53. FPropertyRangeList: TList;
  54. FSelectedObject: TPersistent;
  55. FProps: PPropList;
  56. FCaption: string;
  57. procedure ButtonHandler(Sender: TObject);
  58. procedure TrackBarHandler(Sender: TObject);
  59. procedure ComboBoxHandler(Sender: TObject);
  60. procedure StringGridEditHandler(Sender: TObject; ACol, ARow: Longint; const Value: string);
  61. procedure WMSelectObject(var Msg: TWMSelectObject); message WM_SELECTOBJECT;
  62. protected
  63. function GetControlClass(Kind: TTypeKind): TPersistentClass; // TODO : Unused. What is its purpose?
  64. procedure Paint; override;
  65. public
  66. constructor Create(AOwner: TComponent); override;
  67. destructor Destroy; override;
  68. procedure RemoveSelectedObject;
  69. procedure SelectObject(ObjName: string; AObject: TPersistent);
  70. procedure RegisterClassPropertyRange(AClass: TClass; const PropName: string;
  71. LoValue, HiValue: Single);
  72. procedure GetPropertyRange(Instance: TObject; const PropName: string;
  73. out LoValue, HiValue: Single);
  74. end;
  75. const
  76. // scale trackbar min and max values for floating-point properties
  77. SCALE_FLOAT = 10000;
  78. implementation
  79. uses
  80. SysUtils, Math, GR32, GR32_Resamplers, GR32_LowLevel;
  81. { TSimplePropertyEditor }
  82. procedure TSimplePropertyEditor.ButtonHandler(Sender: TObject);
  83. var
  84. PropInfo: PPropInfo;
  85. Obj: TPersistent;
  86. begin
  87. PropInfo := FProps^[TComponent(Sender).Tag];
  88. Obj := TPersistent(GetObjectProp(FSelectedObject, string(PropInfo.Name)));
  89. PostMessage(Handle, WM_SELECTOBJECT, 0, Integer(Obj));
  90. end;
  91. procedure TSimplePropertyEditor.ComboBoxHandler(Sender: TObject);
  92. var
  93. PropInfo: PPropInfo;
  94. begin
  95. PropInfo := FProps[TComponent(Sender).Tag];
  96. with PropInfo^ do
  97. begin
  98. case PropType^.Kind of
  99. tkEnumeration:
  100. SetOrdProp(FSelectedObject, PropInfo, TComboBox(Sender).ItemIndex);
  101. end;
  102. end;
  103. end;
  104. constructor TSimplePropertyEditor.Create(AOwner: TComponent);
  105. begin
  106. inherited Create(AOwner);
  107. FPropertyControls := TList.Create;
  108. FLabels := TList.Create;
  109. FPropertyRangeList := TList.Create;
  110. BorderWidth := 1;
  111. BorderStyle := bsNone;
  112. {$IFNDEF FPC}
  113. Ctl3D := False;
  114. {$ENDIF}
  115. Color := clWhite;
  116. BevelInner := bvNone;
  117. BevelOuter := bvNone;
  118. Font.Size := 7;
  119. Font.Name := 'Verdana';
  120. end;
  121. destructor TSimplePropertyEditor.Destroy;
  122. var
  123. I: Integer;
  124. begin
  125. if Assigned(FSelectedObject) then
  126. RemoveSelectedObject;
  127. FPropertyControls.Free;
  128. FLabels.Free;
  129. for I := 0 to FPropertyRangeList.Count - 1 do
  130. Dispose(PPropertyRangeEntry(FPropertyRangeList.Items[I]));
  131. FPropertyRangeList.Clear;
  132. FPropertyRangeList.Free;
  133. inherited;
  134. end;
  135. function TSimplePropertyEditor.GetControlClass(
  136. Kind: TTypeKind): TPersistentClass;
  137. begin
  138. case Kind of
  139. tkInteger: Result := TEdit;
  140. tkClass: Result := TButton;
  141. else
  142. Result := TEdit;
  143. end;
  144. end;
  145. procedure TSimplePropertyEditor.GetPropertyRange(Instance: TObject;
  146. const PropName: string; out LoValue, HiValue: Single);
  147. var
  148. I: Integer;
  149. P: PPropertyRangeEntry;
  150. begin
  151. LoValue := 0;
  152. HiValue := 100;
  153. for I := 0 to FPropertyRangeList.Count - 1 do
  154. begin
  155. P := FPropertyRangeList.Items[I];
  156. if Instance is P.AClass then
  157. if P.PropName = PropName then
  158. begin
  159. LoValue := P.LoValue;
  160. HiValue := P.HiValue;
  161. Exit;
  162. end;
  163. end;
  164. end;
  165. procedure TSimplePropertyEditor.Paint;
  166. begin
  167. inherited;
  168. with Canvas do
  169. begin
  170. Brush.Color := clSilver;
  171. Pen.Color := clWhite;
  172. Font.Style := [fsBold];
  173. Font.Size := 8;
  174. Font.Name := 'Tahoma';
  175. if FCaption <> '' then
  176. TextRect(Rect(0, 0, Width, 18), 6, 2, FCaption);
  177. end;
  178. end;
  179. procedure TSimplePropertyEditor.RegisterClassPropertyRange(AClass: TClass;
  180. const PropName: string; LoValue, HiValue: Single);
  181. var
  182. P: PPropertyRangeEntry;
  183. begin
  184. New(P);
  185. P.AClass := AClass;
  186. P.PropName := PropName;
  187. P.LoValue := LoValue;
  188. P.HiValue := HiValue;
  189. FPropertyRangeList.Add(P);
  190. end;
  191. procedure TSimplePropertyEditor.RemoveSelectedObject;
  192. var
  193. I: Integer;
  194. begin
  195. for I := 0 to FPropertyControls.Count - 1 do
  196. begin
  197. if Assigned(FPropertyControls[I]) then
  198. TWinControl(FPropertyControls[I]).Free;
  199. if Assigned(Flabels[I]) then
  200. TLabel(FLabels[I]).Free;
  201. end;
  202. FPropertyControls.Clear;
  203. FLabels.Clear;
  204. if Assigned(FProps) then
  205. FreeMem(FProps);
  206. end;
  207. procedure TSimplePropertyEditor.SelectObject(ObjName: string; AObject: TPersistent);
  208. var
  209. I, L, K, Count, T, T1: Integer;
  210. Control: TWinControl;
  211. ALabel: TLabel;
  212. Map: TIntegerMap;
  213. LoValue, HiValue: Single;
  214. P: PPropInfo;
  215. TD: PTypeData;
  216. S, SelName: string;
  217. const
  218. ROW_SPACE = 30;
  219. TOP_MARGIN = 20;
  220. MARGIN_CONTROLS = TOP_MARGIN + 4;
  221. MARGIN_LABELS = TOP_MARGIN + 8;
  222. begin
  223. if Assigned(FSelectedObject) then
  224. RemoveSelectedObject;
  225. FSelectedObject := AObject;
  226. if not Assigned(AObject) then
  227. begin
  228. FCaption := '';
  229. Repaint;
  230. Exit;
  231. end;
  232. FCaption := ObjName + ': ' + AObject.ClassName;
  233. Count := GetTypeData(AObject.ClassInfo).PropCount;
  234. if AObject is TIntegerMap then
  235. begin
  236. Map := AObject as TIntegerMap;
  237. Control := TStringGrid.Create(nil);
  238. with TStringGrid(Control) do
  239. begin
  240. RowCount := 5;
  241. ColCount := 5;
  242. FixedCols := 0;
  243. FixedRows := 0;
  244. DefaultColWidth := 32;
  245. DefaultRowHeight := 16;
  246. Options := Options + [goEditing];
  247. for K := 0 to 4 do
  248. for L := 0 to 4 do
  249. Cells[K, L] := FloatToStr(Map[K, L] / 256);
  250. OnSetEditText := StringGridEditHandler;
  251. end;
  252. Control.Width := 168;
  253. Control.Height := 89;
  254. Control.Left := 12;
  255. Control.Top := MARGIN_CONTROLS + ROW_SPACE;
  256. Control.Parent := Self;
  257. FPropertyControls.Add(Control);
  258. ALabel := TLabel.Create(nil);
  259. ALabel.Caption := 'Kernel / Structuring Element:';
  260. ALabel.Left := 8;
  261. ALabel.Top := MARGIN_CONTROLS + 8;
  262. ALabel.Width := 84;
  263. ALabel.Parent := Self;
  264. FLabels.Add(ALabel);
  265. end;
  266. FProps := nil;
  267. if Count > 0 then
  268. begin
  269. GetMem(FProps, Count * SizeOf(PPropInfo));
  270. Count := GetPropList(AObject.ClassInfo, tkProperties, FProps);
  271. Self.Canvas.Brush.Color := Self.Color;
  272. T := MARGIN_CONTROLS;
  273. for I := 0 to Count - 1 do
  274. begin
  275. P := FProps[I];
  276. T1 := T;
  277. case P.PropType^.Kind of
  278. tkInteger, tkFloat:
  279. begin
  280. GetPropertyRange(AObject, string(P.Name), LoValue, HiValue);
  281. Control := TTrackBar.Create(nil);
  282. Control.Parent := Self;
  283. Control.Tag := I;
  284. FPropertyControls.Add(Control);
  285. with TTrackBar(Control) do
  286. begin
  287. if P.PropType^.Kind = tkInteger then
  288. begin
  289. Min := Round(LoValue);
  290. Max := Round(HiValue);
  291. Frequency := Math.Max(1, Round(HiValue - LoValue) div 20);
  292. Position := GetOrdProp(FSelectedObject, P)
  293. end
  294. else
  295. begin
  296. LoValue := LoValue * SCALE_FLOAT;
  297. HiValue := HiValue * SCALE_FLOAT;
  298. Min := Round(LoValue);
  299. Max := Round(HiValue);
  300. Frequency := Math.Max(1, Round((HiValue - LoValue) / 20));
  301. Position := Round(GetFloatProp(FSelectedObject, P) * SCALE_FLOAT);
  302. end;
  303. {$IFNDEF FPC}
  304. ThumbLength := 16;
  305. {$ENDIF}
  306. OnChange := TrackBarHandler;
  307. end;
  308. Control.Width := 98;
  309. Control.Height := 25;
  310. Control.Left := 88;
  311. Control.Top := T + 4;
  312. end;
  313. tkClass:
  314. begin
  315. Control := TButton.Create(nil);
  316. Control.Parent := Self;
  317. Control.Tag := I;
  318. FPropertyControls.Add(Control);
  319. TButton(Control).OnClick := ButtonHandler;
  320. TButton(Control).Caption := 'Edit';
  321. Control.Width := 60;
  322. Control.Height := 20;
  323. Control.Left := 90;
  324. Control.Top := T + 4;
  325. if GetObjectProp(FSelectedObject, P) = nil then
  326. Control.Enabled := False;
  327. end;
  328. tkEnumeration:
  329. begin
  330. Control := TComboBox.Create(nil);
  331. Control.Parent := Self;
  332. Control.Tag := I;
  333. FPropertyControls.Add(Control);
  334. TComboBox(Control).OnChange := ComboBoxHandler;
  335. TComboBox(Control).Style := csDropDownList;
  336. Control.Width := 100;
  337. Control.Height := 20;
  338. Control.Left := 90;
  339. Control.Top := T + 4;
  340. SelName := GetEnumProp(FSelectedObject, P);
  341. {$IFDEF FPC}
  342. TD := GetTypeData(P.PropType);
  343. {$ELSE}
  344. TD := GetTypeData(P.PropType^);
  345. {$ENDIF}
  346. L := 0;
  347. for K := TD.MinValue to TD.MaxValue do
  348. begin
  349. {$IFDEF FPC}
  350. S := GetEnumName(P.PropType, K);
  351. {$ELSE}
  352. S := GetEnumName(P.PropType^, K);
  353. {$ENDIF}
  354. if S = SelName then L := K;
  355. TComboBox(Control).AddItem(S, nil);
  356. end;
  357. TComboBox(Control).ItemIndex := L;
  358. end;
  359. else
  360. FPropertyControls.Add(nil);
  361. FLabels.Add(nil);
  362. Continue;
  363. end;
  364. ALabel := TLabel.Create(nil);
  365. ALabel.Caption := string(P.Name + ':');
  366. ALabel.Left := 0;
  367. ALabel.Top := T1 + 8;
  368. ALabel.Width := 84;
  369. ALabel.Alignment := taRightJustify;
  370. ALabel.Parent := Self;
  371. FLabels.Add(ALabel);
  372. Inc(T, ROW_SPACE);
  373. end;
  374. end;
  375. Repaint;
  376. end;
  377. procedure TSimplePropertyEditor.StringGridEditHandler(Sender: TObject;
  378. ACol, ARow: Integer; const Value: string);
  379. var
  380. Weights: TIntegerMap;
  381. W: Real;
  382. Code: Integer;
  383. begin
  384. Weights := FSelectedObject as TIntegerMap;
  385. Val(Value, W, Code);
  386. if Code = 0 then
  387. Weights[ACol, ARow] := Round(W * 256);
  388. end;
  389. procedure TSimplePropertyEditor.TrackBarHandler(Sender: TObject);
  390. var
  391. PropInfo: PPropInfo;
  392. begin
  393. PropInfo := FProps[TComponent(Sender).Tag];
  394. with PropInfo^ do
  395. begin
  396. case PropType^.Kind of
  397. tkInteger:
  398. SetOrdProp(FSelectedObject, PropInfo, TTrackBar(Sender).Position);
  399. tkFloat:
  400. SetFloatProp(FSelectedObject, PropInfo, TTrackBar(Sender).Position / SCALE_FLOAT);
  401. end;
  402. end;
  403. end;
  404. procedure TSimplePropertyEditor.WMSelectObject(var Msg: TWMSelectObject);
  405. begin
  406. SelectObject('Object', Msg.Obj);
  407. end;
  408. end.