# -*- coding: UTF8 -*-
# Este arquivo é parte do programa Impressious
# Copyright 2013-2014 Carlo Oliveira <carlo@nce.ufrj.br>,
# `Labase <http://labase.selfip.org/>`__; `GPL <http://is.gd/3Udt>`__.
#
# Impressious é um software livre; você pode redistribuí-lo e/ou
# modificá-lo dentro dos termos da Licença Pública Geral GNU como
# publicada pela Fundação do Software Livre (FSF); na versão 2 da
# Licença.
#
# Este programa é distribuído na esperança de que possa ser útil,
# mas SEM NENHUMA GARANTIA; sem uma garantia implícita de ADEQUAÇÃO
# a qualquer MERCADO ou APLICAÇÃO EM PARTICULAR. Veja a
# Licença Pública Geral GNU para maiores detalhes.
#
# Você deve ter recebido uma cópia da Licença Pública Geral GNU
# junto com este programa, se não, veja em <http://www.gnu.org/licenses/>
"""
############################################################
Impressious - Principal
############################################################
Módulo que define o editor de apresentações no espaço 2D
"""
LOREM = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy" \
" nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat."
DIM = (180, 180)
ICON = "wysiwyg-classic-icons.jpg"
GUI = None
[docs]class Slide:
"""Um slide com texto que pode ser selecionado e a geometria editada
:param navegador: Referência ao módulo navegador do Brython
:param canvas: àrea onde o slide deve ser desenhado
:param pai: Referência ao objeto pai que possui esse slide
"""
def __init__(self, navegador, canvas, pai):
self.gui = navegador
self.svg = navegador.svg
self.html = navegador.html
self.svgcanvas = canvas
self.pai = pai
self.rect = self.area = self.group = self.position = self.dimension = None
[docs] def slide(self, text=LOREM, position=None, dimension=None):
"""Cria um novo slide com o texto, posição e dimensão dadas
:param text: O texto a ser colocado no slide
:param position: Posição do slide (x, y) - automática se None
:param dimension: Dimensão do slide (w, h) - automática se None
:return: Referência para o objeto slide
"""
x, y = self.position = position or self.pai.new_position()
w, h = self.dimension = dimension or DIM
self.group = self.svg.g(transform='translate (%d, %d)' % self.position)
self.rect = self.svg.rect(x=0, y=0, width=w, height=h, color="grey", opacity=0.2)
self.area = self.svg.foreignObject(x=0, y=0, width=w, height=h)
self.area.html = text
self.group <= self.area
self.group <= self.rect
self.svgcanvas <= self.group
Impressious.SLIDES.append(self)
self.group.onclick = self._select
return self
[docs] def widen(self, delta):
"""Enlarguesse o slide
:param delta: aumento na largura
"""
w, h = self.dimension
w, h = self.dimension = (w+delta, h)
self.rect.setAttribute('width', '%d' % w)
self.area.setAttribute('width', '%d' % w)
[docs] def heighten(self, delta):
"""Enaltece o slide
:param delta: aumento na largura
"""
w, h = self.dimension
w, h = self.dimension = (w, h+delta)
self.rect.setAttribute('height', '%d' % h)
self.area.setAttribute('height', '%d' % h)
[docs] def move(self, x, y):
"""Movimenta o slide para uma nova posição
:param x: nova posição x
:param y: nova posição y
"""
(ox, oy), (w, h) = self.position, self.dimension
self.position = (x-w//2, y-h//2)
self.group.setAttribute('transform', 'translate (%d %d)' % self.position)
def _select(self, event):
"""Cria um cursor ao ser selecionado
:param event: Dados do mouse quando clicado
:return: Nada
"""
(x, y), (w, h) = self.position, self.dimension
center = x+w//2, y+h//2
self.pai.build_cursor(self, center)
[docs]class Impressious:
"""Classe que define o editor de apresentações no espaço 2D
:param navegador: Referência ao módulo navegador do Brython
"""
SLIDES = []
def __init__(self, navegador):
"""Constroi os objetos iniciais. """
global GUI
self.gui = GUI = navegador
self.svg = navegador.svg
self.html = navegador.html
self.ajax = navegador.ajax
self.svgcanvas = self.cursor = self.icon = self.menu = self.back = self.div = None
self.load = self.save = lambda ev: None
self.dim = (800, 600)
[docs] def build_base(self, width=800, height=600):
"""Constrói as partes do Jogo.
:return: Self, referência a este objeto
"""
python_div = self.div = self.gui.document['pydiv']
self.dim = width, height
self.svgcanvas = self.svg.svg(width=width, height=height)
python_div <= self.svgcanvas
self.back = self.svg.g()
self.svgcanvas <= self.back
#self.menu = Menu(self.icon, python_div, display=False, **menu)
# self.icon["main"].render(python_div, 2, 0, self.ad_template, "img50")
# self.icon["save"].render(python_div, 2, 40)
# self.icon["load"].render(python_div, 2, 80)
return self
[docs] def dash(self, ev):
self.menu['dash'].show()
def _process_arguments(self, gui):
def set_prop(value):
self.props = self.json.loads(value)['result']
print('set_prop', self.props)
def set_scene(value):
self.scene = self.json.loads(value)['result']
print('set_scene', self.scene)
args = self.win.location.search
if '=' in args:
self.args = {k: v for k, v in [c.split('=') for c in args[1:].split('&')]}
props = self.properties = self.args.setdefault('props', 'jeppeto')
self.folder = self.args.setdefault('folder', '')
scenes = self.args.setdefault('scenes', 'EICA')
self.gui.send(STUDIO % (props, 1), record=set_prop, method="GET")
self.gui.send(STUDIO % (scenes, 2), record=set_scene, method="GET")
print(self.args, props, STUDIO % (props, 1))
if 'game' in self.args:
gui.start_a_game(self.args['game'])
else:
gui.show_front_menu()
else:
gui.show_front_menu()
[docs] def new_position(self):
"""Aloca uma posição automática para um novo slide
:return: a posição (x, y)
"""
dx, dy = DIM
ox, oy = 10, 10
dx, dy = dx+ox, dy+oy
sx, sy = self.dim
xlim = sx // dx
slide = len(Impressious.SLIDES)
print(xlim, (slide % xlim) * dx + ox, (slide // xlim) * dy + oy)
return (slide % xlim) * dx + ox, (slide // xlim) * dy + oy
[docs] def slide(self, text=LOREM, position=None, dimension=None):
"""Cria um novo slide com o texto, posição e dimensão dadas
:param text: O texto a ser colocado no slide
:param position: Posição do slide (x, y) - automática se None
:param dimension: Dimensão do slide (w, h) - automática se None
:return: Referência para o objeto slide
"""
return Slide(self.gui, self.svgcanvas, self).slide(text, position, dimension)
[docs] def read_wiki(self, url):
"""Lê uma página da wiki com uma chamada REST
:param url: Url REST da wiki a ser lida
:return: COnteúdo da página wiki
"""
FAKEC = '<h1></h1>' + '<li>Lê uma página da wiki com uma chamada REST</li>' * 10
FAKE = dict(result=dict(wikidata=dict(conteudo=FAKEC)))
try:
import urllib.request
import json
_fp = urllib.request.urlopen(url)
print(_fp)
if isinstance(_fp, tuple):
_fp = _fp[0]
_data = _fp.read()
else:
_data = _fp.read().decode('utf8')
print(_data)
_json = json.loads(str(_data))
except Exception as ex:
_json = FAKE
if "result" in _json and "wikidata" in _json["result"]\
and "conteudo" in _json["result"]["wikidata"]:
return _json["result"]["wikidata"]["conteudo"]
else:
return ""
[docs] def parse_wiki(self, html_text):
"""Separa slides e items do texto
:param html_text: texto em html contendo h1 e li
:return: lista de itens na página
"""
conteudo = html_text.split('</h1>')[1]
return [item.split("</li>")[0] for item in conteudo.split("<li>")[1:]]
[docs] def load_slides_from_wiki(self, item_list):
"""Cria slides e items do texto
:param item_list: lista de itens a serem convertidos em slides
:return: lista de slides criados
"""
return [self.slide(item) for item in item_list]
[docs] def build_cursor(self, slide, center):
"""Cria o cursor geométrico
:return: o elemento grupo do cursor
"""
self.cursor = Cursor(self.svgcanvas, self.svg, slide, center)
self.build_cursor = lambda s, p:\
self.cursor.setAttribute(s, 'transform', "translate (%d %d)" % p)
[docs] def ad_template(self, template):
FAKESVG = '<g>%s</g>' % '\n'.join(
['<rect x="%d" y="9" width="9" height="9" color="red"></rect>' % (x*10) for x in range(10)])
try:
import urllib.request
import json
_fp = urllib.request.urlopen(MENUFPX % template.target.id)
print("ad_template", template.target.id)
if isinstance(_fp, tuple):
_fp = _fp[0]
_data = _fp.read()
except Exception as ex:
_data = FAKESVG
#_data = _data.split('<g')[1].split('</g>')[0]
#close_g_tag = _data.find(">")
#_data = _data[close_g_tag+1:]
print("ad_template _data", template.target.id, MENUFPX % template.target.id, _data)
self.back.html = _data
[docs]class Cursor:
"""Cursor usado para modificar geometricamente um slide
:param canvas: elemento svg do DOM
:param svg: módulo svg do browser brython
:param slide: o slide para o qual o cursor foi alocado
:param position: a posição onde o cursor deve ser colocado
"""
def _cursor_start_move(self, event, mover):
self._move = mover
self._mouse_pos = (event.x, event.y)
def _move_slide(self, event):
"""Movimenta o cursor geométrico
"""
self._mouse_pos = (event.x, event.y)
self.cursor.setAttribute('transform', "translate (%d %d)" % (event.x, event.y))
self.slide.move(event.x, event.y)
def _widen_slide(self, event):
"""Enlarguesse o cursor geométrico
"""
self._mouse_pos, delta = (event.x, event.y), event.x - self._mouse_pos[0]
self.cursor.setAttribute('transform', "translate (%d %d)" % (event.x, event.y))
self.slide.widen(delta)
def _heighten_slide(self, event):
"""Enaltece o cursor geométrico
"""
self._mouse_pos, delta = (event.x, event.y), event.y - self._mouse_pos[1]
self.cursor.setAttribute('transform', "translate (%d %d)" % (event.x, event.y))
self.slide.heighten(delta)
def __init__(self, canvas, svg, slide, position=(0, 0)):
x, y = position
self.svg = svg
self.slide = slide
t45 = "rotate (45 0 0)"
group = self.cursor = self.svg.g(Id="cursor", transform="translate (%d %d)" % position)
ne = self.svg.rect(x=0, y=-35, width=35, height=35, style={"opacity": 0.5, "fill": "#b3b3b3"})
se = self.svg.rect(x=0, y=0, width=35, height=35, style={"opacity": 0.5, "fill": "#b3b3b3"})
sw = self.svg.rect(x=-35, y=0, width=35, height=35, style={"opacity": 0.5, "fill": "#b3b3b3"})
nw = self.svg.rect(x=-35, y=-35, width=35, height=35, style={"opacity": 0.5, "fill": "#b3b3b3"})
ww = self.svg.rect(x=0, y=-35, width=35, height=35, transform=t45, style={"opacity": 0.5, "fill": "#b3b3b3"})
ss = self.svg.rect(x=0, y=0, width=35, height=35, transform=t45, style={"opacity": 0.5, "fill": "#b3b3b3"})
ee = self.svg.rect(x=-35, y=0, width=35, height=35, transform=t45, style={"opacity": 0.5, "fill": "#b3b3b3"})
nn = self.svg.rect(x=-35, y=-35, width=35, height=35, transform=t45, style={"opacity": 0.5, "fill": "#b3b3b3"})
circle = self.svg.circle(cx=0, cy=0, r=35, style={"opacity": 0.5, "fill": "#ffffff"})
eye = self.svg.circle(cx=0, cy=0, r=20, style={"opacity": 0.5, "fill": "#999999"})
for element in [ne, se, sw, nw, nn, ee, ss, ww, circle, eye]:
group <= element
canvas <= group
def end_move():
self._move = lambda e: None
end_move()
eye.onmousedown = lambda e: self._cursor_start_move(e, self._move_slide)
ee.onmousedown = lambda e: self._cursor_start_move(e, self._widen_slide)
ww.onmousedown = lambda e: self._cursor_start_move(e, self._widen_slide)
ss.onmousedown = lambda e: self._cursor_start_move(e, self._heighten_slide)
nn.onmousedown = lambda e: self._cursor_start_move(e, self._heighten_slide)
group.onmousemove = lambda e: self._move(e)
group.onmouseup = lambda e: end_move()
[docs] def setAttribute(self, slide, attr, value):
"""Muda o slide corrente e um atributo do slide
:param slide: o novo slide que é controlado pelo cursor
:param attr: o nome do atributo que vai mudado no cursor
:param value: o valor novo do atributo
"""
self.slide = slide
self.cursor.setAttribute(attr, value)
MENUPX = "http://www.corsproxy.com/activufrj.nce.ufrj.br/static/desenhos/img%s.png"
MENUFPX = "http://www.corsproxy.com/activufrj.nce.ufrj.br/static/desenhos/%s.svg"
EL, ED = [], {}
MENU_DEFAULT = ['ad_objeto', 'ad_cenario', 'wiki', 'navegar', 'jeppeto']
[docs]class Sprite:
"""Gerencia uma coleção de sprites a partir de uma folha com imagens
:param img: Url da folha de imagem
:param dx: espaçamento x de cada sprite
:param dy: espaçamento y de cada sprite
:param offx: inicio em x da coleção de sprites (default 0)
:param offy: inicio em y da coleção de sprites (default 0)
:param padx: desconto em x de cada imagem do sprite (default 0)
:param pady: desconto em y de cada imagem do sprite (default 0)
:param x: posição em x na matriz de sprites deste sprite (default 0)
:param y: posição em y na matriz de sprites deste sprite (default 0)
:param Id: identificador do sprite no DOM ou no dicionário SPRITE
"""
SPRITE = {} # Coleção de sprites
def __init__(self, img, dx, dy, offx=0, offy=0, padx=0, pady=0, x=0, y=0, Id=""):
self.img, self.dx, self.dy, self.offx, self.offy, self.padx, self.pady = img, dx, dy, offx, offy, padx, pady
self.x, self.y, self.Id = x, y, Id
self.menu = None
[docs] def sprites(self, **kwargs):
"""Recorta sprites da imagem e registra no dicionário SPRITE.
:param kwargs: lista de argumentos da forma nome_do_sprite=[sprite_x, sprite_y]
:return: o dicionário SPRITE
"""
class Image(Sprite):
def render(self, element, x=0, y=0, action=None, Id="", display=True):
style = dict(width="%dpx" % self.dx, margin="%dpx" % self.padx)
img = GUI.html.IMG(Id=Id or "spr%s" % self.Id, src=self.img, style=style)
img.onclick = lambda ev: action(ev, self.Id) if action else lambda ev: None
element <= img
return img
def cut_sprite(name, x, y=0):
if isinstance(x, str):
return Image(x, self.dx, self.dy, self.offx, self.offy, self.padx, self.pady, 0, y, name)
return Sprite(self.img, self.dx, self.dy, self.offx, self.offy, self.padx, self.pady, x, y, name)
Sprite.SPRITE.update({name: cut_sprite(name, *coordinates) for name, coordinates in kwargs.items()})
return Sprite.SPRITE
[docs] def render(self, element, x=0, y=0, action=None, Id="", display=True):
"""Desenha um sprite no elemento dado
:param element: elemento onde o sprite vai ser desenhado
:param x: posição x no elemento onde o sprite vai ser desenhado (default 0)
:param y: posição y no elemento onde o sprite vai ser desenhado (default 0)
:param action: função aser chamada quando o sprite for clicado (default nenhuma)
:param Id: identificador do sprite no DOM ou no dicionário SPRITE
:return:
"""
self.menu = GUI.html.DIV(Id=Id or "spr%s" % self.Id)
self.menu.style.backgroundImage = "url(%s)" % self.img
#self.menu.style.position = "absolute"
self.menu.style.display = "block" if display else "none"
top = self.offy + self.y*self.dy + self.pady
left = self.offx + self.x*self.dx + self.padx
print(self.img, self.dx, self.dy, self.offx, self.offy, self.padx, self.pady, x, y, top, left)
self.menu.style.top = y
self.menu.style.left = x
self.menu.style.width = self.dx - 2*self.padx
self.menu.style.height = self.dy - 2*self.pady
self.menu.style.backgroundPosition = "-%dpx -%dpx" % (left, top)
self.menu.onclick = action if action else lambda ev: None
element <= self.menu
return self.menu
[docs] def render_div(self, element, w=0, h=0, action=None, Id="", display=False):
css_display = "block" if display else "none"
div = self.div(
s_position='absolute', s_top='0', s_bottom='0', s_margin="auto", s_left='0', s_width='%dpx' % (w*self.dx),
s_height='%dpx' % (h*self.dy), s_display=css_display, s_border='1px solid #d0d0d0', o_Id="div"+Id)
element <= div
div.onclick = action if action else lambda ev: None
return div
def _filter(self, args):
#print(args)
return {k[2:]: value for k, value in args.items() if k[:2] in "s_"}
[docs] def div(self, o_place=None, o_Id=None, o_Class='deafault', **kwargs):
print("Sprite div:", GUI, kwargs, self._filter(kwargs))
return GUI.html.DIV(
Id=o_Id, Class=o_Class, style=self._filter(kwargs))