'''
ARGOMENTI:
---------------------------------------------------------------------


	Eventi
		Un'applicazione Tkinter trascorre la maggior parte del suo tempo all'interno 
		di un ciclo di eventi (metodo mainloop). 


		Gli eventi possono provenire da varie fonti, tra cui:
			- pressione di tasti
			- operazioni del mouse 
		da parte dell'utente.


		attributi di event
			Ogni evento possiede un insieme di attributi.
			Tutti gli attributi sono stati utilizzati e commentati
			nella funzione "visualizzaAttributi"

			N.B. - Non tutti gli attributi sono disponibili per ogni evento


	Binding

		Per ogni widget e' possibile associare agli eventi funzioni e metodi.

		Il procedimento visto finora e' stato quello di utilizzare l'opzione "command" 
		associato ad un qualunque  "click" del mouse o tasto "invio"). 

			Ad esempio:
					Istanza = widget( .... command=FunzioneAssociata)
					Istanza = widget( .... command=partial(FunzioneAssociata, <parametri>)
					Istanza = widget( .... command=lambda:FunzioneAssociata(Parametro)

		Questo metodo e' solo uno dei modi per gestire le chiamate di "callback" 
		(funzioni che vengono fatte "scattare" dal motore interno e non dal programmatore)

		Il modo piu' generale (ma forse il piu' complesso) per gestire la cosa e' quello di 
		utilizzare il "binding" (accoppiamento fra un gestore di eventi e un widget).

		La sintassi e': 

			WIDGET.bind (DESCRIZIONE, gestioneEVENTO) 

		Se si verifica l'evento associato al WIDGET corrispondente alla DESCRIZIONE, 
		viene richiamata la funzione che gestisce l'evento (gestioneEVENTO).

		I valori per DESCRIZIONE possono essere i seguenti
				"<Button-1>"			Click SX mouse
				"<Button-2>"			Click centrale mouse
				"<Button-3>"			Click DX mouse
				"<Button-4>"			"Rotellina" SU del mouse
				"<Button-5>"			"Rotellina" GIU' del mouse
				"<Double-1>"			Doppio click SX mouse
				"<Double-2>"			Doppio click centrale mouse
				"<Double-3>"			Doppio click DX mouse
				"<ButtonRelease-1>"		Rilascio del tasto SX mouse
				"<ButtonRelease-2>"		Rilascio del tasto centrale mouse
				"<ButtonRelease-3>" 	Rilascio del tasto DX mouse
				"<FocusIn>"				Il widget "prende" il focus
				"<FocusOut>"			Il widget "lascia" il focus
				"<B1-Motion>"			"Movimento" sul widget" con tasto premuto
				"<B2-Motion>"				"            "				"
				"<B3-Motion>"				"            "				"
				"<Enter>"				Il puntatore del mouse "entra" nel widget							
				"<Leave>"				Il puntatore del mouse "esce" dal widget
				-------------------------------------------------------------------------------------------------------------------
				"<Key>" 				L'utente ha premuto un tasto qualsiasi. (valore: event.char, tasto speciale: event.keysym )
				-------------------------------------------------------------------------------------------------------------------
						"<Return>"				L'utente ha premuto il tasto "Return" (Invio)
						"<F5>" 					L'utente ha premuto il tasto "F5"
						"<b>" 					L'utente ha premuto il tasto "b"
						"<Up>"					L'utente ha premuto il tasto "Up"
						"<Alt_L>" 				L'utente ha premuto il tasto "Alt" di sinistra
						"<ISO_Level3_Shift>"	L'utente ha premuto il tasto "ALT GR"

						
						In sostanza, oltre al valore <Key>, che intercetta la pressione di 
						un qualsiasi tasto da tastiera, e' possibile gestiste singolarmente 
						tutti i tasti (speciali e non) 

							Esempio: txtTEST.bind("<Return>", funzioneAssociata)

						Oltre a "<Retrun>" si possono dare i seguenti valori:

							Cancel, BackSpace, Tab, Return, 
							Shift_L, Control_L, Alt_L,
							Shift_R, Control_R, ISO_Level3_Shift (Alt_GR) 
							Pause, Caps_Lock, Escape, 
							Prior (Page Up), 
							Next (Page Down), 
							End, Home, Print, Insert, Delete,
							Left, Up, Right, Down, 
							F1, F2, ... , F11, F12, 
							Num_Lock,Scroll_Lock.
							<a>, <b>, ... <z> o qualsiasi carattere

						Volendo scoprire altre rappresentazioni dei tasti, mandare in esecuzione l'esempio.
						I risultati saranno disponibili nel campo "valori degli attributi"
				-------------------------------------------------------------------------------------------------------------------

		Parametro DESCRIZIONE
			Per completezza bisogna dire che i valori per "DESCRIZIONE" sono espressi in questo modo:

				<Modificatore-tipo-dettaglio>

			Quelli che sono stati utilizzati sono relativi al "tipo" (che e' poi la componente fondamentale).
			I valori "modificatore" e "dettaglio" non sono obbligatori e vengono quasi sempre tralasciati.
			Sono usati per fornire informazioni aggiuntive per il "tipo" scelto.


'''
from tkinter import *

