--- a/QScintilla/QsciScintillaCompat.py Thu May 24 19:16:36 2018 +0200 +++ b/QScintilla/QsciScintillaCompat.py Sun May 27 11:32:01 2018 +0200 @@ -9,9 +9,9 @@ from __future__ import unicode_literals -from PyQt5.QtCore import pyqtSignal, Qt -from PyQt5.QtGui import QPalette, QColor -from PyQt5.QtWidgets import QApplication +from PyQt5.QtCore import pyqtSignal, Qt, QPoint +from PyQt5.QtGui import QPalette, QColor, QFontMetrics +from PyQt5.QtWidgets import QApplication, QListWidget from PyQt5.Qsci import QsciScintillaBase, QsciScintilla, \ QSCINTILLA_VERSION as QSCIQSCINTILLA_VERSION @@ -75,6 +75,12 @@ self.userListActivated.connect(self.__completionListSelected) self.modificationChanged.connect(self.__modificationChanged) + + self.maxLines = 5 + self.maxChars = 40 + # Adjust the min. size of the autocomplete list box for short strings. + # Otherwise the width of the list box is at least the standard width. + self.SendScintilla(QsciScintilla.SCI_AUTOCSETMAXWIDTH, 5) def __modificationChanged(self, m): """ @@ -1459,28 +1465,114 @@ ## replacements for buggy methods ########################################################################### - if "showUserList" not in QsciScintilla.__dict__: - def showUserList(self, listId, lst): - """ - Public method to show a user supplied list. - - @param listId id of the list (integer) - @param lst list to be show (list of strings) - """ - if listId <= 0: - return - - self.SendScintilla( - QsciScintilla.SCI_AUTOCSETSEPARATOR, - ord(self.UserSeparator)) - self.SendScintilla( - QsciScintilla.SCI_USERLISTSHOW, listId, - self._encodeString(self.UserSeparator.join(lst))) + def showUserList(self, listId, lst): + """ + Public method to show a user supplied list. + + @param listId id of the list (integer) + @param lst list to be show (list of strings) + """ + if listId <= 0: + return + + # Setup seperator for user lists + self.SendScintilla( + QsciScintilla.SCI_AUTOCSETSEPARATOR, ord(self.UserSeparator)) + self.SendScintilla( + QsciScintilla.SCI_USERLISTSHOW, listId, + self._encodeString(self.UserSeparator.join(lst))) + + self.updateUserListSize() + + def autoCompleteFromDocument(self): + """ + Public method to resize list box after creation. + """ + super(QsciScintillaCompat, self).autoCompleteFromDocument() + self.updateUserListSize() + + def autoCompleteFromAPIs(self): + """ + Public method to resize list box after creation. + """ + super(QsciScintillaCompat, self).autoCompleteFromAPIs() + self.updateUserListSize() + + def autoCompleteFromAll(self): + """ + Public method to resize list box after creation. + """ + super(QsciScintillaCompat, self).autoCompleteFromAll() + self.updateUserListSize() ########################################################################### ## work-arounds for buggy behavior ########################################################################### + def updateUserListSize(self): + """ + Public method to resize the autocompletion list to fit with contents. + """ + childs = self.findChildren(QListWidget) + if not childs: + return + + ch = childs[-1] + geom = ch.geometry() + + baseHeight = geom.height() + + # Workaround for getting all items instead of ch.items() call with + # unknown mime types. + all_items = ch.findItems('', Qt.MatchStartsWith) + if not all_items: + return + + width = 0 + for item in all_items: + itemWidth = ch.visualItemRect(item).width() + if itemWidth > width: + width = itemWidth + + width += 4 # Borders + + itemHeight = ch.visualItemRect(all_items[0]).height() + height = min(self.maxLines, len(all_items)) * itemHeight + # Just a fiddling factor: 4 for the borders, 2 for better readability, + # e.g. underscores at the end of the list. + height += 6 + + sbSize = self.verticalScrollBar().sizeHint().width() + font = ch.font() + fm = QFontMetrics(font) + averageCharWidth = fm.averageCharWidth() + maxWidth = averageCharWidth * self.maxChars + if width > (maxWidth): + width = maxWidth + height += sbSize + # List box doesn't honor limited size to show scroll bars, e.g. + # Python 2 on Win 10. So just force it. + ch.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) + + if len(all_items) > self.maxLines: + width += sbSize + + # Special case, where the space below current line where to less + yPos = geom.y() + charPos = self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS) + currentYPos = self.SendScintilla( + QsciScintilla.SCI_POINTYFROMPOSITION, 0, charPos) + + # X position doesn't matter: set to 0 + globalPos = self.mapToGlobal(QPoint(0, currentYPos)) + if yPos < globalPos.y(): + deltaHeight = baseHeight - height + geom.setY(yPos + deltaHeight - 4) + + geom.setWidth(width) + geom.setHeight(height) + ch.setGeometry(geom) + def __completionListSelected(self, listId, txt): """ Private slot to handle the selection from the completion list.