
    Iik             
          d Z ddlZddlZddlmZ ddlmZ ddlmc m	Z
 ddlZddlZddlmZ ddlZddlmZ ej$                  j'                  dej$                  j)                  ej$                  j)                  ej$                  j+                  e                         ddlmZ dd	lmZ dd
lmZ ddlmZ ddlm Z   ejB                  e"      Z# ed       G d d             Z$ G d dejJ                        Z&y)z&Main window for Play Palace v9 client.    N   )MenuList)LoginDialog)	dataclass)Path)slash_commands)SoundManager)NetworkManager)BufferSystem)set_item_in_dictT)frozenc                       e Zd ZU eeef   ed<   eeef   ed<   eeef   ed<   eeef   ed<   eeef   ed<   eeef   ed<   ed	d       Zy)
UiPlatformConfigwindow_size	menu_sizehistory_size	chat_size	edit_sizemultiline_sizec                  $    t        dddddd      S )N)i  i  )i    )  r   )r      )r   x   )r   r   r   r   r   r   )r        =C:\Users\dbart\PlayPalace11\clients\desktop\ui\main_window.pyfor_platformzUiPlatformConfig.for_platform"   s#      " #%
 	
r   N)returnr   )__name__
__module____qualname__tupleint__annotations__staticmethodr   r   r   r   r   r      sh    sCx S#XS/!S#XS#X#s(O#	
 	
r   r   c                       e Zd ZdZej
                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                  ej                   ej"                  ej$                  ej&                  ej(                  hZd fd	Zd Zd Zd Zd Zd Zd	 Zd
 Zd Zdddede de fdZ!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d Z+d Z,d Z-d Z.d Z/d  Z0d! Z1d" Z2d# Z3d$ Z4d% Z5d& Z6d' Z7d( Z8d)e9de fd*Z:de fd+Z;d)e9de fd,Z<d)e9dedz  fd-Z=d)e9d.e dedz  fd/Z>d)e9dedz  fd0Z?d)e9dedz  fd1Z@d)e9dedz  fd2ZAd)e9dedz  fd3ZBd4ede fd5ZCd6 ZDd7 ZEdd8ZFd9 ZGdd:edefd;ZHdd<edefd=ZId>efd?ZJd@ed>efdAZKddBZL	 	 	 	 	 ddCZMdD ZNdE ZOdF ZPdG ZQd)e9de fdHZRd)e9de fdIZSd)e9ddfdJZTd)e9de fdKZUdLe dMedNe ddfdOZVeWddP       ZXeWd)e9de fdQ       ZYddRZZddSedTe dUe fdVZ[ddWZ\dX Z]dY Z^dZ Z_d[ Z`d\ Zad] Zbd^ Zcd_ Zdd` Zed>efdaZfdbe9dcefddZgde ZhddfZidg Zjdh Zkdi Zldj Zmdk Zndl Zodm Zpdn Zqdo Zrdp Zsdq Ztdr Zuds Zvdt Zwdu Zxdv Zydw Zzdx Z{ddyZ|eWde fdz       Z}eWd{        Z~eWd|        Zd} Zd~ ZdedefdZdede fdZdeddfdZddZdee   de9dz  ddfdZde9dz  deddfdZddZdee   de9dz  ddfdZdee   deedz     deedz     de9dz  ddf
dZdeedz     ddfdZd Zd Zd Zd Zd Zd Z xZS )
MainWindowz2Main application window for Play Palace v9 client.Nc                    t         j                         | _        t        |   dd| j                  j
                         |xs i | _        | j                  j                  d      | _        | j                  j                  d      | _	        d| _
        d| _        d| _        t        j                         | _        t!               | _        | t$        _        | j"                  j)                  dd       t+        |       | _        d	| _        d	| _        d	| _        d	| _        d
| _        d| _        d| _        d| _        d| _        d| _         i | _!        i | _"        | j                  rF| j                  r:| j                  jG                  | j                        | _!        | jI                          d| _%        d| _&        d| _'        d| _(        d| _)        g | _*        d	| _+        d	| _,        d	| _-        d	| _.        d| _/        ta               | _1        | jb                  je                  d       | jb                  je                  d       | jb                  je                  d       | jb                  je                  d       | jb                  je                  d       | jg                         }d|v rA|d   D ]9  }| jb                  ji                  |      r| jb                  jk                  |       ; | jm                          | jo                          | jq                          | js                  tt        jv                  | jx                         | j{                          y)z
        Initialize the main window.

        Args:
            credentials: Dict with username, password, server_url, server_id, config_manager
        NzPlayPalace 11)parenttitlesize	server_idconfig_managerzopen.ogg      ?volumeFr      zmainmus.ogglistalltablechatsactivitymiscmuted_buffers)>r   r   ui_cfgsuper__init__r   credentialsgetr-   r.   	menu_list
chat_inputhistory_textauto_outputAutospeakerr	   sound_managerr   clientplayr
   network	connected_force_closeexpecting_reconnectreturning_to_loginreconnect_attemptsmax_reconnect_attemptslast_server_messagelast_server_status_packetlast_status_announcementconnection_timeout_timerclient_optionsserver_optionsget_client_options_apply_client_audio_optionscurrent_test_musiccurrent_modeedit_mode_callbackcurrent_menu_idcurrent_menu_statecurrent_menu_item_idscurrent_edit_multilinecurrent_edit_read_only_pending_edit_clear_pending_multiline_clear_ping_start_timer   buffer_systemcreate_buffer_load_preferencesis_mutedtoggle_mute
_create_ui_setup_accelerators_populate_test_dataBindwx	EVT_CLOSEon_close_auto_connect)selfr=   preferencesbuffer_name	__class__s       r   r<   zMainWindow.__init__E   s    '335!(( 	 	
 ',"))--k:"..223CD   #'') *^ $ 	
