2021-01-03 00:33:34 +01:00
|
|
|
# THIS FILE IS A PART OF VCStudio
|
|
|
|
# PYTHON 3
|
|
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
from subprocess import *
|
|
|
|
|
|
|
|
# GTK module ( Graphical interface
|
|
|
|
import gi
|
|
|
|
gi.require_version('Gtk', '3.0')
|
|
|
|
from gi.repository import Gtk
|
|
|
|
from gi.repository import GLib
|
|
|
|
from gi.repository import Gdk
|
|
|
|
import cairo
|
|
|
|
|
|
|
|
# Own modules
|
|
|
|
from settings import settings
|
|
|
|
from settings import talk
|
|
|
|
from settings import fileformats
|
|
|
|
from project_manager import pm_project
|
|
|
|
|
|
|
|
#UI modules
|
|
|
|
from UI import UI_elements
|
|
|
|
from UI import UI_color
|
|
|
|
|
|
|
|
# story
|
|
|
|
from studio import story
|
|
|
|
from studio import analytics
|
|
|
|
from studio import history
|
2021-01-03 14:52:42 +01:00
|
|
|
from studio import studio_dialogs
|
2021-01-03 00:33:34 +01:00
|
|
|
|
|
|
|
# network
|
|
|
|
from network import multiuser_terminal
|
|
|
|
|
|
|
|
def layer(win):
|
|
|
|
|
|
|
|
# Making the layer
|
|
|
|
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, win.current['w'],
|
|
|
|
win.current['h'])
|
|
|
|
layer = cairo.Context(surface)
|
|
|
|
|
|
|
|
|
|
|
|
#text setting
|
|
|
|
layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
|
|
|
|
|
|
|
UI_color.set(layer, win, "dark_overdrop")
|
|
|
|
layer.rectangle(
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
win.current["w"],
|
|
|
|
win.current["h"],
|
|
|
|
)
|
|
|
|
layer.fill()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
############################################################################
|
|
|
|
|
|
|
|
# This is our multiuser UI. From here the user will start and stop the server
|
|
|
|
# for the multiuser. See what that server has to say. And write text messages
|
|
|
|
# to all the other users. Like a little messaging app, so they will not use
|
|
|
|
# closed source apps for this. I know a lot of companies that ustilize
|
|
|
|
# whatsapp for this. This is not cool. And I can make a little app here.
|
|
|
|
|
|
|
|
# The way it's going to look it the folosing.
|
|
|
|
|
|
|
|
|
|
|
|
############################################################################
|
|
|
|
# START / STOP BUTTON # #
|
|
|
|
###################################################### BOB: Hello World #
|
|
|
|
# # #
|
|
|
|
# server started # Steve: What's Up #
|
|
|
|
# BOB connected # #
|
|
|
|
# Steve connected # John: Hey guys #
|
|
|
|
# John connected # who can make the #
|
|
|
|
# Steve updated Moria # rig for Moria? #
|
|
|
|
# John reqested Moria # #
|
|
|
|
# Steve sent Moria to John # Steve: I can. #
|
|
|
|
# # #
|
|
|
|
#################################################### # John: Thanks. #
|
|
|
|
# 3 users connected: # #
|
|
|
|
# BOB # #
|
|
|
|
# John #######################
|
|
|
|
# Steve # # #
|
|
|
|
############################################################################
|
|
|
|
|
|
|
|
# I know that it's a bit unfair to give so much space to a terminal like
|
|
|
|
# output window. But this is kind of the most important thing in the
|
|
|
|
# entire Multiuser. The server. Actually the server will run only on one
|
|
|
|
# computer. But all users will feel like they are controlling the server.
|
|
|
|
|
|
|
|
# I don't like when one user thinks that he is more important then the other
|
|
|
|
# . Because in the film production. Usually the director listens even to
|
|
|
|
# the guy who makes the tea. In the case of this program I want everybody
|
|
|
|
# to feel exactly the same amount of power.
|
|
|
|
|
|
|
|
############################################################################
|
|
|
|
|
|
|
|
win.multiuser["unread"] = 0
|
|
|
|
|
|
|
|
# SERVER PEACE FRAME
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
|
|
80,
|
|
|
|
80,
|
|
|
|
win.current["w"]/3*2-160,
|
|
|
|
win.current["h"]/2-100,
|
|
|
|
10)
|
|
|
|
|
|
|
|
# USERS PEACE FRAME
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
|
|
80,
|
|
|
|
win.current["h"]/2,
|
|
|
|
win.current["w"]/3*2-160,
|
|
|
|
win.current["h"]/2-80,
|
|
|
|
10)
|
|
|
|
|
|
|
|
# THE SIDE PEACE FRAME
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
|
|
win.current["w"]/3*2-60,
|
|
|
|
80,
|
|
|
|
win.current["w"]/3-20,
|
|
|
|
win.current["h"]-160,
|
|
|
|
10)
|
|
|
|
|
|
|
|
####### SERVER PART #######
|
|
|
|
|
|
|
|
# On the top panel first button will be either make a server. Or if server exists,
|
|
|
|
# close the server. This will require a little dialog similar to when deleting
|
|
|
|
# scenes in the story editor.
|
|
|
|
|
|
|
|
# I'm going to hack my way into checking the server. Basically it autoconnects to
|
|
|
|
# it if one is up. So..
|
|
|
|
|
|
|
|
if win.multiuser["server"]:
|
|
|
|
|
|
|
|
def do():
|
|
|
|
|
|
|
|
# Simple UDP message
|
|
|
|
multiuser_terminal.message("VCStudio ABORT MULTIUSER")
|
|
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
|
|
90,
|
|
|
|
90,
|
|
|
|
40,
|
|
|
|
40,
|
|
|
|
10,
|
|
|
|
button=do,
|
2021-01-03 14:52:42 +01:00
|
|
|
icon="server_close",
|
|
|
|
tip=talk.text("multiuser_server_stop"))
|
2021-01-03 00:33:34 +01:00
|
|
|
else:
|
|
|
|
def do():
|
|
|
|
|
|
|
|
# Simple Popen
|
|
|
|
Popen(["python3", "network/multiuser_server.py", win.analytics["name"]])
|
|
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
|
|
90,
|
|
|
|
90,
|
|
|
|
40,
|
|
|
|
40,
|
|
|
|
10,
|
|
|
|
button=do,
|
2021-01-03 14:52:42 +01:00
|
|
|
icon="server_new",
|
|
|
|
tip=talk.text("multiuser_server_start"))
|
2021-01-03 00:33:34 +01:00
|
|
|
|
|
|
|
# Server outputs part. I'm creating a layer for it just because it needs
|
|
|
|
# a clipping.
|
|
|
|
|
|
|
|
x = 90
|
|
|
|
y = 140
|
|
|
|
width = win.current["w"]/3*2-160-20
|
|
|
|
height = win.current["h"]/2-170
|
|
|
|
|
|
|
|
|
|
|
|
# Making the layer
|
|
|
|
surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
|
|
|
|
node = cairo.Context(surface2)
|
|
|
|
node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
|
|
|
|
|
|
|
# Clip
|
|
|
|
UI_elements.roundrect(node, win,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
10,
|
|
|
|
fill=False)
|
|
|
|
node.clip()
|
|
|
|
|
|
|
|
# Background tester
|
|
|
|
#UI_color.set(node, win, "dark_overdrop")
|
|
|
|
#node.rectangle(0,0,width, height)
|
|
|
|
#node.fill()
|
|
|
|
|
|
|
|
# Here I want to have the output of the server in a raw fasion.
|
|
|
|
if "multiuser_terminal" not in win.scroll:
|
|
|
|
win.scroll["multiuser_terminal"] = 0
|
|
|
|
|
|
|
|
current_Y = 10
|
|
|
|
|
|
|
|
for message in win.multiuser["terminal"]:
|
|
|
|
|
|
|
|
# We are going to draw a little server icon.
|
|
|
|
UI_elements.image(node, win,
|
|
|
|
"settings/themes/"+win.settings["Theme"]+"/icons/server.png",
|
|
|
|
10,
|
|
|
|
current_Y+win.scroll["multiuser_terminal"],
|
|
|
|
40,
|
|
|
|
40)
|
|
|
|
|
|
|
|
# And we want to have the text of the message
|
|
|
|
|
|
|
|
UI_color.set(node, win, "text_normal")
|
|
|
|
node.set_font_size(15)
|
|
|
|
node.move_to( 60, current_Y+win.scroll["multiuser_terminal"]+27)
|
|
|
|
node.show_text(message)
|
|
|
|
|
|
|
|
current_Y = current_Y + 50
|
|
|
|
|
|
|
|
# Outputting the layer
|
|
|
|
layer.set_source_surface(surface2, x, y)
|
|
|
|
layer.paint()
|
|
|
|
|
|
|
|
UI_elements.scroll_area(layer, win, "multiuser_terminal",
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
current_Y,
|
|
|
|
bar=True,
|
|
|
|
mmb=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
############ USERS PART ##############
|
|
|
|
|
|
|
|
# Here in this part I want to put a complite list of currently connected users.
|
|
|
|
# I have few ideas of what functionality could be added to here. But at this
|
|
|
|
# point I'm just trying to make the window somewhat busy looking.
|
|
|
|
|
|
|
|
# So we need to make layer here. Since I want to clip it. But be able to draw outisde
|
|
|
|
# the clipping area later.
|
|
|
|
|
|
|
|
x = 90
|
|
|
|
y = win.current["h"]/2+10
|
|
|
|
width = win.current["w"]/3*2-160-20
|
|
|
|
height = win.current["h"]/2-80-60
|
|
|
|
|
|
|
|
|
|
|
|
# Making the layer
|
|
|
|
surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
|
|
|
|
node = cairo.Context(surface2)
|
|
|
|
node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
|
|
|
|
|
|
|
# Clip
|
|
|
|
UI_elements.roundrect(node, win,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
10,
|
|
|
|
fill=False)
|
|
|
|
node.clip()
|
|
|
|
|
|
|
|
# Background tester
|
|
|
|
#UI_color.set(node, win, "dark_overdrop")
|
|
|
|
#node.rectangle(0,0,width, height)
|
|
|
|
#node.fill()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if "multiuser_users" not in win.scroll:
|
|
|
|
win.scroll["multiuser_users"] = 0
|
|
|
|
|
|
|
|
current_Y = 10
|
|
|
|
|
|
|
|
for ip in list(win.multiuser["users"].keys()):
|
|
|
|
try:
|
|
|
|
user = win.multiuser["users"][ip]
|
|
|
|
except:
|
|
|
|
continue
|
|
|
|
|
|
|
|
username = user["username"]
|
|
|
|
|
|
|
|
# For each user I want to show the name, then IP:PORT
|
|
|
|
|
|
|
|
# If it's us on the list I want to draw a little rectangle arround
|
|
|
|
# this particular user
|
|
|
|
|
|
|
|
if ip == win.multiuser["userid"]:
|
|
|
|
UI_color.set(node, win, "node_blendfile")
|
|
|
|
UI_elements.roundrect(node, win,
|
|
|
|
0,
|
|
|
|
current_Y+win.scroll["multiuser_users"]-5,
|
|
|
|
width,
|
|
|
|
45,
|
|
|
|
10)
|
|
|
|
|
|
|
|
|
|
|
|
# User Icon
|
|
|
|
UI_elements.image(node, win,
|
|
|
|
"settings/themes/"+win.settings["Theme"]+"/icons/user.png",
|
|
|
|
10,
|
|
|
|
current_Y+win.scroll["multiuser_users"],
|
|
|
|
40,
|
|
|
|
40)
|
|
|
|
|
|
|
|
# Text
|
|
|
|
|
|
|
|
UI_color.set(node, win, "text_normal")
|
|
|
|
node.set_font_size(20)
|
|
|
|
node.move_to( 60, current_Y+win.scroll["multiuser_users"]+25)
|
|
|
|
node.show_text(username+" | "+ip)
|
|
|
|
|
|
|
|
current_Y = current_Y + 50
|
|
|
|
|
|
|
|
|
|
|
|
# Outputting the layer
|
|
|
|
layer.set_source_surface(surface2, x, y)
|
|
|
|
layer.paint()
|
|
|
|
|
|
|
|
UI_elements.scroll_area(layer, win, "multiuser_users",
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
current_Y,
|
|
|
|
bar=True,
|
|
|
|
mmb=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# At the bottom I want to have a little multiuser icon with the count of users.
|
|
|
|
# then a user icon and a name selection.
|
|
|
|
|
|
|
|
UI_elements.image(layer, win,
|
|
|
|
"settings/themes/"+win.settings["Theme"]+"/icons/multiuser.png",
|
|
|
|
x,
|
|
|
|
y+height+5,
|
|
|
|
40,
|
|
|
|
40)
|
|
|
|
|
|
|
|
# The little count thing at the corner
|
|
|
|
if win.multiuser["users"]:
|
|
|
|
count = str(len(win.multiuser["users"]))
|
|
|
|
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
|
|
x+25,
|
|
|
|
y+height,
|
|
|
|
len(count)*12+6,
|
|
|
|
25,
|
|
|
|
5)
|
|
|
|
layer.fill()
|
|
|
|
UI_color.set(layer, win, "text_normal")
|
|
|
|
layer.set_font_size(20)
|
|
|
|
layer.move_to(x+28,y+height+20)
|
|
|
|
layer.show_text(count)
|
|
|
|
|
|
|
|
|
2021-01-03 14:52:42 +01:00
|
|
|
# Documentation entry
|
|
|
|
def do():
|
|
|
|
def after(win, var):
|
|
|
|
pass
|
|
|
|
|
|
|
|
studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_multiuser"))
|
|
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
|
|
win.current["w"]/3*2-160,
|
|
|
|
win.current["h"]-120,
|
|
|
|
40,
|
|
|
|
40,
|
|
|
|
10,
|
|
|
|
do,
|
|
|
|
icon="question")
|
|
|
|
|
2021-01-03 00:33:34 +01:00
|
|
|
# CANCEl
|
|
|
|
|
|
|
|
def do():
|
|
|
|
win.url = "story_editor"
|
|
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
|
|
win.current["w"]/3*2-120,
|
|
|
|
win.current["h"]-120,
|
|
|
|
40,
|
|
|
|
40,
|
|
|
|
10,
|
|
|
|
button=do,
|
|
|
|
icon="cancel",
|
|
|
|
tip=talk.text("cancel"))
|
|
|
|
|
|
|
|
# Short cut ESC
|
|
|
|
if 65307 in win.current["keys"] and not win.textactive:
|
|
|
|
do()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
########## THE MESSANGER APP ON THE RIGHT ##########
|
|
|
|
|
|
|
|
# I'm creating a layer for it just because it needs a clipping.
|
|
|
|
|
|
|
|
x = win.current["w"]/3*2-50
|
|
|
|
y = 90
|
|
|
|
width = win.current["w"]/3-40
|
|
|
|
height = win.current["h"]-220
|
|
|
|
|
|
|
|
|
|
|
|
# Making the layer
|
|
|
|
surface2 = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
|
|
|
|
node = cairo.Context(surface2)
|
|
|
|
node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
|
|
|
|
|
|
|
# Clip
|
|
|
|
UI_elements.roundrect(node, win,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
10,
|
|
|
|
fill=False)
|
|
|
|
node.clip()
|
|
|
|
|
|
|
|
# Background tester
|
|
|
|
#UI_color.set(node, win, "dark_overdrop")
|
|
|
|
#node.rectangle(0,0,width, height)
|
|
|
|
#node.fill()
|
|
|
|
|
|
|
|
|
|
|
|
# So here I want to present all the messages by all the users.
|
|
|
|
if "multiuser_messages" not in win.scroll:
|
|
|
|
win.scroll["multiuser_messages"] = 0
|
|
|
|
|
|
|
|
current_Y = 10
|
|
|
|
|
|
|
|
for message in win.multiuser["messages"]:
|
|
|
|
|
|
|
|
# let's get the name of the user
|
|
|
|
username = message[0]
|
|
|
|
|
|
|
|
if username == "Multiuser Server":
|
|
|
|
continue
|
|
|
|
|
|
|
|
# User Icon
|
|
|
|
UI_elements.image(node, win,
|
|
|
|
"settings/themes/"+win.settings["Theme"]+"/icons/user.png",
|
|
|
|
10,
|
|
|
|
current_Y+win.scroll["multiuser_messages"],
|
|
|
|
40,
|
|
|
|
40)
|
|
|
|
|
|
|
|
UI_color.set(node, win, "text_normal")
|
|
|
|
node.set_font_size(20)
|
|
|
|
node.move_to(60,
|
|
|
|
current_Y+win.scroll["multiuser_messages"]+25)
|
|
|
|
node.show_text(username)
|
|
|
|
|
|
|
|
current_Y = current_Y + 50
|
|
|
|
|
|
|
|
# Now the message it self going to need to have line breaks. For this
|
|
|
|
# we are going to make similar rendering to the one in the script
|
|
|
|
# writer. But simpler.
|
|
|
|
|
|
|
|
tileX = 10
|
|
|
|
|
|
|
|
for word in message[1].split(" "):
|
|
|
|
|
|
|
|
|
|
|
|
if tileX + len(word)*12+12 > width-10:
|
|
|
|
tileX = 10
|
|
|
|
current_Y = current_Y + 30
|
|
|
|
|
|
|
|
UI_color.set(node, win, "text_normal")
|
|
|
|
node.set_font_size(20)
|
|
|
|
node.move_to(tileX,
|
|
|
|
current_Y+win.scroll["multiuser_messages"]+25)
|
|
|
|
node.show_text(word)
|
|
|
|
|
|
|
|
tileX = tileX + len(word)*12+12
|
|
|
|
|
|
|
|
current_Y = current_Y + 50
|
|
|
|
|
|
|
|
# Outputting the layer
|
|
|
|
layer.set_source_surface(surface2, x, y)
|
|
|
|
layer.paint()
|
|
|
|
|
|
|
|
UI_elements.scroll_area(layer, win, "multiuser_messages",
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
current_Y,
|
|
|
|
bar=True,
|
|
|
|
mmb=True)
|
|
|
|
|
|
|
|
# So here after the messages I want to make a little input for the new
|
|
|
|
# message and a send button
|
|
|
|
|
|
|
|
UI_elements.text(layer, win, "multiuser_message",
|
|
|
|
x,
|
|
|
|
y+height+5,
|
|
|
|
width-50,
|
|
|
|
40)
|
|
|
|
|
|
|
|
# Send button
|
|
|
|
|
|
|
|
def do():
|
|
|
|
|
|
|
|
if win.text["multiuser_message"]["text"]:
|
|
|
|
win.multiuser["request"] = ["message", win.text["multiuser_message"]["text"]]
|
|
|
|
win.text["multiuser_message"]["text"] = ""
|
|
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
|
|
x+width-40,
|
|
|
|
y+height+5,
|
|
|
|
40,
|
|
|
|
40,
|
|
|
|
10,
|
|
|
|
button=do,
|
|
|
|
icon="send")
|
|
|
|
|
|
|
|
# ENTER
|
|
|
|
if 65293 in win.current["keys"]:
|
|
|
|
do()
|
|
|
|
win.current["keys"] = []
|
|
|
|
|
|
|
|
return surface
|