unit HSLColorPicker;

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}

interface

{$I mxs.inc}

uses
 {$IFDEF FPC}
 LCLIntf, LCLType, LMessages,
 {$ELSE}
 Windows, Messages,
 {$ENDIF}
 SysUtils, Classes, Controls, Graphics, Forms, Menus,
 {$IFDEF DELPHI_7_UP} Themes, {$ENDIF}
 RGBHSLUtils, HSColorPicker, LColorPicker, HTMLColors;

type
 THSLColorPicker = class(TCustomControl)
 private
  FOnChange: TNotifyEvent;
  FHSPicker: THSColorPicker;
  FLPicker: TLColorPicker;
  FSelectedColor: TColor;
  FHValue, FSValue, FLValue: integer;
  FRValue, FGValue, FBValue: integer;
  FHSHint, FLHint: string;
  FLMenu, FHSMenu: TPopupMenu;
  FLumIncrement: integer;
  FHSCursor, FLCursor: TCursor;
  PBack: TBitmap;

  function GetManual: boolean;
  procedure SetLumIncrement(i: integer);
  procedure SelectColor(c: TColor);
  procedure SetH(v: integer);
  procedure SetS(v: integer);
  procedure SetL(v: integer);
  procedure SetR(v: integer);
  procedure SetG(v: integer);
  procedure SetB(v: integer);
  procedure SetHSHint(h: string);
  procedure SetLHint(h: string);
  procedure SetLMenu(m: TPopupMenu);
  procedure SetHSMenu(m: TPopupMenu);
  procedure SetHSCursor(c: TCursor);
  procedure SetLCursor(c: TCursor);
  procedure PaintParentBack;
  procedure SetSelectedColor(Value: TColor);
 protected
  procedure CreateWnd; override;
  procedure Resize; override;
  procedure Paint; override;
  procedure WMEraseBkgnd(var Message: {$IFDEF FPC}TLMEraseBkgnd{$ELSE}TWMEraseBkgnd{$ENDIF});
    message {$IFDEF FPC}LM_ERASEBKGND{$ELSE}WM_ERASEBKGND{$ENDIF};
  procedure WMSetFocus(var Message: {$IFDEF FPC}TLMSetFocus{$ELSE}TWMSetFocus{$ENDIF});
    message {$IFDEF FPC}LM_SETFOCUS{$ELSE}WM_SETFOCUS{$ENDIF};
  procedure DoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  procedure HSPickerChange(Sender: TObject);
  procedure LPickerChange(Sender: TObject);
  procedure DoChange;
 public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;

  function GetColorUnderCursor: TColor;
  function GetHexColorUnderCursor: string;
  function GetSelectedHexColor: string;
  property ColorUnderCursor: TColor read GetColorUnderCursor;
  property HValue: integer read FHValue write SetH default 0;
  property SValue: integer read FSValue write SetS default 240;
  property LValue: integer read FLValue write SetL default 120;
  property RValue: integer read FRValue write SetR default 255;
  property GValue: integer read FGValue write SetG default 0;
  property BValue: integer read FBValue write SetB default 0;
  property Manual: boolean read GetManual;
 published
  property LuminanceIncrement: integer read FLumIncrement write SetLumIncrement default 1;
  property SelectedColor: TColor read FSelectedColor write SetSelectedColor default clRed;
  property HSPickerPopupMenu: TPopupMenu read FHSMenu write SetHSMenu;
  property LPickerPopupMenu: TPopupMenu read FLMenu write SetLMenu;
  property HSPickerHintFormat: string read FHSHint write SetHSHint;
  property LPickerHintFormat: string read FLHint write SetLHint;
  property HSPickerCursor: TCursor read FHSCursor write SetHSCursor default crDefault;
  property LPickerCursor: TCursor read FLCursor write SetLCursor default crDefault;
  property TabStop default true;
  property ShowHint;
  property ParentShowHint;
  property Anchors;
  property Align;
  property Visible;
  property Enabled;
  property TabOrder;
  property Color;
  property ParentColor default true;
  {$IFDEF DELPHI_7_UP}{$IFDEF DELPHI}
  property ParentBackground default true;
  {$ENDIF}{$ENDIF}

  property OnChange: TNotifyEvent read FOnChange write FOnChange;
  property OnMouseMove;
 end;

