jbqt 0.1.16__py3-none-any.whl → 0.1.18__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of jbqt might be problematic. Click here for more details.

jbqt/dialogs/__init__.py CHANGED
@@ -1,7 +1,8 @@
1
1
  """jbqt Dialog exports"""
2
2
 
3
- from jbqt.dialogs.input_form import InputDialog
3
+ from jbqt.dialogs.input_form import InputFormDialog
4
+ from jbqt.dialogs.single_input import InputDialog
4
5
  from jbqt.dialogs.text_preview import TextPreviewDialog
5
6
  from jbqt.dialogs.file_dialog import JbFileDialog
6
7
 
7
- __all__ = ["InputDialog", "TextPreviewDialog", "JbFileDialog"]
8
+ __all__ = ["InputDialog", "InputFormDialog", "TextPreviewDialog", "JbFileDialog"]
@@ -1,3 +1,4 @@
1
+ from dataclasses import dataclass
1
2
  from typing import Any, Callable
2
3
 
3
4
  from PyQt6.QtCore import pyqtSignal
@@ -5,81 +6,135 @@ from PyQt6.QtWidgets import (
5
6
  QDialog,
6
7
  QDialogButtonBox,
7
8
  QDoubleSpinBox,
9
+ QHBoxLayout,
8
10
  QLabel,
11
+ QLayout,
9
12
  QLineEdit,
13
+ QPushButton,
10
14
  QSpinBox,
11
15
  QVBoxLayout,
16
+ QWidget,
12
17
  )
13
18
 
19
+ from PyQt6 import QtWidgets
14
20
 
15
- INPUT_SIGNAL_TYPES: tuple[Any, ...] = (str, int, float)
21
+ from jbqt.models import DialogOptions
16
22
 
17
23
 
18
- class InputDialog(QDialog):
19
- signal_types: tuple[Any] = INPUT_SIGNAL_TYPES
20
- """ reference value for external use """
24
+ def get_widget(name: str) -> QWidget | None:
25
+ widget: QWidget | None = None
26
+ if hasattr(QtWidgets, name):
27
+ widget = getattr(QtWidgets, name)
28
+ """ elif hasattr(widgets, name):
29
+ widget = getattr(widgets, name) """
21
30
 
22
- value = pyqtSignal(*([ptype] for ptype in INPUT_SIGNAL_TYPES))
31
+ if widget:
32
+ if not callable(widget):
33
+ return
34
+
35
+ widget = widget()
36
+ if isinstance(widget, QWidget):
37
+ return widget
38
+ return None
39
+
40
+
41
+ def get_widget_val(widget: QWidget) -> str | int | float | None:
42
+ # Emit the custom signal with data when the dialog is accepted
43
+ value = None
44
+ if isinstance(widget, QLineEdit):
45
+ value = widget.text()
46
+ elif isinstance(widget, QSpinBox):
47
+ value = widget.value()
48
+ elif isinstance(widget, QDoubleSpinBox):
49
+ value = widget.value()
50
+
51
+ return value
52
+
53
+
54
+ class InputFormDialog(QDialog):
55
+ """reference value for external use"""
56
+
57
+ value = pyqtSignal(dict)
23
58
 
24
59
  def __init__(
25
60
  self,
26
61
  parent=None,
27
- title: str = "Input",
28
- msg_str: str = "Enter Input:",
29
- input_type: type = str,
30
- **opts,
62
+ form_data: list[dict] | None = None,
63
+ opts: DialogOptions | None = None,
31
64
  ):
32
65
  super().__init__(parent)
33
66
 
34
- self.setWindowTitle(title)
67
+ opts = opts or DialogOptions(title="Input")
68
+ opts.apply(self)
35
69
 
36
- QBtn = (
37
- QDialogButtonBox.StandardButton.Cancel
38
- | QDialogButtonBox.StandardButton.Open
39
- )
70
+ self.form_data: list[dict] = [obj.copy() for obj in form_data or []]
71
+ self.input_widgets: dict[str, QWidget] = {}
40
72
 
41
- self.buttonBox = QDialogButtonBox(QBtn)
42
- self.buttonBox.accepted.connect(self.accept)
43
- self.buttonBox.rejected.connect(self.reject)
73
+ self.main_layout = QVBoxLayout()
74
+ self.construct_widgets()
44
75
 
