diff --git a/studio/checklist.py b/studio/checklist.py index c7fbecc..af8ef3b 100644 --- a/studio/checklist.py +++ b/studio/checklist.py @@ -470,7 +470,6 @@ def draw(outlayer, win, path, back="story_editor"): 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 @@ -496,6 +495,7 @@ def draw(outlayer, win, path, back="story_editor"): win.checklists = {} win.assets = {} win.analytics = analytics.load(win.project) + win.multiuser["last_request"] = "" #### THE GRABBING FUNCTION #### @@ -637,6 +637,7 @@ def draw(outlayer, win, path, back="story_editor"): win.checklists = {} win.assets = {} win.analytics = analytics.load(win.project) + win.multiuser["last_request"] = "" elif win.current["LMB"]: @@ -670,6 +671,7 @@ def draw(outlayer, win, path, back="story_editor"): win.checklists = {} win.assets = {} win.analytics = analytics.load(win.project) + win.multiuser["last_request"] = "" elif win.current["LMB"]: inside = True @@ -758,6 +760,7 @@ def draw(outlayer, win, path, back="story_editor"): save(path, win.checklists[path]) win.checklists = {} win.assets = {} + win.multiuser["last_request"] = "" #win.analytics = analytics.load(win.project) UI_elements.roundrect(layer, win, @@ -846,7 +849,7 @@ def draw(outlayer, win, path, back="story_editor"): win.current["schedule_task_selected"] = False # Saving save(path, win.checklists[path]) - + win.multiuser["last_request"] = "" UI_elements.roundrect(layer, win, sx, @@ -878,7 +881,8 @@ def draw(outlayer, win, path, back="story_editor"): win.checklists = {} win.assets = {} win.analytics = analytics.load(win.project) - + win.multiuser["last_request"] = "" + if not task["editing"]: layer.set_font_size(20) layer.move_to( @@ -920,6 +924,7 @@ def draw(outlayer, win, path, back="story_editor"): # Saving save(path, win.checklists[path]) + win.multiuser["last_request"] = "" def button(): do() @@ -1057,7 +1062,7 @@ def draw(outlayer, win, path, back="story_editor"): win.checklists = {} win.assets = {} win.analytics = analytics.load(win.project) - + win.multiuser["last_request"] = "" diff --git a/studio/history.py b/studio/history.py index 04826f0..41dbd28 100644 --- a/studio/history.py +++ b/studio/history.py @@ -159,6 +159,9 @@ def record(win, filename, task, checklist=[] ): analytics.save(win.project, win.analytics) win.analytics = analytics.load(win.project) + # Multiuser sycning + win.multiuser["request"] = "analytics" + def draw(outlayer, win): x = 10 diff --git a/studio/schedule.py b/studio/schedule.py index 5726a4b..87fdcbc 100644 --- a/studio/schedule.py +++ b/studio/schedule.py @@ -459,6 +459,9 @@ def draw(outlayer, win): analytics.save(win.project, win.analytics) win.analytics = analytics.load(win.project) win.checklists = {} + + # Multiuser sycning + win.multiuser["request"] = "analytics" @@ -630,6 +633,8 @@ def draw(outlayer, win): thing[0][-1] = win.text["schedule_username_setting"]["text"] analytics.save(win.project, win.analytics) + # Multiuser sycning + win.multiuser["request"] = "analytics" UI_elements.roundrect(layer, win, width-40, @@ -698,6 +703,9 @@ def draw(outlayer, win): analytics.save(win.project, win.analytics) win.analytics = analytics.load(win.project) + # Multiuser sycning + win.multiuser["request"] = "analytics" + UI_elements.roundrect(layer, win, (width-80)/2+20, win.scroll["schedule"] + current_Y+5, @@ -728,6 +736,8 @@ def draw(outlayer, win): analytics.save(win.project, win.analytics) win.analytics = analytics.load(win.project) + # Multiuser sycning + win.multiuser["request"] = "analytics" UI_elements.roundrect(layer, win, width-40, diff --git a/studio/studio_analyticsLayer.py b/studio/studio_analyticsLayer.py index 127f05f..1694b42 100644 --- a/studio/studio_analyticsLayer.py +++ b/studio/studio_analyticsLayer.py @@ -825,6 +825,10 @@ def layer(win): analytics.save(win.project, win.analytics) win.analytics = analytics.load(win.project) win.checklists = {} + + # Multiuser sycning + win.multiuser["request"] = "analytics" + #print("test 3") else: diff --git a/studio/studio_assetLayer.py b/studio/studio_assetLayer.py index 1b5f412..a426f39 100644 --- a/studio/studio_assetLayer.py +++ b/studio/studio_assetLayer.py @@ -231,8 +231,6 @@ def layer(win): 20) layer.paint() - - # Name of the asset UI_elements.image(layer, win, "settings/themes/"+win.settings["Theme"]+"/icons/"+acur+".png", @@ -308,6 +306,10 @@ def layer(win): # In case the user made the folder manually. try: + os.mkdir(win.project+"/dev/"+win.cur) + except: + pass + try: os.mkdir(win.project+"/dev/"+win.cur+"/renders") os.mkdir(win.project+"/dev/"+win.cur+"/reference") os.mkdir(win.project+"/dev/"+win.cur+"/tex") @@ -807,6 +809,9 @@ def layer(win): if win.current["asset_left_panel"] == "history": history.draw(layer, win) + + + ### SCENES ### # Documentation entry diff --git a/studio/studio_gtk.py b/studio/studio_gtk.py index 2059c92..7b00514 100644 --- a/studio/studio_gtk.py +++ b/studio/studio_gtk.py @@ -10,7 +10,7 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk import cairo import datetime - +import threading # Own modules from settings import settings @@ -26,6 +26,7 @@ from studio import studio_settingsLayer from studio import studio_assetLayer from studio import studio_analyticsLayer from studio import studio_scriptLayer +from studio import studio_multiuserLayer # UI modules from UI import UI_testing @@ -34,6 +35,8 @@ from UI import UI_elements # Network from network import network_renders +from network import network_multiuser +from network import multiuser_terminal def previous(win): win.previous = {} @@ -50,7 +53,11 @@ def run(project, win): # show the first ever version. So there will be a better way to see version. # I think let's do that like in Blender. Drawn with in the window somewhere. - win.destroy() + try: + win.destroy() + except: + pass + # Setting up the window win = Gtk.Window() win.maximize() @@ -100,6 +107,20 @@ def run(project, win): win.renders = {} # List of current active renders. win.undo_history = [] win.undo_index = 0 + win.multiuser = { + "server":False, # Whether we are connected to the server. And the server ID + "userid":"", # The id of current user in the server + "last_request": "", # The last request send to the server. ( for stopping bloat ) + "curs":{}, # The information about various items on other users machines. + "request":[["story"]], # Requests done in UI space + "users":{}, # List of users information Names, IPs etc. + "messages":[], # List of messages + "unread":0 , # Amount of unread messages + "terminal":[], # The outputs from the server + "asset_list_check":False, # Whether the initial update happened when connecting to the server + "story_check":False, # Whether the first story check was done. + "analytics_check":False + } if pm_project.is_legacy(project): win.story = story.get_legacy(project) @@ -158,12 +179,21 @@ def run(project, win): # Setting the drawable pmdraw = Gtk.DrawingArea() - pmdraw.set_size_request(1280, 720) - scroll.set_size_request(1280, 720) # This step is because GTK developers are + pmdraw.set_size_request(1040, 720) + scroll.set_size_request(1040, 720) # This step is because GTK developers are win.add(scroll) # well. A good, nice, people who knows scroll.add_with_viewport(pmdraw) # what they are doing. Really. pmdraw.connect("draw", pmdrawing, win) + # Before we run the UI. Let's run the mutliuser client. + multiuser = threading.Thread(target=network_multiuser.client, args=(win,)) + multiuser.setDaemon(True) + multiuser.start() + + # And let's start also the multiuser_terminal + multiuser_term = threading.Thread(target=multiuser_terminal.listen, args=(win,)) + multiuser_term.setDaemon(True) + multiuser_term.start() #run win.show_all() @@ -273,6 +303,9 @@ def pmdrawing(pmdrawing, main_layer, win): elif win.url == "script": Layers.append([studio_scriptLayer.layer(win), "script"]) + elif win.url == "multiuser": + Layers.append([studio_multiuserLayer.layer(win), "multiuser"]) + # Call layers. See studio/studio_dialogs.py for explanation. It's wild. win.calllayer = False @@ -339,6 +372,12 @@ def pmdrawing(pmdrawing, main_layer, win): # keys when you scroll to different windows. So here is a little fix. if not win.is_active(): win.current["keys"] = [] + + elif "is_active" in win.previous and not win.previous["is_active"]: + win.multiuser["last_request"] = "" + UI_elements.reload_images(win) + + win.current["is_active"] = win.is_active() # Saving data about this frame for the next one. A bit hard to get WTF am I # doing here. Basically trying to avoid current and previous data to be links @@ -402,8 +441,8 @@ def key_release(widget, event, win): # I also want to clean the key letter. Because other wise in the # script writer I had weird key presses all the time. - - win.current["key_letter"] = "" + if not win.current["keys"]: + win.current["key_letter"] = "" def scrolling(widget, event, win): e, x, y = event.get_scroll_deltas() diff --git a/studio/studio_multiuserLayer.py b/studio/studio_multiuserLayer.py new file mode 100644 index 0000000..1987b5a --- /dev/null +++ b/studio/studio_multiuserLayer.py @@ -0,0 +1,510 @@ +# 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 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 + +# network +from network import multiuser_terminal + +def layer(win): + + # 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() + + + + ############################################################################ + + # This is our multiuser UI. From here the user will start and stop the server + # for the multiuser. See what that server has to say. And write text messages + # to all the other users. Like a little messaging app, so they will not use + # closed source apps for this. I know a lot of companies that ustilize + # whatsapp for this. This is not cool. And I can make a little app here. + + # The way it's going to look it the folosing. + + + ############################################################################ + # START / STOP BUTTON # # + ###################################################### BOB: Hello World # + # # # + # server started # Steve: What's Up # + # BOB connected # # + # Steve connected # John: Hey guys # + # John connected # who can make the # + # Steve updated Moria # rig for Moria? # + # John reqested Moria # # + # Steve sent Moria to John # Steve: I can. # + # # # + #################################################### # John: Thanks. # + # 3 users connected: # # + # BOB # # + # John ####################### + # Steve # # # + ############################################################################ + + # I know that it's a bit unfair to give so much space to a terminal like + # output window. But this is kind of the most important thing in the + # entire Multiuser. The server. Actually the server will run only on one + # computer. But all users will feel like they are controlling the server. + + # I don't like when one user thinks that he is more important then the other + # . Because in the film production. Usually the director listens even to + # the guy who makes the tea. In the case of this program I want everybody + # to feel exactly the same amount of power. + + ############################################################################ + + win.multiuser["unread"] = 0 + + # SERVER PEACE FRAME + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + 80, + 80, + win.current["w"]/3*2-160, + win.current["h"]/2-100, + 10) + + # USERS PEACE FRAME + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + 80, + win.current["h"]/2, + win.current["w"]/3*2-160, + win.current["h"]/2-80, + 10) + + # THE SIDE PEACE FRAME + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + win.current["w"]/3*2-60, + 80, + win.current["w"]/3-20, + win.current["h"]-160, + 10) + + ####### SERVER PART ####### + + # On the top panel first button will be either make a server. Or if server exists, + # close the server. This will require a little dialog similar to when deleting + # scenes in the story editor. + + # I'm going to hack my way into checking the server. Basically it autoconnects to + # it if one is up. So.. + + if win.multiuser["server"]: + + def do(): + + # Simple UDP message + multiuser_terminal.message("VCStudio ABORT MULTIUSER") + + UI_elements.roundrect(layer, win, + 90, + 90, + 40, + 40, + 10, + button=do, + icon="server_close") + else: + def do(): + + # Simple Popen + Popen(["python3", "network/multiuser_server.py", win.analytics["name"]]) + + UI_elements.roundrect(layer, win, + 90, + 90, + 40, + 40, + 10, + button=do, + icon="server_new") + + # Server outputs part. I'm creating a layer for it just because it needs + # a clipping. + + x = 90 + y = 140 + width = win.current["w"]/3*2-160-20 + height = win.current["h"]/2-170 + + + # Making the layer + surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) + node = cairo.Context(surface2) + node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + + # Clip + UI_elements.roundrect(node, win, + 0, + 0, + width, + height, + 10, + fill=False) + node.clip() + + # Background tester + #UI_color.set(node, win, "dark_overdrop") + #node.rectangle(0,0,width, height) + #node.fill() + + # Here I want to have the output of the server in a raw fasion. + if "multiuser_terminal" not in win.scroll: + win.scroll["multiuser_terminal"] = 0 + + current_Y = 10 + + for message in win.multiuser["terminal"]: + + # We are going to draw a little server icon. + UI_elements.image(node, win, + "settings/themes/"+win.settings["Theme"]+"/icons/server.png", + 10, + current_Y+win.scroll["multiuser_terminal"], + 40, + 40) + + # And we want to have the text of the message + + UI_color.set(node, win, "text_normal") + node.set_font_size(15) + node.move_to( 60, current_Y+win.scroll["multiuser_terminal"]+27) + node.show_text(message) + + current_Y = current_Y + 50 + + # Outputting the layer + layer.set_source_surface(surface2, x, y) + layer.paint() + + UI_elements.scroll_area(layer, win, "multiuser_terminal", + x, + y, + width, + height, + current_Y, + bar=True, + mmb=True) + + + + ############ USERS PART ############## + + # Here in this part I want to put a complite list of currently connected users. + # I have few ideas of what functionality could be added to here. But at this + # point I'm just trying to make the window somewhat busy looking. + + # So we need to make layer here. Since I want to clip it. But be able to draw outisde + # the clipping area later. + + x = 90 + y = win.current["h"]/2+10 + width = win.current["w"]/3*2-160-20 + height = win.current["h"]/2-80-60 + + + # Making the layer + surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) + node = cairo.Context(surface2) + node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + + # Clip + UI_elements.roundrect(node, win, + 0, + 0, + width, + height, + 10, + fill=False) + node.clip() + + # Background tester + #UI_color.set(node, win, "dark_overdrop") + #node.rectangle(0,0,width, height) + #node.fill() + + + + if "multiuser_users" not in win.scroll: + win.scroll["multiuser_users"] = 0 + + current_Y = 10 + + for ip in list(win.multiuser["users"].keys()): + try: + user = win.multiuser["users"][ip] + except: + continue + + username = user["username"] + + # For each user I want to show the name, then IP:PORT + + # If it's us on the list I want to draw a little rectangle arround + # this particular user + + if ip == win.multiuser["userid"]: + UI_color.set(node, win, "node_blendfile") + UI_elements.roundrect(node, win, + 0, + current_Y+win.scroll["multiuser_users"]-5, + width, + 45, + 10) + + + # User Icon + UI_elements.image(node, win, + "settings/themes/"+win.settings["Theme"]+"/icons/user.png", + 10, + current_Y+win.scroll["multiuser_users"], + 40, + 40) + + # Text + + UI_color.set(node, win, "text_normal") + node.set_font_size(20) + node.move_to( 60, current_Y+win.scroll["multiuser_users"]+25) + node.show_text(username+" | "+ip) + + current_Y = current_Y + 50 + + + # Outputting the layer + layer.set_source_surface(surface2, x, y) + layer.paint() + + UI_elements.scroll_area(layer, win, "multiuser_users", + x, + y, + width, + height, + current_Y, + bar=True, + mmb=True) + + + + # At the bottom I want to have a little multiuser icon with the count of users. + # then a user icon and a name selection. + + UI_elements.image(layer, win, + "settings/themes/"+win.settings["Theme"]+"/icons/multiuser.png", + x, + y+height+5, + 40, + 40) + + # The little count thing at the corner + if win.multiuser["users"]: + count = str(len(win.multiuser["users"])) + + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + x+25, + y+height, + len(count)*12+6, + 25, + 5) + layer.fill() + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to(x+28,y+height+20) + layer.show_text(count) + + + # CANCEl + + def do(): + win.url = "story_editor" + + UI_elements.roundrect(layer, win, + win.current["w"]/3*2-120, + win.current["h"]-120, + 40, + 40, + 10, + button=do, + icon="cancel", + tip=talk.text("cancel")) + + # Short cut ESC + if 65307 in win.current["keys"] and not win.textactive: + do() + + + + ########## THE MESSANGER APP ON THE RIGHT ########## + + # I'm creating a layer for it just because it needs a clipping. + + x = win.current["w"]/3*2-50 + y = 90 + width = win.current["w"]/3-40 + height = win.current["h"]-220 + + + # Making the layer + surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) + node = cairo.Context(surface2) + node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) + + # Clip + UI_elements.roundrect(node, win, + 0, + 0, + width, + height, + 10, + fill=False) + node.clip() + + # Background tester + #UI_color.set(node, win, "dark_overdrop") + #node.rectangle(0,0,width, height) + #node.fill() + + + # So here I want to present all the messages by all the users. + if "multiuser_messages" not in win.scroll: + win.scroll["multiuser_messages"] = 0 + + current_Y = 10 + + for message in win.multiuser["messages"]: + + # let's get the name of the user + username = message[0] + + if username == "Multiuser Server": + continue + + # User Icon + UI_elements.image(node, win, + "settings/themes/"+win.settings["Theme"]+"/icons/user.png", + 10, + current_Y+win.scroll["multiuser_messages"], + 40, + 40) + + UI_color.set(node, win, "text_normal") + node.set_font_size(20) + node.move_to(60, + current_Y+win.scroll["multiuser_messages"]+25) + node.show_text(username) + + current_Y = current_Y + 50 + + # Now the message it self going to need to have line breaks. For this + # we are going to make similar rendering to the one in the script + # writer. But simpler. + + tileX = 10 + + for word in message[1].split(" "): + + + if tileX + len(word)*12+12 > width-10: + tileX = 10 + current_Y = current_Y + 30 + + UI_color.set(node, win, "text_normal") + node.set_font_size(20) + node.move_to(tileX, + current_Y+win.scroll["multiuser_messages"]+25) + node.show_text(word) + + tileX = tileX + len(word)*12+12 + + current_Y = current_Y + 50 + + # Outputting the layer + layer.set_source_surface(surface2, x, y) + layer.paint() + + UI_elements.scroll_area(layer, win, "multiuser_messages", + x, + y, + width, + height, + current_Y, + bar=True, + mmb=True) + + # So here after the messages I want to make a little input for the new + # message and a send button + + UI_elements.text(layer, win, "multiuser_message", + x, + y+height+5, + width-50, + 40) + + # Send button + + def do(): + + if win.text["multiuser_message"]["text"]: + win.multiuser["request"] = ["message", win.text["multiuser_message"]["text"]] + win.text["multiuser_message"]["text"] = "" + + UI_elements.roundrect(layer, win, + x+width-40, + y+height+5, + 40, + 40, + 10, + button=do, + icon="send") + + # ENTER + if 65293 in win.current["keys"]: + do() + win.current["keys"] = [] + + return surface diff --git a/studio/studio_nodes.py b/studio/studio_nodes.py index 7153051..066c4c5 100644 --- a/studio/studio_nodes.py +++ b/studio/studio_nodes.py @@ -1060,6 +1060,8 @@ def link_node(outlayer, win, x, y, width=150, height=150, name="", num=0, linkty UI_elements.tooltip(win, name) else: + + if os.path.exists(win.project+"/"+name): UI_elements.image(layer, win, win.project+"/"+name, @@ -1460,4 +1462,70 @@ def marker(outlayer, win, name ,x, y ): fill=False) outlayer.stroke() + +def user(outlayer, win, name ,x, y ): + + # This function will draw users from multiuser to the screen. + + + + if int(x) in range(int(60), int(win.current["w"]-100))\ + and int(y) in range(int(60), int(win.current["h"]-80)): + width = 200 + height = 40 + + inscreen = True + else: + + x = min(max(x, 60), win.current["w"]-100) + y = min(max(y, 60), win.current["h"]-80) + + width = 40 + height = 40 + + inscreen = False + + # Making the layer + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height)) + layer = cairo.Context(surface) + + # 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() + + # Pin Icon + UI_elements.image(layer, win, + "settings/themes/"+win.settings["Theme"]+"/icons/user.png", + 0, 0, 40, 40) + + + + # Outputting the layer + outlayer.set_source_surface(surface, x, y) + outlayer.paint() + + if inscreen: + + + # Text editor for the marker's name. + + UI_elements.text(outlayer, win, name+"_user", + x+40, + y, + width-40, + 40, + set_text=name, + editable=False) + diff --git a/studio/studio_scriptLayer.py b/studio/studio_scriptLayer.py index 0b06571..3d78b95 100644 --- a/studio/studio_scriptLayer.py +++ b/studio/studio_scriptLayer.py @@ -1379,6 +1379,8 @@ def layer(win): if win.current["key_letter"] not in nonhistory and ORD not in [26, 25]: story.undo_record(win) + # Multiuser sycning + win.multiuser["request"] = "story" # Now let's retrive out data. diff --git a/studio/studio_storyLayer.py b/studio/studio_storyLayer.py index fbed6fd..28b552f 100644 --- a/studio/studio_storyLayer.py +++ b/studio/studio_storyLayer.py @@ -555,7 +555,7 @@ def layer(win): # Multiuser def do(): - win.url = "multiuser_layer" + win.url = "multiuser" UI_elements.roundrect(layer, win, 5, @@ -568,6 +568,22 @@ def layer(win): talk.text("multiuser_tooltip"), url="story_editor") + if win.multiuser["unread"]: + count = str(win.multiuser["unread"]) + + UI_color.set(layer, win, "node_background") + UI_elements.roundrect(layer, win, + 30, + win.current["h"]-100, + len(count)*12+6, + 25, + 5) + layer.fill() + UI_color.set(layer, win, "text_normal") + layer.set_font_size(20) + layer.move_to(33,win.current["h"]-83) + layer.show_text(count) + # Settings def do(): win.url = "settings_layer" @@ -909,6 +925,14 @@ def layer(win): lx = link[2][0] + cx ly = link[2][1] + cy + # For the one inside the project. They should be always relative + # so even if the project is in a complitely different location + # on another machine. Where we have our Multiuser data. It should + # be able to load these. + + if win.project in link[1]: + link[1] = link[1].replace(win.project, "") + studio_nodes.link_node(layer, win, lx, ly, name=linkname, num=num, linktype=linktype ) @@ -948,6 +972,19 @@ def layer(win): except: pass + + # MARKERS + try: + for user in win.multiuser["users"]: + if user != win.multiuser["userid"]: + + mx = 0-win.multiuser["users"][user]["camera"][0] +cx + win.current["w"]/2 + my = 0-win.multiuser["users"][user]["camera"][1] +cy + win.current["h"]/2 + + studio_nodes.user(layer, win, win.multiuser["users"][user]["username"], mx, my) + except Exception as e: + print(e, "USER RENDERING") + ########### TIMES RECORDING FOR PERFONMANCE MEASURING ############# fif = datetime.datetime.now() mil = fif - stf @@ -1119,8 +1156,7 @@ def layer(win): if savenow: - - + # Now let's run the history record. story.undo_record(win) @@ -1129,7 +1165,10 @@ def layer(win): # Need to reload the story to reload the fractions of the scenes. win.story = story.load(win.project) - + + # Multiuser sycning + win.multiuser["request"] = "story" + ########### TIMES RECORDING FOR PERFONMANCE MEASURING ############# fif = datetime.datetime.now() mil = fif - stf