Jeison Yehuda Amihud (Blender Dumbass)
46cfaaa553
The initial file that does all the Terminal mode. It's quite tiny for some reason.
483 lines
17 KiB
Python
483 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+" ] ")
|
|
|
|
|