Browse Source

TTkColor: rework, used rgb data structure, improved ANSI color parse

pull/46/head
Eugenio Parodi 4 years ago
parent
commit
100d24ffe3
  1. 94
      TermTk/TTkCore/TTkTerm/colors.py
  2. 298
      TermTk/TTkCore/TTkTerm/colors_ansi_map.py
  3. 2
      TermTk/TTkCore/canvas.py
  4. 149
      TermTk/TTkCore/color.py
  5. 9
      TermTk/TTkCore/string.py
  6. 2
      docs/MDNotes/Resources.md
  7. 87
      tests/test.ansi.001.py

94
TermTk/TTkCore/TTkTerm/colors.py

@ -25,7 +25,92 @@
# Ansi Escape Codes: # Ansi Escape Codes:
# https://conemu.github.io/en/AnsiEscapeCodes.html # https://conemu.github.io/en/AnsiEscapeCodes.html
import re
from .colors_ansi_map import ansiMap256, ansiMap16
class TTkTermColor(): class TTkTermColor():
BOLD = 0x01
ITALIC = 0x02
UNDERLINE = 0x04
STRIKETROUGH = 0x08
BLINKING = 0x10
@staticmethod
def rgb2ansi(fg: tuple=None, bg:tuple=None, mod:int=0, clean:bool=False):
ret = []
if clean:
ret.append(0)
if fg:
ret.append(f'38;2;{fg[0]};{fg[1]};{fg[2]}')
if bg:
ret.append(f'48;2;{bg[0]};{bg[1]};{bg[2]}')
if mod & TTkTermColor.BOLD:
ret.append('1')
if mod & TTkTermColor.ITALIC:
ret.append('3')
if mod & TTkTermColor.UNDERLINE:
ret.append('4')
if mod & TTkTermColor.STRIKETROUGH:
ret.append('9')
if mod & TTkTermColor.BLINKING:
ret.append('5')
if ret:
return f'\033[{";".join(str(x) for x in ret)}m'
else:
return '\033[0m'
def _256toRgb(val):
pass
ansiParser = re.compile(r'^\033\[([\d;]*)m$')
@staticmethod
def ansi2rgb(ansi:str):
fg = None
bg = None
mod = 0
clean = False
if m := TTkTermColor.ansiParser.match(ansi):
values = m.group(1).split(';')
if not all(values): # Return None if not all the values are set
return (None, None, 0, True)
while values:
s = int(values.pop(0))
if 30 <= s <= 37: # Ansi 16 colors - fg
fg = ansiMap16.get(s-30)
elif 40 <= s <= 47: # Ansi 16 colors - bg
bg = ansiMap16.get(s-40)
elif s == 38:
t = int(values.pop(0))
if t == 5:# 256 fg
fg = ansiMap256.get(int(values.pop(0)))
if t == 2:# 24 bit fg
fg = (int(values.pop(0)),int(values.pop(0)),int(values.pop(0)))
elif s == 48:
t = int(values.pop(0))
if t == 5:# 256 bg
bg = ansiMap256.get(int(values.pop(0)))
if t == 2:# 24 bit bg
bg = (int(values.pop(0)),int(values.pop(0)),int(values.pop(0)))
elif s==0: # Reset Color/Format
fg = None
bg = None
mod = 0
clean = True
elif s==1: mod += TTkTermColor.BOLD
elif s==3: mod += TTkTermColor.ITALIC
elif s==4: mod += TTkTermColor.UNDERLINE
elif s==9: mod += TTkTermColor.STRIKETROUGH
elif s==5: mod += TTkTermColor.BLINKING
return fg,bg,mod,clean
@staticmethod @staticmethod
def esc_color(val: str, fg: bool): def esc_color(val: str, fg: bool):
# Return the escape sequence for bg or fg # Return the escape sequence for bg or fg
@ -36,13 +121,6 @@ class TTkTermColor():
g = int(val[3:5],base=16) g = int(val[3:5],base=16)
b = int(val[5:7],base=16) b = int(val[5:7],base=16)
return f'\033[{38 if fg else 48};2;{r};{g};{b}m' return f'\033[{38 if fg else 48};2;{r};{g};{b}m'
# 256 colors
# if r//11 == g//11 == b//11:
# # Shade of grey
# return f"\033[{38 if fg else 48};5;{232+r//11}m"
# else:
# # truecolor
# return f"\033[{38 if fg else 48};5;{round(r/51)*36 + round(g/51)*6 + round(b/51) + 16}m"
@staticmethod @staticmethod
def fg(val) -> str: def fg(val) -> str:
@ -50,4 +128,4 @@ class TTkTermColor():
@staticmethod @staticmethod
def bg(val) -> str: def bg(val) -> str:
return TTkTermColor.esc_color(val, False) return TTkTermColor.esc_color(val, False)