procedure Register;

implementation

{$IFDEF FPC}
  {$R HSLColorPicker.dcr}
{$ENDIF}

procedure Register;
begin
 RegisterComponents('mbColor Lib', [THSLColorPicker]);
end;

{THSLColorPicker}

constructor THSLColorPicker.Create(AOwner: TComponent);
begin
 inherited;
 ControlStyle := ControlStyle - [csAcceptsControls] + [csOpaque];
 DoubleBuffered := true;
 ParentColor := true;
 PBack := TBitmap.Create;
 PBack.PixelFormat := pf32bit;
 {$IFDEF DELPHI_7_UP} {$IFDEF DELPHI}
 ParentBackground := true;
 {$ENDIF} {$ENDIF}
 Width := 206;
 Height := 146;
 TabStop := true;
 FSelectedColor := clRed;
 FHSPicker := THSColorPicker.Create(Self);
 InsertControl(FHSPicker);
 FLumIncrement := 1;
 FHSCursor := crDefault;
 FLCursor := crDefault;
 with FHSPicker do
  begin
   Height := 134;
   Width := 174;
   Top := 6;
   Left := 0;
   Anchors := [akLeft, akTop, akRight, akBottom];
   Visible := true;
   OnChange := HSPickerChange;
   OnMouseMove := DoMouseMove;
  end;
 FLPicker := TLColorPicker.Create(Self);
 InsertControl(FLPicker);
 with FLPicker do
  begin
   Height := 146;
   Top := 0;
   Left := 184;
   Anchors := [akRight, akTop, akBottom];
   Visible := true;
   OnChange := LPickerChange;
   OnMouseMove := DoMouseMove;
  end;
 FHValue := 0;
 FSValue := 240;
 FLValue := 120;
 FRValue := 255;
 FGValue := 0;
 FBValue := 0;
 FHSHint := 'H: %h S: %hslS'#13'Hex: %hex';
 FLHint := 'Luminance: %l';
end;

destructor THSLColorPicker.Destroy;
begin
 PBack.Free;
 FHSPicker.Free;
 FLPicker.Free;
 inherited Destroy;
end;

procedure THSLColorPicker.HSPickerChange(Sender: TObject);
begin
 FLPicker.Hue := FHSPicker.HueValue;
 FLPicker.Saturation := FHSPicker.SaturationValue;
 DoChange;
end;

procedure THSLColorPicker.LPickerChange(Sender: TObject);
begin
 FHSPicker.Lum := FLPicker.Luminance;
 FSelectedColor := FLPicker.SelectedColor;
 DoChange;
end;

procedure THSLColorPicker.DoChange;
begin
 FHValue := FLPicker.Hue;
 FSValue := FLPicker.Saturation;
 FLValue := FLPicker.Luminance;
 FRValue := GetRValue(FLPicker.SelectedColor);
 FGValue := GetGValue(FLPicker.SelectedColor);
 FBValue := GetBValue(FLPicker.SelectedColor);
 if Assigned(FOnChange) then
  FOnChange(Self);
end;

procedure THSLColorPicker.SelectColor(c: TColor);
begin
 FSelectedColor := c;
 FHSPicker.SelectedColor := c;
 FLPicker.SelectedColor := c;
end;

procedure THSLColorPicker.SetH(v: integer);
begin
 FHValue := v;
 FHSPicker.HueValue := v;
 FLPicker.Hue := v;
end;

procedure THSLColorPicker.SetS(v: integer);
begin
 FSValue := v;
 FHSPicker.SaturationValue := v;
 FLPicker.Saturation := v;
end;

procedure THSLColorPicker.SetL(v: integer);
begin
 FLValue := v;
 FLPicker.Luminance := v;
end;

procedure THSLColorPicker.SetR(v: integer);
begin
 FRValue := v;
 SetSelectedColor(RGB(FRValue, FGValue, FBValue));
end;

procedure THSLColorPicker.SetG(v: integer);
begin
 FGValue := v;
 SetSelectedColor(RGB(FRValue, FGValue, FBValue));
end;

procedure THSLColorPicker.SetB(v: integer);
begin
 FBValue := v;
 SetSelectedColor(RGB(FRValue, FGValue, FBValue));
