MoleditPy 2.8.3__tar.gz → 3.0.0a1__tar.gz

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 (77) hide show
  1. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/PKG-INFO +1 -1
  2. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/pyproject.toml +1 -1
  3. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/MoleditPy.egg-info/PKG-INFO +1 -1
  4. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/MoleditPy.egg-info/SOURCES.txt +3 -1
  5. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/__main__.py +1 -1
  6. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/main.py +3 -3
  7. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/__init__.py +39 -39
  8. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/about_dialog.py +110 -112
  9. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/align_plane_dialog.py +298 -298
  10. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/alignment_dialog.py +37 -37
  11. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/analysis_window.py +226 -226
  12. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/angle_dialog.py +480 -482
  13. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/atom_item.py +62 -74
  14. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/bond_item.py +524 -597
  15. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/bond_length_dialog.py +423 -426
  16. moleditpy-3.0.0a1/src/moleditpy/modules/calculation_worker.py +644 -0
  17. moleditpy-3.0.0a1/src/moleditpy/modules/color_settings_dialog.py +276 -0
  18. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/constants.py +35 -2
  19. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/constrained_optimization_dialog.py +106 -108
  20. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/custom_interactor_style.py +784 -823
  21. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/custom_qt_interactor.py +97 -97
  22. moleditpy-2.8.3/src/moleditpy/modules/dialog3_d_picking_mixin.py → moleditpy-3.0.0a1/src/moleditpy/modules/dialog_3d_picking_mixin.py +210 -220
  23. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/dihedral_dialog.py +28 -31
  24. moleditpy-3.0.0a1/src/moleditpy/modules/main_window.py +98 -0
  25. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/main_window_app_state.py +176 -150
  26. moleditpy-3.0.0a1/src/moleditpy/modules/main_window_compute.py +828 -0
  27. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/main_window_dialog_manager.py +63 -61
  28. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/main_window_edit_3d.py +109 -110
  29. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/main_window_edit_actions.py +352 -514
  30. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/main_window_export.py +138 -138
  31. moleditpy-3.0.0a1/src/moleditpy/modules/main_window_main_init.py +1704 -0
  32. moleditpy-3.0.0a1/src/moleditpy/modules/main_window_molecular_parsers.py +534 -0
  33. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/main_window_project_io.py +384 -392
  34. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/main_window_string_importers.py +253 -239
  35. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/main_window_ui_manager.py +501 -546
  36. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/main_window_view_3d.py +299 -332
  37. moleditpy-3.0.0a1/src/moleditpy/modules/main_window_view_loaders.py +251 -0
  38. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/mirror_dialog.py +139 -139
  39. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/mol_geometry.py +100 -0
  40. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/molecular_data.py +427 -340
  41. moleditpy-3.0.0a1/src/moleditpy/modules/molecular_scene_handler.py +1357 -0
  42. moleditpy-3.0.0a1/src/moleditpy/modules/molecule_scene.py +749 -0
  43. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/move_group_dialog.py +653 -663
  44. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/periodic_table_dialog.py +196 -196
  45. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/planarize_dialog.py +236 -236
  46. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/plugin_manager.py +521 -518
  47. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/plugin_manager_window.py +313 -313
  48. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/settings_dialog.py +1729 -1861
  49. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/sip_isdeleted_safe.py +17 -17
  50. moleditpy-3.0.0a1/src/moleditpy/modules/system_utils.py +70 -0
  51. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/template_preview_item.py +1 -1
  52. moleditpy-3.0.0a1/src/moleditpy/modules/template_preview_view.py +85 -0
  53. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/translation_dialog.py +337 -373
  54. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/user_template_dialog.py +712 -777
  55. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/zoomable_view.py +16 -17
  56. moleditpy-2.8.3/src/moleditpy/modules/calculation_worker.py +0 -1323
  57. moleditpy-2.8.3/src/moleditpy/modules/color_settings_dialog.py +0 -524
  58. moleditpy-2.8.3/src/moleditpy/modules/main_window.py +0 -805
  59. moleditpy-2.8.3/src/moleditpy/modules/main_window_compute.py +0 -1434
  60. moleditpy-2.8.3/src/moleditpy/modules/main_window_main_init.py +0 -2348
  61. moleditpy-2.8.3/src/moleditpy/modules/main_window_molecular_parsers.py +0 -1124
  62. moleditpy-2.8.3/src/moleditpy/modules/main_window_view_loaders.py +0 -337
  63. moleditpy-2.8.3/src/moleditpy/modules/molecule_scene.py +0 -2254
  64. moleditpy-2.8.3/src/moleditpy/modules/template_preview_view.py +0 -89
  65. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/LICENSE +0 -0
  66. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/README.md +0 -0
  67. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/setup.cfg +0 -0
  68. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/MoleditPy.egg-info/dependency_links.txt +0 -0
  69. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/MoleditPy.egg-info/entry_points.txt +0 -0
  70. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/MoleditPy.egg-info/requires.txt +0 -0
  71. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/MoleditPy.egg-info/top_level.txt +0 -0
  72. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/__init__.py +0 -0
  73. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/assets/file_icon.ico +0 -0
  74. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/assets/icon.icns +0 -0
  75. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/assets/icon.ico +0 -0
  76. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/assets/icon.png +0 -0
  77. {moleditpy-2.8.3 → moleditpy-3.0.0a1}/src/moleditpy/modules/plugin_interface.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoleditPy
