libtk.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. #!/usr/bin/python3
  2. import os
  3. import time
  4. import sys
  5. sys.path.insert(0,"/opt/LibreLight/Xdesk/")
  6. import tkinter
  7. tk = tkinter
  8. import __main__ as MAIN
  9. from lib.cprint import cprint
  10. import lib.libwin as libwin
  11. import lib.baselib as baselib
  12. import json
  13. _config = []
  14. try:
  15. h = os.environ["HOME"]
  16. lines = [{}]
  17. try:
  18. f = open(h +"/LibreLight/config.json")
  19. lines = f.readlines()
  20. except FileNotFoundError as e: #Exception as e:
  21. f = open(h +"/LibreLight/config.json","w")
  22. f.write('{"POS_TOP":0}\n{"POS_LEFT":0}')
  23. f.close()
  24. cprint("Exception:",e)
  25. cprint("config read")
  26. for line in lines:
  27. line=line.strip()
  28. print(" config:",line)
  29. row = json.loads(line)
  30. _config.append(row)
  31. except Exception as e:
  32. cprint("Exception:",e)
  33. _POS_LEFT = 0
  34. _POS_TOP = 15
  35. try:
  36. for row in _config:
  37. #print(" config:",row)
  38. if "POS_LEFT" in row:
  39. _POS_LEFT = int(row["POS_LEFT"])
  40. if "POS_TOP" in row:
  41. _POS_TOP = int(row["POS_TOP"])
  42. except Exception as e:
  43. cprint("Exception:",e)
  44. class Event():
  45. def __init__(self,name):
  46. self.name=name
  47. #print("init",self)
  48. def event(self,event):
  49. print(self.name,event)
  50. class scroll():
  51. def __init__(self,canvas):
  52. self.canvas=canvas
  53. def config(self,event):
  54. canvas = self.canvas
  55. canvas.configure(scrollregion=canvas.bbox("all"))#,width=400,height=200)
  56. def ScrollFrame(root,width=50,height=100,bd=1,bg="black",head=None,foot=None):
  57. rframe=tk.Frame(root)
  58. rframe.pack(side="top",fill="both",expand=1) #x=0,y=0)
  59. # frame grid start =========
  60. if head:
  61. height -= 25
  62. hframe=tk.Frame(rframe)
  63. #l = tk.Label(hframe,text="frame")
  64. #l.pack()
  65. hframe.pack(side="top",fill="x",expand=0) #x=0,y=0)
  66. aframe=tk.Frame(rframe)
  67. aframe.pack(side="top",fill="both",expand=1) #x=0,y=0)
  68. if foot:
  69. height -= 25
  70. fframe=tk.Frame(rframe)
  71. #l = tk.Label(fframe,text="frame")
  72. #l.pack()
  73. fframe.pack(side="top",fill="x",expand=0) #x=0,y=0)
  74. # frame grid end ==========
  75. canvas=tk.Canvas(aframe,width=width-24,height=height)
  76. if bg == "":
  77. bg="orange"
  78. canvas["bg"] = bg # "black" #"green"
  79. bframe=tk.Frame(canvas,width=width,height=height,relief=tk.GROOVE)
  80. bframe["bg"] = "blue"
  81. scrollbar=tk.Scrollbar(aframe,orient="vertical",command=canvas.yview,width=20)
  82. canvas.configure(yscrollcommand=scrollbar.set)
  83. scrollbar.pack(side="right",fill="y")
  84. canvas.pack(side="left",expand=1,fill="both")
  85. canvas.create_window((0,0),window=bframe,anchor='nw')
  86. bframe.bind("<Configure>",scroll(canvas).config)
  87. canvas.bind("<Button>",Event("XXX").event)
  88. canvas.bind("<Key>",Event("XXX").event)
  89. canvas.bind("<KeyRelease>",Event("XXX").event)
  90. if head or foot:
  91. return [hframe,bframe,fframe]
  92. return bframe
  93. def frame_of_show_list(frame,cb=None):
  94. c=0
  95. r=0
  96. base = baselib.Base()
  97. for i in ["name","stamp"]: #,"create"]:
  98. b = tk.Label(frame,bg="grey",text=i)
  99. b.grid(row=r, column=c, sticky=tk.W+tk.E)
  100. c+=1
  101. r+=1
  102. blist = baselib.list_shows()
  103. for i in range(10):
  104. blist.append(["",""])
  105. if cb is None:
  106. cb = DummyCallback #("load_show_list.cb")
  107. for i in blist:
  108. #print(i)
  109. c=0
  110. for j in i:
  111. bg="lightgrey"
  112. dbg="lightgrey"
  113. if i[1] > time.strftime("%Y-%m-%d %X", time.localtime(time.time()-3600*4)):
  114. dbg = "lightgreen"
  115. elif i[1] > time.strftime("%Y-%m-%d %X", time.localtime(time.time()-3600*24*7)):
  116. dbg = "green"
  117. if c > 0:
  118. b = tk.Button(frame,text=j,anchor="w",bg=dbg,relief="sunken")
  119. b.config(activebackground=dbg)
  120. b.grid(row=r, column=c, sticky=tk.W+tk.E)
  121. else:
  122. if base.show_name == i[0]:
  123. bg="green"
  124. _cb = cb(j)
  125. b = tk.Button(frame,text=j,anchor="w",height=1,bg=bg,command=_cb.cb)
  126. if base.show_name == i[0]:
  127. b.config(activebackground=bg)
  128. b.grid(row=r, column=c, sticky=tk.W+tk.E)
  129. c+=1
  130. r+=1
  131. class BLINKI():
  132. def __init__(self,e):
  133. self.e = e
  134. def blink(self):
  135. e = self.e
  136. e.config(bg='green')
  137. duration = 150
  138. for i in range(8):
  139. d = i * duration
  140. if i % 2 == 0:
  141. e.after(d, lambda: e.config(bg='white')) # after 1000ms
  142. e.after(d, lambda: e.config(activebackground='white')) # after 1000ms
  143. else:
  144. e.after(d, lambda: e.config(bg='orange')) # after 1000ms
  145. e.after(d, lambda: e.config(activebackground='orange')) # after 1000ms
  146. i+=1
  147. duration = 150
  148. e.after(d, lambda: e.config(bg='white')) # after 1000ms
  149. e.after(d, lambda: e.config(activebackground='white')) # after 1000ms
  150. class on_focus():
  151. def __init__(self,name,mode):
  152. self.name = name
  153. self.mode = mode
  154. def cb(self,event=None):
  155. #print("on_focus",event,self.name,self.mode)
  156. try:
  157. e = MAIN.master.commands.elem["."]
  158. except:pass
  159. if self.mode == "Out":
  160. cmd="xset -display :0.0 r rate 240 20"
  161. #print(cmd)
  162. os.system(cmd)
  163. try:
  164. e["bg"] = "#aaa"
  165. e["activebackground"] = "#aaa"
  166. except:pass
  167. if self.mode == "In":
  168. cmd = "xset -display :0.0 r off"
  169. #print(cmd)
  170. os.system(cmd)
  171. try:
  172. e["bg"] = "#fff"
  173. e["activebackground"] = "#fff"
  174. except:pass
  175. class DummyCallback():
  176. def __init__(self,name="name"):
  177. self.name = name
  178. def cb(self,event=None):
  179. cprint("DummyCallback.cb",[self.name,event])
  180. class WindowContainer():
  181. def __init__(self,args): #title="title",master=0,width=100,height=100,left=None,top=None,exit=0,cb=None,resize=1):
  182. global MAIN #lf_nr
  183. self.args = {"title":"title","master":0,"width":100,"height":100,"left":None,"top":None,"exit":0,"cb":None,"resize":1}
  184. self.args.update(args)
  185. cprint("WindowContainer.init()",self.args["title"],color="yellow")
  186. #cprint("WindowContainer.init()",id(self.args),color="yellow")
  187. #cprint(" ",self.args,color="yellow")
  188. ico_path="./icon/"
  189. self.cb = MAIN.cb
  190. if self.args["master"]:
  191. self.tk = tkinter.Tk()
  192. self.tk.protocol("WM_DELETE_WINDOW", self.close)
  193. self.tk.withdraw() # do not draw
  194. self.tk.resizable(self.args["resize"],self.args["resize"])
  195. self.tk.tk_setPalette(background='#bbb', foreground='black', activeBackground='#aaa', activeForeground="black")
  196. defaultFont = tkinter.font.nametofont("TkDefaultFont")
  197. cprint(defaultFont)
  198. defaultFont.configure(family="FreeSans",
  199. size=10,
  200. weight="bold")
  201. # MAIN MENUE
  202. try:
  203. self.tk.iconphoto(False, tk.PhotoImage(file=ico_path+"main.png"))
  204. except Exception as e:
  205. cprint(" Exception GUIWindowContainer.__init__",e)
  206. else:
  207. # addtional WINDOW
  208. self.tk = tkinter.Toplevel()
  209. self.tk.iconify()
  210. #self.tk.withdraw() # do not draw
  211. self.tk.protocol("WM_DELETE_WINDOW", self.close)
  212. self.tk.resizable(self.args["resize"],self.args["resize"])
  213. try:
  214. if "COLORPICKER" in self.args["title"]:
  215. self.tk.iconphoto(False, tk.PhotoImage(file=ico_path+"picker.png"))
  216. elif "ENCODER" in self.args["title"]:
  217. self.tk.iconphoto(False, tk.PhotoImage(file=ico_path+"enc.png"))
  218. elif "EXEC" in self.args["title"]:
  219. self.tk.iconphoto(False, tk.PhotoImage(file=ico_path+"exec.png"))
  220. elif "FX" in self.args["title"]:
  221. self.tk.iconphoto(False, tk.PhotoImage(file=ico_path+"fx.png"))
  222. else:
  223. self.tk.iconphoto(False, tk.PhotoImage(file=ico_path+"scribble.png"))
  224. except Exception as e:
  225. cprint(" Exception on load window icon",self.args["title"])
  226. cprint(" Exception:",e)
  227. #time.sleep(3)
  228. self.tk.deiconify()
  229. self.tk["bg"] = "black"
  230. self.tk.bind("<Button>",self.callback)
  231. self.tk.bind("<Key>",self.callback)
  232. self.tk.bind("<KeyRelease>",self.callback)
  233. self.tk.bind("<FocusIn>", on_focus(self.args["title"],"In").cb)
  234. self.tk.bind("<FocusOut>", on_focus(self.args["title"],"Out").cb)
  235. self.tk.title(""+str(self.args["title"])+" "+str(MAIN.lf_nr)+":"+str(MAIN.rnd_id))
  236. MAIN.lf_nr+=1
  237. #self.tk.geometry("270x600+0+65")
  238. geo ="{}x{}".format(self.args["width"],self.args["height"])
  239. if self.args["left"] is not None:
  240. geo += "+{}".format(self.args["left"])
  241. if self.args["top"] is not None:
  242. geo += "+{}".format(self.args["top"])
  243. #self._event_clear = MAIN.tk_event(fix=0,elem=None,attr="CLEAR",data=self,mode="ROOT").cb
  244. self.tk.geometry(geo)
  245. self.show()
  246. def update_idle_task(self):
  247. if MAIN.INIT_OK:
  248. tkinter.Tk.update_idletasks(MAIN.gui_menu_gui.tk)
  249. def close(self,event=None):
  250. cprint("WindowContainer.close",self.args["title"],color="red")
  251. #cprint(" ",self.title)
  252. #cprint(" ",self.args)
  253. if self.args["title"] == "MAIN":
  254. MAIN.save_show()
  255. self.tk.destroy()
  256. try:
  257. self.tk.destroy()
  258. except Exception as e:
  259. cprint("WindowContainer.close err",e,color="red")
  260. def title(self,title=None):
  261. if title is None:
  262. return self.tk.title()
  263. else:
  264. #return self.tk.title(title)
  265. self.args["title"] = title
  266. return self.tk.title(""+str(self.args["title"])+" "+str(MAIN.lf_nr)+":"+str(MAIN.rnd_id))
  267. def show(self):
  268. self.tk.deiconify()
  269. pass
  270. def mainloop(self):
  271. #save_window_position_loop() #like autosave
  272. try:
  273. self.tk.mainloop()
  274. finally:
  275. self.tk.quit()
  276. cmd="xset -display :0.0 r rate 240 15"
  277. #print(cmd)
  278. os.system(cmd)
  279. def callback(self,event,data={}):#value=255):
  280. #global MAIN._global_short_key
  281. sstart = time.time()
  282. #time.sleep(0.1)
  283. if not MAIN._global_short_key:
  284. return 1
  285. #global MAIN #_shift_key
  286. #cprint("<GUI>",event,color="yellow")
  287. value = 255
  288. if "Release" in str(event.type) or str(event.type) == '5' or str(event.type) == '3':
  289. value = 0
  290. cprint("<GUI>",event.state,data,value,[event.type,event.keysym],color="yellow")
  291. #print(event)
  292. if "state" in dir(event) and "keysym" in dir(event):
  293. #print([event.state,event.keysym,event.type])
  294. if event.state == 4 and str(2) == str(event.type): # strg + s
  295. if str(event.keysym) == "s":
  296. MAIN.save_show()
  297. e = MAIN.master.setup_elem["SAVE\nSHOW"]
  298. b = BLINKI(e)
  299. b.blink()
  300. if str(event.keysym) == "c":
  301. if MAIN.save_show():
  302. MAIN.LOAD_SHOW_AND_RESTART("").cb(force=1)
  303. return
  304. if "keysym" in dir(event):
  305. if "Escape" == event.keysym:
  306. MAIN.FIXTURES.clear()
  307. MAIN.modes.val("ESC",1)
  308. MAIN.master.refresh_fix()
  309. elif event.keysym in ["Shift_L","Shift_R"]:
  310. #cprint(event.type)
  311. if "KeyRelease" in str(event.type) or str(event.type) in ["3"]:
  312. MAIN._shift_key = 0
  313. else:
  314. MAIN._shift_key = 1
  315. #cprint("SHIFT_KEY",_shift_key,"??????????")
  316. #cprint("SHIFT_KEY",_shift_key,"??????????")
  317. #global MAIN #_ENCODER_WINDOW
  318. try:
  319. if MAIN._shift_key:
  320. MAIN._ENCODER_WINDOW.title("SHIFT/FINE ")
  321. else:
  322. MAIN._ENCODER_WINDOW.title("ENCODER")
  323. except Exception as e:
  324. cprint("exc9800",e)
  325. #raise e
  326. elif event.keysym in "ebfclrmsRx" and value:
  327. if "e" == event.keysym:
  328. MAIN.modes.val("EDIT",1)
  329. elif "b" == event.keysym:
  330. MAIN.modes.val("BLIND",1)
  331. elif "f" == event.keysym:
  332. MAIN.modes.val("FLASH",1)
  333. elif "c" == event.keysym:
  334. MAIN.modes.val("CFG-BTN",1)
  335. elif "l" == event.keysym:
  336. MAIN.modes.val("LABEL",1)
  337. elif "r" == event.keysym:
  338. MAIN.modes.val("REC",1)
  339. elif "R" == event.keysym:
  340. MAIN.modes.val("REC-FX",1)
  341. elif "x" == event.keysym:
  342. MAIN.modes.val("REC-FX",1)
  343. elif "m" == event.keysym:
  344. x=MAIN.modes.val("MOVE",1)
  345. if not x:
  346. MAIN.EXEC.clear_move()
  347. elif "s" == event.keysym:
  348. MAIN.modes.val("SELECT",1)
  349. elif event.keysym in ["F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12"]:
  350. nr = int( event.keysym[1:]) # F:1-12
  351. nr = nr-1+81
  352. cprint("F-KEY",value,nr,event.keysym)
  353. #print(event)
  354. MAIN.master.exec_go(nr-1,xfade=None,val=value)
  355. elif event.keysym in ["1","2","3","4","5","6","7","8","9","0"]:
  356. nr = int( event.keysym)
  357. if nr == 0:
  358. nr = 10
  359. nr = nr-1+161
  360. cprint("NUM-KEY",value,nr)
  361. MAIN.master.exec_go(nr-1,xfade=None,val=value)
  362. elif "numbersign" == event.keysym and value: # is char "#"
  363. cprint("numbersign !!")
  364. MAIN.save_show()
  365. for e in MAIN.master.setup_cmd:
  366. cprint(e)
  367. e = MAIN.master.setup_elem["SAVE\nSHOW"]
  368. cprint(e)
  369. b = BLINKI(e)
  370. b.blink()
  371. #e = MAIN.tk_event(fix=0,elem=None,attr="SAVE\nSHOW",mode="SETUP")
  372. #e.cb(event=event)
  373. elif "End" == event.keysym:
  374. MAIN.FIXTURES.fx_off("all")
  375. CONSOLE.fx_off("all")
  376. CONSOLE.flash_off("all")
  377. elif "Delete" == event.keysym:
  378. #MAIN.EXEC.delete(nr)
  379. if value:
  380. MAIN.modes.val("DEL",1)
  381. #cprint("oipo "*10,round(int(time.time()-sstart)*1000,2))
  382. class window_create_buffer():
  383. # könnte auch direkt im WindowContainer object eingebaut werden !?
  384. def __init__(self,args,cls,data,cb_ok=None,scroll=0,gui=None):
  385. self.args = args.copy()
  386. self.cls = cls
  387. self.cb_ok = cb_ok
  388. self.data = data
  389. self.scroll = scroll
  390. self.gui = gui
  391. def create(self,hidde=0):
  392. obj = None
  393. w = WindowContainer(self.args)
  394. out = []
  395. f = None
  396. h = None
  397. if self.scroll:
  398. head = None
  399. foot = None
  400. if "head" in self.args:
  401. head = self.args["head"]
  402. if "foot" in self.args:
  403. foot = self.args["foot"]
  404. w1 = ScrollFrame(w.tk,width=self.args["width"],height=self.args["height"],foot=foot,head=head)
  405. if type(w1) is list:
  406. try:
  407. h = w1[0]
  408. f = w1[2]
  409. except:pass
  410. w1 = w1[1]
  411. else:
  412. w1 = tk.Frame(w.tk,width=self.args["width"],height=self.args["height"])
  413. w1.pack()
  414. try:
  415. obj=self.cls(self.gui,w1,self.data,foot=f,head=h)
  416. except:
  417. obj=self.cls(self.gui,w1,self.data)
  418. return w,obj,self.cb_ok
  419. class PopupList():
  420. def __init__(self,name="<NAME>",master=0,width=400,height=450,exit=1,left=_POS_LEFT+400,top=_POS_TOP+100,cb=None,bg="black"):
  421. self.name = name
  422. self.frame = None
  423. self.bg=bg
  424. self.cb = cb
  425. if cb is None:
  426. cb = DummyCallback #("load_show_list.cb")
  427. #w = WindowContainer(self.name,master=master,width=width,height=height,exit=exit,left=left,top=top,cb=cb)
  428. args = {"title":self.name,"master":master,"width":width,"height":height,"exit":exit,"left":left,"top":top,"cb":cb}
  429. w = WindowContainer(args)
  430. self.w = w
  431. w.show()
  432. def sframe(self,line1="<line1>",line2="<line2>",data=[]):
  433. xframe=self.w.tk
  434. if self.bg:
  435. xframe.configure(bg=self.bg)
  436. self.w.tk.configure(bg=self.bg)
  437. c=0
  438. r=0
  439. b = tk.Label(xframe,bg="grey",text=line1,anchor="w")
  440. b.pack(side="top",expand=0,fill="x" )
  441. b = tk.Label(xframe,bg="grey",text=line2,anchor="w")
  442. b.pack(side="top",expand=0,fill="x" )
  443. b = tk.Label(xframe,bg="black",fg="black",text="")
  444. if self.bg:
  445. b.configure(fg=self.bg)
  446. b.configure(bg=self.bg)
  447. b.pack(side="top")
  448. b = tk.Entry(xframe,width=10,text="")#,anchor="w")
  449. b.pack(side="top",expand=0,fill="x")
  450. b["state"] = "readonly"
  451. b.focus()
  452. #frame = tk.Frame(xframe,heigh=2800)
  453. #frame.pack(fill=tk.BOTH,expand=1, side=tk.TOP)
  454. frame = ScrollFrame(xframe,width=300,height=500,bd=1,bg=self.bg)
  455. #frame.pack(side="left") #fill=tk.BOTH,expand=1, side=tk.TOP)
  456. #self.frame = frame
  457. self.w.tk.state(newstate='normal')
  458. self.w.tk.attributes('-topmost',True)
  459. return frame
  460. def showwarning(msg="<ERROR>",title="<TITLE>"):
  461. cprint("showwarning","MSG:",msg,"tilte:",title)
  462. if IS_GUI:
  463. _main = tkinter.Tk()
  464. defaultFont = tkinter.font.nametofont("TkDefaultFont")
  465. cprint("showwarning",defaultFont)
  466. if IS_GUI:
  467. defaultFont.configure(family="FreeSans",
  468. size=10,
  469. weight="normal")
  470. geo ="{}x{}".format(20,20)
  471. _main.geometry(geo)
  472. def _quit():
  473. time.sleep(1/10)
  474. _main.quit()
  475. thread.start_new_thread(_main.mainloop,())
  476. r=tkinter.messagebox.showwarning(message=msg,title=title,parent=None)