37 &d+!#( "'"#&(##' )-&(,%(,% !  4>>"&"5"5"H"H"XD,,. #0 #"&#"&%'"&+#&+##( (-% !% *^((/((1((1((4((0 ,,.k)*?;))22;?&&22;?  <
 	  "  " 			",,. 	r   c                     d| j                   v rp| j                   d   }|j                  dd      dz  }|j                  dd      dz  }| j                  j                  |       | j                  j	                  |       yy)z.Apply audio settings from client-side options.audiomusic_volume         Y@ambience_volumeN)rS   r>   rE   set_music_volumeset_ambience_volume)ro   rt   ru   rx   s       r   rV   z&MainWindow._apply_client_audio_options   sx    d)))''0E 99^R85@L#ii(92>FO//=22?C *r   c                 h   t        j                  |       }| j                  }t        j                  |d      | _        t        || j                  |j                  t         j                  t         j                  z        | _
        | j                  j                  t         j                  | j                         | j                  j                  t         j                  | j                         | j                  j                  t         j                   | j"                         t        j                  |d      | _        t        j&                  ||j(                  t         j*                        | _        | j,                  j                  t         j.                  | j0                         | j,                  j                  t         j2                  | j4                         | j,                  j7                          | j$                  j7                          t        j&                  ||j8                  t         j:                  t         j<                  z        | _        | j>                  j                  t         j2                  | j@                         | j>                  j7                          d| _!        d| _"        t        j                  |d      | _#        t        j&                  ||jH                  t         j*                        | _%        | jJ                  j                  t         j.                  | jL                         t        j                  |d	      | _'        t        j&                  ||jP                  t         j:                  t         jR                  z  t         j<                  z        | _*        | jT                  jW                  d
       t        jX                  t         jZ                        }|j]                  | j                  dt         j^                  d       |j]                  | j                  dt         j`                  t         jb                  z  t         jd                  z  t         jf                  z  d       t        jX                  t         jZ                        }|j]                  | jN                  dt         j^                  d       |j]                  | jT                  dt         j`                  t         jb                  z  t         jd                  z  d       |j]                  | jF                  dt         j^                  d       |j]                  | jJ                  dt         j`                  t         jb                  z  t         jd                  z  t         jf                  z  d       t        jX                  t         jh                        }|j]                  |dt         j`                  t         j^                  z  d       |j]                  |dt         j`                  t         j^                  z  d       |jk                  |       y)zACreate the UI components (audio-first, with basic visual layout).z&Menu)label)rE   r,   style&Edit)r,   r}   Tkeybindz&Chatz&HistoryHistoryr      r   N)6rk   Panelr:   
StaticText
menu_labelr   rE   r   	LB_SINGLEWANTS_CHARSr?   rj   EVT_LISTBOX_DCLICKon_menu_activateEVT_SET_FOCUSon_menu_focusEVT_KILL_FOCUSon_menu_unfocus
edit_labelTextCtrlr   TE_PROCESS_ENTER
edit_inputEVT_TEXT_ENTERon_edit_enterEVT_CHARon_edit_charHider   TE_MULTILINETE_DONTWRAPedit_input_multilineon_edit_multiline_charmultiletter_enabledescape_behavior
chat_labelr   r@   on_chat_enterhistory_labelr   TE_READONLYrA   SetNameBoxSizerVERTICALAddALLEXPANDLEFTRIGHTBOTTOM
HORIZONTALSetSizer)ro   panelr:   
left_sizerright_sizersizers         r   rg   zMainWindow._create_ui   s    --W=!,,!!,,/	
 	B1143H3HIB,,d.@.@AB--t/C/CD --W=++e&2B2B"J]J]^R..0B0BCR[[$*;*;< %'KK--R__r~~5U%
! 	!!&&r{{D4O4OP!!&&( $( ( --W=++e&2B2B"J]J]^R..0B0BC  ]]5
CKK$$//BNN2R^^C
 	!!),[[-
t26615t~~q"))bgg*=*H299*TVWXkk"++.**Arvvq9))1bii"''.ABHH.LaPBFFA6BII,?"((,JRYY,VXYZBMM*		*aRVV!3Q7		+q"))bff"4a8ur   c                 B   t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _	        t        j                         | _
        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j                         | _        t        j*                  t         j,                  t/        d      | j                        t        j*                  t         j0                  t         j2                  | j                        t        j*                  t         j4                  t         j2                  | j                        t        j*                  t         j0                  t         j6                  | j
                        t        j*                  t         j0                  t         j8                  | j                        t        j*                  t         j0                  t         j:                  | j                        t        j*                  t         j0                  t         j<                  | j                        t        j*                  t         j0                  t         j>                  | j                        t        j*                  t         j4                  t         j>                  | j                        t        j*                  t         j,                  t/        d      | j                        g
}t        j*                  t         j0                  t/        d      | j                        t        j*                  t         j0                  t/        d      | j                        t        j*                  t         j4                  t/        d      | j                        t        j*                  t         j4                  t/        d      | j                        t        j*                  t         j0                  t/        d      | j                         t        j*                  t         j0                  t/        d      | j"                        t        j*                  t         j4                  t/        d      | j$                        t        j*                  t         j4                  t/        d      | j&                        t        j*                  t         j0                  t         j@                  | j(                        g	}t        jB                  ||z         | _"        t        jB                  |      | _#        | jI                  | jF                         | jK                  t         jL                  | jN                  | j                         | jK                  t         jL                  | jP                  | j                         | jK                  t         jL                  | jR                  | j                         | jK                  t         jL                  | jT                  | j
                         | jK                  t         jL                  | jV                  | j                         | jK                  t         jL                  | jX                  | j                         | jK                  t         jL                  | jZ                  | j                         | jK                  t         jL                  | j\                  | j                         | jK                  t         jL                  | j^                  | j                         | jK                  t         jL                  | j`                  | j                         | jK                  t         jL                  | jb                  | j                         | jK                  t         jL                  | jd                  | j                         | jK                  t         jL                  | jf                  | j                         | jK                  t         jL                  | jh                  | j                         | jK                  t         jL                  | jj                  | j                          | jK                  t         jL                  | jl                  | j"                         | jK                  t         jL                  | jn                  | j$                         | jK                  t         jL                  | jp                  | j&                         | jK                  t         jL                  | jr                  | j(                         | jK                  t         jt                  | jv                         y)	zSetup keyboard accelerators.MP[],.)idN)<rk   NewIdRefID_FOCUS_MENUID_VOLUME_DOWNID_VOLUME_UPID_AMBIENCE_DOWNID_AMBIENCE_UPID_TOGGLE_TABLE_CHATID_TOGGLE_GLOBAL_CHATID_PINGID_LIST_ONLINEID_LIST_ONLINE_WITH_GAMESID_PREV_BUFFERID_NEXT_BUFFERID_FIRST_BUFFERID_LAST_BUFFERID_OLDER_MESSAGEID_NEWER_MESSAGEID_OLDEST_MESSAGEID_NEWEST_MESSAGEID_TOGGLE_MUTEAcceleratorEntry	ACCEL_ALTordACCEL_NORMALWXK_F6ACCEL_SHIFTWXK_F7WXK_F8WXK_F9WXK_F10WXK_F2WXK_F4AcceleratorTableaccel_table_with_buffersaccel_table_without_buffersSetAcceleratorTablerj   EVT_MENUon_focus_menuon_toggle_table_chaton_toggle_global_chaton_ambience_downon_ambience_upon_volume_downon_volume_upon_pingon_list_onlineon_list_online_with_gameson_prev_bufferon_next_bufferon_first_bufferon_last_bufferon_older_messageon_newer_messageon_oldest_messageon_newest_messageon_buffer_mute_toggleEVT_CHAR_HOOKon_char_hook)ro   common_entriesbuffer_entriess      r   rh   zMainWindow._setup_accelerators   sl     [[] kkmKKM " kkm$&KKM!%'[[]"{{} kkm)+& !kkm kkm!{{} kkm " "!#!# kkm c#h8J8JKD<U<UV		4;U;UVD<Q<QRD<O<OPD<O<OPT=N=NOD<O<OP		4;Y;YZc#hE
  S4;N;NOS4;N;NOC$:N:NOC$:M:MNS4;P;PQS4;P;PQC$:P:PQC$:P:PQD<O<OP
  )+(;(;N^<[(\%+-+>+>~+N( 	  !A!AB 			"++t11d6H6H	I		"++t88T=V=V	W		"++t99d>X>X	Y		"++t449N9N	O		"++t22t7J7J	K		"++t22t7J7J	K		"++t00T5F5F	G		"++t||	=		"++t22t7J7J	K		KK**-- 	 	
 			"++t22t7J7J	K		"++t22t7J7J	K		"++t338L8L	M		"++t22t7J7J	K		"++t449N9N	O		"++t449N9N	O		"++t55$:P:P	Q		"++t55$:P:P	Q		"++t99d>Q>Q	R 			"""D$5$56r   c                      y)zPopulate UI with test data.Nr   ro   s    r   ri   zMainWindow._populate_test_dataY  s     	r   c                 L   | j                   r| j                  s|t        j                  | ddt        j                  t        j
                  z  t        j                  z        }|j                         }|j                          |t        j                  k7  ry|j                          y)z=Handle window close (Alt+F4, close button) with confirmation.zAre you sure you want to exit?zConfirm ExitN)rI   rJ   rk   MessageDialogYES_NO
NO_DEFAULTICON_QUESTION	ShowModalDestroyID_YESSkip)ro   eventdlgresults       r   rm   zMainWindow.on_close_  ss    >>$"3"3""0		BMM)B,<,<<	C ]]_FKKM"

r   c                 8    | j                   j                          y)z)Handle Alt+M shortcut to focus menu list.N)r?   SetFocusro   r   s     r   r   zMainWindow.on_focus_menun  s    !r   c                 Z    | j                  | j                         |j                          y)z:Handle menu list gaining focus - enable buffer navigation.N)r   r   r   r  s     r   r   zMainWindow.on_menu_focusr  s      !>!>?

r   c                 z    	 | j                  | j                         |j                          y# t        $ r Y w xY w)z:Handle menu list losing focus - disable buffer navigation.N)r   r   RuntimeErrorr   r  s     r   r   zMainWindow.on_menu_unfocusw  s:    	$$T%E%EF 	

  		s   . 	::Tcreate_modekey_pathr  r   c                    | j                   r| j                  sy| j                   j                  ||| j                  |       t        | j                  |||       y )NFr  )r.   r-   set_client_optionr   rS   )ro   r	  valuer  s       r   modify_option_valuezMainWindow.modify_option_value  sP    ""$..--eT^^ 	. 	
 	,,h;Wr   c                    | j                   j                  }t        d|dz
        }| j                   j                  |       t	        |dz        }| j
                  j                  d| d       | j                  d|       y)z&Handle F7 to decrease ambience volume.        皙?d   
Ambience: %audio/ambience_volumeN)rE   rx   maxrz   r$   rD   speakr  ro   r   current_volume
new_volume
percentages        r   r   zMainWindow.on_ambience_down  s    ++;;ns23
..z:c)*
Z
|156  !8*Er   c                    | j                   j                  }t        d|dz         }| j                   j                  |       t	        |dz        }| j
                  j                  d| d       | j                  d|       y)z&Handle F8 to increase ambience volume.r/   r  r  r  r  r  N)rE   rx   minrz   r$   rD   r  r  r  s        r   r   zMainWindow.on_ambience_up  r  r   c                    | j                   j                  }t        d|dz
        }| j                   j                  |       t	        |dz        }| j
                  j                  d| d       | j                  d|       y)z#Handle F9 to decrease music volume.r  r  r  Music: r  audio/music_volumeN)rE   ru   r  ry   r$   rD   r  r  r  s        r   r   zMainWindow.on_volume_down  s    ++88ns23
++J7c)*
WZL23  !5zBr   c                    | j                   j                  }t        d|dz         }| j                   j                  |       t	        |dz        }| j
                  j                  d| d       | j                  d|       y)z$Handle F10 to increase music volume.r/   r  r  r  r  r   N)rE   ru   r  ry   r$   rD   r  r  r  s        r   r   zMainWindow.on_volume_up  r!  r   c                     ddl }|j                         | _        | j                  j                  d       | j                  j                  ddi       y)z4Handle Alt+P to ping the server and measure latency.r   Nzpingstart.oggtypeping)timera   rE   rG   rH   send_packet)ro   r   r&  s      r   r   zMainWindow.on_ping  s>     $		0  &&!12r   c                 X    | j                   r| j                  j                  ddi       yy)z*Handle F2 to request list of online users.r$  list_onlineN)rI   rH   r'  r  s     r   r   zMainWindow.on_list_online  s%    >>LL$$fm%<= r   c                 x    | j                   r.| j                  dk(  ry| j                  j                  ddi       yy)z7Handle Shift+F2 to request online users with game info.online_usersNr$  list_online_with_games)rI   rZ   rH   r'  r  s     r   r   z$MainWindow.on_list_online_with_games  s7    >>##~5LL$$f.F%GH r   c                     ddl }| j                  kt        |j                         | j                  z
  dz        }d| _        | j                  j	                  d       | j
                  j                  d| d       yy)z!Handle pong response from server.r   N  zpingstop.oggzPing: ms)r&  ra   r$   rE   rG   rD   r  )ro   packetr&  
