easycoder 251104.1__py2.py3-none-any.whl → 260108.1__py2.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 easycoder might be problematic. Click here for more details.

Files changed (60) hide show
  1. easycoder/__init__.py +6 -3
  2. easycoder/debugger/__init__.py +5 -0
  3. easycoder/debugger/ec_dbg_value_display copy.py +195 -0
  4. easycoder/debugger/ec_dbg_value_display.py +24 -0
  5. easycoder/debugger/ec_dbg_watch_list copy.py +219 -0
  6. easycoder/debugger/ec_dbg_watchlist.py +293 -0
  7. easycoder/debugger/ec_debug.py +1025 -0
  8. easycoder/ec_border.py +15 -11
  9. easycoder/ec_classes.py +494 -7
  10. easycoder/ec_compiler.py +82 -44
  11. easycoder/ec_condition.py +1 -1
  12. easycoder/ec_core.py +1043 -1089
  13. easycoder/ec_gclasses.py +236 -0
  14. easycoder/ec_graphics.py +1683 -0
  15. easycoder/ec_handler.py +18 -13
  16. easycoder/ec_keyboard.py +50 -50
  17. easycoder/ec_mqtt.py +249 -0
  18. easycoder/ec_program.py +313 -152
  19. easycoder/ec_psutil.py +48 -0
  20. easycoder/ec_timestamp.py +2 -1
  21. easycoder/ec_value.py +65 -47
  22. easycoder/icons/exit.png +0 -0
  23. easycoder/icons/run.png +0 -0
  24. easycoder/icons/step.png +0 -0
  25. easycoder/icons/stop.png +0 -0
  26. easycoder/pre/README.md +3 -0
  27. easycoder/pre/__init__.py +17 -0
  28. easycoder/pre/debugger/__init__.py +5 -0
  29. easycoder/pre/debugger/ec_dbg_value_display copy.py +195 -0
  30. easycoder/pre/debugger/ec_dbg_value_display.py +24 -0
  31. easycoder/pre/debugger/ec_dbg_watch_list copy.py +219 -0
  32. easycoder/pre/debugger/ec_dbg_watchlist.py +293 -0
  33. easycoder/pre/debugger/ec_debug.py +1014 -0
  34. easycoder/pre/ec_border.py +67 -0
  35. easycoder/pre/ec_classes.py +470 -0
  36. easycoder/pre/ec_compiler.py +291 -0
  37. easycoder/pre/ec_condition.py +27 -0
  38. easycoder/pre/ec_core.py +2772 -0
  39. easycoder/pre/ec_gclasses.py +230 -0
  40. easycoder/{ec_pyside.py → pre/ec_graphics.py} +631 -494
  41. easycoder/pre/ec_handler.py +79 -0
  42. easycoder/pre/ec_keyboard.py +439 -0
  43. easycoder/pre/ec_program.py +557 -0
  44. easycoder/pre/ec_psutil.py +48 -0
  45. easycoder/pre/ec_timestamp.py +11 -0
  46. easycoder/pre/ec_value.py +124 -0
  47. easycoder/pre/icons/close.png +0 -0
  48. easycoder/pre/icons/exit.png +0 -0
  49. easycoder/pre/icons/run.png +0 -0
  50. easycoder/pre/icons/step.png +0 -0
  51. easycoder/pre/icons/stop.png +0 -0
  52. easycoder/pre/icons/tick.png +0 -0
  53. {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/METADATA +11 -1
  54. easycoder-260108.1.dist-info/RECORD +59 -0
  55. easycoder-251104.1.dist-info/RECORD +0 -19
  56. /easycoder/{close.png → icons/close.png} +0 -0
  57. /easycoder/{tick.png → icons/tick.png} +0 -0
  58. {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/WHEEL +0 -0
  59. {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/entry_points.txt +0 -0
  60. {easycoder-251104.1.dist-info → easycoder-260108.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,79 @@
1
+ import sys, json
2
+ from .ec_classes import FatalError, ECValue
3
+
4
+ class Handler:
5
+
6
+ def __init__(self, compiler):
7
+ self.compiler = compiler
8
+ self.program = compiler.program
9
+ self.getToken = compiler.getToken
10
+ self.nextToken = compiler.nextToken
11
+ self.skip = compiler.skip
12
+ self.skipArticles = compiler.skipArticles
13
+ self.peek = compiler.peek
14
+ self.getValue = compiler.getValue
15
+ self.nextValue = compiler.nextValue
16
+ self.getConstant = compiler.getConstant
17
+ self.getCondition = compiler.getCondition
18
+ self.nextCondition = compiler.nextCondition
19
+ self.tokenIs = compiler.tokenIs
20
+ self.nextIs = compiler.nextIs
21
+ self.isSymbol = compiler.isSymbol
22
+ self.nextIsSymbol = compiler.nextIsSymbol
23
+ self.compileVariable = compiler.compileVariable
24
+ self.compileSymbol = compiler.compileSymbol
25
+ self.getSymbolRecord = compiler.getSymbolRecord
26
+ self.rewindTo = compiler.rewindTo
27
+ self.warning = compiler.warning
28
+ self.getCodeSize = compiler.getCodeSize
29
+ self.add = compiler.addCommand
30
+ self.getCommandAt = compiler.getCommandAt
31
+ self.compileOne = compiler.compileOne
32
+ self.compileFromHere = compiler.compileFromHere
33
+ self.compileConstant = compiler.compileConstant
34
+
35
+ self.code = self.program.code
36
+ self.checkObjectType = self.program.checkObjectType
37
+ self.isObjectType = self.program.isObjectType
38
+ self.isObjectType = self.program.isObjectType
39
+ self.getInnerObject = self.program.getInnerObject
40
+ self.getItemType = self.program.getItemType
41
+ self.evaluate = self.program.evaluate
42
+ self.getVariable = self.program.getVariable
43
+ self.getObject = self.program.getObject
44
+ self.textify = self.program.textify
45
+ self.testCondition = self.program.condition.testCondition
46
+ self.symbols = self.program.symbols
47
+ self.stack = self.program.stack
48
+ self.getSymbolContent = self.program.getSymbolContent
49
+ self.getSymbolValue = self.program.getSymbolValue
50
+ self.putSymbolValue = self.program.putSymbolValue
51
+ self.run = self.program.run
52
+ self.callback = self.program.callback
53
+
54
+ self.nonNumericValueError = self.program.nonNumericValueError
55
+
56
+ def nextPC(self):
57
+ return self.program.pc + 1
58
+
59
+ # Get a compile handler (raises an Exception if none)
60
+ def keywordHandler(self, name):
61
+ if hasattr(self, f'k_{name}'):
62
+ return getattr(self, f'k_{name}')
63
+ return None
64
+
65
+ # Get a run handler
66
+ def runHandler(self, name):
67
+ return getattr(self, f'r_{name}')
68
+
69
+ # Get a value handler
70
+ def valueHandler(self, name):
71
+ return getattr(self, f'v_{name}')
72
+
73
+ # Get a condition handler
74
+ def conditionHandler(self, name):
75
+ return getattr(self, f'c_{name}')
76
+
77
+ # Get the value of an unknown item (domain-specific)
78
+ def getUnknownValue(self, value):
79
+ return None # Unable to get value
@@ -0,0 +1,439 @@
1
+ from .ec_handler import Handler
2
+ from .ec_border import Border
3
+ from PySide6.QtWidgets import (
4
+ QDialog,
5
+ QVBoxLayout,
6
+ QHBoxLayout,
7
+ QPushButton,
8
+ QLineEdit,
9
+ QPlainTextEdit,
10
+ QWidget,
11
+ QStackedWidget,
12
+ QSpacerItem,
13
+ QSizePolicy,
14
+ QGraphicsDropShadowEffect
15
+ )
16
+ from PySide6.QtGui import QFont, QIcon, QPixmap, QPainter
17
+ from PySide6.QtCore import Qt, QTimer, Signal, QRect
18
+
19
+ class Keyboard(Handler):
20
+ iconClicked = Signal()
21
+
22
+ def __init__(self, program, keyboardType, receiverLayout, receivers, caller = None, parent=None):
23
+ super().__init__(program.compiler)
24
+
25
+ self.program = program
26
+ self.receivers = receivers
27
+
28
+ dialog = QDialog(caller)
29
+ self.dialog = dialog
30
+
31
+ # dialog.setWindowTitle('')
32
+ dialog.setWindowFlags(Qt.WindowType.FramelessWindowHint)
33
+ dialog.setModal(True)
34
+ dialog.setFixedWidth(500)
35
+ dialog.setStyleSheet('background-color: white;border:1px solid black;')
36
+
37
+ # Add drop shadow
38
+ shadow = QGraphicsDropShadowEffect(dialog)
39
+ shadow.setBlurRadius(40)
40
+ shadow.setOffset(0, 4)
41
+ shadow.setColor(Qt.GlobalColor.black)
42
+ dialog.setGraphicsEffect(shadow)
43
+
44
+ # Add the keyboard
45
+ layout = QVBoxLayout(dialog)
46
+
47
+ border = Border()
48
+ border.tickClicked.connect(self.dialog.accept)
49
+ border.closeClicked.connect(self.reject)
50
+ layout.addWidget(border)
51
+ layout.addLayout(receiverLayout)
52
+ self.vk = VirtualKeyboard(keyboardType, 42, receivers[0], dialog.accept)
53
+ layout.addWidget(self.vk)
54
+
55
+ restore = []
56
+ index = 0
57
+ for receiver in receivers:
58
+ receiver.field.setContainer(self)
59
+ receiver.index = index
60
+ restore.append(receiver.getContent())
61
+ index += 1
62
+ self.restore = restore
63
+
64
+ # Position at bottom of parent window
65
+ dialog.show() # Ensure geometry is calculated
66
+ if parent:
67
+ parent_pos = parent.mapToGlobal(parent.rect().bottomLeft())
68
+ x = parent_pos.x() + (parent.width - dialog.width()) / 2
69
+ y = parent_pos.y() - dialog.height() - 40
70
+ dialog.move(x, y)
71
+
72
+ dialog.exec()
73
+
74
+ def setClickSource(self, field):
75
+ receivers = self.receivers
76
+ for receiver in receivers:
77
+ if receiver.field == field:
78
+ self.vk.setReceiver(receiver)
79
+ return
80
+
81
+ def reject(self):
82
+ receivers = self.receivers
83
+ index = 0
84
+ for receiver in receivers:
85
+ receiver.setContent(self.restore[index])
86
+ index += 1
87
+ self.dialog.reject()
88
+
89
+ class TextReceiver():
90
+ def __init__(self, field):
91
+ self.field = field
92
+
93
+ def addCharacter(self, char):
94
+ char = char.replace('&&', '&')
95
+ if len(char) == 1:
96
+ self.setContent(self.getContent() + char)
97
+ else:
98
+ raise ValueError("Only single characters are allowed.")
99
+
100
+ def backspace(self):
101
+ current_text = self.getContent()
102
+ if current_text:
103
+ self.setContent(current_text[:-1])
104
+
105
+ def setContent(self, text):
106
+ if isinstance(self.field, QLineEdit):
107
+ self.field.setText(text)
108
+ elif isinstance(self.field, QPlainTextEdit):
109
+ self.field.setPlainText(text)
110
+
111
+ def getContent(self):
112
+ if isinstance(self.field, QLineEdit):
113
+ return self.field.text()
114
+ elif isinstance(self.field, QPlainTextEdit):
115
+ return self.field.toPlainText()
116
+
117
+ class KeyboardButton(QPushButton):
118
+ def __init__(self, width, height, onClick, text=None, icon=None):
119
+ if text != None: text = text.replace('&','&&')
120
+ super().__init__(text)
121
+ self.setFixedSize(width, height)
122
+ self.setFont(QFont("Arial", height // 2)) # Font size is half the button height
123
+ self.setStyleSheet(f"""
124
+ QPushButton {{
125
+ background-color: white;
126
+ border: none;
127
+ border-radius: {int(height * 0.2)}px; /* Rounded corners */
128
+ }}
129
+ QPushButton:pressed {{
130
+ background-color: #ddd; /* Slightly darker background when pressed */
131
+ }}
132
+ """)
133
+
134
+ if icon:
135
+ self.setIcon(QIcon(icon))
136
+ self.setIconSize(self.size())
137
+
138
+ self.clicked.connect(lambda: self.animate_button(onClick, text))
139
+
140
+ def animate_button(self, onClick, text):
141
+ # Move the button 2 pixels down and right
142
+ self.move(self.x() + 2, self.y() + 2)
143
+ QTimer.singleShot(200, lambda: self.move(self.x() - 2, self.y() - 2)) # Move back after 200ms
144
+ onClick(text)
145
+
146
+ class KeyboardRow(QHBoxLayout):
147
+ def __init__(self, items):
148
+ super().__init__()
149
+ for item in items:
150
+ if isinstance(item, QWidget):
151
+ self.addWidget(item)
152
+ elif isinstance(item, QSpacerItem):
153
+ self.addSpacerItem(item)
154
+
155
+ class KeyboardView(QVBoxLayout):
156
+ def __init__(self, rows):
157
+ super().__init__()
158
+ for row in rows:
159
+ self.addLayout(row)
160
+
161
+ ###############################################################################
162
+ # VirtualKeyboard Class
163
+ class VirtualKeyboard(QStackedWidget):
164
+ def __init__(self, keyboardType, buttonHeight, receiver, onFinished):
165
+ super().__init__()
166
+ self.keyboardType = keyboardType
167
+ self.buttonHeight = buttonHeight
168
+ self.receiver = receiver
169
+ self.onFinished = onFinished
170
+ self.setStyleSheet('background-color: #ccc;border:none;')
171
+
172
+ # Create the 4 keyboard layouts
173
+ self.addKeyboardLayout0()
174
+ self.addKeyboardLayout1()
175
+ self.addKeyboardLayout2()
176
+ self.addKeyboardLayout3()
177
+
178
+ ###########################################################################
179
+ # Add the first keyboard layout (lowercase letters)
180
+ def addKeyboardLayout0(self):
181
+ rowList = []
182
+
183
+ # Row 1: Numbers
184
+ # row1 = KeyboardRow([KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in '1234567890'])
185
+ # rowList.append(row1)
186
+
187
+ # Row 2: qwertyuiop
188
+ row2 = KeyboardRow([
189
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
190
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in 'qwertyuiop'],
191
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
192
+ ])
193
+ rowList.append(row2)
194
+
195
+ # Row 3: asdfghjkl with horizontal stretches
196
+ row3 = KeyboardRow([
197
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
198
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in 'asdfghjkl'],
199
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
200
+ ])
201
+ rowList.append(row3)
202
+
203
+ # Row 4: Shift, ZXC..., Backspace
204
+ row4 = KeyboardRow([
205
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
206
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickShift, None, 'img/up.png'),
207
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
208
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in 'zxcvbnm'],
209
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
210
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickBack, None, 'img/back.png'),
211
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
212
+ ])
213
+ rowList.append(row4)
214
+
215
+ # Row 5: Numbers, Space, Enter
216
+ row5 = KeyboardRow([
217
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
218
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickNumbers, None, 'img/numbers.png'),
219
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
220
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, ","),
221
+ KeyboardButton(self.buttonHeight * 5, self.buttonHeight, self.onClickSpace, None, 'keyboard/space.png'),
222
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, "."),
223
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
224
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickEnter, None, 'img/enter.png'),
225
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
226
+ ])
227
+ rowList.append(row5)
228
+
229
+ # Add the rows to the KeyboardView
230
+ keyboardView = KeyboardView(rowList)
231
+ container = QWidget()
232
+ container.setLayout(keyboardView)
233
+ self.addWidget(container)
234
+
235
+ ###########################################################################
236
+ # Add the second keyboard layout (uppercase letters)
237
+ def addKeyboardLayout1(self):
238
+ rowList = []
239
+
240
+ # Row 1: Numbers
241
+ # row1 = KeyboardRow([KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in '1234567890'])
242
+ # rowList.append(row1)
243
+
244
+ # Row 2: Uppercase QWERTY
245
+ row2 = KeyboardRow([
246
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
247
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in 'QWERTYUIOP'],
248
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
249
+ ])
250
+ rowList.append(row2)
251
+
252
+ # Row 3: Uppercase ASDFGHJKL with horizontal stretches
253
+ row3 = KeyboardRow([
254
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
255
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in 'ASDFGHJKL'],
256
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
257
+ ])
258
+ rowList.append(row3)
259
+
260
+ # Row 4: Shift, Uppercase ZXC..., Backspace
261
+ row4 = KeyboardRow([
262
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
263
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickShift, None, 'img/up.png'),
264
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
265
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in 'ZXCVBNM'],
266
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
267
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickBack, None, 'img/back.png'),
268
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
269
+ ])
270
+ rowList.append(row4)
271
+
272
+ # Row 5: Numbers, Space, Enter
273
+ row5 = KeyboardRow([
274
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
275
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickNumbers, None, 'img/numbers.png'),
276
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
277
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, ","),
278
+ KeyboardButton(self.buttonHeight * 5, self.buttonHeight, self.onClickSpace, None, 'img/space.png'),
279
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, "."),
280
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
281
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickEnter, None, 'img/enter.png'),
282
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
283
+ ])
284
+ rowList.append(row5)
285
+
286
+ # Add the rows to the KeyboardView
287
+ keyboardView = KeyboardView(rowList)
288
+ container = QWidget()
289
+ container.setLayout(keyboardView)
290
+ self.addWidget(container)
291
+
292
+ ###########################################################################
293
+ # Add the third keyboard layout (numbers and symbols)
294
+ def addKeyboardLayout2(self):
295
+ rowList = []
296
+
297
+ # Row 1: Numbers
298
+ row1 = KeyboardRow([
299
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
300
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in '1234567890'],
301
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
302
+ ])
303
+ rowList.append(row1)
304
+
305
+ # Row 2: Symbols
306
+ row2 = KeyboardRow([
307
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
308
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in '@#£&_-()=%'],
309
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
310
+ ])
311
+ rowList.append(row2)
312
+
313
+ # Row 3: Symbols with horizontal stretches
314
+ row3 = KeyboardRow([
315
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
316
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickSymbols, None, 'img/symbols.png'),
317
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
318
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in '"*\'/:!?+'],
319
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
320
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickBack, None, 'img/back.png'),
321
+ QSpacerItem(20, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
322
+ ])
323
+ rowList.append(row3)
324
+
325
+ # Row 4: Numbers, Space, Enter
326
+ row4 = KeyboardRow([
327
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
328
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickLetters, None, 'img/letters.png'),
329
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
330
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, ","),
331
+ KeyboardButton(self.buttonHeight * 5.2, self.buttonHeight, self.onClickSpace, None, 'keyboard/space.png'),
332
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, "."),
333
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
334
+ KeyboardButton(self.buttonHeight * 1.5, self.buttonHeight, self.onClickEnter, None, 'img/enter.png'),
335
+ QSpacerItem(10, 40, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
336
+ ])
337
+ rowList.append(row4)
338
+
339
+ # Add the rows to the KeyboardView
340
+ keyboardView = KeyboardView(rowList)
341
+ container = QWidget()
342
+ container.setLayout(keyboardView)
343
+ self.addWidget(container)
344
+
345
+ ###########################################################################
346
+ # Add the fourth keyboard layout (additional symbols)
347
+ def addKeyboardLayout3(self):
348
+ rowList = []
349
+
350
+ # Row 1: Extended symbols
351
+ row1 = KeyboardRow([
352
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
353
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in '$€¥¢©®µ~¿¡'],
354
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
355
+ ])
356
+ rowList.append(row1)
357
+
358
+ # Row 2: Additional symbols
359
+ row2 = KeyboardRow([
360
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
361
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in '¼½¾[]{}<>^'],
362
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
363
+ ])
364
+ rowList.append(row2)
365
+
366
+ # Row 3: Symbols with horizontal stretches
367
+ row3 = KeyboardRow([
368
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
369
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickNumbers, None, 'img/numbers.png'),
370
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
371
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in '`;÷\\∣|¬±'],
372
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
373
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickBack, None, 'img/back.png'),
374
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
375
+ ])
376
+ rowList.append(row3)
377
+
378
+ # Row 4: Numbers, Space, Enter
379
+ row4 = KeyboardRow([
380
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum),
381
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickLetters, None, 'img/letters.png'),
382
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
383
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, ","),
384
+ KeyboardButton(self.buttonHeight * 3, self.buttonHeight, self.onClickSpace, None, 'img/space.png'),
385
+ QSpacerItem(self.buttonHeight * 0.05, 0, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum),
386
+ *[KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickChar, char) for char in '✕§¶°'],
387
+ KeyboardButton(self.buttonHeight, self.buttonHeight, self.onClickEnter, None, 'img/enter.png'),
388
+ QSpacerItem(0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
389
+ ])
390
+ rowList.append(row4)
391
+
392
+ # Add the rows to the KeyboardView
393
+ keyboardView = KeyboardView(rowList)
394
+ container = QWidget()
395
+ container.setLayout(keyboardView)
396
+ self.addWidget(container)
397
+
398
+ def setReceiver(self, receiver):
399
+ self.receiver = receiver
400
+
401
+ def getReceiver(self):
402
+ return self.receiver
403
+
404
+ # Callback functions
405
+ def onClickChar(self,keycode):
406
+ # print(f"Key pressed: {keycode}")
407
+ self.receiver.addCharacter(keycode)
408
+
409
+ def onClickShift(self,keycode):
410
+ # print("Shift pressed")
411
+ if self.currentIndex() == 0:
412
+ self.setCurrentIndex(1)
413
+ elif self.currentIndex() == 1:
414
+ self.setCurrentIndex(0)
415
+
416
+ def onClickLetters(self,keycode):
417
+ # print("Letters pressed")
418
+ self.setCurrentIndex(0)
419
+
420
+ def onClickNumbers(self,keycode):
421
+ # print("Numbers pressed")
422
+ self.setCurrentIndex(2)
423
+
424
+ def onClickSymbols(self,keycode):
425
+ # print("Symbols pressed")
426
+ self.setCurrentIndex(3)
427
+
428
+ def onClickBack(self,keycode):
429
+ # print("Backspace pressed")
430
+ self.receiver.backspace()
431
+
432
+ def onClickSpace(self,keycode):
433
+ # print("Space pressed")
434
+ self.receiver.addCharacter(' ')
435
+
436
+ def onClickEnter(self,keycode):
437
+ # print("Enter pressed")
438
+ if self.receiver.field.multiline: self.receiver.addCharacter('\n')
439
+ else: self.onFinished()