# THIS FILE IS A PART OF VCStudio # PYTHON 3 import os import datetime import threading # 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 project_manager import pm_project from studio import analytics from studio import studio_nodes from studio import studio_dialogs from studio import story from studio import analytics from studio import checklist #UI modules from UI import UI_elements from UI import UI_color ################################################################################ # This file is going to handle SCHEDULING. Primarily the output of the schedules # to the screen. But also probably a lot of other things related to schediles. ################################################################################ def filter(project, dates): ############################################################################ # This function is called on reading of analytics read. It will check whether # schedules are finished. Or if they are even found. Using studio/checklist.py # as a help. ############################################################################ checkcashe = {} # Temporary checklist cashe. delete = [] # Stuff I want to delete later for date in dates: for i in ["assets", "scenes", "files"]: if i in dates[date]: for url in dates[date][i]: for num, entry in enumerate(dates[date][i][url]): if dates[date][i][url][num][1] == "schedule": # First of all. I didn't think about it when # writting the analytics read # that I will need to know whether schedules # are [Checked] or [Un-Checked] if not "[Checked]" in dates[date][i][url][num]\ and not "[Un-Checked]" in dates[date][i][url][num]: dates[date][i][url][num].insert(3, "[Un-Checked]") # Then let's actually try to find whether the task # is checked. # For now let's do in a simple way. Because # if the whole checklist is 100% done. Then # obviously the task is also checked. path = dates[date][i][url][num][2] try: # Let's check if path exists in the project first. if os.path.exists(project+"/dev"+url+path): path = project+"/dev"+url+path elif os.path.exists(project+"rnd/"+url+path): path = project+"/rnd"+url+path elif os.path.exists(project+"/set/"+path): path = project+"/set/"+path elif os.path.exists(project+"/"+path): path = project+"/"+path if path not in checkcashe: checkcashe[path] = checklist.get_list(path) # Here we check whether the checklist is 100% if checkcashe[path]["fraction"] == 1.0: dates[date][i][url][num][3] = "[Checked]" # But what if it's not? Now we need to check # them 1 by one. else: dates[date][i][url][num][3] = "[Un-Checked]" task = checklist.get_task_by_path(checkcashe[path]["subtasks"],dates[date][i][url][num][4]) # Now if the task is not found. We delete the schedule if task: if task["fraction"] == 1.0: dates[date][i][url][num][3] = "[Checked]" else: delete.append([date,i,url,dates[date][i][url][num]]) except: delete.append([date,i,url,dates[date][i][url][num]]) # Deleting all kinds of buddah for i in delete: q,w,e,r = i if r in dates[q][w][e]: dates[q][w][e].remove(r) return dates def get_schedules(dates): ############################################################################ # This function will parse the dates data from the analytics. And get only # the schedules. In the format {date {url, [list of schedules]}} ############################################################################ newdates = {} for date in dates: if date not in newdates: newdates[date] = {} for i in ["assets", "scenes", "files"]: if i in dates[date]: for url in dates[date][i]: for num, entry in enumerate(dates[date][i][url]): if entry[1] == "schedule": if url not in newdates[date]: newdates[date][url] = [] if [entry, num] not in newdates[date][url]: newdates[date][url].append([entry, num]) return newdates def draw(outlayer, win): x = 10 y = 70 width = win.current["w"] / 4 - 20 height = win.current["h"] - 80 # At the top above the schedules. In the bar. i want to put 2 # buttons. One will hide done schedules, the other will # hide everything scheduled for other users. if "schedule_layer_settings" not in win.current: win.current["schedule_layer_settings"] = { "checked":False, "multiuser":False } for num, button in enumerate(win.current["schedule_layer_settings"]): if win.current["schedule_layer_settings"][button]: UI_color.set(outlayer, win, "progress_time") UI_elements.roundrect(outlayer, win, 20+width-(40*num)-60, 15, 40, 40, 10) def do(): win.current["schedule_layer_settings"][button] = not win.current["schedule_layer_settings"][button] UI_elements.roundrect(outlayer, win, 20+width-(40*num)-60, 15, 40, 40, 10, do, button) # Now let's make a layer. # Making the layer surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) layer = cairo.Context(surface) layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) # Clip UI_elements.roundrect(layer, win, 0, 0, width, height, 10, fill=False) layer.clip() # Getting various screadule data schedules = get_schedules(win.analytics["dates"]) new_date_format = "%Y/%m/%d" today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format) UI_elements.text(outlayer, win, "current_date_setting", width-100-(width-6*40), 15, (width-6*40), 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(outlayer, win, width-140, 15, 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(outlayer, win, width-140, 15, 40, 40, 10, button=do, icon="cancel", tip=talk.text("cancel")) slist = [] for date in schedules: if win.current["date"] != today and date != win.current["date"]: continue for item in schedules[date]: if win.cur == item or not win.cur: slist.append([date, item, schedules[date][item]]) # Selection magic if "schedule_task_selected" not in win.current: win.current["schedule_task_selected"] = False # Let's draw them to the screen in some way if "schedule" not in win.scroll: win.scroll["schedule"] = 0 current_Y = 0 for entry in slist: for thing in entry[2]: # Parsing the cur to get name and type name = entry[1][entry[1].rfind("/")+1:] acur = entry[1].replace(name, "").replace("/", "") fullurl = "" for e in thing[0][4][:-1]: fullurl = fullurl+e+" > " if acur in ["chr", "veh", "loc","obj"]: itemtype = "assets" elif not acur: itemtype = "files" else: itemtype = "scenes" try: if not win.analytics["dates"][entry[0]][itemtype]\ [entry[1]]: continue except: continue UI_color.set(layer, win, "node_background") # If not all users show only current user's tasks if not win.current["schedule_layer_settings"]["multiuser"]\ and thing[0][-1] != win.settings["Username"]: continue # If the task is checked if thing[0][3] == "[Checked]": if not win.current["schedule_layer_settings"]["checked"]: continue UI_color.set(layer, win, "node_blendfile") # The Green elif entry[0] != "1997/07/30": if entry[0] < today: UI_color.set(layer, win, "node_badfile") # The Red elif entry[0] > today: UI_color.set(layer, win, "node_asset") # The Purple UI_elements.roundrect(layer, win, 0, win.scroll["schedule"] + current_Y, width, 75, 10) # Selection button def do(): if win.current["tool"] == "selection": if win.current["schedule_task_selected"] != [ thing, entry[1] ]: win.current["schedule_task_selected"] = [ thing, entry[1] ] else: win.current["schedule_task_selected"] = False # Clearing the text try: del win.text["schedule_username_setting"] del win.text["schedule_date_setting"] del win.text["schedule_time_setting"] except: pass UI_elements.roundrect(layer, win, 0, win.scroll["schedule"] + current_Y, width, 75, 10, button=do, tip=entry[1]+" : "+fullurl+thing[0][4][-1], offset=[x,y], fill=False) layer.stroke() ############# GRABBING FOR RE-SCHEDULING ############## # Grab if win.current["LMB"]\ and int(win.current["LMB"][0]) in range(int(x), int(x+width))\ and int(win.current["LMB"][1]) in range(int(y+win.scroll["schedule"] + current_Y), int(y+win.scroll["schedule"] + current_Y+75))\ and win.current["tool"] == "selection"\ and int(win.current["LMB"][0]) not in range(int(win.current["mx"]-2), int(win.current["mx"]+2))\ and int(win.current["LMB"][1]) not in range(int(win.current["my"]-2), int(win.current["my"]+2)): try: print(entry) pop = win.analytics["dates"][entry[0]][itemtype]\ [entry[1]].pop(thing[1]) dev = "" if itemtype == "assets": dev = "/dev" win.current["tool"] = "schedule" win.current["grab_data"] = [dev+entry[1]+thing[0][2], win.url, entry[1], pop[4], pop[-1]] win.url = "analytics" except: pass # If you leave it here. if win.current["tool"] == "schedule" and not win.current["LMB"]: path, back, cur, schedulepath, username = win.current["grab_data"].copy() path = path.replace(win.project, "") path = path[path.find(cur)+len(cur):] tname = cur[cur.rfind("/")+1:] tacur = cur.replace(name, "").replace("/", "") if tacur in ["chr", "veh", "loc","obj"]: itemtype = "assets" elif not tacur: itemtype = "files" else: itemtype = "scenes" theday = win.current["date"] if theday not in win.analytics["dates"]: win.analytics["dates"][theday] = {} 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] = [] win.analytics["dates"][theday][itemtype][cur].append( ["00:00:00", "schedule", path, "[Un-Checked]", schedulepath, username] ) # 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 = {} ######################################################### # ICON UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/schedule.png", 5, win.scroll["schedule"] + current_Y+5, 40, 40) # MAIN TASK UI_color.set(layer, win, "text_normal") layer.set_font_size(20) layer.move_to( 50, win.scroll["schedule"] + current_Y+25, ) layer.show_text(thing[0][4][-1]) # TASK URL INSIDE THE CHECKLIST if fullurl: layer.set_font_size(10) layer.move_to( 60+len(thing[0][4][-1])*12, win.scroll["schedule"] + current_Y+25, ) layer.show_text(fullurl) # NAME OF THE ASSET / SHOT if acur in ["chr", "veh", "loc", "obj"]: assetname = talk.text(acur)+": "+name else: assetname = entry[1] layer.set_font_size(15) layer.move_to( 50, win.scroll["schedule"] + current_Y+45, ) layer.show_text(assetname) # DATE if entry[0] != "1997/07/30" and entry[0] != today: layer.set_font_size(15) layer.move_to( width-130, win.scroll["schedule"] + current_Y+45, ) layer.show_text(entry[0]) # TIME layer.set_font_size(15) layer.move_to( width-130, win.scroll["schedule"] + current_Y+65, ) layer.show_text(thing[0][0]) # USERNAME layer.set_font_size(15) layer.move_to( 20, win.scroll["schedule"] + current_Y+65, ) layer.show_text(talk.text("user_schedules")+" "+thing[0][-1]) # IF SELECTED THERE WILL BE MORE STUFF if win.current["schedule_task_selected"] == [ thing, entry[1] ]: UI_color.set(layer, win, "text_normal") UI_elements.roundrect(layer, win, 1, win.scroll["schedule"] + current_Y, width-2, 75, 10, fill=False) layer.stroke() current_Y = current_Y + 85 # If it's a task from an asset or a scene. There should be a link # to it. But first let's check that's it's infect an asset. # because... if entry[1]: # If asset: if acur in ["chr", "veh", "loc","obj"]: # ICON UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/"+acur+".png", 25, win.scroll["schedule"] + current_Y+5, 40, 40) goto = "assets" itemtype = "assets" elif not acur: itemtype = "files" else: # ICON UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/vse.png", 25, win.scroll["schedule"] + current_Y+5, 40, 40) goto = "script" itemtype = "scenes" # Here comes the link button def do(): win.url = goto win.cur = entry[1] win.current["asset_left_panel"] = "schedule" UI_elements.roundrect(layer, win, 20, win.scroll["schedule"] + current_Y+5, width-20, 40, 10, button=do, tip=entry[1]+" : "+fullurl+thing[0][4][-1], offset=[x,y], fill=False) layer.stroke() #Title UI_color.set(layer, win, "text_normal") layer.set_font_size(20) layer.move_to( 80, win.scroll["schedule"] + current_Y+30, ) layer.show_text(assetname) current_Y = current_Y + 50 # Next thing! Let's show the most editable values. I think the first # one. For the director will be important. Is to edit the USER. # or in other words. Who is doing the task. # In the end It will be a drop down menu. Like all of it. But for this # I need to implement MULTIUSER first. And it's not a priority right # now. So a simple text editor could be okay. # ICON UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/user.png", 25, win.scroll["schedule"] + current_Y+5, 40, 40) UI_elements.text(layer, win, "schedule_username_setting", 80, win.scroll["schedule"] + current_Y+5, width-80, 40, set_text=thing[0][-1], tip=talk.text("username"), offset=[x,y]) if win.text["schedule_username_setting"]["text"] != thing[0][-1]: def do(): thing[0][-1] = win.text["schedule_username_setting"]["text"] analytics.save(win.project, win.analytics) UI_elements.roundrect(layer, win, width-40, win.scroll["schedule"] + current_Y+5, 40, 40, 10, button=do, icon="ok", tip=talk.text("checked"), offset=[x,y]) current_Y = current_Y + 50 # DATE : TIME UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/schedule.png", 25, win.scroll["schedule"] + current_Y+5, 40, 40) UI_elements.text(layer, win, "schedule_date_setting", 80, win.scroll["schedule"] + current_Y+5, (width-80)/2-20, 40, set_text=entry[0], tip=talk.text("username"), offset=[x,y]) ### DELETE KEY ### if acur in ["chr", "veh", "loc","obj"]: itemtype = "assets" elif not acur: itemtype = "files" else: itemtype = "scenes" if 65535 in win.current["keys"]: pop = win.analytics["dates"][entry[0]][itemtype]\ [entry[1]].pop(thing[1]) win.current["keys"] = [] analytics.save(win.project, win.analytics) win.analytics = analytics.load(win.project) if win.text["schedule_date_setting"]["text"] != entry[0]\ and analytics.ifdate(win.text["schedule_date_setting"]["text"]): def do(): pop = win.analytics["dates"][entry[0]][itemtype]\ [entry[1]].pop(thing[1]) if win.text["schedule_date_setting"]["text"] not in win.analytics["dates"]: win.analytics["dates"][win.text["schedule_date_setting"]["text"]] = {} if itemtype not in win.analytics["dates"][win.text["schedule_date_setting"]["text"]]: win.analytics["dates"][win.text["schedule_date_setting"]["text"]][itemtype] = {} if entry[1] not in win.analytics["dates"][win.text["schedule_date_setting"]["text"]][itemtype]: win.analytics["dates"][win.text["schedule_date_setting"]["text"]][itemtype][entry[1]] = [] win.analytics["dates"][win.text["schedule_date_setting"]["text"]][itemtype]\ [entry[1]].append(pop) analytics.save(win.project, win.analytics) win.analytics = analytics.load(win.project) UI_elements.roundrect(layer, win, (width-80)/2+20, win.scroll["schedule"] + current_Y+5, 40, 40, 10, button=do, icon="ok", tip=talk.text("checked"), offset=[x,y]) # TIME UI_elements.text(layer, win, "schedule_time_setting", 80+(width-80)/2, win.scroll["schedule"] + current_Y+5, (width-80)/2, 40, set_text=thing[0][0], tip=talk.text("username"), offset=[x,y]) if win.text["schedule_time_setting"]["text"] != thing[0][0]\ and analytics.iftime(win.text["schedule_time_setting"]["text"]): def do(): thing[0][0] = win.text["schedule_time_setting"]["text"] analytics.save(win.project, win.analytics) win.analytics = analytics.load(win.project) UI_elements.roundrect(layer, win, width-40, win.scroll["schedule"] + current_Y+5, 40, 40, 10, button=do, icon="ok", tip=talk.text("checked"), offset=[x,y]) current_Y = current_Y + 70 else: current_Y = current_Y + 85 # Outputting the layer outlayer.set_source_surface(surface, x, y) outlayer.paint() # Scroll UI_elements.scroll_area(outlayer, win, "schedule", x+0, y+50, width, height-50, current_Y, bar=True, mmb=True)