45
- layout = QVBoxLayout()
46
- message = QLabel(msg_str)
47
- layout.addWidget(message)
76
+ button_box = QHBoxLayout()
77
+ submit_btn = QPushButton("Submit", parent=self)
78
+ submit_btn.clicked.connect(self.submit)
48
79
 
49
- self.input_widget = None
50
- if input_type is str:
51
- self.input_widget = QLineEdit()
52
- elif input_type is int:
53
- self.input_widget = QSpinBox()
54
- elif input_type is float:
55
- self.input_widget = QDoubleSpinBox()
80
+ cancel_btn = QPushButton("Cancel", parent=self)
81
+ cancel_btn.clicked.connect(self.close)
56
82
 
57
- self._init_widget(**opts)
83
+ button_box.addWidget(submit_btn)
84
+ button_box.addWidget(cancel_btn)
85
+ self.main_layout.addLayout(button_box)
58
86
 
59
- layout.addWidget(self.input_widget)
60
- layout.addWidget(self.buttonBox)
61
- self.setLayout(layout)
87
+ self.setLayout(self.main_layout)
62
88
 
63
- def _init_widget(self, **opts) -> None:
64
- for key, value in opts.items():
65
- setter_key = f"set{key[0].upper() + key[1:]}"
66
- if hasattr(self.input_widget, setter_key):
67
- setter = getattr(self.input_widget, setter_key)
68
- if setter:
69
- setter(value)
89
+ def construct_widgets(self) -> None:
90
+ for widget_def in self.form_data:
91
+ if not "type" in widget_def:
92
+ continue
70
93
 
71
- def connect(self, callback: Callable) -> None:
72
- for parm_type in self.signal_types:
73
- self.value[parm_type].connect(callback)
94
+ layout = QHBoxLayout()
74
95
 
75
- def accept(self):
76
- # Emit the custom signal with data when the dialog is accepted
96
+ w_type = widget_def.pop("type")
97
+ label = widget_def.pop("label", "")
98
+ key = widget_def.pop("key", "")
99
+ if not key:
100
+ continue
77
101
 
78
- if isinstance(self.input_widget, QLineEdit):
79
- self.value[str].emit(self.input_widget.text())
80
- elif isinstance(self.input_widget, QSpinBox):
81
- self.value[int].emit(self.input_widget.value())
82
- elif isinstance(self.input_widget, QDoubleSpinBox):
83
- self.value[float].emit(self.input_widget.value())
102
+ widget = get_widget(w_type)
103
+ if not widget:
104
+ continue
105
+ if label and isinstance(label, str):
106
+ layout.addWidget(QLabel(label))
84
107
 
