#! /usr/bin/env python
# -*- coding: UTF8 -*-
# Este arquivo é parte do programa Kwarwp
# Copyright 2010-2018 Carlo Oliveira <carlo@nce.ufrj.br>,
# `Labase <http://labase.selfip.org/>`__; `GPL <http://j.mp/GNU_GPL3>`__.
#
# Kwarwp é 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/>
"""Brython front end client.
.. moduleauthor:: Carlo Oliveira <carlo@nce.ufrj.br>
"""
import sys
import traceback
from random import random
from base64 import decodebytes as dcd
random()
IMAGEREPO = 'server_root/image/'
CANVASW, CANVASH = 800, 600
NODICT = {}
EDIT = "{}/{}".format(IMAGEREPO, "sun.gif")
EDTST = {'position': 'relative', 'padding': 10, 'margin': '0', 'flex': '3 1 auto',
'width': '99%', 'resize': 'none', 'borderColor': 'darkslategrey',
'color': 'navajowhite', 'border': 1, 'background': 'rgba(10, 10, 10, 0.5)'}
ERRST = {'position': 'relative', 'padding': 10, 'margin': '0', 'visibility': 'visible', 'flex': '1',
'width': '99%', 'min-height': '30%', 'resize': 'none', 'borderColor': 'darkslategrey',
'color': 'navajowhite', 'border': 1, 'background': 'rgba(200, 54, 54, 0.5)'}
CSLST = {'position': 'relative', 'padding': 10, 'margin': '0', 'visibility': 'visible', 'flex': '1',
'width': '99%', 'min-height': '30%', 'resize': 'none', 'borderColor': 'darkslategrey',
'color': 'navajowhite', 'border': 1, 'background': 'rgba(74, 200, 74, 0.5)'}
#############################################################################
[docs]class Dialog:
def __init__(self, gui, text='xxxx', act=lambda *_: False):
divat = {'position': 'absolute', 'top': 0, 'left': 0, 'display': 'flex', 'padding': '7px',
'flex-direction': 'column', 'align-items': 'stretch',
'width': '100%', 'height': '100%', 'background': 'rgba(10, 10, 10, 0.85)'}
self.text = text
self.gui = gui
self.html, self.dom = gui.html, gui.dom
self._div = self._err = self._area = self.__area = None
self._div = self._div if self._div else self.html.DIV(style=divat)
self.dom <= self._div
text = text if text else self.text
self._area = self.textarea(text, style=EDTST)
self._set_code(text)
self.act = act
def _set_code(self, *_):
def set_hint(cm):
self.gui.window.CodeMirror.simpleHint(cm, self.gui.window.CodeMirror.pythonHint)
self._div <= self._area
self.__area = self.gui.window.CodeMirror.fromTextArea(
self._area, dict(
mode="python", theme="solarized", lineNumbers=True, indentUnit=4,
tabSize=4, smartIndent=False, matchBracket=True, indentWithTabs=False))
self.gui.window.CodeMirror.commands.autocomplete = set_hint
self._doc = self.__area.getDoc()
# self.__area.on("change", lambda *_: print(self._doc.getValue()))
[docs] def textarea(self, text, style=EDTST):
t = self.html.TEXTAREA(text, style=style)
return t
[docs] def remove(self):
self._div.remove()
[docs] def hide(self):
self._div.style.visibility = 'hidden'
# self.remove()
[docs] def show(self):
self._div.style.visibility = 'visible'
self.dom <= self._div
def _update_text(self):
# self.text = self._area.val()
self.text = self._doc.getValue() # self._area.value
return self.text
[docs] def get_text(self):
self.__area.save()
self.text = ''
# return self._doc.getValue() # self.text if self.text else self._update_text()
return self._update_text()
[docs] def set_csl(self, text):
self._err.remove() if self._err else None
self._err = self.textarea(text, style=CSLST)
self._div <= self._err
self.text = ''
[docs] def set_err(self, text):
self._err.remove() if self._err else None
self._err = self.textarea(text, style=ERRST)
self._div <= self._err
self.text = ''
error = text
lines = error.split(' line ')
if len(lines) > 1:
try:
line = int(lines[-1].split("\n")[0])
_ = error.split("\n")[-2]
_ = self._doc.setSelection(dict(line=line - 1, ch=0), dict(line=line - 1, ch=60))
except Exception as x:
print("Exception", x)
[docs] def del_err(self):
self._err.remove() if self._err else None
self._err = None
[docs] def set_text(self, text):
self._area.value = text
[docs] def action(self, extra):
self.text = self._area.value
# self.hide()
self.act(self, lambda *_: self.hide() or extra()) if self.act else None
[docs]class EmpacotadorDeImagem:
def __init__(self, canvas, glyph, x, y, dx, dy):
self.canvas = canvas # .canvas
self.render = canvas
self.img = self.canvas.image(
href=IMAGEREPO + glyph, x=x, y=y,
height="{}px".format(dy), width="{}px".format(dx))
self.x, self.y = x, y
def __le__(self, other):
other <= self.img
[docs] def do_remove(self):
self.img.remove()
[docs] def remove(self):
pass
self.render.renderer(self.img, render=lambda: self.do_remove())
[docs] def do_move(self, x, y, image=None):
self.img.x, self.img.y = x, y
if image:
self.img.href.baseVal = IMAGEREPO + image
[docs] def mover(self, x, y, image=None, *_, **__):
self.x, self.y = x, y
self.render.renderer(self.img, render=lambda: self.do_move(x, y, image))
[docs] def do_translate(self, x, y):
self.x, self.y = self.x + x, self.y + y
self.img.x, self.img.y = self.x, self.y
[docs] def translate(self, x, y):
self.render.renderer(self.img, render=lambda: self.do_translate(x, y))
class _GUI:
def __init__(self, br, **kw):
self.doc, self.html, self.alert, self.storage = br.document, br.html, br.alert, br.storage
self.window = br.window
self.dom = self.doc["pydiv"]
self.document = self.doc
self.events = {}
self.edit = self._edit
self.dialogue = self.code = None
def executa_acao(self, dialog):
return False
def _edit(self, *_):
return self.dialogue
def image(self, glyph, x, y, dx, dy):
img = EmpacotadorDeImagem(self, glyph, x, y, dx, dy)
return img
def textarea(self, text, style=EDTST):
divat = {'position': 'absolute', 'top': 64, 'left': 0,
'width': '800px', 'height': '536px', 'background': 'rgba(10, 10, 10, 0.85)'}
# divat = {'position': 'absolute', 'top': dpx(y), 'left': dpx(x),
# 'width': dpx(w), 'height': dpx(h), 'background': 'rgba(10, 10, 10, 0.85)'}
d = self.html.DIV(style=divat)
t = self.html.TEXTAREA(text, style=style)
d <= t
self.dom <= d
return t
def dialog(self, text=None, act=lambda *_: False):
text = text if text else self.code
# print(" def dialog(self, text=None, act=lambda *_: False):\n", u"{}".format(text))
if self.dialogue:
self.dialogue.set_text(text)
else:
self.dialogue = Dialog(self, text=text, act=act)
# self.dialogue.set_text(text)
# self.dialogue.show()
return self.dialogue
def continua(self):
pass
[docs]class GUI(_GUI):
""" O terreno onde o Festival Kuarup é apresentado
"""
def __init__(self, width=CANVASW, height=CANVASH, code="", codename="", **kwargs):
_GUI.__init__(self, width=width, height=height, **kwargs)
self.code, self.codename = dcd(str.encode(code)), codename
# -XXX- gambiarra para corrigir o brython
codelist = list(self.code)
codeclean = bytes(
c for b, c, d in zip(codelist+[0, 0], [0]+codelist+[0], [0, 0]+codelist)
if (c, d) != (194, 131) != (b, c))
self.code = codeclean[1:-1].decode('utf-8')
# -XXX- fim da gambiarra
# self.code, self.codename = dcd(str.encode(code)).decode("utf-8"), codename
self.error = self.extra = self.dialogue = None
self.dialogue = Dialog(self, text=self.code, act=self.executa_acao)
# self.dialogue = self.dialog(self.code, act=self.executa_acao)
self.dialogue.hide()
def _first_response(self, action, extra, error):
class ConsoleOutput:
def __init__(self):
self.value = ''
def write(self, data):
self.value += str(data)
def flush(self):
self.value = ''
pass
value = self.value = ConsoleOutput()
sys_out, sys.stdout = sys.stdout, value
sys_err, sys.stderr = sys.stderr, value
# logger('first response %s %s %s' % (dialog, sys.stdout, sys.stderr))
# TODO action += self.challenge[1]
# logger('first response code %s' % action)
try:
dialog = self.dialogue # if self.dialogue else dialog
self.code = dialog.get_text()
# self.dialoger = None
action()
'''
extra()
self.dialoger = None
'''
console = str(self.value.value)
if console:
# self.dialogue = self.dialog(self.code, act=self.executa_acao)
self.dialogue.set_csl(console)
else:
# self.dialoger = None
extra()
except Exception as err:
# except Exception as err:
traceback.print_exc(file=sys.stderr)
sys.stdout = sys_out
sys.stderr = sys_err
err_trace = self.value.value
annotated_error = error(str(err_trace))
# self.dialogue = self.dialog(self.code, act=self.executa_acao) # +str(self.value.value))
self.dialogue.set_err(annotated_error)
# print(self.code)
# self.dialoger = None
return False
sys.stdout = sys_out
sys.stderr = sys_err
return True
def _executa_acao(self):
glob = dict(globals())
glob.update(__name__="__main__")
exec(self.code, glob) # dict(__name__="__main__"))
[docs] def get_code(self):
self.code = self.dialogue.get_text()
return self.code
[docs] def executa_acao(self, dialog, action=None):
self.extra = action if action else lambda *_: None
self.error = self.error if self.error else lambda *_: print("NO NO", self.error)
self.code = self.get_code()
self.storage[self.codename] = self.code
return self._first_response(lambda: self._executa_acao(), self.extra, self.error)