unit KOLProgBar;

interface

uses
  Windows, Messages, KOL;

type

  TBevel = (bvUp, bvDown, bvNone);

  PColorProgBar =^TColorProgBar;
  TColorProgressBar = PColorProgBar;
  TColorProgBar = object(TObj)
  private
    { Private declarations }
    fControl : PControl;
    fPosition: integer;
    fOldPosit: integer;
    fBColor,
    fFColor  : TColor;
    fFirst   : boolean;
    fBorder  : integer;
    fParentCl: boolean;
    fBevel   : TBevel;
    fMin,
    fMax     : integer;
    fStr     : string;
    fFont    : PGraphicTool;
    fCanvas  : PCanvas;
    OldWind,
    NewWind  : longint;
    procedure SetFColor(C: TColor);
    procedure SetBColor(C: TColor);
    procedure SetPos(P: integer);
    procedure SetBorder(B: integer);
    procedure SetParentCl(B: boolean);
    procedure SetBevel(B: TBevel);
    procedure SetMin(M: integer);
    procedure SetMax(M: integer);
  protected
    { Protected declarations }
    procedure NewWndProc(var Msg: TMessage);
    procedure Paint;
{    procedure WMPaint(var Msg: TMessage); message WM_PAINT;
    procedure WMSize (var Msg: TMessage); message WM_SIZE;
    procedure WMActiv(var Msg: TMessage); message WM_SHOWWINDOW;
    procedure CMParCl(var Msg: TMessage); message CM_PARENTCOLORCHANGED;}
  public
    destructor Destroy; virtual;
    function  SetPosition(X, Y: integer): PColorProgBar; overload;
    function  SetSize(X, Y: integer): PColorProgBar; overload;
    function  SetAlign(A: TControlAlign): PColorProgBar; overload;
    function  GetFont: PGraphicTool;
    { Public declarations }
{    constructor Create(Owner: TControl); override;}
    property Font: PGraphicTool read GetFont;
    property FColor: TColor read fFColor write SetFColor;
    property BColor: TColor read fBColor write SetBColor;
    property Border: integer read fBorder write SetBorder;
    property Position: integer read fPosition write SetPos;
    property Max: integer read fMax write SetMax;
    property Min: integer read fMin write SetMin;
    property ParentColor: boolean read fParentCl write SetParentCl;
    property Bevel: TBevel read fBevel write SetBevel;
  end;

function NewTColorProgressBar(AOwner: PControl): PColorProgBar;

implementation

uses objects;

function NewTColorProgressBar;
var p: PColorProgBar;
    c: PControl;
begin
{   New(Result, Create);}
   c := pointer(_NewControl( AOwner, 'STATIC', WS_VISIBLE or WS_CHILD or
                 SS_LEFTNOWORDWRAP or SS_NOPREFIX or SS_NOTIFY,
                 False, nil ));
   c.CreateWindow;
   New(p, create);
   AOwner.Add2AutoFree(p);
   p.fControl  := c;
   p.fFont     := NewFont;
   p.fCanvas   := NewCanvas(GetDC(c.Handle));
   p.fMin      := 0;
   p.fMax      := 100;
   p.fFColor   := clRed;
   p.fBColor   := clBtnFace;
   p.fBorder   := 4;
   p.fBevel    := bvDown;
   p.fFirst    := True;
   p.fPosition := 50;
   p.fFont.FontStyle := [fsBold];
   Result  := p;
   p.OldWind := GetWindowLong(c.Handle, GWL_WNDPROC);
   p.NewWind := LongInt(MakeObjectInstance(p.NewWndProc));
   SetWindowLong(c.Handle, GWL_WNDPROC, p.NewWind);
end;

destructor TColorProgBar.Destroy;
begin
   SetWindowLong(fControl.Handle, GWL_WNDPROC, OldWind);
   FreeObjectInstance(Pointer(NewWind));
   fCanvas.Free;
   fFont.Free;
   inherited;
end;

function TColorProgBar.SetPosition(X, Y: integer): PColorProgBar;
begin
   fControl.Left := X;
   fControl.Top := Y;
   Result := @self;
end;

function TColorProgBar.SetSize(X, Y: integer): PColorProgBar;
begin
   fControl.Width  := X;
   fControl.Height := Y;
   Result := @self;
end;

function TColorProgBar.SetAlign(A: TControlAlign): PColorProgBar;
begin
   fControl.Align := A;
   Result := @self;
end;

function TColorProgBar.GetFont;
begin
   Result := fFont;
end;


procedure TColorProgBar.NewWndProc;
begin
   Msg.Result := CallWindowProc(Pointer(OldWind), fControl.Handle, Msg.Msg, Msg.wParam, Msg.lParam);
   case Msg.Msg of
WM_PAINT: Paint;
WM_SIZE: begin
            fFirst := True;
            Paint;
         end;
WM_ACTIVATE:
         begin
            fFirst := True;
            Paint;
         end;
{CM_PARENTCOLORCHANGED:
         begin
            if fParentCl then begin
               if Msg.wParam <> 0 then
               BColor := TColor(Msg.lParam) else
               BColor := (Parent as TForm).Color;
               FColor := (Parent as TForm).Font.Color;
            end;
         end;}
   end;
end;

procedure TColorProgBar.SetFColor;
begin
   fFColor   := C;
   fFirst  := True;
   Paint;
end;

procedure TColorProgBar.SetBColor;
begin
   fBColor := C;
   fFirst  := True;
   Paint;
end;

procedure TColorProgBar.SetPos;
begin
   fPosition := P;
   Paint;
end;

