home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d502 / cells.lha / CELLS / CELLSSource.lzh / cList.c < prev    next >
C/C++ Source or Header  |  1991-04-20  |  22KB  |  791 lines

  1. /*
  2.  *  CELLS       An Implementation of the WireWorld cellular automata
  3.  *              as described in Scientific American, Jan 1990.
  4.  *
  5.  *              Copyright 1990 by Davide P. Cervone.
  6.  *  You may use this code, provided this copyright notice is kept intact.
  7.  *  See the CELLS.HELP file for complete information on distribution conditions.
  8.  */
  9.  
  10. /*
  11.  *  File:  cList.c              Handles name lists for requesters
  12.  *                              (still pretty kludgy, need work)
  13.  */
  14.  
  15.  
  16. #include "Cells.h"
  17. #include "cRequest.h"
  18. #include "cBoxes.h"
  19.  
  20.  
  21. #define SLIDERINFO      ((struct PropInfo *)(theList->Slider->SpecialInfo))
  22.  
  23. static ULONG OldSecs,OldMics;       /* timers for double click */
  24. static LISTINFO *ActiveList;        /* list with active slider */
  25.  
  26.  
  27. /*
  28.  *  FindListPos()
  29.  *
  30.  *  Assumes list is sorted (in reverse order)
  31.  *  Look through the list until a match is found or until we have gone past
  32.  *  the items position in the list.  Set PrevItem to point to the list item
  33.  *  that should preceed the specified item.  Set ItemPtr to the ListItem pointer
  34.  *  that needs to point to the specified item (it could be the head-of-list
  35.  *  pointer iteself).
  36.  */
  37.  
  38. void FindListPos(Name,FirstItem,PrevItem,ItemPtr)
  39. char *Name;
  40. LISTITEM **FirstItem;
  41. LISTITEM **PrevItem;
  42. LISTITEM ***ItemPtr;
  43. {
  44.    LISTITEM *theItem = *FirstItem;
  45.    int NotFound = TRUE;
  46.  
  47.    *PrevItem = NULL;
  48.    *ItemPtr = FirstItem;
  49.    while (theItem && NotFound)
  50.    {
  51.       if (stricmp(Name,theItem->Name) < 0)
  52.       {
  53.          *PrevItem = theItem;
  54.          *ItemPtr = &(theItem->Next);
  55.          theItem = theItem->Next;
  56.       } else {
  57.          NotFound = FALSE;
  58.          if (strcmp(Name,theItem->Name) == 0) *ItemPtr = NULL;
  59.       }
  60.    }
  61. }
  62.  
  63.  
  64. /*
  65.  *  InitList()
  66.  *
  67.  *  Clear the list and select counters
  68.  *  If there are items in the list,
  69.  *    count the first item
  70.  *    check if it is to be selected
  71.  *    While there are items following the current one
  72.  *      go on to the following item
  73.  *      count the new item
  74.  *      if the selected item has been seen, count its position, too
  75.  *      if the current item is to be selected, do so
  76.  *  Set the list to point to the last (first) item in the list (the list is
  77.  *  stored as an inverted list, so this item is really the first item)
  78.  *  If no item was selected
  79.  *    set the list to point to the top if the list and mark no selection
  80.  *  otherwise
  81.  *    set the top item to the selected item, and mark the selected item
  82.  *  return the item at the top of the list
  83.  */
  84.  
  85. LISTITEM *InitList(theList,theItem,SelectItem)
  86. LISTINFO *theList;
  87. LISTITEM *theItem,*SelectItem;
  88. {
  89.    theList->ListLen = 0;
  90.    theList->SelectedItem = LI_NOSELECT;
  91.    if (theItem)
  92.    {
  93.       theList->ListLen++;
  94.       if (theItem == SelectItem) theList->SelectedItem = 0;
  95.       while (theItem->Next)
  96.       {
  97.          theItem = theItem->Next;
  98.          theList->ListLen++;
  99.          if (theList->SelectedItem != LI_NOSELECT) theList->SelectedItem++;
  100.          if (theItem == SelectItem) theList->SelectedItem = 0;
  101.       }
  102.    }
  103.    theList->Item = theItem;
  104.    if (theList->SelectedItem == LI_NOSELECT)
  105.    {
  106.       theList->TopItem = 0;
  107.       theList->ItemSelect = NULL;
  108.    } else {
  109.       theList->TopItem = theList->SelectedItem;
  110.       theList->SelectedItem = 0;
  111.       theItem = SelectItem;
  112.       theList->ItemSelect = SelectItem;
  113.    }
  114.    return(theItem);
  115. }
  116.  
  117.  
  118. /*
  119.  *  SetText()
  120.  *
  121.  *  Set the IntuiTexts pen and top edge correctly for its position
  122.  *  If the text is not past the end of the list
  123.  *    copy the items name into the text and pad it with spaces if necessary
  124.  *  otherwise
  125.  *    fill the text string with spaces (these wipe out any old text that
  126.  *    may have been showing on the screen previously, the alternative would
  127.  *    be to clear the entire list gadget area each time, which would make
  128.  *    the gadget "flash" more).
  129.  */
  130.  
  131. static void SetText(theList,theText,theItem,i)
  132. LISTINFO *theList;
  133. struct IntuiText *theText;
  134. LISTITEM *theItem;
  135. short i;
  136. {
  137.    theText->BackPen = FOREGROUND;
  138.    theText->TopEdge = LNAMEH * i + 2;
  139.    if (theItem)
  140.    {
  141.       strncpy(theText->IText,theItem->Name,theList->Width);
  142.       i = theItem->NameLen; if (i == 0) i = strlen(theText->IText);
  143.       while (i < theList->Width) theText->IText[i++] = ' ';
  144.    } else {
  145.       for (i=0; i<theList->Width; i++) theText->IText[i] = ' ';
  146.    }
  147.    theText->IText[theList->Width] = 0;
  148. }
  149.  
  150.  
  151. /*
  152.  *  SetTextPositions()
  153.  *
  154.  *  Set the top edges of the IntuiTexts according to their positions in the
  155.  *  list (when the list scrolls, the texts are not copied from one to another,
  156.  *  rather, the screen positions of the texts are changed).  TopText holds the
  157.  *  array index of the text currently at the top - the list wraps around to the
  158.  *  top of the array when it falls off the bottom.
  159.  */
  160.  
  161. static void SetTextPositions(theList)
  162. LISTINFO *theList;
  163. {
  164.    struct IntuiText *theText = theList->IText;
  165.    short i,j;
  166.    
  167.    j = theList->TopText;
  168.    for (i=0; i<theList->Height; i++)
  169.    {
  170.       theText[j].TopEdge = LNAMEH * i + 2;
  171.       if (j < theList->Height - 1) j++; else j = 0;
  172.    }
  173. }
  174.  
  175.  
  176. /*
  177.  *  SetListNames()
  178.  *
  179.  *  Set the top item in the list to the specified item
  180.  *  Reset the text array to start at the beginning of the array
  181.  *  For each text in the array
  182.  *    set the text string to the specified item name and position
  183.  *    relink the text pointers (in case they have changed)
  184.  *    If there are more items in the list, go on to the next one
  185.  */
  186.  
  187. static void SetListNames(theList,theItem)
  188. LISTINFO *theList;
  189. LISTITEM *theItem;
  190. {
  191.    struct IntuiText *theText = theList->IText;
  192.    short i;
  193.    
  194.    theList->ItemTop = theItem;
  195.    theList->TopText = 0;
  196.    for (i=0; i<theList->Height; i++,theText++)
  197.    {
  198.       SetText(theList,theText,theItem,i);
  199.       if (i < theList->Height-1)
  200.          theText->NextText = &(theList->IText[i+1]);
  201.         else
  202.          theText->NextText = NULL;
  203.       if (theItem) theItem = theItem->Prev;
  204.    }
  205. }
  206.  
  207.  
  208. /*
  209.  *  UpdateListSelect()
  210.  *
  211.  *  Find the position of the selected text in the text array
  212.  *  If the selected item has changed and the new selected item is visable
  213.  *    put the clear-selection image to appear behind the old selected item
  214.  *    (i.e., so that it clears the previous selection, if any)
  215.  *  otherwise
  216.  *    put the clear-selection image so that it won't appear at all (kludge)
  217.  *  If the selection is visible
  218.  *    put the selection image so that it will appear behind the selected text
  219.  *    link the selection image so that it appears
  220.  *    set the background pen of the selected text to the selection color
  221.  *  otherwise
  222.  *    unlink the selection image so that it won't appear
  223.  */
  224.  
  225. static void UpdateListSelect(theList,OldSelect)
  226. LISTINFO *theList;
  227. UWORD OldSelect;
  228. {
  229.    UWORD Select = theList->SelectedItem;
  230.    short SelectText = (Select+theList->TopText) % theList->Height;
  231.  
  232.    if (Select != OldSelect && OldSelect >= 0 && OldSelect < theList->Height)
  233.       theList->Image[0].TopEdge = LNAMEH * OldSelect + 1;
  234.      else 
  235.       theList->Image[0].TopEdge = -(theList->Gadget->TopEdge + LNAMEH);
  236.  
  237.    if (Select >= 0 && Select < theList->Height)
  238.    {
  239.       theList->Image[1].TopEdge = LNAMEH * Select + 1;
  240.       theList->Image[0].NextImage = &(theList->Image[1]);
  241.       theList->IText[SelectText].BackPen = TEXTSELECT;
  242.    } else {
  243.       theList->Image[0].NextImage = NULL;
  244.    }
  245. }
  246.  
  247.  
  248. /*
  249.  *  UnsetListSelect()
  250.  *
  251.  *  If the selected item follows the top item in the list
  252.  *    if the selected item is visable, then reset its text pen color
  253.  *    set the list's select item to a non-existant position
  254.  *    if we are refreshing the list, do so
  255.  */
  256.  
  257. void UnsetListSelect(theList,Refresh)
  258. LISTINFO *theList;
  259. int Refresh;
  260. {
  261.    struct IntuiText *theText = theList->IText;
  262.    int Select = theList->SelectedItem;
  263.    int UnSelect = -(theList->TopItem + 1);
  264.    int i = (theList->TopText + Select) % theList->Height;
  265.    
  266.    if (theList->SelectedItem > UnSelect)
  267.    {
  268.       if (Select >= 0 && Select < theList->Height)
  269.          theText[i].BackPen = FOREGROUND;
  270.       theList->SelectedItem = UnSelect;
  271.       if (Refresh)
  272.       {
  273.          theList->ItemSelect = NULL;
  274.          UpdateListSelect(theList,Select);
  275.          RefreshGList(theList->Gadget,myWindow,theList->Request,1);
  276.       }
  277.    }
  278. }
  279.  
  280.  
  281. /*
  282.  *  UpdateListSlider()
  283.  *
  284.  *  Calculate the new body and pot values according to the current list
  285.  *  position and length.
  286.  *  If the list's requester is active,
  287.  *    if the slider's position has changed, update the gadget
  288.  *  otherwise
  289.  *    simply set the values of the slider
  290.  */
  291.  
  292. static void UpdateListSlider(theList)
  293. LISTINFO *theList;
  294. {
  295.    int Pot,Body;
  296.  
  297.    if (theList->ListLen > theList->Height)
  298.    {
  299.       Body = 0xFFFF * theList->Height / theList->ListLen;
  300.       Pot  = 0xFFFF * theList->TopItem / (theList->ListLen - theList->Height);
  301.    } else {
  302.       Body = 0xFFFF;
  303.       Pot  = 0;
  304.    }
  305.  
  306.    if (ActiveRequest)
  307.    {
  308.       if (Body != SLIDERINFO->VertBody || Pot != SLIDERINFO->VertPot)
  309.           NewModifyProp(theList->Slider,myWindow,theList->Request,
  310.              SLIDERINFO->Flags,0,Pot,0,Body,1);
  311.    } else {
  312.       SLIDERINFO->VertBody = Body;
  313.       SLIDERINFO->VertPot  = Pot;
  314.    }
  315. }
  316.  
  317.  
  318. /*
  319.  *  SetList()
  320.  *
  321.  *  Initialize the list info structures
  322.  *  If the current position of the list (due to putting selected item at the
  323.  *  top) puts the end of the list within the visable part of the list, 
  324.  *  move the top of the list so that the full list area is used.
  325.  *  Set up the list text names
  326.  *  set up the select images
  327.  *  refresh the list, if necessary
  328.  *  update the lider positions
  329.  */
  330.  
  331. void SetList(theGadget,theItem,SelectItem)
  332. struct Gadget *theGadget;
  333. LISTITEM *theItem;
  334. LISTITEM *SelectItem;
  335. {
  336.    LISTINFO *theList = (LISTINFO *)theGadget->UserData;
  337.  
  338.    theItem = InitList(theList,theItem,SelectItem);
  339.    while (theList->TopItem + theList->Height > theList->ListLen &&
  340.       theList->TopItem && theItem->Next)
  341.    {
  342.       theList->TopItem--; theList->SelectedItem++;
  343.       theItem = theItem->Next;
  344.    }
  345.    SetListNames(theList,theItem);
  346.    UpdateListSelect(theList,LI_NOSELECT);
  347.    if (ActiveRequest) RefreshGList(theGadget,myWindow,theList->Request,1);
  348.    UpdateListSlider(theList);
  349. }
  350.  
  351.  
  352. /*
  353.  *  DoListScrollUp()
  354.  *
  355.  *  While the arrow gadger is still pressed
  356.  *    if there are more items to scroll
  357.  *      remove the select images and text pens
  358.  *      move the top of the list
  359.  *      calculate the new top of list
  360.  *      set the text of the new item in the list
  361.  *      set up the new top item pointer and text array index
  362.  *      set the IntuiText positions to their new positions
  363.  *      put back the select images
  364.  *      refresh the list gadget
  365.  *      update the slider
  366.  */
  367.  
  368. void DoListScrollUp(theList,theGadget,theMessage)
  369. LISTINFO *theList;
  370. struct Gadget *theGadget;
  371. struct IntuiMessage *theMessage;
  372. {
  373.    struct IntuiText *theText = theList->IText;
  374.    short Top;
  375.    short OldSelect;
  376.  
  377.    while (theGadget->Flags & SELECTED)
  378.    {
  379.       if (theList->TopItem)
  380.       {
  381.          OldSelect = theList->SelectedItem;
  382.          UnsetListSelect(theList,FALSE);
  383.          theList->TopItem--; theList->SelectedItem = OldSelect+1;
  384.          if (theList->TopText)
  385.             Top = theList->TopText - 1; else Top = theList->Height - 1;
  386.          SetText(theList,&(theText[Top]),theList->ItemTop->Next,0);
  387.          theList->ItemTop = theList->ItemTop->Next;
  388.          theList->TopText = Top;
  389.          SetTextPositions(theList);
  390.          UpdateListSelect(theList,OldSelect);
  391.          RefreshGList(theList->Gadget,myWindow,theList->Request,1);
  392.          UpdateListSlider(theList);
  393.       }
  394.    }
  395. }
  396.  
  397.  
  398. /*
  399.  *  DoListScrollDown()
  400.  *
  401.  *  Find the bottom of the visable area of the list
  402.  *  While the arrow gadger is still pressed
  403.  *    if there are more items to scroll
  404.  *      remove the select images and text pens
  405.  *      move the top of the list
  406.  *      set the text of the new item in the list
  407.  *      set up the new top item pointer and text array index
  408.  *      set the IntuiText positions to their new positions
  409.  *      put back the select images
  410.  *      refresh the list gadget
  411.  *      update the slider
  412.  */
  413.  
  414. void DoListScrollDown(theList,theGadget,theMessage)
  415. LISTINFO *theList;
  416. struct Gadget *theGadget;
  417. struct IntuiMessage *theMessage;
  418. {
  419.    struct IntuiText *theText = theList->IText;
  420.    LISTITEM *ItemBot = theList->ItemTop;
  421.    int count = 0;
  422.    short OldSelect = theList->SelectedItem;
  423.  
  424.    while (ItemBot && count < theList->Height)
  425.    {
  426.       ItemBot = ItemBot->Prev;
  427.       count++;
  428.    }
  429.  
  430.    while (theGadget->Flags & SELECTED)
  431.    {
  432.       if (theList->TopItem + theList->Height < theList->ListLen)
  433.       {
  434.          OldSelect = theList->SelectedItem;
  435.          UnsetListSelect(theList,FALSE);
  436.          theList->TopItem++; theList->SelectedItem = OldSelect - 1;
  437.          SetText(theList,&(theText[theList->TopText]),ItemBot,0);
  438.          theList->ItemTop = theList->ItemTop->Prev; ItemBot = ItemBot->Prev;
  439.          if (theList->TopText < theList->Height - 1)
  440.             theList->TopText++; else theList->TopText = 0;
  441.          SetTextPositions(theList);
  442.          UpdateListSelect(theList,OldSelect);
  443.          RefreshGList(theList->Gadget,myWindow,theList->Request,1);
  444.          UpdateListSlider(theList);
  445.       }
  446.    }
  447. }
  448.  
  449.  
  450. /*
  451.  *  DoListSlider()
  452.  *
  453.  *  Calculate new list position according to current slider settings
  454.  *  If the position has changed
  455.  *    record the old selected item
  456.  *    set the new top item
  457.  *    set the list name to the new position in the list
  458.  *    update the selected image positions
  459.  *    refresh the list gadget
  460.  */
  461.  
  462. void DoListSlider(theList)
  463. LISTINFO *theList;
  464. {
  465.    LISTITEM *theItem = theList->Item;
  466.    short Top;
  467.    short OldSelect;
  468.    short Size = theList->ListLen - theList->Height;
  469.    
  470.    if (Size < 0) Size = 0; 
  471.    Top = Size * SLIDERINFO->VertPot / 0xFFFF;
  472.    if (Top > Size) Top = Size; else if (Top < 0) Top = 0;
  473.  
  474.    if (Top != theList->TopItem)
  475.    {
  476.       OldSelect = theList->SelectedItem;
  477.       theList->SelectedItem += theList->TopItem - Top;
  478.       theList->TopItem = Top;
  479.       while (Top-- && theItem) theItem = theItem->Prev;
  480.       SetListNames(theList,theItem);
  481.       UpdateListSelect(theList,OldSelect);
  482.       RefreshGList(theList->Gadget,myWindow,theList->Request,1);
  483.    }
  484. }
  485.  
  486.  
  487. /*
  488.  *  StartListSlider()
  489.  *
  490.  *  If the slider's knob was hit, move to the new location, then start
  491.  *  mouse moves and record the list whose slider is active.
  492.  */
  493.  
  494. void StartListSlider(theList)
  495. LISTINFO *theList;
  496. {
  497.    if (SLIDERINFO->Flags & KNOBHIT)
  498.    {
  499.       DoListSlider(theList);
  500.       StartMouseMoves();
  501.       ActiveList = theList;
  502.    }
  503. }
  504.  
  505.  
  506. /*
  507.  *  EndListSlider()
  508.  *
  509.  *  Stop getting mouse moves and clear the active list, and show the new
  510.  *  list position.
  511.  */
  512.  
  513. void EndListSlider(theList)
  514. LISTINFO *theList;
  515. {
  516.    StopMouseMoves(); ActiveList = NULL;
  517.    DoListSlider(theList);
  518. }
  519.  
  520.  
  521. /*
  522.  *  DoListMouse()
  523.  *
  524.  *  If a list slider is active, calculate the new list position according
  525.  *  to the sliders new position.
  526.  */
  527.  
  528. void DoListMouse(MouseX,MouseY,theMessage)
  529. short MouseX,MouseY;
  530. struct IntuiMessage *theMessage;
  531. {
  532.    if (ActiveList) DoListSlider(ActiveList);
  533. }
  534.  
  535.  
  536. /*
  537.  *  DoListHit()
  538.  *
  539.  *  Find the index of the list item that was hit
  540.  *  If the position is within the list (i.e., not past then end of the list)
  541.  *    Find the item within the list (starting from the top of the visable list)
  542.  *    If the item was not the selected one,
  543.  *      remove the selected image and pen colors
  544.  *      set the new selected item
  545.  *      refresh the list gadget
  546.  *      set the selected item pointer
  547.  *      if the list has a name gadget and we have selected a new item
  548.  *        copy the item's name into the name gadget (NOFIRST is a kludge
  549.  *        to keep from copying a directories leading '/')
  550.  *        refresh the name
  551.  *        set the double-click counters
  552.  *        return no item selected (wait for a double-click)
  553.  *      (otherwise with no name gadget, return the selected item)
  554.  *    otherwise (the item was already selected)
  555.  *      if the list has a name gadget
  556.  *        if this is not a double-click,
  557.  *          start a new double-click clock count, and return no item
  558.  *      otherwise
  559.  *        don't return the already-selected item
  560.  *  Otherwise (clicked past the end of the list)
  561.  *    clear the selection and the gadget name string
  562.  */
  563.  
  564. LISTITEM *DoListHit(theList,theMessage)
  565. LISTINFO *theList;
  566. struct IntuiMessage *theMessage;
  567. {
  568.    short y,i;
  569.    short OldSelect = theList->SelectedItem;
  570.    LISTITEM *theItem = NULL;
  571.    
  572.    y = theMessage->MouseY - theList->Gadget->TopEdge -
  573.        theList->Request->er_Request.TopEdge - 1;
  574.    i = y / LNAMEH; y = i;
  575.    if (theList->TopItem + i < theList->ListLen)
  576.    {
  577.       theItem = theList->ItemTop;
  578.       while (y-- && theItem) theItem = theItem->Prev;
  579.  
  580.       if (i != OldSelect)
  581.       {
  582.          UnsetListSelect(theList,FALSE);
  583.          theList->SelectedItem = i;
  584.          UpdateListSelect(theList,OldSelect);
  585.          RefreshGList(theList->Gadget,myWindow,theList->Request,1);
  586.          theList->ItemSelect = theItem;
  587.          if (theList->Name && theItem)
  588.          {
  589.             if (theItem->Flags & LI_NOFIRST)
  590.                SetStringInfo(theList->Name,theItem->Name+1);
  591.               else
  592.                SetStringInfo(theList->Name,theItem->Name);
  593.             RefreshGList(theList->Name,myWindow,theList->Request,1);
  594.             OldSecs = theMessage->Seconds;
  595.             OldMics = theMessage->Micros;
  596.             theItem = NULL;
  597.          }
  598.       } else {
  599.          if (theList->Name)
  600.          {
  601.             if (DoubleClick(OldSecs,OldMics,
  602.                theMessage->Seconds,theMessage->Micros) == FALSE)
  603.             {
  604.                OldSecs = theMessage->Seconds;
  605.                OldMics = theMessage->Micros;
  606.                theItem = NULL;
  607.             }
  608.          } else {
  609.             theItem = NULL;
  610.          }
  611.       }
  612.    } else if (theList->Name) {
  613.       UnsetListSelect(theList,TRUE);
  614.       SetStringInfo(theList->Name,"");
  615.       RefreshGList(theList->Name,myWindow,theList->Request,1);
  616.    }
  617.    return(theItem);
  618. }
  619.  
  620.  
  621. /*
  622.  *  SelectedListItem()
  623.  *
  624.  *  Return the list's selected item (hold-over from previous approach to
  625.  *  selections)
  626.  */
  627.  
  628. LISTITEM *SelectedListItem(theList)
  629. LISTINFO *theList;
  630. {
  631.    return(theList->ItemSelect);
  632. }
  633.  
  634.  
  635. /*
  636.  *  ActivateName()
  637.  *
  638.  *  If a name gadget is hit, clear any selection in its list.
  639.  *  Attempt to activate the name gadget.  (There is a bug in Intuition
  640.  *  that makes this fail if RETURN was pressed within the name gadget
  641.  *  itself)
  642.  */
  643.  
  644. void ActivateName(theList)
  645. LISTINFO *theList;
  646. {
  647.    if (theList->Name)
  648.    {
  649.       UnsetListSelect(theList,TRUE);
  650.       ActivateGadget(theList->Name,myWindow,theList->Request);
  651.    }
  652. }
  653.  
  654.  
  655. /*
  656.  *  ItemBeforeTop()
  657.  *
  658.  *  returns TRUE if the specified item preceeds the top item in the list.
  659.  */
  660.  
  661. int ItemBeforeTop(theItem,theTop)
  662. LISTITEM *theItem,*theTop;
  663. {
  664.    while (theItem != theTop && theItem) theItem = theItem->Prev;
  665.    return(theItem == theTop);
  666. }
  667.  
  668.  
  669. /*
  670.  *  RemoveListSelect()
  671.  *
  672.  *  If the list has a name gadget
  673.  *    clear the name string and refresh
  674.  *  otherwise if the item is the selected item
  675.  *    if there is an item following the selected one, select it,
  676.  *    otherwise set the selected item to the previous one
  677.  *  otherwise
  678.  *   clear the selection
  679.  */
  680.  
  681. static void RemoveListSelect(theList,theItem)
  682. LISTINFO *theList;
  683. LISTITEM *theItem;
  684. {
  685.    if (theList->Name)
  686.    {
  687.       SetStringInfo(theList->Name,"");
  688.       RefreshGList(theList->Name,myWindow,theList->Request,1);
  689.    } else if (theItem == theList->ItemSelect) {
  690.       if (theItem->Prev)
  691.       {
  692.          theList->ItemSelect = theItem->Prev;
  693.       } else {
  694.          theList->ItemSelect = theItem->Next;
  695.          theList->SelectedItem--;
  696.       }
  697.    } else {
  698.       theList->ItemSelect = NULL;
  699.       UnsetListSelect(theList,FALSE); 
  700.    }
  701. }
  702.  
  703.  
  704. /*
  705.  *  RemoveListItem()
  706.  *
  707.  *  Reduce the list length, and unselect the items
  708.  *  If the list head is the removed item, start the list at the next item
  709.  *  If the item is the top one,
  710.  *    If there is an item following it, make that the top
  711.  *    otherwise, make the top the previous item in the list (if any)
  712.  *  otherwise if the deleted item is before the top item
  713.  *    decrement the list position of the top item
  714.  *  if the deletion has moved the bottom of the list into the viable area
  715.  *    move the list down, if possible, to use all of the list
  716.  *  reset the list names and refresh the list
  717.  *  update the slider
  718.  *  return the currently selected item
  719.  */
  720.  
  721. LISTITEM *RemoveListItem(theList,theItem)
  722. LISTINFO *theList;
  723. LISTITEM *theItem;
  724. {
  725.    short OldSelect = theList->SelectedItem;
  726.    LISTITEM *ItemTop = theList->ItemTop;
  727.  
  728.    theList->ListLen--;
  729.    RemoveListSelect(theList,theItem);
  730.    if (theItem == theList->Item) theList->Item = theItem->Prev;
  731.    if (theItem == ItemTop)
  732.    {
  733.       if (ItemTop->Prev)
  734.       {
  735.          ItemTop = ItemTop->Prev;
  736.       } else {
  737.          ItemTop = ItemTop->Next;
  738.          if (theList->TopItem) theList->TopItem--;
  739.       }
  740.    } else if (ItemBeforeTop(theItem,ItemTop)) {
  741.       theList->TopItem--;
  742.    }
  743.    if (theList->TopItem && theList->TopItem+theList->Height > theList->ListLen)
  744.    {
  745.       theList->TopItem--; theList->SelectedItem++;
  746.       ItemTop = ItemTop->Next;
  747.    }
  748.    SetListNames(theList,ItemTop);
  749.    UpdateListSelect(theList,OldSelect);
  750.    RefreshGList(theList->Gadget,myWindow,theList->Request,1);
  751.    UpdateListSlider(theList);
  752.    return(theList->ItemSelect);
  753. }
  754.  
  755.  
  756. /*
  757.  *  DoListPageDown()
  758.  *
  759.  *  If there are more items to show
  760.  *    record the old selected position
  761.  *    calculate how many items are left to scroll (clip off at the list height)
  762.  *    scroll the list by the specified amount
  763.  *    set the list to show the new position
  764.  *    put the selection images in place
  765.  *    refresh the list gadget
  766.  *    update the slider to the new position
  767.  */
  768.  
  769. void DoListPageDown(theList)
  770. LISTINFO *theList;
  771. {
  772.    short i,OldSelect;
  773.    LISTITEM *theItem = theList->ItemTop;
  774.  
  775.    if (theList->TopItem + theList->Height < theList->ListLen)
  776.    {
  777.       OldSelect = theList->SelectedItem;
  778.       i = theList->ListLen - theList->TopItem - theList->Height;
  779.       if (i > theList->Height) i = theList->Height;
  780.       while (i--)
  781.       {
  782.          theItem = theItem->Prev;
  783.          theList->TopItem++; theList->SelectedItem--;
  784.       }
  785.       SetListNames(theList,theItem);
  786.       UpdateListSelect(theList,OldSelect);
  787.       RefreshGList(theList->Gadget,myWindow,theList->Request,1);
  788.       UpdateListSlider(theList);
  789.    }
  790. }
  791.