/***************************************************************************** Gestionnaire de terminal Unix: inputbox.c (c) Pierre Adriaans 1994 *****************************************************************************/ #include "keyboard.h" #include "screen.h" #include "inputbox.h" /* Macro de sauvegarde/restauration d'une eventuelle interruption systeme sur l'horloge. Elles ont pour but d'empecher les affichages de cette interruption (typiquement un affichage de l'heure toutes les secondes) d'interferer avec un rafraichissement d'ecran */ unsigned int IBRemains; #ifdef SIGACT struct sigaction IBOldAlrm,IBNewAlrm; #define SaveAlrm() \ { IBNewAlrm.sa_handler = SIG_IGN; \ sigemptyset(&IBNewAlrm.sa_mask); \ IBNewAlrm.sa_flags = 0; \ sigaction(SIGALRM,&IBNewAlrm,&IBOldAlrm); \ if(IBOldAlrm.sa_handler != SIG_IGN) IBRemains = alarm(0); \ else IBRemains = 0; } #define RestoreAlrm() \ { sigaction(SIGALRM,&IBOldAlrm,&IBNewAlrm); \ if(IBOldAlrm.sa_handler != SIG_IGN) alarm(IBRemains); } #else void (*IBAlrmFct)(int); #define SaveAlrm() \ { IBAlrmFct = signal(SIGALRM,SIG_IGN); \ if(IBAlrmFct != SIG_IGN) IBRemains = alarm(0); \ else IBRemains = 0; } #define RestoreAlrm() \ { signal(SIGALRM,IBAlrmFct); \ if(IBAlrmFct != SIG_IGN) alarm(IBRemains); } #endif /***************************************************************************** InputBox() ------------------------------------------------------------------------------ Macro fonction d'appel a InputBoxCB() lorsqu'il n'y a pas de Check Box *****************************************************************************/ int InputBox(char *Str,int MaxChar,char AttBox,char AttBuffer, char *Title,char *Message, int LigShift,int ColShift,int Frame) { return(InputBoxCB(Str,MaxChar,AttBox,AttBuffer,Title,Message, (CheckBoxItem_t *)NULL,(int *)NULL, LigShift,ColShift,Frame)); } /***************************************************************************** InputBoxCB() *****************************************************************************/ int InputBoxCB(char *Str,int MaxChar,char AttBox,char AttBuffer, char *Title,char *Message, CheckBoxItem_t *CheckStr,int *CheckL, int LigShift,int ColShift,int Frame) { /* Structure de memorisation des coordonnees des cases a cocher */ struct IB_Check { int Lig; int Col; }; VideoEle_t *VM; /* La memoire video */ char *Buffer = (char *)NULL, /* Buffer de saisie */ *Buffer2 = (char *)NULL, /* Buffers pour les decalages a l'ecran lors */ *ShiftBuf, /* des delete et des backspace */ *CheckBuffer = (char *)NULL, /* Ligne d'affichage des check box */ *Line = (char *)NULL, /* Ligne de separation horizontale */ Color; /* Attribut d'affichage actif */ int i, /* Offset d'insertion courante dans le Buffer de saisie */ LastCBuf, /* Offset du dernier caractere dans le Buffer */ TempBuf, /* Pointeur auxiliaire dans le Buffer */ j, /* Compteur */ LastAffX, /* Position a l'ecran du dernier caractere du Buffer */ Ln, /* Calcul de longueur de string */ Fini, /* Temoin de fin de saisie */ ReturnValue, /* Valeur de retour */ AfficheX,AfficheY, /* Position actuelle du curseur */ ViewX1,ViewY1, /* Fenetre active lors de la saisie */ ViewX2,ViewY2, ActH,ActL, /* Hauteur et longueur de la fenetre active */ Offset, /* Calculs d'offset dans la memoire video */ KbKey, /* Touche lue au clavier */ NbreCheck, /* Nbre de check box */ *CB, /* Pointeur de parcours */ *CheckList = (int *)NULL, /* Copie de l'etat des check box */ CheckLn, /* Longueur de la string de check box */ ColCB,LigCB, /* Coord de la ligne de check box */ CheckIndex, /* Index dans les check box */ InCheck, /* Mode de fonctionnement: dans les check box ou en saisie de caracteres */ Lig,Col,Length,Height, /* Coord externes de la boite */ IntLig,IntCol, /* Coord du cadre */ IntLength,IntHeight, NbreLig,NbreCol; /* Resolution de l'ecran */ CheckBoxItem_t *Temp; /* Pointeur de parcours */ /* Tableau de coordonnees */ struct IB_Check *Check = (struct IB_Check * )NULL; MaxChar++; /* Recuperer la resolution d'ecran */ GetScreenRes(&NbreLig,&NbreCol); /* Compte tenu du nombre d'espaces de part et d'autres du buffer de saisie, tronquer MaxChar si besoin est */ if(MaxChar > (NbreCol - 12)) MaxChar = NbreCol - 12; /* Recuperer le nombre de check box */ NbreCheck = GetCBNbreItems(CheckStr); if(NbreCheck != 0) { /* Transferrer les temoins */ CheckList = (int *)malloc(sizeof(int) * NbreCheck); if(CheckList == (int *)NULL) raise(SIGME); memcpy(CheckList,CheckL,NbreCheck * sizeof(int)); /* Construire la string contenant les check box */ CheckBuffer = (char *)malloc(NbreCol); if(CheckBuffer == (char *)NULL) raise(SIGME); strcpy(CheckBuffer,""); for(i = 0,Temp = CheckStr,CB = CheckList; i < NbreCheck; Temp = Temp->Suivant,i++,CB++) { if(*CB) strcat(CheckBuffer," [x] "); else strcat(CheckBuffer," [ ] "); strcat(CheckBuffer,Temp->Str); } /* Calculer la longueur de cette string */ CheckLn = strlen(CheckBuffer); } /* Determiner les 4 coordonnees de la fenetre */ Length = MaxChar + 10; if(NbreCheck != 0) if(CheckLn > Length) Length = CheckLn; Col = (NbreCol / 2) - (Length / 2) + 1; if((Col + ColShift > 0) && (Col + ColShift + Length < NbreCol)) Col += ColShift; if(NbreCheck == 0) Height = 6; else Height = 8; Lig = (NbreLig / 2) - (Height / 2); if((Lig + LigShift > 0) && (Lig + LigShift + Height < NbreLig)) Lig += LigShift; /* Calculer les coord du cadre */ IntLig = Lig + 1; IntCol = Col + 3; IntHeight = Height - 2; IntLength = Length - 6; if(NbreCheck != 0) { /* Construire le tableau de coordonnees */ Check = (struct IB_Check *)malloc(sizeof(struct IB_Check) * NbreCheck); if(Check == (struct IB_Check *)NULL) raise(SIGME); /* ColCB: colonne d'affichage du debut de la string contenant les check boxes. j: colonne de gauche de la premiere zone d'ecran LigCB: ligne ou sont affiches les check boxes */ ColCB = IntCol + 1; j = ColCB + 4; LigCB = IntLig + IntHeight - 2; for(i=0,Temp = CheckStr,CB = CheckList; iSuivant,CB++) { Ln = strlen(Temp->Str); Check[i].Lig = LigCB; Check[i].Col = j; j += Ln + 7; } } /* Initialiser tout le monde */ Buffer = (char *)malloc(NbreCol+1); if(Buffer == (char *)NULL) raise(SIGME); Buffer2 = (char *)malloc(NbreCol+1); if(Buffer2 == (char *)NULL) raise(SIGME); ShiftBuf = Buffer2; AfficheX = ViewX1 = Col + 5; AfficheY = ViewY1 = Lig + 3; ActH = 1; ActL = Length - 10; ViewX1++; ViewY2 = ViewY1 + ActH - 1; ViewX2 = ViewX1 + ActL - 1; Color = AttBuffer; VM = GetVideoMemoryAdress(); /* Dessiner la boite */ if(OpenWin(Lig,Col,Height,Length,AttBox,UNFRAMED,SHADED) != 0) return(-1); PaintFrame(IntLig,IntCol,IntHeight,IntLength,AttBox,Frame); WriteString(Title,AttBox,Lig+1, Col + 2 + (((Length-6) / 2) - (strlen(Title) / 2))); WriteString(Message,AttBox,Lig+2,Col+5); ClrZone(AfficheY,AfficheX,1,ActL,Color); if(NbreCheck != 0) { Line = (char *)malloc(NbreCol); if(Line == (char *)NULL) raise(SIGME); if(Frame == DOUBLE_FRAMED) Line[0] = F_BDSD; else Line[0] = F_BSSS; for(i=1;i, ni */ { if(isdisplay(KbKey) || KbKey == DELETE || KbKey == K_REMOVE ) /* Reset buffer ? */ { AfficheX = ViewX1; LastAffX = AfficheX; ClrZone(AfficheY,AfficheX,1,ViewX2 - AfficheX,Color); i = 0; LastCBuf = 0; GotoXY(AfficheY,AfficheX); } else { /* Reafficher en normal */ if(Ln!=0) WriteString(Buffer,Color,AfficheY,ViewX1); } do /* Traitement de la premiere touche puis des suivantes */ { if(isdisplay(KbKey) && LastAffX <= ViewX2 && !InCheck) { if(i != LastCBuf) /* Si Insertion et curseur au milieu: decalage a droite de la fin */ { TempBuf = LastCBuf; /* Transfert dans ShiftBuf de la string a partir de la position d'insertion courante jusqu'a la fin */ ShiftBuf = Buffer2; strncpy(ShiftBuf,Buffer+i,LastCBuf-i); ShiftBuf[LastCBuf-i] = 0; /* shift a droite dans le buffer de saisie */ for(;TempBuf>i;TempBuf--) Buffer[TempBuf] = Buffer[TempBuf-1]; /* Actualisation de l'affichage: impression de ShiftBuf une position plus a droite */ SaveAlrm(); GotoXY(AfficheY,AfficheX + 1); for(Offset = VidMemOffset(AfficheY,AfficheX + 1); *ShiftBuf; ShiftBuf++,Offset++) { VM[Offset].Code = *ShiftBuf; VM[Offset].Attr = Color; PutToScr(*ShiftBuf); } /* Replacer le curseur a son origine */ GotoXY(AfficheY,AfficheX); RestoreAlrm(); } /* Insertion du caractere dans le buffer de saisie */ Buffer[i] = (char)KbKey; i++; /* Affichage du caractere a l'ecran */ PutToScr((char)KbKey); Offset = VidMemOffset(AfficheY,AfficheX); VM[Offset].Code = (char)KbKey; VM[Offset].Attr = Color; /* Un caractere de plus */ LastCBuf++; LastAffX++; /* Le curseur a bouge */ AfficheX++; SetXY(AfficheY,AfficheX); } else /* Touche de controle ou en mode check box */ { switch(KbKey) { case TAB: if(NbreCheck != 0) { if(!InCheck) { InCheck = 1; CheckIndex = 0; } else CheckIndex++; if(CheckIndex == NbreCheck) { InCheck = 0; GotoXY(AfficheY,AfficheX); } else GotoXY(Check[CheckIndex].Lig,Check[CheckIndex].Col); fflush(stdout); } break; case SPACE: /* Pas besoin de test: un space en mode entree de caracteres est traite plus haut: ici, on est forcement en mode check box */ CheckList[CheckIndex] = !CheckList[CheckIndex]; if(CheckList[CheckIndex]) PutChar('x',Check[CheckIndex].Lig,Check[CheckIndex].Col); else PutChar(' ',Check[CheckIndex].Lig,Check[CheckIndex].Col); break; case BACKSP: /* Backspace */ if(!InCheck) if(AfficheX > ViewX1) { if(iViewX1) { AfficheX--; i--; } break; case K_RIGHT: if(!InCheck) if(i