Blender-Pipeline/studio/studio_storyLayer.py

1033 lines
30 KiB
Python

# THIS FILE IS A PART OF VCStudio
# PYTHON 3
import os
import datetime
import threading
# 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 project_manager import pm_project
from studio import analytics
from studio import studio_nodes
from studio import studio_dialogs
from studio import story
from studio import analytics
#UI modules
from UI import UI_elements
from UI import UI_color
def layer(win):
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
stf = datetime.datetime.now()
perfStat = []
###################################################################
# 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)
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Setup", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
UI_color.set(layer, win, "darker_parts")
UI_elements.roundrect(layer, win,
50,
50,
win.current["w"] - 100,
win.current["h"] - 80,
30)
# Little verion thing in the bottom corner
UI_color.set(layer, win, "testing_banner")
layer.set_font_size(15)
layer.move_to(win.current["w"]-80, win.current["h"] - 7)
layer.show_text(str(win.version))
# Hude analytics button on the top
def do():
print("Analytics")
UI_elements.roundrect(layer, win,
5,
5,
win.current["w"]-10,
40,
10,
do,
"analytics",
talk.text("analytics_tooltip"),
url="story_editor")
# Progressbar
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
55,
15,
win.current["w"]/3*2-10,
20,
10)
timepassed = 0.0
projectdone = 0.0
try:
timepassed = win.analytics["timepassed"]
projectdone = win.analytics["fraction"]
except:
pass
# Timepassed
UI_color.set(layer, win, "progress_time")
UI_elements.roundrect(layer, win,
55,
15,
(win.current["w"]/3*2-10)*timepassed,
20,
10)
# Project Done
UI_color.set(layer, win, "progress_active")
UI_elements.roundrect(layer, win,
55,
15,
(win.current["w"]/3*2-10)*projectdone,
20,
10)
# Separator
UI_color.set(layer, win, "node_background")
layer.move_to(win.current["w"]/3*2+55, 5)
layer.line_to(win.current["w"]/3*2+55, 45)
layer.stroke()
# Schedule
UI_elements.image(layer, win, "settings/themes/"\
+win.settings["Theme"]+"/icons/schedule.png",
win.current["w"]/3*2+60,
5,
40,
40)
# Temporarely:
UI_color.set(layer, win, "text_normal")
layer.set_font_size(20)
layer.move_to(win.current["w"]/3*2+120, 25)
layer.show_text("The Next Task")
layer.set_font_size(12)
layer.move_to(win.current["w"]/3*2+130+len("The Next Task")*12, 25)
layer.show_text("from: AllTasks > Subtasks > This")
layer.set_font_size(12)
layer.move_to(win.current["w"]/3*2+120, 40)
layer.show_text("Character: Moria")
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Analytics", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
###### LEFT PANNEL #######
# New Scene
def do():
# Okay let's make the adding the scene possible.
# First we need to know what scenes are there. So we don't overwrite
# any existing scene.
scenename = "Scene"
count = 2
while scenename in win.story["scenes"]:
scenename = "Scene_"+str(count)
count = count + 1
# Now that we have an empty name. Let's add a scene.
win.story["scenes"][scenename] = {
"fraction":0.0, # Percentage
"position":[
win.current["mx"]-win.story["camera"][0]-50,
win.current["my"]-win.story["camera"][1]-30
],
"size":[100, 60],
"parent":"", # For when it's in a Frame (Event)
"shots":[[
"text_block",[["text", '']]
]]
}
# Auto select the new scene
win.story["selected"] = [["scene", scenename]]
win.current["tool"] = "grab"
# A hack I guess. I don't know what I'm doing. I'm trying to force
# the motion on click.
win.current["LMB"] = [win.current["mx"], win.current["my"], True]
# In studio/studio_gtk.py there is a command that recognizes the length
# of the LMB. And it's more then 2 it does some magic to make stuff move
# without pressing the actuall key. It's slightly too clever even for me
# so yeah.
UI_elements.roundrect(layer, win,
5,
105,
40,
40,
10,
do,
"node",
talk.text("new_scene_tooltip")+"\n[N]",
url="story_editor")
# Shortcut
if 110 in win.current["keys"] and not win.textactive:
do()
win.current["keys"] = []
# Link Asset
def do():
def after(win, var):
print (var)
if var:
win.story["links"].append([
"asset", var, [
win.current["mx"]-win.story["camera"][0]-75,
win.current["my"]-win.story["camera"][1]-75
],
"" # Parent
])
# Now let's select and move the thing
win.story["selected"] = [["asset", len(win.story["links"])-1]]
win.current["tool"] = "grab"
win.current["LMB"] = [win.current["mx"], win.current["my"], True]
studio_dialogs.asset_select(win, "new_asset_story", after)
UI_elements.roundrect(layer, win,
5,
155,
40,
40,
10,
do,
"obj_link",
talk.text("link_asset_tooltip")+"\n[L]",
url="story_editor")
# Shortcut
if 108 in win.current["keys"] and not win.textactive:
do()
win.current["keys"] = []
# Link File
def do():
def after(win, var):
if var:
win.story["links"].append([
"file", var, [
win.current["mx"]-win.story["camera"][0]-75,
win.current["my"]-win.story["camera"][1]-75
],
"" # Parent
])
# Now let's select and move the thing
win.story["selected"] = [["file", len(win.story["links"])-1]]
win.current["tool"] = "grab"
win.current["LMB"] = [win.current["mx"], win.current["my"], True]
studio_dialogs.file_select(win, "new_file_story", after, force=True)
UI_elements.roundrect(layer, win,
5,
205,
40,
40,
10,
do,
"file_link",
talk.text("link_file_tooltip")+"\n[I]",
url="story_editor")
# Shortcut
if 105 in win.current["keys"] and not win.textactive:
do()
win.current["keys"] = []
# Marker
def do():
markername = "Marker"
count = 2
while markername in win.story["markers"]:
markername = "Marker_"+str(count)
count = count + 1
win.story["markers"][markername] = [
win.current["mx"]-win.story["camera"][0]+50,
win.current["my"]-win.story["camera"][1]-20,
"" # Parent
]
win.textactive = markername+"_marker"
win.text[markername+"_marker"] = {
"text" :markername, # Actuall text you are editing.
"cursor":[len(str(markername)),len(str(markername))], # Cursor
"insert":False, # Whether the insert mode is on
"scroll":"markername_scroll" # If multiline. The pointer for the scroll value.
}
win.story["selected"] = [["marker", markername]]
win.current["tool"] = "grab"
win.current["LMB"] = [win.current["mx"], win.current["my"], True]
UI_elements.roundrect(layer, win,
5,
255,
40,
40,
10,
do,
"pin",
talk.text("marker_tooltip")+"\n[M]",
url="story_editor")
# Shortcut
if 109 in win.current["keys"] and not win.textactive:
do()
win.current["keys"] = []
if win.story["selected"]:
# Event
def do():
eventname = "Event"
count = 2
while eventname in win.story["events"]:
eventname = "Event_"+str(count)
count = count + 1
win.story["events"][eventname] = {
"position":[0,0],
"size":[0,0]
}
# Even going to delete it self if there will be noone who parenting
# it.
for thing in win.story["selected"]:
if thing[0] == "scene":
win.story["scenes"][thing[1]]["parent"] = eventname
elif thing[0] in ["file", "asset"]:
win.story["links"][thing[1]][3] = eventname
elif thing[0] == "marker":
win.story["markers"][thing[1]][2] = eventname
UI_elements.roundrect(layer, win,
5,
305,
40,
40,
10,
do,
"event",
talk.text("event_tooltip")+"\n[E]",
url="story_editor")
# Shortcut
if 101 in win.current["keys"] and not win.textactive:
do()
win.current["keys"] = []
# Renders
def do():
print("Renders")
UI_elements.roundrect(layer, win,
5,
405,
40,
40,
10,
do,
"render",
talk.text("render_lists_tooltip"),
url="story_editor")
# Edit Video
def do():
print("Edit Video")
UI_elements.roundrect(layer, win,
5,
455,
40,
40,
10,
do,
"vse",
talk.text("vse_tooltip"),
url="story_editor")
# Bottom
# Multiuser
def do():
win.url = "multiuser_layer"
UI_elements.roundrect(layer, win,
5,
win.current["h"]-95,
40,
40,
10,
do,
"multiuser",
talk.text("multiuser_tooltip"),
url="story_editor")
# Settings
def do():
win.url = "settings_layer"
UI_elements.roundrect(layer, win,
5,
win.current["h"]-45,
40,
40,
10,
do,
"settings",
talk.text("Settings"),
url="story_editor")
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Left Panel", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
###### RIGHT PANNEL #######
def select_character(win, var):
if var:
win.url = "assets"
win.cur = var
win.current["tool"] = "selection"
# Characters
def do():
studio_dialogs.asset_select(win, "new_asset_story", select_character, force=True, cur="chr")
UI_elements.roundrect(layer, win,
win.current["w"]-45,
105,
40,
40,
10,
do,
"chr",
talk.text("chr"),
url="story_editor")
# Vehicles
def do():
studio_dialogs.asset_select(win, "new_asset_story", select_character, force=True, cur="veh")
UI_elements.roundrect(layer, win,
win.current["w"]-45,
155,
40,
40,
10,
do,
"veh",
talk.text("veh"),
url="story_editor")
# Locations
def do():
studio_dialogs.asset_select(win, "new_asset_story", select_character, force=True, cur="loc")
UI_elements.roundrect(layer, win,
win.current["w"]-45,
205,
40,
40,
10,
do,
"loc",
talk.text("loc"),
url="story_editor")
# Other (obj)
def do():
studio_dialogs.asset_select(win, "new_asset_story", select_character, force=True, cur="obj")
UI_elements.roundrect(layer, win,
win.current["w"]-45,
255,
40,
40,
10,
do,
"obj",
talk.text("obj"),
url="story_editor")
# Sounds / Music
def do():
print("Sounds / Music")
UI_elements.roundrect(layer, win,
win.current["w"]-45,
355,
40,
40,
10,
do,
"mus",
talk.text("mus"),
url="story_editor")
# Folder
def do():
os.system("xdg-open "+win.project)
UI_elements.roundrect(layer, win,
win.current["w"]-45,
win.current["h"]-75,
40,
40,
10,
do,
"folder",
talk.text("project_folder"),
url="story_editor")
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Right Pannel", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
####### NODES #######
# Clipping so it wont draw beyon the frame
UI_elements.roundrect(layer, win,
50,
50,
win.current["w"] - 100,
win.current["h"] - 80,
30,
fill=False)
layer.clip()
# Background Image
if os.path.exists(win.project+"/set/banner.png"):
UI_elements.image(layer, win, win.project+"/set/banner.png",
50,
50,
win.current["w"] - 100,
win.current["h"] - 80,
cell="background")
elif os.path.exists(win.project+"/py_data/banner.png"):
UI_elements.image(layer, win, win.project+"/py_data/banner.png",
50,
50,
win.current["w"] - 100,
win.current["h"] - 80,
cell="background")
else:
UI_elements.image(layer, win, "icon.png",
50,
50,
win.current["w"] - 100,
win.current["h"] - 80,
cell="background")
UI_color.set(layer, win, "node_background")
layer.rectangle(0,0,win.current["w"], win.current["h"])
layer.fill()
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Background Image", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
# You probably intersted where is the scroll function for this part. Well
# see there is a thing. It's easier to write one from screach here. Because
# you geassed it we are starting to draw story editor.
# Let's prepare the camera first.
# Animation
win.story["camera"][0] = UI_elements.animate("cameraX", win, 0, win.story["camera"][0])
win.story["camera"][1] = UI_elements.animate("cameraY", win, 0, win.story["camera"][1])
cx, cy = win.story["camera"]
if win.url == "story_editor":
if win.current["MMB"]:
win.story["camera"][0] += ( win.current["mx"]-win.previous["mx"])
win.story["camera"][1] += ( win.current["my"]-win.previous["my"])
win.story["camera"][0] -= win.current["scroll"][0]*50
win.story["camera"][1] -= win.current["scroll"][1]*50
if cx != win.story["camera"][0] or cy != win.story["camera"][1]:
UI_elements.animate("cameraX", win, win.story["camera"][0], force=True)
UI_elements.animate("cameraY", win, win.story["camera"][1], force=True)
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Camera position", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
# EVENTS (Frames)
try:
for event in win.story["events"]:
# Loaction
sx, sy = win.story["events"][event]["position"]
# Scale
ssx, ssy = win.story["events"][event]["size"]
#Draw
studio_nodes.event_node(layer, win, sx, sy, ssx, ssy, name=event)
# Let's now check if the event even has anybody inside. It's a bit
# not the best way to implement it yet. Because I will need to look
# through all items. But we can make it simpler if we find that it has
# we can just break out of a thing.
found = False
for scene in win.story["scenes"]:
if event == win.story["scenes"][scene]["parent"]:
found = True
break
if not found:
for link in win.story["links"]:
if event == link[3]:
found = True
break
if not found:
for marker in win.story["markers"]:
if event == win.story["markers"][marker][2]:
found = True
break
# If nobody is inside. Delete the bastard.
if not found:
del win.story["events"][event]
except:
pass
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Events", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
# SCENES
for scene in win.story["scenes"]:
# Loaction
sx, sy = win.story["scenes"][scene]["position"]
sx = sx + cx
sy = sy + cy
# Scale
ssx, ssy = win.story["scenes"][scene]["size"]
#Fraction
sf = win.story["scenes"][scene]["fraction"]
#Draw
studio_nodes.scene_node(layer, win, sx, sy, ssx, ssy, name=scene, fraction=sf)
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Scenes", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
# LINKS (Images, Stuff)
for num, link in enumerate(win.story["links"]):
linktype = link[0]
linkname = link[1]
lx = link[2][0] + cx
ly = link[2][1] + cy
studio_nodes.link_node(layer, win, lx, ly, name=linkname, num=num, linktype=linktype )
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Files / Assets", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
# Let's put in the start and the end nodes. These are drawn on top of
# everything.
studio_nodes.start_node(layer, win, 60,60,100,40)
studio_nodes.end_node(layer, win, win.current["w"] - 160,
win.current["h"] - 80,
100,40)
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Start / End Nodes", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
# MARKERS
try:
for marker in win.story["markers"]:
mx = win.story["markers"][marker][0] + cx
my = win.story["markers"][marker][1] + cy
studio_nodes.marker(layer, win, marker, mx, my)
except:
pass
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Markers", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
# In case there is a selection bug
if not win.story["selected"] and win.current["tool"] != "connect":
win.current["tool"] = "selection"
# Selector visualization
if win.current["LMB"] and win.current["tool"] == "selection" and win.url == "story_editor":
# Draw selection box
UI_color.set(layer, win, "progress_background")
layer.rectangle(
win.current["mx"],
win.current["my"],
win.current["LMB"][0] - win.current["mx"],
win.current["LMB"][1] - win.current["my"]
)
layer.stroke()
# Now let's draw the cool AF multi selection zone thingy
# Draw selection box
if len(win.story["selected"]) > 1 and win.current["tool"] == "selection":
UI_color.set(layer, win, "progress_background")
layer.rectangle(
win.szone[0][0]-10,
win.szone[0][1]-10,
win.szone[1][0]+20,
win.szone[1][1]+20
)
layer.stroke()
# Now I want to make a tiny widget that will resize the stuff.
if win.story["selected"]:
if win.current["tool"] == "selection":
draw_circle = True
if len(win.story["selected"]) == 1:
if win.story["selected"][0][0] != "scene":
draw_circle = False
if draw_circle:
UI_color.set(layer, win, "node_badfile")
UI_elements.roundrect(layer, win,
win.szone[0][0]+win.szone[1][0],
win.szone[0][1]+win.szone[1][1],
0,
0,
10)
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
win.szone[0][0]+win.szone[1][0],
win.szone[0][1]+win.szone[1][1],
0,
0,
10,
fill=False)
layer.stroke()
elif win.current["tool"] == "scale":
UI_color.set(layer, win, "node_badfile")
UI_elements.roundrect(layer, win,
win.current["mx"]-10,
win.current["my"]-10,
0,
0,
10)
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
win.current["mx"]-10,
win.current["my"]-10,
0,
0,
10,
fill=False)
layer.stroke()
if int(win.current["mx"]) in range(int(win.szone[0][0]+win.szone[1][0]), int(win.szone[0][0]+win.szone[1][0]+20))\
and int(win.current["my"]) in range(int(win.szone[0][1]+win.szone[1][1]), int(win.szone[0][1]+win.szone[1][1]+20))\
and win.current["tool"] == "selection":
UI_color.set(layer, win, "text_normal")
UI_elements.roundrect(layer, win,
win.szone[0][0]+win.szone[1][0],
win.szone[0][1]+win.szone[1][1],
0,
0,
10,
fill=False)
layer.stroke()
if win.current["LMB"] and not win.previous["LMB"]:
win.current["tool"] = "scale"
if win.current["tool"] == "scale" and not win.current["LMB"]:
win.current["tool"] = "selection"
# Canceling seletion. I move it here so it would not interfire with the
# the rest of the program.
if win.current["LMB"] and win.current["tool"] == "selection" and win.url == "story_editor":
# Undo selection
if int(win.current["LMB"][0] - win.current["mx"]) in range(-10, 10)\
and int(win.current["LMB"][1] - win.current["my"])in range(-10, 10)\
and int(win.current["mx"]) in range(50, int(win.current["w"]-50)) \
and int(win.current["my"]) in range(50, int(win.current["h"]-30))\
and 65505 not in win.current["keys"]:
win.story["selected"] = []
win.textactive = ""
# Let's draw the line while connecting 2 scenes together.
if win.current["tool"] == "connect":
if not win.current["LMB"]:
win.current["tool"] = "selection"
fr = win.current["draw_dot"]
if type(fr) == list:
fr = fr[0]+":"+fr[1]
try:
UI_color.set(layer, win, "node_script")
layer.move_to(
win.out_dots[fr][0],
win.out_dots[fr][1]
)
layer.line_to(win.current["mx"], win.current["my"])
layer.stroke()
except:
pass
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Selection", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
# Save story. I'm going to do it the same way as in the old Blender-Organizer
if win.url == "story_editor":
savenow = False
if win.previous["LMB"] and not win.current["LMB"]:
savenow = True
elif win.previous["RMB"] and not win.current["RMB"]:
savenow = True
elif win.previous["MMB"] and not win.current["MMB"]:
savenow = True
elif win.previous["keys"] and not win.current["keys"]:
savenow = True
if savenow:
story.save(win.project, win.story)
analytics.save(win.project, win.analytics)
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "File Saving", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
# To selected
if 65454 in win.current["keys"] and win.story["selected"] and not win.textactive:
nex = cx-win.szone[0][0] - win.szone[1][0]/2 + win.current["w"]/2
ney = cy-win.szone[0][1] - win.szone[1][1]/2 + win.current["h"]/2
UI_elements.animate("cameraX", win, win.story["camera"][0],nex, force=True)
UI_elements.animate("cameraY", win, win.story["camera"][1],ney, force=True)
# Grab
if 103 in win.current["keys"] and win.story["selected"] and not win.textactive:
win.current["tool"] = "grab"
win.current["LMB"] = [win.current["mx"], win.current["my"], True]
# Scale
if 115 in win.current["keys"] and win.story["selected"] and not win.textactive:
win.current["tool"] = "scale"
win.current["LMB"] = [win.current["mx"], win.current["my"], True]
# Deletion
if 65535 in win.current["keys"] and win.current["tool"] == "selection"\
and win.url == "story_editor" and win.story["selected"] and not win.textactive:
win.url = "story_deletion_dialog"
########### TIMES RECORDING FOR PERFONMANCE MEASURING #############
fif = datetime.datetime.now()
mil = fif - stf
perfStat.append([ "Short Cuts", mil.microseconds ])
stf = datetime.datetime.now()
###################################################################
############### PERFORMCE TESTING GROUND ##############
if win.current["testing"]:
h = win.current["h"]+200
w = win.current["w"]
UI_color.set(layer, win, "darker_parts")
UI_elements.roundrect(layer, win,100, h-(len(perfStat)*15)-30-300, 500,len(perfStat)*15+30, 10)
l = 0
s = 0
for i in perfStat:
if int(i[1]) > l:
l = int(i[1])
s = s + int(i[1])
for n, i in enumerate(perfStat):
#UI_color.set(layer, win, "progress_background")
#UI_elements.roundrect(layer, win, 110 + 270, h-(len(perfStat)*15)-20+10+15*n-300, 200,10, 5)
layer.set_source_rgb(1,1,1)
if int(i[1]) == l:
layer.set_source_rgb(1,0,0)
elif int(i[1]) < 1000:
layer.set_source_rgb(0,1,0)
layer.set_font_size(10)
layer.move_to( 110, h-(len(perfStat)*15)+15*n-300)
p = float(i[1]) / s *100
layer.show_text(str(i[0])+" - "+str(i[1])+" MCRS "+str(int(round(p)))+"%")
#UI_color.set(layer, win, "progress_active")
UI_elements.roundrect(layer, win, 110 + 270, h-(len(perfStat)*15)-20+10+15*n-300, int(round(p))*2,10, 5)
return surface