draftomen 0.3.0__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.
Files changed (59) hide show
  1. draftomen/__init__.py +17 -0
  2. draftomen/assets/draftomen.icns +0 -0
  3. draftomen/assets/draftomen.ico +0 -0
  4. draftomen/assets/draftomen_logo.png +0 -0
  5. draftomen/audit.py +606 -0
  6. draftomen/backtest.py +449 -0
  7. draftomen/benchmark.py +834 -0
  8. draftomen/carddb.py +1869 -0
  9. draftomen/cardimages.py +313 -0
  10. draftomen/cli.py +891 -0
  11. draftomen/config.py +133 -0
  12. draftomen/deckbuilder.py +2723 -0
  13. draftomen/events.py +772 -0
  14. draftomen/logfollow.py +451 -0
  15. draftomen/mock_session.py +745 -0
  16. draftomen/paths.py +120 -0
  17. draftomen/pickengine.py +1117 -0
  18. draftomen/pool.py +1259 -0
  19. draftomen/preferences.py +289 -0
  20. draftomen/qml/AboutDialog.qml +156 -0
  21. draftomen/qml/AppBar.qml +120 -0
  22. draftomen/qml/BacktestView.qml +316 -0
  23. draftomen/qml/BuildView.qml +1151 -0
  24. draftomen/qml/CardPreview.qml +434 -0
  25. draftomen/qml/DimensionalButton.qml +42 -0
  26. draftomen/qml/DimensionalComboBox.qml +182 -0
  27. draftomen/qml/DimensionalSurface.qml +118 -0
  28. draftomen/qml/DimensionalTabButton.qml +41 -0
  29. draftomen/qml/LiveDraftView.qml +468 -0
  30. draftomen/qml/Main.qml +175 -0
  31. draftomen/qml/NavigationRail.qml +226 -0
  32. draftomen/qml/PoolSummaryPanel.qml +322 -0
  33. draftomen/qml/PrivacyDialog.qml +96 -0
  34. draftomen/qml/RecentPickThumbnail.qml +83 -0
  35. draftomen/qml/RecentPicksGallery.qml +333 -0
  36. draftomen/qml/RecommendationRow.qml +404 -0
  37. draftomen/qml/SettingsSwitch.qml +141 -0
  38. draftomen/qml/SettingsView.qml +531 -0
  39. draftomen/qml/StateBanner.qml +189 -0
  40. draftomen/qml/StatusStrip.qml +84 -0
  41. draftomen/qml/Theme.qml +71 -0
  42. draftomen/qml/qmldir +23 -0
  43. draftomen/qt_adapter.py +884 -0
  44. draftomen/qt_gui.py +338 -0
  45. draftomen/qt_mock.py +63 -0
  46. draftomen/ranking.py +126 -0
  47. draftomen/replay.py +480 -0
  48. draftomen/session.py +3668 -0
  49. draftomen/setinfo.py +26 -0
  50. draftomen/seventeen.py +2766 -0
  51. draftomen/splash.py +617 -0
  52. draftomen/tui.py +4007 -0
  53. draftomen/watch.py +336 -0
  54. draftomen-0.3.0.dist-info/METADATA +156 -0
  55. draftomen-0.3.0.dist-info/RECORD +59 -0
  56. draftomen-0.3.0.dist-info/WHEEL +5 -0
  57. draftomen-0.3.0.dist-info/entry_points.txt +6 -0
  58. draftomen-0.3.0.dist-info/licenses/LICENSE +21 -0
  59. draftomen-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,333 @@