elapsed_mss       r   on_server_pongzMainWindow.on_server_pong  sm      ,diikD,A,AATIJJ$(D!##N3LL
|267	 -r   c                     | j                   r| j                  sy| j                  j                  di       j                  dd      }| }|rdnd}| j                  j                  d|        | j                  d|       y)	z&Handle F6 to toggle muting table chat.Nsocialmute_table_chatFmutedunmutedzTable chat zsocial/mute_table_chatr.   r-   rS   r>   rD   r  r  ro   r   current_statestatuss       r   r   zMainWindow.on_toggle_table_chat  sv    ""$..++//"=AABSUZ[)))y[12  !9=Ir   c                     | j                   r| j                  sy| j                  j                  di       j                  dd      }| }|rdnd}| j                  j                  d|        | j                  d|       y)	z-Handle Shift+F6 to toggle muting global chat.Nr4  mute_global_chatFr6  r7  zGlobal chat zsocial/mute_global_chatr8  r9  s       r   r   z MainWindow.on_toggle_global_chat  sv    ""$..++//"=AABTV[\)))y\&23  !:MJr   c                 X    | j                   j                          | j                          y)z*Handle [ key to switch to previous buffer.N)rb   previous_buffer_announce_buffer_infor  s     r   r   zMainWindow.on_prev_buffer  s     **,""$r   c                 X    | j                   j                          | j                          y)z&Handle ] key to switch to next buffer.N)rb   next_bufferr@  r  s     r   r   zMainWindow.on_next_buffer       &&(""$r   c                 X    | j                   j                          | j                          y)z'Handle Shift+[ to jump to first buffer.N)rb   first_bufferr@  r  s     r   r   zMainWindow.on_first_buffer  s     '')""$r   c                 X    | j                   j                          | j                          y)z&Handle Shift+] to jump to last buffer.N)rb   last_bufferr@  r  s     r   r   zMainWindow.on_last_buffer  rC  r   c                 Z    | j                   j                  d       | j                          y)z8Handle , key to move to older message in current buffer.olderNrb   move_in_buffer_announce_current_messager  s     r   r   zMainWindow.on_older_message  "    ))'2&&(r   c                 Z    | j                   j                  d       | j                          y)z8Handle . key to move to newer message in current buffer.newerNrJ  r  s     r   r   zMainWindow.on_newer_message   rM  r   c                 Z    | j                   j                  d       | j                          y)z3Handle Shift+, to jump to oldest message in buffer.oldestNrJ  r  s     r   r   zMainWindow.on_oldest_message  "    ))(3&&(r   c                 Z    | j                   j                  d       | j                          y)z3Handle Shift+. to jump to newest message in buffer.newestNrJ  r  s     r   r   zMainWindow.on_newest_message
  rR  r   c                    | j                   j                         }| j                   j                  |       | j                   j                  |      }| j	                          |rdnd}| j
                  j                  d| d| dd       y)	z,Handle F4 to toggle mute for current buffer.r6  r7  zBuffer  r   T	interruptN)rb   get_current_buffer_namerf   re   _save_muted_buffersrD   r  )ro   r   rq   re   r;  s        r   r   z MainWindow.on_buffer_mute_toggle  s    ((@@B&&{3%%..{; 	  " %)W[M6(!<Mr   c                     | j                   j                         \  }}}| j                   j                  |      }|rdnd}| j                  j	                  | | d| dd       y)z=Announce current buffer information (matches Legends format).z, muted z. z itemsTrW  N)rb   get_buffer_infore   rD   r  )ro   namecountpositionre   mute_statuss         r   r@  z MainWindow._announce_buffer_info  sd     $ 2 2 B B DeX%%..t4#+idVK=5'@DQr   c                 ~    | j                   j                         }|r!| j                  j                  |d   d       yy)zDAnnounce the current message in the buffer (matches Legends format).textTrW  N)rb   get_current_itemrD   r  )ro   items     r   rL  z$MainWindow._announce_current_message$  s9    !!224LLtF|t< r   c                    | j                   j                         }|t        j                  k7  r| j                   j	                  |      }t        j
                  j                         | j                   k7  r| j                   j                          | j                   j                  |       	 | j                  j                  |d       yy# t        t        f$ r }t        j                  d|       Y d}~yd}~ww xY w)z;Announce the currently selected menu item to screen reader.TrW  z%Failed to announce menu selection: %sN)r?   GetSelectionrk   	NOT_FOUND	GetStringWindow	FindFocusr  SetSelectionrD   r  AttributeErrorr  LOGdebug)ro   	selectionrc  excs       r   _announce_menu_selectionz#MainWindow._announce_menu_selection,  s    NN//1	$>>++I6D yy""$6'') NN''	2H""44"8 % #L1 H		A3GGHs   *C	 	C8C33C8c                 $   |j                         }| j                  ||      ry| j                  |      sy| j                  ||      ry| j	                  ||      }|s|j                          y| j                  ||      ry|j                          y)z+Handle character input for game keypresses.N)
GetKeyCode_handle_edit_mode_char_should_handle_menu_key_handle_escape_behavior_map_keybind_namer   _send_keybind_if_allowed)ro   r   key_codekey_names       r   r   zMainWindow.on_char_hook>  s    ##%&&uh7++E2''x8))%:JJL((9

r   rz  c                     | j                   dk7  ry|t        j                  k(  r.| j                  r| j                  d       | j	                          y|j                          y)z&Handle key presses while in edit mode.editFr\  T)rX   rk   
WXK_ESCAPErY   switch_to_list_moder   ro   r   rz  s      r   ru  z!MainWindow._handle_edit_mode_charR  sQ    &r}}$&&''+$$&

r   c                     t         j                  j                         }|| j                  k7  r|j	                          yy)zEReturn True if menu list has focus; otherwise allow default handling.FT)rk   rj  rk  r?   r   )ro   r   focuseds      r   rv  z"MainWindow._should_handle_menu_key^  s/    ))%%'dnn$JJLr   c                    |t         j                  t         j                  fvry|t         j                  k(  r | j                  dk(  r|j	                          y| j
                  dk(  r| j                  dk(  r| j                  r| j                  j                         }|dkD  r| j                  r| j                  j                          d| j                  |d}|d	z
  }d|cxk  rt        | j                        k  rn n| j                  |   }|||d
<   | j                  j                  |       y| j
                  dk(  r5| j                  r(| j                  j                  d| j                  d       yy)zBHandle escape/backspace behaviors that bypass normal keybind flow.F	main_menuTselect_last_optionr3   r   menu)r$  menu_idrp  r   selection_idescape_eventescape)r$  r  )rk   r~  WXK_BACKrZ   r   r   rX   rI   r?   GetCountrE   play_menuenterlenr\   rH   r'  )ro   r   rz  
item_countr0  
last_indexitem_ids          r   rw  z"MainWindow._handle_escape_behaviorf  s<   BMM2;;77r{{"t';';{'JJJL#77  F*t~~!^^446
>))**99; &#'#7#7%/F
 ",aJJHT-G-G)HH"&"<"<Z"H".5<F>2LL,,V4>1~~(((tG[G[)\]r   c                    | j                   j                         dk(  }| j                  |||      }||S | j                  ||      }||S |t        j
                  t        j                  fv ry|t        j                  k(  ry| j                  ||      }||S | j                  ||      }||S | j                  |      }||S y)z)Map wx key codes to server keybind names.r   Nr  space)r?   r  _map_direction_key_map_function_keyrk   r~  r  	WXK_SPACE_map_enter_key_map_letter_key_map_number_key)	ro   r   rz  menu_is_emptydirection_keyfunction_key	enter_key
letter_key
number_keys	            r   rx  zMainWindow._map_keybind_name  s    //1Q6//xO$  --eX>#r{{33r||#''x8	 ))%:
!))(3
!r   r  c                     t         j                  dt         j                  dt         j                  dt         j                  di}||vry |r||   S |j                         r||   S |j                          y )Nupdownleftright)rk   WXK_UPWXK_DOWNWXK_LEFT	WXK_RIGHTControlDownr   )ro   r   rz  r  key_maps        r   r  zMainWindow._map_direction_key  sk    IItKKKKLL'	
 7"8$$8$$

r   c                     t         j                  dt         j                  dt         j                  di}|t         j                  t         j
                  fv r|j                          y |j                  |      S )Nf1f3f5)rk   WXK_F1WXK_F3WXK_F5r   r   r   r>   )ro   r   rz  r  s       r   r  zMainWindow._map_function_key  sV    IItIItIIt

 		299--JJL{{8$$r   c                     |t         j                  t         j                  fvry |j                         s |j	                         s|j                         ryy )Nenter)rk   
WXK_RETURNWXK_NUMPAD_ENTERr  	ShiftDownAltDownr  s      r   r  zMainWindow._map_enter_key  s?    BMM2+>+>??%//"3u}}r   c                     |dk  s|dkD  ry |t        d      k(  r!|j                         r|j                          y t        |      j	                         S )NA   Z   r   )r   r  r   chrlowerr  s      r   r  zMainWindow._map_letter_key  sE    b=HrMs3xEMMOJJL8}""$$r   c                 4    d|cxk  rdk  rt        |      S  y y )N0   9   )r  ro   rz  s     r   r  zMainWindow._map_number_key  s!    Rx=   r   r{  c                 D   |j                         }|t        j                  z  dk7  }|t        j                  z  dk7  }|t        j                  z  dk7  }|dv }|xr+ | j
                  xr |xs | j                   xs
 |xs |xs |}|sy| j                  j                         }	|	t        j                  k(  rd}
d}n8|	dz   }
d|	cxk  rt        | j                        k  rn n| j                  |	   }nd}| j                  j                  d||||| j                  |
|d       y)	z,Send a keybind packet when policy allows it.r   )r  f2r  r  r  r  	backspacer  r  r  r  r  FNr   r   )r$  keycontrolaltshiftr  
menu_indexmenu_item_idT)GetModifiersrk   MOD_CONTROLMOD_ALT	MOD_SHIFTrI   r   r?   rg  rh  r  r\   rH   r'  rZ   )ro   r   r{  	modifiershas_controlhas_alt	has_shiftis_function_keyshould_sendmenu_selectionr  r  s               r   ry  z#MainWindow._send_keybind_if_allowed  sF   &&(	 2>>1a7rzz)a/-!3	" '
 
      ///   	 446R\\)JL'!+JNDS)C)C%DD#99.I#  !&"//( ,		
 r   c                    | j                   j                         }|t        j                  k(  ry| j                  rud|dz   d}| j
                  r| j
                  |d<   d|cxk  rt        | j                        k  rn n| j                  |   }|||d<   | j                  j                  |       |j                          y)z7Handle menu item activation (Enter/Space/Double-click).Nr  r   )r$  rp  r  r   r  )r?   rg  rk   rh  rI   rZ   r  r\   rH   r'  r   )ro   r   rp  r0  r  s        r   r   zMainWindow.on_menu_activate  s    NN//1	$ >>&]F
 ##$($8$8y!I?D$>$> ??44Y?&-4F>*LL$$V,

