MoleditPy 3.0.0a1__tar.gz → 3.0.0a2__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.
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/PKG-INFO +4 -4
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/README.md +3 -3
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/pyproject.toml +1 -1
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/MoleditPy.egg-info/PKG-INFO +4 -4
- moleditpy-3.0.0a2/src/moleditpy/main.py +60 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/__init__.py +2 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/about_dialog.py +115 -110
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/align_plane_dialog.py +11 -3
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/alignment_dialog.py +10 -2
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/angle_dialog.py +515 -480
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/atom_item.py +6 -5
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/bond_item.py +11 -7
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/bond_length_dialog.py +455 -423
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/calculation_worker.py +510 -184
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/color_settings_dialog.py +155 -27
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/constants.py +2 -2
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/constrained_optimization_dialog.py +23 -11
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/custom_interactor_style.py +821 -784
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/dialog_3d_picking_mixin.py +1 -1
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/dihedral_dialog.py +50 -19
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window.py +19 -10
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_app_state.py +213 -210
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_compute.py +129 -70
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_dialog_manager.py +4 -4
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_edit_3d.py +20 -8
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_edit_actions.py +24 -9
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_export.py +42 -35
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_main_init.py +1919 -1704
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_molecular_parsers.py +109 -49
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_project_io.py +393 -384
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_string_importers.py +1 -6
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_ui_manager.py +29 -12
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_view_3d.py +103 -53
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/main_window_view_loaders.py +48 -17
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/mirror_dialog.py +3 -2
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/mol_geometry.py +12 -12
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/molecular_data.py +427 -427
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/molecular_scene_handler.py +319 -288
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/molecule_scene.py +113 -85
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/move_group_dialog.py +705 -653
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/periodic_table_dialog.py +1 -1
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/planarize_dialog.py +8 -2
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/plugin_manager.py +73 -16
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/plugin_manager_window.py +1 -1
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/settings_dialog.py +1705 -1729
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/system_utils.py +3 -2
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/translation_dialog.py +18 -8
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/user_template_dialog.py +1 -1
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/zoomable_view.py +3 -1
- moleditpy-3.0.0a1/src/moleditpy/main.py +0 -34
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/LICENSE +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/setup.cfg +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/MoleditPy.egg-info/SOURCES.txt +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/MoleditPy.egg-info/dependency_links.txt +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/MoleditPy.egg-info/entry_points.txt +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/MoleditPy.egg-info/requires.txt +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/MoleditPy.egg-info/top_level.txt +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/__init__.py +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/__main__.py +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/assets/file_icon.ico +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/assets/icon.icns +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/assets/icon.ico +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/assets/icon.png +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/analysis_window.py +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/custom_qt_interactor.py +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/plugin_interface.py +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/sip_isdeleted_safe.py +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/template_preview_item.py +0 -0
- {moleditpy-3.0.0a1 → moleditpy-3.0.0a2}/src/moleditpy/modules/template_preview_view.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.0a2
|
|
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
|
|
@@ -710,10 +710,10 @@ Dynamic: license-file
|
|
|
710
710
|
[](https://pypi.org/project/MoleditPy/)
|
|
711
711
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
712
712
|
[](https://github.com/HiroYokoyama/python_molecular_editor/actions)
|
|
713
|
-

|
|
714
|
+

|
|
715
715
|

|
|
716
|
-

|
|
717
717
|
[](https://pepy.tech/projects/moleditpy)
|
|
718
718
|
|
|
719
719
|
[🇯🇵 日本語 (Japanese)](#japanese)
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
[](https://pypi.org/project/MoleditPy/)
|
|
7
7
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
8
8
|
[](https://github.com/HiroYokoyama/python_molecular_editor/actions)
|
|
9
|
-

|
|
10
|
+

|
|
11
11
|

|
|
12
|
-

|
|
13
13
|
[](https://pepy.tech/projects/moleditpy)
|
|
14
14
|
|
|
15
15
|
[🇯🇵 日本語 (Japanese)](#japanese)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.0a2
|
|
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
|
|
@@ -710,10 +710,10 @@ Dynamic: license-file
|
|
|
710
710
|
[](https://pypi.org/project/MoleditPy/)
|
|
711
711
|
[](https://www.gnu.org/licenses/gpl-3.0)
|
|
712
712
|
[](https://github.com/HiroYokoyama/python_molecular_editor/actions)
|
|
713
|
-

|
|
714
|
+

|
|
715
715
|

|
|
716
|
-

|
|
717
717
|
[](https://pepy.tech/projects/moleditpy)
|
|
718
718
|
|
|
719
719
|
[🇯🇵 日本語 (Japanese)](#japanese)
|
|
@@ -0,0 +1,60 @@
|
|
|
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 ctypes
|
|
14
|
+
import sys
|
|
15
|
+
import argparse
|
|
16
|
+
import logging
|
|
17
|
+
|
|
18
|
+
from PyQt6.QtWidgets import QApplication
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
from .modules.main_window import MainWindow
|
|
22
|
+
except ImportError:
|
|
23
|
+
from modules.main_window import MainWindow
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def setup_logging():
|
|
27
|
+
"""Configure global logging to standard output."""
|
|
28
|
+
logging.basicConfig(
|
|
29
|
+
level=logging.INFO,
|
|
30
|
+
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
|
31
|
+
stream=sys.stdout,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def main():
|
|
36
|
+
# Setup logging as early as possible
|
|
37
|
+
setup_logging()
|
|
38
|
+
|
|
39
|
+
# --- Additional handling for Windows taskbar icon ---
|
|
40
|
+
if sys.platform == "win32":
|
|
41
|
+
myappid = "hyoko.moleditpy.1.0" # Application-specific ID (arbitrary)
|
|
42
|
+
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
|
|
43
|
+
|
|
44
|
+
parser = argparse.ArgumentParser(
|
|
45
|
+
prog="moleditpy", description="MoleditPy molecular editor"
|
|
46
|
+
)
|
|
47
|
+
parser.add_argument("file", nargs="?", default=None, help="File to open on startup")
|
|
48
|
+
parser.add_argument(
|
|
49
|
+
"--safe",
|
|
50
|
+
action="store_true",
|
|
51
|
+
default=False,
|
|
52
|
+
help="Start in safe mode: skip loading all plugins",
|
|
53
|
+
)
|
|
54
|
+
# parse_known_args so Qt's own argv flags (e.g. -platform) are passed through
|
|
55
|
+
args, remaining = parser.parse_known_args()
|
|
56
|
+
|
|
57
|
+
app = QApplication([sys.argv[0]] + remaining)
|
|
58
|
+
window = MainWindow(initial_file=args.file, safe_mode=args.safe)
|
|
59
|
+
window.show()
|
|
60
|
+
sys.exit(app.exec())
|
|
@@ -12,12 +12,14 @@ DOI: 10.5281/zenodo.17268532
|
|
|
12
12
|
|
|
13
13
|
try:
|
|
14
14
|
import importlib.util
|
|
15
|
+
|
|
15
16
|
OBABEL_AVAILABLE = importlib.util.find_spec("openbabel") is not None
|
|
16
17
|
except ImportError:
|
|
17
18
|
OBABEL_AVAILABLE = False
|
|
18
19
|
|
|
19
20
|
try:
|
|
20
21
|
from PyQt6 import sip as _sip # type: ignore
|
|
22
|
+
|
|
21
23
|
_sip_isdeleted = getattr(_sip, "isdeleted", None)
|
|
22
24
|
except ImportError:
|
|
23
25
|
_sip = None
|
|
@@ -1,110 +1,115 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
from PyQt6.
|
|
17
|
-
from PyQt6.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
self.
|
|
30
|
-
self.
|
|
31
|
-
self.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
self.image_label
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
160,
|
|
48
|
-
|
|
49
|
-
Qt.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
pixmap
|
|
55
|
-
|
|
56
|
-
painter
|
|
57
|
-
painter.
|
|
58
|
-
painter.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
#
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
button_layout
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
self.main_window.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
self.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
event.ignore()
|
|
109
|
-
|
|
110
|
-
|
|
1
|
+
import logging
|
|
2
|
+
#!/usr/bin/env python3
|
|
3
|
+
# -*- coding: utf-8 -*-
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
MoleditPy — A Python-based molecular editing software
|
|
7
|
+
|
|
8
|
+
Author: Hiromichi Yokoyama
|
|
9
|
+
License: GPL-3.0 license
|
|
10
|
+
Repo: https://github.com/HiroYokoyama/python_molecular_editor
|
|
11
|
+
DOI: 10.5281/zenodo.17268532
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
|
|
16
|
+
from PyQt6.QtCore import Qt
|
|
17
|
+
from PyQt6.QtGui import QCursor, QPainter, QPen, QPixmap
|
|
18
|
+
from PyQt6.QtWidgets import QDialog, QHBoxLayout, QLabel, QPushButton, QVBoxLayout
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
from .constants import VERSION
|
|
22
|
+
except ImportError:
|
|
23
|
+
from modules.constants import VERSION
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AboutDialog(QDialog):
|
|
27
|
+
def __init__(self, main_window, parent=None):
|
|
28
|
+
super().__init__(parent)
|
|
29
|
+
self.main_window = main_window
|
|
30
|
+
self.setWindowTitle("About MoleditPy")
|
|
31
|
+
self.setFixedSize(250, 300)
|
|
32
|
+
self.init_ui()
|
|
33
|
+
|
|
34
|
+
def init_ui(self):
|
|
35
|
+
layout = QVBoxLayout(self)
|
|
36
|
+
|
|
37
|
+
# Create a clickable image label
|
|
38
|
+
self.image_label = QLabel()
|
|
39
|
+
self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
40
|
+
|
|
41
|
+
# Load the original icon image
|
|
42
|
+
icon_path = os.path.join(os.path.dirname(__file__), "..", "assets", "icon.png")
|
|
43
|
+
if os.path.exists(icon_path):
|
|
44
|
+
original_pixmap = QPixmap(icon_path)
|
|
45
|
+
# Scale to 2x size (160x160)
|
|
46
|
+
pixmap = original_pixmap.scaled(
|
|
47
|
+
160,
|
|
48
|
+
160,
|
|
49
|
+
Qt.AspectRatioMode.KeepAspectRatio,
|
|
50
|
+
Qt.TransformationMode.SmoothTransformation,
|
|
51
|
+
)
|
|
52
|
+
else:
|
|
53
|
+
# Fallback: create a simple placeholder if icon.png not found
|
|
54
|
+
pixmap = QPixmap(160, 160)
|
|
55
|
+
pixmap.fill(Qt.GlobalColor.lightGray)
|
|
56
|
+
painter = QPainter(pixmap)
|
|
57
|
+
painter.setPen(QPen(Qt.GlobalColor.black, 2))
|
|
58
|
+
painter.drawText(pixmap.rect(), Qt.AlignmentFlag.AlignCenter, "MoleditPy")
|
|
59
|
+
painter.end()
|
|
60
|
+
|
|
61
|
+
self.image_label.setPixmap(pixmap)
|
|
62
|
+
try:
|
|
63
|
+
self.image_label.setCursor(QCursor(Qt.CursorShape.ArrowCursor))
|
|
64
|
+
except (AttributeError, RuntimeError, ValueError, TypeError) as e:
|
|
65
|
+
logging.debug(
|
|
66
|
+
f"Suppressed exception: {e}"
|
|
67
|
+
) # Suppress cursor setting errors on about image
|
|
68
|
+
|
|
69
|
+
self.image_label.mousePressEvent = self.image_mouse_press_event
|
|
70
|
+
|
|
71
|
+
layout.addWidget(self.image_label)
|
|
72
|
+
|
|
73
|
+
# Add text information
|
|
74
|
+
info_text = f"MoleditPy Ver. {VERSION}\nAuthor: Hiromichi Yokoyama\nLicense: GPL-3.0 license"
|
|
75
|
+
info_label = QLabel(info_text)
|
|
76
|
+
info_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
77
|
+
layout.addWidget(info_label)
|
|
78
|
+
|
|
79
|
+
# Add OK button
|
|
80
|
+
ok_button = QPushButton("OK")
|
|
81
|
+
ok_button.setFixedSize(80, 30) # Fixed small size
|
|
82
|
+
ok_button.clicked.connect(self.accept)
|
|
83
|
+
|
|
84
|
+
# Center the button
|
|
85
|
+
button_layout = QHBoxLayout()
|
|
86
|
+
button_layout.addStretch()
|
|
87
|
+
button_layout.addWidget(ok_button)
|
|
88
|
+
button_layout.addStretch()
|
|
89
|
+
layout.addLayout(button_layout)
|
|
90
|
+
|
|
91
|
+
def image_clicked(self, event):
|
|
92
|
+
"""Easter egg: Clear all and load bipyrimidine from SMILES"""
|
|
93
|
+
# Clear the current scene
|
|
94
|
+
self.main_window.clear_all()
|
|
95
|
+
|
|
96
|
+
bipyrimidine_smiles = "C1=CN=C(N=C1)C2=NC=CC=N2"
|
|
97
|
+
self.main_window.load_from_smiles(bipyrimidine_smiles)
|
|
98
|
+
|
|
99
|
+
# Close the dialog
|
|
100
|
+
self.accept()
|
|
101
|
+
|
|
102
|
+
def image_mouse_press_event(self, event):
|
|
103
|
+
"""Handle mouse press on the image: trigger easter egg only for right-click."""
|
|
104
|
+
try:
|
|
105
|
+
if event.button() == Qt.MouseButton.RightButton:
|
|
106
|
+
self.image_clicked(event)
|
|
107
|
+
else:
|
|
108
|
+
event.ignore()
|
|
109
|
+
except (AttributeError, RuntimeError, ValueError, TypeError):
|
|
110
|
+
try:
|
|
111
|
+
event.ignore()
|
|
112
|
+
except (AttributeError, RuntimeError, ValueError, TypeError) as e:
|
|
113
|
+
logging.debug(
|
|
114
|
+
f"Suppressed exception: {e}"
|
|
115
|
+
) # Suppress nested event errors
|
|
@@ -20,6 +20,7 @@ from PyQt6.QtWidgets import (
|
|
|
20
20
|
QPushButton,
|
|
21
21
|
QVBoxLayout,
|
|
22
22
|
)
|
|
23
|
+
from rdkit import Geometry
|
|
23
24
|
|
|
24
25
|
try:
|
|
25
26
|
from .dialog_3d_picking_mixin import Dialog3DPickingMixin
|
|
@@ -27,7 +28,7 @@ except ImportError:
|
|
|
27
28
|
from modules.dialog_3d_picking_mixin import Dialog3DPickingMixin
|
|
28
29
|
|
|
29
30
|
|
|
30
|
-
class AlignPlaneDialog(Dialog3DPickingMixin, QDialog):
|
|
31
|
+
class AlignPlaneDialog(Dialog3DPickingMixin, QDialog):
|
|
31
32
|
def __init__(self, mol, main_window, plane, preselected_atoms=None, parent=None):
|
|
32
33
|
QDialog.__init__(self, parent)
|
|
33
34
|
Dialog3DPickingMixin.__init__(self)
|
|
@@ -218,7 +219,9 @@ class AlignPlaneDialog(Dialog3DPickingMixin, QDialog):
|
|
|
218
219
|
eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
|
|
219
220
|
|
|
220
221
|
# Normal vector of the plane corresponds to the smallest eigenvalue
|
|
221
|
-
normal_vector = eigenvectors[
|
|
222
|
+
normal_vector = eigenvectors[
|
|
223
|
+
:, 0
|
|
224
|
+
] # Normal vector of the plane corresponds to the smallest eigenvalue
|
|
222
225
|
|
|
223
226
|
# Define target plane normal vector
|
|
224
227
|
if self.plane == "xy":
|
|
@@ -264,7 +267,12 @@ class AlignPlaneDialog(Dialog3DPickingMixin, QDialog):
|
|
|
264
267
|
centered_pos, rotation_axis, rotation_angle
|
|
265
268
|
)
|
|
266
269
|
new_pos = rotated_pos + centroid
|
|
267
|
-
conf.SetAtomPosition(
|
|
270
|
+
conf.SetAtomPosition(
|
|
271
|
+
i,
|
|
272
|
+
Geometry.Point3D(
|
|
273
|
+
float(new_pos[0]), float(new_pos[1]), float(new_pos[2])
|
|
274
|
+
),
|
|
275
|
+
)
|
|
268
276
|
self.main_window.atom_positions_3d[i] = new_pos
|
|
269
277
|
|
|
270
278
|
# Update 3D visualization
|
|
@@ -19,6 +19,7 @@ from PyQt6.QtWidgets import (
|
|
|
19
19
|
QPushButton,
|
|
20
20
|
QVBoxLayout,
|
|
21
21
|
)
|
|
22
|
+
from rdkit import Geometry
|
|
22
23
|
|
|
23
24
|
try:
|
|
24
25
|
from .dialog_3d_picking_mixin import Dialog3DPickingMixin
|
|
@@ -26,7 +27,7 @@ except ImportError:
|
|
|
26
27
|
from modules.dialog_3d_picking_mixin import Dialog3DPickingMixin
|
|
27
28
|
|
|
28
29
|
|
|
29
|
-
class AlignmentDialog(Dialog3DPickingMixin, QDialog):
|
|
30
|
+
class AlignmentDialog(Dialog3DPickingMixin, QDialog):
|
|
30
31
|
def __init__(self, mol, main_window, axis, preselected_atoms=None, parent=None):
|
|
31
32
|
QDialog.__init__(self, parent)
|
|
32
33
|
Dialog3DPickingMixin.__init__(self)
|
|
@@ -221,7 +222,14 @@ class AlignmentDialog(Dialog3DPickingMixin, QDialog):
|
|
|
221
222
|
rotated_pos = rodrigues_rotation(
|
|
222
223
|
current_pos, rotation_axis, rotation_angle
|
|
223
224
|
)
|
|
224
|
-
conf.SetAtomPosition(
|
|
225
|
+
conf.SetAtomPosition(
|
|
226
|
+
i,
|
|
227
|
+
Geometry.Point3D(
|
|
228
|
+
float(rotated_pos[0]),
|
|
229
|
+
float(rotated_pos[1]),
|
|
230
|
+
float(rotated_pos[2]),
|
|
231
|
+
),
|
|
232
|
+
)
|
|
225
233
|
|
|
226
234
|
# Update 3D positions
|
|
227
235
|
self.main_window.atom_positions_3d = np.array(
|