studio_multiuserLayer.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. # THIS FILE IS A PART OF VCStudio
  2. # PYTHON 3
  3. import os
  4. from subprocess import *
  5. # GTK module ( Graphical interface
  6. import gi
  7. gi.require_version('Gtk', '3.0')
  8. from gi.repository import Gtk
  9. from gi.repository import GLib
  10. from gi.repository import Gdk
  11. import cairo
  12. # Own modules
  13. from settings import settings
  14. from settings import talk
  15. from settings import fileformats
  16. from project_manager import pm_project
  17. #UI modules
  18. from UI import UI_elements
  19. from UI import UI_color
  20. # story
  21. from studio import story
  22. from studio import analytics
  23. from studio import history
  24. from studio import studio_dialogs
  25. # network
  26. from network import multiuser_terminal
  27. def layer(win):
  28. # Making the layer
  29. surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'],
  30. win.current['h'])
  31. layer = cairo.Context(surface)
  32. #text setting
  33. layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  34. UI_color.set(layer, win, "dark_overdrop")
  35. layer.rectangle(
  36. 0,
  37. 0,
  38. win.current["w"],
  39. win.current["h"],
  40. )
  41. layer.fill()
  42. ############################################################################
  43. # This is our multiuser UI. From here the user will start and stop the server
  44. # for the multiuser. See what that server has to say. And write text messages
  45. # to all the other users. Like a little messaging app, so they will not use
  46. # closed source apps for this. I know a lot of companies that ustilize
  47. # whatsapp for this. This is not cool. And I can make a little app here.
  48. # The way it's going to look it the folosing.
  49. ############################################################################
  50. # START / STOP BUTTON # #
  51. ###################################################### BOB: Hello World #
  52. # # #
  53. # server started # Steve: What's Up #
  54. # BOB connected # #
  55. # Steve connected # John: Hey guys #
  56. # John connected # who can make the #
  57. # Steve updated Moria # rig for Moria? #
  58. # John reqested Moria # #
  59. # Steve sent Moria to John # Steve: I can. #
  60. # # #
  61. #################################################### # John: Thanks. #
  62. # 3 users connected: # #
  63. # BOB # #
  64. # John #######################
  65. # Steve # # #
  66. ############################################################################
  67. # I know that it's a bit unfair to give so much space to a terminal like
  68. # output window. But this is kind of the most important thing in the
  69. # entire Multiuser. The server. Actually the server will run only on one
  70. # computer. But all users will feel like they are controlling the server.
  71. # I don't like when one user thinks that he is more important then the other
  72. # . Because in the film production. Usually the director listens even to
  73. # the guy who makes the tea. In the case of this program I want everybody
  74. # to feel exactly the same amount of power.
  75. ############################################################################
  76. win.multiuser["unread"] = 0
  77. # SERVER PEACE FRAME
  78. UI_color.set(layer, win, "node_background")
  79. UI_elements.roundrect(layer, win,
  80. 80,
  81. 80,
  82. win.current["w"]/3*2-160,
  83. win.current["h"]/2-100,
  84. 10)
  85. # USERS PEACE FRAME
  86. UI_color.set(layer, win, "node_background")
  87. UI_elements.roundrect(layer, win,
  88. 80,
  89. win.current["h"]/2,
  90. win.current["w"]/3*2-160,
  91. win.current["h"]/2-80,
  92. 10)
  93. # THE SIDE PEACE FRAME
  94. UI_color.set(layer, win, "node_background")
  95. UI_elements.roundrect(layer, win,
  96. win.current["w"]/3*2-60,
  97. 80,
  98. win.current["w"]/3-20,
  99. win.current["h"]-160,
  100. 10)
  101. ####### SERVER PART #######
  102. # On the top panel first button will be either make a server. Or if server exists,
  103. # close the server. This will require a little dialog similar to when deleting
  104. # scenes in the story editor.
  105. # I'm going to hack my way into checking the server. Basically it autoconnects to
  106. # it if one is up. So..
  107. if win.multiuser["server"]:
  108. def do():
  109. # Simple UDP message
  110. multiuser_terminal.message("VCStudio ABORT MULTIUSER")
  111. UI_elements.roundrect(layer, win,
  112. 90,
  113. 90,
  114. 40,
  115. 40,
  116. 10,
  117. button=do,
  118. icon="server_close",
  119. tip=talk.text("multiuser_server_stop"))
  120. else:
  121. def do():
  122. # Simple Popen
  123. Popen(["python3", "network/multiuser_server.py", win.analytics["name"]])
  124. UI_elements.roundrect(layer, win,
  125. 90,
  126. 90,
  127. 40,
  128. 40,
  129. 10,
  130. button=do,
  131. icon="server_new",
  132. tip=talk.text("multiuser_server_start"))
  133. # Server outputs part. I'm creating a layer for it just because it needs
  134. # a clipping.
  135. x = 90
  136. y = 140
  137. width = win.current["w"]/3*2-160-20
  138. height = win.current["h"]/2-170
  139. # Making the layer
  140. surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
  141. node = cairo.Context(surface2)
  142. node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  143. # Clip
  144. UI_elements.roundrect(node, win,
  145. 0,
  146. 0,
  147. width,
  148. height,
  149. 10,
  150. fill=False)
  151. node.clip()
  152. # Background tester
  153. #UI_color.set(node, win, "dark_overdrop")
  154. #node.rectangle(0,0,width, height)
  155. #node.fill()
  156. # Here I want to have the output of the server in a raw fasion.
  157. if "multiuser_terminal" not in win.scroll:
  158. win.scroll["multiuser_terminal"] = 0
  159. current_Y = 10
  160. for message in win.multiuser["terminal"]:
  161. # We are going to draw a little server icon.
  162. UI_elements.image(node, win,
  163. "settings/themes/"+win.settings["Theme"]+"/icons/server.png",
  164. 10,
  165. current_Y+win.scroll["multiuser_terminal"],
  166. 40,
  167. 40)
  168. # And we want to have the text of the message
  169. UI_color.set(node, win, "text_normal")
  170. node.set_font_size(15)
  171. node.move_to( 60, current_Y+win.scroll["multiuser_terminal"]+27)
  172. node.show_text(message)
  173. current_Y = current_Y + 50
  174. # Outputting the layer
  175. layer.set_source_surface(surface2, x, y)
  176. layer.paint()
  177. UI_elements.scroll_area(layer, win, "multiuser_terminal",
  178. x,
  179. y,
  180. width,
  181. height,
  182. current_Y,
  183. bar=True,
  184. mmb=True)
  185. ############ USERS PART ##############
  186. # Here in this part I want to put a complite list of currently connected users.
  187. # I have few ideas of what functionality could be added to here. But at this
  188. # point I'm just trying to make the window somewhat busy looking.
  189. # So we need to make layer here. Since I want to clip it. But be able to draw outisde
  190. # the clipping area later.
  191. x = 90
  192. y = win.current["h"]/2+10
  193. width = win.current["w"]/3*2-160-20
  194. height = win.current["h"]/2-80-60
  195. # Making the layer
  196. surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
  197. node = cairo.Context(surface2)
  198. node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  199. # Clip
  200. UI_elements.roundrect(node, win,
  201. 0,
  202. 0,
  203. width,
  204. height,
  205. 10,
  206. fill=False)
  207. node.clip()
  208. # Background tester
  209. #UI_color.set(node, win, "dark_overdrop")
  210. #node.rectangle(0,0,width, height)
  211. #node.fill()
  212. if "multiuser_users" not in win.scroll:
  213. win.scroll["multiuser_users"] = 0
  214. current_Y = 10
  215. for ip in list(win.multiuser["users"].keys()):
  216. try:
  217. user = win.multiuser["users"][ip]
  218. except:
  219. continue
  220. username = user["username"]
  221. # For each user I want to show the name, then IP:PORT
  222. # If it's us on the list I want to draw a little rectangle arround
  223. # this particular user
  224. if ip == win.multiuser["userid"]:
  225. UI_color.set(node, win, "node_blendfile")
  226. UI_elements.roundrect(node, win,
  227. 0,
  228. current_Y+win.scroll["multiuser_users"]-5,
  229. width,
  230. 45,
  231. 10)
  232. # User Icon
  233. UI_elements.image(node, win,
  234. "settings/themes/"+win.settings["Theme"]+"/icons/user.png",
  235. 10,
  236. current_Y+win.scroll["multiuser_users"],
  237. 40,
  238. 40)
  239. # Text
  240. UI_color.set(node, win, "text_normal")
  241. node.set_font_size(20)
  242. node.move_to( 60, current_Y+win.scroll["multiuser_users"]+25)
  243. node.show_text(username+" | "+ip)
  244. current_Y = current_Y + 50
  245. # Outputting the layer
  246. layer.set_source_surface(surface2, x, y)
  247. layer.paint()
  248. UI_elements.scroll_area(layer, win, "multiuser_users",
  249. x,
  250. y,
  251. width,
  252. height,
  253. current_Y,
  254. bar=True,
  255. mmb=True)
  256. # At the bottom I want to have a little multiuser icon with the count of users.
  257. # then a user icon and a name selection.
  258. UI_elements.image(layer, win,
  259. "settings/themes/"+win.settings["Theme"]+"/icons/multiuser.png",
  260. x,
  261. y+height+5,
  262. 40,
  263. 40)
  264. # The little count thing at the corner
  265. if win.multiuser["users"]:
  266. count = str(len(win.multiuser["users"]))
  267. UI_color.set(layer, win, "node_background")
  268. UI_elements.roundrect(layer, win,
  269. x+25,
  270. y+height,
  271. len(count)*12+6,
  272. 25,
  273. 5)
  274. layer.fill()
  275. UI_color.set(layer, win, "text_normal")
  276. layer.set_font_size(20)
  277. layer.move_to(x+28,y+height+20)
  278. layer.show_text(count)
  279. # Documentation entry
  280. def do():
  281. def after(win, var):
  282. pass
  283. studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_multiuser"))
  284. UI_elements.roundrect(layer, win,
  285. win.current["w"]/3*2-160,
  286. win.current["h"]-120,
  287. 40,
  288. 40,
  289. 10,
  290. do,
  291. icon="question")
  292. # CANCEl
  293. def do():
  294. win.url = "story_editor"
  295. UI_elements.roundrect(layer, win,
  296. win.current["w"]/3*2-120,
  297. win.current["h"]-120,
  298. 40,
  299. 40,
  300. 10,
  301. button=do,
  302. icon="cancel",
  303. tip=talk.text("cancel"))
  304. # Short cut ESC
  305. if 65307 in win.current["keys"] and not win.textactive:
  306. do()
  307. ########## THE MESSANGER APP ON THE RIGHT ##########
  308. # I'm creating a layer for it just because it needs a clipping.
  309. x = win.current["w"]/3*2-50
  310. y = 90
  311. width = win.current["w"]/3-40
  312. height = win.current["h"]-220
  313. # Making the layer
  314. surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
  315. node = cairo.Context(surface2)
  316. node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
  317. # Clip
  318. UI_elements.roundrect(node, win,
  319. 0,
  320. 0,
  321. width,
  322. height,
  323. 10,
  324. fill=False)
  325. node.clip()
  326. # Background tester
  327. #UI_color.set(node, win, "dark_overdrop")
  328. #node.rectangle(0,0,width, height)
  329. #node.fill()
  330. # So here I want to present all the messages by all the users.
  331. if "multiuser_messages" not in win.scroll:
  332. win.scroll["multiuser_messages"] = 0
  333. current_Y = 10
  334. for message in win.multiuser["messages"]:
  335. # let's get the name of the user
  336. username = message[0]
  337. if username == "Multiuser Server":
  338. continue
  339. # User Icon
  340. UI_elements.image(node, win,
  341. "settings/themes/"+win.settings["Theme"]+"/icons/user.png",
  342. 10,
  343. current_Y+win.scroll["multiuser_messages"],
  344. 40,
  345. 40)
  346. UI_color.set(node, win, "text_normal")
  347. node.set_font_size(20)
  348. node.move_to(60,
  349. current_Y+win.scroll["multiuser_messages"]+25)
  350. node.show_text(username)
  351. current_Y = current_Y + 50
  352. # Now the message it self going to need to have line breaks. For this
  353. # we are going to make similar rendering to the one in the script
  354. # writer. But simpler.
  355. tileX = 10
  356. for word in message[1].split(" "):
  357. if tileX + len(word)*12+12 > width-10:
  358. tileX = 10
  359. current_Y = current_Y + 30
  360. UI_color.set(node, win, "text_normal")
  361. node.set_font_size(20)
  362. node.move_to(tileX,
  363. current_Y+win.scroll["multiuser_messages"]+25)
  364. node.show_text(word)
  365. tileX = tileX + len(word)*12+12
  366. current_Y = current_Y + 50
  367. # Outputting the layer
  368. layer.set_source_surface(surface2, x, y)
  369. layer.paint()
  370. UI_elements.scroll_area(layer, win, "multiuser_messages",
  371. x,
  372. y,
  373. width,
  374. height,
  375. current_Y,
  376. bar=True,
  377. mmb=True)
  378. # So here after the messages I want to make a little input for the new
  379. # message and a send button
  380. UI_elements.text(layer, win, "multiuser_message",
  381. x,
  382. y+height+5,
  383. width-50,
  384. 40)
  385. # Send button
  386. def do():
  387. if win.text["multiuser_message"]["text"]:
  388. win.multiuser["request"] = ["message", win.text["multiuser_message"]["text"]]
  389. win.text["multiuser_message"]["text"] = ""
  390. UI_elements.roundrect(layer, win,
  391. x+width-40,
  392. y+height+5,
  393. 40,
  394. 40,
  395. 10,
  396. button=do,
  397. icon="send")
  398. # ENTER
  399. if 65293 in win.current["keys"]:
  400. do()
  401. win.current["keys"] = []
  402. return surface