home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / vos2-121.zip / v / srcos2 / vcmdprnt.cpp < prev    next >
C/C++ Source or Header  |  1999-02-20  |  35KB  |  947 lines

  1. //===============================================================
  2. // vcmdprnt.cxx - vCmdParent Class - Windows
  3. //
  4. // Copyright (C) 1995,1996,1997,1998  Bruce E. Wampler
  5. //
  6. // This file is part of the V C++ GUI Framework, and is covered
  7. // under the terms of the GNU Library General Public License,
  8. // Version 2. This library has NO WARRANTY. See the source file
  9. // vapp.cxx for more complete information about license terms.
  10. //===============================================================
  11. #include <v/vos2.h>             // for OS/22 stuff
  12. #include <v/vapp.h>             // need the codepage
  13. #include <v/vcmdprnt.h>         // our include
  14. #include <v/vbtncmd.h>          // ButtonCmd
  15. #include <v/vlabelc.h>          // LabelCmd
  16. #include <v/vframec.h>          // FrameCmd
  17. #include <v/vchkboxc.h>         // CheckBoxCmd
  18. #include <v/vradioc.h>          // RadioButtonCmd
  19. #include <v/vtextinc.h>         // TextInCmd
  20. #include <v/vtextc.h>           // TextCmd
  21. #include <v/vlistc.h>           // ListCmd
  22. #include <v/vcomboc.h>          // ComboBoxCmd
  23. #include <v/vspinc.h>           // SpinnerCmd
  24. #include <v/vsliderc.h>         // SliderCmd
  25. #include <v/vprogrsc.h>         // ProgressCmd
  26. #include <v/vboxlblc.h>         // BoxedLabel
  27.  
  28. // ---------------------------------------------------------------------
  29. // Dynamic Dialog Building Support
  30. // ---------------------------------------------------------------------
  31.  
  32.   // this is an attempt to consolidate all the different margin
  33.   // variables that are lying around, but alas all seem to be doing pretty
  34.   // much the same thing. We will stick with StdMargin in vcmd.h as the
  35.   // master margin variable.
  36.   const int _CtrlSpacing = StdMargin;
  37.  
  38.   //======================>>> vCmdParent::vCmdParent <<<========================
  39.   // In this tricky little function, the address of the pointer variable used
  40.   // in the calling function to track the next free byte at the end of the
  41.   // dialog template variable data region is accessed (*inp).
  42.   // The function automatically increments this pointer so that after copying
  43.   // the *src  string to the end of the data region, the original pointer in
  44.   // the calling function now points to the new end of the data region.
  45.   static void CopyStringToDialog (PSZ *inp, PCSZ src)
  46.   {
  47.     char *in = (char  * )(*inp);  // in assigned the address of *inp
  48.  
  49.     do
  50.     {
  51.       *in++ = (char) *src;
  52.     } while (*src++);
  53.     *inp = (char *)in;    // *inp reset to the new end of data
  54.   }
  55.  
  56. //======================>>> vCmdParent::vCmdParent <<<==========================
  57.   vCmdParent::vCmdParent(PaneType pt)
  58.   {
  59.     _cmdList = 0;
  60.     maxX = 0;           // minimum size for a dialog
  61.     maxY = 0;
  62.     if (pt == P_Status)
  63.     {
  64.       maxX = 4;       // give some room at left for drawing box
  65.       maxY = 4;
  66.     }
  67.  
  68.     _callbackID = -1;   // no call back id
  69.     _pt = pt;
  70.   }
  71.  
  72. //======================>>> vCmdParent::~vCmdParent <<<============================
  73.   vCmdParent::~vCmdParent()
  74.   {
  75.     SysDebug(Destructor,"vCmdParent::~vCmdParent() destructor\n")
  76.     // need to delete everything we added
  77.     DlgCmdList* tmp;
  78.     if (_hTemplate != 0)
  79.     {
  80.       DosFreeMem(_hTemplate);
  81.  
  82.       _hTemplate = 0;
  83.     }
  84.     for (DlgCmdList* cc = _cmdList ; cc != 0  ; )
  85.     {
  86.       delete cc->cmdP;        // delete the cmd object
  87.       tmp = cc;               // don't forget where we were
  88.       cc = cc->nextDCL;       // for next time
  89.       delete tmp;             // delete the list cell
  90.     }
  91.   }
  92.  
  93. //======================>>> vCmdParent::AddCmd <<<============================
  94.   vCmd* vCmdParent::AddCmd(CommandObject* cmd)
  95.   {
  96.     // Private method to add a single command to a dialog object.
  97.     SysDebug2(Build,"vCmdParent::AddCmd() - %s(id:%d)\n",cmd->title,cmd->cmdId)
  98.     vCmd* cmdPtr;
  99.     switch (cmd->cmdType)               // depends on type
  100.     {
  101.       case C_IconButton:              // a command button Icon
  102.       case C_ToggleButton:            // a toggle icon button
  103.       case C_ToggleIconButton:        // a toggle icon button
  104.       case C_Button:                  // Button
  105.       case C_ColorButton:             // ColorButton
  106.       {
  107.         cmdPtr = new vButtonCmd(this, cmd);
  108.         break;
  109.       }
  110.       case C_CheckBox:                // Checked Item
  111.       {
  112.         cmdPtr = new vCheckBoxCmd(this, cmd);
  113.         break;
  114.       }
  115.       case C_ComboBox:                // Popup combo list
  116.       {
  117.         cmdPtr = new vComboBoxCmd(this, cmd);
  118.         break;
  119.       }
  120.       case C_Frame:                   // General purpose frame
  121.       case C_ToggleFrame:             // A toggle frame
  122.       {
  123.         cmdPtr = new vFrameCmd(this, cmd);
  124.         break;
  125.       }
  126.       case C_Icon:                    // a static icon
  127.       case C_Blank:                   // to help RightOfs, Belows work
  128.       case C_Label:                   // Regular text label
  129.       case C_ColorLabel:              // Color text label
  130.       {
  131.         cmdPtr = new vLabelCmd(this, cmd);
  132.         break;
  133.       }
  134.       case C_List:                    // List of items (scrollable)
  135.       {
  136.         cmdPtr = new vListCmd(this, cmd);
  137.         break;
  138.       }
  139.       case C_ProgressBar:             // Progress bar
  140.       {
  141.         cmdPtr = new vProgressCmd(this, cmd);
  142.         break;
  143.       }
  144.       case C_RadioButton:             // radio button
  145.       {
  146.         cmdPtr = new vRadioButtonCmd(this, cmd);
  147.         break;
  148.       }
  149.       case C_Slider:                  // slider
  150.       {
  151.         cmdPtr = new vSliderCmd(this, cmd);
  152.         break;
  153.       }
  154.       case C_BoxedLabel:
  155.       {
  156.         cmdPtr = new vBoxedLabelCmd(this, cmd);
  157.         break;
  158.       }
  159.       case C_Text:                    // Text output field
  160.       {
  161.         cmdPtr = new vTextCmd(this, cmd);
  162.         break;
  163.       }
  164.       case C_TextIn:                  // Text input field
  165.       {
  166.         cmdPtr = new vTextInCmd(this, cmd);
  167.         break;
  168.       }
  169.       case C_Spinner:         // Value Box list
  170.       {
  171.         cmdPtr = new vSpinnerCmd(this, cmd);
  172.         break;
  173.       }
  174.       default:                        // unknown!
  175.       {
  176.         SysDebug2(BadVals,"vCmdParent::AddCmd(id:%d, title:%s) ** Unknown DialogCommand\n",
  177.           cmd->cmdId,cmd->title);
  178.         cmd->title = "?? Bad CommandObject ??";
  179.         cmdPtr = new vLabelCmd(this, cmd);
  180.         break;
  181.       }
  182.     }
  183.     return cmdPtr;
  184.   }
  185.  
  186. //====================>>> vCmdParent::HasId <<<=========================
  187.   int vCmdParent::HasId(ItemVal id) VCONST
  188.   {
  189.     // We need this one for panes to work correctly
  190.     for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)
  191.     {
  192.       if (((cc->cmdP)->dlgCmd)->cmdId == id)
  193.       {
  194.         return 1;
  195.       }
  196.     }
  197.     return 0;
  198.   }
  199.  
  200. //====================>>> vCmdParent::GetValue <<<=========================
  201.   int vCmdParent::GetValue(ItemVal id) VCONST
  202.   {
  203.     for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)
  204.     {
  205.       if (((cc->cmdP)->dlgCmd)->cmdId == id)
  206.       {
  207.         return (cc->cmdP)->GetCmdValue(id);  // return the value
  208.       }
  209.     }
  210.     return 0;
  211.   }
  212.  
  213. //====================>>> vCmdParent::SetFrameChildren <<<======================
  214.   void vCmdParent::SetFrameChildren(ItemVal frameId, int frameVal)
  215.   {
  216.     // Set all children of given frame to hidden or not hidden
  217.     // Do this recursively to be sure to get them all.
  218.     // Scan list, setting all children that use this frame
  219.     for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)  // Find the frame
  220.     {
  221.       CommandObject* cop = (cc->cmdP)->dlgCmd;
  222.       if (cop->cFrame == frameId)                     // A child of ours
  223.       {
  224.         // Hide control if not turning on (frameVal is opposite of Hidden)
  225.         SetValue(cop->cmdId, !frameVal, Hidden);
  226.         if (cop->cmdType == C_Frame || cop->cmdType == C_ToggleFrame)
  227.             SetFrameChildren(cop->cmdId, frameVal); // Get other chilren
  228.       }
  229.     }
  230.   }
  231.  
  232. //====================>>> vCmdParent::GetTextIn <<<=========================
  233.   int vCmdParent::GetTextIn(ItemVal id, char* strout, int maxlen)
  234.   {
  235.     // recover the string from TextIn id, up to maxlen
  236.     for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)
  237.     {
  238.       if (((cc->cmdP)->dlgCmd)->cmdId == id)
  239.       {
  240.         // need to cast to a vTextInCmd so we can use getstr
  241.         vTextInCmd* tip = (vTextInCmd*) cc->cmdP;
  242.         return tip->GetTextIn(id, strout, maxlen);  // return the value
  243.       }
  244.     }
  245.     *strout = 0;
  246.     return 0;
  247.   }
  248.  
  249. //====================>>> vCmdParent::getParent <<<=======================
  250.   HWND vCmdParent::getParent(void) VCONST
  251.   {
  252.     //  Return parent's HWND
  253.     return _wDialog;
  254.  }
  255.  
  256. //==================>>> vCmdParent::getThisFromId <<<=======================
  257.   vCmd* vCmdParent::getThisFromId(ItemVal find_id)
  258.   {
  259.     // search the list of cmds for id, return its this
  260.     DlgCmdList* cc;
  261.     // search the list
  262.  
  263.     for (cc = _cmdList; cc != NULL ; cc = cc->nextDCL)
  264.     {
  265.       if (cc->cmdP == NULL || (cc->cmdP)->dlgCmd == NULL)
  266.         return 0;
  267.  
  268.       if (((cc->cmdP)->dlgCmd)->cmdId == find_id)
  269.       {
  270.         return cc->cmdP;
  271.       }
  272.     }
  273.     return 0;                           // failed to find it
  274.   }
  275.  
  276. //====================>>> vCmdParent::SetPosition <<<=========================
  277.   void vCmdParent::SetPosition(int& x, int& y, int w, int h, ItemVal frame,
  278.     ItemVal rightOf, ItemVal below, int isSpinner)
  279.   {
  280.     // This method is responsible for controlling the layout of controls in
  281.     // a dialog. All positions of controls are set relative to other controls,
  282.     // which must have been previously defined (i.e., you start with the upper
  283.     // left control and work to the lower right corner). It must dynamically
  284.     // set the size of frames, and track the maximum x and y of the whole
  285.     // dialog.
  286.     //
  287.     // note: As far as I can tell, the isSpinner variable is never used
  288.     //       and is always 0 so I deleted all the isSpinner code
  289.  
  290.     int margin = _CtrlSpacing;  // spacing between controls
  291.     int FrameMargin = _CtrlSpacing*2;  // spacing between controls and frame edge
  292.  
  293.     vCmd* frameCmd = 0;
  294.  
  295.     x = y = margin;         // start out with standard spacing
  296.  
  297.     if (frame != 0)             // in a frame?
  298.     {
  299.       // refresher:  DlgCmdList is a linked list of pointers to vCmd's
  300.       //             _cmdList is the list of vCmd's (controls) for this dialog
  301.       //             dlgCmd is a pointer to the vCmd static definition
  302.       //
  303.       for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)
  304.       {
  305.         if ((cc->cmdP) == 0 || (cc->cmdP)->dlgCmd == 0) // not completely added yet!
  306.           continue;
  307.  
  308.         // search for the vCmd of our frame
  309.     if (((cc->cmdP)->dlgCmd)->cmdId == frame)
  310.     {
  311.       frameCmd = cc->cmdP;            // remember our frame
  312.       if ((frameCmd->dlgCmd)->attrs & CA_NoSpace)
  313.         FrameMargin = 0;
  314.  
  315.           // position the control relative to the frame based on the specified
  316.           // position data
  317.       if (rightOf == 0)
  318.           {
  319.         x = (cc->cmdP)->_x + FrameMargin; // add to right of frame
  320.             if ((frameCmd->dlgCmd)->attrs & CA_NoSpace)
  321.               ++x;  // adjust for right side BEW 1.21
  322.           }
  323.  
  324.       else
  325.         x = FrameMargin;
  326.  
  327.       if (below == 0)
  328.           {
  329.         y = (cc->cmdP)->_y + FrameMargin;
  330.             if ((frameCmd->dlgCmd)->attrs & CA_NoSpace)
  331.             ++y;  // adjust for bottom  BEW 1.21
  332.           }
  333.  
  334.       else
  335.         y = FrameMargin;
  336.     }
  337.       }
  338.     }  // end of frame procedure
  339.  
  340.     // check if its a command bar and not in a frame
  341.     if (_dialogType == aCmdBar && frame == 0)
  342.     {
  343.       x = maxX + margin; // put the control at the end of the bar + margin
  344.       y = margin;        // bars are linear in x (no y control allowed)
  345.     }
  346.  
  347.     // check if its a status bar and not in a frame
  348.     else if (_dialogType == aStatBar && frame == 0)
  349.     {
  350.       x = maxX + margin;  // put the control at the end of the bar + margin
  351. //      y = margin + 1;   // adjust in y to center better
  352.       y = margin;         // bars are linear in x (no y control allowed)
  353.     }
  354.  
  355.     // else, its a regular dialog with full 2d positioning
  356.     else
  357.     {
  358.       // refresher:  DlgCmdList is a linked list of pointers to vCmd's
  359.       //             _cmdList is the list of vCmd's (controls) for this dialog
  360.       //             dlgCmd is a pointer to the vCmd static definition
  361.       //
  362.       // cycle through all the controls in the dialog
  363.  
  364.       for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)
  365.       {
  366.     // we skip the partially added current control
  367.         if ((cc->cmdP) == 0 || (cc->cmdP)->dlgCmd == 0) // not completely added yet!
  368.           continue;
  369.         // set the control's x posn right of the 'rightof' control
  370.         if (((cc->cmdP)->dlgCmd)->cmdId == rightOf)
  371.         {
  372.           x += ((cc->cmdP)->_x) + ((cc->cmdP)->_w); // position to right of the 'rightOf'
  373.         }
  374.         // set the control's y posn below the 'below' control
  375.         if (((cc->cmdP)->dlgCmd)->cmdId == below)
  376.         {
  377.           y += ((cc->cmdP)->_y) + ((cc->cmdP)->_h); // position below the 'below'
  378.         }
  379.       }
  380.     }
  381.  
  382.     // now we adjust the overall dialog size to enclose the
  383.     // control we just added
  384.     int cxr = x + w;                            // right x of control
  385.     int cyb = y + h;                            // bottom y of control
  386.  
  387.     if (maxX < cxr)                             // track size of the dialog
  388.       maxX = cxr;
  389.  
  390.     if (maxY < cyb)
  391.       maxY = cyb;
  392.  
  393.     // if a frame was used, then we need to also adjust the
  394.     // overall frame size to enclose the control we just added
  395.     if (frameCmd)                               // need to fixup frame
  396.     {
  397.       FixFrame(cxr, cyb, FrameMargin, frameCmd);           // fixup frames
  398.     }
  399.   }
  400.  
  401. //====================>>> vCmdParent::FixFrame <<<=======================
  402. // After a vCmd (control) is added to a frame, we need to readjust the
  403. // overall frame size to make sure it encloses the control we just added
  404. //
  405. //  cxr is the controls rightmost extent
  406. //  cyb is the controls bottommost extent
  407.   void vCmdParent::FixFrame(int cxr, int cyb, int FrameMargin, vCmd* frameCmd)
  408.   {
  409.     int fxr = frameCmd->_x + frameCmd->_w;      // right x of frame
  410.     int fyb = frameCmd->_y + frameCmd->_h;      // bottom y of frame
  411.  
  412.     if (fxr < cxr + FrameMargin)                     // need to make frame wider
  413.     {
  414.       frameCmd->_w = (cxr + FrameMargin) - frameCmd->_x;
  415.       if (FrameMargin == 0)
  416.         ++(frameCmd->_w);  // make nospace look right BEW 1.21
  417.     }
  418.  
  419.     if (fyb < cyb + FrameMargin)                     // need to make frame taller
  420.     {
  421.       frameCmd->_h = (cyb + FrameMargin) - frameCmd->_y;
  422.       if (FrameMargin == 0)
  423.         ++(frameCmd->_h);  // make nospace look right BEW 1.21
  424.     }
  425.  
  426.     // Check if we need fixup the overall dialog size
  427.     if (maxX < frameCmd->_x + frameCmd->_w)
  428.       maxX = frameCmd->_x + frameCmd->_w;
  429.     if (maxY < frameCmd->_y + frameCmd->_h)
  430.       maxY = frameCmd->_y + frameCmd->_h;
  431.  
  432.     // Now fixup the dialog template
  433.     // The dialog template item for the frame control is already created
  434.     // We need to update the template item size parameters with the new
  435.     // values for the frame size
  436.     if (frameCmd->_CtrlOffset != 0)
  437.     {
  438.       ULONG  *wNumBytes;
  439.  
  440.       PDLGTITEM pDlgTItem;
  441.  
  442.       // wNumBytes points to beginning of DLGTEMPLATE memory block.
  443.       wNumBytes = (ULONG *) _hTemplate;
  444.       // pDlgTItem points to start of new DLGTITEM.
  445.       pDlgTItem = (PDLGTITEM) (((PSZ) wNumBytes) + frameCmd->_CtrlOffset);
  446.  
  447.       // Fix the width
  448.       pDlgTItem->cx = frameCmd->_w;
  449.       pDlgTItem->cy = frameCmd->_h;
  450.     }
  451.  
  452.     // Now, fixup surrounding frames!
  453.     int frame = (frameCmd->dlgCmd)->cFrame;
  454.     if (frame != 0)     // Have to fix frame's frame
  455.     {
  456.       // refresher:  DlgCmdList is a linked list of pointers to vCmd's
  457.       //             _cmdList is the list of vCmd's (controls) for this dialog
  458.       //             dlgCmd is a pointer to the vCmd static definition
  459.       //
  460.       // cycle through all the controls in the dialog
  461.       for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)
  462.       {
  463.         if ((cc->cmdP) == 0 || (cc->cmdP)->dlgCmd == 0)  // not completely added yet!
  464.           continue;
  465.         if (((cc->cmdP)->dlgCmd)->cmdId == frame)
  466.         {
  467.           vCmd* fCmd = cc->cmdP;          // remember frame's frame
  468.           fxr = frameCmd->_x + frameCmd->_w;      // right x of frame
  469.           fyb = frameCmd->_y + frameCmd->_h;      // bottom y of frame
  470.           FixFrame(fxr, fyb, FrameMargin, fCmd);
  471.           break;
  472.         }
  473.       }
  474.     }
  475.   }
  476.  
  477. //====================>>> vCmdParent::SetValue <<<=======================
  478.   void vCmdParent::SetValue(ItemVal id, ItemVal val, ItemSetType setType)
  479.   {
  480.     SysDebug2(Misc,"vCmdParent::SetValue(id:%d, val:%d)\n",id,val)
  481.     for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)
  482.     {
  483.       if (((cc->cmdP)->dlgCmd)->cmdId == id)
  484.       {
  485.         (cc->cmdP)->SetCmdVal(val,setType);  // return the value
  486.         return;
  487.       }
  488.     }
  489.   }
  490.  
  491. //====================>>> vCmdParent::SetString <<<=======================
  492.   void vCmdParent::SetString(ItemVal id, char* str) VCONST
  493.   {
  494.     char trunc[80];
  495.     SysDebug2(Misc,"vCmdParent::SetString(id:%d, str:%s)\n",id, strncpy(trunc, str, 60) )
  496.     for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)
  497.     {
  498.       if (((cc->cmdP)->dlgCmd)->cmdId == id)
  499.       {
  500.         (cc->cmdP)->SetCmdStr(str);  // return the value
  501.         return;
  502.       }
  503.     }
  504.   }
  505.  
  506. //====================>>> vCmdParent::CreateDlgTemplate <<<==================
  507. // Creates a Dialog Template in memory.  Avoids needing a resource file
  508. // to build up the dialog controls.
  509.  
  510.   int vCmdParent::CreateDlgTemplate(
  511.     ULONG dtCtlData,        // dialog control data (FCF_*, etc)
  512.     ULONG dtStyle,        // dialog style (WS_* and FS_*)
  513.     SHORT dtX,                  // location, In dialog-box units
  514.     SHORT dtY,
  515.     SHORT dtCX,                   // size, in dialog-box units
  516.     SHORT dtCY,
  517.     SHORT dtID,                    // V doesn't assign an ID to the frame
  518.     PSZ dtMenuName,        // "" if no menu  (not Implemented)
  519.     PSZ dtClassName,        // "" if standard dialog box class  (not implemented)
  520.     PSZ dtCaption,            // caption text for dialog
  521.     PPRESPARAMS pPP)        // Presentation Parameters
  522.   {
  523.     ULONG wBlockLen;
  524.     ULONG wBaseMem, wItemMem;
  525.     ULONG wCaptionLen, PPLen;
  526.     PSZ szDlgTemplate, szDlgTypeFace;
  527.     PDLGTEMPLATE pDlgTemplate;
  528.  
  529.     // Calculate number of bytes required by following fields:
  530.     // Block must be large enough to contain the following:
  531.     // # bytes: fixed part DLGTEMPLATE and one DLGTITEM
  532.     // # bytes: dialog box caption.
  533.     // # bytes: presentation parameters.
  534.  
  535.     wCaptionLen  = (1 + strlen(dtCaption));
  536.     wBlockLen = sizeof(DLGTEMPLATE) + sizeof(dtCtlData) + wCaptionLen;
  537.  
  538.     if (pPP)
  539.     {
  540.       // Dialog box has Presentation Parameters
  541.       // Calculate # of bytes required for PRESPARAM structure
  542.       // cb gives the byte count of the aparam[] array, need to add
  543.       // extra 4 bytes for pPP->cb count
  544.       PPLen = pPP->cb + sizeof(ULONG);
  545.       wBlockLen += PPLen;    // # bytes for PRESPARAM value (font typeface)
  546.     }
  547.     else
  548.     {
  549.       // Dialog box uses the System font.
  550.       // Block length does not change.
  551.       PPLen = 0;
  552.     }
  553.  
  554.     // Allocate global block of memory for Dialog template.
  555.     DosAllocMem ((PPVOID) &_hTemplate, wBlockLen, fALLOC);
  556.  
  557.     if (_hTemplate == NULL)
  558.       return 0;            // memory alloc failed!
  559.  
  560.     // pDlgTemplate points to start of DLGTEMPLATE in block.
  561.     pDlgTemplate = _hTemplate;
  562.  
  563.     // Set the members of the DLGTEMPLATE structure.
  564.     pDlgTemplate->cbTemplate = wBlockLen;
  565.     pDlgTemplate->type = 0;                // not used
  566.     pDlgTemplate->codepage = theApp->AppCP();
  567.     wBaseMem = (ULONG) pDlgTemplate;
  568.     wItemMem = (ULONG) pDlgTemplate->adlgti;
  569.     pDlgTemplate->offadlgti = (SHORT) wItemMem - wBaseMem;
  570.     pDlgTemplate->fsTemplateStatus = 1;    // not used (docs say 0 but debug says 1)
  571.     pDlgTemplate->iItemFocus = (USHORT) -1;         // no focus specified
  572.     pDlgTemplate->coffPresParams = 0;      // never used!
  573.  
  574.     // Set the members of the frame DLGTITEM structure.
  575.     // the first item is always the frame window class (WC_FRAME)
  576.     pDlgTemplate->adlgti[0].fsItemStatus = 0;    // not used
  577.     // no controls yet, Incremented with calls to AddDlgControl.
  578.     pDlgTemplate->adlgti[0].cChildren = 0;
  579.     pDlgTemplate->adlgti[0].cchClassName = 0;          // use PM classes
  580.     pDlgTemplate->adlgti[0].offClassName = SHORT1FROMMP((MPARAM) WC_FRAME);    // PM class
  581.     pDlgTemplate->adlgti[0].cchText = wCaptionLen-1;     // strip null from string
  582.     pDlgTemplate->adlgti[0].flStyle = dtStyle;
  583.     pDlgTemplate->adlgti[0].x = dtX;
  584.     pDlgTemplate->adlgti[0].y = dtY;
  585.     pDlgTemplate->adlgti[0].cx = dtCX;
  586.     pDlgTemplate->adlgti[0].cy = dtCY;
  587.     pDlgTemplate->adlgti[0].id = dtID;               // V doesn't seem to need this
  588.  
  589.     // szDlgTemplate points to start of variable part of DLGTEMPLATE.
  590.     szDlgTemplate = (PSZ) (pDlgTemplate + 1);
  591.  
  592.     // store variable length caption
  593.     // we compute the offset from here to start of DLGTEMPLATE and save
  594.     wItemMem = (ULONG) szDlgTemplate;
  595.  
  596.     pDlgTemplate->adlgti[0].offText =  (SHORT) (wItemMem - wBaseMem);
  597.     CopyStringToDialog(&szDlgTemplate, dtCaption);
  598.  
  599.     // store ULONG control data here
  600.     wItemMem = (ULONG) szDlgTemplate;
  601.     pDlgTemplate->adlgti[0].offCtlData =  (SHORT) wItemMem - wBaseMem;
  602.     memcpy(szDlgTemplate, &dtCtlData, 4);
  603.     szDlgTemplate += 4;
  604.  
  605.     // add the PRESPARAMS info
  606.     if (pPP)
  607.     {
  608.       wItemMem = (ULONG) szDlgTemplate;
  609.       pDlgTemplate->adlgti[0].offPresParams =  (SHORT) wItemMem - wBaseMem;
  610.       memcpy(szDlgTemplate, pPP, PPLen);
  611.       szDlgTemplate += PPLen;
  612.       DosFreeMem (pPP);          // destroy pPP structure after use
  613.     }
  614.     else  // no PPs!
  615.       pDlgTemplate->adlgti[0].offPresParams = (USHORT) -1;
  616.  
  617.     return 1;                   // success
  618. }
  619.  
  620. //====================>>> vCmdParent::AddDlgControl <<<=====================
  621.   int AddDlgControl (SHORT dtilX, SHORT dtilY, SHORT dtilCX, SHORT dtilCY,
  622.         USHORT dtilID, ULONG dtilStyle, PCSZ dtilClass, PCSZ dtilText,
  623.         PPRESPARAMS dtipPP, ULONG dtilCtlLen, PVOID dtilCtlData);
  624.  
  625.   int vCmdParent::AddDlgControl (
  626.     SHORT dtilX, SHORT dtilY,    // In dialog-box units.
  627.     SHORT dtilCX, SHORT dtilCY,    // In dialog-box units.
  628.     USHORT dtilID,
  629.     ULONG dtilStyle,        // WS_* BS_* etc.
  630.     PCSZ dtilClass,        // Class name WC_*
  631.     PCSZ dtilText,        // label
  632.     PPRESPARAMS dtipPP,         // Pointer to presentation parameters
  633.     ULONG dtilCtlLen,            // Control Data length (bytes)
  634.     PVOID dtilCtlData)          // Pointer to control data
  635.   {
  636.     ULONG wBlockLen, wTextLen,  wBaseMem, wItemMem;
  637.     ULONG PPLen;
  638.     USHORT *wCtlLen;
  639.     PDLGTEMPLATE pOldDlgTemplate, pDlgTemplate;
  640.     PDLGTITEM pDlgTItem;
  641.  
  642.     PSZ pszOldData, pszData;
  643.  
  644.     int i, numControls = 0;    // number of controls in dialog
  645.  
  646.     // Calculate number of bytes required by following fields:
  647.     wTextLen  = (1 + strlen(dtilText)) * sizeof (char);
  648.  
  649.     // Block must be increased by the following amount:
  650.     wBlockLen =
  651.       sizeof(DLGTITEM) +      // # bytes for fixed part of DLGTITEM.
  652.       wTextLen +        // # bytes for control text.
  653.       dtilCtlLen;            // # bytes for extra CTRL data.
  654.  
  655.     if (dtipPP)
  656.     {
  657.       // Dialog box has Presentation Parameters
  658.       // Calculate # of bytes required for PRESPARAM structure
  659.       // cb gives the byte count of the aparam[] array, need to add
  660.       // extra (ULONG) bytes for dtipPP->cb member
  661.       PPLen = dtipPP->cb + sizeof(ULONG);
  662.  
  663.       // Block must be large enough to include PP information.
  664.       wBlockLen += PPLen;    // # bytes for PRESPARAM value (font typeface)
  665.     }
  666.     else
  667.     {
  668.       // Dialog box uses the System font.
  669.       // Block length does not change.
  670.       PPLen = 0;
  671.     }
  672.  
  673.     // Add to number of bytes currently in the memory block.
  674.     wBlockLen += _hTemplate->cbTemplate;
  675.  
  676.     // pOldDlgTemplate points to start of old DLGTEMPLATE in block.
  677.     pOldDlgTemplate = _hTemplate;
  678.  
  679.     // Allocate new larger global block of memory for Dialog template.
  680.     // this is probably really inefficient but what else is there to do?
  681.     DosAllocMem ((PPVOID) &pDlgTemplate, wBlockLen, fALLOC);
  682.  
  683.     if (pDlgTemplate == NULL)
  684.       return 0;            // memory alloc failed!
  685.  
  686.     _hTemplate = pDlgTemplate;
  687.     wBaseMem = (ULONG) pDlgTemplate;  // used for offset calcs
  688.  
  689.     // copy over the old template data to the new structure
  690.     // we will fix up the offsets and variable data area later
  691.     memcpy(pDlgTemplate, pOldDlgTemplate, pOldDlgTemplate->cbTemplate);
  692.  
  693.     // save the total size of the new template
  694.     pDlgTemplate->cbTemplate = wBlockLen;
  695.  
  696.     // Increment the number of controls in the WC_FRAME template item.
  697.     numControls = ++pDlgTemplate->adlgti[0].cChildren;
  698.  
  699.     // set pDlgTItem to point to the start of new DLGTITEM.
  700.     // This is near the end of the memory block.
  701.     pDlgTItem = &pDlgTemplate->adlgti[numControls];
  702.  
  703.     // Set the members of the DLGTITEM structure.
  704.     pDlgTItem->fsItemStatus = 0;         // not used
  705.     pDlgTItem->cChildren = 0;            // only WC_FRAME has children
  706.     pDlgTItem->cchClassName = 0;           // use PM classes
  707.     pDlgTItem->offClassName = SHORT1FROMMP((MPARAM) dtilClass); // WC_*
  708.     pDlgTItem->cchText = wTextLen-1;     // label length (drop null at end)
  709.     pDlgTItem->flStyle = dtilStyle;      // WS_* BS_*, MLE_* etc.
  710.     pDlgTItem->x = dtilX;
  711.     pDlgTItem->y = dtilY;
  712.     pDlgTItem->cx = dtilCX;
  713.  
  714.     // We have to handle comboboxes specially because the
  715.     // height needed here is the combobox PLUS its list, while
  716.     // the height we want to use internally is the height WITHOUT the list
  717.     if (dtilClass == WC_COMBOBOX )    // Combo?
  718.       pDlgTItem->cy = dtilCY + 8*6;
  719.     else
  720.       pDlgTItem->cy = dtilCY;
  721.  
  722.     pDlgTItem->id = dtilID;
  723.     pDlgTItem->offPresParams = (USHORT) -1;           // default
  724.  
  725.     // now we need to fix up the variable data area
  726.     // pszData points to start of variable data part of the template
  727.     pszData = (PSZ) (pDlgTItem + 1);
  728.  
  729.     for (i=0; i<numControls; i++)
  730.     {
  731.       // store text label and compute offset to start of DLGTEMPLATE
  732.       wItemMem = (ULONG) pszData;
  733.       pDlgTemplate->adlgti[i].offText =  (USHORT) (wItemMem - wBaseMem);
  734.  
  735.       pszOldData = (PSZ) pOldDlgTemplate;               // base of old template
  736.       pszOldData += pOldDlgTemplate->adlgti[i].offText;  // pointer to old text
  737.       CopyStringToDialog(&pszData, pszOldData);
  738.  
  739.       // store PRESPARAMS and compute offset to start of DLGTEMPLATE
  740.       // if offset = -1 then no data
  741.       if (pOldDlgTemplate->adlgti[i].offPresParams == (USHORT) -1)
  742.     pDlgTemplate->adlgti[i].offPresParams = (USHORT) -1;
  743.  
  744.       else  // else copy over data
  745.       {
  746.     wItemMem = (ULONG) pszData;
  747.     pDlgTemplate->adlgti[i].offPresParams =  (USHORT) wItemMem - wBaseMem;
  748.  
  749.     pszOldData = (PSZ) pOldDlgTemplate;                      // base of old template
  750.     pszOldData += pOldDlgTemplate->adlgti[i].offPresParams;  // pointer to old CtlData
  751.     // get the data length in bytes (first 4 bytes of data)
  752.     PPLen = (ULONG) *pszOldData;
  753.     memcpy(pszData, pszOldData, PPLen + sizeof(ULONG));
  754.     pszData += PPLen + sizeof(ULONG);
  755.       }
  756.  
  757.       // store CTLDATA and compute offset to start of DLGTEMPLATE
  758.       // if offset = -1 then no data
  759.       if (pOldDlgTemplate->adlgti[i].offCtlData == (USHORT) -1)
  760.     pDlgTemplate->adlgti[i].offCtlData = (USHORT) -1;
  761.  
  762.       else  // else copy over data
  763.       {
  764.     wItemMem = (ULONG) pszData;
  765.     pDlgTemplate->adlgti[i].offCtlData =  (USHORT) wItemMem - wBaseMem;
  766.  
  767.     pszOldData = (PSZ) pOldDlgTemplate;                   // base of old template
  768.     pszOldData += pOldDlgTemplate->adlgti[i].offCtlData;  // pointer to old CtlData
  769.     // get the data length in bytes (first 4 bytes of data)
  770.     // Note: WC_FRAME class is non-conforming.  It expects a 4 byte
  771.     //       ULONG in the data area with no size info
  772.     if ( pOldDlgTemplate->adlgti[i].offClassName == SHORT1FROMMP((MPARAM) WC_FRAME))
  773.     {
  774.       memcpy(pszData, pszOldData, 4);  // non-conforming
  775.       pszData += 4;
  776.     }
  777.     else
  778.     {
  779.       wCtlLen = (USHORT*) pszOldData;         // conforming
  780.       memcpy(pszData, pszOldData, *wCtlLen);
  781.       pszData += *wCtlLen;
  782.     }
  783.       }
  784.     }
  785.  
  786.     // now we finish off by storing the current control's data
  787.     // store control label and compute offset to start of DLGTEMPLATE
  788.     wItemMem = (ULONG) pszData;
  789.     pDlgTemplate->adlgti[i].offText =  (USHORT) (wItemMem - wBaseMem);
  790.     CopyStringToDialog(&pszData, dtilText);
  791.  
  792.     // store PRESPARAMS and compute offset to start of DLGTEMPLATE
  793.     if (dtipPP == 0)   // if no data set offset to -1
  794.       pDlgTemplate->adlgti[i].offPresParams = (USHORT) -1;
  795.     else
  796.     {
  797.       wItemMem = (ULONG) pszData;
  798.       pDlgTemplate->adlgti[i].offPresParams =  (USHORT) wItemMem - wBaseMem;
  799.       memcpy(pszData, dtipPP, dtipPP->cb + sizeof(ULONG));
  800.       pszData += dtipPP->cb + sizeof(ULONG);
  801.       DosFreeMem (dtipPP);   // don't forget to clean up afterwards
  802.     }
  803.  
  804.     // store CTLDATA and compute offset to start of DLGTEMPLATE
  805.     if (dtilCtlLen == 0)   // if no data set offset to -1
  806.       pDlgTemplate->adlgti[i].offCtlData = (USHORT) -1;
  807.     else
  808.     {
  809.       wItemMem = (ULONG) pszData;
  810.       pDlgTemplate->adlgti[i].offCtlData =  (USHORT) wItemMem - wBaseMem;
  811.       memcpy(pszData, dtilCtlData, dtilCtlLen);
  812.       pszData += dtilCtlLen;
  813.     }
  814.  
  815.     // now destroy the old template
  816.     DosFreeMem(pOldDlgTemplate);
  817.  
  818.     // offset to start of last control
  819.     return (int) &pDlgTemplate->adlgti[i] - wBaseMem;
  820.   }
  821.  
  822.  
  823. //==================>>> vCmdParent::DoneAddingControls <<<===================
  824.   void vCmdParent::DoneAddingControls(void)
  825.   {
  826.     PDLGTEMPLATE pDlgTemplate;
  827.  
  828.     // set pDlgTemplate to start of DLGTEMPLATE in block.
  829.     pDlgTemplate = _hTemplate;
  830.  
  831.     // Fixup size
  832.     maxX = pDlgTemplate->adlgti[0].cx = maxX + _CtrlSpacing;
  833.     maxY = pDlgTemplate->adlgti[0].cy = maxY + _CtrlSpacing;
  834.  
  835.     // we need to transform all control y-dimensions since V uses upper left as
  836.     // origin and OS/2 assumes lower left
  837.  
  838.     ULONG  *wNumBytes;
  839.     PDLGTITEM pDlgTItem;
  840.  
  841.     // set wNumBytes to beginning of DLGTEMPLATE memory block.
  842.     wNumBytes = (ULONG *) _hTemplate;
  843.  
  844.     for (DlgCmdList* cc = _cmdList ; cc != 0  ; cc = cc->nextDCL)
  845.     {
  846.       // transform the y coord in the dialog template
  847.       if ( (cc->cmdP)->_CtrlOffset != 0)
  848.       {
  849.     // set pDlgTItem to start of current control DLGTITEM.
  850.     pDlgTItem = (PDLGTITEM) (((PSZ) wNumBytes) + (cc->cmdP)->_CtrlOffset);
  851.  
  852.     // invert and shift y coord
  853.     if ( (((cc->cmdP)->dlgCmd)->cmdType) == C_ComboBox )    // Combo?
  854.       pDlgTItem->y = maxY - (cc->cmdP)->_y - (cc->cmdP)->_h - 8*6;
  855.     else
  856.       pDlgTItem->y = maxY - (cc->cmdP)->_y - (cc->cmdP)->_h;
  857.       }
  858.     }
  859.   }
  860.  
  861.  
  862. //================>>> vCmdParent::ChangeDlgTButtonColor <<<=====================
  863. //  routine to change the color button color in the dialog template
  864. //  after the template is assembled in memory
  865. //
  866. void vCmdParent::ChangeDlgTButtonColor(int CtrlOffset, USHORT cmdId, ULONG newColor )
  867. {
  868.   PDLGTITEM pDlgTItem;
  869.  
  870.   // set pDlgTItem to start of current control DLGTITEM.
  871.   pDlgTItem = (PDLGTITEM) (((PSZ) _hTemplate) + CtrlOffset);
  872.  
  873.   // a sanity check
  874.   if (pDlgTItem->id != cmdId)
  875.   {
  876.     // something's gone wrong, better punt!
  877.     return;
  878.   }
  879.   // find the button color pres params word in the template...
  880.   // this is a bit dangerous since we assume that the button
  881.   // color pres param order is fixed, but since we create the template
  882.   // we do have control over this so it shouldn't break later
  883.   // and it makes life simpler this way
  884.   ULONG *buttonColor;
  885.   buttonColor = (ULONG *) (((PSZ) _hTemplate) + pDlgTItem->offPresParams);
  886.  
  887.   // button color is 3rd ULONG in from start of Pres Params
  888.   buttonColor += 3;
  889.   *buttonColor = newColor;
  890. }
  891.  
  892. //====================>>> vCmdParent::AssyPresParams <<<=====================
  893. //----- routine to assemble an arbitrary size PP structure
  894.   PPRESPARAMS vCmdParent::AssyPresParams(PPElement *PPel)
  895.   {
  896.     ULONG PPlen;
  897.     int i;
  898.     PPARAM ixPP;
  899.     PPRESPARAMS pPP;
  900.  
  901.     // first compute necessary storage space for PPs
  902.     PPlen = sizeof(ULONG);    // pp.cb
  903.     for (i=0; PPel[i].PPtype; i++)
  904.     {
  905.       if (PPel[i].PPtype == PP_FONTNAMESIZE)
  906.       // its a font PP
  907.     PPlen += sizeof(PARAM)-1 + strlen(PPel[i].PPval.font)+1;
  908.       else
  909.     // its a color PP
  910.     PPlen += sizeof(PARAM)-1 + sizeof(ULONG);
  911.     }
  912.  
  913.     // now we build up the PRESPARAM structure
  914.     DosAllocMem ((PPVOID) &pPP, PPlen, fALLOC);
  915.  
  916.     // Danger: PRESPARAMS is so braindead that it is unworkable
  917.     //         as designed.  It uses a PARAM as an indexed array
  918.     //         internally, but PARAM is variable length so that
  919.     //         the indexing fails after the first element!
  920.     pPP->cb = PPlen - sizeof(ULONG);
  921.     ixPP = pPP->aparam;
  922.     for (i=0; PPel[i].PPtype; i++)
  923.     {
  924.       ixPP->id = PPel[i].PPtype;
  925.       if (PPel[i].PPtype == PP_FONTNAMESIZE)
  926.       { // its a font PP
  927.     ixPP->cb = strlen(PPel[i].PPval.font)+1;
  928.     strcpy(ixPP->ab, PPel[i].PPval.font);
  929.       }
  930.       else
  931.       {    // its a color PP
  932.     ixPP->cb = sizeof(ULONG);
  933.     memcpy(ixPP->ab, &PPel[i].PPval.color, sizeof(ULONG));
  934.       }
  935.       // now we set the index to the next PARAM element in the PRESPARAM structure
  936.       // Here, we temporarily set ixPP to a PSZ so we can do byte size pointer
  937.       // arithmetic
  938.       ixPP = (PPARAM) (((PSZ) ixPP) + sizeof(PARAM)-1 + ixPP->cb);
  939.     }
  940.     return(pPP);
  941.   }
  942.  
  943. // ---------------------------------------------------------------------
  944.  
  945.  
  946.  
  947.