How to show dialogs at a certain position inside a QScintilla widget?
<p>I got this simple piece of mcve code:</p>

<pre><code>import sys
import re

from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.Qsci import QsciScintilla
from PyQt5 import Qsci


class SimpleEditor(QsciScintilla):

    def __init__(self, language=None, parent=None):
        super().__init__(parent)

        font = QtGui.QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)
        fontmetrics = QtGui.QFontMetrics(font)
        self.setMarginsFont(font)
        self.setMarginWidth(0, fontmetrics.width("00000") + 6)
        self.setMarginLineNumbers(0, True)
        self.setMarginsBackgroundColor(QtGui.QColor("#cccccc"))
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QtGui.QColor("#E8E8FF"))

        if language:
            self.lexer = getattr(Qsci, 'QsciLexer' + language)()
            self.setLexer(self.lexer)

        self.SendScintilla(QsciScintilla.SCI_FOLDALL, True)
        self.setAutoCompletionThreshold(1)
        self.setAutoCompletionSource(QsciScintilla.AcsAPIs)
        self.setFolding(QsciScintilla.BoxedTreeFoldStyle)

        # Signals/Slots
        self.cursorPositionChanged.connect(self.on_cursor_position_changed)
        self.copyAvailable.connect(self.on_copy_available)
        self.indicatorClicked.connect(self.on_indicator_clicked)
        self.indicatorReleased.connect(self.on_indicator_released)
        self.linesChanged.connect(self.on_lines_changed)
        self.marginClicked.connect(self.on_margin_clicked)
        self.modificationAttempted.connect(self.on_modification_attempted)
        self.modificationChanged.connect(self.on_modification_changed)
        self.selectionChanged.connect(self.on_selection_changed)
        self.textChanged.connect(self.on_text_changed)
        self.userListActivated.connect(self.on_user_list_activated)

    def on_cursor_position_changed(self, line, index):
        print("on_cursor_position_changed")

    def on_copy_available(self, yes):
        print('-' * 80)
        print("on_copy_available")

    def on_indicator_clicked(self, line, index, state):
        print("on_indicator_clicked")

    def on_indicator_released(self, line, index, state):
        print("on_indicator_released")

    def on_lines_changed(self):
        print("on_lines_changed")

    def on_margin_clicked(self, margin, line, state):
        print("on_margin_clicked")

    def on_modification_attempted(self):
        print("on_modification_attempted")

    def on_modification_changed(self):
        print("on_modification_changed")

    def on_selection_changed(self):
        print("on_selection_changed")

    def on_text_changed(self):
        print("on_text_changed")

    def on_user_list_activated(self, id, text):
        print("on_user_list_activated")


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    ex = QtWidgets.QWidget()
    hlayout = QtWidgets.QHBoxLayout()
    ed = SimpleEditor("JavaScript")

    hlayout.addWidget(ed)

    ed.setText("""#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : enable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

void main( void ) {

    vec2 st = ( gl_FragCoord.xy / resolution.xy );
    vec2 lefbot = step(vec2(0.1), st);
    float pct = lefbot.x*lefbot.y;
    vec2 rigtop = step(vec2(0.1), 1.-st);
    pct *= rigtop.x*rigtop.y;
    vec3 color = vec3(pct);

    gl_FragColor = vec4( color, 1.0 );""")

    ex.setLayout(hlayout)
    ex.show()
    ex.resize(800, 600)

    sys.exit(app.exec_())
</code></pre>

<p>I'm trying to code a similar solution to the one provided on this <a href="https://www.khanacademy.org/computer-programming/tree-generator/822944839" rel="nofollow">site</a>. As you can see, on that site the user can tweak numeric values only by clicking over, when they do so a little dialog will appear and the user will be able to change values in realtime. </p>

<p>Now, the first thing I need to figure out is which are the signals I need to consider when the user click on the QScintilla widget (I'm using these <a href="http://pyqt.sourceforge.net/Docs/QScintilla2/classQsciScintilla.html" rel="nofollow">docs</a>). Which is/are the one/s I should really care about it.</p>

<p>In any case, assuming I use the right signal to popup my dialog containing some sliders, how could i figure out the right position where my dialog should appear?</p>

<p>The <code>cursorPositionChanged</code> signal can be used to detect whenever the mouse or keyboard moves the caret to a position within a number. A regexp can then be used to find where the number starts and ends on the current line. Once you have that, you can use some low-level functions to calculate the global position of the number.</p>

<p>The method below uses that approach to show a tooltip below the relevant text:</p>

<pre><code>def on_cursor_position_changed(self, line, index):
    text = self.text(line)
    for match in re.finditer('(?:^|(?&lt;=\W))\d+(?:\.\d+)?(?=$|\W)', text):
        start, end = match.span()
        if start &lt;= index &lt;= end:
            pos = self.positionFromLineIndex(line, start)
            x = self.SendScintilla(
                QsciScintilla.SCI_POINTXFROMPOSITION, 0, pos)
            y = self.SendScintilla(
                QsciScintilla.SCI_POINTYFROMPOSITION, 0, pos)
            point = self.mapToGlobal(QtCore.QPoint(x, y))
            num = float(match.group())
            message = 'number: %s' % num
            break
    else:
        point = QtCore.QPoint(0, 0)
        message = ''
    QtWidgets.QToolTip.showText(point, message)
</code></pre>

python pyqt qscintilla