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

  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 KsSkinTrackBars;

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

interface

uses
  Classes, Controls, Windows, Graphics, Messages, KsBitmap, KsUtils, KsControls,
  KsTrackBars, KsSkinVersion, KsSkinObjects, KsSkinSource, KsSkinEngine;

type

{ TSeSkinTrackBar }

{ TSeSkinTrackBar  is a advanced Windows track bar control. }
  TSeSkinTrackBar = class(TKsCustomTrackBar)
  private
    FSkinEngine: TSeSkinEngine;
    FSkinObject: string;
    FSkinTrackBar: TSeSkinObject;
    function GetThumbHeight: integer;
    
    function GetVersion: TSeSkinVersion;
    procedure SetVersion(const Value: TSeSkinVersion);
    procedure SetSkinEngine(const Value: TSeSkinEngine);
  protected
    procedure WMInvalidateSkinObject(var Msg: TMessage); message WM_INVALIDATESKINOBJECT;
    procedure WMBeforeChange(var Msg: TMessage); message WM_BEFORECHANGE;
    procedure WMSkinChange(var Msg: TMessage); message WM_SKINCHANGE;

    function UseSkin: boolean;

    { TrackBar }
    function GetThumbWidth: integer; override;
    function GetSideMargin: integer; override;
    function GetTopBottomMargin: integer; override;
    procedure DrawTrack(BegCoord, EndCoord, PosCooord: integer); override;
    procedure DrawThumb(APosCoord: integer); override;
    procedure DrawTick(Value, Coord: integer; TopLeft: boolean); override;
    { VCL protected  }
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Loaded; override;
  published
    property Blend;
    property BlendValue;
    property Enabled;
    property IntervalHighlightType;
    property LineSize;
    property Max;
    property Min;
    property Orientation;
    property PageSize;
    property Position;
    property Frequency;
    property ShowTicks;
    { Link to TSeSkinEngine component. Specifies the appearance and behavior by using specified skins from TSeSkinEngine components
      See Also
        TSeSkinEngine
    }
    property SkinEngine: TSeSkinEngine read FSkinEngine write SetSkinEngine;
    { Specifies the SkinObject name, your can change default value to set custom skin object for the control
      For Example:
        For TSeSkinButton the SkinObject property set to 'Button', but your can use you own name - example 'My Button' 
    }
    property SkinObject: string read FSkinObject write FSkinObject;
    property ThumbHalfWidth;
    property ThumbVisible;
    property TickMarks;
    property Version: TSeSkinVersion read GetVersion write SetVersion
      stored false;
    property OnChange;
  end;

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

uses Extctrls, Dialogs;

{ TSeSkinTrackBar }

constructor TSeSkinTrackBar.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FSkinObject := 'TrackBar';
  Transparent := true; 
end;

destructor TSeSkinTrackBar.Destroy;
begin
  if FSkinTrackBar <> nil then FSkinTrackBar.Free;
  inherited Destroy;
end;

procedure TSeSkinTrackBar.Loaded;
begin
  inherited;
{  SkinEngine := FSkinEngine; }
end;

{ Theme }

function TSeSkinTrackBar.UseSkin: boolean;
begin
  if (csDestroying in ComponentState) or (csLoading in ComponentState) then
    Result := false
  else
    if (FSkinEngine <> nil) and (FSkinEngine.SkinSource <> nil) and
       (not FSkinEngine.SkinSource.IsChanging) and
       (FSkinEngine.SkinSource.Count > 0) and
       (FSkinEngine.SkinSource.GetObjectByName(FSkinObject) <> nil) and
       (FSkinTrackBar <> nil)
    then
      Result := true
    else
      Result := false;
end;

{ Track Bar }

function TSeSkinTrackBar.GetThumbWidth: integer;
var
  SkinObject: TseSkinObject;
begin
  Result := inherited GetThumbWidth;

  if UseSkin then
  begin
    if (Orientation = toHorizontal) then
      SkinObject := FSkinTrackBar.FindObjectByName('ThumbHorz');

    if (Orientation = toVertical) then
      SkinObject := FSkinTrackBar.FindObjectByName('ThumbVert');

    if SkinObject = nil then
      SkinObject := FSkinTrackBar.FindObjectByName('Thumb');

    if SkinObject <> nil then
      if (Orientation = toHorizontal) then
        Result := SkinObject.Width
      else
        Result := SkinObject.Height;
  end;
end;

function TSeSkinTrackBar.GetThumbHeight: integer;
var
  SkinObject: TseSkinObject;
