FRColorEditor.pas 16 KB

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