# -------------------------------------------------------------------
# funzione che visualizza tutti gli attributi dell'evento intercettato
# -------------------------------------------------------------------
def visualizzaAttributi(event, intestazione):
	msg = intestazione + "-----------------------------\n"

	try: V = str(event)
	except: V = "NONE"  
	msg += "EVENTO...: " + V + "\n"

	try: V = str(event.x)
	except: V = "NONE"  
	msg += "x........: " + V + "\t\t\t\t (Coord. X oggetto) \n"
	
	try: V = str(event.y) 
	except: V = "NONE"
	msg += "y........: " + V + "\t\t\t\t (Coord. Y oggetto) \n"
	
	try: V = str(event.x_root) 
	except: V = "NONE"
	msg += "x_root...: " + V + "\t\t\t\t (Coord. X Schermo) \n"
	
	try: V = str(event.y_root) 
	except: V = "NONE"
	msg += "y_root...: " + V + "\t\t\t\t (Coord. Y Schermo) \n"
	
	try: V = str(event.num) 
	except: V = "NONE"
	msg += "num......: " + V + "\t\t\t\t (Pulsante premuto) \n"
	
	try: V = str(event.char) 
	except: V = "NONE"
	msg += "char.....: " + V + "\t\t\t\t (Carattere) \n"
	
	try: V  = str(event.keysym) 
	except: V  = "NONE"
	msg += "keysym...: " + V + "\t\t\t\t (Carattere speciale) \n"
	
	try: V  = str(event.keycode) 
	except: V = "NONE"
	msg += "keycode..: " + V + "\t\t\t\t (Codice carattere) \n"
	
	try: V = str(event.width) 
	except: V = "NONE"
	msg += "width....: " + V +	"\t\t\t\t (Nuova Larghezza) \n"
	
	try: V = str(event.height) 
	except: V = "NONE"
	msg += "height...: " + V +	"\t\t\t\t (Nuova Altezza) \n"
	
	try: V = str(event.type) 
	except: V = "NONE"
	msg += "type.....: " + V +	"\t\t\t\t (Tipo evento) \n"
	
	try: V = str(event.widget) 
	except: V = "NONE"
	msg += "widget...: " + V +	"\t\t\t\t (Widget attuale) \n"
	
	try: V = str(event.delta) 
	except: V = "NONE"
	msg += "delta....: " + V +	"\t\t\t\t (Supporto MouseWheel: diverso tra SO) \n"
	
	try: V = str(event.state) 
	except: V = "NONE"
	msg += "state....: " + V +	"\t\t\t\t (Stato dei tasti modificatori) \n"
	
	 # event.serial e' un numero seriale intero che viene incrementato ogni volta 
	 # che il server elabora una richiesta. E' possibile utilizzare questi valori 
	 # per trovare la sequenza temporale esatta degli eventi: 
	 # quelli con valori piu' bassi si sono verificati prima.
	try: V = str(event.serial) 
	except: V= "NONE"
	msg += "serial...: " + V +	"\t\t\t\t (Numero seriale cronologia eventi) \n"
	
	try: V = str(event.time) 
	except: V = "NONE"
	msg += "time.....: " + V +	"\t\t\t\t (Contatore incrementato ogni ms) \n"


	try:
		if event.num==1:
			msg += "\n >>> PULSANTE SINISTRO"
		elif event.num==2:
			msg += "\n >>> PULSANTE CENTRALE"
		elif event.num==3:
			msg += "\n >>> PULSANTE DESTRO"
		elif event.num==4:
			msg += "\n >>> ROTELLINA UP"
		elif event.num==5:
			msg += "\n >>> ROTELLINA DOWN"
		else:
			msg += "\n >>> PULSANTE NON RICOGNIZZATO"
	except:
			msg += "\n >>> ATTRIBUTO <num> NON PREVISTO"


	msg += "\n\n\n"
	
	finMessaggi.insert(0.0,msg) 


