/*--------------------- Editeur ------------------------ Programmeur gérant les versions : Gérard COUVERT Date de création : 12 Janvier 2004 Date de dernière modification : 22 Semptembre 2007 Version GC/01 ajouté le 22/07/2007 le type FLOTTANT_100 qui reçoit un entier en 100eme., l'édite en flottant et le restitue en entier. ajouté le 17/01 des "UpdateWindow();" peut être inutiles. ATTENTION les modif de EditeurMFC concernant les mots trops longs pour rentrer dans une ligne ne sont pas reproduit ici. ATTENTION a faire partout les modifications suivantes ! paramètres de ChangeType, ChangeVisu, changeCouleurs pourrait envoyer la valeur de temps en temps (modification au vol) pourrait envoyer la valeur avec ENTREE (sans perte du focus) pourrait envoyer un message pour les ereurs de saisie FUTUR : les filtres le filtre est fait d'une suite de codes (sur deux caractères) correspondant chacun à une position d'édition : µ£ fin du filtre µµ n'importe quel signe µsigne le signe est inamovible et la position sautée µ§ le code précédent se repète à l'infini 09 un chiffre 9, un chiffre (inférieur ou égal) le séparateur décimal 9- un chiffre (inférieur ou égal), les signes + ou - 9+ un chiffre (inférieur ou égal), les signes + ou -, le séparateur décimal 0f un chiffre 'héxa'(compris inclusivement - minuscules) 0F un chiffre 'héxa'(compris inclusivement - majuscules) az une lettre minuscule comprise inclusivement AZ une lettre majuscule comprise inclusivement aZ une lettre minuscule ou minuscule comprise inclusivement A§ une lettre majuscule les signes typographiques ',;:!?"esp a§ une lettre minuscule les signes typographiques ,; les signes séparateurs ";,:." >* les signes mathématiques <>/*-+= Ø-Þ un caractère 'docimo' compris inclusivement char frmDate[] ="0309µ/0109µ/12090909µ µ-µ 09µ:09µµ"; */ #include "stdafx.h" #include "Editeur.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define VERSION 0x11 #define ERR_EDITE -16000 #define ERR_DECIMAL ERR_EDITE - 1 #define ERR_CAR ERR_EDITE - 2 #define ERR_FORMAT ERR_EDITE - 3 #define ERR_ ERR_EDITE - 4 #define COULEUR_FOND 0xFFFFFF #define COULEUR_FOND_LECTURE_SEULE 0xE0E0E0 #define HAUTEUR_LIGNE 12 #define INTERLIGNE 2 #define TAILLE_FONTE 14 BEGIN_MESSAGE_MAP(CEdite, CWnd) //{{AFX_MSG_MAP(CEdite) //ON_WM_SHOWWINDOW() ON_WM_SETFOCUS() ON_WM_PAINT() ON_WM_LBUTTONDOWN() ON_WM_KILLFOCUS() // ON_WM_NCDESTROY() ON_WM_MOUSEWHEEL() ON_WM_MOUSEMOVE() ON_WM_LBUTTONDBLCLK() ON_WM_ACTIVATE() //}}AFX_MSG_MAP END_MESSAGE_MAP() LONG APIENTRY MessagesEdite(HWND idFen, UINT Message, UINT wParam, LONG lParam) { // ceci ne sert qu'une fois lors de la création par Visual CEdite* FenEd; int retour; int type; CREATESTRUCT* pS; pS = (CREATESTRUCT*)lParam; retour = 0; switch (Message) { case WM_CREATE: switch(pS->lpszName[0]) { case 'F': type = FLOTTANT; break; case 'E': type = ENTIER; break; case 'T': type = TEXTE; break; case 'C': type = CHAINE; break; case '%': type = FLOTTANT_100; break; case '¤': return retour; // appel par le créateur standard default: return -1; } type |= (pS->style & 0xFFFF); // 16 bits transmis par Visual FenEd = new CEdite(type, (int)pS->hMenu); retour = FenEd->SubclassWindow(idFen); return retour; } return DefWindowProc(idFen, Message, wParam, lParam); } /* void CEdite::OnShowWindow(BOOL bShow, UINT nStatus) { if(bShow == FAUX) SendMessage(WM_KILLFOCUS, NUL, NUL); } */ BOOL CEdite::PreTranslateMessage(MSG* pMsg) { if(pMsg->message == WM_KEYDOWN) { if(UneToucheAction(pMsg->wParam)) return 1; } if(pMsg->message == WM_CHAR) { if(UneTouche(pMsg->wParam)) return 1; } return 0; } int CEdite::Init(int code, char* chaine /*= NUL*/) { int retour; WNDCLASS sC; sC.style = CS_DBLCLKS; sC.lpfnWndProc = MessagesEdite; sC.cbClsExtra = 0; sC.cbWndExtra = NUL; sC.hInstance = AfxGetInstanceHandle( ); sC.hIcon = NUL; sC.hCursor = LoadCursor(NULL, IDC_IBEAM); sC.hbrBackground = NUL; sC.lpszMenuName = NUL; sC.lpszClassName = "C_EDITEUR"; retour = ERR_ED_ID; if(RegisterClass(&sC)) { if(chaine) sprintf(chaine,"bibliothèque 'Editeur', version %d.%d", (VERSION >> 4), VERSION & 0xF); retour = VERSION; } return retour; } CEdite::CEdite(int type, int id) { // ce constructeur est utilisé directement par Visual Studio Fait(type, id); } CEdite::CEdite(CWnd* parent, RECT rect, int id, int type) { // ce constructeur est utilisé normalement Fait(type, id); Create("C_EDITEUR", "¤", WS_CHILD|WS_VISIBLE, rect, parent, id); } /* type : 28-31 type d'éditeur (chaine, textes, flottant, entier) 24-27 réservés usage futur l'octet [3] est accessible à la création puis avec "changeType" l'octet [2] est inaccessible 16-23 drapeaux internes l'octet [1] est accessible à la création puis avec "changeAnnexe" 12-15 annexe 1: pour les flottants = nombre de décimales 8-11 annexe 2: conditions de validation des données l'octet [0] est accessible à la création puis avec "changeVisu" 4-7 aspect général, sont acessibles 0-3 comportement au focus l'octet [0] est provisoirement modifiable avec "Edite" */ int CEdite::Fait(int type, int id) { lconv* ptS; Etat = 0; ID = id; FlottantParDefaut = 0; EntierParDefaut = 0; TabLigne = NUL; Texte = NUL; ChaineParDefaut = NUL; ptS = localeconv(); if(*ptS->decimal_point != ',') Etat = MODE_P; // permet de ne pas toucher aux réglages ChangeType(type, SANS_REAFFICHE, 0); CouleurFond = COULEUR_FOND; HtLigne = HAUTEUR_LIGNE; Interligne = INTERLIGNE; FonteDef = CreateFont(TAILLE_FONTE, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE|DEFAULT_PITCH, "M S Sans Serif"); //ChangeFonte(NUL); Fonte = FonteDef; ChangeAnnexe(type , SANS_REAFFICHE|0xFF00); // 0x8000FF00 ChangeVisu(type , SANS_REAFFICHE|0xFF); // 0x800000FF return 0; } /* code b0: 0 = changer les tampons ; 1 = ne pas changer MEM_IDEM b1+b2: 0 = laisser la valeur actuelle 1 = initialiser avec la valeur par défaut AFFICHE_DEFAUT 2 = initialiser à 0 ou vide AFFICHE_VIDE 3 = réserve lg = 0 taille par défaut, lg > 0 nouvelle taille */ void CEdite::ChangeType(int type, int code, int lg /*= 0*/) { int maxCar, affichage; char* ptActuel; type &= MSQ_TYPE; if(!type) type = CHAINE; Etat &= 0x0080FFFF; // le mode point n'est pas affecté Etat |= type; NbCar = 0; Position = 0; LignePosition = 0; PremierCaractere = 0; NbSelection = 0; MaxLigne = 1; NbLigne = 0; maxCar = MaxCar; affichage = 0; if(code & b0) { // ne pas toucher aux tampons ATTENTION ! switch(code & (b1+b2)) { case 0: *Texte = 0; *ChaineParDefaut = 0; case b1: // b1 et pas 1 24/06/2007 affichage = VAL_DEF; //AfficheDefaut(VAL_DEF); } } else { // changer les tampons switch(type) { case CHAINE: MaxCar = 60; break; case FLOTTANT: case FLOTTANT_100: case ENTIER: MaxCar = 20; break; case TEXTE: MaxCar = 300; MaxLigne = 20; } if(lg) { MaxCar = lg; if(type == TEXTE) MaxLigne = MaxCar / 15; } ptActuel = new char[MaxCar]; if(maxCar > MaxCar) maxCar = MaxCar; switch(code & (b1+b2)) { // 24/06/2007 correction d'un bogue ! 'case 1 et 2' (juste = 'case b1 et b2') case 0: delete ChaineParDefaut; delete Texte; ChaineParDefaut = ptActuel; Texte = new char[MaxCar]; *Texte = 0; *ChaineParDefaut = 0; break; case b1: memcpy(ptActuel, ChaineParDefaut, maxCar); delete ChaineParDefaut; delete Texte; ChaineParDefaut = ptActuel; Texte = new char[MaxCar]; affichage = VAL_DEF; break; case b2: memcpy(ptActuel, Texte, maxCar); delete ChaineParDefaut; delete Texte; ChaineParDefaut = new char[MaxCar]; case b2+b1: // au cas ou ! Texte = ptActuel; } MaxCar--; if(TabLigne) delete TabLigne; TabLigne = new int[MaxLigne + 1]; } if((code & SANS_REAFFICHE) == 0) AfficheDefaut(affichage); } /* affecte seulement l'octet [1] de Etat si b31 de masque == 0 il y a un réaffichage */ void CEdite::ChangeAnnexe(int valeur, int masque) { int temoin; temoin = masque & SANS_REAFFICHE; masque &= 0x8000FF00; // au cas ou ! valeur &= masque; Etat &= ~masque; Etat |= valeur; if(!temoin) AfficheDefaut(0); } /* affecte seulement l'octet [0] de Etat si b31 de masque == 0 il y a un réaffichage */ void CEdite::ChangeVisu(int valeur, int masque) { int temoin; temoin = masque & SANS_REAFFICHE; masque &= 0x000000FF; // au cas ou ! valeur &= masque; Etat &= ~masque; // mettre à 0 les bits concernés Etat |= valeur; if(!temoin) AfficheDefaut(0); } void CEdite::ChangePosition(RECT* rect) { SetWindowPos(NUL, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, SWP_NOZORDER/*|SWP_SHOWWINDOW*/); AfficheDefaut(0); } void CEdite::ChangeFonte(HFONT fonte) { if(fonte) Fonte = fonte; else Fonte = FonteDef; AfficheDefaut(0); } CEdite::~CEdite() { delete Texte; delete ChaineParDefaut; if(TabLigne) delete TabLigne; DeleteObject(FonteDef); } void CEdite::PostNcDestroy() { delete this; } void CEdite::OnPaint() { POINT point; RECT rect; CPaintDC dc(this); GetClientRect(&rect); dc.FillSolidRect(&rect, CouleurFond); dc.Draw3dRect(&rect, 0x808080, 0xC0C0C0); rect.top += 1; rect.bottom -= 1; rect.left += 1; rect.right -= 1; dc.Draw3dRect(&rect, 0xC0C0C0, 0xFFFFFF); rect.top += 2; rect.bottom -= 2; rect.left += 2; rect.right -= 2; dc.SelectObject(Fonte); dc.SetBkColor(CouleurFond); if((Etat & MSQ_TYPE) == TEXTE) EditeMultiLigne(&dc, Texte, &rect, point); // multi-ligne else EditeMonoLigne(&dc, Texte, &rect, point); // mono-ligne if((Etat & LECTURE_SEULE) == 0) { if(!point.x) point.x = rect.left; SetCaretPos(point); } } void CEdite::OnSetFocus(CWnd* pOldWnd) { if(Etat & LECTURE_SEULE) { Etat &= ~FIXE_POSITION; Etat &= ~SELECTION; } //test 12/07/2007 Etat &= ~ENT; Etat &= ~TAB; ////// AfficheDefaut(FOCUS); } void CEdite::OnActivate(UINT etat, CWnd* pWndOther, BOOL bMinimized) { // utile ? if(etat != WA_INACTIVE) AfficheDefaut(FOCUS); } void CEdite::OnLButtonDown(UINT nFlags, CPoint point) { CWnd* fen; RETOUR retour; fen = GetFocus(); if(fen && (fen->m_hWnd == this->m_hWnd)) { Etat &= ~CLIC_DEBUT; OuDansTexte(point, &retour); LignePosition = retour.ligne; Position = retour.pos; NbSelection = 0; Invalidate(); UpdateWindow(); } else { SetFocus(); Etat |= CLIC_DEBUT; } } void CEdite::OnLButtonDblClk(UINT nFlags, CPoint point) { RETOUR retour; OuDansTexte(point, &retour); Position = retour.posMot; NbSelection = retour.nbLettres; LignePosition = retour.ligne; Invalidate(); UpdateWindow(); } void CEdite::OnMouseMove(UINT etat, CPoint point) { RETOUR retour; int ret, nbSel; if(etat & MK_LBUTTON) { if(Etat & CLIC_DEBUT) return; ret = OuDansTexte(point, &retour); nbSel = retour.pos - Position; if(nbSel != NbSelection) { NbSelection = nbSel; Invalidate(); UpdateWindow(); } } } int CEdite::OuDansTexte(POINT point, RETOUR* ptRetour) { CDC* pRG; RECT rect; int retour; pRG = GetDC(); pRG->SelectObject(Fonte); GetClientRect(&rect); rect.top += 3; rect.bottom -= 3; rect.left += 3; rect.right -= 3; ptRetour->pos = 0; ptRetour->posMot = 0; ptRetour->nbLettres = 0; ptRetour->largeur = 0; ptRetour->ligne = LignePosition; if((Etat & MSQ_TYPE) == TEXTE) { // multi-ligne retour = TrouvePositionMulti(pRG, Texte, &rect, point, ptRetour); } else { // mono-ligne retour = TrouvePositionMono(pRG, Texte, &rect, point, ptRetour); } ReleaseDC(pRG); return retour; } void CEdite::OnKillFocus(CWnd* pNewWnd) { int message; message = ValideValeur(); Position = 0; // pour remettre la séléction en plein HideCaret(); DestroyCaret(); if(message < 0) { // hors limite, ou erreur de filtre // AfficheDefaut(VAL_DEF); // remettre la valeur par défaut SetFocus(); } else { // c'est bon NbSelection = 0; Invalidate(); UpdateWindow(); // if((Etat & LECTURE_SEULE) == 0) // { // test supression le 11/07/2007 switch(Etat & (ENT+TAB)) { case 0: message = MES_ED_PERTEFOCUS_EXT; break; case ENT: message = MES_ED_PERTEFOCUS_ENT; break; case TAB: message = MES_ED_PERTEFOCUS_TAB; break; case ENT+TAB: message = MES_ED_PERTEFOCUS_ECH; } // } } if(message) GetParent()->SendMessage(message, ID, (int)m_hWnd); } // validation de l'entrée int CEdite::ValideValeur() { int retour, valE; float valF; if(Etat & LECTURE_SEULE) return 0; //ajout 11/07/2007 retour = 0; // bon par défaut if(Texte[NbCar] == ',') // pour chiffre ! nettoyer espaces Texte[NbCar--] = 0; switch(Etat & MSQ_TYPE) { case CHAINE: case TEXTE: if(strcmp(ChaineParDefaut, Texte)) retour = 1; break; case FLOTTANT: case FLOTTANT_100: valF = ValeurFlottante(); if(Etat & VERIF_MINI) if(valF < MiniF) retour = MES_ED_MINI; if(Etat & VERIF_MAXI) if(valF > MaxiF) retour = MES_ED_MAXI; if(valF == FlottantParDefaut) retour = 1; break; case ENTIER: valE = ValeurEntiere(); if(Etat & VERIF_MINI) if(valE < Mini) retour = MES_ED_MINI; if(Etat & VERIF_MAXI) if(valE > Maxi) retour = MES_ED_MAXI; if(valE == EntierParDefaut) retour = 1; } return retour; } void CEdite::Edite(EDITEUR_S1* pS) { switch(Etat & MSQ_TYPE) { case CHAINE: case TEXTE: Edite(pS->defaut_C, pS->code); break; case FLOTTANT_100: pS->defaut_F = (float)pS->defaut_E / 100; pS->maxi_F = (float)pS->maxi / 100; pS->mini_F = (float)pS->mini / 100; case FLOTTANT: Edite(pS->defaut_F, pS->code); MaxiF = pS->maxi_F; MiniF = pS->mini_F; break; case ENTIER: Edite(pS->defaut_E, pS->code); Maxi = pS->maxi; Mini = pS->mini; } } void CEdite::Edite(char* defaut, int code) { // texte if(!defaut) defaut = ""; //// if(!defaut) defaut = ChaineVide(); // defaut[LG_MAX_TEXTE] = 0; // prudence strcpy(ChaineParDefaut, defaut); code |= VAL_DEF; AfficheDefaut(code); } void CEdite::Edite(float defaut, int code, float maxi, float mini) { // flottant int nbDecimales; char* ptCar; FlottantParDefaut = defaut; nbDecimales = Etat & MSQ_ANNEXE; nbDecimales >>= 12; // b15-12 (en fait 14-12 MaxiF = maxi; MiniF = mini; if(defaut) { sprintf(ChaineParDefaut, "%.*f", nbDecimales, defaut); if(Etat & MODE_P) { ptCar = strchr(ChaineParDefaut, '.'); if(ptCar) *ptCar = ','; } } else { ChaineParDefaut[0] = '0'; ChaineParDefaut[1] = 0; } code |= VAL_DEF; AfficheDefaut(code); #pragma warning (disable : 4244) nbDecimales = defaut; EntierParDefaut = defaut; #pragma warning(default : 4244) if(defaut != nbDecimales) Etat |= SEP_DECI; } void CEdite::Edite(int defaut, int code, int maxi, int mini) { // entier ou flottant_100 if((Etat & MSQ_TYPE) == FLOTTANT_100) { Edite((float)defaut / 100, code, (float)maxi / 100, (float)mini / 100); return; } Maxi = maxi; Mini = mini; EntierParDefaut = defaut; FlottantParDefaut = defaut; sprintf(ChaineParDefaut, "%d", defaut); code |= VAL_DEF; AfficheDefaut(code); } char* CEdite::ValeurTextuelle() { return Texte; // dangereux } int CEdite::ValeurEntiere() { int val, retour; if ((Etat & MSQ_TYPE) == FLOTTANT_100) { float valF = ValeurFlottante(); if(valF < 0) return ERR_ED_CHAINE; valF *= 100; val = valF; return val; } val = 0; retour = sscanf(Texte, "%d", &val); if(retour > 0) return val; return ERR_ED_CHAINE; } float CEdite::ValeurFlottante() { float val; char* ptCar; int retour; val = 0; if(Etat & MODE_P) { ptCar = strchr(Texte, ','); if(ptCar) *ptCar = '.'; retour = sscanf(Texte, "%f", &val); if(ptCar) *ptCar = ','; } else retour = sscanf(Texte, "%f", &val); if(retour > 0) return val; return (float) ERR_ED_CHAINE; } void CEdite::Zero() { PremierCaractere = 0; NbCar = 0; Position = 0; TabLigne[0] = 0; LignePosition = 0; } /* code : VAL_DEF réaffiche le texte initial SURCLASSE surclassement provisoire de Etat b0-b7 b0-7 valides si SURCLASSE FOCUS applique les bits 0-3 prend le "focus" */ void CEdite::AfficheDefaut(int code) { int etat; if(code & VAL_DEF) { strcpy(Texte, ChaineParDefaut); NbCar = strlen(Texte); } etat = Etat; // copie locale if(code & SURCLASSE) { // les bits 0-7 sont extraits de code etat &= 0xFFFFFF00; etat |= (code & 0xFF); } if(code & FOCUS) { if(etat & FIXE_POSITION) { if(etat & FIN_LIGNE) Position = NbCar; else Position = 0; } if(etat & SELECTION) { if(Position) NbSelection = -NbCar; else NbSelection = NbCar; } // if(code & FOCUS)//testé le 20/09 //{//20/09 Etat |= INTERNE; // interdit l'appel dans "SetFocus" CWnd* fen = GetFocus(); if(fen && (fen->m_hWnd == this->m_hWnd)) { CreateSolidCaret(1, HAUTEUR_LIGNE); ShowCaret(); } else { SetFocus(); } Etat ^= INTERNE; } if(etat & LECTURE_SEULE) CouleurFond = COULEUR_FOND_LECTURE_SEULE; else CouleurFond = COULEUR_FOND; code = SW_SHOW; if(etat & INVISIBLE) code = SW_HIDE; ShowWindow(code); Invalidate(); UpdateWindow(); } int CEdite::UneTouche(int cv) { int retour, b; if((Etat & LECTURE_SEULE) == 0) { switch(Etat & MSQ_TYPE) { case CHAINE: case TEXTE: retour = VerifCarAlpha(cv); break; case FLOTTANT: case FLOTTANT_100: case ENTIER: retour = VerifCarNum(cv); } if(retour >= 0) { if(NbSelection) EffaceSelection(); for(b = NbCar; b > Position; b--) Texte[b] = Texte[b - 1]; Texte[Position] = retour; if(NbCar < MaxCar) NbCar++; if(Position < NbCar) Position++; Texte[NbCar] = 0; Invalidate(); return 1; } } return 0; } /* teste si la touche est une touche d'action 0 = ce n'est pas une touche d'action : transmettre le caractère 2 = action exécutée : ne rien faire 1 = action exécutée et réaffichage : ne rien faire */ int CEdite::UneToucheAction(int cv) { int debSel, etat, nbCar, b; HGLOBAL mem; char* ptCar,* ptPos; debSel = Position; switch(cv) { case VK_ESCAPE: // réaffichage ancienne valeur AfficheDefaut(VAL_DEF); Etat |= ENT; case VK_TAB: Etat |= TAB; goto suite; case VK_RETURN: // sortie etat = GetAsyncKeyState(VK_CONTROL); if(etat & b15) { // UneTouche('10'); UneTouche(13); return 1; // et pas 0 } else Etat |= ENT; suite: GetParent()->SetFocus(); return 2; case 'A': // tout sélectionner case 'X': // couper case 'C': // coller case 'V': // copier etat = GetAsyncKeyState(VK_CONTROL); if(etat & b15) { switch(cv) { case 'A': Position = 0; NbSelection = NbCar; Invalidate(); return 2; case 'C': case 'X': if(NbSelection) { OpenClipboard(); if(NbSelection > 0) { nbCar = NbSelection; ptPos = &Texte[Position]; } else { nbCar = NbSelection * -1; ptPos = &Texte[Position + NbSelection]; } nbCar++; EmptyClipboard(); mem = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, nbCar); ptCar = (char*)GlobalLock(mem); memcpy(ptCar, ptPos, nbCar); SetClipboardData(CF_TEXT, mem); CloseClipboard(); GlobalUnlock(mem); // GlobalFree(mem); if(cv == 'X') EffaceSelection(); } break; case 'V': OpenClipboard(); mem = GetClipboardData(CF_TEXT); ptCar = (char*)GlobalLock(mem); if(ptCar) { // if(NbSelection) EffaceSelection(); nbCar = strlen(ptCar); for(b = 0; b < nbCar; b++) UneTouche(ptCar[b] & 0xFF); } CloseClipboard(); } return 2; } default: return 0; // transmet le caractère case VK_INSERT: // réaffichage ancienne valeur AfficheDefaut(VAL_DEF); // et la selection ? return 2; case VK_BACK: if(Position) --Position; case VK_DELETE: // suppression de la selection EffaceSelection(); return 2; case VK_HOME: // déplacement curseur Position = 0; break; case VK_END: Position = NbCar; break; case VK_LEFT: if(Position) Position--; break; case VK_RIGHT: if(Position < NbCar) Position++; break; case VK_UP: if(LignePosition) { nbCar = Position - TabLigne[LignePosition]; LignePosition--; Position = TabLigne[LignePosition] + nbCar; } break; case VK_DOWN: if(LignePosition < (NbLigne - 1)) { nbCar = Position - TabLigne[LignePosition]; LignePosition++; Position = TabLigne[LignePosition] + nbCar; if(Position > NbCar) Position = NbCar; } break; } etat = GetAsyncKeyState(VK_SHIFT); if(etat & b15) { debSel += NbSelection; NbSelection = debSel - Position; } else { NbSelection = 0; } Invalidate(); return 1; } void CEdite::EffaceSelection() { int b, nbSel; if((Etat & LECTURE_SEULE) == 0) { if(NbSelection) { nbSel = NbSelection; if(NbSelection < 0) { nbSel *= -1; Position -= nbSel; } } else { if(!NbCar) return; nbSel = 1; } for(b = Position; b < (NbCar + nbSel); b++) Texte[b] = Texte[b + nbSel]; Texte[b] = 0; NbCar -= nbSel; if(((Etat & MSQ_TYPE) == FLOTTANT) || ((Etat & MSQ_TYPE) == FLOTTANT_100)) { Etat &= mb16; // efface SEP_DECI for(b = 0; b < NbCar; b++) if(Texte[b] == ',') Etat |= SEP_DECI; } } NbSelection = 0; Invalidate(); } /* traite la conversion du séparateur décimal et son unicité traite l'interdiction des caractères non-numériques ne traite pas les signes mathématiques */ int CEdite::VerifCarNum(int cv) { int retour = cv; switch(cv) { case VK_NUMPAD0: retour = '0'; break; case VK_NUMPAD1: retour = '1'; break; case VK_NUMPAD2: retour = '2'; break; case VK_NUMPAD3: retour = '3'; break; case VK_NUMPAD4: retour = '4'; break; case VK_NUMPAD5: retour = '5'; break; case VK_NUMPAD6: retour = '6'; break; case VK_NUMPAD7: retour = '7'; break; case VK_NUMPAD8: retour = '8'; break; case VK_NUMPAD9: retour = '9'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case '.': case VK_DECIMAL: retour = ','; case ',': if(((Etat & MSQ_TYPE) == FLOTTANT) || ((Etat & MSQ_TYPE) == FLOTTANT_100)) { if(Etat & SEP_DECI) retour = ERR_DECIMAL; Etat |= SEP_DECI; if(!NbCar) UneTouche('0'); break; } default: retour = ERR_CAR; } return retour; } int CEdite::VerifCarAlpha(int cv) { int retour = cv; if(cv < 32) { if( cv != 13) retour = 32; // PROVISOIRE } return retour; } #define LG_ESP 4 /* séquence entre mots : 0, lg, cmd, prm si lg = 0 c'est la fin du texte cmd 32 espace extensible 09 tabulation 13 saut de ligne 14 saut de paragraphe le 32 est un espace fixe mdl = "Toto\000\003 est\000\003 bien\000\003 imprudent," \ "\000\003 mais\000\003 nous\000\003 verrons" \ "\000\003 bien\000\003 si\000\003 cela\000\003 convient" \ "\000\003 à\000\003 ce\000\003 genre\000\003 d'exercice" \ "\000\003 d'adresse\000\003 !\000\000"); */ int CEdite::EditeMonoLigne(CDC* pRG, char* texte, RECT* rectEdite, POINT& point) { char* ptLigne, * ptFinMot; int b, nbMot, motDebut, posX, finSelection, finMot, posY, extraEsp, resteLargeur, htLigne; char car; SIZE taille; RECT rectSel; motDebut = 0; MOTS Mots[100]; LignePosition = -1; TabLigne[0] = 0; NbLigne = 0; finSelection = Position + NbSelection; // évaluation des mots posX = 0; // + premier décalage nbMot = 0; ptLigne = texte; do { ptFinMot = strpbrk(ptLigne, " \r\t\n"); if(!ptFinMot) ptFinMot = strchr(ptLigne, 0); car = *ptFinMot; switch(car) { case 13: b = b13; break; default: b = 0; } Mots[nbMot].pos = ptLigne - texte; Mots[nbMot].nbLettres = ptFinMot - ptLigne; finMot = Mots[nbMot].pos + Mots[nbMot].nbLettres + 1; // et 13 ou 9 ? GetTextExtentPoint32(pRG->m_hDC, ptLigne, Mots[nbMot].nbLettres, &taille); Mots[nbMot].largeur = taille.cx; if((Position >= Mots[nbMot].pos) && (Position < finMot)) { b |= b0; // c'est lui qui à le curseur motDebut = nbMot; // par défaut } if((finSelection >= Mots[nbMot].pos) && (finSelection < finMot)) b |= b1; // c'est lui qui à l'autre bout de la sélection Mots[nbMot].code = b; posX += taille.cx + LG_ESP; nbMot++; ptLigne = ptFinMot + 1; } while(car); posX -= LG_ESP; // évaluation de la ligne NbLigne = 0; LignePosition = 0; PremierCaractere = 0; resteLargeur = (rectEdite->right - rectEdite->left) - posX; posX = rectEdite->left; // + premier décalage extraEsp = LG_ESP; // cadrage à gauche, à droite, centrage if(resteLargeur >= 0) { motDebut = 0; switch(Etat & JUSTIFIE) { case A_GAUCHE: break; case JUSTIFIE: extraEsp = LG_ESP + (resteLargeur / (nbMot - 1)); break; case AU_CENTRE: posX += (resteLargeur / 2); break; case A_DROITE: posX += resteLargeur; } } else { if(motDebut) motDebut--; } ptLigne = texte + Mots[motDebut].pos; TabLigne[NbLigne] = Mots[motDebut].pos; rectSel.right = rectEdite->right; // point.x = posX; for(b = motDebut; b < nbMot; b++) { Mots[b].posX = posX; if(Mots[b].code & b0) { if(NbCar - Position) { finMot = Position - Mots[b].pos; GetTextExtentPoint32(pRG->m_hDC, ptLigne, finMot, &taille); point.x = posX + taille.cx; } else { point.x = posX + Mots[b].largeur; } } if(Mots[b].code & b1) { if(NbCar - finSelection) { finMot = finSelection - Mots[b].pos; GetTextExtentPoint32(pRG->m_hDC, ptLigne, finMot, &taille); rectSel.right = posX + taille.cx; } else { rectSel.right = posX + Mots[b].largeur; } } posX += Mots[b].largeur + extraEsp; ptLigne += Mots[b].nbLettres + 1; } // affichage htLigne = HtLigne + Interligne; ptLigne = texte + Mots[motDebut].pos; // posY = rectEdite->top - 1; // ou centrage posY = 2 + (rectEdite->bottom - rectEdite->top - HtLigne) / 2; point.y = posY; // rectEdite->top; for(b = motDebut; b < nbMot; b++) { pRG->TextOut(Mots[b].posX, posY, ptLigne, Mots[b].nbLettres); ptLigne += Mots[b].nbLettres + 1; } if(NbSelection) { rectSel.top = rectEdite->top; rectSel.bottom = rectEdite->top + htLigne; rectSel.left = point.x; pRG->InvertRect(&rectSel); } return 0; } /* retourne 0 = dans le texte -1 avant 1 aprés */ int CEdite::TrouvePositionMono(CDC* pRG, char* texte, RECT* rectEdite, POINT& point, RETOUR* ptRetour) { int ligne, nbMot, largeurTotale, resteLargeur, posX, extraEsp, b, car; char* ptLigne, * ptFinMot; SIZE taille; MOTS Mots[20]; ligne = 0; ptLigne = texte + TabLigne[ligne]; // évaluation des mots largeurTotale = 0; nbMot = 0; do { ptFinMot = strpbrk(ptLigne, " \r\t\n"); if(!ptFinMot) ptFinMot = strchr(ptLigne, 0); car = *ptFinMot; switch(car) { case 13: b = b13; break; default: b = 0; } Mots[nbMot].pos = ptLigne - texte; Mots[nbMot].nbLettres = ptFinMot - ptLigne; GetTextExtentPoint32(pRG->m_hDC, ptLigne, Mots[nbMot].nbLettres, &taille); Mots[nbMot].largeur = taille.cx; Mots[nbMot].code = b; nbMot++; ptLigne = ptFinMot + 1; largeurTotale += taille.cx + LG_ESP; } while(car); largeurTotale -= LG_ESP; // évaluation de la ligne resteLargeur = (rectEdite->right - rectEdite->left) - largeurTotale; posX = rectEdite->left; // + premier décalage extraEsp = LG_ESP; // cadrage à gauche, à droite, centrage if(resteLargeur >= 0) { switch(Etat & JUSTIFIE) { case A_GAUCHE: break; case JUSTIFIE: extraEsp = LG_ESP + (resteLargeur / (nbMot - 1)); break; case AU_CENTRE: posX += (resteLargeur / 2); break; case A_DROITE: posX += resteLargeur; } } if(posX > point.x) return -1; // avant for(b = 0; b < nbMot; b++) { largeurTotale = posX + Mots[b].largeur + extraEsp; if((point.x > posX) && (point.x <= largeurTotale)) break; posX = largeurTotale; } // if(b == nbMot) b--; if(b == nbMot) { // aprés ptRetour->pos = NbCar; ptRetour->posMot = NbCar; return 1; } ptRetour->posMot = Mots[b].pos; ptRetour->nbLettres = Mots[b].nbLettres; ptRetour->largeur = Mots[b].largeur; ptRetour->ligne = ligne; posX = point.x - posX; ptLigne = texte + Mots[b].pos; for(b = 1; b <= ptRetour->nbLettres; b++) { GetTextExtentPoint32(pRG->m_hDC, ptLigne, b, &taille); if(taille.cx > posX) break; } ptRetour->pos = ptRetour->posMot + b - 1; return 0; } int CEdite::EditeMultiLigne(CDC* pRG, char* texte, RECT* rectEdite, POINT& point) { char* ptLigne, * ptFinMot; int b, nbMot, motCourant, motDebut, posXTest, posX, finSelection, finMot, nbMotValide, posY, extraEsp, resteLargeur, posXMaxi, ligneBoutSel, nbLignesAffichables, htLigne; char car; SIZE taille; POINT pointSel; RECT rectSel1; RECT rectSel2; MOTS Mots[100]; pointSel.x = 0; LignePosition = -1; TabLigne[0] = 0; NbLigne = 0; finSelection = Position + NbSelection; // évaluation des mots nbMot = 0; ptLigne = texte; do { ptFinMot = strpbrk(ptLigne, " \r\t\n"); if(!ptFinMot) ptFinMot = strchr(ptLigne, 0); car = *ptFinMot; switch(car) { case 13: b = b13; break; default: b = 0; } Mots[nbMot].pos = ptLigne - texte; Mots[nbMot].nbLettres = ptFinMot - ptLigne; finMot = Mots[nbMot].pos + Mots[nbMot].nbLettres + 1; // et 13 ou 9 ? GetTextExtentPoint32(pRG->m_hDC, ptLigne, Mots[nbMot].nbLettres, &taille); Mots[nbMot].largeur = taille.cx; if((Position >= Mots[nbMot].pos) && (Position < finMot)) b |= b0; // c'est lui qui à le curseur if((finSelection >= Mots[nbMot].pos) && (finSelection < finMot)) b |= b1; // c'est lui qui à l'autre bout de la sélection Mots[nbMot].code = b; nbMot++; ptLigne = ptFinMot + 1; } while(car); // évaluation des lignes ligneBoutSel = -1; motCourant = 0; posXMaxi = rectEdite->right - rectEdite->left + LG_ESP; while(motCourant < nbMot) { // début d'une ligne nbMotValide = 0; posX = 0; // + premier décalage motDebut = motCourant; for(motCourant; motCourant < nbMot; motCourant++) { posXTest = posX + Mots[motCourant].largeur + LG_ESP; if(posXTest <= posXMaxi) { if(Mots[motCourant].code & b13) { motCourant++; nbMotValide--; break; } posX = posXTest; // position de début du mot suivant nbMotValide++; } else { nbMotValide--; // pas le dernier (LG_ESP) break; } } if(motCourant) Mots[motCourant - 1].code |= b10; // fin de ligne resteLargeur = rectEdite->right - posX; posX = rectEdite->left; // + premier décalage extraEsp = LG_ESP; // cadrage à gauche, à droite, centrage switch(Etat & JUSTIFIE) { case A_GAUCHE: break; case JUSTIFIE: extraEsp = LG_ESP + (resteLargeur / nbMotValide); break; case AU_CENTRE: posX += (resteLargeur / 2); break; case A_DROITE: posX += resteLargeur; } ptLigne = texte + Mots[motDebut].pos; TabLigne[NbLigne] = Mots[motDebut].pos; for(b = motDebut; b < motCourant; b++) { Mots[b].posX = posX; if(Mots[b].code & b0) { LignePosition = NbLigne; if(NbCar - Position) { finMot = Position - Mots[b].pos; GetTextExtentPoint32(pRG->m_hDC, ptLigne, finMot, &taille); point.x = posX + taille.cx; } else { point.x = posX + Mots[b].largeur; } } if(Mots[b].code & b1) { ligneBoutSel = NbLigne; if(NbCar - finSelection) { finMot = finSelection - Mots[b].pos; GetTextExtentPoint32(pRG->m_hDC, ptLigne, finMot, &taille); pointSel.x = posX + taille.cx; } else { pointSel.x = posX + Mots[b].largeur; } } posX += Mots[b].largeur + extraEsp; ptLigne += Mots[b].nbLettres + 1; } NbLigne++; } // affichage htLigne = HtLigne + Interligne; nbLignesAffichables = (rectEdite->bottom - rectEdite->top) / htLigne; if(!nbLignesAffichables) nbLignesAffichables = 1; if(nbLignesAffichables > NbLigne) nbLignesAffichables = NbLigne; if(LignePosition >= nbLignesAffichables) { // par défaut le curseur est mis sur la première ligne PremierCaractere = 1 + LignePosition - nbLignesAffichables; } else { PremierCaractere = 0; } posY = rectEdite->top; b = TabLigne[PremierCaractere]; // la ligne du premier caractère affiché motDebut = -1; while(Mots[++motDebut].pos != b); ptLigne = texte + Mots[motDebut].pos; while(nbLignesAffichables--) { do { pRG->TextOut(Mots[motDebut].posX, posY, ptLigne, Mots[motDebut].nbLettres); ptLigne += Mots[motDebut].nbLettres + 1; motDebut++; } while((Mots[motDebut - 1].code & b10) == 0); posY += htLigne; } point.y = (LignePosition - PremierCaractere) * htLigne; point.y += rectEdite->top; // ou 4 ? if(NbSelection) { pointSel.y = ligneBoutSel * htLigne; pointSel.y += rectEdite->top; // ou 4 ? finSelection = ligneBoutSel - LignePosition; rectSel1.top = point.y; rectSel1.left = point.x; rectSel1.bottom = point.y + htLigne; rectSel2.top = pointSel.y; rectSel2.right = pointSel.x; rectSel2.bottom = pointSel.y + htLigne; if(finSelection == 0) { // la selection est sur une seule ligne rectSel1.right = pointSel.x; } else if(finSelection < 0) { rectSel1.right = rectEdite->left; rectSel2.left = rectEdite->right; pRG->InvertRect(&rectSel2); finSelection++; if(finSelection) { rectSel2.top += htLigne; rectSel2.bottom = rectSel1.bottom - htLigne; rectSel2.right = rectEdite->left; } } else { // selection vers le haut rectSel1.right = rectEdite->right; rectSel2.left = rectEdite->left; pRG->InvertRect(&rectSel2); finSelection--; if(finSelection) { rectSel2.top = rectSel1.top + htLigne; rectSel2.bottom -= htLigne; rectSel2.right = rectEdite->right; } } pRG->InvertRect(&rectSel1); if(finSelection) pRG->InvertRect(&rectSel2); } return 0; } /* retourne 0 = dans le texte -1 avant 1 aprés */ int CEdite::TrouvePositionMulti(CDC* pRG, char* texte, RECT* rectEdite, POINT& point, RETOUR* ptRetour) { int ligne, nbMot, largeurTotale, resteLargeur, posX, extraEsp, b, car; char* ptLigne, * ptFinMot, * ptFinLigne; SIZE taille; MOTS Mots[20]; // if(!NbLigne) return -1; if(!NbCar) return 1; ligne = (point.y - rectEdite->top) / (HtLigne + Interligne); // if(ligne >= NbLigne) ligne = NbLigne - 1; if(ligne >= NbLigne) return 1; ligne += PremierCaractere; ptLigne = texte + TabLigne[ligne]; ptFinLigne = texte + TabLigne[ligne + 1]; // évaluation des mots largeurTotale = 0; nbMot = 0; do { ptFinMot = strpbrk(ptLigne, " \r\t\n"); if(!ptFinMot) ptFinMot = strchr(ptLigne, 0); car = *ptFinMot; switch(car) { case 13: b = b13; break; default: b = 0; } Mots[nbMot].pos = ptLigne - texte; Mots[nbMot].nbLettres = ptFinMot - ptLigne; GetTextExtentPoint32(pRG->m_hDC, ptLigne, Mots[nbMot].nbLettres, &taille); Mots[nbMot].largeur = taille.cx; Mots[nbMot].code = b; nbMot++; ptLigne = ptFinMot + 1; largeurTotale += taille.cx; if(ptLigne == ptFinLigne) break; } while(car); resteLargeur = rectEdite->right - (largeurTotale + rectEdite->left); posX = rectEdite->left; // + premier décalage extraEsp = LG_ESP; // cadrage à gauche, à droite, centrage switch(Etat & JUSTIFIE) { case A_GAUCHE: break; case JUSTIFIE: extraEsp = LG_ESP + (resteLargeur / (nbMot - 1)); break; case AU_CENTRE: posX += (resteLargeur / 2); break; case A_DROITE: posX += resteLargeur; } if(posX > point.x) return -1; // avant for(b = 0; b < nbMot; b++) { largeurTotale = posX + Mots[b].largeur + extraEsp; if((point.x > posX) && (point.x <= largeurTotale)) break; posX = largeurTotale; } // if(b == nbMot) b--; if(b == nbMot) { // aprés ptRetour->pos = NbCar; ptRetour->posMot = NbCar; return 1; } ptRetour->posMot = Mots[b].pos; ptRetour->nbLettres = Mots[b].nbLettres; ptRetour->largeur = Mots[b].largeur; ptRetour->ligne = ligne; posX = point.x - posX; ptLigne = texte + Mots[b].pos; for(b = 1; b <= ptRetour->nbLettres; b++) { GetTextExtentPoint32(pRG->m_hDC, ptLigne, b, &taille); if(taille.cx > posX) break; } ptRetour->pos = ptRetour->posMot + b - 1; return 0; } BOOL CEdite::OnMouseWheel(UINT temoins, short delta, CPoint pt) { int valE, nbDecimales; float valF; char* ptCar; delta /= 120; delta *= -10; if(Etat & ROULETTE) { switch(Etat & MSQ_TYPE) { case TEXTE: case CHAINE: break; case FLOTTANT: case FLOTTANT_100: NbSelection = 0; if(temoins & MK_MBUTTON) valF = (float)(delta / 100); // 0,1 en 0,1 else valF = (float)(delta / 10); // 1 en 1 valF += ValeurFlottante(); nbDecimales = Etat & MSQ_ANNEXE; nbDecimales >>= 12; // b15-12 sprintf(Texte, "%.*f", nbDecimales, valF); if(Etat & MODE_P) { ptCar = strchr(Texte, '.'); if(ptCar) *ptCar = ','; } Invalidate(); OnKillFocus(NUL); break; case ENTIER: NbSelection = 0; if(temoins & MK_MBUTTON) delta *= 10; //10 en 10 ou 100 en 100 valE = delta + ValeurEntiere(); sprintf(Texte, "%d", valE); Invalidate(); OnKillFocus(NUL); } } return 1; }