2

I got this simple piece of mcve 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_())

I'm trying to code a similar solution to the one provided on this site. 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.

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 docs). Which is/are the one/s I should really care about it.

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?

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
BPL
  • 9,632
  • 9
  • 59
  • 117
  • What is currently stopping you from starting to code it yourself? Questions on SO should focus on *one specifc programming problem* - otherwise it just looks like you're asking people to write all the code for you. – ekhumoro Sep 23 '16 at 13:18
  • @ekhumoro Ok, I've got my hands dirty with the task and I've edited my question to try to make it more specific, could you confirm me the format now is something more tractable? In addition, I've get rid of the whole bunch of my offtopic comments so the thread won't be polluted. Hope the question title/content are not broad anymore, pls let me know. Thanks. – BPL Sep 23 '16 at 15:08
  • Thank you for taking the trouble to improve your question. – ekhumoro Sep 23 '16 at 15:34

1 Answers1

3

The cursorPositionChanged 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.

The method below uses that approach to show a tooltip below the relevant text:

def on_cursor_position_changed(self, line, index):
    text = self.text(line)
    for match in re.finditer('(?:^|(?<=\W))\d+(?:\.\d+)?(?=$|\W)', text):
        start, end = match.span()
        if start <= index <= 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)
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Thanks a lot! That's more than good enough to get started. Next step will be creating the different widgets to handle all the different types the glsl language offers (float, vec2, vec3) and parse them properly. Btw, couple of additional fast questions, do you know why using `QtWidgets.QColorDialog.getColor()` instead QToolTip would give me a crash? Also, what's the best way to replace text on QScintilla? Anyway, thanks for your nice answer, really appreciated ;-) – BPL Sep 24 '16 at 20:24
  • @BPL. I think you'll have to post some new questions for those other issues. – ekhumoro Sep 24 '16 at 20:43