Browse Source

Merge pull request #203 from ceccopierangiolieugenio/Multithreaded_input

Multithreaded input
pull/206/head 0.37.0-a
Ceccopierangiolieugenio 2 years ago committed by GitHub
parent
commit
3abf776d74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Makefile
  2. 163
      TermTk/TTkCore/TTkTerm/input.py
  3. 183
      TermTk/TTkCore/TTkTerm/input_mono.py
  4. 213
      TermTk/TTkCore/TTkTerm/input_thread.py
  5. 28
      docs/MDNotes/input/abstracrt.md
  6. 205
      tests/sandbox/js/ttkproxy.js
  7. 181
      tests/sandbox/sandbox.html
  8. 338
      tests/sandbox/sandbox.old.html
  9. 148
      tests/sandbox/standalone.fullscreen.html
  10. 150
      tests/sandbox/standalone.html
  11. 12
      tools/check.import.sh

1
Makefile

@ -97,6 +97,7 @@ deploySandbox:
git checkout gh-pages
cp tmp/sandbox/*.html sandbox
cp -r tmp/sandbox/js sandbox
git submodule foreach git pull
git add sandbox

163
TermTk/TTkCore/TTkTerm/input.py

@ -20,164 +20,5 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
__all__ = ['TTkInput']
import re
from time import time
import platform
from ..drivers import TTkInputDriver
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.signal import pyTTkSignal
from TermTk.TTkCore.TTkTerm.term import TTkTerm
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
class TTkInput:
inputEvent = pyTTkSignal(TTkKeyEvent, TTkMouseEvent)
pasteEvent = pyTTkSignal(str)
_pasteBuffer = ""
_bracketedPaste = False
_readInput = None
_leftLastTime = 0
_midLastTime = 0
_rightLastTime = 0
_leftTap = 0
_midTap = 0
_rightTap = 0
_mouse_re = re.compile(r"\033\[<(\d+);(\d+);(\d+)([mM])")
class Mouse(int):
ON = 0x01
DIRECT = 0x02
@staticmethod
def init(mouse:bool=False, directMouse:bool=False) -> None:
TTkInput._readInput = TTkInputDriver()
TTkTerm.setMouse(mouse, directMouse)
@staticmethod
def close() -> None:
TTkTerm.setMouse(False, False)
if TTkInput._readInput:
TTkInput._readInput.close()
@staticmethod
def stop() -> None:
pass
@staticmethod
def cont() -> None:
if TTkInput._readInput:
TTkInput._readInput.cont()
@staticmethod
def start() -> None:
for stdinRead in TTkInput._readInput.read():
TTkInput.key_process(stdinRead)
TTkLog.debug("Close TTkInput")
@staticmethod
def key_process(stdinRead:str) -> None:
if TTkInput._bracketedPaste:
if stdinRead.endswith("\033[201~"):
TTkInput._pasteBuffer += stdinRead[:-6]
TTkInput._bracketedPaste = False
# due to the CRNL methos (don't ask me why) the terminal
# is substituting all the \n with \r
TTkInput.pasteEvent.emit(TTkInput._pasteBuffer.replace('\r','\n'))
TTkInput._pasteBuffer = ""
else:
TTkInput._pasteBuffer += stdinRead
return
mevt,kevt = None, None
if not stdinRead.startswith("\033[<"):
# Key Event
kevt = TTkKeyEvent.parse(stdinRead)
else:
# Mouse Event
m = TTkInput._mouse_re.match(stdinRead)
if not m:
# TODO: Return Error
hex = [f"0x{ord(x):02x}" for x in stdinRead]
TTkLog.error("UNHANDLED (mouse): "+stdinRead.replace("\033","<ESC>") + " - "+",".join(hex))
return None, None
code = int(m.group(1))
x = int(m.group(2))-1
y = int(m.group(3))-1
state = m.group(4)
key = TTkMouseEvent.NoButton
evt = TTkMouseEvent.Move
tap = 0
def _checkTap(lastTime, tap):
if state=="M":
t = time()
if (t-lastTime) < 0.4:
return t, tap+1
else:
return t, 1
return lastTime, tap
mod = TTkK.NoModifier
if code & 0x10:
code &= ~0x10
mod |= TTkK.ControlModifier
if code & 0x08:
code &= ~0x08
mod |= TTkK.AltModifier
if code == 0x00:
TTkInput._leftLastTime, TTkInput._leftTap = _checkTap(TTkInput._leftLastTime, TTkInput._leftTap)
tap = TTkInput._leftTap
key = TTkMouseEvent.LeftButton
evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release
elif code == 0x01:
TTkInput._midLastTime, TTkInput._midTap = _checkTap(TTkInput._midLastTime, TTkInput._midTap)
tap = TTkInput._midTap
key = TTkMouseEvent.MidButton
evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release
elif code == 0x02:
TTkInput._rightLastTime, TTkInput._rightTap = _checkTap(TTkInput._rightLastTime, TTkInput._rightTap)
tap = TTkInput._rightTap
key = TTkMouseEvent.RightButton
evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release
elif code == 0x20:
key = TTkMouseEvent.LeftButton
evt = TTkMouseEvent.Drag
elif code == 0x21:
key = TTkMouseEvent.MidButton
evt = TTkMouseEvent.Drag
elif code == 0x22:
key = TTkMouseEvent.RightButton
evt = TTkMouseEvent.Drag
elif code == 0x40:
key = TTkMouseEvent.Wheel
evt = TTkMouseEvent.Up
elif code == 0x41:
key = TTkMouseEvent.Wheel
evt = TTkMouseEvent.Down
elif code == 0x23:
evt = TTkMouseEvent.Move
elif code == 0x27:
mod |= TTkK.ShiftModifier
evt = TTkMouseEvent.Move
mevt = TTkMouseEvent(x, y, key, evt, mod, tap, m.group(0).replace("\033", "<ESC>"))
if kevt or mevt:
TTkInput.inputEvent.emit(kevt, mevt)
return
if stdinRead.startswith("\033[200~"):
TTkInput._pasteBuffer = stdinRead[6:]
TTkInput._bracketedPaste = True
return
hex = [f"0x{ord(x):02x}" for x in stdinRead]
TTkLog.error("UNHANDLED: "+stdinRead.replace("\033","<ESC>") + " - "+",".join(hex))
# from .input_mono import *
from .input_thread import *

183
TermTk/TTkCore/TTkTerm/input_mono.py

@ -0,0 +1,183 @@
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
__all__ = ['TTkInput']
import re
from time import time
import platform
from ..drivers import TTkInputDriver
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.signal import pyTTkSignal
from TermTk.TTkCore.TTkTerm.term import TTkTerm
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
class TTkInput:
inputEvent = pyTTkSignal(TTkKeyEvent, TTkMouseEvent)
pasteEvent = pyTTkSignal(str)
_pasteBuffer = ""
_bracketedPaste = False
_readInput = None
_leftLastTime = 0
_midLastTime = 0
_rightLastTime = 0
_leftTap = 0
_midTap = 0
_rightTap = 0
_mouse_re = re.compile(r"\033\[<(\d+);(\d+);(\d+)([mM])")
class Mouse(int):
ON = 0x01
DIRECT = 0x02
@staticmethod
def init(mouse:bool=False, directMouse:bool=False) -> None:
TTkInput._readInput = TTkInputDriver()
TTkTerm.setMouse(mouse, directMouse)
@staticmethod
def close() -> None:
TTkTerm.setMouse(False, False)
if TTkInput._readInput:
TTkInput._readInput.close()
@staticmethod
def stop() -> None:
pass
@staticmethod
def cont() -> None:
if TTkInput._readInput:
TTkInput._readInput.cont()
@staticmethod
def start() -> None:
for stdinRead in TTkInput._readInput.read():
TTkInput.key_process(stdinRead)
TTkLog.debug("Close TTkInput")
@staticmethod
def key_process(stdinRead:str) -> None:
if TTkInput._bracketedPaste:
if stdinRead.endswith("\033[201~"):
TTkInput._pasteBuffer += stdinRead[:-6]
TTkInput._bracketedPaste = False
# due to the CRNL methos (don't ask me why) the terminal
# is substituting all the \n with \r
TTkInput.pasteEvent.emit(TTkInput._pasteBuffer.replace('\r','\n'))
TTkInput._pasteBuffer = ""
else:
TTkInput._pasteBuffer += stdinRead
return
mevt,kevt = None, None
if not stdinRead.startswith("\033[<"):
# Key Event
kevt = TTkKeyEvent.parse(stdinRead)
else:
# Mouse Event
m = TTkInput._mouse_re.match(stdinRead)
if not m:
# TODO: Return Error
hex = [f"0x{ord(x):02x}" for x in stdinRead]
TTkLog.error("UNHANDLED (mouse): "+stdinRead.replace("\033","<ESC>") + " - "+",".join(hex))
return None, None
code = int(m.group(1))
x = int(m.group(2))-1
y = int(m.group(3))-1
state = m.group(4)
key = TTkMouseEvent.NoButton
evt = TTkMouseEvent.Move
tap = 0
def _checkTap(lastTime, tap):
if state=="M":
t = time()
if (t-lastTime) < 0.4:
return t, tap+1
else:
return t, 1
return lastTime, tap
mod = TTkK.NoModifier
if code & 0x10:
code &= ~0x10
mod |= TTkK.ControlModifier
if code & 0x08:
code &= ~0x08
mod |= TTkK.AltModifier
if code == 0x00:
TTkInput._leftLastTime, TTkInput._leftTap = _checkTap(TTkInput._leftLastTime, TTkInput._leftTap)
tap = TTkInput._leftTap
key = TTkMouseEvent.LeftButton
evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release
elif code == 0x01:
TTkInput._midLastTime, TTkInput._midTap = _checkTap(TTkInput._midLastTime, TTkInput._midTap)
tap = TTkInput._midTap
key = TTkMouseEvent.MidButton
evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release
elif code == 0x02:
TTkInput._rightLastTime, TTkInput._rightTap = _checkTap(TTkInput._rightLastTime, TTkInput._rightTap)
tap = TTkInput._rightTap
key = TTkMouseEvent.RightButton
evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release
elif code == 0x20:
key = TTkMouseEvent.LeftButton
evt = TTkMouseEvent.Drag
elif code == 0x21:
key = TTkMouseEvent.MidButton
evt = TTkMouseEvent.Drag
elif code == 0x22:
key = TTkMouseEvent.RightButton
evt = TTkMouseEvent.Drag
elif code == 0x40:
key = TTkMouseEvent.Wheel
evt = TTkMouseEvent.Up
elif code == 0x41:
key = TTkMouseEvent.Wheel
evt = TTkMouseEvent.Down
elif code == 0x23:
evt = TTkMouseEvent.Move
elif code == 0x27:
mod |= TTkK.ShiftModifier
evt = TTkMouseEvent.Move
mevt = TTkMouseEvent(x, y, key, evt, mod, tap, m.group(0).replace("\033", "<ESC>"))
if kevt or mevt:
TTkInput.inputEvent.emit(kevt, mevt)
return
if stdinRead.startswith("\033[200~"):
TTkInput._pasteBuffer = stdinRead[6:]
TTkInput._bracketedPaste = True
return
hex = [f"0x{ord(x):02x}" for x in stdinRead]
TTkLog.error("UNHANDLED: "+stdinRead.replace("\033","<ESC>") + " - "+",".join(hex))

213
TermTk/TTkCore/TTkTerm/input_thread.py

@ -0,0 +1,213 @@
# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
__all__ = ['TTkInput']
import re
from time import time
import threading, queue
from ..drivers import TTkInputDriver
from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.signal import pyTTkSignal
from TermTk.TTkCore.TTkTerm.term import TTkTerm
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent
class TTkInput:
inputEvent = pyTTkSignal(TTkKeyEvent, TTkMouseEvent)
pasteEvent = pyTTkSignal(str)
_pasteBuffer = ""
_bracketedPaste = False
_readInput = None
_inputThread = None
_inputQueue = None
_leftLastTime = 0
_midLastTime = 0
_rightLastTime = 0
_leftTap = 0
_midTap = 0
_rightTap = 0
_mouse_re = re.compile(r"\033\[<(\d+);(\d+);(\d+)([mM])")
class Mouse(int):
ON = 0x01
DIRECT = 0x02
@staticmethod
def init(mouse:bool=False, directMouse:bool=False) -> None:
TTkInput._readInput = TTkInputDriver()
TTkInput._inputThread = threading.Thread(target=TTkInput._run)
TTkInput._inputQueue = queue.Queue()
TTkTerm.setMouse(mouse, directMouse)
@staticmethod
def close() -> None:
TTkTerm.setMouse(False, False)
if TTkInput._readInput:
TTkInput._readInput.close()
@staticmethod
def stop() -> None:
pass
@staticmethod
def cont() -> None:
if TTkInput._readInput:
TTkInput._readInput.cont()
@staticmethod
def start() -> None:
TTkInput._inputThread.start()
while inq := TTkInput._inputQueue.get():
kevt,mevt,paste = inq
# Try to filter out the queued moved mouse events
while (not kevt and
not paste and
mevt and mevt.evt == TTkK.Drag and
not TTkInput._inputQueue.empty() ):
mevtOld = mevt
kevt, mevt, paste = TTkInput._inputQueue.get()
if (kevt or
paste or
mevt and mevt.evt != TTkK.Drag):
TTkInput.inputEvent.emit(kevt, mevtOld)
break
if kevt or mevt:
TTkInput.inputEvent.emit(kevt, mevt)
if paste:
TTkInput.pasteEvent.emit(paste)
TTkLog.debug("Close TTkInput")
@staticmethod
def _run():
for stdinRead in TTkInput._readInput.read():
outq = TTkInput.key_process(stdinRead)
TTkInput._inputQueue.put(outq)
TTkInput._inputQueue.put(None)
@staticmethod
def key_process(stdinRead:str) -> None:
if TTkInput._bracketedPaste:
if stdinRead.endswith("\033[201~"):
TTkInput._pasteBuffer += stdinRead[:-6]
TTkInput._bracketedPaste = False
# due to the CRNL methos (don't ask me why) the terminal
# is substituting all the \n with \r
_paste = TTkInput._pasteBuffer.replace('\r','\n')
TTkInput._pasteBuffer = ""
return None, None, _paste
else:
TTkInput._pasteBuffer += stdinRead
return None, None, None
mevt,kevt = None,None
if not stdinRead.startswith("\033[<"):
# Key Event
kevt = TTkKeyEvent.parse(stdinRead)
else:
# Mouse Event
m = TTkInput._mouse_re.match(stdinRead)
if not m:
# TODO: Return Error
hex = [f"0x{ord(x):02x}" for x in stdinRead]
TTkLog.error("UNHANDLED (mouse): "+stdinRead.replace("\033","<ESC>") + " - "+",".join(hex))
return None, None, None
code = int(m.group(1))
x = int(m.group(2))-1
y = int(m.group(3))-1
state = m.group(4)
key = TTkMouseEvent.NoButton
evt = TTkMouseEvent.Move
tap = 0
def _checkTap(lastTime, tap):
if state=="M":
t = time()
if (t-lastTime) < 0.4:
return t, tap+1
else:
return t, 1
return lastTime, tap
mod = TTkK.NoModifier
if code & 0x10:
code &= ~0x10
mod |= TTkK.ControlModifier
if code & 0x08:
code &= ~0x08
mod |= TTkK.AltModifier
if code == 0x00:
TTkInput._leftLastTime, TTkInput._leftTap = _checkTap(TTkInput._leftLastTime, TTkInput._leftTap)
tap = TTkInput._leftTap
key = TTkMouseEvent.LeftButton
evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release
elif code == 0x01:
TTkInput._midLastTime, TTkInput._midTap = _checkTap(TTkInput._midLastTime, TTkInput._midTap)
tap = TTkInput._midTap
key = TTkMouseEvent.MidButton
evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release
elif code == 0x02:
TTkInput._rightLastTime, TTkInput._rightTap = _checkTap(TTkInput._rightLastTime, TTkInput._rightTap)
tap = TTkInput._rightTap
key = TTkMouseEvent.RightButton
evt = TTkMouseEvent.Press if state=="M" else TTkMouseEvent.Release
elif code == 0x20:
key = TTkMouseEvent.LeftButton
evt = TTkMouseEvent.Drag
elif code == 0x21:
key = TTkMouseEvent.MidButton
evt = TTkMouseEvent.Drag
elif code == 0x22:
key = TTkMouseEvent.RightButton
evt = TTkMouseEvent.Drag
elif code == 0x40:
key = TTkMouseEvent.Wheel
evt = TTkMouseEvent.Up
elif code == 0x41:
key = TTkMouseEvent.Wheel
evt = TTkMouseEvent.Down
elif code == 0x23:
evt = TTkMouseEvent.Move
elif code == 0x27:
mod |= TTkK.ShiftModifier
evt = TTkMouseEvent.Move
mevt = TTkMouseEvent(x, y, key, evt, mod, tap, m.group(0).replace("\033", "<ESC>"))
if kevt or mevt:
return kevt, mevt, None
if stdinRead.startswith("\033[200~"):
TTkInput._pasteBuffer = stdinRead[6:]
TTkInput._bracketedPaste = True
return None, None, None
hex = [f"0x{ord(x):02x}" for x in stdinRead]
TTkLog.error("UNHANDLED: "+stdinRead.replace("\033","<ESC>") + " - "+",".join(hex))

28
docs/MDNotes/input/abstracrt.md

@ -0,0 +1,28 @@
# 0.36.0-a
Single Thread,
```
TTkInputDriver TTkInput TTK
read() <- stdin
yield inString --> for inString in _readInput.read()
key_process(inString)
inputEvent.emit(kevt, mevt) ----> _processInput
pasteEvent.emit(str) ----> _pasteInput
```
# 0.xx.0-a +
multithread
Rework key_process to return kevt,mevt,paste
```
TTkInputDriver TTkInput TTK
Thread1 Thread2 (mainn)
read() <- stdin
yield inString --> for inString in _readInput.read()
kevt,mevt,paste = key_process(inString)
queue.put(kevt,mevt,paste)
queue.get()
inputEvent.emit(kevt, mevt) ------> _processInput
pasteEvent.emit(str) ------> _pasteInput
```

205
tests/sandbox/js/ttkproxy.js

@ -0,0 +1,205 @@
/*
MIT License
Copyright (c) 2023 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// Declaration
class TTkProxy {
constructor(term) {
this.term = term
}
pyodideProxy = {
consoleLog: function(m){
console.log("TTk:",m)
},
termPush: function (s) {
this.term.write(s);
},
termSize: function () {
return [this.term.cols, this.term.rows]
},
setTimeout: function(t, i) {
// console.log("TIME (Start)",i,t)
return setTimeout(() => this.ttk_timer(i), t)
},
stopTimeout: function(t) {
// console.log("TIME (Stop)",t)
clearTimeout(t)
},
clearTimeout: function(){
let highestTimeoutId = setTimeout(";");
for (let i = 0 ; i < highestTimeoutId ; i++) {
clearTimeout(i);
}
},
setInterval: function(t, i) {
setTinterval(() => console.log('WIP -> Interval' + i), t)
}
};
async init(){
this.pyodide = await loadPyodide();
this.ttk_timer = (i) => console.log("ttk_timer unimplemented")
this.term.write('Pyodide ('+this.pyodide.version+') - Loaded\n\r')
this.pyodide.registerJsModule("pyodideProxy", this.pyodideProxy);
this.term.write('Pyodide Proxy - Loaded\n\r')
}
async loadLib(lib) {
let zipResponse = await fetch(lib);
let zipBinary = await zipResponse.arrayBuffer();
this.pyodide.unpackArchive(zipBinary, ".tar.gz");
}
async loadFile(fileUri,file){
this.pyodide.FS.writeFile(this.pyodide.FS.currentPath+file, await (await fetch(fileUri)).text());
}
readFile(file){
return this.pyodide.FS.readFile(file, {encoding:'utf8'})
}
currentPath(){
return this.pyodide.FS.currentPath
}
getAllFiles(p){
let ls = this.pyodide.FS.readdir(p)
let ret = []
for(let i=0 ; i<ls.length; i++){
let n = p+"/"+ls[i]
if(ls[i]=='.' || ls[i]=='..' || n==(this.pyodide.FS.currentPath+"/TermTk")) continue;
if( this.pyodide.FS.isDir(this.pyodide.FS.lstat(n).mode)){
ret.push({id:n, text:ls[i], expanded: true, nodes:this.getAllFiles(n)})
}else{
if(n.endsWith('.py')){
ret.push({id:n, text:ls[i]})
}
}
}
return ret
}
preRun(){
this.namespace = this.pyodide.globals.get("dict")();
this.pyodide.runPython(`
import sys
import TermTk as ttk
from TermTk.TTkCore.TTkTerm.input import TTkInput
import pyodideProxy
def ttk_input(val):
kevt,mevt,paste = TTkInput.key_process(val)
if kevt or mevt:
TTkInput.inputEvent.emit(kevt, mevt)
if paste:
TTkInput.pasteEvent.emit(paste)
def ttk_resize(w,h):
ttk.TTkLog.debug(f"Resize: {w=} {h=}")
if ttk.TTkHelper._rootWidget:
ttk.TTkHelper._rootWidget._win_resize_cb(w,h)
ttk.TTkHelper.rePaintAll()
ttk.TTkTerm.cont()
def ttk_timer(tid):
ttk.TTkTimer.triggerTimerId(tid)
def ttk_log(val):
# hex = [f"0x{ord(x):02x}" for x in val]
ttk.TTkLog.debug("---> "+val.replace("\\033","<ESC>") + " - ")
ttk.TTkHelper.paintAll()
def ttk_clean():
if ttk.TTkHelper._rootWidget:
ttk.TTkTimer.pyodideQuit()
ttk.TTkHelper._rootWidget.quit()
ttk.TTkHelper._focusWidget = None
ttk.TTkHelper._rootCanvas = None
ttk.TTkHelper._rootWidget = None
ttk.TTkHelper._updateBuffer = set()
ttk.TTkHelper._updateWidget = set()
ttk.TTkHelper._overlay = []
ttk.TTkHelper._shortcut = []
ttk.TTkLog._messageHandler = [message_handler]
def ttk_init():
ttk.TTkToolTip.toolTipTimer = ttk.TTkTimer()
ttk.TTkToolTip.toolTipTimer.timeout.connect(ttk.TTkToolTip._toolTipShow)
def message_handler(mode, context, message):
msgType = "DEBUG"
if mode == ttk.TTkLog.InfoMsg: msgType = "[INFO]"
elif mode == ttk.TTkLog.WarningMsg: msgType = "[WARNING]"
elif mode == ttk.TTkLog.CriticalMsg: msgType = "[CRITICAL]"
elif mode == ttk.TTkLog.FatalMsg: msgType = "[FATAL]"
elif mode == ttk.TTkLog.ErrorMsg: msgType = "[ERROR]"
pyodideProxy.consoleLog(f"{msgType} {context.file} {message}")
# Register the callback to the message handler
ttk.TTkLog.installMessageHandler(message_handler)
`,{ globals: this.namespace }
);
this.ttk_log = this.namespace.get("ttk_log");
this.ttk_input = this.namespace.get("ttk_input");
this.ttk_timer = this.namespace.get("ttk_timer");
this.ttk_resize = this.namespace.get("ttk_resize");
this.ttk_clean = this.namespace.get("ttk_clean");
this.ttk_init = this.namespace.get("ttk_init");
this.pyodideProxy.ttk_timer = this.ttk_timer
this.pyodideProxy.term = this.term
this.term.onResize( (obj) => {
this.term.reset()
this.ttk_resize(obj.cols, obj.rows)
});
this.term.onData((d, evt) => { this.ttk_input(d) })
this.pyodide.runPython(`
import sys,os
sys.path.append(os.path.join(sys.path[0],'demo'))
__name__ = "__main__"
`,{ globals: this.namespace }
);
}
run(code,filename,fps) {
this.ttk_clean()
console.log("Run App")
let pwd = this.pyodide.PATH.dirname(filename)
this.pyodide.runPython(`
__file__='`+filename+`'
os.chdir('`+pwd+`')
ttk.TTkCfg.maxFps = `+fps,{ globals: this.namespace })
this.ttk_init()
this.pyodide.runPython(code,{ globals: this.namespace });
this.ttk_log(filename + " - LOADED")
}
}

181
tests/sandbox/sandbox.html

@ -22,6 +22,7 @@
<script src="www/codemirror/codemirror.js"></script>
<script src="www/codemirror/modes/python.js"></script>
<script src="js/ttkproxy.js"></script>
<style>
.CodeMirror { height: 100%; }
</style>
@ -113,87 +114,24 @@
/* pyodide demo */
var pyodide = null
var run = null
var namespace = null
async function main(){
pyodide = await loadPyodide();
let pyodideProxy = {
consoleLog: function(m){
console.log("TTk:",m)
},
termPush: function (s) {
term.write(s);
},
termSize: function () {
return [term.cols, term.rows]
},
setTimeout: function(t, i) {
// console.log("TIME (Start)",i,t)
return setTimeout(() => ttk_timer(i), t)
},
stopTimeout: function(t) {
// console.log("TIME (Stop)",t)
clearTimeout(t)
},
clearTimeout: function(){
let highestTimeoutId = setTimeout(";");
for (let i = 0 ; i < highestTimeoutId ; i++) {
clearTimeout(i);
}
},
setInterval: function(t, i) {
setTinterval(() => console.log('WIP -> Interval' + i), t)
}
};
term.write('Pyodide ('+pyodide.version+') - Loaded\n\r')
pyodide.registerJsModule("pyodideProxy", pyodideProxy);
term.write('Pyodide Proxy - Loaded\n\r')
let zipResponse = await fetch("bin/TermTk.tgz");
let zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
ttkProxy = new TTkProxy(term)
await ttkProxy.init()
await ttkProxy.loadLib("bin/TermTk.tgz");
term.write('TermTk - Loaded\n\r')
zipResponse = await fetch("bin/demo.tgz");
zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
await ttkProxy.loadLib("bin/demo.tgz");
term.write('Demos - Loaded\n\r')
zipResponse = await fetch("bin/tutorial.tgz");
zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
await ttkProxy.loadLib("bin/tutorial.tgz");
term.write('Tutorials - Loaded\n\r')
/* Sidebar
Fetch all the files in the pyodide.FS
And push them in the sidebar
*/
let getAllFiles = function(p){
let ls = pyodide.FS.readdir(p)
let ret = []
for(let i=0 ; i<ls.length; i++){
let n = p+"/"+ls[i]
if(ls[i]=='.' || ls[i]=='..' || n==(pyodide.FS.currentPath+"/TermTk")) continue;
if( pyodide.FS.isDir(pyodide.FS.lstat(n).mode)){
ret.push({id:n, text:ls[i], expanded: true, nodes:getAllFiles(n)})
}else{
if(n.endsWith('.py')){
ret.push({id:n, text:ls[i]})
}
}
}
return ret
}
let files = getAllFiles(pyodide.FS.currentPath)
let files = ttkProxy.getAllFiles(ttkProxy.currentPath())
new w2sidebar({
box: '#sidebar',
name: 'sidebar',
@ -205,7 +143,7 @@
});
var loadFile = function(f){
let content = pyodide.FS.readFile(f, {encoding:'utf8'})
let content = ttkProxy.readFile(f)
setCode(content)
document.getElementById("codeUri").value = f
}
@ -218,112 +156,23 @@
fileUri = urlParams.get("fileUri")
filePath = urlParams.get("filePath")
if (fileUri != null){
pyodide.FS.writeFile(pyodide.FS.currentPath+"/test_file.py", await (await fetch(fileUri)).text());
loadFile(pyodide.FS.currentPath+"/test_file.py")
ttkProxy.loadFile(fileUri, "test_file.py");
loadFile("test_file.py")
}else if (filePath != null){
loadFile(pyodide.FS.currentPath+"/"+filePath)
loadFile(filePath)
}else{
loadFile(pyodide.FS.currentPath+"/demo/demo.py")
loadFile("demo/demo.py")
}
//loadFile("/home/pyodide/tutorial/calculator/calculator.005.py")
w2ui.sidebar.select(pyodide.FS.currentPath+"/demo/demo.py")
w2ui.sidebar.select("demo/demo.py")
term.write('Starting Demo...\n\r')
namespace = pyodide.globals.get("dict")();
pyodide.runPython(`
import sys
import TermTk as ttk
from TermTk.TTkCore.TTkTerm.input import TTkInput
import pyodideProxy
def ttk_input(val):
TTkInput.key_process(val)
def ttk_resize(w,h):
ttk.TTkLog.debug(f"Resize: {w=} {h=}")
if ttk.TTkHelper._rootWidget:
ttk.TTkHelper._rootWidget._win_resize_cb(w,h)
ttk.TTkHelper.rePaintAll()
ttk.TTkTerm.cont()
def ttk_timer(tid):
ttk.TTkTimer.triggerTimerId(tid)
def ttk_log(val):
# hex = [f"0x{ord(x):02x}" for x in val]
ttk.TTkLog.debug("---> "+val.replace("\\033","<ESC>") + " - ")
ttk.TTkHelper.paintAll()
def ttk_clean():
if ttk.TTkHelper._rootWidget:
ttk.TTkTimer.pyodideQuit()
ttk.TTkHelper._rootWidget.quit()
ttk.TTkHelper._focusWidget = None
ttk.TTkHelper._rootCanvas = None
ttk.TTkHelper._rootWidget = None
ttk.TTkHelper._updateBuffer = set()
ttk.TTkHelper._updateWidget = set()
ttk.TTkHelper._overlay = []
ttk.TTkHelper._shortcut = []
ttk.TTkLog._messageHandler = [message_handler]
def ttk_init():
ttk.TTkToolTip.toolTipTimer = ttk.TTkTimer()
ttk.TTkToolTip.toolTipTimer.timeout.connect(ttk.TTkToolTip._toolTipShow)
def message_handler(mode, context, message):
msgType = "DEBUG"
if mode == ttk.TTkLog.InfoMsg: msgType = "[INFO]"
elif mode == ttk.TTkLog.WarningMsg: msgType = "[WARNING]"
elif mode == ttk.TTkLog.CriticalMsg: msgType = "[CRITICAL]"
elif mode == ttk.TTkLog.FatalMsg: msgType = "[FATAL]"
elif mode == ttk.TTkLog.ErrorMsg: msgType = "[ERROR]"
pyodideProxy.consoleLog(f"{msgType} {context.file} {message}")
# Register the callback to the message handler
ttk.TTkLog.installMessageHandler(message_handler)
`,{ globals: namespace }
);
let ttk_log = namespace.get("ttk_log");
let ttk_input = namespace.get("ttk_input");
let ttk_timer = namespace.get("ttk_timer");
let ttk_resize = namespace.get("ttk_resize");
let ttk_clean = namespace.get("ttk_clean");
let ttk_init = namespace.get("ttk_init");
term.onResize( (obj) => {
term.reset()
ttk_resize(obj.cols, obj.rows)
});
term.onData((d, evt) => { ttk_input(d) })
pyodide.runPython(`
import sys,os
sys.path.append(os.path.join(sys.path[0],'demo'))
__name__ = "__main__"
`,{ globals: namespace }
);
ttkProxy.preRun()
run = function(){
ttk_clean()
console.log("Run App")
let filename = document.getElementById("codeUri").value
let fps = document.getElementById("fpsCap").value
let pwd = pyodide.PATH.dirname(filename)
pyodide.runPython(`
__file__='`+filename+`'
os.chdir('`+pwd+`')
ttk.TTkCfg.maxFps = `+fps,{ globals: namespace })
ttk_init()
let content = getCode()
pyodide.runPython(content,{ globals: namespace });
ttk_log(filename + " - LOADED")
ttkProxy.run(getCode(), filename,fps)
};
run()
}

