unit SLColorPicker; {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} interface uses {$IFDEF FPC} LCLIntf, LCLType, LMessages, {$ELSE} Windows, Messages, {$ENDIF} SysUtils, Classes, Controls, Graphics, Math, RGBHSLUtils, Forms, HTMLColors, SelPropUtils, mbColorPickerControl, Scanlines; type TSLColorPicker = class(TmbColorPickerControl) private FManual: boolean; FHue, FSat, FLum: integer; FOnChange: TNotifyEvent; FChange: boolean; FBMP: TBitmap; procedure CreateSLGradient; procedure DrawMarker(x, y: integer); procedure SelectionChanged(x, y: integer); procedure UpdateCoords; procedure SetHue(h: integer); procedure SetSat(s: integer); procedure SetLum(l: integer); protected procedure WebSafeChanged; override; function GetSelectedColor: TColor; override; procedure SetSelectedColor(c: TColor); override; procedure Paint; override; procedure Resize; override; procedure CreateWnd; override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure CNKeyDown(var Message: {$IFDEF FPC}TLMKeyDown{$ELSE}TWMKeyDown{$ENDIF}); message CN_KEYDOWN; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function GetColorAtPoint(x, y: integer): TColor; override; property Manual: boolean read FManual; published property Hue: integer read FHue write SetHue default 0; property Saturation: integer read FSat write SetSat default 0; property Luminance: integer read FLum write SetLum default 255; property SelectedColor default clWhite; property MarkerStyle default msCircle; property OnChange: TNotifyEvent read FOnChange write FOnChange; end; procedure Register; implementation {$IFDEF FPC} {$R SLColorPicker.dcr} {$ENDIF} procedure Register; begin RegisterComponents('mbColor Lib', [TSLColorPicker]); end; constructor TSLColorPicker.Create(AOwner: TComponent); begin inherited; FBMP := TBitmap.Create; FBMP.PixelFormat := pf32bit; FBMP.SetSize(256, 256); Width := 255; Height := 255; MaxHue := 360; MaxSat := 255; MaxLum := 255; FHue := 0; FSat := 0; FLum := 255; FChange := true; MarkerStyle := msCircle; end; destructor TSLColorPicker.Destroy; begin FBMP.Free; inherited; end; procedure TSLColorPicker.CreateSLGradient; var x, y, skip: integer; row: pRGBQuadArray; tc: TColor; begin if FBMP = nil then begin FBMP := TBitmap.Create; FBMP.PixelFormat := pf32bit; FBMP.Width := 256; FBMP.Height := 256; end; row := FBMP.ScanLine[0]; skip := integer(FBMP.ScanLine[1]) - Integer(row); for y := 0 to 255 do begin for x := 0 to 255 do if not WebSafe then row[x] := HSLtoRGBQuad(FHue, x, 255 - y) else begin tc := GetWebSafe(RGBTripleToTColor(HSLToRGBTriple(FHue, x, 255 - y))); row[x] := RGBtoRGBQuad(GetRValue(tc), GetGValue(tc), GetBValue(tc)); end; row := pRGBQuadArray(Integer(row) + skip); end; end; procedure TSLColorPicker.Resize; begin inherited; UpdateCoords; end; procedure TSLColorPicker.CreateWnd; begin inherited; CreateSLGradient; UpdateCoords; end; procedure TSLColorPicker.UpdateCoords; begin mdx := MulDiv(FSat, Width, 255); mdy := MulDiv(255-FLum, Height, 255); end; procedure TSLColorPicker.DrawMarker(x, y: integer); var c: TColor; begin c := not GetColorAtPoint(x, y); case MarkerStyle of msCircle: DrawSelCirc(x, y, Canvas); msSquare: DrawSelSquare(x, y, Canvas); msCross: DrawSelCross(x, y, Canvas, c); msCrossCirc: DrawSelCrossCirc(x, y, Canvas, c); end; end; procedure TSLColorPicker.Paint; begin Canvas.StretchDraw(ClientRect, FBMP); DrawMarker(mdx, mdy); end; procedure TSLColorPicker.SetHue(h: integer); begin if h > 360 then h := 360; if h < 0 then h := 0; if FHue <> h then begin FHue := h; FManual := false; CreateSLGradient; UpdateCoords; Invalidate; if Fchange then if Assigned(FOnChange) then FOnChange(Self); end; end; procedure TSLColorPicker.SetSat(s: integer); begin if s > 255 then s := 255; if s < 0 then s := 0; if FSat <> s then begin FSat := s; FManual := false; UpdateCoords; Invalidate; if Fchange then if Assigned(FOnChange) then FOnChange(Self); end; end; procedure TSLColorPicker.SetLum(l: integer); begin if l > 255 then l := 255; if l < 0 then l := 0; if FLum <> l then begin FLum := l; FManual := false; UpdateCoords; Invalidate; if Fchange then if Assigned(FOnChange) then FOnChange(Self); end; end; procedure TSLColorPicker.SelectionChanged(x, y: integer); begin FChange := false; // SetSat(MulDiv(255, x, Width)); // SetLum(MulDiv(255, Height - y, Height)); SetSat(MulDiv(255, x, Width - 1)); SetLum(MulDiv(255, Height - y -1, Height - 1)); FChange := true; end; procedure TSLColorPicker.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited; {$IFDEF DELPHI} ClipCursor(nil); {$ENDIF} if csDesigning in ComponentState then Exit; if (Button = mbLeft) and PtInRect(ClientRect, Point(x, y)) then begin mdx := x; mdy := y; SelectionChanged(X, Y); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; end; procedure TSLColorPicker.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var R: TRect; begin inherited; if csDesigning in ComponentState then Exit; if (Button = mbLeft) and PtInRect(ClientRect, Point(x, y)) then begin mdx := x; mdy := y; R := ClientRect; R.TopLeft := ClientToScreen(R.TopLeft); R.BottomRight := ClientToScreen(R.BottomRight); {$IFDEF DELPHI} ClipCursor(@R); {$ENDIF} SelectionChanged(X, Y); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; SetFocus; end; procedure TSLColorPicker.MouseMove(Shift: TShiftState; X, Y: Integer); begin inherited; if csDesigning in ComponentState then Exit; if (ssLeft in Shift) and PtInRect(ClientRect, Point(x, y)) then begin mdx := x; mdy := y; SelectionChanged(X, Y); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; end; procedure TSLColorPicker.SetSelectedColor(c: TColor); var h, s, l: integer; begin if WebSafe then c := GetWebSafe(c); FManual := false; Fchange := false; RGBTripleToHSL(RGBtoRGBTriple(GetRValue(c), GetGValue(c), GetBValue(c)), h, s, l); SetHue(h); SetSat(s); SetLum(l); if Fchange then if Assigned(FOnChange) then FOnChange(Self); FChange := true; end; function TSLColorPicker.GetSelectedColor: TColor; var triple: TRGBTriple; begin triple := HSLToRGBTriple(FHue, FSat, FLum); if not WebSafe then Result := RGBTripleToTColor(triple) else Result := GetWebSafe(RGBTripleToTColor(triple)); end; function TSLColorPicker.GetColorAtPoint(x, y: integer): TColor; var triple: TRGBTriple; begin triple := HSLToRGBTriple(FHue, MulDiv(255, x, Width), MulDiv(255, Height - y, Height)); if not WebSafe then Result := RGBTripleToTColor(triple) else Result := GetWebSafe(RGBTripleToTColor(triple)); end; procedure TSLColorPicker.CNKeyDown( var Message: {$IFDEF FPC}TLMKeyDown{$ELSE}TWMKeyDown{$ENDIF} ); var Shift: TShiftState; FInherited: boolean; begin FInherited := false; Shift := KeyDataToShiftState(Message.KeyData); if not (ssCtrl in Shift) then case Message.CharCode of VK_LEFT: if not (mdx - 1 < 0) then begin Dec(mdx, 1); SelectionChanged(mdx, mdy); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; VK_RIGHT: if not (mdx + 1 > Width) then begin Inc(mdx, 1); SelectionChanged(mdx, mdy); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; VK_UP: if not (mdy - 1 < 0) then begin Dec(mdy, 1); SelectionChanged(mdx, mdy); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; VK_DOWN: if not (mdy + 1 > Height) then begin Inc(mdy, 1); SelectionChanged(mdx, mdy); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; else begin FInherited := true; inherited; end; end else case Message.CharCode of VK_LEFT: if not (mdx - 10 < 0) then begin Dec(mdx, 10); SelectionChanged(mdx, mdy); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; VK_RIGHT: if not (mdx + 10 > Width) then begin Inc(mdx, 10); SelectionChanged(mdx, mdy); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; VK_UP: if not (mdy - 10 < 0) then begin Dec(mdy, 10); SelectionChanged(mdx, mdy); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; VK_DOWN: if not (mdy + 10 > Height) then begin Inc(mdy, 10); SelectionChanged(mdx, mdy); FManual := true; if Assigned(FOnChange) then FOnChange(Self); end; else begin FInherited := true; inherited; end; end; if not FInherited then if Assigned(OnKeyDown) then OnKeyDown(Self, Message.CharCode, Shift); end; procedure TSLColorPicker.WebSafeChanged; begin inherited; CreateSLGradient; Invalidate; end; end.