procedure TColorProgBar.SetBorder;
begin
   fBorder := B;
   fFirst := True;
   Paint;
end;

procedure TColorProgBar.SetParentCl;
begin
   fParentCl := B;
   if B then begin
{      Perform(CM_PARENTCOLORCHANGED, 0, 0);}
      Paint;
   end;
end;

procedure TColorProgBar.SetBevel;
begin
   fBevel := B;
   fFirst := True;
   Paint;
end;

procedure TColorProgBar.SetMin;
begin
   fMin := M;
   fFirst := True;
   if fMax = fMin then fMax := fMin + 1;
   Paint;
end;

procedure TColorProgBar.SetMax;
begin
   fMax := M;
   fFirst := True;
   if fMin = fMax then fMin := fMax - 1;
   Paint;
end;

procedure Frame3D(Canvas: PCanvas; var Rect: TRect; TopColor, BottomColor: TColor;
  Width: Integer);

  procedure DoRect;
  var
    TopRight, BottomLeft: TPoint;
  begin
    with Canvas^, Rect do
    begin
      TopRight.X := Right;
      TopRight.Y := Top;
      BottomLeft.X := Left;
      BottomLeft.Y := Bottom;
      Pen.Color := TopColor;
      PolyLine([BottomLeft, TopLeft, TopRight]);
      Pen.Color := BottomColor;
      Dec(BottomLeft.X);
      PolyLine([TopRight, BottomRight, BottomLeft]);
    end;
  end;

begin
  Dec(Rect.Bottom); Dec(Rect.Right);
  while Width > 0 do
  begin
    Dec(Width);
    DoRect;
    InflateRect(Rect, -1, -1);
  end;
  Inc(Rect.Bottom); Inc(Rect.Right);
end;

function ColorToRGB(Color: TColor): Longint;
begin
  if Color < 0 then
    Result := GetSysColor(Color and $000000FF) else
    Result := Color;
end;

procedure TColorProgBar.Paint;
var Rct: TRect;
    Trc: TRect;
    Twk: TRect;
    Str: string;
    Rht: integer;
    Len: integer;
    Rgn: HRgn;
    Stw: integer;
begin
   GetClientRect(fControl.Handle, Rct);
   Trc := Rct;
   if (fPosition <= fOldPosit) or fFirst then begin
      case fBevel of
  bvUp: begin
           Frame3D(fCanvas, Rct, clWhite, clBlack, 1);
        end;
bvDown: begin
           Frame3D(fCanvas, Rct, clBlack, clWhite, 1);
        end;
      end;

      fFirst := False;
      fCanvas.brush.Color := fBColor;
      fCanvas.FillRect(Rct);
   end;
   Rct    := Trc;

   InflateRect(Rct, -fBorder, -fBorder);
   Rct.Right  := Rct.Left + (Rct.Right - Rct.Left) * fPosition div (Max - Min);

   Str := ' ' + int2str(fPosition * 100 div (fMax - fMin)) + '% ';

   SelectObject(fCanvas.Handle, fFont.Handle);
   Stw       := fCanvas.TextWidth(Str);
   Trc.Left  := (fControl.width - Stw) div 2;
   Trc.Right := (fControl.width + Stw) div 2 + 1;
   Twk       := Rct;

   fCanvas.brush.Color := fFColor;
   if (Rct.Right <= Trc.Left) then begin
      fCanvas.FillRect(Rct);
   end else begin
      Twk.Right := Trc.Left;
      fCanvas.FillRect(Twk);
   end;

   Rht := Rct.Right;
   Len := Length(Str);

   Rct.Left  := (fControl.width - Stw) div 2;
   Rct.Right := (fControl.width + Stw) div 2 + 1;

   if fStr <> Str then begin
      if (Rct.Right > Rht) or (fCanvas.TextHeight(Str) > (Rct.Bottom - Rct.Top)) then begin
         Rgn := CreateRectRgn(Rht, Rct.Top, Rct.Right, Rct.Bottom);
         SelectClipRgn(fCanvas.Handle, Rgn);
         SelectObject(fCanvas.Handle, fFont.Handle);
         SetBkColor(fCanvas.Handle, ColorToRGB(fBColor));
         SetTextColor(fCanvas.Handle, ColorToRGB(fFColor));
         DrawText(fCanvas.Handle, @Str[1], Len, Rct, DT_TOP or DT_NOCLIP);
         SelectClipRgn(fCanvas.Handle, 0);
         DeleteObject(Rgn);
      end;
   end;

   if Rht < Rct.Right then begin
      Rct.Right := Rht;
   end;

   Dec(Rct.Left);
   Inc(Rct.Right);

   if (Rct.Right > Rct.Left) then begin
      SelectObject(fCanvas.Handle, fFont.Handle);
      SetBkColor(fCanvas.Handle, ColorToRGB(fFColor));
      SetTextColor(fCanvas.Handle, ColorToRGB(fBColor));
      DrawText(fCanvas.Handle, @Str[1], Len, Rct, DT_TOP);
      if Rct.Right < Trc.Right then begin
         Twk := Rct;
         Twk.Top := Twk.Top + fCanvas.TextHeight(Str);
         fCanvas.brush.Color := fFColor;
         fCanvas.Fillrect(Twk);
      end;
   end;

   if (Rct.Right >= Trc.Right) then begin
      Rct.Left  := Trc.Right - 2;
      Rct.Right := Rht;
      SetBkColor(fCanvas.Handle, ColorToRGB(fFColor));
      fCanvas.FillRect(Rct);
   end;

   fStr := Str;
   fOldPosit := fPosition;
end;

end.
