MoleditPy-linux 2.4.1__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.
- moleditpy_linux/__init__.py +17 -0
- moleditpy_linux/__main__.py +29 -0
- moleditpy_linux/main.py +37 -0
- moleditpy_linux/modules/__init__.py +41 -0
- moleditpy_linux/modules/about_dialog.py +104 -0
- moleditpy_linux/modules/align_plane_dialog.py +292 -0
- moleditpy_linux/modules/alignment_dialog.py +272 -0
- moleditpy_linux/modules/analysis_window.py +209 -0
- moleditpy_linux/modules/angle_dialog.py +440 -0
- moleditpy_linux/modules/assets/file_icon.ico +0 -0
- moleditpy_linux/modules/assets/icon.icns +0 -0
- moleditpy_linux/modules/assets/icon.ico +0 -0
- moleditpy_linux/modules/assets/icon.png +0 -0
- moleditpy_linux/modules/atom_item.py +395 -0
- moleditpy_linux/modules/bond_item.py +464 -0
- moleditpy_linux/modules/bond_length_dialog.py +380 -0
- moleditpy_linux/modules/calculation_worker.py +766 -0
- moleditpy_linux/modules/color_settings_dialog.py +321 -0
- moleditpy_linux/modules/constants.py +88 -0
- moleditpy_linux/modules/constrained_optimization_dialog.py +678 -0
- moleditpy_linux/modules/custom_interactor_style.py +749 -0
- moleditpy_linux/modules/custom_qt_interactor.py +102 -0
- moleditpy_linux/modules/dialog3_d_picking_mixin.py +141 -0
- moleditpy_linux/modules/dihedral_dialog.py +443 -0
- moleditpy_linux/modules/main_window.py +850 -0
- moleditpy_linux/modules/main_window_app_state.py +787 -0
- moleditpy_linux/modules/main_window_compute.py +1242 -0
- moleditpy_linux/modules/main_window_dialog_manager.py +460 -0
- moleditpy_linux/modules/main_window_edit_3d.py +536 -0
- moleditpy_linux/modules/main_window_edit_actions.py +1565 -0
- moleditpy_linux/modules/main_window_export.py +917 -0
- moleditpy_linux/modules/main_window_main_init.py +2100 -0
- moleditpy_linux/modules/main_window_molecular_parsers.py +1044 -0
- moleditpy_linux/modules/main_window_project_io.py +434 -0
- moleditpy_linux/modules/main_window_string_importers.py +275 -0
- moleditpy_linux/modules/main_window_ui_manager.py +602 -0
- moleditpy_linux/modules/main_window_view_3d.py +1539 -0
- moleditpy_linux/modules/main_window_view_loaders.py +355 -0
- moleditpy_linux/modules/mirror_dialog.py +122 -0
- moleditpy_linux/modules/molecular_data.py +302 -0
- moleditpy_linux/modules/molecule_scene.py +2000 -0
- moleditpy_linux/modules/move_group_dialog.py +600 -0
- moleditpy_linux/modules/periodic_table_dialog.py +84 -0
- moleditpy_linux/modules/planarize_dialog.py +220 -0
- moleditpy_linux/modules/plugin_interface.py +215 -0
- moleditpy_linux/modules/plugin_manager.py +473 -0
- moleditpy_linux/modules/plugin_manager_window.py +274 -0
- moleditpy_linux/modules/settings_dialog.py +1503 -0
- moleditpy_linux/modules/template_preview_item.py +157 -0
- moleditpy_linux/modules/template_preview_view.py +74 -0
- moleditpy_linux/modules/translation_dialog.py +364 -0
- moleditpy_linux/modules/user_template_dialog.py +692 -0
- moleditpy_linux/modules/zoomable_view.py +129 -0
- moleditpy_linux-2.4.1.dist-info/METADATA +954 -0
- moleditpy_linux-2.4.1.dist-info/RECORD +59 -0
- moleditpy_linux-2.4.1.dist-info/WHEEL +5 -0
- moleditpy_linux-2.4.1.dist-info/entry_points.txt +2 -0
- moleditpy_linux-2.4.1.dist-info/licenses/LICENSE +674 -0
- moleditpy_linux-2.4.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,321 @@
|
|
|
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
|
+
from PyQt6.QtWidgets import (
|
|
14
|
+
QDialog, QVBoxLayout, QGridLayout, QPushButton, QHBoxLayout, QLabel,
|
|
15
|
+
QApplication, QColorDialog
|
|
16
|
+
)
|
|
17
|
+
from PyQt6.QtGui import QColor
|
|
18
|
+
try:
|
|
19
|
+
from .constants import CPK_COLORS, DEFAULT_CPK_COLORS
|
|
20
|
+
except Exception:
|
|
21
|
+
from modules.constants import CPK_COLORS, DEFAULT_CPK_COLORS
|
|
22
|
+
|
|
23
|
+
class ColorSettingsDialog(QDialog):
|
|
24
|
+
"""Dialog to customize CPK element colors.
|
|
25
|
+
|
|
26
|
+
- Click an element to pick a new color for the element (CPK colors).
|
|
27
|
+
- Reset All button to restore defaults for everything.
|
|
28
|
+
"""
|
|
29
|
+
def __init__(self, current_settings, parent=None):
|
|
30
|
+
super().__init__(parent)
|
|
31
|
+
self.setWindowTitle("CPK Colors")
|
|
32
|
+
self.parent_window = parent
|
|
33
|
+
self.current_settings = current_settings or {}
|
|
34
|
+
|
|
35
|
+
self.changed_cpk = {} # symbol -> hex
|
|
36
|
+
self._reset_all_flag = False
|
|
37
|
+
|
|
38
|
+
layout = QVBoxLayout(self)
|
|
39
|
+
|
|
40
|
+
# Color picking for CPK is available in the periodic table and CPK dialog
|
|
41
|
+
|
|
42
|
+
# Periodic table grid (buttons like PeriodicTableDialog)
|
|
43
|
+
grid = QGridLayout()
|
|
44
|
+
self.element_buttons = {}
|
|
45
|
+
elements = [
|
|
46
|
+
('H',1,1), ('He',1,18),
|
|
47
|
+
('Li',2,1), ('Be',2,2), ('B',2,13), ('C',2,14), ('N',2,15), ('O',2,16), ('F',2,17), ('Ne',2,18),
|
|
48
|
+
('Na',3,1), ('Mg',3,2), ('Al',3,13), ('Si',3,14), ('P',3,15), ('S',3,16), ('Cl',3,17), ('Ar',3,18),
|
|
49
|
+
('K',4,1), ('Ca',4,2), ('Sc',4,3), ('Ti',4,4), ('V',4,5), ('Cr',4,6), ('Mn',4,7), ('Fe',4,8),
|
|
50
|
+
('Co',4,9), ('Ni',4,10), ('Cu',4,11), ('Zn',4,12), ('Ga',4,13), ('Ge',4,14), ('As',4,15), ('Se',4,16),
|
|
51
|
+
('Br',4,17), ('Kr',4,18),
|
|
52
|
+
('Rb',5,1), ('Sr',5,2), ('Y',5,3), ('Zr',5,4), ('Nb',5,5), ('Mo',5,6), ('Tc',5,7), ('Ru',5,8),
|
|
53
|
+
('Rh',5,9), ('Pd',5,10), ('Ag',5,11), ('Cd',5,12), ('In',5,13), ('Sn',5,14), ('Sb',5,15), ('Te',5,16),
|
|
54
|
+
('I',5,17), ('Xe',5,18),
|
|
55
|
+
('Cs',6,1), ('Ba',6,2), ('Hf',6,4), ('Ta',6,5), ('W',6,6), ('Re',6,7), ('Os',6,8),
|
|
56
|
+
('Ir',6,9), ('Pt',6,10), ('Au',6,11), ('Hg',6,12), ('Tl',6,13), ('Pb',6,14), ('Bi',6,15), ('Po',6,16),
|
|
57
|
+
('At',6,17), ('Rn',6,18),
|
|
58
|
+
('Fr',7,1), ('Ra',7,2), ('Rf',7,4), ('Db',7,5), ('Sg',7,6), ('Bh',7,7), ('Hs',7,8),
|
|
59
|
+
('Mt',7,9), ('Ds',7,10), ('Rg',7,11), ('Cn',7,12), ('Nh',7,13), ('Fl',7,14), ('Mc',7,15), ('Lv',7,16),
|
|
60
|
+
('Ts',7,17), ('Og',7,18),
|
|
61
|
+
('La',8,3), ('Ce',8,4), ('Pr',8,5), ('Nd',8,6), ('Pm',8,7), ('Sm',8,8), ('Eu',8,9), ('Gd',8,10), ('Tb',8,11),
|
|
62
|
+
('Dy',8,12), ('Ho',8,13), ('Er',8,14), ('Tm',8,15), ('Yb',8,16), ('Lu',8,17),
|
|
63
|
+
('Ac',9,3), ('Th',9,4), ('Pa',9,5), ('U',9,6), ('Np',9,7), ('Pu',9,8), ('Am',9,9), ('Cm',9,10), ('Bk',9,11),
|
|
64
|
+
('Cf',9,12), ('Es',9,13), ('Fm',9,14), ('Md',9,15), ('No',9,16), ('Lr',9,17),
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
for symbol, row, col in elements:
|
|
68
|
+
b = QPushButton(symbol)
|
|
69
|
+
b.setFixedSize(40, 40)
|
|
70
|
+
# Choose override color (if present) else default CPK color
|
|
71
|
+
override = self.current_settings.get('cpk_colors', {}).get(symbol)
|
|
72
|
+
if override:
|
|
73
|
+
q_color = QColor(override)
|
|
74
|
+
else:
|
|
75
|
+
q_color = CPK_COLORS.get(symbol, CPK_COLORS['DEFAULT'])
|
|
76
|
+
|
|
77
|
+
brightness = (q_color.red() * 299 + q_color.green() * 587 + q_color.blue() * 114) / 1000
|
|
78
|
+
text_color = 'white' if brightness < 128 else 'black'
|
|
79
|
+
b.setStyleSheet(f"background-color: {q_color.name()}; color: {text_color}; border: 1px solid #555; font-weight: bold;")
|
|
80
|
+
b.clicked.connect(self.on_element_clicked)
|
|
81
|
+
grid.addWidget(b, row, col)
|
|
82
|
+
self.element_buttons[symbol] = b
|
|
83
|
+
|
|
84
|
+
layout.addLayout(grid)
|
|
85
|
+
|
|
86
|
+
# Ball & Stick bond color (3D) picker - placed near the periodic table for CPK settings
|
|
87
|
+
self.changed_bs_color = None
|
|
88
|
+
try:
|
|
89
|
+
bs_h = QHBoxLayout()
|
|
90
|
+
bs_label = QLabel("Ball & Stick bond color:")
|
|
91
|
+
self.bs_button = QPushButton()
|
|
92
|
+
self.bs_button.setFixedSize(36, 24)
|
|
93
|
+
# initialize from current settings (if provided)
|
|
94
|
+
try:
|
|
95
|
+
cur_bs = self.current_settings.get('ball_stick_bond_color') if self.current_settings else None
|
|
96
|
+
except Exception:
|
|
97
|
+
cur_bs = None
|
|
98
|
+
if not cur_bs and self.parent_window and hasattr(self.parent_window, 'settings'):
|
|
99
|
+
cur_bs = self.parent_window.settings.get('ball_stick_bond_color', '#7F7F7F')
|
|
100
|
+
try:
|
|
101
|
+
self.bs_button.setStyleSheet(f"background-color: {cur_bs}; border: 1px solid #888;")
|
|
102
|
+
self.bs_button.setToolTip(cur_bs)
|
|
103
|
+
except Exception:
|
|
104
|
+
pass
|
|
105
|
+
self.bs_button.clicked.connect(self.pick_bs_bond_color)
|
|
106
|
+
bs_h.addWidget(bs_label)
|
|
107
|
+
bs_h.addWidget(self.bs_button)
|
|
108
|
+
bs_h.addStretch(1)
|
|
109
|
+
layout.addLayout(bs_h)
|
|
110
|
+
except Exception:
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
# Reset button and action buttons
|
|
114
|
+
h = QHBoxLayout()
|
|
115
|
+
reset_button = QPushButton("Reset All")
|
|
116
|
+
reset_button.clicked.connect(self.reset_all)
|
|
117
|
+
h.addWidget(reset_button)
|
|
118
|
+
h.addStretch(1)
|
|
119
|
+
apply_button = QPushButton("Apply")
|
|
120
|
+
apply_button.clicked.connect(self.apply_changes)
|
|
121
|
+
ok_button = QPushButton("OK")
|
|
122
|
+
ok_button.clicked.connect(self.accept)
|
|
123
|
+
cancel_button = QPushButton("Cancel")
|
|
124
|
+
cancel_button.clicked.connect(self.reject)
|
|
125
|
+
|
|
126
|
+
h.addWidget(apply_button); h.addWidget(ok_button); h.addWidget(cancel_button)
|
|
127
|
+
layout.addLayout(h)
|
|
128
|
+
|
|
129
|
+
# initialize
|
|
130
|
+
# No 2D bond color control here
|
|
131
|
+
|
|
132
|
+
# 2D bond color picker removed — 2D bond color is fixed and not configurable here
|
|
133
|
+
|
|
134
|
+
def on_element_clicked(self):
|
|
135
|
+
b = self.sender()
|
|
136
|
+
symbol = b.text()
|
|
137
|
+
# get current color (override if exists else default)
|
|
138
|
+
cur = self.current_settings.get('cpk_colors', {}).get(symbol)
|
|
139
|
+
if not cur:
|
|
140
|
+
cur = CPK_COLORS.get(symbol, CPK_COLORS['DEFAULT']).name()
|
|
141
|
+
color = QColorDialog.getColor(QColor(cur), self)
|
|
142
|
+
if color.isValid():
|
|
143
|
+
self.changed_cpk[symbol] = color.name()
|
|
144
|
+
# Update button appearance
|
|
145
|
+
brightness = (color.red() * 299 + color.green() * 587 + color.blue() * 114) / 1000
|
|
146
|
+
text_color = 'white' if brightness < 128 else 'black'
|
|
147
|
+
b.setStyleSheet(f"background-color: {color.name()}; color: {text_color}; border: 1px solid #555; font-weight: bold;")
|
|
148
|
+
|
|
149
|
+
def reset_all(self):
|
|
150
|
+
# Clear overrides
|
|
151
|
+
self.changed_cpk = {}
|
|
152
|
+
self._reset_all_flag = True
|
|
153
|
+
|
|
154
|
+
# 1. B&S結合色もリセット対象(デフォルト値)に設定
|
|
155
|
+
try:
|
|
156
|
+
self.changed_bs_color = self.parent_window.default_settings.get('ball_stick_bond_color', '#7F7F7F') if hasattr(self.parent_window, 'default_settings') else '#7F7F7F'
|
|
157
|
+
except Exception:
|
|
158
|
+
self.changed_bs_color = '#7F7F7F'
|
|
159
|
+
|
|
160
|
+
# 2. ダイアログ内のCPKボタンの表示をデフォルトに戻す
|
|
161
|
+
for s, btn in self.element_buttons.items():
|
|
162
|
+
q_color = DEFAULT_CPK_COLORS.get(s, DEFAULT_CPK_COLORS['DEFAULT'])
|
|
163
|
+
brightness = (q_color.red() * 299 + q_color.green() * 587 + q_color.blue() * 114) / 1000
|
|
164
|
+
text_color = 'white' if brightness < 128 else 'black'
|
|
165
|
+
btn.setStyleSheet(f"background-color: {q_color.name()}; color: {text_color}; border: 1px solid #555; font-weight: bold;")
|
|
166
|
+
|
|
167
|
+
# 3. 3Dプレビューを更新する L.3337〜L.3386 の try...finally ブロックは削除
|
|
168
|
+
|
|
169
|
+
# 4. ダイアログ内のB&S結合色ボタンの表示をデフォルトに戻す
|
|
170
|
+
try:
|
|
171
|
+
if hasattr(self, 'bs_button'):
|
|
172
|
+
# self.changed_bs_color に設定したデフォルト値を反映
|
|
173
|
+
hexv = self.changed_bs_color
|
|
174
|
+
self.bs_button.setStyleSheet(f"background-color: {hexv}; border: 1px solid #888;")
|
|
175
|
+
self.bs_button.setToolTip(hexv)
|
|
176
|
+
except Exception:
|
|
177
|
+
pass
|
|
178
|
+
|
|
179
|
+
def apply_changes(self):
|
|
180
|
+
# Persist only changed keys
|
|
181
|
+
if self.parent_window:
|
|
182
|
+
if self._reset_all_flag:
|
|
183
|
+
# Remove any cpk overrides
|
|
184
|
+
try:
|
|
185
|
+
if 'cpk_colors' in self.parent_window.settings:
|
|
186
|
+
del self.parent_window.settings['cpk_colors']
|
|
187
|
+
except Exception:
|
|
188
|
+
pass
|
|
189
|
+
if self.changed_cpk:
|
|
190
|
+
# Merge with existing overrides
|
|
191
|
+
cdict = self.parent_window.settings.get('cpk_colors', {}).copy()
|
|
192
|
+
cdict.update(self.changed_cpk)
|
|
193
|
+
self.parent_window.settings['cpk_colors'] = cdict
|
|
194
|
+
self.parent_window.settings_dirty = True
|
|
195
|
+
# After changing settings, update global CPK color map and refresh views
|
|
196
|
+
try:
|
|
197
|
+
self.parent_window.update_cpk_colors_from_settings()
|
|
198
|
+
except Exception:
|
|
199
|
+
pass
|
|
200
|
+
try:
|
|
201
|
+
self.parent_window.apply_3d_settings(redraw=False)
|
|
202
|
+
except Exception:
|
|
203
|
+
pass
|
|
204
|
+
try:
|
|
205
|
+
if hasattr(self.parent_window, 'current_mol') and self.parent_window.current_mol:
|
|
206
|
+
self.parent_window.draw_molecule_3d(self.parent_window.current_mol)
|
|
207
|
+
except Exception:
|
|
208
|
+
pass
|
|
209
|
+
# update 2D scene objects
|
|
210
|
+
try:
|
|
211
|
+
if hasattr(self.parent_window, 'scene'):
|
|
212
|
+
for it in self.parent_window.scene.items():
|
|
213
|
+
try:
|
|
214
|
+
if hasattr(it, 'update_style'):
|
|
215
|
+
it.update_style()
|
|
216
|
+
except Exception:
|
|
217
|
+
pass
|
|
218
|
+
except Exception:
|
|
219
|
+
pass
|
|
220
|
+
# update periodic table button styles in the dialog to reflect any overrides
|
|
221
|
+
try:
|
|
222
|
+
for s, btn in self.element_buttons.items():
|
|
223
|
+
try:
|
|
224
|
+
q_color = QColor(self.parent_window.settings.get('cpk_colors', {}).get(s, CPK_COLORS.get(s, CPK_COLORS['DEFAULT']).name()))
|
|
225
|
+
brightness = (q_color.red() * 299 + q_color.green() * 587 + q_color.blue() * 114) / 1000
|
|
226
|
+
text_color = 'white' if brightness < 128 else 'black'
|
|
227
|
+
btn.setStyleSheet(f"background-color: {q_color.name()}; color: {text_color}; border: 1px solid #555; font-weight: bold;")
|
|
228
|
+
except Exception:
|
|
229
|
+
pass
|
|
230
|
+
except Exception:
|
|
231
|
+
pass
|
|
232
|
+
# Refresh any open SettingsDialog instances so the ball & stick color preview updates
|
|
233
|
+
try:
|
|
234
|
+
# Avoid circular import at module level; import SettingsDialog on demand
|
|
235
|
+
try:
|
|
236
|
+
from .settings_dialog import SettingsDialog
|
|
237
|
+
except Exception:
|
|
238
|
+
from modules.settings_dialog import SettingsDialog
|
|
239
|
+
|
|
240
|
+
for w in QApplication.topLevelWidgets():
|
|
241
|
+
try:
|
|
242
|
+
if isinstance(w, SettingsDialog):
|
|
243
|
+
try:
|
|
244
|
+
w.update_ui_from_settings(self.parent_window.settings)
|
|
245
|
+
except Exception:
|
|
246
|
+
pass
|
|
247
|
+
except Exception:
|
|
248
|
+
pass
|
|
249
|
+
except Exception:
|
|
250
|
+
pass
|
|
251
|
+
# Persist changed Ball & Stick color if the user changed it from the CPK dialog
|
|
252
|
+
if getattr(self, 'changed_bs_color', None):
|
|
253
|
+
try:
|
|
254
|
+
self.parent_window.settings['ball_stick_bond_color'] = self.changed_bs_color
|
|
255
|
+
try:
|
|
256
|
+
self.parent_window.settings_dirty = True
|
|
257
|
+
except Exception:
|
|
258
|
+
pass
|
|
259
|
+
# After changing ball-stick color, ensure 3D view updates
|
|
260
|
+
try:
|
|
261
|
+
self.parent_window.apply_3d_settings()
|
|
262
|
+
except Exception:
|
|
263
|
+
pass
|
|
264
|
+
try:
|
|
265
|
+
if hasattr(self.parent_window, 'current_mol') and self.parent_window.current_mol:
|
|
266
|
+
self.parent_window.draw_molecule_3d(self.parent_window.current_mol)
|
|
267
|
+
except Exception:
|
|
268
|
+
pass
|
|
269
|
+
except Exception:
|
|
270
|
+
pass
|
|
271
|
+
# Removed 2D bond color control — nothing to persist here
|
|
272
|
+
elif self._reset_all_flag:
|
|
273
|
+
# Reset Ball & Stick 3D bond color to default
|
|
274
|
+
try:
|
|
275
|
+
# Use a stable default instead of relying on parent_window.default_settings
|
|
276
|
+
self.parent_window.settings['ball_stick_bond_color'] = '#7F7F7F'
|
|
277
|
+
try:
|
|
278
|
+
self.parent_window.settings_dirty = True
|
|
279
|
+
except Exception:
|
|
280
|
+
pass
|
|
281
|
+
except Exception:
|
|
282
|
+
pass
|
|
283
|
+
self.parent_window.update_cpk_colors_from_settings()
|
|
284
|
+
self.parent_window.apply_3d_settings()
|
|
285
|
+
if hasattr(self.parent_window, 'current_mol') and self.parent_window.current_mol:
|
|
286
|
+
self.parent_window.draw_molecule_3d(self.parent_window.current_mol)
|
|
287
|
+
|
|
288
|
+
# update 2D scene
|
|
289
|
+
try:
|
|
290
|
+
if hasattr(self.parent_window, 'scene'):
|
|
291
|
+
for it in self.parent_window.scene.items():
|
|
292
|
+
try:
|
|
293
|
+
# AtomItem.update_style uses CPK_COLORS map
|
|
294
|
+
if hasattr(it, 'update_style'):
|
|
295
|
+
it.update_style()
|
|
296
|
+
except Exception:
|
|
297
|
+
pass
|
|
298
|
+
except Exception:
|
|
299
|
+
pass
|
|
300
|
+
|
|
301
|
+
def accept(self):
|
|
302
|
+
self.apply_changes()
|
|
303
|
+
super().accept()
|
|
304
|
+
|
|
305
|
+
def pick_bs_bond_color(self):
|
|
306
|
+
"""Pick Ball & Stick 3D bond color from the CPK dialog and update preview immediately."""
|
|
307
|
+
try:
|
|
308
|
+
cur = getattr(self, 'changed_bs_color', None) or (self.current_settings.get('ball_stick_bond_color') if self.current_settings else None)
|
|
309
|
+
except Exception:
|
|
310
|
+
cur = None
|
|
311
|
+
if not cur and self.parent_window and hasattr(self.parent_window, 'settings'):
|
|
312
|
+
cur = self.parent_window.settings.get('ball_stick_bond_color', '#7F7F7F')
|
|
313
|
+
color = QColorDialog.getColor(QColor(cur), self)
|
|
314
|
+
if color.isValid():
|
|
315
|
+
hexv = color.name()
|
|
316
|
+
self.changed_bs_color = hexv
|
|
317
|
+
try:
|
|
318
|
+
self.bs_button.setStyleSheet(f"background-color: {hexv}; border: 1px solid #888;")
|
|
319
|
+
self.bs_button.setToolTip(hexv)
|
|
320
|
+
except Exception:
|
|
321
|
+
pass
|
|
@@ -0,0 +1,88 @@
|
|
|
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
|
+
# --- Constants ---
|
|
14
|
+
|
|
15
|
+
from PyQt6.QtGui import QFont, QColor
|
|
16
|
+
from rdkit import Chem
|
|
17
|
+
|
|
18
|
+
#Version
|
|
19
|
+
VERSION = '2.4.1'
|
|
20
|
+
|
|
21
|
+
ATOM_RADIUS = 18
|
|
22
|
+
BOND_OFFSET = 3.5
|
|
23
|
+
DEFAULT_BOND_LENGTH = 75 # テンプレートで使用する標準結合長
|
|
24
|
+
CLIPBOARD_MIME_TYPE = "application/x-moleditpy-fragment"
|
|
25
|
+
|
|
26
|
+
# Physical bond length (approximate) used to convert scene pixels to angstroms.
|
|
27
|
+
# DEFAULT_BOND_LENGTH is the length in pixels used in the editor UI for a typical bond.
|
|
28
|
+
# Many molecular file formats expect coordinates in angstroms; use ~1.5 Å as a typical single-bond length.
|
|
29
|
+
DEFAULT_BOND_LENGTH_ANGSTROM = 1.5
|
|
30
|
+
# Multiply pixel coordinates by this to get angstroms: ANGSTROM_PER_PIXEL = 1.5Å / DEFAULT_BOND_LENGTH(px)
|
|
31
|
+
ANGSTROM_PER_PIXEL = DEFAULT_BOND_LENGTH_ANGSTROM / DEFAULT_BOND_LENGTH
|
|
32
|
+
|
|
33
|
+
# UI / drawing / behavior constants (centralized for maintainability)
|
|
34
|
+
FONT_FAMILY = "Arial"
|
|
35
|
+
FONT_SIZE_LARGE = 20
|
|
36
|
+
FONT_SIZE_SMALL = 12
|
|
37
|
+
FONT_WEIGHT_BOLD = QFont.Weight.Bold
|
|
38
|
+
|
|
39
|
+
# Hit / visual sizes (in pixels at scale=1)
|
|
40
|
+
DESIRED_ATOM_PIXEL_RADIUS = 15.0
|
|
41
|
+
DESIRED_BOND_PIXEL_WIDTH = 18.0
|
|
42
|
+
|
|
43
|
+
# Bond/EZ label
|
|
44
|
+
EZ_LABEL_TEXT_OUTLINE = 2.5
|
|
45
|
+
EZ_LABEL_MARGIN = 16
|
|
46
|
+
EZ_LABEL_BOX_SIZE = 28
|
|
47
|
+
|
|
48
|
+
# Interaction thresholds
|
|
49
|
+
SNAP_DISTANCE = 14.0
|
|
50
|
+
SUM_TOLERANCE = 5.0
|
|
51
|
+
|
|
52
|
+
# Misc drawing
|
|
53
|
+
NUM_DASHES = 8
|
|
54
|
+
HOVER_PEN_WIDTH = 8
|
|
55
|
+
|
|
56
|
+
CPK_COLORS = {
|
|
57
|
+
'H': QColor('#FFFFFF'), 'C': QColor('#222222'), 'N': QColor('#3377FF'), 'O': QColor('#FF3333'), 'F': QColor('#99E6E6'),
|
|
58
|
+
'Cl': QColor('#33FF33'), 'Br': QColor('#A52A2A'), 'I': QColor('#9400D3'), 'S': QColor('#FFC000'), 'P': QColor('#FF8000'),
|
|
59
|
+
'Si': QColor('#DAA520'), 'B': QColor('#FA8072'), 'He': QColor('#D9FFFF'), 'Ne': QColor('#B3E3F5'), 'Ar': QColor('#80D1E3'),
|
|
60
|
+
'Kr': QColor('#5CACC8'), 'Xe': QColor('#429EB0'), 'Rn': QColor('#298FA2'), 'Li': QColor('#CC80FF'), 'Na': QColor('#AB5CF2'),
|
|
61
|
+
'K': QColor('#8F44D7'), 'Rb': QColor('#702EBC'), 'Cs': QColor('#561B9E'), 'Fr': QColor('#421384'), 'Be': QColor('#C2FF00'),
|
|
62
|
+
'Mg': QColor('#8AFF00'), 'Ca': QColor('#3DFF00'), 'Sr': QColor('#00FF00'), 'Ba': QColor('#00E600'), 'Ra': QColor('#00B800'),
|
|
63
|
+
'Sc': QColor('#E6E6E6'), 'Ti': QColor('#BFC2C7'), 'V': QColor('#A6A6AB'), 'Cr': QColor('#8A99C7'), 'Mn': QColor('#9C7AC7'),
|
|
64
|
+
'Fe': QColor('#E06633'), 'Co': QColor('#F090A0'), 'Ni': QColor('#50D050'), 'Cu': QColor('#C88033'), 'Zn': QColor('#7D80B0'),
|
|
65
|
+
'Ga': QColor('#C28F8F'), 'Ge': QColor('#668F8F'), 'As': QColor('#BD80E3'), 'Se': QColor('#FFA100'), 'Tc': QColor('#3B9E9E'),
|
|
66
|
+
'Ru': QColor('#248F8F'), 'Rh': QColor('#0A7D8F'), 'Pd': QColor('#006985'), 'Ag': QColor('#C0C0C0'), 'Cd': QColor('#FFD700'),
|
|
67
|
+
'In': QColor('#A67573'), 'Sn': QColor('#668080'), 'Sb': QColor('#9E63B5'), 'Te': QColor('#D47A00'), 'La': QColor('#70D4FF'),
|
|
68
|
+
'Ce': QColor('#FFFFC7'), 'Pr': QColor('#D9FFC7'), 'Nd': QColor('#C7FFC7'), 'Pm': QColor('#A3FFC7'), 'Sm': QColor('#8FFFC7'),
|
|
69
|
+
'Eu': QColor('#61FFC7'), 'Gd': QColor('#45FFC7'), 'Tb': QColor('#30FFC7'), 'Dy': QColor('#1FFFC7'), 'Ho': QColor('#00FF9C'),
|
|
70
|
+
'Er': QColor('#00E675'), 'Tm': QColor('#00D452'), 'Yb': QColor('#00BF38'), 'Lu': QColor('#00AB24'), 'Hf': QColor('#4DC2FF'),
|
|
71
|
+
'Ta': QColor('#4DA6FF'), 'W': QColor('#2194D6'), 'Re': QColor('#267DAB'), 'Os': QColor('#266696'), 'Ir': QColor('#175487'),
|
|
72
|
+
'Pt': QColor('#D0D0E0'), 'Au': QColor('#FFD123'), 'Hg': QColor('#B8B8D0'), 'Tl': QColor('#A6544D'), 'Pb': QColor('#575961'),
|
|
73
|
+
'Bi': QColor('#9E4FB5'), 'Po': QColor('#AB5C00'), 'At': QColor('#754F45'), 'Ac': QColor('#70ABFA'), 'Th': QColor('#00BAFF'),
|
|
74
|
+
'Pa': QColor('#00A1FF'), 'U': QColor('#008FFF'), 'Np': QColor('#0080FF'), 'Pu': QColor('#006BFF'), 'Am': QColor('#545CF2'),
|
|
75
|
+
'Cm': QColor('#785CE3'), 'Bk': QColor('#8A4FE3'), 'Cf': QColor('#A136D4'), 'Es': QColor('#B31FD4'), 'Fm': QColor('#B31FBA'),
|
|
76
|
+
'Md': QColor('#B30DA6'), 'No': QColor('#BD0D87'), 'Lr': QColor('#C70066'), 'Al': QColor('#B3A68F'), 'Y': QColor('#99FFFF'),
|
|
77
|
+
'Zr': QColor('#7EE7E7'), 'Nb': QColor('#68CFCE'), 'Mo': QColor('#52B7B7'), 'DEFAULT': QColor('#FF1493') # Pink fallback
|
|
78
|
+
}
|
|
79
|
+
CPK_COLORS_PV = {
|
|
80
|
+
k: [c.redF(), c.greenF(), c.blueF()] for k, c in CPK_COLORS.items()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# Keep a copy of the original default map so we can restore it when user resets
|
|
84
|
+
DEFAULT_CPK_COLORS = {k: QColor(v) if not isinstance(v, QColor) else v for k, v in CPK_COLORS.items()}
|
|
85
|
+
|
|
86
|
+
pt = Chem.GetPeriodicTable()
|
|
87
|
+
VDW_RADII = {pt.GetElementSymbol(i): pt.GetRvdw(i) * 0.3 for i in range(1, 119)}
|
|
88
|
+
|