ankigammon 1.0.6__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.
- ankigammon/__init__.py +7 -0
- ankigammon/__main__.py +6 -0
- ankigammon/analysis/__init__.py +13 -0
- ankigammon/analysis/score_matrix.py +391 -0
- ankigammon/anki/__init__.py +6 -0
- ankigammon/anki/ankiconnect.py +216 -0
- ankigammon/anki/apkg_exporter.py +111 -0
- ankigammon/anki/card_generator.py +1325 -0
- ankigammon/anki/card_styles.py +1054 -0
- ankigammon/gui/__init__.py +8 -0
- ankigammon/gui/app.py +192 -0
- ankigammon/gui/dialogs/__init__.py +10 -0
- ankigammon/gui/dialogs/export_dialog.py +594 -0
- ankigammon/gui/dialogs/import_options_dialog.py +201 -0
- ankigammon/gui/dialogs/input_dialog.py +762 -0
- ankigammon/gui/dialogs/note_dialog.py +93 -0
- ankigammon/gui/dialogs/settings_dialog.py +420 -0
- ankigammon/gui/dialogs/update_dialog.py +373 -0
- ankigammon/gui/format_detector.py +377 -0
- ankigammon/gui/main_window.py +1611 -0
- ankigammon/gui/resources/down-arrow.svg +3 -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 +402 -0
- ankigammon/gui/resources.py +26 -0
- ankigammon/gui/update_checker.py +259 -0
- ankigammon/gui/widgets/__init__.py +8 -0
- ankigammon/gui/widgets/position_list.py +166 -0
- ankigammon/gui/widgets/smart_input.py +268 -0
- ankigammon/models.py +356 -0
- ankigammon/parsers/__init__.py +7 -0
- ankigammon/parsers/gnubg_match_parser.py +1094 -0
- ankigammon/parsers/gnubg_parser.py +468 -0
- ankigammon/parsers/sgf_parser.py +290 -0
- ankigammon/parsers/xg_binary_parser.py +1097 -0
- ankigammon/parsers/xg_text_parser.py +688 -0
- ankigammon/renderer/__init__.py +5 -0
- ankigammon/renderer/animation_controller.py +391 -0
- ankigammon/renderer/animation_helper.py +191 -0
- ankigammon/renderer/color_schemes.py +145 -0
- ankigammon/renderer/svg_board_renderer.py +791 -0
- ankigammon/settings.py +315 -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 +590 -0
- ankigammon/utils/gnuid.py +577 -0
- ankigammon/utils/move_parser.py +204 -0
- ankigammon/utils/ogid.py +326 -0
- ankigammon/utils/xgid.py +387 -0
- ankigammon-1.0.6.dist-info/METADATA +352 -0
- ankigammon-1.0.6.dist-info/RECORD +61 -0
- ankigammon-1.0.6.dist-info/WHEEL +5 -0
- ankigammon-1.0.6.dist-info/entry_points.txt +2 -0
- ankigammon-1.0.6.dist-info/licenses/LICENSE +21 -0
- ankigammon-1.0.6.dist-info/top_level.txt +1 -0
ankigammon/gui/app.py
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
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 display custom icon in taskbar.
|
|
20
|
+
|
|
21
|
+
On Windows, this enables the application's icon to appear in the taskbar
|
|
22
|
+
instead of the default Python icon.
|
|
23
|
+
"""
|
|
24
|
+
if sys.platform == 'win32':
|
|
25
|
+
try:
|
|
26
|
+
import ctypes
|
|
27
|
+
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('AnkiGammon.GUI.1.0')
|
|
28
|
+
except Exception:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def create_splash_screen(icon_path: Path) -> QSplashScreen:
|
|
33
|
+
"""
|
|
34
|
+
Create a splash screen with modern styling.
|
|
35
|
+
|
|
36
|
+
Features rounded corners, gradient background, branded border,
|
|
37
|
+
drop shadow, and antialiased rendering.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
icon_path: Path to the application icon
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
QSplashScreen: Configured splash screen
|
|
44
|
+
"""
|
|
45
|
+
# Create pixmap with margin for drop shadow
|
|
46
|
+
splash_pix = QPixmap(440, 340)
|
|
47
|
+
splash_pix.fill(Qt.transparent)
|
|
48
|
+
|
|
49
|
+
# Initialize painter with antialiasing
|
|
50
|
+
painter = QPainter(splash_pix)
|
|
51
|
+
painter.setRenderHint(QPainter.Antialiasing)
|
|
52
|
+
painter.setRenderHint(QPainter.SmoothPixmapTransform)
|
|
53
|
+
painter.setRenderHint(QPainter.TextAntialiasing)
|
|
54
|
+
|
|
55
|
+
# Define rounded rectangle with 20px margin for shadow
|
|
56
|
+
rect = QRectF(20, 20, 400, 300)
|
|
57
|
+
corner_radius = 12
|
|
58
|
+
|
|
59
|
+
path = QPainterPath()
|
|
60
|
+
path.addRoundedRect(rect, corner_radius, corner_radius)
|
|
61
|
+
|
|
62
|
+
# Apply gradient background
|
|
63
|
+
gradient = QLinearGradient(20, 20, 20, 320)
|
|
64
|
+
gradient.setColorAt(0.0, QColor("#1e1e2e"))
|
|
65
|
+
gradient.setColorAt(0.3, QColor("#262637"))
|
|
66
|
+
gradient.setColorAt(0.7, QColor("#262637"))
|
|
67
|
+
gradient.setColorAt(1.0, QColor("#1e1e2e"))
|
|
68
|
+
painter.fillPath(path, gradient)
|
|
69
|
+
|
|
70
|
+
# Load and draw application icon
|
|
71
|
+
if icon_path.exists():
|
|
72
|
+
icon_pixmap = QPixmap(str(icon_path))
|
|
73
|
+
icon_size = 120
|
|
74
|
+
scaled_icon = icon_pixmap.scaled(icon_size, icon_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
|
75
|
+
|
|
76
|
+
icon_x = 20 + (400 - scaled_icon.width()) // 2
|
|
77
|
+
icon_y = 20 + 40
|
|
78
|
+
|
|
79
|
+
painter.drawPixmap(icon_x, icon_y, scaled_icon)
|
|
80
|
+
|
|
81
|
+
# Draw border
|
|
82
|
+
border_pen = QPen(QColor("#89b4fa"), 2.5)
|
|
83
|
+
border_pen.setJoinStyle(Qt.RoundJoin)
|
|
84
|
+
border_pen.setCapStyle(Qt.RoundCap)
|
|
85
|
+
painter.setPen(border_pen)
|
|
86
|
+
painter.setBrush(Qt.NoBrush)
|
|
87
|
+
painter.drawPath(path)
|
|
88
|
+
|
|
89
|
+
# Draw application name
|
|
90
|
+
painter.setPen(QColor("#f5e0dc"))
|
|
91
|
+
title_font = QFont("Segoe UI", 24, QFont.Bold)
|
|
92
|
+
title_font.setLetterSpacing(QFont.AbsoluteSpacing, 0.5)
|
|
93
|
+
painter.setFont(title_font)
|
|
94
|
+
painter.drawText(20, 20 + 170, 400, 40, Qt.AlignCenter, "AnkiGammon")
|
|
95
|
+
|
|
96
|
+
# Draw tagline
|
|
97
|
+
painter.setPen(QColor("#b4befe"))
|
|
98
|
+
tagline_font = QFont("Segoe UI", 10)
|
|
99
|
+
painter.setFont(tagline_font)
|
|
100
|
+
painter.drawText(20, 20 + 215, 400, 20, Qt.AlignCenter, "Backgammon Analysis to Flashcards")
|
|
101
|
+
|
|
102
|
+
# Draw loading indicator
|
|
103
|
+
painter.setPen(QColor("#a6adc8"))
|
|
104
|
+
loading_font = QFont("Segoe UI", 11)
|
|
105
|
+
painter.setFont(loading_font)
|
|
106
|
+
painter.drawText(20, 20 + 240, 400, 30, Qt.AlignCenter, "Loading...")
|
|
107
|
+
|
|
108
|
+
painter.end()
|
|
109
|
+
|
|
110
|
+
# Create frameless splash screen
|
|
111
|
+
splash = QSplashScreen(splash_pix, Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
|
|
112
|
+
|
|
113
|
+
# Add drop shadow effect
|
|
114
|
+
shadow = QGraphicsDropShadowEffect()
|
|
115
|
+
shadow.setBlurRadius(30)
|
|
116
|
+
shadow.setColor(QColor(0, 0, 0, 140))
|
|
117
|
+
shadow.setOffset(0, 6)
|
|
118
|
+
splash.setGraphicsEffect(shadow)
|
|
119
|
+
|
|
120
|
+
return splash
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def main():
|
|
124
|
+
"""
|
|
125
|
+
Launch the GUI application.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
int: Application exit code
|
|
129
|
+
"""
|
|
130
|
+
import logging
|
|
131
|
+
logging.basicConfig(
|
|
132
|
+
level=logging.INFO,
|
|
133
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
set_windows_app_id()
|
|
137
|
+
|
|
138
|
+
# Enable High DPI scaling
|
|
139
|
+
QApplication.setHighDpiScaleFactorRoundingPolicy(
|
|
140
|
+
Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
|
|
141
|
+
)
|
|
142
|
+
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
|
143
|
+
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
|
|
144
|
+
|
|
145
|
+
app = QApplication(sys.argv)
|
|
146
|
+
app.setApplicationName("AnkiGammon")
|
|
147
|
+
app.setOrganizationName("AnkiGammon")
|
|
148
|
+
app.setOrganizationDomain("github.com/Deinonychus999/AnkiGammon")
|
|
149
|
+
|
|
150
|
+
# Use Fusion style for consistent cross-platform appearance
|
|
151
|
+
app.setStyle('Fusion')
|
|
152
|
+
|
|
153
|
+
# Set platform-specific application icon
|
|
154
|
+
# macOS: .icns, Windows: .ico, Linux: .png
|
|
155
|
+
if sys.platform == 'darwin':
|
|
156
|
+
icon_file = "ankigammon/gui/resources/icon.icns"
|
|
157
|
+
elif sys.platform == 'win32':
|
|
158
|
+
icon_file = "ankigammon/gui/resources/icon.ico"
|
|
159
|
+
else:
|
|
160
|
+
icon_file = "ankigammon/gui/resources/icon.png"
|
|
161
|
+
|
|
162
|
+
icon_path = get_resource_path(icon_file)
|
|
163
|
+
if icon_path.exists():
|
|
164
|
+
app.setWindowIcon(QIcon(str(icon_path)))
|
|
165
|
+
|
|
166
|
+
# Show splash screen with PNG icon for high-quality rendering
|
|
167
|
+
splash_icon_path = get_resource_path("ankigammon/gui/resources/icon.png")
|
|
168
|
+
splash = create_splash_screen(splash_icon_path)
|
|
169
|
+
splash.show()
|
|
170
|
+
app.processEvents()
|
|
171
|
+
|
|
172
|
+
# Load and apply stylesheet
|
|
173
|
+
style_path = get_resource_path("ankigammon/gui/resources/style.qss")
|
|
174
|
+
if style_path.exists():
|
|
175
|
+
with open(style_path, encoding='utf-8') as f:
|
|
176
|
+
app.setStyleSheet(f.read())
|
|
177
|
+
|
|
178
|
+
settings = get_settings()
|
|
179
|
+
window = MainWindow(settings)
|
|
180
|
+
|
|
181
|
+
# Display splash screen for minimum 1 second before showing main window
|
|
182
|
+
def show_main_window():
|
|
183
|
+
splash.finish(window)
|
|
184
|
+
window.show()
|
|
185
|
+
|
|
186
|
+
QTimer.singleShot(1000, show_main_window)
|
|
187
|
+
|
|
188
|
+
return app.exec()
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
if __name__ == '__main__':
|
|
192
|
+
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
|