From 5916a8b5848e627a64e94553f47e277fca55ef5d Mon Sep 17 00:00:00 2001 From: alexhroom Date: Wed, 6 Nov 2024 15:57:40 +0000 Subject: [PATCH 1/6] added multiselect combobox --- pyproject.toml | 8 +- rascal2/widgets/inputs.py | 170 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 66a72b3..b470c74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,15 +36,21 @@ mark-parentheses = false # if overriding a PyQt method, please add it here! # names should be in alphabetical order for readability extend-ignore-names = ['allKeys', + 'addItem', + 'addItems', 'columnCount', 'createEditor', + 'eventFilter', 'headerData', 'mergeWith', + 'resizeEvent', 'rowCount', 'setData', 'setEditorData', 'setModelData', 'setValue', + 'showEvent', + 'sizeHint', 'stepBy', 'textFromValue', - 'valueFromText',] + 'valueFromText',] \ No newline at end of file diff --git a/rascal2/widgets/inputs.py b/rascal2/widgets/inputs.py index b360ed5..8aded3d 100644 --- a/rascal2/widgets/inputs.py +++ b/rascal2/widgets/inputs.py @@ -274,3 +274,173 @@ def validate(self, input_text, pos) -> tuple[QtGui.QValidator.State, str, int]: self.setDecimals(len(input_text.split(".")[-1])) return (QtGui.QValidator.State.Acceptable, input_text, pos) return super().validate(input_text, pos) + + +class MultiSelectComboBox(QtWidgets.QComboBox): + """ + A custom combo box widget that allows for multi-select functionality. + + This widget provides the ability to select multiple items from a + dropdown list and display them in a comma-separated format in the + combo box's line edit area. + + This is a simplified version of the combobox in + https://github.com/user0706/pyqt6-multiselect-combobox (MIT License) + + """ + + class Delegate(QtWidgets.QStyledItemDelegate): + def sizeHint(self, option, index): + size = super().sizeHint(option, index) + size.setHeight(20) + return size + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + + self.setEditable(True) + self.lineEdit().setReadOnly(True) + + self.setItemDelegate(MultiSelectComboBox.Delegate()) + + self.model().dataChanged.connect(self.update_text) + self.lineEdit().installEventFilter(self) + self.closeOnLineEditClick = False + self.view().viewport().installEventFilter(self) + + def resizeEvent(self, event) -> None: + """Resize event handler. + + Parameters + ---------- + event + The resize event. + + """ + self.update_text() + super().resizeEvent(event) + + def eventFilter(self, obj, event) -> bool: + """Event filter to handle mouse button release events. + + Parameters + ---------- + obj + The object emitting the event. + event + The event being emitted. + + Returns + ------- + bool + True if the event was handled, False otherwise. + + """ + if obj == self.lineEdit() and event.type() == QtCore.QEvent.Type.MouseButtonRelease: + if self.closeOnLineEditClick: + self.hidePopup() + timer = QtCore.QTimer() + timer.setSingleShot(True) + timer.timeout.connect(lambda: setattr(self, "closeOnLineEditClick", False)) + timer.start(100) + else: + self.showPopup() + self.closeOnLineEditClick = True + return True + if obj == self.view().viewport() and event.type() == QtCore.QEvent.Type.MouseButtonRelease: + index = self.view().indexAt(event.position().toPoint()) + item = self.model().itemFromIndex(index) + if item.checkState() == QtCore.Qt.CheckState.Checked: + item.setCheckState(QtCore.Qt.CheckState.Unchecked) + else: + item.setCheckState(QtCore.Qt.CheckState.Checked) + return True + return False + + def update_text(self) -> None: + """Update the displayed text based on selected items.""" + items = self.selected_items() + + if items: + text = ", ".join([str(i) for i in items]) + else: + text = "" + + metrics = QtGui.QFontMetrics(self.lineEdit().font()) + elided_text = metrics.elidedText(text, QtCore.Qt.TextElideMode.ElideRight, self.lineEdit().width()) + self.lineEdit().setText(elided_text) + + def addItem(self, text: str, data: str = None) -> None: + """Add an item to the combo box. + + Parameters + ---------- + text : str + The text to display. + data : str + The associated data. Default is None. + + """ + item = QtGui.QStandardItem() + item.setText(text) + item.setData(data or text) + item.setFlags(QtCore.Qt.ItemFlag.ItemIsEnabled | QtCore.Qt.ItemFlag.ItemIsUserCheckable) + item.setData(QtCore.Qt.CheckState.Unchecked, QtCore.Qt.ItemDataRole.CheckStateRole) + self.model().appendRow(item) + + def addItems(self, texts: list, data_list: list = None) -> None: + """Add multiple items to the combo box. + + Parameters + ---------- + texts : list + A list of items to add. + data_list : list + A list of associated data. Default is None. + + """ + data_list = data_list or [None] * len(texts) + for text, data in zip(texts, data_list): + self.addItem(text, data) + + def selected_items(self) -> list: + """Get the currently selected data. + + Returns + ------- + list + A list of currently selected data. + + """ + return [ + self.model().item(i).data() + for i in range(self.model().rowCount()) + if self.model().item(i).checkState() == QtCore.Qt.CheckState.Checked + ] + + def select_indices(self, indices: list) -> None: + """Set the selected items based on the provided indices. + + Parameters + ---------- + indexes : list + A list of indexes to select. + + """ + for i in range(self.model().rowCount()): + self.model().item(i).setCheckState( + QtCore.Qt.CheckState.Checked if i in indices else QtCore.Qt.CheckState.Unchecked + ) + self.update_text() + + def showEvent(self, event) -> None: + """Show event handler. + + Parameters + ---------- + event + The show event. + + """ + super().showEvent(event) + self.update_text() From c03bbbd02026546548f8ff5f2a25017e39f03715 Mon Sep 17 00:00:00 2001 From: alexhroom Date: Wed, 6 Nov 2024 16:04:03 +0000 Subject: [PATCH 2/6] added domains tab --- rascal2/widgets/delegates.py | 28 ++++++++++++++- rascal2/widgets/project/models.py | 55 +++++++++++++++++++++++++++--- rascal2/widgets/project/project.py | 6 ++-- 3 files changed, 81 insertions(+), 8 deletions(-) diff --git a/rascal2/widgets/delegates.py b/rascal2/widgets/delegates.py index d55be11..0f4a0bb 100644 --- a/rascal2/widgets/delegates.py +++ b/rascal2/widgets/delegates.py @@ -4,7 +4,7 @@ from PyQt6 import QtCore, QtGui, QtWidgets -from rascal2.widgets.inputs import AdaptiveDoubleSpinBox, get_validated_input +from rascal2.widgets.inputs import AdaptiveDoubleSpinBox, MultiSelectComboBox, get_validated_input class ValidatedInputDelegate(QtWidgets.QStyledItemDelegate): @@ -101,3 +101,29 @@ def setEditorData(self, editor: QtWidgets.QWidget, index): def setModelData(self, editor, model, index): data = editor.currentText() model.setData(index, data, QtCore.Qt.ItemDataRole.EditRole) + +class MultiSelectLayerDelegate(QtWidgets.QStyledItemDelegate): + """Item delegate for multiselecting layers.""" + + def __init__(self, project_widget, parent): + super().__init__(parent) + self.project_widget = project_widget + + def createEditor(self, parent, option, index): + widget = MultiSelectComboBox(parent) + + layers = self.project_widget.draft_project["layers"] + widget.addItems([layer.name for layer in layers]) + + current_layers = index.data(QtCore.Qt.ItemDataRole.DisplayRole) + widget.select_indices([i for i, layer in enumerate(layers) if layer in current_layers]) + + return widget + + def setEditorData(self, editor: MultiSelectComboBox, index): + data = index.data(QtCore.Qt.ItemDataRole.DisplayRole) + editor.select_indices([i for i, layer in enumerate(data) if layer in data]) + + def setModelData(self, editor, model, index): + data = editor.selected_items() + model.setData(index, data, QtCore.Qt.ItemDataRole.EditRole) diff --git a/rascal2/widgets/project/models.py b/rascal2/widgets/project/models.py index 408e565..d96fd71 100644 --- a/rascal2/widgets/project/models.py +++ b/rascal2/widgets/project/models.py @@ -8,7 +8,12 @@ from RATapi.utils.enums import Procedures from rascal2.config import path_for -from rascal2.widgets.delegates import ParametersDelegate, ValidatedInputDelegate, ValueSpinBoxDelegate +from rascal2.widgets.delegates import ( + MultiSelectLayerDelegate, + ParametersDelegate, + ValidatedInputDelegate, + ValueSpinBoxDelegate, +) class ClassListModel(QtCore.QAbstractTableModel): @@ -380,15 +385,21 @@ def set_absorption(self, absorption: bool): self.endResetModel() +class ContrastsModel(ClassListModel): + """Classlist model for Contrasts.""" + + def flags(self, index): + flags = super().flags(index) + if self.edit_mode: + flags |= QtCore.Qt.ItemFlag.ItemIsEditable + return flags + + class LayerFieldWidget(ProjectFieldWidget): """Project field widget for Layer objects.""" classlist_model = LayersModel - def __init__(self, field, parent): - super().__init__(field, parent) - self.project_widget = parent.parent - def set_item_delegates(self): for i in range(1, self.model.columnCount()): if i in [1, self.model.columnCount() - 1]: @@ -411,3 +422,37 @@ def set_absorption(self, absorption: bool): self.model.set_absorption(absorption) if self.model.edit_mode: self.edit() + + +class ContrastsModel(ClassListModel): + """Classlist model for Contrasts.""" + + def flags(self, index): + flags = super().flags(index) + if self.edit_mode: + flags |= QtCore.Qt.ItemFlag.ItemIsEditable + return flags + + +class DomainContrastWidget(ProjectFieldWidget): + """Subclass of field widgets for domain contrasts.""" + + classlist_model = ContrastsModel + + def __init__(self, field, parent): + super().__init__(field, parent) + self.project_widget = parent.parent + + + def update_model(self, classlist): + super().update_model(classlist) + + header = self.table.horizontalHeader() + header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeMode.Interactive) + header.setSectionResizeMode(2, QtWidgets.QHeaderView.ResizeMode.Stretch) + + def set_item_delegates(self): + self.table.setItemDelegateForColumn( + 1, ValidatedInputDelegate(self.model.item_type.model_fields["name"], self.table) + ) + self.table.setItemDelegateForColumn(2, MultiSelectLayerDelegate(self.project_widget, self.table)) diff --git a/rascal2/widgets/project/project.py b/rascal2/widgets/project/project.py index 908d18c..371ecc2 100644 --- a/rascal2/widgets/project/project.py +++ b/rascal2/widgets/project/project.py @@ -7,7 +7,7 @@ from RATapi.utils.enums import Calculations, Geometries, LayerModels from rascal2.config import path_for -from rascal2.widgets.project.models import LayerFieldWidget, ParameterFieldWidget, ProjectFieldWidget +from rascal2.widgets.project.models import DomainContrastWidget, LayerFieldWidget, ParameterFieldWidget, ProjectFieldWidget class ProjectWidget(QtWidgets.QWidget): @@ -38,7 +38,7 @@ def __init__(self, parent): "Data": [], "Backgrounds": [], "Contrasts": [], - "Domains": [], + "Domains": ["domain_ratios", "domain_contrasts"], } self.view_tabs = {} @@ -362,6 +362,8 @@ def __init__(self, fields: list[str], parent, edit_mode: bool = False): self.tables[field] = ParameterFieldWidget(field, self) elif field == "layers": self.tables[field] = LayerFieldWidget(field, self) + elif field == "domain_contrasts": + self.tables[field] = DomainContrastWidget(field, self) else: self.tables[field] = ProjectFieldWidget(field, self) layout.addWidget(self.tables[field]) From 48a0baea3096865738972cf93a9f817c3929dca3 Mon Sep 17 00:00:00 2001 From: alexhroom Date: Thu, 7 Nov 2024 09:55:25 +0000 Subject: [PATCH 3/6] added tests --- rascal2/widgets/__init__.py | 11 +++++++-- rascal2/widgets/project/models.py | 6 ++--- tests/widgets/project/test_models.py | 37 +++++++++++++++++++++++++++- tests/widgets/test_inputs.py | 17 ++++++++++++- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/rascal2/widgets/__init__.py b/rascal2/widgets/__init__.py index a4b7a05..2ed2d4f 100644 --- a/rascal2/widgets/__init__.py +++ b/rascal2/widgets/__init__.py @@ -1,6 +1,13 @@ from rascal2.widgets.controls import ControlsWidget -from rascal2.widgets.inputs import AdaptiveDoubleSpinBox, get_validated_input +from rascal2.widgets.inputs import AdaptiveDoubleSpinBox, MultiSelectComboBox, get_validated_input from rascal2.widgets.plot import PlotWidget from rascal2.widgets.terminal import TerminalWidget -__all__ = ["ControlsWidget", "AdaptiveDoubleSpinBox", "get_validated_input", "PlotWidget", "TerminalWidget"] +__all__ = [ + "ControlsWidget", + "AdaptiveDoubleSpinBox", + "get_validated_input", + "MultiSelectComboBox", + "PlotWidget", + "TerminalWidget", +] diff --git a/rascal2/widgets/project/models.py b/rascal2/widgets/project/models.py index d96fd71..a721b10 100644 --- a/rascal2/widgets/project/models.py +++ b/rascal2/widgets/project/models.py @@ -424,8 +424,8 @@ def set_absorption(self, absorption: bool): self.edit() -class ContrastsModel(ClassListModel): - """Classlist model for Contrasts.""" +class DomainsModel(ClassListModel): + """Classlist model for domain contrasts.""" def flags(self, index): flags = super().flags(index) @@ -437,7 +437,7 @@ def flags(self, index): class DomainContrastWidget(ProjectFieldWidget): """Subclass of field widgets for domain contrasts.""" - classlist_model = ContrastsModel + classlist_model = DomainsModel def __init__(self, field, parent): super().__init__(field, parent) diff --git a/tests/widgets/project/test_models.py b/tests/widgets/project/test_models.py index 9fdc455..38f67fc 100644 --- a/tests/widgets/project/test_models.py +++ b/tests/widgets/project/test_models.py @@ -9,6 +9,8 @@ import rascal2.widgets.inputs as inputs from rascal2.widgets.project.models import ( ClassListModel, + DomainContrastWidget, + DomainsModel, LayerFieldWidget, LayersModel, ParameterFieldWidget, @@ -34,7 +36,13 @@ class DataModel(pydantic.BaseModel, validate_assignment=True): @pytest.fixture def classlist(): """A test ClassList.""" - return RATapi.ClassList([DataModel(name="A", value=1), DataModel(name="B", value=6), DataModel(name="C", value=18)]) + return RATapi.ClassList( + [ + DataModel(name="A", value=1), + DataModel(name="B", value=6), + DataModel(name="C", value=18), + ] + ) @pytest.fixture @@ -56,6 +64,17 @@ def _classlist(protected_indices): return _classlist +@pytest.fixture +def domains_classlist(): + return RATapi.ClassList( + [ + RATapi.models.DomainContrast(name="A", model=["LA"]), + RATapi.models.DomainContrast(name="B", model=["LB", "LB2", "LB3"]), + RATapi.models.DomainContrast(name="C", model=["LC", "LC2"]), + ] + ) + + @pytest.fixture def param_model(param_classlist): def _param_model(protected_indices): @@ -353,3 +372,19 @@ def test_layer_widget_delegates(init_class): for i, header in enumerate(widget.model.headers): assert isinstance(widget.table.itemDelegateForColumn(i + 1), expected_delegates[header]) + +@pytest.mark.parametrize("edit_mode", [True, False]) +def test_domains_model_flags(edit_mode, domains_classlist): + """Test that the DomainsModel flags are set correctly.""" + model = DomainsModel(domains_classlist, parent) + model.edit_mode = edit_mode + for row in [0, 1, 2]: + for column in [1, 2]: + assert bool(model.flags(model.index(row, column)) & QtCore.Qt.ItemFlag.ItemIsEditable) == edit_mode + +def test_domains_widget_item_delegates(domains_classlist): + """Test that the domains widget has the expected item delegates.""" + widget = DomainContrastWidget("Test", parent) + widget.update_model(domains_classlist) + assert isinstance(widget.table.itemDelegateForColumn(1), delegates.ValidatedInputDelegate) + assert isinstance(widget.table.itemDelegateForColumn(2), delegates.MultiSelectLayerDelegate) diff --git a/tests/widgets/test_inputs.py b/tests/widgets/test_inputs.py index 8d4b203..33aeefa 100644 --- a/tests/widgets/test_inputs.py +++ b/tests/widgets/test_inputs.py @@ -6,7 +6,7 @@ from pydantic.fields import FieldInfo from PyQt6 import QtWidgets -from rascal2.widgets import AdaptiveDoubleSpinBox, get_validated_input +from rascal2.widgets import AdaptiveDoubleSpinBox, MultiSelectComboBox, get_validated_input class MyEnum(StrEnum): @@ -39,3 +39,18 @@ def test_adaptive_spinbox(value, decimals): spinbox = AdaptiveDoubleSpinBox() spinbox.validate(value, 0) assert spinbox.decimals() == decimals + + +@pytest.mark.parametrize("selected", ([], [1], [0, 2])) +def test_multi_select_update(selected): + """Test that the selected data updates correctly.""" + combobox = MultiSelectComboBox() + assert combobox.lineEdit().text() == "" + assert combobox.selected_items() == [] + items = ["A", "B", "C"] + combobox.addItems(items) + + combobox.select_indices(selected) + expected_items = [items[i] for i in selected] + assert combobox.selected_items() == expected_items + assert combobox.lineEdit().text() == ", ".join(expected_items) From ece5a7a6cda3dc967f5598b04ff352621158d520 Mon Sep 17 00:00:00 2001 From: alexhroom Date: Mon, 11 Nov 2024 14:56:49 +0000 Subject: [PATCH 4/6] fixed domain contrast display --- rascal2/widgets/delegates.py | 12 +++++++----- rascal2/widgets/project/models.py | 7 ++++++- rascal2/widgets/project/project.py | 7 ++++++- tests/widgets/project/test_models.py | 2 ++ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/rascal2/widgets/delegates.py b/rascal2/widgets/delegates.py index 0f4a0bb..1ee48ae 100644 --- a/rascal2/widgets/delegates.py +++ b/rascal2/widgets/delegates.py @@ -102,6 +102,7 @@ def setModelData(self, editor, model, index): data = editor.currentText() model.setData(index, data, QtCore.Qt.ItemDataRole.EditRole) + class MultiSelectLayerDelegate(QtWidgets.QStyledItemDelegate): """Item delegate for multiselecting layers.""" @@ -115,14 +116,15 @@ def createEditor(self, parent, option, index): layers = self.project_widget.draft_project["layers"] widget.addItems([layer.name for layer in layers]) - current_layers = index.data(QtCore.Qt.ItemDataRole.DisplayRole) - widget.select_indices([i for i, layer in enumerate(layers) if layer in current_layers]) - return widget def setEditorData(self, editor: MultiSelectComboBox, index): - data = index.data(QtCore.Qt.ItemDataRole.DisplayRole) - editor.select_indices([i for i, layer in enumerate(data) if layer in data]) + # index.data produces the display string rather than the underlying data, + # so we split it back into a list here + data = index.data(QtCore.Qt.ItemDataRole.DisplayRole).split(", ") + layers = self.project_widget.draft_project["layers"] + + editor.select_indices([i for i, layer in enumerate(layers) if layer.name in data]) def setModelData(self, editor, model, index): data = editor.selected_items() diff --git a/rascal2/widgets/project/models.py b/rascal2/widgets/project/models.py index a721b10..47d1050 100644 --- a/rascal2/widgets/project/models.py +++ b/rascal2/widgets/project/models.py @@ -68,6 +68,8 @@ def data(self, index, role=QtCore.Qt.ItemDataRole.DisplayRole): # pyqt can't automatically coerce enums to strings... if isinstance(data, Enum): return str(data) + if isinstance(data, list): + return ", ".join(data) return data elif role == QtCore.Qt.ItemDataRole.CheckStateRole and self.index_header(index) == "fit": return QtCore.Qt.CheckState.Checked if data else QtCore.Qt.CheckState.Unchecked @@ -400,6 +402,10 @@ class LayerFieldWidget(ProjectFieldWidget): classlist_model = LayersModel + def __init__(self, field, parent): + super().__init__(field, parent) + self.project_widget = parent.parent + def set_item_delegates(self): for i in range(1, self.model.columnCount()): if i in [1, self.model.columnCount() - 1]: @@ -443,7 +449,6 @@ def __init__(self, field, parent): super().__init__(field, parent) self.project_widget = parent.parent - def update_model(self, classlist): super().update_model(classlist) diff --git a/rascal2/widgets/project/project.py b/rascal2/widgets/project/project.py index 371ecc2..37014f6 100644 --- a/rascal2/widgets/project/project.py +++ b/rascal2/widgets/project/project.py @@ -7,7 +7,12 @@ from RATapi.utils.enums import Calculations, Geometries, LayerModels from rascal2.config import path_for -from rascal2.widgets.project.models import DomainContrastWidget, LayerFieldWidget, ParameterFieldWidget, ProjectFieldWidget +from rascal2.widgets.project.models import ( + DomainContrastWidget, + LayerFieldWidget, + ParameterFieldWidget, + ProjectFieldWidget, +) class ProjectWidget(QtWidgets.QWidget): diff --git a/tests/widgets/project/test_models.py b/tests/widgets/project/test_models.py index 38f67fc..b011a34 100644 --- a/tests/widgets/project/test_models.py +++ b/tests/widgets/project/test_models.py @@ -373,6 +373,7 @@ def test_layer_widget_delegates(init_class): for i, header in enumerate(widget.model.headers): assert isinstance(widget.table.itemDelegateForColumn(i + 1), expected_delegates[header]) + @pytest.mark.parametrize("edit_mode", [True, False]) def test_domains_model_flags(edit_mode, domains_classlist): """Test that the DomainsModel flags are set correctly.""" @@ -382,6 +383,7 @@ def test_domains_model_flags(edit_mode, domains_classlist): for column in [1, 2]: assert bool(model.flags(model.index(row, column)) & QtCore.Qt.ItemFlag.ItemIsEditable) == edit_mode + def test_domains_widget_item_delegates(domains_classlist): """Test that the domains widget has the expected item delegates.""" widget = DomainContrastWidget("Test", parent) From abca1da3eb06ed5ee58156df48ec3fba4f3788ac Mon Sep 17 00:00:00 2001 From: alexhroom Date: Wed, 20 Nov 2024 09:48:07 +0000 Subject: [PATCH 5/6] hid domain contrasts when not standard layers and moved tab --- rascal2/widgets/project/project.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rascal2/widgets/project/project.py b/rascal2/widgets/project/project.py index 37014f6..5ebd21c 100644 --- a/rascal2/widgets/project/project.py +++ b/rascal2/widgets/project/project.py @@ -42,8 +42,8 @@ def __init__(self, parent): "Layers": ["layers"], "Data": [], "Backgrounds": [], - "Contrasts": [], "Domains": ["domain_ratios", "domain_contrasts"], + "Contrasts": [], } self.view_tabs = {} @@ -262,11 +262,13 @@ def handle_tabs(self) -> None: self.project_tab.setTabVisible(domain_tab_index, is_domains) self.edit_project_tab.setTabVisible(domain_tab_index, is_domains) - # the layers tab should only be visible in standard layers + # the layers tab and domain contrasts table should only be visible in standard layers layers_tab_index = list(self.view_tabs).index("Layers") is_layers = self.model_combobox.currentText() == LayerModels.StandardLayers self.project_tab.setTabVisible(layers_tab_index, is_layers) self.edit_project_tab.setTabVisible(layers_tab_index, is_layers) + self.view_tabs["Domains"].tables["domain_contrasts"].setVisible(is_layers) + self.edit_tabs["Domains"].tables["domain_contrasts"].setVisible(is_layers) def handle_controls_update(self): """Handle updates to Controls that need to be reflected in the project.""" From 2e0ff2d3e7e4a7fef15170341543e5d018abf81d Mon Sep 17 00:00:00 2001 From: alexhroom Date: Wed, 27 Nov 2024 12:29:55 +0000 Subject: [PATCH 6/6] review fixes --- rascal2/widgets/inputs.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/rascal2/widgets/inputs.py b/rascal2/widgets/inputs.py index 8aded3d..45f73e6 100644 --- a/rascal2/widgets/inputs.py +++ b/rascal2/widgets/inputs.py @@ -305,7 +305,6 @@ def __init__(self, *args, **kwargs) -> None: self.model().dataChanged.connect(self.update_text) self.lineEdit().installEventFilter(self) - self.closeOnLineEditClick = False self.view().viewport().installEventFilter(self) def resizeEvent(self, event) -> None: @@ -336,17 +335,6 @@ def eventFilter(self, obj, event) -> bool: True if the event was handled, False otherwise. """ - if obj == self.lineEdit() and event.type() == QtCore.QEvent.Type.MouseButtonRelease: - if self.closeOnLineEditClick: - self.hidePopup() - timer = QtCore.QTimer() - timer.setSingleShot(True) - timer.timeout.connect(lambda: setattr(self, "closeOnLineEditClick", False)) - timer.start(100) - else: - self.showPopup() - self.closeOnLineEditClick = True - return True if obj == self.view().viewport() and event.type() == QtCore.QEvent.Type.MouseButtonRelease: index = self.view().indexAt(event.position().toPoint()) item = self.model().itemFromIndex(index)