// May 3, 1978  11:35 AM			*** RESIDENT - MAIN ***
//Edited by Lyle Ramshaw  September 2, 1980  10:24 PM:
// Played with centering computation 

//loading instructions are in Draw.ld;  at one point, they were:
//  BLDR/F/B/R   1100/N  725/W  DRAW/S ↑
//  ZPEDIT  ZPUTIL  ZPBLOCK  SPLINE1 (or SPLINE2, SPLINE3, etc)  MICROFLOAT ↑
//  C/Q  ZPINTER  ZPDRAW  ZPTEXT  ZPMAKE  ZPCONVERT  ZPCOLOR  ZPFONT ↑
//  B/Q  ZPINIT1  ZPINIT2  ZPFONTIO  READUSERCMITEM ↑
//  E/Q  MICROFLOATMC  READPRAM ↑
//  B/P  DRAWOV1/B  ZPDISP  ZPUPDATE  ZPITEM ↑
//  B/P  DRAWOV2/B  ZPDISP  ZPIO  ZPFONTIO  ZPADJUST  ZPARROWS ↑
//  B/P  DRAWOV3/B  ZPDISP  ZPFREEHAND ↑
//  C/P  DRAWOV4/B  ZPPRESS  ZPOBJECT1  ZPOBJECT2  ZPPIECE  ZPPUTS  ZPARROWS  TIMECONVA  TIMECONVB  TIMEIO ↑
//  C/P  DRAWOV5/B  ZPINTER  ZPDRAW  ZPTEXT  ZPMAKE  ZPCONVERT  ZPCOLOR  ZPFONT

// WARNING: THE OVERLAY PATTERN IS COMPLICATED
// There are TWO overlay base addresses:
//		B: overlays 1, 2, 3
//			-all overlays contain ZPDISP
//			-the rest of overlay 3 (freehand) is used for STORAGE (sample buffer)
//		C: overlays 4, 5
//			-a copy of overlay 5 is also loaded with the initialization code


get "zpDefs.bcpl"

get "zpComDf.bcpl"


// outgoing procedure

external [
	drawMain
	drawFinish
	grid
	]


// incoming procedures:

external [
				// *** RESIDENT ***

	OpenFile		// SYSTEM
	Zero

	obtainBlock		// ZPBLOCK
	putBlock
	overlay

	makeText		// ZPTEXT
	rewriteText
	turnTextOn
	turnTextOff
	incTextBuffer
	decTextBuffer
	refreshTextBuffer

	confirm			// ZPUTIL
	typeForm
	getInteger
	getLine

	changeCursor		// ZPINTER
	makeTextCursor
	getEventRegular
	curveHitDetect
	textHitDetect

	paintSpline		// ZPCOLOR
	paintText
	setColorMode

				// *** "UNDERLAY" ***

	drawJunta		// ZPINIT

				// *** OVERLAYS ***

	createSpline		// ZPUPDATE	(overlay)
	createCyclicSpline
	redrawSpline
	dashSpline
	addNewKnot
	backUp
	startAgain
	clearSelection
	deleteSelection
	addSplineSelection
	addTextSelection
	selectAll
	prepareTransform
	clearTransform

	DTTitems		// ZPITEM
	unDTTitems
	addItemTable

	refreshDisplay		// ZPDISP
	menuDisplay
	wipeDisplay
	gridDisplay
	frameDisplay

	drawFreeHand		// ZPFREEHAND	(overlay)
	getEventFreeHand
	freeHandCursor

	readPicture		// ZPIO		(overlay)
	writePicture
	writeStatistics
	writeBitmap
	changeTextMode
	readHelp
	readFont

	writePressFile		// ZPPRESS	(overlay)
	]


// outgoing statics:

external [
	@posTextMode
	@showGrid
	@currentTextId
	@colorOn
	]

static[
	@posTextMode=posTextCenter
	@showGrid=0
	@currentTextId=0
	@colorOn=0
	]



// incoming statics:

external [
	fpSysDir		// SYSTEM

	@bitmap			// ZPINIT
	@bitmapSize
	@Xmax
	@Ymax
	@gridSpacing

	@fontFile
	@dspFont
	@font
	@brush
	@color

	@maxSplineID
	@maxTextID
	@splineTable
	@textTable
	@deletionTable
	@transformXYtable
	@transformModeTable
	@commandTable
	@actionTable

	@textOK
	@textString
	@textWidth
	@textHeight

	@help			// ZPIO
	]


