{**********************************************************************
Copyright (C) 2009 by Salvatore Licciardi

Web http://www.webalice.it/turylicciardi    eMail turylicciardi@tiscali.it

 This program is free software: you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation, version 3 of the License.
 This program is distributed in the hope  that it will be useful , but WITHOUT
 ANY WARRANTY without even the implied warranty  of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.
 See the GNU General Public License for more details. You should have received
 a copy of the GNU General Public License along with this program. If not, see
 http://www.gnu.org/licenses/

 **********************************************************************}

{$MODE ObjFpc}
unit Select;   // menu verticale con barra di scorrimento e con commento sopra
               // Richiede FPC 1.9.x
interface

{$ifdef Win64}
 {$define Win32}
{$endif}
{$ifdef Go32v2}
 {$define TxtCrt}
{$endif}             // fare select_V ?
{$ifdef Win32}
 {$define TxtVideo}
{$endif}
{$ifdef OS2}
 {$define TxtVideo}
{$endif}
{$ifdef Linux}
 {$define TxtCrt}
{$endif}


uses Crt,SysUtils,Math,Video,Keyboard,
     {$ifdef Go32v2}
     MsMouse,
     {$else}
     Mouse,Dos,
     {$endif}
     {$ifdef TxtVideo}
     TxtVideo,
     {$endif}
     Lista_S,MClick22, Altro32;

type Sfoglia_Dati=object(Lista_Esadecimale)
(*    METODI public EREDITATI DA Seleziona.Lista_Esadecimale
            constructor init;
            destructor  destroy;
            procedure   Stampa;
            procedure   Cancella_iniziale;
            procedure   Reverse;
            function    Input(s:string):boolean; // in coda, ma e' come se fosse iniziale
            function    NumElementi:longint;
            function    Get_stringa(n:longint):string;   // parte da 1
            function    Get_mem_usata:longint;
            function    Estrai_iniziale:string;  // con rimozione
            function    Inserisci(posizione:longint; testo:string):boolean;
*)

            public
             function    Costruisci(XX,YY,larghezza:byte; topo,mancino:boolean; testo:string; CD,num_righe:longint):longint;
             function    Ultimo_Tasto:string;
             function    get_Menu_Ciclico:boolean;
             procedure   set_Menu_Ciclico(b:boolean);

            private
             function  str_meno:string;
             procedure Mostra(primo:longint);
             procedure GreenZona(precedente:longint);
             procedure Barra_Verticale;
             larghezza_:longint;
             iesimo:longint;
             riga_selezionata:longint;
             righe:longint;
             pos_barraV,
             old_pos_barraV:longint;
             last_key:string;
             X,Y:integer;
             ciclico:boolean;
            end;

implementation

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

function    Sfoglia_Dati.get_Menu_Ciclico:boolean;
begin
get_Menu_Ciclico:=ciclico;
end;

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

procedure   Sfoglia_Dati.set_Menu_Ciclico(b:boolean);
begin
Ciclico:=b;
end;

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

procedure Sfoglia_Dati.Barra_Verticale;
var i:real;
    j:integer;

