home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / msysjour / vol04 / 02b / project / classes / projwind.cls < prev    next >
Text File  |  1988-11-30  |  26KB  |  920 lines

  1. /* Maintain a Project chart in a Window. The ProjWindow is
  2.    responsible for all drawing of the project. The window 
  3.    has full scrolling and supports a keyboard interface.
  4.    If topMethod or botMethod are set, then the corresponding
  5.    method will be executed for each activity while displaying
  6.    the project.
  7.  
  8.    ProjWindow descends from class Window and inherits all of
  9.    its instance variables and methods.
  10.  
  11.    All strings are defined as resources for easy translation.
  12. */!!
  13.  
  14. inherit(Window, #ProjWindow, #(project     /* the project */
  15. fileName    /* of the project */
  16. actions     /* menu actions table */
  17. dirty       /* true if not saved */
  18. view        /* normal or zoomed */
  19. boxHeight   /* based on scrnsize */
  20. boxWidth    /* adjustable for zoom */
  21. boxHSpace   /* adjustable */
  22. activWidth  /* adjustable */
  23. hScrollPos  /* horiz scroll posn */
  24. vScrollPos  /* vert scroll posn */
  25. maxVisCol   /* max visible col */
  26. maxVisRow   /* max visible row */
  27. methTable   /* table of methods */
  28. topMethod   /* offset into table */
  29. botMethod   /* offset into table */
  30. gw          /* a GanttWindow */), 2, nil)!!
  31.  
  32. now(ProjWindowClass)!!
  33.  
  34. /* Return the name of this class's MS-Windows window class
  35.   either for registration or new window creation. */
  36. Def wndClass(self)
  37. { ^"ProjWindow"  }!!
  38.  
  39. /* Create a new window class Struct.
  40.    Change the cursor to a cross.  */
  41. Def newWClass(self, lpCl, lpIcon | wc)
  42. { wc := newWClass(self:WindowClass, lpCl, lpIcon);
  43.   putWord(wc, Call LoadCursor(0, IDC_CROSS), 14);
  44.   ^wc;
  45. } !!
  46.  
  47. now(ProjWindow)!!
  48.  
  49. /* Create the window using a "main" window style. */
  50. Def create(self, par, wName, rect, style)
  51.   ^create(self:Window, nil, wName, rect, 
  52.      WS_OVERLAPPEDWINDOW bitOr WS_VSCROLL bitOr WS_HSCROLL);
  53. }!!
  54.  
  55. /* Set up a dummy project, menus and the method table. */
  56. Def init(self)
  57. {  
  58.   setProject(self, new(Project));
  59.   setAutoCalc(project, true);  
  60.   setView(self, #normal);
  61.   setScrollBars(self);
  62.   setMenus(self);
  63.   checkMenuItem(self, PW_AUTOCALC);
  64.   setMethTable(self);
  65. }!!
  66.  
  67. /* Set the project. */
  68. Def setProject(self, aProject)
  69. {
  70.   project := aProject;
  71. }!!
  72.  
  73. /* Set the resolution for the size of nodes, spacing etc.
  74.    based on the font text size.  There are two views,
  75.    normal and small.  Both are based on text font size so
  76.    that they will display adequately with any resolution. */
  77. Def setView(self, aView | hDC, ts)
  78. {
  79.   view := aView;
  80.   hDC := getContext(self);    /* so we can get text size */
  81.   ts := textSize(self, hDC);  /* x is width, y is height */
  82.   releaseContext(self, hDC);
  83.   if view == #small
  84.     boxWidth := x(ts) * 4;
  85.     boxHSpace := x(ts)/2 + 1;
  86.     boxHeight := y(ts) + 4;
  87.   else
  88.     boxWidth := asInt(x(ts)*8);
  89.     boxHSpace := x(ts) + 2;
  90.     boxHeight := y(ts) * 2;   
  91.   endif;
  92.   activWidth := boxWidth + boxHSpace;
  93.   reSize(self, 0, 0L);        /* so scrolling is adjusted */
  94. }!!
  95.  
  96. /* Set the scroll bar ranges and initial positions. */
  97. Def setScrollBars(self)
  98.   Call SetScrollRange(hWnd, SB_HORZ, 0, PW_MAX_COLS, 0);
  99.   Call SetScrollRange(hWnd, SB_VERT, 0, PW_MAX_ROWS, 0);
  100.   hScrollPos := vScrollPos := 0; 
  101. }!!
  102.  
  103. /* Set up the method table used for display options. 
  104.    Each of these methods should be applicable to all
  105.    activities in the project, that is, both Milestones
  106.    and Tasks. */
  107. Def setMethTable(self)
  108. {
  109.     methTable := #(#getTime, 
  110.                    #getSlack, 
  111.                    #getCost,
  112.                    #getEarlyStart,
  113.                    #getEarlyFinish,
  114.                    #getLateStart,
  115.                    #getLateFinish);
  116.   topMethod := 3;
  117. }!!
  118.  
  119. /* Set the method to display info below each box. 
  120.    The offset refers to the position in the
  121.    methTable. */
  122. Def setBotMethod(self, offset)
  123. {
  124.   botMethod := offset;
  125. }!!
  126.  
  127. /* Set the method to display info atop each box. 
  128.    The offset refers to the position in the
  129.    methTable. */
  130. Def setTopMethod(self, offset)
  131. {
  132.   topMethod := offset;
  133. }!!
  134.  
  135. /* Add an about box and load menu resources.
  136.    Set up the menu actions table. */
  137. Def setMenus(self)
  138. {
  139.   addAbout(self);
  140.   loadMenu(self, "PWMenus");
  141.   setMenu(self, hMenu);
  142.  
  143.   actions := new(Dictionary, 30);
  144.  
  145.   add(actions, PW_FILE_NEW, #fileNew);
  146.   add(actions, PW_FILE_OPEN, #fileOpenAs);
  147.   add(actions, PW_FILE_SAVE, #fileSave);
  148.   add(actions, PW_FILE_SAVEAS, #fileSaveAs);
  149.   add(actions, PW_FILE_PRINT, #print);
  150.   add(actions, PW_FILE_PRINT_GRAPH, #printGraphs);
  151.   add(actions, PW_ABOUT_ACTOR, #aboutActor);
  152.   add(actions, PW_DEL_ACTIVITY, #deleteActivity);
  153.   add(actions, PW_DEL_RESOURCE, #deleteResource);
  154.   add(actions, PW_NEW_MSTONE, #newMilestone);
  155.   add(actions, PW_NEW_TASK, #newTask);
  156.   add(actions, PW_NEW_PERT, #newPERTTask);
  157.   add(actions, PW_DISPLAY, #displaySettings);
  158.   add(actions, PW_AUTOCALC, #autoCalc);
  159.   add(actions, PW_CALC, #recalc);
  160.   add(actions, PW_SHOWROOM, #showRoom);
  161.   add(actions, PW_ZOOM, #zoom);
  162.   add(actions, PW_VIEW_SUMMARY, #viewSummary);
  163.   add(actions, PW_VIEW_ACTIVITIES, #showActivities);
  164.   add(actions, PW_VIEW_GANTT, #gantt);
  165.   add(actions, PW_VIEW_RESOURCES, #showResources);
  166.   add(actions, PW_VIEW_RESOURCE, #editResource);
  167.  
  168.     /* keyboard accelerator commands */
  169.     
  170.   add(actions, PW_HELP, #help);
  171.   add(actions, EDIT_HOME, #home);
  172.   add(actions, PW_COMMAND_MODE, #commandMode);
  173. }!!
  174.  
  175. /* Convert window coordinates to relative display coordinates. */
  176. Def windowToDisplay(self, wPoint)
  177. {
  178.   ^point((x(wPoint) - boxHSpace) / activWidth  + hScrollPos,
  179.          (y(wPoint) - boxHeight) / (boxHeight*2) + vScrollPos);
  180. }!!
  181.  
  182. /* Convert relative display entries to window coordinates. 
  183.    Uses dot notation for speed. */
  184. Def displayToWindow(self, dPoint)
  185. {
  186.    ^point(boxHSpace + (dPoint.x - hScrollPos) * activWidth,
  187.           boxHeight + (dPoint.y - vScrollPos) * boxHeight*2);          
  188. }!!
  189.  
  190. /* The name of application, used for captions. */
  191. Def  appName(self)
  192.   ^loadString(PW_APPNAME);
  193. }!!
  194.  
  195. /* Returns true if the node is visible in the window.
  196.    Used to speed up redrawing. Uses dot notation for speed. */
  197. Def visible(self, aNode)
  198.   ^between(aNode.x, hScrollPos, maxVisCol + hScrollPos)
  199.      cand between(aNode.y, vScrollPos, maxVisRow + vScrollPos);
  200. }!!
  201.  
  202. /* Set up the cursor for use even if there is no mouse. */
  203. Def gotFocus(self, prevHwnd)
  204.   Call ShowCursor(1);
  205. }!!
  206.  
  207. /* Return to normal use of cursor.  */
  208. Def losingFocus(self, hWndNew)
  209.   Call ShowCursor(0);
  210. } !!
  211.  
  212. /* Check if the project has been saved. */
  213. Def shouldClose(self)
  214.   ^checkClean(self)
  215. }!!
  216.  
  217. /* Make sure the window knows that the project has changed. */
  218. Def dirty(self)
  219. {
  220.   invalidate(self);
  221.   dirty := true;
  222.   if gw
  223.     invalidate(gw);
  224.   endif;
  225. }!!
  226.  
  227. /* Returns boolean value true if the project has
  228.    not changed since last save.  If it is dirty,
  229.    the user is prompted for confirmation.  */
  230. Def checkClean(self)
  231. {
  232.   ^ not(dirty) cor 
  233.      yesNoBox(loadString(PW_WARNING),
  234.               loadString(PW_DISCARD)) == IDYES;
  235. }!!
  236.  
  237. /* Get the offset of the botMethod. */
  238. Def getBotMethod(self)
  239. {
  240.   ^botMethod;
  241. }!!
  242.  
  243. /* Get the offset of the topMethod. */
  244. Def getTopMethod(self)
  245. {
  246.   ^topMethod;
  247. }!!
  248.  
  249. /* Resize the window.  Adjust visible rows and cols. */
  250. Def reSize(self, wp, lp)
  251.   maxVisRow := bottom(clientRect(self)) / (boxHeight*2);
  252.   maxVisCol := right(clientRect(self)) / activWidth;
  253. }!!
  254.  
  255. /* Respond to MS-Windows messages to paint the window. 
  256.    Show the project as a network chart.
  257.    Draw each visible node in its proper position. 
  258.    Display the name and any other info required.
  259.    Then draw the lines to connect the outputs.
  260.    
  261.    The displayToWindow message converts a node's
  262.    logical display position to windows coordinates.
  263.    
  264.    This could be further speeded up by repainting 
  265.    only the invalid rectangle.
  266. */
  267. Def paint(self, hDC |wPoint, x, y)
  268. {
  269.   do(nodes(project), 
  270.    {using(aNode)
  271.    
  272.    wPoint := displayToWindow(self, pos(aNode));
  273.    x := x(wPoint);    /* horiz windows posn */
  274.    y := y(wPoint);    /* vert windows posn */
  275.     
  276.    if visible(self, aNode)
  277.      draw(aNode, self, x, y, hDC);  /* node knows how to draw */ 
  278.      drawTextInfo(self, aNode, x, y, hDC);
  279.    endIf;
  280.    /* always draw connections since they may be visible */
  281.    drawConnections(self, aNode, x, y, getOutputs(aNode), hDC);
  282.   }); 
  283. }!!
  284.  
  285. /* Draw lines connecting the nodes in the window. 
  286.    Uses early binding, dot notation and direct
  287.    Windows calls for speed. */
  288. Def drawConnections(self, aNode, x, y, connectedNodes, hDC | wPoint)
  289. {
  290.      do(connectedNodes,
  291.        {using(output)  
  292.         Call MoveTo(hDC,  x + boxWidth, y + boxHeight/2);
  293.         wPoint := displayToWindow(self:ProjWindow, pos(output));
  294.         Call LineTo(hDC, wPoint.x, wPoint.y + boxHeight/2);
  295.  
  296.         if critical(aNode:Activity) cand critical(output:Activity)  
  297.           Call MoveTo(hDC,  x + boxWidth, y + boxHeight/2+1);
  298.           Call LineTo(hDC, wPoint.x, wPoint.y + boxHeight/2+1);
  299.         endif;       
  300.      });   
  301. }!!
  302.  
  303. /* Draw text info in the window.  If the small view is
  304.    being used, show less information.
  305.    Uses early binding and dot notation for speed. */
  306. Def drawTextInfo(self, aNode, x, y, hDC | ts, str, strSize, offsetY, offsetX)
  307. {
  308.  ts := textSize(self, hDC);
  309.  offsetY := (boxHeight - ts.y) / 2;
  310.  strSize := boxWidth / ts.x;
  311.  if view == #small
  312.    offsetX := 2;   /* to make milestones look ok */
  313.  else
  314.    offsetX := 0;
  315.  endif;
  316.  
  317.  str := subString(aNode.name, 0, strSize-1);
  318.  Call TextOut(hDC, x + offsetX + 2, y + offsetY, str, size(str));     
  319.  
  320.  if topMethod     /* display above box */
  321.    str := subString(asString(perform(aNode, methTable[topMethod])),0,strSize);
  322.    Call TextOut(hDC, x + 2, y - ts.y, str, size(str));
  323.  endif;
  324.  
  325.  if view ~= #small
  326.  cand botMethod     /* display below box */
  327.      str :=  subString(asString(perform(aNode, methTable[botMethod])),0,strSize);
  328.      Call TextOut(hDC, x + 2, y + boxHeight, str, size(str));
  329.  endif;
  330. }!!
  331.  
  332. /* Draw a task in the window. 
  333.    Uses early binding and direct Windows call for speed. */
  334. Def drawTask(self, aNode, x, y, hDC)
  335. {
  336.   Call Rectangle(hDC, x, y, x + boxWidth, y + boxHeight);
  337.   if critical(aNode:Activity)
  338.     Call Rectangle(hDC, x+1, y+1, x + boxWidth-1, y + boxHeight-1);
  339.   endif;
  340. }!!
  341.  
  342. /* Draw a milestone in the window. 
  343.    Uses early binding and direct Windows call for speed. */
  344. Def drawMilestone(self, aNode, x, y, hDC)
  345. {
  346.   Call RoundRect(hDC, x, y, x + boxWidth, y + boxHeight, 20,20);
  347.   if critical(aNode:Activity)
  348.     Call RoundRect(hDC, x+1, y+1, x + boxWidth-1, y + boxHeight-1, 17,17);
  349.   endif;     
  350. }!!
  351.  
  352. /* Handle menu events, accelerator keys.
  353.    Lookup the ID in the actions table, if found
  354.    perform it.  */
  355. Def command(self, wp, lp)
  356. {
  357.   if actions[wp]
  358.     perform(self, actions[wp]);
  359.   else
  360.     beep();
  361.     errorBox(loadString(PW_ERROR1), loadString(PW_ERROR2) + asString(wp));
  362.   endif;
  363. }!!
  364.  
  365. /* Go into "command mode" in response to a slash key accelerator.
  366.    This simulates Lotus 1-2-3 style commands by sending an
  367.    ALT key sysCommand message. */
  368. Def commandMode(self)
  369.   WM_SYSCOMMAND(self, 0xF100, 0L);
  370. }!!
  371.  
  372. /* Get a filename from the user in responds to menu event.
  373.    If the file has changed, check with the user.
  374.    Send a fileOpen message to do the work. */
  375. /* Respond to menu choice to create a new project. */
  376. Def fileNew(self)
  377. {
  378.   if checkClean(self)
  379.     if gw
  380.       close(gw);
  381.     endif;
  382.     fileName := nil;
  383.     dirty := nil;  
  384.     setProject(self, new(Project));
  385.     checkMenuItem(self, PW_AUTOCALC);
  386.     setAutoCalc(project, true);
  387.     setText(self, appName(self));   
  388.     editInfo(project);
  389.     invalidate(self);
  390.   endif;
  391. }!!
  392.  
  393. Def fileOpenAs(self | dlg, file, reader)
  394. {
  395.   if checkClean(self)
  396.     dlg := new(FileDialog, "*.PRJ");
  397.     if runModal(dlg, FILE_BOX, self) == IDOK
  398.       fileName := dlg.loadFile;
  399.       fileOpen(self, fileName);
  400.     endif;
  401.   endif;
  402. }!!
  403.  
  404. /* Open the file named fName and read a project from disk.
  405.    Uses the Language Extensions I object storage facility. 
  406.    This method copies the file into a stream so that it
  407.    can read faster.  Also, the old project, file and stream
  408.    are set to nil as soon as possible to free up memory. */
  409. Def fileOpen(self, fName | dlg, file, strm, reader)
  410. {
  411.   showWaitCurs();                       /* this takes a while */
  412.   if gw
  413.     close(gw);                          /* close old GanttWindow */
  414.   endif;      
  415.    
  416.   file := new(File);                    /* open the file etc. */
  417.   setName(file, fName);
  418.   open(file, 0);
  419.   checkError(file);
  420.   project := nil;                       /* free up memory */        
  421.   
  422.   strm := streamOver(copyFrom(file, 0, length(file))); 
  423.   checkError(file);
  424.   close(file);
  425.   file := nil;                          /* free up memory */
  426.   setText(self, appName(self)+": " + fName);  
  427.  
  428.   reader := new(StoredObjectReader);    
  429.   project := readFrom(reader, strm);    /* read the project */
  430.   strm := nil;                          /* free up memory */
  431.     
  432.   setAutoCalc(project, true);           /* other settings */
  433.   checkMenuItem(self, PW_AUTOCALC);
  434.   dirty := nil;
  435.   showOldCurs();                        /* all done */
  436.   invalidate(self);
  437. }!!
  438.  
  439. /* Respond to menu choice to save the file.  If the file
  440.    isn't yet named, prompt the user for a name. */
  441. Def fileSave(self)
  442. {
  443.   if fileName
  444.     fileSaveIt(self, fileName);
  445.   else
  446.     fileSaveAs(self);
  447.   endif;
  448. }!!
  449.  
  450. /* Save the project to disk with a new name. */
  451. Def fileSaveAs(self | dlg)
  452. {
  453.   if not(fileName)
  454.      fileName := getName(project)+".PRJ";
  455.   endif;
  456.      
  457.   dlg := new(InputDialog, loadString(PW_APPNAME),
  458.              loadString(PW_SAVEPROJ), fileName);
  459.   if runModal(dlg, INPUT_BOX, self) == IDOK         
  460.      fileName := getText(dlg);
  461.      setText(self, appName(self) + ": " + fileName);
  462.      fileSaveIt(self, fileName);
  463.   endif;
  464. }!!
  465.  
  466. /* Save the project to disk with the filename fName.  
  467.    Uses the Language Extensions I object storage facility. 
  468.    Note: this will not save any global variables!  */
  469. Def fileSaveIt(self, fName | file)
  470. {
  471.   showWaitCurs();                          /* this takes a while */
  472.   file := new(File);                       
  473.   setName(file, fName);
  474.   create(file);
  475.   checkError(file);
  476.   storeOn(project, file, nil);             /* write to file */
  477.   close(file);
  478.   dirty := false;
  479.   showOldCurs();
  480. }!!
  481.  
  482. /* Print a text summary of the project.
  483.    Uses the Printer, textPrinter classes.  */
  484. Def print(self | prn)
  485. {
  486.   prn := new(TextPrinter);
  487.   showWaitCurs();                              /* takes a while */
  488.   if start(prn, "PC-Project Print")            /* start spooling */
  489.      do(getInfoLines(project),
  490.        {using(line)
  491.         printLine(prn, line);
  492.      });
  493.      printLine(prn, " ");
  494.      printLine(prn, " ");
  495.      printLine(prn, loadString(PW_ACTIVT1)+":");
  496.      printLine(prn, loadString(PW_ACTIVT2));
  497.      printLine(prn, loadString(PW_ACTIVT3));
  498.      printLine(prn, "--------------------------------------------");
  499.      do(sortedActivities(project),
  500.        {using(aNode)
  501.         printLine(prn, getInfoLine(aNode));
  502.      });
  503.      
  504.      if size(resources(project)) > 0
  505.        printLine(prn, " ");
  506.        printLine(prn, " ");
  507.        printLine(prn, loadString(PW_REST1) + ":");
  508.        printLine(prn, loadString(PW_REST2));
  509.        printLine(prn, loadString(PW_REST3));
  510.        printLine(prn, "------------------------------------------");
  511.        do(resources(project),
  512.          {using(aRes)
  513.           printLine(prn, getInfoLine(aRes));
  514.        });
  515.      endif;
  516.      finish(prn);                             /* all done */
  517.      showOldCurs();
  518.   else
  519.     showOldCurs();
  520.     beep();
  521.     errorBox(loadString(PW_PRINTERR1),loadString(PW_PRINTERR2));
  522.   endif;
  523. }!!
  524.  
  525. /* Print graphics charts */
  526. Def printGraphs(self | prn)
  527. {
  528.   errorBox(loadString(PW_NA1), loadString(PW_NA2));
  529. }!!
  530.  
  531. /* Create a new Milestone */
  532. Def newMilestone(self)
  533. {
  534.   newActivity(self, Milestone);
  535. }!!
  536.  
  537. /* Create a new Task */
  538. Def newTask(self)
  539. {
  540.   newActivity(self, Task);
  541. }!!
  542.  
  543. /* Create a new PERTTask */
  544. Def newPERTTask(self)
  545. {
  546.   newActivity(self, PERTTask);
  547. }!!
  548.  
  549. /* Create a new activity based on a menu choice. 
  550.    The nodeClass should be passed in as Task, Milestone etc.
  551.    Return the new activity or nil if canceled. */
  552. Def newActivity(self, nodeClass | activity)
  553. {  
  554.   activity := new(nodeClass);
  555.   setNetwork(activity, project);
  556.   if editInfo(activity) == IDOK   /* let user connect it */
  557.     if pos(activity) = 0@0        /* still not connected */
  558.       activity.y := 1;            /* safe location */
  559.       resetPosn(getNetwork(activity), activity, 0@0);
  560.     endif;
  561.     dirty(self);                  /* redraw etc. */
  562.     ^activity;
  563.   endif;
  564.   ^nil;
  565. }!!
  566.  
  567. /* Delete a resource in response to menu choice. 
  568.    Returns the deleted resource or nil if canceled. */
  569. Def deleteResource(self | dlg, name, res)
  570.   dlg := new(InputDialog, loadString(PW_DELRES1),
  571.       loadString(PW_DELRES2), "");
  572.   if runModal(dlg, INPUT_BOX, self) == IDOK
  573.     name := getText(dlg);
  574.     if res := checkResExists(project, name) 
  575.        delete(res, project);
  576.        dirty(self);
  577.        ^res;
  578.     endif;    
  579.   endif;
  580.   ^nil;
  581. }!!
  582.  
  583. /* Delete an activity in response to menu choice. 
  584.    Returns the deleted node or nil if canceled. */
  585. Def deleteActivity(self | dlg, name, node)
  586.   dlg := new(InputDialog, loadString(PW_DELACT1),
  587.       loadString(PW_DELACT2), "");
  588.   if runModal(dlg, INPUT_BOX, self) == IDOK
  589.     name := getText(dlg);
  590.     if node := checkNodeExists(project, name) 
  591.        delete(node);
  592.        dirty(self);
  593.        ^node;
  594.     endif;
  595.   endif;
  596.   ^nil
  597. }!!
  598.  
  599. /* Edit a particular resource in response to menu choice.
  600.    For now, ask the user which one. Return the resource
  601.    or nil if canceled. */
  602. Def editResource(self | dlg, res)
  603. {
  604.  dlg := new(InputDialog, loadString(PW_VIEWRES1), loadString(PW_VIEWRES2),"");
  605.  if runModal(dlg, INPUT_BOX, self) == IDOK
  606.    if res := checkResExists(project, getText(dlg))
  607.       editInfo(res);
  608.       dirty(self);
  609.       ^res;
  610.    endif;
  611.  endif;  
  612.  ^nil;
  613. }!!
  614.  
  615. /* If the user presses the home key, reset scroll posn. */
  616. Def home(self)
  617. {
  618.   hScrollPos := vScrollPos := 0;
  619.   Call SetScrollPos(hWnd, SB_HORZ, hScrollPos, 1);
  620.   Call SetScrollPos(hWnd, SB_VERT, vScrollPos, 1);
  621.   invalidate(self);
  622. }!!
  623.  
  624. /* If the right button is pressed, toggle the view
  625.    to allow zoom in and out */
  626. Def zoom(self)
  627. {
  628.    if view == #normal
  629.         setView(self, #small);
  630.    else
  631.         setView(self, #normal);
  632.    endif;
  633.    invalidate(self);
  634. }!!
  635.  
  636. /* Show the amount of memory available. */
  637. Def showRoom(self | temp)
  638.  temp := Call GlobalCompact(Call GlobalCompact(0)+16) / 1024;
  639.  
  640.  errorBox(loadString(PW_SHOWROOM1),
  641.    asString(temp) + loadString(PW_SHOWROOM2));
  642. }!!
  643.  
  644. /* Show all of the resources as a table. */
  645. Def showResources(self | str)
  646. {
  647.   str :=  loadString(PW_SHOWRES2) + CR_LF +
  648.          "-----------------------------------------------";
  649.   do(resources(project),
  650.     {using(res)  
  651.      str := str + CR_LF + getInfoLine(res);
  652.   });
  653.   
  654.   errorBox(loadString(PW_REST1), str);
  655. }!!
  656.  
  657. /* Respond to menu choice to recalculate. */
  658. Def recalc(self)
  659. {
  660.   showWaitCurs();
  661.   recalc(project);
  662.   invalidate(self);
  663.   if gw
  664.    invalidate(gw);
  665.   endif;
  666.   showOldCurs();
  667. }!!
  668.  
  669. /* The ganttWindow has closed.  */
  670. Def closeGantt(self)
  671. {
  672.   gw := nil;
  673.   enableMenuItem(self, PW_VIEW_GANTT);
  674. }!!
  675.  
  676. /* Respond to menu choice to set display options.  The user
  677.    can select information to be displayed above or below
  678.    the nodes in the window.  */
  679. Def displaySettings(self | dlg)
  680. {
  681.   dlg := new(PWSetDialog);
  682.   if runModal(dlg, SETTING_BOX, self) == IDOK
  683.      invalidate(self);
  684.   endif;
  685. }!!
  686.  
  687. /* Handle menu choice to create a Gantt chart. 
  688.    Create the window large enough to hold all of
  689.    the activities, plus some extra space. */
  690. Def gantt(self | height)
  691. {
  692.   if screenSize()=640@200
  693.     height := 10
  694.   else
  695.     height := 20;
  696.   endif;
  697.   gw := new(GanttWindow, self, nil, loadString(PW_GANTT),
  698.             rect(asInt(x(screenSize())/3), 
  699.               max(y(screenSize())-(size(project)+5)*height,10),
  700.               x(screenSize()), y(screenSize())));
  701.   setProject(gw, project);
  702.   show(gw,1);
  703.   grayMenuItem(self, PW_VIEW_GANTT);
  704. }!!
  705.  
  706. /* Display help information from resource file. */
  707. Def help(self | dlg)
  708. {
  709.   dlg := new(Dialog);
  710.   checkRunModal(dlg, PW_HELP_BOX, self);
  711. }!!
  712.  
  713. /* Display Actor information from resource file. */
  714. Def aboutActor(self | dlg)
  715. {
  716.   dlg := new(Dialog);
  717.   checkRunModal(dlg, PW_ABOUT_ACTOR_BOX, self);
  718. }!!
  719.  
  720. /* Handles menu choice to set autocalc. */
  721. Def autoCalc(self)
  722. {
  723.   if autoCalc(project)
  724.     unCheckMenuItem(self, PW_AUTOCALC);
  725.     setAutoCalc(project, false);
  726.   else
  727.     checkMenuItem(self, PW_AUTOCALC);
  728.     setAutoCalc(project, true);
  729.     recalc(self);
  730.   endif;
  731. }!!
  732.  
  733. /* Show all of the activities as a table. */
  734. Def showActivities(self | str)
  735. {
  736.   str := loadString(PW_SHOWACT2) + CR_LF +
  737.          "------------------------------------------";
  738.   do(sortedActivities(project),
  739.     {using(aNode)  
  740.      str := str + CR_LF + getInfoLine(aNode);
  741.   });
  742.   
  743.   errorBox(loadString(PW_ACTIVT1), str);
  744. }!!
  745.  
  746. /* Respond to menu choice to edit the project */
  747. Def viewSummary(self)
  748. {
  749.   editInfo(project);
  750. }!!
  751.  
  752. /* See if the user has clicked on a box in the chart.
  753.    If so, bring up a dialog for editing. Return the
  754.    activity or nil if canceled. */
  755. Def WM_LBUTTONDOWN(self, wp, lp | dPoint, activity)
  756. {
  757.   dPoint := windowToDisplay(self, asPoint(lp));
  758.   activity := displayLookup(project, dPoint);
  759.   if activity                       /* logically true if found */
  760.     if editInfo(activity) == IDOK   /* user clicked on activity */
  761.       dirty(self);                  /* changes were made */
  762.       ^activity;
  763.     endif;
  764.   else                              /* false if nothing found */
  765.     beep();                         /* user clicked on dead space */
  766.     ^nil;
  767.   endif;
  768. }!!
  769.  
  770. /* If the right button is pressed, toggle the view
  771.    to allow zoom in and out */
  772. Def WM_RBUTTONDOWN(self, wp, lp)
  773. {
  774.   zoom(self);
  775. }!!
  776.  
  777. /* Trap keyboard events to simulate mouse. Cursor keys move
  778.    the cursor and scroll, return and F2 edit an activity.
  779.    Note anything defined as an accelerator will NOT cause
  780.    a WM_KEYDOWN message.  The keys W, X, A, D can also be 
  781.    used to move the cursor. */
  782. Def WM_KEYDOWN(self, wp, lp | pos, x, y, activity, max, dict)
  783.   pos := getCursorPos(self);    /* client coords */
  784.   x := x(pos);
  785.   y := y(pos);
  786.  
  787.   select
  788.     case wp == VK_UP or wp == asInt('W')
  789.       y := y - boxHeight*2;
  790.     endCase
  791.     case wp == VK_DOWN or wp == asInt('X')
  792.       y := y + boxHeight*2;
  793.     endCase
  794.     case wp == VK_LEFT or wp == asInt('A')
  795.       x := x - activWidth;
  796.     endCase
  797.     case wp == VK_RIGHT or wp == asInt('D')
  798.       x := x + activWidth;
  799.     endCase
  800.     case wp == VK_RETURN or wp == VK_F2  
  801.       WM_LBUTTONDOWN(self, 1, asLong(pos));
  802.     endCase    
  803.   endSelect;
  804.   
  805.  /* If the cursor is moving off screen, scroll. */
  806.   
  807.   select
  808.     case y < 0 
  809.       y := boxHeight;
  810.       WM_VSCROLL(self, SB_LINEUP, 1);
  811.     endCase
  812.     case y > max:=maxVisRow*boxHeight*2
  813.       y := max - boxHeight;
  814.       WM_VSCROLL(self, SB_LINEDOWN, 1);
  815.     endCase
  816.   endSelect;
  817.   
  818.   select
  819.     case x < 0 
  820.       x := boxHSpace;
  821.       WM_HSCROLL(self, SB_LINEUP, 1);
  822.     endCase
  823.     case x > max:=maxVisCol*activWidth
  824.       x := max - boxWidth;
  825.       WM_HSCROLL(self, SB_LINEDOWN, 1);
  826.     endCase
  827.   endSelect;
  828.  
  829.   setCursorPos(self, point(x,y));
  830. }!!
  831.  
  832. /* Trap scrolling.  Adjust as necesary.
  833.    The wp is the scroll code, the lp gives posn. */
  834. Def WM_HSCROLL(self, wp, lp | scroll)
  835.   select
  836.     case wp == SB_LINEUP 
  837.        scroll := -1;
  838.     endCase
  839.     case wp == SB_LINEDOWN 
  840.        scroll := 1;
  841.     endCase
  842.     case wp == SB_PAGEUP
  843.        scroll := negate(maxVisCol);
  844.     endCase;
  845.     case wp == SB_PAGEDOWN
  846.        scroll := maxVisCol;
  847.     endCase;
  848.     case wp == SB_THUMBPOSITION
  849.        hScrollPos := 0; scroll := low(lp);
  850.     endCase;
  851.     default
  852.        scroll := nil;
  853.   endSelect;
  854.  
  855.   if scroll 
  856.     hScrollPos := hScrollPos + scroll;    /* adjust */
  857.     hScrollPos := min(PW_MAX_COLS, max(0, hScrollPos));
  858.     Call SetScrollPos(hWnd, SB_HORZ, hScrollPos, 1);
  859.     invalidate(self);
  860.   endif;
  861. }!!
  862.  
  863. /* Trap scrolling.  Adjust as necesary.
  864.    The wp is the scroll code, the lp gives posn. */
  865. Def WM_VSCROLL(self, wp, lp | scroll)
  866.   select
  867.     case wp == SB_LINEUP 
  868.        scroll := -1;
  869.     endCase
  870.     case wp == SB_LINEDOWN 
  871.        scroll := 1;
  872.     endCase
  873.     case wp == SB_PAGEUP
  874.        scroll := negate(maxVisRow);
  875.     endCase;
  876.     case wp == SB_PAGEDOWN
  877.        scroll := maxVisRow;
  878.     endCase;
  879.     case wp == SB_THUMBPOSITION
  880.        vScrollPos := 0; scroll := low(lp);
  881.     endCase;
  882.   endSelect;
  883.  
  884.   if scroll
  885.     vScrollPos := vScrollPos + scroll;    /* adjust */
  886.     vScrollPos := min(PW_MAX_ROWS, max(0, vScrollPos));
  887.     Call SetScrollPos(hWnd, SB_VERT, vScrollPos, 1);
  888.     invalidate(self);
  889.   endif;
  890. }!!
  891.  
  892.  
  893. /* MS-Window's system-menu message.  Run About app dialog if requested, 
  894.   otherwise, pass through to default window proc.
  895.  
  896.   This will ensure that the application's about box is displayed.
  897. */
  898. Def  WM_SYSCOMMAND(self, wP, lP | win)
  899. { if wP == IDSABOUT
  900.      runModal(new(Dialog), ABOUT_BOX, self);
  901.   else ^asInt(execWindowProc(self, #WM_SYSCOMMAND, wP, lP));
  902.   endif;
  903. }!!
  904.  
  905.