unit uStringGridWithControls;

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, Grids,
  StdCtrls, types, Buttons, ExtCtrls, uDataModule;

type

  // Evento para los BitBtn de la grilla
  TGridBitBtnActionNotifyEvent = procedure(Sender: TObject; kRow, kCol: Integer) of object;
  TGridCheckBoxNotifyEvent = procedure(Sender: TObject; kRow, kCol: Integer;
    Checked:Boolean) of object;

  TButtonType = (BT_Lupa, BT_Lapiz, BT_Clonar, BT_Cortar, BT_Borrar1, BT_Borrar2,
                 BT_Borrar3, BT_Primero, BT_Subir, BT_Bajar, BT_Ultimo, BT_Refresh,
                 BT_Configurar1, BT_Configurar2, BT_Lock, BT_Unlock, BT_SemaforoRojo,
                 BT_SemaforoVerde, BT_Mail, BT_Download, BT_Upload, BT_Conectar,
                 BT_Desconectar, BT_Graficar1, BT_Graficar2, BT_Graficar3 );

  TButtonsType = array of TButtonType;

  { TStringGrigPanel }

  TStringGrigPanel=class(TPanel)
    procedure MouseWheelOnPanel (Sender: TObject; Shift: TShiftState;
         WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  public

    kCol: Integer;
    kRow: Integer;

    constructor Create(AOwner: TComponent; ACol, ARow:Integer);

  end;

  { TSGWC_BitBtn }

  TSGWC_BitBtn = class(TBitBtn)

    procedure MouseWheel (Sender: TObject; Shift: TShiftState;
         WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);

  public
    ButtonType: TButtonType;
    constructor Create(TheOwner: TComponent; xButtonType: TButtonType;
         xHint: string);

    procedure ChangeType (NewType: TButtonType);
  end;

  { TSGWC_CheckBox }

  TSGWC_CheckBox = class(TCheckBox)

    procedure MouseWheel (Sender: TObject; Shift: TShiftState;
         WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);

    constructor Create(TheOwner: TComponent); override;

  end;

  // Tipo de controles para las columnas de la grilla
  TControlType = (CT_CheckBox, CT_ComboBox, CT_BitBtns);

  { TGridTextColumn }

  TGridTextColumn=class(TGridColumn)

    constructor Create (ACollection: TCollection; xTitle: string; xTitleFont: TFont;
         xTitleAlignment: TAlignment; xTitleColor: TColor; xColTextFont:TFont;
         xColTextAlignment: TAlignment; xColColor:TColor; IsReadOnly: Boolean);

  end;

  { TGridControlColumn }

  TGridControlColumn=class(TGridColumn)
    public

    // Tipo de control de la columna
    ControlType: TControlType;

    // Identificador de BitBtns
    iids: array of TButtonType;
    hints: array of string;

    constructor Create (ACollection: TCollection; xTitle: string; xTitleFont: TFont;
         xTitleAlignment: TAlignment; xTitleColor: TColor);

    constructor CreateBitBtnColumn (ACollection: TCollection; xTitle: string;
         xTitleFont: TFont; xTitleAlignment: TAlignment; xTitleColor: TColor;
         x_iids: array of TButtonType; x_hints: array of string);

    constructor CreateCheckBoxColumn (ACollection: TCollection; xTitle: string;
         xTitleFont: TFont; xTitleAlignment: TAlignment; xTitleColor: TColor;
         x_hint: string);

    constructor CreateComboBoxColumn (ACollection: TCollection; xTitle: string;
         xTitleFont: TFont; xTitleAlignment: TAlignment; xTitleColor: TColor;
         x_hint: string);

  end;


  { TStringGridWithControls }

  TStringGridWithControls = class(TStringGrid)
  private

    FOnLupaClick:TGridBitBtnActionNotifyEvent;
    FOnLapizClick: TGridBitBtnActionNotifyEvent;
    FOnClonarClick: TGridBitBtnActionNotifyEvent;
    FOnCortarClick: TGridBitBtnActionNotifyEvent;
    FOnBorrar1Click: TGridBitBtnActionNotifyEvent;
    FOnBorrar2Click: TGridBitBtnActionNotifyEvent;
    FOnPrimeroClick: TGridBitBtnActionNotifyEvent;
    FOnSubirClick: TGridBitBtnActionNotifyEvent;
    FOnBajarClick: TGridBitBtnActionNotifyEvent;
    FOnUltimoClick: TGridBitBtnActionNotifyEvent;
    FOnRefreshClick: TGridBitBtnActionNotifyEvent;
    FOnConfigurar1Click: TGridBitBtnActionNotifyEvent;
    FOnConfigurar2Click: TGridBitBtnActionNotifyEvent;
    FOnLockClick: TGridBitBtnActionNotifyEvent;
    FOnUnlockClick: TGridBitBtnActionNotifyEvent;
    FOnSemaforoRojoClick: TGridBitBtnActionNotifyEvent;
    FOnSemaforoVerdeClick: TGridBitBtnActionNotifyEvent;
    FOnMailClick: TGridBitBtnActionNotifyEvent;
    FOnDownloadClick: TGridBitBtnActionNotifyEvent;
    FOnUploadClick: TGridBitBtnActionNotifyEvent;
    FOnConectarClick: TGridBitBtnActionNotifyEvent;
    FOnDesconectarClick: TGridBitBtnActionNotifyEvent;
    FOnGraficar1Click: TGridBitBtnActionNotifyEvent;
    FOnGraficar2Click: TGridBitBtnActionNotifyEvent;
    FOnGraficar3Click: TGridBitBtnActionNotifyEvent;

    FOnCheckBoxChange: TGridCheckBoxNotifyEvent;

    _maxTopRow:Integer;
    _maxHeight: Integer;
    _maxWidth:Integer;

    procedure TopLeftChanged(Sender: TObject);
    procedure MouseWheelOnSGWC (Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);

    procedure HeaderSizing(const IsColumn:boolean; const AIndex,ASize:Integer);override;

    function GetControlOnCell(kCol, kRow: integer): TStringGrigPanel;
    procedure SetControlOnCell(kCol, kRow: integer; AValue: TStringGrigPanel);
    procedure MoveControl(AControl: TControl; NewPosition: TPoint;
      isVisible: boolean = True);
    procedure ReArrangeControls;


  protected

    property ControlOnCell[kCol, kRow: integer]: TStringGrigPanel
      read GetControlOnCell write SetControlOnCell;

    procedure OnGridAction( Sender: TObject);

    // Escribe el texto en la celda.
    procedure wrText(kCol, kRow: Integer; Text: string);

    // Inserta TCheckBox en la celda kCol, kRow
    procedure wrCheckBox(kCol, kRow: Integer; Hint: string);

    // Inserta TComboBox en la celda kCol, kRow
    procedure wrComboBox(kCol, kRow: Integer; Hint: string);

    // Escribe un array de BitBtn en la misma celda
    procedure wrBitBtns(kCol, kRow: integer; iids: array of TButtonType;
      hints: array of string);

    procedure wrControl(kCol, kRow: Integer);

    procedure AutoSizeColumn(aCol: Integer);

  published

    property OnLupaClick: TGridBitBtnActionNotifyEvent read FOnLupaClick write FOnLupaClick;
    property OnLapizClick: TGridBitBtnActionNotifyEvent read FOnLapizClick write FOnLapizClick;
    property OnClonarClick: TGridBitBtnActionNotifyEvent read FOnClonarClick write FOnClonarClick;
    property OnCortarClick: TGridBitBtnActionNotifyEvent read FOnCortarClick write FOnCortarClick;
    property OnBorrar1Click: TGridBitBtnActionNotifyEvent read FOnBorrar1Click write FOnBorrar1Click;
    property OnBorrar2Click: TGridBitBtnActionNotifyEvent read FOnBorrar2Click write FOnBorrar2Click;
    property OnPrimeroClick: TGridBitBtnActionNotifyEvent read FOnPrimeroClick write FOnPrimeroClick;
    property OnSubirClick: TGridBitBtnActionNotifyEvent read FOnSubirClick write FOnSubirClick;
    property OnBajarClick: TGridBitBtnActionNotifyEvent read FOnBajarClick write FOnBajarClick;
    property OnUltimoClick: TGridBitBtnActionNotifyEvent read FOnUltimoClick write FOnUltimoClick;
    property OnRefreshClick: TGridBitBtnActionNotifyEvent read FOnRefreshClick write FOnRefreshClick;
    property OnConfigurar1Click: TGridBitBtnActionNotifyEvent read FOnConfigurar1Click write FOnConfigurar1Click;
    property OnConfigurar2Click: TGridBitBtnActionNotifyEvent read FOnConfigurar2Click write FOnConfigurar2Click;
    property OnLockClick: TGridBitBtnActionNotifyEvent read FOnLockClick write FOnLockClick;
    property OnUnlockClick: TGridBitBtnActionNotifyEvent read FOnUnlockClick write FOnUnlockClick;
    property OnSemaforoRojoClick: TGridBitBtnActionNotifyEvent read FOnSemaforoRojoClick write FOnSemaforoRojoClick;
    property OnSemaforoVerdeClick: TGridBitBtnActionNotifyEvent read FOnSemaforoVerdeClick write FOnSemaforoVerdeClick;
    property OnMailClick: TGridBitBtnActionNotifyEvent read FOnMailClick write FOnMailClick;
    property OnDownloadClick: TGridBitBtnActionNotifyEvent read FOnDownloadClick write FOnDownloadClick;
    property OnUploadClick: TGridBitBtnActionNotifyEvent read FOnUploadClick write FOnUploadClick;
    property OnConectarClick: TGridBitBtnActionNotifyEvent read FOnConectarClick write FOnConectarClick;
    property OnDesconectarClick: TGridBitBtnActionNotifyEvent read FOnDesconectarClick write FOnDesconectarClick;
    property OnGraficar1Click: TGridBitBtnActionNotifyEvent read FOnGraficar1Click write FOnGraficar1Click;
    property OnGraficar2Click: TGridBitBtnActionNotifyEvent read FOnGraficar2Click write FOnGraficar2Click;
    property OnGraficar3Click: TGridBitBtnActionNotifyEvent read FOnGraficar3Click write FOnGraficar3Click;

    property OnCheckBoxClick: TGridCheckBoxNotifyEvent read FOnCheckBoxChange write FOnCheckBoxChange;

    procedure SetDimension(nRows, nFixedRows, nCols, nFixedCols: Integer);
    procedure AutoSizeColumns;

  public

    { public declarations }
    constructor Create(AOwner: TComponent; AParent:TWinControl; AName: string);

    procedure AddTextColumn( xTitle: string; xTitleFont: TFont;
      xTitleAlignment: TAlignment; xTitleColor: TColor; xColTextFont:TFont;
      xColTextAlignment: TAlignment; xColColor:TColor; IsReadOnly: Boolean);

    procedure AddBitBtnsColumn(xTitle: string; xTitleFont: TFont;
      xTitleAlignment: TAlignment; xTitleColor: TColor;
      x_iids: array of TButtonType; x_hints: array of string);

    procedure AddCheckBoxColumn(xTitle: string; xTitleFont: TFont;
      xTitleAlignment: TAlignment; xTitleColor: TColor; x_hint: string);

    procedure AddComboBoxColumn(xTitle: string; xTitleFont: TFont;
      xTitleAlignment: TAlignment; xTitleColor: TColor; x_hint: string);

    procedure Refresh();virtual;abstract;
    procedure Clear();virtual;abstract;

    // Inserta una fila nueva con los valores y los controles (según corresponda)
    //        SE PUEDE MEJOAR !!!
    procedure InsertRow(Values: TStrings);virtual;

    procedure DeleteRow(kRow:Integer);override;
    procedure ClearAll();virtual;

    procedure Free;

  end;

procedure CreateImageList;
function DefaultHint(xButtonType: TButtonType):string;

implementation

procedure CreateImageList;
var
  mImage:   TPicture;
  mBitmap:  TBitmap;
  archi: String;
begin
  archi:='C:\simsee\simsee_src\src\trunk\Iconos\arrow_down.png';
  if FileExists(archi) then
  begin
    mImage:=TPicture.Create;
    try
      mImage.LoadFromFile(archi);
    except
      on exception do;
    end;
    if (mImage.Width>0) and (mImage.Height>0) then
    begin
      mBitmap:=TBitmap.Create;
      try
        mBitmap.Assign(mImage.Graphic);
        mBitmap.Transparent:=true;
        DataModule_SGWC.ImageList1.add(mBitmap,NIL);
      finally
        mBitmap.Free;
      end;
    end;
  end;
end;

function DefaultHint(xButtonType: TButtonType): string;
begin
  case xButtonType of
    BT_Lupa:            Result:='Lupa';
    BT_Lapiz:           Result:='Editar';
    BT_Clonar:          Result:='Clonar';
    BT_Cortar:          Result:='Cortar';
    BT_Borrar1:         Result:='Eliminar';
    BT_Borrar2:         Result:='Eliminar';
    BT_Primero:         Result:='Primero';
    BT_Subir:           Result:='Subir';
    BT_Bajar:           Result:='Bajar';
    BT_Ultimo:          Result:='Ultimo';
    BT_Refresh:         Result:='Actualizar';
    BT_Configurar1:     Result:='Configuar';
    BT_Configurar2:     Result:='Configuar';
    BT_Lock:            Result:='Bloquear';
    BT_Unlock:          Result:='Desbloquear';
    BT_SemaforoRojo:    Result:='Bloquear';
    BT_SemaforoVerde:   Result:='Desbloquear';
    BT_Mail:            Result:='Mail';
    BT_Download:        Result:='Descargar';
    BT_Upload:          Result:='Cargar';
    BT_Conectar:        Result:='Conectar';
    BT_Desconectar:     Result:='Desconectar';
    BT_Graficar1:       Result:='Graficar';
    BT_Graficar2:       Result:='Graficar';
    BT_Graficar3:       Result:='Graficar';
  end;
end;

{ TSGWC_CheckBox }

procedure TSGWC_CheckBox.MouseWheel(Sender: TObject;
  Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
  var Handled: Boolean);
var
  sg:TStringGridWithControls;
begin
  sg:=TStringGridWithControls(TSGWC_BitBtn(sender).Owner);
  sg.MouseWheelOnSGWC(Sender, Shift, WheelDelta, MousePos, Handled);
end;

constructor TSGWC_CheckBox.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  OnMouseWheel:=self.MouseWheel;
end;

{ TGridControlColumn }

constructor TGridControlColumn.Create(ACollection: TCollection; xTitle: string;
  xTitleFont: TFont; xTitleAlignment: TAlignment; xTitleColor: TColor);
begin
  inherited Create(ACollection);
  CreateTitle;

  Title.Caption:=xTitle;

  if Assigned(xTitleFont) then
    Title.Font:=xTitleFont;
  Title.Alignment:=xTitleAlignment;
  Title.Color:=xTitleColor;

  self.ReadOnly:=True;

end;

constructor TGridControlColumn.CreateBitBtnColumn(ACollection: TCollection;
  xTitle: string; xTitleFont: TFont; xTitleAlignment: TAlignment;
  xTitleColor: TColor; x_iids: array of TButtonType; x_hints: array of string);
var
  i: Integer;
begin
  self.Create(ACollection, xTitle, xTitleFont, xTitleAlignment, xTitleColor);

  SetLength(self.iids, Length(x_iids));
  SetLength(self.hints, Length(x_iids));
  for i:=0 to Length(x_iids)-1 do
  begin
    self.iids[i]:=x_iids[i];
    if i<Length(x_hints) then
      self.hints[i]:=x_hints[i]
    else
      self.hints[i]:=DefaultHint(self.iids[i]);
  end;

  self.ControlType:=CT_BitBtns;
  self.MinSize:=25;
end;

constructor TGridControlColumn.CreateCheckBoxColumn(ACollection: TCollection;
  xTitle: string; xTitleFont: TFont; xTitleAlignment: TAlignment;
  xTitleColor: TColor; x_hint: string);
begin
  self.Create(ACollection, xTitle, xTitleFont, xTitleAlignment, xTitleColor);
  SetLength(self.hints, 1);
  self.hints[0]:=x_hint;
  self.ControlType:=CT_CheckBox;
end;

constructor TGridControlColumn.CreateComboBoxColumn(ACollection: TCollection;
  xTitle: string; xTitleFont: TFont; xTitleAlignment: TAlignment;
  xTitleColor: TColor; x_hint: string);
begin
  self.Create(ACollection, xTitle, xTitleFont, xTitleAlignment, xTitleColor);
  SetLength(self.hints, 1);
  self.hints[0]:=x_hint;
  self.ControlType:=CT_ComboBox;
end;

{ TGridTextColumn }

constructor TGridTextColumn.Create(ACollection: TCollection; xTitle: string;
  xTitleFont: TFont; xTitleAlignment: TAlignment; xTitleColor: TColor;
  xColTextFont: TFont; xColTextAlignment: TAlignment; xColColor: TColor;
  IsReadOnly: Boolean);
begin
  inherited Create(ACollection);
  CreateTitle;

  Title.Caption:=xTitle;

  if Assigned(xTitleFont) then
    Title.Font:=xTitleFont;
  Title.Alignment:=xTitleAlignment;
  Title.Color:=xTitleColor;

  if Assigned(xColTextFont) then
    self.Font:=xColTextFont;
  self.Alignment:=xColTextAlignment;
  self.Color:=xColColor;

  self.ReadOnly:=IsReadOnly;

end;

{ TStringGrigPanel }

procedure TStringGrigPanel.MouseWheelOnPanel(Sender: TObject;
  Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
  var Handled: Boolean);
var
  sg:TStringGridWithControls;
begin
  sg:=TStringGridWithControls(TStringGrigPanel(sender).Owner);
  sg.MouseWheelOnSGWC(Sender, Shift, WheelDelta, MousePos, Handled);
end;

constructor TStringGrigPanel.Create(AOwner: TComponent; ACol,
  ARow: Integer);
begin
  inherited Create(AOwner);
  self.kCol:=ACol;
  self.kRow:=ARow;
//  self.BorderStyle:=bsNone;
  self.OnMouseWheel:=MouseWheelOnPanel;

end;

{ TSGWC_BitBtn }

procedure TSGWC_BitBtn.MouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
var
  sg:TStringGridWithControls;
begin
  sg:=TStringGridWithControls(TSGWC_BitBtn(sender).Owner);
  sg.MouseWheelOnSGWC(Sender, Shift, WheelDelta, MousePos, Handled);
end;

constructor TSGWC_BitBtn.Create(TheOwner: TComponent;
  xButtonType: TButtonType; xHint: string);
begin

  Inherited Create(TheOwner);
  Self.ButtonType:=xButtonType;
  self.ShowHint:=True;
  if xHint='' then
    self.Hint:=DefaultHint(xButtonType)
  else
    self.Hint:=xHint;

  self.Caption:='';
  self.OnMouseWheel:=MouseWheel;

end;

procedure TSGWC_BitBtn.ChangeType(NewType: TButtonType);
begin
  self.ButtonType:=NewType;
  DataModule_SGWC.ImageList1.GetBitmap( ord(NewType),  self.Glyph );
end;

{ TStringGridWithControls }

procedure TStringGridWithControls.TopLeftChanged(Sender: TObject);
begin
  reArrangeControls;
end;

function TStringGridWithControls.GetControlOnCell(kCol, kRow: integer): TStringGrigPanel;
begin
  Result:=nil;
  if Objects[kCol, kRow] is TStringGrigPanel then
    Result :=TStringGrigPanel (Objects[kCol, kRow]);
end;

procedure TStringGridWithControls.SetControlOnCell(kCol, kRow: integer;
  AValue: TStringGrigPanel);
begin
  Objects[kCol, kRow] := AValue;
end;

procedure TStringGridWithControls.MoveControl(AControl: TControl;
  NewPosition: TPoint; isVisible: boolean);
var
  Width, Height: integer;
begin
  AControl.Visible := isVisible;
  Width := AControl.Width;
  Height := AControl.Height;
  if isVisible then
    AControl.SetBounds(NewPosition.x, NewPosition.y, Width, Height);
end;

procedure TStringGridWithControls.OnGridAction(Sender: TObject);
var
  GridPanel: TStringGrigPanel;
  kRow: Integer;
  kCol: Integer;
  ACol: TGridControlColumn;
  btn:TSGWC_BitBtn;
  ButtonType: TButtonType;
begin
  GridPanel:= TStringGrigPanel(TWinControl(Sender).Parent);
  kRow:= GridPanel.kRow;
  kCol:= GridPanel.kCol;

  ACol:= TGridControlColumn( self.Columns[kCol] );

  case ACol.ControlType of

    CT_BitBtns:
      begin
        btn:= TSGWC_BitBtn(Sender);
        case btn.ButtonType of
          BT_Lupa:
            if Assigned(FOnLupaClick) then
              FOnLupaClick(Sender, kRow, kCol)
            else
              showmessage( 'Lupa_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Lapiz:
            if Assigned(FOnLapizClick) then
              FOnLapizClick(Sender, kRow, kCol)
            else
              showmessage( 'Lapiz_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Clonar:
            if Assigned(FOnClonarClick) then
              FOnClonarClick(Sender, kRow, kCol)
            else
              showmessage( 'Clonar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Borrar1:
            if Assigned(FOnBorrar1Click) then
              FOnBorrar1Click(Sender, kRow, kCol)
            else
              showmessage( 'Borrar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Borrar2:
            if Assigned(FOnBorrar2Click) then
              FOnBorrar2Click(Sender, kRow, kCol)
            else
              showmessage( 'Borrar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Primero:
            if Assigned(FOnPrimeroClick) then
              FOnPrimeroClick(Sender, kRow, kCol)
            else
              showmessage( 'Primero_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Subir:
            if Assigned(FOnSubirClick) then
              FOnSubirClick(Sender, kRow, kCol)
            else
              showmessage( 'Subir_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Bajar:
            if Assigned(FOnBajarClick) then
              FOnBajarClick(Sender, kRow, kCol)
            else
              showmessage( 'Bajar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Ultimo:
            if Assigned(FOnUltimoClick) then
              FOnUltimoClick(Sender, kRow, kCol)
            else
              showmessage( 'Ultimo_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Refresh:
            if Assigned(FOnRefreshClick) then
              FOnRefreshClick(Sender, kRow, kCol)
            else
              showmessage( 'Refresh_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Configurar1:
            if Assigned(FOnConfigurar1Click) then
              FOnConfigurar1Click(Sender, kRow, kCol)
            else
              showmessage( 'Configurar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Configurar2:
            if Assigned(FOnConfigurar2Click) then
              FOnConfigurar2Click(Sender, kRow, kCol)
            else
              showmessage( 'Configurar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Lock:
            begin
              TSGWC_BitBtn(Sender).ChangeType(BT_Unlock);
              if Assigned(FOnLockClick) then
                FOnLockClick(Sender, kRow, kCol)
              else
                showmessage( 'Lock_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));
            end;

          BT_Unlock:
            begin
              TSGWC_BitBtn(Sender).ChangeType(BT_Lock);
              if Assigned(FOnLockClick) then
                FOnLockClick(Sender, kRow, kCol)
              else
                showmessage( 'Unlock_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));
            end;

          BT_SemaforoRojo:
            begin
              TSGWC_BitBtn(Sender).ChangeType(BT_SemaforoVerde);
              if Assigned(FOnSemaforoRojoClick) then
                FOnSemaforoRojoClick(Sender, kRow, kCol)
              else
                showmessage( 'SemaforoRojo_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));
            end;

          BT_SemaforoVerde:
            begin
              TSGWC_BitBtn(Sender).ChangeType(BT_SemaforoRojo);
              if Assigned(FOnSemaforoVerdeClick) then
                FOnSemaforoVerdeClick(Sender, kRow, kCol)
              else
                showmessage( 'SemaforoVerde_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));
            end;

          BT_Mail:
            if Assigned(FOnMailClick) then
              FOnMailClick(Sender, kRow, kCol)
            else
              showmessage( 'Mail_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Download:
            if Assigned(FOnDownloadClick) then
              FOnDownloadClick(Sender, kRow, kCol)
            else
              showmessage( 'Download_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Upload:
            if Assigned(FOnUploadClick) then
              FOnUploadClick(Sender, kRow, kCol)
            else
              showmessage( 'Upload_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Conectar:
            begin
              TSGWC_BitBtn(Sender).ChangeType(BT_Desconectar);
              if Assigned(FOnConectarClick) then
                FOnConectarClick(Sender, kRow, kCol)
              else
                showmessage( 'Conectar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));
            end;

          BT_Desconectar:
            begin
              TSGWC_BitBtn(Sender).ChangeType(BT_Conectar);
              if Assigned(FOnDesconectarClick) then
                FOnDesconectarClick(Sender, kRow, kCol)
              else
                showmessage( 'Desconectar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));
            end;

          BT_Graficar1:
            if Assigned(FOnGraficar1Click) then
              FOnGraficar1Click(Sender, kRow, kCol)
            else
              showmessage( 'Graficar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Graficar2:
            if Assigned(FOnGraficar2Click) then
              FOnGraficar2Click(Sender, kRow, kCol)
            else
              showmessage( 'Graficar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));

          BT_Graficar3:
            if Assigned(FOnGraficar3Click) then
              FOnGraficar3Click(Sender, kRow, kCol)
            else
              showmessage( 'Graficar_OnClick Sin escribir.. kRow='+IntToStr(kRow)+' kCol='+IntToStr(kCol));
        end;
      end;

    CT_CheckBox:
      begin
        if Assigned(FOnCheckBoxChange) then
          FOnCheckBoxChange(Sender, kRow, kCol, TSGWC_CheckBox(Sender).Checked)
        else
          showmessage( 'CheckBox_OnChange Sin escribir.. kRow='+IntToStr(kRow)+
            ' kCol='+IntToStr(kCol)+' Checked='+BoolToStr(TSGWC_CheckBox(Sender).Checked, 'True','False'));
      end;
  end;
end;

procedure TStringGridWithControls.ReArrangeControls;
var
  kCol, kRow: integer;
  AControl: TStringGrigPanel;
begin
  _maxTopRow:=Self.RowCount-Self.VisibleRowCount;
  for kCol := FixedCols to ColCount - 1 do
  begin
    if self.Columns[kCol] is TGridControlColumn then
    begin
      for kRow := FixedRows to RowCount - 1 do
      begin
        AControl := ControlOnCell[kCol, kRow];
        if Assigned(AControl) then
        begin
          MoveControl(AControl, CellRect(kCol, kRow).TopLeft,
            ((LeftCol <= kCol) and (TopRow <= kRow)));

          AControl.kCol:=kCol;
          AControl.kRow:=kRow;
        end;
      end;
    end;
  end;
end;

procedure TStringGridWithControls.Free;
var
  kCol, kRow: integer;
  AControl: TControl;
begin
  for kCol := 0 to ColCount - 1 do
    for kRow := 0 to RowCount - 1 do
    begin
      AControl := ControlOnCell[kCol, kRow];
      if AControl <> nil then
        AControl.Free;
    end;
  inherited Free;
end;

constructor TStringGridWithControls.Create(AOwner: TComponent;
  AParent: TWinControl; AName: string);
begin

  inherited Create(AOwner);
  self.Name := AName;

  self.Parent:=AParent;
  self.Width:=AParent.Width;
  self.Height:=AParent.Height;

  self.ScrollBars := ssBoth;
  self.DefaultRowHeight:=25;

  self.Options := [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine,
    goEditing, goColSizing];

  self.MouseWheelOption:=TMouseWheelOption.mwGrid;

  self.OnTopLeftChanged := self.TopLeftChanged;
//  self.OnHeaderSizing:= self.HeaderColumnSizing;

  self.OnMouseWheel:=self.MouseWheelOnSGWC;

  _maxTopRow:=0;
  SetDimension(1, 1, 0, 0);

end;

procedure TStringGridWithControls.AddTextColumn(xTitle: string;
  xTitleFont: TFont; xTitleAlignment: TAlignment; xTitleColor: TColor;
  xColTextFont: TFont; xColTextAlignment: TAlignment; xColColor: TColor;
  IsReadOnly: Boolean);
var
  newCol: TGridColumn;
  ACol: TGridColumn;
  oldCol: TGridColumn;
begin

  newCol:=TGridTextColumn.Create(self.Columns, xTitle, xTitleFont, xTitleAlignment,
    xTitleColor, xColTextFont, xColTextAlignment, xColColor, IsReadOnly);

  ACol := self.Columns.Add;
  oldCol:=Acol;
  ACol:=newCol;
  oldCol.Free;

end;

procedure TStringGridWithControls.AddBitBtnsColumn(xTitle: string;
  xTitleFont: TFont; xTitleAlignment: TAlignment; xTitleColor: TColor;
  x_iids: array of TButtonType; x_hints: array of string);
var
  newCol: TGridColumn;
  ACol: TGridColumn;
  oldCol: TGridColumn;
begin

  newCol:=TGridControlColumn.CreateBitBtnColumn(self.Columns, xTitle, xTitleFont,
    xTitleAlignment, xTitleColor, x_iids, x_hints);

  ACol := self.Columns.Add;
  oldCol:=ACol;
  ACol:=newCol;
  oldCol.Free;

end;

procedure TStringGridWithControls.AddCheckBoxColumn(xTitle: string;
  xTitleFont: TFont; xTitleAlignment: TAlignment; xTitleColor: TColor;
  x_hint: string);
var
  newCol: TGridColumn;
  ACol: TGridColumn;
  oldCol: TGridColumn;
begin

  newCol:=TGridControlColumn.CreateCheckBoxColumn(self.Columns, xTitle, xTitleFont,
    xTitleAlignment, xTitleColor, x_hint);

  ACol := self.Columns.Add;
  oldCol:=ACol;
  ACol:=newCol;
  oldCol.Free;

end;

procedure TStringGridWithControls.AddComboBoxColumn(xTitle: string;
  xTitleFont: TFont; xTitleAlignment: TAlignment; xTitleColor: TColor;
  x_hint: string);
var
  newCol: TGridColumn;
  ACol: TGridColumn;
  oldCol: TGridColumn;
begin

  newCol:=TGridControlColumn.CreateComboBoxColumn(self.Columns, xTitle, xTitleFont,
    xTitleAlignment, xTitleColor, x_hint);

  ACol := self.Columns.Add;
  oldCol:=ACol;
  ACol:=newCol;
  oldCol.Free;

end;

procedure TStringGridWithControls.InsertRow(Values: TStrings);
var
  nCols: Integer;
  i: Integer;
  kRow, kCol: Integer;
begin

  self.Visible:=False;
  nCols:= self.Columns.Count;
  i:=0;

  RowCount:=RowCount+1;
  kRow:=RowCount-1;

  for kCol:=0 to nCols-1 do
  begin
    if self.Columns.Items[i] is TGridTextColumn then
    begin
      if i < Values.Count then
        wrText(i, kRow, Values[i]);
    end
    else
    begin
      wrControl(i, kRow);
    end;
    i:=i+1;
  end;
  self.Visible:=True;
end;

procedure TStringGridWithControls.SetDimension(nRows, nFixedRows, nCols,
  nFixedCols: Integer);
begin

  self.RowCount:=nRows;
  self.FixedRows:=nFixedRows;

  self.ColCount:=nCols;
  self.FixedCols:=nFixedCols;

end;

procedure TStringGridWithControls.MouseWheelOnSGWC(Sender: TObject;
  Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
  var Handled: Boolean);
begin
  if WheelDelta < 0 then
  begin
    if TopRow < _maxTopRow then
      TopRow:=TopRow+1;
  end
  else
  begin
    if TopRow>1 then
      TopRow:=TopRow-1;
  end;
end;

procedure TStringGridWithControls.HeaderSizing(const IsColumn: boolean;
  const AIndex, ASize: Integer);
begin
  ReArrangeControls;
end;

procedure TStringGridWithControls.wrText(kCol, kRow: Integer; Text: string);
begin
  self.Cells[kCol, kRow] := Text;
end;

procedure TStringGridWithControls.wrCheckBox(kCol, kRow: Integer; Hint: string);
var
  R: Classes.TRect;
  P: TStringGrigPanel;
  cb: TCheckBox;
  i, j: Integer;

begin

  R := self.CellRect(kCol, kRow);
  P:=TStringGrigPanel.Create(self, kCol, kRow);
  P.BoundsRect:=R;
  P.Parent:=self;
  P.Color:=clWhite;

  P.Width:=(R.Bottom - R.Top)+2;

  cb := TSGWC_CheckBox.Create(self);
  cb.Parent := P;
  cb.Caption:=#0;
  cb.ShowHint:=True;
  cb.Hint:=Hint;

  cb.OnChange:=OnGridAction;

  i:=trunc(P.Width/2);
  j:=trunc(P.Height/2);

  cb.Height:=20;
  cb.Width:=20;

  cb.Left := i - trunc(cb.Width/2)+3;
  cb.Top := j - trunc(cb.Height/2);

  ControlOnCell[kCol, kRow] := P;



end;

procedure TStringGridWithControls.wrComboBox(kCol, kRow: Integer; Hint: string);
begin
  ShowMessage('TStringGridWithControls.wrComboBox: No implementado aún.');
end;

procedure TStringGridWithControls.wrBitBtns(kCol, kRow: integer;
  iids: array of TButtonType; hints: array of string);
var
  R: Classes.TRect;
  P: TStringGrigPanel;
  Btn: TSGWC_BitBtn;
  i: Integer;
  nBtns:Integer;

begin

  R := self.CellRect(kCol, kRow);
  P:=TStringGrigPanel.Create(self, kCol, kRow);
  P.BoundsRect:=R;
  P.Parent:=self;
//  P.Color:=clBlack;

  nBtns:=0;
  nBtns:=Length(iids);

  for i:=Length(iids)-1 downto 0 do
  begin
    Btn := TSGWC_BitBtn.Create(self, iids[i], hints[i]);
    Btn.Height:=R.Bottom - R.Top;
    Btn.Width:=R.Bottom - R.Top;
    Btn.Parent:= P;
    Btn.OnClick:=self.OnGridAction();
    Btn.Align:=alLeft;
    DataModule_SGWC.ImageList1.GetBitmap( ord(iids[i]),  Btn.Glyph );
    Btn.Spacing := 1;
    Btn.Margin:=0;
  end;


  P.Width:=nBtns*(R.Bottom - R.Top)+2;
  ControlOnCell[kCol, kRow] := P;

end;

procedure TStringGridWithControls.wrControl(kCol, kRow: Integer);
var
  i: Integer;
  ColControl: TGridControlColumn;
begin
  ColControl:=TGridControlColumn(self.Columns[kCol]);
  case ColControl.ControlType of
     CT_BitBtns:
        wrBitBtns(kCol, kRow, ColControl.iids, ColControl.hints);

     CT_CheckBox:
        wrCheckBox(kCol, kRow, ColControl.hints[0]);

     CT_ComboBox:
        wrComboBox(kCol, kRow, ColControl.hints[0]);

  end;
  AutoSizeColumn(kCol);
end;

procedure TStringGridWithControls.DeleteRow(kRow: Integer);
var
  c: TControl;
  i: Integer;
begin
  for i:=self.ColCount-1 downto 0 do
  begin
    c:=ControlOnCell[i,kRow];
    if Assigned(c) then
      c.Free;
  end;
  inherited DeleteRow(kRow);

  ReArrangeControls;
end;

procedure TStringGridWithControls.ClearAll;
var
  i: Integer;
begin
  for i:=RowCount-1 downto FixedRows do
    DeleteRow(i);
end;

procedure TStringGridWithControls.AutoSizeColumns;
var
  i: Integer;
begin
  for i:=0 to ColCount-1 do
    if self.Columns[i] is TGridTextColumn then
      inherited AutoAdjustColumn(i)
    else
      AutoSizeColumn(i);

  ReArrangeControls;
end;

procedure TStringGridWithControls.AutoSizeColumn(aCol: Integer);
var
  maxHeight, maxWidth:integer;
  iRow: Integer;
  ctrl: TControl;
  theCol: TGridColumn;
begin
  maxHeight:=0;
  maxWidth:=0;
  for iRow:=0 to self.RowCount-1 do
  begin
    ctrl:=ControlOnCell[aCol, iRow];
    if Assigned(ctrl) then
    begin
      if ctrl.Width>maxWidth then
        maxWidth:=ctrl.Width;
      if ctrl.Height>maxHeight then
        maxHeight:=ctrl.Height;
    end
    else
      inherited AutoSizeColumn(aCol);

  end;

  theCol := ColumnFromGridColumn(aCol);
  theCol.Width:=maxWidth+1;
end;

initialization

DataModule_SGWC:= TDataModule_SGWC.Create(nil);

finalization

DataModule_SGWC.Free;


end.
