1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * aint32 with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  *
22  * Based on the original sources
23  *   Faery Tale II -- The Halls of the Dead
24  *   (c) 1993-1996 The Wyrmkeep Entertainment Co.
25  */
26 
27 #include "common/keyboard.h"
28 
29 #include "saga2/saga2.h"
30 #include "saga2/document.h"
31 #include "saga2/script.h"
32 #include "saga2/intrface.h"
33 #include "saga2/grequest.h"
34 #include "saga2/mouseimg.h"
35 #include "saga2/version.h"
36 #include "saga2/fontlib.h"
37 
38 namespace Saga2 {
39 
40 /* ===================================================================== *
41     About box
42  * ===================================================================== */
43 
44 #define PROGRAM_ABOUT   " v" VERSION_OPSYS " " VERSION_STAMP
45 
46 
47 // externs
48 extern BackWindow           *mainWindow;
49 
50 // declarations
51 APPFUNC(cmdDocumentQuit);
52 
53 
54 /* ===================================================================== *
55    scroll metrics
56  * ===================================================================== */
57 
58 // buttons
59 //Rect16    closeScrollBtnRect( 184, 206, 44, 42 );
60 
61 // options dialog window decorations
62 static StaticWindow scrollDecorations[] = {
63 	{{202,  54, 232, 100}, nullptr, 0},
64 	{{212, 154, 212, 100}, nullptr, 1},
65 	{{202, 254, 236, 117}, nullptr, 2}
66 };
67 
68 static uint8 scrollTextColors[] = { 65, 65, 65, 65, 65, 65, 65, 66, 66, 67, 67, 67, 67, 66, 66, 66 };
69 
70 CDocumentAppearance scrollAppearance = {
71 	{202, 54, 236, 317},
72 	1,
73 	pageOrientVertical,
74 	scrollTextColors,
75 	{ {50, 64, 131, 169}, {0, 0, 0, 0} },
76 	{184, 206,  44,  42},
77 	scrollDecorations,
78 	ARRAYSIZE(scrollDecorations),
79 	MKTAG('S', 'C', 'R', 'L'),
80 	MKTAG('S', 'R', 'L', 0)
81 };
82 
83 /* ===================================================================== *
84    Book metrics
85  * ===================================================================== */
86 
87 // options dialog window decorations
88 static StaticWindow bookDecorations[] = {
89 	{{123,  76, 394, 88}, nullptr, 0},
90 	{{123, 164, 394, 80}, nullptr, 1},
91 	{{123, 244, 394, 77}, nullptr, 2}
92 };
93 
94 static uint8 bookTextColors[] = { 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65 };
95 
96 CDocumentAppearance bookAppearance = {
97 	{123, 76, 394, 252},
98 	2,
99 	pageOrientHorizontal,
100 	bookTextColors,
101 	{ {40, 26, 135, 205}, {218, 26, 135, 205} },
102 	{231, 217,  34,  27},
103 	bookDecorations,
104 	ARRAYSIZE(bookDecorations),
105 	MKTAG('B', 'O', 'O', 'K'),
106 	MKTAG('B', 'K', 'D', 0)
107 };
108 
109 /* ===================================================================== *
110    Parchment metrics
111  * ===================================================================== */
112 
113 // options dialog window decorations
114 static StaticWindow parchDecorations[] = {
115 	{{202,  54, 208, 256}, nullptr, 0}
116 };
117 
118 CDocumentAppearance parchAppearance = {
119 	{202, 54, 208, 256},
120 	1,
121 	pageOrientVertical,
122 	bookTextColors,
123 	{ {27, 18, 149, 212}, {0, 0, 0, 0} },
124 	{164, 229,  20,  20},
125 	parchDecorations,
126 	ARRAYSIZE(parchDecorations),
127 	MKTAG('P', 'A', 'R', 'C'),
128 	MKTAG('P', 'C', 'H', 0)
129 };
130 
131 // deliminator defines
132 char deliminator    = '@';
133 char dPageBreak[3]  = { "pb" };
134 char dImage[3]      = { "im" };
135 
136 /* ===================================================================== *
137    Document base class
138  * ===================================================================== */
139 
CDocument(CDocumentAppearance & dApp,char * buffer,gFont * font,uint16 ident,AppFunc * cmd)140 CDocument::CDocument(CDocumentAppearance &dApp,
141                      char            *buffer,        // buffer to edit
142                      gFont           *font,          // font of the text
143                      uint16          ident,          // control ID
144                      AppFunc         *cmd)           // application command func
145 	: app(dApp), ModalWindow(dApp.windowPos, ident, cmd) {
146 	// resource handle
147 	hResContext     *decRes;
148 
149 	// init the resource context handle
150 	decRes = resFile->newContext(app.groupID, "docimage context");
151 
152 	// init con pointer to NULL
153 	illustrationCon = NULL;
154 
155 	// set the maxium string length
156 	maxSize = maxPages * maxLines * maxChars;
157 
158 	// get the org text size
159 	textSize = clamp(0, strlen(buffer), maxSize);
160 
161 	// set the original text pointer
162 	origText = new char[textSize + 1];
163 
164 	// and fill it
165 	Common::strlcpy(origText, buffer, textSize + 1);
166 
167 	// make a working buffer
168 	text = new char[textSize + 1];
169 
170 	// and fill it
171 	Common::strlcpy(text, origText, textSize + 1);
172 
173 	textFont        = font;
174 	textHeight      = (textFont ? textFont->height : 0);
175 	lineWidth       = dApp.pageRect[0].width;
176 	pageHeight      = dApp.pageRect[0].height;
177 	currentPage     = 0;
178 	totalLines      = 0;
179 	totalPages      = 0;
180 	pageBreakSet    = true;
181 
182 	// null out the image pointer array
183 	for (int16 i = 0; i < maxPages; i++) {
184 		images[i] = NULL;
185 	}
186 
187 	makePages();
188 
189 	// attach the graphics for the book
190 	setDecorations(app.decoList,
191 	               app.numDecos,
192 	               decRes, app.decoID);
193 
194 	// remove the resource handle
195 	if (decRes) resFile->disposeContext(decRes);
196 	decRes = NULL;
197 
198 
199 }
200 
~CDocument(void)201 CDocument::~CDocument(void) {
202 	int16   i;
203 
204 	for (i = 0; i < maxPages; i++) {
205 		if (images[i]) {
206 			free(images[i]);
207 		}
208 	}
209 
210 	// get rid of the working text buffer
211 	if (text) {
212 		delete[] text;
213 		text = NULL;
214 	}
215 
216 	if (origText) {
217 		delete[] origText;
218 		origText = NULL;
219 	}
220 
221 	// get rid of the resource context
222 	if (illustrationCon)
223 		resFile->disposeContext(illustrationCon);
224 }
225 
deactivate(void)226 void CDocument::deactivate(void) {
227 	selected = 0;
228 	gPanel::deactivate();
229 }
230 
activate(gEventType why)231 bool CDocument::activate(gEventType why) {
232 	if (why == gEventMouseDown) {           // momentarily depress
233 		selected = 1;
234 		notify(why, 0);                      // notify App of successful hit
235 		return true;
236 	}
237 	return false;
238 }
239 
keyStroke(gPanelMessage & msg)240 bool CDocument::keyStroke(gPanelMessage &msg) {
241 	gEvent ev;
242 	switch (msg.key) {
243 	case Common::ASCII_ESCAPE:
244 		cmdDocumentEsc(ev);
245 		return true;
246 	case Common::KEYCODE_LEFT:
247 		cmdDocumentLt(ev);
248 		return true;
249 	case Common::KEYCODE_RIGHT:
250 		cmdDocumentRt(ev);
251 		return true;
252 	case Common::KEYCODE_UP:
253 		cmdDocumentUp(ev);
254 		return true;
255 	case Common::KEYCODE_DOWN:
256 		cmdDocumentDn(ev);
257 		return true;
258 	default:
259 		return false;
260 	}
261 }
262 
263 
264 
keyTest(int16 key)265 gPanel *CDocument::keyTest(int16 key) {
266 	switch (key) {
267 	case Common::ASCII_ESCAPE:
268 	case Common::KEYCODE_LEFT:
269 	case Common::KEYCODE_RIGHT:
270 	case Common::KEYCODE_UP:
271 	case Common::KEYCODE_DOWN:
272 		return this;
273 	default:
274 		return NULL;
275 	}
276 }
277 
278 //  Cursor images for turning book pages
pointerMove(gPanelMessage & msg)279 void CDocument::pointerMove(gPanelMessage &msg) {
280 	Point16 pos     = msg.pickPos;
281 
282 	if (msg.inPanel && Rect16(0, 0, _extent.width, _extent.height).ptInside(pos)) {
283 		if (app.orientation == pageOrientVertical) {
284 			// find out which end of the book we're on
285 			if (pos.y < _extent.height / 2)   setMouseImage(kMousePgUpImage,   -7, -7);
286 			else                            setMouseImage(kMousePgDownImage, -7, -7);
287 		} else {
288 			// find out which side of the book we're on
289 			if (pos.x < _extent.width / 2)    setMouseImage(kMousePgLeftImage,  -7, -7);
290 			else                            setMouseImage(kMousePgRightImage, -7, -7);
291 		}
292 	} else if (msg.pointerLeave) {
293 		setMouseImage(kMouseArrowImage, 0, 0);
294 	}
295 
296 	notify(gEventMouseMove, 0);
297 }
298 
pointerDrag(gPanelMessage &)299 void CDocument::pointerDrag(gPanelMessage &) {
300 	if (selected) {
301 		notify(gEventMouseDrag, 0);
302 	}
303 }
304 
pointerHit(gPanelMessage & msg)305 bool CDocument::pointerHit(gPanelMessage &msg) {
306 	Point16 pos     = msg.pickPos;
307 
308 	if (msg.inPanel && Rect16(0, 0, _extent.width, _extent.height).ptInside(pos)) {
309 		gEvent ev;
310 		if (app.orientation == pageOrientVertical) {
311 			// find out which end of the book we're on
312 			if (pos.y < _extent.height / 2)   cmdDocumentUp(ev); //gotoPage( currentPage - app.numPages );
313 			else                            cmdDocumentDn(ev); //gotoPage( currentPage + app.numPages );
314 		} else {
315 			// find out which side of the book we're on
316 			if (pos.x < _extent.width / 2)    cmdDocumentLt(ev); //gotoPage( currentPage - app.numPages );
317 			else                            cmdDocumentRt(ev); //gotoPage( currentPage + app.numPages );
318 		}
319 	} else {
320 		// mouse hit outside book area, close book
321 		gWindow         *win;
322 		requestInfo     *ri;
323 
324 		win = getWindow();      // get the window pointer
325 		ri = win ? (requestInfo *)win->userData : NULL;
326 
327 		if (ri) {
328 			ri->running = 0;
329 			ri->result  = id;
330 
331 			setMouseImage(kMouseArrowImage, 0, 0);
332 		}
333 	}
334 
335 	activate(gEventMouseDown);
336 	return true;
337 }
338 
gotoPage(int8 page)339 void CDocument::gotoPage(int8 page) {
340 	page = clamp(0, page, maxPages);
341 
342 	while (page % app.numPages) page++;
343 
344 	if (page != currentPage && page < pages) {
345 		currentPage = page;
346 		renderText();
347 	}
348 }
349 
pointerRelease(gPanelMessage &)350 void CDocument::pointerRelease(gPanelMessage &) {
351 	if (selected) notify(gEventMouseUp, 0);   // notify App of successful hit
352 	deactivate();
353 }
354 
checkForPageBreak(char * string,uint16 index,int32 & offset)355 bool CDocument::checkForPageBreak(char *string, uint16 index, int32 &offset) {
356 
357 	// get the current index into the string
358 	char    *strIndex       = string + index;
359 	char *strAfter;
360 
361 	// page break detected
362 	if (strIndex[1] == dPageBreak[0] &&
363 	        strIndex[2] == dPageBreak[1]) {
364 		// eat the page breaks chars
365 		// tie off the end
366 		strIndex[0] = 0;
367 		strAfter = new char[textSize];
368 		Common::strlcpy(strAfter, &strIndex[3], textSize);
369 
370 		// string them together
371 		strcat(&strIndex[0], strAfter);
372 
373 		// take the offset to the end of this line
374 		offset = index;
375 
376 		// and set the new page flag
377 
378 		delete[] strAfter;
379 		return true;
380 	}
381 
382 	return false;
383 }
384 
checkForImage(char * string,uint16 index,uint16 pageIndex,int32 & offset)385 bool CDocument::checkForImage(char      *string,
386                               uint16   index,
387                               uint16   pageIndex,
388                               int32    &offset) {
389 	// get the current index into the string
390 	char    *strIndex       = string + index;
391 	uint16  offPageIndex    = pageIndex;
392 
393 
394 	// if there was not just a page break
395 	if (!pageBreakSet) {
396 		// then the images are going to end up on the next page
397 		offPageIndex++;
398 	}
399 
400 
401 	// image detected marker
402 	if (strIndex[1] == dImage[0] &&
403 	        strIndex[2] == dImage[1]) {
404 		int16   numEat = 0;         // number of characters to eat
405 		char    *argv = &strIndex[2 + 1];  // array to first element
406 
407 		// delete context
408 		if (illustrationCon) resFile->disposeContext(illustrationCon);
409 
410 		// resource handle
411 		illustrationCon = resFile->newContext(MKTAG(argv[0], argv[1], argv[2], argv[3]),
412 		                                      "book internal resources");
413 		// set image for next page
414 		if (offPageIndex < maxPages) {
415 			// if the last entry is defined as a number
416 			if (argv[7] == ':') {
417 				// convert the text into a number
418 				char    numSt[2]  = { argv[8], 0 };
419 				uint8   num         = atoi(numSt);
420 
421 
422 				if (!images[offPageIndex]) {
423 					// get the image
424 					images[offPageIndex] = LoadResource(illustrationCon,
425 					                                      MKTAG(argv[4], argv[5], argv[6], num),
426 					                                      "book internal image");
427 				}
428 
429 				// number of chars to eat
430 				numEat = 9;
431 			} else {
432 				images[offPageIndex] = LoadResource(illustrationCon,
433 				                                      MKTAG(argv[4], argv[5], argv[6], argv[7]),
434 				                                      "book internal image");
435 				numEat = 8;
436 			}
437 
438 			// get the size of the image
439 			imageSizes[offPageIndex] = ((ImageHeader *)images[offPageIndex])->size;
440 
441 			// tie off the end
442 			strIndex[0] = 0;
443 
444 			// and string them together
445 			strcat(&strIndex[0], &strIndex[2 + 1 + numEat]);
446 
447 			// set new line length
448 			offset = index;
449 
450 			// set the line offset
451 			lineOffset[offPageIndex] =
452 				imageSizes[offPageIndex].y / (textHeight + 1) +
453 				textPictureOffset;
454 		} else {
455 			warning("CDocument: Document overflow");
456 		}
457 
458 		// set the new page flag
459 		return true;
460 	}
461 
462 	return false;
463 }
464 
465 
makePages(void)466 void CDocument::makePages(void) {
467 	// copy the original text back to the working buffer
468 	Common::strlcpy(text, origText, textSize + 1);
469 
470 
471 	char    *str            = text;
472 	int32   offset          = 0;
473 	uint16  lineIndex       = 0;
474 	uint16  pageIndex       = 0;
475 	uint16  linesPerPage    = pageHeight / (textHeight + 1);
476 	uint16  dummy;
477 	uint16  i;
478 	bool    newPage         = false;
479 
480 
481 	while (offset >= 0 && pageIndex < maxPages) {
482 		while (offset >= 0 &&
483 		        lineIndex < linesPerPage &&
484 		        !newPage) {
485 			offset = GTextWrap(textFont, str, dummy, lineWidth, 0);
486 
487 			// check for page breaks and images
488 			for (i = 0; i <= offset; i++) {
489 				// we hit a diliminator
490 				if (str[i] == deliminator) {
491 					// page break check
492 					if (checkForPageBreak(str, i, offset)) {
493 						// if a break did not just occur
494 						if (!pageBreakSet) {
495 							newPage         = true;
496 							pageBreakSet    = true;
497 						} else {
498 							// eat the newPage and
499 							// reset the flag for a just set break
500 							pageBreakSet = false;
501 						}
502 					}
503 
504 					// image check
505 					if (checkForImage(str, i, pageIndex, offset)) {
506 						// if a break did not just occur
507 						if (!pageBreakSet) {
508 							newPage         = true;
509 							pageBreakSet    = true;
510 						} else {
511 							// eat the newPage and
512 							// reset the flag for a just set break
513 							pageBreakSet = false;
514 						}
515 
516 						lineIndex   = lineOffset[pageIndex];
517 					}
518 				}
519 
520 				// we got token that was not a page break so reset the flag
521 				pageBreakSet = false;
522 			}
523 
524 			// set the length of this line
525 			if (offset >= 0) {
526 				// number of characters on this line
527 				lineLen[pageIndex][lineIndex] = offset;
528 			} else {
529 				// remaining number of characters in string
530 				lineLen[pageIndex][lineIndex] = strlen(str);
531 			}
532 
533 
534 			// increment the str pointer and line index
535 			str += offset;
536 			lineIndex++;
537 		}
538 
539 		numLines[pageIndex] = lineIndex;
540 		pageIndex++;
541 		newPage     = false;
542 
543 		lineIndex = 0;
544 	}
545 
546 	pages = pageIndex;
547 }
548 
549 // This function will draw the text onto the book.
renderText(void)550 void CDocument::renderText(void) {
551 	gPort           tPort;
552 	gPort           &port = window.windowPort;
553 	uint16          pageIndex;
554 	uint16          lineIndex;
555 	uint16          linesPerPage = pageHeight / (textHeight + 1);
556 	char            *str = text;
557 
558 	assert(textFont);
559 
560 	Rect16  bltRect(0, 0, _extent.width, _extent.height);
561 
562 	if (NewTempPort(tPort, bltRect.width, bltRect.height)) {
563 		// clear out the text buffer
564 		int16           i, k;
565 		uint8           *buffer = (uint8 *)tPort.map->data;
566 
567 		for (i = 0; i < tPort.map->size.x; i++) {
568 			for (k = 0; k < tPort.map->size.y; k++) {
569 				*buffer++ = 0;
570 			}
571 		}
572 
573 		// draw a new copy of the background to the temp port
574 		drawClipped(tPort,
575 		            Point16(_extent.x, _extent.y),
576 		            Rect16(0, 0, _extent.width, _extent.height));
577 
578 		tPort.setFont(textFont);         // setup the string pointer
579 		for (pageIndex = 0; pageIndex < currentPage; pageIndex++) {
580 			if (images[pageIndex]) {
581 				lineIndex = lineOffset[pageIndex];
582 
583 				assert(lineIndex < linesPerPage);
584 			} else {
585 				lineIndex = 0;
586 			}
587 
588 			for (; lineIndex < numLines[pageIndex]; lineIndex++) {
589 				int16   temp = lineLen[pageIndex][lineIndex];
590 
591 				assert(pageIndex < maxPages);
592 				assert(temp < 35);
593 
594 				str += lineLen[pageIndex][lineIndex];
595 			}
596 		}
597 
598 		// draw the text onto the pages of the book
599 		for (pageIndex = currentPage;
600 		        pageIndex - currentPage < app.numPages && pageIndex < pages;
601 		        pageIndex++) {
602 			StaticRect *pageRect = &app.pageRect[pageIndex % app.numPages];
603 
604 			// if there is an image on this page
605 			if (images[pageIndex]) {
606 				Point16 pos;
607 
608 				pos.x = pageRect->x + (pageRect->width - imageSizes[pageIndex].x) / 2;
609 				pos.y = pageRect->y;
610 
611 				drawCompressedImage(tPort, pos, images[pageIndex]);
612 
613 				lineIndex = lineOffset[pageIndex];
614 			} else {
615 				lineIndex = 0;
616 			}
617 
618 			for (; lineIndex < numLines[pageIndex]; lineIndex++) {
619 				assert(pageIndex <= maxPages);
620 
621 				tPort.moveTo(pageRect->x, pageRect->y + (textHeight * lineIndex) + 1);
622 				tPort.setColor(app.textColors[lineIndex]);
623 				tPort.drawText(str, lineLen[pageIndex][lineIndex]);
624 
625 				// grab the next text offset
626 				int16 temp = lineLen[pageIndex][lineIndex];
627 
628 				assert(temp < 35);
629 
630 				str += lineLen[pageIndex][lineIndex];
631 			}
632 		}
633 
634 		port.setMode(drawModeMatte);
635 
636 		g_vm->_pointer->hide();
637 
638 		port.bltPixels(*tPort.map, 0, 0,
639 		               bltRect.x, bltRect.y,
640 		               bltRect.width, bltRect.height);
641 
642 		g_vm->_pointer->show();
643 
644 		DisposeTempPort(tPort);              // dispose of temporary pixelmap
645 	}
646 }
647 
drawClipped(gPort & port,const Point16 & offset,const Rect16 & clipRect)648 void CDocument::drawClipped(
649     gPort         &port,
650     const Point16 &offset,
651     const Rect16  &clipRect) {
652 	g_vm->_pointer->hide();
653 	ModalWindow::drawClipped(port, offset, clipRect);
654 	g_vm->_pointer->show();
655 }
656 
draw(void)657 void CDocument::draw(void) {         // redraw the window
658 	// draw the book image
659 	drawClipped(g_vm->_mainPort, Point16(0, 0), _extent);
660 
661 	// draw the text onto the book
662 	renderText();
663 }
664 
665 /////////
666 // Notes
667 
668 /*
669         // page breaks like:
670     @pb
671 
672         // images declared like:
673     @imDIALBTN:8
674     @imCONTHED:0
675 
676 */
677 
678 /* ===================================================================== *
679    Text buffer
680  * ===================================================================== */
681 
682 const int       textSize = 4096;
683 char            bookText[textSize] = { "" };
684 
appendBookText(char * string)685 void appendBookText(char *string) {
686 	if (string) {
687 		Common::strlcat(bookText, string, textSize - 1);
688 		bookText[textSize - 1] = 0;
689 	}
690 }
691 
692 /* ===================================================================== *
693    scroll window
694  * ===================================================================== */
695 
buildText(uint16 textScript)696 void buildText(uint16 textScript) {
697 	if (textScript > 0) {
698 		// clear out the scroll text
699 		Common::strlcpy(bookText, "", sizeof(bookText));
700 
701 		if (textScript == resImports->reserved[0]) {
702 			Common::strlcpy(bookText, PROGRAM_ABOUT, sizeof(bookText));
703 		}
704 
705 		// generate the text for the book
706 		scriptCallFrame scf;
707 
708 		scf.invokedObject   = Nothing;
709 		scf.enactor         = Nothing;
710 		scf.directObject    = Nothing;
711 		scf.indirectObject  = Nothing;
712 		scf.value           = 0;
713 
714 		//  Run the script
715 		runScript(textScript, scf);
716 	} else {
717 		sprintf(bookText, "Invalid textScript: %d", textScript);
718 	}
719 }
720 
openScroll(uint16 textScript)721 int16 openScroll(uint16 textScript) {
722 	buildText(textScript);
723 
724 	// requester info struct
725 	requestInfo     rInfo;
726 
727 	rInfo.result    = -1;
728 	rInfo.running   = true;
729 
730 
731 	// point to book
732 	CDocument       *win = NULL;
733 
734 	// close button
735 	GfxCompButton     *closeScroll;
736 	void            **closeBtnImage;
737 	uint16          buttonResID     = 0;
738 	hResContext     *decRes;
739 
740 	// init the resource context handle
741 	decRes = resFile->newContext(MKTAG('S', 'C', 'R', 'L'), "book resources");
742 
743 	// get the graphics associated with the buttons
744 	closeBtnImage = loadButtonRes(decRes, buttonResID, numBtnImages);
745 
746 	// create the window
747 	win = new CDocument(scrollAppearance, bookText, &Script10Font, 0, NULL);
748 
749 	// make the quit button
750 	closeScroll = new GfxCompButton(*win, scrollAppearance.closeRect, closeBtnImage, numBtnImages, 0, cmdDocumentQuit);
751 
752 	closeScroll->accelKey = 0x1B;
753 
754 	// attach the structure to the book, open the book
755 	win->userData = &rInfo;
756 	win->open();
757 
758 	// do stuff
759 	EventLoop(rInfo.running, true);
760 
761 	// remove the window all attatched controls
762 	delete  win;
763 
764 	// unload all image arrays
765 	unloadImageRes(closeBtnImage, numBtnImages);
766 
767 	// remove the resource handle
768 	if (decRes)
769 		resFile->disposeContext(decRes);
770 
771 	// return the result code
772 	return rInfo.result;
773 }
774 
775 /* ===================================================================== *
776    Book window
777  * ===================================================================== */
778 
openBook(uint16 textScript)779 int16 openBook(uint16 textScript) {
780 
781 	buildText(textScript);
782 
783 	// requester info struct
784 	requestInfo     rInfo;
785 
786 	rInfo.result    = -1;
787 	rInfo.running   = true;
788 
789 
790 	// point to book
791 	CDocument       *win = NULL;
792 
793 	GfxCompButton *closeBook;
794 	hResContext *decRes;
795 
796 	decRes = resFile->newContext(MKTAG('S', 'C', 'R', 'L'), "book resources");
797 
798 	// create the window
799 	win = new CDocument(bookAppearance, bookText, &Script10Font, 0, NULL);
800 
801 	// make the quit button
802 	closeBook = new GfxCompButton(*win, bookAppearance.closeRect, cmdDocumentQuit);
803 	closeBook->accelKey = 0x1B;
804 
805 	// attach the structure to the book, open the book
806 	win->userData = &rInfo;
807 	win->open();
808 
809 	// do stuff
810 	EventLoop(rInfo.running, true);
811 
812 	// remove the window all attatched controls
813 	delete  win;
814 
815 	if (decRes)
816 		resFile->disposeContext(decRes);
817 
818 	// return the result code
819 	return rInfo.result;
820 }
821 
822 /* ===================================================================== *
823    Parchment window
824  * ===================================================================== */
825 
openParchment(uint16 textScript)826 int16 openParchment(uint16 textScript) {
827 	buildText(textScript);
828 
829 	// requester info struct
830 	requestInfo     rInfo;
831 
832 	rInfo.result    = -1;
833 	rInfo.running   = true;
834 
835 
836 	// point to book
837 	CDocument       *win = NULL;
838 
839 	GfxCompButton *closeParchment;
840 	hResContext *decRes;
841 
842 	decRes = resFile->newContext(MKTAG('S', 'C', 'R', 'L'), "book resources");
843 
844 	// create the window
845 	win = new CDocument(parchAppearance, bookText, &Script10Font, 0, NULL);
846 	// make the quit button
847 	closeParchment = new GfxCompButton(*win, parchAppearance.closeRect, cmdDocumentQuit);
848 	closeParchment->accelKey = 0x1B;
849 
850 	// attach the structure to the book, open the book
851 	win->userData = &rInfo;
852 	win->open();
853 
854 	// do stuff
855 	EventLoop(rInfo.running, true);
856 
857 	// remove the window all attatched controls
858 	delete  win;
859 
860 	if (decRes)
861 		resFile->disposeContext(decRes);
862 
863 	// return the result code
864 	return rInfo.result;
865 }
866 
APPFUNC(cmdDocumentQuit)867 APPFUNC(cmdDocumentQuit) {
868 	gWindow         *win;
869 	requestInfo     *ri;
870 
871 	if (ev.panel && ev.eventType == gEventNewValue && ev.value) {
872 		win = ev.panel->getWindow();        // get the window pointer
873 		ri = win ? (requestInfo *)win->userData : NULL;
874 
875 		if (ri) {
876 			ri->running = 0;
877 			ri->result = ev.panel->id;
878 		}
879 	}
880 }
881 
APPFUNCV(CDocument::cmdDocumentEsc)882 APPFUNCV(CDocument::cmdDocumentEsc) {
883 	requestInfo     *ri = (requestInfo *) userData;
884 	if (ri) {
885 		ri->running = 0;
886 		ri->result = 0;
887 	}
888 }
889 
APPFUNCV(CDocument::cmdDocumentLt)890 APPFUNCV(CDocument::cmdDocumentLt) {
891 	gotoPage(currentPage - app.numPages);    //draw();
892 }
893 
APPFUNCV(CDocument::cmdDocumentRt)894 APPFUNCV(CDocument::cmdDocumentRt) {
895 	gotoPage(currentPage + app.numPages);   //draw();
896 }
897 
APPFUNCV(CDocument::cmdDocumentUp)898 APPFUNCV(CDocument::cmdDocumentUp) {
899 	gotoPage(currentPage - app.numPages);   //draw();
900 }
901 
APPFUNCV(CDocument::cmdDocumentDn)902 APPFUNCV(CDocument::cmdDocumentDn) {
903 	gotoPage(currentPage + app.numPages);   //draw();
904 }
905 
906 } // end of namespace Saga2
907