studio_analyticsLayer.py 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058
  1. # THIS FILE IS A PART OF VCStudio
  2. # PYTHON 3
  3. # This a console project manager.
  4. import os
  5. import datetime
  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 talk
  16. from settings import fileformats
  17. from settings import oscalls
  18. from project_manager import pm_project
  19. #UI modules
  20. from UI import UI_elements
  21. from UI import UI_color
  22. # story
  23. from studio import story
  24. from studio import checklist
  25. from studio import analytics
  26. from studio import studio_dialogs
  27. from studio import schedule
  28. from studio import history
  29. def layer(win):
  30. # Making the layer
  31. surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'],
  32. win.current['h'])
  33. layer = cairo.Context(surface)
  34. #text setting
  35. layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  36. UI_color.set(layer, win, "dark_overdrop")
  37. layer.rectangle(
  38. 0,
  39. 0,
  40. win.current["w"],
  41. win.current["h"],
  42. )
  43. layer.fill()
  44. UI_color.set(layer, win, "node_background")
  45. UI_elements.roundrect(layer, win,
  46. win.current["w"]/4,
  47. 10,
  48. win.current["w"]/2,
  49. win.current["h"]-20,
  50. 10)
  51. ############################################################################
  52. # This is the Analitycs window. This time I want to do something crazy.
  53. # There will be 5 sections on the screen.
  54. ############################################################################
  55. # # # #
  56. # # # #
  57. # # PROGRESS BARS # #
  58. # # # #
  59. # # # #
  60. # # ####################################### # #
  61. # # # #
  62. # SCHEDULING # ANALYTICS GRAPH # MAIN #
  63. # # # CHECKLIS #
  64. # # # #
  65. # # ####################################### # #
  66. # # # #
  67. # # CALENDAR / DAY SELECTOR # #
  68. # # # #
  69. # # X # #
  70. ############################################################################
  71. # The idea is that you could be in Assets or Script Editor and drag the
  72. # tasks from the checklist down to Calendar and leave it there. So when you
  73. # move the task and mouse comes into the center part, you automatically
  74. # transferred to the analytics layer for untill you leave the task somewhere
  75. # or return it back to the checklist.
  76. # I want to do the same with the SCHEDULING. So you could simple drag it to
  77. # the Calendar to change it's date. Let's see how terribly hard will it be
  78. # to implement. Because I'm already fighting with the Scedules all day.
  79. ############################################################################
  80. ############## PROGRESS BARS #############
  81. timepassed = 0.0
  82. projectdone = 0.0
  83. chrdone = 0.0
  84. vehdone = 0.0
  85. locdone = 0.0
  86. objdone = 0.0
  87. rnddone = 0.0
  88. try:
  89. timepassed = win.analytics["timepassed"]
  90. projectdone = win.analytics["fraction"]
  91. chrdone = win.analytics["chr"]
  92. vehdone = win.analytics["veh"]
  93. locdone = win.analytics["loc"]
  94. objdone = win.analytics["obj"]
  95. rnddone = win.analytics["rnd"]
  96. except:
  97. pass
  98. # MAIN PROGRESS
  99. # Icon
  100. UI_elements.image(layer, win, "settings/themes/"\
  101. +win.settings["Theme"]+"/icons/analytics.png",
  102. win.current["w"]/4+10,
  103. 15,
  104. 40,
  105. 40)
  106. # Progressbar
  107. UI_color.set(layer, win, "progress_background")
  108. UI_elements.roundrect(layer, win,
  109. win.current["w"]/4+60,
  110. 25,
  111. win.current["w"]/2-80,
  112. 20,
  113. 10)
  114. # Project Done
  115. UI_color.set(layer, win, "progress_active")
  116. UI_elements.roundrect(layer, win,
  117. win.current["w"]/4+60,
  118. 25,
  119. (win.current["w"]/2-80)*projectdone,
  120. 20,
  121. 10)
  122. # TIME PASSED
  123. # Icon
  124. UI_elements.image(layer, win, "settings/themes/"\
  125. +win.settings["Theme"]+"/icons/schedule.png",
  126. win.current["w"]/4+10,
  127. 55,
  128. 40,
  129. 40)
  130. UI_color.set(layer, win, "progress_background")
  131. UI_elements.roundrect(layer, win,
  132. win.current["w"]/4+60,
  133. 65,
  134. win.current["w"]/2-80,
  135. 20,
  136. 10)
  137. # Timepassed
  138. UI_color.set(layer, win, "progress_time")
  139. UI_elements.roundrect(layer, win,
  140. win.current["w"]/4+60,
  141. 65,
  142. (win.current["w"]/2-80)*timepassed,
  143. 20,
  144. 10)
  145. # SCENES DONE ( RND )
  146. # Icon
  147. UI_elements.image(layer, win, "settings/themes/"\
  148. +win.settings["Theme"]+"/icons/scene.png",
  149. win.current["w"]/4+10,
  150. 95,
  151. 40,
  152. 40)
  153. UI_color.set(layer, win, "progress_background")
  154. UI_elements.roundrect(layer, win,
  155. win.current["w"]/4+60,
  156. 105,
  157. win.current["w"]/2-80,
  158. 20,
  159. 10)
  160. # Scenes
  161. UI_color.set(layer, win, "node_videofile")
  162. UI_elements.roundrect(layer, win,
  163. win.current["w"]/4+60,
  164. 105,
  165. (win.current["w"]/2-80)*rnddone,
  166. 20,
  167. 10)
  168. # CHR DONE
  169. # Icon
  170. UI_elements.image(layer, win, "settings/themes/"\
  171. +win.settings["Theme"]+"/icons/chr.png",
  172. win.current["w"]/4+10,
  173. 135,
  174. 40,
  175. 40)
  176. UI_color.set(layer, win, "progress_background")
  177. UI_elements.roundrect(layer, win,
  178. win.current["w"]/4+60,
  179. 145,
  180. win.current["w"]/4-80,
  181. 20,
  182. 10)
  183. # progress
  184. UI_color.set(layer, win, "node_asset")
  185. UI_elements.roundrect(layer, win,
  186. win.current["w"]/4+60,
  187. 145,
  188. (win.current["w"]/4-80)*chrdone,
  189. 20,
  190. 10)
  191. # VEH DONE
  192. # Icon
  193. UI_elements.image(layer, win, "settings/themes/"\
  194. +win.settings["Theme"]+"/icons/veh.png",
  195. win.current["w"]/2,
  196. 135,
  197. 40,
  198. 40)
  199. UI_color.set(layer, win, "progress_background")
  200. UI_elements.roundrect(layer, win,
  201. win.current["w"]/2+60,
  202. 145,
  203. win.current["w"]/4-80,
  204. 20,
  205. 10)
  206. # progress
  207. UI_color.set(layer, win, "node_imagefile")
  208. UI_elements.roundrect(layer, win,
  209. win.current["w"]/2+60,
  210. 145,
  211. (win.current["w"]/4-80)*vehdone,
  212. 20,
  213. 10)
  214. # LOC DONE
  215. # Icon
  216. UI_elements.image(layer, win, "settings/themes/"\
  217. +win.settings["Theme"]+"/icons/loc.png",
  218. win.current["w"]/4+10,
  219. 175,
  220. 40,
  221. 40)
  222. UI_color.set(layer, win, "progress_background")
  223. UI_elements.roundrect(layer, win,
  224. win.current["w"]/4+60,
  225. 185,
  226. win.current["w"]/4-80,
  227. 20,
  228. 10)
  229. # progress
  230. UI_color.set(layer, win, "node_blendfile")
  231. UI_elements.roundrect(layer, win,
  232. win.current["w"]/4+60,
  233. 185,
  234. (win.current["w"]/4-80)*locdone,
  235. 20,
  236. 10)
  237. # OBJ DONE
  238. # Icon
  239. UI_elements.image(layer, win, "settings/themes/"\
  240. +win.settings["Theme"]+"/icons/obj.png",
  241. win.current["w"]/2,
  242. 175,
  243. 40,
  244. 40)
  245. UI_color.set(layer, win, "progress_background")
  246. UI_elements.roundrect(layer, win,
  247. win.current["w"]/2+60,
  248. 185,
  249. win.current["w"]/4-80,
  250. 20,
  251. 10)
  252. # progress
  253. UI_color.set(layer, win, "node_badfile")
  254. UI_elements.roundrect(layer, win,
  255. win.current["w"]/2+60,
  256. 185,
  257. (win.current["w"]/4-80)*objdone,
  258. 20,
  259. 10)
  260. ############### THE GRAPH ##################
  261. # This graph going to show the entire time of the whole project from
  262. # StartDate till Deadline. It will fill up with data overtime.
  263. # We are going to have a couple of modes.
  264. # Regular mode: Showing actuall values represented on the graph
  265. # it's going to be a diagonal line if the work was done
  266. # linearly.
  267. # Normalized : This this a graph of true values compared to time. So let's
  268. # say at a second day you had to be only at 3%. Being at 3% will
  269. # make graph show 100%. The expected value is linear from 0%
  270. # to 100% over the whole project.
  271. # Pulse mode : This mode will give a graph compared to the previous day.
  272. # if on a given day there was a gib jump in percentage there
  273. # will be a big spike on the graph.
  274. # Let's make a mode selector.
  275. if "analytics_middle_graph_mode" not in win.current:
  276. win.current["analytics_middle_graph_mode"] = "pulse"
  277. for num, thing in enumerate(["linear", "analytics", "pulse"]): # By icons
  278. if win.current["analytics_middle_graph_mode"] == thing:
  279. UI_color.set(layer, win, "progress_time")
  280. UI_elements.roundrect(layer, win,
  281. win.current["w"]/4+10+(40*num),
  282. 225,
  283. 40,
  284. 40,
  285. 10)
  286. def do():
  287. win.current["analytics_middle_graph_mode"] = thing
  288. del win.current["graph_cashe"]
  289. UI_elements.roundrect(layer, win,
  290. win.current["w"]/4+10+(40*num),
  291. 225,
  292. 40,
  293. 40,
  294. 10,
  295. do,
  296. thing)
  297. # And before we start a little settings icon.
  298. # Documentation entry
  299. def do():
  300. def after(win, var):
  301. pass
  302. studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_analytics"))
  303. UI_elements.roundrect(layer, win,
  304. win.current["w"]/4*3-110,
  305. 225,
  306. 40,
  307. 40,
  308. 10,
  309. do,
  310. "question")
  311. # Settings
  312. def do():
  313. win.url = "settings_layer"
  314. UI_elements.roundrect(layer, win,
  315. win.current["w"]/4*3-60,
  316. 225,
  317. 40,
  318. 40,
  319. 10,
  320. do,
  321. "settings",
  322. talk.text("Settings"))
  323. # Now let's make a filter by type. As you maybe already know appart from
  324. # the main progress I'm reading all the other things too. Every progress
  325. # bar on the screen should have a corrisponding graph. But sometimes if
  326. # paths go too far appart, this aint helpfull. So a filter is required to
  327. # switch a category on and off.
  328. if "analytics_middle_graph_switch" not in win.current:
  329. win.current["analytics_middle_graph_switch"] = {
  330. "project":[True,"analytics", "progress_active"],
  331. "checklist":[True,"checklist", "darker_parts"],
  332. "rnd":[True,"scene", "node_videofile"],
  333. "chr":[True,"chr", "node_asset"],
  334. "veh":[True,"veh", "node_imagefile"], # Name in data : [ Active, Icon name, color ]
  335. "loc":[True,"loc", "node_blendfile"],
  336. "obj":[True,"obj", "node_badfile"]
  337. }
  338. cat = win.current["analytics_middle_graph_switch"]
  339. mode = win.current["analytics_middle_graph_mode"]
  340. for num, thing in enumerate(cat):
  341. if cat[thing][0]:
  342. UI_color.set(layer, win, cat[thing][2])
  343. UI_elements.roundrect(layer, win,
  344. win.current["w"]/4+160+(40*num),
  345. 225,
  346. 40,
  347. 40,
  348. 10)
  349. def do():
  350. cat[thing][0] = not cat[thing][0]
  351. del win.current["graph_cashe"]
  352. UI_elements.roundrect(layer, win,
  353. win.current["w"]/4+160+(40*num),
  354. 225,
  355. 40,
  356. 40,
  357. 10,
  358. do,
  359. cat[thing][1])
  360. # Let's set up some very handy values
  361. new_date_format = "%Y/%m/%d"
  362. startdate = win.analytics["startdate"]
  363. deadline = win.analytics["deadline"]
  364. duration = win.analytics["duration"]
  365. # Let's setup the little graph layer. So nothing come out of the frame.
  366. x = win.current["w"]/4
  367. y = 280
  368. width = win.current["w"] / 2
  369. height = (win.current["h"]-300)/2
  370. # Now let's make a layer.
  371. if "graph_cashe" not in win.current:
  372. # Making the layer
  373. graphsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
  374. node = cairo.Context(graphsurface)
  375. node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  376. # Background
  377. #UI_color.set(node, win, "dark_overdrop")
  378. #node.rectangle(0,0,width, height)
  379. #node.fill()
  380. # helping line
  381. UI_color.set(node, win, "progress_background")
  382. if mode == "analytics":
  383. node.move_to(0, height/2)
  384. node.line_to(width, height/2)
  385. elif mode == "pulse":
  386. ty = height / duration
  387. node.move_to(0, height/2-ty)
  388. node.line_to(width, height/2-ty)
  389. else:
  390. node.move_to(0, height)
  391. node.line_to(width, 0)
  392. node.stroke()
  393. for num, thing in enumerate(reversed(cat)):
  394. if cat[thing][0]:
  395. UI_color.set(node, win, cat[thing][2])
  396. if mode == "linear":
  397. node.move_to(0, height)
  398. else:
  399. node.move_to(0, height/2)
  400. pfrac = 0
  401. dates = win.analytics["dates"]
  402. for date in dates:
  403. # Let's calculate the X position of a given part on a graph
  404. sd = datetime.datetime.strptime(startdate, new_date_format)
  405. nd = datetime.datetime.strptime(date , new_date_format)
  406. dn = nd - sd
  407. dn = int(dn.days)
  408. graphX = width / duration * dn
  409. # Let's calculate the Y position of a given part on a graph
  410. if "fractions" in dates[date]:
  411. fracs = dates[date]["fractions"]
  412. if mode == "linear":
  413. gfraction = fracs[thing]
  414. graphY = height - height * gfraction
  415. node.line_to(graphX, graphY)
  416. elif mode == "analytics":
  417. gfraction = fracs[thing]
  418. tfraction = dn / duration
  419. gfraction = gfraction / tfraction / 2
  420. graphY = height - height * gfraction
  421. node.line_to(graphX, graphY)
  422. else:
  423. gfraction = fracs[thing]
  424. gfraction = gfraction - pfrac
  425. graphY = height - height * gfraction - height / 2
  426. node.line_to(graphX, graphY)
  427. pfrac = fracs[thing]
  428. node.stroke()
  429. win.current["graph_cashe"] = graphsurface
  430. # Outputting the layer
  431. layer.set_source_surface(win.current["graph_cashe"], x, y)
  432. layer.paint()
  433. # Let's force graph to refresh on each click
  434. if not win.current["LMB"] and win.previous["LMB"]:
  435. try:
  436. del win.current["graph_cashe"]
  437. except:
  438. pass
  439. ############### SCHEDULING / DATE SELECTION ################
  440. # So here I want to put a dialog that in the Blender-Organizer legacy was
  441. # in the center of the frame. I thought here it makes a bit more sense. Tho
  442. # I will remove the graph from it. I have a very good graph on the top from
  443. # it. And in my opinion this is enough. In you think otherwise let me know.
  444. # or fork VCStudio and implement it yourself. See what I can do with free-
  445. # software. I can just tell you to do everything yourself. Imaging doing this
  446. # when developing proprietery software.
  447. # Anyway back to the thing. I do want to draw schedules inside the days cells.
  448. # and by their colors. RED or GREY or PURPLE or GREEN you will have an idea of
  449. # how much stuff is done and how much stuff is not yet done. A kind of second
  450. # graph, so to speak. But representing differnt kind of data.
  451. # OKAY. SETTINGS.
  452. if "schedule_analytics_settings" not in win.current:
  453. win.current["schedule_analytics_settings"] = {
  454. "checked":False,
  455. "multiuser":False
  456. }
  457. for num, button in enumerate(win.current["schedule_analytics_settings"]):
  458. if win.current["schedule_analytics_settings"][button]:
  459. UI_color.set(layer, win, "progress_time")
  460. UI_elements.roundrect(layer, win,
  461. x+10+(40*num),
  462. y+height+10,
  463. 40,
  464. 40,
  465. 10)
  466. def do():
  467. win.current["schedule_analytics_settings"][button] = not win.current["schedule_analytics_settings"][button]
  468. UI_elements.roundrect(layer, win,
  469. x+10+(40*num),
  470. y+height+10,
  471. 40,
  472. 40,
  473. 10,
  474. do,
  475. button)
  476. # CURRENT DATE
  477. today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
  478. UI_elements.text(layer, win, "current_date_setting",
  479. x+100,
  480. y+height+10,
  481. 200,
  482. 40,
  483. set_text=win.current["date"])
  484. if win.text["current_date_setting"]["text"] != win.current["date"]\
  485. and analytics.ifdate(win.text["current_date_setting"]["text"]):
  486. def do():
  487. win.current["date"] = win.text["current_date_setting"]["text"]
  488. win.textactive = ""
  489. UI_elements.roundrect(layer, win,
  490. x+260,
  491. y+height+10,
  492. 40,
  493. 40,
  494. 10,
  495. button=do,
  496. icon="ok",
  497. tip=talk.text("checked"))
  498. elif win.current["date"] != today:
  499. def do():
  500. win.current["date"] = today
  501. win.text["current_date_setting"]["text"] = today
  502. win.textactive = ""
  503. UI_elements.roundrect(layer, win,
  504. x+260,
  505. y+height+10,
  506. 40,
  507. 40,
  508. 10,
  509. button=do,
  510. icon="cancel",
  511. tip=talk.text("cancel"))
  512. y = y + height + 60
  513. height = height - 100
  514. # Making the layer
  515. graphsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
  516. node = cairo.Context(graphsurface)
  517. node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  518. if "days" not in win.scroll:
  519. win.scroll["days"] = 0 - win.analytics["dayspassed"]*50 + width / 2 - 25
  520. current_X = 0
  521. prevyear = [startdate.split("/")[0], win.scroll["days"]]
  522. prevmonth = [startdate.split("/")[1], win.scroll["days"]]
  523. for doffset in range(duration+1): # FOR ALL DAYS. NO MATTER IF THEY ARE IN DATA
  524. sd = datetime.datetime.strptime(startdate, new_date_format)
  525. theday = datetime.datetime.strftime(sd+datetime.timedelta(days=doffset), new_date_format)
  526. nowyear = [theday.split("/")[0], current_X+win.scroll["days"]]
  527. nowmonth = [theday.split("/")[1], current_X+win.scroll["days"]]
  528. # Focusing if selected
  529. if win.current["date"] != win.previous["date"] and win.current["date"] == theday:
  530. win.scroll["days"] = 0 - current_X + width / 2 - 25
  531. # YEARS
  532. if nowyear[0] != prevyear[0]:
  533. UI_color.set(node, win, "dark_overdrop")
  534. UI_elements.roundrect(node, win,
  535. 5+prevyear[1]+2,
  536. 0,
  537. nowyear[1] - prevyear[1]-7,
  538. 20,
  539. 10)
  540. UI_color.set(node, win, "text_normal")
  541. node.set_font_size(15)
  542. node.move_to(
  543. max(prevyear[1] + 200, min(width/2-23, nowyear[1]- 200)),
  544. 15,
  545. )
  546. node.show_text(prevyear[0])
  547. prevyear = nowyear
  548. # MONTHS
  549. if nowmonth[0] != prevmonth[0]:
  550. UI_color.set(node, win, "dark_overdrop")
  551. UI_elements.roundrect(node, win,
  552. 5+prevmonth[1]+2,
  553. 22,
  554. nowmonth[1]-prevmonth[1]-7,
  555. 20,
  556. 10)
  557. UI_color.set(node, win, "text_normal")
  558. node.set_font_size(15)
  559. node.move_to(
  560. max(prevmonth[1] + 12, min(width/2-12, nowmonth[1]- 35)),
  561. 38,
  562. )
  563. node.show_text(prevmonth[0])
  564. prevmonth = nowmonth
  565. # DAYS
  566. if -50 < current_X+win.scroll["days"] < width:
  567. UI_color.set(node, win, "dark_overdrop")
  568. UI_elements.roundrect(node, win,
  569. 5+current_X+win.scroll["days"],
  570. 44,
  571. 40,
  572. 20,
  573. 10)
  574. UI_color.set(node, win, "text_normal")
  575. node.set_font_size(15)
  576. node.move_to(
  577. 15+current_X+win.scroll["days"],
  578. 59,
  579. )
  580. node.show_text(theday.split("/")[2])
  581. UI_color.set(node, win, "dark_overdrop")
  582. if theday == today:
  583. UI_color.set(node, win, "button_clicked")
  584. UI_elements.roundrect(node, win,
  585. 5+current_X+win.scroll["days"],
  586. 67,
  587. 40,
  588. height-67,
  589. 10)
  590. if win.current["date"] == theday:
  591. UI_color.set(node, win, "progress_background")
  592. UI_elements.roundrect(node, win,
  593. 5+current_X+win.scroll["days"],
  594. 67,
  595. 40,
  596. height-67,
  597. 10,
  598. fill=False)
  599. node.stroke()
  600. # STARTDATE & DEADLINE
  601. elif theday in [startdate, deadline]:
  602. UI_color.set(node, win, "node_badfile")
  603. UI_elements.roundrect(node, win,
  604. 5+current_X+win.scroll["days"],
  605. 67,
  606. 40,
  607. height-67,
  608. 10,
  609. fill=False)
  610. node.stroke()
  611. # SELECTION BUTTON
  612. def do():
  613. if win.current["tool"] == "schedule":
  614. # If it's a scheduling.
  615. path, back, cur, schedulepath, username = win.current["grab_data"].copy()
  616. path = path.replace(win.project, "")
  617. path = path[path.find(cur)+len(cur):]
  618. if theday not in win.analytics["dates"]:
  619. win.analytics["dates"][theday] = {}
  620. name = cur[cur.rfind("/")+1:]
  621. acur = cur.replace(name, "").replace("/", "")
  622. if acur in ["chr", "veh", "loc","obj"]:
  623. itemtype = "assets"
  624. elif not acur:
  625. itemtype = "files"
  626. else:
  627. itemtype = "scenes"
  628. if itemtype not in win.analytics["dates"][theday]:
  629. win.analytics["dates"][theday][itemtype] = {}
  630. if cur not in win.analytics["dates"][theday][itemtype]:
  631. win.analytics["dates"][theday][itemtype][cur] = []
  632. #print("test 1")
  633. win.analytics["dates"][theday][itemtype][cur].append(
  634. ["00:00:00",
  635. "schedule",
  636. path,
  637. "[Un-Checked]",
  638. schedulepath,
  639. username]
  640. )
  641. #print("test 2")
  642. # RETURNING BACK TO NORMAL
  643. win.url = back
  644. win.current["tool"] = "selection"
  645. analytics.save(win.project, win.analytics)
  646. win.analytics = analytics.load(win.project)
  647. win.checklists = {}
  648. # Multiuser sycning
  649. win.multiuser["request"] = "analytics"
  650. #print("test 3")
  651. else:
  652. win.current["date"] = theday
  653. win.text["current_date_setting"]["text"] = theday
  654. UI_elements.roundrect(node, win,
  655. 5+current_X+win.scroll["days"],
  656. 67,
  657. 40,
  658. height-67,
  659. 10,
  660. button=do,
  661. offset=[x,y],
  662. fill=False)
  663. node.stroke()
  664. # Now here I want to draw the representations of scheduled
  665. # tasks that are insife
  666. sch = []
  667. if theday in win.analytics["dates"]:
  668. date = win.analytics["dates"][theday]
  669. for i in ["files", "assets", "scenes"]:
  670. if i in date:
  671. for item in date[i]:
  672. for stuff in date[i][item]:
  673. if stuff[1] == "schedule":
  674. if not win.current["schedule_analytics_settings"]["multiuser"]:
  675. if win.settings["Username"] != stuff[-1]:
  676. continue
  677. if "[Checked]" in stuff:
  678. if win.current["schedule_analytics_settings"]["checked"]:
  679. sch.append(True)
  680. else:
  681. sch.append(False)
  682. for n, s in enumerate(sch):
  683. UI_color.set(node, win, "node_background")
  684. if theday < today:
  685. UI_color.set(node, win, "node_badfile")
  686. elif theday > today:
  687. UI_color.set(node, win, "node_asset")
  688. if s:
  689. UI_color.set(node, win, "node_blendfile")
  690. UI_elements.roundrect(node, win,
  691. 8+current_X+win.scroll["days"],
  692. 70+13*n,
  693. 35,
  694. 8,
  695. 5)
  696. current_X = current_X + 50
  697. UI_color.set(node, win, "dark_overdrop")
  698. UI_elements.roundrect(node, win,
  699. 5+prevyear[1]+2,
  700. 0,
  701. nowyear[1] - prevyear[1]-4 + 50,
  702. 20,
  703. 10)
  704. UI_color.set(node, win, "text_normal")
  705. node.set_font_size(15)
  706. node.move_to(
  707. max(prevyear[1] + 200, min(width/2-23, nowyear[1]- 200)),
  708. 15,
  709. )
  710. node.show_text(prevyear[0])
  711. UI_color.set(node, win, "dark_overdrop")
  712. UI_elements.roundrect(node, win,
  713. 5+prevmonth[1]+2,
  714. 22,
  715. nowmonth[1]-prevmonth[1]-4 + 50,
  716. 20,
  717. 10)
  718. UI_color.set(node, win, "text_normal")
  719. node.set_font_size(15)
  720. node.move_to(
  721. max(prevmonth[1] + 12, min(width/2-12, nowmonth[1]- 35)),
  722. 38,
  723. )
  724. node.show_text(prevmonth[0])
  725. # Outputting the layer
  726. layer.set_source_surface(graphsurface, x, y)
  727. layer.paint()
  728. # Scroll
  729. UI_elements.scroll_area(layer, win, "days",
  730. x,
  731. y,
  732. width,
  733. height+30,
  734. current_X,
  735. bar=True,
  736. mmb=True,
  737. sideways=True)
  738. ############## CHECKLIST ################
  739. if win.current["tool"] == "schedule":
  740. # If the tool is scheduling I want to make sure that the user sees where
  741. # he needs to place the task. A higlight.
  742. UI_color.set(layer, win, "progress_background")
  743. UI_elements.roundrect(layer, win,
  744. x,
  745. y+67,
  746. width,
  747. height-67,
  748. 10,
  749. fill=False)
  750. layer.stroke()
  751. path, back, cur, schedulepath, username = win.current["grab_data"].copy()
  752. checklist.draw(layer, win, path, back)
  753. UI_color.set(layer, win, "node_background")
  754. UI_elements.roundrect(layer, win,
  755. win.current["mx"],
  756. win.current["my"],
  757. 40,
  758. 40,
  759. 10)
  760. UI_elements.image(layer, win,
  761. "settings/themes/"+win.settings["Theme"]+"/icons/schedule.png",
  762. win.current["mx"],
  763. win.current["my"],
  764. 40,
  765. 40)
  766. elif os.path.exists(win.project+"/set/project.progress"):
  767. checklist.draw(layer, win, win.project+"/set/project.progress", back=win.url)
  768. elif os.path.exists(win.project+"/project.progress"):
  769. checklist.draw(layer, win, win.project+"/project.progress", back=win.url)
  770. # In the analytics window there will a choise of whether to see schedules. Or to
  771. # see history.
  772. if "analytics_left_panel" not in win.current:
  773. win.current["analytics_left_panel"] = "schedule"
  774. UI_color.set(layer, win, "node_background")
  775. UI_elements.roundrect(layer, win,
  776. 10,
  777. 10,
  778. win.current["w"]/4-20,
  779. 50,
  780. 10)
  781. for num, thing in enumerate(["schedule", "history"]):
  782. if win.current["analytics_left_panel"] == thing:
  783. UI_color.set(layer, win, "progress_time")
  784. UI_elements.roundrect(layer, win,
  785. 20+(40*num),
  786. 15,
  787. 40,
  788. 40,
  789. 10)
  790. def do():
  791. win.current["analytics_left_panel"] = thing
  792. UI_elements.roundrect(layer, win,
  793. 20+(40*num),
  794. 15,
  795. 40,
  796. 40,
  797. 10,
  798. do,
  799. thing)
  800. ##### SCHEDULE ######
  801. if win.current["analytics_left_panel"] == "schedule":
  802. schedule.draw(layer, win)
  803. ##### HISTORY #######
  804. else:
  805. history.draw(layer, win)
  806. # CANCEl
  807. def do():
  808. win.url = "story_editor"
  809. win.assets = {}
  810. win.current["asset_file_selected"] = ""
  811. UI_elements.roundrect(layer, win,
  812. win.current["w"]-40-win.current["w"]/4,
  813. win.current["h"]-50,
  814. 40,
  815. 40,
  816. 10,
  817. button=do,
  818. icon="cancel",
  819. tip=talk.text("cancel"))
  820. # Short cut ESC
  821. if 65307 in win.current["keys"] and not win.textactive:
  822. do()
  823. return surface