From df5b615ef9e0c518d1aef387f29cf1c1703707c1 Mon Sep 17 00:00:00 2001 From: "Jeison Yehuda Amihud (Blender Dumbass)" Date: Mon, 14 Dec 2020 03:21:25 +0000 Subject: [PATCH] Upload files to 'studio' --- studio/checklist.py | 13 +- studio/history.py | 612 +++++++++++++++++++++++++++++ studio/schedule.py | 164 +++++++- studio/studio_analyticsLayer.py | 137 ++++++- studio/studio_assetLayer.py | 222 ++++++++++- studio/studio_asset_selectLayer.py | 5 + studio/studio_nodes.py | 1 + studio/studio_storyLayer.py | 128 +++++- 8 files changed, 1243 insertions(+), 39 deletions(-) create mode 100644 studio/history.py diff --git a/studio/checklist.py b/studio/checklist.py index 121d9e1..35adb0b 100644 --- a/studio/checklist.py +++ b/studio/checklist.py @@ -13,6 +13,7 @@ from settings import talk #studio from studio import analytics +from studio import history def get_list(filepath): @@ -463,9 +464,11 @@ def draw(outlayer, win, path, back="story_editor"): if "schedule_task_selected" not in win.current: win.current["schedule_task_selected"] = False - if win.current["schedule_task_selected"]: + if win.current["schedule_task_selected"] and win.cur == win.current["schedule_task_selected"][-1]: csl = win.current["schedule_task_selected"][0][0][4] + print(win.current["schedule_task_selected"]) + if " "+task["string"] in csl and not task["open"]: task["open"] = True @@ -595,7 +598,7 @@ def draw(outlayer, win, path, back="story_editor"): if win.current["mx"] < x: win.url = "analytics" - win.current["grab_data"] = [path, back, win.cur, schedulepath] + win.current["grab_data"] = [path, back, win.cur, schedulepath, win.settings["Username"]] win.current["tool"] = "schedule" # # @@ -743,14 +746,16 @@ def draw(outlayer, win, path, back="story_editor"): def do(): if task["fraction"]: task["fraction"] = 0.0 + history.record(win, path, "[Un-Checked]", schedulepath) else: task["fraction"] = 1.0 - + history.record(win, path, "[Checked]", schedulepath) + # Saving save(path, win.checklists[path]) win.checklists = {} win.assets = {} - win.analytics = analytics.load(win.project) + #win.analytics = analytics.load(win.project) UI_elements.roundrect(layer, win, sx, diff --git a/studio/history.py b/studio/history.py new file mode 100644 index 0000000..7a6b669 --- /dev/null +++ b/studio/history.py @@ -0,0 +1,612 @@ +# 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 hande HISTORY. Both recoring and showing. I suppose in +# future when I gonna implement Networking Multiuser support. History will be +# handling some of it too. Will see. ( I might forget about this comment and it's +# already implemented, who knows. ) + +################################################################################ + +def record(win, filename, task, checklist=[] ): + + ############################################################################ + + # This function will write the history file. Or incase connecting to multiuser + # will also notify the server of a task being done. This file probably going + # to change quite usually. Because I might start writting in more or less + # stuff. So keep an eye on it. + + # Now since this will touch the multiuser and I can't guarantee that all + # users will have the same version. The multiuser part of this should insure + # stable backward compatibility with all verisons of VCStudio. + + # BUT THERE IS NO WARRANTY! So who knows if exidentaly break something for + # the old versions. So keeping up to date quite advisable. Or at least keep + # the same version of VCStudio across all the computers involved in multiuser. + + ############################################################################ + + ################### CHECKLIST OF IMPEMENTED DATATYPES ###################### + + # [V] [Openned] # WHEN BLEND FILE IS OPENNED [ settings/oscalls.py ] + # [ ] [Linked] # AS LINKED ASSET INTO BLEND [] + # [ ] [Edited] # WHEN EDITED STORY [] + # [ ] [Updated] # WHEN CONFIGURED STUFF [] + # [V] [Added] # WHEN ADDING A BLEND FILE [ settings/oscalls.py ] + # [V] [Added Asset] # WHEN ADDING AN ASSET [ studio/studio_asset_selectLayer.py ] + # [V] [Checked] # WHEN [V] IN CHECKLIST [ studio/checklist.py ] + # [V] [Un-Checked] # WHEN [ ] IN CHECKLIST [ studio/checklist.py ] + + ############################################################################ + + ############### PARSING THE URLS ############## + + print("HISTORY-RAW: ", filename, task, checklist) + + # Fisrt of all let's remove the project's url + filename = filename.replace(win.project, "").replace("//", "/") + + # Now let's find a type + t = "files" + item = filename + if filename.startswith("/rnd"): + t = "scenes" + item = filename.replace("/rnd", "") + filename = filename[filename.rfind("/"):] + + elif filename.startswith("/ast") or filename.startswith("/dev"): + t = "assets" + + if filename.startswith("/ast"): + filename = "[asset_blend]" + item = item.replace(".blend", "").replace("/ast", "") + + elif filename.startswith("/dev"): + f = filename[filename.rfind("/"):] + item = filename.replace(f, "").replace("/dev", "") + filename = f + else: + filename = filename[filename.rfind("/"):] + + item = item.replace("//", "/") + filename = filename.replace("//", "/") + + print("HISTORY: ", t, item, filename, task, checklist) + + + ########### WRITING TO THE ANANLYTICS ########### + + new_date_format = "%Y/%m/%d" + date = datetime.datetime.strftime(datetime.datetime.today(), new_date_format) + + seconds_format = "%H:%M:%S" + time = datetime.datetime.strftime(datetime.datetime.now(), seconds_format) + + username = win.settings["Username"] + + # Now since we have our DATE and TIME we can start writing. + + + if date not in win.analytics["dates"]: + win.analytics["dates"][date] = {} + if t not in win.analytics["dates"][date]: + win.analytics["dates"][date][t] = {} + if item not in win.analytics["dates"][date][t]: + win.analytics["dates"][date][t][item] = [] + + # APPENDNING + if not checklist: + win.analytics["dates"][date][t][item].append( + [ + time, + "history", + filename, + task, + username + ] + ) + else: + win.analytics["dates"][date][t][item].append( + [ + time, + "history", + filename, + task, + checklist, + username + ] + ) + + # REFRASHING + + analytics.save(win.project, win.analytics) + win.analytics = analytics.load(win.project) + +def draw(outlayer, win): + + x = 10 + y = 70 + width = win.current["w"] / 4 - 20 + height = win.current["h"] - 80 + + + # 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() + + # Background + #UI_color.set(layer, win, "dark_overdrop") + #layer.rectangle(0,0,width, height) + #layer.fill() + + new_date_format = "%Y/%m/%d" + today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format) + + if not win.cur: + 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")) + + + if "history" not in win.scroll: + win.scroll["history"] = 0 + + current_Y = 0 + + # OKAY I GUESS SINCE HISTORY IS RELATIVELLY SIMPLE (LOL) I WILL PARSE IT + # STRAIGHT. Without making a whole lot of parsing. Because with schedules + # it resulted in some rather hilarious stuff. + + if "history_selection" not in win.current: + win.current["history_selection"] = { + "date":win.current["date"], + "item":False, + "user":False + } + + dates = win.analytics["dates"] + + + for date in dates: + + if not win.cur and date != win.current["date"]: + continue + + theday = date + date = dates[date] + + # Now let's parse throught it. I guess. + + for i in ["files", "assets", "scenes"]: + if i in date: + for item in date[i]: + + # This is our individual items. I want to create a folder + # with USERS inside it. So you could see who done what. + + if win.cur and win.cur != item: + continue + + found = {} + + for stuff in date[i][item]: + if stuff[1] == "history": + if stuff[-1] not in found: + found[stuff[-1]] = [] + if stuff[3] in ["[Checked]", "[Un-Checked]"]: + found[stuff[-1]].append([stuff[0],stuff[2],stuff[3],stuff[4]]) + else: + found[stuff[-1]].append([stuff[0],stuff[2],stuff[3],[]]) + + if found: + # Now let's output our findings + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + 0, + win.scroll["history"] + current_Y, + width, + 50, + 10) + + name = item[item.rfind("/")+1:] + acur = item.replace(name, "").replace("/", "") + + + # ICON + if i == "scenes" and not win.cur: + UI_elements.image(layer, win, + "settings/themes/"+win.settings["Theme"]+"/icons/vse.png", + 5, win.scroll["history"] + current_Y+5, 40, 40) + elif i == "assets" and not win.cur: + + if os.path.exists(os.getcwd()+"/settings/themes/"+win.settings["Theme"]+"/icons/"+acur+".png"): + + UI_elements.image(layer, win, + "settings/themes/"+win.settings["Theme"]+"/icons/"+acur+".png", + 5, win.scroll["history"] + current_Y+5, 40, 40) + else: + + UI_elements.image(layer, win, + "settings/themes/"+win.settings["Theme"]+"/icons/"+name+".png", + 5, win.scroll["history"] + current_Y+5, 40, 40) + + name = talk.text(name.replace("/", "")) + else: + UI_elements.image(layer, win, + "settings/themes/"+win.settings["Theme"]+"/icons/history.png", + 5, win.scroll["history"] + 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["history"] + current_Y+30, + ) + if not win.cur: + layer.show_text(name) + else: + layer.show_text(theday) + # Selection button + + def do(): + + win.current["history_selection"]["item"] = item + win.current["history_selection"]["date"] = theday + win.current["history_selection"]["user"] = False + + UI_elements.roundrect(layer, win, + 0, + win.scroll["history"] + current_Y, + width, + 50, + 10, + button=do, + fill=False, + offset=[x,y]) + layer.stroke() + + if win.current["history_selection"]["item"] == item\ + and win.current["history_selection"]["date"] == theday: + + UI_color.set(layer, win, "progress_background") + UI_elements.roundrect(layer, win, + 0, + win.scroll["history"] + current_Y, + width, + 50, + 10, + fill=False) + layer.stroke() + + current_Y = current_Y + 60 + + # It a history is selected you could open up the list + # of users that worked on a given task. + + for user in found: + + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + 20, + win.scroll["history"] + current_Y, + width-20, + 50, + 10) + + UI_elements.image(layer, win, + "settings/themes/"+win.settings["Theme"]+"/icons/user.png", + 25, win.scroll["history"] + current_Y+5, 40, 40) + + # NAME OF THE USER + + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to( + 70, + win.scroll["history"] + current_Y+30, + ) + layer.show_text(user) + + # SELECTION BOX + + def do(): + + win.current["history_selection"]["user"] = user + + UI_elements.roundrect(layer, win, + 20, + win.scroll["history"] + current_Y, + width-20, + 50, + 10, + button=do, + fill=False, + offset=[x,y]) + layer.stroke() + + # IF THE USER IS SELECTED + + if win.current["history_selection"]["user"] == user: + + UI_color.set(layer, win, "progress_background") + UI_elements.roundrect(layer, win, + 20, + win.scroll["history"] + current_Y, + width-20, + 50, + 10, + fill=False) + layer.stroke() + + current_Y = current_Y + 60 + + for stuff in found[user]: + + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + 40, + win.scroll["history"] + current_Y, + width-40, + 50, + 10) + + + # Here if both category and the user are + # selected I need to parse the data of + # the history to present it to you. + + operation_icons = { + "[Openned]":"blender", + "[Linked]":"file_link", + "[Edited]":"copy_file", + "[Updated]":"update", + "[Added]":"new", + "[Added Asset]":"asset_new", + "[Checked]":"checked", + "[Un-Checked]":"unchecked" + } + + + try: + icon = operation_icons[stuff[2]] + except: + icon = "history" + + UI_elements.image(layer, win, + "settings/themes/"+win.settings["Theme"]+"/icons/"+icon+".png", + 45, win.scroll["history"] + current_Y+5, 40, 40) + + # Next will be to add some text about + # what exactly was done here. And I know + # that we are already super inside. I + # mean indentation. If somebody want's + # to reduse a few spaces. They are + # welcome to try. + + # Let's split the the history entries to + # 2 types. Checklists and everything else. + + # CHECKLISTS + if "Checked" in stuff[2]: + + # Let's get task and url + try: + task = stuff[-1][-1] + fullurl = "" + for e in stuff[-1][:-1]: + fullurl = fullurl+e+" > " + except: + tasl = "" + fullurl = "" + + + # MAIN TASK + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to( + 80, + win.scroll["history"] + current_Y+24, + ) + layer.show_text(task) + + + # TASK URL INSIDE THE CHECKLIST + + if fullurl: + UI_color.set(layer, win, "text_normal") + layer.set_font_size(10) + layer.move_to( + 90+len(task)*12, + win.scroll["history"] + current_Y+24, + ) + layer.show_text(fullurl) + + else: + # If it's not a checklist. I just want + # to output what it is and what action + # happened to it. + + task = stuff[1].replace("/", " ") + if task == "[asset_blend]": + task = " Asset Blend File" + + # WHAT + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to( + 80, + win.scroll["history"] + current_Y+24, + ) + layer.show_text(task) + + + # WHAT WAS DONE + + UI_color.set(layer, win, "text_normal") + layer.set_font_size(10) + layer.move_to( + 90+len(task)*12, + win.scroll["history"] + current_Y+24, + ) + layer.show_text(stuff[2]) + + UI_color.set(layer, win, "text_normal") + layer.set_font_size(15) + layer.move_to( + 92, + win.scroll["history"] + current_Y+41, + ) + layer.show_text(stuff[0]) + + # Okay and the last thing. The button of + # when it's clicked. For example to get + # to the item. Or to find the task in + # the checklist. For what ever reason. + + def do(): + + # Let's make the auto-selecting of + # the checklists. OMG I really have + # no space left to type. OMG. What + # is this. + + if "Checked" in stuff[2]: + + # AAAAAAAAAAAAAAAAAAAAAAAAAAAA + # How am I supposed to tell thi- + # ngs? OMG. + + if "schedule_task_selected" not in win.current: + win.current["schedule_task_selected"] = [] + + win.current["schedule_task_selected"] = \ + [[[stuff[0], "schedule", stuff[1], stuff[2], stuff[3]], 0], item] + + # Now since we did this weird + # what ever the mack. Let's make so + # it's going to the asset. + + if i == "assets": + goto = "assets" + elif i == "scenes": + goto = "script" + else: + goto = "analytics" + + win.url = goto + win.cur = item + win.current["asset_left_panel"] = "history" + + if stuff[2] != "[Added Asset]": + + UI_elements.roundrect(layer, win, + 40, + win.scroll["history"] + current_Y, + width-40, + 50, + 10, + button=do, + fill=False, + offset=[x,y]) + layer.stroke() + + + current_Y = current_Y + 60 + else: + current_Y = current_Y + 60 + else: + current_Y = current_Y + 60 + + # Outputting the layer + outlayer.set_source_surface(surface, x, y) + outlayer.paint() + + # Scroll + UI_elements.scroll_area(outlayer, win, "history", + x+0, + y+50, + width, + height-50, + current_Y, + bar=True, + mmb=True) diff --git a/studio/schedule.py b/studio/schedule.py index 3b73cea..47f7e99 100644 --- a/studio/schedule.py +++ b/studio/schedule.py @@ -224,6 +224,48 @@ def draw(outlayer, win): 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: @@ -252,6 +294,8 @@ def draw(outlayer, win): 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("/", "") @@ -259,6 +303,21 @@ def draw(outlayer, win): 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 @@ -289,19 +348,22 @@ def draw(outlayer, win): # Selection button def do(): - 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 + 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, @@ -314,6 +376,84 @@ def draw(outlayer, win): 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", diff --git a/studio/studio_analyticsLayer.py b/studio/studio_analyticsLayer.py index af04c17..ddb5787 100644 --- a/studio/studio_analyticsLayer.py +++ b/studio/studio_analyticsLayer.py @@ -31,6 +31,7 @@ from studio import checklist from studio import analytics from studio import studio_dialogs from studio import schedule +from studio import history def layer(win): @@ -436,6 +437,8 @@ def layer(win): # Now let's make a layer. + + if "graph_cashe" not in win.current: @@ -527,7 +530,13 @@ def layer(win): # 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 ################ @@ -592,7 +601,8 @@ def layer(win): 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, @@ -607,6 +617,7 @@ def layer(win): def do(): win.current["date"] = today win.text["current_date_setting"]["text"] = today + win.textactive = "" UI_elements.roundrect(layer, win, x+260, @@ -736,11 +747,73 @@ def layer(win): 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(): - win.current["date"] = theday - win.text["current_date_setting"]["text"] = theday + + + + 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] = [] + + 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 = {} + + else: + win.current["date"] = theday + win.text["current_date_setting"]["text"] = theday + UI_elements.roundrect(node, win, 5+current_X+win.scroll["days"], 67, @@ -845,9 +918,20 @@ def layer(win): if win.current["tool"] == "schedule": - path, back, cur, schedulepath = win.current["grab_data"] + # If the tool is scheduling I want to make sure that the user sees where + # he needs to place the task. A higlight. - print(schedulepath) + 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) @@ -874,6 +958,14 @@ def layer(win): 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, @@ -881,8 +973,39 @@ def layer(win): 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) - schedule.draw(layer, win) + 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 diff --git a/studio/studio_assetLayer.py b/studio/studio_assetLayer.py index 47a97a4..b636b81 100644 --- a/studio/studio_assetLayer.py +++ b/studio/studio_assetLayer.py @@ -30,6 +30,7 @@ from studio import checklist from studio import analytics from studio import studio_dialogs from studio import schedule +from studio import history def layer(win): @@ -335,7 +336,7 @@ def layer(win): if os.path.exists(win.project+"/ast"+win.cur+".blend") and not newcreate: files.append(["/ast"+win.cur+".blend", "node_asset"]) foundblend = True - for f in os.listdir(win.project+"/dev"+win.cur): + for f in sorted(os.listdir(win.project+"/dev"+win.cur)): if not os.path.isdir(win.project+"/dev"+win.cur+"/"+f): # This is for only the blend files. So let's filter the out of all @@ -361,7 +362,7 @@ def layer(win): elif win.current["asset_cur_folder"] == "render": fl = "renders" - for f in os.listdir(win.project+"/dev"+win.cur+"/"+fl): + for f in sorted(os.listdir(win.project+"/dev"+win.cur+"/"+fl)): if not os.path.isdir(win.project+"/dev"+win.cur+"/"+fl+"/"+f): if newcreate == f: @@ -774,6 +775,12 @@ def layer(win): if win.current["asset_left_panel"] == "schedule": schedule.draw(layer, win) + ### HISTORY ### + + if win.current["asset_left_panel"] == "history": + history.draw(layer, win) + + ### SCENES ### # CANCEl @@ -794,7 +801,216 @@ def layer(win): # Short cut ESC if 65307 in win.current["keys"] and not win.textactive: - do() + do() + + if win.current["asset_left_panel"] == "vse": + + # Here I want to parse the story data in pusuit of all the scenes that + # have the asset. I think I'm going to make it per shot based. Like + # you have the scenes. And you can open them to enter shots. Maybe with + # a tiny exserp from the story. + + if "asset_scenes" not in win.scroll: + win.scroll["asset_scenes"] = 0 + + if "asset_scene_selected" not in win.current: + win.current["asset_scene_selected"] = False + + x = 10 + y = 70 + width = win.current["w"] / 4 - 20 + height = win.current["h"] - 80 + + + UI_elements.roundrect(layer, win, + x, + y, + width, + height, + 10, + fill=False) + layer.clip() + + current_Y_scenes = 0 + + scenes = win.story["scenes"] + + for scene in scenes: + fraction = scenes[scene]["fraction"] + shots = scenes[scene]["shots"] + + foundinscene = [] + + for block in shots: + + si = 1 + if block == "shot_block": + si = 2 + + found = [] + + for n, stuff in enumerate(block[si]): + if stuff[0] == "link" and stuff[1] == win.cur: + + start = "" + part = stuff[-1] + end = "" + + if n > 0: + start = block[si][n-1][-1] + start = start.replace("\n", " ") + + if n < len(block[si])-1: + end = block[si][n+1][-1] + end = end.replace("\n", " ") + + found = [start, part, end] + if si == 2: + foundinscene.append([block[1],found]) + else: + foundinscene.append(["",found]) + + if foundinscene: + + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + x, + y+win.scroll["asset_scenes"]+current_Y_scenes, + width, + 70, + 10) + + # ICON + UI_elements.image(layer, win, + "settings/themes/"+win.settings["Theme"]+"/icons/vse.png", + 20, y+win.scroll["asset_scenes"] + current_Y_scenes+5, 40, 40) + + # SELECTION + def do(): + if win.current["asset_scene_selected"] == scene: + win.current["asset_scene_selected"] = False + else: + win.current["asset_scene_selected"] = scene + + + UI_elements.roundrect(layer, win, + x, + y+win.scroll["asset_scenes"]+current_Y_scenes, + width, + 70, + 10, + button=do, + fill=False) + layer.stroke() + + # SCENE NAME + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to( x+60, y+win.scroll["asset_scenes"] + current_Y_scenes+30) + layer.show_text(scene) + + # FRACTION + UI_color.set(layer, win, "progress_background") + UI_elements.roundrect(layer, win, + x+10, + y+50+win.scroll["asset_scenes"] + current_Y_scenes, + width-20, + 0, + 5) + + UI_color.set(layer, win, "progress_active") + UI_elements.roundrect(layer, win, + x+10, + y+50+win.scroll["asset_scenes"] + current_Y_scenes, + (width-20)*fraction, + 0, + 5) + + # IF SELECTED + if win.current["asset_scene_selected"] == scene: + UI_color.set(layer, win, "progress_background") + UI_elements.roundrect(layer, win, + x, + y+win.scroll["asset_scenes"]+current_Y_scenes, + width, + 70, + 10, + fill=False) + layer.stroke() + + # Here if the current scene is selected I want to draw all + # the parts of the scene. It's already a bit more complex + # then what was in the Blender-Organizer legacy. + + current_Y_scenes = current_Y_scenes + 80 + + for block in foundinscene: + + # If it's a shot let's mark in the different color. + + if block[0]: + UI_color.set(layer, win, "node_background") + else: + UI_color.set(layer, win, "dark_overdrop") + UI_elements.roundrect(layer, win, + x, + y+win.scroll["asset_scenes"]+current_Y_scenes, + width, + 30, + 10) + + start = block[1][0] + name = block[1][1] + end = block[1][2] + + sp = x+width/2-len(name)*12/2-len(start)*12 + np = x+width/2-len(name)*12/2 + ep = x+width/2+len(name)*12/2 + + if sp > x+5 and x+5 + ep + len(end)*12 > width: + sp = x+5 + np = x+5 + len(start)*12 + ep = x+5 + len(start)*12 + len(name)*12 + + elif ep + len(end)*12 < width and sp < x+5: + ep = width - len(end)*12 + np = ep - len(name)*12 + sp = np - len(start)*12 + + # BEFORE NAME + UI_color.set(layer, win, "button_active") + layer.set_font_size(20) + layer.move_to( sp, y+win.scroll["asset_scenes"] + current_Y_scenes+20) + layer.show_text(start) + + # NAME AS MENTIONED IN THE SCRIPT + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to(np, y+win.scroll["asset_scenes"] + current_Y_scenes+20) + layer.show_text(name) + + # AFTER NAME + UI_color.set(layer, win, "button_active") + layer.set_font_size(20) + layer.move_to( ep, y+win.scroll["asset_scenes"] + current_Y_scenes+20) + layer.show_text(end) + + current_Y_scenes = current_Y_scenes + 40 + + else: + current_Y_scenes = current_Y_scenes + 80 + + # Scroll + UI_elements.scroll_area(layer, win, "asset_scenes", + x+0, + y+50, + width, + height-50, + current_Y_scenes, + bar=True, + mmb=True) + + diff --git a/studio/studio_asset_selectLayer.py b/studio/studio_asset_selectLayer.py index 951be5f..3d6fb3f 100644 --- a/studio/studio_asset_selectLayer.py +++ b/studio/studio_asset_selectLayer.py @@ -26,6 +26,7 @@ from UI import UI_color # story from studio import story from studio import analytics +from studio import history def layer(win, call): @@ -338,6 +339,10 @@ def layer(win, call): os.mkdir(win.project+"/dev/"+win.current["asset_cur"]+"/"+newcreate+"/renders") os.mkdir(win.project+"/dev/"+win.current["asset_cur"]+"/"+newcreate+"/reference") os.mkdir(win.project+"/dev/"+win.current["asset_cur"]+"/"+newcreate+"/tex") + + # Recodring to history + history.record(win, win.project+"/dev/"+win.current["asset_cur"]+"/"+newcreate, "[Added Asset]") + except: pass diff --git a/studio/studio_nodes.py b/studio/studio_nodes.py index 38378e9..18dfb89 100644 --- a/studio/studio_nodes.py +++ b/studio/studio_nodes.py @@ -720,6 +720,7 @@ def link_node(outlayer, win, x, y, width=150, height=150, name="", num=0, linkty win.url = "assets" win.cur = name win.current["tool"] = "selection" + win.previous["LMB"] = False if win.current["LMB"] and win.current["tool"] == "selection": diff --git a/studio/studio_storyLayer.py b/studio/studio_storyLayer.py index dbda61d..a826872 100644 --- a/studio/studio_storyLayer.py +++ b/studio/studio_storyLayer.py @@ -23,6 +23,7 @@ from studio import studio_nodes from studio import studio_dialogs from studio import story from studio import analytics +from studio import schedule #UI modules from UI import UI_elements @@ -78,7 +79,7 @@ def layer(win): UI_elements.roundrect(layer, win, 5, 5, - win.current["w"]-10, + win.current["w"]-(win.current["w"]/3)+45, 40, 10, do, @@ -128,28 +129,129 @@ def layer(win): layer.line_to(win.current["w"]/3*2+55, 45) layer.stroke() - # Schedule - UI_elements.image(layer, win, "settings/themes/"\ - +win.settings["Theme"]+"/icons/schedule.png", - win.current["w"]/3*2+60, - 5, - 40, - 40) - # Temporarely: + + ############ CURRENT TASK SCHEDULED ############# + + + # FIRST WE NEED TO GET A LIST OF TASKS + # This is going to be a simplified version of the same stuff as in the + # scheduling. But since we don't care what date we are in and trying to + # get the oldest unchecked task. Here we go. + + schedules = schedule.get_schedules(win.analytics["dates"]) + new_date_format = "%Y/%m/%d" + today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format) + + slist = [] + for date in schedules: + for item in schedules[date]: + if win.cur == item or not win.cur: + slist.append([date, item, schedules[date][item]]) + + + # Now that we have our list we can start paring it the same way as in the + # scheduling. Only removing some unnesesary stuff. + foundtask = False + taskname = "" + taskurl = "" + taskcur = "" + + for entry in slist: + if not foundtask: + for thing in entry[2]: + if thing[0][3] == "[Checked]": + continue # We do not care about those who are checked here. + elif thing[0][-1] != win.settings["Username"]: + continue # We do not care if it's not for us + else: + foundtask = True + + # Here we are going to take out some data about this task + + # First if it's not for today let's get a color for it + if entry[0] != "1997/07/30": + draw = False + if entry[0] < today: + UI_color.set(layer, win, "node_badfile") # The Red + draw = True + elif entry[0] > today: + UI_color.set(layer, win, "node_asset") # The Purple + draw = True + if draw: + UI_elements.roundrect(layer, win, + win.current["w"]/3*2+60, + 5, + (win.current["w"]/3-65), + 40, + 10) + + 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"]: + assetname = talk.text(acur)+": "+name + else: + assetname = entry[1] + + # ASSINGING TEXT VALUES + taskname = thing[0][4][-1] + taskurl = fullurl + taskcur = assetname + + # AND A TINY BUTTON TO ENTER WHAT EVER YOU ARE DOING + goto = "analytics" + if acur in ["chr", "veh", "loc","obj"]: + goto = "assets" + itemtype = "assets" + elif not acur: + itemtype = "files" + else: + goto = "script" + itemtype = "scenes" + + def do(): + win.url = goto + win.cur = entry[1] + win.current["asset_left_panel"] = "schedule" + UI_elements.roundrect(layer, win, + win.current["w"]/3*2+60, + 5, + (win.current["w"]/3-65), + 40, + 10, + button=do) + + break + else: + break + + # Schedule + if taskname: + UI_elements.image(layer, win, "settings/themes/"\ + +win.settings["Theme"]+"/icons/schedule.png", + win.current["w"]/3*2+60, + 5, + 40, + 40) UI_color.set(layer, win, "text_normal") layer.set_font_size(20) layer.move_to(win.current["w"]/3*2+120, 25) - layer.show_text("The Next Task") + layer.show_text(taskname) layer.set_font_size(12) - layer.move_to(win.current["w"]/3*2+130+len("The Next Task")*12, 25) - layer.show_text("from: AllTasks > Subtasks > This") + layer.move_to(win.current["w"]/3*2+130+len(taskname)*12, 25) + layer.show_text(taskurl) layer.set_font_size(12) layer.move_to(win.current["w"]/3*2+120, 40) - layer.show_text("Character: Moria") + layer.show_text(taskcur) ########### TIMES RECORDING FOR PERFONMANCE MEASURING #############