Source code for TermTk.TTkWidgets.TTkPickers.textpicker

# 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.

__all__ = ['TTkTextPicker', 'TTkTextDialogPicker']


from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.helper import TTkHelper
from TermTk.TTkCore.signal import pyTTkSlot, pyTTkSignal
from TermTk.TTkCore.string import TTkString
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkGui.textcursor import TTkTextCursor
from TermTk.TTkGui.textdocument import TTkTextDocument
from TermTk.TTkLayouts.gridlayout import TTkGridLayout
from TermTk.TTkLayouts.boxlayout import TTkHBoxLayout
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView
from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea

from TermTk.TTkWidgets.widget import TTkWidget
from TermTk.TTkWidgets.container import TTkContainer
from TermTk.TTkWidgets.resizableframe import TTkResizableFrame
from TermTk.TTkWidgets.texedit import TTkTextEditView, TTkTextEdit
from TermTk.TTkWidgets.splitter import TTkSplitter
from TermTk.TTkWidgets.button import TTkButton
from TermTk.TTkWidgets.label import TTkLabel
from TermTk.TTkWidgets.checkbox import TTkCheckbox
from TermTk.TTkWidgets.window import TTkWindow
from TermTk.TTkWidgets.TTkModelView.filetree import TTkFileTree
from TermTk.TTkWidgets.TTkModelView.filetreewidgetitem import TTkFileTreeWidgetItem
from TermTk.TTkWidgets.TTkPickers.colorpicker import TTkColorButtonPicker

class _superSimpleHorizontalLine(TTkWidget):
    def paintEvent(self, canvas):
        w,h = self.size()
        canvas.drawText(pos=(0,h-1), text='โ”•'+('โ”'*(w-2))+'โ”™',color=TTkColor.fg("#888888"))

# List taken from:
# https://emojipicker.com