// local statics:

static [
	@command=CMmake
	@freeHandMode=false
	@getEvent
	@pictureSaved=false
	@videoOn=false
	]




  
//*****************************************************************
// main editing loop
//*****************************************************************


let drawStart(loadVec, nil, cfa) be [drawStart
	drawJunta(loadVec, cfa)
	]drawStart



and drawFinish() be [drawFinish
	@ lvDisplayHeader=0
	for i=1 to 1000 do [ let t=nil ]
	]drawFinish



and drawMain() be [drawMain

	//initialize main loop
	unless overlay(updateOverlay) then finish
	getEvent=getEventRegular
	freeHandMode=false
	colorOn=false
	refreshDisplay()
	turnTextOff()
	let p=nil
	let h=vec HITPOINTblockSize
	changeCursor(makeCursor)

	[mainloop
	if (command eq CMfreeHand) & not freeHandMode then setFreeHandMode()
	let event=getEvent(h)
	let eventSwitch=event<<EVENT.switch
	let eventCode=event<<EVENT.code
	let doCommand=command

	unless eventSwitch then [
		let commandEntry=commandTable!(eventCode)
		doCommand=commandEntry<<COMMAND.com
		if commandEntry<<COMMAND.end then
		  switchon (actionTable!command)<<ACTION.end into [
			case EAnothing:
				endcase
			case EAmake:
				createSpline()
				endcase
			case EAcyclic:
				createCyclicSpline()
				commandTable!escKey=CMmake+changeCommand
				endcase
			case EAstartAgain:
				startAgain()
				endcase
			case EAtext:
				currentTextId=0
				endcase
			case EAfreeHand:
				if doCommand ne CMfreeHand then [
					overlay(updateOverlay)
					getEvent=getEventRegular
					freeHandMode=false
					]
				endcase
				]
		if commandEntry<<COMMAND.change then
			command=doCommand
		]

	let action=eventSwitch ?
		(actionTable!doCommand)<<ACTION.switch, 
		(actionTable!doCommand)<<ACTION.begin

	switchon action into [
	case CAnothing:
		loop

	case BAmake:
		changeCursor(makeCursor)
		loop
	case BAcyclic:
		changeCursor(cyclicCursor)
		commandTable!escKey=CMcyclic+changeCommand
		loop
	case SWaddKnot:
		p=whichPoint(eventSwitch, h)
		if p then addNewKnot(p>>HITPOINT.x, p>>HITPOINT.y)
		loop

	case CAbackUp:
		backUp()
		loop
	case CAstartAgain:
		startAgain()
		loop

	case BAdelete:
		changeCursor(deleteCursor)
		loop
	case SWdelete:
		apply(eventSwitch, h, prepareSplineDelete, prepareTextDelete)
		DTTitems(deletionTable)
		deletionTable!0=0
		loop
	case CAundelete:
		unDTTitems()
		loop

	case CAchar:
		incTextBuffer(eventCode)
		loop
	case CAdelChar:
		decTextBuffer()
		loop
	case BAtext:
		turnTextOn()
		makeTextCursor()
		loop
	case SWtext:
		unless textOK loop
		p=whichPoint(eventSwitch, h)
		if p then [
			textPosition(p)
			currentTextId=makeText(textString, 
				p>>HITPOINT.x, p>>HITPOINT.y, font, color)
			]
		loop

	case BAselect:
		changeCursor(selectCursor)
		clearSelection()
		loop
	case BAselectAll:
		selectAll()
		loop
	case SWselect:
		apply(eventSwitch, h, addSplineSelection, addTextSelection)
		loop
	case CAdelSelection:
		deleteSelection()
		loop

	case BAmTransf2:
	case BAcTransf2:
	case BAmTransf4:
	case BAcTransf4:
	case BAmTransf6:
	case BAcTransf6:
		changeCursor(transfCursor0+action-BAmTransf2)
		transformXYtable>>XYTABLE.mode=transformModeTable!(action-BAmTransf2)
		clearTransform()
		loop
	case SWtransform:
		p=whichPoint(eventSwitch, h)
		if p then prepareTransform(p>>HITPOINT.x, p>>HITPOINT.y)
		loop

	case CAshowGrid:
		showGrid=not showGrid
		gridDisplay(gridSpacing)
		loop

	case CAquit:
		if confirm("*NQuit ? ") then [
			camera>>CAMERA.insideMode=altoOnly
			finish
			]
		loop

	case CAplot:
		plot()
		loop
	case CAread:
	case CAwrite:
	case CAtextMode:
	case CAstatistics:
		splineIO(action)
		loop
	case CAbitmap:
		frameDisplay(0)
		splineIO(CAbitmap)
		frameDisplay(1)
		loop
	case CAreadFont:
		splineIO(CAreadFont)
		updateFontStuff()
		loop

	case CAbrush:
		brush<<BRUSH.shape=event-menuCode-1
	case CAthickness:
		if action eq CAthickness then
			brush<<BRUSH.thickness=event-(menuCode+symbolCount+1)
		menuDisplay()
		if freeHandMode then freeHandCursor()
		loop
	case CAfont: [
		let menuNumber=event-menuCode
		let newFont=(menuNumber le symbolCount) ? menuNumber-symbolCount+1, 
				menuNumber-2*symbolCount+3
		if newFont eq dspFont %
			fontFile>>FONTFILE.length↑newFont ne 0 then [
				font=newFont
				updateFontStuff()
				]
		loop
		]

	case BAredraw:
		changeCursor(brushCursor)
		loop
	case SWredraw:
		apply(eventSwitch, h, redrawSpline, rewriteText)
		loop
	case BAdash:
		changeCursor(dashCursor)
		loop
	case SWdash:
		apply(eventSwitch, h, dashSpline, 0)
		loop

	case BApaint:
		setColorMode(event-menuCode)
		endcase
	case SWpaint:
		apply(eventSwitch, h, paintSpline, paintText)
		endcase

	case CAcolorOnOff:
		colorOn=not colorOn
	case CArefresh:
		refreshDisplay()
		loop

	case BAfreeHand:
		setFreeHandMode()
		loop
	case SWfreeHand:
		drawFreeHand()
		loop

	case CAvideo:
		camera>>CAMERA.insideMode= videoOn ? altoOnly, altoAndCamera
		videoOn= not videoOn
		loop

	case CAhelp:
		helpMode()
		loop
	case CAmoreHelp:
		if help then getHelp()
		loop
	default:
		loop
	]
	]mainloop repeat
	]drawMain