3
- Version: 2.8.3
3
+ Version: 3.0.0a1
4
4
  Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
5
5
  Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "MoleditPy"
7
7
 
8
- version = "2.8.3"
8
+ version = "3.0.0a1"
9
9
 
10
10
  license = {file = "LICENSE"}
11
11
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoleditPy
3
- Version: 2.8.3
3
+ Version: 3.0.0a1
4
4
  Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
5
5
  Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -35,7 +35,7 @@ src/moleditpy/modules/constants.py
35
35
  src/moleditpy/modules/constrained_optimization_dialog.py
36
36
  src/moleditpy/modules/custom_interactor_style.py
37
37
  src/moleditpy/modules/custom_qt_interactor.py
38
- src/moleditpy/modules/dialog3_d_picking_mixin.py
38
+ src/moleditpy/modules/dialog_3d_picking_mixin.py
39
39
  src/moleditpy/modules/dihedral_dialog.py
40
40
  src/moleditpy/modules/main_window.py
41
41
  src/moleditpy/modules/main_window_app_state.py
@@ -54,6 +54,7 @@ src/moleditpy/modules/main_window_view_loaders.py
54
54
  src/moleditpy/modules/mirror_dialog.py
55
55
  src/moleditpy/modules/mol_geometry.py
56
56
  src/moleditpy/modules/molecular_data.py
57
+ src/moleditpy/modules/molecular_scene_handler.py
57
58
  src/moleditpy/modules/molecule_scene.py
58
59
  src/moleditpy/modules/move_group_dialog.py
59
60
  src/moleditpy/modules/periodic_table_dialog.py
@@ -63,6 +64,7 @@ src/moleditpy/modules/plugin_manager.py
63
64
  src/moleditpy/modules/plugin_manager_window.py
64
65
  src/moleditpy/modules/settings_dialog.py
65
66
  src/moleditpy/modules/sip_isdeleted_safe.py
67
+ src/moleditpy/modules/system_utils.py
66
68
  src/moleditpy/modules/template_preview_item.py
67
69
  src/moleditpy/modules/template_preview_view.py
68
70
  src/moleditpy/modules/translation_dialog.py
@@ -16,7 +16,7 @@ print("-----------------------------------------------------\n")
16
16
 
17
17
  try:
18
18
  from .main import main
19
- except Exception:
19
+ except ImportError:
20
20
  from main import main
21
21
 
22
22
  # --- Application Execution ---
@@ -17,14 +17,14 @@ from PyQt6.QtWidgets import QApplication
17
17
 
18
18
  try:
19
19
  from .modules.main_window import MainWindow
