{==============================================================================

  Custom Panels
  Copyright (C) 2000-2001 by Evgeny Kryukov
  All rights reserved

  All contents of this file and all other files included in this archive
  are Copyright (C) 2001 Evgeny Kryukov. Use and/or distribution of
  them requires acceptance of the License Agreement.

  See License.txt for licence information

===============================================================================}

unit KsProgress;

{$I KsCommonVer.Inc}
{$T-,W-,X+,P+}

interface

uses
  Windows, Classes, Graphics, Forms, KsBitmap, KsUtils, KsControls;

const

  SegRation   = 0.64; { Segment width to height ration }
  SegSpacing  = 2;    { Spacing b/w segment }

type

{ TKsCustomProgressBar class }

{ TKsCustomProgressBar is a advanced Windows progress bar. }
  TKsCustomProgressBar = class(TKsCustomControl)
  private
    FMax: Integer;
    FMin: Integer;
    FPosition: Integer;
    FOrientation: TKsBarOrientation;
    FBorderWidth: integer;
    FShowBorder: boolean;
    FSmooth: boolean;
    { Properties }
    procedure SetMax(Value: Integer);
    procedure SetMin(Value: Integer);
    procedure SetPosition(Value: Integer);
    procedure SetOrientation(const Value: TKsBarOrientation);
    procedure SetBorderWidth(const Value: integer);
    procedure SetShowBorder(const Value: boolean);
    procedure SetSmooth(const Value: boolean);
  protected
    { Internal }
    function GetPercent(APosition: integer): single;
    { Inherited }
    procedure PaintBuffer; override;
    { ProgressBar }
    function  GetBarRect: TRect; virtual;
    procedure PaintBar; virtual;
    procedure PaintFrame; virtual;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Align;
    property Anchors; 
    { Specifies the distance, in pixels, between the bevel and bar area. }
    property BorderWidth: integer read FBorderWidth write SetBorderWidth;
    property Max: Integer read FMax write SetMax default 100;
    property Min: Integer read FMin write SetMin default 0;
    property Position: Integer read FPosition write SetPosition;
    property Orientation: TKsBarOrientation read FOrientation write SetOrientation;
    { Determines whether to show progress bar border }
    property ShowBorder: boolean read FShowBorder write SetShowBorder;
    property Smooth: boolean read FSmooth write SetSmooth;
  end;

implementation {===============================================================}

{ TKsCustomProgressBar }

constructor TKsCustomProgressBar.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FBorderWidth := 0;
  FMax := 100;
  FSmooth := false;
  FShowBorder := true;

  Color := clBtnFace;
  Width := 140;
  Height := 16;
  Transparent := true;
end;

{ ProgressBar }

function TKsCustomProgressBar.GetPercent(APosition: integer): single;
begin
  if (Min >= 0) and (APosition >= Min) and (Max >= APosition) and (Max - Min <> 0) then
    Result := (APosition - Min) / (Max - Min)
  else
    Result := 0;
end;

function TKsCustomProgressBar.GetBarRect: TRect;
begin
  Result := Rect(0, 0, FWidth, FHeight);

  if FShowBorder then
    InflateRect(Result, -2, -2);
    
  InflateRect(Result, -FBorderWidth, -FBorderWidth);
end;

procedure TKsCustomProgressBar.PaintFrame;
var
  R: TRect;
  BackColor: TKColor;
  RColor, SColor: TKColor;
begin
  with Buffer do
  begin
    R := Rect(0, 0, FWidth, FHeight);
    { Draw Border }
    if FShowBorder then
    begin
      DrawEdge(R, KColor(clBtnShadow), KColor(clBtnHighlight));
      InflateRect(R, -1, -1);
    end;

    FillRect(R, KColor(Color));
  end;
end;

procedure TKsCustomProgressBar.PaintBar;
var
  FillR, R: TRect;
  i, W, Pos: integer;
  SegW, SegH, SegCount, FillSegCount: integer;
  FillColor: TKColor;
