ankigammon 1.0.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.
Potentially problematic release.
This version of ankigammon might be problematic. Click here for more details.
- ankigammon/__init__.py +7 -0
- ankigammon/__main__.py +6 -0
- ankigammon/analysis/__init__.py +13 -0
- ankigammon/analysis/score_matrix.py +373 -0
- ankigammon/anki/__init__.py +6 -0
- ankigammon/anki/ankiconnect.py +224 -0
- ankigammon/anki/apkg_exporter.py +123 -0
- ankigammon/anki/card_generator.py +1307 -0
- ankigammon/anki/card_styles.py +1034 -0
- ankigammon/gui/__init__.py +8 -0
- ankigammon/gui/app.py +209 -0
- ankigammon/gui/dialogs/__init__.py +10 -0
- ankigammon/gui/dialogs/export_dialog.py +597 -0
- ankigammon/gui/dialogs/import_options_dialog.py +163 -0
- ankigammon/gui/dialogs/input_dialog.py +776 -0
- ankigammon/gui/dialogs/note_dialog.py +93 -0
- ankigammon/gui/dialogs/settings_dialog.py +384 -0
- ankigammon/gui/format_detector.py +292 -0
- ankigammon/gui/main_window.py +1071 -0
- ankigammon/gui/resources/icon.icns +0 -0
- ankigammon/gui/resources/icon.ico +0 -0
- ankigammon/gui/resources/icon.png +0 -0
- ankigammon/gui/resources/style.qss +394 -0
- ankigammon/gui/resources.py +26 -0
- ankigammon/gui/widgets/__init__.py +8 -0
- ankigammon/gui/widgets/position_list.py +193 -0
- ankigammon/gui/widgets/smart_input.py +268 -0
- ankigammon/models.py +322 -0
- ankigammon/parsers/__init__.py +7 -0
- ankigammon/parsers/gnubg_parser.py +454 -0
- ankigammon/parsers/xg_binary_parser.py +870 -0
- ankigammon/parsers/xg_text_parser.py +729 -0
- ankigammon/renderer/__init__.py +5 -0
- ankigammon/renderer/animation_controller.py +406 -0
- ankigammon/renderer/animation_helper.py +221 -0
- ankigammon/renderer/color_schemes.py +145 -0
- ankigammon/renderer/svg_board_renderer.py +824 -0
- ankigammon/settings.py +239 -0
- ankigammon/thirdparty/__init__.py +7 -0
- ankigammon/thirdparty/xgdatatools/__init__.py +17 -0
- ankigammon/thirdparty/xgdatatools/xgimport.py +160 -0
- ankigammon/thirdparty/xgdatatools/xgstruct.py +1032 -0
- ankigammon/thirdparty/xgdatatools/xgutils.py +118 -0
- ankigammon/thirdparty/xgdatatools/xgzarc.py +260 -0
- ankigammon/utils/__init__.py +13 -0
- ankigammon/utils/gnubg_analyzer.py +431 -0
- ankigammon/utils/gnuid.py +622 -0
- ankigammon/utils/move_parser.py +239 -0
- ankigammon/utils/ogid.py +335 -0
- ankigammon/utils/xgid.py +419 -0
- ankigammon-1.0.0.dist-info/METADATA +370 -0
- ankigammon-1.0.0.dist-info/RECORD +56 -0
- ankigammon-1.0.0.dist-info/WHEEL +5 -0
- ankigammon-1.0.0.dist-info/entry_points.txt +2 -0
- ankigammon-1.0.0.dist-info/licenses/LICENSE +21 -0
- ankigammon-1.0.0.dist-info/top_level.txt +1 -0
ankigammon/gui/app.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Application entry point for GUI mode.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
import os
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from PySide6.QtWidgets import QApplication, QSplashScreen, QGraphicsDropShadowEffect
|
|
9
|
+
from PySide6.QtCore import Qt, QTimer, QRectF
|
|
10
|
+
from PySide6.QtGui import QIcon, QPixmap, QPainter, QColor, QFont, QLinearGradient, QPainterPath, QPen
|
|
11
|
+
|
|
12
|
+
from ankigammon.gui.main_window import MainWindow
|
|
13
|
+
from ankigammon.gui.resources import get_resource_path
|
|
14
|
+
from ankigammon.settings import get_settings
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def set_windows_app_id():
|
|
18
|
+
"""
|
|
19
|
+
Set Windows AppUserModelID to show custom icon in taskbar.
|
|
20
|
+
|
|
21
|
+
This fixes the issue where Python scripts show the Python icon
|
|
22
|
+
in the Windows taskbar instead of the application's custom icon.
|
|
23
|
+
"""
|
|
24
|
+
if sys.platform == 'win32':
|
|
25
|
+
try:
|
|
26
|
+
import ctypes
|
|
27
|
+
# Set unique AppUserModelID for this application
|
|
28
|
+
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('AnkiGammon.GUI.1.0')
|
|
29
|
+
except Exception:
|
|
30
|
+
# Silently fail if setting AppUserModelID doesn't work
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def create_splash_screen(icon_path: Path) -> QSplashScreen:
|
|
35
|
+
"""
|
|
36
|
+
Create a beautiful splash screen with modern styling.
|
|
37
|
+
|
|
38
|
+
Features:
|
|
39
|
+
- Rounded corners for modern appearance
|
|
40
|
+
- Gradient background for depth
|
|
41
|
+
- Fancy border with brand color
|
|
42
|
+
- Drop shadow for elevation
|
|
43
|
+
- High-quality antialiasing
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
icon_path: Path to the application icon
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
QSplashScreen: Configured splash screen with modern styling
|
|
50
|
+
"""
|
|
51
|
+
# Create larger pixmap to accommodate drop shadow margin
|
|
52
|
+
splash_pix = QPixmap(440, 340)
|
|
53
|
+
splash_pix.fill(Qt.transparent) # Transparent background for rounded corners
|
|
54
|
+
|
|
55
|
+
# Initialize painter with high-quality rendering
|
|
56
|
+
painter = QPainter(splash_pix)
|
|
57
|
+
painter.setRenderHint(QPainter.Antialiasing)
|
|
58
|
+
painter.setRenderHint(QPainter.SmoothPixmapTransform)
|
|
59
|
+
painter.setRenderHint(QPainter.TextAntialiasing)
|
|
60
|
+
|
|
61
|
+
# Define rounded rectangle with margin for shadow (20px margin on all sides)
|
|
62
|
+
rect = QRectF(20, 20, 400, 300)
|
|
63
|
+
corner_radius = 12
|
|
64
|
+
|
|
65
|
+
# Create path for rounded rectangle
|
|
66
|
+
path = QPainterPath()
|
|
67
|
+
path.addRoundedRect(rect, corner_radius, corner_radius)
|
|
68
|
+
|
|
69
|
+
# Apply elegant gradient background (subtle top-to-bottom variation)
|
|
70
|
+
gradient = QLinearGradient(20, 20, 20, 320)
|
|
71
|
+
gradient.setColorAt(0.0, QColor("#1e1e2e")) # Dark blue-gray at top
|
|
72
|
+
gradient.setColorAt(0.3, QColor("#262637")) # Slightly lighter in middle
|
|
73
|
+
gradient.setColorAt(0.7, QColor("#262637")) # Maintain middle tone
|
|
74
|
+
gradient.setColorAt(1.0, QColor("#1e1e2e")) # Return to dark at bottom
|
|
75
|
+
painter.fillPath(path, gradient)
|
|
76
|
+
|
|
77
|
+
# Load and draw the dice icon from the icon file
|
|
78
|
+
if icon_path.exists():
|
|
79
|
+
icon_pixmap = QPixmap(str(icon_path))
|
|
80
|
+
# Scale to a good size for the splash screen (120px width)
|
|
81
|
+
icon_size = 120
|
|
82
|
+
scaled_icon = icon_pixmap.scaled(icon_size, icon_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
|
83
|
+
|
|
84
|
+
# Center the icon in the upper portion
|
|
85
|
+
icon_x = 20 + (400 - scaled_icon.width()) // 2
|
|
86
|
+
icon_y = 20 + 40 # Position higher on the splash screen
|
|
87
|
+
|
|
88
|
+
painter.drawPixmap(icon_x, icon_y, scaled_icon)
|
|
89
|
+
|
|
90
|
+
# Draw fancy border with brand color (blue from Catppuccin palette)
|
|
91
|
+
border_pen = QPen(QColor("#89b4fa"), 2.5) # 2.5px blue border
|
|
92
|
+
border_pen.setJoinStyle(Qt.RoundJoin) # Smooth corner joins
|
|
93
|
+
border_pen.setCapStyle(Qt.RoundCap) # Smooth line caps
|
|
94
|
+
painter.setPen(border_pen)
|
|
95
|
+
painter.setBrush(Qt.NoBrush)
|
|
96
|
+
painter.drawPath(path)
|
|
97
|
+
|
|
98
|
+
# Draw application name with elegant typography
|
|
99
|
+
painter.setPen(QColor("#f5e0dc")) # Warm white text
|
|
100
|
+
title_font = QFont("Segoe UI", 24, QFont.Bold)
|
|
101
|
+
title_font.setLetterSpacing(QFont.AbsoluteSpacing, 0.5) # Slight letter spacing
|
|
102
|
+
painter.setFont(title_font)
|
|
103
|
+
painter.drawText(20, 20 + 170, 400, 40, Qt.AlignCenter, "AnkiGammon")
|
|
104
|
+
|
|
105
|
+
# Draw subtle tagline
|
|
106
|
+
painter.setPen(QColor("#b4befe")) # Lighter blue for accent
|
|
107
|
+
tagline_font = QFont("Segoe UI", 10)
|
|
108
|
+
painter.setFont(tagline_font)
|
|
109
|
+
painter.drawText(20, 20 + 215, 400, 20, Qt.AlignCenter, "Backgammon Analysis to Flashcards")
|
|
110
|
+
|
|
111
|
+
# Draw loading indicator
|
|
112
|
+
painter.setPen(QColor("#a6adc8")) # Muted gray-blue
|
|
113
|
+
loading_font = QFont("Segoe UI", 11)
|
|
114
|
+
painter.setFont(loading_font)
|
|
115
|
+
painter.drawText(20, 20 + 240, 400, 30, Qt.AlignCenter, "Loading...")
|
|
116
|
+
|
|
117
|
+
painter.end()
|
|
118
|
+
|
|
119
|
+
# Create frameless splash screen for clean appearance
|
|
120
|
+
splash = QSplashScreen(splash_pix, Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
|
|
121
|
+
|
|
122
|
+
# Add professional drop shadow for depth and elevation
|
|
123
|
+
shadow = QGraphicsDropShadowEffect()
|
|
124
|
+
shadow.setBlurRadius(30) # Soft, diffused shadow
|
|
125
|
+
shadow.setColor(QColor(0, 0, 0, 140)) # Semi-transparent black
|
|
126
|
+
shadow.setOffset(0, 6) # Slight downward offset
|
|
127
|
+
splash.setGraphicsEffect(shadow)
|
|
128
|
+
|
|
129
|
+
return splash
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def main():
|
|
133
|
+
"""
|
|
134
|
+
Launch the GUI application.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
int: Application exit code
|
|
138
|
+
"""
|
|
139
|
+
# Configure logging
|
|
140
|
+
import logging
|
|
141
|
+
logging.basicConfig(
|
|
142
|
+
level=logging.INFO,
|
|
143
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Set Windows AppUserModelID for custom taskbar icon
|
|
147
|
+
set_windows_app_id()
|
|
148
|
+
|
|
149
|
+
# Enable High DPI scaling
|
|
150
|
+
QApplication.setHighDpiScaleFactorRoundingPolicy(
|
|
151
|
+
Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
|
|
152
|
+
)
|
|
153
|
+
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
|
154
|
+
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
|
|
155
|
+
|
|
156
|
+
app = QApplication(sys.argv)
|
|
157
|
+
app.setApplicationName("AnkiGammon")
|
|
158
|
+
app.setOrganizationName("AnkiGammon")
|
|
159
|
+
app.setOrganizationDomain("github.com/Deinonychus999/AnkiGammon")
|
|
160
|
+
|
|
161
|
+
# Set application style (modern, consistent across platforms)
|
|
162
|
+
app.setStyle('Fusion')
|
|
163
|
+
|
|
164
|
+
# Set application icon (use platform-specific format for best compatibility)
|
|
165
|
+
# macOS requires .icns, Windows prefers .ico, Linux uses .png
|
|
166
|
+
if sys.platform == 'darwin':
|
|
167
|
+
icon_file = "ankigammon/gui/resources/icon.icns"
|
|
168
|
+
elif sys.platform == 'win32':
|
|
169
|
+
icon_file = "ankigammon/gui/resources/icon.ico"
|
|
170
|
+
else:
|
|
171
|
+
icon_file = "ankigammon/gui/resources/icon.png"
|
|
172
|
+
|
|
173
|
+
icon_path = get_resource_path(icon_file)
|
|
174
|
+
if icon_path.exists():
|
|
175
|
+
app.setWindowIcon(QIcon(str(icon_path)))
|
|
176
|
+
|
|
177
|
+
# Show splash screen (always use PNG for high-quality rendering at larger sizes)
|
|
178
|
+
splash_icon_path = get_resource_path("ankigammon/gui/resources/icon.png")
|
|
179
|
+
splash = create_splash_screen(splash_icon_path)
|
|
180
|
+
splash.show()
|
|
181
|
+
app.processEvents() # Ensure splash screen is rendered
|
|
182
|
+
|
|
183
|
+
# Load and apply stylesheet (use resource path helper for PyInstaller compatibility)
|
|
184
|
+
style_path = get_resource_path("ankigammon/gui/resources/style.qss")
|
|
185
|
+
if style_path.exists():
|
|
186
|
+
with open(style_path, encoding='utf-8') as f:
|
|
187
|
+
app.setStyleSheet(f.read())
|
|
188
|
+
|
|
189
|
+
# Load settings
|
|
190
|
+
settings = get_settings()
|
|
191
|
+
|
|
192
|
+
# Create main window (but don't show it yet)
|
|
193
|
+
window = MainWindow(settings)
|
|
194
|
+
|
|
195
|
+
# Close splash screen and show main window after a minimum display time
|
|
196
|
+
# This ensures users see the splash screen even if loading is fast
|
|
197
|
+
def show_main_window():
|
|
198
|
+
splash.finish(window) # Close splash and show window
|
|
199
|
+
window.show()
|
|
200
|
+
|
|
201
|
+
# Minimum splash screen display: 1 second
|
|
202
|
+
# Adjust this value as needed (1000ms = 1 second)
|
|
203
|
+
QTimer.singleShot(1000, show_main_window)
|
|
204
|
+
|
|
205
|
+
return app.exec()
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
if __name__ == '__main__':
|
|
209
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GUI dialogs package.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__all__ = ['SettingsDialog', 'ExportDialog', 'InputDialog', 'ImportOptionsDialog']
|
|
6
|
+
|
|
7
|
+
from .settings_dialog import SettingsDialog
|
|
8
|
+
from .export_dialog import ExportDialog
|
|
9
|
+
from .input_dialog import InputDialog
|
|
10
|
+
from .import_options_dialog import ImportOptionsDialog
|