diff --git a/sys/amiga/winmenu.c b/sys/amiga/winmenu.c new file mode 100644 index 000000000..b2cf1cf37 --- /dev/null +++ b/sys/amiga/winmenu.c @@ -0,0 +1,1597 @@ +/* SCCS Id: @(#)winmenu.c 3.2 96/02/17 */ +/* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */ +/* NetHack may be freely redistributed. See license for details. */ + +#include "NH:sys/amiga/windefs.h" +#include "NH:sys/amiga/winext.h" +#include "NH:sys/amiga/winproto.h" + +/* Start building the text for a menu */ +void +amii_start_menu(window) + register winid window; +{ + register int i; + register struct amii_WinDesc *cw; + register amii_menu_item *mip; + + if(window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU) + panic(winpanicstr,window, "start_menu"); + + amii_clear_nhwindow(window); + + if( cw->data && ( cw->type == NHW_MESSAGE || + cw->type == NHW_MENU || cw->type == NHW_TEXT ) ) + { + for( i = 0; i < cw->maxrow; ++i ) + { + if( cw->data[ i ] ) + free( cw->data[ i ] ); + } + free( cw->data ); + cw->data = NULL; + } + + for( mip = cw->menu.items, i = 0; (mip = cw->menu.items) && i < cw->menu.count; ++i ) + { + cw->menu.items = mip->next; + free( mip ); + } + + cw->menu.items = 0; + cw->menu.count = 0; + cw->menu.chr = 'a'; + + if( cw->morestr ) free( cw->morestr ); + cw->morestr = NULL; + + if( window == WIN_INVEN && cw->win != NULL ) + { + if( alwaysinvent ) + cw->wasup = 1; + } + cw->cury = cw->rows = cw->maxrow = cw->maxcol = 0; + return; +} + +/* Add a string to a menu */ +void +amii_add_menu(window,glyph, id, ch, gch, attr, str, preselected) + register winid window; + register int glyph; + register const anything *id; + register char ch; + register char gch; + register int attr; + register const char *str; + register BOOLEAN_P preselected; +{ + register struct amii_WinDesc *cw; + amii_menu_item *mip; + char buf[ 4+BUFSZ ]; + + if(str == NULL)return; + + if(window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU) + panic(winpanicstr,window, "add_menu"); + + mip = (amii_menu_item *)alloc( sizeof( *mip ) ); + mip->identifier = *id; + mip->selected = preselected; + mip->attr = attr; + mip->glyph = Is_rogue_level(&u.uz) ? NO_GLYPH : glyph; + mip->selector = 0; + mip->gselector = gch; + mip->count = -1; + + if (id->a_void && !ch && cw->menu.chr != 0) + { + ch = cw->menu.chr++; + if( ch == 'z' ) + cw->menu.chr = 'A'; + if( ch == 'Z' ) + cw->menu.chr = 0; + } + + mip->canselect = ( id->a_void != 0 ); + + if( id->a_void && ch != '\0') + { + Sprintf( buf, "%c - %s", ch, str ); + str = buf; + mip->canselect = 1; + } + + mip->selector = ch; + + amii_putstr( window, attr, str ); + + mip->str = cw->data[ cw->cury - 1 ]; + cw->menu.count++; + + mip->next = NULL; + + if( cw->menu.items == 0 ) + cw->menu.last = cw->menu.items = mip; + else + { + cw->menu.last->next = mip; + cw->menu.last = mip; + } +} + +/* Done building a menu. */ + +void +amii_end_menu(window,morestr) + register winid window; + register const char *morestr; +{ + register struct amii_WinDesc *cw; + + if(window == WIN_ERR || (cw=amii_wins[window]) == NULL + || cw->type != NHW_MENU ) + panic(winpanicstr,window, "end_menu"); + + if( morestr && *morestr ) + { + anything any; +#define PROMPTFIRST /* Define this to have prompt first */ +#ifdef PROMPTFIRST + amii_menu_item *mip; + int i; + char *t; + mip = cw->menu.last; +#endif + any.a_void = 0; + amii_add_menu( window, NO_GLYPH, &any, 0, 0, ATR_NONE, morestr, + MENU_UNSELECTED); +#ifdef PROMPTFIRST /* Do some shuffling. Last first, push others one forward */ + mip->next = NULL; + cw->menu.last->next = cw->menu.items; + cw->menu.items = cw->menu.last; + cw->menu.last = mip; + t = cw->data[cw->cury-1]; + for (i=cw->cury-1; i>0; i--) { + cw->data[i] = cw->data[i-1]; + } + cw->data[0] = t; +#endif + } + + /* If prompt first, don't put same string in title where in most cases + it's not entirely visible anyway */ +#ifndef PROMPTFIRST + if( morestr ) + cw->morestr = strdup( morestr ); +#endif +} + +/* Select something from the menu. */ + +int +amii_select_menu(window, how, mip ) + register winid window; + register int how; + register menu_item **mip; +{ + int cnt; + register struct amii_WinDesc *cw; + + if( window == WIN_ERR || ( cw=amii_wins[window] ) == NULL || + cw->type != NHW_MENU ) + panic(winpanicstr,window, "select_menu"); + + cnt = DoMenuScroll( window, 1, how, mip ); + + /* This would allow the inventory window to stay open. */ + if( !alwaysinvent || window != WIN_INVEN ) + dismiss_nhwindow(window); /* Now tear it down */ + return cnt; +} + +amii_menu_item * +find_menu_item( register struct amii_WinDesc *cw, int idx ) +{ + amii_menu_item *mip; + for( mip = cw->menu.items; idx > 0 && mip; mip = mip->next ) + --idx; + + return( mip ); +} + +int +make_menu_items( register struct amii_WinDesc *cw, register menu_item **rmip ) +{ + register int idx = 0; + register amii_menu_item *mip; + register menu_item *mmip; + + for( mip = cw->menu.items; mip; mip = mip->next ) + { + if( mip->selected ) + ++idx; + } + + if( idx ) + { + mmip = *rmip = (menu_item *)alloc( idx * sizeof( *mip ) ); + for( mip = cw->menu.items; mip; mip = mip->next ) + { + if( mip->selected ) + { + mmip->item = mip->identifier; + mmip->count = mip->count; + mmip++; + } + } + + cw->mi = *rmip; + } + return( idx ); +} + +int +DoMenuScroll( win, blocking, how, retmip ) + int win, blocking, how; + menu_item **retmip; +{ + amii_menu_item *amip; + register struct Window *w; + register struct NewWindow *nw; + struct PropInfo *pip; + register struct amii_WinDesc *cw; + struct IntuiMessage *imsg; + struct Gadget *gd; + register int wheight, xsize, ysize, aredone = 0; + register int txwd, txh; + long mics, secs, class, code; + long oldmics = 0, oldsecs = 0; + int aidx, oidx, topidx, hidden; + int totalvis; + SHORT mx, my; + static char title[ 100 ]; + int dosize = 1; + struct Screen *scrn = HackScreen; + int x1,x2,y1,y2; + long counting = FALSE, count = 0, reset_counting = FALSE; + char countString[32]; + + if( win == WIN_ERR || ( cw = amii_wins[ win ] ) == NULL ) + panic(winpanicstr,win,"DoMenuScroll"); + + /* Initial guess at window sizing values */ + txwd = txwidth; + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + txh = max( txheight, pictdata.ysize + 3 ); /* interline space */ + else + txh = txheight; /* interline space */ + } + else + txh = txheight; /* interline space */ + + /* Check to see if we should open the window, should need to for + * TEXT and MENU but not MESSAGE. + */ + + w = cw->win; + topidx = 0; + + if( w == NULL ) + { + +#ifdef INTUI_NEW_LOOK + if( IntuitionBase->LibNode.lib_Version >= 37 ) + { + PropScroll.Flags |= PROPNEWLOOK; + } +#endif + nw = (void *)DupNewWindow( (void *)(&new_wins[ cw->type ].newwin) ); + if( !alwaysinvent || win != WIN_INVEN ) + { + xsize = scrn->WBorLeft + scrn->WBorRight + MenuScroll.Width + 1 + + (txwd * cw->maxcol); + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + xsize += pictdata.xsize + 4; + } + if( xsize > amiIDisplay->xpix ) + xsize = amiIDisplay->xpix; + + /* If next row not off window, use it, else use the bottom */ + + ysize = ( txh * cw->maxrow ) + /* The text space */ + HackScreen->WBorTop + txheight + 1 + /* Top border */ + HackScreen->WBorBottom + 3; /* The bottom border */ + if( ysize > amiIDisplay->ypix ) + ysize = amiIDisplay->ypix; + + /* Adjust the size of the menu scroll gadget */ + + nw->TopEdge = 0; + if( cw->type == NHW_TEXT && ysize < amiIDisplay->ypix ) + nw->TopEdge += ( amiIDisplay->ypix - ysize ) / 2; + nw->LeftEdge = amiIDisplay->xpix - xsize; + if( cw->type == NHW_MENU ) + { + if( nw->LeftEdge > 10 ) + nw->LeftEdge -= 10; + else + nw->LeftEdge = 0; + if( amiIDisplay->ypix - nw->Height > 10 ) + nw->TopEdge += 10; + else + nw->TopEdge = amiIDisplay->ypix - nw->Height - 1; + } + if( cw->type == NHW_TEXT && xsize < amiIDisplay->xpix ) + nw->LeftEdge -= ( amiIDisplay->xpix - xsize ) / 2; + } + else if( win == WIN_INVEN ) + { + struct Window *mw = amii_wins[ WIN_MAP ]->win; + struct Window *sw = amii_wins[ WIN_STATUS ]->win; + + xsize = scrn->WBorLeft + scrn->WBorRight + MenuScroll.Width + 1 + + (txwd * cw->maxcol); + + /* Make space for the glyph to appear at the left of the description */ + if( WINVERS_AMIV ) + xsize += pictdata.xsize + 4; + + if( xsize > amiIDisplay->xpix ) + xsize = amiIDisplay->xpix; + + /* If next row not off window, use it, else use the bottom */ + + ysize = sw->TopEdge - (mw->TopEdge + mw->Height) - 1; + if( ysize > amiIDisplay->ypix ) + ysize = amiIDisplay->ypix; + + /* Adjust the size of the menu scroll gadget */ + + nw->TopEdge = mw->TopEdge + mw->Height; + nw->LeftEdge = 0; + } + cw->newwin = (void *)nw; + if( nw == NULL ) + panic("No NewWindow Allocated" ); + + nw->Screen = HackScreen; + + if( win == WIN_INVEN ) + { + sprintf( title, "%s the %s's Inventory", plname, pl_character ); + nw->Title = title; + if( lastinvent.MaxX != 0 ) + { + nw->LeftEdge = lastinvent.MinX; + nw->TopEdge = lastinvent.MinY; + nw->Width = lastinvent.MaxX; + nw->Height = lastinvent.MaxY; + } + } + else if( cw->morestr ) + nw->Title = cw->morestr; + + /* Adjust the window coordinates and size now that we know + * how many items are to be displayed. + */ + + if( ( xsize > amiIDisplay->xpix - nw->LeftEdge ) && + ( xsize < amiIDisplay->xpix ) ) + { + nw->LeftEdge = amiIDisplay->xpix - xsize; + nw->Width = xsize; + } + else + { + nw->Width = min( xsize, amiIDisplay->xpix - nw->LeftEdge ); + } + nw->Height = min( ysize, amiIDisplay->ypix - nw->TopEdge ); + + if( WINVERS_AMIV || WINVERS_AMII ) + { + /* Make sure we are using the correct hook structure */ + nw->Extension = cw->wintags; + } + + /* Now, open the window */ + w = cw->win = OpenShWindow( (void *)nw ); + + if( w == NULL ) + { + char buf[ 130 ]; + + sprintf( buf, "No Window Opened For Menu (%d,%d,%d-%d,%d-%d)", + nw->LeftEdge, nw->TopEdge, nw->Width, amiIDisplay->xpix, + nw->Height, amiIDisplay->ypix ); + panic( buf ); + } + +#ifdef HACKFONT + if( TextsFont ) + SetFont(w->RPort, TextsFont ); + else if( HackFont ) + SetFont(w->RPort, HackFont ); +#endif + txwd = w->RPort->TxWidth; + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + txh = max( w->RPort->TxHeight, pictdata.ysize + 3 ); /* interline space */ + else + txh = w->RPort->TxHeight; /* interline space */ + } + else + txh = w->RPort->TxHeight; /* interline space */ + + /* subtract 2 to account for spacing away from border (1 on each side) */ + wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / txh; + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + { + cw->cols = ( w->Width - w->BorderLeft - + w->BorderRight - 4 - pictdata.xsize - 3 ) / txwd; + } + else + { + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + } + else + { + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + totalvis = CountLines( win ); + } + else + { + txwd = w->RPort->TxWidth; + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + txh = max( w->RPort->TxHeight, pictdata.ysize + 3 ); /* interline space */ + else + txh = w->RPort->TxHeight; /* interline space */ + } + else + { + txh = w->RPort->TxHeight; /* interline space */ + } + + /* subtract 2 to account for spacing away from border (1 on each side) */ + wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / txh; + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + { + cw->cols = ( w->Width - w->BorderLeft - + w->BorderRight - 4 - pictdata.xsize - 3) / txwd; + } + else + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + else + { + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + + totalvis = CountLines( win ); + + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + if( gd ) + { + pip = (struct PropInfo *)gd->SpecialInfo; + hidden = max( totalvis - wheight, 0 ); + topidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16; + } + } + + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + if( !gd ) panic("Can't find scroll gadget" ); + + morc = 0; + oidx = -1; + +#if 0 + /* Make sure there are no selections left over from last time. */ +/* XXX potential problem for preselection if this is really needed */ + for( amip = cw->menu.items; amip; amip = amip->next ) + amip->selected = 0; +#endif + + DisplayData( win, topidx ); + + /* Make the prop gadget the right size and place */ + + SetPropInfo( w, gd, wheight, totalvis, topidx ); + oldsecs = oldmics = 0; + + /* If window already up, don't stop to process events */ + if( cw->wasup ) + { + aredone = 1; + cw->wasup = 0; + } + + while( !aredone ) + { + /* Process window messages */ + + WaitPort( w->UserPort ); + while( imsg = (struct IntuiMessage * ) GetMsg( w->UserPort ) ) + { + class = imsg->Class; + code = imsg->Code; + mics = imsg->Micros; + secs = imsg->Seconds; + gd = (struct Gadget *) imsg->IAddress; + mx = imsg->MouseX; + my = imsg->MouseY; + + /* Only do our window or VANILLAKEY from other windows */ + + if( imsg->IDCMPWindow != w && class != VANILLAKEY && + class != RAWKEY ) + { + ReplyMsg( (struct Message *) imsg ); + continue; + } + + /* Do DeadKeyConvert() stuff if RAWKEY... */ + if( class == RAWKEY ) + { + class = VANILLAKEY; + code = ConvertKey( imsg ); + } + ReplyMsg( (struct Message *) imsg ); + + switch( class ) + { + case NEWSIZE: + + /* + * Ignore every other newsize, no action needed, + * except RefreshWindowFrame() in case borders got overwritten + * for some reason. It should not happen, but ... + */ + + if( !dosize ) + { + RefreshWindowFrame(w); + dosize = 1; + break; + } + + if( win == WIN_INVEN ) + { + lastinvent.MinX = w->LeftEdge; + lastinvent.MinY = w->TopEdge; + lastinvent.MaxX = w->Width; + lastinvent.MaxY = w->Height; + } + else if( win == WIN_MESSAGE ) + { + lastmsg.MinX = w->LeftEdge; + lastmsg.MinY = w->TopEdge; + lastmsg.MaxX = w->Width; + lastmsg.MaxY = w->Height; + } + + /* Find the gadget */ + + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + if( !gd ) + panic("Can't find scroll gadget" ); + + totalvis = CountLines( win ); + wheight = ( w->Height - w->BorderTop - + w->BorderBottom - 2) / txh; + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + { + cw->cols = ( w->Width - w->BorderLeft - + w->BorderRight - 4 - pictdata.xsize - 3) / txwd; + } + else + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + else + { + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + + if( wheight < 2 ) + wheight = 2; + + /* + * Clear the right side & bottom. Parts of letters are not erased by + * amii_cl_end if window shrinks and columns decrease. + */ + + if ( WINVERS_AMII || WINVERS_AMIV ) { + amii_setfillpens(w, cw->type); + SetDrMd(w->RPort, JAM2); + x2 = w->Width - w->BorderRight; + y2 = w->Height - w->BorderBottom; + x1 = x2 - w->IFont->tf_XSize - w->IFont->tf_XSize; + y1 = w->BorderTop; + if (x1 < w->BorderLeft) + x1 = w->BorderLeft; + RectFill(w->RPort, x1, y1, x2, y2); + x1 = w->BorderLeft; + y1 = y1 - w->IFont->tf_YSize; + RectFill(w->RPort, x1, y1, x2, y2); + RefreshWindowFrame(w); + } + + /* Make the prop gadget the right size and place */ + + DisplayData( win, topidx ); + SetPropInfo( w, gd, wheight, totalvis, topidx ); + + /* Force the window to a text line boundary <= to + * what the user dragged it to. This eliminates + * having to clean things up on the bottom edge. + */ + + SizeWindow( w, 0, ( wheight * txh) + + w->BorderTop + w->BorderBottom + 2 - w->Height ); + + /* Don't do next NEWSIZE, we caused it */ + dosize = 0; + oldsecs = oldmics = 0; + break; + + case VANILLAKEY: +#define CTRL(x) ((x)-'@') + morc = code = map_menu_cmd(code); + if (code == MENU_SELECT_ALL) { + if (how == PICK_ANY) { + amip = cw->menu.items; + while (amip) { + if (amip->canselect && amip->selector) { + /* + * Select those yet unselected + * and apply count if necessary + */ + if (!amip->selected) { + amip->selected = TRUE; + if (counting) { + amip->count = count; + reset_counting = TRUE; + /* + * This makes the assumption that + * the string is in format "X - foo" + * with additional selecting and formatting + * data in front (size SOFF) + */ + amip->str[SOFF+2] = '#'; + } else { + amip->count = -1; + amip->str[SOFF+2] = '-'; + } + } + } + amip=amip->next; + } + DisplayData(win, topidx); + } + } else if (code == MENU_UNSELECT_ALL) { + if (how == PICK_ANY) { + amip = cw->menu.items; + while (amip) { + if (amip->selected) { + amip->selected = FALSE; + amip->count = -1; + amip->str[SOFF+2] = '-'; + } + amip=amip->next; + } + DisplayData(win, topidx); + } + } else if (code == MENU_INVERT_ALL) { + if (how == PICK_ANY) { + amip = cw->menu.items; + while (amip) { + if (amip->canselect && amip->selector) { + amip->selected = !amip->selected; + if (counting && amip->selected) { + amip->count = count; + amip->str[SOFF+2] = '#'; + reset_counting = TRUE; + } else { + amip->count = -1; + amip->str[SOFF+2] = '-'; + } + } + amip=amip->next; + } + DisplayData(win, topidx); + } + } else if (code == MENU_SELECT_PAGE) { + if (how == PICK_ANY) { + int i = 0; + amip = cw->menu.items; + while (amip && i++ < topidx) + amip = amip->next; + for (i=0;i < wheight && amip; i++, amip=amip->next) { + if (amip->canselect && amip->selector) { + if (!amip->selected) { + if (counting) { + amip->count = count; + reset_counting = TRUE; + amip->str[SOFF+2] = '#'; + } else { + amip->count = -1; + amip->str[SOFF+2] = '-'; + } + } + amip->selected = TRUE; + } + } + DisplayData(win, topidx); + } + } else if (code == MENU_UNSELECT_PAGE) { + if (how == PICK_ANY) { + int i = 0; + amip = cw->menu.items; + while (amip && i++ < topidx) + amip = amip->next; + for (i=0;i < wheight && amip; i++, amip=amip->next) { + if (amip->selected) { + amip->selected = FALSE; + amip->count = -1; + amip->str[SOFF+2] = '-'; + } + } + DisplayData(win, topidx); + } + } else if (code == MENU_INVERT_PAGE) { + if (how == PICK_ANY) { + int i = 0; + amip = cw->menu.items; + while (amip && i++ < topidx) + amip = amip->next; + for (i=0;i < wheight && amip; i++, amip=amip->next) { + if (amip->canselect && amip->selector) { + amip->selected = !amip->selected; + if (counting && amip->selected) { + amip->count = count; + amip->str[SOFF+2] = '#'; + reset_counting = TRUE; + } else { + amip->count = -1; + amip->str[SOFF+2] = '-'; + } + } + } + DisplayData(win, topidx); + } + } else if (code == MENU_SEARCH && cw->type == NHW_MENU) { + if (how == PICK_ONE || how == PICK_ANY) { + char buf[BUFSZ]; + amip = cw->menu.items; + amii_getlin("Search for:", buf); + if (!*buf || *buf == '\033') + break; + while (amip) { + if (amip->canselect && amip->selector && amip->str && + strstri(&amip->str[SOFF], buf)) { + if (how == PICK_ONE) { + amip->selected = TRUE; + aredone = 1; + break; + } + amip->selected = !amip->selected; + if (counting && amip->selected) { + amip->count = count; + reset_counting = TRUE; + amip->str[SOFF+2] = '#'; + } else { + amip->count = -1; + reset_counting = TRUE; + amip->str[SOFF+2] = '-'; + } + } + amip = amip->next; + } + } + DisplayData(win, topidx); + } else if (how == PICK_ANY && isdigit(code) && + (counting || (!counting && code !='0'))) { + if (count < LARGEST_INT) { + count = count*10 + (long)(code-'0'); + if (count > LARGEST_INT) + count = LARGEST_INT; + if (count > 0) { + counting = TRUE; + reset_counting = FALSE; + } else { + reset_counting = TRUE; + } + sprintf(countString, "Count: %d", count); + pline(countString); + } + } else if( code == CTRL('D') || code == CTRL('U') || + code == MENU_NEXT_PAGE || code == MENU_PREVIOUS_PAGE || + code == MENU_FIRST_PAGE || code == MENU_LAST_PAGE ) + { + int endcnt, i; + + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + if( !gd ) + panic("Can't find scroll gadget" ); + + endcnt = wheight; /* /2; */ + if( endcnt == 0 ) + endcnt = 1; + + if (code == MENU_FIRST_PAGE) { + topidx = 0; + } else if (code == MENU_LAST_PAGE) { + topidx = cw->maxrow - wheight; + } else for( i = 0; i < endcnt; ++i ) + { + if (code == CTRL('D') || code == MENU_NEXT_PAGE) + { + if( topidx + wheight < cw->maxrow ) + ++topidx; + else + break; + } + else if (code = CTRL('U') || code == MENU_PREVIOUS_PAGE) + { + if( topidx > 0 ) + --topidx; + else + break; + } + } + /* Make prop gadget the right size and place */ + + DisplayData( win, topidx ); + SetPropInfo( w,gd, wheight, totalvis, topidx ); + oldsecs = oldmics = 0; + } + else if( code == '\b' ) + { + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + if( !gd ) + panic("Can't find scroll gadget" ); + + if( topidx - wheight - 2 < 0 ) + { + topidx = 0; + } + else + { + topidx -= wheight - 2; + } + DisplayData( win, topidx ); + SetPropInfo( w, gd, wheight, totalvis, topidx ); + oldsecs = oldmics = 0; + } + else if( code == ' ' ) + { + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + if( !gd ) + panic("Can't find scroll gadget" ); + + if( topidx + wheight >= cw->maxrow ) + { + morc = 0; + aredone = 1; + } + else + { + /* If there are still lines to be seen */ + + if( cw->maxrow > topidx + wheight ) + { + if( wheight > 2 ) + topidx += wheight - 2; + else + ++topidx; + DisplayData( win, topidx ); + SetPropInfo( w, gd, wheight, + totalvis, topidx ); + } + oldsecs = oldmics = 0; + } + } + else if( code == '\n' || code == '\r' ) + { + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + if( !gd ) + panic("Can't find scroll gadget" ); + + /* If all line displayed, we are done */ + + if( topidx + wheight >= cw->maxrow ) + { + morc = 0; + aredone = 1; + } + else + { + /* If there are still lines to be seen */ + + if( cw->maxrow > topidx + 1 ) + { + ++topidx; + DisplayData( win, topidx ); + SetPropInfo( w, gd, wheight, + totalvis, topidx ); + } + oldsecs = oldmics = 0; + } + } + else if( code == '\33' ) + { + if (counting) { + reset_counting = TRUE; + } else { + aredone = 1; + } + } + else + { + int selected = FALSE; + for( amip = cw->menu.items; amip; amip = amip->next ) + { + if( amip->selector == code ) + { + if( how == PICK_ONE ) + aredone = 1; + amip->selected = !amip->selected; + if (counting && amip->selected) { + amip->count = count; + reset_counting = TRUE; + amip->str[SOFF+2] = '#'; + } else { + amip->count = -1; + reset_counting = TRUE; + amip->str[SOFF+2] = '-'; + } + selected = TRUE; + } else if (amip->gselector == code ) + { + amip->selected = !amip->selected; + if (counting) { + amip->count = count; + reset_counting = TRUE; + amip->str[SOFF+2] = '#'; + } else { + amip->count = -1; + reset_counting = TRUE; + amip->str[SOFF+2] = '-'; + } + selected = TRUE; + } + } + if (selected) + DisplayData( win, topidx ); + } + break; + + case CLOSEWINDOW: + if( win == WIN_INVEN ) + { + lastinvent.MinX = w->LeftEdge; + lastinvent.MinY = w->TopEdge; + lastinvent.MaxX = w->Width; + lastinvent.MaxY = w->Height; + } + else if( win == WIN_MESSAGE ) + { + lastmsg.MinX = w->LeftEdge; + lastmsg.MinY = w->TopEdge; + lastmsg.MaxX = w->Width; + lastmsg.MaxY = w->Height; + } + aredone = 1; + morc = '\33'; + break; + + case GADGETUP: + if( win == WIN_MESSAGE ) + aredone = 1; + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + pip = (struct PropInfo *)gd->SpecialInfo; + totalvis = CountLines( win ); + hidden = max( totalvis - wheight, 0 ); + aidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16; + if( aidx != topidx ) + DisplayData( win, topidx = aidx ); + break; + + case MOUSEMOVE: + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + pip = (struct PropInfo *)gd->SpecialInfo; + totalvis = CountLines( win ); + hidden = max( totalvis - wheight, 0 ); + aidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16; + if( aidx != topidx ) + DisplayData( win, topidx = aidx ); + break; + + case INACTIVEWINDOW: + if( win == WIN_MESSAGE || ( win == WIN_INVEN && alwaysinvent ) ) + aredone = 1; + break; + + case MOUSEBUTTONS: + if( ( code == SELECTUP || code == SELECTDOWN ) && + cw->type == NHW_MENU && how != PICK_NONE ) + { + /* Which one is the mouse pointing at? */ + + aidx = ( ( my - w->BorderTop - 1 ) / txh ) + topidx; + + /* If different lines, don't select double click */ + + if( aidx != oidx ) + { + oldsecs = 0; + oldmics = 0; + } + + /* If releasing, check for double click */ + + if( code == SELECTUP ) + { + amip = find_menu_item( cw, aidx ); + if( aidx == oidx ) + { + if( DoubleClick( oldsecs, + oldmics, secs, mics ) ) + { + aredone = 1; + } + oldsecs = secs; + oldmics = mics; + } + else + { + amip = find_menu_item( cw, oidx ); + amip->selected = 0; + amip->count = -1; + reset_counting = TRUE; + if (amip->canselect && amip->selector) + amip->str[SOFF+2] = '-'; + } + if (counting && amip->selected && amip->canselect && amip->selector) { + amip->count = count; + reset_counting = TRUE; + amip->str[SOFF+2] = '#'; + } + DisplayData( win, topidx ); + } + else if( aidx - topidx < wheight && + aidx < cw->maxrow && code == SELECTDOWN ) + { + /* Remove old highlighting if visible */ + + amip = find_menu_item( cw, oidx ); + if( amip && oidx != aidx && + ( oidx > topidx && oidx - topidx < wheight ) ) + { + if( how != PICK_ANY ) { + amip->selected = 0; + amip->count = -1; + reset_counting = TRUE; + if (amip->canselect && amip->selector) + amip->str[SOFF+2] = '-'; + } + oidx = -1; + } + amip = find_menu_item( cw, aidx ); + + if( amip && amip->canselect && amip->selector && how != PICK_NONE ) + { + oidx = aidx; + if( !DoubleClick( oldsecs, + oldmics, secs, mics ) ) + { + amip->selected = !amip->selected; + if (counting && amip->selected) { + amip->count = count; + reset_counting = TRUE; + amip->str[SOFF+2] = '#'; + } else { + amip->count = -1; + reset_counting = TRUE; + if (amip->canselect && amip->selector) + amip->str[SOFF+2] = '-'; + } + } + } + else + { + DisplayBeep( NULL ); + oldsecs = 0; + oldmics = 0; + } + DisplayData( win, topidx ); + } + } + else + { + DisplayBeep( NULL ); + } + break; + } + if (!counting && morc == '\33') { + amip = cw->menu.items; + while (amip) { + if (amip->canselect && amip->selector) { + amip->selected = FALSE; + amip->count = -1; + amip->str[SOFF+2] = '-'; + } + amip=amip->next; + } + } + if (reset_counting) { + count = 0; + if (counting) + pline("Count: 0"); + counting = FALSE; + } + } + } + /* Force a cursor reposition before next message output */ + if( win == WIN_MESSAGE ) + cw->curx = -1; + return( make_menu_items( cw, retmip ) ); +} + +void +ReDisplayData( win ) + winid win; +{ + int totalvis; + register struct amii_WinDesc *cw; + register struct Window *w; + register struct Gadget *gd; + unsigned long hidden, aidx, wheight; + struct PropInfo *pip; + + if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) ) + return; + + for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) + gd = gd->NextGadget; + + if( !gd ) + return; + + wheight = (w->Height - w->BorderTop - w->BorderBottom-2)/w->RPort->TxHeight; + + pip = (struct PropInfo *)gd->SpecialInfo; + totalvis = CountLines( win ); + hidden = max( totalvis - wheight, 0 ); + aidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16; + clear_nhwindow( win ); + DisplayData( win, aidx ); +} + +long +FindLine( win, line ) + winid win; + int line; +{ + int txwd; + register char *t; + register struct amii_WinDesc *cw; + register struct Window *w; + register int i, disprow, len; + int col = -1; + + if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) ) + { + panic( winpanicstr, win, "No Window in FindLine" ); + } + txwd = w->RPort->TxWidth; + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + { + cw->cols = ( w->Width - w->BorderLeft - + w->BorderRight - 4 - pictdata.xsize - 3) / txwd; + } + else + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + else + { + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + + disprow = 0; + for( col = i = 0; line > disprow && i < cw->maxrow; ++i ) + { + t = cw->data[ i ] + SOFF; + if( cw->data[i][1] >= 0 ) + { + ++disprow; + col = 0; + } + + while( *t ) + { + len = strlen( t ); + if( col + len > cw->cols ) + len = cw->cols - col; + while( len > 0 ) + { + if( !t[len] || t[len] == ' ' ) + break; + --len; + } + if( len == 0 ) { + while ( *t && *t != ' ') { + t++; col++; + } + } else { + t += len; + col += len; + } + if( *t ) + { + while( *t == ' ' ) + ++t; + col = 0; + ++disprow; + } + } + } + return( i ); +} + +long +CountLines( win ) + winid win; +{ + int txwd; + amii_menu_item *mip; + register char *t; + register struct amii_WinDesc *cw; + register struct Window *w; + register int i, disprow, len; + int col = -1; + + if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) ) + { + panic( winpanicstr, win, "No Window in CountLines" ); + } + + txwd = w->RPort->TxWidth; + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + { + cw->cols = ( w->Width - w->BorderLeft - + w->BorderRight - 4 - pictdata.xsize - 3) / txwd; + } + else + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + else + { + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + + disprow = cw->maxrow; + mip = cw->menu.items; + for( col = i = 0; i < cw->maxrow; ++i ) + { + t = cw->data[ i ] + SOFF; + if( cw->type == NHW_MESSAGE && cw->data[ i ][ SEL_ITEM ] < 0 ) + --disprow; + else + col = 0; + while( *t ) + { + len = strlen( t ); + if( col + len > cw->cols ) + len = cw->cols - col; + while( len > 0 ) + { + if( !t[len] || t[len] == ' ' ) + break; + --len; + } + if( len == 0 ) { + while ( *t && *t != ' ') { + t++; col++; + } + } else { + t += len; + col += len; + } + if( *t ) + { + while( *t == ' ' ) + ++t; + col = 0; + ++disprow; + } + } + } + return( disprow ); +} + +void +DisplayData( win, start ) + winid win; + int start; +{ + int txwd; + amii_menu_item *mip; + register char *t; + register struct amii_WinDesc *cw; + register struct Window *w; + register struct RastPort *rp; + register int i, disprow, len, wheight; + int whichcolor = -1; + int col; + + if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) ) + { + panic( winpanicstr, win, "No Window in DisplayData" ); + } + + rp = w->RPort; + SetDrMd( rp, JAM2 ); + if( WINVERS_AMIV && win == WIN_INVEN ) + { + wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / + max( rp->TxHeight, pictdata.ysize + 3 ); + } + else + { + wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / + rp->TxHeight; + } + + cw->rows = wheight; + txwd = rp->TxWidth; + if( WINVERS_AMIV ) + { + if( win == WIN_INVEN ) + { + cw->cols = ( w->Width - w->BorderLeft - + w->BorderRight - 4 - pictdata.xsize - 3) / txwd; + } + else + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + else + { + cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; + } + + /* Get the real line to display at */ + start = FindLine( win, start ); + + mip = cw->menu.items; + for( i = 0; mip && i < start; ++i ) + { + mip = mip->next; + } + + /* Skip any initial response to a previous line */ + if( cw->type == NHW_MESSAGE && mip && mip->selected < 0 ) + ++start; + if( WINVERS_AMIV && cw->type == NHW_MESSAGE ) + SetAPen( rp, amii_msgAPen ); + + for( disprow = i = start; disprow < wheight + start; i++ ) + { + /* Just erase unused lines in the window */ + if( i >= cw->maxrow ) + { + if (WINVERS_AMIV && win == WIN_INVEN) { + amii_curs( win, 0, disprow - start ); + amiga_print_glyph( win, 0, NO_GLYPH); + } + amii_curs( win, 1, disprow - start ); + amii_cl_end( cw, 0 ); + ++disprow; + continue; + } + + /* Any string with a highlighted attribute goes + * onto the end of the current line in the message window. + */ + if( cw->type == NHW_MESSAGE ) + SetAPen( rp, cw->data[ i ][ SEL_ITEM ] < 0 ? C_RED : amii_msgAPen ); + + /* Selected text in the message window goes onto the end of the current line */ + if( cw->type != NHW_MESSAGE || cw->data[ i ][ SEL_ITEM ] >= 0 ) + { + amii_curs( win, 1, disprow - start ); + if( WINVERS_AMIV && win == WIN_INVEN ) + { + if( mip ) + amiga_print_glyph( win, 0, mip->glyph ); + amii_curs( win, 1, disprow - start ); + } + col = 0; + } + + /* If this entry is to be highlighted, do so */ + if( mip && mip->selected != 0 ) + { + if( whichcolor != 1 ) + { + SetDrMd( rp, JAM2 ); + if( WINVERS_AMIV ) + { + SetAPen( rp, amii_menuBPen ); + SetBPen( rp, C_BLUE ); + } + else + { + SetAPen( rp, C_BLUE ); + SetBPen( rp, amii_menuAPen ); + } + whichcolor = 1; + } + } + else if( whichcolor != 2 ) + { + SetDrMd( rp, JAM2 ); + if( cw->type == NHW_MESSAGE ) + { + SetAPen( rp, amii_msgAPen ); + SetBPen( rp, amii_msgBPen ); + } + else if( cw->type == NHW_MENU ) + { + SetAPen( rp, amii_menuAPen ); + SetBPen( rp, amii_menuBPen ); + } + else if( cw->type == NHW_TEXT ) + { + SetAPen( rp, amii_textAPen ); + SetBPen( rp, amii_textBPen ); + } + whichcolor = 2; + } + + /* Next line out, wrap if too long */ + + t = cw->data[ i ] + SOFF; + ++disprow; + col = 0; + while( *t ) + { + len = strlen( t ); + if( len > (cw->cols - col) ) + len = cw->cols - col; + while( len > 0 ) + { + if( !t[len] || t[len] == ' ' ) + break; + --len; + } + if( len == 0 ) { + Text( rp, t, cw->cols - col ); + while ( *t && *t != ' ') { + t++; col++; + } + } else { + Text( rp, t, len ); + t += len; + col += len; + } + amii_cl_end( cw, col ); + if( *t ) + { + ++disprow; + /* Stop at the bottom of the window */ + if( disprow > wheight + start ) + break; + while( *t == ' ' ) + ++t; + amii_curs( win, 1, disprow - start - 1 ); + if( mip && win == WIN_INVEN && WINVERS_AMIV ) + { + /* Erase any previous glyph drawn here. */ + amiga_print_glyph( win, 0, NO_GLYPH ); + amii_curs( win, 1, disprow - start - 1 ); + } + Text( rp, "+", 1 ); + col = 1; + } + } + + if( cw->type == NHW_MESSAGE ) + { + SetAPen( rp, amii_msgBPen ); + SetBPen( rp, amii_msgBPen ); + } + else if( cw->type == NHW_MENU ) + { + SetAPen( rp, amii_menuBPen ); + SetBPen( rp, amii_menuBPen ); + } + else if( cw->type == NHW_TEXT ) + { + SetAPen( rp, amii_textBPen ); + SetBPen( rp, amii_textBPen ); + } + amii_cl_end( cw, col ); + whichcolor = -1; + if( mip ) mip = mip->next; + } + RefreshWindowFrame(w); + return; +} + +void SetPropInfo( win, gad, vis, total, top ) + register struct Window *win; + register struct Gadget *gad; + register long vis, total, top; +{ + long mflags; + register long hidden; + register int body, pot; + + hidden = max( total-vis, 0 ); + + /* Force the last section to be just to the bottom */ + + if( top > hidden ) + top = hidden; + + /* Scale the body position. */ + /* 2 lines overlap */ + + if( hidden > 0 && total > 2) + body = (ULONG) ((vis - 2) * MAXBODY) / (total - 2); + else + body = MAXBODY; + + if( hidden > 0 ) + pot = (ULONG) (top * MAXPOT) / hidden; + else + pot = 0; + + mflags = AUTOKNOB|FREEVERT; +#ifdef INTUI_NEW_LOOK + if( IntuitionBase->LibNode.lib_Version >= 37 ) + { + mflags |= PROPNEWLOOK; + } +#endif + + NewModifyProp( gad, win, NULL, + mflags, 0, pot, MAXBODY, body, 1 ); +}