85
- super().accept()
108
+ if widget_def:
109
+ self._init_widget(widget, **widget_def)
110
+ layout.addWidget(widget)
111
+ self.main_layout.addLayout(layout)
112
+ self.input_widgets[key] = widget
113
+
114
+ def get_form_data(self) -> dict:
115
+ form_values: dict[str, Any] = {}
116
+
117
+ for key, widget in self.input_widgets.items():
118
+ value = get_widget_val(widget)
119
+ if value:
120
+ form_values[key] = value
121
+
122
+ return form_values
123
+
124
+ def submit(self) -> None:
125
+ form_data = self.get_form_data()
126
+ self.value.emit(form_data)
127
+ self.close()
128
+
129
+ def close(self) -> bool:
130
+ self.deleteLater()
131
+
132
+ return super().close()
133
+
134
+ def _init_widget(self, widget: QWidget, **opts) -> None:
135
+ for key, value in opts.items():
136
+ setter_key = f"set{key[0].upper() + key[1:]}"
137
+ if hasattr(widget, setter_key):
138
+ setter = getattr(widget, setter_key)
139
+ if setter:
140
+ setter(value)
@@ -0,0 +1,85 @@
1
+ from typing import Any, Callable
2
+
3
+ from PyQt6.QtCore import pyqtSignal
4
+ from PyQt6.QtWidgets import (
5
+ QDialog,
6
+ QDialogButtonBox,
7
+ QDoubleSpinBox,
8
+ QLabel,
9
+ QLineEdit,
10
+ QSpinBox,
11
+ QVBoxLayout,
12
+ )
13
+
14
+
15
+ INPUT_SIGNAL_TYPES: tuple[Any, ...] = (str, int, float)
16
+
17
+
18
+ class InputDialog(QDialog):
19
+ signal_types: tuple[Any] = INPUT_SIGNAL_TYPES
20
+ """ reference value for external use """
21
+
22
+ value = pyqtSignal(*([ptype] for ptype in INPUT_SIGNAL_TYPES))
23
+
24
+ def __init__(
25
+ self,
26
+ parent=None,
27
+ title: str = "Input",
28
+ msg_str: str = "Enter Input:",
29
+ input_type: type = str,
30
+ **opts,
31
+ ):
32
+ super().__init__(parent)
33
+
34
+ self.setWindowTitle(title)
35
+
36
+ QBtn = (
37
+ QDialogButtonBox.StandardButton.Cancel
38
+ | QDialogButtonBox.StandardButton.Open
39
+ )
40
+
41
+ self.buttonBox = QDialogButtonBox(QBtn)
42
+ self.buttonBox.accepted.connect(self.accept)
43
+ self.buttonBox.rejected.connect(self.reject)
44
+
45
+ layout = QVBoxLayout()
46
+ message = QLabel(msg_str)
47
+ layout.addWidget(message)
48
+
49
+ self.input_widget = None
50
+ if input_type is str:
51
+ self.input_widget = QLineEdit()
52
+ elif input_type is int:
53
+ self.input_widget = QSpinBox()
54
+ elif input_type is float:
55
+ self.input_widget = QDoubleSpinBox()
56
+
57
+ self._init_widget(**opts)
58
+
59
+ layout.addWidget(self.input_widget)
60
+ layout.addWidget(self.buttonBox)
61
+ self.setLayout(layout)
62
+
63
+ def _init_widget(self, **opts) -> None:
64
+ for key, value in opts.items():
65
+ setter_key = f"set{key[0].upper() + key[1:]}"
66
+ if hasattr(self.input_widget, setter_key):
67
+ setter = getattr(self.input_widget, setter_key)
68
+ if setter:
69
+ setter(value)
70
+
71
+ def connect(self, callback: Callable) -> None:
72
+ for parm_type in self.signal_types:
73
+ self.value[parm_type].connect(callback)
74
+
75
+ def accept(self):
76
+ # Emit the custom signal with data when the dialog is accepted
77
+
78
+ if isinstance(self.input_widget, QLineEdit):
79
+ self.value[str].emit(self.input_widget.text())
80
+ elif isinstance(self.input_widget, QSpinBox):
81
+ self.value[int].emit(self.input_widget.value())
82
+ elif isinstance(self.input_widget, QDoubleSpinBox):
83
+ self.value[float].emit(self.input_widget.value())
84
+
85
+ super().accept()
jbqt/models/__init__.py CHANGED
@@ -2,11 +2,13 @@
2
2
 
3
3
  from jbqt.models.chips import IChipsWidget
4
4
  from jbqt.models.chip_button import IChipButton
5
+ from jbqt.models.dialog_options import DialogOptions
5
6
  from jbqt.models.model_consts import RegisteredFunctions
6
7
  from jbqt.models.model_utils import get_fct, register_fct
7
8
  from jbqt.models.toolbar_button import ToolbarButton
8
9
 