338
tests/sandbox/sandbox.old.html

@ -0,0 +1,338 @@
<!DOCTYPE html>
<html>
<head>
<title>Mr. pyTermTk Sandbox</title>
<link rel="icon" type="image/x-icon" href="www/favicon.ico">
<script src="www/pyodide/pyodide.js"></script>
<link href="www/xterm/xterm.css" rel="stylesheet" />
<script src="www/xterm/xterm.js"></script>
<script src="www/xterm-addon-fit/xterm-addon-fit.js"></script>
<script src="www/xterm-addon-unicode11/xterm-addon-unicode11.js"></script>
<link href="www/fontawesome/fontawesome.min.css" rel="stylesheet">
<link href="www/fontawesome/regular.min.css" rel="stylesheet">
<script type="text/javascript" src="www/w2ui/w2ui-2.0.min.js"></script>
<link rel="stylesheet" type="text/css" href="www/w2ui/w2ui-2.0.min.css" />
<link href="www/codemirror/theme/mbo.css" rel="stylesheet" >
<link href="www/codemirror/codemirror.css" rel="stylesheet" />
<script src="www/codemirror/codemirror.js"></script>
<script src="www/codemirror/modes/python.js"></script>
<style>
.CodeMirror { height: 100%; }
</style>
</head>
<body>
<div id="layout" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px"></div>
<script type="text/javascript">
let pstyle = 'border: 1px solid #efefef; padding: 5px;';
let expand = 'position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px';
new w2layout({
box: '#layout',
name: 'layout_pyTermTk_sandbox',
padding: 4,
panels: [
//{ type: 'top', size: 50, resizable: true, style: pstyle, html: 'top' },
{ type: 'left', size: 200, resizable: true, style: pstyle,
html: '<div id="sidebar" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px"></div>' },
{ type: 'main', style: pstyle,
toolbar: {
items: [
{ type: 'button', id: 'run_button', text: 'Run', icon: 'far fa-play-circle' },
{ type: 'html', id: 'uri',
html(item) {
let html =
'<div style="padding: 0px 10px; margin-top: -2px;" >'+
' URI: <input id="codeUri" size="50"/>'+
' FPS Cap: <input id="fpsCap" value="30" size="1">'+
'</div>';
return html;
},
},
],
onClick(event) { run(); }
},
html: '<div id="codeArea" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 25px"></div>'+
`<div id="codeArea" style="position: absolute; left: 15px; right: 0px; bottom: 0px">
<a href="https://github.com/ceccopierangiolieugenio/pyTermTk">pyTermTk</a> sandbox,
Powered by <a href="https://pyodide.org/">Pyodide</a>
and <a href="https://xtermjs.org">xterm.js</a>
and <a href="https://codemirror.net/5/">CodeMirror5</a>
and <a href="https://w2ui.com/">w2ui</a>
</div>`},
{ type: 'right', size: 1000, resizable: true, style: pstyle,
html: '<div id="terminal" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px"></div>' }
]
});
new w2field({ el: query('#fpsCap')[0], type: 'int', autoFormat: false })
</script>
<script type="text/javascript">
/* xterm.js demo */
/* https://www.npmjs.com/package/xterm-addon-fit */
const fitAddon = new FitAddon.FitAddon();
/* https://www.npmjs.com/package/xterm-addon-unicode11 */
const unicode11Addon = new Unicode11Addon.Unicode11Addon();
var term = new Terminal({allowProposedApi: true});
term.loadAddon(fitAddon);
term.loadAddon(unicode11Addon);
term.unicode.activeVersion = '11';
term.open(document.getElementById('terminal'));
term.write('xterm.js - Loaded\n\r')
fitAddon.fit()
w2ui.layout_pyTermTk_sandbox.on('resize', (event) => {
setTimeout(()=>{fitAddon.fit()},0.5)
});
/* Code Mirror */
let myCodeMirror = CodeMirror(document.getElementById('codeArea'), {
mode: "python",
lineNumbers: true,
styleActiveLine: true,
matchBrackets: true
});
myCodeMirror.setOption("theme", "mbo");
let getCode = function(){
return myCodeMirror.getValue()
}
let setCode = function(txt){
myCodeMirror.setValue(txt)
}
/* pyodide demo */
var pyodide = null
var run = null
var namespace = null
async function main(){
pyodide = await loadPyodide();
let pyodideProxy = {
consoleLog: function(m){
console.log("TTk:",m)
},
termPush: function (s) {
term.write(s);
},
termSize: function () {
return [term.cols, term.rows]
},
setTimeout: function(t, i) {
// console.log("TIME (Start)",i,t)
return setTimeout(() => ttk_timer(i), t)
},
stopTimeout: function(t) {
// console.log("TIME (Stop)",t)
clearTimeout(t)
},
clearTimeout: function(){
let highestTimeoutId = setTimeout(";");
for (let i = 0 ; i < highestTimeoutId ; i++) {
clearTimeout(i);
}
},
setInterval: function(t, i) {
setTinterval(() => console.log('WIP -> Interval' + i), t)
}
};
term.write('Pyodide ('+pyodide.version+') - Loaded\n\r')
pyodide.registerJsModule("pyodideProxy", pyodideProxy);
term.write('Pyodide Proxy - Loaded\n\r')
let zipResponse = await fetch("bin/TermTk.tgz");
let zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
term.write('TermTk - Loaded\n\r')
zipResponse = await fetch("bin/demo.tgz");
zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
term.write('Demos - Loaded\n\r')
zipResponse = await fetch("bin/tutorial.tgz");
zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
term.write('Tutorials - Loaded\n\r')
/* Sidebar
Fetch all the files in the pyodide.FS
And push them in the sidebar
*/
let getAllFiles = function(p){
let ls = pyodide.FS.readdir(p)
let ret = []
for(let i=0 ; i<ls.length; i++){
let n = p+"/"+ls[i]
if(ls[i]=='.' || ls[i]=='..' || n==(pyodide.FS.currentPath+"/TermTk")) continue;
if( pyodide.FS.isDir(pyodide.FS.lstat(n).mode)){
ret.push({id:n, text:ls[i], expanded: true, nodes:getAllFiles(n)})
}else{
if(n.endsWith('.py')){
ret.push({id:n, text:ls[i]})
}
}
}
return ret
}
let files = getAllFiles(pyodide.FS.currentPath)
new w2sidebar({
box: '#sidebar',
name: 'sidebar',
nodes: files })
w2ui.sidebar.on('click', function (event) {
console.log('Last Event: ' + event.type + ' Target: ' + event.target);
loadFile(event.target)
});
var loadFile = function(f){
let content = pyodide.FS.readFile(f, {encoding:'utf8'})
setCode(content)
document.getElementById("codeUri").value = f
}
/* check the "fileUri" field in the address
and load it if defined */
const queryString = window.location.search;
console.log(queryString);
const urlParams = new URLSearchParams(queryString);
fileUri = urlParams.get("fileUri")
filePath = urlParams.get("filePath")
if (fileUri != null){
pyodide.FS.writeFile(pyodide.FS.currentPath+"/test_file.py", await (await fetch(fileUri)).text());
loadFile(pyodide.FS.currentPath+"/test_file.py")
}else if (filePath != null){
loadFile(pyodide.FS.currentPath+"/"+filePath)
}else{
loadFile(pyodide.FS.currentPath+"/demo/demo.py")
}
//loadFile("/home/pyodide/tutorial/calculator/calculator.005.py")
w2ui.sidebar.select(pyodide.FS.currentPath+"/demo/demo.py")
term.write('Starting Demo...\n\r')
namespace = pyodide.globals.get("dict")();
pyodide.runPython(`
import sys
import TermTk as ttk
from TermTk.TTkCore.TTkTerm.input import TTkInput
import pyodideProxy
def ttk_input(val):
kevt,mevt,paste = TTkInput.key_process(val)
if kevt or mevt:
TTkInput.inputEvent.emit(kevt, mevt)
if paste:
TTkInput.pasteEvent.emit(paste)
def ttk_resize(w,h):
ttk.TTkLog.debug(f"Resize: {w=} {h=}")
if ttk.TTkHelper._rootWidget:
ttk.TTkHelper._rootWidget._win_resize_cb(w,h)
ttk.TTkHelper.rePaintAll()
ttk.TTkTerm.cont()
def ttk_timer(tid):
ttk.TTkTimer.triggerTimerId(tid)
def ttk_log(val):
# hex = [f"0x{ord(x):02x}" for x in val]
ttk.TTkLog.debug("---> "+val.replace("\\033","<ESC>") + " - ")
ttk.TTkHelper.paintAll()
def ttk_clean():
if ttk.TTkHelper._rootWidget:
ttk.TTkTimer.pyodideQuit()
ttk.TTkHelper._rootWidget.quit()
ttk.TTkHelper._focusWidget = None
ttk.TTkHelper._rootCanvas = None
ttk.TTkHelper._rootWidget = None
ttk.TTkHelper._updateBuffer = set()
ttk.TTkHelper._updateWidget = set()
ttk.TTkHelper._overlay = []
ttk.TTkHelper._shortcut = []
ttk.TTkLog._messageHandler = [message_handler]
def ttk_init():
ttk.TTkToolTip.toolTipTimer = ttk.TTkTimer()
ttk.TTkToolTip.toolTipTimer.timeout.connect(ttk.TTkToolTip._toolTipShow)
def message_handler(mode, context, message):
msgType = "DEBUG"
if mode == ttk.TTkLog.InfoMsg: msgType = "[INFO]"
elif mode == ttk.TTkLog.WarningMsg: msgType = "[WARNING]"
elif mode == ttk.TTkLog.CriticalMsg: msgType = "[CRITICAL]"
elif mode == ttk.TTkLog.FatalMsg: msgType = "[FATAL]"
elif mode == ttk.TTkLog.ErrorMsg: msgType = "[ERROR]"
pyodideProxy.consoleLog(f"{msgType} {context.file} {message}")
# Register the callback to the message handler
ttk.TTkLog.installMessageHandler(message_handler)
`,{ globals: namespace }
);
let ttk_log = namespace.get("ttk_log");
let ttk_input = namespace.get("ttk_input");
let ttk_timer = namespace.get("ttk_timer");
let ttk_resize = namespace.get("ttk_resize");
let ttk_clean = namespace.get("ttk_clean");
let ttk_init = namespace.get("ttk_init");
term.onResize( (obj) => {
term.reset()
ttk_resize(obj.cols, obj.rows)
});
term.onData((d, evt) => { ttk_input(d) })
pyodide.runPython(`
import sys,os
sys.path.append(os.path.join(sys.path[0],'demo'))
__name__ = "__main__"
`,{ globals: namespace }
);
run = function(){
ttk_clean()
console.log("Run App")
let filename = document.getElementById("codeUri").value
let fps = document.getElementById("fpsCap").value
let pwd = pyodide.PATH.dirname(filename)
pyodide.runPython(`
__file__='`+filename+`'
os.chdir('`+pwd+`')
ttk.TTkCfg.maxFps = `+fps,{ globals: namespace })
ttk_init()
let content = getCode()
pyodide.runPython(content,{ globals: namespace });
ttk_log(filename + " - LOADED")
};
run()
}
main()
</script>
</body>
</html>

