# THIS FILE IS A PART OF VCStudio # PYTHON 3 import os from subprocess import * # 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 oscalls from settings import talk from settings import fileformats 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 analytics from studio import history from studio import studio_dialogs from studio import history def link_from_script(win): ######################################################################### # This file is here because there are multiple places in the window where # I want to link assets based on what's written in the text of the script. # So this file will basically parse the text and add the assets it finds # linked to the link list. ######################################################################### print("Reading from the scene") # Fist we need to know what scene and shot are we. if win.cur.count("/") > 1: tmp = win.cur.replace("/","",1).split("/") scene, shotis = tmp[0], tmp[1] else: scene = win.cur[win.cur.rfind("/")+1:] shotis = "" print(scene, shotis) # Now let's read through the scene. for shot in win.story["scenes"][scene]["shots"]: # Ignore the non shots. if shot[0] != "shot_block": continue # Ingore all other shots. if shot[1] != shotis: continue # Let's read the shot for asset in shot[-1]: # Ignore text if asset[0] == "text": continue # It's it's a staight up link. Just add it. if asset[0] == "link" and "/dev"+asset[1] not in win.current["linking_asset_data"]["assets"]: win.current["linking_asset_data"]["assets"].append("/dev"+asset[1]) # It's a link in a frase. if asset[0] == "frase" and asset[1][0] == "link" and "/dev"+asset[1][1] not in win.current["linking_asset_data"]["assets"]: win.current["linking_asset_data"]["assets"].append("/dev"+asset[1][1]) def layer(win, call): # 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, 40, 40, win.current["w"]-80, win.current["h"]-80, 10) ############################################################################## # This file is configuring and lanunching the linking into blend files. But it's # not the only file in the chain of files that is responsible for this operation. # For example the linking it self does studio/bpy_do_linking.py that is running # inside blender and communicates with this file for the UI side of things. ############################################################################## # Okay if not win.current["linking_asset_data"]["fraction"]: def do(): # Before we start let's record the history for it. history.record(win, win.project+win.current["linking_asset_data"]["linking_to"], "[Linked]") if not win.current["linking_asset_data"]["process"]: # So this is an apply button. I know it's a little not in the right # order. So please read the rest of the file to see what it does. # So now when a person clicks okay. We first need to save the # autolink.data. datafile = open(win.project+"/rnd"+win.cur+"/extra/autolink.data", "w") for asset in win.current["linking_asset_data"]["assets"]: datafile.write("Link : "+asset+"\n") # Also let's write the mode. Because it's important. datafile.write("Mode : "+win.current["linking_asset_data"]["mode"]+"\n") datafile.close() # Okay... now that we have the file. We can start the process of linking # Which will be done using Blender. So let's get blender's url blenderpath = oscalls.get_current_blender(win) # Now here is the fun part. We gonna start a background process # open there blender and will start linking stuff. win.current["linking_asset_data"]["process"] = Popen(['stdbuf', '-o0', blenderpath, \ "-b", win.project+win.current["linking_asset_data"]["linking_to"], \ "-P", os.getcwd()+"/studio/bpy_do_linking.py"],\ stdout=PIPE, universal_newlines=True) win.current["linking_asset_data"]["fraction"] = 0.01 # Hell of a command isn't it. UI_elements.roundrect(layer, win, win.current["w"]-120, win.current["h"]-80, 40, 40, 10, button=do, icon="ok", tip=talk.text("checked"), url="asset_link") # Documentation entry def do(): def after(win, var): pass studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_link_assets")) UI_elements.roundrect(layer, win, 300, 50, 40, 40, 10, do, "question") # CANCEl if not win.current["linking_asset_data"]["process"]: def do(): if not win.current["linking_asset_data"]["process"]: win.current["calls"][call]["var"] = False win.assets = {} UI_elements.roundrect(layer, win, win.current["w"]-80, win.current["h"]-80, 40, 40, 10, button=do, icon="cancel", tip=talk.text("cancel"), url="asset_link") # Short cut ESC if 65307 in win.current["keys"] and not win.textactive: do() # Now let's prepare the ground for the next part. # Before we do anything we need to make sure that there is an autolink.data # file in the extra folder of the shot. But since this is a system that is # designed to be very simple on the user side. There could not even be the # extra folder. So... try: os.mkdir(win.project+"/rnd"+win.cur+"/extra") except: pass # Next thing will be to see if there is a file called autolink.data. And if # yes read from it. We are going to load the data into the memory. # So if there is nothing yet loaded let's try loading it from file. Try # because there nothing quarantees that the file exists. If file does not # exists we gonna populate it with assets from the shot. As marked in the # scene the user wrote. But it's going to be a separate function since I # want to make a button to do it. if not win.current["linking_asset_data"]["assets"] and not win.current["linking_asset_data"]["read"]: win.current["linking_asset_data"]["read"] = True try: datafile = open(win.project+"/rnd"+win.cur+"/extra/autolink.data") datafile = datafile.read() datafile = datafile.split("\n") for line in datafile: if line.startswith("Link : "): asset = line[7:] win.current["linking_asset_data"]["assets"].append(asset) except: # So if it fails to load the file. Probably because it's not created # yet. Let's load from the story. What's so bad about it? link_from_script(win) # Now keep in mind that to help the script that runs inside blender all # assets have /dev/ in their folder. So to reach /ast/ blend file we will # need to parse the link. It's not hard just reminding it here. # IK everything is all over the place in the file but... # If there is a process. We should be able to see what it does. # Draw like a litte progress bar and stuff if win.current["linking_asset_data"]["process"]: # Basically during the execution of the linking. I want to read the # output and give the user some feedback of what is going on. currentline = win.current["linking_asset_data"]["process"].stdout.readline()[:-1] # In the bpy_do_linking.py file there is an instruction to write # out a fraction of a current operation into terminal. Which is # piped into the VCStudio and I can read it. So we can use it # to draw a progress bar. if currentline.startswith("FRACTION:"): try: fraction = float(currentline.split(":")[1]) win.current["linking_asset_data"]["fraction"] = fraction except: pass if currentline == "FINISHED": win.current["linking_asset_data"]["process"] = False win.current["linking_asset_data"]["fraction"] = 1 # The prgoress bar: if win.current["linking_asset_data"]["fraction"]: fraction = win.current["linking_asset_data"]["fraction"] UI_color.set(layer, win, "progress_background") UI_elements.roundrect(layer, win, 70, win.current["h"]-75, (win.current["w"]-220), 0, 7) UI_color.set(layer, win, "progress_active") UI_elements.roundrect(layer, win, 70, win.current["h"]-75, (win.current["w"]-220)*fraction, 0, 7) # This file will fuel of nightmares. Okay. So while developping it I realzed # one little problem. Overrides are kind a still buggy. Tho it's good to # have them for future releases. And most of rigs work just fine. # The thing that I want to do is to give the user options. Let's say their # rig is broken when trying Library- Overrides but it's okay if you do # legacy Proxy thing. So why not give the user the option of doing both. # And also sometimes you just want to link and decide later what you do with # your rig. # So I gonna make 3 icons. 3 modes so to speak. LINK, OVERRIDE, PROXY. linkoptions = { "link":"link_mode_link", "override":"link_mode_overrides", # Icon / Mode : Tooltip "proxy":"link_mode_proxy" } for num, mode in enumerate(linkoptions): if win.current["linking_asset_data"]["mode"] == mode: UI_color.set(layer, win, "progress_time") UI_elements.roundrect(layer, win, 50+(40*num), 50, 40, 40, 10) def do(): win.current["linking_asset_data"]["mode"] = mode UI_elements.roundrect(layer, win, 50+(40*num), 50, 40, 40, 10, do, mode, tip=talk.text(linkoptions[mode])) # Let's add a button that adds assets based on what's written in the script. def do(): link_from_script(win) UI_elements.roundrect(layer, win, 200, 50, 40, 40, 10, do, "scene_new", tip=talk.text("link_add_from_scene")) if not os.path.exists(win.project+win.current["linking_asset_data"]["selected"]+"/autolink.data")\ or not os.path.exists(win.project+win.current["linking_asset_data"]["selected"].replace("/dev/","/ast/")+".blend"): def do(): def after(win, var): print(var) studio_dialogs.asset_configure(win, "configuring_asset", after, win.current["linking_asset_data"]["selected"].replace("/dev","")) UI_elements.roundrect(layer, win, 250, 50, 40, 40, 10, button=do, icon="link_configure") # That's it. Now we are clipping and drawing the assets them selves. UI_elements.roundrect(layer, win, 50, 100, win.current["w"]-100, win.current["h"]-200, 10, fill=False) layer.clip() tileX = 70 current_Y = 0 if "asset_link" not in win.scroll: win.scroll["asset_link"] = 0 ############################# # Let's draw the list of assets that the user chose. for num, asset in enumerate(win.current["linking_asset_data"]["assets"]): cur, name = asset.split("/")[2], asset.split("/")[3] if int(current_Y + win.scroll["asset_link"] + 100) in range(0-100, win.current["h"]): # Making the layer nodesurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 170, 200) node = cairo.Context(nodesurface) node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) UI_elements.roundrect(node, win, 0, 0, 170, 200, 10, fill=False) node.clip() # Background UI_color.set(node, win, "dark_overdrop") node.rectangle(0,0,170, 200) node.fill() # Banner UI_color.set(node, win, "node_asset") # Now the banner will be node_asset color if the asset is configured # but it could be not configured. Or not even have the asset blend. # so we need to quickly check both. And if any of them missing. Make # the banner a node_badfile color. warning = "" if not os.path.exists(win.project+asset+"/autolink.data")\ or not os.path.exists(win.project+asset.replace("/dev/","/ast/")+".blend"): UI_color.set(node, win, "node_badfile") warning = "\n"+talk.text("link_asset_not_configured") # Let's do even cooler. And let's draw a thing arround the asset. node.set_line_width(10) UI_elements.roundrect(node, win, 0, 0, 170, 200, 10, fill=False) node.stroke() node.set_line_width(2) # Even cooler. Let's put a configuration button right into here node.rectangle(0,0,170, 20) node.fill() # Outputting the layer layer.set_source_surface(nodesurface, tileX-10, current_Y + win.scroll["asset_link"] + 120) layer.paint() # Previes image if os.path.exists(win.project+asset+"/renders/Preview.png"): UI_elements.image(layer, win, win.project+asset+"/renders/Preview.png", tileX, current_Y + win.scroll["asset_link"] + 140, 150, 150) elif os.path.exists(win.project+asset+"/renders/Preview.jpg"): UI_elements.image(layer, win, win.project+asset+"/renders/Preview.jpg", tileX, current_Y + win.scroll["asset_link"] + 140, 150, 150) else: UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/"+cur+".png", tileX+55, current_Y + win.scroll["asset_link"] + 150+55, 150, 150) UI_color.set(layer, win, "text_normal") layer.set_font_size(12) layer.move_to(tileX, current_Y + win.scroll["asset_link"] + 135) layer.show_text(name[:22]) # Let's make a selection of an asset so you could delete one. Or # do other stuff. Maybe. if win.current["linking_asset_data"]["selected"] == asset: layer.set_line_width(4) UI_color.set(layer, win, "progress_background") UI_elements.roundrect(layer, win, tileX-10, current_Y + win.scroll["asset_link"] + 120, 170, 200, 10, fill=False) layer.stroke() layer.set_line_width(2) # And the delete key. if 65535 in win.current["keys"]: try: win.current["linking_asset_data"]["assets"].remove(asset) except: pass win.current["keys"] = [] # Button to activate it def do(): win.current["linking_asset_data"]["selected"] = asset layer.set_line_width(4) UI_elements.roundrect(layer, win, tileX-10, current_Y + win.scroll["asset_link"] + 120, 170, 200, 10, button=do, tip=talk.text(cur)+": "+name+warning, fill=False, clip=[ 50, 100, win.current["w"]-100, win.current["h"]-200 ], url="asset_link") layer.stroke() layer.set_line_width(2) tileX += 200 if tileX > win.current["w"]-220: tileX = 70 current_Y += 230 # Now here I want to put the add new one button. So you could add assets # to the stuff manually. def do(): # Now this is going to be wild. Because I'm going to run a dialog with # in a dialog. And I hope that it's going to work. def after(win, var): # Funny that it's actually working. # Tho there is a little rub. If you press Cancel there is a bug that # makes nothing unusable. so... try: del win.current["calls"]["link_add_asset_select"] except: pass if var and "/dev"+var not in win.current["linking_asset_data"]["assets"]: win.current["linking_asset_data"]["assets"].append("/dev"+var) # So basically I want to add one only if there is not one already. # And then select it. So if the use gets which one is added or # whether it was already there. win.current["linking_asset_data"]["selected"] = "/dev"+var # And since it could allight with the add button. Let's clear the # click win.current["LMB"] = False win.previous["LMB"] = False studio_dialogs.asset_select(win, "link_add_asset_select", after) UI_elements.roundrect(layer, win, tileX-10, current_Y + win.scroll["asset_link"] + 120, 170, 200, 10, button=do, url="asset_link") UI_color.set(layer, win, "progress_background") UI_elements.roundrect(layer, win, tileX-10, current_Y + win.scroll["asset_link"] + 120, 170, 200, 10, fill=False) layer.stroke() UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/asset_new.png", tileX+55, current_Y + win.scroll["asset_link"] + 200, 40, 40) ############################# current_Y += 230 UI_elements.scroll_area(layer, win, "asset_link", 50, 100, win.current["w"]-100, win.current["h"]-200, current_Y, bar=True, mmb=True, url="asset_link", strenght=130 ) return surface