diff --git a/examples/advanced.py b/examples/advanced.py index 5adae4e..b538975 100644 --- a/examples/advanced.py +++ b/examples/advanced.py @@ -16,11 +16,13 @@ def create_datalist_example(): test = [('str *', 'this is a string'), + ('str +', 'this is a string'), ('str_m *', """this is a MULTILINE string"""), ('file *', 'file'), ('list *', [0, '1', '3', '4']), + ('list +', [0, '1', '3', '4']), ('tuple *', (0, '1', '3', '4')), ('list2', ['--', ('none', 'None'), ('--', 'Dashed'), ('-.', 'DashDot'), ('-', 'Solid'), diff --git a/formlayout.py b/formlayout.py index 7135620..97d4e17 100644 --- a/formlayout.py +++ b/formlayout.py @@ -294,6 +294,89 @@ def setStyleSheet(self, style): btn.setStyleSheet(style) +class PlusLayout(QVBoxLayout): + """Field with a '+' PushButton in a QVBoxLayout""" + def __init__(self, field, value, save_value, parent=None): + QVBoxLayout.__init__(self) + self.field = field + self.value = value + self.save_value = save_value + self.style = '' + if isinstance(self.field, QComboBox): + self.index = field.currentIndex() + hbox = QHBoxLayout() + plusbtn = QPushButton('+') + plusbtn.setFixedSize(20, 20) + plusbtn.clicked.connect(self.addfield) + hbox.addWidget(self.field) + hbox.addWidget(plusbtn) + self.addLayout(hbox) + + def addfield(self): + if isinstance(self.field, QLineEdit): + if self.value == 'password': + field = QLineEdit() + field.setEchoMode(QLineEdit.Password) + else: + field = QLineEdit(self.value) + elif isinstance(self.field, QComboBox): + field = QComboBox() + field.addItems(self.value) + field.setCurrentIndex(self.index) + hbox = MoinsLayout(field, self) + self.addLayout(hbox) + + def items(self): + if is_text_string(self.save_value): + items = [to_text_string(self.field.text())] +\ + [to_text_string(self.itemAt(i).field.text())\ + for i in range(1, self.count())] + elif isinstance(self.save_value, list): + indexes = [self.field.currentIndex()] +\ + [self.itemAt(i).field.currentIndex()\ + for i in range(1, self.count())] + items = [] + for index in indexes: + if isinstance(self.save_value[0], int): + value = index + 1 + else: + value = self.save_value[index+1] + if isinstance(value, (list, tuple)): + value = value[0] + items.append(value) + if len(items) == 1: + return items[0] + return items + + def setStyleSheet(self, style): + self.style = style + self.field.setStyleSheet(self.style) + for i in range(1, self.count()): + self.itemAt(i).setStyleSheet(self.style) + + +class MoinsLayout(QHBoxLayout): + """Field with a '-' PushButton""" + def __init__(self, field, parent=None): + QHBoxLayout.__init__(self) + self.field = field + self.parent = parent + self.moinsbtn = QPushButton('-') + self.moinsbtn.setFixedSize(20, 20) + self.moinsbtn.clicked.connect(self.removefield) + self.addWidget(self.field) + self.addWidget(self.moinsbtn) + self.setStyleSheet(parent.style) + + def removefield(self): + self.field.close() + self.moinsbtn.close() + self.parent.removeItem(self) + + def setStyleSheet(self, style): + self.field.setStyleSheet(style) + + def font_is_installed(font): """Check if font is installed""" return [fam for fam in QFontDatabase().families() @@ -427,6 +510,7 @@ def get_dialog(self): def setup(self): for label, value in self.data: + save_value = value if DEBUG_FORMLAYOUT: print("value:", value) if label is None and value is None: @@ -471,7 +555,6 @@ def setup(self): else: field = QLineEdit(value, self) elif isinstance(value, (list, tuple)): - save_value = value value = list(value) # always needed to protect self.data selindex = value.pop(0) if isinstance(selindex, int): @@ -524,6 +607,16 @@ def setup(self): field.setTime(value) else: field = QLineEdit(repr(value), self) + + # Eventually catching the 'addfield' feature and processing it + if label.endswith(' +'): + label = label[:-2] + if isinstance(field, QLineEdit) and is_text_string(value) or\ + isinstance(field, QComboBox): + field = PlusLayout(field, value, save_value) + else: + print("Warning: '%s' doesn't support 'addfield' feature"\ + % label, file=STDERR) # Eventually extracting tooltip from label and processing it index = label.find('::') @@ -587,6 +680,10 @@ def get(self): if label is None: # Separator / Comment continue + if label.endswith(' +'): + label = label[:-2] + if isinstance(field, PlusLayout): + value = field.items() elif tuple_to_qfont(value) is not None: value = field.get_font() elif is_text_string(value): @@ -659,12 +756,18 @@ def get(self): if label.endswith(' *'): label = label[:-2] required = 'true' - child = ET.SubElement(form, label) - if isinstance(value, datetime.datetime): - child.text = value.isoformat() + if isinstance(value, list): + for v in value: + child = ET.SubElement(form, label) + child.text = str(v) + child.attrib['required'] = required else: - child.text = str(value) - child.attrib['required'] = required + child = ET.SubElement(form, label) + if isinstance(value, datetime.datetime): + child.text = value.isoformat() + else: + child.text = str(value) + child.attrib['required'] = required return ET.tostring(form)