148
tests/sandbox/standalone.fullscreen.html

@ -10,11 +10,14 @@
<script src="www/xterm/xterm.js"></script>
<script src="www/xterm-addon-fit/xterm-addon-fit.js"></script>
<script src="www/xterm-addon-unicode11/xterm-addon-unicode11.js"></script>
<link href="www/fontawesome/fontawesome.min.css" rel="stylesheet">
<link href="www/fontawesome/regular.min.css" rel="stylesheet">
<!--
<link href="https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/xterm/xterm.css" rel="stylesheet" />
<script src="https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/xterm/xterm.js"></script>
<script src="https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/xterm-addon-fit/xterm-addon-fit.js"></script>
-->
<script src="js/ttkproxy.js"></script>
</head>
<body>
@ -37,148 +40,27 @@
term.write('xterm.js - Loaded\n\r')
window.addEventListener('resize', (event) => {
setTimeout(()=>{fitAddon.fit()},0.5)
});
fitAddon.fit()
/* pyodide demo */
var pyodide = null
var run = null
var namespace = null
async function main(){
pyodide = await loadPyodide();
let pyodideProxy = {
consoleLog: function(m){
console.log("TTk:",m)
},
termPush: function (s) {
term.write(s);
},
termSize: function () {
return [term.cols, term.rows]
},
setTimeout: function(t, i) {
// console.log("TIME",i,t)
setTimeout(() => ttk_timer(i), t)
},
clearTimeout: function(){
let highestTimeoutId = setTimeout(";");
for (let i = 0 ; i < highestTimeoutId ; i++) {
clearTimeout(i);
}
},
setInterval: function(t, i) {
setTinterval(() => console.log('WIP -> Interval' + i), t)
}
};
pyodide.registerJsModule("pyodideProxy", pyodideProxy);
term.write('Pyodide Proxy - Loaded\n\r')
let zipResponse = await fetch("bin/TermTk.tgz");
let zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
ttkProxy = new TTkProxy(term)
await ttkProxy.init()
await ttkProxy.loadLib("bin/TermTk.tgz");
term.write('TermTk - Loaded\n\r')
zipResponse = await fetch("bin/demo.tgz");
zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
await ttkProxy.loadLib("bin/demo.tgz");
term.write('Demos - Loaded\n\r')
term.write('Starting Demo...\n\r')
namespace = pyodide.globals.get("dict")();
pyodide.runPython(`
import sys
import TermTk as ttk
import pyodideProxy
def ttk_input(val):
if ttk.TTkHelper._rootWidget and ttk.TTkHelper._rootWidget._input:
ttk.TTkHelper._rootWidget._input.key_process(val)
def ttk_resize(w,h):
ttk.TTkLog.debug(f"Resize: {w=} {h=}")
if ttk.TTkHelper._rootWidget:
ttk.TTkHelper._rootWidget._win_resize_cb(w,h)
ttk.TTkHelper.rePaintAll()
# TODO: I need to get rid of this:
ttk.TTkTerm.push(ttk.TTkTerm.ALT_SCREEN + ttk.TTkTerm.CLEAR + ttk.TTkTerm.Cursor.HIDE + ttk.TTkTerm.escTitle(ttk.TTkTerm.title))
ttk.TTkTerm.push(ttk.TTkTerm.Mouse.ON)
def ttk_timer(tid):
ttk.TTkTimer.triggerTimerId(tid)
def ttk_log(val):
# hex = [f"0x{ord(x):02x}" for x in val]
ttk.TTkLog.debug("---> "+val.replace("\\033","<ESC>") + " - ")
ttk.TTkHelper.paintAll()
def ttk_clean():
if ttk.TTkHelper._rootWidget:
ttk.TTkTimer.pyodideQuit()
ttk.TTkHelper._rootWidget.quit()
ttk.TTkHelper._focusWidget = None
ttk.TTkHelper._rootCanvas = None
ttk.TTkHelper._rootWidget = None
ttk.TTkHelper._updateBuffer = []
ttk.TTkHelper._updateWidget = []
ttk.TTkHelper._overlay = []
ttk.TTkHelper._shortcut = []
ttk.TTkLog._messageHandler = [message_handler]
def message_handler(mode, context, message):
msgType = "DEBUG"
if mode == ttk.TTkLog.InfoMsg: msgType = "[INFO]"
elif mode == ttk.TTkLog.WarningMsg: msgType = "[WARNING]"
elif mode == ttk.TTkLog.CriticalMsg: msgType = "[CRITICAL]"
elif mode == ttk.TTkLog.FatalMsg: msgType = "[FATAL]"
elif mode == ttk.TTkLog.ErrorMsg: msgType = "[ERROR]"
pyodideProxy.consoleLog(f"{msgType} {context.file} {message}")
# Register the callback to the message handler
ttk.TTkLog.installMessageHandler(message_handler)
`,{ globals: namespace }
);
let ttk_log = namespace.get("ttk_log");
let ttk_input = namespace.get("ttk_input");
let ttk_timer = namespace.get("ttk_timer");
let ttk_resize = namespace.get("ttk_resize");
let ttk_clean = namespace.get("ttk_clean");
term.onResize( (obj) => {
term.reset()
ttk_resize(obj.cols, obj.rows)
});
term.onData((d, evt) => { ttk_input(d) })
pyodide.runPython(`
import sys,os
sys.path.append(os.path.join(sys.path[0],'demo'))
__file__='/home/pyodide/demo/demo.py'
__name__ = "__main__"
os.chdir('/home/pyodide/demo')
`,{ globals: namespace }
);
console.log("Run App")
let content = pyodide.FS.readFile("demo.py", {encoding:'utf8'})
pyodide.runPython(content,{ globals: namespace });
// TODO: I need to get rid of this:
pyodide.runPython(`
# TODO: I need to get rid of this:
ttk.TTkTerm.push(ttk.TTkTerm.ALT_SCREEN + ttk.TTkTerm.CLEAR + ttk.TTkTerm.Cursor.HIDE + ttk.TTkTerm.escTitle(ttk.TTkTerm.title))
ttk.TTkTerm.push(ttk.TTkTerm.Mouse.ON)
`,{ globals: namespace }
);
ttk_log("demo/demo.py - LOADED")
console.log("pippo")
fitAddon.fit()
ttkProxy.preRun()
let file = "demo/demo.py"
let content = ttkProxy.readFile(file)
ttkProxy.run(content, file, 60)
}
main()
</script>

