# THIS FILE IS A PART OF VCStudio # PYTHON 3 import os import datetime 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 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 # Studio from studio import studio_dialogs from studio import analytics from studio import story from studio import history def layer(win, call): ########################################################################## # This file will do the asset configuration for linking assets into anima- # tion files. The ways it's going to be performed is following: # 0. User creates the asset. The /dev/ folder for the asset is created. # 1. User finished the asset and the checklists is now 100%. # 2. User Clicks on a configure button which launches this UI. # 3. User choses the main blendfile. It is copied to the /ast/ folder. # 4. User choses the collection and the rig with in the file. and it's # saved into autolink.data # 5. User creates a shot in the script editor. And creates a blend-file. # 6. Use presses the link button on the blend file. And it loads the assets # mentioned in the script. # 7. User presses the okay button and a script is running inside blender # that will read autolink.data files. And open /ast/ blend files. From # which it will loaded the right collection and make library override or # proxy to the rig. Both specified here by the user. # See: # studio/studio_shot_linkLayer.py # studio/bpy_do_linking.py # studio/studio_assetLayer.py # The way this file going to work will be like a step by step wizzard. # This file will be able to be openned from studio_shot_linkLayer dialog so # there will be 3 different UIs in this file. # 0. If checklist is not yet 100%. There will be a message to finish the # asset first. # 1. When the checklist is 100%. There will UI to select / copy /ast/file # 2. When that's done. The program going to launch a script to read data # from the newly created /ast/ file. And will present the user with # selection of collections and objects from the collections. So to # what to link and what to proxy. ########################################################################## # 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"]/2-250, 100, 500, win.current["h"]-200, 10) # 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, win.current["w"]/2-250, win.current["h"]-140, 40, 40, 10, do, "question") # Exit button def do(): win.current["calls"][call]["var"] = False UI_elements.roundrect(layer, win, win.current["w"]/2+210, win.current["h"]-140, 40, 40, 10, button=do, icon="cancel", tip=talk.text("cancel")) # Okay so before we going to clip everything. Let's make a little widget. # this will be similar to the thing on top of shots. With the little round # icons. And a some kind of progress bar with fat points. But this one # will have only 3 points. # Let's simplify the process a little bit x = win.current["w"]/2-250 y = 100 width = 500 height = win.current["h"]-200 # Okay. let's draw the icons. threeicons = { "edit_mode":False, "blender":False, "link_configure":False } for numb, icon in enumerate(threeicons): UI_elements.image(layer, win,"settings/themes/"\ +win.settings["Theme"]+"/icons/"+icon+".png", x+(width/4)*numb+(width/8)+40, y+20, 40, 40) # Before we can do progress bar and or progress dots we need to check # a few things about the asset. # First is whether it's done. threeicons["edit_mode"] = story.get_asset_data(win, win.current["asset_configure"]["asset"])["fraction"] == 1 # Then whether the ast exists. threeicons["blender"] = os.path.exists(win.project+"/ast"+win.current["asset_configure"]["asset"]+".blend") # Then whether the autolink.data exists. threeicons["link_configure"] = os.path.exists(win.project+"/dev"+win.current["asset_configure"]["asset"]+"/autolink.data") # Now let's manually make the fraction. fraction = 0.0 if threeicons["edit_mode"]: fraction = 0.33 if threeicons["blender"]: fraction = 0.66 if threeicons["link_configure"]: fraction = 1 UI_color.set(layer, win, "progress_background") UI_elements.roundrect(layer, win, x+20, y+80, width-40, 0, 5) UI_color.set(layer, win, "progress_active") UI_elements.roundrect(layer, win, x+20, y+80, (width-40)*fraction, 0, 5) # And the 3 dots for numb, icon in enumerate(threeicons): UI_color.set(layer, win, "progress_background") if threeicons[icon]: # If this folder has any files. UI_color.set(layer, win, "progress_active") UI_elements.roundrect(layer, win, x+(width/4)*numb+(width/8)+50, y+75, 0, 0, 10) # Now let's do 3 UIs. ################## STEP 1: MAKE ASSET ###################### if not threeicons["edit_mode"]: fraction = story.get_asset_data(win, win.current["asset_configure"]["asset"])["fraction"] UI_elements.text(layer, win, "asset_configuration_step", x, y+150, width, 30, 10, fill=False, centered=True, editable=False) win.text["asset_configuration_step"]["text"] = talk.text("asset_configuration_step_1") UI_elements.text(layer, win, "asset_configuration_step1", x, y+200, width, 30, 10, fill=False, centered=True, editable=False) win.text["asset_configuration_step1"]["text"] = str(int(round(fraction*100)))+"%" UI_color.set(layer, win, "progress_background") UI_elements.roundrect(layer, win, x+20, y+250, width-40, 0, 5) UI_color.set(layer, win, "progress_active") UI_elements.roundrect(layer, win, x+20, y+250, (width-40)*fraction, 0, 5) ####################### STEP 2 : COPY BLEND-FILE TO AST #################### # Setting up the scroll if "asset_configure" not in win.scroll: win.scroll["asset_configure"] = 0 current_Y = 310 # The max scroll value if threeicons["edit_mode"] and not threeicons["blender"]: UI_elements.text(layer, win, "asset_configuration_step", x, y+150, width, 30, 10, fill=False, centered=True, editable=False) win.text["asset_configuration_step"]["text"] = talk.text("asset_configuration_step_2") # So if the file is selected I want to have an apply button. if win.current["asset_configure"]["blend_to_copy"]: UI_color.set(layer, win, "text_normal") layer.set_font_size(20) layer.move_to(x+40, y+height-20) layer.show_text(win.current["asset_configure"]["blend_to_copy"]) def do(): copy_from = win.project+"/dev"+win.current["asset_configure"]["asset"]+"/"+win.current["asset_configure"]["blend_to_copy"] copy_to = win.project+"/ast"+win.current["asset_configure"]["asset"]+".blend" newname = copy_to[copy_to.rfind("/")+1:] copy_to = copy_to[:copy_to.rfind("/")] oscalls.copy_file( win, copy_from, copy_to, newname) UI_elements.roundrect(layer, win, win.current["w"]/2+170, win.current["h"]-140, 40, 40, 10, button=do, icon="ok", tip=talk.text("checked")) # Here I want to draw a whole window with blend file selection and stuff. # so here we go. # Clipping everything UI_elements.roundrect(layer, win, win.current["w"]/2-250, 300, 500, win.current["h"]-460, 10, fill=False) layer.clip() clip = [ win.current["w"]/2-250, 300, 500, win.current["h"]-460] # Background #UI_color.set(layer, win, "dark_overdrop") #layer.rectangle(x, y,width,height) #layer.fill() # Now we draw all the blend files of the file. I know it's redundant but # I want to be able to configure an asset from the linking window. tileX = x+70 for filename in sorted(os.listdir(win.project+"/dev"+win.current["asset_configure"]["asset"])): if filename.endswith(".blend"): if int(current_Y + win.scroll["asset_configure"]) in range(0-200, height): # Making the layer node2surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 170, 200) node2 = cairo.Context(node2surface) node2.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) UI_elements.roundrect(node2, win, 0, 0, 170, 200, 10, fill=False) node2.clip() # Background UI_color.set(node2, win, "dark_overdrop") node2.rectangle(0,0,170, 200) node2.fill() # Banner UI_color.set(node2, win, "node_blendfile") node2.rectangle(0,0,170, 20) node2.fill() # Outputting the layer layer.set_source_surface(node2surface, tileX-10, current_Y + win.scroll["asset_configure"] ) layer.paint() UI_elements.image(layer, win, win.project+"/dev"+win.current["asset_configure"]["asset"]+"/"+filename, tileX, current_Y + win.scroll["asset_configure"] + 30, 150, 150) UI_color.set(layer, win, "text_normal") layer.set_font_size(12) layer.move_to(tileX, current_Y + win.scroll["asset_configure"]+15) layer.show_text(filename[filename.rfind("/")+1:][:22]) # If selected layer.set_line_width(4) if win.current["asset_configure"]["blend_to_copy"] == filename: UI_color.set(layer, win, "progress_background") UI_elements.roundrect(layer, win, tileX-10, current_Y + win.scroll["asset_configure"], 170, 200, 10, fill=False) layer.stroke() # Button to activate it def do(): win.current["asset_configure"]["blend_to_copy"] = filename UI_elements.roundrect(layer, win, tileX-10, current_Y + win.scroll["asset_configure"], 170, 200, 10, button=do, tip=filename, fill=False, clip=clip) layer.stroke() layer.set_line_width(2) tileX += 200 if tileX > 1000: tileX = x+70 current_Y += 230 ####################### STEP 3 : CONFIGURE AUTOLINK.DATA #################### if threeicons["edit_mode"] and threeicons["blender"]: UI_elements.text(layer, win, "asset_configuration_step", x, y+150, width, 30, 10, fill=False, centered=True, editable=False) win.text["asset_configuration_step"]["text"] = talk.text("asset_configuration_step_3") if win.current["asset_configure"]["apply"]: def do(): # Here I'm going to actually write stuff to the file. It's not hard. autolink = open(win.project+"/dev"+win.current["asset_configure"]["asset"]+"/autolink.data", "w") cols = win.current["asset_configure"]["collections"] for col in cols: # If the collection is selected we write it. if cols[col]["selected"]: autolink.write("Link : "+col+"\n") # Also we need to then look throught the collection to # see if there are any proxy objects. Aramtures... objs = cols[col]["objects"] for obj in objs: # Same thing if it's selected. Then write it to file. if objs[obj]["selected"]: autolink.write("Proxy : "+obj+"\n") autolink.close() # And a history entry real quick history.record(win, "/dev"+win.current["asset_configure"]["asset"]+"/autolink.data", "[Updated]") # And we need to quit the window. So... win.current["calls"][call]["var"] = False UI_elements.roundrect(layer, win, win.current["w"]/2+170, win.current["h"]-140, 40, 40, 10, button=do, icon="ok", tip=talk.text("checked")) # For this step I can't just copy stuff from assed layer and pretend that everything # is good. Because this part requires a whole new script to write and test. # See: # studio/bpy_get_blend_content.py # Now let's actually run this script quickly. Basically we need to get data out of # the asset blend file. But of course not on every frame. It's a bit too much. So # here is how we do it. if not win.current["asset_configure"]["collections"]: # If in the current data the data about the file still doesn't exists we load # it. blenderpath = oscalls.get_current_blender(win) assetblend = win.project+"/ast"+win.current["asset_configure"]["asset"]+".blend" checkframes = Popen([blenderpath, "-b", assetblend , "-P", os.getcwd()+"/studio/bpy_get_blend_content.py"],stdout=PIPE, universal_newlines=True) checkframes.wait() checkstring = checkframes.stdout.read() # Let's also see if the file autolink.data already there. Meaning I can get # data that is already saved there. linkcols = [] linkobjs = [] if threeicons["link_configure"]: autolink = open(win.project+"/dev"+win.current["asset_configure"]["asset"]+"/autolink.data") autolink = autolink.read() autolink = autolink.split("\n") for line in autolink: if line.startswith("Link : "): linkcols.append(line[7:]) elif line.startswith("Proxy : "): linkobjs.append(line[8:]) else: # If there is no file. I want to start the applying process already: win.current["asset_configure"]["apply"] = True # Now let's parse this crazy stuff that we've got from the blender script. for line in checkstring.split("\n"): if line.startswith(">>> "): line = line[4:] if "<==" in line: col = line[:line.find(" <==")] obj = line[line.find(" <==")+5:].split(" <== ") else: col = line obj = False selected = False if col in win.current["asset_configure"]["asset"] and not threeicons["link_configure"]: selected = True elif col in linkcols: selected = True # So we found a collection. Let's write it in if col not in win.current["asset_configure"]["collections"]: win.current["asset_configure"]["collections"][col] = { "selected":selected, "objects":{} } # We also got the object. Let's put it inside the collection. # But first. If it's an armature we want it to be selected. if obj: selected = False if "Armature" in obj[1] and not threeicons["link_configure"]: selected = True elif obj[0] in linkobjs: selected = True win.current["asset_configure"]["collections"][col]["objects"][obj[0]] = { "selected":selected, "type":obj[1] } # Now let's draw the findings to the screen. But first we need # buttons to see in what catergory are we. buttons = ["collection", "rig"] for num, button in enumerate(buttons): if win.current["asset_configure"]["step3_button"] == button: UI_color.set(layer, win, "progress_time") UI_elements.roundrect(layer, win, x+10+(40*num), y+200, 40, 40, 10) def do(): win.current["asset_configure"]["step3_button"] = button UI_elements.roundrect(layer, win, x+10+(40*num), y+200, 40, 40, 10, do, button) # Now we can clip the bastard UI_elements.roundrect(layer, win, win.current["w"]/2-250, 350, 500, win.current["h"]-510, 10, fill=False) layer.clip() clip = [ win.current["w"]/2-250, 350, 500, win.current["h"]-510] # Background #UI_color.set(layer, win, "dark_overdrop") #layer.rectangle(x, y,width,height) #layer.fill() # Let's start by drawing the collections first since it's the first thing # that the user will be doing. Is selecting the collections. current_Y = current_Y - 50 if win.current["asset_configure"]["step3_button"] == "collection": for collection in win.current["asset_configure"]["collections"]: # We are going to draw a little collection icon. And put a text # with it's name. UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/collection.png", x+60, y+current_Y+win.scroll["asset_configure"], 40, 40) UI_color.set(layer, win, "text_normal") layer.set_font_size(20) layer.move_to(x+120, y+current_Y + win.scroll["asset_configure"]+30) layer.show_text(collection) # Now let's make a checkbox button beside each collection. # Mimicing the Blender UI so to speak. icon = "unchecked" if win.current["asset_configure"]["collections"][collection]["selected"]: icon = "checked" def do(): win.current["asset_configure"]["collections"][collection]["selected"]\ = not win.current["asset_configure"]["collections"][collection]["selected"] win.current["asset_configure"]["apply"] = True UI_elements.roundrect(layer, win, x+10, y+current_Y + win.scroll["asset_configure"], 40, 40, 10, do, icon) current_Y = current_Y + 50 else: # If we are not doing the collection but instead we are selecting the # rigs. We need to draw different stuff. for collection in win.current["asset_configure"]["collections"]: # But we want to draw only objects that are in selected colllections # so here what we do. if win.current["asset_configure"]["collections"][collection]["selected"]: for obj in win.current["asset_configure"]["collections"][collection]["objects"]: name = obj obj = win.current["asset_configure"]["collections"][collection]["objects"][obj] # Now first thing is we need to find an icon to represent # this object. icon = "obj" if "Mesh" in obj["type"]: icon = "mesh" elif "Armature" in obj["type"]: icon = "rig" elif "Camera" in obj["type"]: icon = "shot" UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/"+icon+".png", x+60, y+current_Y+win.scroll["asset_configure"], 40, 40) UI_color.set(layer, win, "text_normal") layer.set_font_size(20) layer.move_to(x+120, y+current_Y + win.scroll["asset_configure"]+30) layer.show_text(name) icon = "link" if obj["selected"]: icon = "override" def do(): obj["selected"]\ = not obj["selected"] win.current["asset_configure"]["apply"] = True UI_elements.roundrect(layer, win, x+10, y+current_Y + win.scroll["asset_configure"], 40, 40, 10, do, icon) current_Y = current_Y + 50 current_Y = current_Y - 300 ########################### UI_elements.scroll_area(layer, win, "asset_configure", x, y+300, width, height-400, current_Y, bar=True, mmb=True, url="asset_configure" ) return surface