begin
  with Buffer do
  begin
    R := GetBarRect;
    if Orientation = kboHorizontal then
      W := RectWidth(R)
    else
      W := RectHeight(R);
    { Calc Pos }
    Pos := Round(W * GetPercent(Position));
    { Set FillR }
    FillR := R;

    { Set FillColor }
    FillColor := KColor(clHighlight);
    { Draw Bar }
    if FOrientation = kboHorizontal then
    begin
      { Horizontal }
      FillR.Right := FillR.Left + Pos;

      if FSmooth then
      begin
        { Smooth }
        FillRect(FillR, FillColor);
      end
      else
      begin
        { Segments }
        SegH := RectHeight(R);
        SegW := Round(SegH * SegRation) + SegSpacing;
        { Calc SegCount }
        SegCount := W div SegW;
        FillSegCount := Round(SegCount * GetPercent(Position));
        { Draw Segments }
        if GetPercent(Position) >= 0.01 then
          for i := 0 to FillSegCount do
          begin
            FillR := R;
            FillR.Right := FillR.Left + SegW - SegSpacing;
            OffsetRect(FillR, i * SegW, 0);
            { Clip }
            IntersectRect(FillR, FillR, R);
            { Draw }
            FillRect(FillR, FillColor);
          end;
      end;
    end
    else
    begin
      { Vertical }
      FillR.Top := FillR.Bottom - Pos;

      if FSmooth then
      begin
        { Smooth }
        FillRect(FillR, FillColor);
      end
      else
      begin
        { Segments }
        SegH := RectWidth(R);
        SegW := Round(SegH * SegRation) + SegSpacing;
        { Calc SegCount }
        SegCount := W div SegW;
        FillSegCount := Round(SegCount * GetPercent(Position));
        { Draw Segments }
        if GetPercent(Position) >= 0.01 then
          for i := 0 to FillSegCount do
          begin
            FillR := R;
            FillR.Top := FillR.Bottom - SegW + SegSpacing;
            OffsetRect(FillR, 0, - (i * SegW));
            { Clip }
            IntersectRect(FillR, FillR, R);
            { Draw }
            FillRect(FillR, FillColor);
          end;
      end;
    end;
  end;
end;

{ Inherited }

procedure TKsCustomProgressBar.PaintBuffer;
begin
  inherited ;
  PaintFrame;
  PaintBar;
end;

{ Properties }

procedure TKsCustomProgressBar.SetMax(Value: Integer);
begin
  FMax := Value;
  Invalidate;
end;

procedure TKsCustomProgressBar.SetMin(Value: Integer);
begin
  FMin := Value;
  Invalidate;
end;

procedure TKsCustomProgressBar.SetOrientation(
  const Value: TKsBarOrientation);
begin
  if Value <> Orientation then
  begin
    FOrientation := Value;
    Invalidate;
  end;
end;

procedure TKsCustomProgressBar.SetPosition(Value: Integer);
var
  OldPos: integer;
begin
  if Value <> FPosition then
  begin
    OldPos := FPosition;

    FPosition := Value;

    if GetPercent(Position) <> GetPercent(OldPos) then
    begin
      Invalidate;
      Application.ProcessMessages;
    end;
  end;
end;

procedure TKsCustomProgressBar.SetBorderWidth(const Value: integer);
begin
  if FBorderWidth <> Value then
  begin
    FBorderWidth := Value;
    Invalidate;
  end;
end;

procedure TKsCustomProgressBar.SetShowBorder(const Value: boolean);
begin
  if FShowBorder <> Value then
  begin
    FShowBorder := Value;
    Invalidate;
  end;
end;

procedure TKsCustomProgressBar.SetSmooth(const Value: boolean);
begin
  if FSmooth <> Value then
  begin
    FSmooth := Value;
    Invalidate;
  end;
end;

end.
