OPTION NOLET OPTION ANGLE degrees DIM verts(1,1), tempverts(1,1) DIM templist(1),beenthere(1) DIM menuchoices(1), menulabel$(1,1), code$(1,1), oldcode$(1) DIM left(1), right(1), bottom(1), top(1), xpix(0:1), ypix(0:1) DECLARE DEF findvert,find_other_vert DECLARE DEF distance DECLARE DEF which_window DECLARE DEF smarctan LET drawlevel=2 LET numsegs=4 let drawpattern=1 LET graph_win=1 LET menu_win=2 LET message_win=3 LET current_menu=1 LET dowhat$="move1" LET selected=0 CALL init_windows CALL init_pics CALL init_menus CALL init_graph CALL update_menu !################## Main Loop ############# !call clear_mouse DO WINDOW #0 GET MOUSE xmouse,ymouse,statmouse IF statmouse<>0 then CALL mouse_click IF key input then CALL key_press LOOP !################## Handle mouse clicking nonsense ############# SUB mouse_click LOCAL m LET the_win=which_window(xmouse,ymouse) SELECT CASE the_win CASE 1 ! They clicked in the graph's window WINDOW #1 ! The big one to the left (<--courtesy of Joyce) CALL global2local(1,xmouse,ymouse) IF findvert(xmouse,ymouse) <> 0 then ! They clicked on a vertex LET who=findvert(xmouse,ymouse) CALL clicked_on_vert(who) ELSE ! didn't click on a vertex IF dowhat$= "advert2" then CALL advert(xmouse,ymouse) WINDOW #1 CALL drawverts CALL drawedges END IF END IF CASE 2 ! They clicked in the menu region WINDOW #menu_win CALL global2local(menu_win,xmouse,ymouse) LET m=maxchoices-int((ymouse-menuborder)/menuboxheight) IF m=0 then LET current_menu=int(num_menus*(xmouse-menuleft)/menuwidth)+1 ! call message("chose menu "&str$(current_menu),menu_win) LET dowhat$="move1" CALL update_menu CALL clear_mouse EXIT SUB END IF ! call message("yup",menu_win) SELECT CASE current_menu CASE 1 ! graph building menu SELECT CASE m CASE 1 to 5 !move, add/rem vert, add/rem edge WHEN error in LET dowhat$=code$(current_menu,m) USE LET dowhat$=code$(current_menu,1) !default to move END WHEN CASE 6 CALL digraph_toggle CASE 7 CALL saveit CASE 8 CALL oldn CASE 9 CALL nukeall CASE 10 CALL quitit CASE else END SELECT CASE 2 SELECT CASE m CASE 1 to 3 LET dowhat$=code$(current_menu,m) CASE 4 CALL quitit CASE else END SELECT CASE else CALL message("oops",menu_win) END SELECT CALL update_menu CASE else END SELECT END SUB !############# Text message to the user, returns to the specified channel after # SUB message(msg$,return_to) WINDOW #message_win PRINT " "&msg$; !a thin, extended mass of monosodium glutamate ? WINDOW #return_to END SUB SUB quitit SET MODE "80" STOP END SUB !############## Handle a click on a vertex in the graph window ################# SUB clicked_on_vert(who) SELECT CASE dowhat$ !find out what we're doing now CASE "move1" !we're moving things DO GET MOUSE xmouse,ymouse,statmouse IF statmouse=1 then CALL movert(who) END IF LOOP until statmouse=3 or statmouse=0 !CALL movert(who) CASE "adage4","removedge5" !we're adding or removing an edge IF selected=0 then CALL selekt(who) CALL clear_mouse ELSE END IF CASE "advert2" !we're adding a vertex WINDOW #3 PRINT "can't add a node on top of another one" CALL clear_mouse WINDOW #1 CASE "nukevert3" !we're eliminating a vertex CALL nukevert(who) CASE "distance2" IF selected=0 then CALL selekt(who) CALL clear_mouse ELSE LET dist=distance(selected,who) CALL message(str$(dist),menu_win) CALL selekt(0) END IF CASE else !we don't know what we're doing PRINT "not yet implemented" END SELECT END SUB !################## Handle Key Press ####################### SUB key_press LOCAL a GET KEY a SELECT CASE a CASE 17, 272 !ctrl-Q or alt-Q SET MODE "80" STOP CASE 13, 306 !ctrl-M or alt-M LET dowhat$="move1" CASE 22, 303 !ctrl-V or alt-V LET dowhat$="advert2" CASE 14, 305 !ctrl-N or alt-N LET dowhat$="nukevert3" CASE 5, 274 !ctrl-E or alt-E LET dowhat$="adage4" CASE 18, 275 !ctrl-R or alt-R LET dowhat$="removedge5" CASE 19, 287 !ctrl-S or alt-S CALL saveit !(#1,#2,#3) CASE 15, 280 !ctrl-O or alt-O CALL oldn !(#1,#2,#3) CASE else END SELECT CALL update_menu WINDOW #0 END SUB !############### initialize the window channels ########################## SUB init_windows LOCAL i LET num_windows=3 MAT redim left(num_windows),right(num_windows),bottom(num_windows),top(num_windows) MAT redim xpix(0:num_windows),ypix(0:num_windows) ASK PIXELS xpix(0),ypix(0) LET left(1)=1 LET right(1)=int(.8*xpix(0)-1) LET bottom(1)=int(ypix(0)/6-1) LET top(1)=ypix(0)-2 LET left(2)=right(1)+2 LET right(2)=xpix(0)-2 LET bottom(2)=bottom(1) LET top(2)=top(1) LET left(3)=left(1) LET right(3)=right(2) LET bottom(3)=2 LET top(3)=bottom(1)-3 WINDOW #0 SET WINDOW 0,xpix(0)-1,0,ypix(0)-1 FOR i=1 to num_windows OPEN #i:screen left(i)/xpix(0),right(i)/xpix(0),bottom(i)/ypix(0),top(i)/ypix(0) ASK PIXELS xpix(i),ypix(i) SET WINDOW 0,xpix(i)-1,0,ypix(i)-1 NEXT i FOR i=0 to num_windows WINDOW #i SET COLOR "blue" !i+1 BOX LINES 0,xpix(i)-1,0,ypix(i)-1 NEXT i WINDOW #graph_win SET COLOR "green" !green edges for variety END SUB !###################### Initialize menu choices, labels, and codes ##### SUB init_menus LOCAL i,j LET num_menus=1 MAT redim menuchoices(num_menus) DATA 10 !,4 MAT READ menuchoices FOR i=1 to num_menus LET maxchoices=max(maxchoices,menuchoices(i)) NEXT i MAT redim menulabel$(num_menus,maxchoices),code$(num_menus,maxchoices),oldcode$(num_menus) ! main menu DATA fiddle, add node,remove node,nothing,nothing,nothing,save graph,retrieve graph,clear graph,quit ! data move,distance,distance to,quit FOR i=1 to num_menus FOR j=1 to menuchoices(i) READ menulabel$(i,j) IF menulabel$(i,j)="digraph" then LET digraphi=i LET digraphj=j END IF NEXT j NEXT i DATA move,advert,nukevert,adage,removedge,digraph_toggle,saveit,oldn,nukeall,togquit ! data move,distance,disto,quit FOR i=1 to num_menus FOR j=1 to menuchoices(i) READ code$(i,j) LET code$(i,j)=code$(i,j)&str$(j) NEXT j NEXT i LET menuborder=3 LET menuheight=ypix(menu_win)-2*menuborder LET menuwidth=xpix(menu_win)-2*menuborder LET menuboxheight=int(menuheight/(maxchoices+1)) LET menuboxwidth=menuwidth LET menuleft=menuborder LET menuright=menuleft+menuwidth END SUB !###################### Redraw Menu ####################### SUB update_menu LOCAL i,whatitwas,n,m ! if digraph$="yes" then ! menulabel$(digraphi,digraphj)="un-digraph" ! else ! menulabel$(digraphi,digraphj)="make digraph" ! end if WINDOW #menu_win ASK COLOR whatitwas LET n=len(dowhat$) LET m=0 LET i=0 DO LET i=i+1 WHEN error in LET m=val(dowhat$[i:n]) USE END WHEN LOOP until m>0 BOX CLEAR 0,xpix(menu_win),0,ypix(menu_win) BOX LINES 0,xpix(menu_win),0,ypix(menu_win) SET TEXT justify "center","half" FOR i=1 to menuchoices(current_menu) BOX LINES (xpix(2)-menuboxwidth)/2,(xpix(2)-menuboxwidth)/2+menuboxwidth,ypix(2)-i*menuboxheight,ypix(2)-(i+1)*menuboxheight PLOT TEXT, AT xpix(2)/2,ypix(2)-(i+.5)*menuboxheight:menulabel$(current_menu,i) NEXT i FOR i=1 to num_menus IF i=current_menu then SET COLOR "red" else SET COLOR whatitwas PLOT TEXT, AT menuborder+(i-.5)*menuboxwidth/num_menus,ypix(2)-2-.5*menuboxheight:str$(i) NEXT i SET COLOR "red" BOX LINES (xpix(2)-menuboxwidth)/2,(xpix(2)-menuboxwidth)/2+menuboxwidth,ypix(2)-m*menuboxheight,ypix(2)-(m+1)*menuboxheight PLOT TEXT, AT xpix(2)/2,ypix(2)-(m+.5)*menuboxheight:menulabel$(current_menu,m) SET COLOR whatitwas !select case dowhat$ CALL clear_mouse END SUB !########## find which window the point x,y is in: (x,y) in pixels ####### FUNCTION which_window(x,y) LOCAL i LET which_window=0 FOR i=1 to num_windows IF left(i)0 then LET verts(i,5)=verts(i,4)-verts(i-1,4) else LET verts(i,5)=verts(i,4) NEXT i END SUB FUNCTION torange(top,bottom,num) LET torange=min(top,max(num,bottom)) END FUNCTION !################## Nuke Vertex ################# SUB nukevert(who) LOCAL i,j WINDOW #graph_win CALL wipevert(who) FOR i=who to numsegs-1 FOR j=1 to 5 LET verts(i,j)=verts(i+1,j) NEXT j NEXT i LET numsegs=numsegs-1 MAT redim verts(0:numsegs,5) CALL drawverts END SUB !################## Clear Graph #################### SUB nukeall LOCAL answer$,reply$ LET answer$="" WINDOW #message_win DO INPUT prompt "Are you sure you want to permanently destroy the current graph? (y/n) ":reply$ LET answer$=lcase$(reply$[1:1]) LOOP until answer$="y" or answer$="n" IF answer$="y" then IF numsegs>0 then DO CALL nukevert(1) LOOP until numsegs=0 END IF END IF WINDOW #menu_win CALL clear_mouse LET dowhat$=code$(current_menu,1) END SUB !################## Select a Vertex ##################! SUB selekt(who) LET selected=who CALL drawverts END SUB !################ Clear windows ############ !sub windex(#1,#2,#3) SUB windex ! :) FOR i=0 to num_windows WINDOW #i ASK WINDOW xmn,xmx,ymn,ymx BOX CLEAR xmn,xmx,ymn,ymx BOX LINES xmn,xmx,ymn,ymx NEXT i CALL update_menu WINDOW #1 CALL drawverts END SUB !################# Save Config ############## !sub saveit(#1,#2,#3) SUB saveit WINDOW #3 INPUT prompt "filename? (c to cancel)":savefile$ IF lcase$(savefile$)="c" then CALL clear_mouse WINDOW #2 EXIT SUB END IF CALL can_opener(savefile$,"write",#10) PRINT #10:numsegs;",";xpix(graph_win);",";ypix(graph_win) !tell the size of window for portability FOR i=1 to numsegs PRINT#10: verts(i,1);",";verts(i,2) NEXT i PRINT#10: numedges;",";0 CLOSE #10 CALL clear_mouse LET dowhat$="move1" CALL update_menu END SUB !################ Load Saved Config ######### !sub oldn(#1,#2,#3) (If you want it out of main program, you have to ! send the channels SUB oldn WINDOW #message_win INPUT prompt "Name of old file? ":oldfile$ CALL can_opener(oldfile$,"read",#10) IF more #10 then LET xsize,ysize=0 WHEN error in INPUT #10: numsegs,xsize,ysize USE RESET #10: begin INPUT #10: numsegs END WHEN MAT redim verts(numsegs,2) FOR i=1 to numsegs INPUT #10: verts(i,1),verts(i,2) IF verts(i,1)<1 then LET verts(i,1)=verts(i,1)*xpix(graph_win) LET verts(i,2)=verts(i,2)*ypix(graph_win) ELSE IF xsize>0 then LET verts(i,1)=int(verts(i,1)*xpix(graph_win)/xsize) LET verts(i,2)=int(verts(i,2)*ypix(graph_win)/xsize) END IF NEXT i DO while more #10 INPUT #10: numedges,zero !the last pair = numedges,zero LOOP RESET #10: begin IF xsize>0 then INPUT #10: null,nuller,nullest ELSE INPUT #10: null END IF CLOSE #10 END IF CALL clear_mouse LET dowhat$="move1" CALL update_menu CALL windex !(#1,#2,#3) END SUB !##################### Initialize Pictures (little dots, that is) ############ SUB init_pics ASK COLOR whatitwas LET vertsize=6 LET halfvertsize=.5*vertsize BOX CLEAR 0,vertsize,0,vertsize BOX KEEP 0,vertsize,0,vertsize in vertwipe$ SET COLOR "blue" BOX AREA 0,vertsize,0,vertsize BOX KEEP 0,vertsize,0,vertsize in vertpic$ SET COLOR "red" BOX AREA 0,vertsize,0,vertsize BOX KEEP 0,vertsize,0,vertsize in redvert$ SET COLOR whatitwas CLEAR END SUB !#################### Draw the vertices ############### SUB drawverts LOCAL aye !window #graph_win ASK COLOR whatitwas IF selected<>0 and selected <= numsegs then BOX SHOW redvert$ at verts(selected,1)-halfvertsize,verts(selected,2)-halfvertsize END IF SET COLOR "red" PLOT verts(0,1) ,verts(0,2);verts(numsegs,1) ,verts(numsegs,2) SET COLOR whatitwas FOR aye=0 to numsegs BOX SHOW vertpic$ at verts(aye,1)-halfvertsize,verts(aye,2)-halfvertsize !plot verts(aye,1) ,verts(aye,2); NEXT aye PLOT CALL calculengths CALL plaht(verts(0,1) ,verts(0,2),verts(numsegs,1) ,verts(numsegs,2),drawlevel) END SUB SUB drawpat if drawpattern=1 then CALL plaht(verts(0,1) ,verts(0,2),verts(numsegs,1) ,verts(numsegs,2),1) end if END SUB !############### plot relatively ##################### SUB plaht(fromx,fromy,twox,twoy,level) ! get too many of these, and bang, you're a soap opera LOCAL i,x,y,newx,newy,ngle,scale IF level=0 then PLOT fromx,fromy;twox,twoy ELSE LET x=fromx LET y=fromy LET ngle=smarctan(twox-fromx,twoy-fromy) LET scale=sqr((twox-fromx)^2+(twoy-fromy)^2) FOR i=0 to numsegs-1 LET length=scale*verts(i,3) LET ngle=ngle+verts(i,5) LET newx=x+length*cos(ngle) LET newy=y+length*sin(ngle) CALL plaht(x,y,newx,newy,level-1) LET x=newx LET y=newy NEXT i END IF !PLOT END SUB !SUB plaht(fromx,fromy,twox,twoy,level) ! get too many of these, and bang, you're a soap opera ! LOCAL i,j ! ! call calculengths ! LET x=verts(0,1) ! LET y=verts(0,2) ! LET ngle=0 ! PLOT x,y; ! !oldscale=1 ! FOR j=0 to numsegs-1 ! LET scale=totalength*verts(j,3) ! LET ngle=verts(j,4) ! !debuglength=0 ! FOR i=0 to numsegs-1 ! LET length=scale*verts(i,3)*totalength/(verts(numsegs,1)-verts(0,1)) ! !debuglength=debuglength+length ! LET ngle=ngle+verts(i,5) ! LET x=x+length*cos(ngle) ! LET y=y+length*sin(ngle) ! PLOT x,y; ! NEXT i ! !call message(str$(debuglength)&","&str$(scale),graph_win) ! ! !oldscale=verts(j,3) ! NEXT j ! PLOT !END SUB !############### smart arctangent ############## FUNCTION smarctan(cosyne,syne) !local conv IF sin(90)=1 then LET conv=1 else LET conv=pi/180 IF cosyne=0 then LET unconverted=90*sgn(syne) ELSE LET unconverted=atn(syne/cosyne) IF cosyne<0 then LET unconverted=unconverted+180 END IF LET smarctan=conv*unconverted END FUNCTION !#################### Draw all edges ############### SUB drawedges END SUB !############ add an arrow to existing line ############## SUB draw_arrow(x1,y1,x2,y2) LOCAL half_width,half_height,xnear,ynear CALL arrow_width_height(x1,y1,x2,y2,half_width,half_height) LET xnear=x1+.75*(x2-x1) LET ynear=y1+.75*(y2-y1) PLOT xnear+half_width,ynear+half_height; PLOT xnear-half_width,ynear-half_height; PLOT x1+.875*(x2-x1),y1+.875*(y2-y1); PLOT xnear+half_width,ynear+half_height !flood (xnear+x2)/2,(ynear+y2)/2 END SUB SUB arrow_width_height(x1,y1,x2,y2,half_width,half_height) LOCAL slope IF (y2-y1)<>0 then LET slope=-(x2-x1)/(y2-y1) ! half_width=.5*sgn(slope)*sqr(vertsize^2/(1+slope^2)) LET half_width=.5*sqr(vertsize^2/(1+slope^2)) LET half_height=slope*half_width ELSE LET half_width=0 LET half_height=.5*vertsize END IF END SUB !##################### Drag a vertex around, updating edges as you go ########## SUB movert(who) IF who<>0 and who<>numsegs and ( xmouse<>verts(who,1) or ymouse<>verts(who,2) ) then !only let the user move the internal nodes LOCAL i WINDOW #graph_win ! get rid of old vertex's picture BOX SHOW vertwipe$ at verts(who,1)-halfvertsize,verts(who,2)-halfvertsize ASK COLOR whatitwas SET COLOR "background" PLOT verts(who-1,1),verts(who-1,2);verts(who,1),verts(who,2);verts(who+1,1),verts(who+1,2) !CALL plaht CALL plaht(verts(0,1) ,verts(0,2),verts(numsegs,1) ,verts(numsegs,2),drawlevel) call drawpat SET COLOR whatitwas !make sure we're not trying to put it on another vertex IF find_other_vert(xmouse,ymouse,who)=-1 then LET verts(who,1)=max(min(xmouse,xpix(1)-vertsize),0+vertsize) LET verts(who,2)=max(min(ymouse,ypix(1)-vertsize),0+vertsize) END IF !draw the new version of things CALL drawverts SET COLOR "blue" CALL drawpat SET COLOR whatitwas END IF END SUB !################# Erases a drawn edge ############ SUB wipedge(a,b) LOCAL whatitwas ! window #graph_win ASK COLOR whatitwas SET COLOR back PLOT LINES: verts(a,1),verts(a,2);verts(b,1),verts(b,2) SET COLOR whatitwas END SUB !################# Erases a drawn vertex ############ SUB wipevert(who) WINDOW #graph_win BOX SHOW vertwipe$ at verts(who,1)-halfvertsize,verts(who,2)-halfvertsize END SUB !################## Function--sees if mouse is on a vertex or not #################### FUNCTION findvert(xmouse,ymouse) LOCAL I LET findvert=0 FOR i=1 to numsegs IF verts(i,1)<=(xmouse+halfvertsize) and verts(i,2)<=(ymouse+halfvertsize) and xmouse<=verts(i,1)+halfvertsize and ymouse<=verts(i,2)+halfvertsize then LET findvert=i END IF NEXT i END FUNCTION !################## Function--sees if pair of points is within a vertex other than the given one#################### FUNCTION find_other_vert(x,y,given_vert) LOCAL i,ex,why LET find_other_vert=-1 LET ex=max(min(x,xpix(1)-vertsize),0+vertsize) LET why=max(min(y,ypix(1)-vertsize),0+vertsize) FOR i=0 to numsegs IF verts(i,1)<=(ex+3*halfvertsize) and verts(i,2)<=(why+3*halfvertsize) and ex<=verts(i,1)+3*halfvertsize and why<=verts(i,2)+3*halfvertsize then IF i<>given_vert then LET find_other_vert=i END IF NEXT i END FUNCTION !################ Do nothing until mouse button is released ########## SUB clear_mouse DO GET MOUSE x,y,s LOOP until s=0 or s=3 END SUB !################ Find the distance from vert1 to vert2 ########## FUNCTION distance(vert1,vert2) END FUNCTION SUB digraph_toggle END SUB END !################ End of main program ############### !#################### Generic File Opener #################### SUB can_opener (filename$,reedwright$,#1) DO WHEN error in CLOSE #1 OPEN #1: name filename$, org "text", create newold EXIT DO USE INPUT prompt filename$&" can't be opened (not a text file?). Please enter another filename.":filename$ END WHEN LOOP IF more #1 then IF reedwright$="write" then PRINT "File ";filename$;" exists. Type" PRINT "1 to select another file" PRINT "2 to append to the end of this file" PRINT "3 to overwrite this file" DO WHEN error in GET KEY choice LET choice=val(chr$(choice)) IF choice=1 or choice=2 or choice=3 then EXIT DO ELSE PRINT"please enter 1 (select another), 2 (append), or 3 (overwrite)." END IF USE PRINT "Please type a 1, 2, or 3" END WHEN LOOP SELECT CASE choice CASE 1 INPUT prompt "Please input desired filename. ":filename$ CALL can_opener (filename$,reedwright$,#1) EXIT SUB CASE 2 RESET #1:end EXIT SUB CASE 3 INPUT prompt "Are you sure you want to write over the data in "&filename$&"(y/n)?":yesno$ IF lcase$(yesno$[1:1])<>"y" then CALL can_opener(filename$,reedwright$,#1) EXIT SUB ELSE ERASE #1 END IF CASE else PRINT "error--please report to mike" ! print ! print"please enter 1 (select another), 2 (append), or 3 (overwrite)." ! let tryagain=1 END SELECT ! loop until tryagain=0 END IF END IF END SUB !public verts(1,1),tempverts(1,1),edges(1,1),tempedges(1,1),graphsize,xmouse,ymouse !public firstvert,vertpic$,redvert$,vertwipe$,vertsize,halfvertsize,dowhat$ !public menuchoices,menulabel$(6) ! !public left(1),right(1),bottom(1),top(1),xpix(0:1),ypix(0:1) !public verts(1,1),tempverts(1,1),edges(1,1),tempedges(1,1),graphsize !public firstvert,vertpic$,redvert$,vertwipe$,vertsize,halfvertsize,dowhat$ !public menuchoices(),menulabel$(1,1),code$(1,1),oldcode$(1) !public left(1),right(1),bottom(1),top(1),xpix(0:1),ypix(0:1) !public graph_win,menu_win,message_win,current_menu,maxchoices,num_menus !hell? no (line 667, tday+1, 1995)