Commit 3666ccad authored by Flavio TARSETTI's avatar Flavio TARSETTI Committed by Samuel GAIST
Browse files

[widgets] WIP: adding parameter.py

parent adbe43f0
# vim: set fileencoding=utf-8 :
###############################################################################
# #
# Copyright (c) 2019 Idiap Research Institute, http://www.idiap.ch/ #
# Contact: beat.support@idiap.ch #
# #
# This file is part of the beat.editor module of the BEAT platform. #
# #
# Commercial License Usage #
# Licensees holding valid commercial BEAT licenses may use this file in #
# accordance with the terms contained in a written agreement between you #
# and Idiap. For further information contact tto@idiap.ch #
# #
# Alternatively, this file may be used under the terms of the GNU Affero #
# Public License version 3 as published by the Free Software and appearing #
# in the file LICENSE.AGPL included in the packaging of this file. #
# The BEAT platform 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. #
# #
# You should have received a copy of the GNU Affero Public License along #
# with the BEAT platform. If not, see http://www.gnu.org/licenses/. #
# #
###############################################################################
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QListWidget
# from PyQt5.QtWidgets import QTableView
# from PyQt5.QtWidgets import QTableWidget
# from PyQt5.QtWidgets import QTableWidgetItem
# from PyQt5.QtWidgets import QHeaderView
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QComboBox
from PyQt5.QtWidgets import QStackedWidget
from PyQt5.QtWidgets import QFormLayout
from PyQt5.QtWidgets import QGroupBox
from PyQt5.QtWidgets import QRadioButton
# from PyQt5.QtWidgets import QCheckBox
from PyQt5.QtWidgets import QDoubleSpinBox
from PyQt5.QtWidgets import QInputDialog
from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import Qt
# from PyQt5.QtGui import QDoubleValidator
from .spinboxes import Int64SpinBox
from .spinboxes import Uint64SpinBox
from .spinboxes import Float64SpinBox
# from PyQt5.QtCore import QDateTime
# from PyQt5.QtWidgets import QDateTimeEdit
from PyQt5.QtWidgets import QDialogButtonBox
import pkg_resources
import json
import sys
import numpy
from enum import Enum, unique
# from beat.backend.python.algorithm import Storage
# from beat.backend.python.algorithm import Runner # noqa
# from beat.backend.python.algorithm import Algorithm as BackendAlgorithm
# from beat.core.schema import load_schema
NUMPY_TYPES = {
"int8": numpy.iinfo(numpy.int8),
"int16": numpy.iinfo(numpy.int16),
"int32": numpy.iinfo(numpy.int32),
"int64": numpy.iinfo(numpy.int64),
"uint8": numpy.iinfo(numpy.uint8),
"uint16": numpy.iinfo(numpy.uint16),
"uint32": numpy.iinfo(numpy.uint32),
"uint64": numpy.iinfo(numpy.uint64),
"float32": numpy.finfo(numpy.float32),
"float64": numpy.finfo(numpy.float64),
}
@unique
class InputType(Enum):
"""All possible assets available on the BEAT platform"""
(
UNKNOWN,
INT8,
INT16,
INT32,
INT64,
UINT8,
UINT16,
UINT32,
UINT64,
FLOAT32,
FLOAT64,
BOOL,
STRING,
) = range(13)
@classmethod
def get_type(cls, type_):
wanted_type = "unknown"
if type_ == cls.INT8:
wanted_type = "int8"
elif type_ == cls.INT16:
wanted_type = "int16"
elif type_ == cls.INT32:
wanted_type = "int32"
elif type_ == cls.INT64:
wanted_type = "int64"
if type_ == cls.UINT8:
wanted_type = "uint8"
elif type_ == cls.UINT16:
wanted_type = "uint16"
elif type_ == cls.UINT32:
wanted_type = "uint32"
elif type_ == cls.UINT64:
wanted_type = "uint64"
elif type_ == cls.FLOAT32:
wanted_type = "float32"
elif type_ == cls.FLOAT64:
wanted_type = "float64"
elif type_ == cls.BOOL:
wanted_type = "bool"
elif type_ == cls.STRING:
wanted_type = "string"
return wanted_type
@classmethod
def from_type(cls, type_):
if type_ == "int8":
return cls.INT8
elif type_ == "int16":
return cls.INT16
elif type_ == "int32":
return cls.INT32
elif type_ == "int64":
return cls.INT64
elif type_ == "uint8":
return cls.UINT8
elif type_ == "uint16":
return cls.UINT16
elif type_ == "uint32":
return cls.UINT32
elif type_ == "uint64":
return cls.UINT64
elif type_ == "float32":
return cls.FLOAT32
elif type_ == "float64":
return cls.FLOAT64
elif type_ == "bool":
return cls.BOOL
elif type_ == "string":
return cls.STRING
else:
raise RuntimeError("Unknown asset type_ {}".format(type_))
# def validate(self, data):
# if self == self.UNKNOWN:
# raise RuntimeError("Trying to validate unknown type")
# return validate(self.name.lower(), data)
class Type64Dialog(QDialog):
def __init__(self, selected_type, parent=None):
super(Type64Dialog, self).__init__(parent)
self.setWindowTitle(self.tr("Input"))
print("type is here!: {}".format(selected_type))
layout = QVBoxLayout(self)
self.label = QLabel(self.tr("New Choice:"))
if InputType.from_type(selected_type) == InputType.INT64:
self.spinbox = Int64SpinBox(self)
elif InputType.from_type(selected_type) == InputType.UINT64:
self.spinbox = Uint64SpinBox(self)
elif InputType.from_type(selected_type) == InputType.FLOAT64:
self.spinbox = Float64SpinBox(self)
layout.addWidget(self.label)
layout.addWidget(self.spinbox)
# OK and Cancel buttons
self.buttons = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self
)
layout.addWidget(self.buttons)
self.buttons.accepted.connect(self.accept)
self.buttons.rejected.connect(self.reject)
# static method to create the dialog and return qdialog accepted/spinbox value
@staticmethod
def getDialog(selected_type, parent=None):
dialog = Type64Dialog(selected_type, parent)
result = dialog.exec_()
return (dialog.spinbox.value(), result == QDialog.Accepted)
class ChoicesWidget(QWidget):
def __init__(self, parent=None):
super(ChoicesWidget, self).__init__(parent)
# Widgets
label = QLabel(self.tr("Restrict to ..."))
restricts = QComboBox()
restricts.addItems([self.tr("None"), self.tr("Choices")])
# Layouts
layout = QHBoxLayout()
layout.addWidget(label)
layout.addWidget(restricts)
self.setLayout(layout)
def get_information(self):
return "ChoicesWidget"
class ChoicesRangeWidget(QWidget):
def __init__(self, parent=None):
super(ChoicesRangeWidget, self).__init__(parent)
print(self.get_information())
print(dir(parent))
print(parent)
print(parent.selected_type)
# Widgets
self.parent = parent
self.restrict_label = QLabel(self.tr("Restrict to ..."))
self.restricts = QComboBox()
self.restricts.addItems([self.tr("None"), self.tr("Choices"), self.tr("Range")])
self.default_label = QLabel(self.tr("Default:"))
self.default = QLineEdit()
self.stacked_restricts = QStackedWidget()
self.none_stack = QWidget()
self.choices_stack = QWidget()
self.range_stack = QWidget()
self.none_stack_ui()
self.choices_stack_ui()
self.range_stack_ui()
self.Stack = QStackedWidget(self)
self.Stack.addWidget(self.none_stack)
self.Stack.addWidget(self.choices_stack)
self.Stack.addWidget(self.range_stack)
# Layouts
layout = QHBoxLayout()
layout.addWidget(self.restrict_label)
layout.addWidget(self.restricts)
layout.addWidget(self.default_label)
layout.addWidget(self.default)
layout.addWidget(self.Stack)
self.setLayout(layout)
# Signal/Slots connections
# self.basetype.activated.connect(self.changed_type_widget)
self.restricts.currentIndexChanged.connect(self.display)
def none_stack_ui(self):
layout = QHBoxLayout()
self.label = QLabel(self.tr("No restrictions applied"))
layout.addWidget(self.label)
self.none_stack.setLayout(layout)
def choices_stack_ui(self):
self.choices = QListWidget()
self.add_button = QPushButton(self.tr("+"))
self.remove_button = QPushButton(self.tr("-"))
# Layouts
layout = QVBoxLayout()
choices_layout = QVBoxLayout()
choices_layout.addWidget(self.choices)
buttons_layout = QHBoxLayout()
buttons_layout.addWidget(self.add_button)
buttons_layout.addWidget(self.remove_button)
buttons_layout.addStretch(1)
layout.addLayout(choices_layout)
layout.addLayout(buttons_layout)
self.choices_stack.setLayout(layout)
# Signal/Slots connections
self.add_button.clicked.connect(self.__add_choice_clicked)
self.remove_button.clicked.connect(self.__remove_choice_clicked)
def __add_choice_clicked(self):
input_value = None
ok = False
min_value = NUMPY_TYPES[self.parent.selected_type].min
max_value = NUMPY_TYPES[self.parent.selected_type].max
if self.parent.selected_type == InputType.get_type(InputType.STRING):
input_value, ok = QInputDialog.getText(
self, self.tr("Input"), self.tr("New Choice:")
)
elif "int" in self.parent.selected_type:
if "64" in self.parent.selected_type:
input_value, ok = Type64Dialog.getDialog(self.parent.selected_type)
else:
input_value, ok = QInputDialog.getInt(
self,
self.tr("Input"),
self.tr("New Choice:"),
1,
min_value,
max_value,
)
elif "float" in self.parent.selected_type:
if "64" in self.parent.selected_type:
input_value, ok = Type64Dialog.getDialog(self.parent.selected_type)
else:
input_value, ok = QInputDialog.getDouble(
self,
self.tr("Get double"),
self.tr("Value:"),
1,
min_value,
max_value,
10,
)
if ok:
self.choices.addItem(str(input_value))
def __remove_choice_clicked(self):
choices = self.choices.selectedItems()
for choice in choices:
self.choices.takeItem(self.choices.row(choice))
def range_stack_ui(self):
layout = QFormLayout()
self.minimum_value = QDoubleSpinBox()
self.maximum_value = QDoubleSpinBox()
self.minimum_value.setMinimum(-sys.float_info.max)
self.minimum_value.setMaximum(sys.float_info.max)
self.maximum_value.setMinimum(-sys.float_info.max)
self.maximum_value.setMaximum(sys.float_info.max)
layout.addRow(self.tr("Min"), self.minimum_value)
layout.addRow(self.tr("Max"), self.maximum_value)
self.range_stack.setLayout(layout)
def display(self, i):
self.Stack.setCurrentIndex(i)
def get_information(self):
return "ChoicesRangesWidget"
# def get_type(self):
# return self.parent.base
class BoolWidget(QWidget):
def __init__(self, parent=None):
super(BoolWidget, self).__init__(parent)
# Widgets
self.label = QLabel(self.tr("Default"))
self.true_button = QRadioButton(self.tr("True"))
self.true_button.setChecked(True)
self.false_button = QRadioButton(self.tr("False"))
# Layouts
layout = QHBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.true_button)
layout.addWidget(self.false_button)
self.setLayout(layout)
def get_information(self):
return self.true_button.isChecked()
class StackedWidget(QStackedWidget):
def __init__(self, parent=None):
super(StackedWidget, self).__init__(parent)
# members
self.sel = None
class ParameterWidget(QWidget):
"""Class holder for the parameter"""
dataChanged = pyqtSignal()
def __init__(self, parent=None):
"""Constructor"""
super(ParameterWidget, self).__init__(parent)
unwanted_basetypes = {"complex64", "complex128"}
basetypes = json.loads(
pkg_resources.resource_string("beat.core.schema", "common/1.json")
)["definitions"]["basetype"]["enum"]
basetypes = [i for i in basetypes if i not in unwanted_basetypes]
# Widgets
self.parameter_box = QGroupBox(self.tr("Parameter"))
self.name = QLineEdit()
self.description = QLineEdit()
self.basetype = QComboBox()
self.basetype.addItems(basetypes)
self.selected_type = basetypes[0]
self.default = QLineEdit()
# self.restricts = QComboBox()
# self.restricts.addItems([self.tr("None"), self.tr("Choices"), self.tr("Range")])
self.stacked_basetype = QStackedWidget()
self.choices_range_widget = ChoicesRangeWidget(self)
self.choices_widget = ChoicesWidget(self)
self.bool_widget = BoolWidget(self)
self.stacked_basetype.addWidget(self.choices_range_widget)
self.stacked_basetype.addWidget(self.choices_widget)
self.stacked_basetype.addWidget(self.bool_widget)
# self.stacked_basetype2 = StackedWidget(self)
# self.choices_range_widget2 = ChoicesRangeWidget(self)
# self.choices_widget2 = ChoicesWidget()
# self.bool_widget2 = BoolWidget(self)
# self.stacked_basetype2.addWidget(self.choices_range_widget)
# self.stacked_basetype2.addWidget(self.choices_widget)
# self.stacked_basetype2.addWidget(self.bool_widget)
# self.stacked_basetype2.sel = self.selected_type
# Layouts
layout = QVBoxLayout(self)
# QFormLayout for parameter setup
parameter_layout = QFormLayout()
parameter_layout.addRow(self.tr("Name:"), self.name)
parameter_layout.addRow(self.tr("Description:"), self.description)
parameter_layout.addRow(self.tr("Type:"), self.basetype)
parameter_layout.addRow(self.tr("Default:"), self.default)
# parameter_layout.addRow(self.tr("Restrict to:"), self.restricts)
parameter_layout.addRow(self.tr("Defaults/Restriction:"), self.stacked_basetype)
# parameter_layout.addRow(self.tr("Defaults/Restriction:"), self.stacked_basetype2)
self.parameter_box.setLayout(parameter_layout)
# Layouts Design
layout.addWidget(self.parameter_box)
# Signal/Slots connections
# self.basetype.activated.connect(self.changed_type_widget)
self.basetype.currentIndexChanged.connect(self.changed_type_widget)
# Change current index to update stacked widget
# self.basetype.setCurrentIndex(1)
self.name.textChanged.connect(self.updated)
def changed_type_widget(self):
self.selected_type = self.basetype.currentText()
print("Type: {}".format(self.selected_type))
# self.stacked_basetype2.sel = self.selected_type
# print("Type: {}".format(self.stacked_basetype2.sel))
if self.selected_type == InputType.get_type(InputType.BOOL):
self.stacked_basetype.setCurrentIndex(2)
elif self.selected_type == InputType.get_type(InputType.STRING):
self.stacked_basetype.setCurrentIndex(1)
else:
self.stacked_basetype.setCurrentIndex(0)
def get_current_type(self):
return self.basetype.currentText()
def updated(self):
print("Index: {}".format(self.stacked_basetype.currentIndex()))
print("Widget: {}".format(self.stacked_basetype.currentWidget()))
print(
"Info: {}".format(self.stacked_basetype.currentWidget().get_information())
)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment