""" Module de gestion de texte pour Pyxel Permet d'afficher du texte et de capturer la saisie utilisateur """ import pyxel # Mapping des touches Pyxel vers les caractères KEY_MAP = { pyxel.KEY_A: ('a', 'A'), pyxel.KEY_B: ('b', 'B'), pyxel.KEY_C: ('c', 'C'), pyxel.KEY_D: ('d', 'D'), pyxel.KEY_E: ('e', 'E'), pyxel.KEY_F: ('f', 'F'), pyxel.KEY_G: ('g', 'G'), pyxel.KEY_H: ('h', 'H'), pyxel.KEY_I: ('i', 'I'), pyxel.KEY_J: ('j', 'J'), pyxel.KEY_K: ('k', 'K'), pyxel.KEY_L: ('l', 'L'), pyxel.KEY_M: ('m', 'M'), pyxel.KEY_N: ('n', 'N'), pyxel.KEY_O: ('o', 'O'), pyxel.KEY_P: ('p', 'P'), pyxel.KEY_Q: ('q', 'Q'), pyxel.KEY_R: ('r', 'R'), pyxel.KEY_S: ('s', 'S'), pyxel.KEY_T: ('t', 'T'), pyxel.KEY_U: ('u', 'U'), pyxel.KEY_V: ('v', 'V'), pyxel.KEY_W: ('w', 'W'), pyxel.KEY_X: ('x', 'X'), pyxel.KEY_Y: ('y', 'Y'), pyxel.KEY_Z: ('z', 'Z'), pyxel.KEY_0: ('0', ')'), pyxel.KEY_1: ('1', '!'), pyxel.KEY_2: ('2', '@'), pyxel.KEY_3: ('3', '#'), pyxel.KEY_4: ('4', '$'), pyxel.KEY_5: ('5', '%'), pyxel.KEY_6: ('6', '^'), pyxel.KEY_7: ('7', '&'), pyxel.KEY_8: ('8', '*'), pyxel.KEY_9: ('9', '('), pyxel.KEY_SPACE: (' ', ' '), pyxel.KEY_MINUS: ('-', '_'), pyxel.KEY_PERIOD: ('.', '>'), pyxel.KEY_COMMA: (',', '<'), pyxel.KEY_SLASH: ('/', '?'), pyxel.KEY_SEMICOLON: (';', ':'), pyxel.KEY_APOSTROPHE: ("'", '"'), } class TextInput: """ Champ de saisie de texte pour Pyxel Exemple d'utilisation: input_field = TextInput(x=10, y=50, max_length=20) def update(): input_field.update() if input_field.submitted: print(f"Texte saisi: {input_field.text}") input_field.reset() def draw(): input_field.draw() """ def __init__(self, x=0, y=0, max_length=32, width=None, color=7, bg_color=0, cursor_color=8): """ Initialise un champ de saisie Args: x, y: Position du champ max_length: Nombre maximum de caractères width: Largeur du champ en pixels (auto si None) color: Couleur du texte (0-15) bg_color: Couleur de fond (0-15, None pour transparent) cursor_color: Couleur du curseur (0-15) """ self.x = x self.y = y self.max_length = max_length self.width = width if width else (max_length * 4 + 4) self.color = color self.bg_color = bg_color self.cursor_color = cursor_color self.text = "" self.cursor_pos = 0 self.active = True self.submitted = False self._cursor_visible = True self._cursor_timer = 0 def update(self): """Met à jour le champ de saisie (à appeler dans update())""" if not self.active: return self.submitted = False # Clignotement du curseur self._cursor_timer += 1 if self._cursor_timer >= 15: self._cursor_timer = 0 self._cursor_visible = not self._cursor_visible # Validation avec Entrée if pyxel.btnp(pyxel.KEY_RETURN): self.submitted = True return # Suppression avec Backspace if pyxel.btnp(pyxel.KEY_BACKSPACE, hold=10, repeat=3): if self.cursor_pos > 0: self.text = self.text[:self.cursor_pos-1] + self.text[self.cursor_pos:] self.cursor_pos -= 1 # Suppression avec Delete if pyxel.btnp(pyxel.KEY_DELETE, hold=10, repeat=3): if self.cursor_pos < len(self.text): self.text = self.text[:self.cursor_pos] + self.text[self.cursor_pos+1:] # Navigation avec flèches if pyxel.btnp(pyxel.KEY_LEFT, hold=10, repeat=3): self.cursor_pos = max(0, self.cursor_pos - 1) if pyxel.btnp(pyxel.KEY_RIGHT, hold=10, repeat=3): self.cursor_pos = min(len(self.text), self.cursor_pos + 1) if pyxel.btnp(pyxel.KEY_HOME): self.cursor_pos = 0 if pyxel.btnp(pyxel.KEY_END): self.cursor_pos = len(self.text) # Saisie de caractères if len(self.text) < self.max_length: shift = pyxel.btn(pyxel.KEY_LSHIFT) or pyxel.btn(pyxel.KEY_RSHIFT) for key, chars in KEY_MAP.items(): if pyxel.btnp(key, hold=15, repeat=3): char = chars[1] if shift else chars[0] self.text = self.text[:self.cursor_pos] + char + self.text[self.cursor_pos:] self.cursor_pos += 1 break def draw(self): """Dessine le champ de saisie (à appeler dans draw())""" # Fond if self.bg_color is not None: pyxel.rect(self.x, self.y, self.width, 9, self.bg_color) # Bordure si actif if self.active: pyxel.rectb(self.x - 1, self.y - 1, self.width + 2, 11, self.color) # Texte pyxel.text(self.x + 2, self.y + 1, self.text, self.color) # Curseur if self.active and self._cursor_visible: cursor_x = self.x + 2 + self.cursor_pos * 4 pyxel.rect(cursor_x, self.y + 1, 1, 7, self.cursor_color) def reset(self): """Réinitialise le champ""" self.text = "" self.cursor_pos = 0 self.submitted = False def set_text(self, text): """Définit le texte du champ""" self.text = text[:self.max_length] self.cursor_pos = len(self.text) class TextBox: """ Zone de texte multiligne avec retour à la ligne automatique Exemple d'utilisation: textbox = TextBox(x=10, y=10, width=100, color=7) textbox.set_text("Ceci est un long texte qui sera automatiquement découpé en plusieurs lignes.") def draw(): textbox.draw() """ def __init__(self, x=0, y=0, width=100, color=7, line_spacing=8): """ Initialise une zone de texte Args: x, y: Position de la zone width: Largeur en pixels color: Couleur du texte (0-15) line_spacing: Espacement entre les lignes """ self.x = x self.y = y self.width = width self.color = color self.line_spacing = line_spacing self.lines = [] def set_text(self, text): """Définit le texte avec retour à la ligne automatique""" self.lines = [] chars_per_line = self.width // 4 paragraphs = text.split('\n') for paragraph in paragraphs: words = paragraph.split(' ') current_line = "" for word in words: test_line = current_line + (" " if current_line else "") + word if len(test_line) <= chars_per_line: current_line = test_line else: if current_line: self.lines.append(current_line) # Mot trop long, on le coupe while len(word) > chars_per_line: self.lines.append(word[:chars_per_line]) word = word[chars_per_line:] current_line = word if current_line: self.lines.append(current_line) def draw(self): """Dessine la zone de texte""" for i, line in enumerate(self.lines): pyxel.text(self.x, self.y + i * self.line_spacing, line, self.color) def get_height(self): """Retourne la hauteur totale du texte""" return len(self.lines) * self.line_spacing class TypeWriter: """ Effet machine à écrire pour afficher du texte progressivement Exemple d'utilisation: typewriter = TypeWriter(x=10, y=10, speed=3) typewriter.set_text("Bienvenue dans le jeu...") def update(): typewriter.update() def draw(): typewriter.draw() """ def __init__(self, x=0, y=0, width=100, color=7, speed=2, line_spacing=8): """ Args: x, y: Position width: Largeur en pixels color: Couleur du texte speed: Frames entre chaque caractère (plus bas = plus rapide) line_spacing: Espacement entre les lignes """ self.textbox = TextBox(x, y, width, color, line_spacing) self.speed = speed self.full_text = "" self.displayed_chars = 0 self.timer = 0 self.finished = False def set_text(self, text): """Définit le texte à afficher progressivement""" self.full_text = text self.displayed_chars = 0 self.timer = 0 self.finished = False def update(self): """Met à jour l'animation""" if self.finished: return self.timer += 1 if self.timer >= self.speed: self.timer = 0 self.displayed_chars += 1 if self.displayed_chars >= len(self.full_text): self.displayed_chars = len(self.full_text) self.finished = True self.textbox.set_text(self.full_text[:self.displayed_chars]) def draw(self): """Dessine le texte""" self.textbox.draw() def skip(self): """Affiche tout le texte immédiatement""" self.displayed_chars = len(self.full_text) self.finished = True self.textbox.set_text(self.full_text) def is_finished(self): """Retourne True si tout le texte est affiché""" return self.finished # --- Exemple d'utilisation --- if __name__ == "__main__": class Demo: def __init__(self): pyxel.init(200, 150, title="Demo TextInput") self.input_field = TextInput(x=10, y=60, max_length=25, color=7) self.typewriter = TypeWriter(x=10, y=10, width=180, speed=2) self.typewriter.set_text("Bienvenue ! Entrez votre nom ci-dessous et appuyez sur Entree.") self.messages = [] pyxel.run(self.update, self.draw) def update(self): self.typewriter.update() self.input_field.update() # Skip le typewriter avec espace if pyxel.btnp(pyxel.KEY_SPACE) and not self.input_field.active: self.typewriter.skip() # Validation de la saisie if self.input_field.submitted and self.input_field.text: self.messages.append(f"Bonjour, {self.input_field.text} !") self.input_field.reset() def draw(self): pyxel.cls(0) self.typewriter.draw() pyxel.text(10, 50, "Votre nom:", 6) self.input_field.draw() # Afficher les messages for i, msg in enumerate(self.messages[-3:]): pyxel.text(10, 90 + i * 10, msg, 11) Demo()