unit Form_ListBoxSelection;

{$I ..\syslib\_sysdef}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ExtCtrls, math, _alloc, _str, _ef, _plut, _eldraw, _stdapp;

type
  TFormListBoxSelection = class(TMasterForm)
    PanelButtons: TPanel;
    BitBtnOk: TBitBtn;
    BitBtnCancel: TBitBtn;
    ButtonInvSelection: TButton;
    PanelSelector: TPanel;
    GroupBoxSelector: TGroupBox;
    ListBoxSelector: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure ListBoxSelectorDblClick(Sender: TObject);
    procedure ListBoxSelectorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure ButtonInvSelectionClick(Sender: TObject);
  private
    { Private declarations }
    apFlags : Integer;
  public
    { Public declarations }
    procedure ResetParams;
    function  ApplyParams(const Params:LongString):Integer;
  end;

function ListBoxSelection(const aCaption  : ShortString;
                          const aTitle    : ShortString;
                          const aItemList : LongString;
                          var   aFocused  : Integer;
                          const aParams   : LongString=''):Cardinal;

function ListBoxMenu(const aCaption  : ShortString;
                     const aTitle    : ShortString;
                     const aItemList : LongString;
                           aFocused  : Integer = 0;
                     const aParams   : LongString=''
                                   ) : Integer;

function ListBoxMultiSelection(const aCaption   : ShortString;
                               const aTitle     : ShortString;
                               const aItemList  : LongString;
                                     aExtended  : Boolean = false;
                                     GetIndex   : Boolean = false;
                                     aFocused   : Integer = 0;
                                     aSelected  : Integer = 0;
                               const aParams    : LongString=''
                                              ) : LongString;

function MultiSelectionIndexesToInt(Items:LongString; DefValue:Integer=0):Integer;

const
  FormListBoxSelection : TFormListBoxSelection = nil;

implementation

{$R *.DFM}

const                 // ApplyParams flags:
 apFormL = $00000001; // Applied Form.Left
 apFormT = $00000002; // Applied Form.Top
 apFormW = $00000004; // Applied Form.Width
 apFormH = $00000008; // Applied Form.Height
 apFonts = $00000010; // Applied Panel.Font

function ListBoxSelection(const aCaption  : ShortString;
                          const aTitle    : ShortString;
                          const aItemList : LongString;
                          var   aFocused  : Integer;
                          const aParams   : LongString=''):Cardinal;
const
 wmin = 200;
 hmin = 200;
 dw1  = 40;
 dw2  = 40;
 dh1  = 110;
 dh2  = 60;
var
 i,j,w,h,l,vs:Integer;
begin
 Result:=mrCancel;
 if CanShowModal(FormListBoxSelection) then
 try
  if (FormListBoxSelection=nil) then begin
   Application.CreateForm(TFormListBoxSelection, FormListBoxSelection);
   FormListBoxSelection.Master:=FormListBoxSelection;
   FormListBoxSelection.Show;
   FormListBoxSelection.Hide;
  end;
  if (FormListBoxSelection<>nil) then
  with FormListBoxSelection do
  try
   ResetParams;
   apFlags:=ApplyParams(aParams);
   vs:=max(GetSystemMetrics(SM_CXVSCROLL),0);
   l:=1; h:=1; j:=0;
   for i:=1 to Length(aItemList) do
   case aItemList[i] of
    CR : begin inc(h); j:=0; end;
    LF : j:=0;
    else begin inc(j); l:=max(l,j); end;
   end;
   w:=wmin;
   w:=max(w,EvalTextSize(Font,aCaption).cx+vs+dw1);
   w:=max(w,EvalTextSize(GroupBoxSelector.Font,aTitle).cx+vs+dw1);
   w:=max(w,EvalTextSize(ListBoxSelector.Font,StringOfChar('M',l)).cx+vs+dw1);
   w:=min(w,Screen.Width-dw2);
   h:=max(hmin,ListBoxSelector.ItemHeight*h+dh1);
   h:=min(h,Screen.Height-dh2);
   if not HasFlags(apFlags,apFormW) then Width:=w;
   if not HasFlags(apFlags,apFormH) then Height:=h;
   if not HasFlags(apFlags,apFormL+apFormT) then LocateFormToCenterOfScreen(FormListBoxSelection);
   Caption:=aCaption;
   SmartUpdate(GroupBoxSelector,aTitle);
   SmartUpdate(ListBoxSelector,aItemList);
   aFocused:=max(0,min(ListBoxSelector.Items.Count-1,aFocused));
   ListBoxSelector.ItemIndex:=aFocused;
   ButtonInvSelection.Visible:=ListBoxSelector.MultiSelect;
   ActiveControl:=ListBoxSelector;
   ValidateFormPosition(FormListBoxSelection);
   Result:=mrVoice(ShowModal);
   aFocused:=ListBoxSelector.ItemIndex;
  finally
   ResetParams;
  end;
 except
  on E:Exception do BugReport(E,nil,'ListBoxSelection');
 end;