150
tests/sandbox/standalone.html

@ -8,11 +8,18 @@
<link href="www/xterm/xterm.css" rel="stylesheet" />
<script src="www/xterm/xterm.js"></script>
<!--
<script src="www/xterm-addon-fit/xterm-addon-fit.js"></script>
-->
<script src="www/xterm-addon-unicode11/xterm-addon-unicode11.js"></script>
<link href="www/fontawesome/fontawesome.min.css" rel="stylesheet">
<link href="www/fontawesome/regular.min.css" rel="stylesheet">
<!--
<link href="https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/xterm/xterm.css" rel="stylesheet" />
<script src="https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/xterm/xterm.js"></script>
-->
<script src="js/ttkproxy.js"></script>
</head>
<body>
@ -20,10 +27,13 @@
<script type="text/javascript">
/* xterm.js demo */
/* https://www.npmjs.com/package/xterm-addon-fit */
// const fitAddon = new FitAddon.FitAddon();
/* https://www.npmjs.com/package/xterm-addon-unicode11 */
const unicode11Addon = new Unicode11Addon.Unicode11Addon();
var term = new Terminal({allowProposedApi: true});
// term.loadAddon(fitAddon);
term.loadAddon(unicode11Addon);
term.unicode.activeVersion = '11';
@ -32,143 +42,27 @@
term.write('xterm.js - Loaded\n\r')
// fitAddon.fit()
/* pyodide demo */
var pyodide = null
var run = null
var namespace = null
async function main(){
pyodide = await loadPyodide();
let pyodideProxy = {
consoleLog: function(m){
console.log("TTk:",m)
},
termPush: function (s) {
term.write(s);
},
termSize: function () {
return [term.cols, term.rows]
},
setTimeout: function(t, i) {
// console.log("TIME",i,t)
setTimeout(() => ttk_timer(i), t)
},
clearTimeout: function(){
let highestTimeoutId = setTimeout(";");
for (let i = 0 ; i < highestTimeoutId ; i++) {
clearTimeout(i);
}
},
setInterval: function(t, i) {
setTinterval(() => console.log('WIP -> Interval' + i), t)
}
};
pyodide.registerJsModule("pyodideProxy", pyodideProxy);
term.write('Pyodide Proxy - Loaded\n\r')
let zipResponse = await fetch("bin/TermTk.tgz");
let zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
ttkProxy = new TTkProxy(term)
await ttkProxy.init()
await ttkProxy.loadLib("bin/TermTk.tgz");
term.write('TermTk - Loaded\n\r')
zipResponse = await fetch("bin/demo.tgz");
zipBinary = await zipResponse.arrayBuffer();
pyodide.unpackArchive(zipBinary, ".tar.gz");
await ttkProxy.loadLib("bin/demo.tgz");
term.write('Demos - Loaded\n\r')
term.write('Starting Demo...\n\r')
namespace = pyodide.globals.get("dict")();
pyodide.runPython(`
import sys
import TermTk as ttk
import pyodideProxy
def ttk_input(val):
if ttk.TTkHelper._rootWidget and ttk.TTkHelper._rootWidget._input:
ttk.TTkHelper._rootWidget._input.key_process(val)
def ttk_resize(w,h):
ttk.TTkLog.debug(f"Resize: {w=} {h=}")
if ttk.TTkHelper._rootWidget:
ttk.TTkHelper._rootWidget._win_resize_cb(w,h)
ttk.TTkHelper.rePaintAll()
# TODO: I need to get rid of this:
ttk.TTkTerm.push(ttk.TTkTerm.ALT_SCREEN + ttk.TTkTerm.CLEAR + ttk.TTkTerm.Cursor.HIDE + ttk.TTkTerm.escTitle(ttk.TTkTerm.title))
ttk.TTkTerm.push(ttk.TTkTerm.Mouse.ON)
def ttk_timer(tid):
ttk.TTkTimer.triggerTimerId(tid)
def ttk_log(val):
# hex = [f"0x{ord(x):02x}" for x in val]
ttk.TTkLog.debug("---> "+val.replace("\\033","<ESC>") + " - ")
ttk.TTkHelper.paintAll()
def ttk_clean():
if ttk.TTkHelper._rootWidget:
ttk.TTkTimer.pyodideQuit()
ttk.TTkHelper._rootWidget.quit()
ttk.TTkHelper._focusWidget = None
ttk.TTkHelper._rootCanvas = None
ttk.TTkHelper._rootWidget = None
ttk.TTkHelper._updateBuffer = []
ttk.TTkHelper._updateWidget = []
ttk.TTkHelper._overlay = []
ttk.TTkHelper._shortcut = []
ttk.TTkLog._messageHandler = [message_handler]
def message_handler(mode, context, message):
msgType = "DEBUG"
if mode == ttk.TTkLog.InfoMsg: msgType = "[INFO]"
elif mode == ttk.TTkLog.WarningMsg: msgType = "[WARNING]"
elif mode == ttk.TTkLog.CriticalMsg: msgType = "[CRITICAL]"
elif mode == ttk.TTkLog.FatalMsg: msgType = "[FATAL]"
elif mode == ttk.TTkLog.ErrorMsg: msgType = "[ERROR]"
pyodideProxy.consoleLog(f"{msgType} {context.file} {message}")
# Register the callback to the message handler
ttk.TTkLog.installMessageHandler(message_handler)
`,{ globals: namespace }
);
let ttk_log = namespace.get("ttk_log");
let ttk_input = namespace.get("ttk_input");
let ttk_timer = namespace.get("ttk_timer");
let ttk_resize = namespace.get("ttk_resize");
let ttk_clean = namespace.get("ttk_clean");
term.onResize( (obj) => {
term.reset()
ttk_resize(obj.cols, obj.rows)
});
term.onData((d, evt) => { ttk_input(d) })
pyodide.runPython(`
import sys,os
sys.path.append(os.path.join(sys.path[0],'demo'))
__file__='/home/pyodide/demo/demo.py'
__name__ = "__main__"
os.chdir('/home/pyodide/demo')
`,{ globals: namespace }
);
console.log("Run App")
let content = pyodide.FS.readFile("demo.py", {encoding:'utf8'})
pyodide.runPython(content,{ globals: namespace });
// TODO: I need to get rid of this:
pyodide.runPython(`
# TODO: I need to get rid of this:
ttk.TTkTerm.push(ttk.TTkTerm.ALT_SCREEN + ttk.TTkTerm.CLEAR + ttk.TTkTerm.Cursor.HIDE + ttk.TTkTerm.escTitle(ttk.TTkTerm.title))
ttk.TTkTerm.push(ttk.TTkTerm.Mouse.ON)
`,{ globals: namespace }
);
ttk_log("demo/demo.py - LOADED")
console.log("pippo")
ttkProxy.preRun()
let file = "demo/demo.py"
let content = ttkProxy.readFile(file)
ttkProxy.run(content, file, 60)
}
main()
</script>

