FRxColorEditor.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit FRxColorEditor;
  5. (* RGB+Alpha color editor *)
  6. interface
  7. uses
  8. System.SysUtils,
  9. System.Types,
  10. System.UITypes,
  11. System.Classes,
  12. System.Variants,
  13. FMX.Types,
  14. FMX.Graphics,
  15. FMX.Controls,
  16. FMX.Forms,
  17. FMX.Dialogs,
  18. FMX.StdCtrls,
  19. FMX.Colors,
  20. FMX.Edit,
  21. FMX.Controls.Presentation,
  22. FMX.Objects,
  23. Stage.VectorTypes,
  24. Stage.VectorGeometry,
  25. GXS.Color,
  26. GXS.Texture;
  27. type
  28. TColorEditorFrame = class(TFrame)
  29. Label1: TLabel;
  30. Label2: TLabel;
  31. Label3: TLabel;
  32. Label4: TLabel;
  33. Panel1: TPanel;
  34. ColorEditorPaintBox: TPaintBox;
  35. RedEdit: TEdit;
  36. GreenEdit: TEdit;
  37. BlueEdit: TEdit;
  38. AlphaEdit: TEdit;
  39. PAPreview: TColorPanel;
  40. procedure TBEChange(Sender: TObject);
  41. procedure ColorEditorPaintBoxPaint(Sender: TObject; Canvas: TCanvas);
  42. procedure FrameResize(Sender: TObject);
  43. procedure ColorEditorPaintBoxMouseDown(Sender: TObject;
  44. Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  45. procedure ColorEditorPaintBoxMouseMove(Sender: TObject; Shift: TShiftState;
  46. X, Y: Single);
  47. procedure ColorEditorPaintBoxMouseUp(Sender: TObject; Button: TMouseButton;
  48. Shift: TShiftState; X, Y: Single);
  49. procedure RedEditChange(Sender: TObject);
  50. procedure GreenEditChange(Sender: TObject);
  51. procedure BlueEditChange(Sender: TObject);
  52. procedure AlphaEditChange(Sender: TObject);
  53. procedure PAPreviewDblClick(Sender: TObject);
  54. private
  55. FOnChange: TNotifyEvent;
  56. Updating: Boolean;
  57. WorkBitmap: TBitmap;
  58. RedValue: Integer;
  59. GreenValue: Integer;
  60. BlueValue: Integer;
  61. AlphaVAlue: Integer;
  62. DraggingValue: (None, Red, Green, Blue, Alpha);
  63. procedure SetColor(const val: THomogeneousFltVector);
  64. function GetColor: THomogeneousFltVector;
  65. procedure DrawContents;
  66. procedure DragColorSliderToPosition(XPos: Integer);
  67. procedure ContentsChanged;
  68. public
  69. constructor Create(AOwner: TComponent); override;
  70. destructor Destroy; override;
  71. property Color: THomogeneousFltVector read GetColor write SetColor;
  72. published
  73. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  74. end;
  75. // =====================================================================
  76. implementation
  77. // =====================================================================
  78. {$R *.fmx}
  79. const
  80. MaxColorValue = 255;
  81. MaxAlphaValue = 1000;
  82. ColorSliderLeft = 40;
  83. ColorSliderWidth = 128;
  84. ColorSliderHeight = 16;
  85. ColorViewHeight = 7;
  86. ColorSliderMaxValue = ColorSliderWidth - 2;
  87. RTop = 8;
  88. GTop = 30;
  89. BTop = 52;
  90. ATop = 74;
  91. PreviewPanelLeft = 216;
  92. PreviewPanelTop = 10;
  93. PreviewPanelWidth = 65;
  94. PreviewPanelHeight = 74;
  95. AlphaCheckSize = 9;
  96. AlphaChecksHigh = 4;
  97. AlphaChecksWide = 7;
  98. procedure TColorEditorFrame.TBEChange(Sender: TObject);
  99. begin
  100. PAPreview.Color := RedValue + (GreenValue Shl 8) + (BlueValue Shl 16); //RGB(RedValue, GreenValue, BlueValue);
  101. if (not Updating) and Assigned(FOnChange) then
  102. FOnChange(Self);
  103. end;
  104. procedure TColorEditorFrame.SetColor(const val: THomogeneousFltVector);
  105. begin
  106. RedValue := Round(val.X * 255);
  107. GreenValue := Round(val.Y * 255);
  108. BlueValue := Round(val.Z * 255);
  109. AlphaVAlue := Round(val.W * 1000);
  110. ContentsChanged;
  111. end;
  112. function TColorEditorFrame.GetColor: THomogeneousFltVector;
  113. begin
  114. Result := VectorMake(RedValue / 255, GreenValue / 255, BlueValue / 255,
  115. AlphaVAlue / 1000);
  116. end;
  117. procedure TColorEditorFrame.ColorEditorPaintBoxPaint(Sender: TObject;
  118. Canvas: TCanvas);
  119. begin
  120. ColorEditorPaintBox.Canvas.Bitmap.Assign(WorkBitmap);
  121. RedEdit.Height := 16;
  122. GreenEdit.Height := 16;
  123. BlueEdit.Height := 16;
  124. AlphaEdit.Height := 16;
  125. end;
  126. constructor TColorEditorFrame.Create(AOwner: TComponent);
  127. begin
  128. inherited;
  129. WorkBitmap := TBitmap.Create;
  130. (* in VCL
  131. WorkBitmap.PixelFormat := glpf24bit;
  132. WorkBitmap.Handle := TBitmapHandleType.bmDib;
  133. *)
  134. RedValue := 200;
  135. GreenValue := 120;
  136. BlueValue := 60;
  137. AlphaVAlue := 450;
  138. end;
  139. destructor TColorEditorFrame.Destroy;
  140. begin
  141. inherited;
  142. WorkBitmap.Free;
  143. end;
  144. procedure TColorEditorFrame.FrameResize(Sender: TObject);
  145. begin
  146. WorkBitmap.Width := Round(ColorEditorPaintBox.Width);
  147. WorkBitmap.Height := Round(ColorEditorPaintBox.Height);
  148. with WorkBitmap.Canvas do
  149. begin
  150. { TODO : rewright to use TPath and SVG drawing }
  151. (*
  152. Pen.Color := TColors.Lime;
  153. MoveTo(0,0);
  154. LineTo(Width-1,Height-1);
  155. MoveTo(Width-1,0);
  156. LineTo(0,Height-1);
  157. *)
  158. end;
  159. DrawContents;
  160. // Edits have an annoying habit of forgetting their height if they are small
  161. RedEdit.Height := 18;
  162. GreenEdit.Height := 18;
  163. BlueEdit.Height := 18;
  164. AlphaEdit.Height := 18;
  165. end;
  166. function ColorValueToColorViewPosition(ColorValue: Integer): Integer;
  167. begin
  168. Result := Round((ColorSliderMaxValue / (MaxColorValue + 1)) * ColorValue);
  169. end;
  170. function AlphaValueToColorViewPosition(AlphaVAlue: Integer): Integer;
  171. begin
  172. Result := Round((ColorSliderMaxValue / (MaxAlphaValue + 1)) * AlphaVAlue);
  173. end;
  174. function ColorViewPositionToColorValue(ColorViewPosition: Integer): Integer;
  175. begin
  176. if ColorViewPosition < 0 then
  177. ColorViewPosition := 0;
  178. if ColorViewPosition > ColorSliderMaxValue then
  179. ColorViewPosition := ColorSliderMaxValue;
  180. Result := Round(ColorViewPosition / (ColorSliderMaxValue / (MaxColorValue)));
  181. end;
  182. function ColorViewPositionToAlphaValue(ColorViewPosition: Integer): Integer;
  183. begin
  184. if ColorViewPosition < 0 then
  185. ColorViewPosition := 0;
  186. if ColorViewPosition > ColorSliderMaxValue then
  187. ColorViewPosition := ColorSliderMaxValue;
  188. Result := Round(ColorViewPosition / (ColorSliderMaxValue / (MaxAlphaValue)));
  189. end;
  190. procedure TColorEditorFrame.DrawContents;
  191. var
  192. Position: Integer;
  193. tx, ty: Integer;
  194. RViewColor: TColor;
  195. GViewColor: TColor;
  196. BViewColor: TColor;
  197. AViewColor: TColor;
  198. ViewLevel: Integer;
  199. WhiteCheckColor: TColor;
  200. BlackCheckColor: TColor;
  201. AValue: Single;
  202. ARect: TRectF;
  203. begin
  204. WorkBitmap.Canvas.Fill.Color := TColors.cBTNFACE;
  205. ARect := TRectF.Create(0, 0, WorkBitmap.Width, WorkBitmap.Height);
  206. WorkBitmap.Canvas.BeginScene;
  207. WorkBitmap.Canvas.FillRect(ARect, 20, 40, AllCorners, 100);
  208. WorkBitmap.Canvas.EndScene;
  209. { TODO : must be replaced with fmx font, brush and textout }
  210. (*
  211. Font.Color := TColors.Black;
  212. Font.Name := 'Arial';
  213. Font.Height := 14;
  214. TextOut(6,5,'Red');
  215. TextOut(6,26,'Green');
  216. TextOut(6,48,'Blue');
  217. TextOut(6,70,'Alpha');
  218. Brush.Color := TColors.Black;
  219. FrameRect(Rect(ColorSliderLeft,RTop,ColorSliderLeft+ColorSliderWidth,RTop+ColorViewHeight));
  220. FrameRect(Rect(ColorSliderLeft,GTop,ColorSliderLeft+ColorSliderWidth,GTop+ColorViewHeight));
  221. FrameRect(Rect(ColorSliderLeft,BTop,ColorSliderLeft+ColorSliderWidth,BTop+ColorViewHeight));
  222. FrameRect(Rect(ColorSliderLeft,ATop,ColorSliderLeft+ColorSliderWidth,ATop+ColorViewHeight));
  223. // Color View Frames
  224. Pen.Color := TColors.cBTNSHADOW;
  225. PolyLine([ Point(ColorSliderLeft-1,RTop+ColorViewHeight),
  226. Point(ColorSliderLeft-1,RTop-1),
  227. Point(ColorSliderLeft+ColorSliderWidth+1,RTop-1) ]);
  228. PolyLine([ Point(ColorSliderLeft-1,GTop+ColorViewHeight),
  229. Point(ColorSliderLeft-1,GTop-1),
  230. Point(ColorSliderLeft+ColorSliderWidth+1,GTop-1) ]);
  231. PolyLine([ Point(ColorSliderLeft-1,BTop+ColorViewHeight),
  232. Point(ColorSliderLeft-1,BTop-1),
  233. Point(ColorSliderLeft+ColorSliderWidth+1,BTop-1) ]);
  234. PolyLine([ Point(ColorSliderLeft-1,ATop+ColorViewHeight),
  235. Point(ColorSliderLeft-1,ATop-1),
  236. Point(ColorSliderLeft+ColorSliderWidth+1,ATop-1) ]);
  237. Pen.Color := TColors.cBTNHIGHLIGHT;
  238. PolyLine([ Point(ColorSliderLeft,RTop+ColorViewHeight),
  239. Point(ColorSliderLeft+ColorSliderWidth,RTop+ColorViewHeight),
  240. Point(ColorSliderLeft+ColorSliderWidth,RTop) ]);
  241. PolyLine([ Point(ColorSliderLeft,GTop+ColorViewHeight),
  242. Point(ColorSliderLeft+ColorSliderWidth,GTop+ColorViewHeight),
  243. Point(ColorSliderLeft+ColorSliderWidth,GTop) ]);
  244. PolyLine([ Point(ColorSliderLeft,BTop+ColorViewHeight),
  245. Point(ColorSliderLeft+ColorSliderWidth,BTop+ColorViewHeight),
  246. Point(ColorSliderLeft+ColorSliderWidth,BTop) ]);
  247. PolyLine([ Point(ColorSliderLeft,ATop+ColorViewHeight),
  248. Point(ColorSliderLeft+ColorSliderWidth,ATop+ColorViewHeight),
  249. Point(ColorSliderLeft+ColorSliderWidth,ATop) ]);
  250. // Color pointer triangles
  251. Pen.Color := clBlack;
  252. Position:=ColorValueToColorViewPosition(RedValue) + ColorSliderLeft;
  253. PolyLine([ Point(Position,RTop+ColorViewHeight+2),
  254. Point(Position+6,RTop+ColorViewHeight+8),
  255. Point(Position-6,RTop+ColorViewHeight+8),
  256. Point(Position,RTop+ColorViewHeight+2)]);
  257. Position:=ColorValueToColorViewPosition(GreenValue) + ColorSliderLeft;
  258. PolyLine([ Point(Position,GTop+ColorViewHeight+2),
  259. Point(Position+6,GTop+ColorViewHeight+8),
  260. Point(Position-6,GTop+ColorViewHeight+8),
  261. Point(Position,GTop+ColorViewHeight+2)]);
  262. Position:=ColorValueToColorViewPosition(BlueValue) + ColorSliderLeft;
  263. PolyLine([ Point(Position,BTop+ColorViewHeight+2),
  264. Point(Position+6,BTop+ColorViewHeight+8),
  265. Point(Position-6,BTop+ColorViewHeight+8),
  266. Point(Position,BTop+ColorViewHeight+2)]);
  267. Position:=AlphaValueToColorViewPosition(AlphaValue) + ColorSliderLeft;
  268. PolyLine([ Point(Position,ATop+ColorViewHeight+2),
  269. Point(Position+6,ATop+ColorViewHeight+8),
  270. Point(Position-6,ATop+ColorViewHeight+8),
  271. Point(Position,ATop+ColorViewHeight+2)]);
  272. // Color view spectrums
  273. For tx := 1 to ColorSliderWidth - 2 do
  274. begin
  275. ViewLevel := (tx * 256) div ColorSliderWidth;
  276. AViewColor := (ViewLevel) + (ViewLevel shl 8) + (viewLevel shl 16);
  277. RViewColor := (ViewLevel) + (GreenValue Shl 8) + (BlueValue Shl 16);
  278. GViewColor := (RedValue) + (ViewLevel shl 8) + (BlueValue Shl 16);
  279. BViewColor := (RedValue) + (GreenValue Shl 8) + (ViewLevel Shl 16);
  280. For ty := 1 to ColorViewHeight -2 do
  281. begin
  282. Pixels[ColorSliderLeft+tx,Rtop+Ty]:=RViewCOlor;
  283. Pixels[ColorSliderLeft+tx,Gtop+Ty]:=GViewColor;
  284. Pixels[ColorSliderLeft+tx,Btop+Ty]:=BViewColor;
  285. Pixels[ColorSliderLeft+tx,Atop+Ty]:=AViewColor;
  286. end;
  287. end;
  288. // Color preview panel
  289. Pen.Color := clBtnShadow;
  290. PolyLine([ Point(PreviewPanelLeft-1,PreviewPanelTop+PreviewPanelHeight),
  291. Point(PreviewPanelLeft-1,PreviewPanelTop-1),
  292. Point(PreviewPanelLeft+PreviewPanelWidth,PreviewPanelTop-1) ]);
  293. Pen.Color := clBtnHighlight;
  294. PolyLine([ Point(PreviewPanelLeft,PreviewPanelTop+PreviewPanelHeight),
  295. Point(PreviewPanelLeft+PreviewPanelWidth,PreviewPanelTop+PreviewPanelHeight),
  296. Point(PreviewPanelLeft+PreviewPanelWidth,PreviewPanelTop) ]);
  297. Brush.Color := (RedValue) + (GreenValue Shl 8) + (BlueValue Shl 16);
  298. Pen.Color := clBlack;
  299. Rectangle(Rect(PreviewPanelLeft,PreviewPanelTop,PreviewPanelLeft+PreviewPanelWidth,PreviewPanelTop+PreviewPanelHeight div 2 ) );
  300. PolyLine([ Point(PreviewPanelLeft,PreviewPanelTop+PreviewPanelHeight div 2 -1),
  301. Point(PreviewPanelLeft,PreviewPanelTop+PreviewPanelHeight -1),
  302. Point(PreviewPanelLeft+PreviewPanelWidth-1,PreviewPanelTop+PreviewPanelHeight-1),
  303. Point(PreviewPanelLeft+PreviewPanelWidth-1,PreviewPanelTop+PreviewPanelHeight div 2-1)
  304. ]);
  305. AValue := AlphaValue / MaxAlphaValue;
  306. BlackCheckColor := Round(RedValue * Avalue) + Round(GreenValue*AValue) shl 8 + Round(BlueValue*AValue) shl 16;
  307. WhiteCheckColor := Round(RedValue * Avalue + (255 * (1-AValue))) + Round(GreenValue*AValue + (255 * (1-AValue))) shl 8 + Round(BlueValue*AValue + (255 * (1-AValue))) shl 16;
  308. For ty := 0 to AlphaChecksHigh - 1 do
  309. begin
  310. For tx := 0 to AlphaChecksWide - 1 do
  311. begin
  312. if (tx+ty) and 1 = 0 then Brush.Color := BlackCheckColor else Brush.Color := WhiteCheckColor;
  313. FillRect(Rect( PreviewPanelLeft+1 + tx*AlphaCheckSize,
  314. PreviewPanelTop+PreviewPanelHeight Div 2 + ty*AlphaCheckSize,
  315. PreviewPanelLeft+1 + (tx+1)*AlphaCheckSize,
  316. PreviewPanelTop+PreviewPanelHeight Div 2 + (ty+1)*AlphaCheckSize
  317. ));
  318. end;
  319. end;
  320. *)
  321. end;
  322. procedure TColorEditorFrame.ColorEditorPaintBoxMouseDown(Sender: TObject;
  323. Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  324. begin
  325. DraggingValue := None;
  326. if Button = TMouseButton.mbLeft then
  327. begin
  328. if (X > ColorSliderLeft - 5) and
  329. (X < (ColorSliderLeft + ColorSliderMaxValue + 5)) then
  330. begin
  331. // In X range For Color Sliders
  332. If (Y > RTop) and ((RTop + ColorSliderHeight) > Y) then
  333. DraggingValue := Red;
  334. If (Y > GTop) and ((GTop + ColorSliderHeight) > Y) then
  335. DraggingValue := Green;
  336. If (Y > BTop) and ((BTop + ColorSliderHeight) > Y) then
  337. DraggingValue := Blue;
  338. If (Y > ATop) and ((ATop + ColorSliderHeight) > Y) then
  339. DraggingValue := Alpha;
  340. If DraggingValue <> None then
  341. DragColorSliderToPosition(Round(X) - ColorSliderLeft - 1);
  342. end
  343. end;
  344. end;
  345. procedure TColorEditorFrame.DragColorSliderToPosition(XPos: Integer);
  346. begin
  347. case DraggingValue of
  348. Red:
  349. RedValue := ColorViewPositionToColorValue(XPos);
  350. Green:
  351. GreenValue := ColorViewPositionToColorValue(XPos);
  352. Blue:
  353. BlueValue := ColorViewPositionToColorValue(XPos);
  354. Alpha:
  355. AlphaVAlue := ColorViewPositionToAlphaValue(XPos);
  356. end;
  357. ContentsChanged;
  358. end;
  359. procedure TColorEditorFrame.ContentsChanged;
  360. var
  361. ARect: TRectF;
  362. begin
  363. if Not Updating then
  364. begin
  365. Updating := True;
  366. DrawContents;
  367. ARect := TRectF.Create(0, 0, WorkBitmap.Width, WorkBitmap.Height);
  368. WorkBitmap.Canvas.BeginScene();
  369. ColorEditorPaintBox.Canvas.DrawBitmap(WorkBitmap, ARect, ARect, 50);
  370. WorkBitmap.Canvas.EndScene();
  371. RedEdit.Text := IntToStr(RedValue);
  372. GreenEdit.Text := IntToStr(GreenValue);
  373. BlueEdit.Text := IntToStr(BlueValue);
  374. AlphaEdit.Text := IntToStr(AlphaVAlue);
  375. PAPreview.Color := RedValue + (GreenValue Shl 8) + (BlueValue Shl 16);
  376. Updating := False;
  377. TBEChange(Self);
  378. end;
  379. end;
  380. procedure TColorEditorFrame.ColorEditorPaintBoxMouseMove(Sender: TObject;
  381. Shift: TShiftState; X, Y: Single);
  382. begin
  383. if DraggingValue <> None then
  384. DragColorSliderToPosition(Round(X) - ColorSliderLeft - 1);
  385. end;
  386. procedure TColorEditorFrame.ColorEditorPaintBoxMouseUp(Sender: TObject;
  387. Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  388. begin
  389. if Button = TMouseButton.mbLeft then
  390. DraggingValue := None;
  391. end;
  392. procedure TColorEditorFrame.RedEditChange(Sender: TObject);
  393. var
  394. IntValue: Integer;
  395. begin
  396. IntValue := StrToIntDef(RedEdit.Text, -1);
  397. If (IntValue < 0) or (IntValue > MaxColorValue) then
  398. begin
  399. RedEdit.TextSettings.FontColor := TColors.Red;
  400. end
  401. else
  402. begin
  403. RedEdit.TextSettings.FontColor := TColors.cWINDOW;
  404. RedValue := IntValue;
  405. ContentsChanged;
  406. end;
  407. end;
  408. procedure TColorEditorFrame.GreenEditChange(Sender: TObject);
  409. var
  410. IntValue: Integer;
  411. begin
  412. IntValue := StrToIntDef(GreenEdit.Text, -1);
  413. If (IntValue < 0) or (IntValue > MaxColorValue) then
  414. begin
  415. GreenEdit.TextSettings.FontColor := TColors.Red;
  416. end
  417. else
  418. begin
  419. GreenEdit.TextSettings.FontColor := TColors.cWINDOW;
  420. GreenValue := IntValue;
  421. ContentsChanged;
  422. end;
  423. end;
  424. procedure TColorEditorFrame.PAPreviewDblClick(Sender: TObject);
  425. begin
  426. SetColor(ConvertWinColor(PAPreview.Color));
  427. end;
  428. procedure TColorEditorFrame.BlueEditChange(Sender: TObject);
  429. var
  430. IntValue: Integer;
  431. begin
  432. IntValue := StrToIntDef(BlueEdit.Text, -1);
  433. If (IntValue < 0) or (IntValue > MaxColorValue) then
  434. begin
  435. BlueEdit.TextSettings.FontColor := TColors.Red;
  436. end
  437. else
  438. begin
  439. BlueEdit.TextSettings.FontColor := TColors.cWINDOW;
  440. BlueValue := IntValue;
  441. ContentsChanged;
  442. end;
  443. end;
  444. procedure TColorEditorFrame.AlphaEditChange(Sender: TObject);
  445. var
  446. IntValue: Integer;
  447. begin
  448. IntValue := StrToIntDef(AlphaEdit.Text, -1);
  449. If (IntValue < 0) or (IntValue > MaxAlphaValue) then
  450. begin
  451. AlphaEdit.TextSettings.FontColor := TColors.Red;
  452. end
  453. else
  454. begin
  455. AlphaEdit.TextSettings.FontColor := TColors.cWINDOW;
  456. AlphaVAlue := IntValue;
  457. ContentsChanged;
  458. end;
  459. end;
  460. end.