r   c                 H    || _         | j                  j                  |       y)z4Set multiletter navigation state (called by server).N)r   r?   enable_multiletter_navigation)ro   enableds     r   set_multiletter_navigationz%MainWindow.set_multiletter_navigation(  s    #* 44W=r   c                 X    || _         || _        | j                  j                  ||       y)z2Set grid mode navigation state (called by server).N)grid_enabled
grid_widthr?   enable_grid_mode)ro   r  r  s      r   set_grid_modezMainWindow.set_grid_mode-  s%    #$''<r   c                 t   | j                   j                         j                         }|sy|d   dv r[|j                  d      }|dk\  r|d| }||dz   d }n|}d}|d   dk(  r| j                  nt
        j                  }|dd } |||       n| j                  |       | j                   j                          y)zHandle chat message send.Nr   z/.rV  r   r\  r   )	r@   GetValuestripfindsend_global_chatr   process_commandsend_table_chatClear)ro   r   messageindexprefixfuncs         r   r   zMainWindow.on_chat_enter3  s    //**,2241:LL%Ez %!%!)+. ,21I,<4((.B`B`DABZF!  )r   rc  c                 R   |s| j                   d   d   S |j                         }|| j                  j                         v r| j                  |   S |j	                         | j                  j                         v r|j	                         S | j                  j                  | d       y)z*Get the name of a language based on input.r4  chat_input_languagez* is not a valid language name or ISO code.r\  )rS   r  
lang_codeskeys
capitalizevaluesrD   r  )ro   rc  s     r   get_language_namezMainWindow.get_language_nameH  s    &&x01FGGzz|4??''))??4((?? 6 6 88??$$dV#MNOr   r^  c                     |s| j                   d   d   }	 t        | j                  j                               t        | j                  j	                               j                  |         S # t        $ r Y yw xY w)z"Get a language code from its name.r4  r  r\  )rS   r#   r  r  r  r  
ValueError)ro   r^  s     r   get_language_codezMainWindow.get_language_codeT  sm    &&x01FGD	--/0t7M7M7O1P1V1VW[1\]] 		s   AA, ,	A87A8r  c                 T    |syd}|sy| j                   j                  dd||d       y)z"Send table chat message to server.NEnglishchatlocalr$  convor  languagerH   r'  )ro   r  langs      r   r  zMainWindow.send_table_chat]  s1      g'tT	
r   r  c                 T    |syd}|sy| j                   j                  dd||d       y)z#Send global chat message to server.Nr  r  globalr  r  )ro   r  r  r  s       r   r  zMainWindow.send_global_chati  s2      h7PTU	
r   c                 T   | j                   j                  ||       | j                   j                  | j                   j                               s| j                  j                         }|r|j                  d      sd|z   }| j                  j                         }| j                  j                  |dz          | j                  j                  |       |r	 | j                  j                  |d       yyy# t        t        f$ r }t        j                  d|       Y d}~yd}~ww xY w)a  
        Add text to the history window and optionally speak it.

        Args:
            text: The message to add
            buffer_name: Which buffer to add to (default: "misc")
            speak_aloud: Whether to speak the text aloud (default: True)
        
FrW  z Failed to speak history text: %sN)rb   add_itemre   rY  rA   r  endswithGetInsertionPoint
AppendTextSetInsertionPointrD   r  rm  r  rn  ro  )ro   rc  rq   speak_aloudcurrentold_insertion_pointrq  s          r   add_historyzMainWindow.add_historyu  s    	##K6 !!**4+=+=+U+U+WX''002Gw//5d{ #'"3"3"E"E"G ((5 //0CD GLL&&tu&=	  Y( '5 GII@#FFGs   C8 8D'D""D'c                    | j                   dk(  }|s4| j                  j                          | j                  j                          |xs d}| j                  j                  |       |r| j                  j                          | j                  j                          | j                  j                          | j                  j                  |       | j                  j                  |        | j                  j                  |       | j                  j                          d| _        | j                  | j                  d||       n| j                  j                          | j                  j                          | j                  j                          | j                  j                  |       | j                  j                  |        | j                  j                  |       | j                  j                          d| _        | j                  | j                  d||       | j                  j                          d| _         || _        || _        y)a  
        Switch from list mode to edit mode.

        Args:
            prompt: Optional prompt text to speak/display
            callback: Optional callback function to call with the entered text
            default_value: Default text to populate the editbox with
            multiline: Whether to use a multiline editbox
            read_only: Whether the editbox is read-only
        r}  r~   TFN)rX   r?   r   r   r   SetLabelr   r   Showr  SetValueSetEditabler   r  r]   _schedule_pending_clearrY   r^   )ro   promptcallbackdefault_value	multiline	read_onlyalready_in_editr|   s           r   switch_to_edit_modezMainWindow.switch_to_edit_mode  s   $ ++v5NN!OO  " !'  ' OO  "%%**,%%++-%%..}=%%11i-@%%--e4%%..0*.D'(()B)BD-Ybc%%**,OO  "OO!!#OO$$]3OO''I6OO##E*OO$$&*/D'((%PYZ""*&/#r   c                    | j                   dk(  ry| j                  j                          | j                  j                          | j                  j                          | j
                  j                          | j                  j                          | j
                  j                          d| _         d| _	        d| _
        d| _        y)z(Switch from edit mode back to list mode.r3   NF)rX   r   r   r   r   r?   r  r   r  rY   r_   r`   r   s    r   r  zMainWindow.switch_to_list_mode  s    & 	!!&&( 	!""&#( (-%r   c                     | j                   j                         j                         }| j                  r| j                  |       n| j	                  d|        | j                          y)z$Handle Enter key in edit mode input.z	Entered: N)r   r  r  rY   r
  r  )ro   r   rc  s      r   r   zMainWindow.on_edit_enter  s[    '')//1 ""##D) y/0 	  "r   c                    ddl }|j                         }|t        j                  k(  r.| j                  r| j	                  d       | j                          y|| j                  v s0|j                         s |j                         s|j                         rd| _
        |j                          y| j                  r?| j                  ||      r-| j                  s!| j                  j                          d| _
        d|cxk  rdk  run nr| j                   xr, | j                   j#                  di       j#                  dd	      }|r5|j%                  d
d      }d| d}| j&                  j)                  |d       |j                          y)z:Handle character input in edit mode to play typing sounds.r   Nr\  F    ~   	interfaceplay_typing_soundsTr   r   typing.ogg      ?r0   )randomrt  rk   r~  rY   r  _NAVIGATION_KEYSr  r  MetaDownr_   r   _should_clear_on_char_eventr^   r   r  rS   r>   randintrE   rG   ro   r   r"  rz  should_play	sound_num
sound_names          r   r   zMainWindow.on_edit_char  sW   ##% r}}$&&''+$$& ---  "}}~~',D$JJL $$00A//OO!!#',D$  S "999 .d>Q>Q>U>UR?c&-  "NN1a0	%i[5
""''
3'? 	

r   c                    ddl }|j                         }| j                  |      ry| j                  ||      ry| j	                  ||       | j                  ||      ryd|cxk  rdk  run nr| j                   xr, | j                  j                  di       j                  dd      }|r5|j                  dd	      }d
| d}| j                  j                  |d       |j                          y)z.Handle character input in multiline edit mode.r   Nr  r  r  r  Tr   r   r  r   r!  r0   )r"  rt  _handle_multiline_escape"_should_defer_multiline_to_default"_clear_multiline_pending_if_needed_handle_multiline_enterr^   rS   r>   r&  rE   rG   r   r'  s          r   r   z!MainWindow.on_edit_multiline_char%  s    ##%((2225(C//x@''x8  S "999 .d>Q>Q>U>UR?c&-  "NN1a0	%i[5
""''
3'? 	

r   c                     |t         j                  k7  ry| j                  r| j                  d       | j                          y)NFr\  T)rk   r~  rY   r  r  s     r   r,  z#MainWindow._handle_multiline_escapeB  s7    r}}$""##B'  "r   c                     || j                   v s0|j                         s |j                         s|j                         rd| _        |j                          yy)NFT)r#  r  r  r$  r`   r   r  s      r   r-  z-MainWindow._should_defer_multiline_to_defaultJ  sF    ---  "}}~~,1D)JJLr   c                     | j                   rB| j                  ||      r/| j                  s"| j                  j	                          d| _         y y y y NF)r`   r%  r^   r   r  r  s      r   r.  z-MainWindow._clear_multiline_pending_if_neededV  sN    ))00A//%%++-,1D) 0 B *r   c                    |t         j                  k7  ry| j                  rH| j                  j	                         }| j
                  r| j                  |       | j                          y| j                  j                  di       j                  dd      }|si|j                         sX|j                         sH| j                  j	                         }| j
                  r| j                  |       | j                          yy|j                         s|j                         rH| j                  j	                         }| j
                  r| j                  |       | j                          yy)NFTr  invert_multiline_enter_behavior)rk   r  r^   r   r  rY   r  rS   r>   r  r  )ro   r   rz  rc  inverts        r   r/  z"MainWindow._handle_multiline_enter_  s)   r}}$&&,,557D&&''-$$&$$((b9==-u
 ??$U->->-@0099;**++D1((*   E$5$5$70099;**++D1((*r   r  r  r  c                     t        |      xr | xr |j                         }|rd| _        || _        nd| _        || _        |r!t	        j
                  | j                  |       y y r3  )bool	IsEnabledr_   r`   rk   	CallAfter_select_all_text)ro   ctrlr  r  r  should_selects         r   r  z"MainWindow._schedule_pending_clear{  s`     ]+RIR$..BR',D$,9D),1D)'4D$LL..5 r   c                 N    | sy | j                         }| j                  d|       y Nr   )GetLastPositionrl  )r<  lengths     r   r;  zMainWindow._select_all_text  s&    %%'!V$r   c                     d|cxk  rdk  sy y| j                         s | j                         s| j                         ryy)Nr  r  FT)r  r  r$  )r   rz  s     r   r%  z&MainWindow._should_clear_on_char_event  s=    h%#% &%--/U^^5Er   c                 ^    t        j                  | j                  j                  ||||       y)a  
        Play a sound effect (called via CallAfter for non-blocking).

        Args:
            sound_name: Name of sound file (in sounds/ folder)
            volume: Volume 0.0-1.0
            pan: Pan -1.0 to 1.0
            pitch: Pitch multiplier
        N)rk   r:  rE   rG   )ro   r*  r1   panpitchs        r   