begin
  Result := Round(GetThumbWidth * CStdThumbRatio);

  if UseSkin then
  begin
    if (Orientation = toHorizontal) then
      SkinObject := FSkinTrackBar.FindObjectByName('ThumbHorz');

    if (Orientation = toVertical) then
      SkinObject := FSkinTrackBar.FindObjectByName('ThumbVert');

    if SkinObject = nil then
      SkinObject := FSkinTrackBar.FindObjectByName('Thumb');

    if SkinObject <> nil then
      if (Orientation = toHorizontal) then
        Result := SkinObject.Height
      else
        Result := SkinObject.Width;
  end
end;

function TSeSkinTrackBar.GetSideMargin: integer;
var
  SkinObject: TseSkinObject;
begin
  Result := inherited GetSideMargin;

  if UseSkin then
  begin
    if (Orientation = toHorizontal) then
      SkinObject := FSkinTrackBar.FindObjectByName('FrameHorz');

    if (Orientation = toVertical) then
      SkinObject := FSkinTrackBar.FindObjectByName('FrameVert');

    if SkinObject = nil then
      SkinObject := FSkinTrackBar.FindObjectByName('Frame');

    if SkinObject <> nil then
      if (Orientation = toHorizontal) then
        Result := SkinObject.MarginLeft
      else
        Result := SkinObject.MarginTop;
  end
end;

function TSeSkinTrackBar.GetTopBottomMargin: integer;
var
  SkinObject: TseSkinObject;
begin
  Result := inherited GetTopBottomMargin;

  if UseSkin then
  begin
    if (Orientation = toHorizontal) then
      SkinObject := FSkinTrackBar.FindObjectByName('FrameHorz');

    if (Orientation = toVertical) then
      SkinObject := FSkinTrackBar.FindObjectByName('FrameVert');

    if SkinObject = nil then
      SkinObject := FSkinTrackBar.FindObjectByName('Frame');

    if SkinObject <> nil then
      if (Orientation = toHorizontal) then
        Result := SkinObject.MarginTop
      else
        Result := SkinObject.MarginLeft;
  end
end;

procedure TSeSkinTrackBar.DrawTrack(BegCoord, EndCoord, PosCooord: integer);
var
  R, LTrackRect, LowIntervalRect, TmpRect: TRect;
  LSideMarign, LTopBottmMarign, LThumbWidth, LThumbHeight: integer;
  Frame, SkinObject: TSeSkinObject;
begin
  if not UseSkin then
    inherited
  else
  begin
    LThumbWidth := GetThumbWidth;
    LTopBottmMarign := GetTopBottomMargin;
    LSideMarign := GetSideMargin;
    LThumbHeight := GetThumbHeight;

    with LTrackRect do
    begin
      if Orientation = toHorizontal then
      begin
        Top := LTopBottmMarign;
        if TickMarks = tmTopLeft then
          Top := Top + LThumbWidth div 2
        else
          Top := Top + LThumbWidth div 4;

        if ShowTicks and ((TickMarks = tmTopLeft) or (TickMarks = tmBoth)) then
          Top := Top + 4 + 1;

        if TickMarks = tmBoth then
        begin
          Bottom := Top + LThumbHeight - (LThumbWidth div 4) * 2;
          InflateRect(LTrackRect, 0, -1);
        end
        else
          Bottom := Top + LThumbHeight - LThumbWidth div 2 - LThumbWidth div 4;

        Left := BegCoord;
        Right := EndCoord;

        LowIntervalRect.Top := Top;
        LowIntervalRect.Bottom := Bottom;
        if IntervalHighlightType = htLowInterval then
        begin
          LowIntervalRect.Left := Left;
          LowIntervalRect.Right := PosCooord;
        end
        else
        begin
          LowIntervalRect.Left := PosCooord;
          LowIntervalRect.Right := Right;
        end;
      end
      else
      begin
        Left := LTopBottmMarign;
        if TickMarks = tmTopLeft then
          Left := Left + LThumbWidth div 2
        else
          Left := Left + LThumbWidth div 4;

        if ShowTicks and ((TickMarks = tmTopLeft) or (TickMarks = tmBoth)) then
          Left := Left + 4 + 1;

        if TickMarks = tmBoth then
        begin
          Right := Left + LThumbHeight - (LThumbWidth div 4) * 2;
          InflateRect(LTrackRect, -1, 0);
        end
        else
          Right := Left + LThumbHeight - LThumbWidth div 2 - LThumbWidth div 4;

        Top := BegCoord;
        Bottom := EndCoord;

        LowIntervalRect.Left := Left;
        LowIntervalRect.Right := Right;
        if IntervalHighlightType = htLowInterval then
        begin
          LowIntervalRect.Top := Top;
          LowIntervalRect.Bottom := PosCooord;
        end
        else
        begin
          LowIntervalRect.Top := PosCooord;
          LowIntervalRect.Bottom := Bottom;
        end;
      end;
    end;

    if not Enabled or (IntervalHighlightType = htNone) then
      LowIntervalRect := Rect(0, 0, 0, 0);

    { Draw }
    if Orientation = toHorizontal then
      SkinObject := FSkinTrackBar.FindObjectByName('TrackHorz')
    else
      SkinObject := FSkinTrackBar.FindObjectByName('TrackVert');

    if SkinObject = nil then
      SkinObject := FSkinTrackBar.FindObjectByName('Track');

    { Draw Highlight }
    if SkinObject <> nil then
    begin
      R := LTrackRect;
      if Orientation = toHorizontal then
        R.Bottom := R.Top + SkinObject.Height
      else
        R.Right := R.Left + SkinObject.Width;

      RectCenter(R, LTrackRect);

      SkinObject.BoundsRect := R;
      SkinObject.Draw(Buffer);

      LTrackRect := R;

      Frame := SkinObject;

      if Orientation = toHorizontal then
        SkinObject := FSkinTrackBar.FindObjectByName('HighlightHorz')
      else
        SkinObject := FSkinTrackBar.FindObjectByName('HighlightVert');

      if SkinObject = nil then
        SkinObject := FSkinTrackBar.FindObjectByName('Highlight');

      { Draw Highlight }
      if SkinObject <> nil then
      begin
        R := LTrackRect;
        if Orientation = toHorizontal then
        begin
          R.Left := LowIntervalRect.Left;
          R.Right := LowIntervalRect.Right;
        end
        else
        begin
          R.Top := LowIntervalRect.Top;
          R.Bottom := LowIntervalRect.Bottom;
        end;

        if (Orientation = toVertical) and (IntervalHighlightType = htHighInterval) and
           (Frame <> nil) then
        begin
          SkinObject.BoundsRect := R;
          SkinObject.Draw(Buffer);
        end
        else
        begin
          SkinObject.BoundsRect := R;
          SkinObject.Draw(Buffer);
        end;
      end;
    end;
  end;
