/***************************************************************************** Gestionnaire de terminal Unix: AnswerBx.c (c) Pierre Adriaans 1994 *****************************************************************************/ #include "keyboard.h" #include "screen.h" #include "answerbx.h" /***************************************************************************** InitAnswerBoxItem() ------------------------------------------------------------------------------ Input: pointeur de tete par adresse Process: liberation de la liste pointee Output: / *****************************************************************************/ void InitAnswerBoxItem(AnswerBoxItem_t **Liste) { AnswerBoxItem_t *Cour,*Temp; Cour = *Liste; while(Cour != (AnswerBoxItem_t *)NULL) { free(Cour->Str); Temp = Cour; Cour = Cour->Suivant; free(Temp); } *Liste = (AnswerBoxItem_t *)NULL; } /***************************************************************************** AddAnswerBoxItem() ------------------------------------------------------------------------------ Input: pointeur de tete par adresse et string a inserer Process: insertion en queue de la string dans la liste Output: 0 *****************************************************************************/ int AddAnswerBoxItem(AnswerBoxItem_t **Liste,char *Str) { AnswerBoxItem_t *Cour,*Prec, *Temp = (AnswerBoxItem_t *)NULL; Temp = (AnswerBoxItem_t *)malloc(sizeof(AnswerBoxItem_t)); if(Temp == (AnswerBoxItem_t *)NULL) raise(SIGME); Temp->Str = (char *)NULL; Temp->Str = (char *)malloc(strlen(Str) + 1); if(Temp->Str == (char *)NULL) raise(SIGME); strcpy(Temp->Str,Str); Temp->Suivant = (AnswerBoxItem_t *)NULL; if(*Liste == (AnswerBoxItem_t *)NULL) *Liste = Temp; else { Cour = *Liste; Prec = (AnswerBoxItem_t *)NULL; while(Cour != (AnswerBoxItem_t *)NULL) { Prec = Cour; Cour = Cour->Suivant; } Prec->Suivant = Temp; } return(0); } /***************************************************************************** GetABNbreItems() ------------------------------------------------------------------------------ Input: un pointeur de tete Process: calcul du nombre d'items presents dans cette liste *****************************************************************************/ int GetABNbreItems(AnswerBoxItem_t *Liste) { int i; for(i=0;Liste != (AnswerBoxItem_t *)NULL;Liste = Liste->Suivant,i++); return(i); } /***************************************************************************** AnswerBox() ------------------------------------------------------------------------------ La fonction en elle-meme: Voir commentaire general *****************************************************************************/ int AnswerBox(char AttBox,char AttInv,char *Title,AnswerBoxItem_t *Msg, AnswerBoxItem_t *Choices,int LigShift,int ColShift, int Frame) { return(AnswerBoxCB(AttBox,AttInv,Title,Msg,Choices, (CheckBoxItem_t *)NULL,(int *)NULL, LigShift,ColShift,Frame)); } /***************************************************************************** AnswerBoxCB() ------------------------------------------------------------------------------ La fonction en elle-meme: Voir commentaire general *****************************************************************************/ int AnswerBoxCB(char AttBox,char AttInv,char *Title,AnswerBoxItem_t *Msg, AnswerBoxItem_t *Choices,CheckBoxItem_t *CheckStr, int *CheckL,int LigShift,int ColShift,int Frame) { /* Structure utilisee pour memoriser les zones d'inversion video de chaque choix */ struct AB_Zone { int Lig; int Col; int Length; }; /* Structure utilisee pour memoriser la position de chaque 'x' dans la liste de Check Boxes */ struct AB_Check { int Lig; int Col; }; int NbreLig,NbreCol, /* Resolution ecran */ Lig,Col,Height,Length, /* Coord boite externe */ IntLig,IntCol, /* Coord boite interne */ IntHeight,IntLength, NbreMsg, /* Nbre de messages */ NbreChoices, /* Nbre de choix */ NbreCheck, /* Nbre de check box */ MaxMsgLn, /* Longueur du plus grans message */ ChoicesLn, /* Longueur de la string des choix */ CheckLn, /* Longueur de la string des check box */ i,j,Ln, /* Compteurs */ ColAff,LigAff, /* Coord ligne des choix */ ColCB,LigCB, /* Coord ligne des check box */ SelIndex,CheckIndex, /* Index de selection */ Fini = 0, /* Fin d'execution */ rc, /* Code de retour */ X,Y, /* Coord curseur avent appel */ InCheck, /* Mode de fonctionnement */ *CB, /* Pointeur de parcours */ *CheckList = (int *)NULL; /* Replique etat des check boxes */ AnswerBoxItem_t *Temp; /* Pointeur de parcours */ CheckBoxItem_t *Temp2; /* Pointeur de parcours */ char *ChBuffer = (char *)NULL, /* Ligne des choix */ *CheckBuffer = (char *)NULL, /* Ligne des check box */ *Line = (char *)NULL, /* Ligne de separation */ *Buffer = (char *)NULL; /* Tampon d'affichage */ /* Tableau de zones ecran */ struct AB_Zone *Zones = (struct AB_Zone *)NULL; /* Tableau de coordonnees */ struct AB_Check *Check = (struct AB_Check *)NULL; /* Recuperer resolution de l'ecran et la position du curseur */ GetScreenRes(&NbreLig,&NbreCol); GetXY(&Y,&X); Buffer = (char *)malloc(NbreCol); if(Buffer == (char *)NULL) raise(SIGME); /* Calculer le nombre de messages, de choix et de check boxes */ NbreMsg = GetABNbreItems(Msg); NbreChoices = GetABNbreItems(Choices); NbreCheck = GetCBNbreItems(CheckStr); /* Transfert de l'etat initial des check boxes dans CheckList */ if(NbreCheck != 0) { CheckList = (int *)malloc(sizeof(int) * NbreCheck); if(CheckList == (int *)NULL) raise(SIGME); memcpy(CheckList,CheckL,NbreCheck * sizeof(int)); } /* Determination de la hauteur de la boite externe en fonction du nbre de message */ if(NbreCheck == 0) Height = 5 + NbreMsg; else Height = 8 + NbreMsg; /* Tronquer les messages si ils sont trop longs */ for(MaxMsgLn = 0,Temp = Msg,i = 0; i < NbreMsg; Temp = Temp->Suivant,i++) if(strlen(Temp->Str) > NbreCol - 14) (Temp->Str)[NbreCol - 14] = 0; /* Calculer la longueur du plus grand message a afficher */ for(MaxMsgLn = 0,Temp = Msg,i = 0; i < NbreMsg; Temp = Temp->Suivant,i++) switch(Temp->Str[strlen(Temp->Str) - 1]) { case '\f': case '\r': if((Ln = (strlen(Temp->Str) - 1)) > MaxMsgLn) MaxMsgLn = Ln; break; default: if((Ln = strlen(Temp->Str)) > MaxMsgLn) MaxMsgLn = Ln; } /* + 2 pour avoir un espace de chaque cote */ MaxMsgLn += 2; /* Construire la string contenant les choix possibles, chacun separe par 3 espaces */ ChBuffer = (char *)malloc(NbreCol); if(ChBuffer == (char *)NULL) raise(SIGME); strcpy(ChBuffer," "); for(i = 0,Temp = Choices; i < NbreChoices; Temp = Temp->Suivant,i++) { strcat(ChBuffer,Temp->Str); strcat(ChBuffer," "); } /* Calculer la longueur de cette string */ ChoicesLn = strlen(ChBuffer); /* Construire la string contenant les check box */ if(NbreCheck != 0) { CheckBuffer = (char *)malloc(NbreCol); if(CheckBuffer == (char *)NULL) raise(SIGME); strcpy(CheckBuffer,""); for(i = 0,Temp2 = CheckStr,CB = CheckList; i < NbreCheck; Temp2 = Temp2->Suivant,i++,CB++) { if(*CB) strcat(CheckBuffer," [x] "); else strcat(CheckBuffer," [ ] "); strcat(CheckBuffer,Temp2->Str); } /* Calculer la longueur de cette string */ CheckLn = strlen(CheckBuffer); } /* Determiner la longueur de la boite externe en fonction des longueurs respectives des choix ou du plus long message */ if(MaxMsgLn > ChoicesLn) Length = MaxMsgLn + 8; else Length = ChoicesLn + 8; /* Verifier avec la longeur des check boxes */ if(NbreCheck != 0) if(CheckLn + 10 > Length) Length = CheckLn + 10; /* Calcul des coordonnees superieures gauches de la boite externe de maniere a centrer celle-ci a l'ecran */ Lig = (NbreLig / 2) - (Height / 2); Col = (NbreCol / 2) - (Length / 2) + 1; /* Rectifier les coordonnees en fonction des decalages demandes */ if((Col + ColShift > 0) && (Col + ColShift + Length < NbreCol)) Col += ColShift; if((Lig + LigShift > 0) && (Lig + LigShift + Height < NbreLig)) Lig += LigShift; /* Calcul des coordonnes de la fenetre interne */ IntLig = Lig + 1; IntCol = Col + 3; IntHeight = Height - 2; IntLength = Length - 6; /* Construire le tableau de zones correspondant a chaque choix */ Zones = (struct AB_Zone *)malloc(sizeof(struct AB_Zone) * NbreChoices); if(Zones == (struct AB_Zone *)NULL) raise(SIGME); /* ColAff: colonne d'affichage du debut de la string contenant les choix. j: colonne de gauche de la premiere zone d'ecran LigAff: ligne ou sont affiches les choix */ ColAff = (NbreCol / 2) - (strlen(ChBuffer) / 2) + ColShift + 1; j = ColAff + 2; LigAff = IntLig + IntHeight - 2; for(i=0,Temp = Choices; iSuivant) { Ln = strlen(Temp->Str); Zones[i].Lig = LigAff; Zones[i].Col = j; Zones[i].Length = Ln + 2; j += Ln + 3; } if(NbreCheck != 0) { Check = (struct AB_Check *)malloc(sizeof(struct AB_Check) * NbreCheck); if(Check == (struct AB_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 - 4; for(i=0,Temp2 = CheckStr,CB = CheckList; iSuivant,CB++) { Ln = strlen(Temp2->Str); Check[i].Lig = LigCB; Check[i].Col = j; j += Ln + 7; } } /* Ouvrir la fenetre externe sans cadre */ OpenWin(Lig,Col,Height,Length,AttBox,UNFRAMED,SHADED); /* Dessin de la fenetre interne */ PaintFrame(IntLig,IntCol,IntHeight,IntLength,AttBox,Frame); /* Affichage du titre si il y en a un, centre, tronque si besoin est */ if(strcmp(Title,"") != 0) { if(strlen(Title) > IntLength - 4) Title[IntLength - 4] = 0; WriteString(Title,AttBox,IntLig, (NbreCol / 2) - (strlen(Title) / 2) + 1 + ColShift); } /* Afficher les lignes de separation s'il y a des check boxes */ 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;iSuivant) { strcpy(Buffer,Temp->Str); switch(Temp->Str[strlen(Temp->Str) - 1]) { case '\f': /* Justifie a gauche */ Buffer[strlen(Buffer) - 1] = 0; WriteString(Buffer,AttBox,IntLig+i+1,IntCol + 2); break; case '\r': /* Justifie a droite */ Buffer[strlen(Buffer) - 1] = 0; WriteString(Buffer,AttBox,IntLig+i+1, IntCol+IntLength-2-strlen(Temp->Str)); break; default: /* Centre */ WriteString(Buffer,AttBox,IntLig+i+1, (NbreCol / 2) - (strlen(Buffer) / 2) + 1 + ColShift); } } /* Affichage des Check Box */ if(NbreCheck != 0) WriteString(CheckBuffer,AttBox,LigCB,ColCB); /* Affichage des choix */ WriteString(ChBuffer,AttBox,LigAff,ColAff); /* Et on y va ! */ SelIndex = 0; CheckIndex = 0; InCheck = 0; Fini = 0; PaintString(Zones[0].Lig,Zones[0].Col,Zones[0].Length,AttInv); GotoXY(Y,X); fflush(stdout); while(!Fini) { switch(ReadKbd()) { case TAB: if(NbreCheck != 0) if(!InCheck) { InCheck = 1; GotoXY(Check[0].Lig,Check[0].Col); CheckIndex = 0; } else { CheckIndex++; if(CheckIndex == NbreCheck) { InCheck = 0; GotoXY(Y,X); } else GotoXY(Check[CheckIndex].Lig,Check[CheckIndex].Col); } fflush(stdout); break; case SPACE: if(InCheck && NbreCheck != 0) { 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 K_RIGHT: if(NbreChoices > 1) { PaintString(Zones[SelIndex].Lig,Zones[SelIndex].Col, Zones[SelIndex].Length,AttBox); if(SelIndex == NbreChoices - 1) SelIndex = 0; else SelIndex++; PaintString(Zones[SelIndex].Lig,Zones[SelIndex].Col, Zones[SelIndex].Length,AttInv); } break; case K_LEFT: if(NbreChoices > 1) { PaintString(Zones[SelIndex].Lig,Zones[SelIndex].Col, Zones[SelIndex].Length,AttBox); if(SelIndex == 0) SelIndex = NbreChoices - 1; else SelIndex--; PaintString(Zones[SelIndex].Lig,Zones[SelIndex].Col, Zones[SelIndex].Length,AttInv); } break; case K_HOME: case CTRL_B: if(NbreChoices > 1) { if(SelIndex != 0) { PaintString(Zones[SelIndex].Lig,Zones[SelIndex].Col, Zones[SelIndex].Length,AttBox); SelIndex = 0; PaintString(Zones[SelIndex].Lig,Zones[SelIndex].Col, Zones[SelIndex].Length,AttInv); } } break; case K_END: case CTRL_E: if(NbreChoices > 1) { if(SelIndex != NbreChoices - 1) { PaintString(Zones[SelIndex].Lig,Zones[SelIndex].Col, Zones[SelIndex].Length,AttBox); SelIndex = NbreChoices - 1; PaintString(Zones[SelIndex].Lig,Zones[SelIndex].Col, Zones[SelIndex].Length,AttInv); } } break; case ESC: case DELETE: case CTRL_C: CloseWin(); rc = -1; Fini = 1; break; case CR: CloseWin(); rc = SelIndex + 1; Fini = 1; break; } } free(Buffer); free(ChBuffer); free(Zones); if(NbreCheck != 0) { free(CheckBuffer); free(Check); /* Repercuter les changements de check boxes si saisie confirmee */ if(rc != -1) memcpy(CheckL,CheckList,NbreCheck * sizeof(int)); free(CheckList); } return(rc); } /***************************************************************************** InfoBox() ------------------------------------------------------------------------------ AnswerBox simplifiee: n'enfiler que des messages, le seul choix etant "OK". *****************************************************************************/ void InfoBox(char AttBox,char AttInv,char *Title,AnswerBoxItem_t *Msg, int LigShift,int ColShift,int Frame) { AnswerBoxItem_t *Choices = (AnswerBoxItem_t *)NULL; AddAnswerBoxItem(&Choices," OK "); AnswerBoxCB(AttBox,AttInv,Title,Msg,Choices, (CheckBoxItem_t *)NULL,(int *)NULL, LigShift,ColShift,Frame); InitAnswerBoxItem(&Choices); }