├── tests ├── run.py ├── HTMLText_untagged.json ├── HTMLLabel_untagged.json ├── HTMLScrolledText_untagged.json ├── test_widgets.py ├── HTMLText_images.json ├── HTMLScrolledText_images.json ├── HTMLLabel_images.json ├── HTMLText_styles.json ├── HTMLScrolledText_styles.json ├── HTMLLabel_styles.json └── HTMLText_tags.json ├── examples ├── py.png ├── img │ ├── tags_tk.png │ ├── images_tk.png │ ├── styles_tk.png │ ├── tags_pyqt5.png │ ├── images_pyqt5.png │ ├── styles_pyqt5.png │ ├── tags_firefox.png │ ├── images_firefox.png │ └── styles_firefox.png ├── example.py ├── example2.py ├── tk_load_html.py ├── tags.html ├── images.html ├── pyqt5_load_html.py └── styles.html ├── setup.py ├── LICENSE ├── README.md └── tk_html_widgets ├── __init__.py └── html_parser.py /tests/run.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | pytest.main() -------------------------------------------------------------------------------- /examples/py.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/py.png -------------------------------------------------------------------------------- /examples/img/tags_tk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/img/tags_tk.png -------------------------------------------------------------------------------- /examples/img/images_tk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/img/images_tk.png -------------------------------------------------------------------------------- /examples/img/styles_tk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/img/styles_tk.png -------------------------------------------------------------------------------- /examples/img/tags_pyqt5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/img/tags_pyqt5.png -------------------------------------------------------------------------------- /examples/img/images_pyqt5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/img/images_pyqt5.png -------------------------------------------------------------------------------- /examples/img/styles_pyqt5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/img/styles_pyqt5.png -------------------------------------------------------------------------------- /examples/img/tags_firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/img/tags_firefox.png -------------------------------------------------------------------------------- /examples/img/images_firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/img/images_firefox.png -------------------------------------------------------------------------------- /examples/img/styles_firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paolo-gurisatti/tk_html_widgets/HEAD/examples/img/styles_firefox.png -------------------------------------------------------------------------------- /examples/example.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from tk_html_widgets import HTMLLabel 3 | 4 | root = tk.Tk() 5 | html_label = HTMLLabel(root, html='

Hello World

') 6 | html_label.pack(fill="both", expand=True) 7 | html_label.fit_height() 8 | root.mainloop() -------------------------------------------------------------------------------- /tests/HTMLText_untagged.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "SystemWindow", 8 | "foreground": "black", 9 | "justify": "left", 10 | "tabs": [] 11 | }, 12 | "end_index": "end", 13 | "font": { 14 | "family": "Segoe ui", 15 | "overstrike": false, 16 | "size": 9, 17 | "slant": "roman", 18 | "underline": false, 19 | "weight": "normal" 20 | }, 21 | "start_index": "1.0" 22 | } 23 | } -------------------------------------------------------------------------------- /tests/HTMLLabel_untagged.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "SystemButtonFace", 8 | "foreground": "black", 9 | "justify": "left", 10 | "tabs": [] 11 | }, 12 | "end_index": "end", 13 | "font": { 14 | "family": "Segoe ui", 15 | "overstrike": false, 16 | "size": 9, 17 | "slant": "roman", 18 | "underline": false, 19 | "weight": "normal" 20 | }, 21 | "start_index": "1.0" 22 | } 23 | } -------------------------------------------------------------------------------- /tests/HTMLScrolledText_untagged.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "SystemWindow", 8 | "foreground": "black", 9 | "justify": "left", 10 | "tabs": [] 11 | }, 12 | "end_index": "end", 13 | "font": { 14 | "family": "Segoe ui", 15 | "overstrike": false, 16 | "size": 9, 17 | "slant": "roman", 18 | "underline": false, 19 | "weight": "normal" 20 | }, 21 | "start_index": "1.0" 22 | } 23 | } -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | import tk_html_widgets 3 | 4 | with open("README.md", "r") as fh: 5 | long_description = fh.read() 6 | 7 | setuptools.setup( 8 | name="tk_html_widgets", 9 | version=tk_html_widgets.VERSION, 10 | author="Paolo Gurisatti", 11 | author_email="paolo@fastmail.com", 12 | description="HTML widgets for tkinter", 13 | long_description=long_description, 14 | long_description_content_type="text/markdown", 15 | url="https://github.com/paolo-gurisatti/tk_html_widgets", 16 | packages=setuptools.find_packages(), 17 | classifiers=[ 18 | "Programming Language :: Python :: 3", 19 | "License :: OSI Approved :: MIT License", 20 | "Operating System :: OS Independent", 21 | ], 22 | python_requires=">=3.4.*", 23 | install_requires=['Pillow>=5.3.0',], 24 | ) -------------------------------------------------------------------------------- /examples/example2.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from tk_html_widgets import HTMLLabel 3 | 4 | HTML = """ 5 |

6 | 7 | 8 | www.python.org 9 | 10 | 11 | 12 |

""" 13 | 14 | root = tk.Tk() 15 | html_label = HTMLLabel(root, html=HTML % (0, 0, 0), width=50) 16 | html_label.pack(fill="both", expand=True) 17 | html_label.fit_height() 18 | 19 | rgb = [0, 0, 0] 20 | i = 0 21 | while True: 22 | for v in range(256): 23 | if i == 0: 24 | rgb[i] = v 25 | elif i == 1 or i == 2: 26 | rgb[i] = v 27 | rgb[i-1] = 255 - v 28 | elif i == 3: 29 | rgb[i-1] = 255 - v 30 | 31 | html_label.set_html(HTML % tuple(rgb)) 32 | root.update() 33 | i += 1 34 | if i == 4: 35 | i = 0 -------------------------------------------------------------------------------- /examples/tk_load_html.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import tkinter as tk 4 | from argparse import ArgumentParser 5 | 6 | sys.path.insert(0, '..') 7 | from tk_html_widgets import HTMLText, HTMLScrolledText, HTMLLabel 8 | 9 | def start_gui(html): 10 | #---------------------------------------------------------------------------------------------- 11 | root = tk.Tk() 12 | text = HTMLText(root) 13 | text.pack(fill="both", expand=True) 14 | text.set_html(html) 15 | text.fit_height() 16 | return root.mainloop() 17 | 18 | 19 | if __name__ == "__main__": 20 | #---------------------------------------------------------------------------------------------- 21 | parser = ArgumentParser(usage="python3 %s " % __file__) 22 | 23 | parser.add_argument('html_file', help='Set html file to load') 24 | 25 | args = parser.parse_args() 26 | 27 | if os.path.exists(args.html_file): 28 | sys.exit(start_gui(open(args.html_file, "r" ).read())) 29 | else: 30 | print("File not found") 31 | sys.exit(1) 32 | 33 | -------------------------------------------------------------------------------- /examples/tags.html: -------------------------------------------------------------------------------- 1 | 9 | 10 |
    11 |
  1. 1st level 1st element
  2. 12 |
  3. 1st level 2nd element
  4. 13 |
      14 |
    1. 2nd level 1st element
    2. 15 |
    3. 2ndt level 2nd element
    4. 16 |
        17 |
      1. 3rd level 1st element
      2. 18 |
      3. 3rd level 2nd element
      4. 19 |
      20 |
    21 |
22 | 23 | hyperlink
24 | bold
25 | strong
26 | italic
27 | emphasized
28 | underline
29 | marked
30 | spanned 31 |
division
32 |

paragraph

33 |
 preformatted 
34 |

heading 1

35 |

heading 2

36 |

heading 3

37 |

heading 4

38 |
heading 5
39 |
heading 6
-------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 paolo-gurisatti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/images.html: -------------------------------------------------------------------------------- 1 |

image:

2 | span 3 | 4 | span 5 | 6 |

resized image:

7 | span 8 | 9 | span again 10 | 11 | 12 |

links:

13 | default style link
14 | custom style link
15 | clickable image
16 | 17 | 21 | 22 | -------------------------------------------------------------------------------- /examples/pyqt5_load_html.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from argparse import ArgumentParser 4 | 5 | from PyQt5.QtWidgets import QApplication, QTextBrowser 6 | from PyQt5 import QtGui 7 | 8 | #__________________________________________________________________________________________________ 9 | # Terminal Tab viewer 10 | 11 | def start_gui(argv, html): 12 | #---------------------------------------------------------------------------------------------- 13 | app = QApplication(argv) 14 | text = QTextBrowser() 15 | text.setOpenLinks(False) 16 | text.setReadOnly(True) 17 | text.setHtml(html) 18 | text.show() 19 | return app.exec_() 20 | 21 | 22 | if __name__ == "__main__": 23 | #---------------------------------------------------------------------------------------------- 24 | parser = ArgumentParser(usage="python3 %s " % __file__) 25 | 26 | parser.add_argument('html_file', help='Set html file to load') 27 | 28 | args = parser.parse_args() 29 | 30 | if os.path.exists(args.html_file): 31 | sys.exit(start_gui(sys.argv, open(args.html_file, "r" ).read())) 32 | else: 33 | print("File not found") 34 | sys.exit(1) 35 | 36 | -------------------------------------------------------------------------------- /examples/styles.html: -------------------------------------------------------------------------------- 1 | a style 2 | b style 3 | strong style 4 | i style 5 | em style 6 | u style 7 | mark style 8 | span style 9 |
div style
10 |

p style

11 |
 pre style 
12 |

h1 style

13 |

h2 style

14 |

h3 style

15 |

h4 style

16 |
h5 style
17 |
h6 style
18 | 19 | red 20 | green 21 | yellow 22 | 23 | 24 | red again 25 | 26 | -------------------------------------------------------------------------------- /tests/test_widgets.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | import pytest 4 | import tkinter as tk 5 | 6 | sys.path.insert(0, '..') 7 | from tk_html_widgets import HTMLText, HTMLScrolledText, HTMLLabel 8 | from tk_html_widgets.html_parser import * 9 | 10 | 11 | @pytest.mark.parametrize("f", ('tags', 'styles', 'images')) 12 | @pytest.mark.parametrize("Widget", (HTMLText, HTMLScrolledText, HTMLLabel)) 13 | def test_tags(Widget, f): 14 | #---------------------------------------------------------------------------------------------- 15 | for _ in range(10): 16 | try: 17 | root = tk.Tk() 18 | break 19 | except Exception as e: 20 | exception = e 21 | else: 22 | raise exception 23 | text = Widget(root) 24 | text.pack(fill="both", expand=True) 25 | text.set_html(open("../examples/%s.html" % f, 'r').read(), strip=True) 26 | text.fit_height() 27 | tags_json = json.dumps(text.html_parser._w_tags, sort_keys=True, indent=4) 28 | #open(Widget.__name__ + '_%s.json' % f, 'w').write(tags_json) 29 | assert open(Widget.__name__ + '_%s.json' % f, 'r').read() == tags_json 30 | 31 | # check stack lenght 32 | assert len(text.html_parser.stack[WCfg.KEY][WCfg.BACKGROUND]) == 1 33 | assert len(text.html_parser.stack[WCfg.KEY][WCfg.FOREGROUND]) == 1 34 | assert len(text.html_parser.stack[WCfg.KEY][WCfg.JUSTIFY]) == 1 35 | assert len(text.html_parser.stack[WCfg.KEY][WCfg.TABS]) == 1 36 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.FAMILY]) == 1 37 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.SIZE]) == 1 38 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.WEIGHT]) == 1 39 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.SLANT]) == 1 40 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.UNDERLINE]) == 1 41 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.OVERSTRIKE]) == 1 42 | assert len(text.html_parser.stack[Bind.KEY][Bind.LINK]) == 1 43 | root.destroy() 44 | 45 | 46 | @pytest.mark.parametrize("Widget", (HTMLText, HTMLScrolledText, HTMLLabel)) 47 | def test_untagged(Widget): 48 | #---------------------------------------------------------------------------------------------- 49 | for _ in range(10): 50 | try: 51 | root = tk.Tk() 52 | break 53 | except Exception as e: 54 | exception = e 55 | else: 56 | raise exception 57 | text = Widget(root) 58 | text.pack(fill="both", expand=True) 59 | text.set_html("untagged") 60 | text.fit_height() 61 | tags_json = json.dumps(text.html_parser._w_tags, sort_keys=True, indent=4) 62 | #open(Widget.__name__ + '_untagged.json', 'w').write(tags_json) 63 | assert open(Widget.__name__ + '_untagged.json', 'r').read() == tags_json 64 | 65 | # check stack lenght 66 | assert len(text.html_parser.stack[WCfg.KEY][WCfg.BACKGROUND]) == 1 67 | assert len(text.html_parser.stack[WCfg.KEY][WCfg.FOREGROUND]) == 1 68 | assert len(text.html_parser.stack[WCfg.KEY][WCfg.JUSTIFY]) == 1 69 | assert len(text.html_parser.stack[WCfg.KEY][WCfg.TABS]) == 1 70 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.FAMILY]) == 1 71 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.SIZE]) == 1 72 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.WEIGHT]) == 1 73 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.SLANT]) == 1 74 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.UNDERLINE]) == 1 75 | assert len(text.html_parser.stack[Fnt.KEY][Fnt.OVERSTRIKE]) == 1 76 | assert len(text.html_parser.stack[Bind.KEY][Bind.LINK]) == 1 77 | root.destroy() 78 | 79 | 80 | def test_html_format(): 81 | #---------------------------------------------------------------------------------------------- 82 | TEXT = ' text color #%06x' 83 | for _ in range(10): 84 | try: 85 | root = tk.Tk() 86 | break 87 | except Exception as e: 88 | exception = e 89 | else: 90 | raise exception 91 | text = HTMLLabel(root, height=10) 92 | text.pack(fill="both", expand=True) 93 | for increment in (0x010000, 0x000100, 0x000001): 94 | for i in range(0, increment*256, increment): 95 | text.set_html(TEXT % (i, increment*255, i)) 96 | root.update() 97 | root.destroy() 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tk_html_widgets 2 | HTML widgets for tkinter 3 | 4 | ## Overview 5 | This module is a collection of tkinter widgets whose text can be set in HTML format. 6 | A HTML widget isn't a web browser frame, it's only a simple and lightweight HTML parser that formats the tags used by the tkinter Text base class. 7 | The widgets behaviour is similar to the PyQt5 text widgets (see the [PyQt5 HTML markup subset](http://doc.qt.io/qt-5/richtext-html-subset.html)). 8 | 9 | ## Installation 10 | ``pip install tk_html_widgets`` 11 | 12 | ## Requirements 13 | - [Python 3.4 or later](https://www.python.org/downloads/) with tcl/tk support 14 | - [Pillow 5.3.0](https://github.com/python-pillow/Pillow) 15 | 16 | ## Example 17 | ```python 18 | import tkinter as tk 19 | from tk_html_widgets import HTMLLabel 20 | 21 | root = tk.Tk() 22 | html_label = HTMLLabel(root, html='

Hello World

') 23 | html_label.pack(fill="both", expand=True) 24 | html_label.fit_height() 25 | root.mainloop() 26 | ``` 27 | 28 | ## Documentation 29 | 30 | ### Classes: 31 | All widget classes inherits from the tkinter.Text() base class. 32 | 33 | #### class HTMLScrolledText(tkinter.Text) 34 | > Text-box widget with vertical scrollbar 35 | #### class HTMLText(tkinter.Text) 36 | > Text-box widget without vertical scrollbar 37 | #### class HTMLLabel(tkinter.Text) 38 | > Text-box widget with label appereance 39 | 40 | ### Methods: 41 | #### def set_html(self, html, strip=True): 42 | > **Description:** Sets the text in HTML format.
43 | > **Args:** 44 | > - *html*: input HTML string 45 | > - *strip*: if True (default) handles spaces in HTML-like style 46 | 47 | #### def fit_height(self): 48 | > **Description:** Fit widget height in order to display all wrapped lines 49 | 50 | ### HTML support: 51 | Only a subset of the whole HTML tags and attributes are supported (see table below). 52 | Where is possibile, I hope to add more HTML support in the next releases. 53 | 54 | **Tags** | **Attributes** | **Notes** 55 | --- | --- | --- 56 | a| style, href | 57 | b| style | 58 | br|| 59 | code | style | 60 | div | style | 61 | em| style | 62 | h1 | style | 63 | h2 | style | 64 | h3 | style | 65 | h4 | style | 66 | h5 | style | 67 | h6 | style | 68 | i| style | 69 | img| src, width, height | local images only 70 | li| style | 71 | mark| style | 72 | ol| style, type | 1, a, A list types only 73 | p | style | 74 | pre | style | 75 | span| style | 76 | strong| style | 77 | u| style | 78 | ul| style | bullet glyphs only 79 | 80 | ## Comparison chart 81 | In order to check the appearance of the HTML text displayed by the tk_html_widgets, I made some HTML templates and I compared the text displayed by the HTMLText widget with the text displayed by Firefox and the PyQt5 QTextBrowser widget. 82 | See details and templates HTML code in the [examples folder](https://github.com/paolo-gurisatti/tk_html_widgets/tree/master/examples). 83 | 84 | ### Tags template comparison: 85 | **Firefox** | **tk_html_widgets.HTMLText** | **PyQt5.QtWidgets.QTextBrowser** 86 | --- | --- | --- 87 | ![](https://github.com/paolo-gurisatti/tk_html_widgets/blob/master/examples/img/tags_firefox.png)|![](https://github.com/paolo-gurisatti/tk_html_widgets/blob/master/examples/img/tags_tk.png)|![](https://github.com/paolo-gurisatti/tk_html_widgets/blob/master/examples/img/tags_pyqt5.png) 88 | 89 | ### Styles template comparison: 90 | **Firefox** | **tk_html_widgets.HTMLText** | **PyQt5.QtWidgets.QTextBrowser** 91 | --- | --- | --- 92 | ![](https://github.com/paolo-gurisatti/tk_html_widgets/blob/master/examples/img/styles_firefox.png)|![](https://github.com/paolo-gurisatti/tk_html_widgets/blob/master/examples/img/styles_tk.png)|![](https://github.com/paolo-gurisatti/tk_html_widgets/blob/master/examples/img/styles_pyqt5.png) 93 | 94 | ### Images template comparison: 95 | **Firefox** | **tk_html_widgets.HTMLText** | **PyQt5.QtWidgets.QTextBrowser** 96 | --- | --- | --- 97 | ![](https://github.com/paolo-gurisatti/tk_html_widgets/blob/master/examples/img/images_firefox.png)|![](https://github.com/paolo-gurisatti/tk_html_widgets/blob/master/examples/img/images_tk.png)|![](https://github.com/paolo-gurisatti/tk_html_widgets/blob/master/examples/img/images_pyqt5.png) 98 | 99 | 100 | ## Acknowledgements 101 | Thanks to my mentor, valued collegue and friend [JayZar21](https://github.com/JayZar21). 102 | -------------------------------------------------------------------------------- /tk_html_widgets/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | tkinter HTML text widgets 3 | """ 4 | import sys 5 | import tkinter as tk 6 | from tkinter import scrolledtext 7 | from tkinter import font 8 | from tk_html_widgets import html_parser 9 | 10 | VERSION = "0.4.0" 11 | 12 | class _ScrolledText(tk.Text): 13 | #---------------------------------------------------------------------------------------------- 14 | def __init__(self, master=None, **kw): 15 | self.frame = tk.Frame(master) 16 | 17 | self.vbar = tk.Scrollbar(self.frame) 18 | kw.update({'yscrollcommand': self.vbar.set}) 19 | self.vbar.pack(side=tk.RIGHT, fill=tk.Y) 20 | self.vbar['command'] = self.yview 21 | 22 | tk.Text.__init__(self, self.frame, **kw) 23 | self.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) 24 | 25 | text_meths = vars(tk.Text).keys() 26 | methods = vars(tk.Pack).keys() | vars(tk.Grid).keys() | vars(tk.Place).keys() 27 | methods = methods.difference(text_meths) 28 | 29 | for m in methods: 30 | if m[0] != '_' and m != 'config' and m != 'configure': 31 | setattr(self, m, getattr(self.frame, m)) 32 | 33 | def __str__(self): 34 | return str(self.frame) 35 | 36 | class HTMLScrolledText(_ScrolledText): 37 | #---------------------------------------------------------------------------------------------- 38 | """ 39 | HTML scrolled text widget 40 | """ 41 | def __init__(self, *args, html=None, **kwargs): 42 | #------------------------------------------------------------------------------------------ 43 | super().__init__(*args, **kwargs) 44 | self._w_init(kwargs) 45 | self.html_parser = html_parser.HTMLTextParser() 46 | if isinstance(html, str): 47 | self.set_html(html) 48 | 49 | 50 | def _w_init(self, kwargs): 51 | #------------------------------------------------------------------------------------------ 52 | if not 'wrap' in kwargs.keys(): 53 | self.config(wrap='word') 54 | if not 'background' in kwargs.keys(): 55 | if sys.platform.startswith('win'): 56 | self.config(background='SystemWindow') 57 | else: 58 | self.config(background='white') 59 | 60 | 61 | def fit_height(self): 62 | #------------------------------------------------------------------------------------------ 63 | """ 64 | Fit widget height to wrapped lines 65 | """ 66 | for h in range(1, 4): 67 | self.config(height=h) 68 | self.master.update() 69 | if self.yview()[1] >= 1: 70 | break 71 | else: 72 | self.config(height=0.5+3/self.yview()[1]) 73 | 74 | 75 | def set_html(self, html, strip=True): 76 | #------------------------------------------------------------------------------------------ 77 | """ 78 | Set HTML widget text. If strip is enabled (default) it ignores spaces and new lines. 79 | 80 | """ 81 | prev_state = self.cget('state') 82 | self.config(state=tk.NORMAL) 83 | self.delete('1.0', tk.END) 84 | self.tag_delete(self.tag_names) 85 | self.html_parser.w_set_html(self, html, strip=strip) 86 | self.config(state=prev_state) 87 | 88 | 89 | class HTMLText(HTMLScrolledText): 90 | #---------------------------------------------------------------------------------------------- 91 | """ 92 | HTML text widget 93 | """ 94 | def _w_init(self, kwargs): 95 | #------------------------------------------------------------------------------------------ 96 | super()._w_init(kwargs) 97 | self.vbar.pack_forget() 98 | 99 | def fit_height(self): 100 | #------------------------------------------------------------------------------------------ 101 | super().fit_height() 102 | #self.master.update() 103 | self.vbar.pack_forget() 104 | 105 | class HTMLLabel(HTMLText): 106 | #---------------------------------------------------------------------------------------------- 107 | """ 108 | HTML label widget 109 | """ 110 | def _w_init(self, kwargs): 111 | #------------------------------------------------------------------------------------------ 112 | super()._w_init(kwargs) 113 | if not 'background' in kwargs.keys(): 114 | if sys.platform.startswith('win'): 115 | self.config(background='SystemButtonFace') 116 | else: 117 | self.config(background='#d9d9d9') 118 | 119 | if not 'borderwidth' in kwargs.keys(): 120 | self.config(borderwidth=0) 121 | 122 | if not 'padx' in kwargs.keys(): 123 | self.config(padx=3) 124 | 125 | def set_html(self, *args, **kwargs): 126 | #------------------------------------------------------------------------------------------ 127 | super().set_html(*args, **kwargs) 128 | self.config(state=tk.DISABLED) 129 | 130 | -------------------------------------------------------------------------------- /tests/HTMLText_images.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "SystemWindow", 8 | "foreground": "black", 9 | "justify": "center", 10 | "tabs": [] 11 | }, 12 | "end_index": "2.0", 13 | "font": { 14 | "family": "Segoe ui", 15 | "overstrike": false, 16 | "size": 16, 17 | "slant": "roman", 18 | "underline": false, 19 | "weight": "bold" 20 | }, 21 | "start_index": "1.0" 22 | }, 23 | "10.0": { 24 | "bind": { 25 | "link": null 26 | }, 27 | "config": { 28 | "background": "SystemWindow", 29 | "foreground": "black", 30 | "justify": "left", 31 | "tabs": [] 32 | }, 33 | "end_index": "11.0", 34 | "font": { 35 | "family": "Segoe ui", 36 | "overstrike": false, 37 | "size": 9, 38 | "slant": "roman", 39 | "underline": false, 40 | "weight": "normal" 41 | }, 42 | "start_index": "10.0" 43 | }, 44 | "11.0": { 45 | "bind": { 46 | "link": "https://www.python.org" 47 | }, 48 | "config": { 49 | "background": "SystemWindow", 50 | "foreground": "blue", 51 | "justify": "left", 52 | "tabs": [] 53 | }, 54 | "end_index": "11.19", 55 | "font": { 56 | "family": "Segoe ui", 57 | "overstrike": false, 58 | "size": 9, 59 | "slant": "roman", 60 | "underline": true, 61 | "weight": "normal" 62 | }, 63 | "start_index": "11.0" 64 | }, 65 | "11.19": { 66 | "bind": { 67 | "link": null 68 | }, 69 | "config": { 70 | "background": "SystemWindow", 71 | "foreground": "black", 72 | "justify": "left", 73 | "tabs": [] 74 | }, 75 | "end_index": "12.0", 76 | "font": { 77 | "family": "Segoe ui", 78 | "overstrike": false, 79 | "size": 9, 80 | "slant": "roman", 81 | "underline": false, 82 | "weight": "normal" 83 | }, 84 | "start_index": "11.19" 85 | }, 86 | "12.0": { 87 | "bind": { 88 | "link": "https://www.python.org" 89 | }, 90 | "config": { 91 | "background": "SystemWindow", 92 | "foreground": "red", 93 | "justify": "left", 94 | "tabs": [] 95 | }, 96 | "end_index": "12.18", 97 | "font": { 98 | "family": "Segoe ui", 99 | "overstrike": false, 100 | "size": 9, 101 | "slant": "roman", 102 | "underline": false, 103 | "weight": "normal" 104 | }, 105 | "start_index": "12.0" 106 | }, 107 | "12.18": { 108 | "bind": { 109 | "link": null 110 | }, 111 | "config": { 112 | "background": "SystemWindow", 113 | "foreground": "black", 114 | "justify": "left", 115 | "tabs": [] 116 | }, 117 | "end_index": "13.0", 118 | "font": { 119 | "family": "Segoe ui", 120 | "overstrike": false, 121 | "size": 9, 122 | "slant": "roman", 123 | "underline": false, 124 | "weight": "normal" 125 | }, 126 | "start_index": "12.18" 127 | }, 128 | "13.0": { 129 | "bind": { 130 | "link": null 131 | }, 132 | "config": { 133 | "background": "SystemWindow", 134 | "foreground": "black", 135 | "justify": "left", 136 | "tabs": [] 137 | }, 138 | "end_index": "13.16", 139 | "font": { 140 | "family": "Segoe ui", 141 | "overstrike": false, 142 | "size": 9, 143 | "slant": "roman", 144 | "underline": false, 145 | "weight": "normal" 146 | }, 147 | "start_index": "13.0" 148 | }, 149 | "13.16": { 150 | "bind": { 151 | "link": null 152 | }, 153 | "config": { 154 | "background": "SystemWindow", 155 | "foreground": "black", 156 | "justify": "left", 157 | "tabs": [] 158 | }, 159 | "end_index": "14.0", 160 | "font": { 161 | "family": "Segoe ui", 162 | "overstrike": false, 163 | "size": 9, 164 | "slant": "roman", 165 | "underline": false, 166 | "weight": "normal" 167 | }, 168 | "start_index": "13.16" 169 | }, 170 | "14.0": { 171 | "bind": { 172 | "link": null 173 | }, 174 | "config": { 175 | "background": "SystemWindow", 176 | "foreground": "black", 177 | "justify": "left", 178 | "tabs": [] 179 | }, 180 | "end_index": "15.0", 181 | "font": { 182 | "family": "Segoe ui", 183 | "overstrike": false, 184 | "size": 9, 185 | "slant": "roman", 186 | "underline": false, 187 | "weight": "normal" 188 | }, 189 | "start_index": "14.0" 190 | }, 191 | "15.0": { 192 | "bind": { 193 | "link": null 194 | }, 195 | "config": { 196 | "background": "SystemWindow", 197 | "foreground": "#3333ff", 198 | "justify": "left", 199 | "tabs": [ 200 | 30, 201 | "right", 202 | 35, 203 | "left" 204 | ] 205 | }, 206 | "end_index": "15.3", 207 | "font": { 208 | "family": "Segoe ui", 209 | "overstrike": false, 210 | "size": 9, 211 | "slant": "roman", 212 | "underline": false, 213 | "weight": "normal" 214 | }, 215 | "start_index": "15.0" 216 | }, 217 | "15.26": { 218 | "bind": { 219 | "link": null 220 | }, 221 | "config": { 222 | "background": "SystemWindow", 223 | "foreground": "#3333ff", 224 | "justify": "left", 225 | "tabs": [ 226 | 30, 227 | "right", 228 | 35, 229 | "left" 230 | ] 231 | }, 232 | "end_index": "16.0", 233 | "font": { 234 | "family": "Segoe ui", 235 | "overstrike": false, 236 | "size": 9, 237 | "slant": "roman", 238 | "underline": false, 239 | "weight": "normal" 240 | }, 241 | "start_index": "15.26" 242 | }, 243 | "15.3": { 244 | "bind": { 245 | "link": null 246 | }, 247 | "config": { 248 | "background": "SystemWindow", 249 | "foreground": "#3333ff", 250 | "justify": "left", 251 | "tabs": [ 252 | 30, 253 | "right", 254 | 35, 255 | "left" 256 | ] 257 | }, 258 | "end_index": "15.26", 259 | "font": { 260 | "family": "Segoe ui", 261 | "overstrike": false, 262 | "size": 9, 263 | "slant": "roman", 264 | "underline": false, 265 | "weight": "normal" 266 | }, 267 | "start_index": "15.3" 268 | }, 269 | "16.0": { 270 | "bind": { 271 | "link": null 272 | }, 273 | "config": { 274 | "background": "SystemWindow", 275 | "foreground": "#33aaff", 276 | "justify": "left", 277 | "tabs": [ 278 | 30, 279 | "right", 280 | 35, 281 | "left" 282 | ] 283 | }, 284 | "end_index": "16.3", 285 | "font": { 286 | "family": "Segoe ui", 287 | "overstrike": false, 288 | "size": 9, 289 | "slant": "roman", 290 | "underline": false, 291 | "weight": "normal" 292 | }, 293 | "start_index": "16.0" 294 | }, 295 | "16.26": { 296 | "bind": { 297 | "link": null 298 | }, 299 | "config": { 300 | "background": "SystemWindow", 301 | "foreground": "#33aaff", 302 | "justify": "left", 303 | "tabs": [ 304 | 30, 305 | "right", 306 | 35, 307 | "left" 308 | ] 309 | }, 310 | "end_index": "17.0", 311 | "font": { 312 | "family": "Segoe ui", 313 | "overstrike": false, 314 | "size": 9, 315 | "slant": "roman", 316 | "underline": false, 317 | "weight": "normal" 318 | }, 319 | "start_index": "16.26" 320 | }, 321 | "16.3": { 322 | "bind": { 323 | "link": null 324 | }, 325 | "config": { 326 | "background": "SystemWindow", 327 | "foreground": "#33aaff", 328 | "justify": "left", 329 | "tabs": [ 330 | 30, 331 | "right", 332 | 35, 333 | "left" 334 | ] 335 | }, 336 | "end_index": "16.26", 337 | "font": { 338 | "family": "Segoe ui", 339 | "overstrike": false, 340 | "size": 9, 341 | "slant": "roman", 342 | "underline": false, 343 | "weight": "normal" 344 | }, 345 | "start_index": "16.3" 346 | }, 347 | "17.0": { 348 | "bind": { 349 | "link": null 350 | }, 351 | "config": { 352 | "background": "SystemWindow", 353 | "foreground": "black", 354 | "justify": "left", 355 | "tabs": [] 356 | }, 357 | "end_index": "end", 358 | "font": { 359 | "family": "Segoe ui", 360 | "overstrike": false, 361 | "size": 9, 362 | "slant": "roman", 363 | "underline": false, 364 | "weight": "normal" 365 | }, 366 | "start_index": "17.0" 367 | }, 368 | "2.0": { 369 | "bind": { 370 | "link": null 371 | }, 372 | "config": { 373 | "background": "SystemWindow", 374 | "foreground": "black", 375 | "justify": "left", 376 | "tabs": [] 377 | }, 378 | "end_index": "3.0", 379 | "font": { 380 | "family": "Segoe ui", 381 | "overstrike": false, 382 | "size": 9, 383 | "slant": "roman", 384 | "underline": false, 385 | "weight": "normal" 386 | }, 387 | "start_index": "2.0" 388 | }, 389 | "3.0": { 390 | "bind": { 391 | "link": null 392 | }, 393 | "config": { 394 | "background": "black", 395 | "foreground": "yellow", 396 | "justify": "left", 397 | "tabs": [] 398 | }, 399 | "end_index": "3.5", 400 | "font": { 401 | "family": "Segoe ui", 402 | "overstrike": false, 403 | "size": 13, 404 | "slant": "roman", 405 | "underline": false, 406 | "weight": "normal" 407 | }, 408 | "start_index": "3.0" 409 | }, 410 | "3.10": { 411 | "bind": { 412 | "link": null 413 | }, 414 | "config": { 415 | "background": "SystemWindow", 416 | "foreground": "black", 417 | "justify": "left", 418 | "tabs": [] 419 | }, 420 | "end_index": "5.0", 421 | "font": { 422 | "family": "Segoe ui", 423 | "overstrike": false, 424 | "size": 9, 425 | "slant": "roman", 426 | "underline": false, 427 | "weight": "normal" 428 | }, 429 | "start_index": "3.10" 430 | }, 431 | "3.5": { 432 | "bind": { 433 | "link": null 434 | }, 435 | "config": { 436 | "background": "black", 437 | "foreground": "yellow", 438 | "justify": "left", 439 | "tabs": [] 440 | }, 441 | "end_index": "3.10", 442 | "font": { 443 | "family": "Segoe ui", 444 | "overstrike": false, 445 | "size": 13, 446 | "slant": "roman", 447 | "underline": false, 448 | "weight": "normal" 449 | }, 450 | "start_index": "3.5" 451 | }, 452 | "5.0": { 453 | "bind": { 454 | "link": null 455 | }, 456 | "config": { 457 | "background": "SystemWindow", 458 | "foreground": "black", 459 | "justify": "center", 460 | "tabs": [] 461 | }, 462 | "end_index": "6.0", 463 | "font": { 464 | "family": "Segoe ui", 465 | "overstrike": false, 466 | "size": 16, 467 | "slant": "roman", 468 | "underline": false, 469 | "weight": "bold" 470 | }, 471 | "start_index": "5.0" 472 | }, 473 | "6.0": { 474 | "bind": { 475 | "link": null 476 | }, 477 | "config": { 478 | "background": "SystemWindow", 479 | "foreground": "black", 480 | "justify": "left", 481 | "tabs": [] 482 | }, 483 | "end_index": "7.0", 484 | "font": { 485 | "family": "Segoe ui", 486 | "overstrike": false, 487 | "size": 9, 488 | "slant": "roman", 489 | "underline": false, 490 | "weight": "normal" 491 | }, 492 | "start_index": "6.0" 493 | }, 494 | "7.0": { 495 | "bind": { 496 | "link": null 497 | }, 498 | "config": { 499 | "background": "black", 500 | "foreground": "yellow", 501 | "justify": "left", 502 | "tabs": [] 503 | }, 504 | "end_index": "7.5", 505 | "font": { 506 | "family": "Segoe ui", 507 | "overstrike": false, 508 | "size": 20, 509 | "slant": "roman", 510 | "underline": false, 511 | "weight": "normal" 512 | }, 513 | "start_index": "7.0" 514 | }, 515 | "7.16": { 516 | "bind": { 517 | "link": null 518 | }, 519 | "config": { 520 | "background": "SystemWindow", 521 | "foreground": "black", 522 | "justify": "left", 523 | "tabs": [] 524 | }, 525 | "end_index": "9.0", 526 | "font": { 527 | "family": "Segoe ui", 528 | "overstrike": false, 529 | "size": 9, 530 | "slant": "roman", 531 | "underline": false, 532 | "weight": "normal" 533 | }, 534 | "start_index": "7.16" 535 | }, 536 | "7.5": { 537 | "bind": { 538 | "link": null 539 | }, 540 | "config": { 541 | "background": "black", 542 | "foreground": "yellow", 543 | "justify": "left", 544 | "tabs": [] 545 | }, 546 | "end_index": "7.16", 547 | "font": { 548 | "family": "Segoe ui", 549 | "overstrike": false, 550 | "size": 20, 551 | "slant": "roman", 552 | "underline": false, 553 | "weight": "normal" 554 | }, 555 | "start_index": "7.5" 556 | }, 557 | "9.0": { 558 | "bind": { 559 | "link": null 560 | }, 561 | "config": { 562 | "background": "SystemWindow", 563 | "foreground": "black", 564 | "justify": "center", 565 | "tabs": [] 566 | }, 567 | "end_index": "10.0", 568 | "font": { 569 | "family": "Segoe ui", 570 | "overstrike": false, 571 | "size": 16, 572 | "slant": "roman", 573 | "underline": false, 574 | "weight": "bold" 575 | }, 576 | "start_index": "9.0" 577 | } 578 | } -------------------------------------------------------------------------------- /tests/HTMLScrolledText_images.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "SystemWindow", 8 | "foreground": "black", 9 | "justify": "center", 10 | "tabs": [] 11 | }, 12 | "end_index": "2.0", 13 | "font": { 14 | "family": "Segoe ui", 15 | "overstrike": false, 16 | "size": 16, 17 | "slant": "roman", 18 | "underline": false, 19 | "weight": "bold" 20 | }, 21 | "start_index": "1.0" 22 | }, 23 | "10.0": { 24 | "bind": { 25 | "link": null 26 | }, 27 | "config": { 28 | "background": "SystemWindow", 29 | "foreground": "black", 30 | "justify": "left", 31 | "tabs": [] 32 | }, 33 | "end_index": "11.0", 34 | "font": { 35 | "family": "Segoe ui", 36 | "overstrike": false, 37 | "size": 9, 38 | "slant": "roman", 39 | "underline": false, 40 | "weight": "normal" 41 | }, 42 | "start_index": "10.0" 43 | }, 44 | "11.0": { 45 | "bind": { 46 | "link": "https://www.python.org" 47 | }, 48 | "config": { 49 | "background": "SystemWindow", 50 | "foreground": "blue", 51 | "justify": "left", 52 | "tabs": [] 53 | }, 54 | "end_index": "11.19", 55 | "font": { 56 | "family": "Segoe ui", 57 | "overstrike": false, 58 | "size": 9, 59 | "slant": "roman", 60 | "underline": true, 61 | "weight": "normal" 62 | }, 63 | "start_index": "11.0" 64 | }, 65 | "11.19": { 66 | "bind": { 67 | "link": null 68 | }, 69 | "config": { 70 | "background": "SystemWindow", 71 | "foreground": "black", 72 | "justify": "left", 73 | "tabs": [] 74 | }, 75 | "end_index": "12.0", 76 | "font": { 77 | "family": "Segoe ui", 78 | "overstrike": false, 79 | "size": 9, 80 | "slant": "roman", 81 | "underline": false, 82 | "weight": "normal" 83 | }, 84 | "start_index": "11.19" 85 | }, 86 | "12.0": { 87 | "bind": { 88 | "link": "https://www.python.org" 89 | }, 90 | "config": { 91 | "background": "SystemWindow", 92 | "foreground": "red", 93 | "justify": "left", 94 | "tabs": [] 95 | }, 96 | "end_index": "12.18", 97 | "font": { 98 | "family": "Segoe ui", 99 | "overstrike": false, 100 | "size": 9, 101 | "slant": "roman", 102 | "underline": false, 103 | "weight": "normal" 104 | }, 105 | "start_index": "12.0" 106 | }, 107 | "12.18": { 108 | "bind": { 109 | "link": null 110 | }, 111 | "config": { 112 | "background": "SystemWindow", 113 | "foreground": "black", 114 | "justify": "left", 115 | "tabs": [] 116 | }, 117 | "end_index": "13.0", 118 | "font": { 119 | "family": "Segoe ui", 120 | "overstrike": false, 121 | "size": 9, 122 | "slant": "roman", 123 | "underline": false, 124 | "weight": "normal" 125 | }, 126 | "start_index": "12.18" 127 | }, 128 | "13.0": { 129 | "bind": { 130 | "link": null 131 | }, 132 | "config": { 133 | "background": "SystemWindow", 134 | "foreground": "black", 135 | "justify": "left", 136 | "tabs": [] 137 | }, 138 | "end_index": "13.16", 139 | "font": { 140 | "family": "Segoe ui", 141 | "overstrike": false, 142 | "size": 9, 143 | "slant": "roman", 144 | "underline": false, 145 | "weight": "normal" 146 | }, 147 | "start_index": "13.0" 148 | }, 149 | "13.16": { 150 | "bind": { 151 | "link": null 152 | }, 153 | "config": { 154 | "background": "SystemWindow", 155 | "foreground": "black", 156 | "justify": "left", 157 | "tabs": [] 158 | }, 159 | "end_index": "14.0", 160 | "font": { 161 | "family": "Segoe ui", 162 | "overstrike": false, 163 | "size": 9, 164 | "slant": "roman", 165 | "underline": false, 166 | "weight": "normal" 167 | }, 168 | "start_index": "13.16" 169 | }, 170 | "14.0": { 171 | "bind": { 172 | "link": null 173 | }, 174 | "config": { 175 | "background": "SystemWindow", 176 | "foreground": "black", 177 | "justify": "left", 178 | "tabs": [] 179 | }, 180 | "end_index": "15.0", 181 | "font": { 182 | "family": "Segoe ui", 183 | "overstrike": false, 184 | "size": 9, 185 | "slant": "roman", 186 | "underline": false, 187 | "weight": "normal" 188 | }, 189 | "start_index": "14.0" 190 | }, 191 | "15.0": { 192 | "bind": { 193 | "link": null 194 | }, 195 | "config": { 196 | "background": "SystemWindow", 197 | "foreground": "#3333ff", 198 | "justify": "left", 199 | "tabs": [ 200 | 30, 201 | "right", 202 | 35, 203 | "left" 204 | ] 205 | }, 206 | "end_index": "15.3", 207 | "font": { 208 | "family": "Segoe ui", 209 | "overstrike": false, 210 | "size": 9, 211 | "slant": "roman", 212 | "underline": false, 213 | "weight": "normal" 214 | }, 215 | "start_index": "15.0" 216 | }, 217 | "15.26": { 218 | "bind": { 219 | "link": null 220 | }, 221 | "config": { 222 | "background": "SystemWindow", 223 | "foreground": "#3333ff", 224 | "justify": "left", 225 | "tabs": [ 226 | 30, 227 | "right", 228 | 35, 229 | "left" 230 | ] 231 | }, 232 | "end_index": "16.0", 233 | "font": { 234 | "family": "Segoe ui", 235 | "overstrike": false, 236 | "size": 9, 237 | "slant": "roman", 238 | "underline": false, 239 | "weight": "normal" 240 | }, 241 | "start_index": "15.26" 242 | }, 243 | "15.3": { 244 | "bind": { 245 | "link": null 246 | }, 247 | "config": { 248 | "background": "SystemWindow", 249 | "foreground": "#3333ff", 250 | "justify": "left", 251 | "tabs": [ 252 | 30, 253 | "right", 254 | 35, 255 | "left" 256 | ] 257 | }, 258 | "end_index": "15.26", 259 | "font": { 260 | "family": "Segoe ui", 261 | "overstrike": false, 262 | "size": 9, 263 | "slant": "roman", 264 | "underline": false, 265 | "weight": "normal" 266 | }, 267 | "start_index": "15.3" 268 | }, 269 | "16.0": { 270 | "bind": { 271 | "link": null 272 | }, 273 | "config": { 274 | "background": "SystemWindow", 275 | "foreground": "#33aaff", 276 | "justify": "left", 277 | "tabs": [ 278 | 30, 279 | "right", 280 | 35, 281 | "left" 282 | ] 283 | }, 284 | "end_index": "16.3", 285 | "font": { 286 | "family": "Segoe ui", 287 | "overstrike": false, 288 | "size": 9, 289 | "slant": "roman", 290 | "underline": false, 291 | "weight": "normal" 292 | }, 293 | "start_index": "16.0" 294 | }, 295 | "16.26": { 296 | "bind": { 297 | "link": null 298 | }, 299 | "config": { 300 | "background": "SystemWindow", 301 | "foreground": "#33aaff", 302 | "justify": "left", 303 | "tabs": [ 304 | 30, 305 | "right", 306 | 35, 307 | "left" 308 | ] 309 | }, 310 | "end_index": "17.0", 311 | "font": { 312 | "family": "Segoe ui", 313 | "overstrike": false, 314 | "size": 9, 315 | "slant": "roman", 316 | "underline": false, 317 | "weight": "normal" 318 | }, 319 | "start_index": "16.26" 320 | }, 321 | "16.3": { 322 | "bind": { 323 | "link": null 324 | }, 325 | "config": { 326 | "background": "SystemWindow", 327 | "foreground": "#33aaff", 328 | "justify": "left", 329 | "tabs": [ 330 | 30, 331 | "right", 332 | 35, 333 | "left" 334 | ] 335 | }, 336 | "end_index": "16.26", 337 | "font": { 338 | "family": "Segoe ui", 339 | "overstrike": false, 340 | "size": 9, 341 | "slant": "roman", 342 | "underline": false, 343 | "weight": "normal" 344 | }, 345 | "start_index": "16.3" 346 | }, 347 | "17.0": { 348 | "bind": { 349 | "link": null 350 | }, 351 | "config": { 352 | "background": "SystemWindow", 353 | "foreground": "black", 354 | "justify": "left", 355 | "tabs": [] 356 | }, 357 | "end_index": "end", 358 | "font": { 359 | "family": "Segoe ui", 360 | "overstrike": false, 361 | "size": 9, 362 | "slant": "roman", 363 | "underline": false, 364 | "weight": "normal" 365 | }, 366 | "start_index": "17.0" 367 | }, 368 | "2.0": { 369 | "bind": { 370 | "link": null 371 | }, 372 | "config": { 373 | "background": "SystemWindow", 374 | "foreground": "black", 375 | "justify": "left", 376 | "tabs": [] 377 | }, 378 | "end_index": "3.0", 379 | "font": { 380 | "family": "Segoe ui", 381 | "overstrike": false, 382 | "size": 9, 383 | "slant": "roman", 384 | "underline": false, 385 | "weight": "normal" 386 | }, 387 | "start_index": "2.0" 388 | }, 389 | "3.0": { 390 | "bind": { 391 | "link": null 392 | }, 393 | "config": { 394 | "background": "black", 395 | "foreground": "yellow", 396 | "justify": "left", 397 | "tabs": [] 398 | }, 399 | "end_index": "3.5", 400 | "font": { 401 | "family": "Segoe ui", 402 | "overstrike": false, 403 | "size": 13, 404 | "slant": "roman", 405 | "underline": false, 406 | "weight": "normal" 407 | }, 408 | "start_index": "3.0" 409 | }, 410 | "3.10": { 411 | "bind": { 412 | "link": null 413 | }, 414 | "config": { 415 | "background": "SystemWindow", 416 | "foreground": "black", 417 | "justify": "left", 418 | "tabs": [] 419 | }, 420 | "end_index": "5.0", 421 | "font": { 422 | "family": "Segoe ui", 423 | "overstrike": false, 424 | "size": 9, 425 | "slant": "roman", 426 | "underline": false, 427 | "weight": "normal" 428 | }, 429 | "start_index": "3.10" 430 | }, 431 | "3.5": { 432 | "bind": { 433 | "link": null 434 | }, 435 | "config": { 436 | "background": "black", 437 | "foreground": "yellow", 438 | "justify": "left", 439 | "tabs": [] 440 | }, 441 | "end_index": "3.10", 442 | "font": { 443 | "family": "Segoe ui", 444 | "overstrike": false, 445 | "size": 13, 446 | "slant": "roman", 447 | "underline": false, 448 | "weight": "normal" 449 | }, 450 | "start_index": "3.5" 451 | }, 452 | "5.0": { 453 | "bind": { 454 | "link": null 455 | }, 456 | "config": { 457 | "background": "SystemWindow", 458 | "foreground": "black", 459 | "justify": "center", 460 | "tabs": [] 461 | }, 462 | "end_index": "6.0", 463 | "font": { 464 | "family": "Segoe ui", 465 | "overstrike": false, 466 | "size": 16, 467 | "slant": "roman", 468 | "underline": false, 469 | "weight": "bold" 470 | }, 471 | "start_index": "5.0" 472 | }, 473 | "6.0": { 474 | "bind": { 475 | "link": null 476 | }, 477 | "config": { 478 | "background": "SystemWindow", 479 | "foreground": "black", 480 | "justify": "left", 481 | "tabs": [] 482 | }, 483 | "end_index": "7.0", 484 | "font": { 485 | "family": "Segoe ui", 486 | "overstrike": false, 487 | "size": 9, 488 | "slant": "roman", 489 | "underline": false, 490 | "weight": "normal" 491 | }, 492 | "start_index": "6.0" 493 | }, 494 | "7.0": { 495 | "bind": { 496 | "link": null 497 | }, 498 | "config": { 499 | "background": "black", 500 | "foreground": "yellow", 501 | "justify": "left", 502 | "tabs": [] 503 | }, 504 | "end_index": "7.5", 505 | "font": { 506 | "family": "Segoe ui", 507 | "overstrike": false, 508 | "size": 20, 509 | "slant": "roman", 510 | "underline": false, 511 | "weight": "normal" 512 | }, 513 | "start_index": "7.0" 514 | }, 515 | "7.16": { 516 | "bind": { 517 | "link": null 518 | }, 519 | "config": { 520 | "background": "SystemWindow", 521 | "foreground": "black", 522 | "justify": "left", 523 | "tabs": [] 524 | }, 525 | "end_index": "9.0", 526 | "font": { 527 | "family": "Segoe ui", 528 | "overstrike": false, 529 | "size": 9, 530 | "slant": "roman", 531 | "underline": false, 532 | "weight": "normal" 533 | }, 534 | "start_index": "7.16" 535 | }, 536 | "7.5": { 537 | "bind": { 538 | "link": null 539 | }, 540 | "config": { 541 | "background": "black", 542 | "foreground": "yellow", 543 | "justify": "left", 544 | "tabs": [] 545 | }, 546 | "end_index": "7.16", 547 | "font": { 548 | "family": "Segoe ui", 549 | "overstrike": false, 550 | "size": 20, 551 | "slant": "roman", 552 | "underline": false, 553 | "weight": "normal" 554 | }, 555 | "start_index": "7.5" 556 | }, 557 | "9.0": { 558 | "bind": { 559 | "link": null 560 | }, 561 | "config": { 562 | "background": "SystemWindow", 563 | "foreground": "black", 564 | "justify": "center", 565 | "tabs": [] 566 | }, 567 | "end_index": "10.0", 568 | "font": { 569 | "family": "Segoe ui", 570 | "overstrike": false, 571 | "size": 16, 572 | "slant": "roman", 573 | "underline": false, 574 | "weight": "bold" 575 | }, 576 | "start_index": "9.0" 577 | } 578 | } -------------------------------------------------------------------------------- /tests/HTMLLabel_images.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "SystemButtonFace", 8 | "foreground": "black", 9 | "justify": "center", 10 | "tabs": [] 11 | }, 12 | "end_index": "2.0", 13 | "font": { 14 | "family": "Segoe ui", 15 | "overstrike": false, 16 | "size": 16, 17 | "slant": "roman", 18 | "underline": false, 19 | "weight": "bold" 20 | }, 21 | "start_index": "1.0" 22 | }, 23 | "10.0": { 24 | "bind": { 25 | "link": null 26 | }, 27 | "config": { 28 | "background": "SystemButtonFace", 29 | "foreground": "black", 30 | "justify": "left", 31 | "tabs": [] 32 | }, 33 | "end_index": "11.0", 34 | "font": { 35 | "family": "Segoe ui", 36 | "overstrike": false, 37 | "size": 9, 38 | "slant": "roman", 39 | "underline": false, 40 | "weight": "normal" 41 | }, 42 | "start_index": "10.0" 43 | }, 44 | "11.0": { 45 | "bind": { 46 | "link": "https://www.python.org" 47 | }, 48 | "config": { 49 | "background": "SystemButtonFace", 50 | "foreground": "blue", 51 | "justify": "left", 52 | "tabs": [] 53 | }, 54 | "end_index": "11.19", 55 | "font": { 56 | "family": "Segoe ui", 57 | "overstrike": false, 58 | "size": 9, 59 | "slant": "roman", 60 | "underline": true, 61 | "weight": "normal" 62 | }, 63 | "start_index": "11.0" 64 | }, 65 | "11.19": { 66 | "bind": { 67 | "link": null 68 | }, 69 | "config": { 70 | "background": "SystemButtonFace", 71 | "foreground": "black", 72 | "justify": "left", 73 | "tabs": [] 74 | }, 75 | "end_index": "12.0", 76 | "font": { 77 | "family": "Segoe ui", 78 | "overstrike": false, 79 | "size": 9, 80 | "slant": "roman", 81 | "underline": false, 82 | "weight": "normal" 83 | }, 84 | "start_index": "11.19" 85 | }, 86 | "12.0": { 87 | "bind": { 88 | "link": "https://www.python.org" 89 | }, 90 | "config": { 91 | "background": "SystemButtonFace", 92 | "foreground": "red", 93 | "justify": "left", 94 | "tabs": [] 95 | }, 96 | "end_index": "12.18", 97 | "font": { 98 | "family": "Segoe ui", 99 | "overstrike": false, 100 | "size": 9, 101 | "slant": "roman", 102 | "underline": false, 103 | "weight": "normal" 104 | }, 105 | "start_index": "12.0" 106 | }, 107 | "12.18": { 108 | "bind": { 109 | "link": null 110 | }, 111 | "config": { 112 | "background": "SystemButtonFace", 113 | "foreground": "black", 114 | "justify": "left", 115 | "tabs": [] 116 | }, 117 | "end_index": "13.0", 118 | "font": { 119 | "family": "Segoe ui", 120 | "overstrike": false, 121 | "size": 9, 122 | "slant": "roman", 123 | "underline": false, 124 | "weight": "normal" 125 | }, 126 | "start_index": "12.18" 127 | }, 128 | "13.0": { 129 | "bind": { 130 | "link": null 131 | }, 132 | "config": { 133 | "background": "SystemButtonFace", 134 | "foreground": "black", 135 | "justify": "left", 136 | "tabs": [] 137 | }, 138 | "end_index": "13.16", 139 | "font": { 140 | "family": "Segoe ui", 141 | "overstrike": false, 142 | "size": 9, 143 | "slant": "roman", 144 | "underline": false, 145 | "weight": "normal" 146 | }, 147 | "start_index": "13.0" 148 | }, 149 | "13.16": { 150 | "bind": { 151 | "link": null 152 | }, 153 | "config": { 154 | "background": "SystemButtonFace", 155 | "foreground": "black", 156 | "justify": "left", 157 | "tabs": [] 158 | }, 159 | "end_index": "14.0", 160 | "font": { 161 | "family": "Segoe ui", 162 | "overstrike": false, 163 | "size": 9, 164 | "slant": "roman", 165 | "underline": false, 166 | "weight": "normal" 167 | }, 168 | "start_index": "13.16" 169 | }, 170 | "14.0": { 171 | "bind": { 172 | "link": null 173 | }, 174 | "config": { 175 | "background": "SystemButtonFace", 176 | "foreground": "black", 177 | "justify": "left", 178 | "tabs": [] 179 | }, 180 | "end_index": "15.0", 181 | "font": { 182 | "family": "Segoe ui", 183 | "overstrike": false, 184 | "size": 9, 185 | "slant": "roman", 186 | "underline": false, 187 | "weight": "normal" 188 | }, 189 | "start_index": "14.0" 190 | }, 191 | "15.0": { 192 | "bind": { 193 | "link": null 194 | }, 195 | "config": { 196 | "background": "SystemButtonFace", 197 | "foreground": "#3333ff", 198 | "justify": "left", 199 | "tabs": [ 200 | 30, 201 | "right", 202 | 35, 203 | "left" 204 | ] 205 | }, 206 | "end_index": "15.3", 207 | "font": { 208 | "family": "Segoe ui", 209 | "overstrike": false, 210 | "size": 9, 211 | "slant": "roman", 212 | "underline": false, 213 | "weight": "normal" 214 | }, 215 | "start_index": "15.0" 216 | }, 217 | "15.26": { 218 | "bind": { 219 | "link": null 220 | }, 221 | "config": { 222 | "background": "SystemButtonFace", 223 | "foreground": "#3333ff", 224 | "justify": "left", 225 | "tabs": [ 226 | 30, 227 | "right", 228 | 35, 229 | "left" 230 | ] 231 | }, 232 | "end_index": "16.0", 233 | "font": { 234 | "family": "Segoe ui", 235 | "overstrike": false, 236 | "size": 9, 237 | "slant": "roman", 238 | "underline": false, 239 | "weight": "normal" 240 | }, 241 | "start_index": "15.26" 242 | }, 243 | "15.3": { 244 | "bind": { 245 | "link": null 246 | }, 247 | "config": { 248 | "background": "SystemButtonFace", 249 | "foreground": "#3333ff", 250 | "justify": "left", 251 | "tabs": [ 252 | 30, 253 | "right", 254 | 35, 255 | "left" 256 | ] 257 | }, 258 | "end_index": "15.26", 259 | "font": { 260 | "family": "Segoe ui", 261 | "overstrike": false, 262 | "size": 9, 263 | "slant": "roman", 264 | "underline": false, 265 | "weight": "normal" 266 | }, 267 | "start_index": "15.3" 268 | }, 269 | "16.0": { 270 | "bind": { 271 | "link": null 272 | }, 273 | "config": { 274 | "background": "SystemButtonFace", 275 | "foreground": "#33aaff", 276 | "justify": "left", 277 | "tabs": [ 278 | 30, 279 | "right", 280 | 35, 281 | "left" 282 | ] 283 | }, 284 | "end_index": "16.3", 285 | "font": { 286 | "family": "Segoe ui", 287 | "overstrike": false, 288 | "size": 9, 289 | "slant": "roman", 290 | "underline": false, 291 | "weight": "normal" 292 | }, 293 | "start_index": "16.0" 294 | }, 295 | "16.26": { 296 | "bind": { 297 | "link": null 298 | }, 299 | "config": { 300 | "background": "SystemButtonFace", 301 | "foreground": "#33aaff", 302 | "justify": "left", 303 | "tabs": [ 304 | 30, 305 | "right", 306 | 35, 307 | "left" 308 | ] 309 | }, 310 | "end_index": "17.0", 311 | "font": { 312 | "family": "Segoe ui", 313 | "overstrike": false, 314 | "size": 9, 315 | "slant": "roman", 316 | "underline": false, 317 | "weight": "normal" 318 | }, 319 | "start_index": "16.26" 320 | }, 321 | "16.3": { 322 | "bind": { 323 | "link": null 324 | }, 325 | "config": { 326 | "background": "SystemButtonFace", 327 | "foreground": "#33aaff", 328 | "justify": "left", 329 | "tabs": [ 330 | 30, 331 | "right", 332 | 35, 333 | "left" 334 | ] 335 | }, 336 | "end_index": "16.26", 337 | "font": { 338 | "family": "Segoe ui", 339 | "overstrike": false, 340 | "size": 9, 341 | "slant": "roman", 342 | "underline": false, 343 | "weight": "normal" 344 | }, 345 | "start_index": "16.3" 346 | }, 347 | "17.0": { 348 | "bind": { 349 | "link": null 350 | }, 351 | "config": { 352 | "background": "SystemButtonFace", 353 | "foreground": "black", 354 | "justify": "left", 355 | "tabs": [] 356 | }, 357 | "end_index": "end", 358 | "font": { 359 | "family": "Segoe ui", 360 | "overstrike": false, 361 | "size": 9, 362 | "slant": "roman", 363 | "underline": false, 364 | "weight": "normal" 365 | }, 366 | "start_index": "17.0" 367 | }, 368 | "2.0": { 369 | "bind": { 370 | "link": null 371 | }, 372 | "config": { 373 | "background": "SystemButtonFace", 374 | "foreground": "black", 375 | "justify": "left", 376 | "tabs": [] 377 | }, 378 | "end_index": "3.0", 379 | "font": { 380 | "family": "Segoe ui", 381 | "overstrike": false, 382 | "size": 9, 383 | "slant": "roman", 384 | "underline": false, 385 | "weight": "normal" 386 | }, 387 | "start_index": "2.0" 388 | }, 389 | "3.0": { 390 | "bind": { 391 | "link": null 392 | }, 393 | "config": { 394 | "background": "black", 395 | "foreground": "yellow", 396 | "justify": "left", 397 | "tabs": [] 398 | }, 399 | "end_index": "3.5", 400 | "font": { 401 | "family": "Segoe ui", 402 | "overstrike": false, 403 | "size": 13, 404 | "slant": "roman", 405 | "underline": false, 406 | "weight": "normal" 407 | }, 408 | "start_index": "3.0" 409 | }, 410 | "3.10": { 411 | "bind": { 412 | "link": null 413 | }, 414 | "config": { 415 | "background": "SystemButtonFace", 416 | "foreground": "black", 417 | "justify": "left", 418 | "tabs": [] 419 | }, 420 | "end_index": "5.0", 421 | "font": { 422 | "family": "Segoe ui", 423 | "overstrike": false, 424 | "size": 9, 425 | "slant": "roman", 426 | "underline": false, 427 | "weight": "normal" 428 | }, 429 | "start_index": "3.10" 430 | }, 431 | "3.5": { 432 | "bind": { 433 | "link": null 434 | }, 435 | "config": { 436 | "background": "black", 437 | "foreground": "yellow", 438 | "justify": "left", 439 | "tabs": [] 440 | }, 441 | "end_index": "3.10", 442 | "font": { 443 | "family": "Segoe ui", 444 | "overstrike": false, 445 | "size": 13, 446 | "slant": "roman", 447 | "underline": false, 448 | "weight": "normal" 449 | }, 450 | "start_index": "3.5" 451 | }, 452 | "5.0": { 453 | "bind": { 454 | "link": null 455 | }, 456 | "config": { 457 | "background": "SystemButtonFace", 458 | "foreground": "black", 459 | "justify": "center", 460 | "tabs": [] 461 | }, 462 | "end_index": "6.0", 463 | "font": { 464 | "family": "Segoe ui", 465 | "overstrike": false, 466 | "size": 16, 467 | "slant": "roman", 468 | "underline": false, 469 | "weight": "bold" 470 | }, 471 | "start_index": "5.0" 472 | }, 473 | "6.0": { 474 | "bind": { 475 | "link": null 476 | }, 477 | "config": { 478 | "background": "SystemButtonFace", 479 | "foreground": "black", 480 | "justify": "left", 481 | "tabs": [] 482 | }, 483 | "end_index": "7.0", 484 | "font": { 485 | "family": "Segoe ui", 486 | "overstrike": false, 487 | "size": 9, 488 | "slant": "roman", 489 | "underline": false, 490 | "weight": "normal" 491 | }, 492 | "start_index": "6.0" 493 | }, 494 | "7.0": { 495 | "bind": { 496 | "link": null 497 | }, 498 | "config": { 499 | "background": "black", 500 | "foreground": "yellow", 501 | "justify": "left", 502 | "tabs": [] 503 | }, 504 | "end_index": "7.5", 505 | "font": { 506 | "family": "Segoe ui", 507 | "overstrike": false, 508 | "size": 20, 509 | "slant": "roman", 510 | "underline": false, 511 | "weight": "normal" 512 | }, 513 | "start_index": "7.0" 514 | }, 515 | "7.16": { 516 | "bind": { 517 | "link": null 518 | }, 519 | "config": { 520 | "background": "SystemButtonFace", 521 | "foreground": "black", 522 | "justify": "left", 523 | "tabs": [] 524 | }, 525 | "end_index": "9.0", 526 | "font": { 527 | "family": "Segoe ui", 528 | "overstrike": false, 529 | "size": 9, 530 | "slant": "roman", 531 | "underline": false, 532 | "weight": "normal" 533 | }, 534 | "start_index": "7.16" 535 | }, 536 | "7.5": { 537 | "bind": { 538 | "link": null 539 | }, 540 | "config": { 541 | "background": "black", 542 | "foreground": "yellow", 543 | "justify": "left", 544 | "tabs": [] 545 | }, 546 | "end_index": "7.16", 547 | "font": { 548 | "family": "Segoe ui", 549 | "overstrike": false, 550 | "size": 20, 551 | "slant": "roman", 552 | "underline": false, 553 | "weight": "normal" 554 | }, 555 | "start_index": "7.5" 556 | }, 557 | "9.0": { 558 | "bind": { 559 | "link": null 560 | }, 561 | "config": { 562 | "background": "SystemButtonFace", 563 | "foreground": "black", 564 | "justify": "center", 565 | "tabs": [] 566 | }, 567 | "end_index": "10.0", 568 | "font": { 569 | "family": "Segoe ui", 570 | "overstrike": false, 571 | "size": 16, 572 | "slant": "roman", 573 | "underline": false, 574 | "weight": "bold" 575 | }, 576 | "start_index": "9.0" 577 | } 578 | } -------------------------------------------------------------------------------- /tests/HTMLText_styles.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "blue", 8 | "foreground": "yellow", 9 | "justify": "left", 10 | "tabs": [] 11 | }, 12 | "end_index": "1.8", 13 | "font": { 14 | "family": "impact", 15 | "overstrike": false, 16 | "size": 13, 17 | "slant": "roman", 18 | "underline": true, 19 | "weight": "normal" 20 | }, 21 | "start_index": "1.0" 22 | }, 23 | "1.16": { 24 | "bind": { 25 | "link": null 26 | }, 27 | "config": { 28 | "background": "blue", 29 | "foreground": "yellow", 30 | "justify": "left", 31 | "tabs": [] 32 | }, 33 | "end_index": "1.29", 34 | "font": { 35 | "family": "impact", 36 | "overstrike": false, 37 | "size": 13, 38 | "slant": "roman", 39 | "underline": false, 40 | "weight": "bold" 41 | }, 42 | "start_index": "1.16" 43 | }, 44 | "1.29": { 45 | "bind": { 46 | "link": null 47 | }, 48 | "config": { 49 | "background": "blue", 50 | "foreground": "yellow", 51 | "justify": "left", 52 | "tabs": [] 53 | }, 54 | "end_index": "1.37", 55 | "font": { 56 | "family": "impact", 57 | "overstrike": false, 58 | "size": 13, 59 | "slant": "italic", 60 | "underline": true, 61 | "weight": "normal" 62 | }, 63 | "start_index": "1.29" 64 | }, 65 | "1.37": { 66 | "bind": { 67 | "link": null 68 | }, 69 | "config": { 70 | "background": "blue", 71 | "foreground": "yellow", 72 | "justify": "left", 73 | "tabs": [] 74 | }, 75 | "end_index": "1.46", 76 | "font": { 77 | "family": "impact", 78 | "overstrike": false, 79 | "size": 13, 80 | "slant": "italic", 81 | "underline": true, 82 | "weight": "normal" 83 | }, 84 | "start_index": "1.37" 85 | }, 86 | "1.46": { 87 | "bind": { 88 | "link": null 89 | }, 90 | "config": { 91 | "background": "blue", 92 | "foreground": "yellow", 93 | "justify": "left", 94 | "tabs": [] 95 | }, 96 | "end_index": "1.54", 97 | "font": { 98 | "family": "impact", 99 | "overstrike": false, 100 | "size": 13, 101 | "slant": "roman", 102 | "underline": true, 103 | "weight": "normal" 104 | }, 105 | "start_index": "1.46" 106 | }, 107 | "1.54": { 108 | "bind": { 109 | "link": null 110 | }, 111 | "config": { 112 | "background": "blue", 113 | "foreground": "yellow", 114 | "justify": "left", 115 | "tabs": [] 116 | }, 117 | "end_index": "1.65", 118 | "font": { 119 | "family": "impact", 120 | "overstrike": false, 121 | "size": 13, 122 | "slant": "roman", 123 | "underline": true, 124 | "weight": "normal" 125 | }, 126 | "start_index": "1.54" 127 | }, 128 | "1.65": { 129 | "bind": { 130 | "link": null 131 | }, 132 | "config": { 133 | "background": "blue", 134 | "foreground": "yellow", 135 | "justify": "left", 136 | "tabs": [] 137 | }, 138 | "end_index": "1.76", 139 | "font": { 140 | "family": "impact", 141 | "overstrike": false, 142 | "size": 13, 143 | "slant": "roman", 144 | "underline": true, 145 | "weight": "normal" 146 | }, 147 | "start_index": "1.65" 148 | }, 149 | "1.76": { 150 | "bind": { 151 | "link": null 152 | }, 153 | "config": { 154 | "background": "SystemWindow", 155 | "foreground": "black", 156 | "justify": "left", 157 | "tabs": [] 158 | }, 159 | "end_index": "2.0", 160 | "font": { 161 | "family": "Segoe ui", 162 | "overstrike": false, 163 | "size": 9, 164 | "slant": "roman", 165 | "underline": false, 166 | "weight": "normal" 167 | }, 168 | "start_index": "1.76" 169 | }, 170 | "1.8": { 171 | "bind": { 172 | "link": null 173 | }, 174 | "config": { 175 | "background": "blue", 176 | "foreground": "yellow", 177 | "justify": "left", 178 | "tabs": [] 179 | }, 180 | "end_index": "1.16", 181 | "font": { 182 | "family": "impact", 183 | "overstrike": false, 184 | "size": 13, 185 | "slant": "roman", 186 | "underline": true, 187 | "weight": "bold" 188 | }, 189 | "start_index": "1.8" 190 | }, 191 | "10.0": { 192 | "bind": { 193 | "link": null 194 | }, 195 | "config": { 196 | "background": "blue", 197 | "foreground": "yellow", 198 | "justify": "center", 199 | "tabs": [] 200 | }, 201 | "end_index": "11.0", 202 | "font": { 203 | "family": "impact", 204 | "overstrike": false, 205 | "size": 13, 206 | "slant": "roman", 207 | "underline": true, 208 | "weight": "bold" 209 | }, 210 | "start_index": "10.0" 211 | }, 212 | "11.0": { 213 | "bind": { 214 | "link": null 215 | }, 216 | "config": { 217 | "background": "SystemWindow", 218 | "foreground": "black", 219 | "justify": "left", 220 | "tabs": [] 221 | }, 222 | "end_index": "12.0", 223 | "font": { 224 | "family": "Segoe ui", 225 | "overstrike": false, 226 | "size": 9, 227 | "slant": "roman", 228 | "underline": false, 229 | "weight": "normal" 230 | }, 231 | "start_index": "11.0" 232 | }, 233 | "12.0": { 234 | "bind": { 235 | "link": null 236 | }, 237 | "config": { 238 | "background": "blue", 239 | "foreground": "yellow", 240 | "justify": "center", 241 | "tabs": [] 242 | }, 243 | "end_index": "13.0", 244 | "font": { 245 | "family": "impact", 246 | "overstrike": false, 247 | "size": 13, 248 | "slant": "roman", 249 | "underline": true, 250 | "weight": "bold" 251 | }, 252 | "start_index": "12.0" 253 | }, 254 | "13.0": { 255 | "bind": { 256 | "link": null 257 | }, 258 | "config": { 259 | "background": "SystemWindow", 260 | "foreground": "black", 261 | "justify": "left", 262 | "tabs": [] 263 | }, 264 | "end_index": "14.0", 265 | "font": { 266 | "family": "Segoe ui", 267 | "overstrike": false, 268 | "size": 9, 269 | "slant": "roman", 270 | "underline": false, 271 | "weight": "normal" 272 | }, 273 | "start_index": "13.0" 274 | }, 275 | "14.0": { 276 | "bind": { 277 | "link": null 278 | }, 279 | "config": { 280 | "background": "blue", 281 | "foreground": "yellow", 282 | "justify": "center", 283 | "tabs": [] 284 | }, 285 | "end_index": "15.0", 286 | "font": { 287 | "family": "impact", 288 | "overstrike": false, 289 | "size": 13, 290 | "slant": "roman", 291 | "underline": true, 292 | "weight": "bold" 293 | }, 294 | "start_index": "14.0" 295 | }, 296 | "15.0": { 297 | "bind": { 298 | "link": null 299 | }, 300 | "config": { 301 | "background": "SystemWindow", 302 | "foreground": "black", 303 | "justify": "left", 304 | "tabs": [] 305 | }, 306 | "end_index": "16.0", 307 | "font": { 308 | "family": "Segoe ui", 309 | "overstrike": false, 310 | "size": 9, 311 | "slant": "roman", 312 | "underline": false, 313 | "weight": "normal" 314 | }, 315 | "start_index": "15.0" 316 | }, 317 | "16.0": { 318 | "bind": { 319 | "link": null 320 | }, 321 | "config": { 322 | "background": "blue", 323 | "foreground": "yellow", 324 | "justify": "center", 325 | "tabs": [] 326 | }, 327 | "end_index": "17.0", 328 | "font": { 329 | "family": "impact", 330 | "overstrike": false, 331 | "size": 13, 332 | "slant": "roman", 333 | "underline": true, 334 | "weight": "bold" 335 | }, 336 | "start_index": "16.0" 337 | }, 338 | "17.0": { 339 | "bind": { 340 | "link": null 341 | }, 342 | "config": { 343 | "background": "SystemWindow", 344 | "foreground": "black", 345 | "justify": "left", 346 | "tabs": [] 347 | }, 348 | "end_index": "18.0", 349 | "font": { 350 | "family": "Segoe ui", 351 | "overstrike": false, 352 | "size": 9, 353 | "slant": "roman", 354 | "underline": false, 355 | "weight": "normal" 356 | }, 357 | "start_index": "17.0" 358 | }, 359 | "18.0": { 360 | "bind": { 361 | "link": null 362 | }, 363 | "config": { 364 | "background": "blue", 365 | "foreground": "yellow", 366 | "justify": "center", 367 | "tabs": [] 368 | }, 369 | "end_index": "19.0", 370 | "font": { 371 | "family": "impact", 372 | "overstrike": false, 373 | "size": 13, 374 | "slant": "roman", 375 | "underline": true, 376 | "weight": "bold" 377 | }, 378 | "start_index": "18.0" 379 | }, 380 | "19.0": { 381 | "bind": { 382 | "link": null 383 | }, 384 | "config": { 385 | "background": "SystemWindow", 386 | "foreground": "black", 387 | "justify": "left", 388 | "tabs": [] 389 | }, 390 | "end_index": "20.0", 391 | "font": { 392 | "family": "Segoe ui", 393 | "overstrike": false, 394 | "size": 9, 395 | "slant": "roman", 396 | "underline": false, 397 | "weight": "normal" 398 | }, 399 | "start_index": "19.0" 400 | }, 401 | "2.0": { 402 | "bind": { 403 | "link": null 404 | }, 405 | "config": { 406 | "background": "blue", 407 | "foreground": "yellow", 408 | "justify": "center", 409 | "tabs": [] 410 | }, 411 | "end_index": "3.0", 412 | "font": { 413 | "family": "impact", 414 | "overstrike": false, 415 | "size": 13, 416 | "slant": "roman", 417 | "underline": true, 418 | "weight": "normal" 419 | }, 420 | "start_index": "2.0" 421 | }, 422 | "20.0": { 423 | "bind": { 424 | "link": null 425 | }, 426 | "config": { 427 | "background": "red", 428 | "foreground": "black", 429 | "justify": "left", 430 | "tabs": [] 431 | }, 432 | "end_index": "20.4", 433 | "font": { 434 | "family": "Segoe ui", 435 | "overstrike": false, 436 | "size": 9, 437 | "slant": "roman", 438 | "underline": false, 439 | "weight": "normal" 440 | }, 441 | "start_index": "20.0" 442 | }, 443 | "20.10": { 444 | "bind": { 445 | "link": null 446 | }, 447 | "config": { 448 | "background": "yellow", 449 | "foreground": "black", 450 | "justify": "left", 451 | "tabs": [] 452 | }, 453 | "end_index": "20.17", 454 | "font": { 455 | "family": "Segoe ui", 456 | "overstrike": false, 457 | "size": 9, 458 | "slant": "roman", 459 | "underline": false, 460 | "weight": "normal" 461 | }, 462 | "start_index": "20.10" 463 | }, 464 | "20.17": { 465 | "bind": { 466 | "link": null 467 | }, 468 | "config": { 469 | "background": "red", 470 | "foreground": "black", 471 | "justify": "left", 472 | "tabs": [] 473 | }, 474 | "end_index": "20.27", 475 | "font": { 476 | "family": "Segoe ui", 477 | "overstrike": false, 478 | "size": 9, 479 | "slant": "roman", 480 | "underline": false, 481 | "weight": "normal" 482 | }, 483 | "start_index": "20.17" 484 | }, 485 | "20.27": { 486 | "bind": { 487 | "link": null 488 | }, 489 | "config": { 490 | "background": "SystemWindow", 491 | "foreground": "black", 492 | "justify": "left", 493 | "tabs": [] 494 | }, 495 | "end_index": "end", 496 | "font": { 497 | "family": "Segoe ui", 498 | "overstrike": false, 499 | "size": 9, 500 | "slant": "roman", 501 | "underline": false, 502 | "weight": "normal" 503 | }, 504 | "start_index": "20.27" 505 | }, 506 | "20.4": { 507 | "bind": { 508 | "link": null 509 | }, 510 | "config": { 511 | "background": "green", 512 | "foreground": "black", 513 | "justify": "left", 514 | "tabs": [] 515 | }, 516 | "end_index": "20.10", 517 | "font": { 518 | "family": "Segoe ui", 519 | "overstrike": false, 520 | "size": 9, 521 | "slant": "roman", 522 | "underline": false, 523 | "weight": "normal" 524 | }, 525 | "start_index": "20.4" 526 | }, 527 | "3.0": { 528 | "bind": { 529 | "link": null 530 | }, 531 | "config": { 532 | "background": "SystemWindow", 533 | "foreground": "black", 534 | "justify": "left", 535 | "tabs": [] 536 | }, 537 | "end_index": "4.0", 538 | "font": { 539 | "family": "Segoe ui", 540 | "overstrike": false, 541 | "size": 9, 542 | "slant": "roman", 543 | "underline": false, 544 | "weight": "normal" 545 | }, 546 | "start_index": "3.0" 547 | }, 548 | "4.0": { 549 | "bind": { 550 | "link": null 551 | }, 552 | "config": { 553 | "background": "blue", 554 | "foreground": "yellow", 555 | "justify": "center", 556 | "tabs": [] 557 | }, 558 | "end_index": "5.0", 559 | "font": { 560 | "family": "impact", 561 | "overstrike": false, 562 | "size": 13, 563 | "slant": "roman", 564 | "underline": true, 565 | "weight": "normal" 566 | }, 567 | "start_index": "4.0" 568 | }, 569 | "5.0": { 570 | "bind": { 571 | "link": null 572 | }, 573 | "config": { 574 | "background": "SystemWindow", 575 | "foreground": "black", 576 | "justify": "left", 577 | "tabs": [] 578 | }, 579 | "end_index": "6.0", 580 | "font": { 581 | "family": "Segoe ui", 582 | "overstrike": false, 583 | "size": 9, 584 | "slant": "roman", 585 | "underline": false, 586 | "weight": "normal" 587 | }, 588 | "start_index": "5.0" 589 | }, 590 | "6.0": { 591 | "bind": { 592 | "link": null 593 | }, 594 | "config": { 595 | "background": "blue", 596 | "foreground": "yellow", 597 | "justify": "center", 598 | "tabs": [] 599 | }, 600 | "end_index": "7.0", 601 | "font": { 602 | "family": "impact", 603 | "overstrike": false, 604 | "size": 13, 605 | "slant": "roman", 606 | "underline": true, 607 | "weight": "normal" 608 | }, 609 | "start_index": "6.0" 610 | }, 611 | "7.0": { 612 | "bind": { 613 | "link": null 614 | }, 615 | "config": { 616 | "background": "SystemWindow", 617 | "foreground": "black", 618 | "justify": "left", 619 | "tabs": [] 620 | }, 621 | "end_index": "8.0", 622 | "font": { 623 | "family": "Segoe ui", 624 | "overstrike": false, 625 | "size": 9, 626 | "slant": "roman", 627 | "underline": false, 628 | "weight": "normal" 629 | }, 630 | "start_index": "7.0" 631 | }, 632 | "8.0": { 633 | "bind": { 634 | "link": null 635 | }, 636 | "config": { 637 | "background": "blue", 638 | "foreground": "yellow", 639 | "justify": "center", 640 | "tabs": [] 641 | }, 642 | "end_index": "9.0", 643 | "font": { 644 | "family": "impact", 645 | "overstrike": false, 646 | "size": 13, 647 | "slant": "roman", 648 | "underline": true, 649 | "weight": "bold" 650 | }, 651 | "start_index": "8.0" 652 | }, 653 | "9.0": { 654 | "bind": { 655 | "link": null 656 | }, 657 | "config": { 658 | "background": "SystemWindow", 659 | "foreground": "black", 660 | "justify": "left", 661 | "tabs": [] 662 | }, 663 | "end_index": "10.0", 664 | "font": { 665 | "family": "Segoe ui", 666 | "overstrike": false, 667 | "size": 9, 668 | "slant": "roman", 669 | "underline": false, 670 | "weight": "normal" 671 | }, 672 | "start_index": "9.0" 673 | } 674 | } -------------------------------------------------------------------------------- /tests/HTMLScrolledText_styles.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "blue", 8 | "foreground": "yellow", 9 | "justify": "left", 10 | "tabs": [] 11 | }, 12 | "end_index": "1.8", 13 | "font": { 14 | "family": "impact", 15 | "overstrike": false, 16 | "size": 13, 17 | "slant": "roman", 18 | "underline": true, 19 | "weight": "normal" 20 | }, 21 | "start_index": "1.0" 22 | }, 23 | "1.16": { 24 | "bind": { 25 | "link": null 26 | }, 27 | "config": { 28 | "background": "blue", 29 | "foreground": "yellow", 30 | "justify": "left", 31 | "tabs": [] 32 | }, 33 | "end_index": "1.29", 34 | "font": { 35 | "family": "impact", 36 | "overstrike": false, 37 | "size": 13, 38 | "slant": "roman", 39 | "underline": false, 40 | "weight": "bold" 41 | }, 42 | "start_index": "1.16" 43 | }, 44 | "1.29": { 45 | "bind": { 46 | "link": null 47 | }, 48 | "config": { 49 | "background": "blue", 50 | "foreground": "yellow", 51 | "justify": "left", 52 | "tabs": [] 53 | }, 54 | "end_index": "1.37", 55 | "font": { 56 | "family": "impact", 57 | "overstrike": false, 58 | "size": 13, 59 | "slant": "italic", 60 | "underline": true, 61 | "weight": "normal" 62 | }, 63 | "start_index": "1.29" 64 | }, 65 | "1.37": { 66 | "bind": { 67 | "link": null 68 | }, 69 | "config": { 70 | "background": "blue", 71 | "foreground": "yellow", 72 | "justify": "left", 73 | "tabs": [] 74 | }, 75 | "end_index": "1.46", 76 | "font": { 77 | "family": "impact", 78 | "overstrike": false, 79 | "size": 13, 80 | "slant": "italic", 81 | "underline": true, 82 | "weight": "normal" 83 | }, 84 | "start_index": "1.37" 85 | }, 86 | "1.46": { 87 | "bind": { 88 | "link": null 89 | }, 90 | "config": { 91 | "background": "blue", 92 | "foreground": "yellow", 93 | "justify": "left", 94 | "tabs": [] 95 | }, 96 | "end_index": "1.54", 97 | "font": { 98 | "family": "impact", 99 | "overstrike": false, 100 | "size": 13, 101 | "slant": "roman", 102 | "underline": true, 103 | "weight": "normal" 104 | }, 105 | "start_index": "1.46" 106 | }, 107 | "1.54": { 108 | "bind": { 109 | "link": null 110 | }, 111 | "config": { 112 | "background": "blue", 113 | "foreground": "yellow", 114 | "justify": "left", 115 | "tabs": [] 116 | }, 117 | "end_index": "1.65", 118 | "font": { 119 | "family": "impact", 120 | "overstrike": false, 121 | "size": 13, 122 | "slant": "roman", 123 | "underline": true, 124 | "weight": "normal" 125 | }, 126 | "start_index": "1.54" 127 | }, 128 | "1.65": { 129 | "bind": { 130 | "link": null 131 | }, 132 | "config": { 133 | "background": "blue", 134 | "foreground": "yellow", 135 | "justify": "left", 136 | "tabs": [] 137 | }, 138 | "end_index": "1.76", 139 | "font": { 140 | "family": "impact", 141 | "overstrike": false, 142 | "size": 13, 143 | "slant": "roman", 144 | "underline": true, 145 | "weight": "normal" 146 | }, 147 | "start_index": "1.65" 148 | }, 149 | "1.76": { 150 | "bind": { 151 | "link": null 152 | }, 153 | "config": { 154 | "background": "SystemWindow", 155 | "foreground": "black", 156 | "justify": "left", 157 | "tabs": [] 158 | }, 159 | "end_index": "2.0", 160 | "font": { 161 | "family": "Segoe ui", 162 | "overstrike": false, 163 | "size": 9, 164 | "slant": "roman", 165 | "underline": false, 166 | "weight": "normal" 167 | }, 168 | "start_index": "1.76" 169 | }, 170 | "1.8": { 171 | "bind": { 172 | "link": null 173 | }, 174 | "config": { 175 | "background": "blue", 176 | "foreground": "yellow", 177 | "justify": "left", 178 | "tabs": [] 179 | }, 180 | "end_index": "1.16", 181 | "font": { 182 | "family": "impact", 183 | "overstrike": false, 184 | "size": 13, 185 | "slant": "roman", 186 | "underline": true, 187 | "weight": "bold" 188 | }, 189 | "start_index": "1.8" 190 | }, 191 | "10.0": { 192 | "bind": { 193 | "link": null 194 | }, 195 | "config": { 196 | "background": "blue", 197 | "foreground": "yellow", 198 | "justify": "center", 199 | "tabs": [] 200 | }, 201 | "end_index": "11.0", 202 | "font": { 203 | "family": "impact", 204 | "overstrike": false, 205 | "size": 13, 206 | "slant": "roman", 207 | "underline": true, 208 | "weight": "bold" 209 | }, 210 | "start_index": "10.0" 211 | }, 212 | "11.0": { 213 | "bind": { 214 | "link": null 215 | }, 216 | "config": { 217 | "background": "SystemWindow", 218 | "foreground": "black", 219 | "justify": "left", 220 | "tabs": [] 221 | }, 222 | "end_index": "12.0", 223 | "font": { 224 | "family": "Segoe ui", 225 | "overstrike": false, 226 | "size": 9, 227 | "slant": "roman", 228 | "underline": false, 229 | "weight": "normal" 230 | }, 231 | "start_index": "11.0" 232 | }, 233 | "12.0": { 234 | "bind": { 235 | "link": null 236 | }, 237 | "config": { 238 | "background": "blue", 239 | "foreground": "yellow", 240 | "justify": "center", 241 | "tabs": [] 242 | }, 243 | "end_index": "13.0", 244 | "font": { 245 | "family": "impact", 246 | "overstrike": false, 247 | "size": 13, 248 | "slant": "roman", 249 | "underline": true, 250 | "weight": "bold" 251 | }, 252 | "start_index": "12.0" 253 | }, 254 | "13.0": { 255 | "bind": { 256 | "link": null 257 | }, 258 | "config": { 259 | "background": "SystemWindow", 260 | "foreground": "black", 261 | "justify": "left", 262 | "tabs": [] 263 | }, 264 | "end_index": "14.0", 265 | "font": { 266 | "family": "Segoe ui", 267 | "overstrike": false, 268 | "size": 9, 269 | "slant": "roman", 270 | "underline": false, 271 | "weight": "normal" 272 | }, 273 | "start_index": "13.0" 274 | }, 275 | "14.0": { 276 | "bind": { 277 | "link": null 278 | }, 279 | "config": { 280 | "background": "blue", 281 | "foreground": "yellow", 282 | "justify": "center", 283 | "tabs": [] 284 | }, 285 | "end_index": "15.0", 286 | "font": { 287 | "family": "impact", 288 | "overstrike": false, 289 | "size": 13, 290 | "slant": "roman", 291 | "underline": true, 292 | "weight": "bold" 293 | }, 294 | "start_index": "14.0" 295 | }, 296 | "15.0": { 297 | "bind": { 298 | "link": null 299 | }, 300 | "config": { 301 | "background": "SystemWindow", 302 | "foreground": "black", 303 | "justify": "left", 304 | "tabs": [] 305 | }, 306 | "end_index": "16.0", 307 | "font": { 308 | "family": "Segoe ui", 309 | "overstrike": false, 310 | "size": 9, 311 | "slant": "roman", 312 | "underline": false, 313 | "weight": "normal" 314 | }, 315 | "start_index": "15.0" 316 | }, 317 | "16.0": { 318 | "bind": { 319 | "link": null 320 | }, 321 | "config": { 322 | "background": "blue", 323 | "foreground": "yellow", 324 | "justify": "center", 325 | "tabs": [] 326 | }, 327 | "end_index": "17.0", 328 | "font": { 329 | "family": "impact", 330 | "overstrike": false, 331 | "size": 13, 332 | "slant": "roman", 333 | "underline": true, 334 | "weight": "bold" 335 | }, 336 | "start_index": "16.0" 337 | }, 338 | "17.0": { 339 | "bind": { 340 | "link": null 341 | }, 342 | "config": { 343 | "background": "SystemWindow", 344 | "foreground": "black", 345 | "justify": "left", 346 | "tabs": [] 347 | }, 348 | "end_index": "18.0", 349 | "font": { 350 | "family": "Segoe ui", 351 | "overstrike": false, 352 | "size": 9, 353 | "slant": "roman", 354 | "underline": false, 355 | "weight": "normal" 356 | }, 357 | "start_index": "17.0" 358 | }, 359 | "18.0": { 360 | "bind": { 361 | "link": null 362 | }, 363 | "config": { 364 | "background": "blue", 365 | "foreground": "yellow", 366 | "justify": "center", 367 | "tabs": [] 368 | }, 369 | "end_index": "19.0", 370 | "font": { 371 | "family": "impact", 372 | "overstrike": false, 373 | "size": 13, 374 | "slant": "roman", 375 | "underline": true, 376 | "weight": "bold" 377 | }, 378 | "start_index": "18.0" 379 | }, 380 | "19.0": { 381 | "bind": { 382 | "link": null 383 | }, 384 | "config": { 385 | "background": "SystemWindow", 386 | "foreground": "black", 387 | "justify": "left", 388 | "tabs": [] 389 | }, 390 | "end_index": "20.0", 391 | "font": { 392 | "family": "Segoe ui", 393 | "overstrike": false, 394 | "size": 9, 395 | "slant": "roman", 396 | "underline": false, 397 | "weight": "normal" 398 | }, 399 | "start_index": "19.0" 400 | }, 401 | "2.0": { 402 | "bind": { 403 | "link": null 404 | }, 405 | "config": { 406 | "background": "blue", 407 | "foreground": "yellow", 408 | "justify": "center", 409 | "tabs": [] 410 | }, 411 | "end_index": "3.0", 412 | "font": { 413 | "family": "impact", 414 | "overstrike": false, 415 | "size": 13, 416 | "slant": "roman", 417 | "underline": true, 418 | "weight": "normal" 419 | }, 420 | "start_index": "2.0" 421 | }, 422 | "20.0": { 423 | "bind": { 424 | "link": null 425 | }, 426 | "config": { 427 | "background": "red", 428 | "foreground": "black", 429 | "justify": "left", 430 | "tabs": [] 431 | }, 432 | "end_index": "20.4", 433 | "font": { 434 | "family": "Segoe ui", 435 | "overstrike": false, 436 | "size": 9, 437 | "slant": "roman", 438 | "underline": false, 439 | "weight": "normal" 440 | }, 441 | "start_index": "20.0" 442 | }, 443 | "20.10": { 444 | "bind": { 445 | "link": null 446 | }, 447 | "config": { 448 | "background": "yellow", 449 | "foreground": "black", 450 | "justify": "left", 451 | "tabs": [] 452 | }, 453 | "end_index": "20.17", 454 | "font": { 455 | "family": "Segoe ui", 456 | "overstrike": false, 457 | "size": 9, 458 | "slant": "roman", 459 | "underline": false, 460 | "weight": "normal" 461 | }, 462 | "start_index": "20.10" 463 | }, 464 | "20.17": { 465 | "bind": { 466 | "link": null 467 | }, 468 | "config": { 469 | "background": "red", 470 | "foreground": "black", 471 | "justify": "left", 472 | "tabs": [] 473 | }, 474 | "end_index": "20.27", 475 | "font": { 476 | "family": "Segoe ui", 477 | "overstrike": false, 478 | "size": 9, 479 | "slant": "roman", 480 | "underline": false, 481 | "weight": "normal" 482 | }, 483 | "start_index": "20.17" 484 | }, 485 | "20.27": { 486 | "bind": { 487 | "link": null 488 | }, 489 | "config": { 490 | "background": "SystemWindow", 491 | "foreground": "black", 492 | "justify": "left", 493 | "tabs": [] 494 | }, 495 | "end_index": "end", 496 | "font": { 497 | "family": "Segoe ui", 498 | "overstrike": false, 499 | "size": 9, 500 | "slant": "roman", 501 | "underline": false, 502 | "weight": "normal" 503 | }, 504 | "start_index": "20.27" 505 | }, 506 | "20.4": { 507 | "bind": { 508 | "link": null 509 | }, 510 | "config": { 511 | "background": "green", 512 | "foreground": "black", 513 | "justify": "left", 514 | "tabs": [] 515 | }, 516 | "end_index": "20.10", 517 | "font": { 518 | "family": "Segoe ui", 519 | "overstrike": false, 520 | "size": 9, 521 | "slant": "roman", 522 | "underline": false, 523 | "weight": "normal" 524 | }, 525 | "start_index": "20.4" 526 | }, 527 | "3.0": { 528 | "bind": { 529 | "link": null 530 | }, 531 | "config": { 532 | "background": "SystemWindow", 533 | "foreground": "black", 534 | "justify": "left", 535 | "tabs": [] 536 | }, 537 | "end_index": "4.0", 538 | "font": { 539 | "family": "Segoe ui", 540 | "overstrike": false, 541 | "size": 9, 542 | "slant": "roman", 543 | "underline": false, 544 | "weight": "normal" 545 | }, 546 | "start_index": "3.0" 547 | }, 548 | "4.0": { 549 | "bind": { 550 | "link": null 551 | }, 552 | "config": { 553 | "background": "blue", 554 | "foreground": "yellow", 555 | "justify": "center", 556 | "tabs": [] 557 | }, 558 | "end_index": "5.0", 559 | "font": { 560 | "family": "impact", 561 | "overstrike": false, 562 | "size": 13, 563 | "slant": "roman", 564 | "underline": true, 565 | "weight": "normal" 566 | }, 567 | "start_index": "4.0" 568 | }, 569 | "5.0": { 570 | "bind": { 571 | "link": null 572 | }, 573 | "config": { 574 | "background": "SystemWindow", 575 | "foreground": "black", 576 | "justify": "left", 577 | "tabs": [] 578 | }, 579 | "end_index": "6.0", 580 | "font": { 581 | "family": "Segoe ui", 582 | "overstrike": false, 583 | "size": 9, 584 | "slant": "roman", 585 | "underline": false, 586 | "weight": "normal" 587 | }, 588 | "start_index": "5.0" 589 | }, 590 | "6.0": { 591 | "bind": { 592 | "link": null 593 | }, 594 | "config": { 595 | "background": "blue", 596 | "foreground": "yellow", 597 | "justify": "center", 598 | "tabs": [] 599 | }, 600 | "end_index": "7.0", 601 | "font": { 602 | "family": "impact", 603 | "overstrike": false, 604 | "size": 13, 605 | "slant": "roman", 606 | "underline": true, 607 | "weight": "normal" 608 | }, 609 | "start_index": "6.0" 610 | }, 611 | "7.0": { 612 | "bind": { 613 | "link": null 614 | }, 615 | "config": { 616 | "background": "SystemWindow", 617 | "foreground": "black", 618 | "justify": "left", 619 | "tabs": [] 620 | }, 621 | "end_index": "8.0", 622 | "font": { 623 | "family": "Segoe ui", 624 | "overstrike": false, 625 | "size": 9, 626 | "slant": "roman", 627 | "underline": false, 628 | "weight": "normal" 629 | }, 630 | "start_index": "7.0" 631 | }, 632 | "8.0": { 633 | "bind": { 634 | "link": null 635 | }, 636 | "config": { 637 | "background": "blue", 638 | "foreground": "yellow", 639 | "justify": "center", 640 | "tabs": [] 641 | }, 642 | "end_index": "9.0", 643 | "font": { 644 | "family": "impact", 645 | "overstrike": false, 646 | "size": 13, 647 | "slant": "roman", 648 | "underline": true, 649 | "weight": "bold" 650 | }, 651 | "start_index": "8.0" 652 | }, 653 | "9.0": { 654 | "bind": { 655 | "link": null 656 | }, 657 | "config": { 658 | "background": "SystemWindow", 659 | "foreground": "black", 660 | "justify": "left", 661 | "tabs": [] 662 | }, 663 | "end_index": "10.0", 664 | "font": { 665 | "family": "Segoe ui", 666 | "overstrike": false, 667 | "size": 9, 668 | "slant": "roman", 669 | "underline": false, 670 | "weight": "normal" 671 | }, 672 | "start_index": "9.0" 673 | } 674 | } -------------------------------------------------------------------------------- /tests/HTMLLabel_styles.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "blue", 8 | "foreground": "yellow", 9 | "justify": "left", 10 | "tabs": [] 11 | }, 12 | "end_index": "1.8", 13 | "font": { 14 | "family": "impact", 15 | "overstrike": false, 16 | "size": 13, 17 | "slant": "roman", 18 | "underline": true, 19 | "weight": "normal" 20 | }, 21 | "start_index": "1.0" 22 | }, 23 | "1.16": { 24 | "bind": { 25 | "link": null 26 | }, 27 | "config": { 28 | "background": "blue", 29 | "foreground": "yellow", 30 | "justify": "left", 31 | "tabs": [] 32 | }, 33 | "end_index": "1.29", 34 | "font": { 35 | "family": "impact", 36 | "overstrike": false, 37 | "size": 13, 38 | "slant": "roman", 39 | "underline": false, 40 | "weight": "bold" 41 | }, 42 | "start_index": "1.16" 43 | }, 44 | "1.29": { 45 | "bind": { 46 | "link": null 47 | }, 48 | "config": { 49 | "background": "blue", 50 | "foreground": "yellow", 51 | "justify": "left", 52 | "tabs": [] 53 | }, 54 | "end_index": "1.37", 55 | "font": { 56 | "family": "impact", 57 | "overstrike": false, 58 | "size": 13, 59 | "slant": "italic", 60 | "underline": true, 61 | "weight": "normal" 62 | }, 63 | "start_index": "1.29" 64 | }, 65 | "1.37": { 66 | "bind": { 67 | "link": null 68 | }, 69 | "config": { 70 | "background": "blue", 71 | "foreground": "yellow", 72 | "justify": "left", 73 | "tabs": [] 74 | }, 75 | "end_index": "1.46", 76 | "font": { 77 | "family": "impact", 78 | "overstrike": false, 79 | "size": 13, 80 | "slant": "italic", 81 | "underline": true, 82 | "weight": "normal" 83 | }, 84 | "start_index": "1.37" 85 | }, 86 | "1.46": { 87 | "bind": { 88 | "link": null 89 | }, 90 | "config": { 91 | "background": "blue", 92 | "foreground": "yellow", 93 | "justify": "left", 94 | "tabs": [] 95 | }, 96 | "end_index": "1.54", 97 | "font": { 98 | "family": "impact", 99 | "overstrike": false, 100 | "size": 13, 101 | "slant": "roman", 102 | "underline": true, 103 | "weight": "normal" 104 | }, 105 | "start_index": "1.46" 106 | }, 107 | "1.54": { 108 | "bind": { 109 | "link": null 110 | }, 111 | "config": { 112 | "background": "blue", 113 | "foreground": "yellow", 114 | "justify": "left", 115 | "tabs": [] 116 | }, 117 | "end_index": "1.65", 118 | "font": { 119 | "family": "impact", 120 | "overstrike": false, 121 | "size": 13, 122 | "slant": "roman", 123 | "underline": true, 124 | "weight": "normal" 125 | }, 126 | "start_index": "1.54" 127 | }, 128 | "1.65": { 129 | "bind": { 130 | "link": null 131 | }, 132 | "config": { 133 | "background": "blue", 134 | "foreground": "yellow", 135 | "justify": "left", 136 | "tabs": [] 137 | }, 138 | "end_index": "1.76", 139 | "font": { 140 | "family": "impact", 141 | "overstrike": false, 142 | "size": 13, 143 | "slant": "roman", 144 | "underline": true, 145 | "weight": "normal" 146 | }, 147 | "start_index": "1.65" 148 | }, 149 | "1.76": { 150 | "bind": { 151 | "link": null 152 | }, 153 | "config": { 154 | "background": "SystemButtonFace", 155 | "foreground": "black", 156 | "justify": "left", 157 | "tabs": [] 158 | }, 159 | "end_index": "2.0", 160 | "font": { 161 | "family": "Segoe ui", 162 | "overstrike": false, 163 | "size": 9, 164 | "slant": "roman", 165 | "underline": false, 166 | "weight": "normal" 167 | }, 168 | "start_index": "1.76" 169 | }, 170 | "1.8": { 171 | "bind": { 172 | "link": null 173 | }, 174 | "config": { 175 | "background": "blue", 176 | "foreground": "yellow", 177 | "justify": "left", 178 | "tabs": [] 179 | }, 180 | "end_index": "1.16", 181 | "font": { 182 | "family": "impact", 183 | "overstrike": false, 184 | "size": 13, 185 | "slant": "roman", 186 | "underline": true, 187 | "weight": "bold" 188 | }, 189 | "start_index": "1.8" 190 | }, 191 | "10.0": { 192 | "bind": { 193 | "link": null 194 | }, 195 | "config": { 196 | "background": "blue", 197 | "foreground": "yellow", 198 | "justify": "center", 199 | "tabs": [] 200 | }, 201 | "end_index": "11.0", 202 | "font": { 203 | "family": "impact", 204 | "overstrike": false, 205 | "size": 13, 206 | "slant": "roman", 207 | "underline": true, 208 | "weight": "bold" 209 | }, 210 | "start_index": "10.0" 211 | }, 212 | "11.0": { 213 | "bind": { 214 | "link": null 215 | }, 216 | "config": { 217 | "background": "SystemButtonFace", 218 | "foreground": "black", 219 | "justify": "left", 220 | "tabs": [] 221 | }, 222 | "end_index": "12.0", 223 | "font": { 224 | "family": "Segoe ui", 225 | "overstrike": false, 226 | "size": 9, 227 | "slant": "roman", 228 | "underline": false, 229 | "weight": "normal" 230 | }, 231 | "start_index": "11.0" 232 | }, 233 | "12.0": { 234 | "bind": { 235 | "link": null 236 | }, 237 | "config": { 238 | "background": "blue", 239 | "foreground": "yellow", 240 | "justify": "center", 241 | "tabs": [] 242 | }, 243 | "end_index": "13.0", 244 | "font": { 245 | "family": "impact", 246 | "overstrike": false, 247 | "size": 13, 248 | "slant": "roman", 249 | "underline": true, 250 | "weight": "bold" 251 | }, 252 | "start_index": "12.0" 253 | }, 254 | "13.0": { 255 | "bind": { 256 | "link": null 257 | }, 258 | "config": { 259 | "background": "SystemButtonFace", 260 | "foreground": "black", 261 | "justify": "left", 262 | "tabs": [] 263 | }, 264 | "end_index": "14.0", 265 | "font": { 266 | "family": "Segoe ui", 267 | "overstrike": false, 268 | "size": 9, 269 | "slant": "roman", 270 | "underline": false, 271 | "weight": "normal" 272 | }, 273 | "start_index": "13.0" 274 | }, 275 | "14.0": { 276 | "bind": { 277 | "link": null 278 | }, 279 | "config": { 280 | "background": "blue", 281 | "foreground": "yellow", 282 | "justify": "center", 283 | "tabs": [] 284 | }, 285 | "end_index": "15.0", 286 | "font": { 287 | "family": "impact", 288 | "overstrike": false, 289 | "size": 13, 290 | "slant": "roman", 291 | "underline": true, 292 | "weight": "bold" 293 | }, 294 | "start_index": "14.0" 295 | }, 296 | "15.0": { 297 | "bind": { 298 | "link": null 299 | }, 300 | "config": { 301 | "background": "SystemButtonFace", 302 | "foreground": "black", 303 | "justify": "left", 304 | "tabs": [] 305 | }, 306 | "end_index": "16.0", 307 | "font": { 308 | "family": "Segoe ui", 309 | "overstrike": false, 310 | "size": 9, 311 | "slant": "roman", 312 | "underline": false, 313 | "weight": "normal" 314 | }, 315 | "start_index": "15.0" 316 | }, 317 | "16.0": { 318 | "bind": { 319 | "link": null 320 | }, 321 | "config": { 322 | "background": "blue", 323 | "foreground": "yellow", 324 | "justify": "center", 325 | "tabs": [] 326 | }, 327 | "end_index": "17.0", 328 | "font": { 329 | "family": "impact", 330 | "overstrike": false, 331 | "size": 13, 332 | "slant": "roman", 333 | "underline": true, 334 | "weight": "bold" 335 | }, 336 | "start_index": "16.0" 337 | }, 338 | "17.0": { 339 | "bind": { 340 | "link": null 341 | }, 342 | "config": { 343 | "background": "SystemButtonFace", 344 | "foreground": "black", 345 | "justify": "left", 346 | "tabs": [] 347 | }, 348 | "end_index": "18.0", 349 | "font": { 350 | "family": "Segoe ui", 351 | "overstrike": false, 352 | "size": 9, 353 | "slant": "roman", 354 | "underline": false, 355 | "weight": "normal" 356 | }, 357 | "start_index": "17.0" 358 | }, 359 | "18.0": { 360 | "bind": { 361 | "link": null 362 | }, 363 | "config": { 364 | "background": "blue", 365 | "foreground": "yellow", 366 | "justify": "center", 367 | "tabs": [] 368 | }, 369 | "end_index": "19.0", 370 | "font": { 371 | "family": "impact", 372 | "overstrike": false, 373 | "size": 13, 374 | "slant": "roman", 375 | "underline": true, 376 | "weight": "bold" 377 | }, 378 | "start_index": "18.0" 379 | }, 380 | "19.0": { 381 | "bind": { 382 | "link": null 383 | }, 384 | "config": { 385 | "background": "SystemButtonFace", 386 | "foreground": "black", 387 | "justify": "left", 388 | "tabs": [] 389 | }, 390 | "end_index": "20.0", 391 | "font": { 392 | "family": "Segoe ui", 393 | "overstrike": false, 394 | "size": 9, 395 | "slant": "roman", 396 | "underline": false, 397 | "weight": "normal" 398 | }, 399 | "start_index": "19.0" 400 | }, 401 | "2.0": { 402 | "bind": { 403 | "link": null 404 | }, 405 | "config": { 406 | "background": "blue", 407 | "foreground": "yellow", 408 | "justify": "center", 409 | "tabs": [] 410 | }, 411 | "end_index": "3.0", 412 | "font": { 413 | "family": "impact", 414 | "overstrike": false, 415 | "size": 13, 416 | "slant": "roman", 417 | "underline": true, 418 | "weight": "normal" 419 | }, 420 | "start_index": "2.0" 421 | }, 422 | "20.0": { 423 | "bind": { 424 | "link": null 425 | }, 426 | "config": { 427 | "background": "red", 428 | "foreground": "black", 429 | "justify": "left", 430 | "tabs": [] 431 | }, 432 | "end_index": "20.4", 433 | "font": { 434 | "family": "Segoe ui", 435 | "overstrike": false, 436 | "size": 9, 437 | "slant": "roman", 438 | "underline": false, 439 | "weight": "normal" 440 | }, 441 | "start_index": "20.0" 442 | }, 443 | "20.10": { 444 | "bind": { 445 | "link": null 446 | }, 447 | "config": { 448 | "background": "yellow", 449 | "foreground": "black", 450 | "justify": "left", 451 | "tabs": [] 452 | }, 453 | "end_index": "20.17", 454 | "font": { 455 | "family": "Segoe ui", 456 | "overstrike": false, 457 | "size": 9, 458 | "slant": "roman", 459 | "underline": false, 460 | "weight": "normal" 461 | }, 462 | "start_index": "20.10" 463 | }, 464 | "20.17": { 465 | "bind": { 466 | "link": null 467 | }, 468 | "config": { 469 | "background": "red", 470 | "foreground": "black", 471 | "justify": "left", 472 | "tabs": [] 473 | }, 474 | "end_index": "20.27", 475 | "font": { 476 | "family": "Segoe ui", 477 | "overstrike": false, 478 | "size": 9, 479 | "slant": "roman", 480 | "underline": false, 481 | "weight": "normal" 482 | }, 483 | "start_index": "20.17" 484 | }, 485 | "20.27": { 486 | "bind": { 487 | "link": null 488 | }, 489 | "config": { 490 | "background": "SystemButtonFace", 491 | "foreground": "black", 492 | "justify": "left", 493 | "tabs": [] 494 | }, 495 | "end_index": "end", 496 | "font": { 497 | "family": "Segoe ui", 498 | "overstrike": false, 499 | "size": 9, 500 | "slant": "roman", 501 | "underline": false, 502 | "weight": "normal" 503 | }, 504 | "start_index": "20.27" 505 | }, 506 | "20.4": { 507 | "bind": { 508 | "link": null 509 | }, 510 | "config": { 511 | "background": "green", 512 | "foreground": "black", 513 | "justify": "left", 514 | "tabs": [] 515 | }, 516 | "end_index": "20.10", 517 | "font": { 518 | "family": "Segoe ui", 519 | "overstrike": false, 520 | "size": 9, 521 | "slant": "roman", 522 | "underline": false, 523 | "weight": "normal" 524 | }, 525 | "start_index": "20.4" 526 | }, 527 | "3.0": { 528 | "bind": { 529 | "link": null 530 | }, 531 | "config": { 532 | "background": "SystemButtonFace", 533 | "foreground": "black", 534 | "justify": "left", 535 | "tabs": [] 536 | }, 537 | "end_index": "4.0", 538 | "font": { 539 | "family": "Segoe ui", 540 | "overstrike": false, 541 | "size": 9, 542 | "slant": "roman", 543 | "underline": false, 544 | "weight": "normal" 545 | }, 546 | "start_index": "3.0" 547 | }, 548 | "4.0": { 549 | "bind": { 550 | "link": null 551 | }, 552 | "config": { 553 | "background": "blue", 554 | "foreground": "yellow", 555 | "justify": "center", 556 | "tabs": [] 557 | }, 558 | "end_index": "5.0", 559 | "font": { 560 | "family": "impact", 561 | "overstrike": false, 562 | "size": 13, 563 | "slant": "roman", 564 | "underline": true, 565 | "weight": "normal" 566 | }, 567 | "start_index": "4.0" 568 | }, 569 | "5.0": { 570 | "bind": { 571 | "link": null 572 | }, 573 | "config": { 574 | "background": "SystemButtonFace", 575 | "foreground": "black", 576 | "justify": "left", 577 | "tabs": [] 578 | }, 579 | "end_index": "6.0", 580 | "font": { 581 | "family": "Segoe ui", 582 | "overstrike": false, 583 | "size": 9, 584 | "slant": "roman", 585 | "underline": false, 586 | "weight": "normal" 587 | }, 588 | "start_index": "5.0" 589 | }, 590 | "6.0": { 591 | "bind": { 592 | "link": null 593 | }, 594 | "config": { 595 | "background": "blue", 596 | "foreground": "yellow", 597 | "justify": "center", 598 | "tabs": [] 599 | }, 600 | "end_index": "7.0", 601 | "font": { 602 | "family": "impact", 603 | "overstrike": false, 604 | "size": 13, 605 | "slant": "roman", 606 | "underline": true, 607 | "weight": "normal" 608 | }, 609 | "start_index": "6.0" 610 | }, 611 | "7.0": { 612 | "bind": { 613 | "link": null 614 | }, 615 | "config": { 616 | "background": "SystemButtonFace", 617 | "foreground": "black", 618 | "justify": "left", 619 | "tabs": [] 620 | }, 621 | "end_index": "8.0", 622 | "font": { 623 | "family": "Segoe ui", 624 | "overstrike": false, 625 | "size": 9, 626 | "slant": "roman", 627 | "underline": false, 628 | "weight": "normal" 629 | }, 630 | "start_index": "7.0" 631 | }, 632 | "8.0": { 633 | "bind": { 634 | "link": null 635 | }, 636 | "config": { 637 | "background": "blue", 638 | "foreground": "yellow", 639 | "justify": "center", 640 | "tabs": [] 641 | }, 642 | "end_index": "9.0", 643 | "font": { 644 | "family": "impact", 645 | "overstrike": false, 646 | "size": 13, 647 | "slant": "roman", 648 | "underline": true, 649 | "weight": "bold" 650 | }, 651 | "start_index": "8.0" 652 | }, 653 | "9.0": { 654 | "bind": { 655 | "link": null 656 | }, 657 | "config": { 658 | "background": "SystemButtonFace", 659 | "foreground": "black", 660 | "justify": "left", 661 | "tabs": [] 662 | }, 663 | "end_index": "10.0", 664 | "font": { 665 | "family": "Segoe ui", 666 | "overstrike": false, 667 | "size": 9, 668 | "slant": "roman", 669 | "underline": false, 670 | "weight": "normal" 671 | }, 672 | "start_index": "9.0" 673 | } 674 | } -------------------------------------------------------------------------------- /tk_html_widgets/html_parser.py: -------------------------------------------------------------------------------- 1 | """ 2 | HTML parser 3 | """ 4 | import os 5 | import webbrowser 6 | import tkinter as tk 7 | from tkinter import font 8 | from copy import deepcopy 9 | from PIL import Image, ImageTk 10 | from html.parser import HTMLParser 11 | from collections import OrderedDict 12 | 13 | 14 | #__________________________________________________________________________________________________ 15 | class Defs(): 16 | DEFAULT_TEXT_FONT_FAMILY = ("Segoe ui", "Calibri", "Helvetica", "TkTextFont") 17 | FONT_SIZE = 9 18 | PREFORMATTED_FONT_FAMILY = ("Courier", "DejaVu Sans Mono", "TkFixedFont") 19 | HEADINGS_FONT_SIZE = { 20 | 'h1':21, 21 | 'h2':16, 22 | 'h3':12, 23 | 'h4':11, 24 | 'h5':8, 25 | 'h6':7, 26 | } 27 | 28 | 29 | class HTML: 30 | #---------------------------------------------------------------------------------------------- 31 | """ 32 | List of supported HTML tags and attrs 33 | """ 34 | class Tag(): 35 | BR = 'br' 36 | UL = 'ul' 37 | OL = 'ol' 38 | LI = 'li' 39 | IMG = 'img' 40 | A = 'a' 41 | B = 'b' 42 | STRONG = 'strong' 43 | I = 'i' 44 | EM = 'em' 45 | U = 'u' 46 | MARK = 'mark' 47 | SPAN = 'span' 48 | DIV = 'div' 49 | P = 'p' 50 | PRE = 'pre' 51 | CODE = 'code' 52 | H1 = 'h1' 53 | H2 = 'h2' 54 | H3 = 'h3' 55 | H4 = 'h4' 56 | H5 = 'h5' 57 | H6 = 'h6' 58 | 59 | class Attrs(): 60 | STYLE = 'style' 61 | HREF ='href' 62 | SRC = 'src' 63 | WIDTH = 'width' 64 | HEIGHT = 'height' 65 | TYPE = 'type' 66 | 67 | class TypeOrderedList(): 68 | _1 = '1' 69 | a = 'a' 70 | A = 'A' 71 | 72 | class Style(): 73 | COLOR = 'color' 74 | BACKGROUD_COLOR = 'background-color' 75 | FONT_FAMILY = 'font-family' 76 | FONT_SIZE = 'font-size' 77 | TEXT_ALIGN = 'text-align' 78 | TEXT_DECORATION = 'text-decoration' 79 | 80 | class StyleTextDecoration(): 81 | UNDERLINE = 'underline' 82 | LINE_THROUGH = 'line-through' 83 | 84 | HEADING_TAGS = ( 85 | Tag.H1, 86 | Tag.H2, 87 | Tag.H3, 88 | Tag.H4, 89 | Tag.H5, 90 | Tag.H6, 91 | ) 92 | 93 | TEXT_ALIGN_TAGS = HEADING_TAGS + ( 94 | Tag.UL, 95 | Tag.OL, 96 | Tag.LI, 97 | Tag.DIV, 98 | Tag.P, 99 | Tag.PRE, 100 | Tag.CODE, 101 | ) 102 | 103 | NEW_LINE_TAGS = HEADING_TAGS + ( 104 | Tag.UL, 105 | Tag.OL, 106 | Tag.DIV, 107 | Tag.P, 108 | Tag.PRE, 109 | Tag.CODE, 110 | ) 111 | 112 | STYLE_TAGS = TEXT_ALIGN_TAGS + ( 113 | Tag.A, 114 | Tag.B, 115 | Tag.STRONG, 116 | Tag.I, 117 | Tag.EM, 118 | Tag.U, 119 | Tag.MARK, 120 | Tag.SPAN, 121 | ) 122 | 123 | 124 | 125 | #-------------------------------------------------------------------------------------------------- 126 | # Text widget defs 127 | 128 | class WCfg(): 129 | KEY = "config" 130 | BACKGROUND = "background" 131 | FOREGROUND = "foreground" 132 | JUSTIFY = "justify" 133 | TABS = "tabs" 134 | 135 | class Fnt(): 136 | KEY = "font" 137 | FAMILY = "family" 138 | SIZE = "size" 139 | WEIGHT = "weight" 140 | SLANT = "slant" 141 | UNDERLINE = "underline" 142 | OVERSTRIKE = "overstrike" 143 | 144 | class Bind(): 145 | KEY = "bind" 146 | LINK = "link" 147 | IMAGE = "image" 148 | 149 | class WTag(): 150 | START_INDEX = "start_index" 151 | END_INDEX = "end_index" 152 | 153 | DEFAULT_STACK = { 154 | WCfg.KEY:{ 155 | WCfg.BACKGROUND:[], 156 | WCfg.FOREGROUND:[("__DEFAULT__", "black")], 157 | WCfg.JUSTIFY:[("__DEFAULT__", 'left')], 158 | WCfg.TABS:[("__DEFAULT__", ())], 159 | }, 160 | Fnt.KEY:{ 161 | Fnt.FAMILY:[], 162 | Fnt.SIZE:[("__DEFAULT__", Defs.FONT_SIZE)], 163 | Fnt.WEIGHT:[("__DEFAULT__", 'normal')], 164 | Fnt.SLANT:[("__DEFAULT__", 'roman')], 165 | Fnt.UNDERLINE:[("__DEFAULT__", False)], 166 | Fnt.OVERSTRIKE:[("__DEFAULT__", False)], 167 | }, 168 | Bind.KEY:{ 169 | Bind.LINK:[("__DEFAULT__", None)], 170 | }, 171 | } 172 | 173 | #__________________________________________________________________________________________________ 174 | # functions 175 | def get_existing_font(font_families): 176 | #------------------------------------------------------------------------------------------ 177 | try: 178 | return next(filter(lambda f: f.lower() in (f.lower() for f in font.families()), font_families)) 179 | except: 180 | return "TkTextFont" 181 | 182 | 183 | #__________________________________________________________________________________________________ 184 | # classes 185 | class HLinkSlot(): 186 | #---------------------------------------------------------------------------------------------- 187 | 188 | def __init__(self, w, tag_name, url): 189 | #------------------------------------------------------------------------------------------ 190 | self._w = w 191 | self.tag_name = tag_name 192 | self.URL = url 193 | 194 | def call(self, event): 195 | #------------------------------------------------------------------------------------------ 196 | webbrowser.open(self.URL) 197 | self._w.tag_config(self.tag_name, foreground="purple") 198 | 199 | def enter(self, event): 200 | #------------------------------------------------------------------------------------------ 201 | self._w.config(cursor="hand2") 202 | 203 | def leave(self, event): 204 | #------------------------------------------------------------------------------------------ 205 | self._w.config(cursor="") 206 | 207 | 208 | 209 | 210 | class ListTag(): 211 | #---------------------------------------------------------------------------------------------- 212 | def __init__(self, ordered:bool, list_type=None): 213 | #------------------------------------------------------------------------------------------ 214 | self.ordered = ordered 215 | self.type = list_type 216 | self.index = 0 217 | 218 | def add(self): 219 | #------------------------------------------------------------------------------------------ 220 | if self.ordered: 221 | self.index += 1 222 | 223 | def line_index(self): 224 | #------------------------------------------------------------------------------------------ 225 | if self.ordered: 226 | if self.type == HTML.TypeOrderedList._1: 227 | return str(self.index) 228 | elif self.type == HTML.TypeOrderedList.a: 229 | return self._index_to_str(self.index).lower() 230 | elif self.type == HTML.TypeOrderedList.A: 231 | return self._index_to_str(self.index).upper() 232 | else: 233 | return chr(8226) 234 | 235 | def _index_to_str(self, index): 236 | #------------------------------------------------------------------------------------------ 237 | prefix = "" 238 | if index > 26: 239 | prefix = self._index_to_str(index // 26) 240 | index = index % 26 241 | 242 | return prefix + chr(0x60 + index) 243 | 244 | 245 | 246 | class HTMLTextParser(HTMLParser): 247 | #---------------------------------------------------------------------------------------------- 248 | 249 | def __init__(self): 250 | #------------------------------------------------------------------------------------------ 251 | super().__init__() 252 | # set list tabs 253 | self.cached_images = {} 254 | 255 | self.DEFAULT_TEXT_FONT_FAMILY = get_existing_font(Defs.DEFAULT_TEXT_FONT_FAMILY) 256 | self.PREFORMATTED_FONT_FAMILY = get_existing_font(Defs.PREFORMATTED_FONT_FAMILY) 257 | 258 | 259 | def _parse_attrs(self, attrs): 260 | #------------------------------------------------------------------------------------------ 261 | attrs_dict = { 262 | HTML.Attrs.STYLE:{}, 263 | HTML.Attrs.HREF:None, 264 | HTML.Attrs.SRC:None, 265 | HTML.Attrs.WIDTH:None, 266 | HTML.Attrs.HEIGHT:None, 267 | HTML.Attrs.TYPE:None, 268 | } 269 | for k, v in attrs: 270 | k = k.lower() 271 | if k == HTML.Attrs.STYLE: 272 | for p in v.split(";"): 273 | try: 274 | p_key = p.split(":")[0].strip().lower() 275 | p_value = p.split(":")[1].strip().lower() 276 | attrs_dict[HTML.Attrs.STYLE][p_key] = p_value 277 | except: 278 | pass 279 | elif k in (HTML.Attrs.HREF, HTML.Attrs.SRC, HTML.Attrs.WIDTH, HTML.Attrs.HEIGHT, HTML.Attrs.TYPE): 280 | attrs_dict[k] = v 281 | return attrs_dict 282 | 283 | 284 | def _w_tags_add(self): 285 | #------------------------------------------------------------------------------------------ 286 | tag = { 287 | WCfg.KEY:{}, 288 | Fnt.KEY:{}, 289 | Bind.KEY:{} 290 | } 291 | 292 | for k1 in (WCfg.KEY, Fnt.KEY, Bind.KEY): 293 | for k2 in DEFAULT_STACK[k1]: 294 | tag[k1][k2] = self.stack[k1][k2][-1][1] 295 | 296 | self._w_tags[self._w.index("end-1c")] = tag 297 | 298 | 299 | def _stack_get_main_key(self, key): 300 | #------------------------------------------------------------------------------------------ 301 | if key in WCfg.__dict__.values(): 302 | main_key = WCfg.KEY 303 | elif key in Fnt.__dict__.values(): 304 | main_key = Fnt.KEY 305 | elif key in Bind.__dict__.values(): 306 | main_key = Bind.KEY 307 | else: 308 | raise ValueError("key %s doesn't exists" % key) 309 | 310 | return main_key 311 | 312 | 313 | def _stack_add(self, tag, key, value=None): 314 | #------------------------------------------------------------------------------------------ 315 | main_key = self._stack_get_main_key(key) 316 | 317 | if value is None: 318 | # if value is none, add the previous value 319 | value = self.stack[main_key][key][-1][1] 320 | 321 | self.stack[main_key][key].append((tag, value)) 322 | 323 | 324 | def _stack_index(self, tag, key): 325 | #------------------------------------------------------------------------------------------ 326 | main_key = self._stack_get_main_key(key) 327 | index = None 328 | for i, v in enumerate(self.stack[main_key][key]): 329 | if v[0] == tag: 330 | index = i 331 | 332 | return index 333 | 334 | 335 | def _stack_pop(self, tag, key): 336 | #------------------------------------------------------------------------------------------ 337 | main_key = self._stack_get_main_key(key) 338 | 339 | index = None 340 | if len(self.stack[main_key][key]) > 1: 341 | index = self._stack_index(tag, key) 342 | 343 | if index is not None: 344 | return self.stack[main_key][key].pop(index)[1] 345 | 346 | 347 | def _parse_styles(self, tag, attrs): 348 | #------------------------------------------------------------------------------------------ 349 | #-------------------------------------------------------------------------------- [ COLOR ] 350 | if HTML.Style.COLOR in attrs[HTML.Attrs.STYLE].keys(): 351 | self._stack_add(tag, WCfg.FOREGROUND, attrs[HTML.Attrs.STYLE][HTML.Style.COLOR]) 352 | elif tag == HTML.Tag.A and attrs[HTML.Attrs.HREF]: 353 | self._stack_add(tag, WCfg.FOREGROUND, "blue") 354 | else: 355 | self._stack_add(tag, WCfg.FOREGROUND) 356 | 357 | #---------------------------------------------------------------------- [ BACKGROUD_COLOR ] 358 | if HTML.Style.BACKGROUD_COLOR in attrs[HTML.Attrs.STYLE].keys(): 359 | self._stack_add(tag, WCfg.BACKGROUND, attrs[HTML.Attrs.STYLE][HTML.Style.BACKGROUD_COLOR]) 360 | elif tag == HTML.Tag.MARK: 361 | self._stack_add(tag, WCfg.BACKGROUND, "yellow") 362 | else: 363 | self._stack_add(tag, WCfg.BACKGROUND) 364 | 365 | #-------------------------------------------------------------------------- [ FONT_FAMILY ] 366 | # font family 367 | if HTML.Style.FONT_FAMILY in attrs[HTML.Attrs.STYLE].keys(): 368 | font_family = Defs.DEFAULT_TEXT_FONT_FAMILY 369 | for f in attrs[HTML.Attrs.STYLE][HTML.Style.FONT_FAMILY].split(","): 370 | f = f.strip() 371 | if f in map(lambda f: f.lower(), font.families()): 372 | font_family = f 373 | break 374 | self._stack_add(tag, Fnt.FAMILY, font_family) 375 | elif tag in (HTML.Tag.PRE, HTML.Tag.CODE): 376 | self._stack_add(tag, Fnt.FAMILY, self.PREFORMATTED_FONT_FAMILY) 377 | else: 378 | self._stack_add(tag, Fnt.FAMILY) 379 | 380 | #---------------------------------------------------------------------------- [ FONT_SIZE ] 381 | if HTML.Style.FONT_SIZE in attrs[HTML.Attrs.STYLE].keys(): 382 | size = Defs.FONT_SIZE 383 | if attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE].endswith("px"): 384 | if attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE][:-2].isdigit(): 385 | size = int(attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE][:-2]) 386 | elif attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE].endswith(r"%"): 387 | if attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE][:-1].isdigit(): 388 | size = int((int(attrs[HTML.Attrs.STYLE][HTML.Style.FONT_SIZE][:-1]) * Defs.FONT_SIZE)/100) 389 | self._stack_add(tag, Fnt.SIZE, size) 390 | elif tag.startswith('h') and len(tag) == 2: 391 | self._stack_add(tag, Fnt.SIZE, Defs.HEADINGS_FONT_SIZE[tag]) 392 | else: 393 | self._stack_add(tag, Fnt.SIZE) 394 | 395 | #--------------------------------------------------------------------------- [ TEXT_ALIGN ] 396 | if HTML.Style.TEXT_ALIGN in attrs[HTML.Attrs.STYLE].keys() and tag in HTML.TEXT_ALIGN_TAGS: 397 | self._stack_add(tag, WCfg.JUSTIFY, attrs[HTML.Attrs.STYLE][HTML.Style.TEXT_ALIGN]) 398 | else: 399 | self._stack_add(tag, WCfg.JUSTIFY) 400 | 401 | #---------------------------------------------------------------------- [ TEXT_DECORATION ] 402 | if HTML.Style.TEXT_DECORATION in attrs[HTML.Attrs.STYLE].keys(): 403 | if tag == HTML.Tag.STRONG: 404 | self._stack_add(tag, Fnt.UNDERLINE, False) 405 | self._stack_add(tag, Fnt.OVERSTRIKE, False) 406 | elif HTML.StyleTextDecoration.UNDERLINE in attrs[HTML.Attrs.STYLE][HTML.Style.TEXT_DECORATION]: 407 | self._stack_add(tag, Fnt.UNDERLINE, True) 408 | self._stack_add(tag, Fnt.OVERSTRIKE, False) 409 | elif HTML.StyleTextDecoration.LINE_THROUGH in attrs[HTML.Attrs.STYLE][HTML.Style.TEXT_DECORATION]: 410 | self._stack_add(tag, Fnt.UNDERLINE, False) 411 | self._stack_add(tag, Fnt.OVERSTRIKE, True) 412 | else: 413 | self._stack_add(tag, Fnt.UNDERLINE) 414 | self._stack_add(tag, Fnt.OVERSTRIKE) 415 | else: 416 | if tag == HTML.Tag.A and attrs[HTML.Attrs.HREF]: 417 | self._stack_add(tag, Fnt.UNDERLINE, True) 418 | self._stack_add(tag, Fnt.OVERSTRIKE, False) 419 | elif tag == HTML.Tag.U: 420 | self._stack_add(tag, Fnt.UNDERLINE, True) 421 | self._stack_add(tag, Fnt.OVERSTRIKE, False) 422 | else: 423 | self._stack_add(tag, Fnt.UNDERLINE) 424 | self._stack_add(tag, Fnt.OVERSTRIKE) 425 | 426 | 427 | def handle_starttag(self, tag, attrs): 428 | #------------------------------------------------------------------------------------------ 429 | tag = tag.lower() 430 | attrs = self._parse_attrs(attrs) 431 | 432 | if tag in HTML.STYLE_TAGS: 433 | #---------------------------------------------------------------------- [ STYLED_TAGS ] 434 | self._parse_styles(tag, attrs) 435 | 436 | if tag == HTML.Tag.B or tag == HTML.Tag.STRONG or tag in HTML.HEADING_TAGS: 437 | self._stack_add(tag, Fnt.WEIGHT, "bold") 438 | 439 | elif tag == HTML.Tag.I or tag == HTML.Tag.EM: 440 | self._stack_add(tag, Fnt.SLANT, "italic") 441 | 442 | elif tag == HTML.Tag.A: 443 | self._stack_add(tag, Bind.LINK, attrs[HTML.Attrs.HREF]) 444 | 445 | elif tag == HTML.Tag.OL: 446 | #---------------------------------------------------------------- [ ORDERED_LISTS ] 447 | if attrs[HTML.Attrs.TYPE] and attrs[HTML.Attrs.TYPE] in HTML.TypeOrderedList.__dict__.values(): 448 | list_type = attrs[HTML.Attrs.TYPE] 449 | else: 450 | list_type = HTML.TypeOrderedList._1 451 | self.list_tags.append(ListTag(ordered=True, list_type=list_type)) 452 | 453 | tabs = [] 454 | for i in range(len(self.list_tags)): 455 | offset = 30 * (i + 1) 456 | tabs += [offset, tk.RIGHT, offset+5, tk.LEFT ] 457 | self._stack_add(tag, WCfg.TABS, tabs) 458 | 459 | elif tag == HTML.Tag.UL: 460 | #-------------------------------------------------------------- [ UNORDERED_LISTS ] 461 | self.list_tags.append(ListTag(ordered=False)) 462 | 463 | tabs = [] 464 | for i in range(len(self.list_tags)): 465 | offset = 30 * (i + 1) 466 | tabs += [offset, tk.RIGHT, offset+5, tk.LEFT ] 467 | self._stack_add(tag, WCfg.TABS, tabs) 468 | 469 | elif tag == HTML.Tag.LI: 470 | #------------------------------------------------------------------ [ LISTS_LINES ] 471 | level = len(self.list_tags) 472 | if level: 473 | self.list_tags[-1].add() 474 | 475 | if self.strip: 476 | self._insert_new_line() 477 | 478 | line_index = self.list_tags[-1].line_index() 479 | if self.list_tags[-1].ordered: 480 | line_index = "\t" + "\t\t" * (level-1) + line_index + ".\t" 481 | else: 482 | line_index = "\t" + "\t\t" * (level-1) + line_index + "\t" 483 | 484 | self._stack_add(tag, Fnt.UNDERLINE, False) 485 | self._stack_add(tag, Fnt.OVERSTRIKE, False) 486 | self._w_tags_add() 487 | self._w.insert(tk.INSERT, line_index) 488 | self._stack_pop(tag, Fnt.UNDERLINE) 489 | self._stack_pop(tag, Fnt.OVERSTRIKE) 490 | 491 | elif tag == HTML.Tag.IMG and attrs[HTML.Attrs.SRC]: 492 | #-------------------------------------------------------------------- [ UNSTYLED_TAGS ] 493 | image = None 494 | if attrs[HTML.Attrs.SRC] in self.cached_images.keys(): 495 | image = deepcopy(self.cached_images[attrs[HTML.Attrs.SRC]]) 496 | elif os.path.exists(attrs[HTML.Attrs.SRC]): 497 | image = Image.open(attrs[HTML.Attrs.SRC]) 498 | self.cached_images[attrs[HTML.Attrs.SRC]] = deepcopy(image) 499 | if image: 500 | width = image.size[0] 501 | height = image.size[1] 502 | resize = False 503 | if str(attrs[HTML.Attrs.WIDTH]).isdigit(): 504 | width = int(attrs[HTML.Attrs.WIDTH]) 505 | resize = True 506 | if str(attrs[HTML.Attrs.HEIGHT]).isdigit(): 507 | height = int(attrs[HTML.Attrs.HEIGHT]) 508 | resize = True 509 | if resize: 510 | image = image.resize((width, height), Image.ANTIALIAS) 511 | self.images.append(ImageTk.PhotoImage(image)) 512 | self._w.image_create(tk.INSERT, image=self.images[-1]) 513 | 514 | if self.strip: 515 | #------------------------------------------------------------------------ [ NEW_LINES ] 516 | if tag == HTML.Tag.BR: 517 | self._insert_new_line() 518 | else: 519 | self.html_tags.append(tag) 520 | 521 | if tag in HTML.NEW_LINE_TAGS and self.strip and self._w.index("end-1c") != "1.0": 522 | if tag in (HTML.Tag.DIV,): 523 | self._insert_new_line() 524 | elif tag in (HTML.Tag.UL, HTML.Tag.OL): 525 | if len(self.list_tags) == 1: 526 | self._insert_new_line(double=True) 527 | else: 528 | self._insert_new_line(double=False) 529 | else: 530 | self._insert_new_line(double=True) 531 | 532 | self._w_tags_add() 533 | 534 | 535 | def handle_charref(self, data): 536 | #------------------------------------------------------------------------------------------ 537 | try: 538 | char = chr(int(data)) 539 | self._w.insert(tk.INSERT, char) 540 | except: 541 | pass 542 | 543 | 544 | def _insert_new_line(self, double=False): 545 | #------------------------------------------------------------------------------------------ 546 | self._remove_last_space() 547 | if self._w.get("end-3c", "end-1c") == "\n\n": 548 | pass 549 | elif self._w.get("end-2c", "end-1c") == "\n": 550 | if double: 551 | self._w.insert(tk.INSERT, "\n") 552 | else: 553 | if double: 554 | self._w.insert(tk.INSERT, "\n\n") 555 | else: 556 | self._w.insert(tk.INSERT, "\n") 557 | 558 | 559 | def _text_rstrip(self): 560 | #------------------------------------------------------------------------------------------ 561 | for _ in range(3): 562 | if self._w.get("end-2c", "end-1c") in (" ", "\n"): 563 | self._w.delete("end-2c", "end-1c") 564 | 565 | 566 | def _remove_last_space(self): 567 | #------------------------------------------------------------------------------------------ 568 | if self._w.get("end-2c", "end-1c") == " ": 569 | self._w.delete("end-2c", "end-1c") 570 | 571 | 572 | def _remove_multi_spaces(self, data): 573 | #------------------------------------------------------------------------------------------ 574 | data = data.replace(" ", " ") 575 | if " " in data: 576 | data = self._remove_multi_spaces(data) 577 | return data 578 | 579 | 580 | def handle_data(self, data): 581 | #------------------------------------------------------------------------------------------ 582 | if self.strip: 583 | if len(self.html_tags) and self.html_tags[-1] in (HTML.Tag.PRE, HTML.Tag.CODE): 584 | pass 585 | elif not data.strip(): 586 | data = "" 587 | else: 588 | # left strip 589 | if self._w.index("end-1c").endswith(".0"): 590 | data = data.lstrip() 591 | elif self._w.get("end-2c", "end-1c") == " ": 592 | data = data.lstrip() 593 | 594 | data = data.replace("\n", " ").replace("\t", " ") 595 | data = data + " " 596 | data = self._remove_multi_spaces(data) 597 | if len(self.html_tags): 598 | level = len(self.list_tags) 599 | if self.html_tags[-1] in (HTML.Tag.UL, HTML.Tag.OL): 600 | self._w.insert(tk.INSERT, "\t" * 2 * level) 601 | 602 | self._w.insert(tk.INSERT, data) 603 | 604 | 605 | def handle_endtag(self, tag): 606 | #------------------------------------------------------------------------------------------ 607 | tag = tag.lower() 608 | 609 | try: 610 | index = len(self.html_tags) - self.html_tags[::-1].index(tag) - 1 611 | self.html_tags.pop(index) 612 | except: 613 | pass 614 | 615 | if tag in HTML.STYLE_TAGS: 616 | 617 | self._stack_pop(tag, WCfg.FOREGROUND) 618 | self._stack_pop(tag, WCfg.BACKGROUND) 619 | self._stack_pop(tag, WCfg.JUSTIFY) 620 | self._stack_pop(tag, Fnt.FAMILY) 621 | self._stack_pop(tag, Fnt.SIZE) 622 | self._stack_pop(tag, Fnt.UNDERLINE) 623 | self._stack_pop(tag, Fnt.OVERSTRIKE) 624 | 625 | if tag == HTML.Tag.B or tag == HTML.Tag.STRONG or tag in HTML.HEADING_TAGS: 626 | self._stack_pop(tag, Fnt.WEIGHT) 627 | 628 | elif tag == HTML.Tag.I or tag == HTML.Tag.EM: 629 | self._stack_pop(tag, Fnt.SLANT) 630 | 631 | elif tag == HTML.Tag.A: 632 | self._stack_pop(tag, Bind.LINK) 633 | 634 | elif tag == HTML.Tag.OL or tag == HTML.Tag.UL: 635 | if len(self.list_tags): 636 | self.list_tags = self.list_tags[:-1] 637 | 638 | self._stack_pop(tag, WCfg.TABS) 639 | 640 | if tag in HTML.NEW_LINE_TAGS and self.strip: 641 | self._insert_new_line() 642 | 643 | self._w_tags_add() 644 | 645 | if tag in HTML.NEW_LINE_TAGS and self.strip: 646 | if tag in (HTML.Tag.DIV, HTML.Tag.UL, HTML.Tag.OL): 647 | if not len(self.list_tags): 648 | self._insert_new_line(double=True) 649 | else: 650 | self._insert_new_line(double=True) 651 | 652 | 653 | def _w_tags_apply_all(self): 654 | #------------------------------------------------------------------------------------------ 655 | # update indexes 656 | if self.strip: 657 | self._text_rstrip() 658 | end_index = tk.END 659 | for key, tag in reversed(tuple(self._w_tags.items())): 660 | tag[WTag.START_INDEX] = key 661 | tag[WTag.END_INDEX] = end_index 662 | end_index = key 663 | 664 | # add tags 665 | self.hlink_slots = [] 666 | for key, tag in self._w_tags.items(): 667 | self._w.tag_add(key, tag[WTag.START_INDEX], tag[WTag.END_INDEX]) 668 | self._w.tag_config(key, font=font.Font(**tag[Fnt.KEY]), **tag[WCfg.KEY]) 669 | if tag[Bind.KEY][Bind.LINK]: 670 | self.hlink_slots.append(HLinkSlot(self._w, key, tag[Bind.KEY][Bind.LINK])) 671 | self._w.tag_bind(key, "", self.hlink_slots[-1].call) 672 | self._w.tag_bind(key, "", self.hlink_slots[-1].leave) 673 | self._w.tag_bind(key, "", self.hlink_slots[-1].enter) 674 | 675 | 676 | def w_set_html(self, w, html, strip): 677 | #------------------------------------------------------------------------------------------ 678 | self._w = w 679 | self.stack = deepcopy(DEFAULT_STACK) 680 | self.stack[WCfg.KEY][WCfg.BACKGROUND].append(("__DEFAULT__", self._w.cget("background"))) 681 | self.stack[Fnt.KEY][Fnt.FAMILY].append(("__DEFAULT__", self.DEFAULT_TEXT_FONT_FAMILY)) 682 | self._w_tags = OrderedDict() 683 | self.html_tags = [] 684 | self.images = [] 685 | self.list_tags = [] 686 | self.strip = strip 687 | self._w_tags_add() 688 | self.feed(html) 689 | self._w_tags_apply_all() 690 | del self._w 691 | -------------------------------------------------------------------------------- /tests/HTMLText_tags.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.0": { 3 | "bind": { 4 | "link": null 5 | }, 6 | "config": { 7 | "background": "SystemWindow", 8 | "foreground": "black", 9 | "justify": "left", 10 | "tabs": [ 11 | 30, 12 | "right", 13 | 35, 14 | "left" 15 | ] 16 | }, 17 | "end_index": "2.0", 18 | "font": { 19 | "family": "Segoe ui", 20 | "overstrike": false, 21 | "size": 9, 22 | "slant": "roman", 23 | "underline": false, 24 | "weight": "normal" 25 | }, 26 | "start_index": "1.0" 27 | }, 28 | "10.0": { 29 | "bind": { 30 | "link": null 31 | }, 32 | "config": { 33 | "background": "SystemWindow", 34 | "foreground": "black", 35 | "justify": "left", 36 | "tabs": [ 37 | 30, 38 | "right", 39 | 35, 40 | "left", 41 | 60, 42 | "right", 43 | 65, 44 | "left" 45 | ] 46 | }, 47 | "end_index": "10.6", 48 | "font": { 49 | "family": "Segoe ui", 50 | "overstrike": false, 51 | "size": 9, 52 | "slant": "roman", 53 | "underline": false, 54 | "weight": "normal" 55 | }, 56 | "start_index": "10.0" 57 | }, 58 | "10.29": { 59 | "bind": { 60 | "link": null 61 | }, 62 | "config": { 63 | "background": "SystemWindow", 64 | "foreground": "black", 65 | "justify": "left", 66 | "tabs": [ 67 | 30, 68 | "right", 69 | 35, 70 | "left", 71 | 60, 72 | "right", 73 | 65, 74 | "left" 75 | ] 76 | }, 77 | "end_index": "11.0", 78 | "font": { 79 | "family": "Segoe ui", 80 | "overstrike": false, 81 | "size": 9, 82 | "slant": "roman", 83 | "underline": false, 84 | "weight": "normal" 85 | }, 86 | "start_index": "10.29" 87 | }, 88 | "10.6": { 89 | "bind": { 90 | "link": null 91 | }, 92 | "config": { 93 | "background": "SystemWindow", 94 | "foreground": "black", 95 | "justify": "left", 96 | "tabs": [ 97 | 30, 98 | "right", 99 | 35, 100 | "left", 101 | 60, 102 | "right", 103 | 65, 104 | "left" 105 | ] 106 | }, 107 | "end_index": "10.29", 108 | "font": { 109 | "family": "Segoe ui", 110 | "overstrike": false, 111 | "size": 9, 112 | "slant": "roman", 113 | "underline": false, 114 | "weight": "normal" 115 | }, 116 | "start_index": "10.6" 117 | }, 118 | "11.0": { 119 | "bind": { 120 | "link": null 121 | }, 122 | "config": { 123 | "background": "SystemWindow", 124 | "foreground": "black", 125 | "justify": "left", 126 | "tabs": [ 127 | 30, 128 | "right", 129 | 35, 130 | "left", 131 | 60, 132 | "right", 133 | 65, 134 | "left" 135 | ] 136 | }, 137 | "end_index": "11.6", 138 | "font": { 139 | "family": "Segoe ui", 140 | "overstrike": false, 141 | "size": 9, 142 | "slant": "roman", 143 | "underline": false, 144 | "weight": "normal" 145 | }, 146 | "start_index": "11.0" 147 | }, 148 | "11.30": { 149 | "bind": { 150 | "link": null 151 | }, 152 | "config": { 153 | "background": "SystemWindow", 154 | "foreground": "black", 155 | "justify": "left", 156 | "tabs": [ 157 | 30, 158 | "right", 159 | 35, 160 | "left", 161 | 60, 162 | "right", 163 | 65, 164 | "left" 165 | ] 166 | }, 167 | "end_index": "12.0", 168 | "font": { 169 | "family": "Segoe ui", 170 | "overstrike": false, 171 | "size": 9, 172 | "slant": "roman", 173 | "underline": false, 174 | "weight": "normal" 175 | }, 176 | "start_index": "11.30" 177 | }, 178 | "11.6": { 179 | "bind": { 180 | "link": null 181 | }, 182 | "config": { 183 | "background": "SystemWindow", 184 | "foreground": "black", 185 | "justify": "left", 186 | "tabs": [ 187 | 30, 188 | "right", 189 | 35, 190 | "left", 191 | 60, 192 | "right", 193 | 65, 194 | "left" 195 | ] 196 | }, 197 | "end_index": "11.30", 198 | "font": { 199 | "family": "Segoe ui", 200 | "overstrike": false, 201 | "size": 9, 202 | "slant": "roman", 203 | "underline": false, 204 | "weight": "normal" 205 | }, 206 | "start_index": "11.6" 207 | }, 208 | "12.0": { 209 | "bind": { 210 | "link": null 211 | }, 212 | "config": { 213 | "background": "SystemWindow", 214 | "foreground": "black", 215 | "justify": "left", 216 | "tabs": [ 217 | 30, 218 | "right", 219 | 35, 220 | "left", 221 | 60, 222 | "right", 223 | 65, 224 | "left", 225 | 90, 226 | "right", 227 | 95, 228 | "left" 229 | ] 230 | }, 231 | "end_index": "12.8", 232 | "font": { 233 | "family": "Segoe ui", 234 | "overstrike": false, 235 | "size": 9, 236 | "slant": "roman", 237 | "underline": false, 238 | "weight": "normal" 239 | }, 240 | "start_index": "12.0" 241 | }, 242 | "12.31": { 243 | "bind": { 244 | "link": null 245 | }, 246 | "config": { 247 | "background": "SystemWindow", 248 | "foreground": "black", 249 | "justify": "left", 250 | "tabs": [ 251 | 30, 252 | "right", 253 | 35, 254 | "left", 255 | 60, 256 | "right", 257 | 65, 258 | "left", 259 | 90, 260 | "right", 261 | 95, 262 | "left" 263 | ] 264 | }, 265 | "end_index": "13.0", 266 | "font": { 267 | "family": "Segoe ui", 268 | "overstrike": false, 269 | "size": 9, 270 | "slant": "roman", 271 | "underline": false, 272 | "weight": "normal" 273 | }, 274 | "start_index": "12.31" 275 | }, 276 | "12.8": { 277 | "bind": { 278 | "link": null 279 | }, 280 | "config": { 281 | "background": "SystemWindow", 282 | "foreground": "black", 283 | "justify": "left", 284 | "tabs": [ 285 | 30, 286 | "right", 287 | 35, 288 | "left", 289 | 60, 290 | "right", 291 | 65, 292 | "left", 293 | 90, 294 | "right", 295 | 95, 296 | "left" 297 | ] 298 | }, 299 | "end_index": "12.31", 300 | "font": { 301 | "family": "Segoe ui", 302 | "overstrike": false, 303 | "size": 9, 304 | "slant": "roman", 305 | "underline": false, 306 | "weight": "normal" 307 | }, 308 | "start_index": "12.8" 309 | }, 310 | "13.0": { 311 | "bind": { 312 | "link": null 313 | }, 314 | "config": { 315 | "background": "SystemWindow", 316 | "foreground": "black", 317 | "justify": "left", 318 | "tabs": [ 319 | 30, 320 | "right", 321 | 35, 322 | "left", 323 | 60, 324 | "right", 325 | 65, 326 | "left", 327 | 90, 328 | "right", 329 | 95, 330 | "left" 331 | ] 332 | }, 333 | "end_index": "13.8", 334 | "font": { 335 | "family": "Segoe ui", 336 | "overstrike": false, 337 | "size": 9, 338 | "slant": "roman", 339 | "underline": false, 340 | "weight": "normal" 341 | }, 342 | "start_index": "13.0" 343 | }, 344 | "13.31": { 345 | "bind": { 346 | "link": null 347 | }, 348 | "config": { 349 | "background": "SystemWindow", 350 | "foreground": "black", 351 | "justify": "left", 352 | "tabs": [ 353 | 30, 354 | "right", 355 | 35, 356 | "left", 357 | 60, 358 | "right", 359 | 65, 360 | "left", 361 | 90, 362 | "right", 363 | 95, 364 | "left" 365 | ] 366 | }, 367 | "end_index": "14.0", 368 | "font": { 369 | "family": "Segoe ui", 370 | "overstrike": false, 371 | "size": 9, 372 | "slant": "roman", 373 | "underline": false, 374 | "weight": "normal" 375 | }, 376 | "start_index": "13.31" 377 | }, 378 | "13.8": { 379 | "bind": { 380 | "link": null 381 | }, 382 | "config": { 383 | "background": "SystemWindow", 384 | "foreground": "black", 385 | "justify": "left", 386 | "tabs": [ 387 | 30, 388 | "right", 389 | 35, 390 | "left", 391 | 60, 392 | "right", 393 | 65, 394 | "left", 395 | 90, 396 | "right", 397 | 95, 398 | "left" 399 | ] 400 | }, 401 | "end_index": "13.31", 402 | "font": { 403 | "family": "Segoe ui", 404 | "overstrike": false, 405 | "size": 9, 406 | "slant": "roman", 407 | "underline": false, 408 | "weight": "normal" 409 | }, 410 | "start_index": "13.8" 411 | }, 412 | "14.0": { 413 | "bind": { 414 | "link": null 415 | }, 416 | "config": { 417 | "background": "SystemWindow", 418 | "foreground": "black", 419 | "justify": "left", 420 | "tabs": [] 421 | }, 422 | "end_index": "15.0", 423 | "font": { 424 | "family": "Segoe ui", 425 | "overstrike": false, 426 | "size": 9, 427 | "slant": "roman", 428 | "underline": false, 429 | "weight": "normal" 430 | }, 431 | "start_index": "14.0" 432 | }, 433 | "15.0": { 434 | "bind": { 435 | "link": "https://www.python.org" 436 | }, 437 | "config": { 438 | "background": "SystemWindow", 439 | "foreground": "blue", 440 | "justify": "left", 441 | "tabs": [] 442 | }, 443 | "end_index": "15.10", 444 | "font": { 445 | "family": "Segoe ui", 446 | "overstrike": false, 447 | "size": 9, 448 | "slant": "roman", 449 | "underline": true, 450 | "weight": "normal" 451 | }, 452 | "start_index": "15.0" 453 | }, 454 | "15.10": { 455 | "bind": { 456 | "link": null 457 | }, 458 | "config": { 459 | "background": "SystemWindow", 460 | "foreground": "black", 461 | "justify": "left", 462 | "tabs": [] 463 | }, 464 | "end_index": "16.0", 465 | "font": { 466 | "family": "Segoe ui", 467 | "overstrike": false, 468 | "size": 9, 469 | "slant": "roman", 470 | "underline": false, 471 | "weight": "normal" 472 | }, 473 | "start_index": "15.10" 474 | }, 475 | "16.0": { 476 | "bind": { 477 | "link": null 478 | }, 479 | "config": { 480 | "background": "SystemWindow", 481 | "foreground": "black", 482 | "justify": "left", 483 | "tabs": [] 484 | }, 485 | "end_index": "16.5", 486 | "font": { 487 | "family": "Segoe ui", 488 | "overstrike": false, 489 | "size": 9, 490 | "slant": "roman", 491 | "underline": false, 492 | "weight": "bold" 493 | }, 494 | "start_index": "16.0" 495 | }, 496 | "16.5": { 497 | "bind": { 498 | "link": null 499 | }, 500 | "config": { 501 | "background": "SystemWindow", 502 | "foreground": "black", 503 | "justify": "left", 504 | "tabs": [] 505 | }, 506 | "end_index": "17.0", 507 | "font": { 508 | "family": "Segoe ui", 509 | "overstrike": false, 510 | "size": 9, 511 | "slant": "roman", 512 | "underline": false, 513 | "weight": "normal" 514 | }, 515 | "start_index": "16.5" 516 | }, 517 | "17.0": { 518 | "bind": { 519 | "link": null 520 | }, 521 | "config": { 522 | "background": "SystemWindow", 523 | "foreground": "black", 524 | "justify": "left", 525 | "tabs": [] 526 | }, 527 | "end_index": "17.7", 528 | "font": { 529 | "family": "Segoe ui", 530 | "overstrike": false, 531 | "size": 9, 532 | "slant": "roman", 533 | "underline": false, 534 | "weight": "bold" 535 | }, 536 | "start_index": "17.0" 537 | }, 538 | "17.7": { 539 | "bind": { 540 | "link": null 541 | }, 542 | "config": { 543 | "background": "SystemWindow", 544 | "foreground": "black", 545 | "justify": "left", 546 | "tabs": [] 547 | }, 548 | "end_index": "18.0", 549 | "font": { 550 | "family": "Segoe ui", 551 | "overstrike": false, 552 | "size": 9, 553 | "slant": "roman", 554 | "underline": false, 555 | "weight": "normal" 556 | }, 557 | "start_index": "17.7" 558 | }, 559 | "18.0": { 560 | "bind": { 561 | "link": null 562 | }, 563 | "config": { 564 | "background": "SystemWindow", 565 | "foreground": "black", 566 | "justify": "left", 567 | "tabs": [] 568 | }, 569 | "end_index": "18.7", 570 | "font": { 571 | "family": "Segoe ui", 572 | "overstrike": false, 573 | "size": 9, 574 | "slant": "italic", 575 | "underline": false, 576 | "weight": "normal" 577 | }, 578 | "start_index": "18.0" 579 | }, 580 | "18.7": { 581 | "bind": { 582 | "link": null 583 | }, 584 | "config": { 585 | "background": "SystemWindow", 586 | "foreground": "black", 587 | "justify": "left", 588 | "tabs": [] 589 | }, 590 | "end_index": "19.0", 591 | "font": { 592 | "family": "Segoe ui", 593 | "overstrike": false, 594 | "size": 9, 595 | "slant": "roman", 596 | "underline": false, 597 | "weight": "normal" 598 | }, 599 | "start_index": "18.7" 600 | }, 601 | "19.0": { 602 | "bind": { 603 | "link": null 604 | }, 605 | "config": { 606 | "background": "SystemWindow", 607 | "foreground": "black", 608 | "justify": "left", 609 | "tabs": [] 610 | }, 611 | "end_index": "19.11", 612 | "font": { 613 | "family": "Segoe ui", 614 | "overstrike": false, 615 | "size": 9, 616 | "slant": "italic", 617 | "underline": false, 618 | "weight": "normal" 619 | }, 620 | "start_index": "19.0" 621 | }, 622 | "19.11": { 623 | "bind": { 624 | "link": null 625 | }, 626 | "config": { 627 | "background": "SystemWindow", 628 | "foreground": "black", 629 | "justify": "left", 630 | "tabs": [] 631 | }, 632 | "end_index": "20.0", 633 | "font": { 634 | "family": "Segoe ui", 635 | "overstrike": false, 636 | "size": 9, 637 | "slant": "roman", 638 | "underline": false, 639 | "weight": "normal" 640 | }, 641 | "start_index": "19.11" 642 | }, 643 | "2.0": { 644 | "bind": { 645 | "link": null 646 | }, 647 | "config": { 648 | "background": "SystemWindow", 649 | "foreground": "black", 650 | "justify": "left", 651 | "tabs": [ 652 | 30, 653 | "right", 654 | 35, 655 | "left" 656 | ] 657 | }, 658 | "end_index": "2.3", 659 | "font": { 660 | "family": "Segoe ui", 661 | "overstrike": false, 662 | "size": 9, 663 | "slant": "roman", 664 | "underline": false, 665 | "weight": "normal" 666 | }, 667 | "start_index": "2.0" 668 | }, 669 | "2.16": { 670 | "bind": { 671 | "link": null 672 | }, 673 | "config": { 674 | "background": "SystemWindow", 675 | "foreground": "black", 676 | "justify": "left", 677 | "tabs": [ 678 | 30, 679 | "right", 680 | 35, 681 | "left" 682 | ] 683 | }, 684 | "end_index": "3.0", 685 | "font": { 686 | "family": "Segoe ui", 687 | "overstrike": false, 688 | "size": 9, 689 | "slant": "roman", 690 | "underline": false, 691 | "weight": "normal" 692 | }, 693 | "start_index": "2.16" 694 | }, 695 | "2.3": { 696 | "bind": { 697 | "link": null 698 | }, 699 | "config": { 700 | "background": "SystemWindow", 701 | "foreground": "black", 702 | "justify": "left", 703 | "tabs": [ 704 | 30, 705 | "right", 706 | 35, 707 | "left" 708 | ] 709 | }, 710 | "end_index": "2.16", 711 | "font": { 712 | "family": "Segoe ui", 713 | "overstrike": false, 714 | "size": 9, 715 | "slant": "roman", 716 | "underline": false, 717 | "weight": "normal" 718 | }, 719 | "start_index": "2.3" 720 | }, 721 | "20.0": { 722 | "bind": { 723 | "link": null 724 | }, 725 | "config": { 726 | "background": "SystemWindow", 727 | "foreground": "black", 728 | "justify": "left", 729 | "tabs": [] 730 | }, 731 | "end_index": "20.10", 732 | "font": { 733 | "family": "Segoe ui", 734 | "overstrike": false, 735 | "size": 9, 736 | "slant": "roman", 737 | "underline": true, 738 | "weight": "normal" 739 | }, 740 | "start_index": "20.0" 741 | }, 742 | "20.10": { 743 | "bind": { 744 | "link": null 745 | }, 746 | "config": { 747 | "background": "SystemWindow", 748 | "foreground": "black", 749 | "justify": "left", 750 | "tabs": [] 751 | }, 752 | "end_index": "21.0", 753 | "font": { 754 | "family": "Segoe ui", 755 | "overstrike": false, 756 | "size": 9, 757 | "slant": "roman", 758 | "underline": false, 759 | "weight": "normal" 760 | }, 761 | "start_index": "20.10" 762 | }, 763 | "21.0": { 764 | "bind": { 765 | "link": null 766 | }, 767 | "config": { 768 | "background": "yellow", 769 | "foreground": "black", 770 | "justify": "left", 771 | "tabs": [] 772 | }, 773 | "end_index": "21.7", 774 | "font": { 775 | "family": "Segoe ui", 776 | "overstrike": false, 777 | "size": 9, 778 | "slant": "roman", 779 | "underline": false, 780 | "weight": "normal" 781 | }, 782 | "start_index": "21.0" 783 | }, 784 | "21.7": { 785 | "bind": { 786 | "link": null 787 | }, 788 | "config": { 789 | "background": "SystemWindow", 790 | "foreground": "black", 791 | "justify": "left", 792 | "tabs": [] 793 | }, 794 | "end_index": "22.0", 795 | "font": { 796 | "family": "Segoe ui", 797 | "overstrike": false, 798 | "size": 9, 799 | "slant": "roman", 800 | "underline": false, 801 | "weight": "normal" 802 | }, 803 | "start_index": "21.7" 804 | }, 805 | "22.0": { 806 | "bind": { 807 | "link": null 808 | }, 809 | "config": { 810 | "background": "SystemWindow", 811 | "foreground": "black", 812 | "justify": "left", 813 | "tabs": [] 814 | }, 815 | "end_index": "22.8", 816 | "font": { 817 | "family": "Segoe ui", 818 | "overstrike": false, 819 | "size": 9, 820 | "slant": "roman", 821 | "underline": false, 822 | "weight": "normal" 823 | }, 824 | "start_index": "22.0" 825 | }, 826 | "22.8": { 827 | "bind": { 828 | "link": null 829 | }, 830 | "config": { 831 | "background": "SystemWindow", 832 | "foreground": "black", 833 | "justify": "left", 834 | "tabs": [] 835 | }, 836 | "end_index": "23.0", 837 | "font": { 838 | "family": "Segoe ui", 839 | "overstrike": false, 840 | "size": 9, 841 | "slant": "roman", 842 | "underline": false, 843 | "weight": "normal" 844 | }, 845 | "start_index": "22.8" 846 | }, 847 | "23.0": { 848 | "bind": { 849 | "link": null 850 | }, 851 | "config": { 852 | "background": "SystemWindow", 853 | "foreground": "black", 854 | "justify": "left", 855 | "tabs": [] 856 | }, 857 | "end_index": "24.0", 858 | "font": { 859 | "family": "Segoe ui", 860 | "overstrike": false, 861 | "size": 9, 862 | "slant": "roman", 863 | "underline": false, 864 | "weight": "normal" 865 | }, 866 | "start_index": "23.0" 867 | }, 868 | "24.0": { 869 | "bind": { 870 | "link": null 871 | }, 872 | "config": { 873 | "background": "SystemWindow", 874 | "foreground": "black", 875 | "justify": "left", 876 | "tabs": [] 877 | }, 878 | "end_index": "25.0", 879 | "font": { 880 | "family": "Segoe ui", 881 | "overstrike": false, 882 | "size": 9, 883 | "slant": "roman", 884 | "underline": false, 885 | "weight": "normal" 886 | }, 887 | "start_index": "24.0" 888 | }, 889 | "25.0": { 890 | "bind": { 891 | "link": null 892 | }, 893 | "config": { 894 | "background": "SystemWindow", 895 | "foreground": "black", 896 | "justify": "left", 897 | "tabs": [] 898 | }, 899 | "end_index": "26.0", 900 | "font": { 901 | "family": "Segoe ui", 902 | "overstrike": false, 903 | "size": 9, 904 | "slant": "roman", 905 | "underline": false, 906 | "weight": "normal" 907 | }, 908 | "start_index": "25.0" 909 | }, 910 | "26.0": { 911 | "bind": { 912 | "link": null 913 | }, 914 | "config": { 915 | "background": "SystemWindow", 916 | "foreground": "black", 917 | "justify": "left", 918 | "tabs": [] 919 | }, 920 | "end_index": "27.0", 921 | "font": { 922 | "family": "Segoe ui", 923 | "overstrike": false, 924 | "size": 9, 925 | "slant": "roman", 926 | "underline": false, 927 | "weight": "normal" 928 | }, 929 | "start_index": "26.0" 930 | }, 931 | "27.0": { 932 | "bind": { 933 | "link": null 934 | }, 935 | "config": { 936 | "background": "SystemWindow", 937 | "foreground": "black", 938 | "justify": "left", 939 | "tabs": [] 940 | }, 941 | "end_index": "28.0", 942 | "font": { 943 | "family": "Courier", 944 | "overstrike": false, 945 | "size": 9, 946 | "slant": "roman", 947 | "underline": false, 948 | "weight": "normal" 949 | }, 950 | "start_index": "27.0" 951 | }, 952 | "28.0": { 953 | "bind": { 954 | "link": null 955 | }, 956 | "config": { 957 | "background": "SystemWindow", 958 | "foreground": "black", 959 | "justify": "left", 960 | "tabs": [] 961 | }, 962 | "end_index": "29.0", 963 | "font": { 964 | "family": "Segoe ui", 965 | "overstrike": false, 966 | "size": 9, 967 | "slant": "roman", 968 | "underline": false, 969 | "weight": "normal" 970 | }, 971 | "start_index": "28.0" 972 | }, 973 | "29.0": { 974 | "bind": { 975 | "link": null 976 | }, 977 | "config": { 978 | "background": "SystemWindow", 979 | "foreground": "black", 980 | "justify": "left", 981 | "tabs": [] 982 | }, 983 | "end_index": "30.0", 984 | "font": { 985 | "family": "Segoe ui", 986 | "overstrike": false, 987 | "size": 21, 988 | "slant": "roman", 989 | "underline": false, 990 | "weight": "bold" 991 | }, 992 | "start_index": "29.0" 993 | }, 994 | "3.0": { 995 | "bind": { 996 | "link": null 997 | }, 998 | "config": { 999 | "background": "SystemWindow", 1000 | "foreground": "black", 1001 | "justify": "left", 1002 | "tabs": [ 1003 | 30, 1004 | "right", 1005 | 35, 1006 | "left" 1007 | ] 1008 | }, 1009 | "end_index": "3.3", 1010 | "font": { 1011 | "family": "Segoe ui", 1012 | "overstrike": false, 1013 | "size": 9, 1014 | "slant": "roman", 1015 | "underline": false, 1016 | "weight": "normal" 1017 | }, 1018 | "start_index": "3.0" 1019 | }, 1020 | "3.16": { 1021 | "bind": { 1022 | "link": null 1023 | }, 1024 | "config": { 1025 | "background": "SystemWindow", 1026 | "foreground": "black", 1027 | "justify": "left", 1028 | "tabs": [ 1029 | 30, 1030 | "right", 1031 | 35, 1032 | "left" 1033 | ] 1034 | }, 1035 | "end_index": "4.0", 1036 | "font": { 1037 | "family": "Segoe ui", 1038 | "overstrike": false, 1039 | "size": 9, 1040 | "slant": "roman", 1041 | "underline": false, 1042 | "weight": "normal" 1043 | }, 1044 | "start_index": "3.16" 1045 | }, 1046 | "3.3": { 1047 | "bind": { 1048 | "link": null 1049 | }, 1050 | "config": { 1051 | "background": "SystemWindow", 1052 | "foreground": "black", 1053 | "justify": "left", 1054 | "tabs": [ 1055 | 30, 1056 | "right", 1057 | 35, 1058 | "left" 1059 | ] 1060 | }, 1061 | "end_index": "3.16", 1062 | "font": { 1063 | "family": "Segoe ui", 1064 | "overstrike": false, 1065 | "size": 9, 1066 | "slant": "roman", 1067 | "underline": false, 1068 | "weight": "normal" 1069 | }, 1070 | "start_index": "3.3" 1071 | }, 1072 | "30.0": { 1073 | "bind": { 1074 | "link": null 1075 | }, 1076 | "config": { 1077 | "background": "SystemWindow", 1078 | "foreground": "black", 1079 | "justify": "left", 1080 | "tabs": [] 1081 | }, 1082 | "end_index": "31.0", 1083 | "font": { 1084 | "family": "Segoe ui", 1085 | "overstrike": false, 1086 | "size": 9, 1087 | "slant": "roman", 1088 | "underline": false, 1089 | "weight": "normal" 1090 | }, 1091 | "start_index": "30.0" 1092 | }, 1093 | "31.0": { 1094 | "bind": { 1095 | "link": null 1096 | }, 1097 | "config": { 1098 | "background": "SystemWindow", 1099 | "foreground": "black", 1100 | "justify": "left", 1101 | "tabs": [] 1102 | }, 1103 | "end_index": "32.0", 1104 | "font": { 1105 | "family": "Segoe ui", 1106 | "overstrike": false, 1107 | "size": 16, 1108 | "slant": "roman", 1109 | "underline": false, 1110 | "weight": "bold" 1111 | }, 1112 | "start_index": "31.0" 1113 | }, 1114 | "32.0": { 1115 | "bind": { 1116 | "link": null 1117 | }, 1118 | "config": { 1119 | "background": "SystemWindow", 1120 | "foreground": "black", 1121 | "justify": "left", 1122 | "tabs": [] 1123 | }, 1124 | "end_index": "33.0", 1125 | "font": { 1126 | "family": "Segoe ui", 1127 | "overstrike": false, 1128 | "size": 9, 1129 | "slant": "roman", 1130 | "underline": false, 1131 | "weight": "normal" 1132 | }, 1133 | "start_index": "32.0" 1134 | }, 1135 | "33.0": { 1136 | "bind": { 1137 | "link": null 1138 | }, 1139 | "config": { 1140 | "background": "SystemWindow", 1141 | "foreground": "black", 1142 | "justify": "left", 1143 | "tabs": [] 1144 | }, 1145 | "end_index": "34.0", 1146 | "font": { 1147 | "family": "Segoe ui", 1148 | "overstrike": false, 1149 | "size": 12, 1150 | "slant": "roman", 1151 | "underline": false, 1152 | "weight": "bold" 1153 | }, 1154 | "start_index": "33.0" 1155 | }, 1156 | "34.0": { 1157 | "bind": { 1158 | "link": null 1159 | }, 1160 | "config": { 1161 | "background": "SystemWindow", 1162 | "foreground": "black", 1163 | "justify": "left", 1164 | "tabs": [] 1165 | }, 1166 | "end_index": "35.0", 1167 | "font": { 1168 | "family": "Segoe ui", 1169 | "overstrike": false, 1170 | "size": 9, 1171 | "slant": "roman", 1172 | "underline": false, 1173 | "weight": "normal" 1174 | }, 1175 | "start_index": "34.0" 1176 | }, 1177 | "35.0": { 1178 | "bind": { 1179 | "link": null 1180 | }, 1181 | "config": { 1182 | "background": "SystemWindow", 1183 | "foreground": "black", 1184 | "justify": "left", 1185 | "tabs": [] 1186 | }, 1187 | "end_index": "36.0", 1188 | "font": { 1189 | "family": "Segoe ui", 1190 | "overstrike": false, 1191 | "size": 11, 1192 | "slant": "roman", 1193 | "underline": false, 1194 | "weight": "bold" 1195 | }, 1196 | "start_index": "35.0" 1197 | }, 1198 | "36.0": { 1199 | "bind": { 1200 | "link": null 1201 | }, 1202 | "config": { 1203 | "background": "SystemWindow", 1204 | "foreground": "black", 1205 | "justify": "left", 1206 | "tabs": [] 1207 | }, 1208 | "end_index": "37.0", 1209 | "font": { 1210 | "family": "Segoe ui", 1211 | "overstrike": false, 1212 | "size": 9, 1213 | "slant": "roman", 1214 | "underline": false, 1215 | "weight": "normal" 1216 | }, 1217 | "start_index": "36.0" 1218 | }, 1219 | "37.0": { 1220 | "bind": { 1221 | "link": null 1222 | }, 1223 | "config": { 1224 | "background": "SystemWindow", 1225 | "foreground": "black", 1226 | "justify": "left", 1227 | "tabs": [] 1228 | }, 1229 | "end_index": "38.0", 1230 | "font": { 1231 | "family": "Segoe ui", 1232 | "overstrike": false, 1233 | "size": 8, 1234 | "slant": "roman", 1235 | "underline": false, 1236 | "weight": "bold" 1237 | }, 1238 | "start_index": "37.0" 1239 | }, 1240 | "38.0": { 1241 | "bind": { 1242 | "link": null 1243 | }, 1244 | "config": { 1245 | "background": "SystemWindow", 1246 | "foreground": "black", 1247 | "justify": "left", 1248 | "tabs": [] 1249 | }, 1250 | "end_index": "39.0", 1251 | "font": { 1252 | "family": "Segoe ui", 1253 | "overstrike": false, 1254 | "size": 9, 1255 | "slant": "roman", 1256 | "underline": false, 1257 | "weight": "normal" 1258 | }, 1259 | "start_index": "38.0" 1260 | }, 1261 | "39.0": { 1262 | "bind": { 1263 | "link": null 1264 | }, 1265 | "config": { 1266 | "background": "SystemWindow", 1267 | "foreground": "black", 1268 | "justify": "left", 1269 | "tabs": [] 1270 | }, 1271 | "end_index": "40.0", 1272 | "font": { 1273 | "family": "Segoe ui", 1274 | "overstrike": false, 1275 | "size": 7, 1276 | "slant": "roman", 1277 | "underline": false, 1278 | "weight": "bold" 1279 | }, 1280 | "start_index": "39.0" 1281 | }, 1282 | "4.0": { 1283 | "bind": { 1284 | "link": null 1285 | }, 1286 | "config": { 1287 | "background": "SystemWindow", 1288 | "foreground": "black", 1289 | "justify": "left", 1290 | "tabs": [ 1291 | 30, 1292 | "right", 1293 | 35, 1294 | "left", 1295 | 60, 1296 | "right", 1297 | 65, 1298 | "left" 1299 | ] 1300 | }, 1301 | "end_index": "5.0", 1302 | "font": { 1303 | "family": "Segoe ui", 1304 | "overstrike": false, 1305 | "size": 9, 1306 | "slant": "roman", 1307 | "underline": false, 1308 | "weight": "normal" 1309 | }, 1310 | "start_index": "4.0" 1311 | }, 1312 | "40.0": { 1313 | "bind": { 1314 | "link": null 1315 | }, 1316 | "config": { 1317 | "background": "SystemWindow", 1318 | "foreground": "black", 1319 | "justify": "left", 1320 | "tabs": [] 1321 | }, 1322 | "end_index": "end", 1323 | "font": { 1324 | "family": "Segoe ui", 1325 | "overstrike": false, 1326 | "size": 9, 1327 | "slant": "roman", 1328 | "underline": false, 1329 | "weight": "normal" 1330 | }, 1331 | "start_index": "40.0" 1332 | }, 1333 | "5.0": { 1334 | "bind": { 1335 | "link": null 1336 | }, 1337 | "config": { 1338 | "background": "SystemWindow", 1339 | "foreground": "black", 1340 | "justify": "left", 1341 | "tabs": [ 1342 | 30, 1343 | "right", 1344 | 35, 1345 | "left", 1346 | 60, 1347 | "right", 1348 | 65, 1349 | "left" 1350 | ] 1351 | }, 1352 | "end_index": "5.5", 1353 | "font": { 1354 | "family": "Segoe ui", 1355 | "overstrike": false, 1356 | "size": 9, 1357 | "slant": "roman", 1358 | "underline": false, 1359 | "weight": "normal" 1360 | }, 1361 | "start_index": "5.0" 1362 | }, 1363 | "5.18": { 1364 | "bind": { 1365 | "link": null 1366 | }, 1367 | "config": { 1368 | "background": "SystemWindow", 1369 | "foreground": "black", 1370 | "justify": "left", 1371 | "tabs": [ 1372 | 30, 1373 | "right", 1374 | 35, 1375 | "left", 1376 | 60, 1377 | "right", 1378 | 65, 1379 | "left" 1380 | ] 1381 | }, 1382 | "end_index": "6.0", 1383 | "font": { 1384 | "family": "Segoe ui", 1385 | "overstrike": false, 1386 | "size": 9, 1387 | "slant": "roman", 1388 | "underline": false, 1389 | "weight": "normal" 1390 | }, 1391 | "start_index": "5.18" 1392 | }, 1393 | "5.5": { 1394 | "bind": { 1395 | "link": null 1396 | }, 1397 | "config": { 1398 | "background": "SystemWindow", 1399 | "foreground": "black", 1400 | "justify": "left", 1401 | "tabs": [ 1402 | 30, 1403 | "right", 1404 | 35, 1405 | "left", 1406 | 60, 1407 | "right", 1408 | 65, 1409 | "left" 1410 | ] 1411 | }, 1412 | "end_index": "5.18", 1413 | "font": { 1414 | "family": "Segoe ui", 1415 | "overstrike": false, 1416 | "size": 9, 1417 | "slant": "roman", 1418 | "underline": false, 1419 | "weight": "normal" 1420 | }, 1421 | "start_index": "5.5" 1422 | }, 1423 | "6.0": { 1424 | "bind": { 1425 | "link": null 1426 | }, 1427 | "config": { 1428 | "background": "SystemWindow", 1429 | "foreground": "black", 1430 | "justify": "left", 1431 | "tabs": [ 1432 | 30, 1433 | "right", 1434 | 35, 1435 | "left", 1436 | 60, 1437 | "right", 1438 | 65, 1439 | "left" 1440 | ] 1441 | }, 1442 | "end_index": "6.5", 1443 | "font": { 1444 | "family": "Segoe ui", 1445 | "overstrike": false, 1446 | "size": 9, 1447 | "slant": "roman", 1448 | "underline": false, 1449 | "weight": "normal" 1450 | }, 1451 | "start_index": "6.0" 1452 | }, 1453 | "6.18": { 1454 | "bind": { 1455 | "link": null 1456 | }, 1457 | "config": { 1458 | "background": "SystemWindow", 1459 | "foreground": "black", 1460 | "justify": "left", 1461 | "tabs": [ 1462 | 30, 1463 | "right", 1464 | 35, 1465 | "left", 1466 | 60, 1467 | "right", 1468 | 65, 1469 | "left" 1470 | ] 1471 | }, 1472 | "end_index": "7.0", 1473 | "font": { 1474 | "family": "Segoe ui", 1475 | "overstrike": false, 1476 | "size": 9, 1477 | "slant": "roman", 1478 | "underline": false, 1479 | "weight": "normal" 1480 | }, 1481 | "start_index": "6.18" 1482 | }, 1483 | "6.5": { 1484 | "bind": { 1485 | "link": null 1486 | }, 1487 | "config": { 1488 | "background": "SystemWindow", 1489 | "foreground": "black", 1490 | "justify": "left", 1491 | "tabs": [ 1492 | 30, 1493 | "right", 1494 | 35, 1495 | "left", 1496 | 60, 1497 | "right", 1498 | 65, 1499 | "left" 1500 | ] 1501 | }, 1502 | "end_index": "6.18", 1503 | "font": { 1504 | "family": "Segoe ui", 1505 | "overstrike": false, 1506 | "size": 9, 1507 | "slant": "roman", 1508 | "underline": false, 1509 | "weight": "normal" 1510 | }, 1511 | "start_index": "6.5" 1512 | }, 1513 | "7.0": { 1514 | "bind": { 1515 | "link": null 1516 | }, 1517 | "config": { 1518 | "background": "SystemWindow", 1519 | "foreground": "black", 1520 | "justify": "left", 1521 | "tabs": [] 1522 | }, 1523 | "end_index": "8.0", 1524 | "font": { 1525 | "family": "Segoe ui", 1526 | "overstrike": false, 1527 | "size": 9, 1528 | "slant": "roman", 1529 | "underline": false, 1530 | "weight": "normal" 1531 | }, 1532 | "start_index": "7.0" 1533 | }, 1534 | "8.0": { 1535 | "bind": { 1536 | "link": null 1537 | }, 1538 | "config": { 1539 | "background": "SystemWindow", 1540 | "foreground": "black", 1541 | "justify": "left", 1542 | "tabs": [ 1543 | 30, 1544 | "right", 1545 | 35, 1546 | "left" 1547 | ] 1548 | }, 1549 | "end_index": "8.4", 1550 | "font": { 1551 | "family": "Segoe ui", 1552 | "overstrike": false, 1553 | "size": 9, 1554 | "slant": "roman", 1555 | "underline": false, 1556 | "weight": "normal" 1557 | }, 1558 | "start_index": "8.0" 1559 | }, 1560 | "8.27": { 1561 | "bind": { 1562 | "link": null 1563 | }, 1564 | "config": { 1565 | "background": "SystemWindow", 1566 | "foreground": "black", 1567 | "justify": "left", 1568 | "tabs": [ 1569 | 30, 1570 | "right", 1571 | 35, 1572 | "left" 1573 | ] 1574 | }, 1575 | "end_index": "9.0", 1576 | "font": { 1577 | "family": "Segoe ui", 1578 | "overstrike": false, 1579 | "size": 9, 1580 | "slant": "roman", 1581 | "underline": false, 1582 | "weight": "normal" 1583 | }, 1584 | "start_index": "8.27" 1585 | }, 1586 | "8.4": { 1587 | "bind": { 1588 | "link": null 1589 | }, 1590 | "config": { 1591 | "background": "SystemWindow", 1592 | "foreground": "black", 1593 | "justify": "left", 1594 | "tabs": [ 1595 | 30, 1596 | "right", 1597 | 35, 1598 | "left" 1599 | ] 1600 | }, 1601 | "end_index": "8.27", 1602 | "font": { 1603 | "family": "Segoe ui", 1604 | "overstrike": false, 1605 | "size": 9, 1606 | "slant": "roman", 1607 | "underline": false, 1608 | "weight": "normal" 1609 | }, 1610 | "start_index": "8.4" 1611 | }, 1612 | "9.0": { 1613 | "bind": { 1614 | "link": null 1615 | }, 1616 | "config": { 1617 | "background": "SystemWindow", 1618 | "foreground": "black", 1619 | "justify": "left", 1620 | "tabs": [ 1621 | 30, 1622 | "right", 1623 | 35, 1624 | "left" 1625 | ] 1626 | }, 1627 | "end_index": "9.4", 1628 | "font": { 1629 | "family": "Segoe ui", 1630 | "overstrike": false, 1631 | "size": 9, 1632 | "slant": "roman", 1633 | "underline": false, 1634 | "weight": "normal" 1635 | }, 1636 | "start_index": "9.0" 1637 | }, 1638 | "9.27": { 1639 | "bind": { 1640 | "link": null 1641 | }, 1642 | "config": { 1643 | "background": "SystemWindow", 1644 | "foreground": "black", 1645 | "justify": "left", 1646 | "tabs": [ 1647 | 30, 1648 | "right", 1649 | 35, 1650 | "left" 1651 | ] 1652 | }, 1653 | "end_index": "10.0", 1654 | "font": { 1655 | "family": "Segoe ui", 1656 | "overstrike": false, 1657 | "size": 9, 1658 | "slant": "roman", 1659 | "underline": false, 1660 | "weight": "normal" 1661 | }, 1662 | "start_index": "9.27" 1663 | }, 1664 | "9.4": { 1665 | "bind": { 1666 | "link": null 1667 | }, 1668 | "config": { 1669 | "background": "SystemWindow", 1670 | "foreground": "black", 1671 | "justify": "left", 1672 | "tabs": [ 1673 | 30, 1674 | "right", 1675 | 35, 1676 | "left" 1677 | ] 1678 | }, 1679 | "end_index": "9.27", 1680 | "font": { 1681 | "family": "Segoe ui", 1682 | "overstrike": false, 1683 | "size": 9, 1684 | "slant": "roman", 1685 | "underline": false, 1686 | "weight": "normal" 1687 | }, 1688 | "start_index": "9.4" 1689 | } 1690 | } --------------------------------------------------------------------------------