end;

procedure TSeSkinTrackBar.DrawThumb(APosCoord: integer);
var
  Bx, By: integer;
  LThumbWidth, LThumbHeight: integer;
  DrawState: TSeState;
  SkinObject: TSeSkinObject;
begin
  if not ThumbVisible then Exit;

  if not UseSkin then
    inherited
  else
  begin
    LThumbWidth := GetThumbWidth;
    LThumbHeight := GetThumbHeight;

    if not Enabled then
      DrawState := ssDisabled
    else
      if ThumbPressed then
        DrawState := ssPressed
      else
        if MouseOnThumb then
          DrawState := ssHot
        else
          if Focused then
            DrawState := ssFocused
          else
            DrawState := ssNormal;

    with Buffer do
    begin
      if Orientation = toHorizontal then
      begin
        Bx := APosCoord - LThumbWidth div 2;
        By := GetTopBottomMargin;
        if ShowTicks and ((TickMarks = tmTopLeft) or (TickMarks = tmBoth)) then
          By := By + 4 + 1;

        case TickMarks of
          tmTopLeft: SkinObject := FSkinTrackBar.FindObjectByName('ThumbHorzTop');
          tmBottomRight: SkinObject := FSkinTrackBar.FindObjectByName('ThumbHorzBottom');
        else
          SkinObject := nil;
        end;

        if SkinObject = nil then
          SkinObject := FSkinTrackBar.FindObjectByName('ThumbHorz');
        if SkinObject = nil then
          SkinObject := FSkinTrackBar.FindObjectByName('Thumb');

        if SkinObject <> nil then
        begin
          SkinObject.BoundsRect := Rect(Bx, By, Bx + LThumbWidth, By + LThumbHeight);
          SkinObject.State := DrawState;
          SkinObject.Draw(Buffer);
        end;
      end
      else
      begin
        { Orientation = toVertical }

        Bx := GetTopBottomMargin;
        By := APosCoord - LThumbWidth div 2;
        if ShowTicks and ((TickMarks = tmTopLeft) or (TickMarks = tmBoth)) then
          Bx := Bx + 4 + 1;

        case TickMarks of
          tmTopLeft: SkinObject := FSkinTrackBar.FindObjectByName('ThumbVertLeft');
          tmBottomRight: SkinObject := FSkinTrackBar.FindObjectByName('ThumbVertRight');
        else
          SkinObject := nil;
        end;

        if SkinObject = nil then
          SkinObject := FSkinTrackBar.FindObjectByName('ThumbVert');
        if SkinObject = nil then
          SkinObject := FSkinTrackBar.FindObjectByName('Thumb');

        if SkinObject <> nil then
        begin
          SkinObject.BoundsRect := Rect(Bx, By, Bx + LThumbHeight, By + LThumbWidth);
          SkinObject.State := DrawState;
          SkinObject.Draw(Buffer);
        end;
      end;
    end;
  end;
