You've already forked lazarus-ccr
applications
bindings
components
Comba_Animation
aboutcomponent
acs
beepfp
callite
captcha
chelper
chemtext
cmdline
cmdlinecfg
colorpalette
cryptini
csvdocument
epiktimer
everettrandom
examplecomponent
exctrls
extrasyn
fpexif
fpsound
fpspreadsheet
fractions
freetypepascal
geckoport
gradcontrols
grid_semaphor
industrialstuff
iosdesigner
iphonelazext
jujiboutils
jvcllaz
kcontrols
lazautoupdate
lazbarcodes
lazmapviewer
lclextensions
longtimer
manualdock
mbColorLib
examples
BAxisColorPicker.pas
BColorPicker.pas
CColorPicker.pas
CIEAColorPicker.pas
CIEBColorPicker.pas
CIELColorPicker.pas
GAxisColorPicker.pas
GColorPicker.pas
HColorPicker.pas
HRingPicker.pas
HSCirclePicker.pas
HSColorPicker.pas
HSLColorPicker.pas
HSLRingPicker.pas
HTMLColors.pas
HexaColorPicker.pas
KColorPicker.pas
LVColorPicker.pas
MColorPicker.pas
OfficeMoreColorsDialog.lfm
OfficeMoreColorsDialog.pas
PalUtils.pas
PickCursor.res
RAxisColorPicker.pas
RColorPicker.pas
RGBCIEUtils.pas
RGBCMYKUtils.pas
RGBHSLUtils.pas
RGBHSVUtils.pas
Readme.rtf
SColorPicker.pas
SLColorPicker.pas
SLHColorPicker.pas
Scanlines.pas
ScreenWin.lfm
ScreenWin.pas
SelPropUtils.pas
XPLibIntegration.txt
YColorPicker.pas
clean.bat
clear history.bat
mbBasicPicker.pas
mbColorLibD10.dpk
mbColorLibD5.dpk
mbColorLibD7.dpk
mbColorLibD9.dpk
mbColorList.pas
mbColorPalette.pas
mbColorPickerControl.pas
mbColorPreview.pas
mbColorTree.pas
mbDeskPickerButton.pas
mbOfficeColorDialog.pas
mbReg.lrs
mbReg.pas
mbTrackBarPicker.pas
mbcolorconv.pas
mbcolorliblaz.lpk
mbutils.pas
mxs.inc
readme.txt
mplayer
multithreadprocs
nvidia-widgets
onguard
orpheus
playsoundpackage
poweredby
powerpdf
rgbgraphics
richmemo
richview
rtfview
rx
scrolltext
smnetgradient
spktoolbar
splashabout
svn
systools
tdi
thtmlport
tparadoxdataset
tvplanit
xdev_toolkit
zlibar
zmsql
examples
image_sources
lclbindings
wst
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8129 8e941d3f-bd1b-0410-a28a-d453659cc2b4
1427 lines
41 KiB
ObjectPascal
1427 lines
41 KiB
ObjectPascal
unit HexaColorPicker;
|
|
|
|
{$IFDEF FPC}
|
|
{$MODE DELPHI}
|
|
{$ENDIF}
|
|
|
|
interface
|
|
|
|
//{$I mxs.inc}
|
|
|
|
uses
|
|
LCLIntf, LCLType, LMessages, SysUtils, Classes, Controls, Graphics,
|
|
Forms, Themes, Math,
|
|
HTMLColors, mbBasicPicker;
|
|
|
|
const
|
|
CustomCell = -2;
|
|
NoCell = -1;
|
|
|
|
type
|
|
TMarker = (smArrow, smRect);
|
|
|
|
TCombEntry = record
|
|
Position: TPoint;
|
|
Color: COLORREF;
|
|
TabIndex: integer;
|
|
end;
|
|
|
|
TCombArray = array of TCombEntry;
|
|
|
|
TFloatPoint = record
|
|
X, Y: Extended;
|
|
end;
|
|
|
|
TRGBrec = record
|
|
Red, Green, Blue: Single;
|
|
end;
|
|
|
|
TSelectionMode = (smNone, smColor, smBW, smRamp);
|
|
|
|
THexaColorPicker = class(TmbBasicPicker)
|
|
private
|
|
FIncrement: integer;
|
|
FSelectedCombIndex: integer;
|
|
mX, mY: integer;
|
|
FHintFormat: string;
|
|
FUnderCursor: TColor;
|
|
//FOnChange,
|
|
FOnIntensityChange: TNotifyEvent;
|
|
FCurrentColor: TColor;
|
|
FSelectedIndex: Integer;
|
|
FColorCombRect, FBWCombRect, FSliderRect, FCustomColorRect: TRect;
|
|
FCombSize, FLevels: Integer;
|
|
FBWCombs, FColorCombs: TCombArray;
|
|
FCombCorners: array[0..5] of TFloatPoint;
|
|
FCenterColor: TRGBrec;
|
|
FCenterIntensity: Single;
|
|
FSliderWidth: integer;
|
|
FCustomIndex: Integer; // If FSelectedIndex contains CustomCell then this index shows
|
|
// which index in the custom area has been selected.
|
|
// Positive values indicate the color comb and negative values
|
|
// indicate the B&W combs (complement). This value is offset with
|
|
// 1 to use index 0 to show no selection.
|
|
FRadius: Integer;
|
|
FSelectionMode: TSelectionMode;
|
|
FSliderVisible: boolean;
|
|
FMarker: TMarker;
|
|
FNewArrowStyle: boolean;
|
|
FIntensityText: string;
|
|
procedure CalculateCombLayout;
|
|
procedure ChangeIntensity(increase: boolean);
|
|
procedure DrawAll;
|
|
procedure DrawComb(ACanvas: TCanvas; X, Y, Size: Integer);
|
|
procedure DrawCombControls(ACanvas: TCanvas);
|
|
procedure EndSelection;
|
|
procedure EnumerateCombs;
|
|
function FindBWArea(X, Y: Integer): Integer;
|
|
function FindColorArea(X, Y: Integer): Integer;
|
|
function GetIntensity: integer;
|
|
function GetNextCombIndex(i: integer): integer;
|
|
function GetPreviousCombIndex(i: integer): integer;
|
|
procedure HandleCustomColors(var Message: TLMMouse);
|
|
function HandleBWArea(const Message: TLMMouse): Boolean;
|
|
function HandleColorComb(const Message: TLMMouse): Boolean;
|
|
function HandleSlider(const Message: TLMMouse): Boolean;
|
|
procedure Initialize;
|
|
function PtInComb(Comb: TCombEntry; P: TPoint; Scale: Integer): Boolean;
|
|
procedure SetIntensity(v: integer);
|
|
procedure SetNewArrowStyle(Value: boolean);
|
|
procedure SetMarker(Value: TMarker);
|
|
procedure SetRadius(r: integer);
|
|
procedure SetSliderVisible(Value: boolean);
|
|
procedure SetSliderWidth(w: integer);
|
|
function SelectAvailableColor(Color: TColor): boolean;
|
|
procedure SelectColor(Color: TColor);
|
|
protected
|
|
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; override;
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
procedure Paint; override;
|
|
procedure Resize; override;
|
|
procedure SetSelectedColor(Value: TColor); override;
|
|
procedure CMHintShow(var Message: TLMessage); message CM_HINTSHOW;
|
|
procedure WMLButtonDown(var Message: TLMLButtonDown); message LM_LBUTTONDOWN;
|
|
procedure WMLButtonUp(var Message: TLMLButtonUp); message LM_LBUTTONUP;
|
|
procedure WMMouseMove(var Message: TLMMouseMove); message LM_MOUSEMOVE;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function GetColorAtPoint(X, Y: integer): TColor; override;
|
|
function GetColorUnderCursor: TColor; override;
|
|
function GetHexColorUnderCursor: string; override;
|
|
function GetHexColorAtPoint(X, Y: integer): string;
|
|
function GetSelectedCombIndex: integer;
|
|
procedure SelectCombIndex(i: integer);
|
|
property ColorUnderCursor: TColor read GetColorUnderCursor;
|
|
published
|
|
property Align;
|
|
property Anchors;
|
|
property HintFormat: string read FHintFormat write FHintFormat;
|
|
property Intensity: integer read GetIntensity write SetIntensity default 100;
|
|
property IntensityIncrement: integer read FIncrement write FIncrement default 1;
|
|
property IntensityText: string read FIntensityText write FIntensityText;
|
|
property NewArrowStyle: boolean read FNewArrowStyle write SetNewArrowStyle default false;
|
|
property SelectedColor: TColor read FCurrentColor write SetSelectedColor default clBlack;
|
|
property SliderVisible: boolean read FSliderVisible write SetSliderVisible default true;
|
|
property SliderWidth: integer read FSliderWidth write SetSliderWidth default 12;
|
|
property SliderMarker: TMarker read FMarker write SetMarker default smArrow;
|
|
property ShowHint default true;
|
|
property TabStop default true;
|
|
property Visible;
|
|
property Enabled;
|
|
property PopupMenu;
|
|
property TabOrder;
|
|
property Color;
|
|
property ParentColor;
|
|
property DragCursor;
|
|
property DragMode;
|
|
property DragKind;
|
|
property Constraints;
|
|
property OnChange; //: TNotifyEvent read FOnChange write FOnChange;
|
|
property OnIntensityChange: TNotifyEvent read FOnIntensityChange write FOnIntensityChange;
|
|
property OnDblClick;
|
|
property OnContextPopup;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnMouseWheel;
|
|
property OnMouseWheelUp;
|
|
property OnMouseWheelDown;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnEndDrag;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnResize;
|
|
property OnStartDrag;
|
|
end;
|
|
|
|
const
|
|
DefCenterColor: TRGBrec = (Red: 1; Green: 1; Blue: 1); // White
|
|
DefColors: array[0..5] of TRGBrec = (
|
|
(Red: 1; Green: 0; Blue: 1), // Magenta
|
|
(Red: 1; Green: 0; Blue: 0), // Red
|
|
(Red: 1; Green: 1; Blue: 0), // Yellow
|
|
(Red: 0; Green: 1; Blue: 0), // Green
|
|
(Red: 0; Green: 1; Blue: 1), // Cyan
|
|
(Red: 0; Green: 0; Blue: 1) // Blue
|
|
);
|
|
DefCenter: TFloatPoint = (X: 0; Y: 0);
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
PalUtils, mbUtils;
|
|
|
|
{ THexaColorPicker }
|
|
|
|
constructor THexaColorPicker.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
//ControlStyle := ControlStyle - [csAcceptsControls] + [csOpaque];
|
|
FRadius := 90;
|
|
FSliderWidth := 12;
|
|
DoubleBuffered := true;
|
|
SetInitialBounds(0, 0, 204, 204);
|
|
Constraints.MinHeight := 85;
|
|
Constraints.MinWidth := 93;
|
|
TabStop := true;
|
|
FSelectedCombIndex := 0;
|
|
FHintFormat := 'RGB(%r, %g, %b)'#13'Hex: #%hex';
|
|
ShowHint := True;
|
|
FSliderVisible := true;
|
|
FMarker := smArrow;
|
|
FNewArrowStyle := false;
|
|
Initialize;
|
|
DrawAll;
|
|
FIntensityText := 'Intensity';
|
|
{
|
|
MaxHue := 360;
|
|
MaxLum := 255;
|
|
MaxSat := 255;
|
|
}
|
|
end;
|
|
|
|
destructor THexaColorPicker.Destroy;
|
|
begin
|
|
FBWCombs := nil;
|
|
FColorCombs := nil;
|
|
// FBufferBmp.Free; is already destroyed by ancestor TmbBasicPicker
|
|
inherited;
|
|
end;
|
|
|
|
procedure THexaColorPicker.ChangeIntensity(increase: boolean);
|
|
var
|
|
i: integer;
|
|
begin
|
|
i := round(FCenterIntensity * 100);
|
|
if increase then
|
|
begin
|
|
Inc(i, FIncrement);
|
|
if i > 100 then i := 100;
|
|
SetIntensity(i);
|
|
end
|
|
else
|
|
begin
|
|
Dec(i, FIncrement);
|
|
if i < 0 then i := 0;
|
|
SetIntensity(i);
|
|
end;
|
|
end;
|
|
|
|
function THexaColorPicker.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
|
|
MousePos: TPoint): Boolean;
|
|
begin
|
|
Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos);
|
|
if not Result then
|
|
begin
|
|
Result := True;
|
|
ChangeIntensity(WheelDelta > 0);
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.DrawComb(ACanvas: TCanvas; X, Y: Integer; Size: Integer);
|
|
var
|
|
I: Integer;
|
|
P: array[0..5] of TPoint;
|
|
begin
|
|
for I := 0 to 5 do
|
|
begin
|
|
P[I].X := Round(FCombCorners[I].X * Size + X);
|
|
P[I].Y := Round(FCombCorners[I].Y * Size + Y);
|
|
end;
|
|
ACanvas.Polygon(P);
|
|
end;
|
|
|
|
procedure THexaColorPicker.DrawCombControls(ACanvas: TCanvas);
|
|
var
|
|
I, Index: Integer;
|
|
XOffs, YOffs, Count: Integer;
|
|
OffScreen: TBitmap;
|
|
R: TRect;
|
|
begin
|
|
OffScreen := TBitmap.Create;
|
|
try
|
|
OffScreen.Width := Width;
|
|
OffScreen.Height := HeightOfRect(FColorCombRect) + HeightOfRect(FBWCombRect);
|
|
|
|
//Parent background
|
|
if Color = clDefault then
|
|
begin
|
|
Offscreen.Transparent := true;
|
|
Offscreen.TransparentColor := clForm;
|
|
Offscreen.Canvas.Brush.Color := clForm
|
|
end else
|
|
OffScreen.Canvas.Brush.Color := Color;
|
|
OffScreen.Canvas.FillRect(OffScreen.Canvas.ClipRect);
|
|
|
|
with OffScreen.Canvas do
|
|
begin
|
|
Pen.Style := psClear;
|
|
|
|
// draw color combs from FColorCombs array
|
|
XOffs := FRadius + FColorCombRect.Left;
|
|
YOffs := FRadius + FColorCombRect.Top;
|
|
|
|
// draw the combs
|
|
for I := 0 to High(FColorCombs) do
|
|
begin
|
|
Brush.Color := FColorCombs[I].Color;
|
|
Pen.Mode := pmCopy; // the pen is set here so there are no gaps between the combs
|
|
Pen.Style := psSolid;
|
|
Pen.Color := FColorCombs[I].Color;
|
|
DrawComb(OffScreen.Canvas, FColorCombs[I].Position.X + XOffs, FColorCombs[I].Position.Y + YOffs, FCombSize);
|
|
end;
|
|
|
|
// mark selected comb
|
|
if FCustomIndex > 0 then
|
|
begin
|
|
Index := FCustomIndex - 1;
|
|
FSelectedCombIndex := index;
|
|
Pen.Style := psSolid;
|
|
{
|
|
Pen.Mode := pmXOR;
|
|
Pen.Color := clWhite;
|
|
}
|
|
Pen.Color := HighContrastColor(FColorCombs[Index].Color);
|
|
Pen.Width := 2;
|
|
Brush.Style := bsClear;
|
|
DrawComb(OffScreen.Canvas, FColorCombs[Index].Position.X + XOffs, FColorCombs[Index].Position.Y + YOffs, FCombSize);
|
|
Pen.Style := psClear;
|
|
Pen.Mode := pmCopy;
|
|
Pen.Width := 1;
|
|
end;
|
|
|
|
// draw white-to-black combs
|
|
XOffs := FColorCombRect.Left;
|
|
YOffs := FColorCombRect.Bottom - 4;
|
|
// brush is automatically reset to bsSolid
|
|
for I := 0 to High(FBWCombs) do
|
|
begin
|
|
Pen.Mode := pmCopy; // the pen is set here so there are no gaps between the combs
|
|
Pen.Style := psSolid;
|
|
Pen.Color := FBWCombs[I].Color;
|
|
Brush.Color := FBWCombs[I].Color;
|
|
if I in [0, High(FBWCombs)] then
|
|
begin
|
|
if Pen.Color = clWhite then // "white" needs a border if background is white as well
|
|
Pen.Color := clGray;
|
|
DrawComb(OffScreen.Canvas, FBWCombs[I].Position.X + XOffs, FBWCombs[I].Position.Y + YOffs, 2 * FCombSize)
|
|
end else
|
|
DrawComb(OffScreen.Canvas, FBWCombs[I].Position.X + XOffs, FBWCombs[I].Position.Y + YOffs, FCombSize);
|
|
end;
|
|
|
|
// mark selected comb
|
|
if FCustomIndex < 0 then
|
|
begin
|
|
Index := -(FCustomIndex + 1);
|
|
if index < 0 then
|
|
FSelectedCombIndex := Index
|
|
else
|
|
FSelectedCombIndex := -index;
|
|
Pen.Style := psSolid;
|
|
{
|
|
Pen.Mode := pmXOR;
|
|
Pen.Color := clWhite;
|
|
}
|
|
Pen.Mode := pmCopy;
|
|
Pen.Color := HighContrastColor(FBWCombs[Index].Color);
|
|
Pen.Width := 2;
|
|
Brush.Style := bsClear;
|
|
if Index in [0, High(FBWCombs)] then
|
|
begin
|
|
if Index = High(FBWCombs) then begin
|
|
Pen.Color := rgb(254, 254, 254); //clWhite;
|
|
Pen.Mode := pmXOR;
|
|
end;
|
|
if ((FColorCombs[0].Color = Cardinal(clWhite)) and (Index = 0)) or
|
|
((FColorCombs[0].Color = Cardinal(clBlack)) and (Index = High(FBWCombs)))
|
|
then
|
|
DrawComb(OffScreen.Canvas, FRadius + FColorCombRect.Left, FRadius + FColorCombRect.Top, FCombSize); // mark white or black center
|
|
DrawComb(OffScreen.Canvas, FBWCombs[Index].Position.X + XOffs, FBWCombs[Index].Position.Y + YOffs, 2 * FCombSize);
|
|
end
|
|
else
|
|
DrawComb(OffScreen.Canvas, FBWCombs[Index].Position.X + XOffs, FBWCombs[Index].Position.Y + YOffs, FCombSize);
|
|
Pen.Style := psClear;
|
|
Pen.Mode := pmCopy;
|
|
Pen.Width := 1;
|
|
end;
|
|
|
|
// Slider
|
|
if FSliderVisible then
|
|
begin
|
|
// center-color trackbar
|
|
R := FSliderRect;
|
|
R.Right := R.Left + FSliderWidth;
|
|
Pen.Style := psSolid;
|
|
GradientFill(R, clWhite, clBlack, gdVertical);
|
|
|
|
// draw marker
|
|
Count := FSliderRect.Bottom - FSliderRect.Top - 1;
|
|
XOffs := FSliderRect.Left + FSliderWidth + 1;
|
|
YOffs := FSliderRect.Top + Round(Count * (1 - FCenterIntensity));;
|
|
Pen.Color := clBlack;
|
|
case FMarker of
|
|
smArrow:
|
|
begin
|
|
if not FNewArrowStyle then
|
|
begin
|
|
Brush.Color := clBlack;
|
|
Polygon([
|
|
Point(XOffs, YOffs),
|
|
Point(XOffs + 6, YOffs - 4),
|
|
Point(XOffs + 6, YOffs + 4)
|
|
])
|
|
end
|
|
else
|
|
begin
|
|
Brush.Color := clWhite;
|
|
Pen.Color := clBtnShadow;
|
|
Polygon([
|
|
Point(XOffs, YOffs),
|
|
Point(XOffs + 4, YOffs - 4),
|
|
Point(XOffs + 6, YOffs - 4),
|
|
Point(XOffs + 7, YOffs - 3),
|
|
Point(XOffs + 7, YOffs + 3),
|
|
Point(XOffs + 6, YOffs + 4),
|
|
Point(XOffs + 4, YOffs + 4)]);
|
|
end;
|
|
end;
|
|
smRect:
|
|
begin
|
|
Brush.Style := bsClear;
|
|
Pen.Mode := pmNot;
|
|
Rectangle(XOffs - FSliderWidth - 4, YOffs - 3, XOffs + 2, YOffs + 3);
|
|
Pen.Mode := pmCopy;
|
|
Brush.Style := bsSolid;
|
|
end;
|
|
end; // case
|
|
Pen.Style := psClear;
|
|
end;
|
|
end;
|
|
ACanvas.Draw(0, 0, OffScreen);
|
|
finally
|
|
Offscreen.Free;
|
|
end;
|
|
EnumerateCombs;
|
|
end;
|
|
|
|
// Looks for a comb at position (X, Y) in the black&white area.
|
|
// Result is -1 if nothing could be found else the index of the particular comb
|
|
// into FBWCombs.
|
|
function THexaColorPicker.FindBWArea(X, Y: Integer): Integer;
|
|
var
|
|
I, Scale: Integer;
|
|
Pt: TPoint;
|
|
begin
|
|
Result := -1;
|
|
Pt := Point(X - FBWCombRect.Left, Y - FBWCombRect.Top);
|
|
for I := 0 to High(FBWCombs) do
|
|
begin
|
|
if I in [0, High(FBWCombs)] then
|
|
Scale := FCombSize
|
|
else
|
|
Scale := FCombSize div 2;
|
|
if PtInComb(FBWCombs[I], Pt, Scale) then
|
|
begin
|
|
Result := I;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// Looks for a comb at position (X, Y) in the custom color area.
|
|
// Result is -1 if nothing could be found else the index of the particular comb
|
|
// into FColorCombs.
|
|
function THexaColorPicker.FindColorArea(X, Y: Integer): Integer;
|
|
var
|
|
I: Integer;
|
|
Pt: TPoint;
|
|
begin
|
|
Result := -1;
|
|
Pt := Point(X - (FRadius + FColorCombRect.Left), Y - (FRadius + FColorCombRect.Top));
|
|
for I := 0 to High(FColorCombs) do
|
|
begin
|
|
if PtInComb(FColorCombs[I], Pt, FCombSize div 2) then
|
|
begin
|
|
Result := I;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function THexaColorPicker.GetIntensity: integer;
|
|
begin
|
|
Result := round(FCenterIntensity * 100);
|
|
end;
|
|
|
|
function THexaColorPicker.GetNextCombIndex(i: integer): integer;
|
|
begin
|
|
if i = 127 then
|
|
Result := -1
|
|
else
|
|
if i = -15 then
|
|
Result := 1
|
|
else
|
|
if i > 0 then
|
|
Result := i + 1
|
|
else
|
|
Result := i - 1;
|
|
end;
|
|
|
|
function THexaColorPicker.GetPreviousCombIndex(i: integer): integer;
|
|
begin
|
|
if i = 1 then
|
|
Result := -15
|
|
else
|
|
if i = -1 then
|
|
Result := 127
|
|
else
|
|
if i > 0 then
|
|
Result := i - 1
|
|
else
|
|
Result := i + 1;
|
|
end;
|
|
|
|
function THexaColorPicker.GetSelectedCombIndex: integer;
|
|
begin
|
|
if FSelectedCombIndex < 0 then
|
|
Result := FBWCombs[-FSelectedCombIndex].TabIndex
|
|
else
|
|
Result := FColorCombs[FSelectedCombIndex].TabIndex;
|
|
end;
|
|
|
|
// determines whether the mouse position is within the B&W comb area and acts accordingly
|
|
function THexaColorPicker.HandleBWArea(const Message: TLMMouse): Boolean;
|
|
var
|
|
Index: Integer;
|
|
Shift: TShiftState;
|
|
begin
|
|
Result := PtInRect(FBWCombRect, Point(Message.XPos, Message.YPos)) and (FSelectionMode in [smNone, smBW]);
|
|
if Result then
|
|
begin
|
|
Shift := KeysToShiftState(Message.Keys);
|
|
if ssLeft in Shift then
|
|
begin
|
|
FSelectionMode := smBW;
|
|
Index := FindBWArea(Message.XPos, Message.YPos);
|
|
if Index > -1 then
|
|
begin
|
|
// remove selection comb if it was previously in color comb
|
|
if FCustomIndex > 0 then InvalidateRect(Handle, @FColorCombRect, False);
|
|
if FCustomIndex <> -(Index + 1) then
|
|
begin
|
|
FCustomIndex := -(Index + 1);
|
|
InvalidateRect(Handle, @FBWCombRect, False);
|
|
InvalidateRect(Handle, @FCustomColorRect, False);
|
|
EndSelection;
|
|
end;
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// determines whether the mouse position is within the color comb area and acts accordingly
|
|
function THexaColorPicker.HandleColorComb(const Message: TLMMouse): Boolean;
|
|
var
|
|
Index: Integer;
|
|
Shift: TShiftState;
|
|
begin
|
|
Result := PtInRect(FColorCombRect, Point(Message.XPos, Message.YPos)) and (FSelectionMode in [smNone, smColor]);
|
|
if Result then
|
|
begin
|
|
Shift := KeysToShiftState(Message.Keys);
|
|
if ssLeft in Shift then
|
|
begin
|
|
FSelectionMode := smColor;
|
|
Index := FindColorArea(Message.XPos, Message.YPos);
|
|
if Index > -1 then
|
|
begin
|
|
// remove selection comb if it was previously in b&w comb
|
|
if FCustomIndex < 0 then InvalidateRect(Handle, @FBWCombRect, False);
|
|
if FCustomIndex <> (Index + 1) then
|
|
begin
|
|
FCustomIndex := Index + 1;
|
|
InvalidateRect(Handle, @FColorCombRect, False);
|
|
InvalidateRect(Handle, @FCustomColorRect, False);
|
|
EndSelection;
|
|
end;
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.HandleCustomColors(
|
|
var Message: {$IFDEF FPC}TLMMouse{$ELSE}TWMMouse{$ENDIF});
|
|
begin
|
|
if not HandleSlider(Message) then
|
|
if not HandleBWArea(Message) then
|
|
HandleColorComb(Message);
|
|
end;
|
|
|
|
// determines whether the mouse position is within the slider area and acts accordingly
|
|
function THexaColorPicker.HandleSlider(const Message: TLMMouse): Boolean;
|
|
var
|
|
Shift: TShiftState;
|
|
dY: Integer;
|
|
R: TRect;
|
|
begin
|
|
if not FSliderVisible then
|
|
begin
|
|
Result := false;
|
|
Exit;
|
|
end;
|
|
|
|
Result :=
|
|
(PtInRect(FSliderRect, Point(Message.XPos, Message.YPos))
|
|
and (FSelectionMode = smNone))
|
|
or
|
|
((Message.XPos >= FSliderRect.Left) and (Message.XPos <= FSliderRect.Right)
|
|
and (FSelectionMode = smRamp));
|
|
|
|
if Result then
|
|
begin
|
|
Shift := KeysToShiftState(Message.Keys);
|
|
if ssLeft in Shift then
|
|
begin
|
|
FSelectionMode := smRamp;
|
|
dY := FSliderRect.Bottom - FSliderRect.Top;
|
|
FCenterIntensity := 1 - (Message.YPos - FSliderRect.Top) / dY;
|
|
if FCenterIntensity < 0 then FCenterIntensity := 0;
|
|
if FCenterIntensity > 1 then FCenterIntensity := 1;
|
|
FCenterColor.Red := DefCenterColor.Red * FCenterIntensity;
|
|
FCenterColor.Green := DefCenterColor.Green * FCenterIntensity;
|
|
FCenterColor.Blue := DefCenterColor.Blue * FCenterIntensity;
|
|
R := FSliderRect;
|
|
Dec(R.Top, 3);
|
|
Inc(R.Bottom, 3);
|
|
Inc(R.Left, 10);
|
|
InvalidateRect(Handle, @R, False);
|
|
FColorCombs := nil;
|
|
InvalidateRect(Handle, @FColorCombRect, False);
|
|
InvalidateRect(Handle, @FCustomColorRect, False);
|
|
CalculateCombLayout;
|
|
EndSelection;
|
|
if Assigned(FOnIntensityChange) then
|
|
FOnIntensityChange(Self);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.Initialize;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
FSelectedIndex := NoCell;
|
|
for I := 0 to 5 do
|
|
begin
|
|
FCombCorners[I].X := 0.5 * cos(Pi * (90 - I * 60) / 180);
|
|
FCombCorners[I].Y := 0.5 * sin(Pi * (90 - I * 60) / 180);
|
|
end;
|
|
FLevels := 7;
|
|
FCombSize := Round(FRadius / (FLevels - 1));
|
|
FCenterColor := DefCenterColor;
|
|
FIncrement := 1;
|
|
FCenterIntensity := 1;
|
|
end;
|
|
|
|
procedure THexaColorPicker.KeyDown(var Key: Word; Shift: TShiftState);
|
|
var
|
|
eraseKey: Boolean;
|
|
begin
|
|
eraseKey := true;
|
|
if ssCtrl in Shift then
|
|
case Key of
|
|
VK_LEFT: SetSelectedColor(clWhite);
|
|
VK_RIGHT: SetSelectedColor(clBlack);
|
|
VK_UP: if FSliderVisible then SetIntensity(100);
|
|
VK_DOWN: if FSliderVisible then SetIntensity(0);
|
|
else
|
|
eraseKey := false;
|
|
end
|
|
else
|
|
case Key of
|
|
VK_LEFT: SelectCombIndex(GetPreviousCombIndex(GetSelectedCombIndex));
|
|
VK_RIGHT: SelectCombIndex(GetNextCombIndex(GetSelectedCombIndex));
|
|
VK_UP: if FSliderVisible then ChangeIntensity(true);
|
|
VK_DOWN: if FSliderVisible then ChangeIntensity(false);
|
|
else
|
|
eraseKey := false;
|
|
end;
|
|
if eraseKey then
|
|
Key := 0;
|
|
inherited;
|
|
end;
|
|
|
|
procedure THexaColorPicker.Paint;
|
|
begin
|
|
PaintParentBack(Canvas);
|
|
if FColorCombs = nil then
|
|
CalculateCombLayout;
|
|
DrawCombControls(Canvas);
|
|
end;
|
|
|
|
function THexaColorPicker.PtInComb(Comb: TCombEntry; P: TPoint; Scale: Integer): Boolean;
|
|
begin
|
|
Result := (Sqr(Comb.Position.X - P.X) + Sqr(Comb.Position.Y - P.Y)) <= Scale * Scale;
|
|
end;
|
|
|
|
procedure THexaColorPicker.DrawAll;
|
|
var
|
|
WinTop: integer;
|
|
begin
|
|
WinTop := - FRadius div 8; // use 10 instead of 8 if the top has been cut
|
|
FCombSize := Round(1 + FRadius / (FLevels - 1));
|
|
FColorCombRect := Rect(0, WinTop, 2 * FRadius, 2 * FRadius + WinTop);
|
|
FBWCombRect := Rect(
|
|
FColorCombRect.Left,
|
|
FColorCombRect.Bottom - 4,
|
|
Round(17 * FCombSize * cos(Pi / 6) / 2) {%H-}+ 6 * FCombSize,
|
|
FColorCombRect.Bottom + 2 * FCombSize
|
|
);
|
|
if FSliderVisible then
|
|
FSliderRect := Rect(FColorCombRect.Right, FCombSize, FColorCombRect.Right + 10 + FSliderWidth, FColorCombRect.Bottom - FCombSize)
|
|
// FSliderRect := Rect(FColorCombRect.Right, FColorCombRect.Top, FColorCombRect.Right + 10 + FSliderWidth, FColorCombRect.Bottom)
|
|
else
|
|
FSliderRect := Rect(-1, -1, -1, -1);
|
|
end;
|
|
|
|
// fills arrays with centers and colors for the custom color and black & white combs,
|
|
// these arrays are used to quickly draw the combx and do hit tests
|
|
|
|
function RGBFromFloat(Color: TRGBrec): COLORREF;
|
|
begin
|
|
Result := RGB(Round(255 * Color.Red), Round(255 * Color.Green), Round(255 * Color.Blue));
|
|
end;
|
|
|
|
{function TRGBrecFromTColor(Color: TColor): TRGBrec;
|
|
begin
|
|
Result.Red := GetRValue(Color)/255;
|
|
Result.Green := GetGValue(Color)/255;
|
|
Result.Blue := GetBValue(Color)/255;
|
|
end;}
|
|
|
|
procedure THexaColorPicker.CalculateCombLayout;
|
|
|
|
function GrayFromIntensity(Intensity: Byte): COLORREF;
|
|
begin
|
|
Result := RGB(Intensity, Intensity, Intensity);
|
|
end;
|
|
|
|
var
|
|
I, J, Level, CurrentIndex, CombCount: Cardinal;
|
|
CurrentColor: TRGBrec;
|
|
CurrentPos: TFloatPoint;
|
|
Scale: Extended;
|
|
// triangle vars
|
|
Pos1, Pos2, dPos1, dPos2, dPos: TFloatPoint;
|
|
Color1, Color2, dColor1, dColor2, dColor: TRGBrec;
|
|
begin
|
|
// this ensures the radius and comb size is set correctly
|
|
// HandleNeeded;
|
|
if FLevels < 1 then FLevels := 1;
|
|
// To draw perfectly aligned combs we split the final comb into six triangles (sextants)
|
|
// and calculate each separately. The center comb is stored as first entry in the array
|
|
// and will not considered twice (as with the other shared combs too).
|
|
//
|
|
// The way used here for calculation of the layout seems a bit complicated, but works
|
|
// correctly for all cases (even if the comb corners are rotated).
|
|
// initialization
|
|
CurrentIndex := 0;
|
|
CurrentColor := FCenterColor;
|
|
// number of combs can be calculated by:
|
|
// 1 level: 1 comb (the center)
|
|
// 2 levels: 1 comb + 6 combs
|
|
// 3 levels: 1 comb + 1 * 6 combs + 2 * 6 combs
|
|
// n levels: 1 combs + 1 * 6 combs + 2 * 6 combs + .. + (n-1) * 6 combs
|
|
// this equals to 1 + 6 * (1 + 2 + 3 + .. + (n-1)), by using Gauss' famous formula we get:
|
|
// Count = 1 + 6 * (((n-1) * n) / 2)
|
|
// Because there's always an even number involved (either n or n-1) we can use an integer div
|
|
// instead of a float div here...
|
|
CombCount := 1 + 6 * (((FLevels - 1) * FLevels) div 2);
|
|
SetLength(FColorCombs, CombCount);
|
|
// store center values
|
|
FColorCombs[CurrentIndex].Position := Point(0, 0);
|
|
FColorCombs[CurrentIndex].Color := RGBFromFloat(CurrentColor);
|
|
Inc(CurrentIndex);
|
|
// go out off here if there are not further levels to draw
|
|
if FLevels < 2 then Exit;
|
|
// now go for each sextant, the generic corners have been calculated already at creation
|
|
// time for a comb with diameter 1
|
|
// ------
|
|
// /\ 1 /\
|
|
// / \ / \
|
|
// / 2 \/ 0 \
|
|
// -----------
|
|
// \ 3 /\ 5 /
|
|
// \ / \ /
|
|
// \/ 4 \/
|
|
// ------
|
|
for I := 0 to 5 do
|
|
begin
|
|
// initialize triangle corner values
|
|
//
|
|
// center (always at 0,0)
|
|
// /\
|
|
// dPos1 / \ dPos2
|
|
// dColor1 / \ dColor2
|
|
// / dPos \
|
|
// /--------\ (span)
|
|
// / dColor \
|
|
// /____________\
|
|
// comb corner 1 comb corner 2
|
|
//
|
|
// Pos1, Pos2, Color1, Color2 are running terms for both sides of the triangle
|
|
// incremented by dPos1/2 and dColor1/2.
|
|
// dPos and dColor are used to interpolate a span between the values just mentioned.
|
|
//
|
|
// The small combs are actually oriented with corner 0 at top (i.e. mirrored at y = x,
|
|
// compared with the values in FCombCorners), we can achieve that by simply exchanging
|
|
// X and Y values.
|
|
Scale := 2 * FRadius * cos(Pi / 6);
|
|
Pos1.X := FCombCorners[I].Y * Scale;
|
|
Pos1.Y := FCombCorners[I].X * Scale;
|
|
Color1 := DefColors[I];
|
|
if I = 5 then
|
|
begin
|
|
Pos2.X := FCombCorners[0].Y * Scale;
|
|
Pos2.Y := FCombCorners[0].X * Scale;
|
|
Color2 := DefColors[0];
|
|
end
|
|
else
|
|
begin
|
|
Pos2.X := FCombCorners[I + 1].Y * Scale;
|
|
Pos2.Y := FCombCorners[I + 1].X * Scale;
|
|
Color2 := DefColors[I + 1];
|
|
end;
|
|
dPos1.X := Pos1.X / (FLevels - 1);
|
|
dPos1.Y := Pos1.Y / (FLevels - 1);
|
|
dPos2.X := Pos2.X / (FLevels - 1);
|
|
dPos2.Y := Pos2.Y / (FLevels - 1);
|
|
dColor1.Red := (Color1.Red - FCenterColor.Red) / (FLevels - 1);
|
|
dColor1.Green := (Color1.Green - FCenterColor.Green) / (FLevels - 1);
|
|
dColor1.Blue := (Color1.Blue - FCenterColor.Blue) / (FLevels - 1);
|
|
|
|
dColor2.Red := (Color2.Red - FCenterColor.Red) / (FLevels - 1);
|
|
dColor2.Green := (Color2.Green - FCenterColor.Green) / (FLevels - 1);
|
|
dColor2.Blue := (Color2.Blue - FCenterColor.Blue) / (FLevels - 1);
|
|
|
|
Pos1 := DefCenter;
|
|
Pos2 := DefCenter;
|
|
Color1 := FCenterColor;
|
|
Color2 := FCenterColor;
|
|
|
|
// Now that we have finished the initialization for this step we'll go
|
|
// through a loop for each level to calculate the spans.
|
|
// We can ignore level 0 (as this is the center we already have determined) as well
|
|
// as the last step of each span (as this is the start value in the next triangle and will
|
|
// be calculated there). We have, though, take them into the calculation of the running terms.
|
|
for Level := 0 to FLevels - 1 do
|
|
begin
|
|
if Level > 0 then
|
|
begin
|
|
// initialize span values
|
|
dPos.X := (Pos2.X - Pos1.X) / Level;
|
|
dPos.Y := (Pos2.Y - Pos1.Y) / Level;
|
|
dColor.Red := (Color2.Red - Color1.Red) / Level;
|
|
dColor.Green := (Color2.Green - Color1.Green) / Level;
|
|
dColor.Blue := (Color2.Blue - Color1.Blue) / Level;
|
|
CurrentPos := Pos1;
|
|
CurrentColor := Color1;
|
|
for J := 0 to Level - 1 do
|
|
begin
|
|
// store current values in the array
|
|
FColorCombs[CurrentIndex].Position.X := Round(CurrentPos.X);
|
|
FColorCombs[CurrentIndex].Position.Y := Round(CurrentPos.Y);
|
|
FColorCombs[CurrentIndex].Color := RGBFromFloat(CurrentColor);
|
|
Inc(CurrentIndex);
|
|
|
|
// advance in span
|
|
CurrentPos.X := CurrentPos.X + dPos.X;
|
|
CurrentPos.Y := CurrentPos.Y + dPos.Y;
|
|
|
|
CurrentColor.Red := CurrentColor.Red + dColor.Red;
|
|
CurrentColor.Green := CurrentColor.Green + dColor.Green;
|
|
CurrentColor.Blue := CurrentColor.Blue + dColor.Blue;
|
|
end;
|
|
end;
|
|
// advance running terms
|
|
Pos1.X := Pos1.X + dPos1.X;
|
|
Pos1.Y := Pos1.Y + dPos1.Y;
|
|
Pos2.X := Pos2.X + dPos2.X;
|
|
Pos2.Y := Pos2.Y + dPos2.Y;
|
|
|
|
Color1.Red := Color1.Red + dColor1.Red;
|
|
Color1.Green := Color1.Green + dColor1.Green;
|
|
Color1.Blue := Color1.Blue + dColor1.Blue;
|
|
|
|
Color2.Red := Color2.Red + dColor2.Red;
|
|
Color2.Green := Color2.Green + dColor2.Green;
|
|
Color2.Blue := Color2.Blue + dColor2.Blue;
|
|
end;
|
|
end;
|
|
|
|
// second step is to build a list for the black & white area
|
|
// 17 entries from pure white to pure black
|
|
// the first and last are implicitely of double comb size
|
|
SetLength(FBWCombs, 17);
|
|
CurrentIndex := 0;
|
|
FBWCombs[CurrentIndex].Color := GrayFromIntensity(255);
|
|
FBWCombs[CurrentIndex].Position := Point(FCombSize, FCombSize);
|
|
Inc(CurrentIndex);
|
|
|
|
CurrentPos.X := 3 * FCombSize;
|
|
CurrentPos.Y := 3 * (FCombSize div 4);
|
|
dPos.X := Round(FCombSize * cos(Pi / 6) / 2);
|
|
dPos.Y := Round(FCombSize * (1 + sin(Pi / 6)) / 2);
|
|
for I := 0 to 14 do
|
|
begin
|
|
FBWCombs[CurrentIndex].Color := GrayFromIntensity((16 - CurrentIndex) * 15);
|
|
if Odd(I) then
|
|
FBWCombs[CurrentIndex].Position := Point(Round(CurrentPos.X + I * dPos.X), Round(CurrentPos.Y + dPos.Y))
|
|
else
|
|
FBWCombs[CurrentIndex].Position := Point(Round(CurrentPos.X + I * dPos.X), Round(CurrentPos.Y));
|
|
Inc(CurrentIndex);
|
|
end;
|
|
FBWCombs[CurrentIndex].Color := 0;
|
|
FBWCombs[CurrentIndex].Position := Point(Round(CurrentPos.X + 16 * dPos.X + FCombSize), FCombSize);
|
|
EnumerateCombs;
|
|
end;
|
|
|
|
// determine hint message and out-of-hint rect
|
|
procedure THexaColorPicker.CMHintShow(
|
|
var Message: {$IFDEF FPC}TLMessage{$ELSE}TMessage{$ENDIF} );
|
|
var
|
|
Index: Integer;
|
|
Colors: TCombArray;
|
|
cp: TPoint;
|
|
begin
|
|
Colors := nil;
|
|
if (GetColorUnderCursor <> clNone) or PtInRect(FSliderRect, Point(mX, mY)) then
|
|
with TCMHintShow(Message) do
|
|
begin
|
|
if not ShowHint then
|
|
Message.Result := 1
|
|
else
|
|
begin
|
|
with HintInfo^ do
|
|
begin
|
|
// show that we want a hint
|
|
Result := 0;
|
|
cp := CursorPos;
|
|
ReshowTimeout := 0; //1;
|
|
HideTimeout := 5000;
|
|
HintInfo^.CursorRect := Rect(cp.X, cp.Y, cp.X+1, cp.Y+1);
|
|
if PtInRect(FSliderRect, cp) and FSliderVisible then
|
|
begin
|
|
// in case of the intensity slider we show the current intensity
|
|
HintStr := FIntensityText + Format(': %d%%', [Round(100 * FCenterIntensity)]);
|
|
HintPos := ClientToScreen(Point(FSliderRect.Right, CursorPos.Y - 8));
|
|
end
|
|
else
|
|
begin
|
|
Index := -1;
|
|
if PtInRect(FBWCombRect, Point(CursorPos.X, CursorPos.Y)) then
|
|
begin
|
|
// considering black&white area...
|
|
if csLButtonDown in ControlState then
|
|
Index := -(FCustomIndex + 1)
|
|
else
|
|
Index := FindBWArea(CursorPos.X, CursorPos.Y);
|
|
Colors := FBWCombs;
|
|
end
|
|
else
|
|
if PtInRect(FColorCombRect, Point(CursorPos.X, CursorPos.Y)) then
|
|
begin
|
|
// considering color comb area...
|
|
if csLButtonDown in ControlState then
|
|
Index := FCustomIndex - 1
|
|
else
|
|
Index := FindColorArea(CursorPos.X, CursorPos.Y);
|
|
Colors := FColorCombs;
|
|
end;
|
|
if (Index > -1) and (Colors <> nil) then
|
|
HintStr := FormatHint(FHintFormat, Colors[Index].Color);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.SetSelectedColor(Value: TColor);
|
|
begin
|
|
FCurrentColor := Value;
|
|
SelectColor(Value);
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure THexaColorPicker.EndSelection;
|
|
begin
|
|
if FCustomIndex < 0 then
|
|
SetSelectedColor(FBWCombs[-(FCustomIndex + 1)].Color)
|
|
else
|
|
if FCustomIndex > 0 then
|
|
SetSelectedColor(FColorCombs[FCustomIndex - 1].Color)
|
|
else
|
|
SetSelectedColor(clNone);
|
|
end;
|
|
|
|
function THexaColorPicker.GetColorUnderCursor: TColor;
|
|
begin
|
|
Result := FUnderCursor;
|
|
end;
|
|
|
|
function THexaColorPicker.GetColorAtPoint(X, Y: integer): TColor;
|
|
var
|
|
Index: Integer;
|
|
Colors: TCombArray;
|
|
begin
|
|
Colors := nil;
|
|
Index := -1;
|
|
if PtInRect(FBWCombRect, Point(X, Y)) then
|
|
begin
|
|
Index := FindBWArea(X, Y);
|
|
Colors := FBWCombs;
|
|
end
|
|
else
|
|
if PtInRect(FColorCombRect, Point(X, Y)) then
|
|
begin
|
|
Index := FindColorArea(X, Y);
|
|
Colors := FColorCombs;
|
|
end;
|
|
if (Index > -1) and (Colors <> nil) then
|
|
Result := Colors[Index].Color
|
|
else
|
|
Result := clNone;
|
|
end;
|
|
|
|
function THexaColorPicker.GetHexColorUnderCursor: string;
|
|
begin
|
|
Result := ColorToHex(GetColorUnderCursor);
|
|
end;
|
|
|
|
function THexaColorPicker.GetHexColorAtPoint(X, Y: integer): string;
|
|
begin
|
|
Result := ColorToHex(GetColorAtPoint(X, Y));
|
|
end;
|
|
|
|
procedure THexaColorPicker.EnumerateCombs;
|
|
var
|
|
i, k: integer;
|
|
begin
|
|
k := 0;
|
|
if FBWCombs <> nil then
|
|
for i := 1 to High(FBWCombs) do
|
|
begin
|
|
case i of
|
|
// b & w comb indices
|
|
1: k := -1;
|
|
2: k := -9;
|
|
3: k := -2;
|
|
4: k := -10;
|
|
5: k := -3;
|
|
6: k := -11;
|
|
7: k := -4;
|
|
8: k := -12;
|
|
9: k := -5;
|
|
10: k := -13;
|
|
11: k := -6;
|
|
12: k := -14;
|
|
13: k := -7;
|
|
14: k := -15;
|
|
15: k := -8;
|
|
// big black comb index (match center comb)
|
|
16: K := 64;
|
|
end;
|
|
FBWCombs[i].TabIndex := k;
|
|
end;
|
|
if FColorCombs <> nil then
|
|
for i := 0 to High(FColorCombs) do
|
|
begin
|
|
case i of
|
|
// center comb index
|
|
0: k := 64;
|
|
// color comb indices
|
|
1: k := 65;
|
|
2: k := 66;
|
|
3: k := 78;
|
|
4: k := 67;
|
|
5: k := 79;
|
|
6: k := 90;
|
|
7: k := 68;
|
|
8: k := 80;
|
|
9: k := 91;
|
|
10: k := 101;
|
|
11: k := 69;
|
|
12: k := 81;
|
|
13: k := 92;
|
|
14: k := 102;
|
|
15: k := 111;
|
|
16: k := 70;
|
|
17: k := 82;
|
|
18: k := 93;
|
|
19: k := 103;
|
|
20: k := 112;
|
|
21: k := 120;
|
|
22: k := 77;
|
|
23: k := 89;
|
|
24: k := 88;
|
|
25: k := 100;
|
|
26: k := 99;
|
|
27: k := 98;
|
|
28: k := 110;
|
|
29: k := 109;
|
|
30: k := 108;
|
|
31: k := 107;
|
|
32: k := 119;
|
|
33: k := 118;
|
|
34: k := 117;
|
|
35: k := 116;
|
|
36: k := 115;
|
|
37: k := 127;
|
|
38: k := 126;
|
|
39: k := 125;
|
|
40: k := 124;
|
|
41: k := 123;
|
|
42: k := 122;
|
|
43: k := 76;
|
|
44: k := 87;
|
|
45: k := 75;
|
|
46: k := 97;
|
|
47: k := 86;
|
|
48: k := 74;
|
|
49: k := 106;
|
|
50: k := 96;
|
|
51: k := 85;
|
|
52: k := 73;
|
|
53: k := 114;
|
|
54: k := 105;
|
|
55: k := 95;
|
|
56: k := 84;
|
|
57: k := 72;
|
|
58: k := 121;
|
|
59: k := 113;
|
|
60: k := 104;
|
|
61: k := 94;
|
|
62: k := 83;
|
|
63: k := 71;
|
|
64: k := 63;
|
|
65: k := 62;
|
|
66: k := 50;
|
|
67: k := 61;
|
|
68: k := 49;
|
|
69: k := 38;
|
|
70: k := 60;
|
|
71: k := 48;
|
|
72: k := 37;
|
|
73: k := 27;
|
|
74: k := 59;
|
|
75: k := 47;
|
|
76: k := 36;
|
|
77: k := 26;
|
|
78: k := 17;
|
|
79: k := 58;
|
|
80: k := 46;
|
|
81: k := 35;
|
|
82: k := 25;
|
|
83: k := 16;
|
|
84: k := 8;
|
|
85: k := 51;
|
|
86: k := 39;
|
|
87: k := 40;
|
|
88: k := 28;
|
|
89: k := 29;
|
|
90: k := 30;
|
|
91: k := 18;
|
|
92: k := 19;
|
|
93: k := 20;
|
|
94: k := 21;
|
|
95: k := 9;
|
|
96: k := 10;
|
|
97: k := 11;
|
|
98: k := 12;
|
|
99: k := 13;
|
|
100: k := 1;
|
|
101: k := 2;
|
|
102: k := 3;
|
|
103: k := 4;
|
|
104: k := 5;
|
|
105: k := 6;
|
|
106: k := 52;
|
|
107: k := 41;
|
|
108: k := 53;
|
|
109: k := 31;
|
|
110: k := 42;
|
|
111: k := 54;
|
|
112: k := 22;
|
|
113: k := 32;
|
|
114: k := 43;
|
|
115: k := 55;
|
|
116: k := 14;
|
|
117: k := 23;
|
|
118: k := 33;
|
|
119: k := 44;
|
|
120: k := 56;
|
|
121: k := 7;
|
|
122: k := 15;
|
|
123: k := 24;
|
|
124: k := 34;
|
|
125: k := 45;
|
|
126: k := 57;
|
|
end;
|
|
FColorCombs[i].TabIndex := k;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.SelectCombIndex(i: integer);
|
|
var
|
|
j: integer;
|
|
begin
|
|
if i > 0 then
|
|
begin
|
|
if FColorCombs <> nil then
|
|
for j := 0 to High(FColorCombs) do
|
|
begin
|
|
if FColorCombs[j].TabIndex = i then
|
|
begin
|
|
SetSelectedColor(FColorCombs[j].Color);
|
|
Break;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
if FBWCombs <> nil then
|
|
for j := 1 to High(FBWCombs) - 1 do
|
|
begin
|
|
if FBWCombs[j].TabIndex = i then
|
|
begin
|
|
SetSelectedColor(FBWCombs[j].Color);
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.Resize;
|
|
var
|
|
rw, rh: integer;
|
|
begin
|
|
if (Width >= 93) and (Height >= 85) then
|
|
begin
|
|
if FSliderVisible then
|
|
rw := Round((Width - 10 - FSliderWidth)/2)
|
|
else
|
|
rw := Round(Width/2 - 5);
|
|
rh := Round((24/53)*(Height - 6));
|
|
SetRadius(Min(rw, rh));
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
function THexaColorPicker.SelectAvailableColor(Color: TColor): boolean;
|
|
var
|
|
I: integer;
|
|
C: COLORREF;
|
|
found: Boolean;
|
|
begin
|
|
found := False;
|
|
Result := false;
|
|
C := ColorToRGB(Color);
|
|
if FColorCombs = nil then CalculateCombLayout;
|
|
FCustomIndex := 0;
|
|
FSelectedIndex := NoCell;
|
|
for I := 0 to High(FBWCombs) do
|
|
if FBWCombs[I].Color = C then
|
|
begin
|
|
FSelectedIndex := CustomCell;
|
|
FCustomIndex := -(I + 1);
|
|
found := True;
|
|
Result := true;
|
|
Break;
|
|
end;
|
|
if not found then
|
|
for I := 0 to High(FColorCombs) do
|
|
if FColorCombs[I].Color = C then
|
|
begin
|
|
FSelectedIndex := CustomCell;
|
|
FCustomIndex := I + 1;
|
|
Result := true;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.SelectColor(Color: TColor);
|
|
begin
|
|
SelectAvailableColor(Color);
|
|
Invalidate;
|
|
if Assigned(OnChange) then OnChange(Self);
|
|
end;
|
|
|
|
procedure THexaColorPicker.SetIntensity(v: integer);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
FCenterIntensity := EnsureRange(v/100, 0, 1);
|
|
FCenterColor.Red := DefCenterColor.Red * FCenterIntensity;
|
|
FCenterColor.Green := DefCenterColor.Green * FCenterIntensity;
|
|
FCenterColor.Blue := DefCenterColor.Blue * FCenterIntensity;
|
|
R := FSliderRect;
|
|
Dec(R.Top, 3);
|
|
Inc(R.Bottom, 3);
|
|
Inc(R.Left, 10);
|
|
InvalidateRect(Handle, @R, False);
|
|
FColorCombs := nil;
|
|
InvalidateRect(Handle, @FColorCombRect, False);
|
|
InvalidateRect(Handle, @FCustomColorRect, False);
|
|
CalculateCombLayout;
|
|
EndSelection;
|
|
if Assigned(FOnIntensityChange) then
|
|
FOnIntensityChange(Self);
|
|
end;
|
|
|
|
procedure THexaColorPicker.SetMarker(Value: TMarker);
|
|
begin
|
|
if FMarker <> Value then
|
|
begin
|
|
FMarker := Value;
|
|
DrawAll;
|
|
CalculateCombLayout;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.SetNewArrowStyle(Value: boolean);
|
|
begin
|
|
if FNewArrowStyle <> Value then
|
|
begin
|
|
FNewArrowStyle := Value;
|
|
DrawAll;
|
|
CalculateCombLayout;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.SetRadius(r: integer);
|
|
begin
|
|
if Parent = nil then
|
|
exit;
|
|
FRadius := r;
|
|
DrawAll;
|
|
CalculateCombLayout;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure THexaColorPicker.SetSliderVisible(Value: boolean);
|
|
begin
|
|
if FSliderVisible <> Value then
|
|
begin
|
|
FSliderVisible := Value;
|
|
DrawAll;
|
|
CalculateCombLayout;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.SetSliderWidth(w: integer);
|
|
begin
|
|
if (FSliderWidth <> w) and FSliderVisible then
|
|
begin
|
|
FSliderWidth := w;
|
|
DrawAll;
|
|
Width := FSliderRect.Right + 2;
|
|
CalculateCombLayout;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.WMLButtonDown(
|
|
var Message: {$IFDEF FPC}TLMLButtonDown{$ELSE}TWMLButtonDown{$ENDIF} );
|
|
begin
|
|
inherited;
|
|
SetFocus; // needed so the key events work
|
|
if PtInRect(ClientRect, Point(Message.XPos, Message.YPos)) then
|
|
HandleCustomColors(Message);
|
|
end;
|
|
|
|
procedure THexaColorPicker.WMLButtonUp(
|
|
var Message: {$IFDEF FPC}TLMLButtonUp{$ELSE}TWMLButtonUp{$ENDIF} );
|
|
var
|
|
LastMode: TSelectionMode;
|
|
begin
|
|
inherited;
|
|
LastMode := FSelectionMode;
|
|
FSelectionMode := smNone;
|
|
if (FSelectedIndex = CustomCell) and (FCustomIndex <> 0) then
|
|
begin
|
|
if ((FSelectedIndex = CustomCell) and (LastMode in [smColor, smBW])) or
|
|
(FSelectedIndex <> NoCell) and (FSelectedIndex <> CustomCell)
|
|
then
|
|
EndSelection
|
|
end;
|
|
end;
|
|
|
|
procedure THexaColorPicker.WMMouseMove(
|
|
var Message: {$IFDEF FPC}TLMMouseMove{$ELSE}TWMMouseMove{$ENDIF} );
|
|
var
|
|
Shift: TShiftState;
|
|
Index: Integer;
|
|
Colors: TCombArray;
|
|
begin
|
|
inherited;
|
|
mX := Message.XPos;
|
|
mY := Message.YPos;
|
|
//get color under cursor
|
|
Colors := nil;
|
|
FUnderCursor := clNone;
|
|
if PtInRect(FBWCombRect, Point(Message.XPos, Message.YPos)) then
|
|
begin
|
|
Index := FindBWArea(Message.XPos, Message.YPos);
|
|
Colors := FBWCombs;
|
|
if (Index > -1) and (Colors <> nil) then
|
|
FUnderCursor := Colors[Index].Color;
|
|
end
|
|
else
|
|
if PtInRect(FColorCombRect, Point(Message.XPos, Message.YPos)) then
|
|
begin
|
|
Index := FindColorArea(Message.XPos, Message.YPos);
|
|
Colors := FColorCombs;
|
|
if (Index > -1) and (Colors <> nil) then
|
|
FUnderCursor := Colors[Index].Color;
|
|
end
|
|
else
|
|
FUnderCursor := clNone;
|
|
// further process message
|
|
Shift := KeysToShiftState(Message.Keys);
|
|
if ssLeft in Shift then
|
|
HandleCustomColors(Message);
|
|
end;
|
|
|
|
end.
|