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