#################################### # # # COPYRIGHT NOTICE # # # # This file is a part of Victori- # # ous Children Studio Organizer. # # Or simply VCStudio. Copyright # # of J.Y.Amihud. But don't be sad # # because I released the entire # # project under a GNU GPL license. # # You may use Version 3 or later. # # See www.gnu.org/licenses if your # # copy has no License file. Please # # note. Ones I used the GPL v2 for # # it. It's no longer the case. # # # #################################### import os import datetime # GTK module ( Graphical interface import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import GLib from gi.repository import Gdk import cairo # Own modules from settings import settings from settings import talk from settings import fileformats from settings import oscalls from project_manager import pm_project #UI modules from UI import UI_elements from UI import UI_color # story from studio import story from studio import checklist from studio import analytics from studio import studio_dialogs from studio import schedule from studio import history def datetip(win, date): # Function that outputs basic analytics about a given date # in text form # TODO: This function is in a prototype stage. Meaning it's # not translated to multiple languages. This should be fixed. # See settings/talk.py file. text = date try: data = win.analytics["dates"][date] # Expected startdate = win.analytics["startdate"] deadline = win.analytics["deadline"] duration = win.analytics["duration"] new_date_format = "%Y/%m/%d" sd = datetime.datetime.strptime(startdate, new_date_format) nd = datetime.datetime.strptime(date , new_date_format) dn = nd - sd daysin = int(dn.days) expected = round(100 / duration * daysin, 2) text = text +"\n\nExpected: "+str(expected)+"%" # Actual frac = round(data.get("fractions", {}).get("project")*100, 2) text = text +"\nActual: "+str(frac)+"%" # Productivity productivity = int(round(frac - expected+100)) text = text +"\n\nProductivity: "+str(productivity)+"%" except Exception as e: pass return text def layer(win): # This is very important. I makes live easier. LOL. win.current["shot_left_side_scroll_please_work_omg_wtf"] = True # Making the layer surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'], win.current['h']) layer = cairo.Context(surface) #text setting layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) UI_color.set(layer, win, "dark_overdrop") layer.rectangle( 0, 0, win.current["w"], win.current["h"], ) layer.fill() UI_color.set(layer, win, "node_background") UI_elements.roundrect(layer, win, win.current["w"]/4, 10, win.current["w"]/2, win.current["h"]-20, 10) ############################################################################ # This is the Analitycs window. This time I want to do something crazy. # There will be 5 sections on the screen. ############################################################################ # # # # # # # # # # PROGRESS BARS # # # # # # # # # # # # ####################################### # # # # # # # SCHEDULING # ANALYTICS GRAPH # MAIN # # # # CHECKLIS # # # # # # # ####################################### # # # # # # # # CALENDAR / DAY SELECTOR # # # # # # # # X # # ############################################################################ # The idea is that you could be in Assets or Script Editor and drag the # tasks from the checklist down to Calendar and leave it there. So when you # move the task and mouse comes into the center part, you automatically # transferred to the analytics layer for untill you leave the task somewhere # or return it back to the checklist. # I want to do the same with the SCHEDULING. So you could simple drag it to # the Calendar to change it's date. Let's see how terribly hard will it be # to implement. Because I'm already fighting with the Scedules all day. ############################################################################ ############## PROGRESS BARS ############# timepassed = 0.0 projectdone = 0.0 chrdone = 0.0 vehdone = 0.0 locdone = 0.0 objdone = 0.0 rnddone = 0.0 try: timepassed = win.analytics["timepassed"] projectdone = win.analytics["fraction"] chrdone = win.analytics["chr"] vehdone = win.analytics["veh"] locdone = win.analytics["loc"] objdone = win.analytics["obj"] rnddone = win.analytics["rnd"] except: pass # MAIN PROGRESS UI_elements.image(layer, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/star.png", win.current["w"]/4+10, 15, 40, 40) # Progressbar UI_color.set(layer, win, "progress_background") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 25, win.current["w"]/2-80, 20, 10, tip="Today's requirement is: "+str(round(win.analytics.get("needed", 0)*100, 1))+"% ( "+str(round(win.analytics.get("star", 0)*100, 1))+"% of which is done )") UI_color.set(layer, win, "text_link") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 25, (win.current["w"]/2-80)*min(win.analytics.get("star", 0), 1), 20, 10) # # Icon # UI_elements.image(layer, win, "settings/themes/"\ # +win.settings["Theme"]+"/icons/analytics.png", # win.current["w"]/4+10, # 15, # 40, # 40) # # Progressbar # UI_color.set(layer, win, "progress_background") # UI_elements.roundrect(layer, win, # win.current["w"]/4+60, # 25, # win.current["w"]/2-80, # 20, # 10, # tip=str(round(projectdone*100, 1))+"%") # # Project Done # UI_color.set(layer, win, "progress_active") # UI_elements.roundrect(layer, win, # win.current["w"]/4+60, # 25, # (win.current["w"]/2-80)*projectdone, # 20, # 10) # TIME PASSED # Icon UI_elements.image(layer, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/schedule.png", win.current["w"]/4+10, 55, 40, 40) UI_color.set(layer, win, "progress_background") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 65, win.current["w"]/2-80, 20, 10, tip="Time: "+str(round(timepassed*100, 1))+"% Project: "+str(round(projectdone*100, 1))+"%") # Timepassed UI_color.set(layer, win, "progress_time") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 65, (win.current["w"]/2-80)*timepassed, 20, 10) # Project Done UI_color.set(layer, win, "progress_active") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 65, (win.current["w"]/2-80)*projectdone, 20, 10) # SCENES DONE ( RND ) # Icon UI_elements.image(layer, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/shot.png", win.current["w"]/4+10, 95, 40, 40) UI_color.set(layer, win, "shot_5") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 105, win.current["w"]/2-80, 20, 10, tip=str(round(rnddone*100, 1))+"%", fill=False) layer.stroke() # Scenes UI_color.set(layer, win, "shot_5") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 105, (win.current["w"]/2-80)*rnddone, 20, 10) # CHR DONE # Icon UI_elements.image(layer, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/chr.png", win.current["w"]/4+10, 135, 40, 40) UI_color.set(layer, win, "shot_1") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 145, win.current["w"]/4-80, 20, 10, tip=str(round(chrdone*100, 1))+"%", fill=False) layer.stroke() # progress UI_color.set(layer, win, "shot_1") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 145, (win.current["w"]/4-80)*chrdone, 20, 10) # VEH DONE # Icon UI_elements.image(layer, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/veh.png", win.current["w"]/2, 135, 40, 40) UI_color.set(layer, win, "shot_2") UI_elements.roundrect(layer, win, win.current["w"]/2+60, 145, win.current["w"]/4-80, 20, 10, tip=str(round(vehdone*100, 1))+"%", fill=False) layer.stroke() # progress UI_color.set(layer, win, "shot_2") UI_elements.roundrect(layer, win, win.current["w"]/2+60, 145, (win.current["w"]/4-80)*vehdone, 20, 10) # LOC DONE # Icon UI_elements.image(layer, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/loc.png", win.current["w"]/4+10, 175, 40, 40) UI_color.set(layer, win, "shot_3") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 185, win.current["w"]/4-80, 20, 10, tip=str(round(locdone*100, 1))+"%", fill=False) layer.stroke() # progress UI_color.set(layer, win, "shot_3") UI_elements.roundrect(layer, win, win.current["w"]/4+60, 185, (win.current["w"]/4-80)*locdone, 20, 10) # OBJ DONE # Icon UI_elements.image(layer, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/obj.png", win.current["w"]/2, 175, 40, 40) UI_color.set(layer, win, "shot_4") UI_elements.roundrect(layer, win, win.current["w"]/2+60, 185, win.current["w"]/4-80, 20, 10, tip=str(round(objdone*100, 1))+"%", fill=False) layer.stroke() # progress UI_color.set(layer, win, "shot_4") UI_elements.roundrect(layer, win, win.current["w"]/2+60, 185, (win.current["w"]/4-80)*objdone, 20, 10) ############### THE GRAPH ################## # This graph going to show the entire time of the whole project from # StartDate till Deadline. It will fill up with data overtime. # We are going to have a couple of modes. # Regular mode: Showing actuall values represented on the graph # it's going to be a diagonal line if the work was done # linearly. # Normalized : This this a graph of true values compared to time. So let's # say at a second day you had to be only at 3%. Being at 3% will # make graph show 100%. The expected value is linear from 0% # to 100% over the whole project. # Pulse mode : This mode will give a graph compared to the previous day. # if on a given day there was a gib jump in percentage there # will be a big spike on the graph. # Let's make a mode selector. if "analytics_middle_graph_mode" not in win.current: win.current["analytics_middle_graph_mode"] = "linear" for num, thing in enumerate(["linear", "analytics", "pulse"]): # By icons if win.current["analytics_middle_graph_mode"] == thing: UI_color.set(layer, win, "progress_time") UI_elements.roundrect(layer, win, win.current["w"]/4+10+(40*num), 225, 40, 40, 10) def do(): win.current["analytics_middle_graph_mode"] = thing del win.current["graph_cashe"] UI_elements.roundrect(layer, win, win.current["w"]/4+10+(40*num), 225, 40, 40, 10, do, thing) # And before we start a little settings icon. # Documentation entry def do(): def after(win, var): pass studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_analytics")) UI_elements.roundrect(layer, win, win.current["w"]/4*3-110, 225, 40, 40, 10, do, "question") # Settings def do(): win.url = "settings_layer" UI_elements.roundrect(layer, win, win.current["w"]/4*3-60, 225, 40, 40, 10, do, "settings", talk.text("Settings")) # Now let's make a filter by type. As you maybe already know appart from # the main progress I'm reading all the other things too. Every progress # bar on the screen should have a corrisponding graph. But sometimes if # paths go too far appart, this aint helpfull. So a filter is required to # switch a category on and off. if "analytics_middle_graph_switch" not in win.current: win.current["analytics_middle_graph_switch"] = { "project":[True,"analytics", "progress_active"], "checklist":[True,"checklist", "node_videofile"], "rnd":[True,"shot", "shot_5"], "chr":[True,"chr", "shot_1"], "veh":[True,"veh", "shot_2"], # Name in data : [ Active, Icon name, color ] "loc":[True,"loc", "shot_3"], "obj":[True,"obj", "shot_4"] } cat = win.current["analytics_middle_graph_switch"] mode = win.current["analytics_middle_graph_mode"] for num, thing in enumerate(cat): if cat[thing][0]: UI_color.set(layer, win, cat[thing][2]) UI_elements.roundrect(layer, win, win.current["w"]/4+160+(40*num), 225, 38, 40, 10, fill=False) layer.stroke() def do(): cat[thing][0] = not cat[thing][0] del win.current["graph_cashe"] UI_elements.roundrect(layer, win, win.current["w"]/4+160+(40*num), 225, 38, 40, 10, do, cat[thing][1]) # Let's set up some very handy values new_date_format = "%Y/%m/%d" startdate = win.analytics["startdate"] deadline = win.analytics["deadline"] duration = win.analytics["duration"] # Let's setup the little graph layer. So nothing come out of the frame. x = win.current["w"]/4 y = 280 width = win.current["w"] / 2 height = 100 # Now let's make a layer. # CURRENT DATE today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format) if "graph_cashe" not in win.current: # Making the layer graphsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) node = cairo.Context(graphsurface) node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) # Background #UI_color.set(node, win, "dark_overdrop") #node.rectangle(0,0,width, height) #node.fill() # helping line UI_color.set(node, win, "progress_time") if mode == "analytics": node.move_to(0, height/2) node.line_to(width, height/2) elif mode == "pulse": ty = height / duration node.move_to(0, height/2-ty) node.line_to(width, height/2-ty) else: node.move_to(0, height) node.line_to(width, 0) node.stroke() todayX = 0 for num, thing in enumerate(reversed(cat)): if cat[thing][0]: UI_color.set(node, win, cat[thing][2]) if mode == "linear": node.move_to(0, height) else: node.move_to(0, height/2) pfrac = 0 dates = win.analytics["dates"] for date in dates: # Let's calculate the X position of a given part on a graph sd = datetime.datetime.strptime(startdate, new_date_format) nd = datetime.datetime.strptime(date , new_date_format) dn = nd - sd dn = int(dn.days) graphX = width / duration * dn if date == today: todayX = graphX # Let's calculate the Y position of a given part on a graph if "fractions" in dates[date]: fracs = dates[date]["fractions"] if mode == "linear": gfraction = fracs[thing] graphY = height - height * gfraction node.line_to(graphX, graphY) elif mode == "analytics": gfraction = fracs[thing] tfraction = dn / duration gfraction = gfraction / tfraction / 2 graphY = height - height * gfraction node.line_to(graphX, graphY) else: gfraction = fracs[thing] gfraction = gfraction - pfrac graphY = height - height * gfraction - height / 2 node.line_to(graphX, graphY) pfrac = fracs[thing] node.stroke() # Today UI_color.set(node, win, "button_clicked") node.move_to(todayX, 0) node.line_to(todayX, height) node.stroke() win.current["graph_cashe"] = graphsurface # Dynamic elements of the graph! # I sense a possible bug here, since I will draw these on top # of a prebaked image. And something sometimes might not align # properly. I don't know how to deal with it quite yet, perhaps # you can try fixing the issue. LOL. # Bottom Graph position on the top graph. try: posX = width / (duration*50) * win.scroll["days"] posX2 = (width / (duration*50) * (win.scroll["days"]+width))-posX except: posX = 0 posX2 = 20 UI_color.set(layer, win, "dark_overdrop") UI_elements.roundrect(layer, win, x-posX, y, posX2, height, 5, fill=True) layer.stroke() # Mouse drag thingy if x < win.current["mx"] < x+width\ and y < win.current["my"] < y+height: if win.current["LMB"]: win.scroll["days"] = 0- (( win.current["mx"] - x ) / width * (duration*50)) + (width/2) sd = datetime.datetime.strptime(startdate, new_date_format) daysin = int(round( duration / width * (x-win.current["mx"])))*-1 td = datetime.timedelta(days=daysin) hoverdate = sd + td hoverdate = hoverdate.strftime(new_date_format) UI_elements.tooltip(win, datetip(win, hoverdate)) UI_color.set(layer, win, "progress_background") layer.move_to(win.current["mx"], y) layer.line_to(win.current["mx"], y+height) layer.stroke() # Outputting the layer layer.set_source_surface(win.current["graph_cashe"], x, y) layer.paint() # Let's force graph to refresh on each click if not win.current["LMB"] and win.previous["LMB"]: try: del win.current["graph_cashe"] except: pass ############### SCHEDULING / DATE SELECTION ################ # So here I want to put a dialog that in the Blender-Organizer legacy was # in the center of the frame. I thought here it makes a bit more sense. Tho # I will remove the graph from it. I have a very good graph on the top from # it. And in my opinion this is enough. In you think otherwise let me know. # or fork VCStudio and implement it yourself. See what I can do with free- # software. I can just tell you to do everything yourself. Imaging doing this # when developing proprietery software. # Anyway back to the thing. I do want to draw schedules inside the days cells. # and by their colors. RED or GREY or PURPLE or GREEN you will have an idea of # how much stuff is done and how much stuff is not yet done. A kind of second # graph, so to speak. But representing differnt kind of data. # OKAY. SETTINGS. if "schedule_analytics_settings" not in win.current: win.current["schedule_analytics_settings"] = { "checked":False, "multiuser":False } for num, button in enumerate(win.current["schedule_analytics_settings"]): if win.current["schedule_analytics_settings"][button]: UI_color.set(layer, win, "progress_time") UI_elements.roundrect(layer, win, x+10+(40*num), y+height+10, 40, 40, 10) def do(): win.current["schedule_analytics_settings"][button] = not win.current["schedule_analytics_settings"][button] UI_elements.roundrect(layer, win, x+10+(40*num), y+height+10, 40, 40, 10, do, button) UI_elements.text(layer, win, "current_date_setting", x+100, y+height+10, 200, 40, set_text=win.current["date"]) if win.text["current_date_setting"]["text"] != win.current["date"]\ and analytics.ifdate(win.text["current_date_setting"]["text"]): def do(): win.current["date"] = win.text["current_date_setting"]["text"] win.textactive = "" UI_elements.roundrect(layer, win, x+260, y+height+10, 40, 40, 10, button=do, icon="ok", tip=talk.text("checked")) elif win.current["date"] != today: def do(): win.current["date"] = today win.text["current_date_setting"]["text"] = today win.textactive = "" UI_elements.roundrect(layer, win, x+260, y+height+10, 40, 40, 10, button=do, icon="cancel", tip=talk.text("cancel")) y = y + height + 60 height = win.current["h"]-500 # Making the layer graphsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) node = cairo.Context(graphsurface) node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) if "days" not in win.scroll: win.scroll["days"] = 0 - win.analytics["dayspassed"]*50 + width / 2 - 25 current_X = 0 prevyear = [startdate.split("/")[0], win.scroll["days"]] prevmonth = [startdate.split("/")[1], win.scroll["days"]] prevday = "1997/07/30" pfrac = {} for doffset in range(duration+1): # FOR ALL DAYS. NO MATTER IF THEY ARE IN DATA sd = datetime.datetime.strptime(startdate, new_date_format) theday = datetime.datetime.strftime(sd+datetime.timedelta(days=doffset), new_date_format) nowyear = [theday.split("/")[0], current_X+win.scroll["days"]] nowmonth = [theday.split("/")[1], current_X+win.scroll["days"]] # Focusing if selected if win.current["date"] != win.previous["date"] and win.current["date"] == theday: win.scroll["days"] = 0 - current_X + width / 2 - 25 # YEARS if nowyear[0] != prevyear[0]: UI_color.set(node, win, "dark_overdrop") UI_elements.roundrect(node, win, 5+prevyear[1]+2, 0, nowyear[1] - prevyear[1]-7, 20, 10) UI_color.set(node, win, "text_normal") node.set_font_size(15) node.move_to( max(prevyear[1] + 200, min(width/2-23, nowyear[1]- 200)), 15, ) node.show_text(prevyear[0]) prevyear = nowyear # MONTHS if nowmonth[0] != prevmonth[0]: UI_color.set(node, win, "dark_overdrop") UI_elements.roundrect(node, win, 5+prevmonth[1]+2, 22, nowmonth[1]-prevmonth[1]-7, 20, 10) UI_color.set(node, win, "text_normal") node.set_font_size(15) node.move_to( max(prevmonth[1] + 12, min(width/2-12, nowmonth[1]- 35)), 38, ) node.show_text(prevmonth[0]) prevmonth = nowmonth # DAYS if -50 < current_X+win.scroll["days"] < width: UI_color.set(node, win, "dark_overdrop") UI_elements.roundrect(node, win, 5+current_X+win.scroll["days"], 44, 40, 20, 10) UI_color.set(node, win, "text_normal") node.set_font_size(15) node.move_to( 15+current_X+win.scroll["days"], 59, ) node.show_text(theday.split("/")[2]) UI_color.set(node, win, "dark_overdrop") if theday >= today: if theday == today: UI_color.set(node, win, "button_clicked") UI_elements.roundrect(node, win, 5+current_X+win.scroll["days"], 67, 40, height-67, 10) if win.current["date"] == theday: UI_color.set(node, win, "progress_background") UI_elements.roundrect(node, win, 5+current_X+win.scroll["days"], 67, 40, height-67, 10, fill=False) node.stroke() # STARTDATE & DEADLINE elif theday in [startdate, deadline]: UI_color.set(node, win, "node_badfile") UI_elements.roundrect(node, win, 5+current_X+win.scroll["days"], 67, 40, height-67, 10, fill=False) node.stroke() # SELECTION BUTTON def do(): if win.current["tool"] == "schedule": # If it's a scheduling. path, back, cur, schedulepath, username = win.current["grab_data"].copy() path = path.replace(win.project, "") path = path[path.find(cur)+len(cur):] if theday not in win.analytics["dates"]: win.analytics["dates"][theday] = {} name = cur[cur.rfind("/")+1:] acur = cur.replace(name, "").replace("/", "") if acur in ["chr", "veh", "loc","obj"]: itemtype = "assets" elif not acur: itemtype = "files" else: itemtype = "scenes" if itemtype not in win.analytics["dates"][theday]: win.analytics["dates"][theday][itemtype] = {} if cur not in win.analytics["dates"][theday][itemtype]: win.analytics["dates"][theday][itemtype][cur] = [] #print("test 1") win.analytics["dates"][theday][itemtype][cur].append( ["00:00:00", "schedule", path, "[Un-Checked]", schedulepath, username] ) #print("test 2") # RETURNING BACK TO NORMAL win.url = back win.current["tool"] = "selection" analytics.save(win.project, win.analytics) win.analytics = analytics.load(win.project) win.checklists = {} # Multiuser sycning win.multiuser["request"] = "analytics" #print("test 3") else: win.current["date"] = theday win.text["current_date_setting"]["text"] = theday UI_elements.roundrect(node, win, 5+current_X+win.scroll["days"], 67, 40, height-67, 10, button=do, offset=[x,y], fill=False, tip=datetip(win, theday)) node.stroke() ##################### BOTTOM GRAPH ####################### # Blender-Organizer legacy had two graphs. One smaller # that shows all the project from start to finish # ( Implemented above ) and one bigger. That shows a # Zoomed in version of the graph. Back then I made it # executing the same code twice. Which was fine. Since # I had to make a change only ones. Now it's a bit of a # problem to do so. Since the graph above is baked. And # need to be able to navigate with in the bottom graph. # So instead I'm going to redo the graph, but since we # are re-doing it. I orignally wanted to do a different # design. But it ended up looking confusing. It needs lines! # Roundrects will not do. for num, thing in enumerate(reversed(cat)): if cat[thing][0]: UI_color.set(node, win, cat[thing][2]) try: sd = datetime.datetime.strptime(startdate, new_date_format) nd = datetime.datetime.strptime(theday , new_date_format) dn = nd - sd dn = int(dn.days) fracs = win.analytics["dates"][theday]["fractions"] Pfracs = win.analytics["dates"][prevday]["fractions"] gfraction = fracs[thing] if mode == "linear": graphY = ((height-80) - (height-80) * gfraction)+60 elif mode == "analytics": tfraction = dn / duration gfraction = gfraction / tfraction / 2 graphY = ((height-80) - (height-80) * gfraction)+60 else: try: gfraction = fracs[thing] gfraction = gfraction - Pfracs[thing] except: gfraction = 0 graphY = ((height-80) - (height-80) * gfraction - (height-80) / 2)+60 PgraphY = pfrac.get(thing, graphY) pfrac[thing] = graphY node.move_to(current_X+win.scroll["days"]-25, PgraphY) node.line_to(current_X+win.scroll["days"]+25, graphY) node.stroke() except Exception as e: if theday < today and theday not in win.analytics["dates"]: UI_color.set(node, win, "node_badfile") UI_elements.roundrect(node, win, 5+current_X+win.scroll["days"], 67, 40, height-67, 10, fill=False) node.stroke() # Now here I want to draw the representations of scheduled # tasks that are inside # Icons of what was done at the day icons_stuff = {"assets":"obj", "scenes":"shot", "files":"checklist"} icons = [] for t in icons_stuff: if t in win.analytics["dates"].get(theday, {}) and t != "assets": icons.append(icons_stuff[t]) elif t in win.analytics["dates"].get(theday, {}): for at in ["chr", "obj", "loc", "veh"]: for stuff in win.analytics["dates"].get(theday, {})[t]: if at in stuff and at not in icons: icons.append(at) for nicon, icon in enumerate(icons): UI_elements.image(node, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/"+icon+".png", 6+current_X+win.scroll["days"], height-(50*nicon)-50, 40, 40) # Stars! If the day was exceptional. try: if win.analytics["needed"] <= fracs.get("project", 0) - Pfracs.get("project", 0) and theday <= today: stars = (fracs.get("project", 0) - Pfracs.get("project", 0)) / win.analytics["needed"] for star in range(int(round(stars))): UI_elements.image(node, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/star.png", 6+current_X+win.scroll["days"], height-(50*(nicon+star-1))-150, 40, 40) except: pass # Schedules sch = [] if theday in win.analytics["dates"]: date = win.analytics["dates"][theday] for i in ["files", "assets", "scenes"]: if i in date: for item in date[i]: for stuff in date[i][item]: if stuff[1] == "schedule": if not win.current["schedule_analytics_settings"]["multiuser"]: if win.settings["Username"] != stuff[-1]: continue if "[Checked]" in stuff: if win.current["schedule_analytics_settings"]["checked"]: sch.append(True) else: sch.append(False) for n, s in enumerate(sch): UI_color.set(node, win, "node_background") if theday < today: UI_color.set(node, win, "node_badfile") elif theday > today: UI_color.set(node, win, "node_asset") if s: UI_color.set(node, win, "node_blendfile") UI_elements.roundrect(node, win, 8+current_X+win.scroll["days"], 70+13*n, 35, 8, 5) current_X = current_X + 50 prevday = theday UI_color.set(node, win, "dark_overdrop") UI_elements.roundrect(node, win, 5+prevyear[1]+2, 0, nowyear[1] - prevyear[1]-4 + 50, 20, 10) UI_color.set(node, win, "text_normal") node.set_font_size(15) node.move_to( max(prevyear[1] + 200, min(width/2-23, nowyear[1]- 200)), 15, ) node.show_text(prevyear[0]) UI_color.set(node, win, "dark_overdrop") UI_elements.roundrect(node, win, 5+prevmonth[1]+2, 22, nowmonth[1]-prevmonth[1]-4 + 50, 20, 10) UI_color.set(node, win, "text_normal") node.set_font_size(15) node.move_to( max(prevmonth[1] + 12, min(width/2-12, nowmonth[1]- 35)), 38, ) node.show_text(prevmonth[0]) # Outputting the layer layer.set_source_surface(graphsurface, x, y) layer.paint() # Scroll UI_elements.scroll_area(layer, win, "days", x, y, width, height+30, current_X, bar=True, mmb=True, sideways=True) ############## CHECKLIST ################ if win.current["tool"] == "schedule": # If the tool is scheduling I want to make sure that the user sees where # he needs to place the task. A higlight. UI_color.set(layer, win, "progress_background") UI_elements.roundrect(layer, win, x, y+67, width, height-67, 10, fill=False) layer.stroke() path, back, cur, schedulepath, username = win.current["grab_data"].copy() checklist.draw(layer, win, path, back) UI_color.set(layer, win, "node_background") UI_elements.roundrect(layer, win, win.current["mx"], win.current["my"], 40, 40, 10) UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/schedule.png", win.current["mx"], win.current["my"], 40, 40) elif os.path.exists(win.project+"/set/project.progress"): checklist.draw(layer, win, win.project+"/set/project.progress", back=win.url) elif os.path.exists(win.project+"/project.progress"): checklist.draw(layer, win, win.project+"/project.progress", back=win.url) # In the analytics window there will a choise of whether to see schedules. Or to # see history. if "analytics_left_panel" not in win.current: win.current["analytics_left_panel"] = "schedule" UI_color.set(layer, win, "node_background") UI_elements.roundrect(layer, win, 10, 10, win.current["w"]/4-20, 50, 10) for num, thing in enumerate(["schedule", "history"]): if win.current["analytics_left_panel"] == thing: UI_color.set(layer, win, "progress_time") UI_elements.roundrect(layer, win, 20+(40*num), 15, 40, 40, 10) def do(): win.current["analytics_left_panel"] = thing UI_elements.roundrect(layer, win, 20+(40*num), 15, 40, 40, 10, do, thing) ##### SCHEDULE ###### if win.current["analytics_left_panel"] == "schedule": schedule.draw(layer, win) ##### HISTORY ####### else: history.draw(layer, win) # CANCEl def do(): win.url = "story_editor" win.assets = {} win.current["asset_file_selected"] = "" UI_elements.roundrect(layer, win, win.current["w"]-40-win.current["w"]/4, win.current["h"]-50, 40, 40, 10, button=do, icon="cancel", tip=talk.text("cancel")) # Short cut ESC if 65307 in win.current["keys"] and not win.textactive: do() return surface