12
tools/check.import.sh

@ -14,8 +14,6 @@ __check(){
-e "log.py:import inspect" \
-e "log.py:import logging" \
-e "log.py:from collections.abc import Callable, Set" \
-e "input.py:import platform" \
-e "input.py:from time import time" \
-e "term.py:import importlib.util" \
-e "term.*.py:import sys, os, signal" \
-e "term.*.py:from .term_base import TTkTermBase" \
@ -40,7 +38,14 @@ __check(){
-e "propertyanimation.py:import time, math" \
-e "terminal.py:from select import select" |
grep -v \
-e "TTkTerm/input.py:from ..drivers import TTkInputDriver" \
-e "TTkTerm/input_mono.py:from time import time" \
-e "TTkTerm/input_mono.py:import platform" \
-e "TTkTerm/input_mono.py:from ..drivers import TTkInputDriver" \
-e "TTkTerm/input_thread.py:from time import time" \
-e "TTkTerm/input_thread.py:import threading, queue" \
-e "TTkTerm/input_thread.py:from ..drivers import TTkInputDriver" \
-e "TTkTerm/input.py:from .input_thread import *" |
grep -v \
-e "TTkTerm/term.py:from ..drivers import *" \
-e "drivers/unix_thread.py:import sys, os" \
-e "drivers/unix_thread.py:from select import select" \
@ -77,6 +82,7 @@ __check(){
-e "TTkTerminal/terminalhelper.py:from select import select" \
-e "TTkTerminal/__init__.py:import importlib.util" \
-e "TTkTerminal/__init__.py:import platform"
} ;
if __check ; then

Loading…
Cancel
Save