play_soundzMainWindow.play_sound  s$     	T'',,j&#uMr   
music_nameloopingfade_out_oldc                 \    t        j                  | j                  j                  |||       y)a	  
        Play background music (called via CallAfter for non-blocking).

        Args:
            music_name: Name of music file (in sounds/ folder)
            looping: whether to loop the music
            fade_out_old: Whether to fade out current music
        N)rk   r:  rE   music)ro   rG  rH  rI  s       r   
play_musiczMainWindow.play_music  s"     	T''--z7LQr   c                 X    t        j                  | j                  j                  |       y)zStop background music.N)rk   r:  rE   
stop_music)ro   fades     r   rN  zMainWindow.stop_music  s    
T''22D9r   c                 X    t        j                  | j                  j                  |       y)zSet music volume 0.0-1.0.N)rk   r:  rE   ry   )ro   r1   s     r   ry   zMainWindow.set_music_volume  s    
T''88&Ar   c                 :    | j                   j                  |       y)z*Set the menu click sound (server command).N)rE   set_menuclick_soundro   r*  s     r   rR  zMainWindow.set_menuclick_sound      ..z:r   c                 :    | j                   j                  |       y)z3Set the menu enter/activate sound (server command).N)rE   set_menuenter_soundrS  s     r   rV  zMainWindow.set_menuenter_sound  rT  r   c                 T   | j                   j                  dd      }| j                   j                  dd      }| j                   j                  dd      }| j                   j                  d      }| j                   j                  dd      }| j                  j                  d	       | j	                  d
| dd       | j
                  j                  |||||      r<| j	                  d| dd       t        j                  d| j                        | _
        y| j                  d       y)z/Auto-connect to server using login credentials.usernameGuestpasswordr\  refresh_tokenrefresh_expires_at
server_urlzws://localhost:8000connectloop.oggConnecting to ...r7   zConnecting as i'  %Failed to start connection to server.N)r=   r>   rE   rK  r
  rH   connectrk   	CallLater_check_connection_timeoutrR   _show_connection_error)ro   rX  rZ  r[  r\  r]  s         r   rn   zMainWindow._auto_connect  s	   ##''
G<##''
B7((,,_bA!--112FG%%)),8MN
 	  !23>*S9:F<<
HhOab~hZs;ZH -/LL@^@^,_D)''(OPr   c                 t    | j                   s,| j                  s| j                  s| j                  d       yyyy)z4Check if connection succeeded within timeout period.z0Connection timeout: Could not connect to server.NrI   rK   rL   re  r   s    r   rd  z$MainWindow._check_connection_timeout  s6     ~~d&>&>tG^G^''(Z[ H_&>~r   c                 h    d| _         | j                  s| j                  s| j                  d       yyy)zHandle connection loss.FzConnection lost!Nrg  r   s    r   on_connection_lostzMainWindow.on_connection_lost  s2    ''0G0G''(:; 1H'r   c                 d    || _         | j                  |      }|| _        | j                  |       y)z;Handle lifecycle status updates (initializing/maintenance).N)rP   _format_status_textrQ   _announce_status_message)ro   r0  r  s      r   on_server_statuszMainWindow.on_server_status  s0    )/&**62(/%%%g.r   c           	         |j                  dd      }|j                  dd      }|j                  dd      }|j                  d      }|j                  d      }|j                  d      }|rf|xs | j                  | j                  xs i       }| j                  |d	       |r-t	        d
t        |            }	| j                  |	| d|	 d       y|r<t	        d
t        |j                  dd                  }	| j                  |	d|	 d       y|r(|xs | j                  xs d}| j                  ||	       yd| _        | j                  j                  dd       t        j                  d| j                         y)z Handle server disconnect packet.	reconnectFshow_messagereturn_to_loginstatus_moderetry_afterr  T)rq  r   z Reconnecting in z seconds...N   z&Server is restarting. Reconnecting in zDisconnected by server.zDisconnected.rW  i  )r>   rk  rP   re  r  r$   _schedule_reconnect_afterrO   rJ   rD   r  rk   rc  Close)
ro   r0  should_reconnectrp  rq  rr  rs  disconnect_messager  delays
             r   on_server_disconnectzMainWindow.on_server_disconnect  st   !::k59zz.%8 **%6>jj/jj/#ZZ	2( D,D,D..4"-G '''FAs;/0..i0{C 3vzz-;<=E**8{K (aD,D,DaHaG'''Q !%DLL%@LLdjj)r   c                 l    |sy|j                  d      xs d}|j                  d      }|r| d| d}|S )z4Format a lifecycle status packet into readable text.z"Server is temporarily unavailable.r  	resume_atz Expected availability: r   )r>   )ro   r0  r  r|  s       r   rk  zMainWindow._format_status_text  sE    7**Y'O+OJJ{+	 	!9)AFGr   c                 ~   t        | dd      }t        | dd      }|xr: t        |d      xr, t        |d      xr t        |d      xr |xr t        |d      }|r| j                  |d	       	 | j                  j	                  |d
       y# t
        t        f$ r }t        j                  d|       Y d}~yd}~ww xY w)z3Speak and optionally log lifecycle status messages.rb   NrA   r  re   rY  r  r7   )rq   FrW  z"Failed to speak status message: %s)	getattrhasattrr
  rD   r  rm  r  rn  ro  )ro   r  rb   rA   can_logrq  s         r   rl  z#MainWindow._announce_status_message  s    ot<t^T: 2z22z22 '@A2 	2
 j1 	 W*=	ALLw%8- 	AII:C@@	As   /B B<B77B<delay_secondsannounce_textc                     t        dt        |dz              }d _         j                  r! j                  j	                          d _         j
                  j                  |d        fd}t        j                  ||       y)z+Schedule a reconnect attempt after a delay.r.  TNFrW  c                  b    j                   j                  d      j                   j                  d      j                   j                  dd       rWrTj                  j                  dd       j                  j                          t        j                  d fd	       y y y )
Nr]  rX  rZ  r\  zReconnecting...FrW  r.  c                  *    j                         S N_do_reconnectrZ  ro   r]  rX  s   r   <lambda>zIMainWindow._schedule_reconnect_after.<locals>.reconnect.<locals>.<lambda>>  s    4+=+=j(T\+]r   )r=   r>   rD   r  rH   
disconnectrk   rc  )rZ  r]  rX  ro   s   @@@r   ro  z7MainWindow._schedule_reconnect_after.<locals>.reconnect7  s    ))--l;J''++J7H''++J;Hh""#4"F'')T#]^ 'zr   )	r  r$   rK   rR   StoprD   r  rk   rc  )ro   r  r  delay_msro  s   `    r   ru  z$MainWindow._schedule_reconnect_after.  sq    tS!567#' (())..0,0D)=E:	_ 	Xy)r   c                      xj                   dz  c_          j                  rd _        d _         y j                    j                  kD  r<d _        d _          j                  j                  dd        j                          y j                  d d j                    d	        j                  j                           j                  j                  d
d      } j                  j                  d      } j                  j                  ||      rt        j                  d fd       yd _        d _          j                  j                  dd        j                          y)z*Actually perform the reconnection attempt.r   Fr   Nz,Failed to reconnect after multiple attempts.rW  zReconnecting as z... (attempt )r[  r\  r\  i  c                  *    j                         S r  r  r  s   r   r  z*MainWindow._do_reconnect.<locals>.<lambda>\  s    t'9'9*hPX'Yr   zFailed to reconnect.)rM   rI   rK   rN   rD   r  rv  r
  rH   r  r=   r>   rb  rk   rc  )ro   r]  rX  rZ  r[  r\  s   ````  r   r  zMainWindow._do_reconnectB  s>   1$ >>',D$&'D# ""T%@%@@',D$&'D#LLMY^_JJL 	+H:]4CZCZB[[\]^!((,,_bA!--112FG<<
HhOabLLYZ',D$&'D#LL5GJJLr   c                 L   |rd| _         | j                  r!| j                  j                          d| _        | j                  j	                  d       | j
                  j                  d       |}| j                  r | j                  |vr|d| j                   z  }|r|dz  }n|dz  }t        j                  |d	t        j                  t        j                  z         |r| j                          y| j                          t        j                         j                          y)
z@Show error modal and either quit application or return to login.TNFrO  )waitz

Server message: z 

Returning to the login dialog.z!

