|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2009 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing specialized line edits. |
|
8 """ |
|
9 |
|
10 import enum |
|
11 |
|
12 from PyQt6.QtCore import pyqtSignal, Qt, QEvent |
|
13 from PyQt6.QtWidgets import ( |
|
14 QLineEdit, QWidget, QHBoxLayout, QBoxLayout, QLayout, QApplication, |
|
15 QSpacerItem, QSizePolicy |
|
16 ) |
|
17 |
|
18 |
|
19 class EricLineEditSideWidget(QWidget): |
|
20 """ |
|
21 Class implementing the side widgets for the line edit class. |
|
22 |
|
23 @signal sizeHintChanged() emitted to indicate a change of the size hint |
|
24 """ |
|
25 sizeHintChanged = pyqtSignal() |
|
26 |
|
27 def __init__(self, parent=None): |
|
28 """ |
|
29 Constructor |
|
30 |
|
31 @param parent reference to the parent widget (QWidget) |
|
32 """ |
|
33 super().__init__(parent) |
|
34 |
|
35 def event(self, evt): |
|
36 """ |
|
37 Public method to handle events. |
|
38 |
|
39 @param evt reference to the event (QEvent) |
|
40 @return flag indicating, whether the event was recognized (boolean) |
|
41 """ |
|
42 if evt.type() == QEvent.Type.LayoutRequest: |
|
43 self.sizeHintChanged.emit() |
|
44 return QWidget.event(self, evt) |
|
45 |
|
46 |
|
47 class EricLineEditSide(enum.Enum): |
|
48 """ |
|
49 Class defining the line edit sides. |
|
50 """ |
|
51 LEFT = 0 |
|
52 RIGHT = 1 |
|
53 |
|
54 |
|
55 class EricLineEdit(QLineEdit): |
|
56 """ |
|
57 Class implementing a line edit widget showing some inactive text. |
|
58 """ |
|
59 def __init__(self, parent=None, placeholderText=""): |
|
60 """ |
|
61 Constructor |
|
62 |
|
63 @param parent reference to the parent widget |
|
64 @type QWidget |
|
65 @param placeholderText text to be shown on inactivity |
|
66 @type str |
|
67 """ |
|
68 super().__init__(parent) |
|
69 |
|
70 self.setMinimumHeight(22) |
|
71 |
|
72 self.setPlaceholderText(placeholderText) |
|
73 |
|
74 self.__mainLayout = QHBoxLayout(self) |
|
75 self.__mainLayout.setContentsMargins(0, 0, 0, 0) |
|
76 self.__mainLayout.setSpacing(0) |
|
77 |
|
78 self.__leftMargin = 0 |
|
79 self.__leftWidget = EricLineEditSideWidget(self) |
|
80 self.__leftWidget.resize(0, 0) |
|
81 self.__leftLayout = QHBoxLayout(self.__leftWidget) |
|
82 self.__leftLayout.setContentsMargins(0, 0, 2, 0) |
|
83 if QApplication.isRightToLeft(): |
|
84 self.__leftLayout.setDirection(QBoxLayout.Direction.RightToLeft) |
|
85 else: |
|
86 self.__leftLayout.setDirection(QBoxLayout.Direction.LeftToRight) |
|
87 self.__leftLayout.setSizeConstraint( |
|
88 QLayout.SizeConstraint.SetFixedSize) |
|
89 |
|
90 self.__rightWidget = EricLineEditSideWidget(self) |
|
91 self.__rightWidget.resize(0, 0) |
|
92 self.__rightLayout = QHBoxLayout(self.__rightWidget) |
|
93 self.__rightLayout.setContentsMargins(0, 0, 2, 0) |
|
94 if self.isRightToLeft(): |
|
95 self.__rightLayout.setDirection(QBoxLayout.Direction.RightToLeft) |
|
96 else: |
|
97 self.__rightLayout.setDirection(QBoxLayout.Direction.LeftToRight) |
|
98 |
|
99 horizontalSpacer = QSpacerItem( |
|
100 0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) |
|
101 self.__mainLayout.addWidget( |
|
102 self.__leftWidget, 0, |
|
103 Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft) |
|
104 self.__mainLayout.addItem(horizontalSpacer) |
|
105 self.__mainLayout.addWidget( |
|
106 self.__rightWidget, 0, |
|
107 Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignRight) |
|
108 if self.isRightToLeft(): |
|
109 self.__mainLayout.setDirection(QBoxLayout.Direction.RightToLeft) |
|
110 else: |
|
111 self.__mainLayout.setDirection(QBoxLayout.Direction.LeftToRight) |
|
112 |
|
113 self.setWidgetSpacing(3) |
|
114 self.__leftWidget.sizeHintChanged.connect(self._updateTextMargins) |
|
115 self.__rightWidget.sizeHintChanged.connect(self._updateTextMargins) |
|
116 |
|
117 def setLeftMargin(self, margin): |
|
118 """ |
|
119 Public method to set the left margin. |
|
120 |
|
121 @param margin left margin in pixel (integer) |
|
122 """ |
|
123 self.__leftMargin = margin |
|
124 |
|
125 def leftMargin(self): |
|
126 """ |
|
127 Public method to get the size of the left margin. |
|
128 |
|
129 @return left margin in pixel (integer) |
|
130 """ |
|
131 return self.__leftMargin |
|
132 |
|
133 def event(self, evt): |
|
134 """ |
|
135 Public method to handle events. |
|
136 |
|
137 @param evt reference to the event (QEvent) |
|
138 @return flag indicating, whether the event was recognized (boolean) |
|
139 """ |
|
140 if evt.type() == QEvent.Type.LayoutDirectionChange: |
|
141 if self.isRightToLeft(): |
|
142 self.__mainLayout.setDirection( |
|
143 QBoxLayout.Direction.RightToLeft) |
|
144 self.__leftLayout.setDirection( |
|
145 QBoxLayout.Direction.RightToLeft) |
|
146 self.__rightLayout.setDirection( |
|
147 QBoxLayout.Direction.RightToLeft) |
|
148 else: |
|
149 self.__mainLayout.setDirection( |
|
150 QBoxLayout.Direction.LeftToRight) |
|
151 self.__leftLayout.setDirection( |
|
152 QBoxLayout.Direction.LeftToRight) |
|
153 self.__rightLayout.setDirection( |
|
154 QBoxLayout.Direction.LeftToRight) |
|
155 return QLineEdit.event(self, evt) |
|
156 |
|
157 def _updateTextMargins(self): |
|
158 """ |
|
159 Protected slot to update the text margins. |
|
160 """ |
|
161 left = ( |
|
162 self.__leftWidget.sizeHint().width() |
|
163 if self.__leftMargin == 0 else |
|
164 self.__leftMargin |
|
165 ) |
|
166 right = self.__rightWidget.sizeHint().width() |
|
167 top = 0 |
|
168 bottom = 0 |
|
169 self.setTextMargins(left, top, right, bottom) |
|
170 |
|
171 def addWidget(self, widget, position): |
|
172 """ |
|
173 Public method to add a widget to a side. |
|
174 |
|
175 @param widget reference to the widget to add |
|
176 @type QWidget |
|
177 @param position position to add to |
|
178 @type EricLineEditSide |
|
179 """ |
|
180 if widget is None: |
|
181 return |
|
182 |
|
183 if self.isRightToLeft(): |
|
184 if position == EricLineEditSide.LEFT: |
|
185 position = EricLineEditSide.RIGHT |
|
186 else: |
|
187 position = EricLineEditSide.LEFT |
|
188 if position == EricLineEditSide.LEFT: |
|
189 self.__leftLayout.addWidget(widget) |
|
190 else: |
|
191 self.__rightLayout.insertWidget(1, widget) |
|
192 |
|
193 def removeWidget(self, widget): |
|
194 """ |
|
195 Public method to remove a widget from a side. |
|
196 |
|
197 @param widget reference to the widget to remove |
|
198 @type QWidget |
|
199 """ |
|
200 if widget is None: |
|
201 return |
|
202 |
|
203 self.__leftLayout.removeWidget(widget) |
|
204 self.__rightLayout.removeWidget(widget) |
|
205 widget.hide() |
|
206 |
|
207 def widgetSpacing(self): |
|
208 """ |
|
209 Public method to get the side widget spacing. |
|
210 |
|
211 @return side widget spacing (integer) |
|
212 """ |
|
213 return self.__leftLayout.spacing() |
|
214 |
|
215 def setWidgetSpacing(self, spacing): |
|
216 """ |
|
217 Public method to set the side widget spacing. |
|
218 |
|
219 @param spacing side widget spacing (integer) |
|
220 """ |
|
221 self.__leftLayout.setSpacing(spacing) |
|
222 self.__rightLayout.setSpacing(spacing) |
|
223 self._updateTextMargins() |
|
224 |
|
225 def textMargin(self, position): |
|
226 """ |
|
227 Public method to get the text margin for a side. |
|
228 |
|
229 @param position side to get margin for |
|
230 @type EricLineEditSide |
|
231 @return text margin |
|
232 @rtype int |
|
233 """ |
|
234 spacing = self.__rightLayout.spacing() |
|
235 w = 0 |
|
236 w = ( |
|
237 self.__leftWidget.sizeHint().width() |
|
238 if position == EricLineEditSide.LEFT else |
|
239 self.__rightWidget.sizeHint().width() |
|
240 ) |
|
241 if w == 0: |
|
242 return 0 |
|
243 return w + spacing * 2 |
|
244 |
|
245 class EricClearableLineEdit(EricLineEdit): |
|
246 """ |
|
247 Class implementing a line edit widget showing some inactive text and a |
|
248 clear button, if it has some contents. |
|
249 """ |
|
250 def __init__(self, parent=None, placeholderText="", |
|
251 side=EricLineEditSide.RIGHT): |
|
252 """ |
|
253 Constructor |
|
254 |
|
255 @param parent reference to the parent widget |
|
256 @type QWidget |
|
257 @param placeholderText text to be shown on inactivity |
|
258 @type str |
|
259 @param side side the clear button should be shown at |
|
260 @type EricLineEditSide |
|
261 """ |
|
262 super().__init__(parent, placeholderText) |
|
263 |
|
264 self.setClearButtonEnabled(True) |