Fixed issue were click events were not working on Windows - test 1
This commit is contained in:
parent
38b68fe3d7
commit
adc14d0155
166
SearchBox.py
166
SearchBox.py
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user