AGSScriptModuleKitaiCe module permet de transformer un bouton en zone de saisie à plusieurs lignesBloc-Notes2.1betaN¦// TODO // // Éventuellement, garder le texte dans une sprite à part pour ne réécrire que les lignes modifiées // Si MODE_CURSEUR > 0, cela représente le mode de curseur dont utiliser l'image lorsque la souris survole le bloc #define MODE_CURSEUR 0 int buttons_size; Button* buttons[]; int button_background_color[]; int button_background_select_color[]; int button_background_sprite[]; int button_cursor[]; int button_rowcount[]; int button_linecount[]; int button_xoffset[]; int button_yoffset[]; int button_width[]; int button_height[]; int button_select[]; String button_text[]; DynamicSprite* button_sprite[]; eBlocNotes_Scrollable button_scrollable[]; int InArray(this Button*, Button* array[], int size) { if (size < 1) return -1; int i = 0; while (i < size) { if (this == array[i]) return i; i++; } return -1; } /// Cette fonction retournera une copie du tableau auquel on aura ajouté VALEUR Button*[] DynamicArrays_AddButton(Button* tableau[], int taille, Button* valeur) { if (taille < 0) taille = 0; Button* tmp[] = new Button[taille+1]; int i = 0; while (i < taille) { tmp[i] = tableau[i]; i++; } tmp[i] = valeur; return tmp; } /// Cette fonction retournera une copie du tableau auquel on aura ajouté VALEUR DynamicSprite*[] DynamicArrays_AddSprite(DynamicSprite* tableau[], int taille, DynamicSprite* valeur) { if (taille < 0) taille = 0; DynamicSprite* tmp[] = new DynamicSprite[taille+1]; int i = 0; while (i < taille) { tmp[i] = tableau[i]; i++; } tmp[i] = valeur; return tmp; } /// Cette fonction retournera une copie du tableau auquel on aura ajouté VALEUR String[] DynamicArrays_AddString(String tableau[], int taille, String valeur) { if (taille < 0) taille = 0; String tmp[] = new String[taille+1]; int i = 0; while (i < taille) { tmp[i] = tableau[i]; i++; } tmp[i] = valeur; return tmp; } /// Cette fonction retournera une copie du tableau auquel on aura ajouté VALEUR int[] DynamicArrays_AddInt(int tableau[], int taille, int valeur) { if (taille < 0) taille = 0; int tmp[] = new int[taille+1]; int i = 0; while (i < taille) { tmp[i] = tableau[i]; i++; } tmp[i] = valeur; return tmp; } /// Cette fonction retournera une copie du tableau auquel on aura ajouté VALEUR bool[] DynamicArrays_AddBool(bool tableau[], int taille, bool valeur) { if (taille < 0) taille = 0; bool tmp[] = new bool[taille+1]; int i = 0; while (i < taille) { tmp[i] = tableau[i]; i++; } tmp[i] = valeur; return tmp; } // BOUTON représente le bouton qui sert de bloc-notes Button* Bouton; // COULEUR représente la couleur du fond du bloc-notes int Couleur; // FOND_SELECT représente la couleur de fond lors d'une sélection int Fond_Select; // POLICE représente la police du bouton FontType Police; // FONT_HEIGHT représente la hauteur de la police int Font_Height; // NUM_SPR représente le numéro de la sprite de fond du bouton, s'il y en a une int Num_Spr = -1; // SCROLLABLE définit si le texte peut occuper plus de place que les dimensions du bouton eBlocNotes_Scrollable Scrollable; // CADRE contiendra chaque ligne du bloc String Cadre[]; // LINECOUNT correspond au nombre de lignes dans le bloc int LineCount; // BLOCTEXTE contient le texte du bloc String BlocTexte; // BUFFER contient le texte copié/coupé String Buffer; // La sprite qui représente la zone de saisie DynamicSprite* Bloc; // La surface buffer, qui n'a pas le curseur DrawingSurface* surf_buffer; // A sert à faire clignoter le curseur tous les X cycles int a = 0; // AFFCUR représente l'état (affiché ou non) du curseur bool affcur = false; // Le # de la lettre sur laquelle se trouve le curseur int curs = 0; // La position où l'on a cliqué avant de relâcher int sel = 0; // Le # de la ligne tout en haut de la surface int top_ligne = 0; // Les coordonnées du curseur (X en pixels, Y en # de ligne) int x_curs, y_curs; // Cette fonction retourne une copie d'une string avec le caractère LETTRE inséré à POS String InsertAt(this String*, int pos, char lettre) { String tmp = this; if (pos < 0) pos = 0; if (pos == tmp.Length) tmp = tmp.AppendChar(lettre); else { if (pos > tmp.Length) pos = tmp.Length; tmp = String.Format("%s%c%s", tmp.Substring(0, pos), lettre, tmp.Substring(pos, tmp.Length-pos)); } return tmp; } // Cette fonction retourne une copie d'une string avec le TEXTE inséré à POS String InsertStringAt(this String*, int pos, String texte) { String tmp = this; if (pos < 0) pos = 0; if (pos == tmp.Length) tmp = tmp.Append(texte); else { if (pos > tmp.Length) pos = tmp.Length; tmp = String.Format("%s%s%s", tmp.Substring(0, pos), texte, tmp.Substring(pos, tmp.Length-pos)); } return tmp; } int LongueurPourLargeur(this String*, int largeur_max, FontType police) { String tmp = this; int largeur = GetTextWidth(this.Replace(String.Format("%c",10),""), police), largeur_par_caractere = largeur/this.Length; // On réduit du nombre de caractères supposé idéal while (largeur > largeur_max) { int moins = (largeur-largeur_max)/largeur_par_caractere; if (moins < 1) moins = 1; if (tmp.Length-moins >= 0) tmp = tmp.Truncate(tmp.Length-moins); else tmp = ""; largeur = GetTextWidth(tmp.Replace(String.Format("%c",10), ""), police); } int largeur_ajoutee; String letter = ""; if (tmp.Length < this.Length) letter = String.Format("%c",this.Chars[tmp.Length]); largeur_ajoutee = GetTextWidth(letter.Replace(String.Format("%c",10),""), police); // Si on a trop réduit, on ajoute jusqu'au maximum while ((tmp.Length < this.Length) && (largeur+largeur_ajoutee <= largeur_max)) { tmp = tmp.AppendChar(this.Chars[tmp.Length]); largeur += largeur_ajoutee; letter = String.Format("%c",this.Chars[tmp.Length]); largeur_ajoutee = GetTextWidth(letter.Replace(String.Format("%c",10),""), police); } return tmp.Length; } function RemplitCadre(this DrawingSurface*, String texte, FontType police) { if (texte == null) texte = ""; // On mémorise puis "rase" le cadre String ancien_cadre[] = Cadre; int ancien_linecount = LineCount; Cadre = null; LineCount = 0; // On récupère l'id du bouton int id = Bouton.InArray(buttons, buttons_size); // On va retenir la largeur maximale int Width = button_width[id]; // On met à jour la hauteur de la police si besoin if (police != Police) { Font_Height = GetTextHeight("ABCDEFGHIJKLMNOPQRSTUVWXYZ", police, GetTextWidth("ABCDEFGHIJKLMNOPQRSTUVWXYZ", police)+10); Police = police; } // TMP contient la ligne à parser, TMP_MOTS contient la ligne à ajouter String tmp = ""; // I représente le caractère de TEXTE en cours d'inspection int i = 0; // On va parcourir chaque caractère de TEXTE un par un while (i < texte.Length) { String following = texte.Substring(i, texte.Length-i), ligne; tmp = ""; int nextreturn = following.IndexOf(String.Format("%c",10)); // Si on a trouvé un retour à la ligne, on ajoute jusqu'à ce caractère if (nextreturn > -1) tmp = following.Truncate(nextreturn+1); else tmp = following; if (tmp == null) tmp = ""; int width = GetTextWidth(tmp, police); // Si le bloc-notes n'est pas horizontalement dépassable mais qu'on dépasse if ((Scrollable%eBlocN_HorizontallyScrollable) && (width > this.Width)) { // Si on a pas atteint autant de ligne qu'auparavant, on regarde si on n'avait pas déjà tout traité String compare = ""; // On accolle la ligne en cours et la ligne suivante de ce qu'on avait avant if (LineCount < ancien_linecount-1) compare = String.Format("%s%s",ancien_cadre[LineCount], ancien_cadre[LineCount+1]); // Dans un bloc non élargissable, Width = largeur de la surface, donc si la largeur est restée la même qu'avant // et si la ligne en cours et la ligne suivante aussi sont restées les mêmes : on ajoute simplement la ligne en cours if ((this.Width == Width) && (compare.Length) && (following.StartsWith(compare))) tmp = ancien_cadre[LineCount]; // Sinon, il va falloir calculer... else { // On va aller d'espace en epsace String copy_tmp = tmp, new_tmp = ""; int space = copy_tmp.IndexOf(" "); // Tant qu'il y a un espace dans le texte qui suit while (space >= 0) { // On ajoute jusqu'à l'espace new_tmp = new_tmp.Append(copy_tmp.Truncate(space+1)); // On réduit le texte qui suit copy_tmp = copy_tmp.Substring(space+1, copy_tmp.Length-(space+1)); // Si le texte obtenu est de largeur acceptable, TMP devient ce texte if (GetTextWidth(new_tmp, police) <= this.Width) { tmp = new_tmp; space = copy_tmp.IndexOf(" "); } // Sinon, on sort de la boucle else space = -1; } width = GetTextWidth(tmp, police); // Si on dépasse toujours, c'est qu'il n'y avait pas d'espace : on prend la longueur idéale if (width > this.Width) tmp = tmp.Truncate(tmp.LongueurPourLargeur(this.Width, police)); } } // Si on est dans un bloc élargissable et si on dépasse la largeur max : nouvelle largeur max if (!(Scrollable%eBlocN_HorizontallyScrollable) && (width > Width)) Width = width; i += tmp.Length; // On incrémente i en conséquence // On ajoute la ligne Cadre = DynamicArrays_AddString(Cadre, LineCount, tmp); LineCount++; // On augmente le nombre de lignes } // Si la dernière ligne finit par un retour à la ligne ou si on n'a ajouté aucune ligne if (!LineCount || tmp.EndsWith(String.Format("%c",10))) { // On ajoute une ligne vide Cadre = DynamicArrays_AddString(Cadre, LineCount, ""); LineCount++; // On augmente le nombre de lignes } int Height = LineCount*Font_Height; if (Scrollable%eBlocN_HorizontallyScrollable) Width = this.Width; button_width[id] = Width; button_height[id] = Height; button_linecount[id] = LineCount; } // Correspond aux décalages horizontal et vertical (> 0 seulement si scrollable) int Decal_x, Decal_y; // Indique si le décalage doit être géré selon la position du curseur bool CursorDeterminesOffset = true; function Ecrit(this DrawingSurface*, int curseur, FontType police) { String tmp; // Coordonnée y de la sélection int y_sel; // Calcul du curseur int nb_car, li, li_curs, li_sel, nb_sel; // NB_CAR est le nombre de caractères scrutés, LI la ligne à laquelle on se trouve while (li < LineCount) { // On parcourt chaque ligne du bloc tmp = Cadre[li]; // On récupère la ligne LI if (nb_car <= curseur) { // Tant qu'on n'a pas dépassé la position du curseur nb_car += tmp.Length; // On ajoute sa longueur à NB_CAR li_curs++; // On incrémente la ligne où se trouve le curseur } if (nb_sel <= sel) { // Tant qu'on n'a pas dépassé la position de sélection nb_sel += tmp.Length; // On ajoute la longueur de LI à NB_SEL li_sel++; // On incrémente la ligne où se trouve la sélection } li++; // Et on passe à la ligne suivante } li = li_curs; // Une fois qu'on a dépassé la position du curseur, LI représente la ligne suivant celle où se trouve le curseur if (li > 0) li--; if (li_sel > 0) li_sel--; // On récupère la ligne où se trouve le curseur tmp = Cadre[li]; // On calcule la position X du caractère-curseur dans la ligne en question int x_relatif = tmp.Length - (nb_car - curseur); if (x_relatif < 0) x_relatif = 0; // Si cette position est la première, ou si le curseur est tout simplement au tout début, 0 if ((x_relatif == 0) || (curseur == 0)) x_curs = 0; // Sinon... else { tmp = tmp.Substring(0, x_relatif); tmp = tmp.Replace(String.Format("%c", 10),""); x_curs = GetTextWidth(tmp, police); } // Calcul de la coordonnée Y du curseur y_curs = Font_Height*li; // Calcul de la position X sélectionnée tmp = Cadre[li_sel]; x_relatif = tmp.Length - (nb_sel - sel); if (x_relatif < 0) x_relatif = 0; if ((x_relatif == 0) || (sel == 0)) x_relatif = 0; else { tmp = tmp.Substring(0, x_relatif); tmp = tmp.Replace(String.Format("%c", 10),""); x_relatif = GetTextWidth(tmp, police); } // Calcul de la coordonnée Y de la sélection y_sel = Font_Height*li_sel; // Calcul du décalage horizontal if (CursorDeterminesOffset) { if (x_curs > Bloc.Width+Decal_x) Decal_x = x_curs-Bloc.Width; else if (x_curs < Decal_x) Decal_x = x_curs; } // On calcule à quel point le curseur se trouve plus bas que la capacité en hauteur int depasse = (y_curs+(2*Font_Height)-Decal_y) - Bloc.Height; // S'il se trouve effectivement "trop" bas... if ((depasse > 0) && CursorDeterminesOffset) { Decal_y += depasse; } // Si le curseur est "trop" haut, on remplace en conséquence depasse = Decal_y - y_curs; if ((depasse > 0) && CursorDeterminesOffset) Decal_y -= depasse; // Enfin, on calcule de combien de pixels il faut faire "glisser" la surface vers le haut int decal_y = Decal_y; // Si l'utilisateur a spécifié un fond if (Num_Spr > -1) { this.Clear(COLOR_TRANSPARENT); this.DrawImage(0, 0, Num_Spr); } // Sinon, on efface simplement la surface else this.Clear(Couleur); // Traçage de la sélection if (sel != curs) { if (Fond_Select == COLOR_TRANSPARENT) this.DrawingColor = 65535 - Bouton.TextColor; else this.DrawingColor = Fond_Select; if (li == li_sel) { if (curs < sel) this.DrawRectangle(x_curs-Decal_x, y_curs-decal_y, x_relatif-Decal_x, y_sel+Font_Height-decal_y); else this.DrawRectangle(x_relatif-Decal_x, y_sel-decal_y, x_curs-Decal_x, y_curs+Font_Height-decal_y); } else { if (curs < sel) { tmp = Cadre[li].Replace(String.Format("%c",10), ""); this.DrawRectangle(x_curs-Decal_x, y_curs-decal_y, GetTextWidth(tmp, Bouton.Font)-Decal_x, y_curs+Font_Height-decal_y); int i = li+1; while (i < li_sel) { tmp = Cadre[i].Replace(String.Format("%c",10), ""); this.DrawRectangle(0-Decal_x, i*Font_Height-decal_y, GetTextWidth(tmp, Bouton.Font)-Decal_x, (i+1)*Font_Height-decal_y); i++; } this.DrawRectangle(0-Decal_x, y_sel-decal_y, x_relatif-Decal_x, y_sel+Font_Height-decal_y); } else { tmp = Cadre[li_sel].Replace(String.Format("%c",10), ""); this.DrawRectangle(x_relatif-Decal_x, y_sel-decal_y, GetTextWidth(tmp, Bouton.Font)-Decal_x, y_sel+Font_Height-decal_y); int i = li_sel+1; while (i < li) { tmp = Cadre[i].Replace(String.Format("%c",10), ""); this.DrawRectangle(0-Decal_x, i*Font_Height-decal_y, GetTextWidth(tmp, Bouton.Font)-Decal_x, (i+1)*Font_Height-decal_y); i++; } this.DrawRectangle(0-Decal_x, y_curs-decal_y, x_curs-Decal_x, y_curs+Font_Height-decal_y); } } } // La ligne à écrire String ligne; // On va dessiner chaque ligne à (0, #ligne * hauteur_police) this.DrawingColor = Bouton.TextColor; // On a besoin d'écrire uniquement depuis la ligne tout en haut et jusqu'à la ligne tout en bas int n = Decal_y/Font_Height, m = 1 + n + this.Height/Font_Height; while ((n < LineCount) && (n < m)) { this.DrawString(0-Decal_x, 1 + n * Font_Height - decal_y, police, Cadre[n].Replace(String.Format("%c", 10),"")); n++; } // On sauvegarde une copie surf_buffer = this.CreateCopy(); // On release this.Release(); // On retourne return; } // Cette fonction retourne la position (aboslue) du curseur de façon à ce qu'il soit placé sur la ligne nuémro LI // et qu'il reste au plus près possible de son ancienne position horizontale function CaractereProx(int y) { int li = y/Font_Height; if (li >= LineCount) li = LineCount-1; int c = 0; String ligne = Cadre[li], tmp = ligne.Substring(0, c); // Tant qu'on n'est pas arrivé à un décalage dépassant l'actuel et qu'on n'a pas atteint la fin de la ligne while ((GetTextWidth(tmp.Replace(String.Format("%c", 10),""), Bouton.Font) < x_curs) && (c < ligne.Length)) { c++; // On ajoute un caractère à TMP tmp = ligne.Substring(0, c); } // Si on est sur le dernier caractère de la non dernière ligne et qu'il s'agit d'un espace ou d'un retour à la ligne if ((c == ligne.Length) && (li < LineCount-1) && ((ligne.Chars[c-1] == ' ') || (ligne.Chars[c-1] == 10))) c--; // Si on est allé plus loin que le premier caractère... if (c > 0) { // On vérifie si le curseur n'est pas plus près horizontalement du caractère précédent String tmpmoinsun = ligne.Substring(0, c-1); if ((GetTextWidth(tmp.Replace(String.Format("%c", 10),""), Bouton.Font) - x_curs) > (x_curs - GetTextWidth(tmpmoinsun.Replace(String.Format("%c", 10),""), Bouton.Font))) c--; } // NEWPOS vaudra la position de ce caractère, plus tous les caractères des lignes précédentes int i = 0, newpos = c; while (i < li) { tmp = Cadre[i]; newpos += tmp.Length; i++; } if (newpos > BlocTexte.Length) newpos = BlocTexte.Length; return newpos; } bool HasTruncated; /// Sets BLOCTEXTE to TEXT and truncates it if necessary String SetBlocTexte(String text) { HasTruncated = false; int id = Bouton.InArray(buttons, buttons_size); if (String.IsNullOrEmpty(text)) text = ""; // Si le bloc-notes n'est pas horizontalement scrollable, on tronque les lignes s'il faut else if ((Scrollable % eBlocN_VerticallyScrollable) && (Bloc != null)) { DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.RemplitCadre(text, Bouton.Font); int lines = LineCount, size = Bloc.Height / (Font_Height+1); while ((lines > size) && (lines>0)) { String last = Cadre[lines-1]; text = text.Truncate(text.Length-last.Length-1); lines--; HasTruncated = true; } } BlocTexte = text; if (id >= 0) button_text[id] = text; if (curs > BlocTexte.Length) curs = BlocTexte.Length; // Si le bloc-notes est horizontalement scrollable OU si on a tronqué le texte, on (re)remplit if (!(Scrollable % eBlocN_VerticallyScrollable) || HasTruncated || !BlocTexte.Length) { DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.RemplitCadre(BlocTexte, Bouton.Font); } return BlocTexte; } function SaveCurrentBloc() { int id = Bouton.InArray(buttons, buttons_size); if (id < 0) return; button_background_color[id] = Couleur; button_background_select_color[id] = Fond_Select; button_background_sprite[id] = Num_Spr; button_text[id] = BlocTexte; button_sprite[id] = Bloc; button_scrollable[id] = Scrollable; button_cursor[id] = curs; button_select[id] = sel; button_xoffset[id] = Decal_x; button_yoffset[id] = Decal_y; } function NewBloc(this Button*) { // Ajout à la liste // Couleur de fond button_background_color = DynamicArrays_AddInt(button_background_color, buttons_size, Couleur); // Couleur de fond button_background_select_color = DynamicArrays_AddInt(button_background_select_color, buttons_size, Fond_Select); // Image de fond button_background_sprite = DynamicArrays_AddInt(button_background_sprite, buttons_size, Num_Spr); // Texte button_text = DynamicArrays_AddString(button_text, buttons_size, BlocTexte); // Sprite button_sprite = DynamicArrays_AddSprite(button_sprite, buttons_size, Bloc); // Scrollable button_scrollable = DynamicArrays_AddInt(button_scrollable, buttons_size, Scrollable); // Curseur button_cursor = DynamicArrays_AddInt(button_cursor, buttons_size, 0); // Sélection button_select = DynamicArrays_AddInt(button_select, buttons_size, 0); // XOffset button_xoffset = DynamicArrays_AddInt(button_xoffset, buttons_size, 0); // YOffset button_yoffset = DynamicArrays_AddInt(button_yoffset, buttons_size, 0); // Width button_width = DynamicArrays_AddInt(button_width, buttons_size, this.Width); // Height button_height = DynamicArrays_AddInt(button_height, buttons_size, this.Height); // RowCount int font_height = GetTextHeight("ABCDEFGHIJKLMNOPQRSTUVWXYZ", Bouton.Font, GetTextWidth("ABCDEFGHIJKLMNOPQRSTUVWXYZ", Bouton.Font)+10); button_rowcount = DynamicArrays_AddInt(button_rowcount, buttons_size, Bloc.Height / (font_height+1)); // LineCount button_linecount = DynamicArrays_AddInt(button_linecount, buttons_size, 0); // Bouton lui-même buttons = DynamicArrays_AddButton(buttons, buttons_size, this); // Incrémentation du nombre de blocs buttons_size++; Font_Height = font_height; } function LoadBloc(this Button*) { int id = this.InArray(buttons, buttons_size); if (id < 0) return; Couleur = button_background_color[id]; Fond_Select = button_background_select_color[id]; Num_Spr = button_background_sprite[id]; Bloc = button_sprite[id]; Scrollable = button_scrollable[id]; Bouton = this; Decal_x = button_xoffset[id]; Decal_y = button_yoffset[id]; SetBlocTexte(button_text[id]); curs = button_cursor[id]; sel = button_select[id]; int font_height = GetTextHeight("ABCDEFGHIJKLMNOPQRSTUVWXYZ", Bouton.Font, GetTextWidth("ABCDEFGHIJKLMNOPQRSTUVWXYZ", Bouton.Font)+10); button_rowcount[id] = Bloc.Height/(font_height+1); Font_Height = font_height; } // Lorsqu'on appuie sur une touche function on_key_press(int keycode) { if ((Bouton == null) || (!Bouton.OwningGUI.Visible) || (!Bouton.Enabled) || (!Bouton.Visible)) return; if (BlocTexte == null) SetBlocTexte(""); int id = Bouton.InArray(buttons, buttons_size); // On mémorise le texte String memento = BlocTexte; // La surface du bloc DrawingSurface* surf = Bloc.GetDrawingSurface(); // Le curseur détermine le décalage CursorDeterminesOffset = true; // SELECT[0] sera le premier caractère sélectionné et SELECT[1] le dernier int select[2]; select[0] = (curs < sel) * curs + (sel < curs) * sel; select[1] = (curs > sel) * curs + (sel > curs) * sel; // Si du texte est sélectionné et qu'on appuie sur une touche "effective"... if (((27 < keycode) && (keycode < 359)) || (keycode == eKeyDelete) || (keycode == eKeyBackspace) || (keycode == eKeyReturn) || (keycode == eKeyCtrlX) || ((keycode == eKeyCtrlP) && (Buffer != null))) { if (select[0] != select[1]) { // Si CtrlX : dans buffer if (keycode == eKeyCtrlX) Buffer = BlocTexte.Substring(select[0], select[1]-select[0]); // Si Backspace : on augmente le curseur if (IsKeyPressed(eKeyBackspace)) select[0]++; // Si Del : on réduit sel if (IsKeyPressed(eKeyDelete)) select[1]--; // Si la sélection "dépasse" la fin, on se contente de ne récupérer que jusqu'à SELECT[0] if (select[1] >= BlocTexte.Length) SetBlocTexte(BlocTexte.Truncate(select[0])); else SetBlocTexte(String.Format("%s%s", BlocTexte.Substring(0, select[0]), BlocTexte.Substring(select[1], BlocTexte.Length-select[1]))); curs = select[0]; } } // Appui sur une touche alphabétique if (('A' <= keycode) && (keycode <= 'Z')) { char lettre; // Si aucun shift n'est pressé et que le capslock n'est pas activé ou s'il l'est et qu'un shift est pressé >> minuscule if ((!(IsKeyPressed(403)) && !(IsKeyPressed(404)) && (!System.CapsLock)) || ((System.CapsLock) && (IsKeyPressed(403) || IsKeyPressed(404)))) lettre = keycode + 32; else lettre = keycode; SetBlocTexte(BlocTexte.InsertAt(curs, lettre)); curs++; } // Appui sur un caractère à afficher if (((32 <= keycode) && (keycode <= 64)) || ((91 <= keycode) && (keycode <= 255))) { SetBlocTexte(BlocTexte.InsertAt(curs, keycode)); curs++; } // Appui sur CtrlP if ((keycode == eKeyCtrlP) && (Buffer != null)) { SetBlocTexte(BlocTexte.InsertStringAt(curs, Buffer)); curs += Buffer.Length; } // Appui sur Return if (keycode == eKeyReturn) { SetBlocTexte(BlocTexte.InsertAt(curs, 10)); curs++; } // Appui sur Bakcspace if ((keycode == eKeyBackspace) && (curs > 0)) { curs--; SetBlocTexte(String.Format("%s%s", BlocTexte.Substring(0, curs), BlocTexte.Substring(curs+1, BlocTexte.Length-curs-1))); } // Appui sur Suppr if ((keycode == eKeyDelete) && (curs < BlocTexte.Length)) SetBlocTexte(String.Format("%s%s", BlocTexte.Truncate(curs), BlocTexte.Substring(curs+1, BlocTexte.Length-1))); if (curs > BlocTexte.Length) curs = BlocTexte.Length; if (curs < 0) curs = 0; if (sel < 0) sel = 0; // Si on a tronqué, on remet le texte à ce qu'il état avant if (HasTruncated) SetBlocTexte(memento); // Appui sur Ctrl-A if (keycode == eKeyCtrlA) { sel = 0; curs = BlocTexte.Length; } // Appui sur Ctrl-C if ((keycode == eKeyCtrlC) && (select[0] != select[1])) Buffer = BlocTexte.Substring(select[0], select[1]-select[0]); // Appui sur gauche if ((keycode == eKeyLeftArrow) && (curs > 0)) { if (IsKeyPressed(405) || IsKeyPressed(406)) { int i; if (curs >= BlocTexte.Length) i = BlocTexte.Length-1; else i = curs-1; while ((i > 0) && (BlocTexte.Chars[i] > 48)) i--; curs = i+1; } curs--; } // Appui sur droite if ((keycode == eKeyRightArrow) && (curs < BlocTexte.Length)) { if (IsKeyPressed(405) || IsKeyPressed(406)) { int i = curs+1; while ((i < BlocTexte.Length) && (BlocTexte.Chars[i] > 48)) i++; curs = i-1; } curs++; } // Appui sur fin if (keycode == eKeyEnd) { // Si appui simultané sur Ctrl (gauche ou droite) if (IsKeyPressed(405) || (IsKeyPressed(406))) curs = BlocTexte.Length; else { x_curs = GetTextWidth(BlocTexte, Bouton.Font)+10; curs = CaractereProx(y_curs); } } // Appui sur Home if (keycode == eKeyHome) { if (IsKeyPressed(405) || (IsKeyPressed(406))) curs = 0; else { x_curs = 0; curs = CaractereProx(y_curs); } } // Appui sur haut if ((keycode == eKeyUpArrow) && (y_curs > 0)) curs = CaractereProx(y_curs-Font_Height); // Appui sur bas //if ((keycode == eKeyDownArrow) && (y_curs < LineCount-1)) if ((keycode == eKeyDownArrow) && (y_curs < button_height[id])) curs = CaractereProx(y_curs+Font_Height); // Si on a appuyé sur une touche sans maintenir shift (sauf Ctrl-A et Ctrl-C), alors sel = curs if ((keycode != eKeyCtrlA) && (keycode != eKeyCtrlC) && (!((IsKeyPressed(403) || IsKeyPressed(404)) && (370 < keycode ) && (keycode < 382)))) sel = curs; // On affiche le cadre surf.Ecrit(curs, Bouton.Font); Bouton.NormalGraphic = Bloc.Graphic; // On relance le clignotement du curseur a = 0; affcur = true; } // Convertit un bouton en bloc-note static function BlocNotes::Convert(Button* button, int couleur_fond, int fond_select, eBlocNotes_Scrollable scrollable) { if (button == null) return; int id = button.InArray(buttons, buttons_size); // On mémorise if ((Bouton != null) && (id >= 0)) { // On enlève le curseur au cas où affcur = false; DrawingSurface* surf = Bloc.GetDrawingSurface(); //surf.RemplitCadre(BlocTexte, Bouton.Font); surf.Ecrit(curs, Bouton.Font); // On mémorise le bloc en cours SaveCurrentBloc(); } // Nouveau bouton if (id < 0) { Bouton = button; Couleur = couleur_fond; Fond_Select = fond_select; if (button.NormalGraphic > 0) Num_Spr = button.NormalGraphic; else Num_Spr = -1; Scrollable = scrollable; curs = Bouton.Text.Length; sel = curs; Bloc = DynamicSprite.Create(Bouton.Width, Bouton.Height); DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.Clear(couleur_fond); button.NewBloc(); SetBlocTexte(Bouton.Text); //surf.RemplitCadre(BlocTexte, Bouton.Font); surf.Ecrit(curs, Bouton.Font); Bouton.Text = ""; Bouton.NormalGraphic = Bloc.Graphic; } else { button.LoadBloc(); Bouton.Text = ""; Bouton.NormalGraphic = Bloc.Graphic; DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.Ecrit(curs, Bouton.Font); // Le remplissage a été effectué par SetBlocText dans LoadBloc } } void BlocNotes::set_ButtonBloc(Button* button) { this.button = button; } Button* BlocNotes::get_ButtonBloc() { return this.button; } static Button* BlocNotes::get_ActiveButton() { return Bouton; } static void BlocNotes::set_ActiveButton(Button* button) { if (button == null) { // Si on avait un bloc en cours, on efface l'éventuel curseur if (Bouton != null) { DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.DrawSurface(surf_buffer); surf.Release(); SaveCurrentBloc(); } Bouton = null; return; } int id = button.InArray(buttons, buttons_size); if (id < 0) { Bouton = null; return; } BlocNotes.Convert(button); } String BlocNotes::geti_Line(int n) { if (this.button == null) return null; int id = this.button.InArray(buttons, buttons_size); if ((id < 0) || (n < 0)) return ""; DrawingSurface* surf = button_sprite[id].GetDrawingSurface(); surf.RemplitCadre(button_text[id], buttons[id].Font); if (n+1 > LineCount) return ""; String ret = Cadre[n]; surf = Bloc.GetDrawingSurface(); surf.RemplitCadre(BlocTexte, Bouton.Font); return ret; } // Retourne tout le texte contenu dans un bouton String BlocNotes::get_Text() { if (this.button == null) return null; if (this.button == Bouton) return BlocTexte; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return null; return button_text[id]; } // Retourne le nombre de lignes que peut afficher le bloc-notes à la fois int BlocNotes::get_RowCount() { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); return button_rowcount[id]; } int BlocNotes::get_Height() { int id = this.button.InArray(buttons, buttons_size); if (id < 0) return 0; return button_height[id]; } /// Gets the width occupied by the longest line of the bloc-notes int BlocNotes::get_Width() { int id = this.button.InArray(buttons, buttons_size); if (id < 0) return 0; return button_width[id]; } /// Gets the horizontal offset of the bloc-notes int BlocNotes::get_XOffset() { if (this.button == null) return; if (this.button == Bouton) return Decal_x; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; return button_xoffset[id]; } /// Gets the vertical offset of the bloc-notes int BlocNotes::get_YOffset() { if (this.button == null) return; if (this.button == Bouton) return Decal_y; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; return button_yoffset[id]; } String BlocNotes::get_SelectedText() { if (this.button == null) return null; if (this.button == Bouton) { if (curs > sel) return BlocTexte.Substring(sel, curs-sel); else return BlocTexte.Substring(curs, sel-curs); } int id = this.button.InArray(buttons, buttons_size); if (id >= 0) { if (button_select[id] > button_cursor[id]) return button_text[id].Substring(button_cursor[id], button_select[id]-button_cursor[id]); else return button_text[id].Substring(button_select[id], button_cursor[id]-button_select[id]); } } void BlocNotes::set_Select(int index) { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; if (index < 0) index = 0; if (this.button == Bouton) { if (index > BlocTexte.Length) index = BlocTexte.Length; sel = index; } else { if (index > button_text[id].Length) index = button_text[id].Length; button_select[id] = index; } } int BlocNotes::get_Select() { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; if (this.button == Bouton) return sel; else return button_select[id]; } /// Sets the horizontal offset of the bloc-notes void BlocNotes::set_XOffset(int offset) { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; if (button_width[id] button_width[id]-this.button.Width) offset = button_width[id]-this.button.Width; if (offset < 0) offset = 0; button_xoffset[id] = offset; CursorDeterminesOffset = false; if (this.button == Bouton) Decal_x = offset; } /// Sets the horizontal offset of the bloc-notes void BlocNotes::set_YOffset(int offset) { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; if (button_height[id] button_height[id]+Font_Height-this.button.Height) offset = button_height[id]-this.button.Height; if (offset < 0) offset = 0; button_yoffset[id] = offset; CursorDeterminesOffset = false; if (this.button == Bouton) Decal_y = offset; } /// Gets the total number of lines (currently displayed or not) in the bloc-notes int BlocNotes::get_LineCount() { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; return button_linecount[id]; } /// Gets the in-text position of the CARACTEREth character of the LIGNEth line of the bloc-notes int BlocNotes::GetCharIndex(int ligne, int caractere) { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; String text = button_text[id]; if (this.button == Bouton) text = BlocTexte; if (ligne < 0) ligne = 0; if (ligne >= LineCount) ligne = LineCount-1; String tmp = Cadre[ligne]; if (caractere < 0) caractere = 0; if (caractere > tmp.Length) caractere = tmp.Length; int i = 0, nb_car = 0; while (i < ligne) { tmp = Cadre[i]; nb_car += tmp.Length; i++; } return nb_car + caractere; } /// Gets the line on which the INDEXth character is displayed in the bloc-notes int BlocNotes::GetLineOfChar(int index) { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; DrawingSurface* surf = button_sprite[id].GetDrawingSurface(); String text = button_text[id]; if (this.button == Bouton) text = BlocTexte; if (index < 0) index = 0; if (index > text.Length) index = text.Length; int nb_car = 0, i = 0; String tmp = ""; while ((nb_car <= index) && (i < LineCount)) { tmp = Cadre[i]; nb_car += tmp.Length; i++; } return i-1; } int BlocNotes::GetPositionInLineOfChar(int index) { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; DrawingSurface* surf = button_sprite[id].GetDrawingSurface(); String text = button_text[id]; if (this.button == Bouton) text = BlocTexte; if (index < 0) index = 0; if (index > text.Length) index = text.Length; int nb_car = 0, i = 0; String tmp = ""; while ((nb_car <= index) && (i < LineCount)) { tmp = Cadre[i]; nb_car += tmp.Length; i++; } return index - (nb_car - tmp.Length); } int BlocNotes::get_Cursor() { if (this.button == null) return; if (this.button == Bouton) return curs; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; return button_cursor[id]; } /// Puts the cursor on the INDEXth character of the bloc-notes's text void BlocNotes::set_Cursor(int index) { if (this.button == null) return; if (index < 0) index = 0; if (this.button == Bouton) { if (index >= BlocTexte.Length) index = BlocTexte.Length; DrawingSurface* surf = Bloc.GetDrawingSurface(); curs = index; surf.Ecrit(curs, Bouton.Font); Bouton.NormalGraphic = Bloc.Graphic; } else { int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; if (index >= button_text[id].Length) index = button_text[id].Length; button_cursor[id] = index; } } /// Replaces the bloc-notes's text by TEXTE void BlocNotes::set_Text(String texte) { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (id < 0) return; button_text[id] = texte; if (this.button == Bouton) { SetBlocTexte(texte); DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.Ecrit(curs, Bouton.Font); Bouton.NormalGraphic = Bloc.Graphic; } } // Sauvegarde le texte du bloc-notes dans FICHIER // ATTENTION : le fichier FICHIER est écrasé par cette action function BlocNotes::SaveInFile(String fichier) { int id = this.button.InArray(buttons, buttons_size); if (id >= 0) { String texte = BlocTexte; if (this.button != Bouton) texte = button_text[id]; File* tmp = File.Open(fichier, eFileWrite); tmp.WriteRawLine(texte); tmp.Close(); } } // Charge le texte contenu dans FICHIER dans le bloc-notes function BlocNotes::LoadFile(String fichier) { if (this.button == null) return; int id = this.button.InArray(buttons, buttons_size); if (!File.Exists(fichier) || id < 0) return; String txt = ""; File* tmp = File.Open(fichier, eFileRead); while (!tmp.EOF) { // On ne veut pas du caractère ASCII 13 (retour chariot) txt = txt.Replace(String.Format("%c%c", 13, 10), String.Format("%c",10)); txt = txt.Replace(String.Format("%c%c", 10, 13), String.Format("%c",10)); txt = txt.Replace(String.Format("%c", 13), String.Format("%c",10)); if (txt != "") txt = txt.AppendChar(10); txt = txt.Append(tmp.ReadRawLineBack()); } tmp.Close(); this.set_Text(txt); } function BlocNotes::Refresh() { if (this.button == null) return; Button* tmp = Bouton; BlocNotes.Convert(this.button); BlocNotes.Convert(tmp); } // Le controle sur lequel on vient de cliquer GUIControl* Clique; // Si on a deja clique (hors d'un bloc) bool CliqueHorsBloc; function repeatedly_execute() { // Gestion du clignotement du curseur (tous les 20 cycles) if ((Bouton != null) && (!(a % 20))) { if (affcur) { DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.DrawSurface(surf_buffer); surf.DrawingColor = Bouton.TextColor; surf.DrawLine(x_curs-Decal_x, y_curs-Decal_y, x_curs-Decal_x, y_curs+Font_Height-Decal_y); surf.Release(); Bouton.NormalGraphic = Bloc.Graphic; } else { DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.DrawSurface(surf_buffer); surf.Release(); Bouton.NormalGraphic = Bloc.Graphic; } affcur = true - affcur; a = 1; // Retour à 1 } else if (Bouton != null) a++; // On récupère le contrôle survolé GUIControl* control = GUIControl.GetAtScreenXY(mouse.x, mouse.y); // Et on regarde si c'est un bloc bool survolebloc = (control!=null)&&(control.AsButton!=null)&&(control.AsButton.InArray(buttons,buttons_size)>-1); // Si l'utilisateur a spécifié un curseur particulier if (MODE_CURSEUR > 0) { if (survolebloc) mouse.UseModeGraphic(MODE_CURSEUR); else mouse.UseDefaultGraphic(); } // Si besoin, on redimensionne le bloc à la bonne taille if ((Bouton != null) && ((Bloc.Width != Bouton.Width) || (Bloc.Height != Bouton.Height))) { Bloc.Resize(Bouton.Width, Bouton.Height); DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.RemplitCadre(BlocTexte, Bouton.Font); surf.Ecrit(curs, Bouton.Font); Bouton.NormalGraphic = Bloc.Graphic; } // Gestion des clics // Si on ne clique sur rien if (!Mouse.IsButtonDown(eMouseLeft)) { // Si CLIQUE ne valait pas NULL, on relance le clignotement if (Clique != null) { a = 0; affcur = true; } Clique = null; // CLIQUE vaut NULL CliqueHorsBloc = false; // On n'a pas cliqué hors d'un bloc } // Sinon, si on clique effectivement else { // Si on ne maintient pas un clic sur un bloc if ((Clique == null) || (Clique != Bouton)) { // Si on maintient un clic hors bloc ou si on ne survole aucun bloc if ((!survolebloc) || CliqueHorsBloc) { // On enlève l'éventuel focus if (Bouton != null) BlocNotes.set_ActiveButton(null); // On dit qu'on a cliqué hors d'un bloc CliqueHorsBloc = true; // Et on s'en va return; } // Si on clique sur un nouveau bloc : on convertit else if (survolebloc && control.AsButton != Bouton) BlocNotes.Convert(control.AsButton); } CursorDeterminesOffset = true; // On dit qu'on a cliqué sur un bloc CliqueHorsBloc = false; // On calcule la position X relative de la souris et le # de ligne où elle se trouve x_curs = mouse.x-(Bouton.OwningGUI.X+Bouton.X)+Decal_x; y_curs = (mouse.y-(Bouton.OwningGUI.Y+Bouton.Y)+Decal_y); // Puis on cherche le caractère le plus proche de cette position curs = CaractereProx(y_curs); // Si on ne maintient pas le clic : sel = curs if ((Clique == null) || (Clique.AsButton != Bouton)) sel = curs; // On affiche le cadre DrawingSurface* surf = Bloc.GetDrawingSurface(); surf.Ecrit(curs, Bouton.Font); Bouton.NormalGraphic = Bloc.Graphic; if (Clique != Bouton) Clique = control; // CLIQUE vaut le contrôle si on a changé de contrôle } }cenum eBlocNotes_Scrollable { eBlocN_NotScrollable = 1, eBlocN_HorizontallyScrollable = 2, eBlocN_VerticallyScrollable = 3, eBlocN_EvenlyScrollable = 6 }; struct BlocNotes { /// Converts a button to a bloc-notes and gives the focus to it import static function Convert(Button* button, int background_color = COLOR_TRANSPARENT, int selection_color = COLOR_TRANSPARENT, eBlocNotes_Scrollable scrollable = eBlocN_VerticallyScrollable); // $AUTOCOMPLETESTATICONLY$ /// Gets/Sets the bloc-notes button that currently has the focus import static attribute Button* ActiveButton; // $AUTOCOMPLETESTATICONLY$ import static Button* get_ActiveButton(); // $AUTOCOMPLETEIGNORE$ import static void set_ActiveButton(Button* button); // $AUTOCOMPLETEIGNORE$ /// Gets/Sets the bloc-notes button corresponding the the BlocNotes instance import attribute Button* ButtonBloc; import Button* get_ButtonBloc(); // $AUTOCOMPLETEIGNORE$ import void set_ButtonBloc(Button* button); // $AUTOCOMPLETEIGNORE$ protected Button* button; /// Gets the text of the bloc-notes import attribute String Text; import String get_Text(); // $AUTOCOMPLETEIGNORE$ import void set_Text(String texte); // $AUTOCOMPLETEIGNORE$ /// Gets the text of Nth line of the bloc-notes readonly import attribute String Line[]; import String geti_Line(int n); // $AUTOCOMPLETEIGNORE$ /// Gets the number of lines that can be displayed within the bloc-notes readonly import attribute int RowCount; import int get_RowCount(); // $AUTOCOMPLETEIGNORE$ /// Gets the total number of lines contained in the bloc-notes readonly import attribute int LineCount; import int get_LineCount(); // $AUTOCOMPLETEIGNORE$ /// Gets the height occupied by the texte in the bloc-notes readonly import attribute int Height; import int get_Height(); // $AUTOCOMPLETEIGNORE$ /// Gets the width occupied by the longest line of the bloc-notes readonly import attribute int Width; import int get_Width(); // $AUTOCOMPLETEIGNORE$ /// Gets/Sets the horizontal offset of the bloc-notes import attribute int XOffset; import int get_XOffset(); // $AUTOCOMPLETEIGNORE$ import void set_XOffset(int xoffset); // $AUTOCOMPLETEIGNORE$ /// Gets/Sets the vertical offset of the bloc-notes import attribute int YOffset; import int get_YOffset(); // $AUTOCOMPLETEIGNORE$ import void set_YOffset(int yoffset); // $AUTOCOMPLETEIGNORE$ /// Gets the index in bloc's text of the character on which the cursor is currently set import attribute int Cursor; import int get_Cursor(); // $AUTOCOMPLETEIGNORE$ import void set_Cursor(int cursor); // $AUTOCOMPLETEIGNORE$ /// Gets the selected text in the bloc-notes readonly import attribute String SelectedText; import String get_SelectedText(); /// Gets/Puts the character on which is the selection import attribute int Select; import int get_Select(); import void set_Select(int index); /// Gets the in-text position of the CARACTEREth character of the LIGNEth line of the bloc-notes import int GetCharIndex(int line, int character); /// Gets the line of the INDEXth character of the text of the bloc-notes import int GetLineOfChar(int index); /// Gets the index of the INDEXth character in its line in the bloc-notes import int GetPositionInLineOfChar(int index); /// Overwrites the file FICHIER with the content of the bloc-notes import function SaveInFile(String fichier); /// Loads the content of the file FICHIER in the bloc-notes import function LoadFile(String fichier); /// Refreshes the bloc-notes import function Refresh(); };AÞ£;ej÷´