emoji = {
    'Smileys': "๐Ÿ˜€๐Ÿ˜๐Ÿ˜‚๐Ÿคฃ๐Ÿ˜ƒ๐Ÿ˜„๐Ÿ˜…๐Ÿ˜†๐Ÿ˜‰๐Ÿ˜Š๐Ÿ˜‹๐Ÿ˜Ž๐Ÿ˜๐Ÿ˜˜๐Ÿ˜—๐Ÿ˜™๐Ÿ˜š๐Ÿค—๐Ÿค”๐Ÿ˜๐Ÿ˜‘๐Ÿ˜ถ๐Ÿ™„๐Ÿ˜๐Ÿ˜ฃ๐Ÿ˜ฅ๐Ÿ˜ฎ๐Ÿค๐Ÿ˜ฏ๐Ÿ˜ช๐Ÿ˜ซ๐Ÿ˜ด๐Ÿ˜Œ๐Ÿค“๐Ÿ˜›๐Ÿ˜œ๐Ÿ˜๐Ÿคค๐Ÿ˜’๐Ÿ˜“๐Ÿ˜”๐Ÿ˜•๐Ÿ™ƒ๐Ÿค‘๐Ÿ˜ฒ๐Ÿ™๐Ÿ˜–๐Ÿ˜ž๐Ÿ˜Ÿ๐Ÿ˜ค๐Ÿ˜ข๐Ÿ˜ญ๐Ÿ˜ฆ๐Ÿ˜ง๐Ÿ˜จ๐Ÿ˜ฉ๐Ÿ˜ฌ๐Ÿ˜ฐ๐Ÿ˜ฑ๐Ÿ˜ณ๐Ÿ˜ต๐Ÿ˜ก๐Ÿ˜ ๐Ÿ˜‡๐Ÿค ๐Ÿคก๐Ÿคฅ๐Ÿ˜ท๐Ÿค’๐Ÿค•๐Ÿคข๐Ÿคง๐Ÿ˜ˆ๐Ÿ‘ฟ๐Ÿ‘น๐Ÿ‘บ๐Ÿ’€๐Ÿ‘ป๐Ÿ‘ฝ๐Ÿ‘พ๐Ÿค–๐Ÿ’ฉ๐Ÿ˜บ๐Ÿ˜ธ๐Ÿ˜น๐Ÿ˜ป๐Ÿ˜ผ๐Ÿ˜ฝ๐Ÿ™€๐Ÿ˜ฟ๐Ÿ˜พ๐Ÿ™ˆ๐Ÿ™‰๐Ÿ™Š๐Ÿ‘ฆ๐Ÿ‘ง๐Ÿ‘จ๐Ÿ‘ฉ๐Ÿ‘ด๐Ÿ‘ต๐Ÿ‘ถ๐Ÿ‘ผ",
    'Body':    "๐Ÿ’ช๐Ÿคณ๐Ÿ‘ˆ๐Ÿ‘‰๐Ÿ‘†๐Ÿ–•๐Ÿ‘‡๐Ÿคž๐Ÿ––๐Ÿค˜๐Ÿค™โœ‹๐Ÿ‘Œ๐Ÿ‘๐Ÿ‘ŽโœŠ๐Ÿ‘Š๐Ÿค›๐Ÿคœ๐Ÿคš๐Ÿ‘‹๐Ÿ‘๐Ÿ‘๐Ÿ™Œ๐Ÿ™๐Ÿค๐Ÿ’…๐Ÿ‘‚๐Ÿ‘ƒ๐Ÿ‘ฃ๐Ÿ‘€๐Ÿ‘…๐Ÿ‘„",
    # 'Flags':   "๐Ÿ‡ฆ๐Ÿ‡จ๐Ÿ‡ฆ๐Ÿ‡ฉ๐Ÿ‡ฆ๐Ÿ‡ช๐Ÿ‡ฆ๐Ÿ‡ซ๐Ÿ‡ฆ๐Ÿ‡ฌ๐Ÿ‡ฆ๐Ÿ‡ฎ๐Ÿ‡ฆ๐Ÿ‡ฑ๐Ÿ‡ฆ๐Ÿ‡ฒ๐Ÿ‡ฆ๐Ÿ‡ด๐Ÿ‡ฆ๐Ÿ‡ถ๐Ÿ‡ฆ๐Ÿ‡ท๐Ÿ‡ฆ๐Ÿ‡ธ๐Ÿ‡ฆ๐Ÿ‡น๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ‡ฆ๐Ÿ‡ผ๐Ÿ‡ฆ๐Ÿ‡ฝ๐Ÿ‡ฆ๐Ÿ‡ฟ๐Ÿ‡ง๐Ÿ‡ฆ๐Ÿ‡ง๐Ÿ‡ง๐Ÿ‡ง๐Ÿ‡ฉ๐Ÿ‡ง๐Ÿ‡ช๐Ÿ‡ง๐Ÿ‡ซ๐Ÿ‡ง๐Ÿ‡ฌ๐Ÿ‡ง๐Ÿ‡ญ๐Ÿ‡ง๐Ÿ‡ฎ๐Ÿ‡ง๐Ÿ‡ฏ๐Ÿ‡ง๐Ÿ‡ฑ๐Ÿ‡ง๐Ÿ‡ฒ๐Ÿ‡ง๐Ÿ‡ณ๐Ÿ‡ง๐Ÿ‡ด๐Ÿ‡ง๐Ÿ‡ถ๐Ÿ‡ง๐Ÿ‡ท๐Ÿ‡ง๐Ÿ‡ธ๐Ÿ‡ง๐Ÿ‡น๐Ÿ‡ง๐Ÿ‡ป๐Ÿ‡ง๐Ÿ‡ผ๐Ÿ‡ง๐Ÿ‡พ๐Ÿ‡ง๐Ÿ‡ฟ๐Ÿ‡จ๐Ÿ‡ฆ๐Ÿ‡จ๐Ÿ‡จ๐Ÿ‡จ๐Ÿ‡ฉ๐Ÿ‡จ๐Ÿ‡ซ๐Ÿ‡จ๐Ÿ‡ฌ๐Ÿ‡จ๐Ÿ‡ญ๐Ÿ‡จ๐Ÿ‡ฎ๐Ÿ‡จ๐Ÿ‡ฐ๐Ÿ‡จ๐Ÿ‡ฑ๐Ÿ‡จ๐Ÿ‡ฒ๐Ÿ‡จ๐Ÿ‡ณ๐Ÿ‡จ๐Ÿ‡ด๐Ÿ‡จ๐Ÿ‡ต๐Ÿ‡จ๐Ÿ‡ท๐Ÿ‡จ๐Ÿ‡บ๐Ÿ‡จ๐Ÿ‡ป๐Ÿ‡จ๐Ÿ‡ผ๐Ÿ‡จ๐Ÿ‡ฝ๐Ÿ‡จ๐Ÿ‡พ๐Ÿ‡จ๐Ÿ‡ฟ๐Ÿ‡ฉ๐Ÿ‡ช๐Ÿ‡ฉ๐Ÿ‡ฌ๐Ÿ‡ฉ๐Ÿ‡ฏ๐Ÿ‡ฉ๐Ÿ‡ฐ๐Ÿ‡ฉ๐Ÿ‡ฒ๐Ÿ‡ฉ๐Ÿ‡ด๐Ÿ‡ฉ๐Ÿ‡ฟ๐Ÿ‡ช๐Ÿ‡ฆ๐Ÿ‡ช๐Ÿ‡จ๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡ช๐Ÿ‡ฌ๐Ÿ‡ช๐Ÿ‡ญ๐Ÿ‡ช๐Ÿ‡ท๐Ÿ‡ช๐Ÿ‡ธ๐Ÿ‡ช๐Ÿ‡น๐Ÿ‡ช๐Ÿ‡บ๐Ÿ‡ซ๐Ÿ‡ฎ๐Ÿ‡ซ๐Ÿ‡ฏ๐Ÿ‡ซ๐Ÿ‡ฐ๐Ÿ‡ซ๐Ÿ‡ฒ๐Ÿ‡ซ๐Ÿ‡ด๐Ÿ‡ซ๐Ÿ‡ท๐Ÿ‡ฌ๐Ÿ‡ฆ๐Ÿ‡ฌ๐Ÿ‡ง๐Ÿ‡ฌ๐Ÿ‡ฉ๐Ÿ‡ฌ๐Ÿ‡ช๐Ÿ‡ฌ๐Ÿ‡ซ๐Ÿ‡ฌ๐Ÿ‡ฌ๐Ÿ‡ฌ๐Ÿ‡ญ๐Ÿ‡ฌ๐Ÿ‡ฎ๐Ÿ‡ฌ๐Ÿ‡ฑ๐Ÿ‡ฌ๐Ÿ‡ฒ๐Ÿ‡ฌ๐Ÿ‡ณ๐Ÿ‡ฌ๐Ÿ‡ต๐Ÿ‡ฌ๐Ÿ‡ถ๐Ÿ‡ฌ๐Ÿ‡ท๐Ÿ‡ฌ๐Ÿ‡ธ๐Ÿ‡ฌ๐Ÿ‡น๐Ÿ‡ฌ๐Ÿ‡บ๐Ÿ‡ฌ๐Ÿ‡ผ๐Ÿ‡ฌ๐Ÿ‡พ๐Ÿ‡ญ๐Ÿ‡ฐ๐Ÿ‡ญ๐Ÿ‡ฒ๐Ÿ‡ญ๐Ÿ‡ณ๐Ÿ‡ญ๐Ÿ‡ท๐Ÿ‡ญ๐Ÿ‡น๐Ÿ‡ญ๐Ÿ‡บ๐Ÿ‡ฎ๐Ÿ‡จ๐Ÿ‡ฎ๐Ÿ‡ฉ๐Ÿ‡ฎ๐Ÿ‡ช๐Ÿ‡ฎ๐Ÿ‡ฑ๐Ÿ‡ฎ๐Ÿ‡ฒ๐Ÿ‡ฎ๐Ÿ‡ณ๐Ÿ‡ฎ๐Ÿ‡ด๐Ÿ‡ฎ๐Ÿ‡ถ๐Ÿ‡ฎ๐Ÿ‡ท๐Ÿ‡ฎ๐Ÿ‡ธ๐Ÿ‡ฎ๐Ÿ‡น๐Ÿ‡ฏ๐Ÿ‡ช๐Ÿ‡ฏ๐Ÿ‡ฒ๐Ÿ‡ฏ๐Ÿ‡ด๐Ÿ‡ฏ๐Ÿ‡ต๐Ÿ‡ฐ๐Ÿ‡ช๐Ÿ‡ฐ๐Ÿ‡ฌ๐Ÿ‡ฐ๐Ÿ‡ญ๐Ÿ‡ฐ๐Ÿ‡ฎ๐Ÿ‡ฐ๐Ÿ‡ฒ๐Ÿ‡ฐ๐Ÿ‡ณ๐Ÿ‡ฐ๐Ÿ‡ต๐Ÿ‡ฐ๐Ÿ‡ท๐Ÿ‡ฐ๐Ÿ‡ผ๐Ÿ‡ฐ๐Ÿ‡พ๐Ÿ‡ฐ๐Ÿ‡ฟ๐Ÿ‡ฑ๐Ÿ‡ฆ๐Ÿ‡ฑ๐Ÿ‡ง๐Ÿ‡ฑ๐Ÿ‡จ๐Ÿ‡ฑ๐Ÿ‡ฎ๐Ÿ‡ฑ๐Ÿ‡ฐ๐Ÿ‡ฑ๐Ÿ‡ท๐Ÿ‡ฑ๐Ÿ‡ธ๐Ÿ‡ฑ๐Ÿ‡น๐Ÿ‡ฑ๐Ÿ‡บ๐Ÿ‡ฑ๐Ÿ‡ป๐Ÿ‡ฑ๐Ÿ‡พ๐Ÿ‡ฒ๐Ÿ‡ฆ๐Ÿ‡ฒ๐Ÿ‡จ๐Ÿ‡ฒ๐Ÿ‡ฉ๐Ÿ‡ฒ๐Ÿ‡ช๐Ÿ‡ฒ๐Ÿ‡ซ๐Ÿ‡ฒ๐Ÿ‡ฌ๐Ÿ‡ฒ๐Ÿ‡ญ๐Ÿ‡ฒ๐Ÿ‡ฐ๐Ÿ‡ฒ๐Ÿ‡ฑ๐Ÿ‡ฒ๐Ÿ‡ฒ๐Ÿ‡ฒ๐Ÿ‡ณ๐Ÿ‡ฒ๐Ÿ‡ด๐Ÿ‡ฒ๐Ÿ‡ต๐Ÿ‡ฒ๐Ÿ‡ถ๐Ÿ‡ฒ๐Ÿ‡ท๐Ÿ‡ฒ๐Ÿ‡ธ๐Ÿ‡ฒ๐Ÿ‡น๐Ÿ‡ฒ๐Ÿ‡บ๐Ÿ‡ฒ๐Ÿ‡ป๐Ÿ‡ฒ๐Ÿ‡ผ๐Ÿ‡ฒ๐Ÿ‡ฝ๐Ÿ‡ฒ๐Ÿ‡พ๐Ÿ‡ฒ๐Ÿ‡ฟ๐Ÿ‡ณ๐Ÿ‡ฆ๐Ÿ‡ณ๐Ÿ‡จ๐Ÿ‡ณ๐Ÿ‡ช๐Ÿ‡ณ๐Ÿ‡ซ๐Ÿ‡ณ๐Ÿ‡ฌ๐Ÿ‡ณ๐Ÿ‡ฎ๐Ÿ‡ณ๐Ÿ‡ฑ๐Ÿ‡ณ๐Ÿ‡ด๐Ÿ‡ณ๐Ÿ‡ต๐Ÿ‡ณ๐Ÿ‡ท๐Ÿ‡ณ๐Ÿ‡บ๐Ÿ‡ณ๐Ÿ‡ฟ๐Ÿ‡ด๐Ÿ‡ฒ๐Ÿ‡ต๐Ÿ‡ฆ๐Ÿ‡ต๐Ÿ‡ช๐Ÿ‡ต๐Ÿ‡ซ๐Ÿ‡ต๐Ÿ‡ฌ๐Ÿ‡ต๐Ÿ‡ญ๐Ÿ‡ต๐Ÿ‡ฐ๐Ÿ‡ต๐Ÿ‡ฑ๐Ÿ‡ต๐Ÿ‡ฒ๐Ÿ‡ต๐Ÿ‡ณ๐Ÿ‡ต๐Ÿ‡ท๐Ÿ‡ต๐Ÿ‡ธ๐Ÿ‡ต๐Ÿ‡น๐Ÿ‡ต๐Ÿ‡ผ๐Ÿ‡ต๐Ÿ‡พ๐Ÿ‡ถ๐Ÿ‡ฆ๐Ÿ‡ท๐Ÿ‡ช๐Ÿ‡ท๐Ÿ‡ด๐Ÿ‡ท๐Ÿ‡ธ๐Ÿ‡ท๐Ÿ‡บ๐Ÿ‡ท๐Ÿ‡ผ๐Ÿ‡ธ๐Ÿ‡ฆ๐Ÿ‡ธ๐Ÿ‡ง๐Ÿ‡ธ๐Ÿ‡จ๐Ÿ‡ธ๐Ÿ‡ฉ๐Ÿ‡ธ๐Ÿ‡ช๐Ÿ‡ธ๐Ÿ‡ฌ๐Ÿ‡ธ๐Ÿ‡ญ๐Ÿ‡ธ๐Ÿ‡ฎ๐Ÿ‡ธ๐Ÿ‡ฏ๐Ÿ‡ธ๐Ÿ‡ฐ๐Ÿ‡ธ๐Ÿ‡ฑ๐Ÿ‡ธ๐Ÿ‡ฒ๐Ÿ‡ธ๐Ÿ‡ณ๐Ÿ‡ธ๐Ÿ‡ด๐Ÿ‡ธ๐Ÿ‡ท๐Ÿ‡ธ๐Ÿ‡ธ๐Ÿ‡ธ๐Ÿ‡น๐Ÿ‡ธ๐Ÿ‡ป๐Ÿ‡ธ๐Ÿ‡ฝ๐Ÿ‡ธ๐Ÿ‡พ๐Ÿ‡ธ๐Ÿ‡ฟ๐Ÿ‡น๐Ÿ‡ฆ๐Ÿ‡น๐Ÿ‡จ๐Ÿ‡น๐Ÿ‡ฉ๐Ÿ‡น๐Ÿ‡ซ๐Ÿ‡น๐Ÿ‡ฌ๐Ÿ‡น๐Ÿ‡ญ๐Ÿ‡น๐Ÿ‡ฏ๐Ÿ‡น๐Ÿ‡ฐ๐Ÿ‡น๐Ÿ‡ฑ๐Ÿ‡น๐Ÿ‡ฒ๐Ÿ‡น๐Ÿ‡ณ๐Ÿ‡น๐Ÿ‡ด๐Ÿ‡น๐Ÿ‡ท๐Ÿ‡น๐Ÿ‡น๐Ÿ‡น๐Ÿ‡ป๐Ÿ‡น๐Ÿ‡ผ๐Ÿ‡น๐Ÿ‡ฟ๐Ÿ‡บ๐Ÿ‡ฆ๐Ÿ‡บ๐Ÿ‡ฌ๐Ÿ‡บ๐Ÿ‡ฒ๐Ÿ‡บ๐Ÿ‡ณ๐Ÿ‡บ๐Ÿ‡ธ๐Ÿ‡บ๐Ÿ‡พ๐Ÿ‡บ๐Ÿ‡ฟ๐Ÿ‡ป๐Ÿ‡ฆ๐Ÿ‡ป๐Ÿ‡จ๐Ÿ‡ป๐Ÿ‡ช๐Ÿ‡ป๐Ÿ‡ฌ๐Ÿ‡ป๐Ÿ‡ฎ๐Ÿ‡ป๐Ÿ‡ณ๐Ÿ‡ป๐Ÿ‡บ๐Ÿ‡ผ๐Ÿ‡ซ๐Ÿ‡ผ๐Ÿ‡ธ๐Ÿ‡ฝ๐Ÿ‡ฐ๐Ÿ‡พ๐Ÿ‡ช๐Ÿ‡พ๐Ÿ‡น๐Ÿ‡ฟ๐Ÿ‡ฆ๐Ÿ‡ฟ๐Ÿ‡ฒ๐Ÿ‡ฟ๐Ÿ‡ผ",
}