end;

procedure TSeSkinTrackBar.DrawTick(Value, Coord: integer;
  TopLeft: boolean);
var
  VCoord: integer;
  LThumbHeight: integer;
  TickColor: TKColor;
begin
  if not UseSkin then
    inherited
  else
  begin
    LThumbHeight := GetThumbHeight;

    if Enabled then
      TickColor := ckBorder
    else
      TickColor := ckBtnShadow;

    if TopLeft then
    begin
      VCoord := GetTopBottomMargin + 3;
      with Buffer do
      begin
        if Orientation = toHorizontal then
        begin
          MoveTo(Coord, VCoord);
          if (Value = Min) or (Value = Max) then
            LineTo(Coord, VCoord - 4, TickColor)
          else
            LineTo(Coord, VCoord - 3, TickColor);
        end
        else
        begin
          MoveTo(VCoord, Coord);
          if (Value = Min) or (Value = Max) then
            LineTo(VCoord - 4, Coord, TickColor)
          else
            LineTo(VCoord - 3, Coord, TickColor);
        end;
      end
    end
    else
    begin
      if TickMarks = tmBoth then
        VCoord := GetTopBottomMargin + 4 + 1 +
          LThumbHeight + 1
      else
        VCoord := GetTopBottomMargin + 1 +
          LThumbHeight + 1;
      with Buffer do
      begin
        if Orientation = toHorizontal then
        begin
          MoveTo(Coord, VCoord);
          if (Value = Min) or (Value = Max) then
            LineTo(Coord, VCoord + 4, TickColor)
          else
            LineTo(Coord, VCoord + 3, TickColor);
        end
        else
        begin
          MoveTo(VCoord, Coord);
          if (Value = Min) or (Value = Max) then
            LineTo(VCoord + 4, Coord, ckBorder)
          else
            LineTo(VCoord + 3, Coord, ckBorder);
        end;
      end;
    end;
  end;
end;

procedure TSeSkinTrackBar.WMInvalidateSkinObject(var Msg: TMessage);
begin
  Invalidate;
end;

procedure TSeSkinTrackBar.WMBeforeChange(var Msg: TMessage);
begin
  if Pointer(Msg.LParam) = nil then Exit;
  if TSeSkinEngine(Msg.LParam) <> FSkinEngine then Exit;

  if FSkinTrackBar <> nil then FSkinTrackBar.Free;
  FSkinTrackBar := nil;
end;

procedure TSeSkinTrackBar.WMSkinChange(var Msg: TMessage);
begin
  if Pointer(Msg.LParam) = nil then Exit;
  if TSeSkinEngine(Msg.LParam) <> FSkinEngine then Exit;

  SkinEngine := FSkinEngine;
end;

{ VCL }

procedure TSeSkinTrackBar.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited;
  if (Operation = opRemove) and (AComponent = FSkinEngine) then
    SkinEngine := nil;
end;

{ Properties }

function TSeSkinTrackBar.GetVersion: TSeSkinVersion;
begin
  Result := sSeSkinVersion;
end;

procedure TSeSkinTrackBar.SetVersion(const Value: TSeSkinVersion);
begin
end;

procedure TSeSkinTrackBar.SetSkinEngine(const Value: TSeSkinEngine);
begin
  FSkinEngine := Value;

  if (FSkinEngine <> nil) and (FSkinEngine.SkinSource <> nil) and
     (not FSkinEngine.SkinSource.IsChanging) and
     (FSkinEngine.SkinSource.Count > 0) then
  begin
    if FSkinTrackBar <> nil then FSkinTrackBar.Free;
    FSkinTrackBar := nil;

    if FSkinEngine.SkinSource.GetObjectByName(FSkinObject) <> nil then
      FSkinTrackBar := FSkinEngine.SkinSource.GetObjectByName(FSkinObject).CreateCopy(nil);

    if FSkinTrackBar <> nil then FSkinTrackBar.ParentControl := Self;
  end
  else
  begin
    if FSkinTrackBar <> nil then FSkinTrackBar.Free;
    FSkinTrackBar := nil;
  end;

  Invalidate;
end;

end.