298
TermTk/TTkCore/TTkTerm/colors_ansi_map.py

@ -0,0 +1,298 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2022 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.
# Ansi Escape Codes:
# https://conemu.github.io/en/AnsiEscapeCodes.html
# Map retrieved from:
# https://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html
ansiMap16 = {
0 :(0x00,0x00,0x00),
1 :(0xff,0x00,0x00),
2 :(0x00,0xff,0x00),
3 :(0xff,0xff,0x00),
4 :(0x00,0x00,0xff),
5 :(0xff,0x00,0xff),
6 :(0x00,0xff,0xff),
7 :(0xc0,0xc0,0xc0)
}
ansiMap256 = {
0 :(0x00,0x00,0x00),
1 :(0x80,0x00,0x00),
2 :(0x00,0x80,0x00),
3 :(0x80,0x80,0x00),
4 :(0x00,0x00,0x80),
5 :(0x80,0x00,0x80),
6 :(0x00,0x80,0x80),
7 :(0xc0,0xc0,0xc0),
8 :(0x80,0x80,0x80),
9 :(0xff,0x00,0x00),
10 :(0x00,0xff,0x00),
11 :(0xff,0xff,0x00),
12 :(0x00,0x00,0xff),
13 :(0xff,0x00,0xff),
14 :(0x00,0xff,0xff),
15 :(0xff,0xff,0xff),
16 :(0x00,0x00,0x00),
17 :(0x00,0x00,0x5f),
18 :(0x00,0x00,0x87),
19 :(0x00,0x00,0xaf),
20 :(0x00,0x00,0xd7),
21 :(0x00,0x00,0xff),
22 :(0x00,0x5f,0x00),
23 :(0x00,0x5f,0x5f),
24 :(0x00,0x5f,0x87),
25 :(0x00,0x5f,0xaf),
26 :(0x00,0x5f,0xd7),
27 :(0x00,0x5f,0xff),
28 :(0x00,0x87,0x00),
29 :(0x00,0x87,0x5f),
30 :(0x00,0x87,0x87),
31 :(0x00,0x87,0xaf),
32 :(0x00,0x87,0xd7),
33 :(0x00,0x87,0xff),
34 :(0x00,0xaf,0x00),
35 :(0x00,0xaf,0x5f),
36 :(0x00,0xaf,0x87),
37 :(0x00,0xaf,0xaf),
38 :(0x00,0xaf,0xd7),
39 :(0x00,0xaf,0xff),
40 :(0x00,0xd7,0x00),
41 :(0x00,0xd7,0x5f),
42 :(0x00,0xd7,0x87),
43 :(0x00,0xd7,0xaf),
44 :(0x00,0xd7,0xd7),
45 :(0x00,0xd7,0xff),
46 :(0x00,0xff,0x00),
47 :(0x00,0xff,0x5f),
48 :(0x00,0xff,0x87),
49 :(0x00,0xff,0xaf),
50 :(0x00,0xff,0xd7),
51 :(0x00,0xff,0xff),
52 :(0x5f,0x00,0x00),
53 :(0x5f,0x00,0x5f),
54 :(0x5f,0x00,0x87),
55 :(0x5f,0x00,0xaf),
56 :(0x5f,0x00,0xd7),
57 :(0x5f,0x00,0xff),
58 :(0x5f,0x5f,0x00),
59 :(0x5f,0x5f,0x5f),
60 :(0x5f,0x5f,0x87),
61 :(0x5f,0x5f,0xaf),
62 :(0x5f,0x5f,0xd7),
63 :(0x5f,0x5f,0xff),
64 :(0x5f,0x87,0x00),
65 :(0x5f,0x87,0x5f),
66 :(0x5f,0x87,0x87),
67 :(0x5f,0x87,0xaf),
68 :(0x5f,0x87,0xd7),
69 :(0x5f,0x87,0xff),
70 :(0x5f,0xaf,0x00),
71 :(0x5f,0xaf,0x5f),
72 :(0x5f,0xaf,0x87),
73 :(0x5f,0xaf,0xaf),
74 :(0x5f,0xaf,0xd7),
75 :(0x5f,0xaf,0xff),
76 :(0x5f,0xd7,0x00),
77 :(0x5f,0xd7,0x5f),
78 :(0x5f,0xd7,0x87),
79 :(0x5f,0xd7,0xaf),
80 :(0x5f,0xd7,0xd7),
81 :(0x5f,0xd7,0xff),
82 :(0x5f,0xff,0x00),
83 :(0x5f,0xff,0x5f),
84 :(0x5f,0xff,0x87),
85 :(0x5f,0xff,0xaf),
86 :(0x5f,0xff,0xd7),
87 :(0x5f,0xff,0xff),
88 :(0x87,0x00,0x00),
89 :(0x87,0x00,0x5f),
90 :(0x87,0x00,0x87),
91 :(0x87,0x00,0xaf),
92 :(0x87,0x00,0xd7),
93 :(0x87,0x00,0xff),
94 :(0x87,0x5f,0x00),
95 :(0x87,0x5f,0x5f),
96 :(0x87,0x5f,0x87),
97 :(0x87,0x5f,0xaf),
98 :(0x87,0x5f,0xd7),
99 :(0x87,0x5f,0xff),
100 :(0x87,0x87,0x00),
101 :(0x87,0x87,0x5f),
102 :(0x87,0x87,0x87),
103 :(0x87,0x87,0xaf),
104 :(0x87,0x87,0xd7),
105 :(0x87,0x87,0xff),
106 :(0x87,0xaf,0x00),
107 :(0x87,0xaf,0x5f),
108 :(0x87,0xaf,0x87),
109 :(0x87,0xaf,0xaf),
110 :(0x87,0xaf,0xd7),
111 :(0x87,0xaf,0xff),
112 :(0x87,0xd7,0x00),
113 :(0x87,0xd7,0x5f),
114 :(0x87,0xd7,0x87),
115 :(0x87,0xd7,0xaf),
116 :(0x87,0xd7,0xd7),
117 :(0x87,0xd7,0xff),
118 :(0x87,0xff,0x00),
119 :(0x87,0xff,0x5f),
120 :(0x87,0xff,0x87),
121 :(0x87,0xff,0xaf),
122 :(0x87,0xff,0xd7),
123 :(0x87,0xff,0xff),
124 :(0xaf,0x00,0x00),
125 :(0xaf,0x00,0x5f),
126 :(0xaf,0x00,0x87),
127 :(0xaf,0x00,0xaf),
128 :(0xaf,0x00,0xd7),
129 :(0xaf,0x00,0xff),
130 :(0xaf,0x5f,0x00),
131 :(0xaf,0x5f,0x5f),
132 :(0xaf,0x5f,0x87),
133 :(0xaf,0x5f,0xaf),
134 :(0xaf,0x5f,0xd7),
135 :(0xaf,0x5f,0xff),
136 :(0xaf,0x87,0x00),
137 :(0xaf,0x87,0x5f),
138 :(0xaf,0x87,0x87),
139 :(0xaf,0x87,0xaf),
140 :(0xaf,0x87,0xd7),
141 :(0xaf,0x87,0xff),
142 :(0xaf,0xaf,0x00),
143 :(0xaf,0xaf,0x5f),
144 :(0xaf,0xaf,0x87),
145 :(0xaf,0xaf,0xaf),
146 :(0xaf,0xaf,0xd7),
147 :(0xaf,0xaf,0xff),
148 :(0xaf,0xd7,0x00),
149 :(0xaf,0xd7,0x5f),
150 :(0xaf,0xd7,0x87),
151 :(0xaf,0xd7,0xaf),
152 :(0xaf,0xd7,0xd7),
153 :(0xaf,0xd7,0xff),
154 :(0xaf,0xff,0x00),
155 :(0xaf,0xff,0x5f),
156 :(0xaf,0xff,0x87),
157 :(0xaf,0xff,0xaf),
158 :(0xaf,0xff,0xd7),
159 :(0xaf,0xff,0xff),
160 :(0xd7,0x00,0x00),
161 :(0xd7,0x00,0x5f),
162 :(0xd7,0x00,0x87),
163 :(0xd7,0x00,0xaf),
164 :(0xd7,0x00,0xd7),
165 :(0xd7,0x00,0xff),
166 :(0xd7,0x5f,0x00),
167 :(0xd7,0x5f,0x5f),
168 :(0xd7,0x5f,0x87),
169 :(0xd7,0x5f,0xaf),
170 :(0xd7,0x5f,0xd7),
171 :(0xd7,0x5f,0xff),
172 :(0xd7,0x87,0x00),
173 :(0xd7,0x87,0x5f),
174 :(0xd7,0x87,0x87),
175 :(0xd7,0x87,0xaf),
176 :(0xd7,0x87,0xd7),
177 :(0xd7,0x87,0xff),
178 :(0xd7,0xaf,0x00),
179 :(0xd7,0xaf,0x5f),
180 :(0xd7,0xaf,0x87),
181 :(0xd7,0xaf,0xaf),
182 :(0xd7,0xaf,0xd7),
183 :(0xd7,0xaf,0xff),
184 :(0xd7,0xd7,0x00),
185 :(0xd7,0xd7,0x5f),
186 :(0xd7,0xd7,0x87),
187 :(0xd7,0xd7,0xaf),
188 :(0xd7,0xd7,0xd7),
189 :(0xd7,0xd7,0xff),
190 :(0xd7,0xff,0x00),
191 :(0xd7,0xff,0x5f),
192 :(0xd7,0xff,0x87),
193 :(0xd7,0xff,0xaf),
194 :(0xd7,0xff,0xd7),
195 :(0xd7,0xff,0xff),
196 :(0xff,0x00,0x00),
197 :(0xff,0x00,0x5f),
198 :(0xff,0x00,0x87),
199 :(0xff,0x00,0xaf),
200 :(0xff,0x00,0xd7),
201 :(0xff,0x00,0xff),
202 :(0xff,0x5f,0x00),
203 :(0xff,0x5f,0x5f),
204 :(0xff,0x5f,0x87),
205 :(0xff,0x5f,0xaf),
206 :(0xff,0x5f,0xd7),
207 :(0xff,0x5f,0xff),
208 :(0xff,0x87,0x00),
209 :(0xff,0x87,0x5f),
210 :(0xff,0x87,0x87),
211 :(0xff,0x87,0xaf),
212 :(0xff,0x87,0xd7),
213 :(0xff,0x87,0xff),
214 :(0xff,0xaf,0x00),
215 :(0xff,0xaf,0x5f),
216 :(0xff,0xaf,0x87),
217 :(0xff,0xaf,0xaf),
218 :(0xff,0xaf,0xd7),
219 :(0xff,0xaf,0xff),
220 :(0xff,0xd7,0x00),
221 :(0xff,0xd7,0x5f),
222 :(0xff,0xd7,0x87),
223 :(0xff,0xd7,0xaf),
224 :(0xff,0xd7,0xd7),
225 :(0xff,0xd7,0xff),
226 :(0xff,0xff,0x00),
227 :(0xff,0xff,0x5f),
228 :(0xff,0xff,0x87),
229 :(0xff,0xff,0xaf),
230 :(0xff,0xff,0xd7),
231 :(0xff,0xff,0xff),
232 :(0x08,0x08,0x08),
233 :(0x12,0x12,0x12),
234 :(0x1c,0x1c,0x1c),
235 :(0x26,0x26,0x26),
236 :(0x30,0x30,0x30),
237 :(0x3a,0x3a,0x3a),
238 :(0x44,0x44,0x44),
239 :(0x4e,0x4e,0x4e),
240 :(0x58,0x58,0x58),
241 :(0x60,0x60,0x60),
242 :(0x66,0x66,0x66),
243 :(0x76,0x76,0x76),
244 :(0x80,0x80,0x80),
245 :(0x8a,0x8a,0x8a),
246 :(0x94,0x94,0x94),
247 :(0x9e,0x9e,0x9e),
248 :(0xa8,0xa8,0xa8),
249 :(0xb2,0xb2,0xb2),
250 :(0xbc,0xbc,0xbc),
251 :(0xc6,0xc6,0xc6),
252 :(0xd0,0xd0,0xd0),
253 :(0xda,0xda,0xda),
254 :(0xe4,0xe4,0xe4),
255 :(0xee,0xee,0xee)
}

