Source code for TermTk.TTkCrossTools.savetools

# MIT License
#
# Copyright (c) 2024 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__ = [
        'ttkCrossOpen',
        'ttkCrossSave', 'ttkCrossSaveAs',
        'TTkEncoding', 'ImageData',
        'ttkConnectDragOpen',
        'ttkEmitDragOpen', 'ttkEmitFileOpen']

import os
import importlib.util
import json
from dataclasses import dataclass

from TermTk import pyTTkSlot, pyTTkSignal
from TermTk import TTkLog
from TermTk import TTkMessageBox, TTkFileDialogPicker, TTkHelper, TTkString, TTkK, TTkColor

class ImageData:
    size:list[int,int] = (0,0)
    data:list[list[list[int,int,int,int]]] = []

ttkCrossOpen       = None
ttkCrossSave       = None
ttkCrossSaveAs     = None
ttkEmitDragOpen    = None
ttkEmitFileOpen    = None
ttkConnectDragOpen = None

[docs]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, cb=lambda _d:None): pyodideProxy.saveFile(os.path.basename(filePath), content, encoding) def _connectDragOpen(encoding, cb): if encoding not in ttkDragOpen: ttkDragOpen[encoding] = pyTTkSignal(dict) return ttkDragOpen[encoding].connect(cb) def _emitDragOpen(encoding, data): if encoding.startswith(TTkEncoding.IMAGE): from PIL import Image import io im = Image.open(io.BytesIO(data['data'])) data['data'] = im for do in [ttkDragOpen[e] for e in ttkDragOpen if encoding.startswith(e)]: do.emit(data) def _emitFileOpen(encoding, data): if encoding.startswith(TTkEncoding.IMAGE): from PIL import Image import io # TTkLog.debug(data['data']) # TTkLog.debug(type(data['data'])) # Image.open(data['data']) im = Image.open(io.BytesIO(data['data'])) # TTkLog.debug(f"{im.size}") data['data'] = im 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): from PIL import Image pilImage = Image.open(fileName) # pilImage = pilImage.convert('RGBA') # pilData = list(pilImage.getdata()) # data = ImageData() # w,h = data.size = pilImage.size # data.data = [pilData[i:i+w] for i in range(0, len(pilData), w)] return pilImage _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:TTkEncoding, filter:str, cb=None): if not cb: return if encoding.startswith(TTkEncoding.IMAGE): if not importlib.util.find_spec('PIL'): 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=lambda _d:None): 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({'name':fileName}) 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) if cb: cb({'name':fileName}) 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