1import os
2
3from docutils import nodes
4from docutils.parsers.rst import Directive, directives
5from docutils.parsers.rst.directives.images import Image
6from sphinx.directives.code import LiteralInclude
7
8
9def excluded_list(argument):
10    return argument.split(',')
11
12
13
14
15class LvExample(Directive):
16    required_arguments = 1
17    option_spec = {
18        'excluded_languages': excluded_list,
19        'language': directives.unchanged,
20        'description': directives.unchanged
21    }
22    def get_example_code_path(self, example_path, language):
23        return os.path.abspath("../examples/" + example_path + "." + language)
24    def human_language_name(self, language):
25        if language == 'py':
26            return 'MicroPython'
27        elif language == 'c':
28            return 'C'
29        else:
30            return language
31    def github_path(self, example_path, language):
32        env = self.state.document.settings.env
33        return f"https://github.com/lvgl/lvgl/blob/{env.config.repo_commit_hash}/examples/{example_path}.{language}"
34    def embed_code(self, example_file, example_path, language, buttons={}):
35        toggle = nodes.container('', literal_block=False, classes=['toggle'])
36        header = nodes.container('', literal_block=False, classes=['header'])
37        toggle.append(header)
38        try:
39            with open(example_file) as f:
40                contents = f.read()
41        except FileNotFoundError:
42            contents = 'Error encountered while trying to open ' + example_file
43        literal_list = nodes.literal_block(contents, contents)
44        literal_list['language'] = language
45        toggle.append(literal_list)
46        paragraph_node = nodes.raw(text=f"<p>{self.human_language_name(language)} code &nbsp;</p>", format='html')
47        for text, url in buttons.items():
48            paragraph_node.append(nodes.raw(text=f"<a class='lv-example-link-button' onclick=\"event.stopPropagation();\" href='{url}'>{text}</a>", format='html'))
49        header.append(paragraph_node)
50        return toggle
51    def run(self):
52        example_path = self.arguments[0]
53        example_name = os.path.split(example_path)[1]
54        excluded_languages = self.options.get('excluded_languages', [])
55        node_list = []
56
57        env = self.state.document.settings.env
58
59        iframe_html = ""
60
61        c_path = self.get_example_code_path(example_path, 'c')
62        py_path = self.get_example_code_path(example_path, 'py')
63
64        c_code = self.embed_code(c_path, example_path, 'c', buttons={
65            '<i class="fa fa-github"></i>&nbsp;GitHub': self.github_path(example_path, 'c')
66        })
67        py_code = self.embed_code(py_path, example_path, 'py', buttons={
68            '<i class="fa fa-github"></i>&nbsp;GitHub': self.github_path(example_path, 'py'),
69            '<i class="fa fa-play"></i>&nbsp;Simulator': f"https://sim.lvgl.io/v{env.config.version}/micropython/ports/javascript/index.html?script_startup=https://raw.githubusercontent.com/lvgl/lvgl/{env.config.repo_commit_hash}/examples/header.py&script=https://raw.githubusercontent.com/lvgl/lvgl/{env.config.repo_commit_hash}/examples/{example_path}.py"
70        })
71
72        if not 'c' in excluded_languages:
73            if env.app.tags.has('html'):
74                iframe_html = f"<div class='lv-example' data-real-src='/{env.config.version}/_static/built_lv_examples/index.html?example={example_name}&w=320&h=240'></div>"
75
76        description_html = f"<div class='lv-example-description'>{self.options.get('description', '')}</div>"
77        layout_node = nodes.raw(text=f"<div class='lv-example-container'>{iframe_html}{description_html}</div>", format='html')
78
79        node_list.append(layout_node)
80        if not 'c' in excluded_languages:
81            node_list.append(c_code)
82        if not 'py' in excluded_languages:
83            node_list.append(py_code)
84
85        trailing_node = nodes.raw(text=f"<hr/>", format='html')
86        node_list.append(trailing_node)
87
88        return node_list
89
90def setup(app):
91    app.add_directive("lv_example", LvExample)
92    app.add_config_value("repo_commit_hash", "", "env")
93
94    return {
95        'version': '0.1',
96        'parallel_read_safe': True,
97        'parallel_write_safe': True,
98    }
99