studio_dialogs.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. # THIS FILE IS A PART OF VCStudio
  2. # PYTHON 3
  3. ################################################################################
  4. # This file here will act like simple set of functions for the developer of the
  5. # software. But infect will be a little more complex behimith. To explain the
  6. # idea we need to look a little bit deeper into how this program functions and
  7. # draws UI peaces.
  8. # Basically every Layer py file is a set of instuction of how to draw a specific
  9. # UI on to the screen. Those function return the finished canvas. An image
  10. # basically. That the compositing layer (studio_gtk.py or pm_gtk.py ) combine
  11. # into a bigger picture.
  12. # There is a blur effect added to undernith layers if the top layer is drawn.
  13. # I do this by checking the win.url string. Each layer has they own urls.
  14. # Some are composited at all times. Some only if their url is the url. But all
  15. # get blurred if it's not their url.
  16. # Unfortunatly I can't make a function that will return a value. Because it means
  17. # to stop the drawing of the UI. And I need the UI to get to next frame in order
  18. # to draw the function's UI.
  19. # Let's say I want to add a link to an image to the story-editor. I click on the
  20. # add button. Next what I want to see is a searcher dialog appear. As soon as I
  21. # have selected the image I want to link, then the new link appears in the story
  22. # editor space which is automatically moving. Untill I place it.
  23. # For this I need to set up some kind of variable. And as soon as this variable
  24. # is not None. For example. We are doing the rest of the operation.
  25. # Step 0 : User Clicks the add button. And a funtion is called.
  26. # Step 1 : This function creates a dictionary with a variable NONE and a callable
  27. # Step 2 : win.url changes to the Layer which is the searcher.
  28. # Step 3 : User selects the images, or a file that he or she wanted to select.
  29. # Step 4 : This filename is being written into the variable that used to be NONE.
  30. # Step 5 : As soon as this variable is not NONE the callable is called.
  31. # Step 6 : This callable is the one that does the setup work.
  32. # Of course it would defeat the purpose if the callable always standard. It shold
  33. # be one of the inputs to the dialogue function.
  34. # Function template function_name(win, operation_name, callable):
  35. ################################################################################
  36. import os
  37. import time
  38. import threading
  39. # GTK module ( Graphical interface
  40. import gi
  41. gi.require_version('Gtk', '3.0')
  42. from gi.repository import Gtk
  43. from gi.repository import GLib
  44. from gi.repository import Gdk
  45. import cairo
  46. # Own modules
  47. from settings import settings
  48. from settings import talk
  49. from project_manager import pm_project
  50. from studio import analytics
  51. from studio import studio_nodes
  52. #UI modules
  53. from UI import UI_elements
  54. from UI import UI_color
  55. ################################################### ########################
  56. # # #
  57. from studio import studio_file_selectLayer # # These modules he- #
  58. from studio import studio_asset_selectLayer # # re. Are the modu- #
  59. from studio import studio_shot_linkLayer # # les that are ac- #
  60. from studio import studio_asset_configureLayer # # tual UI of dialo- #
  61. from studio import studio_renderLayer # # gs that I was ta- #
  62. from studio import studio_vseLayer # # lking about at #
  63. from UI import UI_helpDialog # # the top. #
  64. from network import http_client # # #
  65. # # #
  66. ################################################### ########################
  67. # ^
  68. # |
  69. # Who does that?
  70. def file_select(win, name, call, force=False, IMAGE=True, BLEND=False, VIDEO=True,
  71. FILE=False, CHR=True, VEH=True, LOC=True, OBJ=True, RND=False, FOLDER=False,
  72. SEARCH=""):
  73. # Forcing reload of the fileswin.current["AllFiles"] = []
  74. try:
  75. del win.current["AllFiles"]
  76. except:
  77. pass
  78. # This function will select files for any kind of stuff. It will search
  79. # through the files of the project. Similar to image searcher in the old
  80. # organizer.
  81. if name not in win.current["calls"]:
  82. win.current["calls"][name] = {
  83. "var" :None, # This is the variable that we are waiting for
  84. "call":call, # This is what it's going to run when it's done
  85. "url" :"file_select",
  86. "back":win.url,# This is where it's going to come back when it's done
  87. "draw":studio_file_selectLayer.layer
  88. }
  89. # Now let's make a container to save those setting between frames
  90. if force or "file_selector" not in win.current:
  91. win.current["file_selector"] = {
  92. "image" :IMAGE,
  93. "blender":BLEND,
  94. "video" :VIDEO,
  95. "file" :FILE,
  96. "chr" :CHR,
  97. "veh" :VEH,
  98. "loc" :LOC,
  99. "obj" :OBJ,
  100. "vse" :RND,
  101. "folder" :FOLDER
  102. }
  103. # Search text
  104. win.text["file_select_search"] = {
  105. "text" :SEARCH, # Actuall text you are editing.
  106. "cursor":[len(str(SEARCH)),len(str(SEARCH))], # Cursor
  107. "insert":False, # Whether the insert mode is on
  108. "scroll":"file_select_search_scroll" # If multiline. The pointer for the scroll value.
  109. }
  110. # Let's activate the text so you could type immediatly
  111. win.textactive = "file_select_search"
  112. # Let's clear the LMB just in case
  113. win.previous["LMB"] = False
  114. def asset_select(win, name, call, force=False, cur="chr", SEARCH=""):
  115. # This function will be an asset selector. The idea it to be something
  116. # in between itemselector and assets in the same time.
  117. # If you remember
  118. # in the Blender-Organizer there were tabs on the top bar. If you click
  119. # on Characters let's say, you would get a full screen selector to enter
  120. # a given character.
  121. # But for linking and such you would get a small window with only names.
  122. # But with a search dialog.
  123. # Well this dialog will be some kind a merge of both of them. Having both
  124. # a very good cell-based preview type list and search. And could be used
  125. # not only to enter the asset, but also for linking and such.
  126. if name not in win.current["calls"]:
  127. win.current["calls"][name] = {
  128. "var" :None, # This is the variable that we are waiting for
  129. "call":call, # This is what it's going to run when it's done
  130. "url" :"asset_select",
  131. "back":win.url,# This is where it's going to come back when it's done
  132. "draw":studio_asset_selectLayer.layer
  133. }
  134. # Now let's make a container to save those setting between frames
  135. if force or "asset_cur" not in win.current:
  136. win.current["asset_cur"] = cur
  137. # Search text
  138. win.text["asset_select_search"] = {
  139. "text" :SEARCH, # Actuall text you are editing.
  140. "cursor":[len(str(SEARCH)),len(str(SEARCH))], # Cursor
  141. "insert":False, # Whether the insert mode is on
  142. "scroll":"asset_select_search_scroll" # If multiline. The pointer for the scroll value.
  143. }
  144. # Let's activate the text so you could type immediatly
  145. win.textactive = "asset_select_search"
  146. # Wiping the history of the assets. See studio/studio_asset_selectLayer.py
  147. win.assets = {}
  148. # Let's clear the LMB just in case
  149. win.previous["LMB"] = False
  150. def asset_link(win, name, call, filename, force=False):
  151. # This function will configure the linking of the assets into animation files
  152. # it's in theory a quite simple operation, but requires nesting of dialogs.
  153. # which is untested by the time I'm writting this comment.
  154. if name not in win.current["calls"]:
  155. win.current["calls"][name] = {
  156. "var" :None, # This is the variable that we are waiting for
  157. "call":call, # This is what it's going to run when it's done
  158. "url" :"asset_link",
  159. "back":win.url,# This is where it's going to come back when it's done
  160. "draw":studio_shot_linkLayer.layer
  161. }
  162. # let's prepare the data for this operation
  163. if force or "linking_asset_data" not in win.current\
  164. or win.current["linking_asset_data"]["linking_to"] != filename:
  165. win.current["linking_asset_data"] = {
  166. "linking_to":filename,
  167. "assets":[],
  168. "read":False,
  169. "selected":"",
  170. "mode":"link",
  171. "fraction":0,
  172. "process":False
  173. }
  174. if win.current["linking_asset_data"]["fraction"]:
  175. win.current["linking_asset_data"]["assets"] = []
  176. win.current["linking_asset_data"]["fraction"] = 0
  177. # Wiping the history of the assets. See studio/studio_asset_selectLayer.py
  178. win.assets = {}
  179. # Let's clear the LMB just in case
  180. win.previous["LMB"] = False
  181. def asset_configure(win, name, call, asset, force=False):
  182. # This function going to configure assets. More deatailed explanation is
  183. # in the file: studio/studio_asset_configureLayer.py
  184. if name not in win.current["calls"]:
  185. win.current["calls"][name] = {
  186. "var" :None, # This is the variable that we are waiting for
  187. "call":call, # This is what it's going to run when it's done
  188. "url" :"asset_configure",
  189. "back":win.url,# This is where it's going to come back when it's done
  190. "draw":studio_asset_configureLayer.layer
  191. }
  192. # let's prepare the data for this operation
  193. if force or "asset_configure" not in win.current\
  194. or win.current["asset_configure"]["asset"] != asset:
  195. win.current["asset_configure"] = {
  196. "asset":asset,
  197. "blend_to_copy":"",
  198. "collections":{},
  199. "step3_button":"collection",
  200. "apply":False
  201. }
  202. # Wiping the history of the assets. See studio/studio_asset_selectLayer.py
  203. win.assets = {}
  204. # Let's clear the LMB just in case
  205. win.previous["LMB"] = False
  206. def render(win, name, call, filename="", force=False):
  207. # This function going to launch a window that shows all current renders and
  208. # confuge them.
  209. if name not in win.current["calls"]:
  210. win.current["calls"][name] = {
  211. "var" :None, # This is the variable that we are waiting for
  212. "call":call, # This is what it's going to run when it's done
  213. "url" :"render",
  214. "back":win.url,# This is where it's going to come back when it's done
  215. "draw":studio_renderLayer.layer
  216. }
  217. # let's prepare the data for this operation
  218. if force or "renders_window" not in win.current\
  219. or win.current["renders_window"]["filename"] != filename:
  220. win.current["renders_window"] = {
  221. "filename":filename
  222. }
  223. # Wiping the history of the assets. See studio/studio_asset_selectLayer.py
  224. win.assets = {}
  225. # Let's clear the LMB just in case
  226. win.previous["LMB"] = False
  227. def vse(win, name, call, filename="", force=False):
  228. # This function going to select vse blend files.
  229. if name not in win.current["calls"]:
  230. win.current["calls"][name] = {
  231. "var" :None, # This is the variable that we are waiting for
  232. "call":call, # This is what it's going to run when it's done
  233. "url" :"vse",
  234. "back":win.url,# This is where it's going to come back when it's done
  235. "draw":studio_vseLayer.layer
  236. }
  237. # Let's clear the LMB just in case
  238. win.previous["LMB"] = False
  239. def help(win, name, call, filename="", force=False, SEARCH=""):
  240. # This function going to select vse blend files.
  241. if name not in win.current["calls"]:
  242. win.current["calls"][name] = {
  243. "var" :None, # This is the variable that we are waiting for
  244. "call":call, # This is what it's going to run when it's done
  245. "url" :"help",
  246. "back":win.url,# This is where it's going to come back when it's done
  247. "draw":UI_helpDialog.layer
  248. }
  249. # Let's clear the LMB just in case
  250. win.previous["LMB"] = False
  251. win.text["in_help"] = {
  252. "text" :SEARCH, # Actuall text you are editing.
  253. "cursor":[len(str(SEARCH)),len(str(SEARCH))], # Cursor
  254. "insert":False, # Whether the insert mode is on
  255. "scroll":"in_help_search_scroll" # If multiline. The pointer for the scroll value.
  256. }
  257. def http_client_dialog(win, name, call, function, args=""):
  258. # This function is going to be the UI for http-client.
  259. if name not in win.current["calls"]:
  260. win.current["calls"][name] = {
  261. "var" :None, # This is the variable that we are waiting for
  262. "call":call, # This is what it's going to run when it's done
  263. "url" :"http-server",
  264. "back":win.url,# This is where it's going to come back when it's done
  265. "draw":http_client.layer
  266. }
  267. # Let's clear the LMB just in case
  268. win.previous["LMB"] = False
  269. # Some variables to pass so the function.
  270. win.current["http-server"] = {
  271. "args" :args, # arguments to the function
  272. "progress":0, # progress of that function
  273. "fileprog":0, # progress for a file download
  274. "call" :name, # The call to stop the process
  275. "message" :"", # message about the progress
  276. "started" :time.time()# current time ( to calculate progress completion )
  277. }
  278. # Let's now run the function
  279. function_run = threading.Thread(target=function, args=(win,))
  280. function_run.setDaemon(True)
  281. function_run.start()
  282. def http_client_update_prompt(win, name, call):
  283. # This function is going to be the UI for http-client.
  284. if name not in win.current["calls"]:
  285. win.current["calls"][name] = {
  286. "var" :None, # This is the variable that we are waiting for
  287. "call":call, # This is what it's going to run when it's done
  288. "url" :"http-server-prompt",
  289. "back":win.url,# This is where it's going to come back when it's done
  290. "draw":http_client.prompt_layer
  291. }
  292. # Let's clear the LMB just in case
  293. win.previous["LMB"] = False