end;

function ListBoxMenu(const aCaption  : ShortString;
                     const aTitle    : ShortString;
                     const aItemList : LongString;
                           aFocused  : Integer = 0;
                     const aParams   : LongString=''
                                   ) : Integer;
begin
 if ListBoxSelection(aCaption,aTitle,aItemList,aFocused,aParams)=mrOk then Result:=aFocused else Result:=-1;
end;

function ListBoxMultiSelection(const aCaption   : ShortString;
                               const aTitle     : ShortString;
                               const aItemList  : LongString;
                                     aExtended  : Boolean = false;
                                     GetIndex   : Boolean = false;
                                     aFocused   : Integer = 0;
                                     aSelected  : Integer = 0;
                               const aParams    : LongString=''
                                              ) : LongString;
var i:Integer; p:TText;
begin
 Result:='';
 try
  if (FormListBoxSelection=nil) then begin
   Application.CreateForm(TFormListBoxSelection, FormListBoxSelection);
   FormListBoxSelection.Master:=FormListBoxSelection;
   FormListBoxSelection.Show;
   FormListBoxSelection.Hide;
  end;
  if (FormListBoxSelection<>nil) then
  with FormListBoxSelection do
  try
   p:=NewText;
   try
    ResetParams;
    ListBoxSelector.MultiSelect:=true;
    Caption:=aCaption;
    SmartUpdate(GroupBoxSelector,aTitle);
    SmartUpdate(ListBoxSelector,aItemList);
    ListBoxSelector.ExtendedSelect:=aExtended;
    for i:=0 to ListBoxSelector.Items.Count-1 do
    ListBoxSelector.Selected[i]:=IsBit(aSelected,i);
    if ListBoxSelection(aCaption,aTitle,aItemList,aFocused,aParams)=mrOk then begin
     for i:=0 to ListBoxSelector.Items.Count-1 do
     if ListBoxSelector.Selected[i] then begin
      if GetIndex
      then p.Addln(IntToStr(i))
      else p.Addln(ListBoxSelector.Items[i]);
     end;
     Result:=p.Text;
    end;
   finally
    Kill(p);
   end;
  finally
   ResetParams;
   ListBoxSelector.MultiSelect:=false;
  end;
 except
  on E:Exception do BugReport(E,nil,'ListBoxMultiSelection');
 end;
end;

function MultiSelectionIndexesToInt(Items:LongString; DefValue:Integer=0):Integer;
var p:TText; i,n:Integer;
begin
 Result:=DefValue;
 if Items<>'' then
 try
  Result:=0;
  p:=NewText;
  try
   p.Text:=Items;
   for i:=0 to p.Count-1 do if Str2Int(p[i],n) then Result:=Result or (1 shl n);
  finally
   Kill(p);
  end;
 except
  on E:Exception do BugReport(E,nil,'MultiSelectionIndexesToInt');
 end;
end;

procedure TFormListBoxSelection.FormCreate(Sender: TObject);
begin
 SetStandardFont(Self);
 SetAllButtonsCursor(Self,crHandPoint);
 SmartUpdate(BitBtnOk,mrCaption(mrOk));
 SmartUpdate(BitBtnCancel,mrCaption(mrCancel));
end;

procedure TFormListBoxSelection.ResetParams;
begin
 SetStandardFont(Self);
 PanelSelector.ParentFont:=true;
 ListBoxSelector.ParentFont:=true;
