484 lines
17 KiB
Python
484 lines
17 KiB
Python
|
# THIS FILE IS A PART OF VCStudio
|
||
|
# PYTHON 3
|
||
|
|
||
|
##############################################################################
|
||
|
|
||
|
# Not all users have the ability or the desire to run a complex Graphical UI
|
||
|
# to do simple tasks in the project. For example Windows users have no ability
|
||
|
# to run Gtk applications in general. Even tho I dislike Window and do not
|
||
|
# condone the use of it. I don't want to make VCStudio completilly unusable
|
||
|
# for them. For example let's say somebody will distribute a story.vcss file.
|
||
|
# I want to give Windows users at least the ability to read the text of the
|
||
|
# scene.
|
||
|
|
||
|
# Also the console mode could be used for the rendering servers of big
|
||
|
# studios. Where running a GUI is just not practical. They usually have a
|
||
|
# terminal only installation. And so some kind of way of working with project
|
||
|
# should be possible from the terminal.
|
||
|
|
||
|
##############################################################################
|
||
|
|
||
|
|
||
|
import os
|
||
|
import re
|
||
|
import datetime
|
||
|
import threading
|
||
|
|
||
|
# Let's get a terminal size for prettier rendering.
|
||
|
|
||
|
try:
|
||
|
w, h = os.get_terminal_size()
|
||
|
except:
|
||
|
w, h, = 50,50
|
||
|
|
||
|
from settings import settings
|
||
|
from settings import talk
|
||
|
from settings import oscalls
|
||
|
from project_manager import pm_project
|
||
|
from project_manager import pm_console
|
||
|
|
||
|
# Studio
|
||
|
from studio import analytics
|
||
|
from studio import story
|
||
|
from studio import studio_storyDeletionLayer
|
||
|
from studio import studio_storyLayer
|
||
|
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
|
||
|
from UI import UI_color
|
||
|
from UI import UI_elements
|
||
|
|
||
|
# Network
|
||
|
from network import network_renders
|
||
|
from network import network_multiuser
|
||
|
from network import multiuser_terminal
|
||
|
|
||
|
|
||
|
|
||
|
commands1 = [
|
||
|
"help",# - returns this help
|
||
|
"asset",# - choose and asset
|
||
|
"assets",# - list existsing assets
|
||
|
"scene",# - read a scene
|
||
|
"scenes",# - lists available scenes
|
||
|
"scenes_main_chain",# - list only scenes from the main chain
|
||
|
"shot",# - choose a shot
|
||
|
"shots",# - list shots of a given scene
|
||
|
"file",# - open a file from a given asset or shot
|
||
|
"files",# - list all files from a given asset or shot
|
||
|
"multiuser_start",# - starts multiuser server for this project
|
||
|
"multiuser_stop",# - stops multiuser
|
||
|
"multiuser_users",# - list of users connected to multiuser
|
||
|
"multiuser_message",# - message users on multiuser
|
||
|
"vse",# - starts a vse file
|
||
|
"vses",# - lists all vse files
|
||
|
"render",# - render a given file from a shot
|
||
|
"render_server",# - become a render server for users on multiuser
|
||
|
"render_not_server",# - stop being a render server for users
|
||
|
"eval", # - run a python expression
|
||
|
"exit"
|
||
|
|
||
|
]
|
||
|
|
||
|
|
||
|
pm_console.commands = commands1.copy()
|
||
|
|
||
|
|
||
|
def cls():
|
||
|
#cleaning the terminal
|
||
|
os.system("clear")
|
||
|
|
||
|
|
||
|
class make_win:
|
||
|
|
||
|
# In order to make it work with all the standard functions build for the GUI
|
||
|
# experience. Like export, multiuser and such. Yes multiuser will be supported
|
||
|
# here fully. We have to be able to access the win.<anything> object. BUT
|
||
|
# there is a rub. The win object is not really accesable from non Gtk system.
|
||
|
|
||
|
# Because I had this genious idea to use already created Gtk.Window and just
|
||
|
# add a bunch stuff to it in order to have a kind of global dictionary thing.
|
||
|
|
||
|
def __init__(self, project):
|
||
|
|
||
|
self.project = project
|
||
|
|
||
|
def previous(win):
|
||
|
win.previous = {}
|
||
|
for i in win.current:
|
||
|
if type(win.current[i]) == list or type(win.current[i]) is dict:
|
||
|
win.previous[i] = win.current[i].copy()
|
||
|
else:
|
||
|
win.previous[i] = win.current[i]
|
||
|
|
||
|
|
||
|
def run(project):
|
||
|
|
||
|
|
||
|
win = make_win(project)
|
||
|
|
||
|
# Setting up the global variables. (kinda)
|
||
|
win.animations = {}
|
||
|
win.previous = {}
|
||
|
win.current = {}
|
||
|
win.images = {}
|
||
|
win.imageload = 0
|
||
|
win.text = {}
|
||
|
win.textactive = ""
|
||
|
win.scroll = {}
|
||
|
win.FPS = 0
|
||
|
win.url = "story_editor"
|
||
|
win.cur = "" # This will be used to get precicelly what asset / scene / shot we are in
|
||
|
win.update = {"versions":{}}
|
||
|
win.project = project
|
||
|
win.out_dots = {}
|
||
|
win.assets = {}
|
||
|
win.szone = [[100,100],[100,100]] # Square drawn if selected more then one node.
|
||
|
win.surround = { # And this is the list of the squares. Because it's not
|
||
|
"frame":0, # as easy to do. See UI / UI_math / rectangle_surround()
|
||
|
"rects":[] # for details of this implementation.
|
||
|
}
|
||
|
win.calllayer = False
|
||
|
win.layercashe = {} # Here I gonna store layers that are inactive to speed up stuff
|
||
|
win.checklists = {}
|
||
|
win.blink = False # Cursor blinking thing.
|
||
|
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)
|
||
|
win.analytics = analytics.get_legacy(project)
|
||
|
else:
|
||
|
win.story = story.load(project)
|
||
|
win.analytics = analytics.load(project)
|
||
|
|
||
|
# Cashed tables
|
||
|
win.color = UI_color.get_table()
|
||
|
win.settings = settings.load_all()
|
||
|
|
||
|
# Default values
|
||
|
win.current["frame"] = 0
|
||
|
win.current["testing"] = False
|
||
|
win.current["LMB"] = False
|
||
|
win.current["MMB"] = False
|
||
|
win.current["RMB"] = False
|
||
|
win.current["keys"] = []
|
||
|
win.current["key_letter"] = ""
|
||
|
win.current["scroll"] = [0,0]
|
||
|
win.current["project"] = ""
|
||
|
win.current["tool"] = "selection"
|
||
|
win.current["draw_dot"] = "end"
|
||
|
win.current["calls"] = {} # Calls. See sutdio/studio_dialogs.py
|
||
|
win.current["script_find"] = [0,0]
|
||
|
win.current["camera_arrived"] = False
|
||
|
|
||
|
if "pointers" not in win.story:
|
||
|
win.story["pointers"] = {} # List of text pointers per scene
|
||
|
|
||
|
new_date_format = "%Y/%m/%d"
|
||
|
today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
|
||
|
win.current["date"] = today # Don't even ask. I'm litteraly tired already.
|
||
|
|
||
|
previous(win)
|
||
|
|
||
|
# Version of the software
|
||
|
win.version = 0.0
|
||
|
try:
|
||
|
vfile = open("settings/update.data")
|
||
|
vfile = vfile.read()
|
||
|
vfile = vfile.split("\n")
|
||
|
|
||
|
for line in vfile:
|
||
|
if line.startswith("VERSION "):
|
||
|
win.version = float(line.replace("VERSION ", ""))
|
||
|
break
|
||
|
except:
|
||
|
win.version = 0.0
|
||
|
|
||
|
# FPS
|
||
|
win.sFPS = datetime.datetime.now()
|
||
|
|
||
|
|
||
|
|
||
|
cls()
|
||
|
|
||
|
|
||
|
# The title thing in the top
|
||
|
|
||
|
print("\033[1;33m\n "+win.analytics["name"]+"")
|
||
|
print("\033[1;33m "+win.analytics["director"]+"")
|
||
|
print("\033[1;33m "+win.analytics["status"]+" \n")
|
||
|
progress_bar(win.analytics["fraction"])
|
||
|
print()
|
||
|
|
||
|
|
||
|
while True:
|
||
|
|
||
|
# making sure Tab is doing autocomlete to the right functions
|
||
|
|
||
|
pm_console.commands = commands1.copy()
|
||
|
|
||
|
command = input("\033[1;35m : \033[1;m")
|
||
|
|
||
|
##############
|
||
|
|
||
|
if command == "exit":
|
||
|
cls()
|
||
|
exit()
|
||
|
|
||
|
###### HELP ######
|
||
|
elif command == "help":
|
||
|
|
||
|
print("\033[1;32m"+talk.text("sc_help")+"\n")
|
||
|
|
||
|
##### ASSETS LIST ####
|
||
|
|
||
|
elif command == "assets":
|
||
|
for asset in network_multiuser.list_all_assets(win):
|
||
|
print("\033[1;35m "+asset)
|
||
|
|
||
|
##### ASSET ACCESS #####
|
||
|
|
||
|
elif command == "asset":
|
||
|
|
||
|
pm_console.commands = pm_project.get_list()
|
||
|
|
||
|
n = input("\033[1;33m : ")
|
||
|
|
||
|
if os.path.exists(win.project+"/dev"+n) and n.count("/") == 2:
|
||
|
|
||
|
win.cur = n
|
||
|
|
||
|
t, cur, name = n.split("/")
|
||
|
|
||
|
print("\033[1;33m\n "+talk.text(cur)+": "+name)
|
||
|
progress_bar(story.get_asset_data(win, n)["fraction"])
|
||
|
print()
|
||
|
|
||
|
|
||
|
else:
|
||
|
print("\033[1;31m"+talk.text("failed"))
|
||
|
|
||
|
#### SCENES LIST ####
|
||
|
|
||
|
elif command == "scenes":
|
||
|
for scene in win.story["scenes"]:
|
||
|
print("\033[1;35m "+scene)
|
||
|
|
||
|
#### SCENES MAIN CHAIN LIST ####
|
||
|
|
||
|
elif command == "scenes_main_chain":
|
||
|
lastarrow = 'start'
|
||
|
for i in win.story["arrows"]:
|
||
|
if lastarrow == "end":
|
||
|
break
|
||
|
for arrow in win.story["arrows"]:
|
||
|
if arrow[0] == lastarrow:
|
||
|
lastarrow = arrow[1]
|
||
|
if arrow[1] != "end":
|
||
|
print("\033[1;35m "+arrow[1][1])
|
||
|
|
||
|
##### READ SCENE TEXT #####
|
||
|
|
||
|
elif command == "scene":
|
||
|
|
||
|
pm_console.commands = list(win.story["scenes"].keys())
|
||
|
|
||
|
n = input("\033[1;33m : ")
|
||
|
|
||
|
|
||
|
|
||
|
if n in win.story["scenes"]:
|
||
|
win.cur = "/"+n
|
||
|
|
||
|
|
||
|
|
||
|
# I want to have the full scene written to the terminal at this
|
||
|
# point. Good that most terminals already support tiling. I don't
|
||
|
# need to care about that. So let's do that.
|
||
|
|
||
|
scene = win.story["scenes"][n]["shots"]
|
||
|
|
||
|
buf = "\033[1;0m"
|
||
|
lines = 0
|
||
|
|
||
|
for block in scene:
|
||
|
|
||
|
|
||
|
# For just text parts.
|
||
|
if block[0] == "text_block":
|
||
|
style = "\033[1;40m"
|
||
|
else:
|
||
|
|
||
|
# If It's a shot. I want the shot color marking
|
||
|
|
||
|
shotis = block[1]
|
||
|
|
||
|
rcolors = {
|
||
|
"shot_1":"\033[1;41m",
|
||
|
"shot_2":"\033[1;43m",
|
||
|
"shot_3":"\033[1;46m",
|
||
|
"shot_4":"\033[1;44m",
|
||
|
"shot_5":"\033[1;42m"
|
||
|
}
|
||
|
|
||
|
# Getting the color. It's not always works.
|
||
|
|
||
|
if "shot_colors" not in win.story:
|
||
|
win.story["shot_colors"] = {}
|
||
|
|
||
|
surl = "/"+n+"/"+shotis
|
||
|
|
||
|
if surl not in win.story["shot_colors"]:
|
||
|
|
||
|
win.story["shot_colors"][surl] = list(rcolors.keys())[len(win.story["shot_colors"]) % len(rcolors)]
|
||
|
|
||
|
style = rcolors[win.story["shot_colors"][surl]]
|
||
|
|
||
|
for text in block[-1]:
|
||
|
|
||
|
# For just regular parts we have our regular text
|
||
|
|
||
|
if text[0] == "text" or text[0] == "link":
|
||
|
|
||
|
for line in re.split("(\n)",text[-1]):
|
||
|
|
||
|
if line == "\n":
|
||
|
|
||
|
while buf:
|
||
|
print(buf[:w])
|
||
|
buf = buf[w:]
|
||
|
lines = lines + 1
|
||
|
if lines + 8 > h:
|
||
|
input("... "+talk.text("press_to_continue")+" ...")
|
||
|
lines = 0
|
||
|
|
||
|
buf = "\033[1;0m"
|
||
|
|
||
|
else:
|
||
|
|
||
|
if text[0] == "text":
|
||
|
buf = buf + style + line + "\033[1;0m"
|
||
|
else:
|
||
|
buf = buf + "\033[1;45m" + line + "\033[1;0m"
|
||
|
|
||
|
elif text[0] == "frase":
|
||
|
|
||
|
while buf:
|
||
|
print(buf[:w])
|
||
|
buf = buf[w:]
|
||
|
lines = lines + 1
|
||
|
if lines + 8 > h:
|
||
|
input("... "+talk.text("press_to_continue")+" ...")
|
||
|
lines = 0
|
||
|
buf = "\033[1;0m"
|
||
|
|
||
|
if text[1][0] == "text":
|
||
|
print(" "*int(w/2-len(text[1][-1])/2)+"\033[1;40m"+text[1][-1])
|
||
|
else:
|
||
|
print(" "*int(w/2-len(text[1][-1])/2)+"\033[1;45m"+text[1][-1]+"\033[1;40m")
|
||
|
|
||
|
|
||
|
for line in re.split("(\n)",text[-1]):
|
||
|
if line == "\n":
|
||
|
print(line)
|
||
|
|
||
|
else:
|
||
|
while line:
|
||
|
print(" "*int(w/3)+style+line[:int(w/3)])
|
||
|
line = line[int(w/3):]
|
||
|
lines = lines + 1
|
||
|
if lines + 8 > h:
|
||
|
input("... "+talk.text("press_to_continue")+" ...")
|
||
|
lines = 0
|
||
|
|
||
|
while buf:
|
||
|
print(buf[:w])
|
||
|
buf = buf[w:]
|
||
|
lines = lines + 1
|
||
|
if lines + 8 > h:
|
||
|
input("... "+talk.text("press_to_continue")+" ...")
|
||
|
lines = 0
|
||
|
|
||
|
print()
|
||
|
print("\033[1;33m\n "+n)
|
||
|
progress_bar(win.story["scenes"][n]["fraction"])
|
||
|
print()
|
||
|
|
||
|
else:
|
||
|
print("\033[1;31m"+talk.text("failed"))
|
||
|
|
||
|
|
||
|
### FILES ###
|
||
|
|
||
|
elif command == "files":
|
||
|
|
||
|
prefix = "/rnd"
|
||
|
for i in ["/chr", "/veh", "/obj","/loc"]:
|
||
|
if win.cur.startswith(i):
|
||
|
prefix = "/dev"
|
||
|
|
||
|
for i in network_multiuser.get_give_folder_list(win.project, prefix+win.cur):
|
||
|
print("\033[1;35m "+i[0])
|
||
|
|
||
|
elif command == "file":
|
||
|
n = input("\033[1;33m : ")
|
||
|
oscalls.Open(win.project+n)
|
||
|
|
||
|
### EVAL ###
|
||
|
|
||
|
elif command == "eval":
|
||
|
n = input("\033[1;33m : ")
|
||
|
try:
|
||
|
print("\033[1;33m"+str(eval(n)))
|
||
|
except Exception as e:
|
||
|
print("\033[1;31m"+talk.text("failed")+" : "+str(e))
|
||
|
|
||
|
|
||
|
#### NOT IMPLEMENTED YET ####
|
||
|
|
||
|
elif command in pm_console.commands:
|
||
|
print("\033[1;31m"+talk.text("failed")+" : Not Implemented Yet")
|
||
|
|
||
|
|
||
|
## FAIL ##
|
||
|
|
||
|
elif command != "":
|
||
|
print("\033[1;31m"+talk.text("failed"))
|
||
|
|
||
|
|
||
|
|
||
|
def progress_bar(f):
|
||
|
|
||
|
# This function will print out a progress bar similar to
|
||
|
|
||
|
# [ ############################.................................. ]
|
||
|
|
||
|
bw = w-6
|
||
|
pw = int(round(bw*f))
|
||
|
lw = bw - pw
|
||
|
|
||
|
print(" [ "+"#"*pw+"."*lw+" ] ")
|
||
|
|
||
|
|