unit SColorPicker; {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} interface uses LCLIntf, LCLType, SysUtils, Classes, Controls, Graphics, Forms, mbColorConv, mbTrackBarPicker, HTMLColors; type TSColorPicker = class(TmbHSLVTrackBarPicker) private function ArrowPosFromSat(s: Double): integer; function SatFromArrowPos(p: integer): Double; protected procedure Execute(tbaAction: integer); override; function GetArrowPos: integer; override; function GetGradientColor(AValue: Integer): TColor; override; function GetSelectedValue: integer; override; procedure SetMaxSat(S: Integer); override; procedure SetRelSat(S: Double); override; procedure SetSelectedColor(c: TColor); override; public constructor Create(AOwner: TComponent); override; published property Hue default 0; property Saturation default 255; property Luminance default 127; property Value default 255; property SelectedColor default clRed; property HintFormat; end; implementation uses mbUtils; { TSColorPicker } constructor TSColorPicker.Create(AOwner: TComponent); begin inherited; FGradientWidth := FMaxSat + 1; FGradientHeight := 1; FHue := 0; FLum := 0.5; FVal := 1.0; Saturation := 255; HintFormat := 'Saturation: %value (selected)'; end; function TSColorPicker.ArrowPosFromSat(s: Double): integer; var a: integer; begin if Layout = lyHorizontal then begin a := Round(s * (Width - 12)); if a > Width - FLimit then a := Width - FLimit; end else begin a := Round((1.0 - s) * (Height - 12)); if a > Height - FLimit then a := Height - FLimit; end; if a < 0 then a := 0; Result := a; end; procedure TSColorPicker.Execute(tbaAction: integer); var dSat: Double; begin if FMaxSat = 0 then dSat := 0 else dSat := Increment / FMaxSat; case tbaAction of TBA_Resize: SetRelSat(FSat); TBA_MouseMove: SetRelSat(SatFromArrowPos(FArrowPos)); TBA_MouseDown: SetRelSat(SatFromArrowPos(FArrowPos)); TBA_MouseUp: SetRelSat(SatFromArrowPos(FArrowPos)); TBA_WheelUp: SetRelSat(FSat + dSat); TBA_WheelDown: SetRelSat(FSat - dSat); TBA_VKLeft: SetRelSat(FSat - dSat); TBA_VKCtrlLeft: SetRelSat(0.0); TBA_VKRight: SetRelSat(FSat + dSat); TBA_VKCtrlRight: SetRelSat(1.0); TBA_VKUp: SetRelSat(FSat + dSat); TBA_VKCtrlUp: SetRelSat(1.0); TBA_VKDown: SetRelSat(FSat - dSat); TBA_VKCtrlDown: SetRelSat(0.0); else inherited; end; end; function TSColorPicker.GetArrowPos: integer; begin if FMaxSat = 0 then Result := inherited GetArrowPos else Result := ArrowPosFromSat(FSat); end; function TSColorPicker.GetGradientColor(AValue: Integer): TColor; begin Result := HSLVtoColor(FHue, AValue/FMaxSat, FLum, FVal); end; function TSColorPicker.GetSelectedValue: integer; begin Result := Saturation; end; function TSColorPicker.SatFromArrowPos(p: integer): Double; var s: Double; begin case Layout of lyHorizontal: s := p / (Width - 12); lyVertical : s := 1.0 - p / (Height - 12); end; Clamp(s, 0, 1.0); Result := s; end; procedure TSColorPicker.SetMaxSat(S: Integer); begin if S = FMaxSat then exit; FMaxSat := S; FGradientWidth := FMaxSat + 1; CreateGradient; Invalidate; DoChange; end; procedure TSColorPicker.SetRelSat(S: Double); begin Clamp(S, 0, 1.0); if FSat <> S then begin FSat := S; FArrowPos := ArrowPosFromSat(S); Invalidate; DoChange; end; end; procedure TSColorPicker.SetSelectedColor(c: TColor); var H: Double = 0; S: Double = 0; L: Double = 0; V: Double = 0; needNewGradient: Boolean; begin if WebSafe then c := GetWebSafe(c); if c = GetSelectedColor then exit; ColorToHSLV(c, H,S,L,V); case BrightnessMode of bmLuminance: begin needNewGradient := (H <> FHue) or (L <> FLum); FLum := L; end; bmValue: begin needNewGradient := (H <> FHue) or (V <> FVal); FVal := V; end; end; FHue := H; FSat := S; if needNewGradient then CreateGradient; Invalidate; DoChange; end; end.