end;

 // @set Panel.Font   Name:PT_Mono\Size:10\Color:Black\Style:[Regular]
 // @set ListBox.Font Name:PT_Mono\Size:10\Color:Black\Style:[Regular]
 // @set Form.Left    400  relative WindowName  ComponentName
 // @set Form.Top     400  relative WindowName  ComponentName
 // @set Form.Width   400
 // @set Form.Height  300
 // @set Form.Width   80  relative Screen
 // @set Form.Height  50  relative Desktop
function TFormListBoxSelection.ApplyParams(const Params:LongString):Integer;
var pars:TText; i,w,h,l,t:Integer; line:ShortString; FontPars:TFontParams; p:TPoint;
begin
 Result:=0;
 if (Self<>nil) then
 if UseEditSettings then
 if (SysUtils.Trim(Params)<>'') then
 try
  pars:=NewText;
  try
   pars.Text:=SysUtils.Trim(Params);
   for i:=0 to pars.Count-1 do begin
    line:=Trim(pars[i]);
    if (StrFetch(line,1)='@') then begin
     if SameText(ExtractWord(1,line,ScanSpaces),'@set') then begin
      if SameText(ExtractWord(2,line,ScanSpaces),'Panel.Font') then begin
       if ReadBufferedFont(FontPars,ExtractWord(3,line,ScanSpaces),true,StandardFont)
       then RestoreFont(PanelSelector.Font,FontPars);
       Result:=Result or apFonts;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'ListBox.Font') then begin
       if ReadBufferedFont(FontPars,ExtractWord(3,line,ScanSpaces),true,StandardFont)
       then RestoreFont(ListBoxSelector.Font,FontPars);
       Result:=Result or apFonts;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'Form.Width') then begin
       if Str2Int(ExtractWord(3,line,ScanSpaces),w) then begin
        if SameText(ExtractWord(4,line,ScanSpaces),'relative')
        then w:=FindRelativeSize(Point(w,0),ExtractWord(5,line,ScanSpaces),ExtractWord(6,line,ScanSpaces)).x;
        Width:=w;
        Result:=Result or apFormW;
       end;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'Form.Height') then begin
       if Str2Int(ExtractWord(3,line,ScanSpaces),h) then begin
        if SameText(ExtractWord(4,line,ScanSpaces),'relative')
        then h:=FindRelativeSize(Point(0,h),ExtractWord(5,line,ScanSpaces),ExtractWord(6,line,ScanSpaces)).y;
        Height:=h;
        Result:=Result or apFormH;
       end;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'Form.Left') then begin
       if Str2Int(ExtractWord(3,line,ScanSpaces),l) then begin
        p:=Point(l,0);
        if SameText(ExtractWord(4,line,ScanSpaces),'relative')
        then p:=FindRelativePos(p,ExtractWord(5,line,ScanSpaces),ExtractWord(6,line,ScanSpaces));
        Left:=p.x;
        Result:=Result or apFormL;
       end;
      end;
      if SameText(ExtractWord(2,line,ScanSpaces),'Form.Top') then begin
       if Str2Int(ExtractWord(3,line,ScanSpaces),t) then begin
        p:=Point(0,t);
        if SameText(ExtractWord(4,line,ScanSpaces),'relative')
        then p:=FindRelativePos(p,ExtractWord(5,line,ScanSpaces),ExtractWord(6,line,ScanSpaces));
        Top:=p.y;
        Result:=Result or apFormT;
       end;
      end;
     end;
    end;
   end;
  finally
   Kill(pars);
  end;
 except
  on E:Exception do BugReport(E,Self,'ApplyParams');
 end;
end;

procedure TFormListBoxSelection.ListBoxSelectorDblClick(Sender: TObject);
begin
 ModalResult:=mrOk;
end;

procedure TFormListBoxSelection.ListBoxSelectorKeyDown(Sender: TObject;
  var Key: Word; Shift: TShiftState);
begin
 case Key of
  VK_RETURN : ModalResult:=mrOk;
  VK_ESCAPE : ModalResult:=mrCancel;
 end;
end;

procedure TFormListBoxSelection.ButtonInvSelectionClick(Sender: TObject);
var i:Integer;
begin
 try
  for i:=0 to ListBoxSelector.Items.Count-1 do
  ListBoxSelector.Selected[i]:=not ListBoxSelector.Selected[i];
 except
  on E:Exception do BugReport(E);
 end;
end;

end.
