Fixed issue were click events were not working on Windows - test 1

This commit is contained in:
Paul Ebbers 2025-01-10 18:59:39 +01:00
parent 38b68fe3d7
commit adc14d0155
2 changed files with 109 additions and 63 deletions

View File

@ -1,24 +1,59 @@
import FreeCADGui as Gui # just used for FreeCADGui.updateGui()
import os import os
from PySide import QtGui
from PySide import QtCore from PySide.QtCore import (
import FreeCADGui # just used for FreeCADGui.updateGui() Qt,
SIGNAL,
QSize,
QIdentityProxyModel,
QPoint,
)
from PySide.QtWidgets import (
QTabWidget,
QSlider,
QSpinBox,
QCheckBox,
QComboBox,
QLabel,
QTabWidget,
QSizePolicy,
QPushButton,
QLineEdit,
QTextEdit,
QListView,
QAbstractItemView,
QWidget,
QVBoxLayout,
QApplication,
QListWidget,
)
from PySide.QtGui import (
QIcon,
QPixmap,
QColor,
QStandardItemModel,
QShortcut,
QKeySequence,
QStandardItem,
)
from SearchBoxLight import SearchBoxLight from SearchBoxLight import SearchBoxLight
import Parameters_SearchBar as Parameters import Parameters_SearchBar as Parameters
genericToolIcon = QtGui.QIcon(QtGui.QIcon(Parameters.genericToolIcon_Pixmap)) genericToolIcon = QIcon(Parameters.genericToolIcon_Pixmap)
globalIgnoreFocusOut = False globalIgnoreFocusOut = False
def easyToolTipWidget(html): def easyToolTipWidget(html):
foo = QtGui.QTextEdit() foo = QTextEdit()
foo.setReadOnly(True) foo.setReadOnly(True)
foo.setAlignment(QtCore.Qt.AlignTop) foo.setAlignment(Qt.AlignmentFlag.AlignTop)
foo.setText(html) foo.setText(html)
return foo return foo
class SearchBox(QtGui.QLineEdit): class SearchBox(QLineEdit):
# The following block of code is present in the lightweight proxy SearchBoxLight # The following block of code is present in the lightweight proxy SearchBoxLight
""" """
resultSelected = QtCore.Signal(int, int) resultSelected = QtCore.Signal(int, int)
@ -39,8 +74,8 @@ class SearchBox(QtGui.QLineEdit):
# Connect signals and slots # Connect signals and slots
self.textChanged.connect(self.filterModel) self.textChanged.connect(self.filterModel)
# Thanks to https://saurabhg.com/programming/search-box-using-qlineedit/ for indicating a few useful options # Thanks to https://saurabhg.com/programming/search-box-using-qlineedit/ for indicating a few useful options
ico = QtGui.QIcon(':/icons/help-browser.svg') ico = QIcon(':/icons/help-browser.svg')
#ico = QtGui.QIcon(':/icons/WhatsThis.svg') #ico = QIcon(':/icons/WhatsThis.svg')
self.addAction(ico, QtGui.QLineEdit.LeadingPosition) self.addAction(ico, QtGui.QLineEdit.LeadingPosition)
self.setClearButtonEnabled(True) self.setClearButtonEnabled(True)
self.setPlaceholderText('Search tools, prefs & tree') self.setPlaceholderText('Search tools, prefs & tree')
@ -54,25 +89,26 @@ class SearchBox(QtGui.QLineEdit):
self.itemGroups = None # Will be initialized by calling getItemGroups() the first time the search box gains focus, through focusInEvent and refreshItemGroups self.itemGroups = None # Will be initialized by calling getItemGroups() the first time the search box gains focus, through focusInEvent and refreshItemGroups
self.maxVisibleRows = maxVisibleRows # TODO: use this to compute the correct height self.maxVisibleRows = maxVisibleRows # TODO: use this to compute the correct height
# Create proxy model # Create proxy model
self.proxyModel = QtCore.QIdentityProxyModel() self.proxyModel = QIdentityProxyModel()
# Filtered model to which items are manually added. Store it as a property of the object instead of a local variable, to prevent grbage collection. # Filtered model to which items are manually added. Store it as a property of the object instead of a local variable, to prevent grbage collection.
self.mdl = QtGui.QStandardItemModel() self.mdl = QStandardItemModel()
# self.proxyModel.setModel(self.model) # self.proxyModel.setModel(self.model)
# Create list view # Create list view
self.listView = QtGui.QListView(self) self.listView = QListView(self)
self.listView.setWindowFlags(QtGui.Qt.ToolTip) self.listView.setWindowFlags(Qt.WindowType.ToolTip)
self.listView.setWindowFlag(QtGui.Qt.FramelessWindowHint) self.listView.setWindowFlag(Qt.WindowType.FramelessWindowHint)
self.listView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.listView.setSelectionMode(self.listView.SelectionMode.SingleSelection)
self.listView.setModel(self.proxyModel) self.listView.setModel(self.proxyModel)
self.listView.setItemDelegate(getItemDelegate()) # https://stackoverflow.com/a/65930408/324969 self.listView.setItemDelegate(getItemDelegate()) # https://stackoverflow.com/a/65930408/324969
self.listView.setMouseTracking(True)
# make the QListView non-editable # make the QListView non-editable
self.listView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.listView.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
# Create pane for showing extra info about the currently-selected tool # Create pane for showing extra info about the currently-selected tool
# self.extraInfo = QtGui.QLabel() # self.extraInfo = QtGui.QLabel()
self.extraInfo = QtGui.QWidget() self.extraInfo = QWidget()
self.extraInfo.setWindowFlags(QtGui.Qt.ToolTip) self.extraInfo.setWindowFlags(Qt.WindowType.ToolTip)
self.extraInfo.setWindowFlag(QtGui.Qt.FramelessWindowHint) self.extraInfo.setWindowFlag(Qt.WindowType.FramelessWindowHint)
self.extraInfo.setLayout(QtGui.QVBoxLayout()) self.extraInfo.setLayout(QVBoxLayout())
self.extraInfo.layout().setContentsMargins(0, 0, 0, 0) self.extraInfo.layout().setContentsMargins(0, 0, 0, 0)
self.setExtraInfoIsActive = False self.setExtraInfoIsActive = False
self.pendingExtraInfo = None self.pendingExtraInfo = None
@ -80,40 +116,32 @@ class SearchBox(QtGui.QLineEdit):
# Connect signals and slots # Connect signals and slots
self.listView.clicked.connect(lambda x: self.selectResult("select", x)) self.listView.clicked.connect(lambda x: self.selectResult("select", x))
self.listView.selectionModel().selectionChanged.connect(self.onSelectionChanged) self.listView.selectionModel().selectionChanged.connect(self.onSelectionChanged)
# Add custom mouse events. On windows the click events were not working for Searcbar versions 1.2.x and older.
# These events and their proxies in the SearchBorLight fixes this
self.listView.mousePressEvent = lambda event: self.proxyMousePressEvent(event)
self.listView.mouseMoveEvent = lambda event: self.proxyMouseMoveEvent(event)
# Note: should probably use the eventFilter method instead... # Note: should probably use the eventFilter method instead...
wdgctx = QtCore.Qt.ShortcutContext.WidgetShortcut wdgctx = Qt.ShortcutContext.WidgetShortcut
QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Down), self, context=wdgctx).activated.connect(self.listDown) QShortcut(QKeySequence(Qt.Key.Key_Down), self, context=wdgctx).activated.connect(self.listDown)
QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Up), self, context=wdgctx).activated.connect(self.listUp) QShortcut(QKeySequence(Qt.Key.Key_Up), self, context=wdgctx).activated.connect(self.listUp)
QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_PageDown), self, context=wdgctx).activated.connect( QShortcut(QKeySequence(Qt.Key.Key_PageDown), self, context=wdgctx).activated.connect(self.listPageDown)
self.listPageDown QShortcut(QKeySequence(Qt.Key.Key_PageUp), self, context=wdgctx).activated.connect(self.listPageUp)
)
QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_PageUp), self, context=wdgctx).activated.connect(
self.listPageUp
)
# Home and End do not work, for some reason. # Home and End do not work, for some reason.
# QtGui.QShortcut(QtGui.QKeySequence.MoveToEndOfDocument, self, context = wdgctx).activated.connect(self.listEnd) # QShortcut(QKeySequence.MoveToEndOfDocument, self, context = wdgctx).activated.connect(self.listEnd)
# QtGui.QShortcut(QtGui.QKeySequence.MoveToStartOfDocument, self, context = wdgctx).activated.connect(self.listStart) # QShortcut(QKeySequence.MoveToStartOfDocument, self, context = wdgctx).activated.connect(self.listStart)
# QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_End), self, context = wdgctx).activated.connect(self.listEnd) # QShortcut(QKeySequence(Qt.Key.Key_End), self, context = wdgctx).activated.connect(self.listEnd)
# QtGui.QShortcut(QtGui.QKeySequence('Home'), self, context = wdgctx).activated.connect(self.listStart) # QShortcut(QKeySequence('Home'), self, context = wdgctx).activated.connect(self.listStart)
QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Enter), self, context=wdgctx).activated.connect( QShortcut(QKeySequence(Qt.Key.Key_Enter), self, context=wdgctx).activated.connect(self.listAccept)
self.listAccept QShortcut(QKeySequence(Qt.Key.Key_Return), self, context=wdgctx).activated.connect(self.listAccept)
) QShortcut(QKeySequence("Ctrl+Return"), self, context=wdgctx).activated.connect(self.listAcceptToggle)
QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Return), self, context=wdgctx).activated.connect( QShortcut(QKeySequence("Ctrl+Enter"), self, context=wdgctx).activated.connect(self.listAcceptToggle)
self.listAccept QShortcut(QKeySequence("Ctrl+Space"), self, context=wdgctx).activated.connect(self.listAcceptToggle)
)
QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Return"), self, context=wdgctx).activated.connect(
self.listAcceptToggle
)
QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Enter"), self, context=wdgctx).activated.connect(self.listAcceptToggle)
QtGui.QShortcut(QtGui.QKeySequence("Ctrl+Space"), self, context=wdgctx).activated.connect(self.listAcceptToggle)
QtGui.QShortcut(QtGui.QKeySequence(QtCore.Qt.Key_Escape), self, context=wdgctx).activated.connect( QShortcut(QKeySequence(Qt.Key.Key_Escape), self, context=wdgctx).activated.connect(self.listCancel)
self.listCancel
)
# Initialize the model with the full list (assuming the text() is empty) # Initialize the model with the full list (assuming the text() is empty)
# self.proxyFilterModel(self.text()) # This is done by refreshItemGroups on focusInEvent, because the initial loading from cache can take time # self.proxyFilterModel(self.text()) # This is done by refreshItemGroups on focusInEvent, because the initial loading from cache can take time
@ -121,6 +149,16 @@ class SearchBox(QtGui.QLineEdit):
self.isInitialized = True self.isInitialized = True
return self return self
@staticmethod
def proxyMousePressEvent(self, event):
self.selectResult(mode=None, index=self.listView.currentIndex())
return
@staticmethod
def proxyMouseMoveEvent(self, arg__1):
self.listView.setCurrentIndex(self.listView.indexAt(arg__1.pos()))
return
@staticmethod @staticmethod
def refreshItemGroups(self): def refreshItemGroups(self):
self.itemGroups = self.getItemGroups() self.itemGroups = self.getItemGroups()
@ -129,18 +167,18 @@ class SearchBox(QtGui.QLineEdit):
@staticmethod @staticmethod
def proxyFocusInEvent(self, qFocusEvent): def proxyFocusInEvent(self, qFocusEvent):
if self.firstShowList: if self.firstShowList:
mdl = QtGui.QStandardItemModel() mdl = QStandardItemModel()
mdl.appendRow( mdl.appendRow(
[ [
QtGui.QStandardItem(genericToolIcon, "Please wait, loading results from cache…"), QStandardItem(genericToolIcon, "Please wait, loading results from cache…"),
QtGui.QStandardItem("0"), QStandardItem("0"),
QtGui.QStandardItem("-1"), QStandardItem("-1"),
] ]
) )
self.proxyModel.setSourceModel(mdl) self.proxyModel.setSourceModel(mdl)
self.showList() self.showList()
self.firstShowList = False self.firstShowList = False
FreeCADGui.updateGui() Gui.updateGui()
global globalIgnoreFocusOut global globalIgnoreFocusOut
if not globalIgnoreFocusOut: if not globalIgnoreFocusOut:
self.refreshItemGroups() self.refreshItemGroups()
@ -192,6 +230,7 @@ class SearchBox(QtGui.QLineEdit):
@staticmethod @staticmethod
def acceptKey(self, mode): def acceptKey(self, mode):
print(f"Got here, {mode}")
currentIndex = self.listView.currentIndex() currentIndex = self.listView.currentIndex()
self.showList() self.showList()
if currentIndex.isValid(): if currentIndex.isValid():
@ -220,9 +259,9 @@ class SearchBox(QtGui.QLineEdit):
key = qKeyEvent.key() key = qKeyEvent.key()
modifiers = qKeyEvent.modifiers() modifiers = qKeyEvent.modifiers()
self.showList() self.showList()
if key == QtCore.Qt.Key_Home and modifiers & QtCore.Qt.CTRL != 0: if key == Qt.Key.Key_Home and modifiers & Qt.Key.CTRL != 0:
self.listStart() self.listStart()
elif key == QtCore.Qt.Key_End and modifiers & QtCore.Qt.CTRL != 0: elif key == Qt.Key.Key_End and modifiers & Qt.Key.CTRL != 0:
self.listEnd() self.listEnd()
else: else:
super(SearchBoxLight, self).keyPressEvent(qKeyEvent) super(SearchBoxLight, self).keyPressEvent(qKeyEvent)
@ -244,8 +283,9 @@ class SearchBox(QtGui.QLineEdit):
self.extraInfo.hide() self.extraInfo.hide()
@staticmethod @staticmethod
def selectResult(self, mode, index): def selectResult(self, mode: None, index):
groupId = int(index.model().itemData(index.siblingAtColumn(2))[0]) groupId = int(index.model().itemData(index.siblingAtColumn(2))[0])
print(f"Got here, {index}")
self.hideList() self.hideList()
# TODO: allow other options, e.g. some items could act as combinators / cumulative filters # TODO: allow other options, e.g. some items could act as combinators / cumulative filters
self.setText("") self.setText("")
@ -281,7 +321,7 @@ class SearchBox(QtGui.QLineEdit):
groups = (filterGroup(group) for group in groups) groups = (filterGroup(group) for group in groups)
return [group for group in groups if group is not None] return [group for group in groups if group is not None]
self.mdl = QtGui.QStandardItemModel() self.mdl = QStandardItemModel()
self.mdl.appendColumn([]) self.mdl.appendColumn([])
def addGroups(filteredGroups, depth=0): def addGroups(filteredGroups, depth=0):
@ -289,9 +329,9 @@ class SearchBox(QtGui.QLineEdit):
# TODO: this is not very clean, we should memorize the index from the original itemgroups # TODO: this is not very clean, we should memorize the index from the original itemgroups
self.mdl.appendRow( self.mdl.appendRow(
[ [
QtGui.QStandardItem(group["icon"] or genericToolIcon, group["text"]), QStandardItem(group["icon"] or genericToolIcon, group["text"]),
QtGui.QStandardItem(str(depth)), QStandardItem(str(depth)),
QtGui.QStandardItem(str(group["id"])), QStandardItem(str(group["id"])),
] ]
) )
addGroups(group["subitems"], depth + 1) addGroups(group["subitems"], depth + 1)
@ -314,12 +354,12 @@ class SearchBox(QtGui.QLineEdit):
def getScreenPosition(widget): def getScreenPosition(widget):
geo = widget.geometry() geo = widget.geometry()
parent = widget.parent() parent = widget.parent()
parentPos = getScreenPosition(parent) if parent is not None else QtCore.QPoint(0, 0) parentPos = getScreenPosition(parent) if parent is not None else QPoint(0, 0)
return QtCore.QPoint(geo.x() + parentPos.x(), geo.y() + parentPos.y()) return QPoint(geo.x() + parentPos.x(), geo.y() + parentPos.y())
pos = getScreenPosition(self) pos = getScreenPosition(self)
siz = self.size() siz = self.size()
screen = QtGui.QGuiApplication.screenAt(pos) screen = QApplication.screenAt(pos)
x = pos.x() x = pos.x()
y = pos.y() + siz.height() y = pos.y() + siz.height()
hint_w = self.listView.sizeHint().width() hint_w = self.listView.sizeHint().width()
@ -346,7 +386,7 @@ class SearchBox(QtGui.QLineEdit):
@staticmethod @staticmethod
def proxyOnSelectionChanged(self, selected, deselected): def proxyOnSelectionChanged(self, selected, deselected):
# The list has .setSelectionMode(QtGui.QAbstractItemView.SingleSelection), # The list has .setSelectionMode(QAbstractItemView.SingleSelection),
# so there is always at most one index in selected.indexes() and at most one # so there is always at most one index in selected.indexes() and at most one
# index in deselected.indexes() # index in deselected.indexes()
selected = selected.indexes() selected = selected.indexes()

View File

@ -41,6 +41,12 @@ class SearchBoxLight(QtGui.QLineEdit):
return types.MethodType(f, self) return types.MethodType(f, self)
def MousePressEvent(self, *args, **kwargs):
return self.proxyMousePressEvent(*args, **kwargs)
def MouseMoveEvent(self, *args, **kwargs):
return self.proxyMouseMoveEvent(*args, **kwargs)
def focusInEvent(self, *args, **kwargs): def focusInEvent(self, *args, **kwargs):
return self.proxyFocusInEvent(*args, **kwargs) return self.proxyFocusInEvent(*args, **kwargs)