The application will now close.zConnection Error)rL   rR   r  rE   rN  rH   r  rO   rk   
MessageBoxOK
ICON_ERROR_return_to_loginrv  GetAppExitMainLoop)ro   r  rq  
error_bodys       r   re  z!MainWindow._show_connection_errorc  s     &*D#(())..0,0D) 	%%5%1 	T* 
##(@(@
(R01I1I0JKKJ>>J??J 	j"4beebmm6KL!!# JJLIIK$$&r   c                 4   | j                          t        |       }|j                         t        j                  k(  r|j                         }|j                          || _        |j                  d      | _	        |j                  d      | _
        d| _        d| _        d| _        d| _        d| _        d| _        t#        |       | _        | j&                  j)                          | j+                          |j                  d      }|j                  d      }|j                  dd	      }|j                  d
d	      }|j                  d      }| j-                  d| d| dd       | j.                  j1                  d       | j$                  j3                  |||||      r&t        j4                  d| j6                        | _        y| j9                  d       y|j                          | j;                          t        j<                         j?                          y)z.Close main window and show login dialog again.r-   r.   Fr   Nr]  rX  rZ  r\  r[  r\  r_   as r`  r7   r^  i:  ra  ) r   r   r   rk   ID_OKget_credentialsr   r=   r>   r-   r.   rI   rK   rL   rM   rO   rR   r
   rH   rA   r  r  r
  rE   rK  rb  rc  rd  re  rv  r  r  )ro   login_dialognew_credentialsr]  rX  rZ  r[  r\  s           r   r  zMainWindow._return_to_login  s    			 #4(!!#rxx/*::<O  "  /D,00=DN"1"5"56F"GD #DN',D$&+D#&'D#'+D$,0D) *$/DL ##%IIK ),,\:J&**:6H&**:r:H+//DM!0!4!45I!J~j\hZsKZX$$%67||##Hh?Q 13UDDbDb0c-++,ST   "JJLIIK$$&r   c           	      P   d| _         |j                  dd      }|j                  d      xs | j                  j                  dd      }| j                  j                  dd      }|j                  d      }|j                  d	      }| j                  r!| j                  j	                          d
| _        | j
                  j                  d       | j
                  j                  dd       |r| j                  d| d| d| dd       n| j                  d| d| dd       |r| j                  rs| j                  rf| j                  j                  d      }|rH| j                  j                  | j                  |||       || j                  d<   || j                  d	<   y
y
y
y
y
)z)Handle authorization success from server.TversionunknownrX  rY  r]  r\  r[  r\  NFr  zwelcome.oggr/   r0   zConnected to r  z	 (server r  r7   zConnected as 
account_id)r[  r\  )rI   r>   r=   rR   r  rE   rN  rG   r
  r.   r-   update_account)ro   r0  r  rX  r]  r[  r\  r  s           r   on_authorize_successzMainWindow.on_authorize_success  s   **Y	2::j)VT-=-=-A-A*g-V%%)),;


?3#ZZ(<= (())..0,0D) 	%%5%1c:
|4z7)1M
 z7)1=
 T00T^^))--l;J##22NN"/'9	 3  5B  19K  !56  6D0=r   c                 2    |j                  di       | _        y)zHandle open server options packet from server.

        #This handler is for
        server-side options like battle reserves and account settings.
        optionsN)r>   rT   ro   r0  s     r   on_open_server_optionsz!MainWindow.on_open_server_options  s     %jjB7r   c                    |j                  dg       | _        |j                  di       }t        |t              r|D ci c]  }|| }}|| _        | j
                  r| j                  sy| j
                  j                  }|j                  di        |j                  di       j                  di       j                  di        |j                  di       j                  di       j                  d	i        d
}t        | j                  j                               }| j                  r|d   j                  di       }|j                  di       }| j                  D ]  }|d   }	|	|vsd||	<   d} |j                  di       }
| j                  |
v re|
| j                     j                  di       }|j                  di       }|j                  di       }| j                  D ]  }|d   }	|	|vsd||	<   d} |r:|d   j                  di       }|j                  d	i       }i }|D ]  }|j                  |d
      ||<    t        |j                               t        |j                               k7  r||d	<   d}|j                  di       }
| j                  |
v r|
| j                     j                  di       }|j                  di       }|j                  d	i       }i }|D ]  }|j                  |d
      ||<    t        |j                               t        |j                               k7  r||d	<   d}|rD| j
                  j                          | j
                  j                  | j                        | _        | j                          yc c}w )zHandle update_options_lists packet from server.

        Automatically updates client options to include new games and languages
        without requiring the user to open the options dialog.
        games	languagesNrT   client_options_defaultslocal_tablecreation_notificationsr4  language_subscriptionsFr^  Toptions_overrides)r>   
games_list
isinstancer3   r  r.   r-   profiles
setdefaultr#   r  r  save_profilesrU   rS   send_client_options_to_server)ro   r0  r  coder  updateddefault_local_tabledefault_creation_notifications	game_info	game_nameserver_profilesserver_overridesserver_local_tableserver_creation_notificationsdefault_socialdefault_lang_subscriptionsnew_default_subscriptionsr  social_overrideslang_subscriptionsnew_subscriptionss                        r   on_update_options_listsz"MainWindow.on_update_options_lists  s    !**Wb1JJ{B/	i&09:	t	I:#""$.. &&//,b15r:EEmUWXcc$b	
 	5r:EEhPRS^^$b	
 $//0023	??"*+D"E"P"PQ^`b"c-@-K-K(".* "__	%f-	$BB@D29="G	 - 'll+;R@O~~0#24>>#B#M#M'$  &6%@%@PR%S"0B0M0M,b1- "&I )& 1I (EECG5i@"&	 "1 %&?@KKHVXYN)7););<TVX)Y&(*%%6P6T6Te7)(3 & -2245>X>]>]>_9``;T78 'll+;R@O~~0#24>>#B#M#M'$  $4#>#>x#L %5%9%9:RTV%W"$&! )H2D2H2HSX2Y%h/ !* )..01T:L:Q:Q:S5TTAR$%=>"G --/"&"5"5"H"H"XD 	**,s ;s   
N	c                     | j                   r| j                  r| j                  sy| j                  j                  | j                        }| j                  j                  d|d       y)zSend server profile client options to the server.

        Sends only the server-specific options (not defaults) to inform
        the server of the client's preferences.
        NrS   )r$  r  )rI   r.   r-   rU   rH   r'  )ro   r  s     r   r  z(MainWindow.send_client_options_to_serverT  sU     ~~T%8%8 %%88H  ("	
r   c                 l   | j                   r| j                  s7t        j                  ddt        j                  t        j
                  z         yddlm}  || | j                   | j                  | j                  | j                  | j                        }|j                          | j                          y)zOHandle server request to open client options dialog (includes server nickname).zClient options not availableErrorNr   )ClientOptionsDialog)r.   r-   rk   r  r  r  options_dialogr  r  rE   rS   r   r  )ro   r0  r  r   s       r   on_open_client_optionsz!MainWindow.on_open_client_optionsg  s    ""$..MM8'2552==CXY 	8 "NNOO
 	**,r   c                     |j                  dd      }|j                  dd      }|j                  dd      }|r|| _        | j                  |||        yy)	z Handle speak packet from server.rc  r\  bufferr8   r6  F)r  N)r>   rO   r
  )ro   r0  rc  rq   re   s        r   on_server_speakzMainWindow.on_server_speak  sY    zz&"%jj62::gu-'+D$T;\K	 r   c                    |j                  d      }|j                  d      }|j                  d      | j                  d   k(  }	 |dk(  r&|j                  d       d|j                  d       }n%|j                  d       d|j                  d       }	 	 d	}|d
k(  r|d
z  }| j                  j                  |dz          | j                  j                  |       | j                  |dd       y)zHandle chat packet from server.r  r  senderrX  r  z globally: r  : r  r  r   r6   FN)r>   r=   rE   rG   rD   r  r
  )ro   r0  r  r  	same_userr  sounds          r   on_receive_chatzMainWindow.on_receive_chat  s    

7#zz*%JJx(D,<,<Z,HH		$ HH-.k&**Y:O9PQGH-.bI1F0GHG
 E ##EFN3LLw''51r   c                    |j                  d|j                  dd            }|j                  dd      dz  }|j                  dd      dz  }|j                  d	d      dz  }|r| j                  j                  ||||       y
y
)z%Handle play_sound packet from server.r^  r  r\  r1   r  rw   rD  r   rE  N)r>   rE   rG   )ro   r0  r  r1   rD  rE  s         r   on_server_play_soundzMainWindow.on_server_play_sound  s~    

66::gr#:;Hc*U2jj"U*

7C(50##E63> r   c                     |j                  d|j                  dd            }|j                  dd      }|r| j                  j                  ||       yy)z%Handle play_music packet from server.r^  rK  r\  rH  T)rH  N)r>   rE   rK  )ro   r0  rK  rH  s       r   on_server_play_musiczMainWindow.on_server_play_music  sN    

66::gr#:;**Y-$$UG$< r   c                     |j                  d      }|j                  d      }|j                  d      }|r| j                  j                  |||       yy)z(Handle play_ambience packet from server.introloopoutroN)r>   rE   ambience)ro   r0  r  r  r  s        r   on_server_play_ambiencez"MainWindow.on_server_play_ambience  sL    

7#zz&!

7#''tU; r   c                 8    | j                   j                          y)z(Handle stop_ambience packet from server.N)rE   stop_ambiencer  s     r   on_server_stop_ambiencez"MainWindow.on_server_stop_ambience  s    ((*r   c           	      H   |j                  dd      }|j                  dg       }|j                  dd      }|j                  dd      }|j                  dd	      }|j                  d
d      }|j                  dd      }|r"| j                  j                  |||||||       yy)z'Handle add_playlist packet from server.playlist_idmusic_playlisttracks
audio_typerK  shuffle_tracksFrepeatsr   
auto_startTauto_removeN)r>   rE   add_playlist)	ro   r0  r  r  r  r  r  r  r  s	            r   on_server_add_playlistz!MainWindow.on_server_add_playlist  s    jj+
 Hb)ZZg6
$4e<**Y*ZZd3
jj5++ r   c                     |j                  dd      }| j                  j                  |      }|r%|j                  sd|_        |j	                          yyy)z)Handle start_playlist packet from server.r  r  TN)r>   rE   get_playlist	is_active_play_next_track)ro   r0  r  playlists       r   on_server_start_playlistz#MainWindow.on_server_start_playlist  sO    jj0@A%%22;?H..!%H%%' /8r   c                 ^    |j                  dd      }| j                  j                  |       y)z*Handle remove_playlist packet from server.r  r  N)r>   rE   remove_playlist)ro   r0  r  s      r   on_server_remove_playlistz$MainWindow.on_server_remove_playlist  s'    jj0@A**;7r   c                    |j                  dd      }|j                  dd      }|j                  d      }| j                  j                  |      }d}|rG|dk(  r|j                         }||nd}n+|dk(  r|j	                         }n|d	k(  r|j                         }|r$d
||||d}| j                  j                  |       yy)z0Handle get_playlist_duration packet from server.r  r  duration_typetotal
request_idr   Nelapsed	remainingplaylist_duration_response)r$  r  r  r  duration)r>   rE   r  get_total_durationget_elapsed_durationget_remaining_durationrH   r'  )	ro   r0  r  r  r  r  r  r   responses	            r   on_server_get_playlist_durationz*MainWindow.on_server_get_playlist_duration  s    jj0@A