end;

function THSLColorPicker.GetSelectedHexColor: string;
begin
 Result := ColorToHex(FSelectedColor);
end;

procedure THSLColorPicker.SetHSHint(h: string);
begin
 FHSHint := h;
 FHSPicker.HintFormat := h;
end;

procedure THSLColorPicker.SetLHint(h: string);
begin
 FLHint := h;
 FLPicker.HintFormat := h;
end;

procedure THSLColorPicker.SetLMenu(m: TPopupMenu);
begin
 FLMenu := m;
 FLPicker.PopupMenu := m;
end;

procedure THSLColorPicker.SetHSMenu(m: TPopupMenu);
begin
 FHSMenu := m;
 FHSPicker.PopupMenu := m;
end;

procedure THSLColorPicker.SetLumIncrement(i: integer);
begin
 FLumIncrement := i;
 FLPicker.Increment := i;
end;

procedure THSLColorPicker.DoMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
 if Assigned(OnMouseMove) then
  OnMouseMove(Self, Shift, x, y);
 inherited;
end;

function THSLColorPicker.GetColorUnderCursor: TColor;
begin
 Result := FHSPicker.GetColorUnderCursor;
end;

function THSLColorPicker.GetHexColorUnderCursor: string;
begin
 Result := FHSPicker.GetHexColorUnderCursor;
end;

procedure THSLColorPicker.SetHSCursor(c: TCursor);
begin
 FHSCursor := c;
 FHSPicker.Cursor := c;
end;

procedure THSLColorPicker.SetLCursor(c: TCursor);
begin
 FLCursor := c;
 FLPicker.Cursor := c;
end;

procedure THSLColorPicker.WMSetFocus(
  var Message: {$IFDEF FPC}TLMSetFocus{$ELSE}TWMSetFocus{$ENDIF} );
begin
 FHSPicker.SetFocus;
 Message.Result := 1;
end;

function THSLColorPicker.GetManual:boolean;
begin
 Result := FHSPicker.Manual or FLPicker.Manual;
end;

procedure THSLColorPicker.PaintParentBack;
{$IFDEF DELPHI_7_UP} {$IFDEF DELPHI}
var
 MemDC: HDC;
 OldBMP: HBITMAP;
 {$ENDIF} {$ENDIF}
begin
 if PBack = nil then
  begin
   PBack := TBitmap.Create;
   PBack.PixelFormat := pf32bit;
  end;
 PBack.Width := Width;
 PBack.Height := Height;
 {$IFDEF FPC}
 if Color = clDefault then
   PBack.Canvas.Brush.Color := clForm
 else
 {$ENDIF}
 PBack.Canvas.Brush.Color := Color;
 PBack.Canvas.FillRect(PBack.Canvas.ClipRect);
 {$IFDEF DELPHI_7_UP} {$IFDEF DELPHI}
 if ParentBackground then
  with ThemeServices do
   if ThemesEnabled then
    begin
     MemDC := CreateCompatibleDC(0);
     OldBMP := SelectObject(MemDC, PBack.Handle);
     DrawParentBackground(Handle, MemDC, nil, False);
     if OldBMP <> 0 then SelectObject(MemDC, OldBMP);
     if MemDC <> 0 then DeleteDC(MemDC);
    end;
 {$ENDIF} {$ENDIF}
end;

procedure THSLColorPicker.Resize;
begin
 inherited;
 PaintParentBack;
end;

procedure THSLColorPicker.CreateWnd;
begin
 inherited;
 PaintParentBack;
end;

procedure THSLColorPicker.Paint;
begin
 PaintParentBack;
 Canvas.Draw(0, 0, PBack);
end;

procedure THSLColorPicker.WMEraseBkgnd(
  var Message: {$IFDEF FPC}TLMEraseBkgnd{$ELSE}TWMEraseBkgnd{$ENDIF} );
begin
 Message.Result := 1;
end;

procedure THSLColorPicker.SetSelectedColor(Value: TColor);
begin
 if FSelectedColor <> Value then
  begin
   SelectColor(Value);
   //FLPicker.Hue := FHSPicker.HueValue;
   //FLPicker.Saturation := FHSPicker.SaturationValue;
  end;
end;

end.