9
10
  __all__ = [
11
+ "DialogOptions",
10
12
  "get_fct",
11
13
  "IChipButton",
12
14
  "IChipsWidget",
@@ -0,0 +1,28 @@
1
+ from dataclasses import dataclass
2
+
3
+ from PyQt6.QtCore import QObject
4
+ from PyQt6.QtWidgets import QWidget, QMainWindow, QApplication, QDialog
5
+
6
+
7
+ @dataclass
8
+ class DialogOptions:
9
+ title: str = ""
10
+ x_pos: int | None = None
11
+ y_pos: int | None = None
12
+ height: int | None = None
13
+ width: int | None = None
14
+
15
+ def apply(self, q_obj: QWidget | QMainWindow | QDialog):
16
+ if self.title:
17
+ q_obj.setWindowTitle(self.title)
18
+
19
+ h, w, x, y = self.height, self.width, self.x_pos, self.y_pos
20
+ if h or w:
21
+ h = h or 400
22
+ w = w or 400
23
+ q_obj.resize(w, h)
24
+
25
+ if x is not None or y is not None:
26
+ x = x or 0
27
+ y = y or 0
28
+ q_obj.move(x, y)
jbqt/widgets/chips.py CHANGED
@@ -96,7 +96,7 @@ class ChipsWidget(IChipsWidget):
96
96
  input_layout = QHBoxLayout()
97
97
  self.input_field = QLineEdit(self)
98
98
  self.add_button = QPushButton("Add", self)
99
- self.add_button.clicked.connect(self.add_chip)
99
+ self.add_button.clicked.connect(self.parse_chip_input)
100
100
 
101
101
  self.clear_button = QPushButton(consts.ICONS.TRASH("darkred"), "", self)
102
102
  self.clear_button.clicked.connect(self.remove_all)
@@ -124,7 +124,7 @@ class ChipsWidget(IChipsWidget):
124
124
  if a1.type() == QEvent.Type.KeyPress and focus == self.input_field:
125
125
  match a1.key():
126
126
  case Qt.Key.Key_Return | Qt.Key.Key_Enter:
127
- self.add_chip()
127
+ self.parse_chip_input()
128
128
  return super().eventFilter(a0, a1)
129
129
 
130
130
  def get_unweight_chip(self, tag: str) -> str:
@@ -221,8 +221,16 @@ class ChipsWidget(IChipsWidget):
221
221
  def emit_changes(self):
222
222
  self.valuesChanged.emit(self.values)
223
223
 
224
+ def parse_chip_input(self) -> None:
225
+ text = self.input_field.text().strip()
226
+ if "," in text:
227
+ self.add_chips(utils.parse_csv_line(text))
228
+ else:
229
+ self.add_chip()
230
+
224
231
  def add_chip(self):
225
232
  text = self.input_field.text().strip()
233
+
226
234
  if text and text not in self.values:
227
235
  chip_button = ChipButton(text, self.update_chip, self.remove_chip)
228
236
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jbqt
3
- Version: 0.1.16
3
+ Version: 0.1.18
4
4
  Summary:
5
5
  Author: Joseph Bochinski
6
6
  Author-email: stirgejr@gmail.com
@@ -9,7 +9,7 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.12
10
10
  Requires-Dist: fuzzywuzzy (>=0.18.0,<0.19.0)
11
11
  Requires-Dist: jbconsts (>=0.1.1,<0.2.0)
12
- Requires-Dist: jbutils (>=0.1.23,<0.2.0)
12
+ Requires-Dist: jbutils (>=0.1.27,<0.2.0)
13
13
  Requires-Dist: pyqt6 (>=6.9.0,<7.0.0)
14
14
  Requires-Dist: python-levenshtein (>=0.27.1,<0.28.0)
15
15
  Requires-Dist: rich (>=14.0.0,<15.0.0)
@@ -2,13 +2,15 @@ jbqt/__init__.py,sha256=qGE1sO5jh_hT3pr4AQQBKELiPxqSFna__j8u-sJz2nU,161
2
2
  jbqt/common/__init__.py,sha256=knxf7Rc2gEN9qjWgZQdSu8oIznNlR6Z8D4zD_KU3UCE,151
3
3
  jbqt/common/qt_utils.py,sha256=ag_CJfEQK-xFg8PvX6m4A5GplMjcRKFVCledVQVF9CA,2300
4
4
  jbqt/consts/__init__.py,sha256=J2-z6t848A-FzSiZ7sASONSKn9Zn7VOSIphMNhv9zTE,6018
5
- jbqt/dialogs/__init__.py,sha256=DZi-qwW75JKfTLk33bowjt9Nhn1mpOO6kmP7mSMGz0o,245
5
+ jbqt/dialogs/__init__.py,sha256=8FBzE6e-0rupN4ODzNpTHHJZxfKGyciLIfYWSEKSrGs,318
6
6
  jbqt/dialogs/file_dialog.py,sha256=QMUxgSNt1IGLqgPgKqrEwlPjKIQ7D5qrY2cJCXmW654,1830
7
- jbqt/dialogs/input_form.py,sha256=pJVuP5fYc9USiwLmaSm66hrr-iW8XeZSY3eqxIUnVd0,2456
7
+ jbqt/dialogs/input_form.py,sha256=VYq8DRqMb3ZEOhyCl6NH_TssU8ekCVUxnTm75No7xSM,3741
8
+ jbqt/dialogs/single_input.py,sha256=pJVuP5fYc9USiwLmaSm66hrr-iW8XeZSY3eqxIUnVd0,2456
8
9
  jbqt/dialogs/text_preview.py,sha256=5rZjMvvMPq0jenPQkxKTFsGzuebdH_EnjKsdgNzv93o,1244
9
- jbqt/models/__init__.py,sha256=Wqk71mCSqtxWHIielBecnsw5TmlgQxjk48UbKo1Lu9M,417
10
+ jbqt/models/__init__.py,sha256=ZftJAf2S8rqoN1o_pJ2yYAhoENnKsofttt64b1kYxdE,491
10
11
  jbqt/models/chip_button.py,sha256=lG76aNgnrZcSw5QzAJ6UUHMbNNkDI-yZAp3iJlKr0Ms,220
11
12
  jbqt/models/chips.py,sha256=Qil50f1DcmYDHxiQgf0qs0kqERb-PTH37eOLHCuWA2o,625
13
+ jbqt/models/dialog_options.py,sha256=r3_0eVC3swrfUcbaV2mTXszuoBs4mbFK9r5okHB3boE,730
12
14
  jbqt/models/model_consts.py,sha256=84xPj4RNCGib7d4dBOOybzD3z0_uav37jrzqGfZkAQ8,170
13
15
  jbqt/models/model_utils.py,sha256=Tf8QwJKHj3vpAkSTn-qP3XdihKnPqJvr5gq2c-8cCJM,809
14
16
  jbqt/models/toolbar_button.py,sha256=5jQisgsFaQ7_b0D-bV9jiHDIMOO6-j_H8qgA2Qdn7NU,1736
@@ -16,11 +18,11 @@ jbqt/types/__init__.py,sha256=er6dhNIqsfQr8mdpA2f7LIvX2CPmRG2Xyqj0cneitpg,407
16
18
  jbqt/view_icons.py,sha256=Jy_o5dFSzKZGUX7oBq0sEi8jTrI5eI4COu5e4bWKT9o,6559
17
19
  jbqt/widgets/__init__.py,sha256=WxDWM5MDnB9NkvaYxE4AiT7tFjGB9fBirEx2iZUujeU,523
18
20
  jbqt/widgets/chip_button.py,sha256=mmh9EZfYY-d0hiQbGIZDvmi6RrBfKgGein_f_69gnCY,6362
19
- jbqt/widgets/chips.py,sha256=DH6Y1xr7vydq7dNOlETcXaOPy6rTu8IfrdUO8BAKjmg,8123
21
+ jbqt/widgets/chips.py,sha256=THekZ4LUHQ5lXMbQoh16y0vYAb-0ulWNIv8YI5HMKwc,8349
20
22
  jbqt/widgets/multiselect.py,sha256=ucL6QeFHs12DnHAHASMwdOD9YFYu4x4NDCYa6Pl41HM,7328
21
23
  jbqt/widgets/simple.py,sha256=pj2PBdR1am7VtPi4jGxsKm5nOLyTwiZV4jCuTd58rpk,1841
22
24
  jbqt/widgets/toast.py,sha256=S85PgcydbmICnjSY5VR6KUG_UZv4UERjvE_mP_zE9GA,1179
23
25
  jbqt/widgets/widget_utils.py,sha256=IEVg60rJ6hL0_9wre7j-_aprg-fccNZhwwOtbVEmHvw,2525
24
- jbqt-0.1.16.dist-info/METADATA,sha256=w4GgzEmkvlAPj0BhqiV1FD12BVNXMEnDQyOhBCOFTyQ,544
25
- jbqt-0.1.16.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
26
- jbqt-0.1.16.dist-info/RECORD,,
26
+ jbqt-0.1.18.dist-info/METADATA,sha256=LuBD7VrwmWKKUeaDh81szdCSGcoC38FmX_SaUXPy7s0,544
27
+ jbqt-0.1.18.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
28
+ jbqt-0.1.18.dist-info/RECORD,,
File without changes