From 0872883a5cd30b836e704519b5efe027175b96ec Mon Sep 17 00:00:00 2001 From: Faraphel Date: Fri, 3 Mar 2023 12:47:27 +0100 Subject: [PATCH] the chat is now fully working, input can now take a type_check regex --- NOTE.md | 2 +- assets/image/input/active.png | Bin 6611 -> 311 bytes source/gui/scene/Game.py | 36 ++++++++++++++++++++++++--------- source/gui/scene/RoomCreate.py | 14 +++++++++---- source/gui/scene/RoomJoin.py | 8 ++++++-- source/gui/widget/Input.py | 27 ++++++++++++++++++------- 6 files changed, 64 insertions(+), 23 deletions(-) diff --git a/NOTE.md b/NOTE.md index 2acd8e7..284ba4a 100644 --- a/NOTE.md +++ b/NOTE.md @@ -1,10 +1,10 @@ A faire : -- Faire marcher le tchat - Sauvegarde / Quitter - Historique / Replay - Police d'écriture - Gérer les erreurs (quitter en cours de connexion, ...) - Documenter +- Rendre le texte de status plus visible - Changer les images, rajouter les fonds, ... diff --git a/assets/image/input/active.png b/assets/image/input/active.png index 8a099176228ce165ab4d1c8dfec962ec2f0163ac..2f3c320656ea2303b8e4ccc9644377ec90132b2c 100644 GIT binary patch literal 311 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