# -------------------------------------------------------------------
# 				funzioni di gestione degli eventi
# Non fanno altro che visualizzare un HEADER con il nome dell'evento
# gestito e richiamare, successivamente, la visualizzazione degli attributi
# -------------------------------------------------------------------
def gestioneClick(event):
	intestazione  = "GESTIONE CLICK\n"
	visualizzaAttributi(event, intestazione)

def gestioneDoubleClick(event):
	intestazione  = "GESTIONE DOPPIO CLICK\n"
	visualizzaAttributi(event, intestazione)

def gestioneFocusIn(event):
	intestazione  = "GESTIONE FOCUS IN\n"
	visualizzaAttributi(event, intestazione)

def gestioneFocusOut(event):
	intestazione  = "GESTIONE FOCUS OUT\n"
	visualizzaAttributi(event, intestazione)

def gestioneMotion(event):
	intestazione  = "GESTIONE MOTION\n"
	visualizzaAttributi(event, intestazione)

def gestioneRelease(event):
	intestazione  = "GESTIONE RELEASE\n"
	visualizzaAttributi(event, intestazione)

def gestioneEnter(event):
	intestazione  = "GESTIONE ENTER\n"
	visualizzaAttributi(event, intestazione)

def gestioneLeave(event):
	intestazione  = "GESTIONE LEAVE\n"
	visualizzaAttributi(event, intestazione)

def gestioneTasti(event):
	intestazione  = "GESTIONE TASTI\n"
	visualizzaAttributi(event, intestazione)

def gestioneSingoloTasto(event):
	intestazione  = "GESTIONE SINGOLO TASTO\n"
	visualizzaAttributi(event, intestazione)





# definizione della finestra
fin = Tk()
fin.title("Applicazione")
fin.resizable(width=False, height=False)


# labelframe contenente un' area testo e un pulsante
# sui quali e' possibile intercettare gli eventi
# -------------------------------------------------------------
contenitore1=LabelFrame(text="Intercettazione eventi")
# area testo
txtTEST = Text(contenitore1, height=6, width=60)   
txtTEST.insert(END,"TextArea")
txtTEST.pack(pady=(10, 0)) # padding verticale 10:nord, 0:sud
#pulsante
btnTEST = Button(contenitore1, text="Pulsante")
btnTEST.pack()         
contenitore1.pack(fill="x")         


# labelframe contenente un' area testo per i messaggi,
# una scrollbar associata ed un pulsante per ripulire l'area
# -------------------------------------------------------------
contenitore2=LabelFrame(text="Valori degli attributi")
# area testo
finMessaggi = Text(contenitore2,bg="white")   
finMessaggi.grid(row=0, column=0, pady=(10, 0), sticky='nsew')
# scrollbar associata all'area testo
scrollb = Scrollbar(contenitore2, command=finMessaggi.yview)
scrollb.grid(row=0, column=1, sticky='nsew')
finMessaggi['yscrollcommand'] = scrollb.set
contenitore2.pack(pady=(20, 0)) # padding verticale 20:nord, 0:sud
# pulsanti ripulisci area testo
btnPULISCI = Button(text="Ripulisci", command=lambda:(finMessaggi.delete("1.0", END))).pack()  
# -------------------------------------------------------------