1
+ pragma ComponentBehavior: Bound
2
+
3
+ import QtQuick 2.15
4
+ import QtQuick.Controls 2.15
5
+
6
+ Item {
7
+ id: root
8
+
9
+ required property var pool
10
+ required property bool narrow
11
+
12
+ readonly property var recentPicks: root.pool && root.pool.recent_picks
13
+ ? root.pool.recent_picks : []
14
+ readonly property int targetColumns: root.narrow ? 4 : 6
15
+ readonly property int gap: 6
16
+ readonly property int hoverDelay: 501
17
+ readonly property int dismissDelay: 100
18
+
19
+ property var hoveredThumbnail: null
20
+ property var previewedPick: null
21
+ property bool thumbnailHovered: false
22
+ property bool previewHovered: false
23
+
24
+ implicitHeight: galleryColumn.implicitHeight
25
+ Accessible.role: Accessible.Pane
26
+ Accessible.name: "Recent picks"
27
+ Accessible.description: "Cards picked most recently, newest first."
28
+
29
+ function pickForThumbnail(thumbnail) {
30
+ return thumbnail && thumbnail.recentPick && thumbnail.recentPick.card
31
+ ? thumbnail.recentPick : null
32
+ }
33
+
34
+ function containsPick(pick) {
35
+ if (!pick || !pick.card)
36
+ return false
37
+ for (let index = 0; index < root.recentPicks.length; index++) {
38
+ const recentPick = root.recentPicks[index]
39
+ if (recentPick && recentPick.card
40
+ && recentPick.card.grp_id === pick.card.grp_id)
41
+ return true
42
+ }
43
+ return false
44
+ }
45
+ function handleThumbnailEntered(thumbnail) {
46
+ const pick = root.pickForThumbnail(thumbnail)
47
+ if (!pick)
48
+ return
49
+ dismissTimer.stop()
50
+ if (root.hoveredThumbnail === thumbnail && root.thumbnailHovered)
51
+ return
52
+
53
+ if (root.hoveredThumbnail === thumbnail && previewCard.visible
54
+ && root.previewedPick && root.previewedPick.card
55
+ && pick.card
56
+ && root.previewedPick.card.grp_id === pick.card.grp_id) {
57
+ root.thumbnailHovered = true
58
+ root.previewedPick = pick
59
+ previewTimer.stop()
60
+ return
61
+ }
62
+
63
+ root.hoveredThumbnail = thumbnail
64
+ root.thumbnailHovered = true
65
+ root.previewedPick = null
66
+ previewTimer.restart()
67
+ }
68
+
69
+ function handleThumbnailExited(thumbnail) {
70
+ if (root.hoveredThumbnail !== thumbnail)
71
+ return
72
+ root.thumbnailHovered = false
73
+ previewTimer.stop()
74
+ dismissTimer.restart()
75
+ }
76
+
77
+ function dismissPreviewIfOutside() {
78
+ if (root.thumbnailHovered || root.previewHovered)
79
+ return
80
+ root.clearHoverState()
81
+ }
82
+
83
+ function showCurrentPreview() {
84
+ const pick = root.pickForThumbnail(root.hoveredThumbnail)
85
+ if (!root.thumbnailHovered || !pick
86
+ || !root.containsPick(pick))
87
+ return
88
+ root.previewedPick = pick
89
+ root.schedulePreviewGeometry()
90
+ }
91
+
92
+ function schedulePreviewGeometry() {
93
+ if (!root.previewedPick || !previewCard.parent)
94
+ return
95
+ Qt.callLater(root.updatePreviewGeometry)
96
+ }
97
+
98
+ function updatePreviewGeometry() {
99
+ const overlay = previewCard.parent
100
+ if (!overlay || !root.hoveredThumbnail || !root.previewedPick
101
+ || !previewCard.visible)
102
+ return
103
+
104
+ const galleryTopLeft = root.mapToItem(overlay, 0, 0)
105
+ const galleryBottomRight = root.mapToItem(
106
+ overlay, root.width, root.height
107
+ )
108
+ const margin = 8
109
+ const gap = 8
110
+ const availableAbove = Math.max(
111
+ 0, galleryTopLeft.y - gap - margin
112
+ )
113
+ const availableBelow = Math.max(
114
+ 0, overlay.height - galleryBottomRight.y - gap - margin
115
+ )
116
+ const maximumWidth = Math.min(
117
+ 260, Math.max(1, overlay.width - margin * 2)
118
+ )
119
+ previewCard.previewWidth = Math.min(
120
+ maximumWidth,
121
+ Math.max(1, Math.max(availableAbove, availableBelow) / 1.4)
122
+ )
123
+
124
+ const maximumX = Math.max(
125
+ margin, overlay.width - previewCard.width - margin
126
+ )
127
+ const nextX = Math.max(
128
+ margin, Math.min(galleryTopLeft.x, maximumX)
129
+ )
130
+ const belowY = galleryBottomRight.y + gap
131
+ const aboveY = galleryTopLeft.y - previewCard.height - gap
132
+ const maximumY = Math.max(
133
+ margin, overlay.height - previewCard.height - margin
134
+ )
135
+ const belowFits = belowY >= margin && belowY <= maximumY
136
+ const aboveFits = aboveY >= margin && aboveY <= maximumY
137
+ let nextY
138
+ if (availableBelow >= availableAbove && belowFits) {
139
+ nextY = belowY
140
+ } else if (aboveFits) {
141
+ nextY = aboveY
142
+ } else {
143
+ nextY = availableBelow >= availableAbove ? belowY : aboveY
144
+ nextY = Math.max(margin, Math.min(nextY, maximumY))
145
+ }
146
+
147
+ previewCard.x = nextX
148
+ previewCard.y = nextY
149
+ }
150
+
151
+ function syncRecentPicks() {
152
+ const hoveredPick = root.pickForThumbnail(root.hoveredThumbnail)
153
+ if (hoveredPick && root.containsPick(hoveredPick)) {
154
+ if (root.previewedPick)
155
+ root.previewedPick = hoveredPick
156
+ return
157
+ }
158
+ root.clearHoverState()
159
+ }
160
+
161
+ function clearHoverState() {
162
+ previewTimer.stop()
163
+ dismissTimer.stop()
164
+ root.hoveredThumbnail = null
165
+ root.thumbnailHovered = false
166
+ root.previewHovered = false
167
+ root.previewedPick = null
168
+ }
169
+
170
+ onRecentPicksChanged: Qt.callLater(root.syncRecentPicks)
171
+ onWidthChanged: root.schedulePreviewGeometry()
172
+ onHeightChanged: root.schedulePreviewGeometry()
173
+ onVisibleChanged: {
174
+ if (!root.visible)
175
+ root.clearHoverState()
176
+ }
177
+
178
+ Column {
179
+ id: galleryColumn
180
+ width: root.width
181
+ spacing: 8
182
+
183
+ Label {
184
+ id: heading
185
+ width: parent.width
186
+ text: "RECENT PICKS"
187
+ color: Theme.textMuted
188
+ font.pixelSize: Theme.textPixelSize(11)
189
+ font.bold: true
190
+ font.letterSpacing: 1
191
+ }
192
+
193
+ Grid {
194
+ id: recentPicksGrid
195
+ objectName: "recentPicksGrid"
196
+ width: parent.width
197
+ columns: Math.min(root.targetColumns, Math.max(1,
198
+ Math.floor((width + root.gap) / (64 + root.gap))))
199
+ columnSpacing: root.gap
200
+ rowSpacing: root.gap
201
+ height: childrenRect.height
202
+
203
+ Repeater {
204
+ model: root.recentPicks
205
+
206
+ delegate: RecentPickThumbnail {
207
+ required property int index
208
+ required property var modelData
209
+
210
+ pickIndex: index
211
+ recentPick: modelData
212
+ width: Math.max(1, (recentPicksGrid.width
213
+ - (recentPicksGrid.columns - 1) * root.gap)
214
+ / recentPicksGrid.columns)
215
+ onHoverEntered: root.handleThumbnailEntered(this)
216
+ onHoverExited: root.handleThumbnailExited(this)
217
+ }
218
+ }
219
+ }
220
+ }
221
+ Rectangle {
222
+ id: previewCard
223
+ objectName: "recentPickPreview"
224
+ parent: Overlay.overlay
225
+ z: 100
226
+ property bool modal: false
227
+ property real previewWidth: Math.min(
228
+ 260, Math.max(200, parent ? parent.width - 16 : 200)
229
+ )
230
+ focus: false
231
+ width: previewWidth
232
+ height: width * 1.4
233
+ visible: root.previewedPick !== null
234
+ color: Theme.surface
235
+ border.color: Theme.outline
236
+ border.width: 1
237
+ radius: Theme.radius
238
+ clip: true
239
+ Accessible.role: Accessible.Pane
240
+ Accessible.name: root.previewedPick && root.previewedPick.card
241
+ ? root.previewedPick.card.name + " preview" : "Card preview"
242
+
243
+ Image {
244
+ id: previewImage
245
+ objectName: "recentPickPreviewImage"
246
+ anchors.fill: parent
247
+ anchors.margins: 12
248
+ source: root.previewedPick && root.previewedPick.image
249
+ && root.previewedPick.image.phase === "ready"
250
+ && root.previewedPick.image.image_path
251
+ ? root.previewedPick.image.image_path : ""
252
+ fillMode: Image.PreserveAspectFit
253
+ asynchronous: true
254
+ visible: status === Image.Ready
255
+ }
256
+
257
+ Label {
258
+ id: previewFallbackLabel
259
+ objectName: "recentPickPreviewFallbackLabel"
260
+ anchors.fill: parent
261
+ anchors.margins: 28
262
+ text: {
263
+ const image = root.previewedPick
264
+ ? root.previewedPick.image : null
265
+ if (previewImage.status === Image.Error)
266
+ return "Image failed to display"
267
+ if (image && image.phase === "loading")
268
+ return "Loading image"
269
+ if (image && image.phase === "failed")
270
+ return "Image unavailable"
271
+ if (image && image.phase === "ready"
272
+ && previewImage.source.toString().length > 0)
273
+ return "Loading image"
274
+ return "No image available"
275
+ }
276
+ color: Theme.textMuted
277
+ font.pixelSize: Theme.textPixelSize(15)
278
+ font.bold: true
279
+ horizontalAlignment: Text.AlignHCenter
280
+ verticalAlignment: Text.AlignVCenter
281
+ wrapMode: Text.Wrap
282
+ visible: !previewImage.visible
283
+ Accessible.name: text
284
+ }
285
+ MouseArea {
286
+ id: previewHoverArea
287
+ anchors.fill: parent
288
+ z: 1
289
+ hoverEnabled: true
290
+ acceptedButtons: Qt.NoButton
291
+
292
+ onEntered: {
293
+ root.previewHovered = true
294
+ dismissTimer.stop()
295
+ }
296
+ onExited: {
297
+ root.previewHovered = false
298
+ if (root.thumbnailHovered)
299
+ dismissTimer.stop()
300
+ else
301
+ dismissTimer.restart()
302
+ }
303
+ }
304
+ }
305
+ Connections {
306
+ id: previewOverlayConnections
307
+ target: previewCard.parent
308
+
309
+ function onWidthChanged() {
310
+ root.schedulePreviewGeometry()
311
+ }
312
+
313
+ function onHeightChanged() {
314
+ root.schedulePreviewGeometry()
315
+ }
316
+ }
317
+
318
+ Timer {
319
+ id: previewTimer
320
+ objectName: "recentPickHoverTimer"
321
+ interval: root.hoverDelay
322
+ repeat: false
323
+ onTriggered: root.showCurrentPreview()
324
+ }
325
+
326
+ Timer {
327
+ id: dismissTimer
328
+ objectName: "recentPickDismissTimer"
329
+ interval: root.dismissDelay
330
+ repeat: false
331
+ onTriggered: root.dismissPreviewIfOutside()
332
+ }
333
+ }