?G<ZZ-
%%22;?'!446%+%76Q)+#88:+-#::< 4(*!.$H LL$$X. r   c                     |j                  d      }|j                  d      }| j                  d   d   |   sy | j                  j                  d       | j	                  | d| dd       y )	Nhostgamer  r  z
notify.oggz is hosting r   r7   )r>   rS   rE   rG   r
  )ro   r0  r  r	  s       r   on_table_createzMainWindow.on_table_create  sk    zz&!zz&!""=12JKDQ-D6dV15zBr   c                    g }i }t        t        ||            D ]  \  }\  }}	|||	f||<    i }
t        t        ||            D ]  \  }\  }}	|||	f|
|<    t        |j                               }t        |
j                               }||z
  }||z
  }||z  }|sE|sC||k7  r>g }t        t        ||            D ]"  \  }\  }}||k7  s|j	                  d||f       $ |S |D ]  }||   d   }|j	                  d|f        t        t        ||            D ]K  \  }\  }}|||v r|j	                  d||f       %||v s*||   d   }||k7  s8|j	                  d||f       M |S )a?  
        Compute minimal operations using item IDs to transform old_items into new_items.
        This is much simpler and more reliable than text-based LCS diffing.

        Returns list of operations: ('insert', index, text), ('delete', index), ('update', index, text)

        Algorithm:
        1. Build maps of IDs to (index, text) for old and new lists
        2. Identify deleted IDs (in old but not new)
        3. Identify inserted IDs (in new but not old)
        4. Identify common IDs that may need text updates
        5. Generate operations accordingly
        updater   deleteinsertr   )	enumeratezipsetr  append)ro   	old_items	new_itemsold_idsnew_ids
operationsold_mapir  rc  new_map
old_id_set
new_id_setdeleted_idsinserted_ids
common_idsold_textnew_text	old_indexnew_ids                       r   compute_menu_diff_by_idz"MainWindow.compute_menu_diff_by_id  s    
 "+C,C"DA"$%t9  #E "+C,C"DA"$%t9  #E
 (
(
 :-!J.*,

 <Gw4FJ+4SI5N+O''Hhx'%%xH&=> ,P  #G(+Ix34 #
 &/s7I/F%G!A!~%!!8Q"9::%"6?1-x'%%xH&=> &H r   c                     | j                  ||||      r| j                  ||||      S g }| j                  ||      }||S | j                  ||      }|S )a/  
        Compute minimal operations to transform old_items into new_items.
        Returns list of operations: ('insert', index, text), ('delete', index), ('update', index, text)

        If all items have IDs (old_ids and new_ids provided and no None values), use the simpler
        ID-based algorithm. Otherwise fall back to LCS-based text diffing.

        For simplicity and screen reader friendliness:
        - If lists are same length, generate update operations for changed items
        - Otherwise use LCS-based diff for structural changes
        )_can_use_id_diffr$  _diff_same_length_diff_with_lcs)ro   r  r  r  r  r  same_length_opss          r   compute_menu_diffzMainWindow.compute_menu_diff[  sl       IwH//	9gwWW 
00IF&""((I>
r   c                     |d uxr^ |d uxrX t        |      t        |       k(  xr? t        |      t        |      k(  xr& t        d |D              xr t        d |D              S )Nc              3   $   K   | ]  }|d u 
 y wr  r   .0r  s     r   	<genexpr>z.MainWindow._can_use_id_diff.<locals>.<genexpr>|       ?wGG4'w   c              3   $   K   | ]  }|d u 
 y wr  r   r-  s     r   r/  z.MainWindow._can_use_id_diff.<locals>.<genexpr>}  r0  r1  )r  r4   )r  r  r  r  s       r   r&  zMainWindow._can_use_id_diffu  sy     4 @t#@GI.@ GI.@ ?w??	@
 ?w??	
r   c                     t        |       t        |      k7  ry g }t        t        |             D ]%  }| |   ||   k7  s|j                  d|||   f       ' |S )Nr  )r  ranger  )r  r  r  r  s       r   r'  zMainWindow._diff_same_length  s^    y>S^+
s9~&A|y|+!!8Q	!"=> ' r   c                    t        |       t        |      }}t        |dz         D cg c]  }dg|dz   z   }}t        d|dz         D ]c  }t        d|dz         D ]O  }| |dz
     ||dz
     k(  r||dz
     |dz
     dz   ||   |<   ,t        ||dz
     |   ||   |dz
           ||   |<   Q e g }||}}|dkD  s|dkD  r|dkD  r!|dkD  r| |dz
     ||dz
     k(  r|dz  }|dz  }na|dkD  r@|dk(  s||   |dz
     ||dz
     |   k\  r$|j                  dd|dz
  ||dz
     f       |dz  }n|j                  dd|dz
  f       |dz  }|dkD  r|dkD  r|S c c}w )Nr   r   r  r  )r  r4  r  r  )	r  r  mn_lcsr  jr  s	            r   r(  zMainWindow._diff_with_lcs  s   9~s9~1&+AEl3lsa!e}l3q!a%A1a!e_QU#yQ'77 #AE
1q5 1A 5CF1I #CAJqM3q6!a%= ACF1I	 % ! 
!1!eq1u1uQ9QU#3yQ7G#GQQQAFc!fQUms1q5z!}&D!!!hAyQ7G%HIQ!!!hA%67Q !eq1u + 4s   Ec                    |}|D cg c]  }|d   dk(  s|d   f }}|D cg c]  }|d   dk(  s| }}|D cg c]  }|d   dk(  s| }}t        |d d      D ]k  \  }| j                  j                  |       |t        j                  k7  s4||k  r|dz  }?||k(  sEt        || j                  j                         dz
        }m |D ]D  ^}	}
|
\  }}| j                  j                  ||       |t        j                  k7  s:||k  s@|dz  }F |D ]%  ^}	}
|
\  }}| j                  j                  ||       ' |S c c}w c c}w c c}w )	aY  
        Apply diff operations to menu_list while preserving screen reader context.
        Returns new selection index after operations.

        Operations must be applied carefully:
        - Deletes in reverse order (high index to low) to avoid index shifting issues
        - Inserts in forward order
        - Updates in any order
        r   r  r   r  r  c                     | d   S r?  r   )xs    r   r  z,MainWindow.apply_menu_diff.<locals>.<lambda>  s    adr   T)r  reverse)	sortedr?   Deleterk   rh  r  r  Insert	SetString)ro   r  old_selectionnew_selectionopdeletesinsertsupdatesr  op_typeargsrc  s               r   apply_menu_diffzMainWindow.apply_menu_diff  sh    & '1FjBqEX4EBqE8jF *@
"bex.?2
@ *@
"bex.?2
@ wNDIHUNN!!%(,=(!Q&Mm+$'t~~7N7N7PST7T$UM J &NGdKE4NN!!$.,-1G" & &NGdKE4NN$$UD1 & ; G@@s   EEEEE	Ec                 t   | j                  |      }|d   }|d   }|d   }|d   }|d   }|j                  dd      }| j                  |      r'| j                  ||       |r| j	                  ||       y| j                  |       | j                  |k(  }	| j                  |       t        | d	g       }
|| _	        |	s| j                  ||       nD| j                  j                         d
kD  r| j                  |||
|       n| j                  ||       | j                  |       |r| j	                  ||       yy)zHandle menu packet from server.itemsitem_idsitem_soundsr  r`  play_selection_soundFNr\   r   )_parse_menu_packetr>   _menu_state_is_unchanged_apply_menu_position_play_menu_selection_sound_apply_menu_settingsrZ   _prepare_menu_moder~  r\   _rebuild_menur?   r  _apply_menu_diff_update_update_menu_sounds)ro   r0  	menu_datarM  rN  rO  r  r`  rP  is_same_menu_idold_item_idss              r   on_server_menuzMainWindow.on_server_menu  s?   ++F3	'"Z(.I&Z(%zz*@%H((3%%eX6#//+F!!),..'9(t%<bA%-"uh/^^$$&*((,Quh/  -++HkB  r   r0  c           
         |j                  dg       }|j                  dd      }t        | j                  t              r*| j                  j                  d      |k(  r| j                  ni }|j                  d|j                  dd            }|j                  d|j                  dd            }|j                  dd      }|j                  d	d      }|j                  d
|j                  d
d            }	|j                  d|j                  dd            }
g }g }g }|D ]  }t        |t              rb|j	                  |j                  dd             |j	                  |j                  d             |j	                  |j                  d             u|j	                  t        |             |j	                  d       |j	                  d        ||	 |j                  |      }|||||||	|
|d	S # t        $ r Y w xY w)z'Parse menu packet into structured data.rM  r  Nr   Tr   r   r`  r  r  Fr  r   rc  r\  r   r  )	rM  rN  rO  r  r   r   r  r  r`  )r>   r  r[   dictr  strr  r  )ro   r0  	items_rawr  previous_stater   r   r`  r  r  r  rM  rN  rO  re  s                  r   rQ  zMainWindow._parse_menu_packet  s   JJw+	**Y- $1148''++I6'A ## 	 	 %jj!4d;
 !**0)<
 ::j$/zz.$7zz..2D2D^UZ2[\ZZn.@.@q.QR
D$%TXXfb12/""488G#45SY'%""4(  #(8#>>,7
  &#6.($ 

 
	
  s   G4 4	H ?H rZ  c                 p    |d   |d   |d   |d   |d   |d   |d   d}| j                   |k(  ry	|| _         y
)Nr  rM  rO  r   r   r  r  )r  rM  rO  r   r   r  r  TF)r[   )ro   rZ  new_menu_states      r   rR  z#MainWindow._menu_state_is_unchanged'  sa     +w'$]3#,-B#C():;%n5#L1
 ""n4"0r   c                 p    | j                  |d          | j                  |d   |d          |d   | _        y )Nr   r  r  r   )r  r  r   )ro   rZ  s     r   rU  zMainWindow._apply_menu_settings6  s>    ''	2G(HI9^4i6MN():;r   c                 P    | j                   dk(  r| j                          || _        y )Nr}  )rX   r  rZ   )ro   r  s     r   rV  zMainWindow._prepare_menu_mode;  s$    &$$&&r   rM  r`  c                     |^t        |      dkD  rOd|cxk  rt        |      k  r:n y | j                  j                  |       | j                  j                  |       y y y y r?  )r  r?   rl  EnsureVisible)ro   rM  r`  s      r   rS  zMainWindow._apply_menu_position@  sQ    CJNqH7Qs5z7QNN''1NN((2 8RNr   rO  c                     | j                   r|yd|cxk  rt        |      k  r'n n$||   r| j                   j                  ||          y| j                   j                          y)z2Play the selection sound for the item at position.Nr   )rE   r  rG   play_menuclick)ro   r`  rO  s      r   rT  z%MainWindow._play_menu_selection_soundE  sW    !!X%5+3{++H0E##K$9:--/r   c                     t         j                  j                         }|| j                  k7  r+|| j                  k7  r| j
                  j                          y y y r  )rk   rj  rk  r@   rA   r?   r  )ro   r  s     r   _set_menu_focuszMainWindow._set_menu_focusN  sF    ))%%'doo%'T5F5F*FNN##% +G%r   c                 Z   | j                   j                          |D ]  }| j                   j                  |        | j                          t	        |      dkD  rQ|3d|cxk  rt	        |      k  rn n| j                   j                  |       y | j                   j                  d       y y r?  )r?   r  Appendrl  r  rl  )ro   rM  r`  re  s       r   rW  zMainWindow._rebuild_menuS  s    DNN!!$' u:>#X(BE
