1 /*    SCCS Id: @(#)winstr.c    3.1    93/04/02 */
2 /* Copyright (c) Gregg Wonderly, Naperville, Illinois,  1991,1992,1993. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include "NH:sys/amiga/windefs.h"
6 #include "NH:sys/amiga/winext.h"
7 #include "NH:sys/amiga/winproto.h"
8 
9 /* Put a string into the indicated window using the indicated attribute */
10 
11 void
amii_putstr(window,attr,str)12 amii_putstr(window,attr,str)
13     winid window;
14     int attr;
15     const char *str;
16 {
17     int fudge;
18     int len;
19     struct Window *w;
20     register struct amii_WinDesc *cw;
21     char *ob;
22     int i, j, n0, bottom, totalvis, wheight;
23 
24     /* Always try to avoid a panic when there is no window */
25     if( window == WIN_ERR )
26     {
27 	window = WIN_BASE;
28 	if( window == WIN_ERR )
29 	    window = WIN_BASE = amii_create_nhwindow( NHW_BASE );
30     }
31 
32     if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL )
33     {
34 	iflags.window_inited=0;
35 	panic(winpanicstr,window, "putstr");
36     }
37 
38     w = cw->win;
39 
40     if(!str) return;
41     amiIDisplay->lastwin = window;    /* do we care??? */
42 
43     /* NHW_MENU windows are not opened immediately, so check if we
44      * have the window pointer yet
45      */
46 
47     if( w )
48     {
49 	/* Set the drawing mode and pen colors */
50 	SetDrMd( w->RPort, JAM2 );
51 	amii_sethipens( w, cw->type, attr );
52     }
53     else if( cw->type != NHW_MENU && cw->type != NHW_TEXT )
54     {
55 	panic( "NULL window pointer in putstr 2: %d", window );
56     }
57 
58     /* Okay now do the work for each type */
59 
60     switch(cw->type)
61     {
62     case NHW_MESSAGE:
63 	if( WINVERS_AMIV )
64 	    fudge = 2;
65 	else
66 	{
67 	    /* 8 for --more--, 1 for preceeding sp, 1 for putstr pad */
68 	    fudge = 10;
69 	}
70 
71     	/* There is a one pixel border at the borders, so subtract two */
72     	bottom = amii_msgborder( w );
73 
74 	wheight = ( w->Height - w->BorderTop -
75 			    w->BorderBottom - 3 ) / w->RPort->TxHeight;
76 
77 	if (scrollmsg || wheight > 1)
78 	    fudge = 0;
79 
80 	amii_scrollmsg( w, cw );
81 
82 	while (isspace(*str)) str++;
83 	strncpy( toplines, str, TBUFSZ );
84 	toplines[ TBUFSZ - 1 ] = 0;
85 
86 	/* For initial message to be visible, we need to explicitly position the
87 	 * cursor.  This flag, cw->curx == -1 is set elsewhere to force the
88 	 * cursor to be repositioned to the "bottom".
89 	 */
90 	if( cw->curx == -1 )
91 	{
92 	    amii_curs( WIN_MESSAGE, 1, bottom );
93 	    cw->curx = 0;
94 	}
95 
96 	/* If used all of history lines, move them down */
97 	if( cw->maxrow >= iflags.msg_history )
98 	{
99 	    if( cw->data[ 0 ] )
100 		free( cw->data[ 0 ] );
101 	    memcpy( cw->data, &cw->data[ 1 ],
102 		( iflags.msg_history - 1 ) * sizeof( char * ) );
103 	    cw->data[ iflags.msg_history - 1 ] =
104 			    (char *) alloc( strlen( toplines ) + 5 );
105 	    strcpy( cw->data[ i = iflags.msg_history - 1 ] +
106 				SOFF + (scrollmsg!=0), toplines );
107 	}
108 	else
109 	{
110 	    /* Otherwise, allocate a new one and copy the line in */
111 	    cw->data[ cw->maxrow ] = (char *)
112 					alloc( strlen( toplines ) + 5 );
113 	    strcpy( cw->data[ i = cw->maxrow++ ] +
114 				SOFF + (scrollmsg!=0), toplines );
115 	}
116 	cw->data[ i ][ SEL_ITEM ] = 1;
117 	cw->data[ i ][ VATTR ] = attr+1;
118 
119 	if( scrollmsg )
120 	{
121 	    cw->curx = 0;
122 	    cw->data[ i ][2] = (cw->wflags & FLMSG_FIRST ) ? '>' : ' ';
123 	}
124 
125 	str = cw->data[i] + SOFF;
126 	if( cw->curx + strlen(str) >= (cw->cols-fudge) )
127 	{
128 	    int i;
129 	    char *ostr = (char *)str;
130 	    char *p;
131 
132 	    while( cw->curx + strlen( str ) >= (cw->cols-fudge) )
133 	    {
134 		for(p=((char *)&str[ cw->cols-1 - cw->curx ])-fudge; !isspace(*p) && p > str;)
135 		    --p;
136 		if (p < str) p = (char *)str;
137 
138 		if( p == str ) {
139 		/*    p = (char *)&str[ cw->cols ]; */
140 		    outmore(cw);
141 		    continue;
142 		}
143 
144 		i = (long)p-(long)str;
145 		outsubstr( cw, (char *)str, i, fudge );
146 		cw->curx += i;
147 
148 		while(isspace(*p)) p++;
149 		str = p;
150 
151 #if 0
152 		if( str != ostr ) {
153 		    outsubstr( cw, "+", 1, fudge );
154 		    cw->curx+=2;
155 		}
156 #endif
157 		if(*str)
158 		    amii_scrollmsg( w, cw );
159 		amii_cl_end( cw, cw->curx );
160 	    }
161 
162 	    if( *str )
163 	    {
164 		if( str != ostr )
165 		{
166 		    outsubstr( cw, "+", 1, fudge );
167 		    cw->curx+=2;
168 		}
169 		while ( isspace( *str ) )
170 		    ++str;
171 		outsubstr( cw, (char *)str, i = strlen( (char *)str ), fudge );
172 		cw->curx += i;
173 		amii_cl_end( cw, cw->curx );
174 	    }
175 	}
176 	else
177 	{
178 	    outsubstr( cw, (char *)str, i = strlen( (char *)str ), fudge );
179 	    cw->curx += i;
180 	    amii_cl_end( cw, cw->curx );
181 	}
182 	cw->wflags &= ~FLMSG_FIRST;
183 	len = 0;
184 	if( scrollmsg )
185 	{
186 	    totalvis = CountLines( window );
187 	    SetPropInfo( w, &MsgScroll,
188 	      ( w->Height-w->BorderTop-w->BorderBottom ) / w->RPort->TxHeight,
189 	      totalvis, totalvis );
190 	}
191 	i = strlen( toplines + SOFF );
192 	cw->maxcol = max( cw->maxcol, i );
193 	cw->vwy = cw->maxrow;
194 	break;
195 
196     case NHW_STATUS:
197 	if( cw->data[ cw->cury ] == NULL )
198 	    panic( "NULL pointer for status window" );
199 	ob = &cw->data[cw->cury][j = cw->curx];
200 	if(flags.botlx) *ob = 0;
201 
202 	    /* Display when beam at top to avoid flicker... */
203 	WaitTOF();
204 	Text(w->RPort,(char *)str,strlen((char *)str));
205 	if( cw->cols > strlen( str ) )
206 	    TextSpaces( w->RPort, cw->cols - strlen( str ) );
207 
208 	(void) strncpy(cw->data[cw->cury], str, cw->cols );
209 	cw->data[cw->cury][cw->cols-1] = '\0'; /* null terminate */
210 	cw->cury = (cw->cury+1) % 2;
211 	cw->curx = 0;
212 	break;
213 
214     case NHW_MAP:
215     case NHW_BASE:
216 	amii_curs(window, cw->curx+1, cw->cury);
217 	Text(w->RPort,(char *)str,strlen((char *)str));
218 	cw->curx = 0;
219 	    /* CR-LF is automatic in these windows */
220 	cw->cury++;
221 	break;
222 
223     case NHW_MENU:
224     case NHW_TEXT:
225 
226 	/* always grows one at a time, but alloc 12 at a time */
227 
228 	if( cw->cury >= cw->rows || !cw->data )
229 	{
230 	    char **tmp;
231 
232 		/* Allocate 12 more rows */
233 	    cw->rows += 12;
234 	    tmp = (char**) alloc(sizeof(char*) * cw->rows);
235 
236 		/* Copy the old lines */
237 	    for(i=0; i<cw->cury; i++)
238 		tmp[i] = cw->data[i];
239 
240 	    if( cw->data )
241 		free( cw->data );
242 
243 	    cw->data = tmp;
244 
245 		/* Null out the unused entries. */
246 	    for(i=cw->cury; i<cw->rows; i++)
247 		cw->data[i] = 0;
248 	}
249 
250 	if( !cw->data )
251 	    panic("no data storage");
252 
253 	    /* Shouldn't need to do this, but... */
254 
255 	if( cw->data && cw->data[cw->cury] )
256 	    free( cw->data[cw->cury] );
257 
258 	n0 = strlen(str)+1;
259 	cw->data[cw->cury] = (char*) alloc(n0+SOFF);
260 
261 	    /* avoid nuls, for convenience */
262 	cw->data[cw->cury][VATTR] = attr+1;
263 	cw->data[cw->cury][SEL_ITEM] = 0;
264 	Strcpy( cw->data[cw->cury] + SOFF, str);
265 
266 	if(n0 > cw->maxcol) cw->maxcol = n0;
267 	if(++cw->cury > cw->maxrow) cw->maxrow = cw->cury;
268 	break;
269 
270     default:
271 	panic("Invalid or unset window type in putstr()");
272     }
273 }
274 
275 void
amii_scrollmsg(w,cw)276 amii_scrollmsg( w, cw )
277     register struct Window *w;
278     register struct amii_WinDesc *cw;
279 {
280     int bottom, wheight;
281 
282     bottom = amii_msgborder( w );
283 
284     wheight = ( w->Height - w->BorderTop -
285 			w->BorderBottom - 3 ) / w->RPort->TxHeight;
286 
287     if( scrollmsg )
288     {
289 	if( ++cw->disprows > wheight )
290 	{
291 	    outmore( cw );
292 	    cw->disprows = 1; /* count this line... */
293 	}
294 	else
295 	{
296 	    ScrollRaster( w->RPort, 0, w->RPort->TxHeight,
297 		    w->BorderLeft, w->BorderTop + 1,
298 		    w->Width - w->BorderRight-1,
299 		    w->Height - w->BorderBottom - 1 );
300 	}
301 	amii_curs( WIN_MESSAGE, 1, bottom );
302     }
303 }
304 
305 int
amii_msgborder(w)306 amii_msgborder( w )
307     struct Window *w;
308 {
309     register int bottom;
310 
311     /* There is a one pixel border at the borders, so subtract two */
312     bottom = w->Height - w->BorderTop - w->BorderBottom - 2;
313     bottom /= w->RPort->TxHeight;
314     if( bottom > 0 )
315 	--bottom;
316     return( bottom );
317 }
318 
319 void
outmore(cw)320 outmore( cw )
321     register struct amii_WinDesc *cw;
322 {
323     struct Window *w = cw->win;
324 
325     if((cw->wflags & FLMAP_SKIP) == 0)
326     {
327 	if( scrollmsg )
328 	{
329 	    int bottom;
330 
331 	    bottom = amii_msgborder( w );
332 
333 	    ScrollRaster( w->RPort, 0, w->RPort->TxHeight,
334 			w->BorderLeft, w->BorderTop+1,
335 			w->Width - w->BorderRight-1,
336 			w->Height - w->BorderBottom - 1 );
337 	    amii_curs( WIN_MESSAGE, 1, bottom ); /* -1 for inner border */
338 	    Text( w->RPort, "--more--", 8 );
339 	}
340 	else
341 	    Text( w->RPort, " --more--", 9 );
342 
343 	/* Make sure there are no events in the queue */
344 	flushIDCMP( HackPort );
345 
346 	/* Allow mouse clicks to clear --more-- */
347 	WindowGetchar();
348 	if( lastevent.type == WEKEY && lastevent.un.key == '\33' )
349 	    cw->wflags |= FLMAP_SKIP;
350     }
351     if( !scrollmsg )
352     {
353 	amii_curs( WIN_MESSAGE, 1, 0 );
354 	amii_cl_end( cw, cw->curx );
355     }
356 }
357 
358 void
outsubstr(cw,str,len,fudge)359 outsubstr( cw, str, len, fudge )
360     register struct amii_WinDesc *cw;
361     char *str;
362     int len;
363     int fudge;
364 {
365     struct Window *w = cw->win;
366 
367     if( cw->curx )
368     {
369 	/* Check if this string and --more-- fit, if not,
370 	 * then put out --more-- and wait for a key.
371 	 */
372 	if( (len + fudge ) + cw->curx >= cw->cols )
373 	{
374 	    if( !scrollmsg )
375 		outmore( cw );
376 	}
377 	else
378 	{
379 	    /* Otherwise, move and put out a blank separator */
380 	    Text( w->RPort, spaces, 1 );
381 	    cw->curx += 1;
382 	}
383     }
384 
385     Text(w->RPort,str,len);
386 }
387 
388 /* Put a graphics character onto the screen */
389 
390 void
amii_putsym(st,i,y,c)391 amii_putsym( st, i, y, c )
392     winid st;
393     int i, y;
394     CHAR_P c;
395 {
396     amii_curs( st, i, y );
397     Text(amii_wins[st]->win->RPort, &c, 1);
398 }
399 
400 /* Add to the last line in the message window */
401 
402 void
amii_addtopl(s)403 amii_addtopl(s)
404     const char *s;
405 {
406     register struct amii_WinDesc *cw = amii_wins[WIN_MESSAGE];
407 
408     while(*s) {
409 	if(cw->curx == cw->cols - 1)
410 	    amii_putstr(WIN_MESSAGE, 0, "");
411 	amii_putsym(WIN_MESSAGE, cw->curx + 1, amii_msgborder(cw->win), *s++);
412 	cw->curx++;
413     }
414 }
415 
416 void
TextSpaces(rp,nr)417 TextSpaces( rp, nr )
418     struct RastPort *rp;
419     int nr;
420 {
421     if( nr < 1 )
422 	return;
423 
424     while (nr > sizeof(spaces) - 1)
425     {
426 	Text(rp, spaces, (long)sizeof(spaces) - 1);
427 	nr -= sizeof(spaces) - 1;
428     }
429     if (nr > 0)
430 	Text(rp, spaces, (long)nr);
431 }
432 
433 void
amii_remember_topl()434 amii_remember_topl()
435 {
436     /* ignore for now.  I think this will be done automatically by
437      * the code writing to the message window, but I could be wrong.
438      */
439 }
440 
441 int
amii_doprev_message()442 amii_doprev_message()
443 {
444     struct amii_WinDesc *cw;
445     struct Window *w;
446     char *str;
447 
448     if( WIN_MESSAGE == WIN_ERR ||
449 	( cw = amii_wins[ WIN_MESSAGE ] ) == NULL || ( w = cw->win ) == NULL )
450     {
451 	panic(winpanicstr,WIN_MESSAGE, "doprev_message");
452     }
453 
454     /* When an interlaced/tall screen is in use, the scroll bar will be there */
455     /* Or in some other cases as well */
456     if( scrollmsg )
457     {
458 	struct Gadget *gd;
459 	struct PropInfo *pip;
460 	int hidden, topidx, i, total, wheight;
461 
462 	for( gd = w->FirstGadget; gd && gd->GadgetID != 1; )
463 	    gd = gd->NextGadget;
464 
465 	if( gd )
466 	{
467 	    pip = (struct PropInfo *)gd->SpecialInfo;
468 	    wheight = ( w->Height - w->BorderTop -
469 			    w->BorderBottom - 2 ) / w->RPort->TxHeight;
470 	    hidden = max( cw->maxrow - wheight, 0 );
471 	    topidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16;
472 	    for( total = i = 0; i < cw->maxrow; ++i )
473 	    {
474 		if( cw->data[i][1] != 0 )
475 		    ++total;
476 	    }
477 
478 	    i = 0;
479 	    topidx -= wheight/4 + 1;
480 	    if (topidx < 0)
481 		topidx = 0;
482 	    SetPropInfo( w, &MsgScroll, wheight, total, topidx );
483 	    DisplayData( WIN_MESSAGE, topidx );
484 	}
485 	return(0);
486     }
487 
488     if( --cw->vwy < 0 )
489     {
490 	cw->maxcol = 0;
491 	DisplayBeep( NULL );
492 	str = "\0\0No more history saved...";
493     }
494     else
495 	str = cw->data[ cw->vwy ];
496 
497     amii_cl_end(cw, 0);
498     amii_curs( WIN_MESSAGE, 1, 0 );
499     amii_setdrawpens( amii_wins[WIN_MESSAGE]->win, NHW_MESSAGE );
500     Text(w->RPort,str+SOFF,strlen(str+SOFF));
501     cw->curx = cw->cols + 1;
502 
503     return( 0 );
504 }
505