class _emojiPickerView(TTkAbstractScrollView):
    __slots__ = ('_btns', '_labels', 'emojiClicked')
    def __init__(self, *args, **kwargs) -> None:
        self.emojiClicked = pyTTkSignal(str)
        super().__init__(*args, **kwargs)
        self.viewChanged.connect(self._viewChangedHandler)
        self._btns = {}
        self._labels = {}
        for t in emoji:
            self._btns[t]=[]
            self._labels[t] = TTkLabel(parent=self, text=t,size=(len(t),1))
            for e in emoji[t]:
                self._btns[t].append(btn := TTkButton(parent=self, text=e,size=(4,3),border=True))
                def _cbEmoji(ch):
                    def _ccb(): self.emojiClicked.emit(ch)
                    return _ccb
                btn.clicked.connect(_cbEmoji(e))

    def resizeEvent(self, w, h):
        self._placeEmojis()
        return super().resizeEvent(w, h)

    def _placeEmojis(self):
        x,y=0,0
        w,h=self.size()
        for t in self._btns:
            if x:
                y+=3
            self._labels[t].move(0,y)
            x=0
            y+=1
            for e in self._btns[t]:
                e.move(x,y)
                if x+7>=w:
                    x=0
                    y+=3
                else:
                    x+=4

    @pyTTkSlot()
    def _viewChangedHandler(self):
        x,y = self.getViewOffsets()
        self.layout().setOffset(-x,-y)

    def viewFullAreaSize(self) -> (int, int):
        _,_,w,h = self.layout().fullWidgetAreaGeometry()
        return w , h

    def maximumWidth(self):   return 0x10000
    def maximumHeight(self):  return 0x10000
    def minimumWidth(self):   return 0
    def minimumHeight(self):  return 0

