From a09b61c000347b5345f77a991958c1588b1097eb Mon Sep 17 00:00:00 2001 From: "Jeison Yehuda Amihud (Blender Dumbass)" Date: Sat, 19 Dec 2020 10:20:34 +0000 Subject: [PATCH] Upload files to 'studio' --- studio/bpy_do_linking.py | 266 ++++++++++ studio/bpy_get_blend_content.py | 63 +++ studio/studio_assetLayer.py | 27 + studio/studio_asset_configureLayer.py | 735 ++++++++++++++++++++++++++ studio/studio_asset_selectLayer.py | 48 +- studio/studio_dialogs.py | 73 +++ studio/studio_gtk.py | 33 +- studio/studio_scriptLayer.py | 22 +- studio/studio_shot_linkLayer.py | 642 ++++++++++++++++++++++ 9 files changed, 1864 insertions(+), 45 deletions(-) create mode 100644 studio/bpy_do_linking.py create mode 100644 studio/bpy_get_blend_content.py create mode 100644 studio/studio_asset_configureLayer.py create mode 100644 studio/studio_shot_linkLayer.py diff --git a/studio/bpy_do_linking.py b/studio/bpy_do_linking.py new file mode 100644 index 0000000..6c7ed80 --- /dev/null +++ b/studio/bpy_do_linking.py @@ -0,0 +1,266 @@ +# THIS FILE IS A PART OF VCStudio +# PYTHON 3 +# BPY ( WITH IN BLENDER ) + +################################################################# + +# This file is running with in Blender to link assets from their +# AST files into the animation files. And make library overrides. + +# NOTE: It's using BPY module which is not available outside of +# blender. So in order to test any changes to it. You have to +# run it with in Blender. Or Using blender -P . +# See blender --help for details. + +################################################################# + +import bpy +import os + +# The main problem with running from with in blender is that we +# have no access to all the outside modules. And this script +# will be there on it's own. So it need a way of knowing where +# are the assets. + +blendpath = bpy.data.filepath # Animation file path +folder = blendpath[:blendpath.rfind("/")] # Animation shot folder +pf = folder[:folder.rfind("/rnd/")] # Project's folder + +# In order for VCStudio or Blender-Organizer to know what is going +# on I use print(). It's not going to be outputted into terminal. +# since we are piping everything directly into VCStudio. Which is +# going to parse those lines to give the user some graphical feed +# back. + +print("BLENDPATH : ", blendpath) +print("FOLDER : ", folder) +print("PROJECT FOLDER : ", pf) + +# Now we are going to abort the process if there is no file in the +# shot folder that has the info about the linked data. autolink.data + +if os.path.exists(folder+"/extra/autolink.data"): + print("FOUND AUTOLINK.DATA YEY :)") + + + # Now let's parse the extra/autolink.data file + + df = open(folder+"/extra/autolink.data" , "r") + df = df.read() + + # These 2 values will be our location in the blender space since + # I don't think any user wants all of their assets to be in the + # same exact spot. + + movey = 0 + movex = 0 + + # We need to get our mode first. Because the user might want to + # just link. Or make the old proxy. + mode = "link" + for num, line in enumerate(df.split("\n")): + if line.startswith("Mode : "): + mode = line[7:] + + + # Let's see if there any lines that say what we want to link. + + for num, line in enumerate(df.split("\n")): + if line.startswith("Link : "): + + # So here is out item. ( asset ). NOTE: THe item in + # autolink.data will have /dev/ added to the begining + # like all links in Blender-Organizer. + + item = line[7:] + print("\nLINKING ITEM : "+item) + + # Now let's see if the asset also has an autolink.data + # configured. Because if not. Script would not know what + # to link. + + itemsdf = pf+item+"/autolink.data" + + if os.path.exists(itemsdf): + print("FOUND "+item+"'S AUTOLINK.DATA :)") + + # Now let's parse the autolink.data of the asset. + + idf = open(itemsdf, "r") + idf = idf.read() + + # We need to find 2 types of data. What collections + # to link. Since not all of them are nessesary. And + # whether to do library-overrides. + + # At the time of Blender-Organizer library-overrides + # was still a very unstable thing. So I was going + # proxies. Now I don't want to break backward compati- + # bility with Blender-Organizer. So we are going to + # read the full list of Proxies. And if they exist + # we are going to use library override instead. So + # keep in mind. They called proxies in the script. But + # they are library-overrides. + + linkdata = [] # Lits of colletions to link + proxydata = [] # Lits of "Proxies" so to speak. + + for iline in idf.split("\n"): + if iline.startswith("Link : "): + linkdata.append(iline[7:]) + elif iline.startswith("Proxy : "): + proxydata.append(iline[8:]) + + print("LINKDATA ", linkdata) + print("PROXYDATA ", proxydata) + + # Okay. Now we got both lists. Let's see if there is + # an asset blend file. Because for any reason it might + # not exists. + + astblend = pf+"/ast/"+item[5:]+".blend" + print("AST BLEND : "+astblend) + + + if os.path.exists(astblend): + print("YAY FOUND THE BLENDFILE :)") + + # We found our asset blend file. So now let's do + # the linking. + + for collection in linkdata: + + + + print("ATTEMPTING TO LINK : "+collection) + + # Now let's try actually doing it. + + try: + with bpy.data.libraries.load(astblend, link=True) as (data_from, data_to): + data_to.collections = [c for c in data_from.collections if c == collection] + + for num2, new_coll in enumerate(data_to.collections): + + print("TRYING LINKING ", new_coll.name) + + try: + if new_coll.name: + instance = bpy.data.objects.new(new_coll.name, None) + instance.instance_type = 'COLLECTION' + instance.instance_collection = new_coll + bpy.context.scene.collection.objects.link(instance) + if not item[5:].startswith("loc"): + bpy.data.objects[collection].location[1] = movey + bpy.data.objects[collection].location[0] = movex + + # So here we already linked our data. And placed the + # objects. Next we want to do library-overrides. + + if proxydata and mode == "override": + + # With library overrides there is one little problem. + # It nullifies the location. Because the location is + # now also overriden. + + bpy.data.objects[collection].select_set(True) + bpy.context.view_layer.objects.active = bpy.data.objects[collection] + bpy.ops.object.make_override_library() + + + # So after we do the override we need to change the + # location again. + + if not item[5:].startswith("loc"): + bpy.data.objects[proxydata[0]].location[1] = movey + bpy.data.objects[proxydata[0]].location[0] = movex + + # And while we are on it. In the Blender-Organizer + # linker there was one inconvinience that you had + # to hide the rig from viewport since if not you will + # have both linked and proxy rig drawn on screen at + # the same time. So let's unhide it. + + bpy.data.objects[proxydata[0]].hide_viewport = False + + # Also while we are here. Let's use the size of the + # rig to offset it's location instead of 5. If the + # rig exists. + + + + movey = movey + bpy.data.objects[proxydata[0]].dimensions.y+1 + if movey > 25: + movey = 0 + movex = movex + 5 + + elif proxydata and mode == "proxy": + + # Now the used could select to do it the old way. + # using a proxy. Then this is the way. + for proxymake in proxydata: + print("TRYING PROXING ", proxymake) + + try: + + ob = bpy.context.scene.objects[new_coll.name] + ob.select_set(True) + bpy.context.view_layer.objects.active = ob + bpy.ops.object.proxy_make(object=proxymake) + except Exception as e: + print("PROXY FAILED ", proxymake) + print(e, "ERROR IN PROXY") + + movey = movey + 5 + if movey > 25: + movey = 0 + movex = movex + 5 + + else: + + # If ther is no library - override enabled. The instance + # empty has a size of 0. So this same dimension thing + # would not work here. :(. I might come up with something + # later. + + movey = movey + 5 + if movey > 25: + movey = 0 + movex = movex + 5 + + # Now I want to save the file. BUT. In the old way of + # doing it I made a mistake to save without checking + # that all paths should be RELATIVE. And so copying the + # project to another computer bloke all the files. + + bpy.ops.file.make_paths_relative() + bpy.ops.wm.save_mainfile() + + # So ther is 2 line now when saving. + + # Now I'd like to print out the current fraction of + # the linking progress done. So I could make a progress + # bar in the VCStudio. + + print("FRACTION:", (num+1)/len(df.split("\n"))) + + except Exception as e: + print(e, "ERROR IN LINING") + except Exception as e: + print(e, "ERROR IN GENERAL") + + + else: + print("NO BLENDFILE DOEN'T EXIST :(") + + + else: + print("NO "+item+"'S AUTOLINK.DATA :(") + + + + +else: + print("NO AUTOLINK.DATA SORRY :(") + +print("FINISHED") diff --git a/studio/bpy_get_blend_content.py b/studio/bpy_get_blend_content.py new file mode 100644 index 0000000..25178aa --- /dev/null +++ b/studio/bpy_get_blend_content.py @@ -0,0 +1,63 @@ +# THIS FILE IS A PART OF VCStudio +# PYTHON 3 +# BPY ( WITH IN BLENDER ) + +################################################################# + +# This file is running with in Blender to link get data from blend +# files about their contents. + +# NOTE: It's using BPY module which is not available outside of +# blender. So in order to test any changes to it. You have to +# run it with in Blender. Or Using blender -P . +# See blender --help for details. + +################################################################# + +import bpy + +# Basically I want to have 3 types of data. + +# 0. What collections does the blend file has. +# 1. What objects does the blend file has. And in what collection are they. +# 2. Whether those objects are armatures. Or in other words what types are +# these objects. + +# It's not going to work on pre 2.80 blenders. So there is this try. + +try: + + # Now let's look through all the collections that the blend file has. + + for n, i in enumerate(bpy.data.collections): + + # Then I want to know whether in this collection are any objects. + foundobj = False + + # So let's try itterating through the object os the collection. + + for nn, b in enumerate(i.objects): + + # If we found enything there is this. + foundobj = True + print( ">>>", i.name, "<==" ,b.name, "<==" ,b.data) + + # Now some scenes have terribly huge amount of + # stuff in there. This is why I break early. + # Now this value probably should be done using a + # setting in the UI somewhere. I'm not sure how + # to do it yet. So yeah. + + if nn > 200: + print("BROKEN AFTER", b.name) + break + + if not foundobj: + print( ">>>", i.name) + + #if n > 300: + # break + + print ("VERSION = SUCCESS") +except: + print("ERROR") diff --git a/studio/studio_assetLayer.py b/studio/studio_assetLayer.py index eef5ad3..5d791bf 100644 --- a/studio/studio_assetLayer.py +++ b/studio/studio_assetLayer.py @@ -262,6 +262,33 @@ def layer(win): 0, 10) + # Before search. On the other side when you have done the asset there will + # be a little configure icon. This is configuration for linking. Creating + # the /ast/ blend.file and autolink.data file. So the linker could link + # the files into the animation scene. + # + # See: + # studio/studio_shot_linkLayer.py + # studio/bpy_do_linking.py + # studio/studio_asset_configureLayer.py + + def do(): + + def after(win, var): + print(var) + + studio_dialogs.asset_configure(win, "configuring_asset", after, win.cur) + + UI_elements.roundrect(layer, win, + win.current["w"]/4*3-60, + 210, + 40, + 40, + 10, + button=do, + icon="link_configure") + + # Search UI_elements.image(layer, win, "settings/themes/"\ diff --git a/studio/studio_asset_configureLayer.py b/studio/studio_asset_configureLayer.py new file mode 100644 index 0000000..e320a01 --- /dev/null +++ b/studio/studio_asset_configureLayer.py @@ -0,0 +1,735 @@ +# 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 + +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) + + # 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 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 diff --git a/studio/studio_asset_selectLayer.py b/studio/studio_asset_selectLayer.py index 4d5df01..4059eb1 100644 --- a/studio/studio_asset_selectLayer.py +++ b/studio/studio_asset_selectLayer.py @@ -52,10 +52,10 @@ def layer(win, call): UI_color.set(layer, win, "node_background") UI_elements.roundrect(layer, win, - 40, - 40, - win.current["w"]-80, - win.current["h"]-80, + 80, + 80, + win.current["w"]-160, + win.current["h"]-160, 10) ############################################################################ @@ -97,8 +97,8 @@ def layer(win, call): UI_color.set(layer, win, "progress_time") UI_elements.roundrect(layer, win, - 50+(40*num), - 50, + 100+(40*num), + 100, 40, 40, 10) @@ -107,8 +107,8 @@ def layer(win, call): win.current["asset_cur"] = cur UI_elements.roundrect(layer, win, - 50+(40*num), - 50, + 100+(40*num), + 100, 40, 40, 10, @@ -119,7 +119,7 @@ def layer(win, call): # In case the user is confused UI_color.set(layer, win, "text_normal") layer.set_font_size(30) - layer.move_to(250,80) + layer.move_to(300,130) layer.show_text(talk.text(win.current["asset_cur"])) @@ -128,14 +128,14 @@ def layer(win, call): UI_elements.image(layer, win, "settings/themes/"\ +win.settings["Theme"]+"/icons/search.png", win.current["w"]-440, - 50, + 100, 40, 40) UI_elements.text(layer, win, "asset_select_search", win.current["w"]-400, - 50, - 350, + 100, + 250, 40) # CANCEl @@ -145,8 +145,8 @@ def layer(win, call): win.assets = {} UI_elements.roundrect(layer, win, - win.current["w"]-80, - win.current["h"]-80, + win.current["w"]-120, + win.current["h"]-120, 40, 40, 10, @@ -161,18 +161,18 @@ def layer(win, call): # Now let's prepare the ground for the next part. UI_elements.roundrect(layer, win, - 50, 100, - win.current["w"]-100, - win.current["h"]-200, + 150, + win.current["w"]-200, + win.current["h"]-250, 10, fill=False) layer.clip() - tileX = 70 - current_Y = 0 + tileX = 120 + current_Y = 50 if "asset_select" not in win.scroll: win.scroll["asset_select"] = 0 @@ -304,10 +304,10 @@ def layer(win, call): tip=talk.text(win.current["asset_cur"])+": "+asset, fill=False, clip=[ - 50, 100, - win.current["w"]-100, - win.current["h"]-200 + 150, + win.current["w"]-200, + win.current["h"]-250 ]) layer.stroke() @@ -315,8 +315,8 @@ def layer(win, call): tileX += 200 - if tileX > win.current["w"]-220: - tileX = 70 + if tileX > win.current["w"]-270: + tileX = 120 current_Y += 230 diff --git a/studio/studio_dialogs.py b/studio/studio_dialogs.py index 28f4139..9fdbbe6 100644 --- a/studio/studio_dialogs.py +++ b/studio/studio_dialogs.py @@ -72,6 +72,8 @@ from UI import UI_color from studio import studio_file_selectLayer from studio import studio_asset_selectLayer +from studio import studio_shot_linkLayer +from studio import studio_asset_configureLayer ################# @@ -167,6 +169,77 @@ def asset_select(win, name, call, force=False, cur="chr", SEARCH=""): # Let's activate the text so you could type immediatly win.textactive = "asset_select_search" + # Wiping the history of the assets. See studio/studio_asset_selectLayer.py + win.assets = {} + + # Let's clear the LMB just in case + win.previous["LMB"] = False + +def asset_link(win, name, call, filename, force=False): + + # This function will configure the linking of the assets into animation files + # it's in theory a quite simple operation, but requires nesting of dialogs. + # which is untested by the time I'm writting this comment. + + if name not in win.current["calls"]: + win.current["calls"][name] = { + "var" :None, # This is the variable that we are waiting for + "call":call, # This is what it's going to run when it's done + "url" :"asset_link", + "back":win.url,# This is where it's going to come back when it's done + "draw":studio_shot_linkLayer.layer + } + + # let's prepare the data for this operation + + if force or "linking_asset_data" not in win.current\ + or win.current["linking_asset_data"]["linking_to"] != filename: + win.current["linking_asset_data"] = { + "linking_to":filename, + "assets":[], + "read":False, + "selected":"", + "mode":"link", + "fraction":0, + "process":False + } + if win.current["linking_asset_data"]["fraction"]: + win.current["linking_asset_data"]["assets"] = [] + win.current["linking_asset_data"]["fraction"] = 0 + + # Wiping the history of the assets. See studio/studio_asset_selectLayer.py + win.assets = {} + + # Let's clear the LMB just in case + win.previous["LMB"] = False + +def asset_configure(win, name, call, asset, force=False): + + # This function going to configure assets. More deatailed explanation is + # in the file: studio/studio_asset_configureLayer.py + + if name not in win.current["calls"]: + win.current["calls"][name] = { + "var" :None, # This is the variable that we are waiting for + "call":call, # This is what it's going to run when it's done + "url" :"asset_configure", + "back":win.url,# This is where it's going to come back when it's done + "draw":studio_asset_configureLayer.layer + } + + # let's prepare the data for this operation + + if force or "asset_configure" not in win.current\ + or win.current["asset_configure"]["asset"] != asset: + win.current["asset_configure"] = { + "asset":asset, + "blend_to_copy":"", + "collections":{}, + "step3_button":"collection", + "apply":False + } + + # Wiping the history of the assets. See studio/studio_asset_selectLayer.py win.assets = {} diff --git a/studio/studio_gtk.py b/studio/studio_gtk.py index f18799d..99eb929 100644 --- a/studio/studio_gtk.py +++ b/studio/studio_gtk.py @@ -272,22 +272,25 @@ def pmdrawing(pmdrawing, main_layer, win): win.calllayer = False remlater = [] - for call in win.current["calls"]: - - if win.current["calls"][call]["var"] == None: - Layers.append([win.current["calls"][call]["draw"](win, call)]) - win.url = win.current["calls"][call]["url"] - win.calllayer = True - - else: - win.url = win.current["calls"][call]["back"] - win.current["calls"][call]["call"](win, win.current["calls"][call]["var"]) - win.textactive = "" - remlater.append(call) - - for call in remlater: + try: + for call in win.current["calls"]: - del win.current["calls"][call] + if win.current["calls"][call]["var"] == None: + Layers.append([win.current["calls"][call]["draw"](win, call)]) + win.url = win.current["calls"][call]["url"] + win.calllayer = True + + else: + win.url = win.current["calls"][call]["back"] + win.current["calls"][call]["call"](win, win.current["calls"][call]["var"]) + win.textactive = "" + remlater.append(call) + + for call in remlater: + + del win.current["calls"][call] + except: + pass Layers.append([UI_testing.layer(win)]) Layers.append([win.tooltip_surface]) diff --git a/studio/studio_scriptLayer.py b/studio/studio_scriptLayer.py index f377a38..fe78929 100644 --- a/studio/studio_scriptLayer.py +++ b/studio/studio_scriptLayer.py @@ -1,8 +1,6 @@ # THIS FILE IS A PART OF VCStudio # PYTHON 3 -# This a console project manager. - import os import datetime import re @@ -2588,12 +2586,22 @@ def layer(win): 148, 10, button=do, - fill=False) + fill=False, + tip=blend) layer.stroke() # Link things into Blend-File def do(): - print("Link") + + # I'm using a dialog here. Because I want to return back + # to the shot we were in. But I don't really want to do + # anything after the dialog is closed. So there is this + # empty function. + + def after(win, var): + pass + + studio_dialogs.asset_link(win, "asset_linking", after, "/rnd"+win.cur+"/"+blend) UI_elements.roundrect(layer, win, x+tileX+20, @@ -2602,7 +2610,8 @@ def layer(win): 40, 10, icon="obj_link", - button=do) + button=do, + tip=talk.text("link_shot_blend_tooltip")+blend) # Render def do(): @@ -2615,7 +2624,8 @@ def layer(win): 40, 10, icon="render", - button=do) + button=do, + tip=talk.text("render_shot_blend_tooltip")+blend) tileX = tileX + 150 if tileX + 128 > width - 10 and bn != len(blendfiles)-1: diff --git a/studio/studio_shot_linkLayer.py b/studio/studio_shot_linkLayer.py new file mode 100644 index 0000000..3ada2aa --- /dev/null +++ b/studio/studio_shot_linkLayer.py @@ -0,0 +1,642 @@ +# 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 + +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(): + + 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") + + # 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