and updateFontStuff() be [updateFontStuff
	menuDisplay()
	refreshTextBuffer()
	if command eq CMtext then makeTextCursor()
	]updateFontStuff


and setFreeHandMode() be [setFreeHandMode
	overlay(freeHandOverlay)
	getEvent=getEventFreeHand
	freeHandMode=true
	freeHandCursor()
	]setFreeHandMode


//*****************************************************************
// deletion
//*****************************************************************


and prepareSplineDelete(id) = addItemTable(deletionTable, id)


and prepareTextDelete(id) = addItemTable(deletionTable, id+textFlag)



//*****************************************************************
// x y stuff
//*****************************************************************


and whichPoint(eventSwitch, h) = valof [whichPoint
	// h is a HITPOINT vector
	// resultis is 0, or h (modified)
	switchon eventSwitch into [
	case 1: 
		resultis h
	case 2:
		test curveHitDetect(h) % textHitDetect(h)
		ifso resultis h
		ifnot resultis 0
	case 3:
		h>>HITPOINT.x=grid(h>>HITPOINT.x)
		h>>HITPOINT.y=grid(h>>HITPOINT.y)
		resultis h
	default:
		resultis 0
		]
	]whichPoint



and textPosition(p) be [textPosition
	// p is a HITPOINT vector
	let tw2, th2=(textWidth+1)/2, textHeight/2
	p>>HITPOINT.x=p>>HITPOINT.x +1 - selecton posTextMode into [
		case posTextCenter: tw2;
		case posTextTop: tw2;
		case posTextBottom: tw2;
		case posTextLeft: 0;
		case posTextRight: textWidth
		]
	p>>HITPOINT.y=p>>HITPOINT.y + selecton posTextMode into [
		case posTextCenter: th2;
		case posTextTop: 0;
		case posTextBottom: textHeight;
		case posTextLeft: th2;
		case posTextRight: th2
		]
	]textPosition