B z@D+HXKJP?X6k?3^&l^@*PF_T}%8SGQEBv`#ZZ6+?OO0Qc`1!R#7Mv>4mpj#JJ^hQ1 zc0^Y!r&m6u=XnNSV3hoo(De}>t^cb3K7+xKbl{VaZWc+1iJH~k&!N};z?LD(L;`tr zc^mZkdwoFGF?0*&Is;Cad2R9>A`4C9Os_8#yza|aw!0NpSc3>5bgzjvpd;h>RllTk{};*PXlH^}A;mU< z$wg&!Pf$M3FgA?=iM1>SVR}}w+yf6GNxBsnOV1~KG<4wh?sSxRTtD6OsiNQ>>lg~z zZ4hYGnJI#qOk(F4lwcN6cPvA=pV0Y}%&pC2Hqc1oPV5lOnd2}J@F*d~;l-m@zB*uh&MQ9qezTNrn=jJW-g!0!=ox8fCD zoMyy53kVo#R&<%Mg*p%4s5EbX%l>kdf1c3DB~{Db)A4K65FbO~M)2|)YAuqL<%){$ zQQ>EeC3K=|No%hL6L@M_dMho6g&1JZbnGeH7V=&t4MgW2OAcHyIMt;~knAog{oMSE zG@!cD>SbG%wZjY-b(-25!@1TYZhs8KsI)H^xB#MM?g1NVOL{-JYj;YHp`T=VjaMAG zc2oLla)Cf8f}@<1I#QPUjl8b=|7nX@8Q)ejSNWcHyV;RmF-fbmBtqV%WP{5Ek~oZ9 zoSPrs){(+Q=z;U6(Q}zm!~IxPbobJ=3P8pQ44(^~QILz;Oviq^!Xj7lfj)yKej9oc zG7!oQ%6rEfK`v+&^MPg%)2dH3`AtK8<2d`A1i|9vcq^E8Kajh_bS8Fz)XuTzi5+jG zWU$Z3F-?8Z{4UL-+o?zg(4ad>8`}zBe8_}r58P~|SptHE6Nf&9*Py8poy=s+sU%<`fUTvORoP0CSzM$HSRBh5m zK4}~4`A<1fiPD*97Y|ZJF}3ULU>{;{4bN`ne(*R!hV0i>1+DdZFulJm<>#^evlL^Hx zVzzHs&DV$6cs}dzc{&FsZBP@mCw%qXjKrCm2bLc(bKKEdCE!J6`2yBqFQ#7>i4$B7 zlo5!r=c0ZsdfU>&D-HC$<+y2))H(VR^uVK|Nz&44W^I;5dRCd~t3`@Ue2QvMRM{(A z;ywO8Dd3nRKysL@EwM#mnW*F*s+8e~XJwa5pf@A|hca~h6L#OMGvaz73M2+NA>mx> z9I`)fxQV(pZS}8+p_;d}=j(g>BrbnED4v&m0&WSH<~SC2bA(dT>6HlH9flhW#+UC3 z+cHuz>M?yb~_V{R2iwSp4ixPyb9cm$&+=MDk#ZFdcQ76LuVa*?D*?Kul#Ml&ki?d&#F^a zv`-V;54`Rycm=<0!T4}WeSpG5`c1DGD72uNB&^KSpY>@8&2cDC2S)GIl=qvT4z^Hp z=)1?S-OoJ`fVUmxLL4+5YK^JR$KIgo#A_?V3#exe#M~-8^ z?nCO>=(R6a=!GK~0leLhs;2n3IaHsMZ0Js$j-flwlfm=5NOuv`Jo5?b#h8(HQG)NS z0T4rqU4b}V26DezEo!=2mVXM0E;D$O&S|4<>3p0w;7`Ft@RiyPs}c4`#_Xa>bp~J& zXi>e8r~4(^a(~GCn!ui5yXh|L>#`3n!-_P{y?JVCMfu?tk^=`cw!XD+CfiTp_G6b5 zXN3FEoE8anIYFu&>Kf$>L~{@7KY+HXie4+ix7E?Id4tyIvT|V&u+|wWOx?L+kMUE? zL0~kKJJe5xTL&1;j^hx|K|A!D8Aw1Yl9hiD8AW;ep8>(Kz-+A=MGwI=jWVh40F+! zCD$lHl?wGx8VcpG3%s7SFy$?zdk@y~h{O=&K*i0b6Ae&ru*1?eQLIb(I@xBYV`V-` zx%g|XvUS3GyKizKnCcpA9i={{*)ZHO{xk2lNcpcs^th*Em0>=_(EEbg3k>v>Zrz0C zG!qD(Ugn;_h5wK$uY=oSw~yzR?9KGMq{lkBj2eM-C|X&>mqDbt0GLl)+`~P0re16w zzm|T0s=`Wb#qyTY+~s#+a{xleMG&I^%%BH{tpNH@7XSej!<@iYy9AcKHgM z(6|b5PAbr9ZCpQskGTy_CMUqked9rv*_R}j4CTvl(%fK3O#hjy#wMW%j# zj{hU0|K4C8tSE{^Ru>;hFXvduo+(qjOYD*5^2K=Ws*{g-u77Bq#;;;5 z!22y7I44MMbuHkJi;9GIbfmMZ+?v4KGW{*3s|_>hmG-09X@!<_EhEp&6nxb($}TTd zusps+ax*&}Qj|y7h6s7FaRu46_rwiR&}02zYBBhS$1k}z7Wa6e+`vn`swv*P69Uz6!z z!E?$-1V?)DqkxKyp z%;>cwx~x}@U$6D7yhEn`&w`|ixJxYmQZyk%)s!W{!&3Z3+{exUKm~8zln?oc`-$zP zVR`f8iTC?yntJi48ZIYaDHusblvH{OBa8$_s3}lWB z>K~==nS_R>?SxIVIZm2nv6fOMnie{x7Cs~D&n*PL`rnPmbF8x>T6{SYa_3T0EI=yhq$gDud1~dp%VUt(^&yteh82vwAQK*7yRmMv SiM;;8fRmL}lz@mC1^o}~0y>`n diff --git a/source/gui/scene/Game.py b/source/gui/scene/Game.py index 72765e0..b603bd0 100644 --- a/source/gui/scene/Game.py +++ b/source/gui/scene/Game.py @@ -1,8 +1,6 @@ import socket from typing import TYPE_CHECKING -import pyglet - from source.core.enums import BombState from source.core.error import InvalidBombPosition, PositionAlreadyShot from source.gui.scene import Result @@ -127,10 +125,10 @@ class Game(Scene): self.chat_log = self.add_widget( widget.Text, - x=10, y=35, width=0.5, + x=10, y=45, width=0.4, text="", - anchor_x="left", + anchor_x="left", anchor_y="bottom", multiline=True ) @@ -139,16 +137,16 @@ class Game(Scene): x=10, y=10, width=0.5, height=30, + type_regex=".{0,60}", + style=texture.Button.Style1 ) def send_chat(widget): - text = widget.text + text: str = widget.text widget.text = "" - self.chat_log.text += "\n" + text - self.chat_log.label.y = self.chat_log.y + self.chat_log.label.content_height - + self.chat_new_message(self.name_ally, text) PacketChat(message=text).send_connection(connection) self.chat_input.add_listener("on_enter", send_chat) @@ -196,6 +194,15 @@ class Game(Scene): # function + def _refresh_chat_box(self): + # supprime des messages jusqu'à ce que la boite soit plus petite que un quart de la fenêtre + while self.chat_log.label.content_height > (self.window.height / 4): + chat_logs: list[str] = self.chat_log.text.split("\n") + self.chat_log.text = "\n".join(chat_logs[1:]) + + # ajuste la boite de message pour être collé en bas + self.chat_log.label.y = self.chat_log.y + self.chat_log.label.content_height + def _refresh_turn_text(self): self.label_state.text = ( "Placer vos bateaux" if not self.boat_ready_ally else @@ -207,6 +214,12 @@ class Game(Scene): def game_end(self, won: bool): self.window.add_scene(Result, won=won) + def chat_new_message(self, author: str, content: str): + message: str = f"[{author}] - {content}" + self.chat_log.text += "\n" + message + + self._refresh_chat_box() + # property @property @@ -257,7 +270,7 @@ class Game(Scene): # network def network_on_chat(self, connection: socket.socket, packet: PacketChat): - print(packet.message) + self.chat_new_message(self.name_enemy, packet.message) def network_on_boat_placed(self, connection: socket.socket, packet: PacketBoatPlaced): self.boat_ready_enemy = True @@ -309,3 +322,8 @@ class Game(Scene): # si cette bombe a touché le dernier bateau, alors l'on a gagné self.game_end(won=True) return True # coupe la connexion + + # event + + def on_resize_after(self, width: int, height: int): + self._refresh_chat_box() diff --git a/source/gui/scene/RoomCreate.py b/source/gui/scene/RoomCreate.py index 26b9afd..967a5e5 100644 --- a/source/gui/scene/RoomCreate.py +++ b/source/gui/scene/RoomCreate.py @@ -44,7 +44,8 @@ class RoomCreate(Scene): style=texture.Input.Style1, - regex=r"\d{1,5}", + type_regex=r"\d{0,5}", + check_regex=r"\d{1,5}", label_text="52321" ) @@ -66,6 +67,8 @@ class RoomCreate(Scene): x=0.2, y=0.45, width=0.15, height=0.1, + type_regex=r".{0,16}", + style=texture.Input.Style1, label_text="Host" @@ -86,7 +89,8 @@ class RoomCreate(Scene): x=0.2, y=0.86, width=0.1, height=0.08, - regex=r"\d+", + type_regex=r"\d{0,4}", + check_regex=r"\d+", style=texture.Input.Style1, @@ -106,7 +110,8 @@ class RoomCreate(Scene): x=0.2, y=0.76, width=0.1, height=0.08, - regex=r"\d+", + type_regex=r"\d{0,4}", + check_regex=r"\d+", style=texture.Input.Style1, @@ -196,7 +201,8 @@ class RoomCreate(Scene): x=0.7, y=0.68, width=0.2, height=0.08, - regex=r"\d+", + type_regex=r"\d{0,4}", + check_regex=r"\d+", style=texture.Input.Style1, diff --git a/source/gui/scene/RoomJoin.py b/source/gui/scene/RoomJoin.py index 375db2f..97d2646 100644 --- a/source/gui/scene/RoomJoin.py +++ b/source/gui/scene/RoomJoin.py @@ -29,6 +29,8 @@ class RoomJoin(Scene): widget.Input, x=0.4, y=0.55, width=0.2, height=0.1, + type_regex=r".{0,16}", + style=texture.Input.Style1, label_text="Client" @@ -40,7 +42,8 @@ class RoomJoin(Scene): widget.Input, x=0.4, y=0.45, width=0.13, height=0.1, - regex=r"\d{1,3}(\.\d{1,3}){3}", + type_regex=r"[\d\.]{0,15}", + check_regex=r"\d{1,3}(\.\d{1,3}){3}", style=texture.Input.Style1, @@ -51,7 +54,8 @@ class RoomJoin(Scene): widget.Input, x=0.53, y=0.45, width=0.07, height=0.1, - regex=r"\d{1,5}", + type_regex=r"\d{0,5}", + check_regex=r"\d{1,5}", label_text="52321", diff --git a/source/gui/widget/Input.py b/source/gui/widget/Input.py index e20ccfe..517bdce 100644 --- a/source/gui/widget/Input.py +++ b/source/gui/widget/Input.py @@ -22,7 +22,8 @@ class Input(BoxWidget): style: Type[Style], - regex: Optional[str | re.Pattern] = None, + type_regex: Optional[str | re.Pattern] = None, + check_regex: Optional[str | re.Pattern] = None, x: Distance = 0, y: Distance = 0, @@ -36,7 +37,8 @@ class Input(BoxWidget): self._invalid = False - self.regex = re.compile(regex) if isinstance(regex, str) else regex + self.type_regex = re.compile(type_regex) if type_regex is not None else None + self.check_regex = re.compile(check_regex) if check_regex is not None else None self.background = Sprite( img=self.style.get("normal"), @@ -65,10 +67,9 @@ class Input(BoxWidget): and if click the clicking texture (if it exists) :return: the corresponding texture """ - return ( texture if self.activated and (texture := self.style.get("active")) is not None else # NOQA - texture if self.invalid and (texture := self.style.get("signal")) is not None else + texture if self.invalid and (texture := self.style.get("error")) is not None else self.style.get("normal") ) @@ -84,6 +85,10 @@ class Input(BoxWidget): # center the label self.label.x, self.label.y = self.center + def check(self): + if self.check_regex is not None: # si il y a un regex de validation, applique le pour vérifier le texte + self.invalid = self.check_regex.fullmatch(self.text) is None + # property @property @@ -110,18 +115,26 @@ class Input(BoxWidget): if symbol == pyglet.window.key.BACKSPACE: # si la touche "supprimé" est enfoncé self.text = self.text[0:-1] # retire le dernier caractère du texte + self.check() if symbol == pyglet.window.key.ENTER: self.trigger_event("on_enter") def on_text(self, char: str): + print("on_text") + if not self.activated: return # ignore si ce widget est désactivé / non sélectionné if not self.label.multiline and char in "\r\n": return # si le texte est sur une ligne, ignore les retours - self.text += char # ajoute le caractère au label + new_text: str = self.text + char - if self.regex is not None: # si il y a un regex de validation, applique le pour vérifier le texte - self.invalid = self.regex.fullmatch(self.text) is None + if self.type_regex is not None: + # s'il y a un regex d'écriture, vérifie qu'il est respecté, sinon ignore le nouveau caractère + if self.type_regex.fullmatch(new_text) is None: return + + self.text = new_text # ajoute le caractère au label + + self.check() # rafraichi le fait que le texte est considéré comme valide ou non if not self.invalid: self.trigger_event("on_valid_text")