1 /*
2  * draw.c
3  * Copyright (C) 1998-2005 A.J. van Os; Released under GPL
4  *
5  * Description:
6  * Functions to deal with the Draw format
7  */
8 
9 #include <stdlib.h>
10 #include <ctype.h>
11 #include <string.h>
12 #include "DeskLib:KeyCodes.h"
13 #include "DeskLib:Error.h"
14 #include "DeskLib:Menu.h"
15 #include "DeskLib:Template.h"
16 #include "DeskLib:Window.h"
17 #include "DeskLib:EventMsg.h"
18 #include "flexlib:flex.h"
19 #include "drawfile.h"
20 #include "antiword.h"
21 
22 /* The work area must be a little bit larger than the diagram */
23 #define WORKAREA_EXTENSION	    5
24 /* Diagram memory */
25 #define INITIAL_SIZE		32768	/* 32k */
26 #define EXTENSION_SIZE		 4096	/*  4k */
27 /* Main window title */
28 #define WINDOW_TITLE_LEN	   28
29 #define FILENAME_TITLE_LEN	(WINDOW_TITLE_LEN - 10)
30 
31 
32 #if !defined(__GNUC__)
33 int
flex_alloc(flex_ptr anchor,int n)34 flex_alloc(flex_ptr anchor, int n)
35 {
36 	void	*pvTmp;
37 
38 	TRACE_MSG("flex_alloc");
39 
40 	if (anchor == NULL || n < 0) {
41 		return 0;
42 	}
43 	if (n == 0) {
44 		n = 1;
45 	}
46 	pvTmp = malloc(n);
47 	if (pvTmp == NULL) {
48 		return 0;
49 	}
50 	*anchor = pvTmp;
51 	return 1;
52 } /* end of flex_alloc */
53 
54 void
flex_free(flex_ptr anchor)55 flex_free(flex_ptr anchor)
56 {
57 	TRACE_MSG("flex_free");
58 
59 	if (anchor == NULL || *anchor == NULL) {
60 		return;
61 	}
62 	free(*anchor);
63 	*anchor = NULL;
64 } /* end of flex_free */
65 
66 int
flex_extend(flex_ptr anchor,int newsize)67 flex_extend(flex_ptr anchor, int newsize)
68 {
69 	void	*pvTmp;
70 
71 	TRACE_MSG("flex_extend");
72 
73 	if (anchor == NULL || newsize < 0) {
74 		return 0;
75 	}
76 	if (newsize == 0) {
77 		newsize = 1;
78 	}
79 	pvTmp = realloc(*anchor, newsize);
80 	if (pvTmp == NULL) {
81 		return 0;
82 	}
83 	*anchor = pvTmp;
84 	return 1;
85 } /* end of flex_extend */
86 #endif /* !__GNUC__ */
87 
88 /*
89  * vCreateMainWindow - create the Main window
90  *
91  * remark: does not return if the Main window can't be created
92  */
93 static window_handle
tCreateMainWindow(void)94 tCreateMainWindow(void)
95 {
96 	window_handle	tMainWindow;
97 
98 	TRACE_MSG("tCreateMainWindow");
99 
100 	tMainWindow = Window_Create("MainWindow", template_TITLEMIN);
101 	if (tMainWindow == 0) {
102 		werr(1, "I can't find the 'MainWindow' template");
103 	}
104 	return tMainWindow;
105 } /* end of tCreateMainWindow */
106 
107 /*
108  * vCreateScaleWindow - create the Scale view window
109  *
110  * remark: does not return if the Scale view window can't be created
111  */
112 static window_handle
tCreateScaleWindow(void)113 tCreateScaleWindow(void)
114 {
115 	window_handle	tScaleWindow;
116 
117 	TRACE_MSG("tCreateScaleWindow");
118 
119 	tScaleWindow = Window_Create("ScaleView", template_TITLEMIN);
120 	if (tScaleWindow == 0) {
121 		werr(1, "I can't find the 'ScaleView' template");
122 	}
123 	return tScaleWindow;
124 } /* end of tCreateScaleWindow */
125 
126 /*
127  * pCreateDiagram - create and initialize a diagram
128  *
129  * remark: does not return if the diagram can't be created
130  */
131 diagram_type *
pCreateDiagram(const char * szTask,const char * szFilename)132 pCreateDiagram(const char *szTask, const char *szFilename)
133 {
134 	diagram_type	*pDiag;
135 	options_type	tOptions;
136 	window_handle	tMainWindow, tScaleWindow;
137 	wimp_box	tBox;
138 
139 	TRACE_MSG("pCreateDiagram");
140 
141 	fail(szTask == NULL || szTask[0] == '\0');
142 
143 	/* Create the main window */
144 	tMainWindow = tCreateMainWindow();
145 
146 	/* Create the scale view window */
147 	tScaleWindow = tCreateScaleWindow();
148 
149 	/* Get the necessary memory */
150 	pDiag = xmalloc(sizeof(diagram_type));
151 	if (flex_alloc((flex_ptr)&pDiag->tInfo.data, INITIAL_SIZE) != 1) {
152 		werr(1, "Memory allocation failed, unable to continue");
153 	}
154 
155 	/* Initialize the diagram */
156 	vGetOptions(&tOptions);
157 	pDiag->tMainWindow = tMainWindow;
158 	pDiag->tScaleWindow = tScaleWindow;
159 	pDiag->iScaleFactorCurr = tOptions.iScaleFactor;
160 	pDiag->iScaleFactorTemp = tOptions.iScaleFactor;
161 	pDiag->tMemorySize = INITIAL_SIZE;
162 	tBox.min.x = 0;
163 	tBox.min.y = -(Drawfile_ScreenToDraw(32 + 3) * 8 + 1);
164 	tBox.max.x = Drawfile_ScreenToDraw(16) * MIN_SCREEN_WIDTH + 1;
165 	tBox.max.y = 0;
166 	Error_CheckFatal(Drawfile_CreateDiagram(&pDiag->tInfo,
167 					pDiag->tMemorySize, szTask, tBox));
168 	DBG_DEC(pDiag->tInfo.length);
169 	pDiag->lXleft = 0;
170 	pDiag->lYtop = 0;
171 	strncpy(pDiag->szFilename,
172 			szBasename(szFilename), sizeof(pDiag->szFilename) - 1);
173 	pDiag->szFilename[sizeof(pDiag->szFilename) - 1] = '\0';
174 	/* Return success */
175 	return pDiag;
176 } /* end of pCreateDiagram */
177 
178 /*
179  * bDestroyDiagram - remove a diagram by freeing the memory it uses
180  */
181 BOOL
bDestroyDiagram(event_pollblock * pEvent,void * pvReference)182 bDestroyDiagram(event_pollblock *pEvent, void *pvReference)
183 {
184 	diagram_type	*pDiag;
185 	window_handle	tWindow;
186 
187 	TRACE_MSG("bDestroyDiagram");
188 
189 	fail(pEvent == NULL);
190 	fail(pvReference == NULL);
191 
192 	if (pEvent == NULL || pvReference == NULL) {
193 		return FALSE;
194 	}
195 
196 	pDiag = (diagram_type *)pvReference;
197 
198 	switch (pEvent->type) {
199 	case event_CLOSE:
200 		tWindow = pEvent->data.openblock.window;
201 		break;
202 	case event_KEY:
203 		tWindow = pEvent->data.key.caret.window;
204 		break;
205 	default:
206 		DBG_DEC(pEvent->type);
207 		return FALSE;
208 	}
209 	if (tWindow != pDiag->tMainWindow) {
210 		return FALSE;
211 	}
212 
213 	/* Delete the main window */
214 	Window_Delete(pDiag->tMainWindow);
215 	pDiag->tMainWindow = 0;
216 
217 	/* Delete the scale window */
218 	Window_Delete(pDiag->tScaleWindow);
219 	pDiag->tScaleWindow = 0;
220 
221 #if defined(__GNUC__)
222 	/*
223 	 * Remove all references to the diagram that will be free-ed
224 	 * by undoing the EventMsg_Claim's from within the Menu_Warn's
225 	 */
226 	while (EventMsg_ReleaseSpecific(message_MENUWARNING, window_ANY,
227 					bSaveTextfile, pDiag))
228 		; /* EMPTY */
229 	while (EventMsg_ReleaseSpecific(message_MENUWARNING, window_ANY,
230 					bSaveDrawfile, pDiag))
231 		; /* EMPTY */
232 	while (EventMsg_ReleaseSpecific(message_MENUWARNING, window_ANY,
233 					bScaleOpenAction, pDiag))
234 		; /* EMPTY */
235 #endif /* __GNUC__ */
236 
237 	/* Free the memory */
238 	if (pDiag->tInfo.data != NULL && pDiag->tMemorySize != 0) {
239 		flex_free((flex_ptr)&pDiag->tInfo.data);
240 	}
241 	/* Just to be on the save side */
242 	pDiag->tInfo.data = NULL;
243 	pDiag->tInfo.length = 0;
244 	pDiag->tMemorySize = 0;
245 
246 	/* Destroy the diagram itself */
247 	pDiag = xfree(pDiag);
248 	return TRUE;
249 } /* end of bDestroyDiagram */
250 
251 /*
252  * vExtendDiagramSize - make sure the diagram is big enough
253  */
254 static void
vExtendDiagramSize(diagram_type * pDiag,size_t tSize)255 vExtendDiagramSize(diagram_type *pDiag, size_t tSize)
256 {
257 	TRACE_MSG("vExtendDiagramSize");
258 
259 	fail(pDiag == NULL || tSize % 4 != 0);
260 
261 	while (pDiag->tInfo.length + tSize > pDiag->tMemorySize) {
262 		if (flex_extend((flex_ptr)&pDiag->tInfo.data,
263 				pDiag->tMemorySize + EXTENSION_SIZE) != 1) {
264 			werr(1, "Memory extend failed, unable to continue");
265 		}
266 		pDiag->tMemorySize += EXTENSION_SIZE;
267 		NO_DBG_DEC(pDiag->tMemorySize);
268 	}
269 	TRACE_MSG("end of vExtendDiagramSize");
270 } /* end of vExtendDiagramSize */
271 
272 /*
273  * vPrologue2 - prologue part 2; add a font list to a diagram
274  */
275 void
vPrologue2(diagram_type * pDiag,int iWordVersion)276 vPrologue2(diagram_type *pDiag, int iWordVersion)
277 {
278 	drawfile_object	*pNew;
279 	const font_table_type	*pTmp;
280 	char	*pcTmp;
281 	size_t	tRealSize, tSize;
282 	int	iCount;
283 
284 	TRACE_MSG("vPrologue2");
285 
286 	fail(pDiag == NULL);
287 
288 	if (tGetFontTableLength() == 0) {
289 		return;
290 	}
291 	tRealSize = offsetof(drawfile_object, data);
292 	pTmp = NULL;
293 	while ((pTmp = pGetNextFontTableRecord(pTmp)) != NULL) {
294 		tRealSize += 2 + strlen(pTmp->szOurFontname);
295 	}
296 	DBG_DEC(tRealSize);
297 	tSize = ROUND4(tRealSize);
298 	vExtendDiagramSize(pDiag, tSize);
299 	pNew = xmalloc(tSize);
300 	memset(pNew, 0, tSize);
301 	pNew->type = drawfile_TYPE_FONT_TABLE;
302 	pNew->size = tSize;
303 	pcTmp = (char *)&pNew->data.font_table.font_def[0].font_ref;
304 	iCount = 0;
305 	pTmp = NULL;
306 	while ((pTmp = pGetNextFontTableRecord(pTmp)) != NULL) {
307 		*pcTmp = ++iCount;
308 		pcTmp++;
309 		strcpy(pcTmp, pTmp->szOurFontname);
310 		pcTmp += 1 + strlen(pTmp->szOurFontname);
311 	}
312 	Error_CheckFatal(Drawfile_AppendObject(&pDiag->tInfo,
313 			pDiag->tMemorySize, pNew, TRUE));
314 	pNew = xfree(pNew);
315 } /* end of vPrologue2 */
316 
317 /*
318  * vSubstring2Diagram - put a sub string into a diagram
319  */
320 void
vSubstring2Diagram(diagram_type * pDiag,char * szString,size_t tStringLength,long lStringWidth,UCHAR ucFontColor,USHORT usFontstyle,drawfile_fontref tFontRef,USHORT usFontSize,USHORT usMaxFontSize)321 vSubstring2Diagram(diagram_type *pDiag,
322 	char *szString, size_t tStringLength, long lStringWidth,
323 	UCHAR ucFontColor, USHORT usFontstyle, drawfile_fontref tFontRef,
324 	USHORT usFontSize, USHORT usMaxFontSize)
325 {
326 	drawfile_object	*pNew;
327 	long	lSizeX, lSizeY, lOffset, l20, lYMove;
328 	size_t	tRealSize, tSize;
329 
330 	TRACE_MSG("vSubstring2Diagram");
331 
332 	fail(pDiag == NULL || szString == NULL);
333 	fail(pDiag->lXleft < 0);
334 	fail(tStringLength != strlen(szString));
335 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
336 	fail(usMaxFontSize < MIN_FONT_SIZE || usMaxFontSize > MAX_FONT_SIZE);
337 	fail(usFontSize > usMaxFontSize);
338 
339 	if (szString[0] == '\0' || tStringLength == 0) {
340 		return;
341 	}
342 
343 	if (tFontRef == 0) {
344 		lOffset = Drawfile_ScreenToDraw(2);
345 		l20 = Drawfile_ScreenToDraw(32 + 3);
346 		lSizeX = Drawfile_ScreenToDraw(16);
347 		lSizeY = Drawfile_ScreenToDraw(32);
348 	} else {
349 		lOffset = lToBaseLine(usMaxFontSize);
350 		l20 = lWord2DrawUnits20(usMaxFontSize);
351 		lSizeX = lWord2DrawUnits00(usFontSize);
352 		lSizeY = lWord2DrawUnits00(usFontSize);
353 	}
354 
355 	lYMove = 0;
356 
357 	/* Up for superscript */
358 	if (bIsSuperscript(usFontstyle)) {
359 		lYMove = lMilliPoints2DrawUnits((((long)usFontSize + 1) / 2) * 375);
360 	}
361 	/* Down for subscript */
362 	if (bIsSubscript(usFontstyle)) {
363 		lYMove = -lMilliPoints2DrawUnits((long)usFontSize * 125);
364 	}
365 
366 	tRealSize = offsetof(drawfile_object, data);
367 	tRealSize += sizeof(drawfile_text) + tStringLength;
368 	tSize = ROUND4(tRealSize);
369 	vExtendDiagramSize(pDiag, tSize);
370 	pNew = xmalloc(tSize);
371 	memset(pNew, 0, tSize);
372 	pNew->type = drawfile_TYPE_TEXT;
373 	pNew->size = tSize;
374 	pNew->data.text.bbox.min.x = (int)pDiag->lXleft;
375 	pNew->data.text.bbox.min.y = (int)(pDiag->lYtop + lYMove);
376 	pNew->data.text.bbox.max.x = (int)(pDiag->lXleft + lStringWidth);
377 	pNew->data.text.bbox.max.y = (int)(pDiag->lYtop + l20 + lYMove);
378 	pNew->data.text.fill.value = (int)ulColor2Color(ucFontColor);
379 	pNew->data.text.bg_hint.value = 0xffffff00;	/* White */
380 	pNew->data.text.style.font_ref = tFontRef;
381 	pNew->data.text.style.reserved[0] = 0;
382 	pNew->data.text.style.reserved[1] = 0;
383 	pNew->data.text.style.reserved[2] = 0;
384 	pNew->data.text.xsize = (int)lSizeX;
385 	pNew->data.text.ysize = (int)lSizeY;
386 	pNew->data.text.base.x = (int)pDiag->lXleft;
387 	pNew->data.text.base.y = (int)(pDiag->lYtop + lOffset + lYMove);
388 	strncpy(pNew->data.text.text, szString, tStringLength);
389 	pNew->data.text.text[tStringLength] = '\0';
390 	Error_CheckFatal(Drawfile_AppendObject(&pDiag->tInfo,
391 			pDiag->tMemorySize, pNew, TRUE));
392 	pNew = xfree(pNew);
393 	/*draw_translateText(&pDiag->tInfo);*/
394 	pDiag->lXleft += lStringWidth;
395 	TRACE_MSG("leaving vSubstring2Diagram");
396 } /* end of vSubstring2Diagram */
397 
398 /*
399  * vImage2Diagram - put an image into a diagram
400  */
401 void
vImage2Diagram(diagram_type * pDiag,const imagedata_type * pImg,UCHAR * pucImage,size_t tImageSize)402 vImage2Diagram(diagram_type *pDiag, const imagedata_type *pImg,
403 	UCHAR *pucImage, size_t tImageSize)
404 {
405   	drawfile_object	*pNew;
406 	long	lWidth, lHeight;
407 	size_t	tRealSize, tSize;
408 
409 	TRACE_MSG("vImage2Diagram");
410 
411 	fail(pDiag == NULL);
412 	fail(pImg == NULL);
413 	fail(pDiag->lXleft < 0);
414 	fail(pImg->eImageType != imagetype_is_dib &&
415 	     pImg->eImageType != imagetype_is_jpeg);
416 
417 	DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
418 
419 	lWidth = lPoints2DrawUnits(pImg->iHorSizeScaled);
420 	lHeight = lPoints2DrawUnits(pImg->iVerSizeScaled);
421 	DBG_DEC(lWidth);
422 	DBG_DEC(lHeight);
423 
424 	pDiag->lYtop -= lHeight;
425 
426 	tRealSize = offsetof(drawfile_object, data);
427 	switch (pImg->eImageType) {
428 	case imagetype_is_dib:
429 		tRealSize += sizeof(drawfile_sprite) + tImageSize;
430 		tSize = ROUND4(tRealSize);
431 		vExtendDiagramSize(pDiag, tSize);
432 		pNew = xmalloc(tSize);
433 		memset(pNew, 0, tSize);
434 		pNew->type = drawfile_TYPE_SPRITE;
435 		pNew->size = tSize;
436 		pNew->data.sprite.bbox.min.x = (int)pDiag->lXleft;
437 		pNew->data.sprite.bbox.min.y = (int)pDiag->lYtop;
438 		pNew->data.sprite.bbox.max.x = (int)(pDiag->lXleft + lWidth);
439 		pNew->data.sprite.bbox.max.y = (int)(pDiag->lYtop + lHeight);
440 		memcpy(&pNew->data.sprite.header, pucImage, tImageSize);
441 		break;
442 	case imagetype_is_jpeg:
443 #if defined(DEBUG)
444 		(void)bGetJpegInfo(pucImage, tImageSize);
445 #endif /* DEBUG */
446 		tRealSize += sizeof(drawfile_jpeg) + tImageSize;
447 		tSize = ROUND4(tRealSize);
448 		vExtendDiagramSize(pDiag, tSize);
449 		pNew = xmalloc(tSize);
450 		memset(pNew, 0, tSize);
451 		pNew->type = drawfile_TYPE_JPEG;
452 		pNew->size = tSize;
453 		pNew->data.jpeg.bbox.min.x = (int)pDiag->lXleft;
454 		pNew->data.jpeg.bbox.min.y = (int)pDiag->lYtop;
455 		pNew->data.jpeg.bbox.max.x = (int)(pDiag->lXleft + lWidth);
456 		pNew->data.jpeg.bbox.max.y = (int)(pDiag->lYtop + lHeight);
457 		pNew->data.jpeg.width = (int)lWidth;
458 		pNew->data.jpeg.height = (int)lHeight;
459 		pNew->data.jpeg.xdpi = 90;
460 		pNew->data.jpeg.ydpi = 90;
461 		pNew->data.jpeg.trfm.entries[0][0] = 0x10000;
462 		pNew->data.jpeg.trfm.entries[0][1] = 0;
463 		pNew->data.jpeg.trfm.entries[1][0] = 0;
464 		pNew->data.jpeg.trfm.entries[1][1] = 0x10000;
465 		pNew->data.jpeg.trfm.entries[2][0] = (int)pDiag->lXleft;
466 		pNew->data.jpeg.trfm.entries[2][1] = (int)pDiag->lYtop;
467 		pNew->data.jpeg.len = tImageSize;
468 		memcpy(pNew->data.jpeg.data, pucImage, tImageSize);
469 		break;
470 	default:
471 		DBG_DEC(pImg->eImageType);
472 		pNew = NULL;
473 		break;
474 	}
475 
476 	Error_CheckFatal(Drawfile_AppendObject(&pDiag->tInfo,
477 					pDiag->tMemorySize, pNew, TRUE));
478 	pNew = xfree(pNew);
479 	pDiag->lXleft = 0;
480 } /* end of vImage2Diagram */
481 
482 /*
483  * bAddDummyImage - add a dummy image
484  *
485  * return TRUE when successful, otherwise FALSE
486  */
487 BOOL
bAddDummyImage(diagram_type * pDiag,const imagedata_type * pImg)488 bAddDummyImage(diagram_type *pDiag, const imagedata_type *pImg)
489 {
490   	drawfile_object	*pNew;
491 	int	*piTmp;
492 	long	lWidth, lHeight;
493 	size_t	tRealSize, tSize;
494 
495 	TRACE_MSG("bAddDummyImage");
496 
497 	fail(pDiag == NULL);
498 	fail(pImg == NULL);
499 	fail(pDiag->lXleft < 0);
500 
501 	if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
502 		return FALSE;
503 	}
504 
505 	DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
506 
507 	lWidth = lPoints2DrawUnits(pImg->iHorSizeScaled);
508 	lHeight = lPoints2DrawUnits(pImg->iVerSizeScaled);
509 
510 	pDiag->lYtop -= lHeight;
511 
512 	tRealSize = offsetof(drawfile_object, data);
513 	tRealSize += sizeof(drawfile_path) + (14 - 1) * sizeof(int);
514 	tSize = ROUND4(tRealSize);
515 	vExtendDiagramSize(pDiag, tSize);
516 	pNew = xmalloc(tSize);
517 	memset(pNew, 0, tSize);
518 	pNew->type = drawfile_TYPE_PATH;
519 	pNew->size = tSize;
520 	pNew->data.path.bbox.min.x = (int)pDiag->lXleft;
521 	pNew->data.path.bbox.min.y = (int)pDiag->lYtop;
522 	pNew->data.path.bbox.max.x = (int)(pDiag->lXleft + lWidth);
523 	pNew->data.path.bbox.max.y = (int)(pDiag->lYtop + lHeight);
524 	pNew->data.path.fill.value = -1;
525 	pNew->data.path.outline.value = 0x4d4d4d00;	/* Gray 70 percent */
526 	pNew->data.path.width = (int)lMilliPoints2DrawUnits(500);
527 	pNew->data.path.style.flags = 0;
528 	pNew->data.path.style.reserved = 0;
529 	pNew->data.path.style.cap_width = 0;
530 	pNew->data.path.style.cap_length = 0;
531 	piTmp = pNew->data.path.path;
532 	*piTmp++ = drawfile_PATH_MOVE_TO;
533 	*piTmp++ = pNew->data.path.bbox.min.x;
534 	*piTmp++ = pNew->data.path.bbox.min.y;
535 	*piTmp++ = drawfile_PATH_LINE_TO;
536 	*piTmp++ = pNew->data.path.bbox.min.x;
537 	*piTmp++ = pNew->data.path.bbox.max.y;
538 	*piTmp++ = drawfile_PATH_LINE_TO;
539 	*piTmp++ = pNew->data.path.bbox.max.x;
540 	*piTmp++ = pNew->data.path.bbox.max.y;
541 	*piTmp++ = drawfile_PATH_LINE_TO;
542 	*piTmp++ = pNew->data.path.bbox.max.x;
543 	*piTmp++ = pNew->data.path.bbox.min.y;
544 	*piTmp++ = drawfile_PATH_CLOSE_LINE;
545 	*piTmp++ = drawfile_PATH_END_PATH;
546 
547 	Error_CheckFatal(Drawfile_AppendObject(&pDiag->tInfo,
548 					pDiag->tMemorySize, pNew, TRUE));
549 	pNew = xfree(pNew);
550 	pDiag->lXleft = 0;
551 	return TRUE;
552 } /* end of bAddDummyImage */
553 
554 /*
555  * vMove2NextLine - move to the next line
556  */
557 void
vMove2NextLine(diagram_type * pDiag,drawfile_fontref tFontRef,USHORT usFontSize)558 vMove2NextLine(diagram_type *pDiag, drawfile_fontref tFontRef,
559 	USHORT usFontSize)
560 {
561 	long	l20;
562 
563 	TRACE_MSG("vMove2NextLine");
564 
565 	fail(pDiag == NULL);
566 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
567 
568 	if (tFontRef == 0) {
569 		l20 = Drawfile_ScreenToDraw(32 + 3);
570 	} else {
571 		l20 = lWord2DrawUnits20(usFontSize);
572 	}
573 	pDiag->lYtop -= l20;
574 } /* end of vMove2NextLine */
575 
576 /*
577  * Create an start of paragraph (Phase 1)
578  */
579 void
vStartOfParagraph1(diagram_type * pDiag,long lBeforeIndentation)580 vStartOfParagraph1(diagram_type *pDiag, long lBeforeIndentation)
581 {
582 	TRACE_MSG("vStartOfParagraph1");
583 
584 	fail(pDiag == NULL);
585 	fail(lBeforeIndentation < 0);
586 
587 	pDiag->lXleft = 0;
588 	pDiag->lYtop -= lMilliPoints2DrawUnits(lBeforeIndentation);
589 } /* end of vStartOfParagraph1 */
590 
591 /*
592  * Create an start of paragraph (Phase 2)
593  * DUMMY function
594  */
595 void
vStartOfParagraph2(diagram_type * pDiag)596 vStartOfParagraph2(diagram_type *pDiag)
597 {
598 	TRACE_MSG("vStartOfParagraph2");
599 } /* end of vStartOfParagraph2 */
600 
601 /*
602  * Create an end of paragraph
603  */
604 void
vEndOfParagraph(diagram_type * pDiag,drawfile_fontref tFontRef,USHORT usFontSize,long lAfterIndentation)605 vEndOfParagraph(diagram_type *pDiag,
606 	drawfile_fontref tFontRef, USHORT usFontSize, long lAfterIndentation)
607 {
608 	TRACE_MSG("vEndOfParagraph");
609 
610 	fail(pDiag == NULL);
611 	fail(usFontSize < MIN_FONT_SIZE || usFontSize > MAX_FONT_SIZE);
612 	fail(lAfterIndentation < 0);
613 
614 	pDiag->lXleft = 0;
615 	pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
616 } /* end of vEndOfParagraph */
617 
618 /*
619  * Create an end of page
620  */
621 void
vEndOfPage(diagram_type * pDiag,long lAfterIndentation,BOOL bNewSection)622 vEndOfPage(diagram_type *pDiag, long lAfterIndentation, BOOL bNewSection)
623 {
624 	TRACE_MSG("vEndOfPage");
625 
626 	fail(pDiag == NULL);
627 	fail(lAfterIndentation < 0);
628 
629 	pDiag->lXleft = 0;
630 	pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
631 } /* end of vEndOfPage */
632 
633 /*
634  * vSetHeaders - set the headers
635  * DUMMY function
636  */
637 void
vSetHeaders(diagram_type * pDiag,USHORT usIstd)638 vSetHeaders(diagram_type *pDiag, USHORT usIstd)
639 {
640 	TRACE_MSG("vSetHeaders");
641 } /* end of vSetHeaders */
642 
643 /*
644  * Create a start of list
645  * DUMMY function
646  */
647 void
vStartOfList(diagram_type * pDiag,UCHAR ucNFC,BOOL bIsEndOfTable)648 vStartOfList(diagram_type *pDiag, UCHAR ucNFC, BOOL bIsEndOfTable)
649 {
650 	TRACE_MSG("vStartOfList");
651 } /* end of vStartOfList */
652 
653 /*
654  * Create an end of list
655  * DUMMY function
656  */
657 void
vEndOfList(diagram_type * pDiag)658 vEndOfList(diagram_type *pDiag)
659 {
660 	TRACE_MSG("vEndOfList");
661 } /* end of vEndOfList */
662 
663 /*
664  * Create a start of a list item
665  * DUMMY function
666  */
667 void
vStartOfListItem(diagram_type * pDiag,BOOL bNoMarks)668 vStartOfListItem(diagram_type *pDiag, BOOL bNoMarks)
669 {
670 	TRACE_MSG("vStartOfListItem");
671 } /* end of vStartOfListItem */
672 
673 /*
674  * Create an end of a table
675  * DUMMY function
676  */
677 void
vEndOfTable(diagram_type * pDiag)678 vEndOfTable(diagram_type *pDiag)
679 {
680 	TRACE_MSG("vEndOfTable");
681 } /* end of vEndTable */
682 
683 /*
684  * Add a table row
685  * DUMMY function
686  *
687  * Returns TRUE when conversion type is XML
688  */
689 BOOL
bAddTableRow(diagram_type * pDiag,char ** aszColTxt,int iNbrOfColumns,const short * asColumnWidth,UCHAR ucBorderInfo)690 bAddTableRow(diagram_type *pDiag, char **aszColTxt,
691 	int iNbrOfColumns, const short *asColumnWidth, UCHAR ucBorderInfo)
692 {
693 	TRACE_MSG("bAddTableRow");
694 
695 	return FALSE;
696 } /* end of bAddTableRow */
697 
698 /*
699  * vForceRedraw - force a redraw of the main window
700  */
701 static void
vForceRedraw(diagram_type * pDiag)702 vForceRedraw(diagram_type *pDiag)
703 {
704 	window_state		tWindowState;
705 	window_redrawblock	tRedraw;
706 	int	x0, y0, x1, y1;
707 
708 	TRACE_MSG("vForceRedraw");
709 
710 	fail(pDiag == NULL);
711 
712 	DBG_DEC(pDiag->iScaleFactorCurr);
713 
714 	/* Read the size of the current diagram */
715 	Drawfile_QueryBox(&pDiag->tInfo, &tRedraw.rect, TRUE);
716 	/* Adjust the size of the work area */
717 	x0 = tRedraw.rect.min.x * pDiag->iScaleFactorCurr / 100 - 1;
718 	y0 = tRedraw.rect.min.y * pDiag->iScaleFactorCurr / 100 - 1;
719 	x1 = tRedraw.rect.max.x * pDiag->iScaleFactorCurr / 100 + 1;
720 	y1 = tRedraw.rect.max.y * pDiag->iScaleFactorCurr / 100 + 1;
721 	/* Work area extension */
722 	x0 -= WORKAREA_EXTENSION;
723 	y0 -= WORKAREA_EXTENSION;
724 	x1 += WORKAREA_EXTENSION;
725 	y1 += WORKAREA_EXTENSION;
726 	Window_SetExtent(pDiag->tMainWindow, x0, y0, x1, y1);
727 	/* Widen the box slightly to be sure all the edges are drawn */
728 	x0 -= 5;
729 	y0 -= 5;
730 	x1 += 5;
731 	y1 += 5;
732 	/* Force the redraw */
733 	Window_ForceRedraw(pDiag->tMainWindow, x0, y0, x1, y1);
734 	/* Reopen the window to show the correct size */
735 	Error_CheckFatal(Wimp_GetWindowState(pDiag->tMainWindow, &tWindowState));
736 	tWindowState.openblock.behind = -1;
737 	Error_CheckFatal(Wimp_OpenWindow(&tWindowState.openblock));
738 } /* end of vForceRedraw */
739 
740 /*
741  * vShowDiagram - put the diagram on the screen
742  */
743 void
vShowDiagram(diagram_type * pDiag)744 vShowDiagram(diagram_type *pDiag)
745 {
746 	wimp_box	tRect;
747 	int	x0, y0, x1, y1;
748 
749 	TRACE_MSG("vShowDiagram");
750 
751 	fail(pDiag == NULL);
752 
753 	Window_Show(pDiag->tMainWindow, open_NEARLAST);
754 	Drawfile_QueryBox(&pDiag->tInfo, &tRect, TRUE);
755 	/* Work area extension */
756 	x0 = tRect.min.x - WORKAREA_EXTENSION;
757 	y0 = tRect.min.y - WORKAREA_EXTENSION;
758 	x1 = tRect.max.x + WORKAREA_EXTENSION;
759 	y1 = tRect.max.y + WORKAREA_EXTENSION;
760 	Window_SetExtent(pDiag->tMainWindow, x0, y0, x1, y1);
761 	vForceRedraw(pDiag);
762 } /* end of vShowDiagram */
763 
764 /*
765  * vMainButtonClick - handle mouse buttons clicks for the main screen
766  */
767 void
vMainButtonClick(mouse_block * pMouse)768 vMainButtonClick(mouse_block *pMouse)
769 {
770 	caret_block	tCaret;
771 	window_state	ws;
772 
773 	TRACE_MSG("vMainButtonClick");
774 
775 	fail(pMouse == NULL);
776 
777 	DBG_DEC(pMouse->button.data.select);
778 	DBG_DEC(pMouse->button.data.adjust);
779 	DBG_DEC(pMouse->window);
780 	DBG_DEC(pMouse->icon);
781 
782 	if (pMouse->window >= 0 &&
783 	    pMouse->icon == -1 &&
784 	    (pMouse->button.data.select || pMouse->button.data.adjust)) {
785 		/* Get the input focus */
786 		Error_CheckFatal(Wimp_GetWindowState(pMouse->window, &ws));
787 		tCaret.window = pMouse->window;
788 		tCaret.icon = -1;
789 		tCaret.offset.x = pMouse->pos.x - ws.openblock.screenrect.min.x;
790 		tCaret.offset.y = pMouse->pos.y - ws.openblock.screenrect.max.y;
791 		tCaret.height = (int)BIT(25);
792 		tCaret.index = 0;
793 		Error_CheckFatal(Wimp_SetCaretPosition(&tCaret));
794 	}
795 } /* end of vMainButtonClick */
796 
797 /*
798  * bMainKeyPressed - handle pressed keys for the main window
799  */
800 BOOL
bMainKeyPressed(event_pollblock * pEvent,void * pvReference)801 bMainKeyPressed(event_pollblock *pEvent, void *pvReference)
802 {
803 	diagram_type 	*pDiag;
804 
805 	TRACE_MSG("bMainKeyPressed");
806 
807 	fail(pEvent == NULL);
808 	fail(pEvent->type != event_KEY);
809 	fail(pvReference == NULL);
810 
811 	pDiag = (diagram_type *)pvReference;
812 
813 	fail(pEvent->data.key.caret.window != pDiag->tMainWindow);
814 
815 
816 	switch (pEvent->data.key.code) {
817 	case keycode_CTRL_F2:		/* Ctrl F2 */
818 		bDestroyDiagram(pEvent, pvReference);
819 		break;
820 	case keycode_F3:		/* F3 */
821 		bSaveDrawfile(pEvent, pvReference);
822 		break;
823 	case keycode_SHIFT_F3:		/* Shift F3 */
824 		bSaveTextfile(pEvent, pvReference);
825 		break;
826 	default:
827 		DBG_DEC(pEvent->data.key.code);
828 		Error_CheckFatal(Wimp_ProcessKey(pEvent->data.key.code));
829 	}
830 	return TRUE;
831 } /* end of bMainKeyPressed */
832 
833 /*
834  * bRedrawMainWindow - redraw the main window
835  */
836 BOOL
bRedrawMainWindow(event_pollblock * pEvent,void * pvReference)837 bRedrawMainWindow(event_pollblock *pEvent, void *pvReference)
838 {
839 	window_redrawblock	tBlock;
840 	diagram_type	*pDiag;
841 	drawfile_info	*pInfo;
842 	double		dScaleFactor;
843 	BOOL		bMore;
844 
845 	TRACE_MSG("bRedrawMainWindow");
846 
847 	fail(pEvent == NULL);
848 	fail(pEvent->type != event_REDRAW);
849 	fail(pvReference == NULL);
850 
851 	pDiag = (diagram_type *)pvReference;
852 
853 	fail(pDiag->tMainWindow != pEvent->data.openblock.window);
854 	fail(pDiag->iScaleFactorCurr < MIN_SCALE_FACTOR);
855 	fail(pDiag->iScaleFactorCurr > MAX_SCALE_FACTOR);
856 
857 	dScaleFactor = (double)pDiag->iScaleFactorCurr / 100.0;
858 	pInfo = &pDiag->tInfo;
859 
860 	tBlock.window = pEvent->data.openblock.window;
861 	Error_CheckFatal(Wimp_RedrawWindow(&tBlock, &bMore));
862 
863 	/* If there is no real diagram just go thru the motions */
864 	while (bMore) {
865 		if (pInfo->data != NULL && pInfo->length != 0) {
866 			Error_CheckFatal(Drawfile_RenderDiagram(pInfo,
867 						&tBlock, dScaleFactor));
868 		}
869 		Error_CheckFatal(Wimp_GetRectangle(&tBlock, &bMore));
870 	}
871 	return TRUE;
872 } /* end of bRedrawMainWindow */
873 
874 /*
875  * bScaleOpenAction - action to be taken when the Scale view window opens
876  */
877 BOOL
bScaleOpenAction(event_pollblock * pEvent,void * pvReference)878 bScaleOpenAction(event_pollblock *pEvent, void *pvReference)
879 {
880 	window_state	tWindowState;
881 	diagram_type	*pDiag;
882 
883 	TRACE_MSG("bScaleOpenAction");
884 
885 	fail(pEvent == NULL);
886 	fail(pEvent->type != event_SEND);
887 	fail(pEvent->data.message.header.action != message_MENUWARN);
888 	fail(pvReference == NULL);
889 
890 	pDiag = (diagram_type *)pvReference;
891 
892 	if (menu_currentopen != pDiag->pSaveMenu ||
893 	    pEvent->data.message.data.menuwarn.selection[0] != SAVEMENU_SCALEVIEW) {
894 		return FALSE;
895 	}
896 
897 	Error_CheckFatal(Wimp_GetWindowState(pDiag->tScaleWindow,
898 						&tWindowState));
899 	if (tWindowState.flags.data.open) {
900 		/* The window is already open */
901 		return TRUE;
902 	}
903 
904 	DBG_MSG("vScaleOpenAction for real");
905 
906 	pDiag->iScaleFactorTemp = pDiag->iScaleFactorCurr;
907 	vUpdateWriteableNumber(pDiag->tScaleWindow,
908 			SCALE_SCALE_WRITEABLE, pDiag->iScaleFactorTemp);
909 	Window_Show(pDiag->tScaleWindow, open_UNDERPOINTER);
910 	return TRUE;
911 } /* end of bScaleOpenAction */
912 
913 /*
914  * vSetTitle - set the title of a window
915  */
916 void
vSetTitle(diagram_type * pDiag)917 vSetTitle(diagram_type *pDiag)
918 {
919 	char	szTitle[WINDOW_TITLE_LEN];
920 
921 	TRACE_MSG("vSetTitle");
922 
923 	fail(pDiag == NULL);
924 	fail(pDiag->szFilename[0] == '\0');
925 
926 	(void)sprintf(szTitle, "%.*s at %d%%",
927 				FILENAME_TITLE_LEN,
928 				pDiag->szFilename,
929 				pDiag->iScaleFactorCurr % 1000);
930 	if (strlen(pDiag->szFilename) > FILENAME_TITLE_LEN) {
931 		szTitle[FILENAME_TITLE_LEN - 1] = OUR_ELLIPSIS;
932 	}
933 
934 	Window_SetTitle(pDiag->tMainWindow, szTitle);
935 } /* end of vSetTitle */
936 
937 /*
938  * vScaleButtonClick - handle a mouse button click in the Scale view window
939  */
940 void
vScaleButtonClick(mouse_block * pMouse,diagram_type * pDiag)941 vScaleButtonClick(mouse_block *pMouse, diagram_type *pDiag)
942 {
943 	BOOL	bCloseWindow, bRedraw;
944 
945 	TRACE_MSG("vScaleButtonClick");
946 
947 	fail(pMouse == NULL || pDiag == NULL);
948 	fail(pMouse->window != pDiag->tScaleWindow);
949 
950 	bCloseWindow = FALSE;
951 	bRedraw = FALSE;
952 	switch (pMouse->icon) {
953 	case SCALE_CANCEL_BUTTON:
954 		bCloseWindow = TRUE;
955 		pDiag->iScaleFactorTemp = pDiag->iScaleFactorCurr;
956 		break;
957 	case SCALE_SCALE_BUTTON:
958 		bCloseWindow = TRUE;
959 		bRedraw = pDiag->iScaleFactorCurr != pDiag->iScaleFactorTemp;
960 		pDiag->iScaleFactorCurr = pDiag->iScaleFactorTemp;
961 		break;
962 	case SCALE_50_PCT:
963 		pDiag->iScaleFactorTemp = 50;
964 		break;
965 	case SCALE_75_PCT:
966 		pDiag->iScaleFactorTemp = 75;
967 		break;
968 	case SCALE_100_PCT:
969 		pDiag->iScaleFactorTemp = 100;
970 		break;
971 	case SCALE_150_PCT:
972 		pDiag->iScaleFactorTemp = 150;
973 		break;
974 	default:
975 		DBG_DEC(pMouse->icon);
976 		break;
977 	}
978 	if (bCloseWindow) {
979 		/* Close the scale window */
980 		Error_CheckFatal(Wimp_CloseWindow(pMouse->window));
981 		if (bRedraw) {
982 			/* Redraw the main window */
983 			vSetTitle(pDiag);
984 			vForceRedraw(pDiag);
985 		}
986 	} else {
987 		vUpdateWriteableNumber(pMouse->window,
988 				SCALE_SCALE_WRITEABLE,
989 				pDiag->iScaleFactorTemp);
990 	}
991 } /* end of vScaleButtonClick */
992 
993 /*
994  * bScaleKeyPressed - handle pressed keys for the scale window
995  */
996 BOOL
bScaleKeyPressed(event_pollblock * pEvent,void * pvReference)997 bScaleKeyPressed(event_pollblock *pEvent, void *pvReference)
998 {
999 	icon_block	tIcon;
1000 	diagram_type	*pDiag;
1001 	caret_block	*pCaret;
1002 	char		*pcChar;
1003 	int		iTmp;
1004 
1005 	TRACE_MSG("bScaleKeyPressed");
1006 
1007         fail(pEvent == NULL);
1008         fail(pEvent->type != event_KEY);
1009         fail(pvReference == NULL);
1010 
1011 	pCaret = &pEvent->data.key.caret;
1012 	pDiag = (diagram_type *)pvReference;
1013 
1014         fail(pEvent->data.key.caret.window != pDiag->tScaleWindow);
1015 
1016 	DBG_DEC_C(pCaret->icon != SCALE_SCALE_WRITEABLE, pCaret->icon);
1017 	DBG_DEC_C(pCaret->icon == SCALE_SCALE_WRITEABLE, pEvent->data.key.code);
1018 
1019 	if (pEvent->data.key.code != '\r' ||
1020 	    pCaret->icon != SCALE_SCALE_WRITEABLE) {
1021 		Error_CheckFatal(Wimp_ProcessKey(pEvent->data.key.code));
1022 		return TRUE;
1023 	}
1024 
1025 	Error_CheckFatal(Wimp_GetIconState(pCaret->window, pCaret->icon, &tIcon));
1026 	if (!tIcon.flags.data.text || !tIcon.flags.data.indirected) {
1027 		werr(1, "Icon %d must be indirected text", (int)pCaret->icon);
1028 	}
1029 	iTmp = (int)strtol(tIcon.data.indirecttext.buffer, &pcChar, 10);
1030 	if (*pcChar != '\0' && *pcChar != '\r') {
1031 		DBG_DEC(*pcChar);
1032 	} else if (iTmp < MIN_SCALE_FACTOR) {
1033 		pDiag->iScaleFactorTemp = MIN_SCALE_FACTOR;
1034 	} else if (iTmp > MAX_SCALE_FACTOR) {
1035 		pDiag->iScaleFactorTemp = MAX_SCALE_FACTOR;
1036 	} else {
1037 		pDiag->iScaleFactorTemp = iTmp;
1038 	}
1039 	pDiag->iScaleFactorCurr = pDiag->iScaleFactorTemp;
1040 	/* Close the scale window */
1041 	Error_CheckFatal(Wimp_CloseWindow(pCaret->window));
1042 	/* Redraw the main window */
1043 	vSetTitle(pDiag);
1044 	vForceRedraw(pDiag);
1045 	return TRUE;
1046 } /* end of bScaleKeyPressed */
1047 
1048