home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / PRMASTR3.ZIP / IO.PAS next >
Encoding:
Pascal/Delphi Source File  |  1990-01-22  |  23.0 KB  |  950 lines

  1. {$F+}
  2. {
  3.    "Created using Turbo Pascal, copyright (c) Borland International
  4.    1987, 1988."      Turbo Pascal 5.5
  5. }
  6. UNIT IO;
  7.  
  8. INTERFACE
  9.  
  10. USES DOS,CRT;
  11.  
  12. CONST
  13.   ScreenX = 80;
  14.   ScreenY = 25;
  15.   VideoBufferSize = ScreenX*ScreenY;  { E.g., 25 X 80 = 2000 words }
  16.  
  17. TYPE
  18.   wrdptr        = ^word;
  19.   window_action = Procedure;
  20.   menuitemptr   = ^menuitem;
  21.   Menuitem      = record
  22.                     itemlabel      : string;
  23.                     proc           : window_action;
  24.                     prev,
  25.                     next           : menuitemptr;
  26.                   end;
  27.  
  28.   windaptr = ^winda;
  29.   winda    = object
  30.                x1,y1,x2,y2    : integer;
  31.                oldwindowmin,
  32.                oldwindowmax   : word;
  33.                oldx,oldy      : byte;
  34.                screenvar      : pointer;
  35.                title          : string;
  36.                ta,fg,bg       : word;
  37.                constructor init(a,b,c,d:integer;t:string;a1,a2,a3:word);
  38.                destructor done;virtual;
  39.                Procedure storescreen;
  40.                Procedure restorescreen;
  41.              end;
  42.  
  43.   popptr   = ^pop;
  44.   pop      = object(winda)
  45.                msg:string;
  46.                constructor init(a,b,c,d:integer;t,s:string;a1,a2,a3:word);
  47.                Procedure showit;virtual;
  48.                destructor done;virtual;
  49.              end;
  50.  
  51.   popfetchptr = ^popfetch;
  52.   popfetch    = object(winda)
  53.                  msg:string;
  54.                  constructor init(a,b,c,d:integer;t,s:string;a1,a2,a3:word);
  55.                  Function fetchit:string;virtual;
  56.                  destructor done;virtual;
  57.                 end;
  58.  
  59.   menuptr2    = ^menu;
  60.   menu        = object(winda)
  61.                   current,item   : menuitemptr;
  62.                   maxwidth,
  63.                   itemcount      : integer;
  64.                   constructor init(a,b,c,d:integer;t:string;a1,a2,a3:word);
  65.                   destructor done;virtual;
  66.                   Procedure add2menu(labelname:string;procname:window_action);
  67.                   Procedure nukethelist;
  68.                   Procedure pickmenu;virtual;
  69.                 end;
  70. Var
  71.   alert,
  72.   stimulus,
  73.   quit,
  74.   up1level           : boolean;
  75.   global_choice      : integer;
  76.   XSave,
  77.   YSave              : Integer;
  78.   SavePtr,
  79.   VideoPtr           : wrdptr;
  80.   VideoSeg           : Word;
  81.   left_mkey_pressed,
  82.   center_mkey_pressed, {works for 3 button logitech.....}
  83.   right_mkey_pressed,
  84.   islogitech,
  85.   mouse_exists,
  86.   mkeypressed        : boolean;
  87.   numkeys,
  88.   whichmkey,
  89.   mousex,
  90.   mousey             :integer;
  91.  
  92. Procedure whooop(low,high,increment,del:integer);
  93. Function  MONOCHROME : Boolean;
  94. Procedure CURSORON;
  95. Procedure CURSOROFF;
  96. Procedure WAITFORKEY;
  97.  
  98. Procedure Writeat(a,c,r:integer;s:string);
  99. Procedure waitforaction;
  100. Procedure mouseinit;
  101. Procedure showmouse;
  102. Procedure unshowmouse;
  103. Procedure mouseinfo;
  104. Procedure putatxy(x,y:integer);
  105. Procedure mouse_window(x1,y1,x2,y2:integer);
  106. Procedure id;
  107. Procedure setsensitivity(horizon,vertic,doub:integer);
  108. Procedure getsensitivity(Var horiz,vert,double:integer);
  109. Function HeapFunc(size:word):integer;
  110.  
  111. IMPLEMENTATION
  112.  
  113. var
  114.   startscanline,
  115.   endscanline     : byte;
  116.  
  117. Function HeapFunc(size:word):integer;   {out of memory...}
  118. begin
  119.   window(1,1,80,25);
  120.   clrscr;
  121.   writeln('You are out of memory.');
  122.   writeln('Program will halt.');
  123.   halt;
  124.   heapfunc:=1;
  125. end;
  126.  
  127. Procedure whooop(low,high,increment,del:integer);
  128. Var q:integer;
  129. begin
  130.   q:=low;
  131.   while q < high+1 do
  132.     begin
  133.       sound(q);
  134.       delay(del);
  135.       q:=q+increment;
  136.     end;
  137.   nosound;
  138. end;
  139.  
  140. {*********************************************************************}
  141. { This function will be true if the video adapter is a monochrom video}
  142. { adapter and false if any other adapter is in place.  This is used   }
  143. { by other functions to determine where video ram is.                 }
  144.  
  145. function monochrome : Boolean;
  146. var
  147.   Regs : Registers;
  148. begin
  149.   intr($11,Regs);                   {get equipment status word}
  150.   if (Regs.AX AND $0030) = $30 then {are bit 4-5 = 11?}
  151.     monochrome := True
  152.   else
  153.     monochrome := False;
  154. end;
  155.  
  156. {*********************************************************************}
  157. { This procedure will turn the cursor on (after a call to CURSOROFF)  }
  158.  
  159. procedure cursoron;
  160. var regs   : registers;
  161. begin
  162.   regs.ax:=$0100;
  163.   regs.ch:=startscanline;
  164.   regs.cl:=endscanline;
  165.   intr($10,regs);                  {set cursor scan lines}
  166. end;
  167.  
  168.  
  169. {*********************************************************************}
  170. { This procedure will turn the cursor off.                            }
  171.  
  172. procedure cursoroff;
  173. VAR Regs : Registers;
  174.     active_page:byte;
  175. begin
  176.  regs.ah:=$0F;          {we need current video page}
  177.  intr($10,regs);
  178.  active_page:=regs.bh;
  179.  
  180.  regs.ah:=$03;          {determine cursor scan lines and save for later}
  181.  regs.bh:=active_page;
  182.  intr($10,regs);
  183.  startscanline:=regs.ch;
  184.  endscanline:=regs.cl;
  185.  
  186.  regs.ah:=$01;          {Turn cursor off}
  187.  regs.ch:=$20;
  188.  intr($10,regs);
  189. end;
  190.  
  191.  
  192. {*********************************************************************}
  193. { This Procedure will wait until a key is pressed, with no cursor on  }
  194. { the screen.                                                         }
  195.  
  196.   Procedure WAITFORKEY;
  197.   Var Dummy   : Char;
  198.   BEGIN
  199.     gotoxy(1,1);
  200.     REPEAT
  201.       {nothing}
  202.     UNTIL KeyPressed;
  203.     Dummy := ReadKey;
  204.     IF Dummy = Chr(0) THEN
  205.        Dummy := ReadKey;
  206.   END;
  207.  
  208. {*********************************************************************}
  209. { This is a replacement write Procedure and is window relative        }
  210. { a           = attribute to use for string                           }
  211. { c           = column to begin writing                               }
  212. { r           = row of begin writing                                  }
  213. { s           = string to write                                       }
  214. { This procedure may have snow, but it does NOT have the stupid scroll}
  215. { when you write to the last character of the last line of the window.}
  216.  
  217. Procedure Writeat(a,c,r:integer;s:string);
  218. type artype = array[1..videobuffersize] of word;
  219. Var d:word;
  220.     x,z:integer;
  221.     l:integer;
  222. begin
  223.    l:=length(s);
  224.    if monochrome then
  225.       d:= $B000
  226.    else
  227.       d:=$B800;
  228.    z:=1;
  229.    r:=r+hi(windmin);
  230.    if r > screeny then
  231.       exit;
  232.    c:=c+lo(windmin);
  233.    if (c+1-1) > 80 then
  234.       exit;
  235.    for x:=c to c+l-1 do {horizontal column}
  236.      begin
  237.        memw[d:word((r-1)*160+(2*(x-1)))]:=word(256*a+byte(s[z]));
  238.        z:=z+1;
  239.      end;
  240. end;
  241.  
  242. Procedure mouseinfo;
  243. Var regs:registers;
  244. begin
  245.   regs.ax:=3;
  246.   intr($33,regs);
  247.   if regs.bx = 0 then
  248.      mkeypressed:=false
  249.   else
  250.      begin
  251.         mkeypressed:=true;
  252.         whichmkey:=integer(regs.bx);
  253.         left_mkey_pressed:=false;
  254.         center_mkey_pressed:=false;
  255.         right_mkey_pressed:=false;
  256.         case whichmkey of
  257.           1 : left_mkey_pressed := true;
  258.           2 : right_mkey_pressed := true;
  259.           3 : begin
  260.                 left_mkey_pressed:=true;
  261.                 right_mkey_pressed:=true;
  262.               end;
  263.           4 : center_mkey_pressed := true;
  264.         end;
  265.  
  266.         regs.ax:=3;
  267.         repeat
  268.           intr($33,regs)
  269.         until regs.bx = 0;
  270.  
  271.      end;
  272.   mousex:=regs.cx;
  273.   mousey:=regs.dx;
  274. end;
  275.  
  276.   Procedure MOUSE_WAITFORKEY;
  277.   Var Dummy   : Char;
  278.   BEGIN
  279.     REPEAT
  280.       mouseinfo
  281.     UNTIL (KeyPressed or mkeypressed);
  282.     if keypressed then
  283.       begin
  284.        Dummy := ReadKey;
  285.        IF Dummy = Chr(0) THEN
  286.           Dummy := ReadKey;
  287.       end;
  288.   END;
  289.  
  290.  
  291.   Procedure waitforaction;
  292.   begin
  293.     if mouse_exists then
  294.        mouse_waitforkey
  295.     else
  296.        waitforkey;
  297.   end;
  298.  
  299. Procedure mouseinit;
  300. Var regs:registers;
  301.  
  302.    Function logi_mouse:boolean;
  303.    type
  304.      signature = array[0..13] of char;
  305.      sigptr = ^signature;
  306.    const logitechsig : signature = 'LOGITECH MOUSE';
  307.    Var
  308.      testvector : sigptr;
  309.      l          : longint;
  310.    begin
  311.      getintvec($33,pointer(testvector));
  312.      longint(testvector) := longint(testvector) + 16;
  313.      if testvector^ = logitechsig then
  314.         logi_mouse := true
  315.      else
  316.         logi_mouse := false;
  317.    end;
  318.  
  319. begin
  320.   regs.ax:=0;
  321.   intr($33,regs);
  322.   if regs.ax > 0 then
  323.     begin
  324.      numkeys:=regs.bx;
  325.      mouse_exists:=true;
  326.      islogitech:=logi_mouse;
  327.     end
  328.   else
  329.     begin
  330.      numkeys:=0;
  331.      mouse_exists:=false;
  332.      islogitech:=false;
  333.     end;
  334.   mkeypressed:=false;
  335.   left_mkey_pressed:=false;
  336.   center_mkey_pressed:=false;
  337.   right_mkey_pressed:=false;
  338. end;
  339.  
  340. Procedure showmouse;
  341. Var regs:registers;
  342. begin
  343.   regs.ax:=1;
  344.   intr($33,regs);
  345. end;
  346.  
  347. Procedure unshowmouse;
  348. Var regs:registers;
  349. begin
  350.   regs.ax:=2;
  351.   intr($33,regs);
  352. end;
  353.  
  354. Procedure putatxy(x,y:integer);
  355. Var regs:registers;
  356. begin
  357.   x:=x*8+4;
  358.   y:=y*8+4;
  359.   regs.ax:=4;
  360.   regs.cx:=x;
  361.   regs.dx:=y;
  362.   intr($33,regs);
  363.   mousex:=x;
  364.   mousey:=y;
  365. end;
  366.  
  367. Procedure setsensitivity(horizon,vertic,doub:integer);
  368. Var regs:registers;
  369. begin
  370.   regs.ax:=26;
  371.   regs.bx:=word(horizon);
  372.   regs.cx:=word(vertic);
  373.   regs.dx:=word(doub);
  374.   intr($33,regs);
  375. end;
  376.  
  377. Procedure getsensitivity(Var horiz,vert,double:integer);
  378. Var regs:registers;
  379. begin
  380.   regs.ax:=27;
  381.   intr($33,regs);
  382.   horiz:=integer(lo(regs.bx));
  383.   vert:=integer(lo(regs.cx));
  384.   double:=integer(lo(regs.dx));
  385. end;
  386.  
  387. Procedure setfastmode(switchspeed:integer);
  388. Var regs:registers;
  389. begin
  390.   regs.ax:=19;
  391.   regs.dx:=word(switchspeed);
  392.   intr($33,regs);
  393. end;
  394.  
  395. Procedure mouse_window(x1,y1,x2,y2:integer);
  396. Var regs:registers;
  397. begin
  398.   {set min/max horizontal}
  399.   regs.ax:=7;
  400.   regs.cx:=word(x1*8);
  401.   regs.dx:=word(x2*8);
  402.   intr($33,regs);
  403.   {set min/max vertical}
  404.   regs.ax:=8;
  405.   regs.cx:=word(y1*8);
  406.   regs.dx:=word(y2*8);
  407.   intr($33,regs);
  408. end;
  409.  
  410. Procedure id;
  411. Var regs:registers;
  412.     h,v,d:integer;
  413. begin
  414.   regs.ax:=36;
  415.   intr($33,regs);
  416.   with regs do
  417.     begin
  418.       case integer(ch) of
  419.         1 : writeln('Bus mouse driver');
  420.         2 : writeln('Serial mouse driver');
  421.         3 : writeln('InPort mouse driver');
  422.         4 : writeln('PS/2 mouse driver');
  423.         5 : writeln('Hewlett-Packard mouse driver');
  424.       end;
  425.       writeln('Version ',integer(bh),'.',integer(bl));
  426.       writeln('IRQ line ',integer(cl));
  427.     end;
  428.   getsensitivity(h,v,d);
  429.   writeln('Horizontal factor = ',h);
  430.   writeln('Vertical factor   = ',v);
  431.   write('Turbo threshold   = ',d);
  432.   waitforaction;
  433. end;
  434.  
  435. constructor winda.init(a,b,c,d:integer;t:string;a1,a2,a3:word);
  436. begin
  437.   x1:=a;
  438.   y1:=b;
  439.   x2:=c;
  440.   y2:=d;
  441.   title:=t;
  442.   ta:=a1;
  443.   fg:=a2;
  444.   bg:=a3;
  445. end;
  446.  
  447. Procedure winda.storescreen;
  448.  
  449.    {*********************************************************************}
  450.    { This Procedure stores a portion of the screen to the heap           }
  451.    { x1            = column of upper left corner                         }
  452.    { y1            = row of upper left corner                            }
  453.    { x2            = column of lower right corner                        }
  454.    { y2            = row of lower right corner                           }
  455.    { holding_place = generic pointer to where the screen data is on heap }
  456.  
  457.    Procedure SCREEN2RAM2(x1,y1,x2,y2: integer;Var holding_place:pointer);
  458.    type artype = array[1..videobuffersize] of word;
  459.    Var d:word;
  460.       x,y,z:integer;
  461.       junk:^artype;
  462.       size_of_screen_chunk:integer;
  463.    begin
  464.       if (x2 <= x1) or   {if invalid coordinates, then just exit and}
  465.          (y2 <= y1) then {set pointer to nil                        }
  466.          begin
  467.            holding_place:=nil;
  468.            exit;
  469.          end;
  470.       size_of_screen_chunk:=(y2-y1+1)*(x2-x1+1)*2;
  471.       getmem(junk,word(size_of_screen_chunk));
  472.       if monochrome then
  473.          d:= $B000
  474.       else
  475.          d:=$B800;
  476.       z:=1;
  477.       for y:=y1 to y2 do {vertical row}
  478.        begin
  479.         for x:=x1 to x2 do {horizontal column}
  480.           begin
  481.             junk^[z]:=memw[d:word(((y-1)*160)+(2*(x-1)))];
  482.             z:=z+1;
  483.           end;
  484.        end;
  485.       holding_place:=junk;
  486.    end;
  487.  
  488.      Procedure border(x1,y1,x2,y2:integer;title:string);
  489.      const
  490.       ULCORNER = CHR(201);
  491.       URCORNER = CHR(187);
  492.       LLCORNER = CHR(200);
  493.       LRCORNER = CHR(188);
  494.       HBAR     = CHR(205);
  495.       VBAR     = CHR(186);
  496.      Var
  497.       i,j,k    : integer;
  498.      BEGIN
  499.         window(1,1,80,screeny);
  500.         highvideo;
  501.         writeat(white,x1,y1,ulcorner);
  502.  
  503.         if title = '' then
  504.            FOR i:=x1+1 to x2-1 DO
  505.                writeat(white,i,y1,hbar)
  506.         else
  507.           begin
  508.             {title...}
  509.             K:=length(title);    {length of title plus ends}
  510.             J:=x2-x1-1;            {length of space to put title in}
  511.             K:=(j-k) div 2;        {k = half of space left}
  512.             for i:=x1+1 to x1+k-1 do
  513.               writeat(white,i,y1,hbar);
  514.             writeat(white,x1+k,y1,chr(181));
  515.             writeat(ta,x1+k+1,y1,title);
  516.             writeat(white,x1+k+1+length(title),y1,chr(198));
  517.             for i:=x1+k+1+length(title)+1 to x2-1 do
  518.               writeat(white,i,y1,hbar);
  519.           end;
  520.  
  521.         writeat(white,x2,y1,urcorner);
  522.         FOR i:=y1+1 to y2-1 DO
  523.             BEGIN
  524.               writeat(white,x1,i,vbar);
  525.               writeat(white,x2,i,vbar);
  526.             END;
  527.         writeat(white,x1,y2,llcorner);
  528.  
  529.         FOR i:=x1+1 to x2-1 DO
  530.            writeat(white,i,y2,hbar);
  531.  
  532.         writeat(white,x2,y2,lrcorner);
  533.      END;
  534.  
  535. begin
  536.   oldwindowmin:=windmin;
  537.   oldwindowmax:=windmax;
  538.   oldx:=wherex;
  539.   oldy:=wherey;
  540.   screen2ram2(x1-1,y1-1,x2+1,y2+1,screenvar);
  541.   border(x1-1,y1-1,x2+1,y2+1,title);
  542.   window(x1,y1,x2,y2);
  543.   clrscr;
  544. end;
  545.  
  546. destructor winda.done;
  547. begin
  548. end;
  549.  
  550. Procedure winda.restorescreen;
  551.  
  552.     {*********************************************************************}
  553.     { This Procedure restores a portion of the screen from the heap       }
  554.     { x1            = column of upper left corner                         }
  555.     { y1            = row of upper left corner                            }
  556.     { x2            = column of lower right corner                        }
  557.     { y2            = row of lower right corner                           }
  558.     { holding_place = generic pointer to where the screen data is on heap }
  559.  
  560.     Procedure RAM2SCREEN2(x1,y1,x2,y2: integer;Var holding_place:pointer);
  561.     type artype = array[1..videobuffersize] of word;
  562.     Var d:word;
  563.         x,y,z:integer;
  564.         junk:^artype;
  565.         size_of_screen_chunk:integer;
  566.     begin
  567.        if (x2 <= x1) or   {if invalid coordinates, then just exit and}
  568.           (y2 <= y1) then {set pointer to nil                        }
  569.           begin
  570.             holding_place:=nil;
  571.             exit;
  572.           end;
  573.        size_of_screen_chunk:=(y2-y1+1)*(x2-x1+1)*2;
  574.        junk:=holding_place;
  575.        if monochrome then
  576.           d:=$B000
  577.        else
  578.           d:=$B800;
  579.        z:=1;
  580.        for y:=y1 to y2 do {vertical row}
  581.         begin
  582.          for x:=x1 to x2 do {horizontal column}
  583.            begin
  584.              memw[d:word(((y-1)*160)+(2*(x-1)))]:=junk^[z];
  585.              z:=z+1;
  586.            end;
  587.         end;
  588.        freemem(junk,size_of_screen_chunk);
  589.     end;
  590.  
  591. begin
  592.   window(lo(oldwindowmin)+1,hi(oldwindowmin)+1,   {restore old window}
  593.          lo(oldwindowmax)+1,hi(oldwindowmax)+1);  {coordinates       }
  594.   ram2screen2(x1-1,y1-1,x2+1,y2+1,screenvar);
  595.   gotoxy(oldx,oldy);
  596. end;
  597.  
  598. constructor pop.init(a,b,c,d:integer;t,s:string;a1,a2,a3:word);
  599. begin
  600.   winda.init(a,b,c,d,t,a1,a2,a3);
  601.   msg:=s;
  602. end;
  603.  
  604. Procedure pop.showit;
  605. Var ch:char;
  606. begin
  607.   storescreen;
  608.   writeat(white,1,1,msg);
  609.    if alert and stimulus then
  610.      begin
  611.        repeat
  612.          whooop(220,880,5,2);
  613.          delay(200);
  614.          if mouse_exists then
  615.             mouseinfo
  616.          else
  617.             mkeypressed:=false;
  618.        until (keypressed or mkeypressed);
  619.        if keypressed then
  620.          begin
  621.            ch:=readkey;
  622.            if ch = #0 then
  623.               ch:=readkey;
  624.          end;
  625.      end
  626.     else
  627.      waitforaction;
  628.   restorescreen;
  629. end;
  630.  
  631. destructor pop.done;
  632. begin
  633.   winda.done;
  634. end;
  635.  
  636. constructor menu.init(a,b,c,d:integer;t:string;a1,a2,a3:word);
  637. begin
  638.   winda.init(a,b,c,d,t,a1,a2,a3);
  639.   itemcount:=0;
  640.   maxwidth:=0;
  641.   item:=nil;
  642.   current:=nil;
  643. end;
  644.  
  645. Procedure menu.nukethelist;
  646. begin
  647.   current:=item;
  648.   while current <> nil do
  649.     begin
  650.       item:=current^.next;
  651.       dispose(current);
  652.       current:=item;
  653.     end;
  654.   itemcount:=0;
  655. end;
  656.  
  657. destructor menu.done;
  658. begin
  659.   menu.nukethelist;
  660.   winda.done;
  661. end;
  662.  
  663. Procedure menu.add2menu(labelname:string;procname:window_action);
  664. Var k:menuitemptr;
  665. begin
  666.   if maxwidth < length(labelname) then
  667.      maxwidth := length(labelname);
  668.   itemcount:=itemcount+1;
  669.   new(k);
  670.   k^.itemlabel:=labelname;
  671.   k^.proc:=procname;
  672.   k^.next:=nil;
  673.   if item = nil then
  674.     begin
  675.       item:=k;
  676.       current:=k;
  677.       k^.prev:=nil;
  678.     end
  679.   else
  680.     begin
  681.       k^.prev:=current;
  682.       current^.next:=k;
  683.       current:=k;
  684.     end;
  685. end;
  686.  
  687. Procedure menu.pickmenu;
  688. Var disphight,
  689.     j,w:integer;
  690.     tchar:char;
  691.  
  692.      Function nextkey:char;
  693.      Var inchar:char;
  694.      begin
  695.         repeat
  696.            {nothing}
  697.         until keypressed;
  698.         inchar := readkey;
  699.         if inchar = chr(0) then
  700.            inchar := readkey;
  701.         nextkey:=inchar;
  702.      end;
  703.  
  704.      Function mousenextkey:char;
  705.      Var inchar:char;
  706.          v:integer;
  707.          crud,crud2:string;
  708.      begin
  709.         mouseinfo;
  710.         repeat
  711.           mouseinfo;
  712.           v:=(mousey div 8)-y1+1;
  713.         until (  keypressed or
  714.                  mkeypressed or
  715.                  (v <> w)  );
  716.         if keypressed then
  717.           begin
  718.             inchar := readkey;
  719.             if inchar = chr(0) then
  720.                inchar := readkey;
  721.             mousenextkey:=inchar;
  722.           end
  723.         else
  724.           if not mkeypressed then
  725.               if v > w then
  726.                  mousenextkey:=chr(80) {up}
  727.               else
  728.                  mousenextkey:=chr(72);{down}
  729.      end;
  730.  
  731.      Procedure up_arrow;
  732.      Var tVar:integer;
  733.      begin
  734.        if current = item then
  735.          begin
  736.            if mouse_exists then
  737.               putatxy(x1+10,y1+w-1);
  738.            exit;
  739.          end;
  740.        writeat(fg,1,w,current^.itemlabel);
  741.        current:=current^.prev;
  742.        if w > 1 then
  743.          w:=w-1
  744.        else
  745.          begin
  746.            gotoxy(1,1);
  747.            insline;
  748.          end;
  749.       writeat(bg,1,w,current^.itemlabel);
  750.       if mouse_exists then
  751.          putatxy(x1+10,y1+w-1);
  752.      end;
  753.  
  754.      Procedure down_arrow;
  755.      begin
  756.        if current^.next = nil then
  757.          begin
  758.            if mouse_exists then
  759.               putatxy(x1+10,y1+w-1);
  760.            exit;
  761.          end;
  762.  
  763.        writeat(fg,1,w,current^.itemlabel);
  764.        current:=current^.next;
  765.  
  766.        if (w=disphight) and (disphight<itemcount) then
  767.          begin
  768.            gotoxy(1,1);
  769.            delline;
  770.          end
  771.        else
  772.          w:=w+1;
  773.        writeat(bg,1,w,current^.itemlabel);
  774.        if mouse_exists then
  775.           putatxy(x1+10,y1+w-1);
  776.      end;
  777.  
  778.      Procedure call_the_Procedure;
  779.      begin
  780.        current^.proc;       {execute the proper procedure}
  781.        if mouse_exists then {reset mouse window, put mouse back in right spot}
  782.          begin
  783.            mouse_window(x1,y1-1,
  784.                         x2,y2+1);
  785.            putatxy(x1+10,y1+w-1);
  786.          end;
  787.        global_choice := 1;
  788.      end;
  789.  
  790.    function min(a,b:integer):integer;
  791.    begin
  792.      if a < b then
  793.         min:=a
  794.      else
  795.         min:=b;
  796.    end;
  797.  
  798. begin
  799.    if stimulus then
  800.       whooop(500,1800,17,1);
  801.    if maxwidth < (length(title)+2) then
  802.       maxwidth := length(title)+2;
  803.    x1:=((80-(maxwidth+1)) div 2) +1;
  804.    if itemcount < (screeny-2) then
  805.       y1:=((screeny-itemcount) div 2)+1
  806.    else
  807.       y1:=2;
  808.    x2:=x1+maxwidth-1;
  809.    disphight:=min(itemcount,(screeny-2));
  810.    y2:=y1+disphight-1;
  811.    if (maxwidth < 10) and (disphight < itemcount) then
  812.       maxwidth :=10;  {to make room for 'scroll' message}
  813.    storescreen;
  814.    clrscr;
  815.  
  816.    current:=item;
  817.    for j:=1 to disphight do
  818.      begin
  819.        writeat(fg,1,j,current^.itemlabel);
  820.        current:=current^.next;
  821.      end;
  822.    if disphight < itemcount then
  823.       writeat(white+blink,2,disphight+1,'»Scroll«');
  824.    current:=item;
  825.    writeat(bg,1,1,current^.itemlabel);
  826.  
  827.    if mouse_exists then
  828.     begin
  829.       mouse_window(x1,y1-1,
  830.                   x2,y2+1);
  831.       putatxy(x1+10,y1);
  832.     end;
  833.  
  834.    gotoxy(1,1);
  835.    w:=1;
  836.    global_choice:=0;
  837.    quit:=false;
  838.    up1level:=false;
  839.    global_choice:=0;
  840.    repeat
  841.        if mouse_exists then
  842.           tchar:=mousenextkey
  843.        else
  844.           tchar:=nextkey;
  845.        if (not mkeypressed) or (not mouse_exists) then
  846.          case tchar of
  847.            chr(68) : quit:=true;               {f10}
  848.            chr(13) : call_the_Procedure;       {Enter}
  849.            chr(72) : up_arrow;                 {up arrow}
  850.            chr(80) : down_arrow;               {down arrow}
  851.            chr(27) : up1level:=true;           {esc}
  852.          else
  853.            sound(440);
  854.            delay(200);
  855.            nosound;
  856.          end
  857.        else
  858.          case whichmkey of
  859.            1 : call_the_Procedure; {left mouse key pressed}
  860.            2 : up1level:=true;     {right mouse key pressed}
  861.          3,4 : quit:=true;         {both mouse keys pressed,
  862.                                     center key on logitech}
  863.          else
  864.            sound(440);
  865.            delay(200);
  866.            nosound;
  867.          end;
  868.    until quit or up1level;
  869.  
  870.    if up1level then up1level:=false;
  871.    restorescreen;
  872. end;
  873.  
  874. constructor popfetch.init(a,b,c,d:integer;t,s:string;a1,a2,a3:word);
  875. begin
  876.   winda.init(a,b,c,d,t,a1,a2,a3);
  877.   msg:=s;
  878. end;
  879.  
  880. Function popfetch.fetchit:string;
  881. Var a:string;
  882.     ch:char;
  883.     p:integer;
  884.  
  885.    function nextkey:char;
  886.    begin
  887.      if mouse_exists then
  888.        repeat
  889.          mouseinfo
  890.        until keypressed or mkeypressed
  891.      else
  892.        repeat
  893.        until keypressed;
  894.  
  895.      if keypressed then
  896.        nextkey:=readkey
  897.      else
  898.        case whichmkey of
  899.            1 : nextkey:=chr(13);
  900.        2,3,4 : nextkey:=chr(27);
  901.        end;
  902.    end;
  903.  
  904. begin
  905.   storescreen;
  906.   p:=length(msg);
  907.   write(msg);
  908.   a:='';
  909.   ch:=nextkey;
  910.   while not (ord(ch) in [13,27]) do
  911.     if ord(ch)=8 then  {backspace key}
  912.       begin
  913.        if length(a) <= 1 then
  914.         a:=''
  915.        else
  916.         a:=copy(a,1,length(a)-1);
  917.        if wherex-1 > p then
  918.           gotoxy(wherex-1,1);
  919.        clreol;
  920.        ch:=nextkey;
  921.       end
  922.     else
  923.      begin
  924.       write(ch);
  925.       a:=a+ch;
  926.       ch:=nextkey;
  927.      end;
  928.   if ord(ch) = 27 then
  929.      fetchit:=''
  930.   else
  931.      fetchit:=a;
  932.   restorescreen;
  933. end;
  934.  
  935. destructor popfetch.done;
  936. begin
  937.   winda.done;
  938. end;
  939.  
  940. { initialize static Variables }
  941. begin
  942.     stimulus:=false;
  943.     alert:=false;
  944.     quit:=false;
  945.     up1level:=false;
  946.     global_choice:=0;
  947.     mouseinit;
  948.     heaperror:=@heapfunc;
  949. END.
  950.