20
- except Exception:
20
+ except ImportError:
21
21
  from modules.main_window import MainWindow
22
22
 
23
23
 
24
24
  def main():
25
- # --- Windows タスクバーアイコンのための追加処理 ---
25
+ # --- Additional handling for Windows taskbar icon ---
26
26
  if sys.platform == "win32":
27
- myappid = "hyoko.moleditpy.1.0" # アプリケーション固有のID(任意)
27
+ myappid = "hyoko.moleditpy.1.0" # Application-specific ID (arbitrary)
28
28
  ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
29
29
 
30
30
  app = QApplication(sys.argv)
@@ -1,39 +1,39 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- MoleditPy — A Python-based molecular editing software
6
-
7
- Author: Hiromichi Yokoyama
8
- License: GPL-3.0 license
9
- Repo: https://github.com/HiroYokoyama/python_molecular_editor
10
- DOI: 10.5281/zenodo.17268532
11
- """
12
-
13
- try:
14
- import importlib.util
15
- OBABEL_AVAILABLE = importlib.util.find_spec("openbabel") is not None
16
- except Exception:
17
- OBABEL_AVAILABLE = False
18
-
19
- try:
20
- from PyQt6 import sip as _sip # type: ignore
21
- _sip_isdeleted = getattr(_sip, "isdeleted", None)
22
- except Exception:
23
- _sip = None
24
- _sip_isdeleted = None
25
-
26
-
27
- def sip_isdeleted_safe(obj) -> bool:
28
- """Return True if sip reports the given wrapper object as deleted.
29
-
30
- This function is conservative: if SIP isn't available or any error
31
- occurs while checking, it returns False (i.e. not deleted) so that the
32
- caller can continue other lightweight guards (like checking scene()).
33
- """
34
- try:
35
- if _sip_isdeleted is None:
36
- return False
37
- return bool(_sip_isdeleted(obj))
38
- except Exception:
39
- return False
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ MoleditPy — A Python-based molecular editing software
6
+
7
+ Author: Hiromichi Yokoyama
8
+ License: GPL-3.0 license
9
+ Repo: https://github.com/HiroYokoyama/python_molecular_editor
10
+ DOI: 10.5281/zenodo.17268532
11
+ """
12
+
13
+ try:
14
+ import importlib.util
15
+ OBABEL_AVAILABLE = importlib.util.find_spec("openbabel") is not None
16
+ except ImportError:
17
+ OBABEL_AVAILABLE = False
18
+
19
+ try:
20
+ from PyQt6 import sip as _sip # type: ignore
21
+ _sip_isdeleted = getattr(_sip, "isdeleted", None)
22
+ except ImportError:
23
+ _sip = None
24
+ _sip_isdeleted = None
25
+
26
+
27
+ def sip_isdeleted_safe(obj) -> bool:
28
+ """Return True if sip reports the given wrapper object as deleted.
29
+
30
+ This function is conservative: if SIP isn't available or any error
31
+ occurs while checking, it returns False (i.e. not deleted) so that the
32
+ caller can continue other lightweight guards (like checking scene()).
33
+ """
34
+ try:
35
+ if _sip_isdeleted is None:
36
+ return False
37
+ return bool(_sip_isdeleted(obj))
38
+ except (AttributeError, RuntimeError, TypeError):
39
+ return False
@@ -1,112 +1,110 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
-
4
- """
5
- MoleditPy — A Python-based molecular editing software
6
-
7
- Author: Hiromichi Yokoyama
8
- License: GPL-3.0 license
9
- Repo: https://github.com/HiroYokoyama/python_molecular_editor
10
- DOI: 10.5281/zenodo.17268532
11
- """
12
-
13
- import os
14
-
15
- from PyQt6.QtCore import Qt
16
- from PyQt6.QtGui import QCursor, QPainter, QPen, QPixmap
17
- from PyQt6.QtWidgets import QDialog, QHBoxLayout, QLabel, QPushButton, QVBoxLayout
18
-
19
- try:
20
- from .constants import VERSION
21
- except Exception:
22
- from modules.constants import VERSION
23
-
24
-
25
- class AboutDialog(QDialog): # pragma: no cover
26
- def __init__(self, main_window, parent=None):
27
- super().__init__(parent)
28
- self.main_window = main_window
29
- self.setWindowTitle("About MoleditPy")
30
- self.setFixedSize(250, 300)
31
- self.init_ui()
32
-
33
- def init_ui(self):
34
- layout = QVBoxLayout(self)
35
-
36
- # Create a clickable image label
37
- self.image_label = QLabel()
38
- self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
39
-
40
- # Load the original icon image
41
- icon_path = os.path.join(os.path.dirname(__file__), "..", "assets", "icon.png")
42
- if os.path.exists(icon_path):
43
- original_pixmap = QPixmap(icon_path)
44
- # Scale to 2x size (160x160)
45
- pixmap = original_pixmap.scaled(
46
- 160,
47
- 160,
48
- Qt.AspectRatioMode.KeepAspectRatio,
49
- Qt.TransformationMode.SmoothTransformation,
50
- )
51
- else:
52
- # Fallback: create a simple placeholder if icon.png not found
53
- pixmap = QPixmap(160, 160)
54
- pixmap.fill(Qt.GlobalColor.lightGray)
55
- painter = QPainter(pixmap)
56
- painter.setPen(QPen(Qt.GlobalColor.black, 2))
57
- painter.drawText(pixmap.rect(), Qt.AlignmentFlag.AlignCenter, "MoleditPy")
58
- painter.end()
59
-
60
- self.image_label.setPixmap(pixmap)
61
- try:
62
- self.image_label.setCursor(QCursor(Qt.CursorShape.ArrowCursor))
63
- except Exception: # pragma: no cover
64
- import traceback
65
- traceback.print_exc()
66
-
67
- self.image_label.mousePressEvent = self.image_mouse_press_event
68
-
69
- layout.addWidget(self.image_label)
70
-
71
- # Add text information
72
- info_text = f"MoleditPy Ver. {VERSION}\nAuthor: Hiromichi Yokoyama\nLicense: GPL-3.0 license"
73
- info_label = QLabel(info_text)
74
- info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
75
- layout.addWidget(info_label)
76
-
77
- # Add OK button
78
- ok_button = QPushButton("OK")
79
- ok_button.setFixedSize(80, 30) # 小さいサイズに固定
80
- ok_button.clicked.connect(self.accept)
81
-
82
- # Center the button
83
- button_layout = QHBoxLayout()
84
- button_layout.addStretch()
85
- button_layout.addWidget(ok_button)
86
- button_layout.addStretch()
87
- layout.addLayout(button_layout)
88
-
89
- def image_clicked(self, event):
90
- """Easter egg: Clear all and load bipyrimidine from SMILES"""
91
- # Clear the current scene
92
- self.main_window.clear_all()
93
-
94
- bipyrimidine_smiles = "C1=CN=C(N=C1)C2=NC=CC=N2"
95
- self.main_window.load_from_smiles(bipyrimidine_smiles)
96
-
97
- # Close the dialog
98
- self.accept()
99
-
100
- def image_mouse_press_event(self, event):
101
- """Handle mouse press on the image: trigger easter egg only for right-click."""
102
- try:
103
- if event.button() == Qt.MouseButton.RightButton:
104
- self.image_clicked(event)
105
- else:
106
- event.ignore()
107
- except Exception:
108
- try:
109
- event.ignore()
110
- except Exception: # pragma: no cover
111
- import traceback
112
- traceback.print_exc()
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ MoleditPy — A Python-based molecular editing software
6
+
7
+ Author: Hiromichi Yokoyama
8
+ License: GPL-3.0 license
9
+ Repo: https://github.com/HiroYokoyama/python_molecular_editor
10
+ DOI: 10.5281/zenodo.17268532
11
+ """
12
+
13
+ import os
14
+
15
+ from PyQt6.QtCore import Qt
16
+ from PyQt6.QtGui import QCursor, QPainter, QPen, QPixmap
17
+ from PyQt6.QtWidgets import QDialog, QHBoxLayout, QLabel, QPushButton, QVBoxLayout
18
+
19
+ try:
20
+ from .constants import VERSION
21
+ except ImportError:
22
+ from modules.constants import VERSION
23
+
24
+
25
+ class AboutDialog(QDialog):
26
+ def __init__(self, main_window, parent=None):
27
+ super().__init__(parent)
28
+ self.main_window = main_window
29
+ self.setWindowTitle("About MoleditPy")
30
+ self.setFixedSize(250, 300)
31
+ self.init_ui()
32
+
33
+ def init_ui(self):
34
+ layout = QVBoxLayout(self)
35
+
36
+ # Create a clickable image label
37
+ self.image_label = QLabel()
38
+ self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
39
+
40
+ # Load the original icon image
41
+ icon_path = os.path.join(os.path.dirname(__file__), "..", "assets", "icon.png")
42
+ if os.path.exists(icon_path):
43
+ original_pixmap = QPixmap(icon_path)
44
+ # Scale to 2x size (160x160)
45
+ pixmap = original_pixmap.scaled(
46
+ 160,
47
+ 160,
48
+ Qt.AspectRatioMode.KeepAspectRatio,
49
+ Qt.TransformationMode.SmoothTransformation,
50
+ )
51
+ else:
52
+ # Fallback: create a simple placeholder if icon.png not found
53
+ pixmap = QPixmap(160, 160)
54
+ pixmap.fill(Qt.GlobalColor.lightGray)
55
+ painter = QPainter(pixmap)
56
+ painter.setPen(QPen(Qt.GlobalColor.black, 2))
57
+ painter.drawText(pixmap.rect(), Qt.AlignmentFlag.AlignCenter, "MoleditPy")
58
+ painter.end()
59
+
60
+ self.image_label.setPixmap(pixmap)
61
+ try:
62
+ self.image_label.setCursor(QCursor(Qt.CursorShape.ArrowCursor))
63
+ except (AttributeError, RuntimeError, ValueError, TypeError):
64
+ pass # Suppress cursor setting errors on about image
65
+
66
+ self.image_label.mousePressEvent = self.image_mouse_press_event
67
+
68
+ layout.addWidget(self.image_label)
69
+
70
+ # Add text information
71
+ info_text = f"MoleditPy Ver. {VERSION}\nAuthor: Hiromichi Yokoyama\nLicense: GPL-3.0 license"
72
+ info_label = QLabel(info_text)
73
+ info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
74
+ layout.addWidget(info_label)
75
+
76
+ # Add OK button
77
+ ok_button = QPushButton("OK")
78
+ ok_button.setFixedSize(80, 30) # Fixed small size
79
+ ok_button.clicked.connect(self.accept)
80
+
81
+ # Center the button
82
+ button_layout = QHBoxLayout()
83
+ button_layout.addStretch()
84
+ button_layout.addWidget(ok_button)
85
+ button_layout.addStretch()
86
+ layout.addLayout(button_layout)
87
+
88
+ def image_clicked(self, event):
89
+ """Easter egg: Clear all and load bipyrimidine from SMILES"""
90
+ # Clear the current scene
91
+ self.main_window.clear_all()
92
+
93
+ bipyrimidine_smiles = "C1=CN=C(N=C1)C2=NC=CC=N2"
94
+ self.main_window.load_from_smiles(bipyrimidine_smiles)
95
+
96
+ # Close the dialog
97
+ self.accept()
98
+
99
+ def image_mouse_press_event(self, event):
100
+ """Handle mouse press on the image: trigger easter egg only for right-click."""
101
+ try:
102
+ if event.button() == Qt.MouseButton.RightButton:
103
+ self.image_clicked(event)
104
+ else:
105
+ event.ignore()
106
+ except (AttributeError, RuntimeError, ValueError, TypeError):
107
+ try:
108
+ event.ignore()
109
+ except (AttributeError, RuntimeError, ValueError, TypeError):
110
+ pass # Suppress nested event errors