class _emojiPickerArea(TTkAbstractScrollArea):
    __slots__ = ('_areaView')
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        kwargs.pop('parent',None)
        kwargs.pop('visible',None)
        self._areaView = _emojiPickerView(*args, **kwargs)
        self.setFocusPolicy(TTkK.ClickFocus)
        self.setViewport(self._areaView)

class _emojiPicker(TTkResizableFrame):
    __slots__ = ('emojiClicked')
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs|{'layout':TTkGridLayout()})
        self.layout().addWidget(epa := _emojiPickerArea())
        self.emojiClicked = epa.viewport().emojiClicked

[docs] class TTkTextDialogPicker(TTkWindow): __slots__ = ('_textEdit', '_autoSize') def __init__(self, *, autoSize=False, multiLine=True, wrapMode=TTkK.WidgetWidth, **kwargs) -> None: self._autoSize = autoSize super().__init__(**kwargs) fontLayout = TTkGridLayout(columnMinWidth=1) # Char Fg/Bg buttons fontLayout.addWidget(cb_fg := TTkCheckbox(text=" FG"),0,0) fontLayout.addWidget(btn_fgColor := TTkColorButtonPicker(border=True, enabled=False, maxSize=(7,3), minSize=(7,3)),1,0) fontLayout.addWidget(cb_bg := TTkCheckbox(text=" BG"),0,2) fontLayout.addWidget(btn_bgColor := TTkColorButtonPicker(border=True, enabled=False, maxSize=(7,3), minSize=(7,3)),1,2) # Char style buttons fontLayout.addWidget(btn_bold := TTkButton(border=True, maxSize=(5,3), minSize=(5,3), checkable=True, text=TTkString( 'a' , TTkColor.BOLD) ),1,4) fontLayout.addWidget(btn_italic := TTkButton(border=True, maxSize=(5,3), minSize=(5,3), checkable=True, text=TTkString( 'a' , TTkColor.ITALIC) ),1,5) fontLayout.addWidget(btn_underline := TTkButton(border=True, maxSize=(5,3), minSize=(5,3), checkable=True, text=TTkString(' a ', TTkColor.UNDERLINE) ),1,6) fontLayout.addWidget(btn_strikethrough := TTkButton(border=True, maxSize=(5,3), minSize=(5,3), checkable=True, text=TTkString(' a ', TTkColor.STRIKETROUGH)),1,7) fontLayout.addWidget(btn_emoji := TTkButton(border=True, maxSize=(6,4), minSize=(6,3), text=TTkString('๐Ÿ˜Ž')),1,9) fontLayout.addWidget(_superSimpleHorizontalLine(),0,10,2,1) self._textEdit = TTkTextEdit(document=kwargs.get('document',TTkTextDocument()),multiLine=multiLine) self._textEdit.setReadOnly(False) self._textEdit.setLineWrapMode(wrapMode) self._textEdit.setLineNumber('\n' in self._textEdit.toPlainText()) @pyTTkSlot() def _showEmojiPicker(): ep = _emojiPicker(size=(40,10)) def _addEmoji(e): self._textEdit.textCursor().insertText(e, moveCursor=True) ep.emojiClicked.connect(_addEmoji) TTkHelper.overlay(btn_emoji, ep, 0, 0) btn_emoji.clicked.connect(_showEmojiPicker) @pyTTkSlot(TTkColor) def _currentColorChangedCB(format): if fg := format.foreground(): cb_fg.setCheckState(TTkK.Checked) btn_fgColor.setEnabled() btn_fgColor.setColor(fg.invertFgBg()) else: cb_fg.setCheckState(TTkK.Unchecked) btn_fgColor.setDisabled() if bg := format.background(): cb_bg.setCheckState(TTkK.Checked) btn_bgColor.setEnabled() btn_bgColor.setColor(bg) else: cb_bg.setCheckState(TTkK.Unchecked) btn_bgColor.setDisabled() btn_bold.setChecked(format.bold()) btn_italic.setChecked(format.italic()) btn_underline.setChecked(format.underline()) btn_strikethrough.setChecked(format.strikethrough()) # TTkLog.debug(f"{fg=} {bg=} {bold=} {italic=} {underline=} {strikethrough= }") self._textEdit.currentColorChanged.connect(_currentColorChangedCB) def _setStyle(): color = TTkColor() if cb_fg.checkState() == TTkK.Checked: color += btn_fgColor.color().invertFgBg() if cb_bg.checkState() == TTkK.Checked: color += btn_bgColor.color() if btn_bold.isChecked(): color += TTkColor.BOLD if btn_italic.isChecked(): color += TTkColor.ITALIC if btn_underline.isChecked(): color += TTkColor.UNDERLINE if btn_strikethrough.isChecked(): color += TTkColor.STRIKETROUGH cursor = self._textEdit.textCursor() cursor.applyColor(color) cursor.setColor(color) self._textEdit.setFocus() cb_fg.toggled.connect(btn_fgColor.setEnabled) cb_bg.toggled.connect(btn_bgColor.setEnabled) cb_fg.clicked.connect(_setStyle) cb_bg.clicked.connect(_setStyle) btn_fgColor.colorSelected.connect(_setStyle) btn_bgColor.colorSelected.connect(_setStyle) btn_bold.clicked.connect(_setStyle) btn_italic.clicked.connect(_setStyle) btn_underline.clicked.connect(_setStyle) btn_strikethrough.clicked.connect(_setStyle) layout = TTkGridLayout() layout.addItem(fontLayout,0,0) layout.addWidget(self._textEdit,1,0) self.setLayout(layout) self._textEdit.viewport().viewChanged.connect(self._textPickerViewChanged)
[docs] def focusTextEdit(self): self._textEdit.setFocus()
@pyTTkSlot() def _textPickerViewChanged(self): w,h = self.size() self.resize(w,h) def resize(self, w: int, h: int): tw,th = self._textEdit.viewport().viewFullAreaSize() self._textEdit.setLineNumber(th>1) if not self._autoSize: return super().resize(w,h) t,b,l,r = self.getPadding() return super().resize(w, th+t+b+4)
[docs] class TTkTextPicker(TTkContainer): '''TTkTextPicker .. note:: This is an early unstable prototype Do not use it unless you know what you are doing And I've no idea what I am doing ''' __slots__ = ('_teButton','_textEdit', 'documentViewChanged', 'textChanged', '_autoSize') def __init__(self, *, text='', autoSize=False, multiLine=True, wrapMode=TTkK.WidgetWidth, **kwargs) -> None: self.documentViewChanged = pyTTkSignal(int,int) self._autoSize = autoSize super().__init__(**kwargs|{'layout':TTkHBoxLayout()}) self._textEdit = TTkTextEdit(pos=(0,0), size=(self.width()-2,self.height()),multiLine=multiLine) self._textEdit.setText(text) self._textEdit.setReadOnly(False) self._textEdit.setLineWrapMode(wrapMode) self.textChanged = self._textEdit.textChanged self._teButton = TTkButton(border=True, text='โ—‰', addStyle={'default':{'borderColor':TTkColor.fg("#AAAAFF")+TTkColor.bg("#002244")}} , pos=(self.width()-2,0), size=(2,self.height()), minSize=(3,1),maxWidth=3) self.layout().addWidget(self._textEdit) self.layout().addWidget(self._teButton) @pyTTkSlot() def _showTextDialogPicker(): w,h = self.size() tdp = TTkTextDialogPicker(size=(50,8+h), document=self._textEdit.document(), autoSize=autoSize, multiLine=multiLine, wrapMode=wrapMode) TTkHelper.overlay(self, tdp, -1, -7, modal=True) tdp.focusTextEdit() self._teButton.clicked.connect(_showTextDialogPicker) self._textEdit.viewport().viewChanged.connect(self._textPickerViewChanged) def setFocus(self): return self._textEdit.setFocus()
[docs] def getTTkString(self): return self._textEdit.toRawText()
@pyTTkSlot() def _textPickerViewChanged(self): wa,ha = self._textEdit.viewport().viewFullAreaSize() tw,th = self._textEdit.size() bw,bh = self._teButton.size() w,h = self.size() self._textEdit.setLineNumber(ha>1) self.documentViewChanged.emit(tw+bw,ha) if self._autoSize: self.resize(w,ha)