Addon Manager: Refactor main GUI area
This commit is contained in:
22
src/Mod/AddonManager/Widgets/CMakeLists.txt
Normal file
22
src/Mod/AddonManager/Widgets/CMakeLists.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
SET(AddonManagerWidget_SRCS
|
||||
__init__.py
|
||||
addonmanager_widget_filter_selector.py
|
||||
addonmanager_widget_search.py
|
||||
addonmanager_widget_top_bar.py
|
||||
addonmanager_widget_view_selector.py
|
||||
)
|
||||
|
||||
SOURCE_GROUP("" FILES ${AddonManagerWidget_SRCS})
|
||||
|
||||
ADD_CUSTOM_TARGET(AddonManagerWidget ALL
|
||||
SOURCES ${AddonManagerWidget_SRCS}
|
||||
)
|
||||
|
||||
fc_copy_sources(AddonManagerWidget "${CMAKE_BINARY_DIR}/Mod/AddonManager/Widgets" ${AddonManagerWidget_SRCS})
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
${AddonManagerWidget_SRCS}
|
||||
DESTINATION
|
||||
Mod/AddonManager/Widgets
|
||||
)
|
||||
0
src/Mod/AddonManager/Widgets/__init__.py
Normal file
0
src/Mod/AddonManager/Widgets/__init__.py
Normal file
@@ -0,0 +1,243 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2022-2024 FreeCAD Project Association *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, but *
|
||||
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
""" Defines a QWidget-derived class for displaying the view selection buttons. """
|
||||
|
||||
from enum import IntEnum
|
||||
|
||||
try:
|
||||
import FreeCAD
|
||||
|
||||
translate = FreeCAD.Qt.translate
|
||||
except ImportError:
|
||||
FreeCAD = None
|
||||
|
||||
def translate(_: str, text: str):
|
||||
return text
|
||||
|
||||
|
||||
# Get whatever version of PySide we can
|
||||
try:
|
||||
import PySide # Use the FreeCAD wrapper
|
||||
except ImportError:
|
||||
try:
|
||||
import PySide6 # Outside FreeCAD, try Qt6 first
|
||||
|
||||
PySide = PySide6
|
||||
except ImportError:
|
||||
import PySide2 # Fall back to Qt5 (if this fails, Python will kill this module's import)
|
||||
|
||||
PySide = PySide2
|
||||
|
||||
from PySide import QtCore, QtWidgets
|
||||
|
||||
|
||||
class FilterType(IntEnum):
|
||||
"""There are currently two sections in this drop down, for two different types of filters."""
|
||||
|
||||
PACKAGE_CONTENTS = 0
|
||||
INSTALLATION_STATUS = 1
|
||||
|
||||
|
||||
class StatusFilter(IntEnum):
|
||||
"""Predefined filters for status"""
|
||||
|
||||
ANY = 0
|
||||
INSTALLED = 1
|
||||
NOT_INSTALLED = 2
|
||||
UPDATE_AVAILABLE = 3
|
||||
|
||||
|
||||
class ContentFilter(IntEnum):
|
||||
"""Predefined filters for addon content type"""
|
||||
|
||||
ANY = 0
|
||||
WORKBENCH = 1
|
||||
MACRO = 2
|
||||
PREFERENCE_PACK = 3
|
||||
|
||||
|
||||
class Filter:
|
||||
def __init__(self):
|
||||
self.status_filter = StatusFilter.ANY
|
||||
self.content_filter = ContentFilter.ANY
|
||||
|
||||
|
||||
class WidgetFilterSelector(QtWidgets.QComboBox):
|
||||
"""A label and menu for selecting what sort of addons are displayed"""
|
||||
|
||||
filter_changed = QtCore.Signal(object) # technically, actually class Filter
|
||||
|
||||
def __init__(self, parent: QtWidgets.QWidget = None):
|
||||
super().__init__(parent)
|
||||
self.addon_type_index = 0
|
||||
self.installation_status_index = 0
|
||||
self._setup_ui()
|
||||
self._setup_connections()
|
||||
self.retranslateUi(None)
|
||||
self.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
|
||||
|
||||
def _setup_ui(self):
|
||||
self._build_menu()
|
||||
|
||||
def _build_menu(self):
|
||||
self.clear()
|
||||
self.addItem(translate("AddonsInstaller", "Filter by..."))
|
||||
self.insertSeparator(self.count())
|
||||
self.addItem(translate("AddonsInstaller", "Addon Type"))
|
||||
self.addon_type_index = self.count() - 1
|
||||
self.addItem(
|
||||
translate("AddonsInstaller", "Any"), (FilterType.PACKAGE_CONTENTS, ContentFilter.ANY)
|
||||
)
|
||||
self.addItem(
|
||||
translate("AddonsInstaller", "Workbench"),
|
||||
(FilterType.PACKAGE_CONTENTS, ContentFilter.WORKBENCH),
|
||||
)
|
||||
self.addItem(
|
||||
translate("AddonsInstaller", "Macro"),
|
||||
(FilterType.PACKAGE_CONTENTS, ContentFilter.MACRO),
|
||||
)
|
||||
self.addItem(
|
||||
translate("AddonsInstaller", "Preference Pack"),
|
||||
(FilterType.PACKAGE_CONTENTS, ContentFilter.PREFERENCE_PACK),
|
||||
)
|
||||
self.insertSeparator(self.count())
|
||||
self.addItem(translate("AddonsInstaller", "Installation Status"))
|
||||
self.installation_status_index = self.count() - 1
|
||||
self.addItem(
|
||||
translate("AddonsInstaller", "Any"), (FilterType.INSTALLATION_STATUS, StatusFilter.ANY)
|
||||
)
|
||||
self.addItem(
|
||||
translate("AddonsInstaller", "Not installed"),
|
||||
(FilterType.INSTALLATION_STATUS, StatusFilter.NOT_INSTALLED),
|
||||
)
|
||||
self.addItem(
|
||||
translate("AddonsInstaller", "Installed"),
|
||||
(FilterType.INSTALLATION_STATUS, StatusFilter.INSTALLED),
|
||||
)
|
||||
self.addItem(
|
||||
translate("AddonsInstaller", "Update available"),
|
||||
(FilterType.INSTALLATION_STATUS, StatusFilter.UPDATE_AVAILABLE),
|
||||
)
|
||||
model: QtCore.QAbstractItemModel = self.model()
|
||||
for row in range(model.rowCount()):
|
||||
if row <= self.addon_type_index:
|
||||
model.item(row).setEnabled(False)
|
||||
elif row < self.installation_status_index:
|
||||
item = model.item(row)
|
||||
item.setCheckState(QtCore.Qt.Unchecked)
|
||||
elif row == self.installation_status_index:
|
||||
model.item(row).setEnabled(False)
|
||||
else:
|
||||
item = model.item(row)
|
||||
item.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
for row in range(model.rowCount()):
|
||||
data = self.itemData(row)
|
||||
if data:
|
||||
item = model.item(row)
|
||||
if data[0] == FilterType.PACKAGE_CONTENTS and data[1] == ContentFilter.ANY:
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
elif data[0] == FilterType.INSTALLATION_STATUS and data[1] == StatusFilter.ANY:
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
else:
|
||||
item.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
def set_contents_filter(self, contents_filter: ContentFilter):
|
||||
model = self.model()
|
||||
for row in range(model.rowCount()):
|
||||
item = model.item(row)
|
||||
user_data = self.itemData(row)
|
||||
if user_data and user_data[0] == FilterType.PACKAGE_CONTENTS:
|
||||
if user_data[1] == contents_filter:
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
else:
|
||||
item.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
def set_status_filter(self, status_filter: StatusFilter):
|
||||
model = self.model()
|
||||
for row in range(model.rowCount()):
|
||||
item = model.item(row)
|
||||
user_data = self.itemData(row)
|
||||
if user_data and user_data[0] == FilterType.INSTALLATION_STATUS:
|
||||
if user_data[1] == status_filter:
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
else:
|
||||
item.setCheckState(QtCore.Qt.Unchecked)
|
||||
|
||||
def _setup_connections(self):
|
||||
self.activated.connect(self._selected)
|
||||
|
||||
def retranslateUi(self, _):
|
||||
self._build_menu()
|
||||
|
||||
def _selected(self, row: int):
|
||||
if row == 0:
|
||||
return
|
||||
if row == self.installation_status_index or row == self.addon_type_index:
|
||||
self.setCurrentIndex(0)
|
||||
return
|
||||
model = self.model()
|
||||
selected_data = self.itemData(row)
|
||||
if not selected_data:
|
||||
return
|
||||
selected_row_type = selected_data[0]
|
||||
|
||||
for row in range(model.rowCount()):
|
||||
item = model.item(row)
|
||||
user_data = self.itemData(row)
|
||||
if user_data and user_data[0] == selected_row_type:
|
||||
if user_data[1] == selected_data[1]:
|
||||
item.setCheckState(QtCore.Qt.Checked)
|
||||
else:
|
||||
item.setCheckState(QtCore.Qt.Unchecked)
|
||||
self._emit_current_filter()
|
||||
self.setCurrentIndex(0)
|
||||
self._update_first_row_text()
|
||||
|
||||
def _emit_current_filter(self):
|
||||
model = self.model()
|
||||
new_filter = Filter()
|
||||
for row in range(model.rowCount()):
|
||||
item = model.item(row)
|
||||
data = self.itemData(row)
|
||||
if data and item.checkState() == QtCore.Qt.Checked:
|
||||
if data[0] == FilterType.INSTALLATION_STATUS:
|
||||
new_filter.status_filter = data[1]
|
||||
elif data[0] == FilterType.PACKAGE_CONTENTS:
|
||||
new_filter.content_filter = data[1]
|
||||
self.filter_changed.emit(new_filter)
|
||||
|
||||
def _update_first_row_text(self):
|
||||
model = self.model()
|
||||
state1 = ""
|
||||
state2 = ""
|
||||
for row in range(model.rowCount()):
|
||||
item = model.item(row)
|
||||
if item.checkState() == QtCore.Qt.Checked:
|
||||
if not state1:
|
||||
state1 = item.text()
|
||||
else:
|
||||
state2 = item.text()
|
||||
break
|
||||
model.item(0).setText(translate("AddonsInstaller", "Filter") + f": {state1}, {state2}")
|
||||
103
src/Mod/AddonManager/Widgets/addonmanager_widget_search.py
Normal file
103
src/Mod/AddonManager/Widgets/addonmanager_widget_search.py
Normal file
@@ -0,0 +1,103 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2022-2024 FreeCAD Project Association *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, but *
|
||||
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
""" Defines a QWidget-derived class for displaying the view selection buttons. """
|
||||
|
||||
try:
|
||||
import FreeCAD
|
||||
|
||||
translate = FreeCAD.Qt.translate
|
||||
except ImportError:
|
||||
FreeCAD = None
|
||||
|
||||
def translate(_: str, text: str):
|
||||
return text
|
||||
|
||||
|
||||
# Get whatever version of PySide we can
|
||||
try:
|
||||
import PySide # Use the FreeCAD wrapper
|
||||
except ImportError:
|
||||
try:
|
||||
import PySide6 # Outside FreeCAD, try Qt6 first
|
||||
|
||||
PySide = PySide6
|
||||
except ImportError:
|
||||
import PySide2 # Fall back to Qt5 (if this fails, Python will kill this module's import)
|
||||
|
||||
PySide = PySide2
|
||||
|
||||
from PySide import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class WidgetSearch(QtWidgets.QWidget):
|
||||
"""A widget for selecting the Addon Manager's primary view mode"""
|
||||
|
||||
search_changed = QtCore.Signal(str)
|
||||
|
||||
def __init__(self, parent: QtWidgets.QWidget = None):
|
||||
super().__init__(parent)
|
||||
self._setup_ui()
|
||||
self._setup_connections()
|
||||
self.retranslateUi(None)
|
||||
|
||||
def _setup_ui(self):
|
||||
self.horizontal_layout = QtWidgets.QHBoxLayout()
|
||||
self.filter_line_edit = QtWidgets.QLineEdit(self)
|
||||
self.filter_line_edit.setClearButtonEnabled(True)
|
||||
self.horizontal_layout.addWidget(self.filter_line_edit)
|
||||
self.filter_validity_label = QtWidgets.QLabel(self)
|
||||
self.horizontal_layout.addWidget(self.filter_validity_label)
|
||||
self.filter_validity_label.hide() # This widget starts hidden
|
||||
self.setLayout(self.horizontal_layout)
|
||||
|
||||
def _setup_connections(self):
|
||||
self.filter_line_edit.textChanged.connect(self.set_text_filter)
|
||||
|
||||
def set_text_filter(self, text_filter: str) -> None:
|
||||
"""Set the current filter. If the filter is valid, this will emit a filter_changed
|
||||
signal. text_filter may be regular expression."""
|
||||
|
||||
if text_filter:
|
||||
test_regex = QtCore.QRegularExpression(text_filter)
|
||||
if test_regex.isValid():
|
||||
self.filter_validity_label.setToolTip(
|
||||
translate("AddonsInstaller", "Filter is valid")
|
||||
)
|
||||
icon = QtGui.QIcon.fromTheme("ok", QtGui.QIcon(":/icons/edit_OK.svg"))
|
||||
self.filter_validity_label.setPixmap(icon.pixmap(16, 16))
|
||||
else:
|
||||
self.filter_validity_label.setToolTip(
|
||||
translate("AddonsInstaller", "Filter regular expression is invalid")
|
||||
)
|
||||
icon = QtGui.QIcon.fromTheme("cancel", QtGui.QIcon(":/icons/edit_Cancel.svg"))
|
||||
self.filter_validity_label.setPixmap(icon.pixmap(16, 16))
|
||||
self.filter_validity_label.show()
|
||||
else:
|
||||
self.filter_validity_label.hide()
|
||||
self.search_changed.emit(text_filter)
|
||||
|
||||
def retranslateUi(self, _):
|
||||
self.filter_line_edit.setPlaceholderText(
|
||||
QtCore.QCoreApplication.translate("AddonsInstaller", "Filter", None)
|
||||
)
|
||||
159
src/Mod/AddonManager/Widgets/addonmanager_widget_top_bar.py
Normal file
159
src/Mod/AddonManager/Widgets/addonmanager_widget_top_bar.py
Normal file
@@ -0,0 +1,159 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2022-2024 FreeCAD Project Association *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, but *
|
||||
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
""" Defines a class derived from QWidget for displaying the bar at the top of the addons list. """
|
||||
|
||||
from enum import IntEnum
|
||||
from addonmanager_widget_view_selector import WidgetViewSelector
|
||||
|
||||
# Get whatever version of PySide we can
|
||||
try:
|
||||
import PySide # Use the FreeCAD wrapper
|
||||
except ImportError:
|
||||
try:
|
||||
import PySide6 # Outside FreeCAD, try Qt6 first
|
||||
|
||||
PySide = PySide6
|
||||
except ImportError:
|
||||
import PySide2 # Fall back to Qt5 (if this fails, Python will kill this module's import)
|
||||
|
||||
PySide = PySide2
|
||||
|
||||
from PySide import QtCore, QtWidgets
|
||||
|
||||
translate = FreeCAD.Qt.translate
|
||||
|
||||
|
||||
class StatusFilter(IntEnum):
|
||||
"""Predefined filers"""
|
||||
|
||||
ANY = 0
|
||||
INSTALLED = 1
|
||||
NOT_INSTALLED = 2
|
||||
UPDATE_AVAILABLE = 3
|
||||
|
||||
|
||||
# pylint: disable=too-few-public-methods
|
||||
|
||||
|
||||
class WidgetTopBar(QtWidgets.QWidget):
|
||||
"""A widget to display the buttons at the top of the Addon manager, for changing the view,
|
||||
filtering, and sorting."""
|
||||
|
||||
view_changed = QtCore.Signal(int)
|
||||
filter_changed = QtCore.Signal(str)
|
||||
search_changed = QtCore.Signal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.horizontal_layout = None
|
||||
self.package_type_label = None
|
||||
self.package_type_combobox = None
|
||||
self._setup_ui()
|
||||
self._setup_connections()
|
||||
self.retranslateUi()
|
||||
|
||||
def _setup_ui(self):
|
||||
self.horizontal_layout = QtWidgets.QHBoxLayout()
|
||||
|
||||
self.view_selector = WidgetViewSelector(self)
|
||||
self.horizontal_layout.addWidget(self.view_selector)
|
||||
|
||||
self.package_type_label = QtWidgets.QLabel(self)
|
||||
self.horizontal_layout.addWidget(self.package_type_label)
|
||||
|
||||
self.package_type_combobox = QtWidgets.QComboBox(self)
|
||||
self.horizontal_layout.addWidget(self.package_type_combobox)
|
||||
|
||||
self.status_combo_box = QtWidgets.QComboBox(self)
|
||||
self.horizontal_layout.addWidget(self.status_combo_box)
|
||||
|
||||
self.filter_line_edit = QtWidgets.QLineEdit(self)
|
||||
self.horizontal_layout.addWidget(self.filter_line_edit)
|
||||
|
||||
# Only shows when the user types in a filter
|
||||
self.ui.filter_validity_label = QtWidgets.QLabel(self)
|
||||
self.horizontal_layout.addWidget(self.filter_validity_label)
|
||||
self.ui.filter_validity_label.hide()
|
||||
|
||||
def _setup_connections(self):
|
||||
self.ui.view_selector.view_changed.connect(self.view_changed.emit)
|
||||
|
||||
# Set up the view the same as the last time:
|
||||
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
|
||||
package_type = pref.GetInt("PackageTypeSelection", 1)
|
||||
self.ui.comboPackageType.setCurrentIndex(package_type)
|
||||
status = pref.GetInt("StatusSelection", 0)
|
||||
self.ui.comboStatus.setCurrentIndex(status)
|
||||
|
||||
def update_type_filter(self, type_filter: int) -> None:
|
||||
"""hide/show rows corresponding to the type filter
|
||||
|
||||
type_filter is an integer: 0 for all, 1 for workbenches, 2 for macros,
|
||||
and 3 for preference packs
|
||||
|
||||
"""
|
||||
|
||||
self.item_filter.setPackageFilter(type_filter)
|
||||
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
|
||||
pref.SetInt("PackageTypeSelection", type_filter)
|
||||
|
||||
def update_status_filter(self, status_filter: int) -> None:
|
||||
"""hide/show rows corresponding to the status filter
|
||||
|
||||
status_filter is an integer: 0 for any, 1 for installed, 2 for not installed,
|
||||
and 3 for update available
|
||||
|
||||
"""
|
||||
|
||||
self.item_filter.setStatusFilter(status_filter)
|
||||
pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons")
|
||||
pref.SetInt("StatusSelection", status_filter)
|
||||
|
||||
def update_text_filter(self, text_filter: str) -> None:
|
||||
"""filter name and description by the regex specified by text_filter"""
|
||||
|
||||
if text_filter:
|
||||
if hasattr(self.item_filter, "setFilterRegularExpression"): # Added in Qt 5.12
|
||||
test_regex = QtCore.QRegularExpression(text_filter)
|
||||
else:
|
||||
test_regex = QtCore.QRegExp(text_filter)
|
||||
if test_regex.isValid():
|
||||
self.ui.labelFilterValidity.setToolTip(
|
||||
translate("AddonsInstaller", "Filter is valid")
|
||||
)
|
||||
icon = QtGui.QIcon.fromTheme("ok", QtGui.QIcon(":/icons/edit_OK.svg"))
|
||||
self.ui.labelFilterValidity.setPixmap(icon.pixmap(16, 16))
|
||||
else:
|
||||
self.ui.labelFilterValidity.setToolTip(
|
||||
translate("AddonsInstaller", "Filter regular expression is invalid")
|
||||
)
|
||||
icon = QtGui.QIcon.fromTheme("cancel", QtGui.QIcon(":/icons/edit_Cancel.svg"))
|
||||
self.ui.labelFilterValidity.setPixmap(icon.pixmap(16, 16))
|
||||
self.ui.labelFilterValidity.show()
|
||||
else:
|
||||
self.ui.labelFilterValidity.hide()
|
||||
if hasattr(self.item_filter, "setFilterRegularExpression"): # Added in Qt 5.12
|
||||
self.item_filter.setFilterRegularExpression(text_filter)
|
||||
else:
|
||||
self.item_filter.setFilterRegExp(text_filter)
|
||||
@@ -0,0 +1,152 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2022-2024 FreeCAD Project Association *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, but *
|
||||
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
""" Defines a QWidget-derived class for displaying the view selection buttons. """
|
||||
|
||||
from enum import IntEnum
|
||||
|
||||
try:
|
||||
import FreeCAD
|
||||
|
||||
translate = FreeCAD.Qt.translate
|
||||
except ImportError:
|
||||
FreeCAD = None
|
||||
|
||||
def translate(context: str, text: str):
|
||||
return text
|
||||
|
||||
|
||||
# Get whatever version of PySide we can
|
||||
try:
|
||||
import PySide # Use the FreeCAD wrapper
|
||||
except ImportError:
|
||||
try:
|
||||
import PySide6 # Outside FreeCAD, try Qt6 first
|
||||
|
||||
PySide = PySide6
|
||||
except ImportError:
|
||||
import PySide2 # Fall back to Qt5 (if this fails, Python will kill this module's import)
|
||||
|
||||
PySide = PySide2
|
||||
|
||||
from PySide import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class AddonManagerDisplayStyle(IntEnum):
|
||||
"""The display mode of the Addon Manager"""
|
||||
|
||||
COMPACT = 0
|
||||
EXPANDED = 1
|
||||
COMPOSITE = 2
|
||||
|
||||
|
||||
class WidgetViewSelector(QtWidgets.QWidget):
|
||||
"""A widget for selecting the Addon Manager's primary view mode"""
|
||||
|
||||
view_changed = QtCore.Signal(int)
|
||||
|
||||
def __init__(self, parent: QtWidgets.QWidget = None):
|
||||
super().__init__(parent)
|
||||
self.horizontal_layout = None
|
||||
self.composite_button = None
|
||||
self.expanded_button = None
|
||||
self.compact_button = None
|
||||
self._setup_ui()
|
||||
self._setup_connections()
|
||||
|
||||
def set_current_view(self, view: AddonManagerDisplayStyle):
|
||||
"""Set the current selection. Does NOT emit a view_changed signal, only changes the
|
||||
interface display."""
|
||||
self.compact_button.setChecked(False)
|
||||
self.expanded_button.setChecked(False)
|
||||
self.composite_button.setChecked(False)
|
||||
if view == AddonManagerDisplayStyle.COMPACT:
|
||||
self.compact_button.setChecked(True)
|
||||
elif view == AddonManagerDisplayStyle.EXPANDED:
|
||||
self.expanded_button.setChecked(True)
|
||||
elif view == AddonManagerDisplayStyle.COMPOSITE:
|
||||
self.composite_button.setChecked(True)
|
||||
else:
|
||||
if FreeCAD is not None:
|
||||
FreeCAD.Console.PrintWarning(f"Unrecognized display style {view}")
|
||||
|
||||
def _setup_ui(self):
|
||||
self.horizontal_layout = QtWidgets.QHBoxLayout()
|
||||
self.compact_button = QtWidgets.QToolButton(self)
|
||||
self.compact_button.setObjectName("compact_button")
|
||||
self.compact_button.setIcon(
|
||||
QtGui.QIcon.fromTheme("back", QtGui.QIcon(":/icons/compact_view.svg"))
|
||||
)
|
||||
self.compact_button.setCheckable(True)
|
||||
self.compact_button.setAutoExclusive(True)
|
||||
|
||||
self.expanded_button = QtWidgets.QToolButton(self)
|
||||
self.expanded_button.setObjectName("expanded_button")
|
||||
self.expanded_button.setCheckable(True)
|
||||
self.expanded_button.setChecked(True)
|
||||
self.expanded_button.setAutoExclusive(True)
|
||||
self.expanded_button.setIcon(
|
||||
QtGui.QIcon.fromTheme("expanded_view", QtGui.QIcon(":/icons/expanded_view.svg"))
|
||||
)
|
||||
|
||||
self.composite_button = QtWidgets.QToolButton(self)
|
||||
self.composite_button.setObjectName("expanded_button")
|
||||
self.composite_button.setCheckable(True)
|
||||
self.composite_button.setChecked(True)
|
||||
self.composite_button.setAutoExclusive(True)
|
||||
self.composite_button.setIcon(
|
||||
QtGui.QIcon.fromTheme("composite_button", QtGui.QIcon(":/icons/composite_view.svg"))
|
||||
)
|
||||
|
||||
self.horizontal_layout.addWidget(self.compact_button)
|
||||
self.horizontal_layout.addWidget(self.expanded_button)
|
||||
self.horizontal_layout.addWidget(self.composite_button)
|
||||
|
||||
self.compact_button.clicked.connect(
|
||||
lambda: self.view_changed.emit(AddonManagerDisplayStyle.COMPACT)
|
||||
)
|
||||
self.expanded_button.clicked.connect(
|
||||
lambda: self.view_changed.emit(AddonManagerDisplayStyle.EXPANDED)
|
||||
)
|
||||
self.composite_button.clicked.connect(
|
||||
lambda: self.view_changed.emit(AddonManagerDisplayStyle.COMPOSITE)
|
||||
)
|
||||
|
||||
self.setLayout(self.horizontal_layout)
|
||||
self.retranslateUi(None)
|
||||
|
||||
def _setup_connections(self):
|
||||
self.compact_button.clicked.connect(
|
||||
lambda: self.view_changed.emit(AddonManagerDisplayStyle.COMPACT)
|
||||
)
|
||||
self.expanded_button.clicked.connect(
|
||||
lambda: self.view_changed.emit(AddonManagerDisplayStyle.EXPANDED)
|
||||
)
|
||||
self.composite_button.clicked.connect(
|
||||
lambda: self.view_changed.emit(AddonManagerDisplayStyle.COMPOSITE)
|
||||
)
|
||||
|
||||
def retranslateUi(self, _):
|
||||
self.composite_button.setToolTip(translate("AddonsInstaller", "Composite view"))
|
||||
self.expanded_button.setToolTip(translate("AddonsInstaller", "Expanded view"))
|
||||
self.compact_button.setToolTip(translate("AddonsInstaller", "Compact view"))
|
||||
Reference in New Issue
Block a user