3003 lines
122 KiB
Python
3003 lines
122 KiB
Python
# THIS FILE IS A PART OF VCStudio
|
|
# PYTHON 3
|
|
|
|
import os
|
|
import datetime
|
|
import re
|
|
import json
|
|
|
|
# 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 settings import oscalls
|
|
from project_manager import pm_project
|
|
|
|
#UI modules
|
|
from UI import UI_elements
|
|
from UI import UI_color
|
|
from UI import UI_math
|
|
|
|
# story
|
|
from studio import story
|
|
from studio import checklist
|
|
from studio import analytics
|
|
from studio import studio_dialogs
|
|
from studio import schedule
|
|
from studio import history
|
|
|
|
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 a file that will draw the text editor of VCStudio. The idea is that
|
|
# you not only work on making the movie in VCStudio, but the script to the
|
|
# movie is also written in VCStudio. This was already implemented in Blender-
|
|
# Organizer legacy. And already implemented partially in VCStudio. As there
|
|
# is story editor in place where you can add empty scenes. Or deal with
|
|
# scenes that are converted from legacy.
|
|
|
|
# But as you may guess by the time I'm writting it there is no way of editing
|
|
# those scene's contents. Or read them in full. ( You can see peaces in the
|
|
# assets )
|
|
|
|
# The implementation of the editor will be different from Blender-Organizer's
|
|
# where I used an off the shelf GTK text writting widget.
|
|
|
|
# The problem was that I could not really do much with that widget appart from
|
|
# text. Don't get me wrong it was good for text. But I could not make for
|
|
# example custom ways of drawing particular parts. Like what if I want a
|
|
# round-rectangle arround each frase that the crachater's say. Or what if I
|
|
# want to draw some custom UI buttons somewhere in the text. Stuff like this.
|
|
|
|
# Which resulted in a weird workflow. I had a pretty script preview thing.
|
|
# and another non-pretty script preview thing. And a script writer thing where
|
|
# you type in code to mark thing. Very non pretty. Non user-friendly. And
|
|
# you had to learn the code. And stuff. Yeah...
|
|
|
|
# So here I want to make more of traditional editor. Where you see what you are
|
|
# editing as you editing it. Hopefully it's going to work.
|
|
|
|
############################################################################
|
|
|
|
####### TOP PANEL #########
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/4,
|
|
10,
|
|
win.current["w"]/2,
|
|
50,
|
|
10)
|
|
|
|
|
|
# Let's add the toolbar. There is not a lot of tools we need. Since it's
|
|
# a program only for writting a script.
|
|
|
|
# Mark Shot
|
|
# Mark Asset
|
|
# Start Dialogue
|
|
# Link Image
|
|
|
|
# MARK SHOT
|
|
def do():
|
|
win.current["key_letter"] = chr(19)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/4+5,
|
|
15,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"shot_new",
|
|
talk.text("add_shot_tooltip")+"\n\n[Ctrl - S]")
|
|
|
|
# MARK ASSET
|
|
def do():
|
|
win.current["key_letter"] = chr(12)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/4+55,
|
|
15,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"obj_link",
|
|
talk.text("add_asset_tooltip")+"\n\n[Ctrl - L]")
|
|
|
|
# Do DIALOGUE
|
|
def do():
|
|
|
|
# Later on I'm doing the Ctrl - D combination to add a frase part
|
|
# and this gives me a character of 00000011 or in other words a 4.
|
|
# So i guess making it thing that I pressed Ctrl-D is fine.
|
|
|
|
win.current["key_letter"] = chr(4)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/4+105,
|
|
15,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"frase_new",
|
|
talk.text("add_phrase_tooltip")+"\n\n[Ctrl - D]")
|
|
|
|
# ADD IMAGE
|
|
def do():
|
|
win.current["key_letter"] = chr(9)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/4+155,
|
|
15,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"image_link",
|
|
talk.text("add_image_script_tooltip")+"\n\n[Ctrl - I]")
|
|
|
|
# Next part is to add the scene name editor. It's not as easy as you might
|
|
# thing. Since every scene's shot might contain an actuall folder on the
|
|
# operating system after you create a first blend file to animate the shot.
|
|
|
|
# So there will be a folder for the scene with many folders for shots inside.
|
|
# And if you change the name of the scene in the story you probably want to
|
|
# change the name of the scene in the folder as well. BUT. Since there could
|
|
# be countless blend files inside. And some names just could be already taken
|
|
# and stuff like that, I will block the editing of the scene if a folder exists.
|
|
# And will give a folder icon.
|
|
|
|
# Technically it's going to be possible to rename the scene. By renaming the
|
|
# folder first. But this is a kind of breaking everything operation i don't
|
|
# want to implement inside the VCStudio it self. I give constant folder links
|
|
# so editing of files could be done by the user at any time.
|
|
|
|
# But I don't want it to feel easy. Since stuff like deleting assets or
|
|
# editing names could break things in a different place in the program. That's
|
|
# why I don't provide easy to use functions for it. The user should really
|
|
# decide to make a change like this. To the point of breaking the convinience
|
|
# of VCStudio.
|
|
|
|
# Parsing the url
|
|
if win.cur.count("/") > 1:
|
|
tmp = win.cur.replace("/","",1).split("/")
|
|
scene, shot = tmp[0], tmp[1]
|
|
else:
|
|
scene = win.cur[win.cur.rfind("/")+1:]
|
|
shot = ""
|
|
|
|
|
|
|
|
# Let's find out if a folder exists.
|
|
|
|
if os.path.exists(win.project+"/rnd/"+scene):
|
|
editable = False
|
|
minus = 50
|
|
|
|
# The minus is the width of the folder button
|
|
|
|
def do():
|
|
oscalls.Open(win.project+"/rnd/"+scene)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/4*3-45,
|
|
15,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"folder",
|
|
tip="/rnd/"+scene)
|
|
|
|
|
|
|
|
else:
|
|
editable = True
|
|
minus = 0
|
|
|
|
UI_elements.text(layer, win, "scene_name",
|
|
win.current["w"]/4+205,
|
|
15,
|
|
win.current["w"]/2-210-minus,
|
|
40,
|
|
set_text=scene,
|
|
editable=editable,
|
|
fill=False)
|
|
|
|
# Now let's do the actual edititing part. What we want to look for is whether
|
|
# the key already exists in the scenes, if not allow it to be applied. Now
|
|
# you are probably asking yourself. But the current scene exists there? So
|
|
# how could you apply it. Easy. If you change anything. It already doesn't
|
|
# exist there. And if you didn't change anything. What's the point of applying
|
|
# anyway? So here what we are going to do.
|
|
|
|
newname = win.text["scene_name"]["text"].replace("/","_").replace(" ", "_")\
|
|
.replace('"',"_").replace("(","_").replace(")","_").replace("'","_")\
|
|
.replace("[","_").replace("]","_").replace("{","_").replace("}","_")
|
|
|
|
if newname not in win.story["scenes"]:
|
|
|
|
def do():
|
|
|
|
win.story["scenes"][newname] = win.story["scenes"].pop(scene)
|
|
win.text["scene_name"]["text"] = newname
|
|
win.cur = newname
|
|
|
|
|
|
|
|
# There is one more rub. Scenes could be connected together.
|
|
# so now we need to preserve the connections as well. This is
|
|
# not that hard.
|
|
|
|
for arrow in win.story["arrows"]:
|
|
if arrow[0][1] == scene:
|
|
arrow[0][1] = newname
|
|
if arrow[1][1] == scene:
|
|
arrow[1][1] = newname
|
|
|
|
# Easy. I like how if it's a list. it's a link to the list.
|
|
# so there will not be memory overdrives. So I can itterate
|
|
# over a list of lists and assing values of to the itteration
|
|
# and not trying to get the main list. LOVELY.
|
|
|
|
|
|
|
|
# Saving to the file
|
|
story.save(win.project, win.story)
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/4*3-45,
|
|
15,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"ok",
|
|
tip=talk.text("checked"))
|
|
|
|
# Just in case parsing the url again
|
|
if win.cur.count("/") > 1:
|
|
tmp = win.cur.replace("/","",1).split("/")
|
|
scene, shot = tmp[0], tmp[1]
|
|
else:
|
|
scene = win.cur[win.cur.rfind("/")+1:]
|
|
shot = ""
|
|
|
|
######### MAIN PART ###########
|
|
|
|
# Oh dear. I have no idea how hard it's going to be. But let's try. I don't
|
|
# thing it's going to be that insane. But I need to take in consideration
|
|
# a couple of things. Mainly text warping. Meaning I'm probably rendering
|
|
# each word as an individual object. Now this creates a challenge.
|
|
|
|
# How do I mark parts of the text having more then 1 word it it? I probably
|
|
# will need to draw a couple layers at ones.
|
|
|
|
# TEXT LAYER
|
|
# SHOTS MARKING LAYER
|
|
# ASSET MARKING LAYER
|
|
|
|
# And then combine them in a different order
|
|
|
|
# SHOT MARKING LAYER
|
|
# ASSET MARKING LAYER (on top)
|
|
# TEXT LAYER (on top of everything)
|
|
|
|
# So let's make those 3 layers.
|
|
|
|
x = win.current["w"]/4
|
|
y = 70
|
|
width = win.current["w"]/2 -30
|
|
height = win.current["h"]-130
|
|
|
|
# Good that at least all layers have the same size.
|
|
|
|
textsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
|
|
text = cairo.Context(textsurface)
|
|
text.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
|
|
|
shotsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
|
|
shots = cairo.Context(shotsurface)
|
|
shots.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
|
|
|
assetsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
|
|
assets = cairo.Context(assetsurface)
|
|
assets.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
|
|
|
frasesurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
|
|
frases = cairo.Context(frasesurface)
|
|
frases.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
|
|
|
###########################
|
|
|
|
# Oh dear
|
|
|
|
# Clips:
|
|
UI_elements.roundrect(text, win, 0,0,width, height, 10,fill=False)
|
|
text.clip()
|
|
UI_elements.roundrect(shots, win, 0,0,width, height, 10,fill=False)
|
|
shots.clip()
|
|
UI_elements.roundrect(assets, win, 0,0,width, height, 10,fill=False)
|
|
assets.clip()
|
|
UI_elements.roundrect(frases, win, 0,0,width, height, 10,fill=False)
|
|
frases.clip()
|
|
|
|
# Background
|
|
UI_color.set(frases, win, "node_background")
|
|
frases.rectangle(0,0,width, height)
|
|
frases.fill()
|
|
|
|
# Scroll stuff
|
|
if "script" not in win.scroll:
|
|
win.scroll["script"] = 0
|
|
|
|
tileX = 12
|
|
current_Y = 0
|
|
|
|
# For highlights of assets and shots. Basically when mouse is over a given
|
|
# asset it will record itself into the higlight. And be read on the next
|
|
# frame by those above it which are links to the same asset / shot.
|
|
# This is done like so, so I could make multiline drawing of markings.
|
|
|
|
if "script_asset_higlight" not in win.current:
|
|
win.current["script_asset_higlight"] = ""
|
|
if "script_shot_higlight" not in win.current:
|
|
win.current["script_shot_higlight"] = ""
|
|
|
|
|
|
# Next. For editing the text we need a cursor on the screen. A kind of pointer
|
|
# that will be our selection. The only problem is that we are trying to make
|
|
# usefull text editor where you can select a part of text. And do things to it
|
|
# like let's say mark a shot or an asset. This is why there are actually 2
|
|
# points which are souce of quite heavy head auks later on.
|
|
|
|
pointer = [0,0] # The editing cursor
|
|
point = 0 # The current place in the text of the scene.
|
|
if scene in win.story["pointers"]: # Also I thought sinec we are
|
|
pointer = win.story["pointers"][scene] # saving selection in story
|
|
# editor. Why not save also
|
|
# The text pointers.
|
|
|
|
# Coming back to the previous thing. If I mouse over the part the part get's
|
|
# highlighted. But simply removing the mouse is not enough. Because I'm
|
|
# writting that it's higlighted into a global dictionary. So I want to clean.
|
|
# it ones in a while. And for now ( It does cause some visual noise ) I chose
|
|
# to remove the selection if the mouse cursor moved over 1 pixel from it's
|
|
# previous frame. So if you move the cursor very slowly, there will be no
|
|
# change.
|
|
|
|
if int(win.current["mx"]) not in range(int(win.previous["mx"])-1, int(win.previous["mx"])+1)\
|
|
and int(win.current["my"]) not in range(int(win.previous["my"])-1, int(win.previous["my"])+1):
|
|
win.current["script_asset_higlight"] = ""
|
|
win.current["script_shot_higlight"] = ""
|
|
|
|
|
|
# This 2 fellas will be responsible for drawing the shot marking.
|
|
shotpart = 0 # This is a pixel where to start the rounded rectangle.
|
|
shotis = "" # this is a current drawing shot's name.
|
|
|
|
# Same idea for the selection cursor.
|
|
ss = 0 # The pixel where to start drawing the selection cursor.
|
|
smx = ss
|
|
|
|
# Another one of these for the rectangles under frases. This one is Y location
|
|
# instead.
|
|
frasepart = 0
|
|
|
|
# This is the scroll when typing.
|
|
|
|
putscroll = 0
|
|
|
|
|
|
# Before we start. Let's bullet proof this. So if the scene does not exist
|
|
# we will be transferred back to story editor and not stuck.
|
|
|
|
try:
|
|
win.story["scenes"][scene]["shots"]
|
|
except:
|
|
win.url = "story_editor"
|
|
win.cur = ""
|
|
return surface
|
|
|
|
# Okay if nothing is in the scene we want to create a text block of 1 character
|
|
# into the scene. Because if it will have 0 characters it will be automatically
|
|
# deleted.
|
|
|
|
if not win.story["scenes"][scene]["shots"]\
|
|
or win.story["scenes"][scene]["shots"][-1][0] == "shot_block":
|
|
win.story["scenes"][scene]["shots"].append([
|
|
"text_block",[["text", ' ']]
|
|
])
|
|
|
|
|
|
# This is a list of parts that are inside the selection. I will populate it
|
|
# as I itterate trough text. The problem with this text is that it's not a
|
|
# long string. It's a list of blocks. Each of them has a string. But also
|
|
# each of them has some aditional metadata. Like is it a shot, or not. Is it
|
|
# a frase. Is it a link to an asset. This kind a thing. So in order to edit it
|
|
# I need to get all selected peaces into a big thing.
|
|
|
|
selecwords = []
|
|
|
|
# And a little thing for the left panel. Since we already itterating through.
|
|
# the shots. Why not get a quick list of them
|
|
|
|
shot_list = {}
|
|
|
|
# Okay so let's begin itterating the scene blocks. There are 2 types of scene
|
|
# blocks. (At least for now.) Those are shot_block and text_block. Text is a
|
|
# normal text parts. Shot is everything with in a shot. Shot has one more item
|
|
# in the list. It's the name of the shot. ['shot_block', 'shot_name', [<text>]]
|
|
# while text has just 2. ['text_block', [<text>]]. So you can see me refencing
|
|
# the block[-1] a lot. To get the text parts of the block.
|
|
|
|
|
|
|
|
for num, block in enumerate(win.story["scenes"][scene]["shots"]):
|
|
|
|
|
|
# If shot block is empty Let's get rig of it, so not to collect garbage in
|
|
# our story file. Each empty srting is still a string. That requires some
|
|
# characters to write it to file. So let's get rid of it here.
|
|
|
|
if not block[-1]:
|
|
del win.story["scenes"][scene]["shots"][num]
|
|
|
|
# Here I want to make another type of filtering. So there will not be
|
|
# 1 million blocks each 1 character long. I want to make it next.
|
|
# If the previous block has the same metadata as this one. Join them.
|
|
|
|
if num > 0 and win.story["scenes"][scene]["shots"][num-1][0] == "text_block" and block[0] == "text_block":
|
|
win.story["scenes"][scene]["shots"][num-1][-1] = win.story["scenes"][scene]["shots"][num-1][-1] + block[-1]
|
|
del win.story["scenes"][scene]["shots"][num]
|
|
|
|
|
|
# THIS ONE IS NOT TESTED YET, BUT I MIGHT ALSO FORGET TO DELETE THE COMMENT.
|
|
elif num > 0 and win.story["scenes"][scene]["shots"][num-1][0] == "shot_block" and block[0] == "shot_block"\
|
|
and win.story["scenes"][scene]["shots"][num-1][1] == block[1]:
|
|
win.story["scenes"][scene]["shots"][num-1][-1] = win.story["scenes"][scene]["shots"][num-1][-1] + block[-1]
|
|
del win.story["scenes"][scene]["shots"][num]
|
|
|
|
if block[0] == "shot_block" and block[1] not in shot_list:
|
|
shot_list[block[1]] = block
|
|
|
|
|
|
# Now other windows might want to reference the script. Like assets for
|
|
# example. So this script_find is for other windows to set. So while in
|
|
# the script it would automatically scroll to that part. And so if set
|
|
# only shot. Here is out shot finder, auto-scroller thingy.
|
|
|
|
if win.current["script_find"][0] and win.current["script_find"][0] == num:
|
|
win.scroll["script"] = 0-current_Y+height/2
|
|
win.current["script_find"][0] = 0
|
|
|
|
# Now let's itterate over parts of the text. Now you probably asking wasn't
|
|
# blocks just strings with some metadata? Yes and know. Every text block has
|
|
# blocks with in it. So I could mark items and images and frases with in text
|
|
# across or without a shot. Basically there is our simple Hello-World thing
|
|
# written inside a scene data. ['text_block', ['text','Hello-World']]
|
|
# This are similar. The actual sting is always in the very end. So to find it
|
|
# I'm using part[-1]
|
|
|
|
for n, part in enumerate(block[-1]):
|
|
|
|
# If you remember me deleting every empty block. Not this is the same
|
|
# but with empty parts. So you could delete a frase for example. While
|
|
# just backspacing.
|
|
|
|
if not part[-1]:
|
|
del block[-1][n]
|
|
|
|
# Here I want to make another type of filtering. So there will not be
|
|
# 1 million blocks each 1 character long. I want to make it next.
|
|
# If the previous block has the same metadata as this one. Join them.
|
|
|
|
if n > 0 and block[-1][n-1][0] == "text" and part[0] == "text":
|
|
block[-1][n-1][-1] = block[-1][n-1][-1]+part[-1]
|
|
part[-1] = ""
|
|
|
|
# Now this is our search finder auto-scroller again. But if a part
|
|
# also specified.
|
|
|
|
if win.current["script_find"][1] and win.current["script_find"][1] == n:
|
|
win.scroll["script"] = 0-current_Y+height/2
|
|
win.current["script_find"][1] = 0
|
|
|
|
# Now t and p. Well t is simply a shortcut to the string it self. Tho
|
|
# I found it not really usefull since it's not a link to the data. Like
|
|
# in the case of part[-1]. But for rendering it will be okay.
|
|
|
|
t = part[-1]
|
|
|
|
# Now p is a bit more complicated to explain. Basically I always need
|
|
# an index number from all character in the whole scene in relation to
|
|
# this particular part. See i will have a selection across the blocks
|
|
# and across the parts. And in order to edit them at the right place
|
|
# I need a reference point of where in the whole, this part starts.
|
|
|
|
p = point
|
|
|
|
# Now xb and mt you could see as margins of the text. Sometimes you
|
|
# want the whole width to be text. And sometimes. Like in frases you
|
|
# will want the text closer to the center.
|
|
|
|
xb = 12 # Where is the start of the line
|
|
mt = width # Where is the maximum width
|
|
|
|
##### FRASE #####
|
|
|
|
# Now let's make an example of xb and mt. Here is a frase. So when
|
|
# it's a frase. You want the text be closer to the center.
|
|
|
|
if part[0] == "frase":
|
|
|
|
|
|
# Give it some space. It's a rendering of a frase. You don't
|
|
# want to be a part of the rest of the text.
|
|
|
|
current_Y = current_Y + 30
|
|
|
|
# Now frase metadata has another part. Which could be either
|
|
# text or link. This is the name of our character. The little
|
|
# part at the top, in the center. If it's a link we want to
|
|
# draw it accordingly
|
|
|
|
if part[1][0] == "link":
|
|
|
|
# First we draw a little purple rectangle. To show us that
|
|
# it's a link to an item.
|
|
|
|
UI_color.set(assets, win, "node_asset")
|
|
UI_elements.roundrect(assets, win,
|
|
width/2-len(part[1][-1])*6-6,
|
|
win.scroll["script"] + current_Y+6,
|
|
len(part[1][-1])*12+12,
|
|
28,
|
|
10)
|
|
|
|
# Then we make a selection by hovering with the mouse. So if
|
|
# you click later. You will be transferred to the thing.
|
|
|
|
if int(win.current['mx']) in range(int(x+width/2-len(part[1][-1])*6-6), int(x+width/2-len(part[1][-1])*6-6+len(part[1][-1])*12+12)) \
|
|
and int(win.current['my']) in range(int(y+win.scroll["script"] + current_Y+8), int(y+win.scroll["script"] + current_Y+8+22)) :
|
|
|
|
win.current["script_asset_higlight"] = part[1][1]
|
|
|
|
# And if the mouse is over the item's link. No matter if the
|
|
# link is this one. But if mouse is over any other mention of
|
|
# the same asset. We want to draw another rectangle. To give
|
|
# the user a feedback.
|
|
|
|
if part[1][1] == win.current["script_asset_higlight"]:
|
|
|
|
UI_color.set(assets, win, "text_normal")
|
|
UI_elements.roundrect(assets, win,
|
|
width/2-len(part[1][-1])*6-6,
|
|
win.scroll["script"] + current_Y+30,
|
|
len(part[1][-1])*12+12,
|
|
0,
|
|
3)
|
|
|
|
|
|
# Next we will want to do it make a little button to edit the
|
|
# name of the character. Because I guess I'm not smart enough
|
|
# to figure out how to make this a part of the script. And this
|
|
# implementation is not that terrible. I have a chance to put a
|
|
# single line entry into a multiline text. This is something.
|
|
|
|
if "current_name_frase_editing" not in win.current:
|
|
win.current["current_name_frase_editing"] = False
|
|
win.previous["current_name_frase_editing"] = False
|
|
|
|
# So we put a selection variable. And set up the button.
|
|
|
|
if not win.current["current_name_frase_editing"]:
|
|
def do():
|
|
|
|
win.current["LMB"] = False
|
|
win.previous["LMB"] = False
|
|
if not win.previous["current_name_frase_editing"]:
|
|
print(part[1][-1])
|
|
win.current["current_name_frase_editing"] = [num, n]
|
|
if "current_name_frase_editing" in win.text:
|
|
win.text["current_name_frase_editing"]["text"] = part[1][-1]
|
|
win.textactive = "current_name_frase_editing"
|
|
UI_elements.roundrect(frases, win,
|
|
0,
|
|
win.scroll["script"] + current_Y+6,
|
|
width,
|
|
28,
|
|
10,
|
|
button=do,
|
|
offset=[x,y])
|
|
|
|
# Now let's draw a little text editor with in a text editor. IK wild.
|
|
# but since everything is custom I can do wild things.
|
|
|
|
if win.current["current_name_frase_editing"] == [num, n]:
|
|
|
|
UI_elements.text(text, win, "current_name_frase_editing",
|
|
200,
|
|
win.scroll["script"] + current_Y-5,
|
|
width-400,
|
|
40,
|
|
set_text=part[1][-1],
|
|
offset=[x,y])
|
|
|
|
# Here I will add some logic to this little editor with in
|
|
# editor. OMG WHAT AM I DOING?
|
|
|
|
# First let's make the apply button. And I guess the enter key.
|
|
|
|
def linking():
|
|
print("linking")
|
|
|
|
if "linking_asset_operation_metadata" not in win.current:
|
|
win.current["linking_asset_operation_metadata"] = []
|
|
|
|
win.current["linking_asset_operation_metadata"] = part
|
|
|
|
def after(win, var):
|
|
print(var)
|
|
if var:
|
|
|
|
part = win.current["linking_asset_operation_metadata"]
|
|
|
|
|
|
print(part)
|
|
part[1] = ["link", var, part[1][-1]]
|
|
|
|
|
|
studio_dialogs.asset_select(win, "link_asset_script_frase", after,
|
|
SEARCH=win.text["current_name_frase_editing"]["text"])
|
|
|
|
|
|
UI_elements.roundrect(text, win,
|
|
width-240,
|
|
win.scroll["script"] + current_Y-5,
|
|
40,
|
|
40,
|
|
10,
|
|
button=linking,
|
|
icon="obj_link",
|
|
offset=[x,y])
|
|
|
|
def do():
|
|
part[1][-1] = win.text["current_name_frase_editing"]["text"]
|
|
win.current["current_name_frase_editing"] = False
|
|
win.current["LMB"] = False
|
|
win.previous["LMB"] = False
|
|
win.textactive = False
|
|
win.current["key_letter"] = ""
|
|
|
|
UI_elements.roundrect(text, win,
|
|
width-280,
|
|
win.scroll["script"] + current_Y-5,
|
|
40,
|
|
40,
|
|
10,
|
|
button=do,
|
|
icon="ok",
|
|
offset=[x,y])
|
|
|
|
# Enter key.
|
|
|
|
if 65293 in win.current["keys"]:
|
|
do()
|
|
|
|
# If you press Ctrl-Enter instead of Enter. I want it
|
|
# to apply and also give you automatically to select
|
|
# the asset to link in the frase header.
|
|
|
|
if 65507 in win.current["keys"]:
|
|
linking()
|
|
|
|
win.current["keys"] = []
|
|
|
|
# Canceling the editing. If we don't do that the entry thing
|
|
# will still be on the screen. And it's not something that
|
|
# I want to have there.
|
|
|
|
if not win.textactive:
|
|
win.current["current_name_frase_editing"] = False
|
|
win.current["key_letter"] = ""
|
|
else:
|
|
|
|
# And if we are not editing the name currently
|
|
# let's just draw the name in the center of the
|
|
# screen.
|
|
|
|
UI_color.set(text, win, "text_normal")
|
|
text.set_font_size(20)
|
|
text.move_to(
|
|
width/2-len(part[1][-1])*6,
|
|
win.scroll["script"] + current_Y+25,
|
|
)
|
|
text.show_text(part[1][-1])
|
|
|
|
# Giving it a new line.
|
|
|
|
current_Y = current_Y + 35
|
|
|
|
# Putting the line into the frasepart so to draw a rectangle
|
|
# later under the whole thing.
|
|
|
|
frasepart = current_Y
|
|
|
|
# And here we are editing the margins. Because actuall text will
|
|
# be done in a different place.
|
|
|
|
xb = 212
|
|
mt = width - 200
|
|
tileX = xb
|
|
|
|
# And passing the current starting position to selection drawing
|
|
# so it too will start where it should.
|
|
|
|
if ss:
|
|
ss = xb
|
|
|
|
# Now if we are not in the frase. Let's draw the damn rectangle under
|
|
# it finally. # THIS IS STILL BUGGY.
|
|
|
|
if frasepart and part[0] != "frase":
|
|
UI_color.set(frases, win, "dark_overdrop")
|
|
UI_elements.roundrect(frases, win,
|
|
200,
|
|
win.scroll["script"] + frasepart,
|
|
width-400,
|
|
current_Y - frasepart+40,
|
|
10)
|
|
frasepart = 0
|
|
|
|
# MAKING A NEW LINE
|
|
|
|
smx = tileX
|
|
tileX = xb
|
|
|
|
if assetpart:
|
|
assetpart = xb
|
|
if shotpart:
|
|
shotpart = xb
|
|
|
|
if ss:
|
|
|
|
UI_color.set(assets, win, "node_blendfile")
|
|
UI_elements.roundrect(assets, win,
|
|
ss,
|
|
win.scroll["script"] + current_Y+5,
|
|
smx-ss,
|
|
26,
|
|
10)
|
|
smx = ss
|
|
ss = xb
|
|
|
|
current_Y = current_Y + 30
|
|
|
|
|
|
|
|
# Now let's draw our images. If they are in the scene. # THIS IS STILL BUGGY
|
|
|
|
if part[0] == "image":
|
|
|
|
if UI_math.line_overlap([pointer[1], pointer[0]],[point, point+1]):
|
|
if win.current["key_letter"] and not win.textactive:
|
|
|
|
# Let's make it possible to delete images by just
|
|
# deleting near them.
|
|
|
|
part[-1] = ""
|
|
|
|
current_Y = current_Y + 30
|
|
|
|
if os.path.exists(win.project+t):
|
|
UI_elements.image(text, win, win.project+t,
|
|
100,
|
|
win.scroll["script"] + current_Y,
|
|
int(width)-200,
|
|
380,
|
|
cell="script_images")
|
|
else:
|
|
UI_elements.image(text, win, t,
|
|
100,
|
|
win.scroll["script"] + current_Y,
|
|
int(width)-200,
|
|
380,
|
|
cell="script_images")
|
|
|
|
# Now I guess to simplify the matters let's create a selection
|
|
# button. Double clicking which will open the file.
|
|
|
|
# So we need a selection dialog. I think I'm going to hack into
|
|
# my own program right now because I'm lazy to implement anything
|
|
# normal. This image thing. Will need more love later on. Now it's
|
|
# thrown together quite in a rush. I would say.
|
|
|
|
def do():
|
|
if t != win.textactive:
|
|
win.textactive = t
|
|
else:
|
|
oscalls.file_open(win, t)
|
|
UI_elements.roundrect(text, win,
|
|
100,
|
|
win.scroll["script"] + current_Y,
|
|
int(width)-200,
|
|
380,
|
|
10,
|
|
button=do,
|
|
fill=False,
|
|
offset=[x,y])
|
|
text.stroke()
|
|
|
|
# Selection drawing
|
|
|
|
if t == win.textactive:
|
|
|
|
UI_color.set(text, win, "text_normal")
|
|
UI_elements.roundrect(text, win,
|
|
100,
|
|
win.scroll["script"] + current_Y,
|
|
int(width)-200,
|
|
380,
|
|
10,
|
|
fill=False)
|
|
text.stroke()
|
|
|
|
# Removing it from the selection using ESC
|
|
|
|
if 65307 in win.current["keys"]:
|
|
win.textactive = ""
|
|
win.current["keys"] = []
|
|
win.current["key_letter"] = ""
|
|
|
|
# Deleting the image if pressing Delete or Backspace
|
|
|
|
if 65288 in win.current["keys"] or 65535 in win.current["keys"]:
|
|
win.textactive = ""
|
|
part[-1] = ""
|
|
win.current["keys"] = []
|
|
win.current["key_letter"] = ""
|
|
|
|
current_Y = current_Y + 400
|
|
|
|
continue # we don't want to image url in the text it self.
|
|
|
|
# Do you remember I was doing the starting positions of shots and
|
|
# selection? These 2 are the same concept but to links to assets.
|
|
|
|
assetpart = 0
|
|
assetis = ""
|
|
|
|
############## TEXT IT SELF ###############
|
|
|
|
# Here we go and render the text. Now you can see I iterate over
|
|
# lines using re.split rather then built in split(). It's because
|
|
# I need all characters still be present. Since I'm counting every
|
|
# each character.
|
|
|
|
for line in re.split("(\n)",t):
|
|
|
|
# Now if the line says '\n' (new_line) then I just want to
|
|
# draw the next line. Note that I'm also drawing the selection
|
|
# box here. And moving all assetpart, shotpart and ss. So on
|
|
# the next line those rectangles would start their drawing from
|
|
# the begining of the line.
|
|
|
|
# Also not the large comment with a POINT in it. It's I'm counting
|
|
# this character in for to know where I'm editing.
|
|
|
|
if line == "\n":
|
|
|
|
smx = tileX
|
|
|
|
tileX = xb
|
|
#point = point + 1 #################### <<<<<< POINT
|
|
|
|
|
|
if assetpart:
|
|
assetpart = xb
|
|
if shotpart:
|
|
shotpart = xb
|
|
|
|
if ss:
|
|
|
|
UI_color.set(assets, win, "node_blendfile")
|
|
UI_elements.roundrect(assets, win,
|
|
ss,
|
|
win.scroll["script"] + current_Y+5,
|
|
smx-ss,
|
|
26,
|
|
10)
|
|
text.stroke()
|
|
smx = ss
|
|
ss = xb
|
|
|
|
current_Y = current_Y + 30
|
|
|
|
|
|
line = " "
|
|
#continue # And this is since I don't want weird rectangles
|
|
# on the screen. And just new lines.
|
|
|
|
# Now let's itterate over each and every word. Since we want
|
|
# text wrapping. So if a certain word goes off screen I want
|
|
# to declare a next line. NOTE: I'm still using re.split()
|
|
# becuase we are counting charaters still.
|
|
|
|
for word in re.split("( )", line):
|
|
|
|
# Now let's do the actuall text wrapping. For size 20 which
|
|
# is what I'm using. With monospace font. Width of each
|
|
# character is 12 pixels. ( More or less. Good enough for
|
|
# what we are doing ). So if lenght of word times 12, plus
|
|
# current place on X is more then the width of our screen,
|
|
# with all the margins. We want to start a new line.
|
|
|
|
if tileX + len(word)*12 > mt:
|
|
|
|
smx = tileX
|
|
|
|
tileX = xb
|
|
|
|
# And do not forget about all the asset, shot and selection
|
|
# rendering too.
|
|
|
|
if assetpart:
|
|
assetpart = xb
|
|
if shotpart:
|
|
shotpart = xb
|
|
|
|
|
|
if ss:
|
|
|
|
UI_color.set(assets, win, "node_blendfile")
|
|
UI_elements.roundrect(assets, win,
|
|
ss,
|
|
win.scroll["script"] + current_Y+5,
|
|
smx-ss,
|
|
26,
|
|
10)
|
|
text.stroke()
|
|
|
|
ss = xb
|
|
|
|
current_Y = current_Y + 30
|
|
|
|
|
|
|
|
# This is logic to draw ASSETS higlights.
|
|
|
|
if part[0] == "link" and part[1] != assetis and not assetpart:
|
|
assetpart = tileX
|
|
assetis = part[1]
|
|
|
|
if assetpart:
|
|
|
|
if word:
|
|
UI_color.set(assets, win, "node_asset")
|
|
UI_elements.roundrect(assets, win,
|
|
assetpart-5,
|
|
win.scroll["script"] + current_Y+8,
|
|
tileX - assetpart + len(word)*12+12,
|
|
22,
|
|
10)
|
|
|
|
# Selectiong asset. ( Not actually.) But making a
|
|
# highlight of the asset. And if clicked. Going
|
|
# to the asset.
|
|
|
|
if int(win.current['mx']) in range(int(x+assetpart-5), int(x+tileX + len(word)*12+12)) \
|
|
and int(win.current['my']) in range(int(y+win.scroll["script"] + current_Y+8), int(y+win.scroll["script"] + current_Y+8+22)) :
|
|
|
|
win.current["script_asset_higlight"] = assetis
|
|
|
|
if assetis == win.current["script_asset_higlight"]:
|
|
UI_color.set(assets, win, "text_normal")
|
|
UI_elements.roundrect(assets, win,
|
|
assetpart-6,
|
|
win.scroll["script"] + current_Y+26,
|
|
tileX - assetpart + len(word)*12+12,
|
|
0,
|
|
3)
|
|
|
|
|
|
assetpart = tileX
|
|
assetis = part[1]
|
|
|
|
if part[0] != "link":
|
|
assetpart = 0
|
|
assetis = ""
|
|
|
|
# And this is logic to draw SHOTS higlights.
|
|
|
|
if block[0] == "shot_block" and block[1] != shotis and not shotpart:
|
|
shotpart = tileX
|
|
shotis = block[1]
|
|
|
|
|
|
if shotpart:
|
|
|
|
if word:
|
|
|
|
# I want to randomize the shots colors. But I don't it to be an epileptic
|
|
# show. But not too much. Let's actually write the colors into the story
|
|
# data. Why not.
|
|
|
|
if "shot_colors" not in win.story:
|
|
win.story["shot_colors"] = {}
|
|
|
|
surl = "/"+scene+"/"+shotis
|
|
|
|
if surl not in win.story["shot_colors"]:
|
|
|
|
|
|
rcolors = [
|
|
"shot_1",
|
|
"shot_2",
|
|
"shot_3",
|
|
"shot_4",
|
|
"shot_5"
|
|
]
|
|
|
|
win.story["shot_colors"][surl] = rcolors[len(win.story["shot_colors"]) % len(rcolors)]
|
|
|
|
col = win.story["shot_colors"][surl]
|
|
|
|
if int(win.current['mx']) in range(int(x+shotpart-5), int(x+tileX + len(word)*12+12)) \
|
|
and int(win.current['my']) in range(int(y+win.scroll["script"] + current_Y+8), int(y+win.scroll["script"] + current_Y+8+22)) :
|
|
|
|
win.current["script_shot_higlight"] = shotis
|
|
|
|
UI_color.set(shots, win, col)
|
|
UI_elements.roundrect(shots, win,
|
|
shotpart-6,
|
|
win.scroll["script"] + current_Y+5,
|
|
tileX - shotpart + len(word)*12+12,
|
|
28,
|
|
10)
|
|
|
|
# This is a bit of a hack because I was lazy to
|
|
# figure out how to make shot markings as good
|
|
# as I made the selection. So drawing a thing around it
|
|
# would not really work that well. But a line under the
|
|
# text looks quite alright. I like the look of it.
|
|
# Maybe I will polish this in future and give people
|
|
# an option to draw it differently. I don't know yet.
|
|
|
|
if shotis == win.current["script_shot_higlight"] or shot == shotis:
|
|
UI_color.set(shots, win, "text_normal")
|
|
UI_elements.roundrect(shots, win,
|
|
shotpart-6,
|
|
win.scroll["script"] + current_Y+30,
|
|
tileX - shotpart + len(word)*12+12,
|
|
0,
|
|
3)
|
|
|
|
|
|
|
|
shotpart = tileX
|
|
shotis = block[1]
|
|
|
|
if block[0] != "shot_block":
|
|
shotpart = 0
|
|
shotis = ""
|
|
|
|
|
|
|
|
# Now let's draw our word. Simple really. What's so special
|
|
# about it? Why is this comment 2 lines high?
|
|
|
|
UI_color.set(text, win, "text_normal")
|
|
#if win.current["script_shot_higlight"] == block[1] or shot == block[1]:
|
|
# UI_color.set(text, win, "darker_parts")
|
|
text.set_font_size(20)
|
|
text.move_to(
|
|
tileX,
|
|
win.scroll["script"] + current_Y+25,
|
|
)
|
|
text.show_text(word)
|
|
|
|
# Here I want to make a selection using a mouse. I think it's quite important
|
|
# since using a Shift key and pressing sideways is not cool
|
|
# and I want it to be cool.
|
|
|
|
if win.current["LMB"]:
|
|
if int(win.current["LMB"][1]) in range(int(y+win.scroll["script"] + current_Y), int(y+win.scroll["script"] + current_Y)+25)\
|
|
and int(win.current["LMB"][0]-x) in range(tileX, tileX+len(word)*12+12):
|
|
pointer[0] = int(point - (tileX+len(word)*12 - int(win.current["LMB"][0]-x))/12 + len(word))
|
|
|
|
if int(win.current["my"]) in range(int(y+win.scroll["script"] + current_Y), int(y+win.scroll["script"] + current_Y)+25)\
|
|
and int(win.current["mx"]-x) in range(tileX, tileX+len(word)*12+12):
|
|
pointer[1] = int(point - (tileX+len(word)*12 - int(win.current["mx"]-x))/12 + len(word))
|
|
|
|
win.cur = "/"+scene
|
|
win.textactive = ""
|
|
|
|
if int(win.current["my"]) in range(int(y+win.scroll["script"] + current_Y), int(y+win.scroll["script"] + current_Y)+25)\
|
|
and int(win.current["mx"]-x) in range(tileX, tileX+len(word)*12+12):
|
|
|
|
win.current["cursor"] = win.cursors["text"]
|
|
|
|
# This is the logic to draw our selection and logic that
|
|
# come with the selection.
|
|
|
|
if UI_math.line_overlap([pointer[1], pointer[0]],[point, point+len(word)+1]) and not ss:
|
|
ss = tileX+(min(pointer[1], pointer[0])-point)*12
|
|
smx = ss
|
|
|
|
# If current word is inside the selection. It means that
|
|
# current text part is also inside the selection. And this
|
|
# means this part should be edited if I press a button.
|
|
|
|
if UI_math.line_overlap([pointer[1], pointer[0]],[point, point+len(word)+1]):
|
|
|
|
# So we need to add this part and some data about this
|
|
# part like amount of characters it's away from the
|
|
# begining of the scene into a list that I could reference
|
|
# later in the writting logic.
|
|
|
|
if [part, p, num, n] not in selecwords:
|
|
selecwords.append([part, p, num, n])
|
|
|
|
# Let's make something for me to understand what is going
|
|
# on. If I will enter the testing mode. Let it draw the
|
|
# current number of characters. And the current characrter.
|
|
|
|
if win.current["testing"]:
|
|
|
|
# This is our character. It's not always available.
|
|
# sometimes you migt be on the edge of something and
|
|
# something else. So !! will mean seomthing is wrong.
|
|
|
|
try:
|
|
c = part[-1][pointer[0]-p]
|
|
except:
|
|
c = "!!"
|
|
|
|
|
|
UI_color.set(text, win, "text_normal")
|
|
text.set_font_size(10)
|
|
text.move_to(
|
|
tileX+(pointer[0]-point)*12-26,
|
|
win.scroll["script"] + current_Y+35,
|
|
)
|
|
text.show_text(str(pointer[0])+"["+c+"]")
|
|
|
|
# Now doing it again for the second pointer. If you
|
|
# remeber, We have 2.
|
|
|
|
try:
|
|
c = part[-1][pointer[1]-p]
|
|
except:
|
|
c = "!!"
|
|
|
|
|
|
UI_color.set(text, win, "text_normal")
|
|
text.set_font_size(10)
|
|
text.move_to(
|
|
tileX+(pointer[1]-point)*12-26,
|
|
win.scroll["script"] + current_Y+35,
|
|
)
|
|
text.show_text(str(pointer[1])+"["+c+"]")
|
|
|
|
if max(pointer[1], pointer[0]) in range(point, point+len(word)+1):
|
|
# This is some more drawing of the selection. This is
|
|
# if the selection is ending mid way through the line.
|
|
|
|
if ss:
|
|
|
|
if pointer[0] != pointer[1] :
|
|
UI_color.set(assets, win, "node_blendfile")
|
|
UI_elements.roundrect(assets, win,
|
|
max(ss, xb),
|
|
win.scroll["script"] + current_Y+5,
|
|
min(tileX+(max(pointer[1], pointer[0])-point)*12-max(ss, xb), mt-max(ss, xb)),
|
|
26,
|
|
10)
|
|
|
|
elif not win.textactive and win.blink:
|
|
UI_color.set(text, win, "node_blendfile")
|
|
text.rectangle(
|
|
max(ss, xb),
|
|
win.scroll["script"] + current_Y+5,
|
|
min(tileX+(max(pointer[1], pointer[0])-point)*12-max(ss, xb), mt-max(ss, xb)),
|
|
26)
|
|
text.stroke()
|
|
|
|
# win.scroll["script"] + current_Y,
|
|
# min(mt-max(ss,xb), mt-xb),
|
|
|
|
ss = 0
|
|
#smx = 0
|
|
|
|
if win.current["keys"] and not win.textactive and not putscroll:
|
|
putscroll = min(0 - current_Y + width/2, win.scroll["script"])
|
|
|
|
|
|
# Now in the end of our word. We are counting it's lenght
|
|
# and moving the tileX so the next word draws after this
|
|
# one and not on top of this one. I think it's important.
|
|
|
|
point = point + len(word) #################### <<<<<< POINT
|
|
tileX = tileX + len(word)*12
|
|
|
|
# Also what you probably want to happen is when you type the script
|
|
# will scroll down. Yeah. It's not coming by default. Even on standart
|
|
# GTK text parts. So here is a little thing.
|
|
|
|
|
|
|
|
if putscroll:
|
|
win.scroll["script"] = putscroll
|
|
|
|
############# LOGIC ###############
|
|
|
|
# So I'm doing the logic of typing separatelly from rendering of the text.
|
|
# because it kind a seems right to do so. I'm still figuring it out at this
|
|
# point. I have no idea what could go wrong. Maybe I will reddo the whole
|
|
# thing. Maybe few times. IDK.
|
|
|
|
|
|
|
|
if 65363 in win.current["keys"]: # RIGHT
|
|
pointer[0] = pointer[0]+1
|
|
if not 65506 in win.current["keys"]:
|
|
pointer[1] = pointer[0]
|
|
#win.current["keys"].remove(65363)
|
|
|
|
|
|
if 65361 in win.current["keys"]: # LEFT
|
|
pointer[0] = pointer[0]-1
|
|
if not 65506 in win.current["keys"]:
|
|
pointer[1] = pointer[0]
|
|
#win.current["keys"].remove(65361)
|
|
|
|
|
|
if 65362 in win.current["keys"]: # UP
|
|
pointer[0] = pointer[0]-min(len(line), int((mt-12)/12)) # STILL BUGGY
|
|
if not 65506 in win.current["keys"]:
|
|
pointer[1] = pointer[0]
|
|
#win.current["keys"].remove(65362)
|
|
|
|
if 65364 in win.current["keys"]: # DOWN
|
|
pointer[0] = pointer[0]+min(len(line), int((mt-12)/12)) # STILL BUGGY
|
|
if not 65506 in win.current["keys"]:
|
|
pointer[1] = pointer[0]
|
|
#win.current["keys"].remove(65364)
|
|
|
|
# In order for history to work properly I don't want to save history on
|
|
# each button press. But rather ones every time the scene is edited. So
|
|
|
|
if "scene_edited_already" not in win.current:
|
|
win.current["scene_edited_already"] = False
|
|
|
|
|
|
# I'm going to implement some basic clipboard. It will need love in future.
|
|
# I just need for now something that will "work" so to speak. See where I
|
|
# use the clipboard variable later to learn how it all works.
|
|
|
|
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) # This is a clipboard object
|
|
|
|
|
|
# If there is a key press that contains a string. Like anything on a keyboard
|
|
# where you can actually type. Let's do something with it.
|
|
|
|
def clean():
|
|
# This is an empty function. Placeholder for a clean operation after
|
|
# a given key press. Because we are dealing with multiple blocks of
|
|
# text that look like 1 block for the user.
|
|
pass
|
|
|
|
# To make shot I want to write a little list of text parts that will come
|
|
# into that shot.
|
|
|
|
new_shot_list = []
|
|
after_shot_list = []
|
|
new_shot = []
|
|
|
|
if win.current["key_letter"] and not win.textactive:
|
|
|
|
# Here I'm going to implement history
|
|
if not win.current["scene_edited_already"]:
|
|
win.current["scene_edited_already"] = True
|
|
history.record(win, "/rnd"+win.cur, "[Edited]")
|
|
|
|
|
|
#print("------{ BEFORE }--------")
|
|
#print(win.story["scenes"][scene]["shots"])
|
|
#print("------{ }------")
|
|
#print()
|
|
|
|
|
|
#print() # For testing
|
|
|
|
for u, stuff in enumerate(selecwords):
|
|
part, p, num, n = stuff
|
|
|
|
try:
|
|
block = win.story["scenes"][scene]["shots"][num]
|
|
except:
|
|
break
|
|
|
|
try:
|
|
ORD = ord(win.current["key_letter"])
|
|
except:
|
|
ORD = 0
|
|
|
|
print(ORD, "ORD") # Output the value of the button.
|
|
|
|
# Now some of the ORDs I found to be weird characters. Like on
|
|
# CTRL - C or CTRL - V. So I want to filter them out. So there
|
|
# wont be a bunch of rectangles every time you type.
|
|
|
|
# Now I need the minimum and maximum parts. So there will not be
|
|
# scips of content I guess.
|
|
|
|
MIN = min(len(part[-1]), max(0, min(pointer[1], pointer[0])-p))
|
|
MAX = max(0, min(len(part[-1]), max(pointer[1], pointer[0])-p))
|
|
|
|
#print(pointer,"POINTER")
|
|
#print(p, "P")
|
|
#print(len(part[-1]), "LENGHT", [part[-1]])
|
|
#print(MIN, "MIN")
|
|
#print(MAX, "MAX")
|
|
#print()
|
|
|
|
# Here I want to record undo history for the script writer. I am going
|
|
# to ignore the letters. And only forcus on other simbols such as
|
|
# spacebars and various commands.
|
|
|
|
nonhistory = "1234567890qwertyuiopasdfghjklzxcvbnnmQWERTYUIOPASDFGHJKLZXCVBNM"
|
|
|
|
if win.current["key_letter"] not in nonhistory and ORD not in [26, 25]:
|
|
story.undo_record(win)
|
|
# Multiuser sycning
|
|
win.multiuser["request"] = "story"
|
|
|
|
# Now let's retrive out data.
|
|
|
|
# UNDO
|
|
if ORD == 26:
|
|
story.undo(win)
|
|
|
|
# REDO
|
|
if ORD == 25:
|
|
story.redo(win)
|
|
|
|
|
|
if u == 0:
|
|
|
|
if ORD not in range(32) or ORD in range(127, 160):
|
|
|
|
# Typing logic
|
|
|
|
part[-1] = \
|
|
part[-1][:MIN]+\
|
|
win.current["key_letter"]+\
|
|
part[-1][MAX:]
|
|
|
|
def clean():
|
|
pointer[0] = pointer[0] + 1
|
|
pointer[1] = pointer[0]
|
|
point = point + 1
|
|
|
|
if ORD == 22: # Paste ( Ctrl - V )
|
|
|
|
cliptext = str(clipboard.wait_for_text())
|
|
|
|
part[-1] = \
|
|
part[-1][:MIN]+\
|
|
cliptext+\
|
|
part[-1][MAX:]
|
|
|
|
def clean():
|
|
pointer[0] = pointer[0] + len(cliptext)
|
|
pointer[1] = pointer[0]
|
|
|
|
point = point + len(cliptext)
|
|
|
|
if ORD == 3: # Copy ( Ctrl - C )
|
|
|
|
clipboard.set_text( part[-1][MIN:MAX] , -1) # VERY BASIC
|
|
|
|
# If ord 13 it means you pressed enter. And it should be a new line.
|
|
# but for some reason it's ord 13. Maybe it is a new line. Who knows
|
|
# Anyway. It does not return \n but returns a weird rectangle. So
|
|
# here is a little solution.
|
|
|
|
if ORD == 13: # ENTER
|
|
|
|
# Only I want to use new line to exit from all kind of things.
|
|
# Like double enter will exit the frase. Ans stuff like this.
|
|
|
|
if part[-1][MIN-1] == "\n" and part[0] != "text":
|
|
|
|
block[-1].insert(n+1,
|
|
["text", "\n"]
|
|
)
|
|
block[-1].insert(n+2,
|
|
["text", part[-1][MAX:]+" "]
|
|
)
|
|
|
|
part[-1] = \
|
|
part[-1][:MIN-1]
|
|
|
|
else:
|
|
part[-1] = \
|
|
part[-1][:MIN]+\
|
|
"\n"+\
|
|
part[-1][MAX:]
|
|
|
|
def clean():
|
|
pointer[0] = pointer[0] + 1
|
|
pointer[1] = pointer[0]
|
|
point = point + 1
|
|
|
|
if ORD == 4: # CTRL D ( FOR SOME REASON)
|
|
|
|
block[-1].insert(n+1,
|
|
["frase", ["text", " "], " "]
|
|
)
|
|
block[-1].insert(n+2,
|
|
["text", part[-1][MAX:]]
|
|
)
|
|
|
|
part[-1] = \
|
|
part[-1][:MIN]
|
|
def clean():
|
|
pointer[0] = pointer[0] + 1
|
|
pointer[1] = pointer[0]
|
|
point = point + 1
|
|
|
|
# Activating the editing of the name automatically
|
|
if "current_name_frase_editing" in win.text:
|
|
win.text["current_name_frase_editing"]["text"] = ""
|
|
if "current_name_frase_editing" not in win.current:
|
|
win.current["current_name_frase_editing"] = False
|
|
win.current["current_name_frase_editing"] = [num, n+1]
|
|
win.textactive = "current_name_frase_editing"
|
|
|
|
if ORD == 8: # BACKSPACE
|
|
if pointer[1] == pointer[0]:
|
|
part[-1] = \
|
|
part[-1][:MIN-1]+\
|
|
part[-1][MAX:]
|
|
def clean():
|
|
pointer[0] = pointer[0] - 1
|
|
pointer[1] = pointer[0]
|
|
point = point - 1
|
|
else:
|
|
part[-1] = \
|
|
part[-1][:MIN]+\
|
|
part[-1][MAX:]
|
|
def clean():
|
|
pointer[0] = min(pointer[0], pointer[1])
|
|
pointer[1] = pointer[0]
|
|
|
|
if ORD == 127: # DELETE (FORWARD)
|
|
part[-1] = \
|
|
part[-1][:MIN]+\
|
|
part[-1][MAX+1:]
|
|
def clean():
|
|
pointer[0] = pointer[0]
|
|
pointer[1] = pointer[0]
|
|
|
|
if ORD == 19: # NEW SHOT ( CTRL - S )
|
|
app = part.copy()
|
|
app[-1] = part[-1][MIN:MAX]
|
|
new_shot_list.append(app)
|
|
new_shot = [num , n]
|
|
|
|
after_shot_list = block.copy()
|
|
after_shot_list[-1] = []
|
|
|
|
app2 = part.copy()
|
|
app2[-1] = part[-1][MAX:]
|
|
after_shot_list[-1].append(app2)
|
|
|
|
part[-1] = part[-1][:MIN]
|
|
|
|
if ORD == 12 and part[0] == "text" and pointer[1] != pointer[0]: # Asset higlight
|
|
|
|
if "linking_asset_operation_metadata" not in win.current:
|
|
win.current["linking_asset_operation_metadata"] = []
|
|
|
|
win.current["linking_asset_operation_metadata"] = [part , block, MIN, MAX]
|
|
|
|
def after(win, var):
|
|
print(var)
|
|
if var:
|
|
|
|
part , block, MIN, MAX = win.current["linking_asset_operation_metadata"]
|
|
|
|
block[-1].insert(n+1,
|
|
["link", var, part[-1][MIN:MAX]]
|
|
)
|
|
block[-1].insert(n+2,
|
|
["text", part[-1][MAX:]]
|
|
)
|
|
|
|
part[-1] = \
|
|
part[-1][:MIN]
|
|
win.current["key_letter"] = ""
|
|
|
|
studio_dialogs.asset_select(win, "link_asset_script_frase", after,
|
|
SEARCH=part[-1][MIN:MAX])
|
|
|
|
if ORD == 9 and part[0] == "text" and pointer[1] == pointer[0]: # Insert image
|
|
|
|
if "linking_asset_operation_metadata" not in win.current:
|
|
win.current["linking_asset_operation_metadata"] = []
|
|
|
|
win.current["linking_asset_operation_metadata"] = [part , block, MIN, MAX]
|
|
|
|
def after(win, var):
|
|
print(var)
|
|
if var:
|
|
|
|
part , block, MIN, MAX = win.current["linking_asset_operation_metadata"]
|
|
|
|
block[-1].insert(n+1,
|
|
["image", var]
|
|
)
|
|
block[-1].insert(n+2,
|
|
["text", part[-1][MAX:]]
|
|
)
|
|
|
|
part[-1] = \
|
|
part[-1][:MIN]
|
|
win.current["key_letter"] = ""
|
|
|
|
studio_dialogs.file_select(win, "link_asset_script_frase", after,
|
|
SEARCH=part[-1][MIN:MAX])
|
|
|
|
|
|
|
|
# Making stuff happen
|
|
elif u < len(selecwords)-1:
|
|
if ORD not in [12, 19, 3, 22, 26, 25]: # 3 = Crtl - C, 22 = Ctrl - V
|
|
part[-1] = ""
|
|
|
|
if ORD == 19:
|
|
app = part.copy()
|
|
new_shot_list.append(app)
|
|
|
|
part[-1] = ""
|
|
|
|
else:
|
|
|
|
MIN = min(len(part[-1])-1, max(0, min(pointer[1], pointer[0])-p))
|
|
MAX = max(0, min(len(part[-1])-1, max(pointer[1], pointer[0])-p))
|
|
|
|
if ORD not in [12, 19, 3, 22, 26, 25]:
|
|
part[-1] = part[-1][MAX:]
|
|
|
|
if ORD == 19:
|
|
app = part.copy()
|
|
app[-1] = part[-1][MIN:]
|
|
new_shot_list.append(app)
|
|
|
|
|
|
part[-1] = ""
|
|
|
|
# Saving to the file
|
|
story.save(win.project, win.story)
|
|
win.current["key_letter"] = ""
|
|
|
|
# Let's get all the rest of the parts from that block so I could insert them
|
|
# as a separate thing later. Because we basically splitting 1 block into 3
|
|
# making the selection. Middle one our new shot_block. And the rest. Should
|
|
# stay the same.
|
|
|
|
if new_shot:
|
|
num , n = new_shot
|
|
for l, part in enumerate(win.story["scenes"][scene]["shots"][num][-1]):
|
|
if l > n:
|
|
app = part.copy()
|
|
after_shot_list[-1].append(app)
|
|
part[-1] = ""
|
|
if after_shot_list[0] == "shot_block"\
|
|
and win.story["scenes"][scene]["shots"][num][0] == "shot_block":
|
|
after_shot_list[1] = win.story["scenes"][scene]["shots"][num][1]
|
|
|
|
if new_shot_list:
|
|
|
|
#print("NEW: ", new_shot_list)
|
|
#print("KEEP: ", after_shot_list)
|
|
|
|
nename = "Shot_1"
|
|
count = 1
|
|
while nename in shot_list:
|
|
count = count + 1
|
|
nename = "Shot_"+str(count)
|
|
|
|
|
|
num , n = new_shot
|
|
win.story["scenes"][scene]["shots"].insert(num+1,
|
|
["shot_block", nename, new_shot_list])
|
|
|
|
win.story["scenes"][scene]["shots"].insert(num+2,
|
|
after_shot_list)
|
|
|
|
# Saving to the file
|
|
story.save(win.project, win.story)
|
|
|
|
#print()
|
|
#print("------{ AFTER }--------")
|
|
#print(win.story["scenes"][scene]["shots"])
|
|
#print("------{ }------")
|
|
|
|
clean()
|
|
|
|
current_Y = current_Y + 30
|
|
|
|
|
|
|
|
|
|
if scene not in win.story["pointers"]:
|
|
pointer = [point, point]
|
|
win.story["pointers"][scene] = pointer
|
|
else:
|
|
pointer[0] = min(pointer[0], point)
|
|
pointer[1] = min(pointer[1], point)
|
|
pointer[0] = max(pointer[0], 1)
|
|
pointer[1] = max(pointer[1], 1)
|
|
win.story["pointers"][scene] = pointer
|
|
|
|
# Selecting the shot
|
|
if win.current["script_shot_higlight"] and win.previous["LMB"] and not win.current["LMB"]:
|
|
win.cur = "/"+scene+"/"+win.current["script_shot_higlight"]
|
|
# Going to that asset
|
|
|
|
if win.current["script_asset_higlight"] and win.previous["LMB"] and not win.current["LMB"]:
|
|
try:
|
|
del win.text["scene_name"]
|
|
win.previous["script_asset_higlight"]
|
|
win.url = "assets"
|
|
win.cur = win.current["script_asset_higlight"]
|
|
win.current["asset_scene_selected"] = scene
|
|
win.current["asset_left_panel"] = "scene"
|
|
del win.current["script_asset_higlight"]
|
|
# Saving to the file
|
|
story.save(win.project, win.story)
|
|
except:
|
|
pass
|
|
|
|
|
|
|
|
|
|
###########################
|
|
|
|
# And finally combine the layers
|
|
|
|
# Outputting the layer
|
|
layer.set_source_surface(frasesurface, x, y)
|
|
layer.paint()
|
|
|
|
# Outputting the layer
|
|
layer.set_source_surface(shotsurface, x, y)
|
|
layer.paint()
|
|
|
|
# Outputting the layer
|
|
layer.set_source_surface(assetsurface, x, y)
|
|
layer.paint()
|
|
|
|
# Outputting the layer
|
|
layer.set_source_surface(textsurface, x, y)
|
|
layer.paint()
|
|
|
|
# Scroll
|
|
UI_elements.scroll_area(layer, win, "script",
|
|
x+0,
|
|
y+0,
|
|
width+30,
|
|
height-0,
|
|
current_Y,
|
|
bar=True,
|
|
mmb=True,
|
|
bar_always=True)
|
|
|
|
####### BOTTOM PANEL #########
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/4,
|
|
win.current["h"]-50,
|
|
win.current["w"]/2,
|
|
40,
|
|
10)
|
|
|
|
# Documentation entry
|
|
def do():
|
|
def after(win, var):
|
|
pass
|
|
|
|
studio_dialogs.help(win, "help", after, SEARCH=talk.text("documentation_script_writer"))
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/4,
|
|
win.current["h"]-50,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"question")
|
|
|
|
# Here in the bottom I want to introduce little things to go between scenes
|
|
# back and forth.
|
|
|
|
left = ""
|
|
right = ""
|
|
|
|
for arrow in win.story["arrows"]:
|
|
if arrow[0][1] == scene and arrow[1] != "end":
|
|
right = arrow[1][1]
|
|
if arrow[1][1] == scene and arrow[0] != "start":
|
|
left = arrow[0][1]
|
|
|
|
|
|
if left:
|
|
def do():
|
|
win.scroll["script"] = 0
|
|
win.cur = "/"+left
|
|
win.url = "script"
|
|
try:
|
|
del win.text["scene_name"]
|
|
except:
|
|
pass
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/2-45,
|
|
win.current["h"]-50,
|
|
40,
|
|
40,
|
|
10,
|
|
button=do,
|
|
icon="left")
|
|
|
|
if right:
|
|
def do():
|
|
win.scroll["script"] = 0
|
|
win.cur = "/"+right
|
|
win.url = "script"
|
|
try:
|
|
del win.text["scene_name"]
|
|
except:
|
|
pass
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]/2+5,
|
|
win.current["h"]-50,
|
|
40,
|
|
40,
|
|
10,
|
|
button=do,
|
|
icon="right")
|
|
|
|
|
|
# CANCEl
|
|
|
|
def do():
|
|
win.url = "story_editor"
|
|
win.assets = {}
|
|
try:
|
|
del win.text["scene_name"]
|
|
except:
|
|
pass
|
|
win.story["selected"] = []
|
|
win.scroll["script"] = 0
|
|
win.current["scene_edited_already"] = False
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
win.current["w"]-40-win.current["w"]/4,
|
|
win.current["h"]-50,
|
|
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()
|
|
|
|
############# CHECKLIST #################
|
|
|
|
# Here I want to have some checklists. Now... I have 4 types of new check-
|
|
# lists prepared for shots and scene. There are 3 types of checklists for
|
|
# a shot. So I can't just simply generate one on the fly. Since I don't
|
|
# know whether this shot is a simple shot, animated or VFX. And also I
|
|
# don't want to generate folders when they are not nessesary. So I want to
|
|
# implement a kind of selection thingy when if a checklists does not exist.
|
|
|
|
# Now let's first of all display our checklists properly.
|
|
|
|
if os.path.exists(win.project+"/rnd"+win.cur+"/shot.progress"):
|
|
checklist.draw(layer, win, win.project+"/rnd"+win.cur+"/shot.progress", back=win.url)
|
|
elif os.path.exists(win.project+"/rnd"+win.cur+"/scene.progress") and not shot:
|
|
checklist.draw(layer, win, win.project+"/rnd"+win.cur+"/scene.progress", back=win.url)
|
|
|
|
else:
|
|
|
|
# Now if we have no checklist what so ever. We want to give user a way
|
|
# to choose to generate one.
|
|
|
|
x = win.current["w"] / 4 * 3 + 10
|
|
y = 10
|
|
width = win.current["w"] / 4 - 20
|
|
height = win.current["h"] - 20
|
|
|
|
|
|
if shot:
|
|
|
|
# If we are in a shot I want to give different option to choose from
|
|
# then if we are just simply in a scene.
|
|
|
|
shot_options = {
|
|
"shot":"add_shot_live_checklist",
|
|
"shot_anim":"add_shot_anim_checklist", # First name of new_file then text on screen
|
|
"shot_vfx":"add_shot_vfx_checklist"
|
|
}
|
|
|
|
for num, option in enumerate(shot_options):
|
|
|
|
# We want to draw a button, a rectangle arround it and the text
|
|
# tooltip.
|
|
|
|
def do():
|
|
|
|
# First let's make sure that the folder exists. Because
|
|
# it might not exists. I think doing it automatically
|
|
# makes sense.
|
|
|
|
try:
|
|
os.makedirs(win.project+"/rnd"+win.cur)
|
|
except:
|
|
pass
|
|
|
|
# Then we copy the file.
|
|
|
|
oscalls.copy_file(
|
|
win,
|
|
os.getcwd()+"/new_file/"+option+".progress",
|
|
"/rnd"+win.cur+"/",
|
|
"shot.progress")
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x,
|
|
y+(50*num),
|
|
width,
|
|
40,
|
|
10,
|
|
button=do,
|
|
icon="checklist_new")
|
|
|
|
UI_color.set(layer, win, "progress_background")
|
|
UI_elements.roundrect(layer, win,
|
|
x,
|
|
y+(50*num),
|
|
width,
|
|
40,
|
|
10,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
UI_color.set(layer, win, "text_normal")
|
|
layer.set_font_size(20)
|
|
layer.move_to( x+50, y+(50*num)+25)
|
|
layer.show_text(talk.text(shot_options[option]))
|
|
|
|
else:
|
|
|
|
# Now... If it's not a shot. We can do it in one line.
|
|
# It's pretty simple.
|
|
|
|
def do():
|
|
|
|
# First let's make sure that the folder exists. Because
|
|
# it might not exists. I think doing it automatically
|
|
# makes sense.
|
|
|
|
try:
|
|
os.makedirs(win.project+"/rnd"+win.cur)
|
|
except:
|
|
pass
|
|
|
|
# Then we copy the file.
|
|
|
|
oscalls.copy_file(
|
|
win,
|
|
os.getcwd()+"/new_file/scene.progress",
|
|
"/rnd"+win.cur+"/",
|
|
"scene.progress")
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x,
|
|
y,
|
|
width,
|
|
40,
|
|
10,
|
|
button=do,
|
|
icon="checklist_new")
|
|
|
|
UI_color.set(layer, win, "progress_background")
|
|
UI_elements.roundrect(layer, win,
|
|
x,
|
|
y,
|
|
width,
|
|
40,
|
|
10,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
UI_color.set(layer, win, "text_normal")
|
|
layer.set_font_size(20)
|
|
layer.move_to( x+50, y+25)
|
|
layer.show_text(talk.text("add_scene_checklist"))
|
|
|
|
|
|
############## LEFT PANEL #####################
|
|
|
|
leftpanellist = ["shot", "schedule", "history"] # Using the names of the icons.
|
|
|
|
# We need to choose the correct category based smartly on the project's
|
|
# current progress. Or at least on the current progress of this asset.
|
|
|
|
if "script_left_panel" not in win.current:
|
|
|
|
win.current["script_left_panel"] = "shot"
|
|
|
|
# A little banner.
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
UI_elements.roundrect(layer, win,
|
|
10,
|
|
10,
|
|
win.current["w"]/4-20,
|
|
50,
|
|
10)
|
|
|
|
for num, thing in enumerate(leftpanellist):
|
|
if win.current["script_left_panel"] == thing:
|
|
|
|
UI_color.set(layer, win, "progress_time")
|
|
UI_elements.roundrect(layer, win,
|
|
20+(40*num),
|
|
15,
|
|
40,
|
|
40,
|
|
10)
|
|
|
|
def do():
|
|
win.current["script_left_panel"] = thing
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
20+(40*num),
|
|
15,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
thing)
|
|
|
|
### SCHEDULES ###
|
|
|
|
if win.current["script_left_panel"] == "schedule":
|
|
schedule.draw(layer, win)
|
|
|
|
### HISTORY ###
|
|
|
|
if win.current["script_left_panel"] == "history":
|
|
history.draw(layer, win)
|
|
|
|
|
|
#### SHOTS ####
|
|
|
|
if win.current["script_left_panel"] == "shot":
|
|
|
|
# Here I want to draw the left panel full of shots and stuff. So you
|
|
# could access the animation Blend-Files, render them and see analytics
|
|
# or rendering.
|
|
|
|
# Since it's the last thing I'm drawing to this layer. I guess we can clip it.
|
|
|
|
x = 10
|
|
y = 70
|
|
width = win.current["w"] / 4 - 20
|
|
height = win.current["h"] - 80
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
10,
|
|
fill=False)
|
|
layer.clip()
|
|
|
|
|
|
if "script_shots" not in win.scroll:
|
|
win.scroll["script_shots"] = 0
|
|
|
|
current_Y_shots = 0
|
|
|
|
rcolors = [
|
|
"shot_1",
|
|
"shot_2",
|
|
"shot_3",
|
|
"shot_4",
|
|
"shot_5"
|
|
]
|
|
|
|
# So let's itterate over a lit of shots we've got from the textview.
|
|
|
|
for shotis in shot_list:
|
|
|
|
# Getting the color. It's not always works.
|
|
|
|
if "shot_colors" not in win.story:
|
|
win.story["shot_colors"] = {}
|
|
|
|
surl = "/"+scene+"/"+shotis
|
|
|
|
if surl not in win.story["shot_colors"]:
|
|
|
|
win.story["shot_colors"][surl] = rcolors[len(win.story["shot_colors"]) % len(rcolors)]
|
|
|
|
col = win.story["shot_colors"][surl]
|
|
|
|
UI_color.set(layer, win, "node_background")
|
|
UI_elements.roundrect(layer, win,
|
|
x,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
width,
|
|
50,
|
|
10)
|
|
UI_color.set(layer, win, col)
|
|
UI_elements.roundrect(layer, win,
|
|
x+60,
|
|
y+win.scroll["script_shots"]+current_Y_shots+15,
|
|
10,
|
|
10,
|
|
10)
|
|
|
|
# SHOT NAME
|
|
UI_color.set(layer, win, "text_normal")
|
|
layer.set_font_size(20)
|
|
layer.move_to( x+90, y+win.scroll["script_shots"] + current_Y_shots+30)
|
|
layer.show_text(shotis)
|
|
|
|
# ICON
|
|
UI_elements.image(layer, win,
|
|
"settings/themes/"+win.settings["Theme"]+"/icons/shot.png",
|
|
20, y+win.scroll["script_shots"] + current_Y_shots+5, 40, 40)
|
|
|
|
# The selection will be badically the current win.cur value. SO...
|
|
|
|
if surl == win.cur:
|
|
|
|
UI_color.set(layer, win, "text_normal")
|
|
UI_elements.roundrect(layer, win,
|
|
x,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
width,
|
|
50,
|
|
10,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
# If this shot has a folder already. Unfortunatly it's not wise
|
|
# to make it editable. But I already talk about it in the
|
|
# beggining of this file.
|
|
|
|
# But a folder button could be cool.
|
|
|
|
if os.path.exists(win.project+"/rnd"+win.cur):
|
|
def do():
|
|
oscalls.Open(win.project+"/rnd"+win.cur)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
width-45,
|
|
y+win.scroll["script_shots"]+current_Y_shots+5,
|
|
40,
|
|
40,
|
|
10,
|
|
do,
|
|
"folder",
|
|
tip="/rnd"+win.cur )
|
|
else:
|
|
|
|
# If there is no folder I want to give people an ability
|
|
# to edit it. I think let's do it like with checklists.
|
|
# like a little second button. That if you click it. You
|
|
# create a text entry. I know. Quite a lot of text entries.
|
|
# There will be more.
|
|
|
|
if "current_shot_name_editor" not in win.current:
|
|
win.current["current_shot_name_editor"] = ""
|
|
|
|
|
|
# Now if the button is clicked. There will be an editor
|
|
# let's make one.
|
|
|
|
if win.current["current_shot_name_editor"] == shotis and win.textactive == "shot_name":
|
|
|
|
UI_elements.text(layer, win, "shot_name",
|
|
x+85,
|
|
y+win.scroll["script_shots"]+current_Y_shots+5,
|
|
width-90,
|
|
40,
|
|
set_text=shotis)
|
|
|
|
# Now let's make it applyable. But first we need to filter
|
|
# the name. So there will not be any weird stuff. So the
|
|
# folder when it's created will not make problems.
|
|
|
|
newname = win.text["shot_name"]["text"].replace("/","_").replace(" ", "_")\
|
|
.replace('"',"_").replace("(","_").replace(")","_").replace("'","_")\
|
|
.replace("[","_").replace("]","_").replace("{","_").replace("}","_")
|
|
|
|
if newname not in shot_list:
|
|
|
|
def do():
|
|
win.current["key_letter"] = ""
|
|
|
|
shot_list[shotis][1] = newname
|
|
win.cur = "/"+scene+"/"+newname
|
|
|
|
# Saving to the file
|
|
story.save(win.project, win.story)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
width-45,
|
|
y+win.scroll["script_shots"]+current_Y_shots+5,
|
|
40,
|
|
40,
|
|
10,
|
|
button=do,
|
|
icon="ok")
|
|
|
|
else:
|
|
|
|
# A button to activate the editing I guess.
|
|
|
|
def do():
|
|
win.current["current_shot_name_editor"] = shotis
|
|
try:
|
|
del win.text["shot_name"]
|
|
except:
|
|
pass
|
|
|
|
win.textactive = "shot_name"
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x+85,
|
|
y+win.scroll["script_shots"]+current_Y_shots+5,
|
|
width-90,
|
|
40,
|
|
10,
|
|
button=do,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
|
|
current_Y_shots = current_Y_shots + 60
|
|
|
|
# Let's make the color selectiong thing. Because I know people
|
|
# gonna eat me alive if the software does everything for them.
|
|
# Especially when it's something that customazible.
|
|
|
|
for num, col in enumerate(rcolors):
|
|
|
|
if win.story["shot_colors"][surl] == col:
|
|
|
|
# If the current color is the color of the shot then
|
|
# let's draw a little white thing around it.
|
|
|
|
UI_color.set(layer, win, "text_normal")
|
|
UI_elements.roundrect(layer, win,
|
|
x+(width/len(rcolors)*num),
|
|
y+win.scroll["script_shots"]+current_Y_shots-2,
|
|
width/len(rcolors),
|
|
10,
|
|
12)
|
|
|
|
UI_color.set(layer, win, col)
|
|
UI_elements.roundrect(layer, win,
|
|
x+(width/len(rcolors)*num)+2,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
width/len(rcolors)-4,
|
|
10,
|
|
10)
|
|
|
|
# Also let's make a button that the user can click to change
|
|
# the color.
|
|
|
|
def do():
|
|
win.story["shot_colors"][surl] = col
|
|
UI_elements.roundrect(layer, win,
|
|
x+(width/len(rcolors)*num),
|
|
y+win.scroll["script_shots"]+current_Y_shots-2,
|
|
width/len(rcolors),
|
|
20,
|
|
12,
|
|
button=do,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
current_Y_shots = current_Y_shots + 30
|
|
|
|
# Now let's draw 4 main folders of the shot.
|
|
|
|
# storyboard
|
|
# opengl
|
|
# test_rnd
|
|
# rendered
|
|
|
|
# There is also an extra folder created always.
|
|
# but since it's very technical let's not include it here.
|
|
# let's focus on those 4 because for the user these 4 will
|
|
# be our progress bar.
|
|
|
|
##### ##### ##### #####
|
|
########## ######### ########## ######## ##########
|
|
##### ##### ##### #####
|
|
|
|
# Like 4 links in a chain or something. I think it's a good
|
|
# representation.
|
|
|
|
fouricons = {
|
|
"storyboard":[],
|
|
"opengl":[],
|
|
"test_rnd":[],
|
|
"rendered":[]
|
|
}
|
|
|
|
fraction = 0.0
|
|
|
|
# Let's create a variable for the current selected folder.
|
|
|
|
if shotis+"_active_folder" not in win.current:
|
|
win.current[shotis+"_active_folder"] = "Pending"
|
|
|
|
for numb, icon in enumerate(fouricons):
|
|
|
|
# While we are drawing them. Let's find out whether there
|
|
# are any images inside. If yes. We add this to the over
|
|
# all percentage.
|
|
|
|
files = []
|
|
try:
|
|
files = sorted(os.listdir(win.project+"/rnd"+win.cur+"/"+icon))
|
|
except:
|
|
pass
|
|
|
|
fouricons[icon] = files
|
|
|
|
if files:
|
|
fraction = 0.25*(numb+1)
|
|
|
|
# If the icon is currently selected.
|
|
|
|
if win.current[shotis+"_active_folder"] == icon:
|
|
UI_color.set(layer, win, "progress_time")
|
|
UI_elements.roundrect(layer, win,
|
|
x+(width/5)*numb+(width/10)+20,
|
|
y+win.scroll["script_shots"]+current_Y_shots-2,
|
|
40,
|
|
40,
|
|
20)
|
|
|
|
def do():
|
|
win.current[shotis+"_active_folder"] = icon
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x+(width/5)*numb+(width/10)+20,
|
|
y+win.scroll["script_shots"]+current_Y_shots-2,
|
|
40,
|
|
40,
|
|
20,
|
|
button=do,
|
|
icon=icon,
|
|
tip=icon)
|
|
|
|
|
|
current_Y_shots = current_Y_shots + 50
|
|
|
|
# Let's find out which one is going to be selected.
|
|
|
|
if win.current[shotis+"_active_folder"] == "Pending":
|
|
if fouricons["rendered"]:
|
|
win.current[shotis+"_active_folder"] = "rendered"
|
|
elif fouricons["test_rnd"]:
|
|
win.current[shotis+"_active_folder"] = "test_rnd"
|
|
elif fouricons["opengl"]:
|
|
win.current[shotis+"_active_folder"] = "opengl"
|
|
else:
|
|
win.current[shotis+"_active_folder"] = "storyboard"
|
|
|
|
|
|
# Now let's draw a line that will act almost like a progress
|
|
# bar of a kind.
|
|
|
|
# It will be made of 4 circles stading on a line.
|
|
|
|
UI_color.set(layer, win, "progress_background")
|
|
UI_elements.roundrect(layer, win,
|
|
x+20,
|
|
y+win.scroll["script_shots"]+current_Y_shots-2,
|
|
width-40,
|
|
0,
|
|
5)
|
|
|
|
UI_color.set(layer, win, "progress_active")
|
|
UI_elements.roundrect(layer, win,
|
|
x+20,
|
|
y+win.scroll["script_shots"]+current_Y_shots-2,
|
|
(width-40)*fraction,
|
|
0,
|
|
5)
|
|
|
|
# Now the 4 circles.
|
|
|
|
for numb, icon in enumerate(fouricons):
|
|
|
|
|
|
UI_color.set(layer, win, "progress_background")
|
|
if fouricons[icon]: # If this folder has any files.
|
|
UI_color.set(layer, win, "progress_active")
|
|
UI_elements.roundrect(layer, win,
|
|
x+(width/5)*numb+(width/10)+30,
|
|
y+win.scroll["script_shots"]+current_Y_shots-7,
|
|
0,
|
|
0,
|
|
10)
|
|
|
|
current_Y_shots = current_Y_shots + 50
|
|
|
|
# Now after we have the progress bar / selection type thingy.
|
|
# let's do a preview of the render. Usually. When rendering
|
|
# using Blender-Organizer legacy ( or blender console ) it makes
|
|
# files like 0001.png, 0002.png, 0003.png and so on. Now
|
|
# user might any type of stuff in that folder. And I don't want
|
|
# a broken program if stuff like this happens. So.
|
|
|
|
if shotis+"_active_folder_item" not in win.current:
|
|
win.current[shotis+"_active_folder_item"] = 0
|
|
|
|
# Making sure that we never going to select something beyond selectable.
|
|
if win.current[shotis+"_active_folder_item"] > len(fouricons[win.current[shotis+"_active_folder"]])-1:
|
|
win.current[shotis+"_active_folder_item"] = len(fouricons[win.current[shotis+"_active_folder"]])-1
|
|
|
|
|
|
# This will be the user selected file inside the folder.
|
|
|
|
|
|
# The frame. In case image fails to load.
|
|
|
|
UI_color.set(layer, win, "progress_background")
|
|
UI_elements.roundrect(layer, win,
|
|
x+5,
|
|
y+win.scroll["script_shots"]+current_Y_shots-7,
|
|
width-10,
|
|
200,
|
|
10,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
# Image it self.
|
|
if fouricons[win.current[shotis+"_active_folder"]]:
|
|
|
|
imageurl = win.project+"/rnd"+win.cur+"/"+win.current[shotis+"_active_folder"]+"/"+fouricons[win.current[shotis+"_active_folder"]][win.current[shotis+"_active_folder_item"]]
|
|
|
|
UI_elements.image(layer, win,
|
|
imageurl,
|
|
x+10,
|
|
y+win.scroll["script_shots"]+current_Y_shots-2,
|
|
int(width-20),
|
|
int(190),
|
|
cell="shot_renders")
|
|
|
|
# Well how to live without a clickable openable thingy.
|
|
|
|
def do():
|
|
oscalls.file_open(win, imageurl)
|
|
UI_elements.roundrect(layer, win,
|
|
x+5,
|
|
y+win.scroll["script_shots"]+current_Y_shots-7,
|
|
width-10,
|
|
200,
|
|
10,
|
|
button=do,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
|
|
current_Y_shots = current_Y_shots + 210
|
|
|
|
# After we drew our image. Let's draw a little timeline thing.
|
|
# so the user could select which frame from the animation they
|
|
# want to see. Basically a little bar. I guess. IDK. Like
|
|
# Blender's timeline I guess. But later I will draw a time
|
|
# graph on it. So it's not as simple as that.
|
|
|
|
UI_color.set(layer, win, "dark_overdrop")
|
|
layer.rectangle(
|
|
x+5,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
width-10,
|
|
100)
|
|
layer.fill()
|
|
|
|
numofis = len(fouricons[win.current[shotis+"_active_folder"]])
|
|
|
|
# Here as you can see I made the the rectangle a 100 pixels high
|
|
# this is for 1 simple reason. To be able to draw analytics.
|
|
|
|
# But.
|
|
|
|
# There are like one million problems with it. Let's go over them.
|
|
|
|
# * There are multiple blend files each one with analytics data.
|
|
|
|
# * Reading JSON files and drawing graphs is not a trivial thing
|
|
# requiring cashing of the image. Such as in Analytics window.
|
|
# Bull will see.
|
|
|
|
# * During rendeing the DATA changes. And I want to see the up
|
|
# to date data at all times.
|
|
|
|
# Let's try to implement it the simple way. Reading everything
|
|
# live. I've done that in Blender-Organizer. But the data was
|
|
# way simpler.
|
|
|
|
alldata = {}
|
|
largest = 1
|
|
|
|
# WAIT extra might not exists.
|
|
|
|
try:
|
|
for filename in os.listdir(win.project+"/rnd"+win.cur+"/extra"):
|
|
if filename.endswith(".blend.json"):
|
|
|
|
# I want to now open JSON FILE for each one and parse
|
|
# it. Actually when I think about it. It's not supposed
|
|
# to be that bad. But this computer has an SSD. LOL.
|
|
|
|
data = {}
|
|
try:
|
|
with open(win.project+"/rnd"+win.cur+"/extra/"+filename) as json_file:
|
|
data = json.load(json_file)
|
|
|
|
# Since I'm inside try I can do some wild stuff here.
|
|
data = data["analytics"][win.current[shotis+"_active_folder"]]
|
|
|
|
alldata[filename.replace(".json", "")] = data
|
|
|
|
for i in data:
|
|
if data[i] > largest:
|
|
largest = data[i]
|
|
|
|
except:
|
|
pass
|
|
except:
|
|
pass
|
|
|
|
# So let's now read through all the data that we have
|
|
for n, blend in enumerate(alldata):
|
|
|
|
data = alldata[blend]
|
|
|
|
# I want each new file to have it's own color. So
|
|
|
|
UI_color.set(layer, win, rcolors[n % len(rcolors)])
|
|
layer.move_to(
|
|
x+5,
|
|
y+win.scroll["script_shots"]+current_Y_shots+100
|
|
)
|
|
|
|
# Now let's draw everything.
|
|
for numb, fil in enumerate(fouricons[win.current[shotis+"_active_folder"]]):
|
|
|
|
if str(numb+1) in data:
|
|
layer.line_to(
|
|
x+5+(width-10)/numofis*(numb+0.5),
|
|
(y+win.scroll["script_shots"]+current_Y_shots+100)-(100/largest*data[str(numb+1)])
|
|
)
|
|
layer.stroke()
|
|
|
|
# Funny that it didn't really stuck too much like this. Please
|
|
# let me know if on your machine this way of doing it is hell
|
|
# a slow.
|
|
|
|
for numb, fil in enumerate(fouricons[win.current[shotis+"_active_folder"]]):
|
|
|
|
|
|
# Here I'm going to put some logic. That will enable me to
|
|
# scroll trough the images. In a way that allows me to
|
|
# preview the animation. Simple button wouldn't work since
|
|
# it's waiting for the user to release the button to be
|
|
# activated. This one will be activated by just dragging
|
|
# across.
|
|
|
|
# Also my roundrect buttons are not ideal when you have little
|
|
# space and 10000 frames.
|
|
|
|
fill = False
|
|
|
|
if int(win.current["mx"]) in range(int(x+5+(width-10)/numofis*numb),int(x+5+(width-10)/numofis*numb+(width-10)/numofis))\
|
|
and int(win.current["my"]) in range(int(y+win.scroll["script_shots"]+current_Y_shots), int(y+win.scroll["script_shots"]+current_Y_shots+100)):
|
|
|
|
# Before we are doing the logic. I want to give user a
|
|
# tooltip about render analytics. So let's do this.
|
|
|
|
tip = ""
|
|
for n, blend in enumerate(alldata):
|
|
data = alldata[blend]
|
|
if str(numb+1) in data:
|
|
tip = tip + blend+" "+UI_math.timestring(data[str(numb+1)]/1000000)+"\n"
|
|
if tip:
|
|
tip = tip[:-1] # Removing the last \n
|
|
UI_elements.tooltip(win, tip)
|
|
|
|
# Now let's do the fill and other stuff
|
|
|
|
fill = True
|
|
|
|
if win.current["LMB"]:
|
|
|
|
win.current[shotis+"_active_folder_item"] = numb
|
|
|
|
if fill or win.current[shotis+"_active_folder_item"] == numb:
|
|
|
|
UI_color.set(layer, win, "progress_time")
|
|
layer.rectangle(
|
|
x+5+(width-10)/numofis*numb,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
(width-10)/numofis,
|
|
100)
|
|
layer.fill()
|
|
|
|
|
|
current_Y_shots = current_Y_shots + 110
|
|
|
|
# Okay let's put blend file from the shot. So you could actually
|
|
# do work on it.
|
|
|
|
# But first. I want to add a seach promt. So I could add new ones
|
|
# the same way I do it in any other window. By searching. I think
|
|
# it's important to keep the workflow similar.
|
|
|
|
# I think that if we have no blend files at all. It might give you
|
|
# to make a new one with the name of the shot. And all the rest will
|
|
# be done by searching. Yeah. Makes sense. Wait. I can put the name of
|
|
# the shot in the search. Hm... Okay. Let's make the seach icon first.
|
|
|
|
UI_elements.image(layer, win,
|
|
"settings/themes/"+win.settings["Theme"]+"/icons/search.png",
|
|
x+10,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
40,
|
|
40)
|
|
|
|
# Now beside it will be out text entry.
|
|
|
|
UI_elements.text(layer, win, "shot_search",
|
|
x+50,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
width-55,
|
|
40)
|
|
|
|
current_Y_shots = current_Y_shots + 50
|
|
|
|
# Now let's get the blend file list. It's going to take a few
|
|
# stept. First we are going to try getting all the files in the
|
|
# folder. Then filter them by .blend in the end. We do not want
|
|
# to show you the .blend1 files. We don't want to show you
|
|
# anything.
|
|
|
|
blendfiles = []
|
|
|
|
try:
|
|
for blend in os.listdir(win.project+"/rnd"+win.cur):
|
|
if blend.endswith(".blend"):
|
|
blendfiles.append(blend)
|
|
except:
|
|
pass
|
|
|
|
# Now since we've got our blendfiles list. We can now draw them.
|
|
# But I want to preserve the countinuity with the rest of the
|
|
# software. So I will need to draw a little Blendfile node each
|
|
# time. For which I'm going to create a node. But this time it's
|
|
# going to have 2 icons at the bottom.
|
|
|
|
############## ############## ##############
|
|
# 01.blend # # 02.blend # # 03.blend #
|
|
############## ############## ##############
|
|
# ____ # # ____ # # ____ #
|
|
# ( 0 0 ) # # ( 0 0 ) # # ( 0 0 ) #
|
|
# ) ( # # ) ( # # ) ( #
|
|
# \__/ # # \__/ # # \__/ #
|
|
# # # # # #
|
|
############## ############## ##############
|
|
# 0 # 0 # # 0 # 0 # # 0 # 0 #
|
|
############## ############## ##############
|
|
|
|
# Those 2 icons in the bottom of each will be buttons for render
|
|
# and linking. The linking is what you do to put assets inside
|
|
# animation files. A new dialog should be developped for this.
|
|
|
|
# The rendering will resemble rendering of Blender-Organizer with
|
|
# render times analytics and stuff. But will be way more extended.
|
|
# For example with an ability to open a render task on another
|
|
# computer. So groups of people could work together.
|
|
|
|
tileX = 5
|
|
|
|
searchis = win.text["shot_search"]["text"].replace("/","_").replace(" ", "_")\
|
|
.replace('"',"_").replace("(","_").replace(")","_").replace("'","_")\
|
|
.replace("[","_").replace("]","_").replace("{","_").replace("}","_")
|
|
|
|
for bn, blend in enumerate(blendfiles):
|
|
|
|
# Each one will be drawn in it's own little layer. Because
|
|
# I want the top bar to have a nice rounded corner and also
|
|
# the image to be cut.
|
|
|
|
# Each one here will 128 pixels wide. ( Because this is the
|
|
# resolution of blender-thumbnailer.py thumbnails. And I
|
|
# want to save horizontal resolution as much as possible
|
|
|
|
# But before I render a Blend. I want to exclude it if it's
|
|
# not in a search.
|
|
|
|
if searchis and searchis.lower() not in blend.lower():
|
|
continue
|
|
|
|
# Making the layer
|
|
nodesurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 128, 198)
|
|
node = cairo.Context(nodesurface)
|
|
node.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
|
|
|
|
UI_elements.roundrect(node, win,
|
|
0,
|
|
0,
|
|
128,
|
|
198,
|
|
10,
|
|
fill=False)
|
|
|
|
node.clip()
|
|
|
|
# Background
|
|
UI_color.set(node, win, "dark_overdrop")
|
|
node.rectangle(0,0,128, 198)
|
|
node.fill()
|
|
|
|
# Blender icon
|
|
|
|
UI_elements.image(node, win,
|
|
win.project+"/rnd"+win.cur+"/"+blend,
|
|
0,
|
|
20,
|
|
128,
|
|
128, cell="shot_blends")
|
|
|
|
# Banner
|
|
UI_color.set(node, win, "node_blendfile")
|
|
node.rectangle(0,0,128, 20)
|
|
node.fill()
|
|
|
|
# Filename
|
|
UI_color.set(node, win, "text_normal")
|
|
node.set_font_size(12)
|
|
node.move_to(5, 15)
|
|
node.show_text(blend)
|
|
|
|
# Outputting the layer
|
|
layer.set_source_surface(nodesurface,
|
|
x+tileX,
|
|
y+win.scroll["script_shots"]+current_Y_shots)
|
|
layer.paint()
|
|
|
|
# Here we gonna out 3 buttons:
|
|
|
|
# 1. Launch the Blend-File
|
|
# 2. Link into Blend-File
|
|
# 3. Render Blend-File
|
|
|
|
# Launch the Blend file:
|
|
def do():
|
|
oscalls.file_open(win, win.project+"/rnd"+win.cur+"/"+blend)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x+tileX,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
128,
|
|
148,
|
|
10,
|
|
button=do,
|
|
fill=False,
|
|
tip=blend)
|
|
layer.stroke()
|
|
|
|
# Link things into Blend-File
|
|
def do():
|
|
|
|
# I'm using a dialog here. Because I want to return back
|
|
# to the shot we were in. But I don't really want to do
|
|
# anything after the dialog is closed. So there is this
|
|
# empty function.
|
|
|
|
def after(win, var):
|
|
pass
|
|
|
|
studio_dialogs.asset_link(win, "asset_linking", after, "/rnd"+win.cur+"/"+blend)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x+tileX+20,
|
|
y+win.scroll["script_shots"]+current_Y_shots+152,
|
|
40,
|
|
40,
|
|
10,
|
|
icon="obj_link",
|
|
button=do,
|
|
tip=talk.text("link_shot_blend_tooltip")+blend)
|
|
|
|
# Render
|
|
def do():
|
|
def after(win, var):
|
|
pass
|
|
|
|
studio_dialogs.render(win, "render_setup", after, "/rnd"+win.cur+"/"+blend)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x+tileX+65,
|
|
y+win.scroll["script_shots"]+current_Y_shots+152,
|
|
40,
|
|
40,
|
|
10,
|
|
icon="render",
|
|
button=do,
|
|
tip=talk.text("render_shot_blend_tooltip")+blend)
|
|
|
|
tileX = tileX + 150
|
|
if tileX + 128 > width - 10 and bn != len(blendfiles)-1:
|
|
tileX = 5
|
|
current_Y_shots = current_Y_shots + 205
|
|
|
|
|
|
# Now before we are finished. We want to able to add new files
|
|
# by typing the names in the search.
|
|
|
|
if not blendfiles and not searchis:
|
|
searchis = shotis
|
|
|
|
if not searchis.endswith(".blend"):
|
|
searchis = searchis + ".blend"
|
|
|
|
if searchis != ".blend" and searchis not in blendfiles:
|
|
|
|
# There will be 2 buttons. To add a brand new file and to
|
|
# copy one from a different shot. In Blender-Oraniger it
|
|
# had a copy-paste kind of system for this. But since we
|
|
# have a file selector. I'm going to use it instead. Tho
|
|
# tell me if a copy-paste for files is a cool idea.
|
|
|
|
if tileX + 128 > width - 10:
|
|
tileX = 5
|
|
current_Y_shots = current_Y_shots + 205
|
|
|
|
# ADD NEW BLEND
|
|
|
|
def do():
|
|
|
|
# First let's make sure that the folder exists. Because
|
|
# it might not exists. I think doing it automatically
|
|
# makes sense.
|
|
|
|
try:
|
|
os.makedirs(win.project+"/rnd"+win.cur)
|
|
except:
|
|
pass
|
|
|
|
# Then we copy the file.
|
|
|
|
oscalls.copy_file(
|
|
win,
|
|
os.getcwd()+"/new_file/rnd.blend",
|
|
"/rnd"+win.cur+"/",
|
|
searchis)
|
|
|
|
# And clear the search
|
|
|
|
win.text["shot_search"]["text"] = ""
|
|
win.images = {}
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x+tileX,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
128,
|
|
198,
|
|
10,
|
|
button=do)
|
|
|
|
# A little surrounding thing.
|
|
|
|
UI_color.set(layer, win, "progress_background")
|
|
UI_elements.roundrect(layer, win,
|
|
x+tileX,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
128,
|
|
198,
|
|
10,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
# Icon
|
|
|
|
UI_elements.image(layer, win,
|
|
"settings/themes/"+win.settings["Theme"]+"/icons/new_file.png",
|
|
x+tileX+44,
|
|
y+win.scroll["script_shots"]+current_Y_shots + 70,
|
|
40, 40)
|
|
|
|
# preiew
|
|
|
|
UI_color.set(layer, win, "text_normal")
|
|
layer.set_font_size(12)
|
|
layer.move_to(x+tileX+64-len(searchis)*4,
|
|
y+win.scroll["script_shots"]+current_Y_shots+150)
|
|
layer.show_text(searchis)
|
|
|
|
tileX = tileX + 150
|
|
if tileX + 128 > width - 10:
|
|
tileX = 5
|
|
current_Y_shots = current_Y_shots + 205
|
|
|
|
# And a copy file here too
|
|
|
|
# COPY BLEND
|
|
|
|
def do():
|
|
|
|
# Now the copy function going to be a tiny bit harder
|
|
# since we will need to launch a dialog for you to
|
|
# select the file. I think you gonna look for files
|
|
# from this scene more often. So let's do that.
|
|
|
|
def after(win, var):
|
|
if var:
|
|
try:
|
|
os.makedirs(win.project+"/rnd"+win.cur)
|
|
except:
|
|
pass
|
|
|
|
# Then we copy the file.
|
|
|
|
oscalls.copy_file(
|
|
win,var,
|
|
"/rnd"+win.cur+"/",
|
|
searchis)
|
|
|
|
# And clear the search
|
|
|
|
win.text["shot_search"]["text"] = ""
|
|
win.images = {}
|
|
|
|
studio_dialogs.file_select(win, shotis+"_blends", after, force=True,
|
|
IMAGE=False, BLEND=True, VIDEO=False, FILE=False, CHR=False, VEH=False,
|
|
LOC=False, OBJ=False, RND=True, FOLDER=False, SEARCH=scene)
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x+tileX,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
128,
|
|
198,
|
|
10,
|
|
button=do)
|
|
|
|
# A little surrounding thing.
|
|
|
|
UI_color.set(layer, win, "progress_background")
|
|
UI_elements.roundrect(layer, win,
|
|
x+tileX,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
128,
|
|
198,
|
|
10,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
# Icon
|
|
|
|
UI_elements.image(layer, win,
|
|
"settings/themes/"+win.settings["Theme"]+"/icons/copy_file.png",
|
|
x+tileX+44,
|
|
y+win.scroll["script_shots"]+current_Y_shots + 70,
|
|
40, 40)
|
|
|
|
# preiew
|
|
|
|
UI_color.set(layer, win, "text_normal")
|
|
layer.set_font_size(12)
|
|
layer.move_to(x+tileX+64-len(searchis)*4,
|
|
y+win.scroll["script_shots"]+current_Y_shots+150)
|
|
layer.show_text(searchis)
|
|
|
|
|
|
|
|
current_Y_shots = current_Y_shots + 205
|
|
|
|
else:
|
|
|
|
# If the shot is not selected I want to be able to select it
|
|
# even if I can't find it in the text of the script.
|
|
def do():
|
|
win.cur = surl
|
|
|
|
|
|
UI_elements.roundrect(layer, win,
|
|
x,
|
|
y+win.scroll["script_shots"]+current_Y_shots,
|
|
width,
|
|
50,
|
|
10,
|
|
button=do,
|
|
fill=False)
|
|
layer.stroke()
|
|
|
|
|
|
|
|
current_Y_shots = current_Y_shots + 60
|
|
|
|
# Scroll
|
|
UI_elements.scroll_area(layer, win, "script_shots",
|
|
x+0,
|
|
y+0,
|
|
width,
|
|
height,
|
|
current_Y_shots,
|
|
bar=True,
|
|
mmb=True)
|
|
|
|
|
|
|
|
return surface
|