PROGRAM ListDlg;
{ This code demonstrates how to display different dialogs in one dialog. You can also use
  this code to build a dialog with register cards.
  (c) 1997 U. Conrad, uconrad1@gwdg.de }

{$R MULTIDLG.RES }  { located at the end .. use XX34 to decode }
USES OWindows,ODialogs,Strings,Objects,WinProcs,WinTypes;

CONST idd_ListBox         = 301;
      idd_Anchor          = 302;

CONST wm_MyFocus          = wm_User + 1000;

TYPE PHwnd = ^HWnd;
     PAtom = ^TAtom;

TYPE TDemoApp=OBJECT(TApplication)
       PROCEDURE InitMainWindow; virtual;
     END;

TYPE DlgInfoStruct = RECORD                 { contains informations about a sub dialog }
       szListText  : array[0..50] of char;  { title which should be displayed in the list box }
       ResName     : array[0..50] of char;  { ID of the sub dialog }
       fPresent    : boolean;               { loaded or not, that's the question }
       pCtrlHndls  : THandle;               { handle for hwnd of controls }
       pCtrlTexts  : THandle;               { handle for atoms of controls }
       CntCntrls   : byte;                  { number of control elements in this dialog }
     END;

TYPE PDemoDlg = ^TDemoDlg;
     TDemoDlg = OBJECT(TDialog)
       diDlgs         : array[0..2] of DlgInfoStruct;
       iCurDlg        : integer;
       CONSTRUCTOR Init(AParent : PWindowsObject;AName : PChar);
       PROCEDURE SetupWindow; virtual;
       PROCEDURE MyFocus(var Msg : TMessage); virtual wm_First + wm_MyFocus;
       PROCEDURE ListBox(var Msg : TMessage); virtual id_First + idd_ListBox;
       PROCEDURE ChildDialogVisible(iDialog : integer;State : boolean);
       PROCEDURE LoadAndCreateControls(iDialog : integer);
       PROCEDURE WMDestroy(var Msg : TMessage); virtual wm_First + wm_Destroy;
       PROCEDURE Ok(var Msg : TMessage); virtual id_First + id_ok;
       DESTRUCTOR Done; virtual;
     END;

{ ================== Methods of the program dialog object ===================== }
CONSTRUCTOR TDemoDlg.Init(AParent : PWindowsObject;AName : PChar);
VAR b          : byte;
BEGIN
  inherited Init(AParent,AName);
  { Initializing sub dialog informations }
  FillChar(diDlgs[0],SizeOf(diDlgs[0]),#0);
  StrCopy(diDlgs[0].szListText,'Identification');
  StrCopy(diDlgs[0].ResName,'DLG_IDEN');
  FillChar(diDlgs[1],SizeOf(diDlgs[1]),#0);
  StrCopy(diDlgs[1].szListText,'Preferences');
  StrCopy(diDlgs[1].ResName,'DLG_PREF');
  FillChar(diDlgs[2],SizeOf(diDlgs[2]),#0);
  StrCopy(diDlgs[2].szListText,'Wishes');
  StrCopy(diDlgs[2].ResName,'DLG_WISH');
  iCurDlg:=-1;
  { no dialog displayed 'til yet }
END;

PROCEDURE TDemoDlg.SetupWindow;
VAR i            : integer;
BEGIN
  inherited SetupWindow;
  FOR i:=0 TO 2 DO BEGIN
    LoadAndCreateControls(i);     { load control elements of one child dialog }
    ChildDialogVisible(i,false);  { and hide them, they will be visible after selecting one from the listbox }
    SendDlgItemMessage(HWindow,idd_ListBox,lb_AddString,0,LongInt(@diDlgs[i].szListText));
  END;
  { If you want to init the control elements do it here }
  SetDlgItemText(HWindow,1000,'My');
  SetDlgItemText(HWindow,1001,'Name');
  { fill list box with dialog titles }
  SendDlgItemMessage(HWindow,idd_ListBox,lb_SetCurSel,0,0);
  { select first dialog and make it visible }
  PostMessage(HWindow,wm_command,idd_ListBox,MakeLong(GetDlgItem(HWindow,idd_ListBox),lbn_SelChange));
  { pretend a user's selection in the list box }
  PostMessage(HWindow,wm_MyFocus,0,0);
END;

PROCEDURE TDemoDlg.ListBox(var Msg : TMessage);
VAR lCurSel        : integer;
BEGIN
  IF Msg.lParamHi=lbn_SelChange THEN BEGIN    { new child dialog selected }
    lCurSel:=SendDlgItemMessage(HWindow,idd_ListBox,lb_GetCurSel,0,0);
    IF lCurSel=-1 THEN Exit;
    IF lCurSel<>iCurDlg THEN BEGIN            { a different child dialog was selected }
      ChildDialogVisible(iCurDlg,false);      { hide actual child dialog }
      iCurDlg:=lCurSel;                       { new actual child dialog }
      ChildDialogVisible(iCurDlg,true);       { show new actual child dialog }
    END;
  END;
  Msg.Receiver:=0;
END;

PROCEDURE TDemoDlg.MyFocus(var Msg : TMessage);
BEGIN
  SetFocus(GetDlgItem(HWindow,idd_ListBox));
  { will give the focus back to the list box }
  Msg.Receiver:=0;
END;

PROCEDURE TDemoDlg.LoadAndCreateControls(iDialog : integer);
{ This function will load the resource of a child dialog and put its control elements
  to the dialog }
VAR hDlgFont          : HFont;
    hDlgRes           : THandle;
    hDlgResMem        : THandle;
    lpDlgRes          : PChar;
    style             : longint;
    bNumOfCtrls       : byte;
    bCurCtrl          : byte;
    xOffset, yOffset  : integer;
    hAnchor           : HWnd;
    rc, trc           : TRect;
    pt                : TPoint;
    wID               : word;
    classname         : PChar;
    phw               : PHWnd;
    PTmp              : PAtom;
BEGIN
  hDlgFont:=SendMessage(HWindow,wm_GetFont,0,0);
  { First we need to know which font is used in the dialog so we can set the font of
    the child controls. }
  hDlgRes:=FindResource(hInstance,diDlgs[iDialog].ResName,rt_dialog);
  hDlgResMem:=LoadResource(hInstance,hDlgRes);
  { load the resource }
  lpDlgRes:=LockResource(hDlgResMem);
  { get a pointer to the resource }
  style:=PLongint(lpDlgRes)^;
  { get the dialog's style. This and the following operations get their information from
    the dialog header. It's structur is described in the help under the topic " dialog box header" }
  lpDlgRes:=lpDlgRes+SizeOf(Style);    { increment pointer }
  bNumOfCtrls:=PByte(lpDlgRes)^;       { get number of controls }
  diDlgs[iDialog].CntCntrls:=bNumOfCtrls;
  lpDlgRes:=lpDlgRes+SizeOf(byte);     { increment pointer }
  lpDlgRes:=lpDlgRes+(4*SizeOf(word)); { ingnore  x, y, cx, and cy of dialog }
  IF PByte(lpDlgRes)^=$FF THEN  lpDlgRes:=lpDlgRes+3
    ELSE WHILE lpDlgRes^<>#0 DO lpDlgRes:=lpDlgRes+1;                { ignore menu }
  lpDlgRes:=lpDlgRes+1;
  WHILE lpDlgRes^<>#0 DO lpDlgRes:=lpDlgRes+1;
  lpDlgRes:=lpDlgRes+1;                { pass the class name }
  WHILE lpDlgRes^<>#0 DO lpDlgRes:=lpDlgRes+1;
  lpDlgRes:=lpDlgRes+1;                { pass the caption }
  IF style and ds_SetFont<>0 THEN BEGIN { if ds_SetFont is set we have to skip font information }
    lpDlgRes:=lpDlgRes+SizeOf(word);   { pass point size }
    WHILE lpDlgRes^<>#0 DO lpDlgRes:=lpDlgRes+1;
    lpDlgRes:=lpDlgRes+1;              { pass the font name }
  END;
  diDlgs[iDialog].pCtrlHndls:=LocalAlloc(lptr,SizeOf(HWnd)+SizeOf(HWnd)*bNumOfCtrls);
  { get memory for control's window handles }
  diDlgs[iDialog].pCtrlTexts:=LocalAlloc(lptr,SizeOf(TAtom)*bNumOfCtrls);
  { get memory for control's atom handles }
  pTmp:=PAtom(LocalLock(diDlgs[iDialog].pCtrlTexts));
  FOR bCurCtrl:=1 TO bNumOfCtrls DO BEGIN       { initialize atoms }
    pTmp^:=AddAtom('');
    pTmp:=PAtom(Pchar(PTmp)+SizeOf(TAtom));
  END;
  LocalUnlock(diDlgs[iDialog].pCtrlTexts);
  hAnchor:=GetDlgItem(HWindow,idd_Anchor);
  GetWindowRect (hAnchor,rc);
  { get position of anchor }
  pt.x:=rc.left;
  pt.y:=rc.top;
  ScreenToClient(HWindow,pt);
  rc.left:=pt.x;
  rc.top:=pt.y;
  pt.x:=rc.right;
  pt.y:=rc.bottom;
  ScreenToClient(HWindow,pt);
  rc.right:=pt.x;
  rc.bottom:=pt.y;
  xOffset:=rc.right;
  yOffset:=rc.top;
  { get offset for control elements in client coordinates }
  phw:=PHwnd(LocalLock(diDlgs[iDialog].pCtrlHndls));
  FOR bCurCtrl:=1 TO bNumOfCtrls DO BEGIN    { start creating controls }
    WITH trc DO BEGIN
      left:=PInteger(lpDlgRes)^;
      lpDlgRes:=lpDlgRes+SizeOf(integer);        { increment pointer }
      top:=PInteger(lpDlgRes)^;
      lpDlgRes:=lpDlgRes+SizeOf(integer);        { increment pointer }
      right:=PInteger(lpDlgRes)^;
      lpDlgRes:=lpDlgRes+SizeOf(integer);        { increment pointer }
      bottom:=PInteger(lpDlgRes)^;
      lpDlgRes:=lpDlgRes+SizeOf(integer);        { increment pointer }
    END;
    CopyRect(rc,trc);                        { get the control's coordinates }
    MapDialogRect(HWindow,rc);               { convert to pixels }
    rc.left:=rc.left+xOffset;                { add offset }
    rc.top:=rc.top+yOffset;
    wID:=PWord(lpDlgRes)^;                   { get the control's ID }
    lpDlgRes:=lpDlgRes+SizeOf(word);         { increment pointer }
    style:=PLongint(lpDlgRes)^;              { get the control's styles }
    lpDlgRes:=lpDlgRes+SizeOf(longint);      { increment pointer }
    CASE PByte(lpDlgRes)^ OF
      $80   : classname:='button';
      $81   : classname:='edit';
      $82   : classname:='static';
      $83   : classname:='listbox';
      $84   : classname:='scrollbar';
      $85   : classname:='combobox';
      ELSE BEGIN { get the special class name }
        classname:=lpDlgRes;
        WHILE lpDlgRes^<>#0 DO lpDlgRes:=lpDlgRes+1;
      END;
    END;
    lpDlgRes:=lpDlgRes+1;
    phw^:=CreateWindow(Classname,lpDlgRes,style,rc.left,rc.top,rc.right,rc.bottom,HWindow,wID,hInstance,nil);
    { create the control element }
    IF hDlgFont<>0 THEN SendMessage(pHW^,wm_SetFont,hDlgFont,0); { give the control the right font }
    WHILE lpDlgRes^<>#0 DO lpDlgRes:=lpDlgRes+1;                 { skip window text }
    lpDlgRes:=lpDlgRes+1;                                        { skip null terminator }
    lpDlgRes:=lpDlgRes+1;                                        { skip second null terminator }
    phw:=PHWnd(PChar(phw)+SizeOf(HWnd));
  END;
  LocalUnlock(diDlgs[iDialog].pCtrlHndls);
  UnlockResource(hDlgResMem);
  FreeResource(hDlgResMem);
  { the resource isn't needed any more, so free it }
  diDlgs[iDialog].fPresent:=true;
END;

PROCEDURE TDemoDlg.ChildDialogVisible(iDialog : integer;State : boolean);
VAR hCtl         : PHwnd;
    i            : integer;
    pa           : PAtom;
    buf          : array[0..80] of char;
    dwCtlCode    : longint;
    IgnoreText   : boolean;
    lStyle       : longint;
BEGIN
  IF iDialog<0 THEN Exit;
  hCtl:=PHwnd(LocalLock(diDlgs[iDialog].pCtrlHndls));
  pa:=PAtom(LocalLock(diDlgs[iDialog].pCtrlTexts));
  IF State THEN BEGIN      { show the dialog }
    FOR i:=1 TO diDlgs[iDialog].CntCntrls DO BEGIN
      IF pa^<>0 THEN BEGIN
        GetAtomName(pa^,buf,SizeOf(buf));
        SetWindowText(hCtl^,buf);
        DeleteAtom(pa^);
      END;
      ShowWindow(hCtl^,sw_Show);
      pa:=PAtom(PChar(pa)+SizeOf(TAtom));
      hCtl:=PHWnd(Pchar(hCtl)+SizeOf(HWnd));
    END;
  END
  ELSE BEGIN               { hide the dialog }
    FOR i:=1 TO diDlgs[iDialog].CntCntrls DO BEGIN
      ShowWindow(hCtl^,sw_Hide);
      dwCtlCode:=SendMessage(hCtl^,wm_GetDlgCode,0,0);
      ignoreText:=false;
      IF dwCtlCode and dlgc_WantChars<>0 THEN BEGIN
        pa^:=0;
        IgnoreText:=true;
      END;
      IF dwCtlCode and dlgc_Static<>0 THEN BEGIN
        lStyle:=GetWindowLong(hCtl^,gwl_Style);
        IF lStyle and ss_NoPrefix<>0 THEN BEGIN
          pa^:=0;
          IgnoreText:=true;
        END;
      END;
      IF not IgnoreText THEN BEGIN
        GetWindowText(hCtl^,buf,SizeOf(buf));
        pa^:=AddAtom(buf);
        SetWindowText(hCtl^,'');
      END;
      pa:=PAtom(PChar(pa)+SizeOf(TAtom));
      hCtl:=PHWnd(Pchar(hCtl)+SizeOf(HWnd));
    END;
  END;
  LocalUnlock(diDlgs[iDialog].pCtrlTexts);
  LocalUnlock(diDlgs[iDialog].pCtrlHndls);
END;

PROCEDURE TDemoDlg.Ok(var Msg : TMessage);
VAR buf          : array[0..255] of char;
BEGIN
  GetDlgItemText(HWindow,1000,buf,SizeOf(buf)-1);
  { here you can receive the state of all dialog control elements, for example the "First" edit }
  EndDlg(id_ok);       { finally close this dialog }
END;

PROCEDURE TDemoDlg.WMDestroy(var Msg : TMessage);
VAR i        : integer;
BEGIN
  FOR i:=0 TO 2 DO IF diDlgs[i].fPresent THEN BEGIN { free handles of controls }
    LocalFree(diDlgs[i].pCtrlHndls);
    LocalFree(diDlgs[i].pCtrlTexts);
  END;
  inherited WMDestroy(Msg);
END;

DESTRUCTOR TDemoDlg.Done;
BEGIN
  inherited done;
END;

{ ================== Methods of the application ===================== }
PROCEDURE TDemoApp.InitMainWindow;
BEGIN
  MainWindow:=New(PDemoDlg,Init(nil,'DLG_Main'));
  { will create a window from dialog template DLG_Main }
END;

{ *****************   Program ******************* }

VAR DemoApp  : TDemoApp;

BEGIN
  DemoApp.Init('DemoApp');
  DemoApp.Run;
  DemoApp.Done;
END.

END.

{ the following contains additional files that should be included with this
  file.  To extract, you need XX3402 available with the SWAG distribution.

  1.     Cut the text below out, and save to a file  ..  filename.xx
  2.     Use XX3402  :   xx3402 d filename.xx
  3.     The decoded file should be created in the same directory.
  4.     If the file is a archive file, use the proper archive program to
         extract the members.

{ ------------------            CUT              ----------------------}


*XX3402-000956-290697--72--85-61452----MULTIDLG.RES--1-OF--1
zkI+F2l5LoZ2FIs+A-0w++++E+0+U+V4++Y+YU-N++++++U+HJAUIq3iQm-HNL7dNU+3++2+
5U+8+Cs1+++0I66aFaZmQrE+++I+1++d++w+u+C++63EUE++BE+-+-s+0k1j+k+++Z007YlV
QrE++1I+1+-I++w+uEC++63EUE++-E+S+-s+0E1k+k+++Z007Y3YN57ZQrAu+++3+0U+V++D
+Cc1U+0-I62+++I+C+02++w+v+C++63EUE++-E-6+6E+1k1h+s++UJ0-++1z-E-2H2RTHI37
HU+k26o+++1++AWE-46+9+1Z+4w+++-BRKloOG-YOK3gPqQUN4JhPqtnR57VR4ZjPU+6+2pH
63BVPbAUIqJmOKM+0k-7+16+1U+-++2++J0+Hog+++g+KU+m++s++U++++3EU2BVPaBZP+++
0k+7+1Y+0++i+E+++Z007YFdMKljNk++0k+J+16+9++h+E2-cJ01++1z-E-2H2RTI373FU+k
2+w-++-++60+0YM+0E0G+3U+++++0+-BIm-HMKtn63BZQaZa++A+-+-2+2E+oEQ5++3EU2Jb
NrA+++Y+2U+t++g+oUQ7++7EU0NHMr7VPK7gNKE+++Y+5k+t++g+okQ7++-EU0NDRaJm9KJV
QrY+++Y+9++n++g+p+Q7++-EU0N6ML7Y627jOKlZN+++0E+t+0s+0k1J-kY++30+7Z7VRk++
H++2+2++Ak1E-kQ++p0+Ea3b++-F+-++BE+9+BM50E+0I6+aI43kNL6++32+5++r++g+pkQ7
++-EU3+aP43nR4ZX++-F+0U+Bk+9+BU50E++I6+aEqljR4U++2k+DU-+++s+qEQ+++BEU0N2
OKtbQk++zkI+F2l5LpR7IoU+A-1+++++E+0+U+N4++Y+YU-M++++++U+HJAUIq3iQm-HNL7d
NU+5++E+6U+C+9c9+k+-I6+aH4xqNE++-k+H+2w+1U0s0kA++J0+IqJiQqIUPqMU7Z-pQb-j
QqI+++Q+6U+x++s+ikg1++3EU0N4RKlaOKlgPKJiR+++-k+l+2o+1U0t0kA++J0+FaJZP4Zi
Nm-jNW+aJqxmR4U+++Q+FU+W++g+j+g1++3EU0NDR4VZQXc++0c+F+-a+-2+jEi++63EUE++
zkw+zk2+A-lE++++2++3++4++2FAFpx7F2JC+-++-E+0U+-2H2RTHI37HU+E++I++s++F2l5
Lp-GFIM+2++3++G++2FAFpxLGJB6++++++++++++++++++++++++
***** END OF BLOCK 1 *****

