diff --git a/Makefile b/Makefile index e2021b1f..59a9e05b 100644 --- a/Makefile +++ b/Makefile @@ -116,6 +116,10 @@ deployTest: .venv . .venv/bin/activate ; \ python3 -m twine upload --repository testpypi tmp/dist/* --verbose +itchDumbPaintToolexporter: + tools/webExporterInit.sh + python3 -m http.server --directory tmp + test: .venv # Record a stream # tests/pytest/test_001_demo.py -r test.input.bin diff --git a/TermTk/TTkCore/color.py b/TermTk/TTkCore/color.py index 19b4bae7..616687f7 100644 --- a/TermTk/TTkCore/color.py +++ b/TermTk/TTkCore/color.py @@ -113,7 +113,7 @@ class _TTkColor: cmax = max(r,g,b) cmin = min(r,g,b) - lum = (cmax-cmin)/2 + lum = (cmax+cmin)/2 if cmax == cmin: return 0,0,lum @@ -388,10 +388,67 @@ class TTkColor(_TTkColor): color_1 = color_fg_red + color_bg_blue color_2 = color_fg_red + TTkColor.bg('#FFFF00') color_3 = color_2 + TTkColor.UNDERLINE + TTkColor.BOLD + + # Use presets + color_4 = TTkColor.RED + color_5 = TTkColor.BG_YELLOW + color_4 + color_6 = color_5 + TTkColor.UNDERLINE + TTkColor.BOLD + ''' RST = _TTkColor() '''Reset to the default terminal color and modifiers''' + BLACK = _TTkColor(fg=( 0, 0, 0)) + '''(fg) #000000 - Black''' + WHITE = _TTkColor(fg=(255,255,255)) + '''(fg) #FFFFFF - White''' + RED = _TTkColor(fg=(255, 0, 0)) + '''(fg) #FF0000 - Red''' + GREEN = _TTkColor(fg=( 0,255, 0)) + '''(fg) #00FF00 - Green''' + BLUE = _TTkColor(fg=( 0, 0,255)) + '''(fg) #0000FF - Blue''' + CYAN = _TTkColor(fg=( 0,255,255)) + '''(fg) #00FFFF - Cyan''' + MAGENTA = _TTkColor(fg=(255, 0,255)) + '''(fg) #FF00FF - Magenta''' + YELLOW = _TTkColor(fg=(255,255, 0)) + '''(fg) #FFFF00 - Yellow''' + + FG_BLACK = BLACK + '''(fg) #000000 - Black''' + FG_WHITE = WHITE + '''(fg) #FFFFFF - White''' + FG_RED = RED + '''(fg) #FF0000 - Red''' + FG_GREEN = GREEN + '''(fg) #00FF00 - Green''' + FG_BLUE = BLUE + '''(fg) #0000FF - Blue''' + FG_CYAN = CYAN + '''(fg) #00FFFF - Cyan''' + FG_MAGENTA = MAGENTA + '''(fg) #FF00FF - Magenta''' + FG_YELLOW = YELLOW + '''(fg) #FFFF00 - Yellow''' + + BG_BLACK = BLACK.invertFgBg() + '''(bg) #000000 - Black''' + BG_WHITE = WHITE.invertFgBg() + '''(bg) #FFFFFF - White''' + BG_RED = RED.invertFgBg() + '''(bg) #FF0000 - Red''' + BG_GREEN = GREEN.invertFgBg() + '''(bg) #00FF00 - Green''' + BG_BLUE = BLUE.invertFgBg() + '''(bg) #0000FF - Blue''' + BG_CYAN = CYAN.invertFgBg() + '''(bg) #00FFFF - Cyan''' + BG_MAGENTA = MAGENTA.invertFgBg() + '''(bg) #FF00FF - Magenta''' + BG_YELLOW = YELLOW.invertFgBg() + '''(bg) #FFFF00 - Yellow''' + # Modifiers: BOLD = _TTkColor(mod=TTkHelper.Color.BOLD) '''**Bold** modifier''' diff --git a/TermTk/TTkCrossTools/__init__.py b/TermTk/TTkCrossTools/__init__.py new file mode 100644 index 00000000..25c440ef --- /dev/null +++ b/TermTk/TTkCrossTools/__init__.py @@ -0,0 +1 @@ +from .savetools import * \ No newline at end of file diff --git a/TermTk/TTkCrossTools/savetools.py b/TermTk/TTkCrossTools/savetools.py new file mode 100644 index 00000000..12469577 --- /dev/null +++ b/TermTk/TTkCrossTools/savetools.py @@ -0,0 +1,159 @@ +# MIT License +# +# Copyright (c) 2024 Eugenio Parodi +# +# 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__ = ['ttkCrossOpen', 'ttkCrossSave', 'ttkCrossSaveAs', 'TTkEncoding', 'ttkConnectDragOpen', 'ttkEmitDragOpen', 'ttkEmitFileOpen'] + +import os +import importlib.util +import json + +from TermTk import pyTTkSlot, pyTTkSignal +from TermTk import TTkLog +from TermTk import TTkMessageBox, TTkFileDialogPicker, TTkHelper, TTkString, TTkK, TTkColor + +ttkCrossOpen = None +ttkCrossSave = None +ttkCrossSaveAs = None +ttkEmitDragOpen = None +ttkEmitFileOpen = None +ttkConnectDragOpen = None + +class TTkEncoding(str): + TEXT = "text" + TEXT_PLAIN = "text/plain" + TEXT_PLAIN_UTF8 = "text/plain;charset=utf-8" + APPLICATION = 'application' + APPLICATION_JSON = 'application/json' + IMAGE = 'image' + IMAGE_PNG = 'image/png' + IMAGE_SVG = 'image/svg+xml' + IMAGE_JPG = 'image/jpeg' + +if importlib.util.find_spec('pyodideProxy'): + TTkLog.info("Using 'pyodideProxy' as clipboard manager") + import pyodideProxy + ttkDragOpen = {} + ttkFileOpen = pyTTkSignal(dict) + + def _open(path, encoding, filter, cb=None): + if not cb: return + ttkFileOpen.connect(cb) + pyodideProxy.openFile(encoding) + + def _save(filePath, content, encoding, filter=None): + pyodideProxy.saveFile(os.path.basename(filePath), content, encoding) + + def _connectDragOpen(encoding, cb): + if not encoding in ttkDragOpen: + ttkDragOpen[encoding] = pyTTkSignal(dict) + return ttkDragOpen[encoding].connect(cb) + + def _emitDragOpen(encoding, data): + for do in [ttkDragOpen[e] for e in ttkDragOpen if encoding.startswith(e)]: + do.emit(data) + + def _emitFileOpen(encoding, data): + ttkFileOpen.emit(data) + ttkFileOpen.clear() + + ttkCrossOpen = _open + ttkCrossSave = _save + ttkCrossSaveAs = _save + ttkEmitDragOpen = _emitDragOpen + ttkEmitFileOpen = _emitFileOpen + ttkConnectDragOpen = _connectDragOpen + +else: + def _crossDecoder_text(fileName) : + with open(fileName) as fp: + return fp.read() + def _crossDecoder_json(fileName) : + with open(fileName) as fp: + # return json.load(fp) + return fp.read() + def _crossDecoder_image(fileName): + return None + + _crossDecoder = { + TTkEncoding.TEXT : _crossDecoder_text , + TTkEncoding.TEXT_PLAIN : _crossDecoder_text , + TTkEncoding.TEXT_PLAIN_UTF8 : _crossDecoder_text , + TTkEncoding.APPLICATION : _crossDecoder_json , + TTkEncoding.APPLICATION_JSON : _crossDecoder_json , + TTkEncoding.IMAGE : _crossDecoder_image , + TTkEncoding.IMAGE_PNG : _crossDecoder_image , + TTkEncoding.IMAGE_SVG : _crossDecoder_image , + TTkEncoding.IMAGE_JPG : _crossDecoder_image , + } + + def _open(path, encoding, filter, cb=None): + if not cb: return + def __openFile(fileName): + _decoder = _crossDecoder.get(encoding,lambda _:None) + content = _decoder(fileName) + cb({'name':fileName, 'data':content}) + filePicker = TTkFileDialogPicker(pos = (3,3), size=(100,30), caption="Open", path=path, fileMode=TTkK.FileMode.ExistingFile ,filter=filter) + filePicker.pathPicked.connect(__openFile) + TTkHelper.overlay(None, filePicker, 5, 5, True) + + def _save(filePath, content, encoding): + TTkLog.info(f"Saving to: {filePath}") + with open(filePath,'w') as fp: + fp.write(content) + + def _saveAs(filePath, content, encoding, filter, cb=None): + if not cb: return + def _approveFile(fileName): + if os.path.exists(fileName): + @pyTTkSlot(TTkMessageBox.StandardButton) + def _cb(btn): + if btn == TTkMessageBox.StandardButton.Save: + ttkCrossSave(fileName,content,encoding) + elif btn == TTkMessageBox.StandardButton.Cancel: + return + if cb: + cb() + messageBox = TTkMessageBox( + text= ( + TTkString( f'A file named "{os.path.basename(fileName)}" already exists.\nDo you want to replace it?', TTkColor.BOLD) + + TTkString( f'\n\nReplacing it will overwrite its contents.') ), + icon=TTkMessageBox.Icon.Warning, + standardButtons=TTkMessageBox.StandardButton.Discard|TTkMessageBox.StandardButton.Save|TTkMessageBox.StandardButton.Cancel) + messageBox.buttonSelected.connect(_cb) + TTkHelper.overlay(None, messageBox, 5, 5, True) + else: + ttkCrossSave(fileName,content,encoding) + filePicker = TTkFileDialogPicker( + size=(100,30), path=filePath, + acceptMode=TTkK.AcceptMode.AcceptSave, + caption="Save As...", + fileMode=TTkK.FileMode.AnyFile , + filter=filter) + filePicker.pathPicked.connect(_approveFile) + TTkHelper.overlay(None, filePicker, 5, 5, True) + + ttkCrossOpen = _open + ttkCrossSave = _save + ttkCrossSaveAs = _saveAs + ttkEmitDragOpen = lambda a:None + ttkEmitFileOpen = lambda a:None + ttkConnectDragOpen = lambda a,b:None diff --git a/TermTk/TTkGui/clipboard.py b/TermTk/TTkGui/clipboard.py index 07e5b022..da626127 100644 --- a/TermTk/TTkGui/clipboard.py +++ b/TermTk/TTkGui/clipboard.py @@ -61,10 +61,21 @@ class TTkClipboard(): try: if importlib.util.find_spec('pyodideProxy'): TTkLog.info("Using 'pyodideProxy' as clipboard manager") - import pyodideProxy as _c - TTkClipboard._manager = _c - TTkClipboard._setText = _c.copy - TTkClipboard._text = _c.paste + import pyodideProxy + import asyncio + async def _async_co(): + text = await pyodideProxy.paste() + TTkLog.debug(f"ttkProxy paste_co: {text}") + return text + def _paste(): + loop = asyncio.get_event_loop() + text = loop.run_until_complete(_async_co()) + # text = loop.run_until_complete(pyodideProxy.paste()) + TTkLog.debug(f"ttkProxy paste: {text=} {_async_co()=}") + return text + TTkClipboard._manager = pyodideProxy + TTkClipboard._setText = pyodideProxy.copy + TTkClipboard._text = pyodideProxy.paste # _paste elif importlib.util.find_spec('copykitten'): TTkLog.info("Using 'copykitten' as clipboard manager") import copykitten as _c @@ -113,13 +124,13 @@ class TTkClipboard(): except Exception as e: TTkLog.error("Clipboard error, try to export X11 if you are running this UI via SSH") for line in str(e).split("\n"): - TTkLog.error(line) + TTkLog.error(str(line)) @staticmethod def text(): '''text''' if TTkClipboard._text: - txt = "" + txt = None try: txt = TTkClipboard._text() except Exception as e: diff --git a/TermTk/__init__.py b/TermTk/__init__.py index 482217d3..2ccdd521 100644 --- a/TermTk/__init__.py +++ b/TermTk/__init__.py @@ -1,11 +1,12 @@ -from .TTkCore import * -from .TTkTheme import * -from .TTkGui import * -from .TTkWidgets import * -from .TTkTypes import * -from .TTkLayouts import * +from .TTkCore import * +from .TTkTheme import * +from .TTkGui import * +from .TTkWidgets import * +from .TTkTypes import * +from .TTkLayouts import * from .TTkTestWidgets import * -from .TTkAbstract import * -from .TTkUiTools import * +from .TTkAbstract import * +from .TTkUiTools import * +from .TTkCrossTools import * TTkCfg.theme = TTkTheme() diff --git a/docs/MDNotes/Fonts/Font2Glyph.md b/docs/MDNotes/Fonts/Font2Glyph.md index f1eafb88..d0dfe333 100644 --- a/docs/MDNotes/Fonts/Font2Glyph.md +++ b/docs/MDNotes/Fonts/Font2Glyph.md @@ -13,4 +13,12 @@ You can use this command: /usr/share/fonts/truetype/unifont/unifont_upper.ttf: Unifont Upper:style=Regular /usr/share/fonts/opentype/3270/3270Condensed-Regular.otf: IBM 3270 Condensed:style=Condensed -``` \ No newline at end of file +``` + +Check the font rendering in the browser: +https://typezebra.com +OK: +* FreeSans Regular +* FreeSerif Regular +* FreeMono Regular + diff --git a/docs/MDNotes/webExporter/Javascript Open,DnD Files.md b/docs/MDNotes/webExporter/Javascript Open,DnD Files.md new file mode 100644 index 00000000..0860e174 --- /dev/null +++ b/docs/MDNotes/webExporter/Javascript Open,DnD Files.md @@ -0,0 +1,2 @@ +https://dev.to/shubhamtiwari909/drag-and-drop-file-using-javascript-2h99 +https://www.smashingmagazine.com/2018/01/drag-drop-file-uploader-vanilla-js/ \ No newline at end of file diff --git a/tests/sandbox/Makefile b/tests/sandbox/Makefile index 04859ddd..6642646b 100644 --- a/tests/sandbox/Makefile +++ b/tests/sandbox/Makefile @@ -4,7 +4,7 @@ testSandbox: python3 -m http.server --directory ./ www: - mkdir -p www/pyodide www/xterm/ www/xterm-addon-fit www/codemirror www/codemirror/theme www/codemirror/modes www/fontawesome www/w2ui www/webfonts www/nerdfonts + mkdir -p www/pyodide www/xterm/ www/xterm-addon-fit www/codemirror www/codemirror/theme www/codemirror/modes www/fontawesome www/w2ui www/webfonts www/fonts/nerdfonts wget -P www/pyodide/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/pyodide/pyodide.js wget -P www/pyodide/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/pyodide/python_stdlib.zip @@ -25,8 +25,8 @@ www: wget -P www/fontawesome/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/fontawesome/fontawesome.min.css wget -P www/webfonts/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/webfonts/fa-regular-400.woff2 - wget -P www/nerdfonts/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/nerdfonts/HurmitNerdFontMono-Regular.otf - wget -P www/nerdfonts/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/nerdfonts/DejaVuSansMNerdFont-Regular.ttf + wget -P www/fonts/nerdfonts/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/nerdfonts/HurmitNerdFontMono-Regular.otf + wget -P www/fonts/nerdfonts/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/nerdfonts/DejaVuSansMNerdFont-Regular.ttf wget -P www/w2ui/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/w2ui/w2ui-2.0.min.js wget -P www/w2ui/ https://ceccopierangiolieugenio.github.io/binaryRepo/pyTermTk/www/w2ui/w2ui-2.0.min.css @@ -43,6 +43,7 @@ updateXterm: www npm install xterm npm install xterm-addon-fit npm install xterm-addon-unicode11 + npm install xterm-addon-canvas cp node_modules/xterm/css/xterm.css \ node_modules/xterm/lib/xterm.js \ node_modules/xterm/lib/xterm.js.map \ @@ -53,6 +54,9 @@ updateXterm: www cp node_modules/xterm-addon-fit/lib/xterm-addon-fit.js \ node_modules/xterm-addon-fit/lib/xterm-addon-fit.js.map \ www/xterm-addon-fit/ + cp node_modules/xterm-addon-canvas/lib/xterm-addon-canvas.js \ + node_modules/xterm-addon-canvas/lib/xterm-addon-canvas.js.map \ + www/xterm-addon-fit/ rm -rf node_modules package.json package-lock.json buildSandbox: www diff --git a/tests/sandbox/sandbox.NerdFont.html b/tests/sandbox/sandbox.NerdFont.html index d0740d6a..bdac0341 100644 --- a/tests/sandbox/sandbox.NerdFont.html +++ b/tests/sandbox/sandbox.NerdFont.html @@ -29,9 +29,9 @@ /* @font-face { font-family: "NerdFont"; - src: url(www/nerdfonts/HurmitNerdFontMono-Regular.otf) format("opentype"); - src: url(www/nerdfonts/DejaVuSansMNerdFont-Regular.ttf) format("truetype"); - src: url(www/nerdfonts/DejaVuSansMNerdFont-Regular.ttf) format("truetype"); + src: url(www/fonts/nerdfonts/HurmitNerdFontMono-Regular.otf) format("opentype"); + src: url(www/fonts/nerdfonts/DejaVuSansMNerdFont-Regular.ttf) format("truetype"); + src: url(www/fonts/nerdfonts/DejaVuSansMNerdFont-Regular.ttf) format("truetype"); } */ @@ -84,7 +84,7 @@ + +
+