diff --git a/TermTk/TTkCore/TTkTerm/colors.py b/TermTk/TTkCore/TTkTerm/colors.py index 342e96c6..f2deb877 100644 --- a/TermTk/TTkCore/TTkTerm/colors.py +++ b/TermTk/TTkCore/TTkTerm/colors.py @@ -25,7 +25,92 @@ # Ansi Escape Codes: # https://conemu.github.io/en/AnsiEscapeCodes.html +import re + +from .colors_ansi_map import ansiMap256, ansiMap16 + 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 def esc_color(val: str, fg: bool): # Return the escape sequence for bg or fg @@ -36,13 +121,6 @@ class TTkTermColor(): g = int(val[3:5],base=16) b = int(val[5:7],base=16) 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 def fg(val) -> str: @@ -50,4 +128,4 @@ class TTkTermColor(): @staticmethod def bg(val) -> str: - return TTkTermColor.esc_color(val, False) \ No newline at end of file + return TTkTermColor.esc_color(val, False) diff --git a/TermTk/TTkCore/TTkTerm/colors_ansi_map.py b/TermTk/TTkCore/TTkTerm/colors_ansi_map.py new file mode 100644 index 00000000..495adabd --- /dev/null +++ b/TermTk/TTkCore/TTkTerm/colors_ansi_map.py @@ -0,0 +1,298 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2022 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. + +# 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) +} \ No newline at end of file diff --git a/TermTk/TTkCore/canvas.py b/TermTk/TTkCore/canvas.py index 257cd7a7..a4f2b2dc 100644 --- a/TermTk/TTkCore/canvas.py +++ b/TermTk/TTkCore/canvas.py @@ -654,7 +654,7 @@ class TTkCanvas: ansi = TTkTerm.Cursor.moveTo(y+1,x+1) empty = False if color != lastcolor: - ansi += color-lastcolor + ansi += str(color-lastcolor) lastcolor = color ansi+=ch if not empty: diff --git a/TermTk/TTkCore/color.py b/TermTk/TTkCore/color.py index 49bf9bb8..7693829b 100644 --- a/TermTk/TTkCore/color.py +++ b/TermTk/TTkCore/color.py @@ -61,13 +61,15 @@ from TermTk.TTkCore.helper import TTkHelper # [49m 2.53 set background color to default (black) class _TTkColor: - __slots__ = ('_fg','_bg','_mod', '_colorMod') - _fg: str; _bg: str; _mod: str - def __init__(self, fg:str="", bg:str="", mod:str="", colorMod=None): + __slots__ = ('_fg','_bg','_mod', '_colorMod', '_buffer', '_clean') + _fg: tuple; _bg: tuple; _mod: int + def __init__(self, fg:tuple=None, bg:tuple=None, mod:int=0, colorMod=None, clean=False): self._fg = fg self._bg = bg self._mod = mod + self._clean = clean or not (fg or bg or mod) self._colorMod = colorMod + self._buffer = None def foreground(self): if self._fg: @@ -82,25 +84,25 @@ class _TTkColor: return None def bold(self) -> bool: - return TTkColor.BOLD._mod in self._mod + return self._mod & TTkHelper.Color.BOLD def italic(self) -> bool: - return TTkColor.ITALIC._mod in self._mod + return self._mod & TTkHelper.Color.ITALIC def underline(self) -> bool: - return TTkColor.UNDERLINE._mod in self._mod + return self._mod & TTkHelper.Color.UNDERLINE def strikethrough(self) -> bool: - return TTkColor.STRIKETROUGH._mod in self._mod + return self._mod & TTkHelper.Color.STRIKETROUGH def blinking(self) -> bool: - return TTkColor.BLINKING._mod in self._mod + return self._mod & TTkHelper.Color.BLINKING def colorType(self): return \ - ( TTkK.Foreground if self._fg != "" else TTkK.NONE ) | \ - ( TTkK.Background if self._bg != "" else TTkK.NONE ) | \ - ( TTkK.Modifier if self._mod != "" else TTkK.NONE ) + ( TTkK.Foreground if self._fg else TTkK.NONE ) | \ + ( TTkK.Background if self._bg else TTkK.NONE ) | \ + ( TTkK.Modifier if self._mod else TTkK.NONE ) def getHex(self, ctype): if ctype == TTkK.Foreground: @@ -110,70 +112,54 @@ class _TTkColor: return f"#{r<<16|g<<8|b:06x}" def fgToRGB(self): - if self._fg == "": return 0xff,0xff,0xff - cc = self._fg.split(';') - r = int(cc[2]) - g = int(cc[3]) - b = int(cc[4][:-1]) - return r,g,b + return self._fg if self._fg else (0,0,0) def bgToRGB(self): - if self._bg == "": return 0,0,0 - cc = self._bg.split(';') - r = int(cc[2]) - g = int(cc[3]) - b = int(cc[4][:-1]) - return r,g,b + return self._bg if self._bg else (0,0,0) def invertFgBg(self): ret = self.copy() - ret._fg = self._bg.replace('\033[48','\033[38') - ret._bg = self._fg.replace('\033[38','\033[48') + ret._fg = self._bg + ret._bg = self._fg return ret 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): if other is None: return False return \ - self._fg == other._fg and \ - self._bg == other._bg and \ - self._mod== other._mod + self._fg == other._fg and \ + self._bg == other._bg and \ + self._mod == other._mod + # self + other def __add__(self, other): # TTkLog.debug("__add__") - if isinstance(other, str): - return str(self)+other - else: - fg: str = other._fg or self._fg - bg: str = other._bg or self._bg - mod: str = self._mod + other._mod - colorMod = other._colorMod or self._colorMod - return TTkColor(fg,bg,mod,colorMod) - - 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) + if other._clean: + return other.copy() + clean = self._clean + fg: str = other._fg or self._fg + bg: str = other._bg or self._bg + mod: str = self._mod + other._mod + colorMod = other._colorMod or self._colorMod + return TTkColor(fg,bg,mod,colorMod,clean) def __sub__(self, other): # TTkLog.debug("__sub__") # if other is None: return str(self) - if ( "" == self._bg != other._bg or - "" == self._fg != other._fg or - self._mod != other._mod ): - return '\033[0m'+self - return str(self) + if ( None == self._bg != other._bg or + None == self._fg != other._fg or + self._mod != other._mod ): + ret = self.copy() + ret._clean = True + return ret + return self def modParam(self, *args, **kwargs): - if self._colorMod is None: return self + if not self._colorMod: return self ret = self.copy() ret._colorMod.setParam(*args, **kwargs) return ret @@ -184,10 +170,11 @@ class _TTkColor: def copy(self, modifier=True): ret = _TTkColor() - ret._fg = self._fg - ret._bg = self._bg - ret._mod = self._mod - if modifier and ret._colorMod: + ret._fg = self._fg + ret._bg = self._bg + ret._mod = self._mod + ret._clean = self._clean + if modifier and self._colorMod: ret._colorMod = self._colorMod.copy() return ret @@ -208,17 +195,15 @@ class TTkColorGradient(_TTkColorModifier): self._val = kwargs.get("val",0) def exec(self, x, y, color): def _applyGradient(c): - if c == "": return c + if not c: return c multiplier = abs(self._val + y) - cc = c.split(';') - #TTkLog.debug("Eugenio "+c.replace('\033','')) - r = int(cc[2]) + self._increment * multiplier - g = int(cc[3]) + self._increment * multiplier - b = int(cc[4][:-1])+ self._increment * multiplier + r = int(c[0])+ self._increment * multiplier + g = int(c[1])+ self._increment * multiplier + b = int(c[2])+ self._increment * multiplier r = max(min(255,r),0) g = max(min(255,g),0) b = max(min(255,b),0) - return f"{cc[0]};{cc[1]};{r};{g};{b}m" + return (r,g,b) bname = str(color) # 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): return self - #ret = TTkColorGradient() - #ret._increment = self._increment - #ret._val = self._val - #return ret - - class TTkColor(_TTkColor): ''' TermTk Color helper @@ -272,22 +251,34 @@ class TTkColor(_TTkColor): color_2 = color_fg_red + TTkColor.bg('#FFFF00') color_3 = color_2 + TTkColor.UNDERLINE + TTkColor.BOLD ''' - RST = _TTkColor(fg='\033[0m') + RST = _TTkColor() '''Reset to the default terminal color and modifiers''' # Modifiers: - BOLD = _TTkColor(mod='\033[1m') + BOLD = _TTkColor(mod=TTkHelper.Color.BOLD) '''**Bold** modifier''' - ITALIC = _TTkColor(mod='\033[3m') + ITALIC = _TTkColor(mod=TTkHelper.Color.ITALIC) '''*Italic* modifier''' - UNDERLINE = _TTkColor(mod='\033[4m') + UNDERLINE = _TTkColor(mod=TTkHelper.Color.UNDERLINE) ''':underline:`Underline` modifier''' - STRIKETROUGH = _TTkColor(mod='\033[9m') + STRIKETROUGH = _TTkColor(mod=TTkHelper.Color.STRIKETROUGH) ''':strike:`Striketrough` modifier''' - BLINKING = _TTkColor(mod='\033[5m') + BLINKING = _TTkColor(mod=TTkHelper.Color.BLINKING) '''"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 def fg(*args, **kwargs): ''' Helper to generate a Foreground color @@ -310,7 +301,7 @@ class TTkColor(_TTkColor): color = args[0] else: color = kwargs.get('color', "" ) - return TTkColor(fg=TTkHelper.Color.fg(color), colorMod=mod) + return TTkColor(fg=TTkColor.hexToRGB(color), colorMod=mod) @staticmethod def bg(*args, **kwargs): @@ -334,4 +325,4 @@ class TTkColor(_TTkColor): color = args[0] else: color = kwargs.get('color', "" ) - return TTkColor(bg=TTkHelper.Color.bg(color), colorMod=mod) + return TTkColor(bg=TTkColor.hexToRGB(color), colorMod=mod) diff --git a/TermTk/TTkCore/string.py b/TermTk/TTkCore/string.py index c24b42e4..dafccb09 100644 --- a/TermTk/TTkCore/string.py +++ b/TermTk/TTkCore/string.py @@ -78,14 +78,11 @@ class TTkString(): index = text.index(m,pos) txt = text[pos:index] txtret += txt - colret += [TTkColor(mod=color) if type(color) is str else color]*len(txt) - if pos == index: - color+=m - else: - color=m + colret += [color]*len(txt) + color+=TTkColor.ansi(m) pos = index+len(m) 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 def __len__(self): diff --git a/docs/MDNotes/Resources.md b/docs/MDNotes/Resources.md index 6169ae1e..ddb89341 100644 --- a/docs/MDNotes/Resources.md +++ b/docs/MDNotes/Resources.md @@ -23,12 +23,14 @@ ## Terminal #### ANSI Escape Sequences https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#file-ansi-md +https://conemu.github.io/en/AnsiEscapeCodes.html #### Hyperlink https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda #### ANSI 16 256 24bit color conversion https://www.calmar.ws/vim/256-xterm-24bit-rgb-color-chart.html #### ANSI Colors https://talyian.github.io/ansicolors/ +http://pueblo.sourceforge.net/doc/manual/ansi_color_codes.html #### Blinking Text ```bash diff --git a/tests/test.ansi.001.py b/tests/test.ansi.001.py new file mode 100755 index 00000000..7257d827 --- /dev/null +++ b/tests/test.ansi.001.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 + +# MIT License +# +# Copyright (c) 2022 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. + +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")