studio_storyLayer.py 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. # THIS FILE IS A PART OF VCStudio
  2. # PYTHON 3
  3. import os
  4. import datetime
  5. import threading
  6. # GTK module ( Graphical interface
  7. import gi
  8. gi.require_version('Gtk', '3.0')
  9. from gi.repository import Gtk
  10. from gi.repository import GLib
  11. from gi.repository import Gdk
  12. import cairo
  13. # Own modules
  14. from settings import settings
  15. from settings import oscalls
  16. from settings import talk
  17. from project_manager import pm_project
  18. from studio import analytics
  19. from studio import studio_nodes
  20. from studio import studio_dialogs
  21. from studio import story
  22. from studio import analytics
  23. from studio import schedule
  24. #UI modules
  25. from UI import UI_elements
  26. from UI import UI_color
  27. from network import http_client
  28. def layer(win):
  29. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  30. stf = datetime.datetime.now()
  31. perfStat = []
  32. ###################################################################
  33. # Making the layer
  34. surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'],
  35. win.current['h'])
  36. layer = cairo.Context(surface)
  37. #text setting
  38. layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  39. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  40. fif = datetime.datetime.now()
  41. mil = fif - stf
  42. perfStat.append([ "Setup", mil.microseconds ])
  43. stf = datetime.datetime.now()
  44. ###################################################################
  45. UI_color.set(layer, win, "darker_parts")
  46. UI_elements.roundrect(layer, win,
  47. 50,
  48. 50,
  49. win.current["w"] - 100,
  50. win.current["h"] - 80,
  51. 30)
  52. # Little verion thing in the bottom corner
  53. UI_color.set(layer, win, "testing_banner")
  54. layer.set_font_size(15)
  55. layer.move_to(win.current["w"]-80, win.current["h"] - 7)
  56. layer.show_text(str(win.version))
  57. # Hude analytics button on the top
  58. def do():
  59. win.cur = "/set"
  60. win.url = "analytics"
  61. UI_elements.roundrect(layer, win,
  62. 5,
  63. 5,
  64. win.current["w"]-(win.current["w"]/3)+45,
  65. 40,
  66. 10,
  67. do,
  68. "analytics",
  69. talk.text("analytics_tooltip"),
  70. url="story_editor")
  71. # Progressbar
  72. UI_color.set(layer, win, "progress_background")
  73. UI_elements.roundrect(layer, win,
  74. 55,
  75. 15,
  76. win.current["w"]/3*2-10,
  77. 20,
  78. 10)
  79. timepassed = 0.0
  80. projectdone = 0.0
  81. try:
  82. timepassed = win.analytics["timepassed"]
  83. projectdone = win.analytics["fraction"]
  84. except:
  85. pass
  86. # Timepassed
  87. UI_color.set(layer, win, "progress_time")
  88. UI_elements.roundrect(layer, win,
  89. 55,
  90. 15,
  91. (win.current["w"]/3*2-10)*timepassed,
  92. 20,
  93. 10)
  94. # Project Done
  95. UI_color.set(layer, win, "progress_active")
  96. UI_elements.roundrect(layer, win,
  97. 55,
  98. 15,
  99. (win.current["w"]/3*2-10)*projectdone,
  100. 20,
  101. 10)
  102. # Separator
  103. UI_color.set(layer, win, "node_background")
  104. layer.move_to(win.current["w"]/3*2+55, 5)
  105. layer.line_to(win.current["w"]/3*2+55, 45)
  106. layer.stroke()
  107. ############ CURRENT TASK SCHEDULED #############
  108. # FIRST WE NEED TO GET A LIST OF TASKS
  109. # This is going to be a simplified version of the same stuff as in the
  110. # scheduling. But since we don't care what date we are in and trying to
  111. # get the oldest unchecked task. Here we go.
  112. schedules = schedule.get_schedules(win.analytics["dates"])
  113. new_date_format = "%Y/%m/%d"
  114. today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
  115. slist = []
  116. for date in schedules:
  117. for item in schedules[date]:
  118. if win.cur == item or not win.cur == "/set":
  119. slist.append([date, item, schedules[date][item]])
  120. # Now that we have our list we can start parsing it the same way as in the
  121. # scheduling. Only removing some unnesesary stuff.
  122. foundtask = False
  123. taskname = ""
  124. taskurl = ""
  125. taskcur = ""
  126. for entry in slist:
  127. if not foundtask:
  128. for thing in entry[2]:
  129. if thing[0][3] == "[Checked]":
  130. continue # We do not care about those who are checked here.
  131. elif thing[0][-1] != win.settings["Username"]:
  132. continue # We do not care if it's not for us
  133. else:
  134. foundtask = True
  135. # Here we are going to take out some data about this task
  136. # First if it's not for today let's get a color for it
  137. if entry[0] != "1997/07/30":
  138. draw = False
  139. if entry[0] < today:
  140. UI_color.set(layer, win, "node_badfile") # The Red
  141. draw = True
  142. elif entry[0] > today:
  143. UI_color.set(layer, win, "node_asset") # The Purple
  144. draw = True
  145. if draw:
  146. UI_elements.roundrect(layer, win,
  147. win.current["w"]/3*2+60,
  148. 5,
  149. (win.current["w"]/3-65),
  150. 40,
  151. 10)
  152. name = entry[1][entry[1].rfind("/")+1:]
  153. acur = entry[1].replace(name, "").replace("/", "")
  154. fullurl = ""
  155. for e in thing[0][4][:-1]:
  156. fullurl = fullurl+e+" > "
  157. if acur in ["chr", "veh", "loc", "obj"]:
  158. assetname = talk.text(acur)+": "+name
  159. else:
  160. assetname = entry[1]
  161. # ASSINGING TEXT VALUES
  162. taskname = thing[0][4][-1]
  163. taskurl = fullurl
  164. taskcur = assetname.replace("/set","")
  165. # AND A TINY BUTTON TO ENTER WHAT EVER YOU ARE DOING
  166. goto = "analytics"
  167. if acur in ["chr", "veh", "loc","obj"]:
  168. goto = "assets"
  169. itemtype = "assets"
  170. elif not acur:
  171. itemtype = "files"
  172. else:
  173. goto = "script"
  174. itemtype = "scenes"
  175. def do():
  176. win.url = goto
  177. win.cur = entry[1]
  178. win.current["asset_left_panel"] = "schedule"
  179. UI_elements.roundrect(layer, win,
  180. win.current["w"]/3*2+60,
  181. 5,
  182. (win.current["w"]/3-65),
  183. 40,
  184. 10,
  185. button=do)
  186. break
  187. else:
  188. break
  189. # Schedule
  190. if taskname:
  191. UI_elements.image(layer, win, "settings/themes/"\
  192. +win.settings["Theme"]+"/icons/schedule.png",
  193. win.current["w"]/3*2+60,
  194. 5,
  195. 40,
  196. 40)
  197. UI_color.set(layer, win, "text_normal")
  198. layer.set_font_size(20)
  199. layer.move_to(win.current["w"]/3*2+120, 25)
  200. layer.show_text(taskname)
  201. layer.set_font_size(12)
  202. layer.move_to(win.current["w"]/3*2+130+len(taskname)*12, 25)
  203. layer.show_text(taskurl)
  204. layer.set_font_size(12)
  205. layer.move_to(win.current["w"]/3*2+120, 40)
  206. layer.show_text(taskcur)
  207. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  208. fif = datetime.datetime.now()
  209. mil = fif - stf
  210. perfStat.append([ "Analytics", mil.microseconds ])
  211. stf = datetime.datetime.now()
  212. ###################################################################
  213. ###### LEFT PANNEL #######
  214. # New Scene
  215. def do():
  216. # Okay let's make the adding the scene possible.
  217. # First we need to know what scenes are there. So we don't overwrite
  218. # any existing scene.
  219. scenename = "Scene"
  220. count = 2
  221. while scenename in win.story["scenes"]:
  222. scenename = "Scene_"+str(count)
  223. count = count + 1
  224. # Now that we have an empty name. Let's add a scene.
  225. win.story["scenes"][scenename] = {
  226. "fraction":0.0, # Percentage
  227. "position":[
  228. win.current["mx"]-win.story["camera"][0]-50,
  229. win.current["my"]-win.story["camera"][1]-30
  230. ],
  231. "size":[100, 60],
  232. "parent":"", # For when it's in a Frame (Event)
  233. "shots":[[
  234. "text_block",[["text", '']]
  235. ]]
  236. }
  237. # Auto select the new scene
  238. win.story["selected"] = [["scene", scenename]]
  239. win.current["tool"] = "grab"
  240. # A hack I guess. I don't know what I'm doing. I'm trying to force
  241. # the motion on click.
  242. win.current["LMB"] = [win.current["mx"], win.current["my"], True]
  243. # In studio/studio_gtk.py there is a command that recognizes the length
  244. # of the LMB. And it's more then 2 it does some magic to make stuff move
  245. # without pressing the actuall key. It's slightly too clever even for me
  246. # so yeah.
  247. UI_elements.roundrect(layer, win,
  248. 5,
  249. 105,
  250. 40,
  251. 40,
  252. 10,
  253. do,
  254. "scene_new",
  255. talk.text("new_scene_tooltip")+"\n[N]",
  256. url="story_editor")
  257. # Shortcut
  258. if 110 in win.current["keys"] and not win.textactive:
  259. do()
  260. win.current["keys"] = []
  261. # Link Asset
  262. def do():
  263. def after(win, var):
  264. print (var)
  265. if var:
  266. win.story["links"].append([
  267. "asset", var, [
  268. win.current["mx"]-win.story["camera"][0]-75,
  269. win.current["my"]-win.story["camera"][1]-75
  270. ],
  271. "" # Parent
  272. ])
  273. # Now let's select and move the thing
  274. win.story["selected"] = [["asset", len(win.story["links"])-1]]
  275. win.current["tool"] = "grab"
  276. win.current["LMB"] = [win.current["mx"], win.current["my"], True]
  277. studio_dialogs.asset_select(win, "new_asset_story", after)
  278. UI_elements.roundrect(layer, win,
  279. 5,
  280. 155,
  281. 40,
  282. 40,
  283. 10,
  284. do,
  285. "obj_link",
  286. talk.text("link_asset_tooltip")+"\n[L]",
  287. url="story_editor")
  288. # Shortcut
  289. if 108 in win.current["keys"] and not win.textactive:
  290. do()
  291. win.current["keys"] = []
  292. # Link File
  293. def do():
  294. def after(win, var):
  295. if var:
  296. win.story["links"].append([
  297. "file", var, [
  298. win.current["mx"]-win.story["camera"][0]-75,
  299. win.current["my"]-win.story["camera"][1]-75
  300. ],
  301. "" # Parent
  302. ])
  303. # Now let's select and move the thing
  304. win.story["selected"] = [["file", len(win.story["links"])-1]]
  305. win.current["tool"] = "grab"
  306. win.current["LMB"] = [win.current["mx"], win.current["my"], True]
  307. studio_dialogs.file_select(win, "new_file_story", after, force=True)
  308. UI_elements.roundrect(layer, win,
  309. 5,
  310. 205,
  311. 40,
  312. 40,
  313. 10,
  314. do,
  315. "file_link",
  316. talk.text("link_file_tooltip")+"\n[I]",
  317. url="story_editor")
  318. # Shortcut
  319. if 105 in win.current["keys"] and not win.textactive:
  320. do()
  321. win.current["keys"] = []
  322. # Marker
  323. def do():
  324. markername = "Marker"
  325. count = 2
  326. while markername in win.story["markers"]:
  327. markername = "Marker_"+str(count)
  328. count = count + 1
  329. win.story["markers"][markername] = [
  330. win.current["mx"]-win.story["camera"][0]+50,
  331. win.current["my"]-win.story["camera"][1]-20,
  332. "" # Parent
  333. ]
  334. win.textactive = markername+"_marker"
  335. win.text[markername+"_marker"] = {
  336. "text" :markername, # Actuall text you are editing.
  337. "cursor":[len(str(markername)),len(str(markername))], # Cursor
  338. "insert":False, # Whether the insert mode is on
  339. "scroll":"markername_scroll" # If multiline. The pointer for the scroll value.
  340. }
  341. win.story["selected"] = [["marker", markername]]
  342. win.current["tool"] = "grab"
  343. win.current["LMB"] = [win.current["mx"], win.current["my"], True]
  344. UI_elements.roundrect(layer, win,
  345. 5,
  346. 255,
  347. 40,
  348. 40,
  349. 10,
  350. do,
  351. "pin",
  352. talk.text("marker_tooltip")+"\n[M]",
  353. url="story_editor")
  354. # Shortcut
  355. if 109 in win.current["keys"] and not win.textactive:
  356. do()
  357. win.current["keys"] = []
  358. if win.story["selected"]:
  359. # Event
  360. def do():
  361. eventname = "Event"
  362. count = 2
  363. while eventname in win.story["events"]:
  364. eventname = "Event_"+str(count)
  365. count = count + 1
  366. win.story["events"][eventname] = {
  367. "position":[0,0],
  368. "size":[0,0]
  369. }
  370. # Even going to delete it self if there will be noone who parenting
  371. # it.
  372. for thing in win.story["selected"]:
  373. if thing[0] == "scene":
  374. win.story["scenes"][thing[1]]["parent"] = eventname
  375. elif thing[0] in ["file", "asset"]:
  376. win.story["links"][thing[1]][3] = eventname
  377. elif thing[0] == "marker":
  378. win.story["markers"][thing[1]][2] = eventname
  379. UI_elements.roundrect(layer, win,
  380. 5,
  381. 305,
  382. 40,
  383. 40,
  384. 10,
  385. do,
  386. "event",
  387. talk.text("event_tooltip")+"\n[E]",
  388. url="story_editor")
  389. # Shortcut
  390. if 101 in win.current["keys"] and not win.textactive:
  391. do()
  392. win.current["keys"] = []
  393. # Renders
  394. def do():
  395. def after(win, var):
  396. pass
  397. studio_dialogs.render(win, "current_renders", after)
  398. UI_elements.roundrect(layer, win,
  399. 5,
  400. 405,
  401. 40,
  402. 40,
  403. 10,
  404. do,
  405. "render",
  406. talk.text("render_lists_tooltip"),
  407. url="story_editor")
  408. # Let's draw on top of this button a little indicator of how many renders
  409. # are currently setup.
  410. if win.renders:
  411. count = str(len(win.renders))
  412. UI_color.set(layer, win, "node_background")
  413. UI_elements.roundrect(layer, win,
  414. 30,
  415. 405,
  416. len(count)*12+6,
  417. 25,
  418. 5)
  419. layer.fill()
  420. UI_color.set(layer, win, "text_normal")
  421. layer.set_font_size(20)
  422. layer.move_to(33,425)
  423. layer.show_text(count)
  424. # Edit Video
  425. def do():
  426. def after(win, var):
  427. if var:
  428. print(var)
  429. oscalls.file_open(win, var)
  430. # Remote Server Stuff
  431. if win.analytics["from-remote-server"]:
  432. # Checking date [ FOLDER NAME ] [ FILES TO CHECK FOR ]
  433. check_folders = {"/rnd/" : "*"
  434. }
  435. check_updates = threading.Thread(target=http_client.get_folder_info,
  436. args=(win, check_folders, "vse", ))
  437. check_updates.setDaemon(True)
  438. check_updates.start()
  439. studio_dialogs.vse(win, "VSEs", after)
  440. UI_elements.roundrect(layer, win,
  441. 5,
  442. 455,
  443. 40,
  444. 40,
  445. 10,
  446. do,
  447. "vse",
  448. talk.text("vse_tooltip"),
  449. url="story_editor")
  450. # Export to ODT
  451. def do():
  452. story.export_to_odt(win)
  453. UI_elements.roundrect(layer, win,
  454. 5,
  455. 555,
  456. 40,
  457. 40,
  458. 10,
  459. do,
  460. "export",
  461. talk.text("export_tooltip"),
  462. url="story_editor")
  463. # Bottom
  464. # Backup launcher
  465. def do():
  466. os.system("gnome-terminal -- python3 "+os.getcwd()+"/studio/backup_blends.py "+win.project)
  467. UI_elements.roundrect(layer, win,
  468. 5,
  469. win.current["h"]-95,
  470. 40,
  471. 40,
  472. 10,
  473. do,
  474. "copy_file",
  475. talk.text("back_up_tooltip"),
  476. url="story_editor")
  477. # # Multiuser
  478. # def do():
  479. # win.url = "multiuser"
  480. # UI_elements.roundrect(layer, win,
  481. # 5,
  482. # win.current["h"]-95,
  483. # 40,
  484. # 40,
  485. # 10,
  486. # do,
  487. # "multiuser",
  488. # talk.text("multiuser_tooltip"),
  489. # url="story_editor")
  490. if win.multiuser["unread"]:
  491. count = str(win.multiuser["unread"])
  492. UI_color.set(layer, win, "node_background")
  493. UI_elements.roundrect(layer, win,
  494. 30,
  495. win.current["h"]-100,
  496. len(count)*12+6,
  497. 25,
  498. 5)
  499. layer.fill()
  500. UI_color.set(layer, win, "text_normal")
  501. layer.set_font_size(20)
  502. layer.move_to(33,win.current["h"]-83)
  503. layer.show_text(count)
  504. # Settings
  505. def do():
  506. win.url = "settings_layer"
  507. UI_elements.roundrect(layer, win,
  508. 5,
  509. win.current["h"]-45,
  510. 40,
  511. 40,
  512. 10,
  513. do,
  514. "settings",
  515. talk.text("Settings"),
  516. url="story_editor")
  517. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  518. fif = datetime.datetime.now()
  519. mil = fif - stf
  520. perfStat.append([ "Left Panel", mil.microseconds ])
  521. stf = datetime.datetime.now()
  522. ###################################################################
  523. ###### RIGHT PANNEL #######
  524. def select_character(win, var):
  525. if var:
  526. win.url = "assets"
  527. win.cur = var
  528. win.current["tool"] = "selection"
  529. # Characters
  530. def do():
  531. studio_dialogs.asset_select(win, "new_asset_story", select_character, force=True, cur="chr")
  532. # Remote Server Stuff
  533. if win.analytics["from-remote-server"]:
  534. def after(win, var):
  535. pass
  536. studio_dialogs.http_client_dialog(win, "http-client", after, http_client.get_folders, "/dev/chr")
  537. UI_elements.roundrect(layer, win,
  538. win.current["w"]-45,
  539. 105,
  540. 40,
  541. 40,
  542. 10,
  543. do,
  544. "chr",
  545. talk.text("chr")+"\n[Shift-C]",
  546. url="story_editor")
  547. # Shortcut
  548. if 67 in win.current["keys"] and not win.textactive:
  549. do()
  550. win.current["keys"] = []
  551. # Vehicles
  552. def do():
  553. studio_dialogs.asset_select(win, "new_asset_story", select_character, force=True, cur="veh")
  554. # Remote Server Stuff
  555. if win.analytics["from-remote-server"]:
  556. def after(win, var):
  557. pass
  558. studio_dialogs.http_client_dialog(win, "http-client", after, http_client.get_folders, "/dev/veh")
  559. UI_elements.roundrect(layer, win,
  560. win.current["w"]-45,
  561. 155,
  562. 40,
  563. 40,
  564. 10,
  565. do,
  566. "veh",
  567. talk.text("veh")+"\n[Shift-V]",
  568. url="story_editor")
  569. # Shortcut
  570. if 86 in win.current["keys"] and not win.textactive:
  571. do()
  572. win.current["keys"] = []
  573. # Locations
  574. def do():
  575. studio_dialogs.asset_select(win, "new_asset_story", select_character, force=True, cur="loc")
  576. # Remote Server Stuff
  577. if win.analytics["from-remote-server"]:
  578. def after(win, var):
  579. pass
  580. studio_dialogs.http_client_dialog(win, "http-client", after, http_client.get_folders, "/dev/loc")
  581. UI_elements.roundrect(layer, win,
  582. win.current["w"]-45,
  583. 205,
  584. 40,
  585. 40,
  586. 10,
  587. do,
  588. "loc",
  589. talk.text("loc")+"\n[Shift-L]",
  590. url="story_editor")
  591. # Shortcut
  592. if 76 in win.current["keys"] and not win.textactive:
  593. do()
  594. win.current["keys"] = []
  595. # Other (obj)
  596. def do():
  597. studio_dialogs.asset_select(win, "new_asset_story", select_character, force=True, cur="obj")
  598. # Remote Server Stuff
  599. if win.analytics["from-remote-server"]:
  600. def after(win, var):
  601. pass
  602. studio_dialogs.http_client_dialog(win, "http-client", after, http_client.get_folders, "/dev/obj")
  603. UI_elements.roundrect(layer, win,
  604. win.current["w"]-45,
  605. 255,
  606. 40,
  607. 40,
  608. 10,
  609. do,
  610. "obj",
  611. talk.text("obj")+"\n[Shift-O]",
  612. url="story_editor")
  613. # Shortcut
  614. if 79 in win.current["keys"] and not win.textactive:
  615. do()
  616. win.current["keys"] = []
  617. # Sounds / Music
  618. def do():
  619. os.system("xdg-open "+win.project+"/mus")
  620. UI_elements.roundrect(layer, win,
  621. win.current["w"]-45,
  622. 355,
  623. 40,
  624. 40,
  625. 10,
  626. do,
  627. "mus",
  628. talk.text("mus"),
  629. url="story_editor")
  630. # Help
  631. def do():
  632. def after(win, var):
  633. pass
  634. studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_story_editor"))
  635. UI_elements.roundrect(layer, win,
  636. win.current["w"]-45,
  637. win.current["h"]-125,
  638. 40,
  639. 40,
  640. 10,
  641. do,
  642. "question",
  643. url="story_editor")
  644. # Folder
  645. def do():
  646. os.system("xdg-open "+win.project)
  647. UI_elements.roundrect(layer, win,
  648. win.current["w"]-45,
  649. win.current["h"]-75,
  650. 40,
  651. 40,
  652. 10,
  653. do,
  654. "folder",
  655. talk.text("project_folder"),
  656. url="story_editor")
  657. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  658. fif = datetime.datetime.now()
  659. mil = fif - stf
  660. perfStat.append([ "Right Pannel", mil.microseconds ])
  661. stf = datetime.datetime.now()
  662. ###################################################################
  663. if win.url == "story_editor"\
  664. and int(win.current["mx"]) in range(50, int(win.current["w"]-50)) \
  665. and int(win.current["my"]) in range(50, int(win.current["h"]-30)):
  666. # The cross cursor
  667. win.current["cursor"] = win.cursors["cross"]
  668. ####### NODES #######
  669. # Clipping so it wont draw beyon the frame
  670. UI_elements.roundrect(layer, win,
  671. 50,
  672. 50,
  673. win.current["w"] - 100,
  674. win.current["h"] - 80,
  675. 30,
  676. fill=False)
  677. layer.clip()
  678. # Background Image
  679. if os.path.exists(win.project+"/set/banner.png"):
  680. UI_elements.image(layer, win, win.project+"/set/banner.png",
  681. 50,
  682. 50,
  683. win.current["w"] - 100,
  684. win.current["h"] - 80,
  685. cell="background")
  686. elif os.path.exists(win.project+"/py_data/banner.png"):
  687. UI_elements.image(layer, win, win.project+"/py_data/banner.png",
  688. 50,
  689. 50,
  690. win.current["w"] - 100,
  691. win.current["h"] - 80,
  692. cell="background")
  693. else:
  694. UI_elements.image(layer, win, "icon.png",
  695. 50,
  696. 50,
  697. win.current["w"] - 100,
  698. win.current["h"] - 80,
  699. cell="background")
  700. UI_color.set(layer, win, "node_background")
  701. layer.rectangle(0,0,win.current["w"], win.current["h"])
  702. layer.fill()
  703. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  704. fif = datetime.datetime.now()
  705. mil = fif - stf
  706. perfStat.append([ "Background Image", mil.microseconds ])
  707. stf = datetime.datetime.now()
  708. ###################################################################
  709. # You probably intersted where is the scroll function for this part. Well
  710. # see there is a thing. It's easier to write one from screach here. Because
  711. # you geassed it we are starting to draw story editor.
  712. # Let's prepare the camera first.
  713. # Animation
  714. win.story["camera"][0] = UI_elements.animate("cameraX", win, 0, win.story["camera"][0])
  715. win.story["camera"][1] = UI_elements.animate("cameraY", win, 0, win.story["camera"][1])
  716. cx, cy = win.story["camera"]
  717. if win.url == "story_editor":
  718. if win.current["MMB"]:
  719. win.story["camera"][0] += ( win.current["mx"]-win.previous["mx"])
  720. win.story["camera"][1] += ( win.current["my"]-win.previous["my"])
  721. win.story["camera"][0] -= win.current["scroll"][0]*50
  722. win.story["camera"][1] -= win.current["scroll"][1]*50
  723. if cx != win.story["camera"][0] or cy != win.story["camera"][1]:
  724. UI_elements.animate("cameraX", win, win.story["camera"][0], force=True)
  725. UI_elements.animate("cameraY", win, win.story["camera"][1], force=True)
  726. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  727. fif = datetime.datetime.now()
  728. mil = fif - stf
  729. perfStat.append([ "Camera position", mil.microseconds ])
  730. stf = datetime.datetime.now()
  731. ###################################################################
  732. # EVENTS (Frames)
  733. try:
  734. for event in win.story["events"]:
  735. # Loaction
  736. sx, sy = win.story["events"][event]["position"]
  737. # Scale
  738. ssx, ssy = win.story["events"][event]["size"]
  739. #Draw
  740. studio_nodes.event_node(layer, win, sx, sy, ssx, ssy, name=event)
  741. # Let's now check if the event even has anybody inside. It's a bit
  742. # not the best way to implement it yet. Because I will need to look
  743. # through all items. But we can make it simpler if we find that it has
  744. # we can just break out of a thing.
  745. found = False
  746. for scene in win.story["scenes"]:
  747. if event == win.story["scenes"][scene]["parent"]:
  748. found = True
  749. break
  750. if not found:
  751. for link in win.story["links"]:
  752. if event == link[3]:
  753. found = True
  754. break
  755. if not found:
  756. for marker in win.story["markers"]:
  757. if event == win.story["markers"][marker][2]:
  758. found = True
  759. break
  760. # If nobody is inside. Delete the bastard.
  761. if not found:
  762. del win.story["events"][event]
  763. except:
  764. pass
  765. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  766. fif = datetime.datetime.now()
  767. mil = fif - stf
  768. perfStat.append([ "Events", mil.microseconds ])
  769. stf = datetime.datetime.now()
  770. ###################################################################
  771. # SCENES
  772. try:
  773. for scene in win.story["scenes"]:
  774. # Loaction
  775. sx, sy = win.story["scenes"][scene]["position"]
  776. sx = sx + cx
  777. sy = sy + cy
  778. # Scale
  779. ssx, ssy = win.story["scenes"][scene]["size"]
  780. #Fraction
  781. sf = win.story["scenes"][scene]["fraction"]
  782. #Draw
  783. studio_nodes.scene_node(layer, win, sx, sy, ssx, ssy, name=scene, fraction=sf, shots=win.story["scenes"][scene]["shots"])
  784. except:
  785. pass
  786. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  787. fif = datetime.datetime.now()
  788. mil = fif - stf
  789. perfStat.append([ "Scenes", mil.microseconds ])
  790. stf = datetime.datetime.now()
  791. ###################################################################
  792. # LINKS (Images, Stuff)
  793. for num, link in enumerate(win.story["links"]):
  794. linktype = link[0]
  795. linkname = link[1]
  796. lx = link[2][0] + cx
  797. ly = link[2][1] + cy
  798. # For the one inside the project. They should be always relative
  799. # so even if the project is in a complitely different location
  800. # on another machine. Where we have our Multiuser data. It should
  801. # be able to load these.
  802. if win.project in link[1]:
  803. link[1] = link[1].replace(win.project, "")
  804. studio_nodes.link_node(layer, win, lx, ly, name=linkname, num=num, linktype=linktype )
  805. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  806. fif = datetime.datetime.now()
  807. mil = fif - stf
  808. perfStat.append([ "Files / Assets", mil.microseconds ])
  809. stf = datetime.datetime.now()
  810. ###################################################################
  811. # Let's put in the start and the end nodes. These are drawn on top of
  812. # everything.
  813. studio_nodes.start_node(layer, win, 60,60,100,40)
  814. studio_nodes.end_node(layer, win, win.current["w"] - 160,
  815. win.current["h"] - 80,
  816. 100,40)
  817. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  818. fif = datetime.datetime.now()
  819. mil = fif - stf
  820. perfStat.append([ "Start / End Nodes", mil.microseconds ])
  821. stf = datetime.datetime.now()
  822. ###################################################################
  823. # MARKERS
  824. try:
  825. for marker in win.story["markers"]:
  826. mx = win.story["markers"][marker][0] + cx
  827. my = win.story["markers"][marker][1] + cy
  828. studio_nodes.marker(layer, win, marker, mx, my)
  829. except:
  830. pass
  831. # MARKERS
  832. try:
  833. for user in win.multiuser["users"]:
  834. if user != win.multiuser["userid"]:
  835. mx = 0-win.multiuser["users"][user]["camera"][0] +cx + win.current["w"]/2
  836. my = 0-win.multiuser["users"][user]["camera"][1] +cy + win.current["h"]/2
  837. studio_nodes.user(layer, win, win.multiuser["users"][user]["username"], mx, my, user)
  838. except Exception as e:
  839. print(e, "USER RENDERING")
  840. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  841. fif = datetime.datetime.now()
  842. mil = fif - stf
  843. perfStat.append([ "Markers", mil.microseconds ])
  844. stf = datetime.datetime.now()
  845. ###################################################################
  846. # In case there is a selection bug
  847. if not win.story["selected"] and win.current["tool"] != "connect":
  848. win.current["tool"] = "selection"
  849. # Selector visualization
  850. if win.current["LMB"] and win.current["tool"] == "selection" and win.url == "story_editor":
  851. # Draw selection box
  852. UI_color.set(layer, win, "progress_background")
  853. layer.rectangle(
  854. win.current["mx"],
  855. win.current["my"],
  856. win.current["LMB"][0] - win.current["mx"],
  857. win.current["LMB"][1] - win.current["my"]
  858. )
  859. layer.stroke()
  860. # Now let's draw the cool AF multi selection zone thingy
  861. # Draw selection box
  862. if len(win.story["selected"]) > 1 and win.current["tool"] == "selection":
  863. UI_color.set(layer, win, "progress_background")
  864. layer.rectangle(
  865. win.szone[0][0]-10,
  866. win.szone[0][1]-10,
  867. win.szone[1][0]+20,
  868. win.szone[1][1]+20
  869. )
  870. layer.stroke()
  871. # Now I want to make a tiny widget that will resize the stuff.
  872. if win.story["selected"]:
  873. if win.current["tool"] == "selection":
  874. draw_circle = True
  875. if len(win.story["selected"]) == 1:
  876. if win.story["selected"][0][0] != "scene":
  877. draw_circle = False
  878. if draw_circle:
  879. UI_color.set(layer, win, "node_badfile")
  880. UI_elements.roundrect(layer, win,
  881. win.szone[0][0]+win.szone[1][0],
  882. win.szone[0][1]+win.szone[1][1],
  883. 0,
  884. 0,
  885. 10)
  886. UI_color.set(layer, win, "progress_background")
  887. UI_elements.roundrect(layer, win,
  888. win.szone[0][0]+win.szone[1][0],
  889. win.szone[0][1]+win.szone[1][1],
  890. 0,
  891. 0,
  892. 10,
  893. fill=False)
  894. layer.stroke()
  895. elif win.current["tool"] == "scale":
  896. UI_color.set(layer, win, "node_badfile")
  897. UI_elements.roundrect(layer, win,
  898. win.current["mx"]-10,
  899. win.current["my"]-10,
  900. 0,
  901. 0,
  902. 10)
  903. UI_color.set(layer, win, "progress_background")
  904. UI_elements.roundrect(layer, win,
  905. win.current["mx"]-10,
  906. win.current["my"]-10,
  907. 0,
  908. 0,
  909. 10,
  910. fill=False)
  911. layer.stroke()
  912. if int(win.current["mx"]) in range(int(win.szone[0][0]+win.szone[1][0]), int(win.szone[0][0]+win.szone[1][0]+20))\
  913. and int(win.current["my"]) in range(int(win.szone[0][1]+win.szone[1][1]), int(win.szone[0][1]+win.szone[1][1]+20))\
  914. and win.current["tool"] == "selection":
  915. UI_color.set(layer, win, "text_normal")
  916. UI_elements.roundrect(layer, win,
  917. win.szone[0][0]+win.szone[1][0],
  918. win.szone[0][1]+win.szone[1][1],
  919. 0,
  920. 0,
  921. 10,
  922. fill=False)
  923. layer.stroke()
  924. win.current["cursor"] = win.cursors["arrow"]
  925. if win.current["LMB"] and not win.previous["LMB"]:
  926. win.current["tool"] = "scale"
  927. if win.current["tool"] == "scale" and not win.current["LMB"]:
  928. win.current["tool"] = "selection"
  929. # Canceling seletion. I move it here so it would not interfire with the
  930. # the rest of the program.
  931. if win.current["LMB"] and win.current["tool"] == "selection" and win.url == "story_editor":
  932. # Undo selection
  933. if int(win.current["LMB"][0] - win.current["mx"]) in range(-10, 10)\
  934. and int(win.current["LMB"][1] - win.current["my"])in range(-10, 10)\
  935. and int(win.current["mx"]) in range(50, int(win.current["w"]-50)) \
  936. and int(win.current["my"]) in range(50, int(win.current["h"]-30))\
  937. and 65505 not in win.current["keys"]:
  938. win.story["selected"] = []
  939. win.textactive = ""
  940. # Let's draw the line while connecting 2 scenes together.
  941. if win.current["tool"] == "connect":
  942. win.current["cursor"] = win.cursors["arrow"]
  943. if not win.current["LMB"]:
  944. win.current["tool"] = "selection"
  945. fr = win.current["draw_dot"]
  946. if type(fr) == list:
  947. fr = fr[0]+":"+fr[1]
  948. try:
  949. UI_color.set(layer, win, "node_script")
  950. layer.move_to(
  951. win.out_dots[fr][0],
  952. win.out_dots[fr][1]
  953. )
  954. layer.line_to(win.current["mx"], win.current["my"])
  955. layer.stroke()
  956. except:
  957. pass
  958. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  959. fif = datetime.datetime.now()
  960. mil = fif - stf
  961. perfStat.append([ "Selection", mil.microseconds ])
  962. stf = datetime.datetime.now()
  963. ###################################################################
  964. # The undo history is quite a new adition so the limit setting might
  965. # not exists. So let's make it if so.
  966. if "Undo_Limit" not in win.settings:
  967. win.settings["Undo_Limit"] = 32
  968. settings.write("Undo_Limit", 32)
  969. if win.animations["cameraX"][1] == cx:
  970. win.current["camera_arrived"] = True
  971. else:
  972. win.current["camera_arrived"] = False
  973. # Save story. I'm going to do it the same way as in the old Blender-Organizer
  974. if win.url == "story_editor":
  975. savenow = False
  976. if win.previous["LMB"] and not win.current["LMB"]:
  977. savenow = True
  978. elif win.previous["RMB"] and not win.current["RMB"]:
  979. savenow = True
  980. elif win.previous["MMB"] and not win.current["MMB"]:
  981. savenow = True
  982. elif win.previous["keys"] and not win.current["keys"]:
  983. savenow = True
  984. elif win.current["camera_arrived"] and not win.previous["camera_arrived"]:
  985. savenow = True
  986. if savenow:
  987. win.current["cursor"] = win.cursors["watch"]
  988. # Now let's run the history record.
  989. story.undo_record(win)
  990. story.save(win.project, win.story)
  991. analytics.save(win.project, win.analytics)
  992. # Need to reload the story to reload the fractions of the scenes.
  993. win.story = story.load(win.project)
  994. # Multiuser sycning
  995. win.multiuser["request"] = "story"
  996. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  997. fif = datetime.datetime.now()
  998. mil = fif - stf
  999. perfStat.append([ "File Saving", mil.microseconds ])
  1000. stf = datetime.datetime.now()
  1001. ###################################################################
  1002. # To selected
  1003. if 65454 in win.current["keys"] and win.story["selected"] and not win.textactive:
  1004. nex = cx-win.szone[0][0] - win.szone[1][0]/2 + win.current["w"]/2
  1005. ney = cy-win.szone[0][1] - win.szone[1][1]/2 + win.current["h"]/2
  1006. UI_elements.animate("cameraX", win, win.story["camera"][0],nex, force=True)
  1007. UI_elements.animate("cameraY", win, win.story["camera"][1],ney, force=True)
  1008. # Undo
  1009. if 65507 in win.current["keys"] and 122 in win.current["keys"] and not win.textactive:
  1010. story.undo(win)
  1011. win.current["keys"] = []
  1012. # Redo
  1013. if 65507 in win.current["keys"] and 121 in win.current["keys"] and not win.textactive:
  1014. story.redo(win)
  1015. win.current["keys"] = []
  1016. # Grab
  1017. if 103 in win.current["keys"] and win.story["selected"] and not win.textactive:
  1018. win.current["tool"] = "grab"
  1019. win.current["LMB"] = [win.current["mx"], win.current["my"], True]
  1020. # Scale
  1021. if 115 in win.current["keys"] and win.story["selected"] and not win.textactive:
  1022. win.current["tool"] = "scale"
  1023. win.current["LMB"] = [win.current["mx"], win.current["my"], True]
  1024. # Deletion
  1025. if 65535 in win.current["keys"] and win.current["tool"] == "selection"\
  1026. and win.url == "story_editor" and win.story["selected"] and not win.textactive:
  1027. win.url = "story_deletion_dialog"
  1028. # Enter
  1029. if 65293 in win.current["keys"] and win.current["tool"] == "selection":
  1030. print(win.story["selected"])
  1031. if win.story["selected"][0][0] == "scene":
  1032. win.url = "script"
  1033. win.cur = "/"+win.story["selected"][0][1]
  1034. win.current["tool"] = "selection"
  1035. win.current["keys"].remove(65293)
  1036. # Right
  1037. if 65363 in win.current["keys"] and win.current["tool"] == "selection":
  1038. try:
  1039. if win.story["selected"][0][0] == "scene":
  1040. scene = win.story["selected"][0][1]
  1041. for arrow in win.story["arrows"]:
  1042. if arrow[0][1] == scene and arrow[1] != "end":
  1043. win.story["selected"] = [["scene", arrow[1][1]]]
  1044. win.story["active"] = ["scene", arrow[1][1]]
  1045. nex = 0-win.story["scenes"][arrow[1][1]]["position"][0] + win.current["w"]/2
  1046. ney = 0-win.story["scenes"][arrow[1][1]]["position"][1] + win.current["h"]/2
  1047. UI_elements.animate("cameraX", win, win.story["camera"][0],nex, time=20, force=True)
  1048. UI_elements.animate("cameraY", win, win.story["camera"][1],ney, time=20, force=True)
  1049. win.current["keys"].remove(65363)
  1050. except:
  1051. pass
  1052. # Left
  1053. if 65361 in win.current["keys"] and win.current["tool"] == "selection":
  1054. try:
  1055. if win.story["selected"][0][0] == "scene":
  1056. scene = win.story["selected"][0][1]
  1057. for arrow in win.story["arrows"]:
  1058. if arrow[1][1] == scene and arrow[0] != "start":
  1059. win.story["selected"] = [["scene", arrow[0][1]]]
  1060. win.story["active"] = ["scene", arrow[0][1]]
  1061. nex = 0-win.story["scenes"][arrow[0][1]]["position"][0] + win.current["w"]/2
  1062. ney = 0-win.story["scenes"][arrow[0][1]]["position"][1] + win.current["h"]/2
  1063. UI_elements.animate("cameraX", win, win.story["camera"][0],nex, time=20, force=True)
  1064. UI_elements.animate("cameraY", win, win.story["camera"][1],ney, time=20, force=True)
  1065. win.current["keys"].remove(65361)
  1066. except:
  1067. pass
  1068. ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
  1069. fif = datetime.datetime.now()
  1070. mil = fif - stf
  1071. perfStat.append([ "Short Cuts", mil.microseconds ])
  1072. stf = datetime.datetime.now()
  1073. ###################################################################
  1074. ############### PERFORMCE TESTING GROUND ##############
  1075. if win.current["testing"]:
  1076. h = win.current["h"]+200
  1077. w = win.current["w"]
  1078. UI_color.set(layer, win, "darker_parts")
  1079. UI_elements.roundrect(layer, win,100, h-(len(perfStat)*15)-30-300, 500,len(perfStat)*15+30, 10)
  1080. l = 0
  1081. s = 0
  1082. for i in perfStat:
  1083. if int(i[1]) > l:
  1084. l = int(i[1])
  1085. s = s + int(i[1])
  1086. for n, i in enumerate(perfStat):
  1087. #UI_color.set(layer, win, "progress_background")
  1088. #UI_elements.roundrect(layer, win, 110 + 270, h-(len(perfStat)*15)-20+10+15*n-300, 200,10, 5)
  1089. layer.set_source_rgb(1,1,1)
  1090. if int(i[1]) == l:
  1091. layer.set_source_rgb(1,0,0)
  1092. elif int(i[1]) < 1000:
  1093. layer.set_source_rgb(0,1,0)
  1094. layer.set_font_size(10)
  1095. layer.move_to( 110, h-(len(perfStat)*15)+15*n-300)
  1096. p = float(i[1]) / s *100
  1097. layer.show_text(str(i[0])+" - "+str(i[1])+" MCRS "+str(int(round(p)))+"%")
  1098. #UI_color.set(layer, win, "progress_active")
  1099. UI_elements.roundrect(layer, win, 110 + 270, h-(len(perfStat)*15)-20+10+15*n-300, int(round(p))*2,10, 5)
  1100. return surface