home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windoware
/
WINDOWARE_1_6.iso
/
winutil
/
project
/
projwind.cls
< prev
next >
Wrap
Text File
|
1990-05-24
|
30KB
|
1,063 lines
/* Maintain a Project chart in a Window. The ProjWindow is
responsible for all drawing of the project. The window
has full scrolling and supports a keyboard interface.
If topMethod or botMethod are set, then the corresponding
method will be executed for each activity while displaying
the project.
ProjWindow descends from class Window and inherits all of
its instance variables and methods.
All strings are defined as resources for easy translation.
*/!!
inherit(Window, #ProjWindow, #(project /* the project */
fileName /* of the project */
actions /* menu actions table */
dirty /* true if not saved */
view /* normal or zoomed */
boxHeight /* based on scrnsize */
boxWidth /* adjustable for zoom */
boxHSpace /* adjustable */
activWidth /* adjustable */
hScrollPos /* horiz scroll posn */
vScrollPos /* vert scroll posn */
maxVisCol /* max visible col */
maxVisRow /* max visible row */
methTable /* table of methods */
topMethod /* offset into table */
botMethod /* offset into table */
gw /* a GanttWindow */
/* these are new for dragging */
dragDC /* for drawing */
anchorPt /* starting point */
oldPt /* end point */
), 2, nil)!!
now(ProjWindowClass)!!
/* Return the name of this class's MS-Windows window class
either for registration or new window creation. */
Def wndClass(self)
{ ^"ProjWindow" }!!
/* Create a new window class Struct.
Change the cursor to a cross. */
Def newWClass(self, lpCl, lpIcon | wc)
{ wc := newWClass(self:WindowClass, lpCl, lpIcon);
putWord(wc, Call LoadCursor(0, IDC_CROSS), 14);
^wc;
} !!
now(ProjWindow)!!
/* Allow the user to change the printer setup. */
Def printerSetup(self | prn)
{
prn := new(Printer);
getPrinterParms(prn);
deviceMode(prn, self);
}
!!
/* Respond to menu choice to run a program.
By default, run MSDOS executive shell.*/
Def run(self | dlg, progName)
{
dlg := new(InputDialog, "Run","Program name:","MSDOS.EXE");
if runModal(dlg, INPUT_BOX, self) == IDOK
progName:=getText(dlg);
exec(progName);
endif;
}!!
/* Handles menu choice to set colors. Global variables
CritColor and SlackColor determine the application
colors. */
Def toggleColor(self)
{
if CritColor <> BLACK
unCheckMenuItem(self, PW_COLOR);
CritColor := BLACK;
SlackColor := BLACK;
else
checkMenuItem(self, PW_COLOR);
CritColor := RED;
SlackColor := BLUE;
endif;
invalidate(self);
if gw invalidate(gw); endif;
}!!
/* Create a new Milestone */
Def newMilestone(self)
{
newActivity(self, Milestone);
}!!
/* Create the window using a "main" window style. */
Def create(self, par, wName, rect, style)
{
^create(self:Window, nil, wName, rect,
WS_OVERLAPPEDWINDOW bitOr WS_VSCROLL bitOr WS_HSCROLL);
}!!
/* Set up a dummy project, menus and the method table. */
Def init(self)
{
setProject(self, new(Project));
setAutoCalc(project, true);
setView(self, #normal);
setScrollBars(self);
setMenus(self);
checkMenuItem(self, PW_AUTOCALC);
checkMenuItem(self, PW_COLOR);
setMethTable(self);
}!!
/* Set the project. */
Def setProject(self, aProject)
{
project := aProject;
}!!
/* Set the resolution for the size of nodes, spacing etc.
based on the font text size. There are two views,
normal and small. Both are based on text font size so
that they will display adequately with any resolution. */
Def setView(self, aView | hDC, ts)
{
view := aView;
hDC := getContext(self); /* so we can get text size */
ts := textSize(self, hDC); /* x is width, y is height */
releaseContext(self, hDC);
if view == #small
boxWidth := x(ts) * 4;
boxHSpace := x(ts)/2 + 1;
boxHeight := y(ts) + 4;
else
boxWidth := asInt(x(ts)*8);
boxHSpace := x(ts) + 2;
boxHeight := y(ts) * 2;
endif;
activWidth := boxWidth + boxHSpace;
reSize(self, 0, 0L); /* so scrolling is adjusted */
}!!
/* Set the scroll bar ranges and initial positions. */
Def setScrollBars(self)
{
Call SetScrollRange(hWnd, SB_HORZ, 0, PW_MAX_COLS, 0);
Call SetScrollRange(hWnd, SB_VERT, 0, PW_MAX_ROWS, 0);
hScrollPos := vScrollPos := 0;
}!!
/* Set up the method table used for display options.
Each of these methods should be applicable to all
activities in the project, that is, both Milestones
and Tasks. */
Def setMethTable(self)
{
methTable := #(#getTime,
#getSlack,
#getCost,
#getEarlyStart,
#getEarlyFinish,
#getLateStart,
#getLateFinish);
topMethod := 3;
}!!
/* Set the method to display info below each box.
The offset refers to the position in the
methTable. */
Def setBotMethod(self, offset)
{
botMethod := offset;
}!!
/* Set the method to display info atop each box.
The offset refers to the position in the
methTable. */
Def setTopMethod(self, offset)
{
topMethod := offset;
}!!
/* Add an about box and load menu resources.
Set up the menu actions table. Each entry
consists of a constant ID and a message
that will be performed. */
Def setMenus(self)
{
addAbout(self);
loadMenu(self, "PWMenus");
setMenu(self, hMenu);
actions := new(Dictionary, 30);
add(actions, PW_FILE_NEW, #fileNew);
add(actions, PW_FILE_OPEN, #fileOpenAs);
add(actions, PW_FILE_SAVE, #fileSave);
add(actions, PW_FILE_SAVEAS, #fileSaveAs);
add(actions, PW_FILE_PRINT, #print);
add(actions, PW_FILE_PRINT_GRAPH, #printGraphs);
add(actions, PW_FILE_SETTINGS, #printerSetup);
add(actions, PW_RUN, #run);
add(actions, PW_FILE_QUIT, #close);
add(actions, PW_CLIP, #clipChart);
add(actions, PW_ABOUT_ACTOR, #aboutActor);
add(actions, PW_DEL_ACTIVITY, #deleteActivity);
add(actions, PW_DEL_RESOURCE, #deleteResource);
add(actions, PW_NEW_MSTONE, #newMilestone);
add(actions, PW_NEW_TASK, #newTask);
add(actions, PW_NEW_PERT, #newPERTTask);
add(actions, PW_DISPLAY, #displaySettings);
add(actions, PW_COLOR, #toggleColor);
add(actions, PW_AUTOCALC, #autoCalc);
add(actions, PW_CALC, #recalc);
add(actions, PW_SHOWROOM, #showRoom);
add(actions, PW_ZOOM, #zoom);
add(actions, PW_VIEW_SUMMARY, #viewSummary);
add(actions, PW_VIEW_ACTIVITIES, #showActivities);
add(actions, PW_VIEW_GANTT, #gantt);
add(actions, PW_VIEW_RESOURCES, #showResources);
add(actions, PW_VIEW_RESOURCE, #editResource);
/* keyboard accelerator commands */
add(actions, PW_HELP, #help);
add(actions, EDIT_HOME, #home);
add(actions, PW_COMMAND_MODE, #commandMode);
}!!
/* Convert window coordinates to relative display coordinates. */
Def windowToDisplay(self, wPoint)
{
^point((x(wPoint) - boxHSpace) / activWidth + hScrollPos,
(y(wPoint) - boxHeight) / (boxHeight*2) + vScrollPos);
}!!
/* Convert relative display entries to window coordinates.
Uses dot notation for speed. */
Def displayToWindow(self, dPoint)
{
^point(boxHSpace + (dPoint.x - hScrollPos) * activWidth,
boxHeight + (dPoint.y - vScrollPos) * boxHeight*2);
}!!
/* The name of application, used for captions. */
Def appName(self)
{
^loadString(PW_APPNAME);
}!!
/* Check if there is a file error and display an error box.
Return the error number, 0 for no error. */
Def checkError(self, aFile | errNo)
{
errNo := getError(aFile);
if errNo <> 0
beep();
errorBox(loadString(PW_FILEERR1),
loadString(PW_FILEERR2) + asString(aFile) +
loadString(PW_FILEERR3) + asString(errNo) +
loadString(50+errNo));
endif;
^errNo;
}!!
/* Returns true if the node is visible in the window.
Used to speed up redrawing. Uses dot notation for speed. */
Def visible(self, aNode)
{
^between(aNode.x, hScrollPos, maxVisCol + hScrollPos)
cand between(aNode.y, vScrollPos, maxVisRow + vScrollPos);
}!!
/* Set up the cursor for use even if there is no mouse. */
Def gotFocus(self, prevHwnd)
{
Call ShowCursor(1);
}!!
/* Return to normal use of cursor. */
Def losingFocus(self, hWndNew)
{
Call ShowCursor(0);
} !!
/* Check if the project has been saved. */
Def shouldClose(self)
{
^checkClean(self)
}!!
/* Make sure the window knows that the project has changed. */
Def dirty(self)
{
invalidate(self);
dirty := true;
if gw
invalidate(gw);
endif;
}!!
/* Returns boolean value true if the project has
not changed since last save. If it is dirty,
the user is prompted for confirmation. */
Def checkClean(self)
{
^ not(dirty) cor
yesNoBox(loadString(PW_WARNING),
loadString(PW_DISCARD)) == IDYES;
}!!
/* Get the offset of the botMethod. */
Def getBotMethod(self)
{
^botMethod;
}!!
/* Get the offset of the topMethod. */
Def getTopMethod(self)
{
^topMethod;
}!!
/* Resize the window. Adjust visible rows and cols. */
Def reSize(self, wp, lp)
{
maxVisRow := bottom(clientRect(self)) / (boxHeight*2);
maxVisCol := right(clientRect(self)) / activWidth;
}!!
/* Respond to MS-Windows messages to paint the window.
Show the project as a network chart.
Draw each visible node in its proper position.
Display the name and any other info required.
Then draw the lines to connect the outputs.
The displayToWindow message converts a node's
logical display position to windows coordinates.
This could be further speeded up by repainting
only the invalid rectangle.
*/
Def paint(self, hDC |wPoint, x, y)
{
do(nodes(project),
{using(aNode)
wPoint := displayToWindow(self, pos(aNode));
x := x(wPoint); /* horiz windows posn */
y := y(wPoint); /* vert windows posn */
if visible(self, aNode)
draw(aNode, self, x, y, hDC); /* node knows how to draw */
drawTextInfo(self, aNode, x, y, hDC);
endIf;
/* always draw connections since they may be visible */
drawConnections(self, aNode, x, y, getOutputs(aNode), hDC);
});
}!!
/* Draw lines connecting the nodes in the window.
Uses early binding, dot notation and direct
Windows calls for speed. */
Def drawConnections(self, aNode, x, y, connectedNodes, hDC | wPoint)
{
do(connectedNodes,
{using(output)
Call MoveTo(hDC, x + boxWidth, y + boxHeight/2);
wPoint := displayToWindow(self:ProjWindow, pos(output));
Call LineTo(hDC, wPoint.x, wPoint.y + boxHeight/2);
if critical(aNode:Activity) cand critical(output:Activity)
Call MoveTo(hDC, x + boxWidth, y + boxHeight/2+1);
Call LineTo(hDC, wPoint.x, wPoint.y + boxHeight/2+1);
endif;
});
}!!
/* Draw text info in the window. If the small view is
being used, show less information.
Uses early binding and dot notation for speed. */
Def drawTextInfo(self, aNode, x, y, hDC | ts, str, strSize, offsetY, offsetX)
{
ts := textSize(self, hDC);
offsetY := (boxHeight - ts.y) / 2;
strSize := boxWidth / ts.x;
if view == #small
offsetX := 2; /* to make milestones look ok */
else
offsetX := 0;
endif;
str := subString(aNode.name, 0, strSize-1);
Call SetTextColor(hDC, SlackColor);
Call TextOut(hDC, x + offsetX + 2, y + offsetY, str, size(str));
if critical(aNode)
Call SetTextColor(hDC, CritColor);
endif;
if topMethod /* display above box */
str := subString(asString(perform(aNode, methTable[topMethod])),0,strSize);
Call TextOut(hDC, x + 2, y - ts.y, str, size(str));
endif;
if view ~= #small
cand botMethod /* display below box */
str := subString(asString(perform(aNode, methTable[botMethod])),0,strSize);
Call TextOut(hDC, x + 2, y + boxHeight, str, size(str));
endif;
}!!
/* Draw a task in the window.
Uses early binding and direct Windows call for speed. */
Def drawTask(self, aNode, x, y, hDC)
{
Call Rectangle(hDC, x, y, x + boxWidth, y + boxHeight);
if critical(aNode:Activity)
Call Rectangle(hDC, x+1, y+1, x + boxWidth-1, y + boxHeight-1);
endif;
}!!
/* Draw a milestone in the window.
Uses early binding and direct Windows call for speed. */
Def drawMilestone(self, aNode, x, y, hDC)
{
Call RoundRect(hDC, x, y, x + boxWidth, y + boxHeight, 20,20);
if critical(aNode:Activity)
Call RoundRect(hDC, x+1, y+1, x + boxWidth-1, y + boxHeight-1, 17,17);
endif;
}!!
/* Handle menu events, accelerator keys.
Lookup the ID in the actions table, if found
perform it. */
Def command(self, wp, lp)
{
if actions[wp]
perform(self, actions[wp]);
else /* these keys might be accelerators */
if wp == VK_UP cor wp == VK_DOWN cor
wp == VK_RIGHT cor wp == VK_LEFT
WM_KEYDOWN(self, wp, lp);
else
beep(); /* internal error! */
errorBox(loadString(PW_ERROR1),
loadString(PW_ERROR2) + asString(wp));
endif;
endif;
}!!
/* Go into "command mode" in response to a slash key accelerator.
This simulates Lotus 1-2-3 style commands by sending an
ALT key sysCommand message. */
Def commandMode(self)
{
WM_SYSCOMMAND(self, 0xF100, 0L);
}!!
/* Get a filename from the user in responds to menu event.
If the file has changed, check with the user.
Send a fileOpen message to do the work. */
/* Respond to menu choice to create a new project. */
Def fileNew(self)
{
if checkClean(self)
if gw
close(gw);
endif;
fileName := nil;
dirty := nil;
setProject(self, new(Project));
checkMenuItem(self, PW_AUTOCALC);
setAutoCalc(project, true);
setText(self, appName(self));
editInfo(project);
invalidate(self);
endif;
}!!
/* Prompt the user for the filename to open.
Use the new combo box type of file dialog. */
Def fileOpenAs(self | dlg, file, reader)
{
if checkClean(self)
dlg := new(FileDialog, "*."+loadString(PW_EXTENSION));
if runModal(dlg, FILE_BOX, self) == IDOK
fileName := loadFile(dlg);
fileOpen(self, fileName);
endif;
endif;
}!!
/* Open the file named fName and read a project from disk.
If a DOS error occurs (like file not found) then stop.
Uses the Language Extensions I object storage facility.
This method copies the file into a stream so that it
can read faster. Also, the old project, file and stream
are set to nil as soon as possible to free up memory. */
Def fileOpen(self, fName | dlg, file, strm, reader)
{
showWaitCurs(); /* this takes a while */
if gw
close(gw); /* close old GanttWindow */
endif;
file := new(File); /* open the file etc. */
setName(file, fName);
open(file, 0);
if checkError(self, file) == 0 /* no DOS errors */
project := nil; /* free up memory */
strm := streamOver(copyFrom(file, 0, length(file)));
close(file);
setText(self, appName(self)+": " + fName);
reader := new(StoredObjectReader);
project := readFrom(reader, strm); /* read the project */
strm := nil; /* free up memory */
setAutoCalc(project, true); /* other settings */
checkMenuItem(self, PW_AUTOCALC);
dirty := nil;
invalidate(self); /* redraw the window */
else
fileName := nil; /* due to DOS error */
endif;
showOldCurs(); /* all done */
}!!
/* Respond to menu choice to save the file. If the file
isn't yet named, prompt the user for a name. */
Def fileSave(self)
{
if fileName
fileSaveIt(self, fileName);
else
fileSaveAs(self);
endif;
}!!
/* Save the project to disk with a new name. */
Def fileSaveAs(self | dlg)
{
if not(fileName)
fileName := getName(project)+"."+loadString(PW_EXTENSION);
endif;
dlg := new(InputDialog, loadString(PW_APPNAME),
loadString(PW_SAVEPROJ), fileName);
if runModal(dlg, INPUT_BOX, self) == IDOK
fileName := getText(dlg);
fileSaveIt(self, fileName);
endif;
}!!
/* Save the project to disk with the filename fName.
If a DOS error occurs (like file not found) stop.
Uses the Language Extensions I object storage facility.
Note: this will not save any global variables! */
Def fileSaveIt(self, fName | file)
{
showWaitCurs(); /* this takes a while */
file := new(File);
setName(file, fName);
create(file);
if checkError(self, file) == 0 /* no DOS error */
setText(self, appName(self) + ": " + fileName);
storeOn(project, file, nil); /* write to file */
close(file);
dirty := false;
else
fileName := nil; /* due to DOS error */
endif;
showOldCurs();
}!!
/* Print a text summary of the project.
Uses the Printer class. */
Def print(self | prn)
{
prn := new(Printer);
showWaitCurs(); /* takes a while */
if start(prn, "Project", self) /* start printing */
do(getInfoLines(project),
{using(line)
printLine(prn, line);
});
printLine(prn, " ");
printLine(prn, " ");
printLine(prn, loadString(PW_ACTIVT1)+":");
printLine(prn, loadString(PW_ACTIVT2));
printLine(prn, loadString(PW_ACTIVT3));
printLine(prn, "--------------------------------------------");
do(sortedActivities(project),
{using(aNode)
printLine(prn, getInfoLine(aNode));
});
if size(resources(project)) > 0
printLine(prn, " ");
printLine(prn, " ");
printLine(prn, loadString(PW_REST1) + ":");
printLine(prn, loadString(PW_REST2));
printLine(prn, loadString(PW_REST3));
printLine(prn, "------------------------------------------");
do(resources(project),
{using(aRes)
printLine(prn, getInfoLine(aRes));
});
endif;
finish(prn); /* all done */
showOldCurs();
else
showOldCurs();
beep();
errorBox(loadString(PW_PRINTERR1),loadString(PW_PRINTERR2));
endif;
}!!
/* Print graphics charts */
Def printGraphs(self)
{
printWindow(self, 1);
}!!
/* Copy bitmap to clipboard */
Def clipChart(self)
{
clipWindow(self, 1);
}
/* Create a new Milestone */
Def newMilestone(self)
{
newActivity(self, Milestone);
}!!
/* Create a new Task */
Def newTask(self)
{
newActivity(self, Task);
}!!
/* Create a new PERTTask */
Def newPERTTask(self)
{
newActivity(self, PERTTask);
}!!
/* Create a new activity based on a menu choice.
The nodeClass should be passed in as Task, Milestone etc.
Return the new activity or nil if canceled. */
Def newActivity(self, nodeClass | activity)
{
activity := new(nodeClass);
setNetwork(activity, project);
if editInfo(activity) == IDOK /* let user connect it */
if pos(activity) = 0@0 /* still not connected */
activity.y := 1; /* safe location */
resetPosn(getNetwork(activity), activity, 0@0);
endif;
dirty(self); /* redraw etc. */
^activity;
endif;
^nil;
}!!
/* Delete a resource in response to menu choice.
Returns the deleted resource or nil if canceled. */
Def deleteResource(self | dlg, name, res)
{
dlg := new(InputDialog, loadString(PW_DELRES1),
loadString(PW_DELRES2), "");
if runModal(dlg, INPUT_BOX, self) == IDOK
name := getText(dlg);
if res := checkResExists(project, name)
delete(res, project);
dirty(self);
^res;
endif;
endif;
^nil;
}!!
/* Delete an activity in response to menu choice.
Returns the deleted node or nil if canceled. */
Def deleteActivity(self | dlg, name, node)
{
dlg := new(InputDialog, loadString(PW_DELACT1),
loadString(PW_DELACT2), "");
if runModal(dlg, INPUT_BOX, self) == IDOK
name := getText(dlg);
if node := checkNodeExists(project, name)
delete(node);
dirty(self);
^node;
endif;
endif;
^nil
}!!
/* Edit a particular resource in response to menu choice.
For now, ask the user which one. Return the resource
or nil if canceled. */
Def editResource(self | dlg, res)
{
dlg := new(InputDialog, loadString(PW_VIEWRES1), loadString(PW_VIEWRES2),"");
if runModal(dlg, INPUT_BOX, self) == IDOK
if res := checkResExists(project, getText(dlg))
editInfo(res);
dirty(self);
^res;
endif;
endif;
^nil;
}!!
/* Show all of the resources as in a TextWindow. */
Def showResources(self | tw)
{
tw := new(TextWindow, self, nil, loadString(PW_REST1), nil);
show(tw, 1);
printLine(tw, loadString(PW_SHOWRES2));
printLine(tw, "-----------------------------------------------");
do(resources(project),
{using(res)
printLine(tw, getInfoLine(res));
});
}!!
/* Show all of the activities in a TextWindow. */
Def showActivities(self | tw)
{
tw := new(TextWindow, self, nil, loadString(PW_ACTIVT1), nil);
show(tw, 1);
printLine(tw, loadString(PW_SHOWACT2));
printLine(tw, "------------------------------------------");
do(sortedActivities(project),
{using(aNode)
printLine(tw, getInfoLine(aNode));
});
}!!
/* Respond to menu choice to edit the project */
Def viewSummary(self)
{
editInfo(project);
}!!
/* If the user presses the home key, reset scroll posn. */
Def home(self)
{
hScrollPos := vScrollPos := 0;
Call SetScrollPos(hWnd, SB_HORZ, hScrollPos, 1);
Call SetScrollPos(hWnd, SB_VERT, vScrollPos, 1);
invalidate(self);
}!!
/* If the right button is pressed, toggle the view
to allow zoom in and out */
Def zoom(self)
{
if view == #normal
setView(self, #small);
else
setView(self, #normal);
endif;
invalidate(self);
}!!
/* Show the amount of memory available. */
Def showRoom(self | temp)
{
temp := Call GlobalCompact(Call GlobalCompact(0)+16) / 1024;
errorBox(loadString(PW_SHOWROOM1),
asString(temp) + loadString(PW_SHOWROOM2));
}!!
/* Respond to menu choice to recalculate. */
Def recalc(self)
{
showWaitCurs();
recalc(project);
invalidate(self);
if gw
invalidate(gw);
endif;
showOldCurs();
}!!
/* The ganttWindow has closed. */
Def closeGantt(self)
{
gw := nil;
enableMenuItem(self, PW_VIEW_GANTT);
}!!
/* Respond to menu choice to set display options. The user
can select information to be displayed above or below
the nodes in the window. */
Def displaySettings(self | dlg)
{
dlg := new(PWSetDialog);
if runModal(dlg, SETTING_BOX, self) == IDOK
invalidate(self);
endif;
}!!
/* Handle menu choice to create a Gantt chart.
Create the window large enough to hold all of
the activities, plus some extra space. */
Def gantt(self | height)
{
if screenSize()=640@200
height := 10
else
height := 20;
endif;
gw := new(GanttWindow, self, nil, loadString(PW_GANTT),
rect(asInt(x(screenSize())/3),
max(y(screenSize())-(size(project)+5)*height,10),
x(screenSize()), y(screenSize())));
setProject(gw, project);
show(gw,1);
grayMenuItem(self, PW_VIEW_GANTT);
}!!
/* Display help information from resource file. */
Def help(self | dlg)
{
dlg := new(Dialog);
checkRunModal(dlg, PW_HELP_BOX, self);
}!!
/* Display Actor information from resource file. */
Def aboutActor(self | dlg)
{
dlg := new(Dialog);
checkRunModal(dlg, PW_ABOUT_ACTOR_BOX, self);
}!!
/* Handles menu choice to set autocalc. */
Def autoCalc(self)
{
if autoCalc(project)
unCheckMenuItem(self, PW_AUTOCALC);
setAutoCalc(project, false);
else
checkMenuItem(self, PW_AUTOCALC);
setAutoCalc(project, true);
recalc(self);
endif;
}!!
/* See if the user has double clicked on a box.
If so, bring up a dialog for editing. Return the
activity or nil if canceled. */
Def WM_LBUTTONDBLCLK(self, wp, lp | dPoint, activity)
{
dPoint := windowToDisplay(self, asPoint(lp));
activity := displayLookup(project, dPoint);
if activity /* logically true if found */
if editInfo(activity) == IDOK /* user clicked on activity */
dirty(self); /* changes were made */
^activity;
endif;
else /* false if nothing found */
beep(); /* user clicked on dead space */
endif;
^nil;
}!!
/* If the right button is pressed, toggle the view
to allow zoom in and out */
Def WM_RBUTTONDOWN(self, wp, lp)
{
zoom(self);
}!!
/* Trap keyboard events to simulate mouse. Cursor keys move
the cursor and scroll, return and F2 edit an activity.
Note anything defined as an accelerator will NOT cause
a WM_KEYDOWN message. The keys W, X, A, D can also be
used to move the cursor. */
Def WM_KEYDOWN(self, wp, lp | pos, x, y, activity, max, dict)
{
pos := getCursorPos(self); /* client coords */
x := x(pos);
y := y(pos);
select
case wp == VK_UP or wp == asInt('W')
y := y - boxHeight*2;
endCase
case wp == VK_DOWN or wp == asInt('X')
y := y + boxHeight*2;
endCase
case wp == VK_LEFT or wp == asInt('A')
x := x - activWidth;
endCase
case wp == VK_RIGHT or wp == asInt('D')
x := x + activWidth;
endCase
case wp == VK_RETURN or wp == VK_F2
WM_LBUTTONDBLCLK(self, 1, asLong(pos));
endCase
endSelect;
/* If the cursor is moving off screen, scroll. */
select
case y < 0
y := boxHeight;
WM_VSCROLL(self, SB_LINEUP, 1);
endCase
case y > max:=maxVisRow*boxHeight*2
y := max - boxHeight;
WM_VSCROLL(self, SB_LINEDOWN, 1);
endCase
endSelect;
select
case x < 0
x := boxHSpace;
WM_HSCROLL(self, SB_LINEUP, 1);
endCase
case x > max:=maxVisCol*activWidth
x := max - boxWidth;
WM_HSCROLL(self, SB_LINEDOWN, 1);
endCase
endSelect;
setCursorPos(self, point(x,y));
}!!
/* Trap scrolling. Adjust as necesary.
The wp is the scroll code, the lp gives posn. */
Def WM_HSCROLL(self, wp, lp | scroll)
{
select
case wp == SB_LINEUP
scroll := -1;
endCase
case wp == SB_LINEDOWN
scroll := 1;
endCase
case wp == SB_PAGEUP
scroll := negate(maxVisCol);
endCase;
case wp == SB_PAGEDOWN
scroll := maxVisCol;
endCase;
case wp == SB_THUMBPOSITION
hScrollPos := 0; scroll := low(lp);
endCase;
default
scroll := nil;
endSelect;
if scroll
hScrollPos := hScrollPos + scroll; /* adjust */
hScrollPos := min(PW_MAX_COLS, max(0, hScrollPos));
Call SetScrollPos(hWnd, SB_HORZ, hScrollPos, 1);
invalidate(self);
endif;
}!!
/* Trap scrolling. Adjust as necesary.
The wp is the scroll code, the lp gives posn. */
Def WM_VSCROLL(self, wp, lp | scroll)
{
select
case wp == SB_LINEUP
scroll := -1;
endCase
case wp == SB_LINEDOWN
scroll := 1;
endCase
case wp == SB_PAGEUP
scroll := negate(maxVisRow);
endCase;
case wp == SB_PAGEDOWN
scroll := maxVisRow;
endCase;
case wp == SB_THUMBPOSITION
vScrollPos := 0; scroll := low(lp);
endCase;
endSelect;
if scroll
vScrollPos := vScrollPos + scroll; /* adjust */
vScrollPos := min(PW_MAX_ROWS, max(0, vScrollPos));
Call SetScrollPos(hWnd, SB_VERT, vScrollPos, 1);
invalidate(self);
endif;
}!!
/* Begin dragging to allow the user to draw a line
that will connect two boxes. Setup the anchorPt and
dragDC to allow dragging to do the drawing.
BW 02/05/89 */
Def beginDrag(self, wp, aPt | dPoint, activity, dMode)
{
dPoint := windowToDisplay(self, aPt);
activity := displayLookup(project, dPoint);
if activity /* logically true if found */
anchorPt := aPt;
dragDC := getContext(self);
dMode := Call SetROP2(dragDC,7);
Call SelectObject(dragDC,Call GetStockObject(6));
endif;
}!!
/* Do the drag and draw the feedback.
BW 02/05/89 */
Def drag(self, wp, aPt )
{ if dragDC then
if oldPt cand (oldPt <> aPt)
then moveTo(anchorPt,dragDC);
lineTo(oldPt,dragDC);
endif;
oldPt := aPt;
moveTo(anchorPt,dragDC);
lineTo(aPt,dragDC);
endif;
}!!
/* Finish the drag connection of two tasks.
Create a new task if necessary. */
Def endDrag(self, wp, aPt | dPoint1, dPoint2, activity1, activity2)
{
if dragDC then
dPoint2 := windowToDisplay(self, aPt);
activity2 := displayLookup(project, dPoint2);
if activity2 /* logically true if found */
dPoint1 := windowToDisplay(self,anchorPt);
activity1 := displayLookup(project, dPoint1);
if activity1 <> activity2
connect(project,getName(activity1),
getName(activity2));
invalidate(self);
endif;
else /* maybe the user wants a new node */
if activity2 := newActivity(self,Task) then
dPoint1 := windowToDisplay(self,anchorPt);
activity1 := displayLookup(project, dPoint1);
connect(project,getName(activity1),
getName(activity2));
invalidate(self);
else
moveTo(anchorPt,dragDC); /* erase last line*/
lineTo(oldPt,dragDC);
endif;
endif;
releaseContext(self,dragDC); /* done drawing */
dragDC := nil;
oldPt := nil;
endif;
}!!