sc_main.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. # THIS FILE IS A PART OF VCStudio
  2. # PYTHON 3
  3. ##############################################################################
  4. # Not all users have the ability or the desire to run a complex Graphical UI
  5. # to do simple tasks in the project. For example Windows users have no ability
  6. # to run Gtk applications in general. Even tho I dislike Window and do not
  7. # condone the use of it. I don't want to make VCStudio completilly unusable
  8. # for them. For example let's say somebody will distribute a story.vcss file.
  9. # I want to give Windows users at least the ability to read the text of the
  10. # scene.
  11. # Also the console mode could be used for the rendering servers of big
  12. # studios. Where running a GUI is just not practical. They usually have a
  13. # terminal only installation. And so some kind of way of working with project
  14. # should be possible from the terminal.
  15. ##############################################################################
  16. import os
  17. import re
  18. import datetime
  19. import threading
  20. # Let's get a terminal size for prettier rendering.
  21. try:
  22. w, h = os.get_terminal_size()
  23. except:
  24. w, h, = 50,50
  25. from settings import settings
  26. from settings import talk
  27. from settings import oscalls
  28. from project_manager import pm_project
  29. from project_manager import pm_console
  30. # Studio
  31. from studio import analytics
  32. from studio import story
  33. from studio import studio_storyDeletionLayer
  34. from studio import studio_storyLayer
  35. from studio import studio_settingsLayer
  36. from studio import studio_assetLayer
  37. from studio import studio_analyticsLayer
  38. from studio import studio_scriptLayer
  39. from studio import studio_multiuserLayer
  40. # UI modules
  41. from UI import UI_testing
  42. from UI import UI_color
  43. from UI import UI_elements
  44. # Network
  45. from network import network_renders
  46. from network import network_multiuser
  47. from network import multiuser_terminal
  48. commands1 = [
  49. "help",# - returns this help
  50. "asset",# - choose and asset
  51. "assets",# - list existsing assets
  52. "scene",# - read a scene
  53. "scenes",# - lists available scenes
  54. "scenes_main_chain",# - list only scenes from the main chain
  55. "shot",# - choose a shot
  56. "shots",# - list shots of a given scene
  57. "file",# - open a file from a given asset or shot
  58. "files",# - list all files from a given asset or shot
  59. "multiuser_start",# - starts multiuser server for this project
  60. "multiuser_stop",# - stops multiuser
  61. "multiuser_users",# - list of users connected to multiuser
  62. "multiuser_message",# - message users on multiuser
  63. "vse",# - starts a vse file
  64. "vses",# - lists all vse files
  65. "render",# - render a given file from a shot
  66. "render_server",# - become a render server for users on multiuser
  67. "render_not_server",# - stop being a render server for users
  68. "eval", # - run a python expression
  69. "exit"
  70. ]
  71. pm_console.commands = commands1.copy()
  72. def cls():
  73. #cleaning the terminal
  74. os.system("clear")
  75. class make_win:
  76. # In order to make it work with all the standard functions build for the GUI
  77. # experience. Like export, multiuser and such. Yes multiuser will be supported
  78. # here fully. We have to be able to access the win.<anything> object. BUT
  79. # there is a rub. The win object is not really accesable from non Gtk system.
  80. # Because I had this genious idea to use already created Gtk.Window and just
  81. # add a bunch stuff to it in order to have a kind of global dictionary thing.
  82. def __init__(self, project):
  83. self.project = project
  84. def previous(win):
  85. win.previous = {}
  86. for i in win.current:
  87. if type(win.current[i]) == list or type(win.current[i]) is dict:
  88. win.previous[i] = win.current[i].copy()
  89. else:
  90. win.previous[i] = win.current[i]
  91. def run(project):
  92. win = make_win(project)
  93. # Setting up the global variables. (kinda)
  94. win.animations = {}
  95. win.previous = {}
  96. win.current = {}
  97. win.images = {}
  98. win.imageload = 0
  99. win.text = {}
  100. win.textactive = ""
  101. win.scroll = {}
  102. win.FPS = 0
  103. win.url = "story_editor"
  104. win.cur = "" # This will be used to get precicelly what asset / scene / shot we are in
  105. win.update = {"versions":{}}
  106. win.project = project
  107. win.out_dots = {}
  108. win.assets = {}
  109. win.szone = [[100,100],[100,100]] # Square drawn if selected more then one node.
  110. win.surround = { # And this is the list of the squares. Because it's not
  111. "frame":0, # as easy to do. See UI / UI_math / rectangle_surround()
  112. "rects":[] # for details of this implementation.
  113. }
  114. win.calllayer = False
  115. win.layercashe = {} # Here I gonna store layers that are inactive to speed up stuff
  116. win.checklists = {}
  117. win.blink = False # Cursor blinking thing.
  118. win.renders = {} # List of current active renders.
  119. win.undo_history = []
  120. win.undo_index = 0
  121. win.multiuser = {
  122. "server":False, # Whether we are connected to the server. And the server ID
  123. "userid":"", # The id of current user in the server
  124. "last_request": "", # The last request send to the server. ( for stopping bloat )
  125. "curs":{}, # The information about various items on other users machines.
  126. "request":[["story"]], # Requests done in UI space
  127. "users":{}, # List of users information Names, IPs etc.
  128. "messages":[], # List of messages
  129. "unread":0 , # Amount of unread messages
  130. "terminal":[], # The outputs from the server
  131. "asset_list_check":False, # Whether the initial update happened when connecting to the server
  132. "story_check":False, # Whether the first story check was done.
  133. "analytics_check":False
  134. }
  135. if pm_project.is_legacy(project):
  136. win.story = story.get_legacy(project)
  137. win.analytics = analytics.get_legacy(project)
  138. else:
  139. win.story = story.load(project)
  140. win.analytics = analytics.load(project)
  141. # Cashed tables
  142. win.color = UI_color.get_table()
  143. win.settings = settings.load_all()
  144. # Default values
  145. win.current["frame"] = 0
  146. win.current["testing"] = False
  147. win.current["LMB"] = False
  148. win.current["MMB"] = False
  149. win.current["RMB"] = False
  150. win.current["keys"] = []
  151. win.current["key_letter"] = ""
  152. win.current["scroll"] = [0,0]
  153. win.current["project"] = ""
  154. win.current["tool"] = "selection"
  155. win.current["draw_dot"] = "end"
  156. win.current["calls"] = {} # Calls. See sutdio/studio_dialogs.py
  157. win.current["script_find"] = [0,0]
  158. win.current["camera_arrived"] = False
  159. if "pointers" not in win.story:
  160. win.story["pointers"] = {} # List of text pointers per scene
  161. new_date_format = "%Y/%m/%d"
  162. today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
  163. win.current["date"] = today # Don't even ask. I'm litteraly tired already.
  164. previous(win)
  165. # Version of the software
  166. win.version = 0.0
  167. try:
  168. vfile = open("settings/update.data")
  169. vfile = vfile.read()
  170. vfile = vfile.split("\n")
  171. for line in vfile:
  172. if line.startswith("VERSION "):
  173. win.version = float(line.replace("VERSION ", ""))
  174. break
  175. except:
  176. win.version = 0.0
  177. # FPS
  178. win.sFPS = datetime.datetime.now()
  179. cls()
  180. # The title thing in the top
  181. print("\033[1;33m\n "+win.analytics["name"]+"")
  182. print("\033[1;33m "+win.analytics["director"]+"")
  183. print("\033[1;33m "+win.analytics["status"]+" \n")
  184. progress_bar(win.analytics["fraction"])
  185. print()
  186. while True:
  187. # making sure Tab is doing autocomlete to the right functions
  188. pm_console.commands = commands1.copy()
  189. command = input("\033[1;35m : \033[1;m")
  190. ##############
  191. if command == "exit":
  192. cls()
  193. exit()
  194. ###### HELP ######
  195. elif command == "help":
  196. print("\033[1;32m"+talk.text("sc_help")+"\n")
  197. ##### ASSETS LIST ####
  198. elif command == "assets":
  199. for asset in network_multiuser.list_all_assets(win):
  200. print("\033[1;35m "+asset)
  201. ##### ASSET ACCESS #####
  202. elif command == "asset":
  203. pm_console.commands = pm_project.get_list()
  204. n = input("\033[1;33m : ")
  205. if os.path.exists(win.project+"/dev"+n) and n.count("/") == 2:
  206. win.cur = n
  207. t, cur, name = n.split("/")
  208. print("\033[1;33m\n "+talk.text(cur)+": "+name)
  209. progress_bar(story.get_asset_data(win, n)["fraction"])
  210. print()
  211. else:
  212. print("\033[1;31m"+talk.text("failed"))
  213. #### SCENES LIST ####
  214. elif command == "scenes":
  215. for scene in win.story["scenes"]:
  216. print("\033[1;35m "+scene)
  217. #### SCENES MAIN CHAIN LIST ####
  218. elif command == "scenes_main_chain":
  219. lastarrow = 'start'
  220. for i in win.story["arrows"]:
  221. if lastarrow == "end":
  222. break
  223. for arrow in win.story["arrows"]:
  224. if arrow[0] == lastarrow:
  225. lastarrow = arrow[1]
  226. if arrow[1] != "end":
  227. print("\033[1;35m "+arrow[1][1])
  228. ##### READ SCENE TEXT #####
  229. elif command == "scene":
  230. pm_console.commands = list(win.story["scenes"].keys())
  231. n = input("\033[1;33m : ")
  232. if n in win.story["scenes"]:
  233. win.cur = "/"+n
  234. # I want to have the full scene written to the terminal at this
  235. # point. Good that most terminals already support tiling. I don't
  236. # need to care about that. So let's do that.
  237. scene = win.story["scenes"][n]["shots"]
  238. buf = "\033[1;0m"
  239. lines = 0
  240. for block in scene:
  241. # For just text parts.
  242. if block[0] == "text_block":
  243. style = "\033[1;40m"
  244. else:
  245. # If It's a shot. I want the shot color marking
  246. shotis = block[1]
  247. rcolors = {
  248. "shot_1":"\033[1;41m",
  249. "shot_2":"\033[1;43m",
  250. "shot_3":"\033[1;46m",
  251. "shot_4":"\033[1;44m",
  252. "shot_5":"\033[1;42m"
  253. }
  254. # Getting the color. It's not always works.
  255. if "shot_colors" not in win.story:
  256. win.story["shot_colors"] = {}
  257. surl = "/"+n+"/"+shotis
  258. if surl not in win.story["shot_colors"]:
  259. win.story["shot_colors"][surl] = list(rcolors.keys())[len(win.story["shot_colors"]) % len(rcolors)]
  260. style = rcolors[win.story["shot_colors"][surl]]
  261. for text in block[-1]:
  262. # For just regular parts we have our regular text
  263. if text[0] == "text" or text[0] == "link":
  264. for line in re.split("(\n)",text[-1]):
  265. if line == "\n":
  266. while buf:
  267. print(buf[:w])
  268. buf = buf[w:]
  269. lines = lines + 1
  270. if lines + 8 > h:
  271. input("... "+talk.text("press_to_continue")+" ...")
  272. lines = 0
  273. buf = "\033[1;0m"
  274. else:
  275. if text[0] == "text":
  276. buf = buf + style + line + "\033[1;0m"
  277. else:
  278. buf = buf + "\033[1;45m" + line + "\033[1;0m"
  279. elif text[0] == "frase":
  280. while buf:
  281. print(buf[:w])
  282. buf = buf[w:]
  283. lines = lines + 1
  284. if lines + 8 > h:
  285. input("... "+talk.text("press_to_continue")+" ...")
  286. lines = 0
  287. buf = "\033[1;0m"
  288. if text[1][0] == "text":
  289. print(" "*int(w/2-len(text[1][-1])/2)+"\033[1;40m"+text[1][-1])
  290. else:
  291. print(" "*int(w/2-len(text[1][-1])/2)+"\033[1;45m"+text[1][-1]+"\033[1;40m")
  292. for line in re.split("(\n)",text[-1]):
  293. if line == "\n":
  294. print(line)
  295. else:
  296. while line:
  297. print(" "*int(w/3)+style+line[:int(w/3)])
  298. line = line[int(w/3):]
  299. lines = lines + 1
  300. if lines + 8 > h:
  301. input("... "+talk.text("press_to_continue")+" ...")
  302. lines = 0
  303. while buf:
  304. print(buf[:w])
  305. buf = buf[w:]
  306. lines = lines + 1
  307. if lines + 8 > h:
  308. input("... "+talk.text("press_to_continue")+" ...")
  309. lines = 0
  310. print()
  311. print("\033[1;33m\n "+n)
  312. progress_bar(win.story["scenes"][n]["fraction"])
  313. print()
  314. else:
  315. print("\033[1;31m"+talk.text("failed"))
  316. ### FILES ###
  317. elif command == "files":
  318. prefix = "/rnd"
  319. for i in ["/chr", "/veh", "/obj","/loc"]:
  320. if win.cur.startswith(i):
  321. prefix = "/dev"
  322. for i in network_multiuser.get_give_folder_list(win.project, prefix+win.cur):
  323. print("\033[1;35m "+i[0])
  324. elif command == "file":
  325. n = input("\033[1;33m : ")
  326. oscalls.Open(win.project+n)
  327. ### EVAL ###
  328. elif command == "eval":
  329. n = input("\033[1;33m : ")
  330. try:
  331. print("\033[1;33m"+str(eval(n)))
  332. except Exception as e:
  333. print("\033[1;31m"+talk.text("failed")+" : "+str(e))
  334. #### NOT IMPLEMENTED YET ####
  335. elif command in pm_console.commands:
  336. print("\033[1;31m"+talk.text("failed")+" : Not Implemented Yet")
  337. ## FAIL ##
  338. elif command != "":
  339. print("\033[1;31m"+talk.text("failed"))
  340. def progress_bar(f):
  341. # This function will print out a progress bar similar to
  342. # [ ############################.................................. ]
  343. bw = w-6
  344. pw = int(round(bw*f))
  345. lw = bw - pw
  346. print(" [ "+"#"*pw+"."*lw+" ] ")