bec-widgets 1.13.0__py3-none-any.whl → 1.14.1__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.
- CHANGELOG.md +24 -0
- PKG-INFO +1 -1
- bec_widgets/cli/client.py +4 -0
- bec_widgets/widgets/games/__init__.py +3 -0
- bec_widgets/widgets/games/minesweeper.py +413 -0
- bec_widgets/widgets/games/minesweeper.pyproject +1 -0
- bec_widgets/widgets/games/minesweeper_plugin.py +54 -0
- bec_widgets/widgets/games/register_minesweeper.py +15 -0
- bec_widgets/widgets/utility/spinner/spinner.py +1 -1
- {bec_widgets-1.13.0.dist-info → bec_widgets-1.14.1.dist-info}/METADATA +1 -1
- {bec_widgets-1.13.0.dist-info → bec_widgets-1.14.1.dist-info}/RECORD +15 -10
- pyproject.toml +1 -1
- {bec_widgets-1.13.0.dist-info → bec_widgets-1.14.1.dist-info}/WHEEL +0 -0
- {bec_widgets-1.13.0.dist-info → bec_widgets-1.14.1.dist-info}/entry_points.txt +0 -0
- {bec_widgets-1.13.0.dist-info → bec_widgets-1.14.1.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
@@ -1,6 +1,30 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## v1.14.1 (2025-01-10)
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
- Cast spinner widget angle to int when using for arc
|
9
|
+
([`fa9ecaf`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fa9ecaf43347f6a07f86075d7ea54463684344f1))
|
10
|
+
|
11
|
+
|
12
|
+
## v1.14.0 (2025-01-09)
|
13
|
+
|
14
|
+
### Documentation
|
15
|
+
|
16
|
+
- Add docs for games/minesweeper
|
17
|
+
([`e2c7dc9`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e2c7dc98d2f1c627fcc1aac045fa32dc94057bb0))
|
18
|
+
|
19
|
+
### Features
|
20
|
+
|
21
|
+
- **widget**: Make Minesweeper into BEC widget
|
22
|
+
([`507d46f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/507d46f88bd06a3e77b1e60a6ce56c80f622cb6c))
|
23
|
+
|
24
|
+
- **widgets**: Added minesweeper widget
|
25
|
+
([`57dc1a3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/57dc1a3afc60b6c27b42c258a6fd1ea1ddb24637))
|
26
|
+
|
27
|
+
|
4
28
|
## v1.13.0 (2025-01-09)
|
5
29
|
|
6
30
|
### Bug Fixes
|
PKG-INFO
CHANGED
bec_widgets/cli/client.py
CHANGED
@@ -31,6 +31,7 @@ class Widgets(str, enum.Enum):
|
|
31
31
|
DeviceComboBox = "DeviceComboBox"
|
32
32
|
DeviceLineEdit = "DeviceLineEdit"
|
33
33
|
LMFitDialog = "LMFitDialog"
|
34
|
+
Minesweeper = "Minesweeper"
|
34
35
|
PositionIndicator = "PositionIndicator"
|
35
36
|
PositionerBox = "PositionerBox"
|
36
37
|
PositionerControlLine = "PositionerControlLine"
|
@@ -3181,6 +3182,9 @@ class LMFitDialog(RPCBase):
|
|
3181
3182
|
"""
|
3182
3183
|
|
3183
3184
|
|
3185
|
+
class Minesweeper(RPCBase): ...
|
3186
|
+
|
3187
|
+
|
3184
3188
|
class PositionIndicator(RPCBase):
|
3185
3189
|
@rpc_call
|
3186
3190
|
def set_value(self, position: float):
|
@@ -0,0 +1,413 @@
|
|
1
|
+
import enum
|
2
|
+
import random
|
3
|
+
import time
|
4
|
+
|
5
|
+
from bec_qthemes import material_icon
|
6
|
+
from qtpy.QtCore import QSize, Qt, QTimer, Signal, Slot
|
7
|
+
from qtpy.QtGui import QBrush, QColor, QPainter, QPen
|
8
|
+
from qtpy.QtWidgets import (
|
9
|
+
QApplication,
|
10
|
+
QComboBox,
|
11
|
+
QGridLayout,
|
12
|
+
QHBoxLayout,
|
13
|
+
QLabel,
|
14
|
+
QPushButton,
|
15
|
+
QVBoxLayout,
|
16
|
+
QWidget,
|
17
|
+
)
|
18
|
+
|
19
|
+
from bec_widgets.utils.bec_widget import BECWidget
|
20
|
+
|
21
|
+
NUM_COLORS = {
|
22
|
+
1: QColor("#f44336"),
|
23
|
+
2: QColor("#9C27B0"),
|
24
|
+
3: QColor("#3F51B5"),
|
25
|
+
4: QColor("#03A9F4"),
|
26
|
+
5: QColor("#00BCD4"),
|
27
|
+
6: QColor("#4CAF50"),
|
28
|
+
7: QColor("#E91E63"),
|
29
|
+
8: QColor("#FF9800"),
|
30
|
+
}
|
31
|
+
|
32
|
+
LEVELS: dict[str, tuple[int, int]] = {"1": (8, 10), "2": (16, 40), "3": (24, 99)}
|
33
|
+
|
34
|
+
|
35
|
+
class GameStatus(enum.Enum):
|
36
|
+
READY = 0
|
37
|
+
PLAYING = 1
|
38
|
+
FAILED = 2
|
39
|
+
SUCCESS = 3
|
40
|
+
|
41
|
+
|
42
|
+
class Pos(QWidget):
|
43
|
+
expandable = Signal(int, int)
|
44
|
+
clicked = Signal()
|
45
|
+
ohno = Signal()
|
46
|
+
|
47
|
+
def __init__(self, x, y, *args, **kwargs):
|
48
|
+
super().__init__(*args, **kwargs)
|
49
|
+
|
50
|
+
self.setFixedSize(QSize(20, 20))
|
51
|
+
|
52
|
+
self.x = x
|
53
|
+
self.y = y
|
54
|
+
self.is_start = False
|
55
|
+
self.is_mine = False
|
56
|
+
self.adjacent_n = 0
|
57
|
+
self.is_revealed = False
|
58
|
+
self.is_flagged = False
|
59
|
+
|
60
|
+
def reset(self):
|
61
|
+
"""Restore the tile to its original state before mine status is assigned"""
|
62
|
+
self.is_start = False
|
63
|
+
self.is_mine = False
|
64
|
+
self.adjacent_n = 0
|
65
|
+
|
66
|
+
self.is_revealed = False
|
67
|
+
self.is_flagged = False
|
68
|
+
|
69
|
+
self.update()
|
70
|
+
|
71
|
+
def paintEvent(self, event):
|
72
|
+
p = QPainter(self)
|
73
|
+
|
74
|
+
r = event.rect()
|
75
|
+
|
76
|
+
if self.is_revealed:
|
77
|
+
color = self.palette().base().color()
|
78
|
+
outer, inner = color, color
|
79
|
+
else:
|
80
|
+
outer, inner = (self.palette().highlightedText().color(), self.palette().text().color())
|
81
|
+
|
82
|
+
p.fillRect(r, QBrush(inner))
|
83
|
+
pen = QPen(outer)
|
84
|
+
pen.setWidth(1)
|
85
|
+
p.setPen(pen)
|
86
|
+
p.drawRect(r)
|
87
|
+
|
88
|
+
if self.is_revealed:
|
89
|
+
if self.is_mine:
|
90
|
+
p.drawPixmap(r, material_icon("experiment", convert_to_pixmap=True, filled=True))
|
91
|
+
|
92
|
+
elif self.adjacent_n > 0:
|
93
|
+
pen = QPen(NUM_COLORS[self.adjacent_n])
|
94
|
+
p.setPen(pen)
|
95
|
+
f = p.font()
|
96
|
+
f.setBold(True)
|
97
|
+
p.setFont(f)
|
98
|
+
p.drawText(r, Qt.AlignHCenter | Qt.AlignVCenter, str(self.adjacent_n))
|
99
|
+
|
100
|
+
elif self.is_flagged:
|
101
|
+
p.drawPixmap(
|
102
|
+
r,
|
103
|
+
material_icon(
|
104
|
+
"flag",
|
105
|
+
size=(50, 50),
|
106
|
+
convert_to_pixmap=True,
|
107
|
+
filled=True,
|
108
|
+
color=self.palette().base().color(),
|
109
|
+
),
|
110
|
+
)
|
111
|
+
p.end()
|
112
|
+
|
113
|
+
def flag(self):
|
114
|
+
self.is_flagged = not self.is_flagged
|
115
|
+
self.update()
|
116
|
+
|
117
|
+
self.clicked.emit()
|
118
|
+
|
119
|
+
def reveal(self):
|
120
|
+
self.is_revealed = True
|
121
|
+
self.update()
|
122
|
+
|
123
|
+
def click(self):
|
124
|
+
if not self.is_revealed:
|
125
|
+
self.reveal()
|
126
|
+
if self.adjacent_n == 0:
|
127
|
+
self.expandable.emit(self.x, self.y)
|
128
|
+
|
129
|
+
self.clicked.emit()
|
130
|
+
|
131
|
+
def mouseReleaseEvent(self, event):
|
132
|
+
if event.button() == Qt.MouseButton.RightButton and not self.is_revealed:
|
133
|
+
self.flag()
|
134
|
+
return
|
135
|
+
|
136
|
+
if event.button() == Qt.MouseButton.LeftButton:
|
137
|
+
self.click()
|
138
|
+
if self.is_mine:
|
139
|
+
self.ohno.emit()
|
140
|
+
|
141
|
+
|
142
|
+
class Minesweeper(BECWidget, QWidget):
|
143
|
+
|
144
|
+
PLUGIN = True
|
145
|
+
ICON_NAME = "videogame_asset"
|
146
|
+
USER_ACCESS = []
|
147
|
+
|
148
|
+
def __init__(self, parent=None, *args, **kwargs):
|
149
|
+
super().__init__(*args, **kwargs)
|
150
|
+
QWidget.__init__(self, parent=parent)
|
151
|
+
|
152
|
+
self._ui_initialised = False
|
153
|
+
self._timer_start_num_seconds = 0
|
154
|
+
self._set_level_params(LEVELS["1"])
|
155
|
+
|
156
|
+
self._init_ui()
|
157
|
+
self._init_map()
|
158
|
+
|
159
|
+
self.update_status(GameStatus.READY)
|
160
|
+
self.reset_map()
|
161
|
+
self.update_status(GameStatus.READY)
|
162
|
+
|
163
|
+
def _init_ui(self):
|
164
|
+
if self._ui_initialised:
|
165
|
+
return
|
166
|
+
self._ui_initialised = True
|
167
|
+
|
168
|
+
status_hb = QHBoxLayout()
|
169
|
+
self.mines = QLabel()
|
170
|
+
self.mines.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
|
171
|
+
f = self.mines.font()
|
172
|
+
f.setPointSize(24)
|
173
|
+
self.mines.setFont(f)
|
174
|
+
|
175
|
+
self.reset_button = QPushButton()
|
176
|
+
self.reset_button.setFixedSize(QSize(32, 32))
|
177
|
+
self.reset_button.setIconSize(QSize(32, 32))
|
178
|
+
self.reset_button.setFlat(True)
|
179
|
+
self.reset_button.pressed.connect(self.reset_button_pressed)
|
180
|
+
|
181
|
+
self.clock = QLabel()
|
182
|
+
self.clock.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
|
183
|
+
self.clock.setFont(f)
|
184
|
+
self._timer = QTimer()
|
185
|
+
self._timer.timeout.connect(self.update_timer)
|
186
|
+
self._timer.start(1000) # 1 second timer
|
187
|
+
self.mines.setText(f"{self.num_mines:03d}")
|
188
|
+
self.clock.setText("000")
|
189
|
+
|
190
|
+
status_hb.addWidget(self.mines)
|
191
|
+
status_hb.addWidget(self.reset_button)
|
192
|
+
status_hb.addWidget(self.clock)
|
193
|
+
|
194
|
+
level_hb = QHBoxLayout()
|
195
|
+
self.level_selector = QComboBox()
|
196
|
+
self.level_selector.addItems(list(LEVELS.keys()))
|
197
|
+
level_hb.addWidget(QLabel("Level: "))
|
198
|
+
level_hb.addWidget(self.level_selector)
|
199
|
+
self.level_selector.currentTextChanged.connect(self.change_level)
|
200
|
+
|
201
|
+
vb = QVBoxLayout()
|
202
|
+
vb.addLayout(level_hb)
|
203
|
+
vb.addLayout(status_hb)
|
204
|
+
|
205
|
+
self.grid = QGridLayout()
|
206
|
+
self.grid.setSpacing(5)
|
207
|
+
|
208
|
+
vb.addLayout(self.grid)
|
209
|
+
self.setLayout(vb)
|
210
|
+
|
211
|
+
def _init_map(self):
|
212
|
+
"""Redraw the grid of mines"""
|
213
|
+
|
214
|
+
# Remove any previous grid items and reset the grid
|
215
|
+
for i in reversed(range(self.grid.count())):
|
216
|
+
w: Pos = self.grid.itemAt(i).widget()
|
217
|
+
w.clicked.disconnect(self.on_click)
|
218
|
+
w.expandable.disconnect(self.expand_reveal)
|
219
|
+
w.ohno.disconnect(self.game_over)
|
220
|
+
w.setParent(None)
|
221
|
+
w.deleteLater()
|
222
|
+
|
223
|
+
# Add positions to the map
|
224
|
+
for x in range(0, self.b_size):
|
225
|
+
for y in range(0, self.b_size):
|
226
|
+
w = Pos(x, y)
|
227
|
+
self.grid.addWidget(w, y, x)
|
228
|
+
# Connect signal to handle expansion.
|
229
|
+
w.clicked.connect(self.on_click)
|
230
|
+
w.expandable.connect(self.expand_reveal)
|
231
|
+
w.ohno.connect(self.game_over)
|
232
|
+
|
233
|
+
def reset_map(self):
|
234
|
+
"""
|
235
|
+
Reset the map and add new mines.
|
236
|
+
"""
|
237
|
+
# Clear all mine positions
|
238
|
+
for x in range(0, self.b_size):
|
239
|
+
for y in range(0, self.b_size):
|
240
|
+
w = self.grid.itemAtPosition(y, x).widget()
|
241
|
+
w.reset()
|
242
|
+
|
243
|
+
# Add mines to the positions
|
244
|
+
positions = []
|
245
|
+
while len(positions) < self.num_mines:
|
246
|
+
x, y = (random.randint(0, self.b_size - 1), random.randint(0, self.b_size - 1))
|
247
|
+
if (x, y) not in positions:
|
248
|
+
w = self.grid.itemAtPosition(y, x).widget()
|
249
|
+
w.is_mine = True
|
250
|
+
positions.append((x, y))
|
251
|
+
|
252
|
+
def get_adjacency_n(x, y):
|
253
|
+
positions = self.get_surrounding(x, y)
|
254
|
+
num_mines = sum(1 if w.is_mine else 0 for w in positions)
|
255
|
+
|
256
|
+
return num_mines
|
257
|
+
|
258
|
+
# Add adjacencies to the positions
|
259
|
+
for x in range(0, self.b_size):
|
260
|
+
for y in range(0, self.b_size):
|
261
|
+
w = self.grid.itemAtPosition(y, x).widget()
|
262
|
+
w.adjacent_n = get_adjacency_n(x, y)
|
263
|
+
|
264
|
+
# Place starting marker
|
265
|
+
while True:
|
266
|
+
x, y = (random.randint(0, self.b_size - 1), random.randint(0, self.b_size - 1))
|
267
|
+
w = self.grid.itemAtPosition(y, x).widget()
|
268
|
+
# We don't want to start on a mine.
|
269
|
+
if (x, y) not in positions:
|
270
|
+
w = self.grid.itemAtPosition(y, x).widget()
|
271
|
+
w.is_start = True
|
272
|
+
|
273
|
+
# Reveal all positions around this, if they are not mines either.
|
274
|
+
for w in self.get_surrounding(x, y):
|
275
|
+
if not w.is_mine:
|
276
|
+
w.click()
|
277
|
+
break
|
278
|
+
|
279
|
+
def get_surrounding(self, x, y):
|
280
|
+
positions = []
|
281
|
+
for xi in range(max(0, x - 1), min(x + 2, self.b_size)):
|
282
|
+
for yi in range(max(0, y - 1), min(y + 2, self.b_size)):
|
283
|
+
positions.append(self.grid.itemAtPosition(yi, xi).widget())
|
284
|
+
return positions
|
285
|
+
|
286
|
+
def get_num_hidden(self) -> int:
|
287
|
+
"""
|
288
|
+
Get the number of hidden positions.
|
289
|
+
"""
|
290
|
+
return sum(
|
291
|
+
1
|
292
|
+
for x in range(0, self.b_size)
|
293
|
+
for y in range(0, self.b_size)
|
294
|
+
if not self.grid.itemAtPosition(y, x).widget().is_revealed
|
295
|
+
)
|
296
|
+
|
297
|
+
def get_num_remaining_flags(self) -> int:
|
298
|
+
"""
|
299
|
+
Get the number of remaining flags.
|
300
|
+
"""
|
301
|
+
return self.num_mines - sum(
|
302
|
+
1
|
303
|
+
for x in range(0, self.b_size)
|
304
|
+
for y in range(0, self.b_size)
|
305
|
+
if self.grid.itemAtPosition(y, x).widget().is_flagged
|
306
|
+
)
|
307
|
+
|
308
|
+
def reset_button_pressed(self):
|
309
|
+
match self.status:
|
310
|
+
case GameStatus.PLAYING:
|
311
|
+
self.game_over()
|
312
|
+
case GameStatus.FAILED | GameStatus.SUCCESS:
|
313
|
+
self.reset_map()
|
314
|
+
|
315
|
+
def reveal_map(self):
|
316
|
+
for x in range(0, self.b_size):
|
317
|
+
for y in range(0, self.b_size):
|
318
|
+
w = self.grid.itemAtPosition(y, x).widget()
|
319
|
+
w.reveal()
|
320
|
+
|
321
|
+
@Slot(str)
|
322
|
+
def change_level(self, level: str):
|
323
|
+
self._set_level_params(LEVELS[level])
|
324
|
+
self._init_map()
|
325
|
+
self.reset_map()
|
326
|
+
|
327
|
+
@Slot(int, int)
|
328
|
+
def expand_reveal(self, x, y):
|
329
|
+
"""
|
330
|
+
Expand the reveal to the surrounding
|
331
|
+
|
332
|
+
Args:
|
333
|
+
x (int): The x position.
|
334
|
+
y (int): The y position.
|
335
|
+
"""
|
336
|
+
for xi in range(max(0, x - 1), min(x + 2, self.b_size)):
|
337
|
+
for yi in range(max(0, y - 1), min(y + 2, self.b_size)):
|
338
|
+
w = self.grid.itemAtPosition(yi, xi).widget()
|
339
|
+
if not w.is_mine:
|
340
|
+
w.click()
|
341
|
+
|
342
|
+
@Slot()
|
343
|
+
def on_click(self):
|
344
|
+
"""
|
345
|
+
Handle the click event. If the game is not started, start the game.
|
346
|
+
"""
|
347
|
+
self.update_available_flags()
|
348
|
+
if self.status != GameStatus.PLAYING:
|
349
|
+
# First click.
|
350
|
+
self.update_status(GameStatus.PLAYING)
|
351
|
+
# Start timer.
|
352
|
+
self._timer_start_num_seconds = int(time.time())
|
353
|
+
return
|
354
|
+
self.check_win()
|
355
|
+
|
356
|
+
def update_available_flags(self):
|
357
|
+
"""
|
358
|
+
Update the number of available flags.
|
359
|
+
"""
|
360
|
+
self.mines.setText(f"{self.get_num_remaining_flags():03d}")
|
361
|
+
|
362
|
+
def check_win(self):
|
363
|
+
"""
|
364
|
+
Check if the game is won.
|
365
|
+
"""
|
366
|
+
if self.get_num_hidden() == self.num_mines:
|
367
|
+
self.update_status(GameStatus.SUCCESS)
|
368
|
+
|
369
|
+
def update_status(self, status: GameStatus):
|
370
|
+
"""
|
371
|
+
Update the status of the game.
|
372
|
+
|
373
|
+
Args:
|
374
|
+
status (GameStatus): The status of the game.
|
375
|
+
"""
|
376
|
+
self.status = status
|
377
|
+
match status:
|
378
|
+
case GameStatus.READY:
|
379
|
+
icon = material_icon(icon_name="add", convert_to_pixmap=False)
|
380
|
+
case GameStatus.PLAYING:
|
381
|
+
icon = material_icon(icon_name="smart_toy", convert_to_pixmap=False)
|
382
|
+
case GameStatus.FAILED:
|
383
|
+
icon = material_icon(icon_name="error", convert_to_pixmap=False)
|
384
|
+
case GameStatus.SUCCESS:
|
385
|
+
icon = material_icon(icon_name="celebration", convert_to_pixmap=False)
|
386
|
+
self.reset_button.setIcon(icon)
|
387
|
+
|
388
|
+
def update_timer(self):
|
389
|
+
"""
|
390
|
+
Update the timer.
|
391
|
+
"""
|
392
|
+
if self.status == GameStatus.PLAYING:
|
393
|
+
num_seconds = int(time.time()) - self._timer_start_num_seconds
|
394
|
+
self.clock.setText(f"{num_seconds:03d}")
|
395
|
+
|
396
|
+
def game_over(self):
|
397
|
+
"""Cause the game to end early"""
|
398
|
+
self.reveal_map()
|
399
|
+
self.update_status(GameStatus.FAILED)
|
400
|
+
|
401
|
+
def _set_level_params(self, level: tuple[int, int]):
|
402
|
+
self.b_size, self.num_mines = level
|
403
|
+
|
404
|
+
|
405
|
+
if __name__ == "__main__":
|
406
|
+
from bec_widgets.utils.colors import set_theme
|
407
|
+
|
408
|
+
app = QApplication([])
|
409
|
+
set_theme("light")
|
410
|
+
widget = Minesweeper()
|
411
|
+
widget.show()
|
412
|
+
|
413
|
+
app.exec_()
|
@@ -0,0 +1 @@
|
|
1
|
+
{'files': ['minesweeper.py']}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Copyright (C) 2022 The Qt Company Ltd.
|
2
|
+
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
3
|
+
|
4
|
+
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
5
|
+
|
6
|
+
from bec_widgets.utils.bec_designer import designer_material_icon
|
7
|
+
from bec_widgets.widgets.games.minesweeper import Minesweeper
|
8
|
+
|
9
|
+
DOM_XML = """
|
10
|
+
<ui language='c++'>
|
11
|
+
<widget class='Minesweeper' name='minesweeper'>
|
12
|
+
</widget>
|
13
|
+
</ui>
|
14
|
+
"""
|
15
|
+
|
16
|
+
|
17
|
+
class MinesweeperPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
18
|
+
def __init__(self):
|
19
|
+
super().__init__()
|
20
|
+
self._form_editor = None
|
21
|
+
|
22
|
+
def createWidget(self, parent):
|
23
|
+
t = Minesweeper(parent)
|
24
|
+
return t
|
25
|
+
|
26
|
+
def domXml(self):
|
27
|
+
return DOM_XML
|
28
|
+
|
29
|
+
def group(self):
|
30
|
+
return "BEC Games"
|
31
|
+
|
32
|
+
def icon(self):
|
33
|
+
return designer_material_icon(Minesweeper.ICON_NAME)
|
34
|
+
|
35
|
+
def includeFile(self):
|
36
|
+
return "minesweeper"
|
37
|
+
|
38
|
+
def initialize(self, form_editor):
|
39
|
+
self._form_editor = form_editor
|
40
|
+
|
41
|
+
def isContainer(self):
|
42
|
+
return False
|
43
|
+
|
44
|
+
def isInitialized(self):
|
45
|
+
return self._form_editor is not None
|
46
|
+
|
47
|
+
def name(self):
|
48
|
+
return "Minesweeper"
|
49
|
+
|
50
|
+
def toolTip(self):
|
51
|
+
return "Minesweeper"
|
52
|
+
|
53
|
+
def whatsThis(self):
|
54
|
+
return self.toolTip()
|
@@ -0,0 +1,15 @@
|
|
1
|
+
def main(): # pragma: no cover
|
2
|
+
from qtpy import PYSIDE6
|
3
|
+
|
4
|
+
if not PYSIDE6:
|
5
|
+
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
6
|
+
return
|
7
|
+
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
8
|
+
|
9
|
+
from bec_widgets.widgets.games.minesweeper_plugin import MinesweeperPlugin
|
10
|
+
|
11
|
+
QPyDesignerCustomWidgetCollection.addCustomWidget(MinesweeperPlugin())
|
12
|
+
|
13
|
+
|
14
|
+
if __name__ == "__main__": # pragma: no cover
|
15
|
+
main()
|
@@ -75,7 +75,7 @@ class SpinnerWidget(QWidget):
|
|
75
75
|
proportion = 1 / 4
|
76
76
|
angle_span = int(proportion * 360 * 16)
|
77
77
|
angle_span += angle_span * ease_in_out_sine(self.time / self.duration)
|
78
|
-
painter.drawArc(adjusted_rect, self.angle * 16, int(angle_span))
|
78
|
+
painter.drawArc(adjusted_rect, int(self.angle * 16), int(angle_span))
|
79
79
|
painter.end()
|
80
80
|
|
81
81
|
def closeEvent(self, event):
|
@@ -2,11 +2,11 @@
|
|
2
2
|
.gitlab-ci.yml,sha256=CLlFGYRGKp4FxCPTkyF9p-7qx67KmbM9Yok9JQEU_Ls,8677
|
3
3
|
.pylintrc,sha256=eeY8YwSI74oFfq6IYIbCqnx3Vk8ZncKaatv96n_Y8Rs,18544
|
4
4
|
.readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
|
5
|
-
CHANGELOG.md,sha256=
|
5
|
+
CHANGELOG.md,sha256=FFvwVqBUD_q2IiMmx4HdvyGB5NKM2DG0Tkcfcy_9reE,220975
|
6
6
|
LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=NtdzzO4MGjNTXBbNulluYh__nOLWcQX820P88EixW30,1339
|
8
8
|
README.md,sha256=Od69x-RS85Hph0-WwWACwal4yUd67XkEn4APEfHhHFw,2649
|
9
|
-
pyproject.toml,sha256=
|
9
|
+
pyproject.toml,sha256=a_6QuEHoaPGQEUAHvY24XelSuVDR_Df6wf0IAftbEvg,2596
|
10
10
|
.git_hooks/pre-commit,sha256=n3RofIZHJl8zfJJIUomcMyYGFi_rwq4CC19z0snz3FI,286
|
11
11
|
.gitlab/issue_templates/bug_report_template.md,sha256=gAuyEwl7XlnebBrkiJ9AqffSNOywmr8vygUFWKTuQeI,386
|
12
12
|
.gitlab/issue_templates/documentation_update_template.md,sha256=FHLdb3TS_D9aL4CYZCjyXSulbaW5mrN2CmwTaeLPbNw,860
|
@@ -24,7 +24,7 @@ bec_widgets/assets/app_icons/alignment_1d.png,sha256=5VouaWieb4lVv3wUBNHaO5ovUW2
|
|
24
24
|
bec_widgets/assets/app_icons/bec_widgets_icon.png,sha256=K8dgGwIjalDh9PRHUsSQBqgdX7a00nM3igZdc20pkYM,1747017
|
25
25
|
bec_widgets/cli/__init__.py,sha256=d0Q6Fn44e7wFfLabDOBxpcJ1DPKWlFunGYDUBmO-4hA,22
|
26
26
|
bec_widgets/cli/auto_updates.py,sha256=Pj8OHlSlKN3JOAmuuBC5oUMzdfC8TYRY7QKT5BQ2cZo,5171
|
27
|
-
bec_widgets/cli/client.py,sha256=
|
27
|
+
bec_widgets/cli/client.py,sha256=8JLY18GiUYMlIw4I4WXnNWiGmJ40P5TylrbyUAIv3ik,98833
|
28
28
|
bec_widgets/cli/client_utils.py,sha256=DXHHw1LNkKVCApbWmOAdZqU_qdvvqx28QiWV-Uf-jos,12207
|
29
29
|
bec_widgets/cli/generate_cli.py,sha256=2BFNgxM_0XLy2OXxG_SX0rgPHFc27oq0_yoOI2h2Rgw,6605
|
30
30
|
bec_widgets/cli/server.py,sha256=j5S3-HUCcKE_rip4PDP7nNBAMObO6Ja6D66zhYxXmsE,10693
|
@@ -225,6 +225,11 @@ bec_widgets/widgets/editors/website/register_website_widget.py,sha256=VSVrZRCZoI
|
|
225
225
|
bec_widgets/widgets/editors/website/website.py,sha256=VFFdrFX3P0Pf1V21oXrjGyCNrNp7fCsfbWPuRp9xEd8,3030
|
226
226
|
bec_widgets/widgets/editors/website/website_widget.pyproject,sha256=scOiV3cV1_BjbzpPzy2N8rIJL5P2qIZz8ObTJ-Uvdtg,25
|
227
227
|
bec_widgets/widgets/editors/website/website_widget_plugin.py,sha256=-YezP8dDqWZ9Xjjl-e5QTZuBPxxKyY4Lqcs7iaetIa8,1349
|
228
|
+
bec_widgets/widgets/games/__init__.py,sha256=jWW-3K3f3gqYM48Tp8rBxPebwPqxAcb7Q4dm_eE7FwI,89
|
229
|
+
bec_widgets/widgets/games/minesweeper.py,sha256=WQpyKwkNLCcH0t8InnFLM9TOiQSkbfOKp1uq3wwsPFo,12373
|
230
|
+
bec_widgets/widgets/games/minesweeper.pyproject,sha256=wHrLKY3H8uNiVgb9BIrj4S0Jeet9fjoR0BTnKzpx-vY,29
|
231
|
+
bec_widgets/widgets/games/minesweeper_plugin.py,sha256=oPEjSTpdIIkvuGThHxhVS8Rp47DWiaXHROtm8NJWYwo,1255
|
232
|
+
bec_widgets/widgets/games/register_minesweeper.py,sha256=8fgMBD3yB-5_eGqhG_qxpj3igXDK9WZfHrdYcA1aqz8,467
|
228
233
|
bec_widgets/widgets/plots/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
229
234
|
bec_widgets/widgets/plots/image/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
230
235
|
bec_widgets/widgets/plots/image/bec_image_widget.pyproject,sha256=PHisdBo5_5UCApd27GkizzqgfdjsDx2bFZa_p9LiSW8,30
|
@@ -291,7 +296,7 @@ bec_widgets/widgets/services/device_browser/device_item/device_item.py,sha256=u3
|
|
291
296
|
bec_widgets/widgets/utility/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
292
297
|
bec_widgets/widgets/utility/spinner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
293
298
|
bec_widgets/widgets/utility/spinner/register_spinner_widget.py,sha256=96A13dEcyTgXfc9G0sTdlXYCDcVav8Z2P2eDC95bESQ,484
|
294
|
-
bec_widgets/widgets/utility/spinner/spinner.py,sha256=
|
299
|
+
bec_widgets/widgets/utility/spinner/spinner.py,sha256=6c0fN7mdGzELg4mf_yG08ubses3svb6w0EqMeHDFkIw,2651
|
295
300
|
bec_widgets/widgets/utility/spinner/spinner_widget.pyproject,sha256=zzLajGB3DTgVnrSqMey2jRpBlxTq9cBXZL9tWJCKe-I,25
|
296
301
|
bec_widgets/widgets/utility/spinner/spinner_widget_plugin.py,sha256=kRQCOwxPQsFOrJIkSoqq7xdF_VtoRo_b2vOZEr5eXrA,1363
|
297
302
|
bec_widgets/widgets/utility/toggle/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -320,8 +325,8 @@ bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py,sha256=Z
|
|
320
325
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.pyproject,sha256=Lbi9zb6HNlIq14k6hlzR-oz6PIFShBuF7QxE6d87d64,34
|
321
326
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button_plugin.py,sha256=CzChz2SSETYsR8-36meqWnsXCT-FIy_J_xeU5coWDY8,1350
|
322
327
|
bec_widgets/widgets/utility/visual/dark_mode_button/register_dark_mode_button.py,sha256=rMpZ1CaoucwobgPj1FuKTnt07W82bV1GaSYdoqcdMb8,521
|
323
|
-
bec_widgets-1.
|
324
|
-
bec_widgets-1.
|
325
|
-
bec_widgets-1.
|
326
|
-
bec_widgets-1.
|
327
|
-
bec_widgets-1.
|
328
|
+
bec_widgets-1.14.1.dist-info/METADATA,sha256=NtdzzO4MGjNTXBbNulluYh__nOLWcQX820P88EixW30,1339
|
329
|
+
bec_widgets-1.14.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
330
|
+
bec_widgets-1.14.1.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
|
331
|
+
bec_widgets-1.14.1.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
332
|
+
bec_widgets-1.14.1.dist-info/RECORD,,
|
pyproject.toml
CHANGED
File without changes
|
File without changes
|
File without changes
|