{***************************************************************************}
{ TMS IntraWeb Component Pack Pro                                           }
{ for Delphi & C++Builder                                                   }
{                                                                           }
{ written by TMS Software                                                   }
{            copyright © 2002 - 2009                                        }
{            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 IWAdvRadioGroup;

interface

{$I TMSDEFS.INC}

uses
  {$IFDEF LINUX}
  QControls, QGraphics, QForms, QIWPicCntnr,
  {$ELSE}
  Controls, Graphics, Forms, Windows, IWPicCntnr,
  {$ENDIF}
  {$IFDEF DELPHI6_LVL}
  Types,
  {$ENDIF}
  Classes,
  {$IFDEF TMSIW51}
  IWBaseControl, IWColor, IWFont,
  {$ENDIF}
  IWControl, IWTypes, SysUtils, IWCompButton,
  IWCompEdit, IWCompLabel, IWCompCheckbox, IWExtCtrls, IWHTMLTag, IWCompListbox,
  IWTMSBase,IWCompRectangle
  {$IFDEF TMSIW6}
  , IWRenderContext
  {$ENDIF}
  {$IFDEF TMSIW7}
  , IWBaseHTMLControl, IWScriptEvents
  {$ENDIF}
  {$IFDEF TMSIW9}
  ,IWXMLTag
  {$ENDIF}
  ;

type
  TIntList = class(TList)
  private
    FOnChange: TNotifyEvent;
    procedure SetInteger(Index: Integer; Value: Integer);
    function GetInteger(Index: Integer): Integer;
    function GetStrValue: string;
    procedure SetStrValue(const Value: string);
  public
    constructor Create;
    property Items[index: Integer]: Integer read GetInteger write SetInteger;
    default;
    procedure Add(Value: Integer);
    procedure Delete(Index: Integer);
    property StrValue: string read GetStrValue write SetStrValue;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

  TTIWAdvRadioGroup = class(TIWRadioGroup)
  private
    FBackGroundColor: TIWColor;
    FCaption: string;
    FCaptionFont: TIWFont;
    FColumnBorderColor: TIWColor;
    FColumnBorderWidth: integer;
    FColumns: integer;
    FBorderColor: TIWColor;
    FBorderWidht: integer;
    FEnabledItems: TIntList;
    FRadioChecked: string;
    FRadioCheckedDisabled: string;
    FRadioUnchecked: string;
    FRadioUncheckedDisabled: string;
    FValues: TStringList;    
    procedure SetCaptionFont(const Value: TIWFont);
    procedure SetValues(const Value: TStringList);    
    procedure DrawRadio(R:TRect;State,Enabled: Boolean);
  protected
    {$IFDEF TMSIW6}
    procedure IWPaint; override;
    {$ELSE}
    procedure Paint; override;
    {$ENDIF}
    procedure SetValue(const AValue: string); override;    
    procedure RenderRB(Contents: TIWHTMLTagCollection; i: integer);
    procedure RenderRBImage(Contents: TIWHTMLTagCollection; i: integer);
    function ReplaceInput(Index: Integer): string;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    {$IFDEF TMSIW6}
    function RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag; override;
    {$ELSE}
    function RenderHTML: TIWHTMLTag; override;
    {$ENDIF}
    property EnabledItems: TIntList read FEnabledItems write FEnabledItems;
  published
    property BackGroundColor: TIWColor read FBackGroundColor write FBackGroundColor default clNone;
    property Caption: string read FCaption write FCaption;
    property CaptionFont: TIWFont read FCaptionFont write SetCaptionFont;
    property ColumnBorderColor: TIWColor read FColumnBorderColor write FColumnBorderColor default clNone;
    property ColumnBorderWidth: integer read FColumnBorderWidth write FColumnBorderWidth default 0;
    property Columns: integer read FColumns write FColumns default 1;
    property BorderColor: TIWColor read FBorderColor write FBorderColor default clWebSilver;
    property BorderWidth: integer read FBorderWidht write FBorderWidht default 1;
    property Items;
    property Values: TStringList read FValues write SetValues;
    property RadioChecked: string read FRadioChecked write FRadioChecked;
    property RadioCheckedDisabled: string read FRadioCheckedDisabled write FRadioCheckedDisabled;
    property RadioUnchecked: string read FRadioUnchecked write FRadioUnchecked;
    property RadioUncheckedDisabled: string read FRadioUncheckedDisabled write FRadioUncheckedDisabled;
    property Width default 120;
  end;

implementation

uses
  {$IFDEF LINUX}
  QImgList,
  {$ELSE}
  ImgList, ShellAPI, CommCtrl,
  {$ENDIF}
  IWApplication, IWServerControllerBase,IWResourceStrings,
  SWStrings, SWSystem, IWAppForm, IWServer //, IWBaseHTMLControl
  ;

{$IFDEF TMSIW6}
procedure TTIWAdvRadioGroup.IWPaint;
{$ELSE}
procedure TTIWAdvRadioGroup.Paint;
{$ENDIF}
var
  i, colwidth, itemTop, rowCount, itemsPerCol, checkSize, lineHeight, colCount: integer;
  R, Rchk: TRect;
  defaultStr: string;
begin
  Canvas.Font.Assign(Self.Font);
  Canvas.Brush.Color := Color;
  Canvas.Pen.Color := BorderColor;
  Canvas.Pen.Width := BorderWidth;
  R := Rect(2, 2, Width - 2, Height - 2);

  InflateRect(R,-1,-1);
  {$IFNDEF LINUX}
  SetBKMode(Canvas.Handle,TRANSPARENT);

  if (Items.Count = 0) and (Caption = EmptyStr) then
  begin
    defaultStr := 'TIWAdvRadioGroup';
    DrawText(Canvas.Handle,PChar(defaultStr),Length(defaultStr),R,DT_LEFT);
  end
  else
  begin
    DrawText(Canvas.Handle,PChar(Caption),Length(Caption),R,DT_LEFT);

    rowCount := 0;
    colCount := 1;
    checkSize := 18;
    lineHeight := 25;
    itemsPerCol := Items.Count div Columns;
    if (Items.Count mod Columns) > 0 then
      itemsPerCol := itemsPerCol + 1;

    with Canvas do
    begin
      for I := 0 to Items.Count - 1 do
      begin

        if Layout = glVertical then
        begin
          colwidth := Width div Columns * (i div itemsPerCol);

          itemTop := rowCount * checkSize;
          rowCount := rowCount + 1;

          if rowCount = itemsPerCol then
              rowCount := 0;

        end
        else
        begin
          colwidth := Width div Columns * (colCount-1);

          itemTop := rowCount * checkSize;

          if (colCount = Columns) then
          begin
            rowCount := rowCount + 1;
            colCount := 0;
          end;

          colCount := colCount + 1;

        end;

        Rchk := Rect(2+colwidth, itemtop+lineHeight, 2+checkSize+colwidth, itemtop+lineHeight+checkSize);
        DrawRadio(Rchk, StrToBool(iif(i = 0, 'True', 'False')), False);
        TextOut(lineHeight+colwidth, itemtop+lineHeight, Items[i]);

      end;
    end;
  end;
  {$ENDIF}
end;

procedure TTIWAdvRadioGroup.DrawRadio(R:TRect;State,Enabled: Boolean);
  var
    DrawState: Integer;
    DrawRect: TRect;
    CheckSize: integer;
    DRect: TRect;
    Hold: integer;
  begin
        CheckSize := 16;

        DrawState := DFCS_BUTTONRADIO;

        if Enabled then
          DrawState := DrawState or DFCS_INACTIVE;

        if State then
          DrawState := DrawState or DFCS_CHECKED;

        DrawRect.Left := R.Left + (R.Right - R.Left - CheckSize) div 2;
        DrawRect.Top:= R.Top + (R.Bottom - R.Top - CheckSize) div 2;
        DrawRect.Right := DrawRect.Left + CheckSize;
        DrawRect.Bottom := DrawRect.Top + CheckSize;

        if UseRightToLeftAlignment then
        begin
          DRect := DrawRect;

          DrawRect.Left := ClientWidth - DrawRect.Left;
          DrawRect.Right := ClientWidth - DrawRect.Right;

          Hold := DrawRect.Left;
          DrawRect.Left := DrawRect.Right;
          DrawRect.Right := Hold;
        end;

        DrawFrameControl(Canvas.Handle,DrawRect,DFC_BUTTON,DrawState);

        if UseRightToLeftAlignment then
        begin
          DrawRect := DRect;
        end;
  end;


constructor TTIWAdvRadioGroup.Create(AOwner: TComponent);
begin
  inherited;
  BackGroundColor := clNone;
  //Caption := 'Caption';
  FCaptionFont := TIWFont.Create;
  ColumnBorderColor := clNone;
  ColumnBorderWidth := 0;
  Columns := 1;
  BorderWidth := 1;
  FEnabledItems := TIntList.Create;
  FValues := TStringList.Create;
  Width := 120;
end;

destructor TTIWAdvRadioGroup.Destroy;
begin
  FEnabledItems.Free;
  FCaptionFont.Free;
  FValues.Free;
  inherited;
end;


procedure TTIWAdvRadioGroup.RenderRB(Contents: TIWHTMLTagCollection; i: Integer);
begin

   with Contents.AddTag('INPUT') do
    begin
      AddStringParam('TYPE', 'RADIO');
      Add(iif(ItemIndex = i, ' CHECKED'));
      AddStringParam('NAME', HTMLName + 'CHK');
      AddStringParam('id', HTMLName + '_CHK_'+IntToStr(i+1));
      AddStringParam('VALUE', IntToStr(i));

      Add(iif((not Enabled) or (not Editable) or (EnabledItems.Items[i] = 0) , 'DISABLED'));
 
      AddStringParam('onClick', HTMLName + 'RadioClick(' + IntToStr(i) + ',true);');
    end;

    with Contents.AddTag('SPAN') do
    begin
      if Enabled and Editable and (EnabledItems.Items[i] = 1) then
      begin
        AddStringParam('OnClick', HTMLName + 'RadioClick(' + IntToStr(i) + ',false);');
      end;
      //Contents.AddText(Items.Strings[i]);
      Contents.AddText(ReplaceInput(i));
    end;
end;

procedure TTIWAdvRadioGroup.RenderRBImage(Contents: TIWHTMLTagCollection; i: Integer);
begin

  with Contents.AddTag('IMG') do
  begin
//    Add(iif((not Enabled) or (not Editable) or (EnabledItems.Items[i] = 0) , 'DISABLED'));

    if (not Enabled) or (not Editable) or (EnabledItems.Items[i] = 0) then
      Add(iif(ItemIndex = i, 'SRC=' + RadioCheckedDisabled, 'SRC=' + RadioUncheckedDisabled))
    else
      Add(iif(ItemIndex = i, 'SRC=' + RadioChecked, 'SRC=' + RadioUnchecked));

    AddStringParam('NAME', HTMLName + '_CHK');
    AddStringParam('id', HTMLName + '_CHK_'+IntToStr(i+1));

    if Enabled and Editable and (EnabledItems.Items[i] = 1) then
      AddStringParam('onClick', HTMLName + 'RadioClick(' + IntToStr(i) + ');');

  end;

    with Contents.AddTag('SPAN') do
    begin
      if Enabled and Editable and (EnabledItems.Items[i] = 1) then
      begin
        AddStringParam('onClick', HTMLName + 'RadioClick(' + IntToStr(i) + ');');
      end;
      //Contents.AddText(Items.Strings[i]);
      Contents.AddText(ReplaceInput(i));
    end;
end;

function TTIWAdvRadioGroup.ReplaceInput(Index: Integer): string;
var
  itemText, itemValue: string;
begin
  itemText := Items.Strings[Index];

  if (pos('<INPUT', itemText) > 0) then
  begin

    if pos('width=', itemText) > 0 then
    begin
      itemText := StringReplace(itemText, 'width="', 'style="width:', [rfIgnoreCase]);

      if pos('" color=', itemText) > 0 then
        itemText := StringReplace(itemText, '" color="', ';background-color:', [rfIgnoreCase]);
    end
    else if pos('color=', itemText) > 0 then
        itemText := StringReplace(itemText, 'color="', 'background-color:', [rfIgnoreCase]);

    if Assigned(Values) then
    begin
      if Values.Count > 0 then
        itemValue := StringReplace(Values.Strings[Index], '"', '''', [rfReplaceAll])
      else
        itemValue := EmptyStr;
    end;

    itemText := StringReplace(itemText, '<INPUT', '<INPUT VALUE="' + itemValue
      + '" ONBLUR="' + HTMLName + 'SetCustomValues()" TYPE="TEXT" ID="' + HTMLName + 'VAL' + IntToStr(Index) + '"', [rfIgnoreCase]);
  end;

  Result := itemText;
end;

procedure TTIWAdvRadioGroup.SetCaptionFont(const Value: TIWFont);
begin
  FCaptionFont.Assign(Value);
  Changed;
end;

procedure TTIWAdvRadioGroup.SetValue(const AValue: string);
var
  vp: integer;
  VarVal, su: string;
begin
  //OutputDebugString(pchar('SetValue: ' + AValue + '.'));

  if AValue <> EmptyStr then
  begin

    if pos('|', AValue) > 0 then
    begin
      VarVal := AValue;

      //Retrieve CheckBox Indexes
      vp := pos('|', VarVal);
      if vp > 0 then
      begin
        su := copy(VarVal, 1, vp - 1);
        Delete(VarVal, 1, vp);

        if Length(su) > 0 then
          ItemIndex := StrToInt(su);
      end;

      //Retrieve custom values
      vp := pos('^', VarVal);
      if vp > 0 then
      begin

        Values.Clear();
        VarVal := VarVal + '^';

        while pos('^', VarVal) > 0 do
        begin
          vp := pos('^', VarVal);
          su := copy(VarVal, 1, vp - 1);
          Delete(VarVal, 1, vp);

//         OutputDebugString(pchar('add value: ' + su));
          Values.Add(su);
        end;

      end;

    end
    else
    begin
  //    inherited;
      ItemIndex := StrToInt(AValue);
    end;
  end;
end;

procedure TTIWAdvRadioGroup.SetValues(const Value: TStringList);
begin
  FValues.Assign(Value);
end;

{$IFDEF TMSIW6}
function TTIWAdvRadioGroup.RenderHTML(AContext: TIWBaseComponentContext): TIWHTMLTag;
{$ELSE}
function TTIWAdvRadioGroup.RenderHTML: TIWHTMLTag;
{$ENDIF}
var
  i, j: Integer;
  columnItem, itemCount, valueCount, itemsPerCol: integer;
  tempCount, script, colBorder, startupscript: string;
begin

Result := TIWHTMLTag.CreateTag('DIV'); try

  with Result.Contents.AddTag('FIELDSET') do
  begin

    AddStringParam('style','border:' + IntToStr(BorderWidth)
    + 'px solid ' + ColorToRGBString(BorderColor) + ';width:'
    + IntToStr(Width) + 'px;height:auto;'
    + iif(BackGroundColor <> clNone, 'background-color:' + ColorToRGBString(BackGroundColor) + ';', ''));

    if Caption <> EmptyStr then
    begin
      with Contents.AddTag('LEGEND') do
      begin
         AddStringParam('style',
         'font-family:' + iif(CaptionFont.FontFamily <> EmptyStr, CaptionFont.FontFamily, CaptionFont.FontName + ';')
         + iif(CaptionFont.Color <> clNone, 'color:' + ColorToRGBString(CaptionFont.Color) + ';', '')
         + 'font-size:' + IntToStr(CaptionFont.Size) + 'pt;'
         + iif(fsBold in CaptionFont.Style, 'font-weight:bold;', 'font-weight:normal;')
         + iif(fsItalic in CaptionFont.Style, 'font-style:italic;', 'font-style:normal;')
         );
         Contents.AddText(Caption);
      end;
    end;

    columnItem := 0;
    Contents.AddText('<TABLE cellspacing=0 cellpadding=4 style="font-size:' + IntToStr(Font.Size) + 'pt;'
      + iif(fsBold in Font.Style, 'font-weight:bold;', '')
      + iif(fsItalic in Font.Style, 'font-style:italic;', '')
      + 'color:' + ColorToRGBString(Font.Color) + ';width:100%;height:auto;">');   

    if Layout = glHorizontal then
    begin

      for i := 0 to Items.Count - 1 do
      begin

        if (columnItem = 0) then
            Contents.AddText('<TR>');

        if (columnItem = Columns - 1) or (ColumnBorderColor = clNone) or (ColumnBorderWidth = 0) then
          colBorder := EmptyStr
        else
          colBorder := 'border-right:' + IntToStr(ColumnBorderWidth)
            + 'px solid ' + ColorToRGBString(ColumnBorderColor) + ';';

        Contents.AddText('<TD style="' + colBorder + 'vertical-align:top;width:' + IntToStr(100 div Columns) + '%">');

        if (RadioChecked = EmptyStr) or (RadioUnchecked = EmptyStr)
          or (RadioCheckedDisabled = EmptyStr) or (RadioUncheckedDisabled = EmptyStr) then
          RenderRB(Contents,i)
        else
          RenderRBImage(Contents,i);

        Contents.AddText('</TD>');
        columnItem := columnItem + 1;

        if (columnItem = Columns) then
        begin
          Contents.AddText('</TR>');
          columnItem := 0;
        end;

      end;
    end
    else
    begin

      tempCount := FloatToStr(Items.count div Columns);
      itemCount := StrToInt(tempCount);
      itemsPerCol := (Items.count mod Columns);
      if itemsPerCol > 0 then
        itemCount := itemCount + 1;

      for j := 0 to itemCount - 1 do                             
      begin

        for i := 0 to Columns - 1 do
        begin

          if (columnItem = 0) then
            Contents.AddText('<TR>');

          if (columnItem = Columns - 1) or (ColumnBorderColor = clNone) or (ColumnBorderWidth = 0) then
            colBorder := EmptyStr
          else
            colBorder := 'border-right:' + IntToStr(ColumnBorderWidth)
              + 'px solid ' + ColorToRGBString(ColumnBorderColor) + ';';

          Contents.AddText('<TD style="' + colBorder + 'vertical-align:top;width:' + IntToStr(100 div Columns) + '%">');

          if (RadioChecked = EmptyStr) or (RadioUnchecked = EmptyStr)
            or (RadioCheckedDisabled = EmptyStr) or (RadioUncheckedDisabled = EmptyStr) then
          begin
            if i = 0 then
              RenderRB(Contents, j)
            else if Items.Count > j+(i*itemCount) then
              RenderRB(Contents, j+(i*itemCount));
          end
          else
          begin
            if i = 0 then
              RenderRBImage(Contents, j)
            else if Items.Count > j+(i*itemCount) then
              RenderRBImage(Contents, j+(i*itemCount));
          end;

          Contents.AddText('</TD>');
          columnItem := columnItem + 1;

          if (columnItem = Columns) then
          begin
            Contents.AddText('</TR>');
            columnItem := 0;
          end;

        end

      end;
        
    end;

    Contents.AddText('</TABLE>');

  end;
  except FreeAndNil(Result); raise; end;

  if Values.Count > 0 then
    valueCount := Values.Count
  else
    valueCount := Items.Count;  

  //add hidden input
  {
  with Result.Contents.AddTag('INPUT') do
  begin
//    AddStringParam('TYPE', 'hidden');
    AddStringParam('TYPE', 'text');
    AddStringParam('NAME', HTMLName);
    AddStringParam('ID', HTMLName + '_INPUT');
    AddStringParam('VALUE', IntToStr(ItemIndex));
  end;
  }

  if (RadioChecked = EmptyStr) or (RadioUnchecked = EmptyStr)
  or (RadioCheckedDisabled = EmptyStr) or (RadioUncheckedDisabled = EmptyStr) then
  begin
    script := script
     + '<script>'#13
     + 'var ' + HTMLName + 'Index = ' + IntToStr(ItemIndex) + ';'#13
     + 'function ' + HTMLName + 'RadioClick(index,chk)'#13
     + '{'#13
     + '  var ctrl = FindElem(''' + HTMLName + '_CHK_''+(index+1));'#13
     + '  if (!chk) {'#13
//     + '    ctrl.checked = !ctrl.checked;'#13
     + '    ctrl.checked = true;'#13
     + '  }'#13
     + ''#13
     + '  ' + HTMLName + 'Index = index;'#13
//     + '  var hi = FindElem(''' + HTMLName + '_INPUT'');'#13
     + '  var hi = document.getElementsByName(''' + HTMLName + '_INPUT'');'#13
     + '  hi[0].value = ' + HTMLName +'Index;'#13
//     + '  hi.value = ' + HTMLName +'Index;'#13
     + '}'#13
     + '</script>'#13
     ;
  end
  else
  begin
    script := script
     + '<script>'#13
     + 'var ' + HTMLName + 'Index = ' + IntToStr(ItemIndex) + ';'#13
     + 'function ' + HTMLName + 'RadioClick(index)'#13
     + '{'#13
     + ' if (index != ' + HTMLName + 'Index)'#13
     + ' {'#13
     + '  var ctrl = FindElem(''' + HTMLName +'_CHK_''+(index+1));'#13
     + '  ctrl.src = ctrl.src.replace("' + RadioUnChecked + '", "' + RadioChecked + '");'#13
     + '  if (' + HTMLName + 'Index > -1)'#13
     + '  {'#13
     + '    ctrl = FindElem(''' + HTMLName +'_CHK_''+(' + HTMLName + 'Index+1));'#13
     + '    ctrl.src = ctrl.src.replace("' + RadioChecked + '", "' + RadioUnChecked + '");'#13
     + '  }'#13
     + ''#13
     + '  ' + HTMLName + 'Index = index;'#13
     + '  var hi = FindElem(''' + HTMLName + '_INPUT'');'#13
     + '  var hi = document.getElementsByName(''' + HTMLName + '_INPUT'');'#13
     + '  hi[0].value = ' + HTMLName +'Index;'#13
//     + '  hi.value = ' + HTMLName +'Index;'#13
     + ' }'#13
     + '}'#13
     + '</script>'#13
     ;
  end;

  script := script
   + '<script>'
   + 'function ' + HTMLNAME + 'SetCustomValues() '#13
   + '{'#13
   + '  var hi = document.getElementsByName(''' + HTMLName + '_INPUT'');'#13
//   + '  var hi = FindElem(''' + HTMLName + '_INPUT'');'#13

   + '  if (hi[0].value.indexOf("|") > 0)'#13
   + '  {'#13
   + '    var shi = hi[0].value.split("|");'#13
   + '    hi[0].value = shi[0];'#13
   + '  }'#13

   + '  hi[0].value += "|";'#13

   + '  for (i = 0; i < ' + IntToStr(valueCount) + '; i++)'#13
   + '  {'#13
   + '    ctrl = FindElem("'+ HTMLName +'VAL" + i);'#13
   + '    if (ctrl)'#13
   + '      hi[0].value += ctrl.value;'#13
   + '    if (i < ' + IntToStr(valueCount) + ' - 1)'#13
   + '      hi[0].value += "^";'#13
   + '  }'#13
   + '}'#13
   + '</script>'
   ;

   startupscript := HTMLName + 'SetCustomValues();';

  {$IFDEF TMSIW6}
  TIWComponent40Context(AContext).AddToInitProc(startupscript + EOL);
  {$ELSE}
  TIWAppForm(Form).AddToInitProc(startupscript + EOL);
  {$ENDIF}

  Result.Contents.AddText(script);

end;


{ TIntList }

constructor TIntList.Create;
begin
  inherited Create;
end;

procedure TIntList.SetInteger(Index: Integer; Value: Integer);
begin
  if Index < 0 then
    Exit;

  while Index >= Count do
  begin
    Add(1);
  end;

  inherited Items[Index] := Pointer(Value);
  if Assigned(OnChange) then
    OnChange(Self);
end;

function TIntList.GetInteger(Index: Integer): Integer;
begin
  Result := 0;
  if Index < 0 then
    Exit;

  while Index >= Count do
  begin
    Add(1);
  end;

  Result := Integer(inherited Items[Index]);
end;

procedure TIntList.Add(Value: Integer);
begin
  inherited Add(Pointer(Value));
  if Assigned(OnChange) then
    OnChange(Self);
end;

procedure TIntList.Delete(Index: Integer);
begin
  inherited Delete(Index);
  if Assigned(OnChange) then
    OnChange(Self);
end;

function TIntList.GetStrValue: string;
var
  i: integer;
begin
  for i := 1 to Count do
    if i = 1 then
      Result := IntToStr(Items[i - 1])
    else
      Result := Result + ',' + IntToStr(Items[i - 1]);
end;

procedure TIntList.SetStrValue(const Value: string);
var
  sl: TStringList;
  i: Integer;
begin
  sl := TStringList.Create;
  sl.CommaText := Value;
  Clear;
  for i := 1 to sl.Count do
    Add(StrToInt(sl.Strings[i - 1]));
  sl.Free;
end;

end.
