"""
This module contain bunch of stateless functions. They all takes a
:class:`Cursor` object as first argument and return a JSON serializable value.
"""
import os
from . import model
from . import projects
from . import PROJECTS_DIR
from .cursor import UndefinedProjectError
from . import tags
[docs]def get_path(cursor, file=""):
"""
Return path to the project (or path to a file in the project).
"""
return os.path.join(PROJECTS_DIR, cursor.proj.name, file)
[docs]def get_projects_tree(cursor):
"""
Return a dict withs all projects in the projects dir as keys and a list of
the projects' anims as values
"""
list_anims = lambda p: [
file[:-4]
for file in os.path.join(PROJECTS_DIR, p)
if file.endswith('.ogn')
]
return {
project_name:list_anims(project_name)
for project_name in projects.get_saved_projects_list()
}
[docs]def get_projects(cursor):
"""
Return a list of all projects in the projects dir
"""
return sorted([proj for proj in projects.get_saved_projects_list()])
[docs]def get_view_config(cursor, option=None):
"""
Return the projects view configuration.
If an option arg is passed, return the specified option.
"""
if option:
return cursor.proj.config['view'][option]
else:
return cursor.proj.config['view']
[docs]def get_config(cursor):
"""
Return the project configuration
"""
return cursor.proj.config
[docs]def get_anims(cursor):
"""
Return a list of the projects' anims.
"""
return sorted([anim for anim in cursor.proj.anims])
[docs]def get_playing(cursor):
"""
Return the value of cursor.playing
"""
return cursor.playing
[docs]def get_timeline(cursor):
"""
Return a dict with informations about organization of the anim.
The 'len' field contain the animation length.
The 'layers' field contain a list of layers as lists of elements.
Each element is describe as a dict with elements infos from get_element_infos.
So the output may look like this :
::
{
'len':4,
'layers':[
[{...}],
[{...}, {...}],
[{...}, {...}]
]
}
"""
# TODO: add an 'empty' key in element dict
return {
'len':cursor.anim_len(),
'layers':[[get_element_infos(cursor, element=element)
for element in layer.elements]
for layer in cursor.get_anim().layers]
}
[docs]def get_cursor_infos(cursor):
"""
Return a dict containing informations about the cursor state
keys are : 'project_name', 'playing', 'clipboard', 'anim', 'frm', 'layer'
"""
infos = {
'project_name':cursor.proj.name,
'playing':cursor.playing,
'clipboard':cursor.clipboard is not None,
}
# infos.update(cursor._pos) DEL ?
infos.update(cursor.get_pos())
return infos
[docs]def get_project_defined(cursor):
"""
Return True or False if the cursor has a project defined.
"""
try:
return cursor.proj is not None
except UndefinedProjectError:
return False
[docs]def get_element_infos(cursor, anim=None, layer=None, frm=None, element=None):
"""
Return a dict containing informations about the current element
keys are : 'type', 'len', 'tags', 'name'
Alternatives frm index and anim name can be passed.
If an element is passed, return element infos and ignore position args.
"""
e = element if element is not None else cursor.get_element(anim, layer, frm)
try:
empty = len(e.lines)==0
except AttributeError:
empty = False
infos = {
'type':type(e).__name__,
'len':cursor.element_len(e),
'tags':e.tags,
'name':e.name if hasattr(e ,'name') else None,
}
return infos
[docs]def get_lines(cursor, anim=None, frm=None, playing=None):
"""
Return all current visible lines as a list of dict.
Each dict has 'coords' and specials lines dict also has a 'line_type' key.
Alternatives frm index, anim name and playing value can be passed.
"""
playing = playing if playing is not None else cursor.playing
lines = []
if not playing :
lines += get_onion_skin(cursor)
for i in range(len(cursor.get_anim(anim).layers)):
try:
pos = _, element, at = cursor.get_element_pos(anim, i, frm)
except TypeError:
continue
# get lines from cell
if type(element) is model.Cell:
element_lines = [{'coords': line.coords} for line in element.lines]
# get lines from animref
elif type(element) is model.AnimRef:
element_lines = get_lines(cursor, element.name, at, True)
else:
continue
for line in element_lines:
# add 'selected' if not playing
if not playing and pos == cursor.get_element_pos():
line['line_type'] = line.get('line_type', set()).union({'selected'})
# calculate tags
for tag in element.tags:
line['coords'] = tags.calculate_coords(line['coords'],
playing, at, cursor.element_len(element), tag)
line_type = tags.calculate_line_type(line.get('line_type', set()), playing, tag)
if line_type:
line['line_type'] = line_type
lines += element_lines
return lines
[docs]def get_drawing(cursor):
# WARNING : untested
return {
'playing': cursor.playing,
'lines':get_lines(cursor)
}
[docs]def get_onion_skin(cursor, anim=None, frm=None):
"""
Return a list of onion skin lines.
"""
frm = frm if frm is not None else cursor.get_pos('frm')
lines=[]
lines += [{
'coords':line['coords'],
'line_type':line.get('line_type', set()).union({'onion_skin_backward'})
}
for line in get_lines(cursor, anim=anim, frm=cursor.constrain_frm(frm-1), playing=True)]
lines += [{
'coords':line['coords'],
'line_type':line.get('line_type', set()).union({'onion_skin_forward'})
}
for line in get_lines(cursor, anim=anim, frm=cursor.constrain_frm(frm+1), playing=True)]
return lines