GR32.Design.ColorPicker.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. unit GR32.Design.ColorPicker;
  2. (* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1 or LGPL 2.1 with linking exception
  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. * Alternatively, the contents of this file may be used under the terms of the
  16. * Free Pascal modified version of the GNU Lesser General Public License
  17. * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
  18. * of this license are applicable instead of those above.
  19. * Please see the file LICENSE.txt for additional information concerning this
  20. * license.
  21. *
  22. * The Original Code is Graphics32
  23. *
  24. * The Initial Developer of the Original Code is
  25. * Alex A. Denisov
  26. *
  27. * Portions created by the Initial Developer are Copyright (C) 2000-2009
  28. * the Initial Developer. All Rights Reserved.
  29. *
  30. * ***** END LICENSE BLOCK ***** *)
  31. interface
  32. {$include GR32.inc}
  33. uses
  34. Classes, SysUtils,
  35. {$IFDEF FPC}
  36. RTLConsts, LazIDEIntf, PropEdits, Graphics, Dialogs, Forms, Spin, ExtCtrls,
  37. StdCtrls, Controls,
  38. {$ifdef MSWINDOWS}
  39. Windows, Registry,
  40. {$ENDIF}
  41. {$ELSE}
  42. Consts,
  43. DesignIntf, DesignEditors, VCLEditors, StdCtrls, Controls,
  44. Windows, Registry, Graphics, Dialogs, Forms, ExtCtrls, Spin,
  45. {$ENDIF}
  46. GR32, GR32_ColorPicker, GR32_ColorSwatch;
  47. type
  48. TFormColorPicker = class(TForm)
  49. ButtonCancel: TButton;
  50. ButtonOK: TButton;
  51. ButtonPickFromScreen: TButton;
  52. CheckBoxWebSafe: TCheckBox;
  53. PanelColorPickerMain: TPanel;
  54. EditColor: TEdit;
  55. LabelAlpha: TLabel;
  56. LabelBlue: TLabel;
  57. LabelGreen: TLabel;
  58. LabelPreview: TLabel;
  59. LabelRed: TLabel;
  60. LabelWebColor: TLabel;
  61. PanelControl: TPanel;
  62. SpinEditAlpha: TSpinEdit;
  63. SpinEditBlue: TSpinEdit;
  64. SpinEditGreen: TSpinEdit;
  65. SpinEditRed: TSpinEdit;
  66. PanelPreview: TPanel;
  67. PanelSwatches: TPanel;
  68. procedure ButtonPickFromScreenClick(Sender: TObject);
  69. procedure ColorPickerChanged(Sender: TObject);
  70. procedure SpinEditColorChange(Sender: TObject);
  71. procedure CheckBoxWebSafeClick(Sender: TObject);
  72. procedure EditColorChange(Sender: TObject);
  73. procedure ColorSwatchClick(Sender: TObject);
  74. private
  75. FColor: TColor32;
  76. FScreenColorPickerForm: TScreenColorPickerForm;
  77. FColorPickerAlpha: TColorPickerComponent;
  78. FColorPickerBlue: TColorPickerComponent;
  79. FColorPickerGreen: TColorPickerComponent;
  80. FColorPickerRed: TColorPickerComponent;
  81. FColorSwatch: TColorSwatch;
  82. FColorSwatchOpaque: TColorSwatch;
  83. FColorPickerGTK: TColorPickerGTK;
  84. FLockChanged: integer;
  85. procedure UpdateColor;
  86. procedure ScreenColorPickerMouseMove(Sender: TObject; Shift: TShiftState; X,
  87. Y: Integer);
  88. procedure SetColor32(const Value: TColor32);
  89. public
  90. constructor Create(AOwner: TComponent); override;
  91. function Execute: boolean;
  92. property Color: TColor32 read FColor write SetColor32;
  93. end;
  94. implementation
  95. {$R *.dfm}
  96. { TFormColorPicker }
  97. constructor TFormColorPicker.Create(AOwner: TComponent);
  98. function CreateColorPickerComponent(ColorComponent: TColorComponent; ALabel: TLabel; AEdit: TControl): TColorPickerComponent;
  99. begin
  100. Result := TColorPickerComponent.Create(Self);
  101. Result.Left := ALabel.Left + ALabel.Width + 1;
  102. Result.Top := AEdit.Top;
  103. Result.Height := AEdit.Height;
  104. Result.Width := AEdit.Left - Result.Left - 8;
  105. Result.Cursor := crHandPoint;
  106. Result.Border := True;
  107. Result.ColorComponent := ColorComponent;
  108. Result.OnChanged := ColorPickerChanged;
  109. Result.Parent := Self;
  110. // Resize the label now that we don't need its width to align with anymore
  111. ALabel.AutoSize := True;
  112. end;
  113. const
  114. SwatchColors: array[0..7] of TColor32 =
  115. (clBlack32, clWhite32, clRed32, clLime32, clBlue32, clYellow32, clFuchsia32, clAqua32);
  116. var
  117. SwatchColor: TColor32;
  118. Swatch: TColorSwatch;
  119. PanelSpace: integer;
  120. NextPos: integer;
  121. begin
  122. inherited;
  123. // Create Graphics32 controls at run-time so we don't need to
  124. // have the design-time package installed before the form can
  125. // be opened.
  126. // This is only really done to avoid users messing up the form
  127. // if they open it before the package has been installed.
  128. FColorPickerRed := CreateColorPickerComponent(ccRed, LabelRed, SpinEditRed);
  129. FColorPickerGreen := CreateColorPickerComponent(ccGreen, LabelGreen, SpinEditGreen);
  130. FColorPickerBlue := CreateColorPickerComponent(ccBlue, LabelBlue, SpinEditBlue);
  131. FColorPickerAlpha := CreateColorPickerComponent(ccAlpha, LabelAlpha, SpinEditAlpha);
  132. FColorSwatch := TColorSwatch.Create(Self);
  133. FColorSwatch.Border := False;
  134. FColorSwatch.Width := (PanelPreview.Width-4) div 2;
  135. FColorSwatch.Align := alLeft;
  136. FColorSwatch.Parent := PanelPreview;
  137. FColorSwatchOpaque := TColorSwatch.Create(Self);
  138. FColorSwatchOpaque.Border := False;
  139. FColorSwatchOpaque.Width := (PanelPreview.Width-4) div 2;
  140. FColorSwatchOpaque.Align := alClient;
  141. FColorSwatchOpaque.Parent := PanelPreview;
  142. // Note: Swatch.Width = Swatch.Height = PanelSwatches.Height
  143. PanelSpace := PanelSwatches.Height + (PanelSwatches.Width - Length(SwatchColors) * PanelSwatches.Height) div (Length(SwatchColors)-1);
  144. NextPos := 0;
  145. for SwatchColor in SwatchColors do
  146. begin
  147. Swatch := TColorSwatch.Create(Self);
  148. Swatch.Cursor := crHandPoint;
  149. Swatch.Border := True;
  150. Swatch.Color := SwatchColor;
  151. Swatch.OnClick := ColorSwatchClick;
  152. Swatch.Height := PanelSwatches.Height;
  153. Swatch.Width := Swatch.Height;
  154. Swatch.Left := NextPos;
  155. Swatch.Parent := PanelSwatches;
  156. Inc(NextPos, PanelSpace);
  157. end;
  158. FColorPickerGTK := TColorPickerGTK.Create(Self);
  159. FColorPickerGTK.Align := alClient;
  160. FColorPickerGTK.Parent := PanelColorPickerMain;
  161. FColorPickerGTK.Cursor := crHandPoint;
  162. FColorPickerGTK.OnChanged := ColorPickerChanged;
  163. end;
  164. procedure TFormColorPicker.ButtonPickFromScreenClick(Sender: TObject);
  165. var
  166. SaveBounds: TRect;
  167. begin
  168. Invalidate;
  169. SaveBounds := BoundsRect;
  170. FScreenColorPickerForm := TScreenColorPickerForm.Create(nil);
  171. try
  172. FScreenColorPickerForm.OnMouseMove := ScreenColorPickerMouseMove;
  173. if FScreenColorPickerForm.Execute then
  174. Color := FScreenColorPickerForm.SelectedColor;
  175. finally
  176. FreeAndNil(FScreenColorPickerForm);
  177. end;
  178. BoundsRect := SaveBounds;
  179. end;
  180. procedure TFormColorPicker.CheckBoxWebSafeClick(Sender: TObject);
  181. begin
  182. FColorPickerGTK.WebSafe := CheckBoxWebSafe.Checked;
  183. FColorPickerRed.WebSafe := CheckBoxWebSafe.Checked;
  184. FColorPickerGreen.WebSafe := CheckBoxWebSafe.Checked;
  185. FColorPickerBlue.WebSafe := CheckBoxWebSafe.Checked;
  186. FColorPickerAlpha.WebSafe := CheckBoxWebSafe.Checked;
  187. end;
  188. procedure TFormColorPicker.ColorPickerChanged(Sender: TObject);
  189. begin
  190. if (FLockChanged > 0) then
  191. exit;
  192. Inc(FLockChanged);
  193. try
  194. if (Sender = FColorPickerGTK) then
  195. Color := SetAlpha(FColorPickerGTK.SelectedColor, TColor32Entry(FColorPickerAlpha.SelectedColor).A)
  196. else
  197. Color := Color32(
  198. TColor32Entry(FColorPickerRed.SelectedColor).R,
  199. TColor32Entry(FColorPickerGreen.SelectedColor).G,
  200. TColor32Entry(FColorPickerBlue.SelectedColor).B,
  201. TColor32Entry(FColorPickerAlpha.SelectedColor).A);
  202. finally
  203. Dec(FLockChanged);
  204. end;
  205. end;
  206. procedure TFormColorPicker.ColorSwatchClick(Sender: TObject);
  207. begin
  208. Color := TColorSwatch(Sender).Color;
  209. end;
  210. procedure TFormColorPicker.EditColorChange(Sender: TObject);
  211. var
  212. ColorText: string;
  213. Value: Integer;
  214. begin
  215. if (FLockChanged > 0) then
  216. exit;
  217. Inc(FLockChanged);
  218. try
  219. ColorText := StringReplace(EditColor.Text, '#', '$', []);
  220. if TryStrToInt(ColorText, Value) then
  221. Color := Value;
  222. finally
  223. Dec(FLockChanged);
  224. end;
  225. end;
  226. function TFormColorPicker.Execute: boolean;
  227. begin
  228. Result := (ShowModal = mrOK);
  229. end;
  230. procedure TFormColorPicker.ScreenColorPickerMouseMove(Sender: TObject;
  231. Shift: TShiftState; X, Y: Integer);
  232. var
  233. FormCenter: TPoint;
  234. const
  235. DMZ = 20;
  236. MoveSize = 80;
  237. procedure MoveHorizontally;
  238. begin
  239. if (FormCenter.X > X) then
  240. begin
  241. // We are to the right. Can we move more toward the right?
  242. if (BoundsRect.Right + MoveSize < Monitor.BoundsRect.Right) then
  243. Left := Left + MoveSize
  244. else
  245. // Move left of center instead
  246. Left := Monitor.BoundsRect.CenterPoint.X - Width;
  247. end else
  248. begin
  249. // We are to the left. Can we move more toward the left?
  250. if (BoundsRect.Left - MoveSize > Monitor.BoundsRect.Left) then
  251. Left := Left - MoveSize
  252. else
  253. // Move right of center instead
  254. Left := Monitor.BoundsRect.CenterPoint.X;
  255. end;
  256. end;
  257. procedure MoveVertically;
  258. begin
  259. if (FormCenter.Y > Y) then
  260. begin
  261. // We are at the bottom. Can we move more toward the bottom?
  262. if (BoundsRect.Bottom + MoveSize < Monitor.BoundsRect.Bottom) then
  263. Top := Top + MoveSize
  264. else
  265. // Move above center instead
  266. Top := Monitor.BoundsRect.CenterPoint.Y - Height;
  267. end else
  268. begin
  269. // We are to the top. Can we move more toward the top?
  270. if (BoundsRect.Top - MoveSize > Monitor.BoundsRect.Top) then
  271. Top := Top - MoveSize
  272. else
  273. // Move below center instead
  274. Top := Monitor.BoundsRect.CenterPoint.Y;
  275. end;
  276. end;
  277. var
  278. r: TRect;
  279. Collision: boolean;
  280. begin
  281. // Move ourself if we are getting in the way of the screen color picker
  282. r := BoundsRect;
  283. InflateRect(r, DMZ, DMZ);
  284. if (PtInRect(r, Point(X, Y))) then
  285. begin
  286. FormCenter := BoundsRect.CenterPoint;
  287. // Horizontal collision?
  288. Collision := (Abs(FormCenter.X - X) - Width <= DMZ);
  289. if (Collision) and (Y >= BoundsRect.Top) and (Y <= BoundsRect.Bottom) then
  290. begin
  291. MoveHorizontally;
  292. FormCenter := BoundsRect.CenterPoint;
  293. end;
  294. // Vertical collision?
  295. Collision := (Abs(FormCenter.Y - Y) - Height <= DMZ);
  296. if (Collision) and (X >= BoundsRect.Left) and (X <= BoundsRect.Right) then
  297. MoveVertically;
  298. end;
  299. Color := FScreenColorPickerForm.SelectedColor;
  300. Update;
  301. end;
  302. procedure TFormColorPicker.SetColor32(const Value: TColor32);
  303. begin
  304. if FColor <> Value then
  305. begin
  306. FColor := Value;
  307. UpdateColor;
  308. end;
  309. end;
  310. procedure TFormColorPicker.SpinEditColorChange(Sender: TObject);
  311. begin
  312. if (FLockChanged > 0) then
  313. exit;
  314. Inc(FLockChanged);
  315. try
  316. Color := Color32(SpinEditRed.Value, SpinEditGreen.Value, SpinEditBlue.Value, SpinEditAlpha.Value);
  317. finally
  318. Dec(FLockChanged);
  319. end;
  320. end;
  321. procedure TFormColorPicker.UpdateColor;
  322. var
  323. SelStart: Integer;
  324. begin
  325. // disable OnChange handler
  326. Inc(FLockChanged);
  327. try
  328. // update spin edits
  329. SpinEditRed.Value := TColor32Entry(FColor).R;
  330. SpinEditGreen.Value := TColor32Entry(FColor).G;
  331. SpinEditBlue.Value := TColor32Entry(FColor).B;
  332. SpinEditAlpha.Value := TColor32Entry(FColor).A;
  333. // update color edit
  334. SelStart := EditColor.SelStart;
  335. EditColor.Text := '$' + IntToHex(FColor, 8);
  336. EditColor.SelStart := SelStart;
  337. FColorPickerRed.SelectedColor := Color32(TColor32Entry(FColor).R, 0, 0);
  338. FColorPickerGreen.SelectedColor := Color32(0, TColor32Entry(FColor).G, 0);
  339. FColorPickerBlue.SelectedColor := Color32(0, 0, TColor32Entry(FColor).B);
  340. FColorPickerAlpha.SelectedColor := SetAlpha(clWhite32, TColor32Entry(FColor).A);
  341. FColorPickerGTK.SelectedColor := FColor;
  342. FColorSwatch.Color := FColor;
  343. FColorSwatchOpaque.Color := SetAlpha(FColor, 255);
  344. finally
  345. // re-enable OnChange handler
  346. Dec(FLockChanged);
  347. end;
  348. end;
  349. end.