# Inline documentation options

**URL:** <https://discourse.slicer.org/t/inline-documentation-options/41032>\
**Category:** Support\
**Created:** [January 10, 2025, 7:45pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032 "2025-01-10T19:45:35Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![muratmaga](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/muratmaga/32/3622_2.png) [@muratmaga](https://discourse.slicer.org/u/muratmaga)\
**Post date:** [January 10, 2025, 7:45pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/1 "2025-01-10T19:45:35Z")

</div>

For SlicerMorph, we maintain a tutorials page as a github repo:

> **[GitHub - SlicerMorph/Tutorials: SlicerMorph module tutorials](https://github.com/SlicerMorph/Tutorials/)**
>
> SlicerMorph module tutorials

I want to have a Tutorials module within SlicerMorph so that people can navigate to this site easily (or be aware of its existence). I can of course simply point this out as a URL in a basic module interface. But given that we have nice [README.MD file with links to the tutorials](https://github.com/SlicerMorph/Tutorials?tab=readme-ov-file#slicermorph-tutorials), I am wondering if there is a way to import this dynamically? I.e., I do not want to replicate the contents of the README.MD as part of the module help page (too much duplicated work).

I guess I am looking into something like making a snapshot of this README during module build and rendered with clickable links…

I am still fuzzy on details, so can use suggestions.

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [January 10, 2025, 8:29pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/2 "2025-01-10T20:29:55Z")

</div>

Well you could bundle the contents of the tutorials (either just the readme or the full repo contents) when the extension is built or you could assume people will have internet when they use it and fetch dynamically.

Do you want to show the tutorials in a web view that can interact somehow with Slicer or just have them in an independent system browser?

---

<div class="post-metadata">

**Author:** ![muratmaga](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/muratmaga/32/3622_2.png) [@muratmaga](https://discourse.slicer.org/u/muratmaga)\
**Post date:** [January 10, 2025, 9:32pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/3 "2025-01-10T21:32:24Z")

</div>

This is sort of what I want to, when I choose SlicerMorph-\>Tutorials from the module panel, this page shows up like this:

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/b/3/b3e4b3ff0cf32da75e34de6b52c71a341f367cf2.png)

Then clicking on a link, opens the tutorial in the system registered web browser.

I am not interested in offline availability or want to use the internal browser.

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [January 10, 2025, 9:47pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/4 "2025-01-10T21:47:33Z")

</div>

If you are using the external browser I think it would be much easier just to open the readme page in the external browser. So you would just open that from a button in Slicer. Otherwise you’l be messing with getting the rendered markdown into a Slicer widget and handling links, which can be done (most easily with a webwidget) but it doesn’t look like it buys you much.

---

<div class="post-metadata">

**Author:** ![muratmaga](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/muratmaga/32/3622_2.png) [@muratmaga](https://discourse.slicer.org/u/muratmaga)\
**Post date:** [January 10, 2025, 9:50pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/5 "2025-01-10T21:50:27Z")

</div>

That means you need

> [@pieper](#):
>
> open the readme page in the external browser.

true, but that means you know the URL before hand. Point of this is increasing the discoverability of the content.

---

<div class="post-metadata">

**Author:** ![muratmaga](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/muratmaga/32/3622_2.png) [@muratmaga](https://discourse.slicer.org/u/muratmaga)\
**Post date:** [January 10, 2025, 10:00pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/6 "2025-01-10T22:00:27Z")

</div>

For example. I can have convert the README.MD to html via tool, and dump it in the `self.parent.helpText =` field, which gives me this. But I want this to be in the module panel, and not the help field which is almost always overlooked.

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/b/8/b8469a6f0438116b77355fe4c3bb2a7d9ee12bdd.png)

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [January 10, 2025, 10:03pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/7 "2025-01-10T22:03:59Z")

</div>

yes, that’s what I was would be the easiest, just to use an html widget in Slicer (could be a full web widget or just a simpler html render) but you need to integrate a markdown to html converter somewhere, either in slicer or in your build process or fetch the html from github when you open the module.

---

<div class="post-metadata">

**Author:** ![muratmaga](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/muratmaga/32/3622_2.png) [@muratmaga](https://discourse.slicer.org/u/muratmaga)\
**Post date:** [January 10, 2025, 10:09pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/8 "2025-01-10T22:09:20Z")

</div>

Supposedly QT support markdown? [QTextEdit Class | Qt Widgets 5.15.18](https://doc.qt.io/qt-5/qtextedit.html#markdown-prop)

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [January 10, 2025, 10:21pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/9 "2025-01-10T22:21:08Z")

</div>

I didn’t know about that and it might work, but remember there are ‘[flavors](https://gist.github.com/vimtaai/99f8c89e7d3d02a362117284684baa0f)’ of markdown and that could bite you at some point (looks like Qt supports a basic one). In any case you can get the contents either at build time or run time.

---

<div class="post-metadata">

**Author:** ![muratmaga](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/muratmaga/32/3622_2.png) [@muratmaga](https://discourse.slicer.org/u/muratmaga)\
**Post date:** [January 10, 2025, 10:30pm UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/10 "2025-01-10T22:30:16Z")

</div>

> [@pieper](#):
>
> there are ‘[flavors](https://gist.github.com/vimtaai/99f8c89e7d3d02a362117284684baa0f)’ of markdown and that could bite you at some point

True. But I think we use a very minimal and fairly standard subset on that Readme.  
Mostly heading levels #, ##, ###, emphasis (\*\*), and link.

---

<div class="post-metadata">

**Author:** ![muratmaga](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/muratmaga/32/3622_2.png) [@muratmaga](https://discourse.slicer.org/u/muratmaga)\
**Post date:** [January 11, 2025, 4:12am UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/11 "2025-01-11T04:12:00Z")

</div>

I used Bing Chat to build the module. Seems to work, but can’t quite get it to use the full height of the module panel

```auto
import os
import vtk, qt, ctk, slicer
from slicer.ScriptedLoadableModule import *
import logging
import mistune
import requests
import webbrowser

class SlicerMorphTutorials(ScriptedLoadableModule):

    def __init__ (self, parent):
        ScriptedLoadableModule. __init__ (self, parent)
        self.parent.title = "SlicerMorph Tutorials"
        self.parent.categories = ["Examples"]
        self.parent.dependencies = []
        self.parent.contributors = ["Your Name (Your Institution)"]
        self.parent.helpText = """This is an example of a scripted module that displays Markdown text in a QTextBrowser."""
        self.parent.acknowledgementText = """This file was originally developed by Your Name, Your Institution."""

class SlicerMorphTutorialsWidget(ScriptedLoadableModuleWidget):

    def setup(self):
        ScriptedLoadableModuleWidget.setup(self)

        # URL of the Markdown file
        markdown_url = "https://raw.githubusercontent.com/SlicerMorph/Tutorials/main/README.md"

        # Fetch the Markdown content
        response = requests.get(markdown_url)
        markdown_text = response.text

        # Create a Markdown renderer
        renderer = mistune.create_markdown()

        # Convert Markdown to HTML
        html_content = renderer(markdown_text)

        # Add some basic styling for better display
        styled_html_content = f"""
        <html>
        <head>
        <style>
        body {{ font-family: Arial, sans-serif; }}
        h1 {{ color: #333; }}
        ul {{ list-style-type: disc; padding-left: 20px; }}
        li {{ margin: 5px 0; }}
        </style>
        </head>
        <body>
        {html_content}
        </body>
        </html>
        """

        # Create a QTextBrowser widget
        self.textWidget = qt.QTextBrowser()
        self.textWidget.setReadOnly(True)
        self.textWidget.setOpenExternalLinks(True) # Ensure external links open in the default web browser

        # Set the styled HTML content in the QTextBrowser widget
        self.textWidget.setHtml(styled_html_content)

        # Create a vertical layout for the widget
        layout = qt.QVBoxLayout()

        # Add the QTextBrowser widget with full stretch factor
        layout.addWidget(self.textWidget)

        # Set the layout for the module
        self.layout.addLayout(layout)

    def cleanup(self):
        pass

class SlicerMorphTutorialsLogic(ScriptedLoadableModuleLogic):
    pass

class SlicerMorphTutorialsTest(ScriptedLoadableModuleTest):
    def runTest(self):
        self.setUp()
        self.test_SlicerMorphTutorials1()

    def test_SlicerMorphTutorials1(self):
        self.delayDisplay("Starting the test")
        self.delayDisplay('Test passed!')

```

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/f/4/f47b1b88726cdc6f54390d4dfde997183c6a55d1.png)

---

<div class="post-metadata">

**Author:** ![Thibault\_Pelletier](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/thibault_pelletier/32/4767_2.png) [@Thibault\_Pelletier](https://discourse.slicer.org/u/Thibault_Pelletier)\
**Post date:** [January 13, 2025, 7:55am UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/12 "2025-01-13T07:55:21Z")

</div>

If you want to package the exact version of the tutorial the module was built with, it may be worthwhile to package the sphinx HTML documentation directly with the module during the build / install step in the CI. (it would also be useful for offline usage).

For the height of the widget, maybe changing the size policy to MinimumExpanding could help.

---

<div class="post-metadata">

**Author:** ![shai-ikko](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shai-ikko/32/15765_2.png) [@shai-ikko](https://discourse.slicer.org/u/shai-ikko)\
**Post date:** [January 13, 2025, 9:14am UTC](https://discourse.slicer.org/t/inline-documentation-options/41032/13 "2025-01-13T09:14:13Z")

</div>

Python stdlib has a module called “webbrowser”. You can do this:

```python
import webbrowser
webbrowser.open("https://slicer.org")

```

and it opens a web page in your external browser. This works from within Slicer (for me on Linux, but I expect elsewhere too), so you could trigger that from a button in your module. The users don’t need to know the URL in advance.

I thought this was what @pieper meant in the message you replied to.
