{**********************************************************************
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/

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

unit Menu_X_V;        // Menu_X formato Video solo per FreePascal 1.x.x

interface

uses Crt,Keyboard,Video,
     {$ifdef Go32v2}
      MsMouse,
     {$else}
     Mouse,
      {$endif}
     MClick22,TxtVideo,altro32,m_x;

type  MenuLista_X=object
       public
        x,y,error,bk_color,txt_Color,selezionato,bk_selezione,txt_Color_Veloce,
        txt_Color_Selezione,txt_Color_Selezione_Disabilitato:byte;
        controllo{ se la riga entra nel monitor },topo,tastiera,fine_riga,mancino:boolean;
        constructor init(massimaX,massimaY:longint);
        constructor init;
        destructor  destroy;
        procedure   Mostra;
        procedure   stampa_selezionato;
        function    AggiornaElemento(elemento:integer; testo:string; tasto:byte; abilitato:boolean):boolean;
        function    AggiornaElemento(posizione:byte; abilitato:boolean):boolean;
        function    NuovoElemento(testo:string; tasto:byte; abilitato:boolean):byte;  {torna la posizione dove inserito}
        function    NuovoElemento(testo:string; abilitato:boolean):byte;
        function    NuovoElemento(testo:string):byte;
        function    NuovoElemento(testo:string; tasto:byte):byte;
        function    Costruisci:integer; { ritorna la colonna selezionata, negativa se ho premuto ESC }
        function    NumElementi:byte;
        function    get_nome(i:byte):string;
        function    Get_X(elemento:integer):integer;

       private
        mox,moy,old_selezionato,elementi:byte;
        MaxX,gettextmaxX_,gettextmaxY_:integer;
        lista:array [1..num] of tipo;
        procedure   writeColor(s:string; txt,Veloce,elemento,selezionato_:byte);
        procedure   Fine_Riga_;
        function    Costruisci_Crt:integer;
        function    Costruisci_Keyboard:integer;
        function    Dimensioni(x2,y2:byte):byte;
       end;

implementation

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

function  MenuLista_X.get_nome(i:byte):string;
begin
if (i>elementi)or(i<1) then
   begin
   get_nome:='';
   Exit;
   end;
get_nome:=lista[i].nome;
end;

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

function MenuLista_X.NumElementi:byte;
begin
NumElementi:=elementi;
end;

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

function MenuLista_X.NuovoElemento(testo:string; tasto:byte; abilitato:boolean):byte;  {torna la posizione dove inserito}
begin
if elementi=num then
   begin
   NuovoElemento:=0;
   Error:=1;
   exit;
   end;
inc(elementi);
lista[elementi].nome:=testo;
lista[elementi].Tasto:=tasto;
lista[elementi].Abilitato:=abilitato;
NuovoElemento:=elementi;
end;

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

function MenuLista_X.NuovoElemento(testo:string; abilitato:boolean):byte;  {torna la posizione dove inserito}
begin
exit(NuovoElemento(testo,1,abilitato));
end;

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

function MenuLista_X.NuovoElemento(testo:string):byte;  {torna la posizione dove inserito}
begin
exit(NuovoElemento(testo,1,true));
end;

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

function MenuLista_X.NuovoElemento(testo:string; tasto:byte):byte;  {torna la posizione dove inserito}
begin
exit(NuovoElemento(testo,tasto,true));
end;

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

function MenuLista_X.AggiornaElemento(posizione:byte; abilitato:boolean):boolean;  {torna true se aggionato}
begin
if (posizione>elementi)or(posizione<1) then
                      begin
                      AggiornaElemento:=false;
                      Exit;
                      end;
lista[posizione].Abilitato:=abilitato;
AggiornaElemento:=true;
end;

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

constructor MenuLista_X.init(massimaX,massimaY:longint);
var i:byte;
begin
initvideo;
mancino:=false;
GetTextMaxX_:=byte(massimaX);
GetTextMaxY_:=byte(massimaY);
if massimaX<=0 then GetTextMaxX_:=ScreenWidth;
if massimaY<=0 then GetTextMaxY_:=ScreenHeight;
if controllo then maxX:=-1
             else MaxX:=GetTextMaxX_;
fine_riga:=false;
txt_Color:=7;
txt_Color_Selezione:=0;
txt_Color_Veloce:=white;
bk_selezione:=7;
bk_color:=0;
controllo:=false;
elementi:=0;
error:=0;
txt_Color_Selezione_Disabilitato:=7; {grigio}
selezionato:=0;
x:=1;
y:=1;
tastiera:=true;
topo:=true;
for i:=1 to num do
    begin
    lista[i].nome:='';
    lista[i].Tasto:=0;
    lista[i].abilitato:=false;
    end;
end;

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

constructor MenuLista_X.init;
begin
init(-1,-1);
end;

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

destructor MenuLista_X.destroy;
begin
elementi:=0;
end;

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

procedure MenuLista_X.writeColor(s:string; txt,Veloce,elemento,selezionato_:byte);
var i:longint;
begin
hidemouse;
i:=pos(char(lista[elemento].tasto),s);
if elemento<>selezionato_ then
                           if lista[elemento].abilitato then OutText(copy(s,1,i-1),0,bk_color,txt)
                                                        else OutText(copy(s,1,i-1),0,bk_color,txt_Color_Selezione_Disabilitato)
                          else
                           if lista[elemento].abilitato then OutText(copy(s,1,i-1),0,bk_selezione,txt_Color_Selezione)
                                                        else OutText(copy(s,1,i-1),0,bk_selezione,txt_Color_Selezione_Disabilitato);
MoveCursor(i-1);
if i>0 then
       if elemento<>selezionato_ then OutText(copy(s,i,1),0,bk_color,veloce)
                                 else OutText(copy(s,i,1),0,bk_selezione,veloce)
       else OutText(copy(s,i,1),0,bk_selezione,txt_Color_Selezione);
MoveCursor(1);
if elemento<>selezionato_ then
                           if lista[elemento].abilitato then OutText(copy(s,i+1,255),0,bk_color,txt)
                                                        else OutText(copy(s,i+1,255),0,bk_color,txt_Color_Selezione_Disabilitato)
                          else
                           if lista[elemento].abilitato then OutText(copy(s,i+1,255),0,bk_selezione,txt_Color_Selezione)
                                                        else OutText(copy(s,i+1,255),0,bk_selezione,txt_Color_Selezione_Disabilitato);
MoveCursor(length(copy(s,i+1,255)));
updateScreen(false);
showmouse;
end;

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

procedure MenuLista_X.stampa_selezionato;
var x_pos,i:byte;
begin
hidemouse;
if old_selezionato>0 then
   begin
   x_pos:=0;
   for i:=1 to old_selezionato-1 do x_pos:=x_pos+length(lista[i].nome)+2;
   setcursorPos(x+x_pos-1,y-1);
   writeColor(' '+lista[old_selezionato].nome+' ',txt_Color,txt_Color_Veloce,old_selezionato,selezionato);
   end;
x_pos:=0;
for i:=1 to selezionato-1 do x_pos:=x_pos+length(lista[i].nome)+2;
setcursorPos(x+x_pos-1,y-1);
writeColor(' '+lista[selezionato].nome+' ',txt_Color,txt_Color_Veloce,selezionato,selezionato);
showmouse;
end;

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

function MenuLista_X.Dimensioni(x2,y2:byte):byte;
var maxl,x_,y_:byte;
begin
maxl:=0;
for x_:=1 to elementi do maxl:=maxl+2+length(lista[x_].nome);
x_:=GetTextMaxX_;
MaxX:=x_;
y_:=GetTextMaxY_;
if x2-1+maxl>x_ then Dimensioni:=12 else
if (x2-1+maxl=x_)and(y2=y_) then Dimensioni:=12 else dimensioni:=0;
end;

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

procedure MenuLista_X.Fine_Riga_;
var lunghezza,i:integer;
    s:string;
begin
if not fine_riga then Exit;
lunghezza:=0;
for i:=1 to elementi do lunghezza:=lunghezza+length(lista[i].nome)+2;
if maxX=-1 then maxX:=GetTextMaxX_;
s:='';
for i:=x+lunghezza to maxX do s:=s+' ';
OutTextXY(x+lunghezza-1,y-1,s,0,bk_color,txt_Color);
end;

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

procedure MenuLista_X.Mostra;
var i,j,old_selezionato_:byte;
begin
hidemouse;
if (not tastiera) and (not topo) then
   begin
   Error:=2;
   RunError(201);
   exit;
   end;
if elementi=0 then
   begin
   error:=3;
   RunError(201);
   exit;
   end;
if (selezionato>elementi) then
   begin
   Error:=4;
   RunError(201);
   Exit;
   end;
for i:=1 to elementi do
    for j:=1 to length(lista[i].nome) do
        if lista[i].nome[j]<#32 then
                                begin
                                Error:=6;
                                RunError(201);
                                Exit;
                                end;
old_selezionato_:=0;
for i:=1 to elementi do
    begin
    if not (char(lista[i].tasto) in ['0'..'9','a'..'z','A'..'Z',#1]) then
                 begin
                 Error:=10;
                 RunError(201);
                 Exit;
                 end;
    for j:=1 to length(lista[i].nome) do
        if lista[i].nome[j]<#32 then
                                begin
                                Error:=6;
                                RunError(201);
                                Exit;
                                end;
    end;
if selezionato=0 then
   for i:=1 to elementi do
       if lista[i].nome<>'' then
          begin
          selezionato:=i;
          break;
          end;
if controllo then
   begin
   Error:=dimensioni(x,y);
   if Error<>0 then
      begin
      RunError(201);
      Exit;
      end;
   end;
cursorOff;
setcursorPos(x-1,y-1);
old_selezionato_:=selezionato;
selezionato:=0; {valore non valido}
for i:=1 to elementi do writeColor(' '+lista[i].nome+' ',txt_color,txt_color_Veloce,i,selezionato);
fine_riga_;
selezionato:=old_selezionato_;
showmouse;
end;

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

function MenuLista_X.Costruisci_Crt:integer;
var i,j,tasto:byte;
    c:char;
    cliccato:boolean;
    Doppio_Click:More_Click;
begin
Doppio_Click.init;
Doppio_Click.set_mancino(mancino);
mostra;
stampa_selezionato;
repeat
 if keypressed or (not topo) then
     begin
     c:=readkey;
     case ord(c) of
         13: begin  { invio }
             if not lista[selezionato].abilitato then continue;
             Costruisci_Crt:=selezionato;
             Exit;
             end;
         27: begin  { esc }
             Costruisci_Crt:=0;
             Exit;
             end;
          0: begin
             c:=readkey;
             case ord(c) of
                  68: begin  { F10 }
                      Costruisci_Crt:=0;
                      Exit;
                      end;
               72,80: begin { freccia su/giu' }
                      if not lista[selezionato].abilitato then continue;
                      Costruisci_Crt:=selezionato;
                      Exit;
                      end;
                  77: begin { freccia destra }
                      old_selezionato:=selezionato;
                      if selezionato<elementi then inc(selezionato)
                                              else selezionato:=1;
                      stampa_selezionato;
                      end;
                  75: begin { freccia sinistra }
                      old_selezionato:=selezionato;
                      if selezionato>1 then dec(selezionato)
                                       else selezionato:=elementi;
                      stampa_selezionato;
                      end;
                   else
                    for i:=1 to elementi do { ho premuto un tasto alt+selezionato? quale? }
                        if (upcase(char(lista[i].Tasto))=upcase(from_alt_to_char(ord(c)))) and (lista[i].Tasto<>1) then
                                begin
                                old_selezionato:=selezionato;
                                costruisci_Crt:=i;
                                selezionato:=i;
                                stampa_selezionato;
                                exit;
                                end;
                  end;
             end
          else
           for i:=1 to elementi do { ho premuto un tasto selezionato? quale? }
               if upcase(char(lista[i].Tasto))=upcase(c) then
                      begin
                      old_selezionato:=selezionato;
                      costruisci_Crt:=i;
                      selezionato:=i;
                      stampa_selezionato;
                      exit;
                      end;
          end;
     end
    else
     begin
     Delay(5);
     cliccato:=Doppio_Click.Mouse_Down(mox,moy,tasto);
     if cliccato then tasto:=1
                 else tasto:=0;
     if tasto=1 then
                begin
                costruisci_Crt:=0;
                if moy=y then
                   begin
                   j:=0;
                   for i:=1 to elementi do
                       begin
                       j:=j+2+length(lista[i].nome);
                       if byte(mox-x+1) in [j-1-length(lista[i].nome)..j] then
                           begin
                           old_selezionato:=selezionato;
                           costruisci_Crt:=i;
                           selezionato:=i;
                           stampa_selezionato;
                           exit;     { ho cliccato su una colonna valida }
                           end;
                       end;
                   end;
                gotoxy(x,y);         { ho cliccato fuori dalle colonne valide }
                old_selezionato:=0;
                Textbackground(bk_color);
                textcolor(txt_Color);
                for i:=1 to elementi do
                    writeColor(' '+lista[i].nome+' ',txt_color,txt_color_Veloce,i,selezionato);
                exit;
                end;
     {$ifdef Go32v2}                           // il click e' invertito
     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 tasto:=1
                 else tasto:=0;
     if tasto=1 then
             begin
             Costruisci_Crt:=0;
             Exit;
             end;
     {$endif}
     end;
until false;
end;

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

{$ifdef FPC}
function MenuLista_X.Costruisci_Keyboard:integer;
var i,j,tasto:byte;
    c:string;
    cliccato:boolean;
    Doppio_Click:More_Click;
begin
initmouse;
initkeyboard;
Doppio_Click.init;
Doppio_Click.set_mancino(mancino);
mostra;
stampa_selezionato;
repeat
 if (PollKeyEvent<>0) or (not topo) then
     begin
     c:=KeyEventToString(TranslateKeyEvent(GetKeyEvent));
     if c=#13 then
             begin  { invio }
             if not lista[selezionato].abilitato then continue;
             Costruisci_Keyboard:=selezionato;
             Exit;
             end else
     if c=#27 then
             begin  { esc }
             Costruisci_Keyboard:=0;
             Exit;
             end else
     if c='F10' then
             begin   { F10 }  // 68
             Costruisci_Keyboard:=0;
             Exit;
             end else
     if (c='Up')or(c='Down') then
                      begin { freccia su/giu' }  // 72,80
                      if not lista[selezionato].abilitato then continue;
                      Costruisci_Keyboard:=selezionato;
                      Exit;
                      end else
     if c='Right' then
                      begin { freccia destra }  // 77
                      old_selezionato:=selezionato;
                      if selezionato<elementi then inc(selezionato)
                                              else selezionato:=1;
                      stampa_selezionato;
                      end else
     if c='Left' then
                      begin { freccia sinistra }  // 75
                      old_selezionato:=selezionato;
                      if selezionato>1 then dec(selezionato)
                                       else selezionato:=elementi;
                      stampa_selezionato;
                      end
                 else
                  begin
                  for i:=1 to elementi do { ho premuto un tasto alt+selezionato? quale? }
                      if (upcase(char(lista[i].Tasto))=upcase(from_alt_to_char(c))) then
                                begin
                                old_selezionato:=selezionato;
                                costruisci_keyboard:=i;
                                selezionato:=i;
                                stampa_selezionato;
                                exit;
                                end;
                  for i:=1 to elementi do { ho premuto un tasto selezionato? quale? }
                      if ( upcase(char(lista[i].Tasto))=upcase(c) ) or
                         ( (copy(c,1,6)='SHIFT ')and(upcase(char(lista[i].Tasto))=upcase(c[7])) ) then
                         begin
                         old_selezionato:=selezionato;
                         costruisci_Keyboard:=i;
                         selezionato:=i;
                         stampa_selezionato;
                         exit;
                         end;
                  end;
     end
    else   // il mouse
     begin
     Delay(5);
     cliccato:=Doppio_Click.Mouse_Down(mox,moy,tasto);
     if cliccato then tasto:=1
                 else tasto:=0;
     if tasto=1 then
                begin
                costruisci_Keyboard:=0;
                if moy=y then
                   begin
                   j:=0;
                   for i:=1 to elementi do
                       begin
                       j:=j+2+length(lista[i].nome);
                       if byte(mox-x+1) in [j-1-length(lista[i].nome)..j] then
                           begin
                           old_selezionato:=selezionato;
                           costruisci_Keyboard:=i;
                           selezionato:=i;
                           stampa_selezionato;
                           exit;     { ho cliccato su una colonna valida }
                           end;
                       end;
                   end;
                gotoxy(x,y);         { ho cliccato fuori dalle colonne valide }
                old_selezionato:=0;
                Textbackground(bk_color);
                textcolor(txt_Color);
                for i:=1 to elementi do
                    writeColor(' '+lista[i].nome+' ',txt_color,txt_color_Veloce,i,selezionato);
                exit;
                end;
     {$ifdef go32v2}                            // click invertito
     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 tasto:=1
                 else tasto:=0;
     if tasto=1 then
             begin
             Costruisci_Keyboard:=0;
             Exit;
             end;
     {$endif}
     end;
until false;
end;
{$endif}

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

function MenuLista_X.Costruisci:integer;
begin
{$ifdef BP7}
 Costruisci:=Costruisci_Crt;
{$else}
 Costruisci:=Costruisci_Keyboard;
{$endif}
end;

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

function MenuLista_X.AggiornaElemento(elemento:integer; testo:string; tasto:byte; abilitato:boolean):boolean;
begin
if elemento>elementi then
   begin
   AggiornaElemento:=false;
   exit;
   end;
lista[elemento].nome:=testo;
lista[elemento].Tasto:=tasto;
lista[elemento].Abilitato:=abilitato;
AggiornaElemento:=true;
end;

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

function MenuLista_X.Get_X(elemento:integer):integer;
var i:integer;
begin
get_X:=0;
if elemento>elementi then exit;
for i:=1 to elemento-1 do get_x:=get_x+length(lista[i].nome)+2;
get_x:=get_x+2;
end;

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

begin
end.


fine_riga: true=il menu deve continuare fino a fine riga

 Error
   0  : nesssun errore
   1  : troppe righe inserite
   2  : tastiera e mouse disabilitati (*)
   3  : 0 elementi (*)
   4  : elemento selezionato non valido (*)
   5  :
   6  : il nome della riga contiene caratteri non validi (<#32) (*)
   7  :
   8  :
   10 : tasto di scalta rapido non compreso tra  a..z  o  A..Z, #27, #1 (non assegnato) (*)
   12 : se la finestra non entra nel monitor (*)
(*)  quando chiamo il metodo Costruisci
