4 changed files with 536 additions and 0 deletions
@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
# 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. |
||||
|
||||
import sys, os, argparse |
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'..')) |
||||
import TermTk as ttk |
||||
|
||||
from dumb_paint_lib import * |
||||
|
||||
ttk.TTkTheme.loadTheme(ttk.TTkTheme.NERD) |
||||
|
||||
class PaintTemplate(ttk.TTkAppTemplate): |
||||
def __init__(self, border=False, **kwargs): |
||||
super().__init__(border, **kwargs) |
||||
|
||||
self.setWidget(pa:=PaintArea() , self.MAIN) |
||||
self.setItem( ptk:=PaintToolKit(), self.TOP, size=3, fixed=True) |
||||
self.setItem( ta:=TextArea() , self.RIGHT, size=50) |
||||
|
||||
self.setMenuBar(appMenuBar:=ttk.TTkMenuBarLayout(), self.TOP) |
||||
fileMenu = appMenuBar.addMenu("&File") |
||||
buttonOpen = fileMenu.addMenu("&Open") |
||||
buttonClose = fileMenu.addMenu("&Save") |
||||
buttonClose = fileMenu.addMenu("Save &As...") |
||||
fileMenu.addSpacer() |
||||
buttonExit = fileMenu.addMenu("E&xit") |
||||
buttonExit.menuButtonClicked.connect(ttk.TTkHelper.quit) |
||||
|
||||
# extraMenu = appMenuBar.addMenu("E&xtra") |
||||
# extraMenu.addMenu("Scratchpad").menuButtonClicked.connect(self.scratchpad) |
||||
# extraMenu.addSpacer() |
||||
|
||||
helpMenu = appMenuBar.addMenu("&Help", alignment=ttk.TTkK.RIGHT_ALIGN) |
||||
helpMenu.addMenu("About ...").menuButtonClicked |
||||
helpMenu.addMenu("About tlogg").menuButtonClicked |
||||
|
||||
ptk.updatedColor.connect(pa.setGlyphColor) |
||||
ta.charSelected.connect(ptk.glyphFromString) |
||||
ta.charSelected.connect(pa.glyphFromString) |
||||
|
||||
|
||||
|
||||
root = ttk.TTk( |
||||
title="Dumb Paint Tool", |
||||
layout=ttk.TTkGridLayout(), |
||||
mouseTrack=True, |
||||
sigmask=( |
||||
# ttk.TTkTerm.Sigmask.CTRL_C | |
||||
ttk.TTkTerm.Sigmask.CTRL_Q | |
||||
ttk.TTkTerm.Sigmask.CTRL_S | |
||||
ttk.TTkTerm.Sigmask.CTRL_Z )) |
||||
|
||||
PaintTemplate(parent=root) |
||||
|
||||
root.mainloop() |
||||
@ -0,0 +1,2 @@
|
||||
from .paintarea import * |
||||
from .textarea import * |
||||
@ -0,0 +1,207 @@
|
||||
# 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__ = ['PaintArea','PaintToolKit'] |
||||
|
||||
import sys, os |
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'../..')) |
||||
import TermTk as ttk |
||||
|
||||
|
||||
class PaintToolKit(ttk.TTkGridLayout): |
||||
__slots__ = ('_rSelect', '_rPaint', '_lgliph', '_cbFg', '_cbBg', '_bpFg', '_bpBg', |
||||
'_glyph', |
||||
#Signals |
||||
'updatedColor') |
||||
def __init__(self, *args, **kwargs): |
||||
self._glyph = 'X' |
||||
super().__init__(*args, **kwargs) |
||||
self.updatedColor = ttk.pyTTkSignal(ttk.TTkColor) |
||||
self._rSelect = ttk.TTkRadioButton(text='Select ' , maxWidth=10) |
||||
self._rPaint = ttk.TTkRadioButton(text='Paint ' ) |
||||
self._lgliph = ttk.TTkLabel(text="" , maxWidth=8) |
||||
self._cbFg = ttk.TTkCheckbox(text="Fg" , maxWidth= 6) |
||||
self._cbBg = ttk.TTkCheckbox(text="Bg" ) |
||||
self._bpFg = ttk.TTkColorButtonPicker(enabled=False, maxWidth= 6) |
||||
self._bpBg = ttk.TTkColorButtonPicker(enabled=False, ) |
||||
self.addWidget(self._rSelect ,0,0) |
||||
self.addWidget(self._rPaint ,1,0) |
||||
self.addWidget(self._lgliph ,0,1,2,1) |
||||
self.addWidget(self._cbFg ,0,2) |
||||
self.addWidget(self._cbBg ,1,2) |
||||
self.addWidget(self._bpFg ,0,3) |
||||
self.addWidget(self._bpBg ,1,3) |
||||
self.addItem(ttk.TTkLayout() ,0,4,3,1) |
||||
|
||||
self._cbFg.toggled.connect(self._bpFg.setEnabled) |
||||
self._cbBg.toggled.connect(self._bpBg.setEnabled) |
||||
self._cbFg.toggled.connect(self._refreshColor) |
||||
self._cbBg.toggled.connect(self._refreshColor) |
||||
|
||||
self._bpFg.colorSelected.connect(self._refreshColor) |
||||
self._bpBg.colorSelected.connect(self._refreshColor) |
||||
|
||||
self._refreshColor(emit=False) |
||||
|
||||
@ttk.pyTTkSlot() |
||||
def _refreshColor(self, emit=True): |
||||
color =self.color() |
||||
self._lgliph.setText( |
||||
ttk.TTkString("Glyph\n '") + |
||||
ttk.TTkString(self._glyph,color) + |
||||
ttk.TTkString("'")) |
||||
if emit: |
||||
self.updatedColor.emit(color) |
||||
|
||||
|
||||
@ttk.pyTTkSlot(ttk.TTkString) |
||||
def glyphFromString(self, ch:ttk.TTkString): |
||||
if len(ch)<=0: return |
||||
self._glyph = ch.charAt(0) |
||||
self.setColor(ch.colorAt(0)) |
||||
|
||||
def color(self): |
||||
color = ttk.TTkColor() |
||||
if self._cbFg.checkState() == ttk.TTkK.Checked: |
||||
color += self._bpFg.color().invertFgBg() |
||||
if self._cbBg.checkState() == ttk.TTkK.Checked: |
||||
color += self._bpBg.color() |
||||
return color |
||||
|
||||
def setColor(self, color:ttk.TTkColor): |
||||
if fg := color.foreground(): |
||||
self._cbFg.setCheckState(ttk.TTkK.Checked) |
||||
self._bpFg.setEnabled() |
||||
self._bpFg.setColor(fg.invertFgBg()) |
||||
else: |
||||
self._cbFg.setCheckState(ttk.TTkK.Unchecked) |
||||
self._bpFg.setDisabled() |
||||
|
||||
if bg := color.background(): |
||||
self._cbBg.setCheckState(ttk.TTkK.Checked) |
||||
self._bpBg.setEnabled() |
||||
self._bpBg.setColor(bg) |
||||
else: |
||||
self._cbBg.setCheckState(ttk.TTkK.Unchecked) |
||||
self._bpBg.setDisabled() |
||||
self._refreshColor(emit=False) |
||||
|
||||
class PaintArea(ttk.TTkWidget): |
||||
|
||||
__slots__ = ('_canvasArea', '_canvasSize', |
||||
'_transparentColor', |
||||
'_mouseMove', |
||||
'_glyph', '_glyphColor') |
||||
|
||||
def __init__(self, *args, **kwargs): |
||||
self._transparentColor = ttk.TTkColor.bg('#FF00FF') |
||||
self._canvasSize = (0,0) |
||||
self._canvasArea = {'data':[],'colors':[]} |
||||
self._glyph = 'X' |
||||
self._glyphColor = ttk.TTkColor.fg("#0000FF") |
||||
self._mouseMove = None |
||||
super().__init__(*args, **kwargs) |
||||
self.resizeCanvas(80,25) |
||||
self.setFocusPolicy(ttk.TTkK.ClickFocus + ttk.TTkK.TabFocus) |
||||
|
||||
def resizeCanvas(self, w, h): |
||||
self._canvasSize = (w,h) |
||||
self._canvasArea['data'] = (self._canvasArea['data'] + [[] for _ in range(h)])[:h] |
||||
self._canvasArea['colors'] = (self._canvasArea['colors'] + [[] for _ in range(h)])[:h] |
||||
for i in range(h): |
||||
self._canvasArea['data'][i] = (self._canvasArea['data'][i] + [' ' for _ in range(w)])[:w] |
||||
self._canvasArea['colors'][i] = (self._canvasArea['colors'][i] + [ttk.TTkColor.RST for _ in range(w)])[:w] |
||||
self.update() |
||||
|
||||
def mouseMoveEvent(self, evt) -> bool: |
||||
x,y = evt.x, evt.y |
||||
w,h = self._canvasSize |
||||
if 0<=x<w and 0<=y<h: |
||||
self._mouseMove = (x, y) |
||||
self.update() |
||||
return True |
||||
self._mouseMove = None |
||||
self.update() |
||||
return super().mouseMoveEvent(evt) |
||||
|
||||
def mouseDragEvent(self, evt) -> bool: |
||||
if self._placeGlyph(evt.x, evt.y): |
||||
return True |
||||
return super().mouseDragEvent(evt) |
||||
|
||||
def mousePressEvent(self, evt) -> bool: |
||||
if self._placeGlyph(evt.x, evt.y): |
||||
return True |
||||
return super().mousePressEvent(evt) |
||||
|
||||
@ttk.pyTTkSlot(ttk.TTkString) |
||||
def glyphFromString(self, ch:ttk.TTkString): |
||||
if len(ch)<=0: return |
||||
self._glyph = ch.charAt(0) |
||||
self._glyphColor = ch.colorAt(0) |
||||
|
||||
def glyph(self): |
||||
return self._glyph |
||||
def setGlyph(self, glyph): |
||||
if len(glyph) <= 0: return |
||||
if type(glyph)==str: |
||||
self._glyph = glyph[0] |
||||
if type(glyph)==ttk.TTkString: |
||||
self._glyph = glyph.charAt(0) |
||||
self._glyphColor = glyph.colorAt(0) |
||||
|
||||
def glyphColor(self): |
||||
return self._glyphColor |
||||
def setGlyphColor(self, color): |
||||
self._glyphColor = color |
||||
|
||||
def _placeGlyph(self,x,y): |
||||
self._mouseMove = None |
||||
w,h = self._canvasSize |
||||
data = self._canvasArea['data'] |
||||
colors = self._canvasArea['colors'] |
||||
if 0<=x<w and 0<=y<h: |
||||
data[y][x] = self._glyph |
||||
colors[y][x] = self._glyphColor |
||||
self.update() |
||||
return True |
||||
return False |
||||
|
||||
def paintEvent(self, canvas: ttk.TTkCanvas): |
||||
pw,ph = self._canvasSize |
||||
cw,ch = canvas.size() |
||||
w=min(cw,pw) |
||||
h=min(ch,ph) |
||||
data = self._canvasArea['data'] |
||||
colors = self._canvasArea['colors'] |
||||
tc = self._transparentColor |
||||
for y in range(h): |
||||
canvas._data[y][0:w] = data[y][0:w] |
||||
for x in range(w): |
||||
c = colors[y][x] |
||||
canvas._colors[y][x] = c if c._bg else c+tc |
||||
if self._mouseMove: |
||||
x,y = self._mouseMove |
||||
gc = self._glyphColor |
||||
canvas._data[y][x] = self._glyph |
||||
canvas._colors[y][x] = gc if gc._bg else gc+tc |
||||
@ -0,0 +1,250 @@
|
||||
# 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__ = ['TextArea'] |
||||
|
||||
import sys, os |
||||
|
||||
sys.path.append(os.path.join(sys.path[0],'../..')) |
||||
import TermTk as ttk |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_StartingText = '''Ansi Editor: |
||||
|
||||
─ ┌─┬┐ ┏━┳┓ ┎─┰┒ ┍━┯┑ ┏┭┲━┱┮┓ |
||||
━ │ ││ ┃ ┃┃ ┃ ┃┃ │ ││ ┞╁╀┰╀╁┦ |
||||
│ ├─┼┤ ┣━╋┫ ┠─╂┨ ┝━┿┥ ┟╄╈╇╈╃┧ |
||||
┃ └─┴┘ ┗━┻┛ ┖─┸┚ ┕━┷┙ ┡┽╊┷╉┾┩ |
||||
┄ ╴ ╵╷ ╸ ╹╻ ╼ ╽╿ ╽╵┞╼┩┕┙╻ |
||||
┅ ╶ ╺ ╾ ╿╷┝╾┤┌┮╋╸ |
||||
┆ ┌─┬┐ ╔═╦╗ ╓─╥╖ ╒═╤╕ ┢┽╆━╅┾┪╹ |
||||
┇ │ ││ ║ ║║ ║ ║║ │ ││ ┗┵┺━┹┶┛ |
||||
┈ ├─┼┤ ╠═╬╣ ╟─╫╢ ╞═╪╡ ┞ ┦ ┭ ┵ ┽ ╃ ╇ |
||||
┉ └─┴┘ ╚═╩╝ ╙─╨╜ ╘═╧╛ ┟ ┧ ┮ ┶ ┾ ╄ ╈ |
||||
┊ ╭───────────────────╮ ┡ ┩ ┱ ┹ ╀ ╅ ╉ |
||||
┋ │ ╔═══╗ Some Text │░ ┢ ┪ ┲ ┺ ╁ ╆ ╊ |
||||
╌ │ ╚═╦═╝ in the box │▒ |
||||
╍ ╞═╤══╩══╤═══════════╡▒ ╭─────╮ |
||||
╎ │ ├──┬──┤ │▒ ╭ │╲ ╳ ╱│ |
||||
╏ │ ╰──┴──╯ │▓ ╮ │ ╳╳╳ │ |
||||
═ └───────────────────┘▓ ╯ ╰─────╯ |
||||
║ ░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓█ ╰ ╱ ╲ ╳ |
||||
|
||||
▄ ▀ █ - Half,Full |
||||
▁ ▂ ▃ ▄ ▅ ▆ ▇ █ |
||||
|
||||
█ Full █ ▌ ▐ ▏ ▕ ▔ ▁ |
||||
▉ ░ ▒ ▓ █ |
||||
▊ |
||||
▋ ▘ ▚ ▟ |
||||
▌ ▝ ▞ ▙ |
||||
▍ ▖ ▌ ▜ |
||||
▎ ▗ ▐ ▛ |
||||
▏ 1/8 |
||||
◢ ◣ ◤ ◥ ■ □ ▢ ▣ |
||||
|
||||
🬼 🭇 🭗 🭢 🭨 |
||||
🬽 🭈 🭘 🭣 🭩 |
||||
🬾 🭉 🭙 🭤 🭪 |
||||
🬿 🭊 🭚 🭥 🭫 |
||||
🭀 🭋 🭛 🭦 🭬 |
||||
🭌 🭁 🭝 🭒 🭭 |
||||
🭍 🭂 🭞 🭓 🭮 |
||||
🭎 🭃 🭟 🭔 🭯 |
||||
🭏 🭄 🭠 🭕 🮚 |
||||
🭐 🭅 🭡 🭖 🮛 |
||||
🭑 🭆 🭜 🭧 |
||||
|
||||
🭇🬼 |
||||
🭃🭌🬿 |
||||
🭥🭒█🭏🬼 |
||||
🭋🭍🭑🬽🭢🭕█🭌🬿 |
||||
🭅███🭀 🭥🭒█🭏🬼 |
||||
🭋████🭐 🭢🭕█🭌🬿 |
||||
🭅██🭞🭜🭘 🭈🭆🭂███🭏🬼 |
||||
🭣🭧🭚 🭈🭆🭂██████🭠🭗 |
||||
🭥🭒██🭝🭚 |
||||
🭢🭕🭠🭗 |
||||
|
||||
''' |
||||
class TextArea(ttk.TTkGridLayout): |
||||
__slots__ = ('_te','charSelected') |
||||
def __init__(self, *args, **kwargs): |
||||
self.charSelected = ttk.pyTTkSignal(ttk.TTkString) |
||||
super().__init__(*args, **kwargs) |
||||
|
||||
self._te = ttk.TTkTextEdit(lineNumber=True, readOnly=False) |
||||
self._te.setText(_StartingText) |
||||
|
||||
self.addItem(wrapLayout := ttk.TTkGridLayout(), 0,0) |
||||
self.addItem(fontLayout := ttk.TTkGridLayout(columnMinWidth=1), 1,0) |
||||
self.addWidget(self._te,2,0,1,2) |
||||
|
||||
wrapLayout.addWidget(ttk.TTkLabel(text="Wrap: ", maxWidth=6),0,0) |
||||
wrapLayout.addWidget(lineWrap := ttk.TTkComboBox(list=['NoWrap','WidgetWidth','FixedWidth'], maxWidth=20),0,1) |
||||
wrapLayout.addWidget(ttk.TTkLabel(text=" Type: ",maxWidth=7),0,2) |
||||
wrapLayout.addWidget(wordWrap := ttk.TTkComboBox(list=['WordWrap','WrapAnywhere'], maxWidth=20, enabled=False),0,3) |
||||
wrapLayout.addWidget(ttk.TTkLabel(text=" FixW: ",maxWidth=7),0,4) |
||||
wrapLayout.addWidget(fixWidth := ttk.TTkSpinBox(value=self._te.wrapWidth(), maxWidth=5, maximum=500, minimum=10, enabled=False),0,5) |
||||
wrapLayout.addWidget(ttk.TTkSpacer(),0,10) |
||||
|
||||
# Empty columns/cells are 1 char wide due to "columnMinWidth=1" parameter in the GridLayout |
||||
# 1 3 8 11 |
||||
# 0 2 4 5 6 7 9 10 12 |
||||
# 0 [ ] FG [ ] BG [ ] LineNumber |
||||
# 1 ┌─────┐ ┌─────┐ ╒═══╕╒═══╕╒═══╕╒═══╕ ┌──────┐┌──────┐ |
||||
# 2 │ │ │ │ │ a ││ a ││ a ││ a │ │ UNDO ││ REDO │ |
||||
# 3 └─────┘ └─────┘ └───┘└───┘└───┘└───┘ ╘══════╛└──────┘ ┕━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┙ |
||||
|
||||
# Char Fg/Bg buttons |
||||
fontLayout.addWidget(cb_fg := ttk.TTkCheckbox(text=" FG"),0,0) |
||||
fontLayout.addWidget(btn_fgColor := ttk.TTkColorButtonPicker(border=True, enabled=False, maxSize=(7,3)),1,0) |
||||
|
||||
fontLayout.addWidget(cb_bg := ttk.TTkCheckbox(text=" BG"),0,2) |
||||
fontLayout.addWidget(btn_bgColor := ttk.TTkColorButtonPicker(border=True, enabled=False, maxSize=(7 ,3)),1,2) |
||||
|
||||
fontLayout.addWidget(cb_linenumber := ttk.TTkCheckbox(text=" LineNumber", checked=True),0,4,1,3) |
||||
|
||||
# Char style buttons |
||||
fontLayout.addWidget(btn_bold := ttk.TTkButton(border=True, maxSize=(5,3), checkable=True, text=ttk.TTkString( 'a' , ttk.TTkColor.BOLD) ),1,4) |
||||
fontLayout.addWidget(btn_italic := ttk.TTkButton(border=True, maxSize=(5,3), checkable=True, text=ttk.TTkString( 'a' , ttk.TTkColor.ITALIC) ),1,5) |
||||
fontLayout.addWidget(btn_underline := ttk.TTkButton(border=True, maxSize=(5,3), checkable=True, text=ttk.TTkString(' a ', ttk.TTkColor.UNDERLINE) ),1,6) |
||||
fontLayout.addWidget(btn_strikethrough := ttk.TTkButton(border=True, maxSize=(5,3), checkable=True, text=ttk.TTkString(' a ', ttk.TTkColor.STRIKETROUGH)),1,7) |
||||
|
||||
# Undo/Redo buttons |
||||
fontLayout.addWidget(btn_undo := ttk.TTkButton(border=True, maxSize=(8,3), enabled=self._te.isUndoAvailable(), text=' UNDO '),1,9 ) |
||||
fontLayout.addWidget(btn_redo := ttk.TTkButton(border=True, maxSize=(8,3), enabled=self._te.isRedoAvailable(), text=' REDO '),1,10) |
||||
# Undo/Redo events |
||||
self._te.undoAvailable.connect(btn_undo.setEnabled) |
||||
self._te.redoAvailable.connect(btn_redo.setEnabled) |
||||
btn_undo.clicked.connect(self._te.undo) |
||||
btn_redo.clicked.connect(self._te.redo) |
||||
|
||||
@ttk.pyTTkSlot(ttk.TTkColor) |
||||
def _currentColorChangedCB(format): |
||||
if fg := format.foreground(): |
||||
cb_fg.setCheckState(ttk.TTkK.Checked) |
||||
btn_fgColor.setEnabled() |
||||
btn_fgColor.setColor(fg.invertFgBg()) |
||||
else: |
||||
cb_fg.setCheckState(ttk.TTkK.Unchecked) |
||||
btn_fgColor.setDisabled() |
||||
|
||||
if bg := format.background(): |
||||
cb_bg.setCheckState(ttk.TTkK.Checked) |
||||
btn_bgColor.setEnabled() |
||||
btn_bgColor.setColor(bg) |
||||
else: |
||||
cb_bg.setCheckState(ttk.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()) |
||||
# ttk.TTkLog.debug(f"{fg=} {bg=} {bold=} {italic=} {underline=} {strikethrough= }") |
||||
|
||||
self._te.currentColorChanged.connect(_currentColorChangedCB) |
||||
|
||||
def _setStyle(): |
||||
color = ttk.TTkColor() |
||||
if cb_fg.checkState() == ttk.TTkK.Checked: |
||||
color += btn_fgColor.color().invertFgBg() |
||||
if cb_bg.checkState() == ttk.TTkK.Checked: |
||||
color += btn_bgColor.color() |
||||
if btn_bold.isChecked(): |
||||
color += ttk.TTkColor.BOLD |
||||
if btn_italic.isChecked(): |
||||
color += ttk.TTkColor.ITALIC |
||||
if btn_underline.isChecked(): |
||||
color += ttk.TTkColor.UNDERLINE |
||||
if btn_strikethrough.isChecked(): |
||||
color += ttk.TTkColor.STRIKETROUGH |
||||
cursor = self._te.textCursor() |
||||
cursor.applyColor(color) |
||||
cursor.setColor(color) |
||||
self._te.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) |
||||
|
||||
cb_linenumber.toggled.connect(self._te.setLineNumber) |
||||
|
||||
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) |
||||
|
||||
lineWrap.setCurrentIndex(0) |
||||
wordWrap.setCurrentIndex(1) |
||||
|
||||
fixWidth.valueChanged.connect(self._te.setWrapWidth) |
||||
|
||||
@ttk.pyTTkSlot(int) |
||||
def _lineWrapCallback(index): |
||||
if index == 0: |
||||
self._te.setLineWrapMode(ttk.TTkK.NoWrap) |
||||
wordWrap.setDisabled() |
||||
fixWidth.setDisabled() |
||||
elif index == 1: |
||||
self._te.setLineWrapMode(ttk.TTkK.WidgetWidth) |
||||
wordWrap.setEnabled() |
||||
fixWidth.setDisabled() |
||||
else: |
||||
self._te.setLineWrapMode(ttk.TTkK.FixedWidth) |
||||
self._te.setWrapWidth(fixWidth.value()) |
||||
wordWrap.setEnabled() |
||||
fixWidth.setEnabled() |
||||
|
||||
lineWrap.currentIndexChanged.connect(_lineWrapCallback) |
||||
|
||||
@ttk.pyTTkSlot(int) |
||||
def _wordWrapCallback(index): |
||||
if index == 0: |
||||
self._te.setWordWrapMode(ttk.TTkK.WordWrap) |
||||
else: |
||||
self._te.setWordWrapMode(ttk.TTkK.WrapAnywhere) |
||||
|
||||
wordWrap.currentIndexChanged.connect(_wordWrapCallback) |
||||
|
||||
self._te.document().cursorPositionChanged.connect(self._cursorPositionChanged) |
||||
|
||||
@ttk.pyTTkSlot(ttk.TTkTextCursor) |
||||
def _cursorPositionChanged(self, cursor): |
||||
ch = cursor.positionChar() |
||||
color = cursor.positionColor() |
||||
self.charSelected.emit(ttk.TTkString(ch,color)) |
||||
|
||||
def te(self): |
||||
return self._te |
||||
Loading…
Reference in new issue