'''
 NOTA: 
 	se si usa un metodo di posizionamento (grid, place, pack),
 	questo deve essere sempre lo stesso in relazione al contenitore,
 	nel nostro caso:

 			finestra
 				contenitore1.pack()
					test.pack()
					button.pack()
 				contenitore2.pack()
					test.grid()
					button.grid()
					scrollbar.grid()
 '''			

# "bind" sul pulsante
btnTEST.bind("<Button-1>",  		gestioneClick)
btnTEST.bind("<Button-2>",  		gestioneClick)
btnTEST.bind("<Button-3>",  		gestioneClick)
btnTEST.bind("<Button-4>",  		gestioneClick)
btnTEST.bind("<Button-5>",  		gestioneClick)
btnTEST.bind("<Double-1>",  		gestioneDoubleClick)
btnTEST.bind("<Double-2>",  		gestioneDoubleClick)
btnTEST.bind("<Double-3>",  		gestioneDoubleClick)
btnTEST.bind("<FocusIn>",   		gestioneFocusIn)
btnTEST.bind("<FocusOut>",  		gestioneFocusOut)
btnTEST.bind("<B1-Motion>", 		gestioneMotion)
btnTEST.bind("<B2-Motion>", 		gestioneMotion)
btnTEST.bind("<B3-Motion>", 		gestioneMotion)
btnTEST.bind("<ButtonRelease-1>", 	gestioneRelease)
btnTEST.bind("<ButtonRelease-2>", 	gestioneRelease)
btnTEST.bind("<ButtonRelease-3>", 	gestioneRelease)
btnTEST.bind("<Enter>", 			gestioneEnter)
btnTEST.bind("<Leave>", 			gestioneLeave)
btnTEST.bind("<Key>", 				gestioneTasti)
btnTEST.bind("<Return>", 			gestioneSingoloTasto)
btnTEST.bind("<F5>", 				gestioneSingoloTasto)
btnTEST.bind("<b>", 				gestioneSingoloTasto)
btnTEST.bind("<Up>", 				gestioneSingoloTasto)
btnTEST.bind("<Alt_L>", 			gestioneSingoloTasto)
# btnTEST.bind("<ISO_Level3_Shift>",  gestioneSingoloTasto) # Sistemi LINUX


# "bind" sulla casella di testo
txtTEST.bind("<Button-1>", 			gestioneClick)
txtTEST.bind("<Button-2>", 			gestioneClick)
txtTEST.bind("<Button-3>", 			gestioneClick)
txtTEST.bind("<Button-4>", 			gestioneClick)
txtTEST.bind("<Button-5>", 			gestioneClick)
txtTEST.bind("<Double-1>", 			gestioneDoubleClick)  
txtTEST.bind("<Double-2>", 			gestioneDoubleClick)  
txtTEST.bind("<Double-3>",			gestioneDoubleClick)       
txtTEST.bind("<FocusIn>", 			gestioneFocusIn)
txtTEST.bind("<FocusOut>", 			gestioneFocusOut)
txtTEST.bind("<B1-Motion>", 		gestioneMotion)
txtTEST.bind("<B2-Motion>", 		gestioneMotion)
txtTEST.bind("<B3-Motion>", 		gestioneMotion)
txtTEST.bind("<ButtonRelease-1>", 	gestioneRelease)
txtTEST.bind("<ButtonRelease-2>", 	gestioneRelease)
txtTEST.bind("<ButtonRelease-3>", 	gestioneRelease)
txtTEST.bind("<Enter>", 			gestioneEnter)
txtTEST.bind("<Leave>", 			gestioneLeave)
txtTEST.bind("<Key>", 				gestioneTasti)
txtTEST.bind("<Return>", 			gestioneSingoloTasto)
txtTEST.bind("<F5>", 				gestioneSingoloTasto)
txtTEST.bind("<b>", 				gestioneSingoloTasto)
txtTEST.bind("<Up>", 				gestioneSingoloTasto)
txtTEST.bind("<Alt_L>", 			gestioneSingoloTasto)
# txtTEST.bind("<ISO_Level3_Shift>",	gestioneSingoloTasto) # Sistemi LINUX

fin.mainloop()