2
TermTk/TTkCore/canvas.py

@ -654,7 +654,7 @@ class TTkCanvas:
ansi = TTkTerm.Cursor.moveTo(y+1,x+1) ansi = TTkTerm.Cursor.moveTo(y+1,x+1)
empty = False empty = False
if color != lastcolor: if color != lastcolor:
ansi += color-lastcolor ansi += str(color-lastcolor)
lastcolor = color lastcolor = color
ansi+=ch ansi+=ch
if not empty: if not empty:

149
TermTk/TTkCore/color.py

@ -61,13 +61,15 @@ from TermTk.TTkCore.helper import TTkHelper
# [49m 2.53 set background color to default (black) # [49m 2.53 set background color to default (black)
class _TTkColor: class _TTkColor:
__slots__ = ('_fg','_bg','_mod', '_colorMod') __slots__ = ('_fg','_bg','_mod', '_colorMod', '_buffer', '_clean')
_fg: str; _bg: str; _mod: str _fg: tuple; _bg: tuple; _mod: int
def __init__(self, fg:str="", bg:str="", mod:str="", colorMod=None): def __init__(self, fg:tuple=None, bg:tuple=None, mod:int=0, colorMod=None, clean=False):
self._fg = fg self._fg = fg
self._bg = bg self._bg = bg
self._mod = mod self._mod = mod
self._clean = clean or not (fg or bg or mod)
self._colorMod = colorMod self._colorMod = colorMod
self._buffer = None
def foreground(self): def foreground(self):
if self._fg: if self._fg:
@ -82,25 +84,25 @@ class _TTkColor:
return None return None
def bold(self) -> bool: def bold(self) -> bool:
return TTkColor.BOLD._mod in self._mod return self._mod & TTkHelper.Color.BOLD
def italic(self) -> bool: def italic(self) -> bool:
return TTkColor.ITALIC._mod in self._mod return self._mod & TTkHelper.Color.ITALIC
def underline(self) -> bool: def underline(self) -> bool:
return TTkColor.UNDERLINE._mod in self._mod return self._mod & TTkHelper.Color.UNDERLINE
def strikethrough(self) -> bool: def strikethrough(self) -> bool:
return TTkColor.STRIKETROUGH._mod in self._mod return self._mod & TTkHelper.Color.STRIKETROUGH
def blinking(self) -> bool: def blinking(self) -> bool:
return TTkColor.BLINKING._mod in self._mod return self._mod & TTkHelper.Color.BLINKING
def colorType(self): def colorType(self):
return \ return \
( TTkK.Foreground if self._fg != "" else TTkK.NONE ) | \ ( TTkK.Foreground if self._fg else TTkK.NONE ) | \
( TTkK.Background if self._bg != "" else TTkK.NONE ) | \ ( TTkK.Background if self._bg else TTkK.NONE ) | \
( TTkK.Modifier if self._mod != "" else TTkK.NONE ) ( TTkK.Modifier if self._mod else TTkK.NONE )
def getHex(self, ctype): def getHex(self, ctype):
if ctype == TTkK.Foreground: if ctype == TTkK.Foreground:
@ -110,70 +112,54 @@ class _TTkColor:
return f"#{r<<16|g<<8|b:06x}" return f"#{r<<16|g<<8|b:06x}"
def fgToRGB(self): def fgToRGB(self):
if self._fg == "": return 0xff,0xff,0xff return self._fg if self._fg else (0,0,0)
cc = self._fg.split(';')
r = int(cc[2])
g = int(cc[3])
b = int(cc[4][:-1])
return r,g,b
def bgToRGB(self): def bgToRGB(self):
if self._bg == "": return 0,0,0 return self._bg if self._bg else (0,0,0)
cc = self._bg.split(';')
r = int(cc[2])
g = int(cc[3])
b = int(cc[4][:-1])
return r,g,b
def invertFgBg(self): def invertFgBg(self):
ret = self.copy() ret = self.copy()
ret._fg = self._bg.replace('\033[48','\033[38') ret._fg = self._bg
ret._bg = self._fg.replace('\033[38','\033[48') ret._bg = self._fg
return ret return ret
def __str__(self): def __str__(self):
return self._fg+self._bg+self._mod if not self._buffer:
self._buffer = TTkHelper.Color.rgb2ansi(self._fg,self._bg,self._mod,self._clean)
return self._buffer
def __eq__(self, other): def __eq__(self, other):
if other is None: return False if other is None: return False
return \ return \
self._fg == other._fg and \ self._fg == other._fg and \
self._bg == other._bg and \ self._bg == other._bg and \
self._mod== other._mod self._mod == other._mod
# self + other
def __add__(self, other): def __add__(self, other):
# TTkLog.debug("__add__") # TTkLog.debug("__add__")
if isinstance(other, str): if other._clean:
return str(self)+other return other.copy()
else: clean = self._clean
fg: str = other._fg or self._fg fg: str = other._fg or self._fg
bg: str = other._bg or self._bg bg: str = other._bg or self._bg
mod: str = self._mod + other._mod mod: str = self._mod + other._mod
colorMod = other._colorMod or self._colorMod colorMod = other._colorMod or self._colorMod
return TTkColor(fg,bg,mod,colorMod) return TTkColor(fg,bg,mod,colorMod,clean)
def __radd__(self, other):
# TTkLog.debug("__radd__")
if isinstance(other, str):
return other+str(self)
else:
fg: str = other._fg or self._fg
bg: str = other._bg or self._bg
mod: self._mod + other._mod
colorMod = other._colorMod or self._colorMod
return TTkColor(fg,bg,mod,colorMod)
def __sub__(self, other): def __sub__(self, other):
# TTkLog.debug("__sub__") # TTkLog.debug("__sub__")
# if other is None: return str(self) # if other is None: return str(self)
if ( "" == self._bg != other._bg or if ( None == self._bg != other._bg or
"" == self._fg != other._fg or None == self._fg != other._fg or
self._mod != other._mod ): self._mod != other._mod ):
return '\033[0m'+self ret = self.copy()
return str(self) ret._clean = True
return ret
return self
def modParam(self, *args, **kwargs): def modParam(self, *args, **kwargs):
if self._colorMod is None: return self if not self._colorMod: return self
ret = self.copy() ret = self.copy()
ret._colorMod.setParam(*args, **kwargs) ret._colorMod.setParam(*args, **kwargs)
return ret return ret
@ -184,10 +170,11 @@ class _TTkColor:
def copy(self, modifier=True): def copy(self, modifier=True):
ret = _TTkColor() ret = _TTkColor()
ret._fg = self._fg ret._fg = self._fg
ret._bg = self._bg ret._bg = self._bg
ret._mod = self._mod ret._mod = self._mod
if modifier and ret._colorMod: ret._clean = self._clean
if modifier and self._colorMod:
ret._colorMod = self._colorMod.copy() ret._colorMod = self._colorMod.copy()
return ret return ret
@ -208,17 +195,15 @@ class TTkColorGradient(_TTkColorModifier):
self._val = kwargs.get("val",0) self._val = kwargs.get("val",0)
def exec(self, x, y, color): def exec(self, x, y, color):
def _applyGradient(c): def _applyGradient(c):
if c == "": return c if not c: return c
multiplier = abs(self._val + y) multiplier = abs(self._val + y)
cc = c.split(';') r = int(c[0])+ self._increment * multiplier
#TTkLog.debug("Eugenio "+c.replace('\033','<ESC>')) g = int(c[1])+ self._increment * multiplier
r = int(cc[2]) + self._increment * multiplier b = int(c[2])+ self._increment * multiplier
g = int(cc[3]) + self._increment * multiplier
b = int(cc[4][:-1])+ self._increment * multiplier
r = max(min(255,r),0) r = max(min(255,r),0)
g = max(min(255,g),0) g = max(min(255,g),0)
b = max(min(255,b),0) b = max(min(255,b),0)
return f"{cc[0]};{cc[1]};{r};{g};{b}m" return (r,g,b)
bname = str(color) bname = str(color)
# I made a buffer to keep all the gradient values to speed up the paint process # I made a buffer to keep all the gradient values to speed up the paint process
@ -235,12 +220,6 @@ class TTkColorGradient(_TTkColorModifier):
def copy(self): def copy(self):
return self return self
#ret = TTkColorGradient()
#ret._increment = self._increment
#ret._val = self._val
#return ret
class TTkColor(_TTkColor): class TTkColor(_TTkColor):
''' TermTk Color helper ''' TermTk Color helper
@ -272,22 +251,34 @@ class TTkColor(_TTkColor):
color_2 = color_fg_red + TTkColor.bg('#FFFF00') color_2 = color_fg_red + TTkColor.bg('#FFFF00')
color_3 = color_2 + TTkColor.UNDERLINE + TTkColor.BOLD color_3 = color_2 + TTkColor.UNDERLINE + TTkColor.BOLD
''' '''
RST = _TTkColor(fg='\033[0m') RST = _TTkColor()
'''Reset to the default terminal color and modifiers''' '''Reset to the default terminal color and modifiers'''
# Modifiers: # Modifiers:
BOLD = _TTkColor(mod='\033[1m') BOLD = _TTkColor(mod=TTkHelper.Color.BOLD)
'''**Bold** modifier''' '''**Bold** modifier'''
ITALIC = _TTkColor(mod='\033[3m') ITALIC = _TTkColor(mod=TTkHelper.Color.ITALIC)
'''*Italic* modifier''' '''*Italic* modifier'''
UNDERLINE = _TTkColor(mod='\033[4m') UNDERLINE = _TTkColor(mod=TTkHelper.Color.UNDERLINE)
''':underline:`Underline` modifier''' ''':underline:`Underline` modifier'''
STRIKETROUGH = _TTkColor(mod='\033[9m') STRIKETROUGH = _TTkColor(mod=TTkHelper.Color.STRIKETROUGH)
''':strike:`Striketrough` modifier''' ''':strike:`Striketrough` modifier'''
BLINKING = _TTkColor(mod='\033[5m') BLINKING = _TTkColor(mod=TTkHelper.Color.BLINKING)
'''"Blinking" modifier''' '''"Blinking" modifier'''
@staticmethod
def hexToRGB(val):
r = int(val[1:3],base=16)
g = int(val[3:5],base=16)
b = int(val[5:7],base=16)
return (r,g,b)
@staticmethod
def ansi(ansi):
fg,bg,mod,clean = TTkHelper.Color.ansi2rgb(ansi)
return TTkColor(fg=fg, bg=bg, mod=mod, clean=clean)
@staticmethod @staticmethod
def fg(*args, **kwargs): def fg(*args, **kwargs):
''' Helper to generate a Foreground color ''' Helper to generate a Foreground color
@ -310,7 +301,7 @@ class TTkColor(_TTkColor):
color = args[0] color = args[0]
else: else:
color = kwargs.get('color', "" ) color = kwargs.get('color', "" )
return TTkColor(fg=TTkHelper.Color.fg(color), colorMod=mod) return TTkColor(fg=TTkColor.hexToRGB(color), colorMod=mod)
@staticmethod @staticmethod
def bg(*args, **kwargs): def bg(*args, **kwargs):
@ -334,4 +325,4 @@ class TTkColor(_TTkColor):
color = args[0] color = args[0]
else: else:
color = kwargs.get('color', "" ) color = kwargs.get('color', "" )
return TTkColor(bg=TTkHelper.Color.bg(color), colorMod=mod) return TTkColor(bg=TTkColor.hexToRGB(color), colorMod=mod)

