{***************************************************************************}
{ TMS IntraWeb Component Pack Pro                                           }
{ for Delphi & C++Builder                                                   }
{                                                                           }
{ written by TMS Software                                                   }
{            copyright © 2002 - 2008                                        }
{            Email : info@tmssoftware.com                                   }
{            Web : http://www.tmssoftware.com                               }
{                                                                           }
{ The source code is given as is. The author is not responsible             }
{ for any possible damage done due to the use of this code.                 }
{ The component can be freely used in any application. The complete         }
{ source code remains property of the author and may not be distributed,    }
{ published, given or sold in any form as such. No parts of the source      }
{ code can be included in any other component or application without        }
{ written authorization of the author.                                      }
{***************************************************************************}

unit IWExchangeBar;

interface
                                      
{$R TMSIWEXCHANGEBAR.RES}

{$I TMSDEFS.INC}

uses
  Classes, SysUtils, ExtCtrls, Windows, Math, Graphics,
  IWTMSImg, IWControl, IWExtCtrls, IWTypes, IWHTMLTag, IWTMSBase, IWImageList,
  IWColor, IWFont
  {$IFDEF TMSIW6}
  , IWRenderContext
  {$ENDIF}
  {$IFDEF TMSIW9}
  , IWXMLTag
  {$ENDIF}
  ;

type
  TIWGradientDirection = (gdHorizontal, gdVertical);

  TTIWExchangeBar = class;
  TExchangeBarPanel = class;
  TExchangeBarPanels = class;
  TExchangeBarItem = class;
  TExchangeBarItems = class;

  TTIWPicture = class(TPersistent)
  private
    FFileName: string;
    FImageIndex: integer;
  public
    constructor Create;
    procedure Assign(Source: TPersistent); override;
    function ImageRef(Control: TIWControl; Images: TIWImageList): string;
  published
     property FileName: string read FFileName write FFileName;
     property ImageIndex: integer read FImageIndex write FImageIndex default -1;
  end;

  TExchangeBarButton = class(TPersistent)
  private
    FActiveColor: TIWColor;
    FActiveColorTo: TIWColor;
    FActiveHoverColor: TIWColor;
    FActiveHoverColorTo: TIWColor;
    FBackColor: TIWColor;
    FBackColorTo: TIWColor;
    FCollapsedImage: TTIWPicture;
    FExpandedImage: TTIWPicture;
    FFont: TIWFont;
    FForeColor: TIWColor;
    FGradientDirection: TIWGradientDirection;
    FHeight: integer;
    FHoverColor: TIWColor;
    FHoverColorTo: TIWColor;
    FSelectColor: TIWColor;
    FSelectColorTo: TIWColor;
    procedure SetFont(const Value: TIWfont);
  public
    constructor Create;
    destructor Destroy; override;
  published
    property ActiveColor: TIWColor read FActiveColor write FActiveColor default clWebGOLD;
    property ActiveColorTo: TIWColor read FActiveColorTo write FActiveColorTo default clWebRED;
    property ActiveHoverColor: TIWColor read FActiveHoverColor write FActiveHoverColor default clWebSILVER;
    property ActiveHoverColorTo: TIWColor read FActiveHoverColorTo write FActiveHoverColorTo default clWebRED;
    property BackColor: TIWColor read FBackColor write FBackColor default clWebSKYBLUE;
    property BackColorTo: TIWColor read FBackColorTo write FBackColorTo default clWebSTEELBLUE;
    property Font: TIWFont read FFont write SetFont;
    property ForeColor: TIWColor read FForeColor write FForeColor default clBlack;
    property GradientDirection: TIWGradientDirection read FGradientDirection write FGradientDirection default gdVertical;
    property Height: integer read FHeight write FHeight default 30;
    property HoverColor: TIWColor read FHoverColor write FHoverColor default clWebOLDLACE;
    property HoverColorTo: TIWColor read FHoverColorTo write FHoverColorTo default clWebORANGE;
    property SelectColor: TIWColor read FSelectColor write FSelectColor default clWebLIGHTSKYBLUE;
    property SelectColorTo: TIWColor read FSelectColorTo write FSelectColorTo default clWebDODGERBLUE;
  end;

  TExchangeBarClientEvents = class(TPersistent)
  private
    FItemClick: TStringList;
    FItemCollapse: TStringList;
    FItemExpand: TStringList;
    FPanelChange: TStringList;
    FPanelClose: TStringList;
    FPanelMove: TStringList;
    FPanelOpen: TStringList;
    FSplitterMove: TStringList;
    FSplitterMoved: TStringList;

    procedure SetItemClick(const Value: TStringList);
    procedure SetItemCollapse(const Value: TStringList);
    procedure SetItemExpand(const Value: TStringList);
    procedure SetPanelChange(const Value: TStringList);
    procedure SetPanelClose(const Value: TStringList);
    procedure SetPanelMove(const Value: TStringList);
    procedure SetPanelOpen(const Value: TStringList);
    procedure SetSplitterMove(const Value: TStringList);
    procedure SetSplitterMoved(const Value: TStringList);
  public
    constructor Create;
    destructor Destroy; override;
    function GetJSFunction(PropName: string): string;    
  published
    property ItemClick: TStringList read FItemClick write SetItemClick;
    property ItemCollapse: TStringList read FItemCollapse write SetItemCollapse;
    property ItemExpand: TStringList read FItemExpand write SetItemExpand;
    property PanelChange: TStringList read FPanelChange write SetPanelChange;
    property PanelClose: TStringList read FPanelClose write SetPanelClose;
    property PanelMove: TStringList read FPanelMove write SetPanelMove;
    property PanelOpen: TStringList read FPanelOpen write SetPanelOpen;
    property SplitterMove: TStringList read FSplitterMove write SetSplitterMove;
    property SplitterMoved: TStringList read FSplitterMoved write SetSplitterMoved;
  end;

  TExchangeBarDivider = class(TPersistent)
  private
    FBackColor: TIWColor;
    FBackColorTo: TIWColor;
    FGradientDirection: TIWGradientDirection;
  public
    constructor Create;
  published
    property BackColor: TIWColor read FBackColor write FBackColor default clWebWHITESMOKE;
    property BackColorTo: TIWColor read FBackColorTo write FBackColorTo default clSilver;
    property GradientDirection: TIWGradientDirection read FGradientDirection write FGradientDirection default gdVertical;
  end;

  TExchangeBarSplitter = class(TPersistent)
  private
    FBackColor: TIWColor;
    FBackColorTo: TIWColor;
    FHeight: integer;
    FGlyph: TTIWPicture;
  public
    constructor Create;
    destructor Destroy; override;
  published
    property BackColor: TIWColor read FBackColor write FBackColor default clWebSKYBLUE;
    property BackColorTo: TIWColor read FBackColorTo write FBackColorTo default clWebSLATEGRAY;
    property Height: integer read FHeight write FHeight default 5;
    property Glyph: TTIWPicture read FGlyph write FGlyph;    
  end;

  TExchangeBarItemImageMargin = class(TPersistent)
  private
    Ftop: integer;
    FRight: integer;
    FBottom: integer;
    FLeft: integer;
  public
    constructor Create;
  published
    property Top: integer read FTop write FTop default 2;
    property Right: integer read FRight write FRight default 2;
    property Bottom: integer read FBottom write FBottom default 2;
    property Left: integer read FLeft write FLeft default 2;
  end;

  TExchangeBarItemImageSize = class(TPersistent)
  private
    FHeight: integer;
    FWidth: integer;
  public
    constructor Create;
  published
    property Height: integer read FHeight write FHeight default 16;
    property Width: integer read FWidth write FWidth default 16;
  end;


  TExchangeBarItemDisplay = class(TPersistent)
  private
    FCollapsedImage: TTIWPicture;
    FExpandedImage: TTIWPicture;
    FHoverBackColor: TIWColor;
    FHoverForeColor: TIWColor;
    FImageMargin: TExchangeBarItemImageMargin;
    FImageSize: TExchangeBarItemImageSize;
    FSelectBackColor: TIWColor;
    FSelectForeColor: TIWColor;
    FSpacing: integer;
  public
    constructor Create;
    destructor Destroy; override;
  published
    property CollapsedImage: TTIWPicture read FCollapsedImage write FCollapsedImage;
    property ExpandedImage: TTIWPicture read FExpandedImage write FExpandedImage;
    property HoverBackColor: TIWColor read FHoverBackColor write FHoverBackColor default clBlue;
    property HoverForeColor: TIWColor read FHoverForeColor write FHoverForeColor default clWhite;
    property ImageMargin: TExchangeBarItemImageMargin read FImageMargin write FImageMargin;
    property ImageSize: TExchangeBarItemImageSize read FImageSize write FImageSize;
    property SelectBackColor: TIWColor read FSelectBackColor write FSelectBackColor default clBlue;
    property SelectForeColor: TIWColor read FSelectForeColor write FSelectForeColor default clWhite;
    property Spacing: integer read FSpacing write FSpacing default 0;
  end;

  TExchangeBarItem = class(TCollectionItem)
  private
    FOwner: TExchangeBarItems;  
    FCaption: string;
    FGlyph: TTIWPicture;
    FHint: string;
    FIsDivider: boolean;
    FIsExpanded: boolean;
    FIsExpandedInt: boolean;
    FLevel: integer;
    FName: string;
    FLink: string;
    FScript: string;
    FTag: integer;
    FTarget: string;
    procedure SetIsExpanded(const Value: Boolean);
  public
    constructor Create(Collection: TCollection);  override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function GetOwner: TPersistent; override;
  protected
    property IsExpandedInt: boolean read FIsExpandedInt write FIsExpandedInt default false;
    function GetDisplayName: string; override;
  published
    property Caption: string read FCaption write FCaption;
    property Glyph: TTIWPicture read FGlyph write FGlyph;
    property Hint: string read FHint write FHint;
    property IsDivider: boolean read FIsDivider write FIsDivider default false;
    property IsExpanded: Boolean read FIsExpanded write SetIsExpanded default false;
    property Level: integer read FLevel write FLevel default 0;
    property Name: string read FName write FName;
    property Link: string read FLink write FLink;
    property Script: string read FScript write FScript;
    property Tag: integer read FTag write FTag default 0;
    property Target: string read FTarget write FTarget;
  end;

  TExchangeBarItems = class(TCollection)
  private
    FOwner: TExchangeBarPanel;
    function GetItems(Index: Integer): TExchangeBarItem;
    procedure SetItems(Index: Integer; const Value: TExchangeBarItem);
  protected
    procedure Update(Item: TCollectionItem); override;
  public
    constructor Create(AOwner: TExchangeBarPanel);
    function GetOwner: TPersistent; override;
    function Add: TExchangeBarItem;
    function Insert(Index: Integer):TExchangeBarItem;
    property Items[Index: Integer]: TExchangeBarItem read GetItems write SetItems; default;
  end;

  TExchangeBarPanel = class(TCollectionItem)
  private
    FOwner: TExchangeBarPanels;
    FBackColor: TIWColor;
    FCaption: string;
    {$IFDEF TMSIW7}
    FControl: TIWCustomControl;
    {$ENDIF}
    {$IFNDEF TMSIW7}
    FControl: TIWControl;
    {$ENDIF}
    FGlyph: TTIWPicture;
    FItems: TExchangeBarItems;
    FName: string;
    FScript: string;
    FTag: integer;
  protected
    function GetDisplayName: String; override;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    function GetOwner: TPersistent; override;
  published
    property BackColor: TIWColor read FBackColor write FBackColor default clNone;
    property Caption: string read FCaption write FCaption;
    {$IFDEF TMSIW7}
    property Control: TIWCustomControl read FControl write FControl;
    {$ENDIF}
    {$IFNDEF TMSIW7}
    property Control: TIWControl read FControl write FControl;
    {$ENDIF}
    property Glyph: TTIWPicture read FGlyph write FGlyph;
    property Items: TExchangeBarItems read FItems write FItems;
    property Name: string read FName write FName;
    property Script: string read FScript write FScript;
    property Tag: integer read FTag write FTag default 0;
  end;

  TExchangeBarPanels = class(TCollection)
  private
    FOwner: TTIWExchangeBar;
    function GetItem(Index: Integer): TExchangeBarPanel;
    procedure SetItem(Index: Integer; const Value: TExchangeBarPanel);
  protected
    procedure Update(Item: TCollectionItem); override;  
  public
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
    constructor Create(AOwner: TTIWExchangeBar);
    function Add: TExchangeBarPanel;
    function GetOwner: TPersistent; override;
    property Items[Index: Integer]: TExchangeBarPanel read GetItem write SetItem; default;
  end;

  TItemEvent = procedure(Sender: TComponent; PanelIndex, ItemIndex: Integer) of object;
  TPanelEvent = procedure(Sender: TComponent; PanelIndex: Integer) of object;

  {$IFDEF TMSIW9}
  TIWAsyncItemEvent = procedure (Sender: TObject; EventParams: TStringList; PanelIndex, ItemIndex: Integer) of object;
  TIWAsyncPanelEvent = procedure (Sender: TObject; EventParams: TStringList; PanelIndex: Integer) of object;
  {$ENDIF}

  TTIWExchangeBar = class(TIWControl)
  private
    FActivePanel: integer;
    FBackColor: TIWColor;
    FBackColorTo: TIWColor;
    FBackColorGradientDirection: TIWGradientDirection;
    FBackgroundImage: TTIWPicture;
    FBorderColor: TIWColor;
    FBorderWidth: integer;
    FForeColor: TIWColor;
    FVisiblePanels: integer;
    FSelectedItem: integer;
    FImages: TIWImageList;
    FButton: TExchangeBarButton;
    FItem: TExchangeBarItemDisplay;
    FPanels: TExchangeBarPanels;
    FClientEvents: TExchangeBarClientEvents;
    FDivider: TExchangeBarDivider;
    FSplitter: TExchangeBarSplitter;
    FOnItemClick: TItemEvent;
    FOnPanelChange: TPanelEvent;

    {$IFDEF TMSIW9}
    FOnAsyncItemClick: TIWAsyncItemEvent;
    FOnAsyncPanelChange: TIWAsyncPanelEvent;
    procedure DoAsyncPanelChange(AParams: TStringList);
    procedure DoAsyncItemClick(AParams: TStringList);
    {$ENDIF}

    procedure SetActivePanel(const Value: integer);
    procedure SetSelectedItem(const Value: integer);
    procedure SetVisiblePanels(const Value: integer);
  protected
    procedure SetValue(const AValue: string); override;
    procedure Submit(const AValue: string); override;
    {$IFDEF TMSIW6}
    function ImageHTML(const ASrc,BSrc,IMap: string; AContext: TIWBaseComponentContext): string;
    {$ELSE}
    function ImageHTML(const ASrc,BSrc,IMap: string): string;
    {$ENDIF}
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure DrawGradient(Canvas: TCanvas; FromColor, ToColor: TIWColor; Steps: Integer; r:TRect; Direction: Boolean);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Loaded; override;
    {$IFDEF TMSIW6}
    procedure IWPaint; override;
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    procedure Invalidate; override;
    {$ELSE}
    procedure Paint; override;
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    {$IFDEF TMSIW9}
    function RenderAsync(AContext: TIWBaseHTMLComponentContext): TIWXMLTag; override;
    {$ENDIF}
  published
    property ActivePanel: integer read FActivePanel write SetActivePanel default 0;
    property SelectedItem: integer read FSelectedItem write SetSelectedItem default 0; 
    property BackColor: TIWColor read FBackColor write FBackColor default clWebALICEBLUE;
    property BackColorTo: TIWColor read FBackColorTo write FBackColorTo default clWebALICEBLUE;
    property BackColorGradientDirection: TIWGradientDirection read FBackColorGradientDirection write FBackColorGradientDirection default gdVertical;
    property BackgroundImage: TTIWPicture read FBackgroundImage write FBackgroundImage;
    property BorderColor: TIWColor read FBorderColor write FBorderColor default clNone;
    property BorderWidth: integer read FBorderWidth write FBorderWidth default 0;
    property ForeColor: TIWColor read FForeColor write FForeColor default $C7581E;

    property Images: TIWImageList read FImages write FImages;
    property VisiblePanels: Integer read FVisiblePanels write SetVisiblePanels default 3;
    property Button: TExchangeBarButton read FButton write FButton;
    property Font;
    property Item: TExchangeBarItemDisplay read FItem write FItem;
    property Panels: TExchangeBarPanels read FPanels write FPanels;
    property ClientEvents: TExchangeBarClientEvents read FClientEvents write FClientEvents;
    property Divider: TExchangeBarDivider read FDivider write FDivider;
    property Splitter: TExchangeBarSplitter read FSplitter write FSplitter;

    property OnItemClick: TItemEvent read FOnItemClick write FOnItemClick;
    property OnPanelChange: TPanelEvent read FOnPanelChange write FOnPanelChange;
    {$IFDEF TMSIW9}
    property OnAsyncItemClick: TIWAsyncItemEvent read FOnAsyncItemClick write FOnAsyncItemClick;
    property OnAsyncPanelChange: TIWAsyncPanelEvent read FOnAsyncPanelChange write FOnAsyncPanelChange;
    {$ENDIF}

  end;


//============================================================ IMPLEMENTATION ==
implementation

uses
  IWLineLibrary, IWAppForm, IWForm, IWServerControllerBase, SWSystem, SWStrings,
  IWServer
  {$IFDEF TMSIW7}
  , IWBaseHTMLControl, IWVCLBaseControl, IWGlobal
  {$ENDIF}
  ;


{ TExchangeBarPanels }

//------------------------------------------------------------------------------
function TExchangeBarPanels.Add: TExchangeBarPanel;
begin
  Result := TExchangeBarPanel(inherited Add);
end;

//------------------------------------------------------------------------------
procedure TExchangeBarPanels.Assign(Source: TPersistent);
var
  i: Integer;
  S: TExchangeBarPanels;
begin
  inherited;
  S := TExchangeBarPanels(Source);
  Clear;
  for i := 0 to S.Count-1 do
    Add.Assign(S[i]);
end;

//------------------------------------------------------------------------------
constructor TExchangeBarPanels.Create(AOwner: TTIWExchangeBar);
begin
  inherited Create(TExchangeBarPanel);
  FOwner := AOwner;
end;

//------------------------------------------------------------------------------
destructor TExchangeBarPanels.Destroy;
begin
  inherited;
end;


//------------------------------------------------------------------------------
function TExchangeBarPanels.GetItem(Index: Integer): TExchangeBarPanel;
begin
  Result := TExchangeBarPanel(inherited GetItem(Index));
end;

//------------------------------------------------------------------------------
function TExchangeBarPanels.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

//------------------------------------------------------------------------------
procedure TExchangeBarPanels.SetItem(Index: Integer; const Value: TExchangeBarPanel);
begin
  inherited SetItem(Index, Value);
end;

{ TExchangeBarPanel }

//------------------------------------------------------------------------------
function TExchangeBarPanel.GetDisplayName: String;
begin
  if Caption <> '' then
    Result := Caption
  else
    Result := 'Panel' + IntToStr(Index);
end;

//------------------------------------------------------------------------------
procedure TExchangeBarPanel.Assign(Source: TPersistent);
begin
  if Source is TExchangeBarPanel then
  begin
    FBackColor := (Source as TExchangeBarPanel).BackColor;
    FCaption := (Source as TExchangeBarPanel).Caption;
    FControl := (Source as TExchangeBarPanel).Control;
    FGlyph.Assign((Source as TExchangeBarPanel).Glyph);
    FItems.Assign((Source as TExchangeBarPanel).Items);
    FName := (Source as TExchangeBarPanel).Name;
    FTag := (Source as TExchangeBarPanel).Tag;
  end;
end;

//------------------------------------------------------------------------------
constructor TExchangeBarPanel.Create(Collection: TCollection);
begin
  inherited;

  if Collection is TExchangeBarPanels then
  begin
    FOwner := Collection as TExchangeBarPanels;
  end;
  FItems := TExchangeBarItems.Create(Self);
  FCaption := 'Panel ' + IntToStr(Collection.Count - 1);
  FGlyph := TTIWPicture.Create;
  FBackColor := clNone;
  FControl := nil;
  FName := EmptyStr;
  FScript := EmptyStr;
  FTag := 0;

end;

//------------------------------------------------------------------------------
destructor TExchangeBarPanel.Destroy;
begin
  FItems.Free;
  FGlyph.Free;
  inherited;
end;


function TExchangeBarPanel.GetOwner: TPersistent;
begin
  Result := FOwner;
end;


{ TTIWExchangeBar }
{$IFDEF TMSIW9}
procedure TTIWExchangeBar.DoAsyncPanelChange(AParams: TStringList);
begin
  if Assigned(OnAsyncPanelChange) then
    OnAsyncPanelChange(Self, AParams, ActivePanel);
end;

procedure TTIWExchangeBar.DoAsyncItemClick(AParams: TStringList);
begin
  if Assigned(OnAsyncItemClick) then
    OnAsyncItemClick(Self, AParams, ActivePanel, FSelectedItem);
end;

function TTIWExchangeBar.RenderAsync(
  AContext: TIWBaseHTMLComponentContext): TIWXMLTag;
begin
  Result := TIWXMLTag.CreateTag('control');
  try
    Result.AddStringParam('id', HTMLName);
    Result.AddStringParam('type', 'TTIWEXCHANGEBAR');
    RenderAsyncCommonProperties( AContext, Result );
  except
    FreeAndNil(Result);
  end;
end;
{$ENDIF}

constructor TTIWExchangeBar.Create(AOwner: TComponent);
var
  p,i: integer;
begin
  inherited;
  {$IFDEF TMSIW6}
  {TODO}
  {$ELSE}
  FSupportsSubmit := True;
  FSupportsInput := True;
  FSupportedScriptEvents := 'OnAbort,OnError,OnKeyDown,OnKeyPress,OnKeyUp,OnLoad';
  {$ENDIF}
  FPanels := TExchangeBarPanels.Create(Self);
  FButton := TExchangeBarButton.Create;
  FItem := TExchangeBarItemDisplay.Create;
  FClientEvents := TExchangeBarClientEvents.Create;
  FDivider := TExchangeBarDivider.Create;
  FSplitter := TExchangeBarSplitter.Create;  
  FBackgroundImage := TTIWPicture.Create;

  FActivePanel := 0;
  FBackColor := clWebALICEBLUE;
  FBackColorTo := clWebALICEBLUE;
  FBackColorGradientDirection := gdVertical;
  FBorderColor := clNone;
  FBorderWidth := 0;
  FForeColor := $C7581E;
  FVisiblePanels := 3;
  FSelectedItem := 0;

  Width := 220;
  Height := 360;

   if not (csDesigning in Componentstate) then
  begin
    {$IFDEF TMSIW51}
    TIWServer.AddInternalFile('IW_JS_TMSIWEXCHANGEBAR','/js/TMSIWEXCHANGEBAR.js');
    {$ELSE}
    GIWServer.AddInternalFile('IW_JS_TMSIWEXCHANGEBAR');
    {$ENDIF}
  end;

  if (csDesigning in ComponentState) and not (csLoading in ComponentState) then
  begin
    for p:=0 to 2 do
    begin
      with Panels.Add do
      begin
        Caption := 'Panel ' + IntToStr(p);
        for i:=0 to 2 do
        begin
          with Items.Add do
          begin
            Caption := 'item ' + IntToStr(i);
          end;
        end;
      end;
    end;
  end;


  {$IFDEF TMSIW7}
  SupportsPartial := true;
  {$ENDIF}
  
end;

destructor TTIWExchangeBar.Destroy;
begin
  FPanels.Free;
  FButton.Free;
  FItem.Free;
  FClientEvents.Free;
  FDivider.Free;
  FSplitter.Free;  
  FBackgroundImage.Free;
  inherited;
end;

{$IFDEF TMSIW6}
procedure TTIWExchangeBar.Invalidate;
begin
  inherited;
end;
{$ENDIF}

procedure TTIWExchangeBar.DrawGradient(Canvas: TCanvas; FromColor, ToColor: TIWColor; Steps: Integer; r:TRect; Direction: Boolean);
var
  diffr,startr,endr: Integer;
  diffg,startg,endg: Integer;
  diffb,startb,endb: Integer;
  iend: Integer;
  rstepr,rstepg,rstepb,rstepw: Real;
  i,stepw: Word;

begin
  if Steps = 0 then
    Steps := 1;

  FromColor := ColorToRGB(FromColor);
  ToColor := ColorToRGB(ToColor);

  startr := (FromColor and $0000FF);
  startg := (FromColor and $00FF00) shr 8;
  startb := (FromColor and $FF0000) shr 16;
  endr := (ToColor and $0000FF);
  endg := (ToColor and $00FF00) shr 8;
  endb := (ToColor and $FF0000) shr 16;

  diffr := endr - startr;
  diffg := endg - startg;
  diffb := endb - startb;

  rstepr := diffr / steps;
  rstepg := diffg / steps;
  rstepb := diffb / steps;

  if Direction then
    rstepw := (R.Right - R.Left) / Steps
  else
    rstepw := (R.Bottom - R.Top) / Steps;

  with Canvas do
  begin
    for i := 0 to Steps - 1 do
    begin
      endr := startr + Round(rstepr*i);
      endg := startg + Round(rstepg*i);
      endb := startb + Round(rstepb*i);
      stepw := Round(i*rstepw);
      Pen.Color := endr + (endg shl 8) + (endb shl 16);
      Brush.Color := Pen.Color;
      if Direction then
      begin
        iend := R.Left + stepw + Trunc(rstepw) + 1;
        if iend > R.Right then
          iend := R.Right;
        Rectangle(R.Left + stepw,R.Top,iend,R.Bottom)
      end
      else
      begin
        iend := R.Top + stepw + Trunc(rstepw)+1;
        if iend > r.Bottom then
          iend := r.Bottom;
        Rectangle(R.Left, R.Top+stepw,R.Right,iend);
      end;
    end;
  end;
end;

{$IFDEF TMSIW6}
procedure TTIWExchangeBar.IWPaint;
{$ELSE}
procedure TTIWExchangeBar.Paint;
{$ENDIF}
var
  th,i,j, offsy: Integer;
  r: TRect;

begin
  if Panels.Count = 0 then
  begin
    Canvas.TextOut(0,0,'TTIWExchangeBar');  
    Exit;
  end;  
    
  th := Canvas.TextHeight('gh') + 12;

  r := ClientRect;
  r.Bottom := th;
  DrawGradient(Canvas, Button.SelectColor, Button.SelectColorTo, 64, r, false);
  Canvas.Brush.Style := bsClear;  
  Canvas.TextOut(r.Left + 4, r.Top + 4, Panels[ActivePanel].Caption );

  j := 0;
  for i := Panels.Count downto 1 do
  begin
    if (i - 1) <> ActivePanel then
    begin
      r.Bottom := ClientRect.Bottom - j * th;
      r.Top := r.Bottom - th;
      DrawGradient(Canvas, Button.BackColor, Button.BackColorTo, 64, r, false);
      Canvas.Brush.Style := bsClear;
      Canvas.TextOut(r.Left + 4, r.Top + 4, Panels[i - 1].Caption);
      inc(j);
    end;
  end;

  r.Top := th;
  r.Bottom := ClientRect.Bottom - ((Panels.Count - 1) *  th);
  DrawGradient(Canvas, BackColor, BackColorTo, 64, r, BackColorGradientDirection <> gdVertical);

  offsy := th + 4;
  for i := 1 to Panels[ActivePanel].Items.Count do
  begin
    if (offsy < r.Bottom - th) then
    begin
      Canvas.Brush.Style := bsClear;
      Canvas.TextOut(r.Left + 4, offsy + 4, Panels[ActivePanel].Items[i - 1].Caption);
    end;
    offsy := offsy + th;  
  end;

end;

procedure TTIWExchangeBar.Notification(AComponent: TComponent; Operation: TOperation);
var
  i: integer;
begin
  if (csDestroying in ComponentState) then
    Exit;
    
  if (Operation = opRemove) then
  begin
    for i := 1 to Panels.Count do
    begin
      if Panels[i - 1].Control = AComponent then
        Panels[i - 1].Control := nil;
    end;

    if FImages = AComponent then
      FImages := nil;
  end;
end;

{$IFDEF TMSIW6}
function TTIWExchangeBar.ImageHTML(const ASrc,BSrc,IMap: string; AContext: TIWBaseComponentContext): string;
{$ELSE}
function TTIWExchangeBar.ImageHTML(const ASrc,BSrc,IMap: string): string;
{$ENDIF}
begin
end;

procedure TTIWExchangeBar.Loaded;
var
  i, j: integer;
begin
  inherited;

  for I := 0 to panels.Count - 1 do
  begin
    for j := 0 to Panels[I].Items.Count - 1 do
    begin
      Panels[I].Items[j].IsExpanded := Panels[I].Items[j].IsExpanded;
    end;
  end;
end;

{$IFDEF TMSIW6}
function TTIWExchangeBar.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWExchangeBar.RenderHTML: TIWHTMLTag;
{$ENDIF}
var
  htmlres, s, GradDir, PanelImage, ListImage, img: string;
  itemIm, RenderImgTag, isDiv, setNode, nodeClosed, itemCaption: string;
  i,j,k,n,h,w,bw,HeightTable: integer;
  found: boolean;
  isPartial: boolean;
  ajaxcall, submitclick: string;
begin

  {$IFDEF TMSIW6}
  with AContext.PageContext as TIWPageContext40 do
    isPartial := WebApplication.IsPartialUpdate;
  {$ELSE}
  isPartial := false;
  {$ENDIF}

  {$IFDEF TMSIW6}
  if not isPartial then
    TIWComponent40Context(AContext).AddScriptFile('/js/TMSIWEXCHANGEBAR.js');
  {$ENDIF}
  {$IFNDEF TMSIW6}
  AddScriptFile('/js/TMSIWEXCHANGEBAR.js');
  {$ENDIF}


  h := Height + 1;
  w := Width;
  bw := BorderWidth;
  HeightTable := h - (Panels.Count * Button.Height);

  if not isPartial then
  begin

    s := s
      + '<script>'#13
      + 'function '+HTMLName+'Obj(){'#13
      + ' this.UniqueID = "' + HTMLName + '";'#13
      + ' this.Generator = "DELPHI";'#13
      + ' this.Height = ' + IntToStr(h) +';'#13
      + ' this.HeightContent = ' + IntToStr(HeightTable) +';'#13
      //+ ' this.Width = "100%";'#13
      + ' this.Width = ' + IntToStr(w) + ';'#13
      + ' this.AbsWidth = ' + IntToStr(w) + ';'#13
      + ' this.ActivePanel = ' + IntToStr(ActivePanel) + ';'#13
      + ' this.ActiveItem = "0";'#13
      + ' this.SplitterImage = "' + Splitter.Glyph.ImageRef(Self,Images) + '";'#13
      + ' this.SplitterHeight = ' + IntToStr(Splitter.Height) + ';'#13
      + ' this.SplitterColor = "' + ColorToRGBString(Splitter.BackColor) + '";'#13
      + ' this.ItemCollapsedImage = "'+ Item.CollapsedImage.ImageRef(Self,Images)+'";'#13
      + ' this.ItemExpandedImage = "'+ Item.ExpandedImage.ImageRef(Self,Images)+'";'#13
      + ' this.PanelCount = ' + IntToStr(Panels.Count) + ';'#13
      + ' this.VisiblePanels = ' + IntToStr(VisiblePanels) + ';'#13
      + '';

   if not (Splitter.BackColorTo = clNone) then
      s := s  + ' this.SplitterColorTo = "filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=' + ColorToRGBString(Splitter.BackColor) + ',EndColorStr=' + ColorToRGBString(Splitter.BackColorTo) + ')";'#13
    else
      s := s  + ' this.SplitterColorTo = "";'#13;

    if (BackColor = clNone) then
      s := s  + ' this.BackgroundColor = "' + ColorToRGBString(clWhite) + '";'#13
    else
      s := s  + ' this.BackgroundColor = "' + ColorToRGBString(BackColor) + '";'#13;

    if (BackColorTo = clNone) then
    begin
      s := s  + ' this.PanelColor = "background:' + ColorToRGBString(BackColor) + '";'#13;
    end
    else
    begin
      GradDir := '0';
      if (BackColorGradientDirection = gdHorizontal) then
        GradDir := '1';

      s := s  + ' this.PanelColor = "background:' + ColorToRGBString(BackColor) + ';filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(BackColor) + ',EndColorStr=' + ColorToRGBString(BackColorTo) + ')";'#13;
    end;

    if not (BackgroundImage.FileName = EmptyStr) then
      s := s
        + ' this.BackgroundImage = ";background-Image:url('+StringReplace(BackgroundImage.FileName,'\','/',[rfReplaceAll])+')";'#13
    else
      s := s
        + ' this.BackgroundImage = "";'#13;

    s := s
      + ' this.BorderSize = ' + IntToStr(bw) + ';'#13
      + ' this.ButtonHeight = ' + IntToStr(Button.Height) + ';'#13
      + ' this.BorderColor = "' + ColorToRGBString(BorderColor) + '";'#13;

    // Divider Color
    if (Divider.BackColorTo = clNone) then
    begin
      s := s
        + ' this.DividerColor = "background:'+ ColorToRGBString(Divider.BackColor) + '";'#13;
    end
    else
    begin
      GradDir := '0';
      if (Divider.GradientDirection = gdHorizontal) then
        GradDir := '1';

      s := s
        + ' this.DividerColor = "background:'+ ColorToRGBString(Divider.BackColor) + ';filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(Divider.BackColor) + ',EndColorStr=' + ColorToRGBString(Divider.BackColorTo) + ')";'#13;
    end;
    //end  Divider Color

    // Panel Button colors
    if (Button.SelectColorTo = clNone) then
    begin
      s := s
        + ' this.ButtonSelectColor = "background:'+ ColorToRGBString(Button.SelectColor) + '";'#13;
    end
    else
    begin
      GradDir := '0';
      if (Button.GradientDirection = gdHorizontal) then
        GradDir := '1';

      s := s
        + ' this.ButtonSelectColor = "background:'+ ColorToRGBString(Button.SelectColor) + ';filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(Button.SelectColor) + ',EndColorStr=' + ColorToRGBString(Button.SelectColorTo) + ')";'#13;

    end;

    if (Button.BackColorTo = clNone) then
    begin
      s := s
        + ' this.ButtonColor = "background:'+ ColorToRGBString(Button.BackColor) + '";'#13;
      s := s
        + ' this.ButtonColor2 = "' + ColorToRGBString(Button.BackColor) + '";'#13;
      s := s
        + ' this.ButtonColorTo = "";'#13;
    end
    else
    begin
      GradDir := '0';
      if (Button.GradientDirection = gdHorizontal) then
        GradDir := '1';

      s := s
        + ' this.ButtonColor = "background:'+ ColorToRGBString(Button.BackColor) + ';filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(Button.BackColor) + ',EndColorStr=' + ColorToRGBString(Button.BackColorTo) + ')";'#13;
      s := s
        + ' this.ButtonColor2 = "' + ColorToRGBString(Button.BackColor) + '";'#13;
      s := s
        + ' this.ButtonColorTo = "filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(Button.BackColor) + ',EndColorStr=' + ColorToRGBString(Button.BackColorTo) + ')";'#13;

    end;

    if (Button.HoverColorTo = clNone) then
    begin
      s := s
        + ' this.ButtonHoverColor = "' + ColorToRGBString(Button.HoverColor) + '";'#13;
      s := s
        + ' this.ButtonHoverColorTo = "";'#13;
    end
    else
    begin
      GradDir := '0';
      if (Button.GradientDirection = gdHorizontal) then
        GradDir := '1';

      s := s
        + ' this.ButtonHoverColor = "' + ColorToRGBString(Button.HoverColor) + '";'#13;
      s := s
        + ' this.ButtonHoverColorTo = "progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(Button.HoverColor) + ',EndColorStr=' + ColorToRGBString(Button.HoverColorTo) + ')";'#13;
    end;

    if (Button.ActiveColorTo = clNone) then
    begin
      s := s
        + ' this.ButtonActiveColor = "background:'+ ColorToRGBString(Button.ActiveColor) + '";'#13;
      s := s
        + ' this.ButtonActiveColor2 = "' + ColorToRGBString(Button.ActiveColor) + '";'#13;
      s := s
        + ' this.ButtonActiveColorTo = "";'#13;
    end
    else
    begin
      GradDir := '0';
      if (Button.GradientDirection = gdHorizontal) then
        GradDir := '1';

      s := s
        + ' this.ButtonActiveColor = "background:'+ ColorToRGBString(Button.ActiveColor) + ';filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(Button.ActiveColor) + ',EndColorStr=' + ColorToRGBString(Button.ActiveColorTo) + ')";'#13;
      s := s
        + ' this.ButtonActiveColor2 = "' + ColorToRGBString(Button.ActiveColor) + '";'#13;
      s := s
        + ' this.ButtonActiveColorTo = "filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(Button.ActiveColor) + ',EndColorStr=' + ColorToRGBString(Button.ActiveColorTo) + ')";'#13;
    end;

    if (Button.ActiveHoverColorTo = clNone) then
    begin
      s := s
        + ' this.ButtonActiveHoverColor = "background:'+ ColorToRGBString(Button.ActiveHoverColor) + '";'#13;
      s := s
        + ' this.ButtonActiveHoverColor2 = "' + ColorToRGBString(Button.ActiveHoverColor) + '";'#13;
      s := s
        + ' this.ButtonActiveHoverColorTo = "";'#13;
    end
    else
    begin
      GradDir := '0';
      if (Button.GradientDirection = gdHorizontal) then
        GradDir := '1';

      s := s
        + ' this.ButtonActiveHoverColor = "background:'+ ColorToRGBString(Button.ActiveHoverColor) + ';filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(Button.ActiveHoverColor) + ',EndColorStr=' + ColorToRGBString(Button.ActiveHoverColorTo) + ')";'#13;
      s := s
        + ' this.ButtonActiveHoverColor2 = "' + ColorToRGBString(Button.ActiveHoverColor) + '";'#13;
      s := s
        + ' this.ButtonActiveHoverColorTo = "filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' + GradDir + ',StartColorStr=' + ColorToRGBString(Button.ActiveHoverColor) + ',EndColorStr=' + ColorToRGBString(Button.ActiveHoverColorTo) + ')";'#13;
    end;
    //end  Panel Button Colors

    // panel button font family
    if not (Button.Font.FontName = EmptyStr) then
      s := s  + ' this.ButtonFontFamily = "'+Button.Font.FontName+'";'#13
    else
      s := s  + ' this.ButtonFontFamily = "'+Font.FontName+'";'#13;

    if not (Button.Font.Size = 0) then
      s := s  + ' this.ButtonFontSize = "' + IntToStr(Button.Font.Size) +'";'#13
    else
      s := s  + ' this.ButtonFontSize = 12;'#13;

    s := s + ' this.ButtonFontColor = "' + ColorToRGBString(Button.ForeColor)+ '";'#13;

     if (fsBold in Button.Font.Style) then
      s := s  + ' this.ButtonFontBold = true;'#13
    else
      s := s  + ' this.ButtonFontBold = false;'#13;

    if (fsItalic in Button.Font.Style) then
      s := s  + ' this.ButtonFontItalic = true;'#13
    else
      s := s  + ' this.ButtonFontItalic = false;'#13;

    if (fsUnderline in Button.Font.Style) then
      s := s  + ' this.ButtonFontUnderline = true;'#13
    else
      s := s  + ' this.ButtonFontUnderline = false;'#13;

    s := s  + ' this.ButtonCSSStyle= "";'#13
      + ' this.tabScrollSpeed = 4;'#13;

    s := s  + ' this.LabelFontFamily = "'+Font.FontName+'";'#13;

    if not (Font.Size = 0) then
      s := s  + ' this.LabelFontSize = ' + IntToStr(Font.Size) + ';'#13
    else
      s := s  + ' this.LabelFontSize = 12;'#13;

    s := s  + ' this.LabelFontColor = "' + ColorToRGBString(ForeColor)+'";'#13;

     if (fsBold in Font.Style) then
      s := s  + ' this.LabelFontBold = true;'#13
    else
      s := s  + ' this.LabelFontBold = false;'#13;

    if (fsItalic in Font.Style) then
      s := s  + ' this.LabelFontItalic = true;'#13
    else
      s := s  + ' this.LabelFontItalic = false;'#13;

    if (fsUnderline in Font.Style) then
      s := s  + ' this.LabelFontUnderline = true;'#13
    else
      s := s  + ' this.LabelFontUnderline = false;'#13;

    //end   panel button font family

    // Item Properties
    s := s  + ' this.LabelCSSStyle = "";'#13
      + ' this.ColorOver = "' + ColorToRGBString(Item.HoverForeColor) + '";'#13
      + ' this.BackColorOver = "' + ColorToRGBString(Item.HoverBackColor) + '";'#13
      + ' this.ColorSel = "' + ColorToRGBString(Item.SelectForeColor) + '";'#13
      + ' this.BackColorSel = "' + ColorToRGBString(Item.SelectBackColor) + '";'#13
      + ' this.ItemPicHeight = ' + IntToStr(Item.ImageSize.Height) + ';'#13
      + ' this.ItemPicWidth = ' + IntToStr(Item.ImageSize.Width) + ';'#13
      + ' this.ItemPicMarginLeft = ' + IntToStr(Item.ImageMargin.Left) + ';'#13
      + ' this.ItemPicMarginRight = ' + IntToStr(Item.ImageMargin.Right) + ';'#13
      + ' this.ItemPicMarginTop = ' + IntToStr(Item.ImageMargin.Top) + ';'#13
      + ' this.ItemPicMarginBottom = ' + IntToStr(Item.ImageMargin.Bottom) + ';'#13
      + 'this.itemSpacing = ' + IntToStr(Item.Spacing) + ';'#13
      + ' this.itemScrollSpeed = 4;'#13;
    //end  Item Properties

    // setting some variables
    s := s                                                   
      + ' this.mx = 0;'#13
      + ' this.toty = 0;'#13
      + ' this.toWrite = "";'#13
      + ' this.tabs = new Array();'#13
      + ' this.containers = new Array();'#13
      + ' this.position = new Array();'#13
      + ' this.tabscount = 0;'#13
      + ' this.isInScroll = 0;'#13
      + ' this.xPosition = 0;'#13
      + ' this.yPosition = 0;'#13
      + ' this.theBiggest = 0;'#13
      + ' this.functions = new Array();'#13
      + ' this.visibleHeight = 0;'#13
      + ' this.listHeight = 0;'#13
      + ' this.MenuCont = "";'#13
      + ' this.Left = 0;'#13
      + ' this.Top = 0;'#13
      + ' this.AbsLeft = 0;'#13
      + ' this.AbsTop = 0;'#13;

    s := s  + ' this.PanelHeight = "0";'#13;

    // ClientEvents
    s := s
    + ' '+HTMLName+'Obj.prototype.ItemClick = function(obj,pnlIndex,itmIndex) {'#13 + ClientEvents.ItemClick.Text + #13'}'#13
    + ' '+HTMLName+'Obj.prototype.NodeOpen = function (obj,pnlIndex,itmIndex) {'#13 + ClientEvents.ItemExpand.Text + #13'}'#13
    + ' '+HTMLName+'Obj.prototype.NodeClose = function(obj,pnlIndex,itmIndex) {'#13 + ClientEvents.ItemCollapse.Text + #13'}'#13
    + ' '+HTMLName+'Obj.prototype.PanelChange = function(obj,pnlFrom,pnlTo) {'#13 + ClientEvents.PanelChange.Text + #13'}'#13
    + ' '+HTMLName+'Obj.prototype.SplitterMoved = function(obj,pnlsVisible) {'#13 + ClientEvents.SplitterMoved.Text + #13'}'#13
    + ' '+HTMLName+'Obj.prototype.SplitterMove = function(obj,pnlIndex,pnlHeight) {'#13
    + '  '+HTMLName+'SplitterMove(obj,pnlIndex,pnlHeight);'#13
    + ' }'#13
    + ' '+HTMLName+'Obj.prototype.PanelClose = function(obj,pnlIndex) {'#13
    + '  '+HTMLName+'PanelClose(obj,pnlIndex);'#13
    + ' }'#13
    + ' '+HTMLName+'Obj.prototype.PanelOpen = function(obj,pnlIndex,pnlTop,pnlLeft,pnlWidth,pnlHeight) {'#13
    + '  '+HTMLName+'PanelOpen(obj,pnlIndex,pnlTop,pnlLeft,pnlWidth,pnlHeight);'#13
    + ' }'#13
    + '';
    // end ClientEvents


    htmlres := htmlres + s;
    s := EmptyStr;

    htmlres := htmlres
    + '}'#13
    + HTMLName + 'Obj = new '+HTMLName+'Obj();'#13
    + 'document.ExchangeBarObj = '+HTMLName+'Obj;'#13
    + 'document.exchangebarObj = '+HTMLName+'Obj;'#13;

    htmlres := htmlres + '</script>'#13;
    //end javascript object
  end;


    for k := 1 to Panels.Count do
      s := s + '<input type="hidden" value="" name="'+ HTMLName + 'HT_' + IntToStr(k - 1) + '" id="'+ HTMLName + 'HT_' + IntToStr(k - 1) + '">';

    s := s + '<input type="hidden" value="'+ IntToStr(ActivePanel) +'" name="'+ HTMLName + 'AP' + '" id="'+ HTMLName + 'AP">';
    s := s + '<input type="hidden" value="'+ IntToStr(VisiblePanels) +'" name="'+HTMLName+'VP" id="'+ HTMLName + 'VP">';
    s := s + '<input type="hidden" value="'+ IntToStr(FSelectedItem) +'" name="'+HTMLName+'SI" id="'+ HTMLName + 'SI">';


  if not isPartial then
  begin
    s := s + '<script>';

    // Render Exchangebar
    s := s + 'exchangebar_start('+HTMLName+'Obj);'#13;
    j := 0;                                                         
                                                                  
                                                           
    // Render Panels                                         
    for k := 1 to Panels.Count do
    begin

      if (Assigned (OnPanelChange)) then
        submitclick := 'return SubmitClick('#39 + HTMLName + #39','#39'PANELCHANGE#' + IntToStr(j)+ '#0'#39',false);'#13
      else
        submitclick := '';

      {$IFDEF TMSIW9}
      if Assigned(FOnAsyncPanelChange) then
      begin
        ajaxcall := 'processAjaxEvent(''onPanelChange'', '
          + HTMLControlImplementation.IWCLName
          + ',''' + HTMLName + '.' + 'DoAsyncPanelChange' + ''','
          + 'true' + ', null, '
          + 'true' + ');';

          Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoAsyncPanelChange', DoAsyncPanelChange);

          submitclick := '';
      end;
      {$ENDIF}

      s := s + 'function activepanel_' + HTMLName + '_' + IntToStr(j) + '(){'#13
      + ajaxcall
      + submitclick;

      img := Panels[k - 1].Glyph.ImageRef(Self,Images);

      if not (img = '') then
      begin
        PanelImage := '<img border="0" src="'+img+'" align="middle">&nbsp;';
        ListImage := '<img border="0" title="'+ StringReplace(Panels[k - 1].Caption,'"','&quot;',[rfReplaceAll]) +'" width=16 height=16 src="'+img+'" align="middle">';
      end
      else
      begin
        PanelImage := '';
        ListImage := '';
      end;

      i := 0;

      s := s
        + 'p = ' + IntToStr(j) + ';'#13
        + Panels[k - 1].Script + '}'#13
        + 'exchangebar_tabstart('+HTMLName+'Obj,''' + PanelImage + ''',''' + ListImage + ''',"' + StringReplace(Panels[k - 1].Caption,'"','&quot;',[rfReplaceAll]) + '","JSCRIPT:activepanel_' + HTMLName + '_' + IntToStr(j) + '()");'#13;

     // render Items
      for n:=1 to Panels[j].Items.Count do
      begin
        //if not (Panels[j].Items[n - 1].Caption = '') then
        //begin

          if Assigned(OnItemClick) then
            submitclick := 'return SubmitClick('#39 + HTMLName + #39','#39'ITEMCLICK#' + IntToStr(j)+ '#' + IntToStr(n - 1) + #39',false);'#13
          else
            submitclick := '';

          {$IFDEF TMSIW9}
          if Assigned(OnAsyncItemClick) then
          begin
            ajaxcall := 'processAjaxEvent(''onItemClick'', '
              + HTMLControlImplementation.IWCLName
              + ',''' + HTMLName + '.' + 'DoAsyncItemClick' + ''','
              + 'true' + ', null, '
              + 'true' + ');';

              Acontext.WebApplication.RegisterCallBack(HTMLName+'.DoAsyncItemClick', DoAsyncItemClick);

              submitclick := '';
          end;
          {$ENDIF}

          s := s + 'function itemclick_' + HTMLName + '_' + IntToStr(j) + '_' + IntToStr(i) + '(){'#13
            + 'p = ' + IntToStr(j) +';'#13
            + 'i = ' + IntToStr(i) +';'#13
            + Panels[j].Items[n - 1].Script
            + ajaxcall
            + submitclick
            + '}'#13;
        //end;

        itemIm := Panels[j].Items[i].Glyph.ImageRef(Self,Images);

        RenderImgTag := '';

        if not (itemIm = '') then
        begin
          RenderImgTag := '1';
        end
        else
        begin
          itemIm := ' ';
          RenderImgTag := '0';
        end;

        setnode := 'false';
        nodeclosed := 'true';
  //            nextlevel := 0;

        if (n-1 < Panels[j].Items.Count - 1) then
        begin
  //              nextlevel := Panels[j].Items[i].Level;

          if (Panels[j].Items[n].Level > Panels[j].Items[n - 1].Level) then
          begin
            setnode := 'True';
            if (Panels[j].Items[n].IsExpandedInt) then
              nodeclosed := 'false';
          end
        end;

        //changed: also level 0 items can bet set IsExpanded = False
        //if (Panels[j].Items[n - 1].Level = 0) then
        //  s := s + 'document.getElementById("' + HTMLName + 'HT_'+ IntToStr(j)+ '").value += "1,";'#13
        //else
        //begin
          if not (Panels[j].Items[n - 1].IsExpandedInt) then
            s := s + 'document.getElementById("' + HTMLName + 'HT_'+ IntToStr(j)+ '").value += "0,";'#13
          else
            s := s + 'document.getElementById("' + HTMLName + 'HT_'+ IntToStr(j)+ '").value += "1,";'#13;
        //end;

        isDiv := 'false';
        if (Panels[j].Items[n - 1].IsDivider) then
          isDiv := 'true';

        itemCaption := Panels[j].Items[i].Caption;
        if itemCaption = EmptyStr then
          itemCaption := '&nbsp;';

        s := s + 'exchangebar_tabadditem('+HTMLName+'Obj,"' + RenderImgTag + '","' + StringReplace(itemCaption,'"','&quot;',[rfReplaceAll]) + '","' + Panels[j].Items[i].Link + '","' + Panels[j].Items[i].Target + '","' + IntToStr(Panels[j].Items[i].Level) + '","' + isdiv + '","' + LowerCase(nodeclosed) +'","' + setnode + '","'+ IntToStr(j) +'","'+ IntToStr(i) +'","'+ IntToStr(Panels[j].Items.Count) +'","' + itemIm + '","' + Panels[j].Items[i].Hint + '","JScript:itemclick_';
        s := s + HTMLName + '_' + IntToStr(j) + '_' + IntToStr(i) + '()");'#13;

        i := i + 1;
      end;

      //end render Items

      s := s + 'exchangebar_tabend('+HTMLName+'Obj);'#13;

      j := j + 1;                                        

    end;

    s := s + 'exchangebar_end('+HTMLName+'Obj);'#13;

    // Splitter Move
    s := s + 'var panelH=0;'#13;

    s := s + 'function '+HTMLName+'SplitterMove(obj,pnlIndex,pnlHeight) {'#13;
    s := s + 'panelH = pnlHeight;'#13;

    found := false;                             
                                                    
    for i:=1 to Panels.Count do                        
    begin
      if Assigned(Panels[i - 1].Control) then
      begin
        found := true;                                                      
        break;
      end;
    end;                                               

    if (found) then
    begin
      s := s + '  switch(pnlIndex) {'#13;

      for i:=1 to Panels.Count do
      begin
        if Assigned(Panels[i - 1].Control) then
        begin
          s := s + '  case ' + IntToStr(i - 1) + ' :'#13;
          s := s + '    addCC = document.getElementById("' + Panels[i - 1].Control.HTMLName + '");'#13;
          s := s + '    if (addCC !== null) {'#13;
          s := s + '      addCC.style.visibility = "visible";'#13;
          s := s + '      addCC.style.display = "";'#13;
          s := s + '      addCC.style.height = pnlHeight;'#13;
          s := s + '    }'#13;
          s := s + '    break;'#13;
        end;
      end;

      s := s + '  default:'#13;
      s := s + '    break;'#13;
      s := s + '  }'#13;
    end;
    s := s + ClientEvents.SplitterMove.Text + #13;
    s := s + '}'#13;
    //end Splitter Move
                                                                                   
    //region Panel Close
    s := s + 'function '+HTMLName+'PanelClose(obj,pnlIndex) {'#13;

    s := s + '  switch(pnlIndex) {'#13;

    for i:=1 to Panels.Count do
    begin                                               
      if Assigned(Panels[i - 1].Control) then
      begin
        s := s + '  case ' + IntToStr(i - 1) + ' :'#13;
        s := s + '    ExchangeBar_Hide("' + Panels[i - 1].Control.HTMLName + '",' + Panels[i - 1].FControl.HTMLName + 'IWCL);'#13;
        s := s + '    break;'#13;                       
      end;
    end;                                             

    s := s + '  default:'#13;                  
    s := s + '    break;'#13;                                    
    s := s + '  }'#13;

    s := s + ClientEvents.PanelClose.Text + #13;

    s := s + '}'#13;
    //endregion Panel Close

    //region Panel Open
    s := s + 'function '+HTMLName+'PanelOpen(obj,pnlIndex,pnlTop,pnlLeft,pnlWidth,pnlHeight){'#13;

    found := false;

    for i:=1 to Panels.Count do
    begin
      if Assigned(Panels[i - 1].Control) then
      begin
        found := true;
        break;
      end;
    end;                                          

    if (found) then                                           
    begin
      s := s + '  switch(pnlIndex) {'#13;          

      for i:=1 to Panels.Count do
      begin
        if Assigned(Panels[i - 1].Control) then
        begin
          s := s + '  case ' + IntToStr(i - 1) + ' :'#13;
          s := s  + '    ExchangeBar_Show("' + Panels[i - 1].FControl.HTMLName + '",true,pnlTop,pnlLeft,pnlHeight,pnlWidth,' + Panels[i - 1].FControl.HTMLName + 'IWCL);'#13;
          s := s + '    break;'#13;
        end;
      end;

      s := s                                               
        + 'default:'#13
        + '   break;'#13
        + '}'#13;
    end;

    s := s + ClientEvents.PanelOpen.Text + #13;
    s := s + '}'#13;
    //endregion Panel Open

    htmlres := htmlres + s + '</script>';
  end;
  
  PanelImage := '';
  ListImage := '';

  Result := TIWHTMLTag.CreateTag('DIV');
  Result.Contents.AddText(htmlres);

  if not isPartial then
  begin
    s := EmptyStr;
    s := s + 'document.ExchangeBarObj.ActivePanel = ' + IntToStr(ActivePanel) + ';'#13;
    s := s + 'document.ExchangeBarObj.UniqueID = "' + HtmlName + '";'#13;
    s := s + 'exchangebar_init('+HTMLName+'Obj);'#13;

    {$IFDEF TMSIW6}
     with AContext.PageContext as TIWPageContext40 do
     begin
       if WebApplication.IsPartialUpdate then
       begin
         TIWComponent40Context(AContext).AddToUpdateInitProc(s + EOL)
       end
       else
       begin
         TIWComponent40Context(AContext).AddToInitProc(s + EOL);
       end;
     end;
    {$ELSE}
    TIWAppForm(Form).AddToInitProc(s + EOL);
    {$ENDIF}

    s := EmptyStr;
  end;  

  with Result.Contents.AddTag('INPUT') do
  begin
    AddStringParam('TYPE', 'hidden');
    AddStringParam('NAME', HTMLName);
    AddStringParam('ID', HTMLName + '_INPUT');
  end;

end;

procedure TTIWExchangeBar.SetSelectedItem(const Value: integer);
begin
  if (csLoading in ComponentState) then
    FSelectedItem := Value
  else
  begin
    if (Value < Panels[ActivePanel].Items.Count) and (Value >= 0) then
      FSelectedItem := Value
  end;
end;


procedure TTIWExchangeBar.SetActivePanel(const Value: integer);
begin
  if (csLoading in ComponentState) then
    FActivePanel := Value
  else
  begin
    if (Value < Panels.Count) and (Value >= 0) then
      FActivePanel := Value
  end;
end;

procedure TTIWExchangeBar.SetVisiblePanels(const Value: integer);
begin
  if (csLoading in ComponentState) then
    FVisiblePanels := Value
  else
  begin
    if (Value <= Panels.Count) and (Value >= 0) then
      FVisiblePanels := Value
  end;
end;

procedure TTIWExchangeBar.Submit(const AValue: string);
var
  si, sp, sval: string;
  itemindex, panelindex, err: Integer;
begin
  inherited;
  // postback command
  // -> server control events

  if Pos('ITEMCLICK', AValue) > 0 then
  begin
    si := '-1';
    sp := '-1';
    sval := AValue;

    system.Delete(sval, 1, 10);
    if pos('#', sval) > 0 then
    begin
      sp := copy(sval, 1, pos('#',sval));
      si := copy(sval, pos('#',sval) + 1, length(sval));
    end;
    val(si,itemindex, err);
    val(sp,panelindex, err);
    if Assigned(FOnItemClick) then
      FOnItemClick(Self,panelindex,itemindex);
    Exit;
  end;

  if Pos('PANELCHANGE', AValue) > 0 then
  begin
    sp := '-1';
    sval := AValue;

    system.Delete(sval, 1, 11);
    if pos('#', sval) > 0 then
    begin
      si := copy(sval, 1, pos('#',sval));
      sp := copy(sval, pos('#',sval) + 1, length(sval));

    end;
    val(sp,panelindex, err);

    if Assigned(FOnPanelChange) then
      FOnPanelChange(Self,panelindex);
    Exit;
  end;
end;

procedure TTIWExchangeBar.SetValue(const AValue: string);
var
vp,vi,vt,i,j: integer;
VarVal,su,si,st: string;
begin
  // hidden input value
  // -> property updating

    VarVal := aValue;

    //retrieve visible panels
    vp := pos('|', VarVal);
    if vp > 0 then
    begin
      su := copy(VarVal, 1, vp - 1);
      Delete(VarVal, 1, vp);

      FVisiblePanels := StrToInt(su);
    end;

    //retrieve selected item
    vp := pos('|', VarVal);
    if vp > 0 then
    begin
      su := copy(VarVal, 1, vp - 1);
      Delete(VarVal, 1, vp);

      FSelectedItem := StrToInt(su);
    end;

    //retrieve active panel
    vp := pos('|', VarVal);
    if vp > 0 then
    begin
      su := copy(VarVal, 1, vp - 1);
      Delete(VarVal, 1, vp);

      ActivePanel := StrToInt(su);

    end;

    //retrieve treeview state
    vp := pos('|', VarVal);
    if vp > 0 then
    begin
      su := copy(VarVal, 1, vp - 1);
      Delete(VarVal, 1, vp);

     for i:=1 to Panels.Count do
      begin
        vi := pos('#', su);
        if vi > 0 then
        begin                                            
          si := copy(su, 1, vi - 1);
          Delete(su, 1, vi);

          for j:=1 to Panels[i - 1].Items.Count do
          begin
            vt := pos(',', si);
            if vt > 0 then
            begin
              st := copy(si, 1, vt - 1);
              Delete(si, 1, vt);

              if (Length(st) > 0) then
              begin
                if (StrToInt(st) = 1) then
                  Panels[i - 1].Items[j - 1].IsExpandedInt := true
                else
                  Panels[i - 1].Items[j - 1].IsExpandedInt := false;
              end;
            end;

          end;
        end;
      end;
    end;

end;


{ TExchangeBarButton }

constructor TExchangeBarButton.Create;
begin
  inherited;
     FActiveColor := clWebGOLD;
     FActiveColorTo := clWebRED;
     FActiveHoverColor := clWebSILVER;
     FActiveHoverColorTo := clWebRED;
     FBackColor := clWebSKYBLUE;
     FBackColorTo := clWebSTEELBLUE;
     FCollapsedImage := TTIWPicture.Create;
     FExpandedImage := TTIWPicture.Create;
     FFont := TIWFont.Create;
     FForeColor := clBlack;
     FGradientDirection := gdVertical;
     FHeight := 30;
     FHoverColor := clWebOLDLACE;
     FHoverColorTo := clWebORANGE;
     FSelectColor := clWebLIGHTSKYBLUE;
     FSelectColorTo := clWebDODGERBLUE;
end;

destructor TExchangeBarButton.Destroy;
begin
  FCollapsedImage.Free;
  FExpandedImage.Free;
  FFont.Free;
  inherited;
end;

procedure TExchangeBarButton.SetFont(const Value: TIWfont);
begin
  FFont.Assign(Value);
end;

{ TExchangeBarClientEvents }

constructor TExchangeBarClientEvents.Create;
begin
  inherited;
  FItemClick := TStringList.Create;
  FItemCollapse := TStringList.Create;                         
  FItemExpand := TStringList.Create;
  FPanelChange := TStringList.Create;
  FPanelClose := TStringList.Create;
  FPanelMove := TStringList.Create;
  FPanelOpen := TStringList.Create;
  FSplitterMove := TStringList.Create;
  FSplitterMoved := TStringList.Create;
end;

destructor TExchangeBarClientEvents.Destroy;
begin
  FItemClick.Free;
  FItemCollapse.Free;
  FItemExpand.Free;
  FPanelChange.Free;
  FPanelClose.Free;
  FPanelMove.Free;
  FPanelOpen.Free;
  FSplitterMove.Free;
  FSplitterMoved.Free;
  inherited;
end;
                          
function TExchangeBarClientEvents.GetJSFunction(PropName: string): string;
begin
  if (PropName = 'ItemClick') then
    Result := 'ItemClick(obj,pnlIndex,itmIndex) // obj = ExchangeBar object, pnlIndex = Panel index, itmIndex = Item Index';

  if (PropName = 'ItemCollapse') then
    Result := 'ItemCollapse(obj,pnlIndex,itmIndex) // obj = ExchangeBar object, pnlIndex = Panel index, itmIndex = Item Index';

  if (PropName = 'ItemExpand') then
    Result := 'ItemExpand(obj,pnlIndex,itmIndex) // obj = ExchangeBar object, pnlIndex = Panel index, itmIndex = Item Index';

  if (PropName = 'PanelChange') then
    Result := 'PanelChange(obj,pnlFrom,pnlTo) // obj = ExchangeBar object, pnlFrom = Position from, pnlTo = Position To';

  if (PropName = 'PanelClose') then
    Result := 'PanelClose(obj,pnlIndex) // obj = ExchangeBar object, pnlIndex = Panel index';

  if (PropName = 'PanelOpen') then
    Result := 'PanelOpen(obj,pnlIndex,pnlTop,pnlLeft,pnlWidth,pnlHeight,srvrIndex) // obj = ExchangeBar object';

  if (PropName = 'PanelMove') then
    Result := 'PanelOpen(obj,pnlIndex,pnlTop,pnlLeft,pnlWidth,pnlHeight,srvrIndex) // obj = ExchangeBar object';

  if (PropName = 'SplitterMove') then
    Result := 'SplitterMove(obj,pnlIndex,pnlHeight) // obj = ExchangeBar object';

  if (PropName = 'SplitterMoved') then
    Result := 'SplitterMoved(obj,pnlsVisible) // obj = ExchangeBar object';
end;


procedure TExchangeBarClientEvents.SetItemClick(const Value: TStringList);
begin
  FItemClick.Assign(Value);
end;

procedure TExchangeBarClientEvents.SetItemCollapse(
  const Value: TStringList);
begin
  FItemCollapse.Assign(Value);
end;

procedure TExchangeBarClientEvents.SetItemExpand(const Value: TStringList);
begin
  FItemExpand.Assign(Value);
end;

procedure TExchangeBarClientEvents.SetPanelChange(const Value: TStringList);
begin
  FPanelChange.Assign(Value);
end;

procedure TExchangeBarClientEvents.SetPanelClose(const Value: TStringList);
begin
  FPanelClose.Assign(Value);
end;

procedure TExchangeBarClientEvents.SetPanelMove(const Value: TStringList);
begin
  FPanelMove.Assign(Value);
end;

procedure TExchangeBarClientEvents.SetPanelOpen(const Value: TStringList);
begin
  FPanelOpen.Assign(Value);
end;

procedure TExchangeBarClientEvents.SetSplitterMove(const Value: TStringList);
begin
  FSplitterMove.Assign(Value);
end;

procedure TExchangeBarClientEvents.SetSplitterMoved(const Value: TStringList);
begin
  FSplitterMoved.Assign(Value);
end;

{ TExchangeBarDivider }

constructor TExchangeBarDivider.Create;
begin
  inherited;
     FBackColor := clWebWHITESMOKE;
     FBackColorTo := clSilver;
     FGradientDirection := gdVertical;
end;

{ TExchangeBarSplitter }

constructor TExchangeBarSplitter.Create;
begin
  inherited;
     FBackColor := clWebSKYBLUE;
     FBackColorTo := clWebSLATEGRAY;
     FHeight := 5;
     FGlyph := TTIWPicture.Create;
end;


destructor TExchangeBarSplitter.Destroy;
begin
  FGlyph.Free;
  inherited;
end;

{ TExchangeBarItems }

function TExchangeBarItems.Add: TExchangeBarItem;
begin
  Result := TExchangeBarItem(inherited Add);
end;

constructor TExchangeBarItems.Create(AOwner: TExchangeBarPanel);
begin
  inherited Create(TExchangeBarItem);
  FOwner := AOwner;
end;

function TExchangeBarItems.GetItems(Index: Integer): TExchangeBarItem;
begin
  Result := TExchangeBarItem(inherited Items[Index]);
end;

function TExchangeBarItems.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

function TExchangeBarItems.Insert(Index: Integer): TExchangeBarItem;
begin
  Result := TExchangeBarItem(inherited Insert(Index));
end;

procedure TExchangeBarItems.SetItems(Index: Integer;
  const Value: TExchangeBarItem);
begin
  inherited Items[Index] := Value;
end;

procedure TExchangeBarItems.Update(Item: TCollectionItem);
begin
  inherited;
  TExchangeBarPanels(FOwner.Collection).FOwner.Invalidate;
end;

{ TExchangeBarItemDisplay }

constructor TExchangeBarItemDisplay.Create;
begin
  inherited Create;
  FCollapsedImage := TTIWPicture.Create;
  FExpandedImage := TTIWPicture.Create;
  FHoverBackColor := clBlue;
  FHoverForeColor := clWhite;
  FImageMargin := TExchangeBarItemImageMargin.Create;
  FImageSize := TExchangeBarItemImageSize.Create;
  FSelectBackColor := clBlue;
  FSelectForeColor := clWhite;
  FSpacing := 0;
end;

destructor TExchangeBarItemDisplay.Destroy;
begin
  FCollapsedImage.Free;
  FExpandedImage.Free;
  FImageMargin.Free;
  FImageSize.Free;
  inherited;
end;

{ TTIWPicture }

procedure TTIWPicture.Assign(Source: TPersistent);
begin
  if (Source is TTIWPicture) then
  begin
    FFileName := (Source as TTIWPicture).FileName;
    FImageIndex := (Source as TTIWPicture).ImageIndex;
  end;
end;

constructor TTIWPicture.Create;
begin
  inherited Create;
  FFileName := '';
  FImageIndex := -1;
end;

function TTIWPicture.ImageRef(Control: TIWControl; Images: TIWImageList): string;
begin
  Result := '';

  if FileName <> '' then
    Result :=  StringReplace(FileName,'\','/',[rfReplaceAll])
  else
    if Assigned(Images) and (ImageIndex >= 0) then
    {$IFDEF TMSIW7}
      Result := GServerController.CacheURL + Images.ExtractImageToCache(ImageIndex);
    {$ELSE}
      Result := GetCacheDir(Control) + Images.ExtractImageToCache(ImageIndex);
    {$ENDIF}
end;

{ TExchangeBarItemImageMargin }

constructor TExchangeBarItemImageMargin.Create;
begin
  inherited Create;
  FBottom := 2;
  FLeft := 2;
  FRight := 2;
  FTop := 2;
end;

{ TExchangeBarItemImageSize }

constructor TExchangeBarItemImageSize.Create;
begin
  inherited Create;
  FHeight := 16;
  FWidth := 16;
end;

{ TExchangeBarItem }

procedure TExchangeBarItem.Assign(Source: TPersistent);
begin
  if (Source is TExchangeBarItem) then
  begin
    FCaption := (Source as TExchangeBarItem).Caption;
    FGlyph.Assign((Source as TExchangeBarItem).Glyph);
    FHint := (Source as TExchangeBarItem).Hint;
    FIsDivider := (Source as TExchangeBarItem).IsDivider;
    FIsExpandedInt := (Source as TExchangeBarItem).IsExpandedInt;
    FLevel := (Source as TExchangeBarItem).Level;
    FName := (Source as TExchangeBarItem).Name;
    FLink := (Source as TExchangeBarItem).Link;
    FScript := (Source as TExchangeBarItem).Script;
    FTag := (Source as TExchangeBarItem).Tag;
    FTarget := (Source as TExchangeBarItem).Target;
  end;
end;

constructor TExchangeBarItem.Create(Collection: TCollection);
begin
  inherited;
  FGlyph := TTIWPicture.Create;

  if Collection is TExchangeBarItems then
  begin
    FOwner := Collection as TExchangeBarItems;
  end;

  FCaption := 'Item ' + IntToStr(Collection.Count - 1) ;
  FHint := EmptyStr;
  FIsDivider := false;
  FIsExpandedInt := false;
  FIsExpanded := false;
  FLevel := 0;
  FName := EmptyStr;
  FLink := EmptyStr;
  FScript := EmptyStr;
  FTag := 0;
  FTarget := EmptyStr;

end;

destructor TExchangeBarItem.Destroy;
begin
  FGlyph.Free;
  inherited;
end;

function TExchangeBarItem.GetDisplayName: string;
begin
  if Caption <> '' then
    Result := Caption
  else
    Result := 'Item '+ IntToStr(Index);
end;

function TExchangeBarItem.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

procedure TExchangeBarItem.SetIsExpanded(const Value: Boolean);
var
  I: Integer;
begin
  if not (csLoading in  self.FOwner.FOwner.FOwner.FOwner.ComponentState) then
  begin
    for I := Self.Index + 1 to Self.FOwner.FOwner.Items.Count - 1 do
    begin
//      if (Self.FOwner.FOwner.Items[I].Level = Self.Level + 1) then
      if (Self.FOwner.FOwner.Items[I].Level > Self.Level) then
      begin
        //Self.FOwner.FOwner.Items[I].IsExpandedInt := Value;
        Self.FOwner.FOwner.Items[I].FIsExpandedInt := Value;
      end
      else
        break;
    end;
  end;

  FIsExpanded := Value;
  //FIsExpandedInt := Value;
end;

procedure TExchangeBarPanels.Update(Item: TCollectionItem);
begin
  inherited;
  FOwner.Invalidate;
end;

end.