and grid(z) = valof [grid
	let g=(z/gridSpacing)*gridSpacing
	if (z-g) ge (gridSpacing rshift 1) then g=g+gridSpacing
	resultis g
	]grid



and apply(eventSwitch, h, splineOperation, textOperation) be [apply
	// h is a HITPOINT vector
	unless eventSwitch return

	test eventSwitch le 3
	//apply to hit items
	ifso test textOperation & textHitDetect(h)
		ifso textOperation(h>>HITPOINT.id)
		ifnot if splineOperation & curveHitDetect(h) then
			splineOperation(h>>HITPOINT.id, h)
	//NOTICE: the 2nd argument (h) is used only by addSplineSelection
	//		and by paintSpline

	ifnot [
	// apply to area
	let left=h>>HITPOINT.x1
	let top=h>>HITPOINT.y1
	let right=h>>HITPOINT.x2
	let bottom=h>>HITPOINT.y2
	if left gr right then [ right=left; left=h>>HITPOINT.x2 ]
	if bottom gr top then [ top=bottom; bottom=h>>HITPOINT.y1 ]
	if splineOperation & splineTable!0 then
	for id=1 to maxSplineID do [
		let splinePointer=splineTable!id
		unless splinePointer loop
		if (left le splinePointer>>SPLINE.left) &
		 (right ge splinePointer>>SPLINE.right) &
		 (top ge splinePointer>>SPLINE.top) &
		 (bottom le splinePointer>>SPLINE.bottom) then
				splineOperation(id)
		]
	if textOperation & textTable!0 then
	for id=1 to maxTextID do [
		let textPointer=textTable!id
		unless textPointer loop
		if (left le textPointer>>TEXT.left) &
		 (right ge textPointer>>TEXT.right) &
		 (top ge textPointer>>TEXT.top) &
		 (bottom le textPointer>>TEXT.bottom) then
				textOperation(id)
		]
		]
	]apply


//*****************************************************************
// help stuff (ioOverlay)
//*****************************************************************

and helpMode() be [helpMode
	let savedPictureFile="DRAW-SAVE.DRAW"
	test help
	ifso [
		// return from help mode
		wipeDisplay()
		help=0
		if pictureSaved & overlay(ioOverlay) then [
			readPicture(OpenFile(savedPictureFile, ksTypeReadOnly))
			pictureSaved=0
			]
		]
	ifnot [
		// get into help mode
		help=1
		if (splineTable!0 % textTable!0) & overlay(ioOverlay) then [
			typeForm(0, "Saving your picture away! ")
			writePicture(OpenFile(savedPictureFile, ksTypeWriteOnly))
			pictureSaved=true
			]
			getHelp()
		]
	resetOverlay()
	]helpMode


and getHelp() be [getHelp
	overlay(updateOverlay)
	wipeDisplay()
	if overlay(ioOverlay) then readHelp()
	resetOverlay()
	]getHelp


//*****************************************************************
// various I/O functions (ioOverlay)
//*****************************************************************

and splineIO(CAfileIO) be [splineIO
	unless overlay(ioOverlay) return
	switchon CAfileIO into [
	case CAread:
		readPicture(); endcase
	case CAwrite:
		writePicture(); endcase
	case CAtextMode:
		changeTextMode()
		if command eq CMtext then makeTextCursor()
		endcase
	case CAstatistics:
		// special command
		writeStatistics(); endcase
	case CAbitmap:
		// special command
		writeBitmap(); endcase
	case CAreadFont:
		readFont(); endcase
		]
	resetOverlay()
	]splineIO


and resetOverlay() = overlay(freeHandMode ? freeHandOverlay, updateOverlay)



//*****************************************************************
// PRESS I/O (pressOverlay, on top of BOTH residentOverlay & updateOverlay)
//*****************************************************************


and plot() be [plot
	clearSelection()
	// first partial refresh
	refreshDisplay(true)
	if overlay(pressOverlay) then [
		writePressFile()
		overlay(residentOverlay)
		resetOverlay()
		// then full refresh
		refreshDisplay()
		]
	]plot