9
TermTk/TTkCore/string.py

@ -78,14 +78,11 @@ class TTkString():
index = text.index(m,pos) index = text.index(m,pos)
txt = text[pos:index] txt = text[pos:index]
txtret += txt txtret += txt
colret += [TTkColor(mod=color) if type(color) is str else color]*len(txt) colret += [color]*len(txt)
if pos == index: color+=TTkColor.ansi(m)
color+=m
else:
color=m
pos = index+len(m) pos = index+len(m)
txtret += text[pos:] txtret += text[pos:]
colret += [TTkColor(mod=color) if type(color) is str else color]*(len(text)-pos) colret += [color]*(len(text)-pos)
return txtret, colret return txtret, colret
def __len__(self): def __len__(self):

2
docs/MDNotes/Resources.md

@ -23,12 +23,14 @@
## Terminal ## Terminal
#### ANSI Escape Sequences #### ANSI Escape Sequences
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#file-ansi-md https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#file-ansi-md
https://conemu.github.io/en/AnsiEscapeCodes.html
#### Hyperlink #### Hyperlink
https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
#### ANSI 16 256 24bit color conversion #### ANSI 16 256 24bit color conversion
https://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html https://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html
#### ANSI Colors #### ANSI Colors
https://talyian.github.io/ansicolors/ https://talyian.github.io/ansicolors/
http://pueblo.sourceforge.net/doc/manual/ansi_color_codes.html
#### Blinking Text #### Blinking Text
```bash ```bash

