Jeison Yehuda Amihud (Blender Dumbass)
162d3f8038
Implemented missing features that could be seen as bugs for the casual users. Such as sync of the main checklist. And other minor changes.
1274 lines
39 KiB
Python
1274 lines
39 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 oscalls
|
|
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
|
|
from studio import schedule
|
|
|
|
#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():
|
|
win.cur = "/set"
|
|
win.url = "analytics"
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
5,
|
|
5,
|
|
win.current["w"]-(win.current["w"]/3)+45,
|
|
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()
|
|
|
|
|
|
|
|
############ CURRENT TASK SCHEDULED #############
|
|
|
|
|
|
# FIRST WE NEED TO GET A LIST OF TASKS
|
|
# This is going to be a simplified version of the same stuff as in the
|
|
# scheduling. But since we don't care what date we are in and trying to
|
|
# get the oldest unchecked task. Here we go.
|
|
|
|
schedules = schedule.get_schedules(win.analytics["dates"])
|
|
new_date_format = "%Y/%m/%d"
|
|
today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
|
|
|
|
slist = []
|
|
for date in schedules:
|
|
for item in schedules[date]:
|
|
if win.cur == item or not win.cur == "/set":
|
|
slist.append([date, item, schedules[date][item]])
|
|
|
|
|
|
# Now that we have our list we can start paring it the same way as in the
|
|
# scheduling. Only removing some unnesesary stuff.
|
|
foundtask = False
|
|
taskname = ""
|
|
taskurl = ""
|
|
taskcur = ""
|
|
|
|
for entry in slist:
|
|
if not foundtask:
|
|
for thing in entry[2]:
|
|
if thing[0][3] == "[Checked]":
|
|
continue # We do not care about those who are checked here.
|
|
elif thing[0][-1] != win.settings["Username"]:
|
|
continue # We do not care if it's not for us
|
|
else:
|
|
foundtask = True
|
|
|
|
# Here we are going to take out some data about this task
|
|
|
|
# First if it's not for today let's get a color for it
|
|
if entry[0] != "1997/07/30":
|
|
draw = False
|
|
if entry[0] < today:
|
|
UI_color.set(layer, win, "node_badfile") # The Red
|
|
draw = True
|
|
elif entry[0] > today:
|
|
UI_color.set(layer, win, "node_asset") # The Purple
|
|
draw = True
|
|
if draw:
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/3*2+60,
|
|
5,
|
|
(win.current["w"]/3-65),
|
|
40,
|
|
10)
|
|
|
|
name = entry[1][entry[1].rfind("/")+1:]
|
|
acur = entry[1].replace(name, "").replace("/", "")
|
|
|
|
fullurl = ""
|
|
for e in thing[0][4][:-1]:
|
|
fullurl = fullurl+e+" > "
|
|
|
|
|
|
if acur in ["chr", "veh", "loc", "obj"]:
|
|
assetname = talk.text(acur)+": "+name
|
|
else:
|
|
assetname = entry[1]
|
|
|
|
# ASSINGING TEXT VALUES
|
|
taskname = thing[0][4][-1]
|
|
taskurl = fullurl
|
|
taskcur = assetname.replace("/set","")
|
|
|
|
# AND A TINY BUTTON TO ENTER WHAT EVER YOU ARE DOING
|
|
goto = "analytics"
|
|
if acur in ["chr", "veh", "loc","obj"]:
|
|
goto = "assets"
|
|
itemtype = "assets"
|
|
elif not acur:
|
|
itemtype = "files"
|
|
else:
|
|
goto = "script"
|
|
itemtype = "scenes"
|
|
|
|
def do():
|
|
win.url = goto
|
|
win.cur = entry[1]
|
|
win.current["asset_left_panel"] = "schedule"
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/3*2+60,
|
|
5,
|
|
(win.current["w"]/3-65),
|
|
40,
|
|
10,
|
|
button=do)
|
|
|
|
break
|
|
else:
|
|
break
|
|
|
|
# Schedule
|
|
if taskname:
|
|
UI_elements.image(layer, win, "settings/themes/"\
|
|
+win.settings["Theme"]+"/icons/schedule.png",
|
|
win.current["w"]/3*2+60,
|
|
5,
|
|
40,
|
|
40)
|
|
|
|
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(taskname)
|
|
|
|
layer.set_font_size(12)
|
|
layer.move_to(win.current["w"]/3*2+130+len(taskname)*12, 25)
|
|
layer.show_text(taskurl)
|
|
|
|
layer.set_font_size(12)
|
|
layer.move_to(win.current["w"]/3*2+120, 40)
|
|
layer.show_text(taskcur)
|
|
|
|
|
|
########### 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,
|
|
"scene_new",
|
|
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():
|
|
def after(win, var):
|
|
pass
|
|
|
|
studio_dialogs.render(win, "current_renders", after)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
5,
|
|
405,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"render",
|
|
talk.text("render_lists_tooltip"),
|
|
url="story_editor")
|
|
|
|
# Let's draw on top of this button a little indicator of how many renders
|
|
# are currently setup.
|
|
|
|
if win.renders:
|
|
count = str(len(win.renders))
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
UI_elements.roundrect(layer, win,
|
|
30,
|
|
405,
|
|
len(count)*12+6,
|
|
25,
|
|
5)
|
|
layer.fill()
|
|
UI_color.set(layer, win, "text_normal")
|
|
layer.set_font_size(20)
|
|
layer.move_to(33,425)
|
|
layer.show_text(count)
|
|
|
|
|
|
# Edit Video
|
|
def do():
|
|
def after(win, var):
|
|
if var:
|
|
print(var)
|
|
oscalls.file_open(win, var)
|
|
|
|
studio_dialogs.vse(win, "VSEs", after)
|
|
|
|
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"
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
5,
|
|
win.current["h"]-95,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"multiuser",
|
|
talk.text("multiuser_tooltip"),
|
|
url="story_editor")
|
|
|
|
if win.multiuser["unread"]:
|
|
count = str(win.multiuser["unread"])
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
UI_elements.roundrect(layer, win,
|
|
30,
|
|
win.current["h"]-100,
|
|
len(count)*12+6,
|
|
25,
|
|
5)
|
|
layer.fill()
|
|
UI_color.set(layer, win, "text_normal")
|
|
layer.set_font_size(20)
|
|
layer.move_to(33,win.current["h"]-83)
|
|
layer.show_text(count)
|
|
|
|
# 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")+"\n[Shift-C]",
|
|
url="story_editor")
|
|
|
|
# Shortcut
|
|
if 67 in win.current["keys"] and not win.textactive:
|
|
do()
|
|
win.current["keys"] = []
|
|
|
|
# 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")+"\n[Shift-V]",
|
|
url="story_editor")
|
|
|
|
# Shortcut
|
|
if 86 in win.current["keys"] and not win.textactive:
|
|
do()
|
|
win.current["keys"] = []
|
|
|
|
# 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")+"\n[Shift-L]",
|
|
url="story_editor")
|
|
|
|
# Shortcut
|
|
if 76 in win.current["keys"] and not win.textactive:
|
|
do()
|
|
win.current["keys"] = []
|
|
|
|
# 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")+"\n[Shift-O]",
|
|
url="story_editor")
|
|
|
|
# Shortcut
|
|
if 79 in win.current["keys"] and not win.textactive:
|
|
do()
|
|
win.current["keys"] = []
|
|
|
|
# Sounds / Music
|
|
def do():
|
|
os.system("xdg-open "+win.project+"/mus")
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]-45,
|
|
355,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"mus",
|
|
talk.text("mus"),
|
|
url="story_editor")
|
|
|
|
# Help
|
|
def do():
|
|
def after(win, var):
|
|
pass
|
|
|
|
studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_story_editor"))
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]-45,
|
|
win.current["h"]-125,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"question",
|
|
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
|
|
try:
|
|
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)
|
|
except:
|
|
pass
|
|
|
|
########### 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
|
|
|
|
# For the one inside the project. They should be always relative
|
|
# so even if the project is in a complitely different location
|
|
# on another machine. Where we have our Multiuser data. It should
|
|
# be able to load these.
|
|
|
|
if win.project in link[1]:
|
|
link[1] = link[1].replace(win.project, "")
|
|
|
|
|
|
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
|
|
|
|
|
|
# MARKERS
|
|
try:
|
|
for user in win.multiuser["users"]:
|
|
if user != win.multiuser["userid"]:
|
|
|
|
mx = 0-win.multiuser["users"][user]["camera"][0] +cx + win.current["w"]/2
|
|
my = 0-win.multiuser["users"][user]["camera"][1] +cy + win.current["h"]/2
|
|
|
|
studio_nodes.user(layer, win, win.multiuser["users"][user]["username"], mx, my, user)
|
|
except Exception as e:
|
|
print(e, "USER RENDERING")
|
|
|
|
########### 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()
|
|
###################################################################
|
|
|
|
# The undo history is quite a new adition so the limit setting might
|
|
# not exists. So let's make it if so.
|
|
if "Undo_Limit" not in win.settings:
|
|
win.settings["Undo_Limit"] = 32
|
|
settings.write("Undo_Limit", 32)
|
|
|
|
if win.animations["cameraX"][1] == cx:
|
|
win.current["camera_arrived"] = True
|
|
else:
|
|
win.current["camera_arrived"] = False
|
|
|
|
|
|
|
|
|
|
# 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
|
|
elif win.current["camera_arrived"] and not win.previous["camera_arrived"]:
|
|
savenow = True
|
|
|
|
if savenow:
|
|
|
|
# Now let's run the history record.
|
|
story.undo_record(win)
|
|
|
|
story.save(win.project, win.story)
|
|
analytics.save(win.project, win.analytics)
|
|
|
|
# Need to reload the story to reload the fractions of the scenes.
|
|
win.story = story.load(win.project)
|
|
|
|
# Multiuser sycning
|
|
win.multiuser["request"] = "story"
|
|
|
|
########### 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)
|
|
|
|
# Undo
|
|
if 65507 in win.current["keys"] and 122 in win.current["keys"] and not win.textactive:
|
|
story.undo(win)
|
|
win.current["keys"] = []
|
|
|
|
# Redo
|
|
if 65507 in win.current["keys"] and 121 in win.current["keys"] and not win.textactive:
|
|
story.redo(win)
|
|
win.current["keys"] = []
|
|
|
|
# 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
|
|
|