(B++H5++A.	 r   rN  r\  c                    t        | j                  j                               D cg c]  }| j                  j                  |       }}| j                  j	                         }| j                  ||||      }| j                  ||      }	|Ct        |      dkD  r5d|cxk  rt        |      k  r!n n|}	| j                  j                  |	       y t        |      dkD  r| j                  j	                         }
|	t        j                  k7  r"|
|	k7  r| j                  j                  |	       y y |
t        j                  k(  r| j                  j                  d       y y y c c}w r?  )r4  r?   r  ri  rg  r*  rK  r  rl  rk   rh  )ro   rM  rN  r\  r`  r  r  rC  r  rD  current_selections              r   rX  z"MainWindow._apply_menu_diff_update^  s&    ;@@W@W@Y:Z[:ZQT^^--a0:Z	[335++IulHU
,,ZGCJNqH7Qs5z7Q$MNN''6Z!^ $ ; ; =,$5NN//> 6 %4NN//2 5  \s   "Ec                     t        |      D ]`  \  }}|| j                  j                         k  s$|r| j                  j                  |d|i       E| j                  j                  |d        b y )Nr  )r  r?   r  SetClientData)ro   rO  r  r  s       r   rY  zMainWindow._update_menu_soundsv  sZ    !+.HAu4>>**,,NN00We4DENN00D9 /r   c                      |j                  dd      }|j                  dd      |j                  dd      }|j                  dd      }|j                  d	d      } fd
} j                  |||||       y)z(Handle request_input packet from server.r  zEnter text:input_idNr  r\  r  Fr  c                 T    d| d}r|d<   j                   j                  |       y )Neditbox)r$  rc  rt  r  )rc  event_packetrt  ro   s     r   	on_submitz5MainWindow.on_server_request_input.<locals>.on_submit  s,    $-t<L+3Z(LL$$\2r   )r>   r  )ro   r0  r  r  r  r  rx  rt  s   `      @r   on_server_request_inputz"MainWindow.on_server_request_input~  sp    Hm4::j$/

?B7JJ{E2	JJ{E2		3 	  M9iXr   c           
          ddl m} |j                  dd      |j                  dd      }|j                  d      }|j                  d      }|j                  d      }|j                  d	d
      } fd} fd}	 | |||||||	      }
|
j                         }|
j	                          |t
        j                  t
        j                  fvr |	        yy)uE   Handle document_editor packet from server — open the editor dialog.r   )DocumentEditorDialog	dialog_idr\  contentcontent_labelsource_contentsource_labelr  zEdit documentc                 F    j                   j                  dd| d       y )Ndocument_editorsaver$  r|  actionr}  r  )rc  r|  ro   s    r   on_savez5MainWindow.on_server_document_editor.<locals>.on_save  s&    LL$$-!*$#	r   c                  F    j                   j                  d ddd       y )Nr  cancelr\  r  r  )r|  ro   s   r   	on_cancelz7MainWindow.on_server_document_editor.<locals>.on_cancel  s&    LL$$-!*&!	r   )r~  r  r  r  r  N)document_editor_dialogr{  r>   r   r   rk   ID_SAVE	ID_CANCEL)ro   r0  r{  r}  r~  r  r  r  r  r  r   r   r|  s   `           @r   on_server_document_editorz$MainWindow.on_server_document_editor  s    @JJ{B/	**Y+

?3$45zz.1Ho6		 #')%	
  "**bll33K 4r   c                 6   | j                   j                          d| _        d| _        | j                  dk(  r| j                          | j                  j                          | j                  j                  d       | j                  j                  d       y)z#Handle clear_ui packet from server.Nr}  Tr  F)force)
r?   r  rZ   r[   rX   r  rE   remove_all_playlistsrN  r  r  s     r   on_server_clear_uizMainWindow.on_server_clear_ui  s~     	#"&&$$&//1%%4%0((u(5r   c                     |j                  dg       }|r>d}|D ]%  }||d    d|d    d|d    d|d	    d
|d    d
z  }' | j                  |       y| j                  d       y)z$Handle game_list packet from server.r  zAvailable games:
r   r  r^  z (r$  z) - players/max_playersz	 players
zNo games availableN)r>   r
  )ro   r0  r  game_list_strr	  s        r   on_server_game_listzMainWindow.on_server_game_list  s    

7B'0MDJ<r$v,r$v,tTXYbTcSddefjkxfyez  {E  "F  F ]+12r   c                     t        j                         dz  }|dz  }|j                         r,	 t        |d      5 }t	        j
                  |      cddd       S i S # 1 sw Y   i S xY w# t        $ r i cY S w xY w)z
        Load preferences from ~/.playpalace/preferences.json

        Returns:
            Dict containing preferences, or empty dict if file doesn't exist
        .playpalacepreferences.jsonrN)r   homeexistsopenjsonload	Exception)ro   
config_dirpreferences_filefs       r   rd   zMainWindow._load_preferences  s|     YY[=0
%(::""$*C0A99Q<( (
 	 1
 	  	s.   A( A	A( A% A( %A( (A65A6c                    t        j                         dz  }|dz  }| j                         }t        | j                  j                               |d<   |j                  dd       	 t        |d      5 }t        j                  ||d       d	d	d	       y	# 1 sw Y   y	xY w# t        t        t        f$ r }t        j                  d
|       Y d	}~y	d	}~ww xY w)z'Save muted buffers to preferences file.r  r  r9   T)parentsexist_okw   )indentNzFailed to save preferences: %s)r   r  rd   r3   rb   get_muted_buffersmkdirr  r  dumpOSError	TypeErrorr  rn  ro  )ro   r  r  rp   r  rq  s         r   rZ  zMainWindow._save_muted_buffers  s    YY[=0
%(:: ,,. (,D,>,>,P,P,R'SO$ 	5	=&,		+q3 -,,J/ 	=II6<<	=s6   'B! 3BB! BB! B! !C5CCr  )r   )r\  )r8   T)r\  Nr\  FF)r   N)r/   r  r/   )TT)T)F)NN)r    r!   r"   __doc__rk   r  r  r  r  WXK_NUMPAD_LEFTWXK_NUMPAD_RIGHTWXK_NUMPAD_UPWXK_NUMPAD_DOWNWXK_HOMEWXK_ENDWXK_NUMPAD_HOMEWXK_NUMPAD_END
WXK_PAGEUPWXK_PAGEDOWNWXK_NUMPAD_PAGEUPWXK_NUMPAD_PAGEDOWNr#  r<   rV   rg   rh   ri   rm   r   r   r   r`  r8  r  r   r   r   r   r   r   r   r2  r   r   r   r   r   r   r   r   r   r   r   r@  rL  rr  r   r$   ru  rv  rw  rx  r  r  r  r  r  ry  r   r  r  r   r  r  r  r  r
  r  r  r   r   r   r,  r-  r.  r/  r  r&   r;  r%  rF  rL  rN  ry   rR  rV  rn   rd  ri  rm  rz  rk  rl  ru  r  re  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r
  r$  r*  r&  r'  r(  rK  r]  r_  rQ  rR  rU  rV  r3   rS  rT  rl  rW  rX  rY  ry  r  r  r  rd   rZ  __classcell__)rr   s   @r   r(   r(   /   s   < 	

		














!&fPDDLZ7x"
 PT XC X XX\ XFFCC3>
I8JK%
%
%
%
)
)
)
)
NR=H$(
c 
d 
 s t > t <# d sUYz "	% 	%t 	%c cDj %s %sTz % d
 
; ; ;z0>
= *
c 
3 
c 3 

s 



s 

S 

"GP 70r.(#,\:  
# 
$ 
2# 2$ 2s t 86#6476DH6	6 % % S T  
N	RS 	R4 	Rd 	R:B;;Q(\</$*LA A&*s *3 *(B!'F4'p'LR8c-J
&-0
L(2T?=<+,(8
/:C@D4 
D 
 
    2*XCB4
 4
$ 4
l$ 4 <d <t <
'
3$s) 3sTz 3d 3
03: 0D 0UY 0&
	/49 	/d
 	/t 	/3Cy3 sTz"3 3:&	3
 *3 
30:tC$J/? :D :Y".`6	3&=r   r(   )'r  rk   loggingr?   r   r  r   accessible_output2.outputs.autooutputsautorB   sysosdataclassesr   r  pathlibr   pathr  dirnameabspath__file__r\  r   rE   r	   network_managerr
   rb   r   r.   r   	getLoggerr    rn  r   Framer(   r   r   r   <module>r     s    , 	   % 5 5 
 	 !   277??277??277??83L#MN O  & * & +g! $
 
 
*P#= P#=r   