codegen.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:37k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * codegen.cxx
  3.  *
  4.  * Resource compiler C++ code generator
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: codegen.cxx,v $
  30.  * Revision 1.4  2000/06/21 02:15:25  robertj
  31.  * Removed some warnings on compiling colour icons.
  32.  *
  33.  * Revision 1.3  1999/10/18 04:41:09  robertj
  34.  * Added decompile of .BMP and .ICO files and fixed ability to have 64x64 icons
  35.  *
  36.  * Revision 1.2  1998/09/26 01:24:02  robertj
  37.  * Added open source license
  38.  *
  39.  * Revision 1.1  1998/09/26 00:46:21  robertj
  40.  * Initial revision
  41.  *
  42.  * Revision 1.22  1998/09/14 13:45:02  robertj
  43.  * Allowed suppression of some warnings.
  44.  *
  45.  * Revision 1.21  1996/05/23 10:06:38  robertj
  46.  * Fixed bug in OK/Cancel buttons of dialogs not being set as special buttons.
  47.  *
  48.  * Revision 1.20  1996/01/23 13:32:41  robertj
  49.  * More changes for editor
  50.  *
  51.  * Revision 1.19  1995/12/23 03:51:05  robertj
  52.  * Removed multiple classes for Layout types.
  53.  * Added extra collections for editor use.
  54.  *
  55.  * Revision 1.18  1995/12/10 12:11:57  robertj
  56.  * Changes to support graphical resource file editor.
  57.  *
  58.  * Revision 1.17  1995/10/14 15:19:07  robertj
  59.  * Fixed missing font size on font keyword.
  60.  * Changes required by move of standard buttons to PDialog.
  61.  *
  62.  * Revision 1.16  1995/08/24 12:46:38  robertj
  63.  * Removed redundant parent parameter for ConstructEnd().
  64.  *
  65.  * Revision 1.14  1995/07/31 12:30:10  robertj
  66.  * Changed all generated resource IDs to be in the same "number space". This
  67.  *   is to avoid problems with IDs being used for more than one type of resource
  68.  *   eg a menu item and an image for a toolbar.
  69.  * Fixed the generated #line commands to include a relative path instead of an
  70.  *   absolute one.
  71.  *
  72.  * Revision 1.13  1995/04/02 09:28:12  robertj
  73.  * Added "balloon" help.
  74.  *
  75.  * Revision 1.12  1995/02/19 04:19:25  robertj
  76.  * Added dynamically linked command processing.
  77.  *
  78. // Revision 1.11  1995/02/11  04:13:18  robertj
  79. // Changed #include generated in .cxx file to not include full path.
  80. //
  81. // Revision 1.10  1995/01/27  11:25:38  robertj
  82. // Added pattern resource.
  83. //
  84.  */
  85. #include <ptlib.h>
  86. #include "pwrc.h"
  87. extern ResourceFile * current_file;
  88. /////////////////////////////////////////
  89. //
  90. //  Line numbers from parser
  91. //
  92. ostream & operator<<(ostream & out, const LineNumber & line)
  93. {
  94.   out << "n#line " << line.number << " "";
  95.   PINDEX i;
  96.   PDirectory dir;
  97.   for (i = 0; i < dir.GetLength(); i++)
  98.     if (dir[i] != line.filename[i])
  99.       break;
  100.   PString filestr = line.filename.Mid(i);
  101.   if (filestr.Find('\') == P_MAX_INDEX)
  102.     out << filestr;
  103.   else {
  104.     for (i = 0; i < filestr.GetLength(); i++) {
  105.       if (filestr[i] != '\')
  106.         out << filestr[i];
  107.       else
  108.         out << "\\";
  109.     }
  110.   }
  111.   return out << ""n";
  112. }
  113. /////////////////////////////////////////
  114. //
  115. //  key code structure
  116. //
  117. AccelCode::AccelCode(const PString & resrcStr)
  118. {
  119.   value = NullValue;
  120.   modifiers = NoModifier;
  121.   PCaselessString code(resrcStr(1, resrcStr.GetLength()-2));
  122.   if (code.IsEmpty())
  123.     return;
  124.   PINDEX pos;
  125.   if ((pos = code.Find("shift+")) != P_MAX_INDEX) {
  126.     code.Delete(pos, 6);
  127.     modifiers |= Shift;
  128.   }
  129.   if ((pos = code.Find("ctrl+")) != P_MAX_INDEX) {
  130.     code.Delete(pos, 5);
  131.     modifiers |= Control;
  132.   }
  133.   if ((pos = code.Find("alt+")) != P_MAX_INDEX) {
  134.     code.Delete(pos, 4);
  135.     modifiers |= Alt;
  136.   }
  137.   if ((pos = code.Find("cmd+")) != P_MAX_INDEX) {
  138.     code.Delete(pos, 4);
  139.     modifiers |= Command;
  140.   }
  141.   if ((pos = code.Find("opt+")) != P_MAX_INDEX) {
  142.     code.Delete(pos, 4);
  143.     modifiers |= Option;
  144.   }
  145.   if ((pos = code.Find("acc1+")) != P_MAX_INDEX) {
  146.     code.Delete(pos, 5);
  147.     modifiers |= Accelerator1;
  148.   }
  149.   if ((pos = code.Find("acc2+")) != P_MAX_INDEX) {
  150.     code.Delete(pos, 5);
  151.     modifiers |= Accelerator2;
  152.   }
  153.   static PCaselessString simpleCode("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
  154.   static PString keypadCode("0123456789+-*/,.");
  155.   switch (code.GetLength()) {
  156.     case 1 :
  157.       if ((pos = simpleCode.Find(code[0])) != P_MAX_INDEX)
  158.         value = (Value)(pos + PKeyCode::A);
  159.       break;
  160.     case 2 :
  161.       if (code(0,0) == "F" && code[1] >= '1' && code[1] <= '9')
  162.         value = (Value)(code[1] - '1' + PKeyCode::F1);
  163.       break;
  164.       
  165.     case 3 :
  166.       if (code(0,1) == "KP" && (pos = keypadCode.Find(code[2])) != P_MAX_INDEX)
  167.         value = (Value)(pos + PKeyCode::KP0);
  168.       else if (code(0,1) == "F1" && code[2] >= '0' && code[2] <= '2')
  169.         value = (Value)(code[2] - '0' + PKeyCode::F10);
  170.       break;
  171.   }
  172.   if (value == NullValue) {
  173.     static char *miscKeys[] = {
  174.       "Up", "Down", "Left", "Right", "PgUp", "PgDn", "Home", "End",
  175.       "Ins", "Del", "Undo", "Cut", "Copy", "Paste", "Clear", "Cancel",
  176.       "Help", "Quit", "BkSp", "Tab", "Ret", "Esc", " "
  177.     };
  178.     for (PINDEX i = 0; i < PARRAYSIZE(miscKeys); i++) {
  179.       if (code == miscKeys[i]) {
  180.         value = (Value)(i + PKeyCode::Up);
  181.         break;
  182.       }
  183.     }
  184.     if (value == NullValue)
  185.       PError << StdError(Fatal) << "Unknown accelerator code " << resrcStr << endl;
  186.   }
  187. }
  188. /////////////////////////////////////////
  189. //
  190. //  point for resource position
  191. //
  192. Point::Point(long nx, long ny)
  193. {
  194.   if (nx < -32767 || nx > 32767 || ny < -32767 || ny > 32767)
  195.     PError << StdError(Warning)
  196.            << "position must be 16 bit, truncating." << endl;
  197.   x = (int)nx;
  198.   y = (int)ny;
  199. }
  200. void Point::SetX(long nx)
  201. {
  202.   if (nx < -32767 || nx > 32767)
  203.     PError << StdError(Warning)
  204.            << "position must be 16 bit, truncating." << endl;
  205.   x = (int)nx;
  206. }
  207. void Point::SetY(long ny)
  208. {
  209.   if (ny < -32767 || ny > 32767)
  210.     PError << StdError(Warning)
  211.            << "position must be 16 bit, truncating." << endl;
  212.   y = (int)ny;
  213. }
  214. Point & Point::operator=(const Point & pt)
  215. {
  216.   x = pt.x;
  217.   y = pt.y;
  218.   return *this;
  219. }
  220. /////////////////////////////////////////
  221. //
  222. //  a resource item which has an id and a string
  223. //
  224. ResourceObject::ResourceObject(ResourceID * newId, PString * newText)
  225. {
  226.   SetID(newId);
  227.   SetText(newText);
  228. }
  229. void ResourceObject::SetText(PString * newText)
  230. {
  231.   if (newText != NULL) {
  232.     textLiteral = *newText;
  233.     delete newText;
  234.     textConverted = PString(PString::Literal, textLiteral);
  235.     if (textConverted.GetLength() > 255) {
  236.       textLiteral = textLiteral(0,254);
  237.       PError << StdError(Warning)
  238.              << "string too long, may be truncated to 255 characters." << endl;
  239.     }
  240.   }
  241. }
  242. void ResourceObject::SetID(ResourceID * newId)
  243. {
  244.   if (newId == NULL)
  245.     id = -1;
  246.   else {
  247.     long num = newId->GetNum();
  248.     if (num < -32767 || num > 65535)
  249.        PError << StdError(Warning)
  250.              << "resource ID must be 16 bit, truncating." << endl;
  251.     id = (int)num;
  252.     identifier = newId->GetIdent();
  253.     delete newId;
  254.   }
  255. }
  256. PString ResourceObject::GetIDString() const
  257. {
  258.   if (identifier.IsEmpty())
  259.     return PString(PString::Unsigned, id);
  260.   return identifier;
  261. }
  262. PObject::Comparison ResourceObject::Compare (const PObject & obj) const
  263. {
  264.   int otherId = ((const ResourceObject &)obj).id;
  265.   if (id < otherId)
  266.     return LessThan;
  267.   if (id > otherId)
  268.     return GreaterThan;
  269.   return EqualTo;
  270. }
  271. PINDEX ResourceObject::HashFunction() const
  272. {
  273.   return PABSINDEX(id)%23;
  274. }
  275. /////////////////////////////////////////
  276. //
  277. //  A resource with a class specification
  278. //
  279. ClassedResource::ClassedResource(const char * className)
  280.   : resourceClass(className)
  281. {
  282. }
  283. ClassedResource::ClassedResource(PString * className)
  284.   : resourceClass(*className)
  285. {
  286.   delete className;
  287. }
  288. ClassedResource::ClassedResource(PString * className, PString * ancestorName)
  289.   : resourceClass(*className),
  290.     ancestorClass(*ancestorName)
  291. {
  292.   delete className;
  293.   delete ancestorName;
  294. }
  295. void ClassedResource::SetResClass(const PString & newClassname)
  296. {
  297.   resourceClass = newClassname;
  298.   classLine.Set();
  299. }
  300. /////////////////////////////////////////
  301. //
  302. //  menu items
  303. //
  304. void MenuItem::SetFieldName(PString * newFieldName)
  305. {
  306.   fieldName = *newFieldName;
  307.   delete newFieldName;
  308.   fieldLine.Set();
  309. }
  310. void MenuItem::SetNotify(PString * newNotify)
  311. {
  312.   notifyName = *newNotify;
  313.   if (notifyName(0,1) == "::")
  314.     PError << StdError(Fatal)
  315.            << "menu item notify cannot be non-member function." << endl;
  316.   delete newNotify;
  317.   notifyLine.Set();
  318. }
  319. void MenuItem::SetAccelerators(PStringList * newAcc)
  320. {
  321.   if (newAcc != NULL) {
  322.     for (PINDEX i = 0; i < newAcc->GetSize(); i++) {
  323.       AccelCode key((*newAcc)[i]);
  324.       if (key.GetValue() != PKeyCode::NullValue)
  325.         accel.Append(new PKeyCode(key));
  326.     }
  327.     delete newAcc;
  328.   }
  329. }
  330. BOOL MenuItem::NeedsWindowParameter() const
  331. {
  332.   return !notifyName.IsEmpty() && notifyName[0] != '"';
  333. }
  334. void MenuItem::OutputCode(ostream & hdr_stream,
  335.                                           ostream & src_stream, MenuBar & mbar)
  336. {
  337.   hdr_stream << hdr_before;
  338.   src_stream << src_before;
  339.   if (!notifyName.IsEmpty()) {
  340.     PINDEX i;
  341.     for (i = 0; i < mbar.itemDict.GetSize(); i++)
  342.       if (notifyName == mbar.itemDict.GetDataAt(i).notifyName)
  343.         break;
  344.     if (this == &mbar.itemDict.GetDataAt(i)) {
  345.       src_stream << notifyLine << "  PNotifier notifier_";
  346.       if (notifyName[0] == '"')
  347.         src_stream << notifyName(1, notifyName.GetLength()-2)
  348.                    << " = PCREATE_COMMAND(";
  349.       else {
  350.         src_stream << notifyName << " = PCREATE_NOTIFIER2(wnd, ";
  351.         if (notifyName.Find("::") == P_MAX_INDEX)
  352.           src_stream << mbar.window << "::";
  353.       }
  354.       src_stream << notifyName << ");n";
  355.     }
  356.     src_stream << "  keyedItems[" << id << "].SetNotifier(notifier_";
  357.     if (notifyName[0] == '"')
  358.       src_stream << notifyName(1, notifyName.GetLength()-2) << ", TRUE";
  359.     else
  360.       src_stream << notifyName;
  361.     src_stream << ");n";
  362.   }
  363.   if (!fieldName.IsEmpty()) {
  364.     hdr_stream << fieldLine
  365.                << "    PMenuItem * " << fieldName << ";n";
  366.     src_stream << fieldLine
  367.                << "  " << fieldName << " = GetItemFromKey(" << id << ");n";
  368.   }
  369.   hdr_stream << hdr_after;
  370.   src_stream << src_after;
  371. }
  372. /////////////////////////////////////////
  373. //
  374. //  sub-menus
  375. //
  376. Menu::Menu(PString * title, MenuItemList * newItems)
  377.   : MenuItem(NULL),
  378.     items(*newItems)
  379. {
  380.   delete newItems;
  381.   SetText(title);
  382. }
  383. void Menu::SetUniqueItemIDs(MenuItemDict & itemDict)
  384. {
  385.   for (PINDEX i = 0; i < items.GetSize(); i++) {
  386.     if (items[i].IsClass(Menu::Class()))
  387.       ((Menu&)items[i]).SetUniqueItemIDs(itemDict);
  388.     else {
  389.       if (items[i].GetID() == -1) {
  390.         items[i].SetID(current_file->GetUniqueIdentifierValue(itemDict));
  391.         itemDict.SetAt(items[i].GetID(), &items[i]);
  392.       }
  393.     }
  394.   }
  395. }
  396. /////////////////////////////////////////
  397. //
  398. //  menubar
  399. //
  400. MenuBar::MenuBar(ResourceID * newID)
  401. {
  402.   ancestorClass = "PRootMenu";
  403.   SetID(newID);
  404.   itemDict.DisallowDeleteObjects();
  405. }
  406. void MenuBar::SetWindow(PString * newWindow)
  407. {
  408.   window = *newWindow;
  409.   delete newWindow;
  410.   windowLine.Set();
  411. }
  412. void MenuBar::SetMenuList(MenuList * newMenus)
  413. {
  414.   menus = *newMenus;
  415.   delete newMenus;
  416.   for (PINDEX i = 0; i < menus.GetSize(); i++)
  417.     menus[i].SetUniqueItemIDs(itemDict);
  418. }
  419. void MenuBar::OutputCode(ostream & hdr_stream, ostream & src_stream)
  420. {
  421.   // if the class definition does not contain a class name or window
  422.   // the the generation of any output is supressed
  423.   if (resourceClass.IsEmpty()) {
  424.     PError << StdError(Info, firstLine)
  425.            << "code generation supressed due to omission of class namen";
  426.     return;
  427.   }
  428.   BOOL needsWindowParameter = FALSE;
  429.   PINDEX i;
  430.   for (i = 0; i < itemDict.GetSize(); i++)
  431.     if (itemDict.GetDataAt(i).NeedsWindowParameter()) {
  432.       needsWindowParameter = TRUE;
  433.       break;
  434.     }
  435.   if (needsWindowParameter && window.IsEmpty()) {
  436.     PError << StdError(Info, firstLine)
  437.            << "code generation supressed due to omission of window namen";
  438.     return;
  439.   }
  440.   hdr_stream << hdr_before
  441.              << classLine
  442.              << "PDECLARE_CLASS(" << resourceClass
  443.              << ", " << ancestorClass << ")n"
  444.              << "  public:"
  445.              << windowLine
  446.              << "    " << resourceClass << '(';
  447.   if (needsWindowParameter)
  448.     hdr_stream << window << " * wnd";
  449.   hdr_stream << ");n";
  450.   src_stream << "nnn// " << resourceClass << "n"
  451.              << src_before
  452.              << classLine
  453.              << resourceClass << "::" << resourceClass << '(';
  454.   if (needsWindowParameter)
  455.     src_stream << windowLine << window << " * wnd";
  456.   src_stream << ")n  : " << ancestorClass << '(' << id << ")n{n";
  457.   for (i = 0; i < itemDict.GetSize(); i++)
  458.     itemDict.GetDataAt(i).OutputCode(hdr_stream, src_stream, *this);
  459.   hdr_stream << hdr_after << "};n";
  460.   src_stream << src_after << "}n";
  461. }
  462. /////////////////////////////////////////
  463. //
  464. //  A resource with a class specification and a position
  465. //
  466. ComplexResource::ComplexResource(const char * className)
  467.   : ClassedResource(className),
  468.     dim(0, 0)
  469. {
  470.   dim_set = FALSE;
  471. }
  472. void ComplexResource::SetDim(Point * newDim)
  473. {
  474.   dim = *newDim;
  475.   delete newDim;
  476.   dim_set = TRUE;
  477. }
  478. void ComplexResource::SetPos(Point * newPos)
  479. {
  480.   pos = *newPos;
  481.   delete newPos;
  482. }
  483. /////////////////////////////////////////
  484. //
  485. //  Control
  486. //    The base control type
  487. //
  488. Control::Control(const char * className, const char * valType)
  489.   : ComplexResource(className), valueType(valType)
  490. {
  491.   options = 0;
  492.   iconID = -1;
  493. }
  494. void Control::SetValueName(PString * newValuename, PString * newInitialiser)
  495. {
  496.   if (valueType.IsEmpty()) 
  497.     PError << StdError(Fatal)
  498.            << "control class " << resourceClass
  499.            << " cannot have a Value attribute." << endl;
  500.   else {
  501.     valueName = *newValuename;
  502.     initialiser = *newInitialiser;
  503.     valueLine.Set();
  504.   }
  505.   delete newValuename;
  506.   delete newInitialiser;
  507. }
  508. void Control::SetFieldName(PString * newFieldName)
  509. {
  510.   fieldName = *newFieldName;
  511.   delete newFieldName;
  512.   fieldLine.Set();
  513. }
  514. void Control::SetNotify(PString * newNotify)
  515. {
  516.   notifyName = *newNotify;
  517.   delete newNotify;
  518.   notifyLine.Set();
  519. }
  520. void Control::SetOptions(long)
  521. {
  522.   PError << StdError(Fatal)
  523.          << "control class " << resourceClass
  524.          << " cannot have an Options attribute." << endl;
  525. }
  526. void Control::SetLimits(long, long, long, long)
  527. {
  528.   PError << StdError(Fatal)
  529.          << "control class " << resourceClass
  530.          << " cannot have a Limits attribute." << endl;
  531. }
  532. void Control::SetIcon(long)
  533. {
  534.   PError << StdError(Fatal)
  535.          << "control class " << resourceClass
  536.          << " cannot have an icon attribute." << endl;
  537. }
  538. void Control::SetHelp(PString * newHelp)
  539. {
  540.   balloonHelp = *newHelp;
  541.   delete newHelp;
  542. }
  543. void Control::SetStringList(PStringList *)
  544. {
  545.   PError << StdError(Fatal)
  546.          << "control class " << resourceClass
  547.          << " does not have an attached string list." << endl;
  548. }
  549. void Control::OutputCode(ostream & hdr_stream, ostream & src_stream,
  550.                          ostream & save, ostream & restore,
  551.                          PString & ok_button, PString & cancel_button,
  552.                          PString & help_button, Layout & layout)
  553. {
  554.   hdr_stream << hdr_before;
  555.   src_stream << src_before;
  556.   // calculate the name and type of the "field" attribute
  557.   // if the field attribute is local, then declare it 
  558.   // if it is global or static, then do NOT declare it
  559.   // in any case, add the command to the constructor
  560.   if (fieldName.IsEmpty()) {
  561.     if ((options & OkButtonOption) != 0) {
  562.       fieldName = "ok";
  563.       fieldLine = layout.firstLine;
  564.     }
  565.     else if ((options & CancelButtonOption) != 0) {
  566.       fieldName = "cancel";
  567.       fieldLine = layout.firstLine;
  568.     }
  569.     else if ((options & HelpButtonOption) != 0) {
  570.       fieldName = "help";
  571.       fieldLine = layout.firstLine;
  572.     }
  573.   }
  574.   else if (fieldName.Find("::") == P_MAX_INDEX)
  575.     hdr_stream << fieldLine
  576.                << "  public: " << resourceClass << " * " << fieldName << ";n";
  577.   PString idstr(PString::Unsigned, (long)id);
  578.   // add the constructor for the control to the layout constructor string
  579.   src_stream << classLine << "  ";
  580.   if (!fieldName.IsEmpty())
  581.     src_stream << fieldName << " = ";
  582.   src_stream << "PNEW " << resourceClass << "(this, " << idstr << ", ";
  583.   // declare and implement the notify function
  584.   if (notifyName.IsEmpty())
  585.     src_stream << "PNotifier(), ";
  586.   else if (notifyName[0] == '"')
  587.     src_stream << "PCREATE_COMMAND(" << notifyName << "), ";
  588.   else {
  589.     src_stream << "PCREATE_NOTIFIER(";
  590.     if (notifyName.Find("::") != P_MAX_INDEX) {
  591.       PString local_notify = "_pnotify_" + idstr;
  592.       hdr_stream << notifyLine
  593.                  <<  "  private: PDECLARE_NOTIFIER(" << resourceClass << ", "
  594.                  << layout.resourceClass << ", " << local_notify << ")n"
  595.                     "      { " << notifyName << "(note, extra); }n";
  596.       src_stream << local_notify;
  597.     }
  598.     else {
  599.       PINDEX i;
  600.       for (i = 0; i < layout.itemDict.GetSize(); i++)
  601.         if (notifyName == layout.itemDict.GetDataAt(i).notifyName)
  602.           break;
  603.       if (this == &layout.itemDict.GetDataAt(i))
  604.         hdr_stream << notifyLine
  605.                    << "  public: PDECLARE_NOTIFIER(" << resourceClass << ", "
  606.                    << layout.resourceClass << ", " << notifyName << ");n";
  607.       src_stream << notifyName;
  608.     }
  609.     src_stream << "), ";
  610.   }
  611.   // if there is a value field, output the declaration and
  612.   // add the command to the constructor
  613.   if (valueName.IsEmpty())
  614.     src_stream << "NULL);n";
  615.   else {
  616.     if (valueName.Find("::") == P_MAX_INDEX)
  617.       hdr_stream << valueLine
  618.                  << "  public: " << valueType << ' ' << valueName << ";n";
  619.     // declare the "undo" buffer
  620.     PString undo_name = "_psave_" + idstr;
  621.     hdr_stream << "  protected: " << valueType << ' ' << undo_name << ";n";
  622.     src_stream << '&' << valueName << ");n";
  623.     if (!initialiser.IsEmpty())
  624.       src_stream << "  " << valueName << " = " << initialiser << ";n";
  625.     save << "  " << undo_name << " = " << valueName << ";n";
  626.     restore << "  " << valueName << " = " << undo_name << ";n";
  627.   }
  628.   // grab ok, cancel and help buttons
  629.   if ((options & OkButtonOption) != 0)
  630.     ok_button = fieldName;
  631.   else if ((options & CancelButtonOption) != 0)
  632.     cancel_button = fieldName;
  633.   else if ((options & HelpButtonOption) != 0)
  634.     help_button = fieldName;
  635.   hdr_stream << hdr_after;
  636.   src_stream << src_after;
  637. }
  638. /////////////////////////////////////////
  639. //
  640. //  ListControl
  641. //    The base control type for list controls. This class exists because
  642. //    the AddString and SetOptions functions are overrided from Control
  643. //
  644. ListControl::ListControl(const char * className, const char * valueType)
  645.   : Control(className, valueType)
  646. {
  647. }
  648. void ListControl::SetOptions(long new_option)
  649. {
  650.   if (new_option & ~(SortedOption|MultiSelectOption|MultiColumnOption|Special))
  651.     PError << StdError(Fatal)
  652.            << "invalid option for " << resourceClass << " control." << endl;
  653.   else
  654.     options |= new_option;
  655. }
  656. void ListControl::SetStringList(PStringList * newStringList)
  657. {
  658.   strList = *newStringList; delete newStringList;
  659. }
  660. /////////////////////////////////////////
  661. //
  662. //  LimitControl
  663. //    The base control type for controls that support limits. This class exists
  664. //    because the SetLimits functions is overrided from Control
  665. //
  666. LimitControl::LimitControl (const char * className, const char * valueType)
  667.   : Control(className, valueType)
  668. {
  669.   minimum = 0;
  670.   maximum = 100;
  671.   smallNudge = 1;
  672.   largeNudge = 10;
  673. }
  674. void LimitControl::SetLimits(long min, long max, long sml, long lge)
  675. {
  676.   minimum = min;
  677.   maximum = max;
  678.   smallNudge = sml;
  679.   largeNudge = lge;
  680. }
  681. /////////////////////////////////////////
  682. //
  683. //  control types
  684. //
  685. void PushButton::SetOptions(long new_option)
  686. {
  687.   if (new_option & ~(OkButtonOption|CancelButtonOption|HelpButtonOption|DefaultButtonOption))
  688.     PError << StdError(Fatal)
  689.            << "invalid option for " << resourceClass << " control." << endl;
  690.   else
  691.     options |= new_option;
  692. }
  693. BOOL PushButton::Validate()
  694. {
  695.   if ((options & OkButtonOption) != 0) {
  696.     if (id != -1)
  697.       PError << StdError(Warning)
  698.              << "OK button should be ID 1." << endl;
  699.     else
  700.       id = 1;
  701.   }
  702.   else if ((options & CancelButtonOption) != 0) {
  703.     if (id != -1)
  704.       PError << StdError(Warning)
  705.              << "Cancel button should be ID 2." << endl;
  706.     else
  707.       id = 2;
  708.   }
  709.   else if ((options & HelpButtonOption) != 0) {
  710.     if (id != -1)
  711.       PError << StdError(Warning)
  712.              << "Help button should be ID 3." << endl;
  713.     else
  714.       id = 3;
  715.   }
  716.   return TRUE;
  717. }
  718. void StaticIcon::SetIcon(long icon)
  719. {
  720.   if (icon < -32767 || icon > 65535)
  721.     PError << StdError(Warning)
  722.            << "icon ID must be 16 bit, truncating." << endl;
  723.   iconID = (int)icon;
  724. }
  725. BOOL UserControl::Validate()
  726. {
  727.   if (resourceClass.IsEmpty()) {
  728.     PError << StdError(Fatal)
  729.            << "User controls must have class defined." << endl;
  730.     return FALSE;
  731.   }
  732.   return TRUE;
  733. }
  734. /////////////////////////////////////////
  735. //
  736. //  add a control to a layout
  737. //
  738. Layout::Layout(const PString & ancestorName, int type)
  739. {
  740.   subtype = type;
  741.   fontSize = -1;
  742.   itemDict.DisallowDeleteObjects();
  743.   SetAncestorClass(ancestorName);
  744. }
  745. void Layout::SetFontInfo(PString * newFontname, int nsize)
  746. {
  747.   fontName = *newFontname;
  748.   delete newFontname;
  749.   fontSize = nsize; 
  750. }
  751. void Layout::SetHeader(PString * newHeader)
  752. {
  753.   header = *newHeader;
  754.   delete newHeader;
  755. }
  756. void Layout::AddControl(Control * newControl)
  757. {
  758.   if (!newControl->Validate())
  759.     return;
  760.   if (itemDict.GetAt(newControl->GetID()) != NULL) {
  761.     PError << StdError(Warning)
  762.            << "ignoring multiple definition of dialog item "
  763.            << newControl->GetID() << '.' << endl;
  764.     return;
  765.   }
  766.   if (newControl->GetID() != -1)
  767.     itemDict.SetAt(newControl->GetID(), newControl);
  768.   itemList.Append(newControl);
  769.   if (!dim_set) {
  770.     Point ctl_pos = newControl->GetPos();
  771.     Point ctl_dim = newControl->GetDim();
  772.     int tmp = ctl_pos.X()+ctl_dim.X()+10;
  773.     if (dim.X() < tmp)
  774.       dim.SetX(tmp);
  775.     tmp = ctl_pos.Y()+ctl_dim.Y()+10;
  776.     if (dim.Y() < tmp)
  777.       dim.SetY(tmp);
  778.   }
  779. }
  780. void Layout::SetUniqueItemIDs()
  781. {
  782.   for (PINDEX i = 0; i < itemList.GetSize(); i++)
  783.     if (itemList[i].GetID() == -1) {
  784.       itemList[i].SetID(current_file->GetUniqueIdentifierValue(itemDict));
  785.       itemDict.SetAt(itemList[i].GetID(), &itemList[i]);
  786.     }
  787. }
  788. void Layout::OutputCode(ostream & hdr_stream, ostream & src_stream)
  789. {
  790.   // if the class definition does not contain a class name,
  791.   // the the generation of any output is supressed
  792.   if (resourceClass.IsEmpty()) {
  793.     PError << StdError(Info, firstLine) 
  794.            << "code generation supressed due to omission of class namen";
  795.     return;
  796.   }
  797.   src_stream << "nnn// " << resourceClass << "nn";
  798.   // output class declaration and constructor code or Construct body
  799.   if (header.IsEmpty()) {
  800.     hdr_stream << classLine
  801.                << "PDECLARE_CLASS(" << resourceClass << ", "
  802.                << ancestorClass << ")n"
  803.                << hdr_before
  804.                << "  public:n"
  805.                << "    " << resourceClass
  806.                << "(PInteractor *, PRESOURCE_ID id = " << id << ");n";
  807.     src_stream << classLine << resourceClass << "::" << resourceClass
  808.                << "(PInteractor * parent, PRESOURCE_ID id)n"
  809.                   "  : " << ancestorClass << "(parent, id)n"
  810.                   "{n";
  811.   }
  812.   else {
  813.     hdr_stream << "#include " << header << "nn"
  814.                << hdr_before
  815.                << "  public:n"
  816.                   "    void Construct(PRESOURCE_ID id = " << id << ");n";
  817.     src_stream << "void " << resourceClass << "::Construct(PRESOURCE_ID id)n"
  818.                   "{n";
  819.   }
  820.   src_stream << src_before;
  821.   PStringStream layout_save, layout_restore;
  822.   PString ok_button, cancel_button, help_button;
  823.   for (PINDEX i = 0; i < itemList.GetSize(); i++)
  824.     itemList[i].OutputCode(hdr_stream, src_stream,
  825.                            layout_save, layout_restore,
  826.                            ok_button, cancel_button, help_button,
  827.                            *this);
  828.   // output public declarations and constructor declaration
  829.   if (!layout_save.IsEmpty())
  830.     hdr_stream << "  public:n"
  831.                   "    void Restore();n"
  832.                   "    void Save();n";
  833.   // finish class declaration
  834.   hdr_stream << hdr_after << "n};nn";
  835.   if (subtype == 0) {
  836.     if (!ok_button.IsEmpty() || !cancel_button.IsEmpty())
  837.       PError << StdError(Info, firstLine)
  838.              << "layout defined with "Ok" or "Cancel" buttonn";
  839.   }
  840.   else {
  841.     if (subtype == 2 && ok_button.IsEmpty() && cancel_button.IsEmpty())
  842.       PError << StdError(Warning, firstLine)
  843.              << "modal dialog defined without "Ok" or "Cancel" buttonn";
  844.     src_stream << "  SetStdButtons(";
  845.     if (ok_button.IsEmpty())
  846.       src_stream << "NULL";
  847.     else
  848.       src_stream << ok_button;
  849.     src_stream << ", ";
  850.     if (cancel_button.IsEmpty())
  851.       src_stream << "NULL";
  852.     else
  853.       src_stream << cancel_button;
  854.     src_stream << ", ";
  855.     if (help_button.IsEmpty()) 
  856.       src_stream << "NULL";
  857.     else
  858.       src_stream << help_button;
  859.     src_stream << ");n";
  860.   }
  861.   src_stream << "  ConstructEnd(id);n"
  862.              << src_after
  863.              << "}nn";
  864.   // output the save and restore functions if there is something in them
  865.   if (!layout_save.IsEmpty()) 
  866.     src_stream << "void "
  867.                << resourceClass
  868.                << "::Save()n{n"
  869.                << layout_save
  870.                << "n}nnvoid "
  871.                << resourceClass
  872.                << "::Restore()n{n"
  873.                << layout_restore
  874.                << "n}nnn";
  875. }
  876. /////////////////////////////////////////
  877. //
  878. //  holder for assorted binary data items
  879. //
  880. BinaryData::BinaryData()
  881.   : PAbstractArray(sizeof(BYTE), 512),
  882.     realSize(0)
  883. {
  884. }
  885. BinaryData::BinaryData(const BinaryData & array)
  886.   : PAbstractArray(array),
  887.     realSize(array.realSize)
  888. {
  889. }
  890. BinaryData & BinaryData::operator=(const BinaryData & array)
  891. {
  892.   PAbstractArray::operator=(array);
  893.   realSize = array.realSize;
  894.   return *this;
  895. }
  896. void BinaryData::Append (int newSize, const BYTE * newData)
  897. {
  898.   if (realSize + newSize > PAbstractArray::GetSize())
  899.     SetSize((PAbstractArray::GetSize() + newSize+511)&~511);
  900.   memcpy (theArray + realSize, newData, newSize);
  901.   realSize += newSize;
  902. }
  903. /////////////////////////////////////////
  904. //
  905. //  pixel resource objects
  906. //
  907. PixelContents::PixelContents()
  908. {
  909.   haveDimensions = FALSE;
  910.   haveHotSpot = FALSE;
  911.   depth = 1;
  912. }
  913. void PixelContents::SetDimensions(long w, long h, long d)
  914. {
  915.   if (w < -32767 || w > 32767 || h < -32767 || h > 32767)
  916.       PError << StdError(Warning)
  917.              << "image dimensions must be 16 bit, truncating." << endl;
  918.   if (d < 0 || d > 32767)
  919.       PError << StdError(Warning)
  920.              << "image depth must be 16 bit, truncating." << endl;
  921.   width = (int)w;
  922.   height = (int)h;
  923.   depth = (int)d;
  924.   haveDimensions = TRUE;
  925. }
  926.       
  927. void PixelContents::SetHotSpot(long hx, long hy)
  928. {
  929.   if (hx < -32767 || hx > 32767 || hy < -32767 || hy > 32767)
  930.       PError << StdError(Warning)
  931.              << "image position must be 16 bit, truncating." << endl;
  932.   x = (int)hx;
  933.   y = (int)hy;
  934.   haveHotSpot = TRUE;
  935. }
  936. void PixelContents::SetClut(BinaryData * data)
  937. {
  938.   clut = *data;
  939.   delete data;
  940. }
  941. void PixelContents::SetAndMask(PixData * data)
  942. {
  943.   andMask = *data;
  944.   delete data;
  945. }
  946. void PixelContents::SetXorMask(PixData * data)
  947. {
  948.   xorMask = *data;
  949.   delete data;
  950. }
  951. void PixelContents::SetPixels(PixData * data)
  952. {
  953.   pixels = *data;
  954.   delete data;
  955. }
  956. void PixelContents::Verify(int dfltWidth, int dfltHeight, const char * resname,
  957.                            BOOL masks, BOOL allowScaling)
  958. {
  959.   if (haveDimensions) {
  960.     if ((dfltWidth  != 0 && width  != dfltWidth  && (!allowScaling || (width  != dfltWidth*2  && width  != dfltWidth/2))) ||
  961.         (dfltHeight != 0 && height != dfltHeight && (!allowScaling || (height != dfltHeight*2 && height != dfltHeight/2))))
  962.       PError << StdError(Warning)
  963.              << resname << " dimensions should be "
  964.              << dfltWidth << 'x' << dfltHeight << '.' << endl;
  965.   }
  966.   else {
  967.     if (dfltWidth != 0) { // Is Pixmap
  968.       width = dfltWidth;
  969.       height = dfltHeight;
  970.     }
  971.     else {
  972.       PError << StdError(Fatal)
  973.              << resname << " must have a dimension." << endl;
  974.       return;
  975.     }
  976.   }
  977.   if (depth != 1 && depth != 4 && depth != 8 && depth != 24) {
  978.     PError << StdError(Fatal)
  979.            << resname << " should have depth of 1, 4, 8 or 24 bits." << endl;
  980.     return;
  981.   }
  982.   if (clut.GetSize() != 0 || (depth != 1 && depth != 24)) {
  983.     int clutSize = (1 << depth)*3;
  984.     if (clut.GetSize() != (PINDEX)clutSize) {
  985.       PError << StdError(Warning)
  986.              << resname << " should have "
  987.              << clutSize << " bytes of colour data ("
  988.              << clut.GetSize() << " found)." << endl;
  989.       clut.SetSize((PINDEX)clutSize);
  990.     }
  991.   }
  992.   if (clut.GetSize() == 0) {
  993.     int numColours = 1 << depth;
  994.     int inc = (256+numColours-1)/numColours;
  995.     int val = 0;
  996.     for (int col = 0; col < numColours-1; col++) {
  997.       clut.Append((BYTE)val);
  998.       clut.Append((BYTE)val);
  999.       clut.Append((BYTE)val);
  1000.       val += inc;
  1001.     }
  1002.     clut.Append(0xff);
  1003.     clut.Append(0xff);
  1004.     clut.Append(0xff);
  1005.   }
  1006.   if (!masks || depth != 1) { // Is Pixmap or colour icon/cursor
  1007.     long pixSize = width*height;
  1008.     if (depth == 24)
  1009.       pixSize *= 3;
  1010.     if (pixels.GetSize() != (PINDEX)pixSize) {
  1011.       PError << StdError(Warning)
  1012.              << resname << " should have "
  1013.              << pixSize << " pixels ("
  1014.              << pixels.GetSize() << " found)." << endl;
  1015.       pixels.SetSize((PINDEX)pixSize);
  1016.     }
  1017.   }
  1018.   if (masks) { // Is Icon or Cursor
  1019.     long maskSize = width*height;
  1020.     if (andMask.GetSize() != (PINDEX)maskSize) {
  1021.       PError << StdError(Warning)
  1022.              << resname << " should have "
  1023.              << maskSize << " pixels of AND mask data ("
  1024.              << andMask.GetSize() << " found)." << endl;
  1025.       andMask.SetSize((PINDEX)maskSize);
  1026.     }
  1027.     if (depth == 1 && xorMask.GetSize() != (PINDEX)maskSize) {
  1028.       PError << StdError(Warning)
  1029.              << resname << " should have "
  1030.              << maskSize << " pixels of XOR mask data ("
  1031.              << xorMask.GetSize() << " found)." << endl;
  1032.       xorMask.SetSize((PINDEX)maskSize);
  1033.     }
  1034.   }
  1035. }
  1036. /////////////////////////////////////////
  1037. //
  1038. //  pixel based resources
  1039. //
  1040. PixelResource::PixelResource(ResourceID * newId, PixelContents * newContents)
  1041.   : ResourceObject(newId, NULL),
  1042.     contents(*newContents)
  1043. {
  1044.   delete newContents;
  1045. }
  1046. /////////////////////////////////////////
  1047. //
  1048. //  icon resources
  1049. //
  1050. Icon::Icon(ResourceID * id, PixelContents * newContents)
  1051.   : PixelResource(id, newContents)
  1052. {
  1053.   contents.Verify(32, 32, "icon", TRUE, TRUE);
  1054. }
  1055. /////////////////////////////////////////
  1056. //
  1057. //  cursor resources
  1058. //
  1059. CursorResource::CursorResource(ResourceID * id, PixelContents * newContents)
  1060.   : PixelResource(id, newContents)
  1061. {
  1062.   contents.Verify(16, 16, "cursor", TRUE, FALSE);
  1063.   if (!contents.haveHotSpot) {
  1064.     PError << StdError(Info)
  1065.          << "cursor should have a HOTSPOT, assuming 1,1." << endl;
  1066.     contents.x = contents.y = 1;
  1067.   }
  1068. }
  1069. /////////////////////////////////////////
  1070. //
  1071. //  pattern resources
  1072. //
  1073. Pattern::Pattern(ResourceID * id, PixelContents * newContents)
  1074.   : PixelResource(id, newContents)
  1075. {
  1076.   contents.Verify(8, 8, "pattern", FALSE, FALSE);
  1077. }
  1078. /////////////////////////////////////////
  1079. //
  1080. //  image resources
  1081. //
  1082. Image::Image(ResourceID * id, PixelContents * newContents)
  1083.   : PixelResource(id, newContents)
  1084. {
  1085.   contents.Verify(0, 0, "image", FALSE, FALSE);
  1086. }
  1087. /////////////////////////////////////////
  1088. //
  1089. //  arbitrary data resources
  1090. //
  1091. DataResource::DataResource(ResourceID * id,
  1092.                                        PString * newText, BinaryData * newData)
  1093.   : ResourceObject(id, NULL), data(*newData)
  1094. {
  1095.   delete newData;
  1096.   if (newText != NULL) {
  1097.     textLiteral = *newText;
  1098.     delete newText;
  1099.     textConverted = PString(PString::Literal, textLiteral);
  1100.     if (textConverted.GetLength() < 4) {
  1101.       textConverted += "    ";
  1102.       textConverted = textConverted(0,3);
  1103.       PError << StdError(Info)
  1104.              << "resource type name too short, spaced out to 4 characters."
  1105.              << endl;
  1106.     }
  1107.     else if (textConverted.GetLength() > 4) {
  1108.       textConverted = textConverted(0,3);
  1109.       PError << StdError(Warning)
  1110.              << "resource type name too long, truncated to 4 characters."
  1111.              << endl;
  1112.     }
  1113.   }
  1114. }
  1115. /////////////////////////////////////////
  1116. //
  1117. //  resource file data
  1118. //
  1119. void ResourceFile::OutputCode(const PFilePath & hdrname,
  1120.                  ostream & hdr_stream, ostream & src_stream, BOOL suppressFlag)
  1121. {
  1122.   src_stream << "//n// Source file generated by PWRCn//nn";
  1123.   if (!suppressFlag) 
  1124.     src_stream << "#include <pwlib.h>n"
  1125.                   "#include "" << hdrname.GetFileName() << ""nn";
  1126.   hdr_stream << "//n// Header file generated by PWRCn//nn"
  1127.              << "#ifndef _PWRC_GENERATED_HEADERn"
  1128.              << "#define _PWRC_GENERATED_HEADERnn"
  1129.              << hdr_inline;
  1130.   src_stream << src_inline;
  1131.   PINDEX i;
  1132.   for (i = 0; i < menubarDict.GetSize(); i++)
  1133.     menubarDict.GetDataAt(i).OutputCode(hdr_stream, src_stream);
  1134.   for (i = 0; i < dialogDict.GetSize(); i++)
  1135.     dialogDict.GetDataAt(i).OutputCode(hdr_stream, src_stream);
  1136.   hdr_stream << "n#endifnn";
  1137. }
  1138. ResourceID * ResourceFile::GetAutoIdentifier(PString * identifier,
  1139.                                               const PAbstractDictionary & dict)
  1140. {
  1141.   PString ident = *identifier;
  1142.   if (defineDict.GetAt(ident) != NULL)
  1143.     return PNEW ResourceID(GetIdentifierValue(identifier), ident);
  1144.   while (dict.GetAt(nextResourceId) != NULL)
  1145.     nextResourceId++;
  1146.   hdr_inline << LineNumber()
  1147.              << "#define " << ident << ' ' << nextResourceId << 'n';
  1148.   AddDefineIdentifier(identifier, new DefineValue(nextResourceId, TRUE));
  1149.   return PNEW ResourceID(nextResourceId, ident);
  1150. }
  1151. ResourceID * 
  1152.        ResourceFile::GetUniqueIdentifierValue(const PAbstractDictionary & dict)
  1153. {
  1154.   while (dict.GetAt(nextResourceId) != NULL)
  1155.     nextResourceId++;
  1156.   return PNEW ResourceID(nextResourceId++);
  1157. }
  1158. void ResourceFile::AddDefineIdentifier(PString * identifer,DefineValue * value)
  1159. {
  1160.   if (defineDict.GetAt(*identifer) == NULL)
  1161.     defineDict.SetAt(*identifer, value);
  1162.   else {
  1163.     PError << StdError(Warning) 
  1164.          << "ignoring redefinition of macro "" << *identifer << ""." << endl;
  1165.     delete value;
  1166.   }
  1167.   delete identifer;
  1168. }
  1169. int ResourceFile::GetIdentifierValue(PString * identifier)
  1170. {
  1171.   PString id = *identifier;
  1172.   delete identifier;
  1173.   if (defineDict.GetAt(id) == NULL) {
  1174.     PError << StdError(Fatal)
  1175.            << "reference to undefined macro "" << id << ""." << endl;
  1176.     return 1;
  1177.   }
  1178.   if (defineDict[id].IsString()) {
  1179.     PError << StdError(Fatal)
  1180.            << "macro "" << id << "" of incorrect type." << endl;
  1181.     return 1;
  1182.   }
  1183.   return (int)defineDict[id];
  1184. }
  1185. void ResourceFile::AddResource(ResourceList::ResTypes res,
  1186.                                     ResourceObject * obj, const char * resname)
  1187. {
  1188.   if (obj->GetID() == -1)
  1189.     obj->SetID(GetUniqueIdentifierValue(*resourceDict[res]));
  1190.   if (resourceDict[res]->GetAt(obj->GetID()) == NULL) {
  1191.     resourceDict[res]->SetAt(obj->GetID(), obj);
  1192.     resources[res].Append(obj);
  1193.   }
  1194.   else {
  1195.     PError << StdError(Warning)
  1196.            << "ignoring redefinition of " << resname << " resource number "
  1197.            << obj->GetID() << '.' << endl;
  1198.     delete obj;
  1199.   }
  1200. }
  1201. // End CODEGEN.CXX ////////////////////////////////////////////////////////////