begin
if righe<3 then Exit;
HideMouse;
i:=numElementi / (righe-2);
if i<>0 then i:=iesimo / i;
i:=i+2;
if round(i)>=righe then i:=righe-1;
if iesimo=1 then i:=2;
pos_barraV:=longint(round(i));
if pos_barraV<>old_pos_barraV then
        begin
        old_pos_barraV:=pos_barraV;
        {$ifdef TxtCrt}
        textbackground(3);
        for j:=1 to righe-2 do
            begin
            gotoxy(X+1+larghezza_,Y+2+j);
            write(c_B);   //  '±'
            end;
        gotoxy(X+1+larghezza_,y+pos_barraV+1);
        textbackground(black+7);
        textcolor(black);
        write(c_S);       //  #9
        gotoxy(x+1,y+1+riga_selezionata);
        {$endif}
        {$ifdef TxtVideo}
        for j:=0 to righe-3 do outtextxy(x+larghezza_,y+2+j,c_B{'±'},255,3,white);
        outtextxy(x+larghezza_,y+pos_barrav,c_S{#9},255,black+7,black);
        updatescreen(false);
        {$endif}
        end;
showmouse;
end;

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

procedure Sfoglia_Dati.Mostra(primo:longint);
var s:string;
    i:longint;
begin
{$ifdef TxtCrt}
textbackground(3);  {*** la stampa}
textcolor(blue);
{$endif}
for i:=primo to righe+primo-1 do
    begin
    s:=Get_stringa(i);
    while length(s)<larghezza_ do s:=s+' ';
    setlength(s,larghezza_);
    {$ifdef TxtCrt}
    gotoxy(X+1,Y+2+i-primo);
    write(s);
    {$endif}
    {$ifdef TxtVideo}
    outtextxy(X,Y+i+1-primo,s,255,3,blue);
    {$endif}
    end;
end;

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

procedure Sfoglia_Dati.GreenZona(precedente:longint);   {*** da aggiornare quello selezionato}
var str:string;
begin
hidemouse;
if precedente<>0 then
      begin
      str:=Get_stringa(iesimo+(precedente-iesimo));
      while length(str)<larghezza_ do str:=str+' ';
      setlength(str,larghezza_);
      {$ifdef TxtCrt}
      gotoxy(X+1,Y+riga_selezionata+1+(precedente-iesimo));
      textbackground(3);
      textcolor(blue);
      write(str);
      {$endif}
      {$ifdef TxtVideo}
      outtextxy(X,Y+riga_selezionata+(precedente-iesimo),str,255,3,blue);
      {$endif}
      end;

str:=Get_stringa(iesimo);
while length(str)<larghezza_ do str:=str+' ';
setlength(str,larghezza_);

{$ifdef TxtCrt}
gotoxy(X+1,Y+riga_selezionata+1);
textbackground(green);
textcolor(white);
write(str);
gotoxy(X+1,Y+riga_selezionata+1);
{$endif}
{$ifdef TxtVideo}
outtextxy(X,Y+riga_selezionata,str,255,green,white);
setcursorpos(X,Y+riga_selezionata);
updatescreen(false);
{$endif}
showmouse;
end;

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

function Sfoglia_Dati.Ultimo_Tasto:string;
begin
Ultimo_Tasto:=last_key; { puo' assumere i valori :
'destra'  'sinistra'  'esc'  'invio'  mox|moy  'canc'  ''}
end;

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

function Sfoglia_Dati.str_meno:string;
var s:string;
begin
s:='';
while length(s)<larghezza_ do s:=s+c_D1;   //  'Ä'
exit(s);
end;

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

function Sfoglia_Dati.Costruisci(XX,YY,larghezza:byte; topo,mancino:boolean; testo:string; CD{click delay},num_righe:longint):longint;
var mox,moy,tasto:byte;
    posizione,i,primo:longint;
    cliccato:boolean;
    Doppio_Click:More_Click;
    r:real;
    c:string;
    {$ifdef TxtVideo}
    ii:longint;
    {$endif}
label inizio_case;
begin
initvideo;
initkeyboard;
Doppio_Click.init;
Doppio_Click.set_mancino(mancino);
Doppio_Click.Set_Num_Click_Max(2);
righe:=num_righe;
larghezza_:=larghezza;
last_key:='';

if YY+righe>ScreenHeight then righe:=ScreenHeight-YY+1;
righe:=righe-3; // numero di righe riservate alla lista (minimo=4: 2 per le frecce e 2 per la barra verticale)
if righe<2-1 then runerror(0); // bisogna fare prima: initvideo
if cd>100 then cd:=100;
while (XX+larghezza_>ScreenWidth) do dec(larghezza_);
if larghezza_<1 then runerror(1); // riga troppo stretta
trim(testo);
X:=XX;
Y:=YY;
cursorOff;
hidemouse;
pos_barraV:=0;
old_pos_barraV:=-1;

while length(testo)<larghezza_+2 do testo:=' '+testo+' ';
setlength(testo,larghezza_+2);
{$ifdef TxtCrt}
textbackground(white);
textcolor(black);
gotoxy(X,Y);
write(testo);
textbackground(3);
gotoxy(X,Y+1);
write(c_UL1{'Ú'}+str_meno+c_UR1{'¿'});
for i:=1 to righe do
    begin
    gotoxy(x,y+1+i);
    write(c_U1{'³'});
    end;
for i:=2 to righe do
    begin
    gotoxy(x+1+larghezza_,y+2+i);
    write(c_B{'±'});
    end;
gotoxy(X,Y+righe+2);
write(c_DL1{'À'}+str_meno+c_DR1{'Ù'});
textbackground(3);
textcolor(white);
gotoxy(X+1+larghezza_,Y+2);
write(c_FU{#24});
gotoxy(X+1+larghezza_,Y+righe+1);
write(c_FD{#25});  {grafica finita}
{$endif}
{$ifdef TxtVideo}
outtextxy(x-1,y-1,' ',255,7,black,larghezza_+2);
outtextxy(X-1,Y-1,testo,255,7,black);
for ii:=Y+1 to Y+num_righe-1 do outtextxy(x-1,ii-1,' ',255,3,black,larghezza_+2);
outtextxy(x-1,y,c_UL1{'Ú'}+str_meno+c_UR1{'¿'});
for i:=1 to righe do outtextxy(x-1,y+i,c_U1{'³'});
for i:=2 to righe do outtextxy(x+larghezza_,y-1+i,c_B{'±'},255,255,white);
outtextxy(x-1,y+righe+1,c_DL1{'À'}+str_meno+c_DR1{'Ù'});
outtextxy(x+larghezza_,y+1,c_FU{#24},255,3,white);
outtextxy(x+larghezza_,y+righe,c_FD{#25},255,3,white);     {grafica finita}
updatescreen(false);
{$endif}

c:=#1;                          {inizializzo}
iesimo:=1;  {a cui punta}
primo:=1;   {in alto}
riga_selezionata:=1;
Mostra(primo);
GreenZona(0);
showmouse;
Barra_Verticale;
showmouse;
repeat
if (PollKeyEvent<>0) or (not topo) then
      begin
      c:=KeyEventToString(TranslateKeyEvent(GetKeyEvent));
      inizio_case:
      if c='Delete' then
                  begin
                  last_key:='canc';
                  Exit(min(iesimo,numElementi));
                  end else
      if c='Left' then    // #75
                  begin
                  last_key:='sinistra';
                  Exit(0);  { sinistra disabilitata }
                  end else
      if c='PgUp' then
                  begin
                  if iesimo>righe then  { pag su }
                                  begin
                                  iesimo:=max(iesimo-righe,1);
                                  primo:=max(primo-righe,1);
                                  Mostra(primo);
                                  GreenZona(0);
                                  end
                                 else
                                  begin
                                  c:='Home';  // #71
                                  goto inizio_case;
                                  end;
                  end else
      if c='Right' then
                   begin
                   last_key:='destra';
                   Exit(0);  { destra disabilitata }
                   end else
      if c='PgDn'  then
                   begin
                   if (iesimo<numElementi-(righe-1))and(numElementi>righe) then  { pag giu' | destra disabilitata }
                                  begin
                                  iesimo:=iesimo+righe;
                                  primo:=primo+righe;
                                  Mostra(primo);
                                  GreenZona(0);
                                  end
                                 else
                                  begin
                                  c:='End';
                                  goto inizio_case;
                                  end;
                   end else
      if c='End' then
                 begin
                 if iesimo<numElementi then     { fine }
                                begin
                                iesimo:=numElementi;
                                primo:=(numElementi div righe) *righe +1;
                                riga_selezionata:=numElementi mod righe;
                                if riga_selezionata=0 then
                                            begin
                                            riga_selezionata:=byte(righe);
                                            primo:=primo-righe;
                                            end;
                                Mostra(primo);
                                GreenZona(0);
                                end;
                 end else
      if c='Up' then
                begin
                if iesimo>1 then   { su }
                            begin
                            dec(iesimo);
                            if riga_selezionata>1 then dec(riga_selezionata)
                                                  else
                                                   if primo>1 then
                                                              begin
                                                              dec(primo);
                                                              Mostra(primo);
                                                              end;
                            GreenZona(iesimo+1);
                            end
                           else
                            if ciclico and (iesimo=1) then
                                begin
                                c:='End';  //  #79
                                goto inizio_case;
                                end;
                end else
      if c='Home' then
                  begin
                  if iesimo>1 then            { inizio }  // #71
                              begin
                              iesimo:=1;
                              primo:=1;
                              riga_selezionata:=1;
                              Mostra(primo);
                              GreenZona(0);
                              end;
                  end else
      if c='Down' then  // #80
                  begin
                  if iesimo<numElementi then  { giu' }
                                begin
                                inc(iesimo);
                                if riga_selezionata<righe then inc(riga_selezionata)
                                                          else
                                                           begin
                                                           inc(primo);
                                                           Mostra(primo);
                                                           end;
                                GreenZona(iesimo-1);
                                end
                               else
                                if ciclico and (iesimo=numElementi) then
                                begin
                                c:='Home';  // #71
                                goto inizio_case;
                                end;
                  end else
      if (length(c)=7)and(copy(c,1,6)='SHIFT ')and(c[7] in ['a'..'z','A'..'Z'] ) then
         begin
         c:=c[7];
         goto inizio_case;
         end else
      if (length(c)=1) and (c[1] in ['0'..'9','a'..'z','A'..'Z'] ) then
                        begin
                        c:=upcase(c);
                        posizione:=0;
                        for i:=iesimo+1 to numElementi do
                            if c=upcase(copy(get_stringa(i),1,1)) then
                               begin
                               posizione:=i;
                               break;
                               end;
                        if posizione=0 then
                           for i:=1 to iesimo-1 do
                               if c=upcase(copy(get_stringa(i),1,1)) then
                                  begin
                                  posizione:=i;
                                  break;
                                  end;
                        if posizione<>0 then
                           begin
                           iesimo:=posizione;
                           riga_selezionata:=1;
                           primo:=posizione;
                           Mostra(primo);
                           GreenZona(0);
                           end;
                        end else
      if c=#13 then
                begin
                last_key:='invio';
                exit(min(iesimo,numElementi)); // invio
                end else
      if c=#27 then
                begin
                last_key:='exit';
                exit(0);      // Esc
                end;
      Barra_Verticale;
      end
     else   // not PollKeyEvent
      begin
      sleep(5);
      {$ifdef Go32v2}
       cliccato:=Doppio_Click.Mouse_Up(mox,moy,tasto);
      {$else}
       cliccato:=Doppio_Click.Mouse_Down(mox,moy,tasto);
      {$endif}
      if cliccato then tasto:=1
                  else tasto:=0;
      if Doppio_Click.More_Click(2) then
         if (mox>X)and(mox<X+larghezza_+1)and(moy>Y+1)and(moy<Y+righe+2) then
                        begin  {sulla lista}
                        i:=moy-yy-1;
                        if primo-1+i>numElementi then Continue; // non esce se c'e' doppioclick oltre la lista ma dentro il riquadro
                        mostra(primo);
                        iesimo:=primo-1+i;
                        riga_selezionata:=i;
                        GreenZona(0);
                        last_Key:='invio'; // anche se e' inttostr(mox)+'|'+inttostr(moy); e' come se simulasse l'invio, perche' cliccando non esce senza far nulla
                        exit(min(iesimo,numElementi));
                        end;
      {$ifdef Go32v2}        // e' invertito il click
      if mancino then cliccato:=Doppio_Click.Mouse_up_L(mox,moy,tasto)
                 else cliccato:=Doppio_Click.Mouse_up_R(mox,moy,tasto);
      if cliccato then
                  begin
                  last_Key:=inttostr(mox)+'|'+inttostr(moy);
                  Exit(0); // si esce con il mouse
                  end;
      cliccato:=Doppio_Click.Mouse_down(mox,moy,tasto);
      if cliccato then tasto:=1
                  else tasto:=0;
      {$endif}
      if tasto=1 then      {Gestione mouse}
                 begin
                 if (mox=X+larghezza_+1) and (moy=Y+2) then  {freccina alta}
                                              begin
                                              c:='Up';  // #72
                                              delay2(CD);
                                              goto inizio_case;
                                              end;
                 if (mox=X+larghezza_+1) and (moy=Y+righe+1) then {freccina bassa}
                                              begin
                                              c:='Down'; // #80
                                              delay2(CD);
                                              goto inizio_case;
                                              end;
                 if (mox=X+larghezza_+1)and(moy>Y+2)and(moy<Y+righe+1)and(NumElementi>righe) then
                        begin  {barra}
                        if righe<4 then Continue;
                        r:=numElementi / (righe-2);
                        if r<>0 then r:=iesimo / r;
                        r:=r+2;
                        if round(r)>=righe then r:=righe-1;
                        if iesimo=1 then r:=2;
                        i:=longint(round(r));
                        iesimo:=longint(round(numElementi / (righe-2)*(moy-3-y)))+2;
                        if i=old_pos_barraV then continue;
                        if i=2 then iesimo:=1;
                        pos_barraV:=i;
                        primo:=iesimo;
                        riga_selezionata:=1;
                        mostra(primo);
                        GreenZona(0);
                        barra_verticale;
                        end;
                 end;
      {$ifndef Go32v2}
      if Doppio_Click.Move then
          begin
          mox:=getMouseX+1;
          moy:=getMouseY+1;
          Doppio_Click.Empty_Mouse;
      {$endif}
          if (mox>X)and(mox<X+larghezza_+1)and(moy>Y+1)and(moy<Y+righe+2) then
                        begin  {sulla lista}
                        i:=moy-yy-1;
                        if i=riga_selezionata then continue;
                        if get_stringa(primo-1+i)='' then continue;
                        mostra(primo);
                        iesimo:=primo-1+i;
                        riga_selezionata:=i;
                        GreenZona(0);
                        end;
      {$ifndef Go32v2}
          end;
      {$endif}
      if (mox>X-1)and(mox<X+larghezza_+2)and(moy>=Y)and(moy<Y+righe+3) then
         else  // si esce con il mouse cliccando fuori dall'area sul fronte di risalita
          if tasto=1 then
              begin
              {$ifdef Go32v2}
              cliccato:=Doppio_Click.Mouse_Up(mox,moy,tasto);
              {$endif}
              if tasto<>1 then continue;
              last_Key:=inttostr(mox)+'|'+inttostr(moy);
              Exit(0);
              end;
      end;    // not PollKeyEvent
until false;
end;

{+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}

end.