87
tests/test.ansi.001.py

@ -0,0 +1,87 @@
#!/usr/bin/env python3
# MIT License
#
# Copyright (c) 2022 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
import logging
import time
sys.path.append(os.path.join(sys.path[0],'..'))
from TermTk import TTkLog
from TermTk.TTkCore import TTkColor
from TermTk.TTkCore import TTkHelper
from TermTk.TTkCore import TTkString
from TermTk.TTkCore import TTkTerm
def test(ansi):
print(f"{ansi} Test Color \033[0m")
print(f"result: {TTkHelper.Color.ansi2rgb(ansi)}")
# 24bit fg RED
test("\033[38;2;255;0;0m")
# 24bit bg GREEN
test("\033[48;2;0;255;0m")
# 24bit fg RED bg BLUE
test("\033[38;2;255;0;0;48;2;0;0;255m")
# 256 fg RED
test("\033[38;5;9m")
# 256 bg GREEN
test("\033[48;5;10m")
# 24bit fg RED bg BLUE
test("\033[38;5;9;48;5;4m")
test("\033[48;5;0m")
test("\033[48;5;1m")
test("\033[48;5;2m")
test("\033[48;5;3m")
test("\033[48;5;4m")
test("\033[48;5;5m")
test("\033[48;5;6m")
test("\033[48;5;7m")
test("\033[48;5;8m")
test("\033[48;5;9m")
test("\033[48;5;10m")
test("\033[48;5;11m")
test("\033[48;5;12m")
test("\033[48;5;13m")
test("\033[48;5;14m")
test("\033[48;5;15m")
test("\033[30m")
test("\033[31m")
test("\033[32m")
test("\033[33m")
test("\033[34m")
test("\033[35m")
test("\033[36m")
test("\033[37m")
test("\033[40m")
test("\033[41m")
test("\033[42m")
test("\033[43m")
test("\033[44m")
test("\033[45m")
test("\033[46m")
test("\033[47m")
Loading…
Cancel
Save