MoleditPy 2.2.0a1__py3-none-any.whl → 2.2.0a2__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/modules/constants.py +1 -1
- moleditpy/modules/main_window_ui_manager.py +21 -2
- moleditpy/plugins/Input Generator/orca_xyz2inp_gui.py +1 -1
- moleditpy/plugins/Utility/atom_colorizer.py +46 -331
- moleditpy/plugins/Utility/vdw_radii_overlay.py +150 -21
- {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a2.dist-info}/METADATA +1 -1
- {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a2.dist-info}/RECORD +11 -11
- {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a2.dist-info}/WHEEL +0 -0
- {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a2.dist-info}/entry_points.txt +0 -0
- {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a2.dist-info}/licenses/LICENSE +0 -0
- {moleditpy-2.2.0a1.dist-info → moleditpy-2.2.0a2.dist-info}/top_level.txt +0 -0
moleditpy/modules/constants.py
CHANGED
|
@@ -298,7 +298,7 @@ class MainWindowUiManager(object):
|
|
|
298
298
|
|
|
299
299
|
|
|
300
300
|
def dragEnterEvent(self, event):
|
|
301
|
-
"""
|
|
301
|
+
"""ウィンドウ全体でサポートされているファイルのドラッグを受け入れる"""
|
|
302
302
|
# Accept if any dragged local file has a supported extension
|
|
303
303
|
if event.mimeData().hasUrls():
|
|
304
304
|
urls = event.mimeData().urls()
|
|
@@ -306,9 +306,28 @@ class MainWindowUiManager(object):
|
|
|
306
306
|
try:
|
|
307
307
|
if url.isLocalFile():
|
|
308
308
|
file_path = url.toLocalFile()
|
|
309
|
-
|
|
309
|
+
file_lower = file_path.lower()
|
|
310
|
+
|
|
311
|
+
# Built-in extensions
|
|
312
|
+
if file_lower.endswith(('.pmeraw', '.pmeprj', '.mol', '.sdf', '.xyz')):
|
|
310
313
|
event.acceptProposedAction()
|
|
311
314
|
return
|
|
315
|
+
|
|
316
|
+
# Plugin-registered file openers
|
|
317
|
+
if self.plugin_manager and hasattr(self.plugin_manager, 'file_openers'):
|
|
318
|
+
for ext in self.plugin_manager.file_openers.keys():
|
|
319
|
+
if file_lower.endswith(ext):
|
|
320
|
+
event.acceptProposedAction()
|
|
321
|
+
return
|
|
322
|
+
|
|
323
|
+
# Plugin drop handlers (accept more liberally for custom logic)
|
|
324
|
+
# A plugin drop handler might handle it, so accept
|
|
325
|
+
if self.plugin_manager and hasattr(self.plugin_manager, 'drop_handlers'):
|
|
326
|
+
if len(self.plugin_manager.drop_handlers) > 0:
|
|
327
|
+
# Accept any file if drop handlers are registered
|
|
328
|
+
# They will check the file type in dropEvent
|
|
329
|
+
event.acceptProposedAction()
|
|
330
|
+
return
|
|
312
331
|
except Exception:
|
|
313
332
|
continue
|
|
314
333
|
event.ignore()
|
|
@@ -9,7 +9,7 @@ import json
|
|
|
9
9
|
__version__="2025.12.25"
|
|
10
10
|
__author__="HiroYokoyama"
|
|
11
11
|
PLUGIN_NAME = "ORCA xyz2inp GUI"
|
|
12
|
-
SETTINGS_JSON = os.path.join(os.path.dirname(__file__), "
|
|
12
|
+
SETTINGS_JSON = os.path.join(os.path.dirname(__file__), "orca_xyz2inp_gui.json")
|
|
13
13
|
|
|
14
14
|
class OrcaInputDialog(QDialog):
|
|
15
15
|
def __init__(self, main_window):
|
|
@@ -9,7 +9,6 @@ import traceback
|
|
|
9
9
|
import sys
|
|
10
10
|
import os
|
|
11
11
|
import json
|
|
12
|
-
import functools # Added for polite patching
|
|
13
12
|
|
|
14
13
|
# Try importing from the installed package first (pip package structure)
|
|
15
14
|
try:
|
|
@@ -31,7 +30,6 @@ class AtomColorizerWindow(QDialog):
|
|
|
31
30
|
def __init__(self, main_window):
|
|
32
31
|
super().__init__(parent=main_window)
|
|
33
32
|
self.mw = main_window
|
|
34
|
-
# self.dock = dock_widget # Removed as per instruction
|
|
35
33
|
self.plotter = self.mw.plotter
|
|
36
34
|
|
|
37
35
|
# Set window properties for modeless behavior
|
|
@@ -71,8 +69,6 @@ class AtomColorizerWindow(QDialog):
|
|
|
71
69
|
self.le_indices.setPlaceholderText("e.g. 0, 1, 5")
|
|
72
70
|
sel_layout.addWidget(self.le_indices)
|
|
73
71
|
|
|
74
|
-
# 'Get Selection' button removed as per user request (auto-update is active)
|
|
75
|
-
|
|
76
72
|
# Auto-update timer
|
|
77
73
|
from PyQt6.QtCore import QTimer
|
|
78
74
|
self.sel_timer = QTimer(self)
|
|
@@ -140,13 +136,6 @@ class AtomColorizerWindow(QDialog):
|
|
|
140
136
|
if isinstance(item, int):
|
|
141
137
|
indices.add(item)
|
|
142
138
|
|
|
143
|
-
# 2D Selection logic removed as per request ("2Dはいらない")
|
|
144
|
-
|
|
145
|
-
if not indices:
|
|
146
|
-
# Silent return if auto-updating, or maybe clear?
|
|
147
|
-
# If we invoke manually, we might want info, but generic message is okay if list is empty.
|
|
148
|
-
pass
|
|
149
|
-
|
|
150
139
|
# Update the line edit
|
|
151
140
|
sorted_indices = sorted(list(indices))
|
|
152
141
|
new_text = ",".join(map(str, sorted_indices))
|
|
@@ -155,9 +144,6 @@ class AtomColorizerWindow(QDialog):
|
|
|
155
144
|
|
|
156
145
|
def _auto_update_selection(self):
|
|
157
146
|
"""Timer slot to auto-update selection."""
|
|
158
|
-
# Only update if the user is not actively typing?
|
|
159
|
-
# For now, just call get_selection_from_viewer which now checks for changes before setting text.
|
|
160
|
-
# However, checking if le_indices has focus might be good.
|
|
161
147
|
if self.le_indices.hasFocus():
|
|
162
148
|
return
|
|
163
149
|
self.get_selection_from_viewer()
|
|
@@ -169,51 +155,6 @@ class AtomColorizerWindow(QDialog):
|
|
|
169
155
|
# Update button style
|
|
170
156
|
self.btn_color.setStyleSheet(f"background-color: {c.name()}; color: {'black' if c.lightness() > 128 else 'white'};")
|
|
171
157
|
|
|
172
|
-
def _update_3d_actor(self):
|
|
173
|
-
"""Re-generate glyphs and update the actor to reflect color changes."""
|
|
174
|
-
try:
|
|
175
|
-
# 1. Re-run glyph filter to propagate color changes from glyph_source to mesh
|
|
176
|
-
if hasattr(self.mw, 'glyph_source') and self.mw.glyph_source:
|
|
177
|
-
# Read resolution from settings or default
|
|
178
|
-
try:
|
|
179
|
-
style = self.mw.current_3d_style
|
|
180
|
-
if style == 'cpk':
|
|
181
|
-
resolution = self.mw.settings.get('cpk_resolution', 32)
|
|
182
|
-
elif style == 'stick':
|
|
183
|
-
resolution = self.mw.settings.get('stick_resolution', 16)
|
|
184
|
-
else: # ball_stick
|
|
185
|
-
resolution = self.mw.settings.get('ball_stick_resolution', 16)
|
|
186
|
-
except Exception:
|
|
187
|
-
resolution = 16
|
|
188
|
-
|
|
189
|
-
glyphs = self.mw.glyph_source.glyph(
|
|
190
|
-
scale='radii',
|
|
191
|
-
geom=pv.Sphere(radius=1.0, theta_resolution=resolution, phi_resolution=resolution),
|
|
192
|
-
orient=False
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
# 2. Update the actor
|
|
196
|
-
if hasattr(self.mw, 'atom_actor') and self.mw.atom_actor:
|
|
197
|
-
self.mw.plotter.remove_actor(self.mw.atom_actor)
|
|
198
|
-
|
|
199
|
-
# Re-add mesh (copying properties logic from main_window_view_3d roughly)
|
|
200
|
-
is_lighting_enabled = self.mw.settings.get('lighting_enabled', True)
|
|
201
|
-
mesh_props = dict(
|
|
202
|
-
smooth_shading=True,
|
|
203
|
-
specular=self.mw.settings.get('specular', 0.2),
|
|
204
|
-
specular_power=self.mw.settings.get('specular_power', 20),
|
|
205
|
-
lighting=is_lighting_enabled,
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
self.mw.atom_actor = self.mw.plotter.add_mesh(
|
|
209
|
-
glyphs, scalars='colors', rgb=True, **mesh_props
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
self.mw.plotter.render()
|
|
213
|
-
except Exception as e:
|
|
214
|
-
print(f"Error updating 3D actor: {e}")
|
|
215
|
-
traceback.print_exc()
|
|
216
|
-
|
|
217
158
|
def apply_color(self):
|
|
218
159
|
txt = self.le_indices.text().strip()
|
|
219
160
|
if not txt:
|
|
@@ -227,321 +168,95 @@ class AtomColorizerWindow(QDialog):
|
|
|
227
168
|
QMessageBox.warning(self, "Error", "Invalid indices format.")
|
|
228
169
|
return
|
|
229
170
|
|
|
230
|
-
if not
|
|
231
|
-
QMessageBox.warning(self, "Error", "No
|
|
171
|
+
if not self.mw.current_mol:
|
|
172
|
+
QMessageBox.warning(self, "Error", "No molecule loaded.")
|
|
232
173
|
return
|
|
233
174
|
|
|
234
|
-
|
|
235
|
-
# 1. Update glyph_source colors
|
|
236
175
|
try:
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
colors = self.mw.glyph_source.point_data['colors']
|
|
176
|
+
# Use the API to set atom colors
|
|
177
|
+
hex_color = self.current_color.name()
|
|
241
178
|
|
|
242
|
-
# Helper to normalize color to whatever format 'colors' is using
|
|
243
|
-
r, g, b = self.current_color.red(), self.current_color.green(), self.current_color.blue()
|
|
244
|
-
|
|
245
|
-
# Store simple 0-255 list for persistence to avoid numpy type issues in JSON
|
|
246
|
-
stored_color = [r, g, b]
|
|
247
|
-
|
|
248
|
-
# Check if colors are float (0-1) or uint8 (0-255)
|
|
249
|
-
is_float = (colors.dtype.kind == 'f')
|
|
250
|
-
|
|
251
|
-
new_color_val = [r/255.0, g/255.0, b/255.0] if is_float else [r, g, b]
|
|
252
|
-
|
|
253
179
|
for idx in target_indices:
|
|
254
|
-
if 0 <= idx <
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
180
|
+
if 0 <= idx < self.mw.current_mol.GetNumAtoms():
|
|
181
|
+
# Access via main_window_view_3d proxy
|
|
182
|
+
if hasattr(self.mw, 'main_window_view_3d'):
|
|
183
|
+
self.mw.main_window_view_3d.update_atom_color_override(idx, hex_color)
|
|
184
|
+
else:
|
|
185
|
+
# Fallback if unproxied (unlikely in this architecture)
|
|
186
|
+
pass
|
|
187
|
+
|
|
262
188
|
except Exception as e:
|
|
263
|
-
|
|
189
|
+
QMessageBox.critical(self, "Error", f"Failed to apply color: {e}")
|
|
264
190
|
traceback.print_exc()
|
|
265
191
|
|
|
266
192
|
def reset_colors(self):
|
|
267
|
-
if not hasattr(self.mw, 'glyph_source') or self.mw.glyph_source is None:
|
|
268
|
-
return
|
|
269
193
|
if not self.mw.current_mol:
|
|
270
194
|
return
|
|
271
195
|
|
|
272
196
|
try:
|
|
273
|
-
# Clear
|
|
274
|
-
if hasattr(self.mw, 'custom_atom_colors'):
|
|
275
|
-
self.mw.custom_atom_colors = {}
|
|
276
|
-
|
|
277
|
-
colors = self.mw.glyph_source.point_data['colors']
|
|
278
|
-
is_float = (colors.dtype.kind == 'f')
|
|
279
|
-
|
|
280
|
-
# Iterate atoms and reset to CPK
|
|
197
|
+
# Clear all color overrides using the API
|
|
281
198
|
for i in range(self.mw.current_mol.GetNumAtoms()):
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
# Get default color (float 0-1)
|
|
285
|
-
base_col = CPK_COLORS_PV.get(sym, [0.5, 0.5, 0.5])
|
|
199
|
+
if hasattr(self.mw, 'main_window_view_3d'):
|
|
200
|
+
self.mw.main_window_view_3d.update_atom_color_override(i, None)
|
|
286
201
|
|
|
287
|
-
if is_float:
|
|
288
|
-
colors[i] = base_col
|
|
289
|
-
else:
|
|
290
|
-
colors[i] = [int(c*255) for c in base_col]
|
|
291
|
-
|
|
292
|
-
self._update_3d_actor()
|
|
293
|
-
|
|
294
202
|
except Exception as e:
|
|
295
203
|
QMessageBox.critical(self, "Error", f"Failed to reset colors: {e}")
|
|
296
204
|
|
|
297
205
|
|
|
298
|
-
def _restore_colors_from_file(self):
|
|
299
|
-
"""
|
|
300
|
-
Check if the main window has a valid .pmeprj file open.
|
|
301
|
-
If so, read it manually to find 'custom_atom_colors' and apply them.
|
|
302
|
-
This handles the case where the file was loaded *before* this plugin started.
|
|
303
|
-
"""
|
|
304
|
-
# If no file path or not a .pmeprj, ignore
|
|
305
|
-
if not hasattr(self.mw, 'current_file_path') or not self.mw.current_file_path:
|
|
306
|
-
return
|
|
307
|
-
if not self.mw.current_file_path.lower().endswith('.pmeprj'):
|
|
308
|
-
return
|
|
309
|
-
|
|
310
|
-
# If we already have colors (unlikely if plugin just started, unless double-patched), skip
|
|
311
|
-
if hasattr(self.mw, 'custom_atom_colors') and self.mw.custom_atom_colors:
|
|
312
|
-
return
|
|
313
|
-
|
|
314
|
-
try:
|
|
315
|
-
with open(self.mw.current_file_path, 'r', encoding='utf-8') as f:
|
|
316
|
-
data = json.load(f)
|
|
317
|
-
|
|
318
|
-
if "3d_structure" in data and data["3d_structure"]:
|
|
319
|
-
raw_colors = data["3d_structure"].get("custom_atom_colors")
|
|
320
|
-
if raw_colors:
|
|
321
|
-
custom_colors = {int(k): v for k, v in raw_colors.items()}
|
|
322
|
-
|
|
323
|
-
# Apply to MainWindow
|
|
324
|
-
self.mw.custom_atom_colors = custom_colors
|
|
325
|
-
|
|
326
|
-
# Force update of 3D actor
|
|
327
|
-
# We might need to ensure glyph_source is ready; assuming file load populated it.
|
|
328
|
-
if hasattr(self.mw, 'glyph_source') and self.mw.glyph_source:
|
|
329
|
-
# We need to manually inject these colors into the polydata
|
|
330
|
-
colors = self.mw.glyph_source.point_data['colors']
|
|
331
|
-
is_float = (colors.dtype.kind == 'f')
|
|
332
|
-
|
|
333
|
-
for idx, col_val in custom_colors.items():
|
|
334
|
-
if 0 <= idx < len(colors):
|
|
335
|
-
if is_float:
|
|
336
|
-
# If stored as 0-255 but buffer is float 0-1
|
|
337
|
-
if any(c > 1.0 for c in col_val):
|
|
338
|
-
colors[idx] = [c/255.0 for c in col_val]
|
|
339
|
-
else:
|
|
340
|
-
colors[idx] = col_val
|
|
341
|
-
else:
|
|
342
|
-
# If stored as float 0-1 but buffer is uint8
|
|
343
|
-
if all(c <= 1.0 for c in col_val):
|
|
344
|
-
colors[idx] = [int(c*255) for c in col_val]
|
|
345
|
-
else:
|
|
346
|
-
colors[idx] = col_val
|
|
347
|
-
|
|
348
|
-
self._update_3d_actor()
|
|
349
|
-
print(f"Atom Colorizer: Restored {len(custom_colors)} custom colors from file.")
|
|
350
|
-
except Exception as e:
|
|
351
|
-
print(f"Atom Colorizer: Failed to lazy-load colors from file: {e}")
|
|
352
|
-
traceback.print_exc()
|
|
353
|
-
|
|
354
206
|
# Global reference to keep window alive
|
|
355
207
|
_atom_colorizer_window = None
|
|
356
|
-
_patches_installed = False
|
|
357
208
|
|
|
358
209
|
def run(mw):
|
|
359
|
-
global _atom_colorizer_window, _patches_installed
|
|
360
|
-
|
|
361
|
-
# Check if this is the first run (patches not installed)
|
|
362
|
-
first_run = not _patches_installed
|
|
363
|
-
|
|
364
|
-
# Install patches for persistence
|
|
365
|
-
install_patches(mw)
|
|
366
|
-
|
|
367
210
|
global _atom_colorizer_window
|
|
211
|
+
|
|
368
212
|
# Check if window already exists
|
|
369
213
|
if _atom_colorizer_window is None:
|
|
370
214
|
_atom_colorizer_window = AtomColorizerWindow(mw)
|
|
371
215
|
# Handle cleanup when window is closed
|
|
372
216
|
_atom_colorizer_window.finished.connect(lambda: _cleanup_window())
|
|
373
217
|
|
|
374
|
-
# Only restore from file if this is the first execution
|
|
375
|
-
if first_run:
|
|
376
|
-
_atom_colorizer_window._restore_colors_from_file()
|
|
377
|
-
|
|
378
218
|
_atom_colorizer_window.show()
|
|
379
219
|
_atom_colorizer_window.raise_()
|
|
380
220
|
_atom_colorizer_window.activateWindow()
|
|
381
221
|
|
|
382
|
-
# initialize removed as it only registered the menu action
|
|
383
|
-
|
|
384
222
|
def _cleanup_window():
|
|
385
223
|
global _atom_colorizer_window
|
|
386
224
|
_atom_colorizer_window = None
|
|
387
225
|
|
|
388
|
-
|
|
226
|
+
|
|
227
|
+
def initialize(context):
|
|
389
228
|
"""
|
|
390
|
-
|
|
391
|
-
Checks `_patches_installed` to avoid double patching.
|
|
229
|
+
Register plugin save/load handlers for persistence.
|
|
392
230
|
"""
|
|
393
|
-
|
|
394
|
-
if _patches_installed:
|
|
395
|
-
return
|
|
396
|
-
|
|
397
|
-
# Initialize persistent storage on MainWindow if not present
|
|
398
|
-
if not hasattr(mw, 'custom_atom_colors'):
|
|
399
|
-
mw.custom_atom_colors = {}
|
|
400
|
-
|
|
401
|
-
# --- Patch 1: MainWindowView3d.draw_molecule_3d ---
|
|
402
|
-
# Purpose: Re-apply colors after any redraw (e.g. style change, molecular edit)
|
|
403
|
-
# We patch the instance method on 'mw' which is the entry point for other modules.
|
|
404
|
-
|
|
405
|
-
original_draw_3d = mw.draw_molecule_3d
|
|
406
|
-
|
|
407
|
-
def patched_draw_3d(mol):
|
|
408
|
-
# Call original
|
|
409
|
-
res = original_draw_3d(mol)
|
|
410
|
-
|
|
411
|
-
# Apply custom colors if they exist
|
|
412
|
-
if hasattr(mw, 'custom_atom_colors') and mw.custom_atom_colors and hasattr(mw, 'glyph_source') and mw.glyph_source:
|
|
413
|
-
try:
|
|
414
|
-
import pyvista as pv # Ensure pyvista is available inside closure if needed
|
|
415
|
-
|
|
416
|
-
colors = mw.glyph_source.point_data['colors']
|
|
417
|
-
is_float = (colors.dtype.kind == 'f')
|
|
418
|
-
|
|
419
|
-
# 1. Update the source colors
|
|
420
|
-
for idx, col_val in mw.custom_atom_colors.items():
|
|
421
|
-
if isinstance(idx, str): idx = int(idx)
|
|
422
|
-
# Check index bounds
|
|
423
|
-
if 0 <= idx < len(colors):
|
|
424
|
-
if is_float:
|
|
425
|
-
if any(c > 1.0 for c in col_val):
|
|
426
|
-
colors[idx] = [c/255.0 for c in col_val]
|
|
427
|
-
else:
|
|
428
|
-
colors[idx] = col_val
|
|
429
|
-
else:
|
|
430
|
-
if all(c <= 1.0 for c in col_val):
|
|
431
|
-
colors[idx] = [int(c*255) for c in col_val]
|
|
432
|
-
else:
|
|
433
|
-
colors[idx] = col_val
|
|
434
|
-
|
|
435
|
-
# 2. Re-generate the actor (Glyph filter)
|
|
436
|
-
# Mimic common 3D view logic to respect resolution settings
|
|
437
|
-
try:
|
|
438
|
-
style = getattr(mw, 'current_3d_style', 'cpk')
|
|
439
|
-
if style == 'cpk':
|
|
440
|
-
resolution = mw.settings.get('cpk_resolution', 32)
|
|
441
|
-
elif style == 'stick':
|
|
442
|
-
resolution = mw.settings.get('stick_resolution', 16)
|
|
443
|
-
else: # ball_stick
|
|
444
|
-
resolution = mw.settings.get('ball_stick_resolution', 16)
|
|
445
|
-
except Exception:
|
|
446
|
-
resolution = 16
|
|
447
|
-
|
|
448
|
-
glyphs = mw.glyph_source.glyph(
|
|
449
|
-
scale='radii',
|
|
450
|
-
geom=pv.Sphere(radius=1.0, theta_resolution=resolution, phi_resolution=resolution),
|
|
451
|
-
orient=False
|
|
452
|
-
)
|
|
453
|
-
|
|
454
|
-
# Remove old actor
|
|
455
|
-
if hasattr(mw, 'atom_actor') and mw.atom_actor:
|
|
456
|
-
mw.plotter.remove_actor(mw.atom_actor)
|
|
457
|
-
|
|
458
|
-
# Add new actor
|
|
459
|
-
is_lighting_enabled = mw.settings.get('lighting_enabled', True)
|
|
460
|
-
mesh_props = dict(
|
|
461
|
-
smooth_shading=True,
|
|
462
|
-
specular=mw.settings.get('specular', 0.2),
|
|
463
|
-
specular_power=mw.settings.get('specular_power', 20),
|
|
464
|
-
lighting=is_lighting_enabled,
|
|
465
|
-
)
|
|
466
|
-
|
|
467
|
-
mw.atom_actor = mw.plotter.add_mesh(
|
|
468
|
-
glyphs, scalars='colors', rgb=True, **mesh_props
|
|
469
|
-
)
|
|
470
|
-
|
|
471
|
-
# Force render
|
|
472
|
-
if hasattr(mw, 'plotter'):
|
|
473
|
-
mw.plotter.render()
|
|
474
|
-
|
|
475
|
-
except Exception as e:
|
|
476
|
-
print(f"Patched draw_3d error: {e}")
|
|
477
|
-
traceback.print_exc()
|
|
478
|
-
return res
|
|
479
|
-
|
|
480
|
-
mw.draw_molecule_3d = patched_draw_3d
|
|
481
|
-
|
|
482
|
-
# --- Patch 2: MainWindowAppState.create_json_data ---
|
|
483
|
-
# Purpose: Save colors to .pmeprj
|
|
484
|
-
|
|
485
|
-
original_create_json = mw.create_json_data
|
|
486
|
-
|
|
487
|
-
def patched_create_json():
|
|
488
|
-
data = original_create_json()
|
|
489
|
-
if hasattr(mw, 'custom_atom_colors') and mw.custom_atom_colors:
|
|
490
|
-
if "3d_structure" in data and data["3d_structure"]:
|
|
491
|
-
data["3d_structure"]["custom_atom_colors"] = mw.custom_atom_colors
|
|
492
|
-
return data
|
|
493
|
-
|
|
494
|
-
mw.create_json_data = patched_create_json
|
|
495
|
-
|
|
496
|
-
# --- Patch 3: MainWindowAppState.load_from_json_data ---
|
|
497
|
-
# Purpose: Load colors from .pmeprj
|
|
231
|
+
mw = context.get_main_window()
|
|
498
232
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
if "3d_structure" in json_data and json_data["3d_structure"]:
|
|
505
|
-
raw_colors = json_data["3d_structure"].get("custom_atom_colors")
|
|
506
|
-
if raw_colors:
|
|
507
|
-
# Ensure keys are ints (JSON keys are strings)
|
|
508
|
-
custom_colors = {int(k): v for k, v in raw_colors.items()}
|
|
509
|
-
|
|
510
|
-
# Set colors to mw BEFORE calling original logic
|
|
511
|
-
# (because original logic calls draw_molecule_3d, which uses our patch)
|
|
512
|
-
mw.custom_atom_colors = custom_colors
|
|
513
|
-
|
|
514
|
-
return original_load_json(json_data)
|
|
233
|
+
def save_handler():
|
|
234
|
+
"""Save color overrides to project file."""
|
|
235
|
+
# _plugin_color_overrides is stored on the MainWindow instance by the API
|
|
236
|
+
if not hasattr(mw, '_plugin_color_overrides'):
|
|
237
|
+
return {}
|
|
515
238
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
original_clear_all = mw.clear_all
|
|
239
|
+
# Convert color overrides to JSON-serializable format
|
|
240
|
+
return {
|
|
241
|
+
"atom_colors": {str(k): v for k, v in mw._plugin_color_overrides.items()}
|
|
242
|
+
}
|
|
522
243
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
mw.custom_atom_colors = {}
|
|
528
|
-
return original_clear_all()
|
|
244
|
+
def load_handler(data):
|
|
245
|
+
"""Load color overrides from project file."""
|
|
246
|
+
if not data:
|
|
247
|
+
return
|
|
529
248
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
# --- Patch 5: MainWindow.trigger_conversion (2D -> 3D) ---
|
|
533
|
-
# Purpose: Reset colors when generating new 3D structure
|
|
534
|
-
|
|
535
|
-
original_trigger_conversion = mw.trigger_conversion
|
|
536
|
-
|
|
537
|
-
@functools.wraps(original_trigger_conversion)
|
|
538
|
-
def patched_trigger_conversion():
|
|
539
|
-
# Reset colors because structure is being regenerated
|
|
540
|
-
if hasattr(mw, 'custom_atom_colors'):
|
|
541
|
-
mw.custom_atom_colors = {}
|
|
542
|
-
return original_trigger_conversion()
|
|
249
|
+
atom_colors = data.get("atom_colors", {})
|
|
543
250
|
|
|
544
|
-
|
|
251
|
+
# Restore color overrides using the API
|
|
252
|
+
if hasattr(mw, 'main_window_view_3d'):
|
|
253
|
+
for atom_idx_str, hex_color in atom_colors.items():
|
|
254
|
+
try:
|
|
255
|
+
atom_idx = int(atom_idx_str)
|
|
256
|
+
mw.main_window_view_3d.update_atom_color_override(atom_idx, hex_color)
|
|
257
|
+
except Exception as e:
|
|
258
|
+
print(f"Failed to restore color for atom {atom_idx_str}: {e}")
|
|
545
259
|
|
|
546
|
-
|
|
547
|
-
|
|
260
|
+
# Register handlers
|
|
261
|
+
context.register_save_handler(save_handler)
|
|
262
|
+
context.register_load_handler(load_handler)
|
|
@@ -7,8 +7,8 @@ import numpy as np
|
|
|
7
7
|
import functools
|
|
8
8
|
import types
|
|
9
9
|
from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QLabel,
|
|
10
|
-
QSlider, QHBoxLayout, QPushButton)
|
|
11
|
-
from PyQt6.QtGui import QAction
|
|
10
|
+
QSlider, QHBoxLayout, QPushButton, QDoubleSpinBox)
|
|
11
|
+
from PyQt6.QtGui import QAction, QColor
|
|
12
12
|
from PyQt6.QtCore import Qt, QTimer
|
|
13
13
|
|
|
14
14
|
# Try to import VDW radii from constants, fallback if needed
|
|
@@ -35,7 +35,8 @@ SETTINGS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "vdw_ra
|
|
|
35
35
|
# Global State
|
|
36
36
|
_config_window = None
|
|
37
37
|
_vdw_settings = {
|
|
38
|
-
"occupancy": 0.3 # Opacity (0.0 - 1.0)
|
|
38
|
+
"occupancy": 0.3, # Opacity (0.0 - 1.0)
|
|
39
|
+
"resolution": 0.125 # Voxel spacing in Angstroms
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
def load_settings():
|
|
@@ -44,9 +45,10 @@ def load_settings():
|
|
|
44
45
|
if os.path.exists(SETTINGS_FILE):
|
|
45
46
|
with open(SETTINGS_FILE, 'r') as f:
|
|
46
47
|
saved = json.load(f)
|
|
47
|
-
# Filter to only keep occupancy
|
|
48
48
|
if "occupancy" in saved:
|
|
49
49
|
_vdw_settings["occupancy"] = float(saved["occupancy"])
|
|
50
|
+
if "resolution" in saved:
|
|
51
|
+
_vdw_settings["resolution"] = float(saved["resolution"])
|
|
50
52
|
except Exception as e:
|
|
51
53
|
print(f"Error loading VDW settings: {e}")
|
|
52
54
|
|
|
@@ -63,7 +65,7 @@ class VDWConfigWindow(QDialog):
|
|
|
63
65
|
self.mw = main_window
|
|
64
66
|
self.setWindowTitle("VDW Overlay Settings")
|
|
65
67
|
self.setModal(False)
|
|
66
|
-
self.resize(
|
|
68
|
+
self.resize(350, 150)
|
|
67
69
|
self.init_ui()
|
|
68
70
|
|
|
69
71
|
def init_ui(self):
|
|
@@ -74,14 +76,45 @@ class VDWConfigWindow(QDialog):
|
|
|
74
76
|
occ_layout.addWidget(QLabel("Occupancy:"))
|
|
75
77
|
self.slider_occ = QSlider(Qt.Orientation.Horizontal)
|
|
76
78
|
self.slider_occ.setRange(0, 100)
|
|
77
|
-
current_occ =
|
|
78
|
-
self.slider_occ.setValue(current_occ)
|
|
79
|
-
self.slider_occ.valueChanged.connect(self.
|
|
79
|
+
current_occ = _vdw_settings.get("occupancy", 0.3)
|
|
80
|
+
self.slider_occ.setValue(int(current_occ * 100))
|
|
81
|
+
self.slider_occ.valueChanged.connect(self.on_occupancy_slider_changed)
|
|
80
82
|
occ_layout.addWidget(self.slider_occ)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
|
|
84
|
+
self.spin_occ = QDoubleSpinBox()
|
|
85
|
+
self.spin_occ.setRange(0.0, 1.0)
|
|
86
|
+
self.spin_occ.setSingleStep(0.05)
|
|
87
|
+
self.spin_occ.setValue(current_occ)
|
|
88
|
+
self.spin_occ.valueChanged.connect(self.on_occupancy_spin_changed)
|
|
89
|
+
occ_layout.addWidget(self.spin_occ)
|
|
90
|
+
|
|
83
91
|
layout.addLayout(occ_layout)
|
|
92
|
+
|
|
93
|
+
# Resolution Slider
|
|
94
|
+
res_layout = QHBoxLayout()
|
|
95
|
+
res_layout.addWidget(QLabel("Resolution (Å):"))
|
|
96
|
+
self.slider_res = QSlider(Qt.Orientation.Horizontal)
|
|
97
|
+
self.slider_res.setRange(5, 50) # 0.05 to 0.50
|
|
98
|
+
current_res = _vdw_settings.get("resolution", 0.125)
|
|
99
|
+
self.slider_res.setValue(int(current_res * 100))
|
|
100
|
+
self.slider_res.valueChanged.connect(self.on_resolution_slider_changed)
|
|
101
|
+
res_layout.addWidget(self.slider_res)
|
|
102
|
+
|
|
103
|
+
self.spin_res = QDoubleSpinBox()
|
|
104
|
+
self.spin_res.setRange(0.05, 0.50)
|
|
105
|
+
self.spin_res.setSingleStep(0.005)
|
|
106
|
+
self.spin_res.setDecimals(3)
|
|
107
|
+
self.spin_res.setValue(current_res)
|
|
108
|
+
self.spin_res.valueChanged.connect(self.on_resolution_spin_changed)
|
|
109
|
+
res_layout.addWidget(self.spin_res)
|
|
84
110
|
|
|
111
|
+
layout.addLayout(res_layout)
|
|
112
|
+
|
|
113
|
+
# Reset Button
|
|
114
|
+
btn_reset = QPushButton("Reset to Defaults")
|
|
115
|
+
btn_reset.clicked.connect(self.reset_defaults)
|
|
116
|
+
layout.addWidget(btn_reset)
|
|
117
|
+
|
|
85
118
|
# Close Button
|
|
86
119
|
btn_close = QPushButton("Close")
|
|
87
120
|
btn_close.clicked.connect(self.close)
|
|
@@ -89,13 +122,93 @@ class VDWConfigWindow(QDialog):
|
|
|
89
122
|
|
|
90
123
|
self.setLayout(layout)
|
|
91
124
|
|
|
92
|
-
def
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
self.
|
|
125
|
+
def on_occupancy_slider_changed(self, value):
|
|
126
|
+
val_float = value / 100.0
|
|
127
|
+
self.spin_occ.blockSignals(True)
|
|
128
|
+
self.spin_occ.setValue(val_float)
|
|
129
|
+
self.spin_occ.blockSignals(False)
|
|
130
|
+
self._update_occupancy(val_float)
|
|
131
|
+
|
|
132
|
+
def on_occupancy_spin_changed(self, value):
|
|
133
|
+
val_int = int(value * 100)
|
|
134
|
+
self.slider_occ.blockSignals(True)
|
|
135
|
+
self.slider_occ.setValue(val_int)
|
|
136
|
+
self.slider_occ.blockSignals(False)
|
|
137
|
+
self._update_occupancy(value)
|
|
138
|
+
|
|
139
|
+
def _update_occupancy(self, value):
|
|
140
|
+
_vdw_settings["occupancy"] = value
|
|
141
|
+
save_settings()
|
|
142
|
+
self.update_view()
|
|
143
|
+
|
|
144
|
+
def on_resolution_slider_changed(self, value):
|
|
145
|
+
val_float = value / 100.0
|
|
146
|
+
self.spin_res.blockSignals(True)
|
|
147
|
+
self.spin_res.setValue(val_float)
|
|
148
|
+
self.spin_res.blockSignals(False)
|
|
149
|
+
self._update_resolution(val_float)
|
|
150
|
+
|
|
151
|
+
def on_resolution_spin_changed(self, value):
|
|
152
|
+
val_int = int(value * 100)
|
|
153
|
+
self.slider_res.blockSignals(True)
|
|
154
|
+
self.slider_res.setValue(val_int)
|
|
155
|
+
self.slider_res.blockSignals(False)
|
|
156
|
+
self._update_resolution(value)
|
|
157
|
+
|
|
158
|
+
def _update_resolution(self, value):
|
|
159
|
+
_vdw_settings["resolution"] = value
|
|
96
160
|
save_settings()
|
|
97
161
|
self.update_view()
|
|
98
162
|
|
|
163
|
+
def reset_defaults(self):
|
|
164
|
+
# Default values
|
|
165
|
+
def_occ = 0.3
|
|
166
|
+
def_res = 0.125
|
|
167
|
+
|
|
168
|
+
# Block signals to prevent redundant updates/saves during setting
|
|
169
|
+
self.slider_occ.blockSignals(True)
|
|
170
|
+
self.spin_occ.blockSignals(True)
|
|
171
|
+
self.slider_res.blockSignals(True)
|
|
172
|
+
self.spin_res.blockSignals(True)
|
|
173
|
+
|
|
174
|
+
# Set values
|
|
175
|
+
self.slider_occ.setValue(int(def_occ * 100))
|
|
176
|
+
self.spin_occ.setValue(def_occ)
|
|
177
|
+
self.slider_res.setValue(int(def_res * 100))
|
|
178
|
+
self.spin_res.setValue(def_res)
|
|
179
|
+
|
|
180
|
+
# Unblock
|
|
181
|
+
self.slider_occ.blockSignals(False)
|
|
182
|
+
self.spin_occ.blockSignals(False)
|
|
183
|
+
self.slider_res.blockSignals(False)
|
|
184
|
+
self.spin_res.blockSignals(False)
|
|
185
|
+
|
|
186
|
+
# Update settings and view once
|
|
187
|
+
_vdw_settings["occupancy"] = def_occ
|
|
188
|
+
_vdw_settings["resolution"] = def_res
|
|
189
|
+
save_settings()
|
|
190
|
+
self.update_view()
|
|
191
|
+
|
|
192
|
+
def refresh_ui_values(self):
|
|
193
|
+
"""Update UI elements from global settings."""
|
|
194
|
+
occ = _vdw_settings.get("occupancy", 0.3)
|
|
195
|
+
res = _vdw_settings.get("resolution", 0.125)
|
|
196
|
+
|
|
197
|
+
self.slider_occ.blockSignals(True)
|
|
198
|
+
self.spin_occ.blockSignals(True)
|
|
199
|
+
self.slider_res.blockSignals(True)
|
|
200
|
+
self.spin_res.blockSignals(True)
|
|
201
|
+
|
|
202
|
+
self.slider_occ.setValue(int(occ * 100))
|
|
203
|
+
self.spin_occ.setValue(occ)
|
|
204
|
+
self.slider_res.setValue(int(res * 100))
|
|
205
|
+
self.spin_res.setValue(res)
|
|
206
|
+
|
|
207
|
+
self.slider_occ.blockSignals(False)
|
|
208
|
+
self.spin_occ.blockSignals(False)
|
|
209
|
+
self.slider_res.blockSignals(False)
|
|
210
|
+
self.spin_res.blockSignals(False)
|
|
211
|
+
|
|
99
212
|
def update_view(self):
|
|
100
213
|
# Trigger redraw if we are in the correct mode
|
|
101
214
|
if hasattr(self.mw, 'current_3d_style') and self.mw.current_3d_style == "vdw_overlay":
|
|
@@ -130,8 +243,10 @@ def draw_vdw_overlay(mw, mol):
|
|
|
130
243
|
radii = []
|
|
131
244
|
atom_colors = []
|
|
132
245
|
|
|
133
|
-
# Use custom colors if available
|
|
134
|
-
custom_map = getattr(mw, '
|
|
246
|
+
# Use custom colors if available (API-based or legacy)
|
|
247
|
+
custom_map = getattr(mw, '_plugin_color_overrides', {})
|
|
248
|
+
if not custom_map:
|
|
249
|
+
custom_map = getattr(mw, 'custom_atom_colors', {})
|
|
135
250
|
|
|
136
251
|
if mol.GetNumConformers() > 0:
|
|
137
252
|
conf = mol.GetConformer()
|
|
@@ -149,10 +264,18 @@ def draw_vdw_overlay(mw, mol):
|
|
|
149
264
|
|
|
150
265
|
# Color handling
|
|
151
266
|
if i in custom_map:
|
|
152
|
-
|
|
153
|
-
#
|
|
154
|
-
if
|
|
155
|
-
|
|
267
|
+
val = custom_map[i]
|
|
268
|
+
# Handling new API (Hex string) vs Legacy (List/Tuple)
|
|
269
|
+
if isinstance(val, str) and val.startswith('#'):
|
|
270
|
+
# Convert Hex to RGB [0-1]
|
|
271
|
+
qc = QColor(val)
|
|
272
|
+
c = [qc.redF(), qc.greenF(), qc.blueF()]
|
|
273
|
+
else:
|
|
274
|
+
# Assume legacy list/tuple
|
|
275
|
+
c = val
|
|
276
|
+
# Normalize 0-255 to 0-1 if needed
|
|
277
|
+
if any(x > 1.0 for x in c):
|
|
278
|
+
c = [x/255.0 for x in c]
|
|
156
279
|
else:
|
|
157
280
|
c = CPK_COLORS_PV.get(sym, [0.8, 0.8, 0.8]) # Default grey if missing
|
|
158
281
|
atom_colors.append(c)
|
|
@@ -170,7 +293,10 @@ def draw_vdw_overlay(mw, mol):
|
|
|
170
293
|
max_bounds = positions.max(axis=0) + padding
|
|
171
294
|
|
|
172
295
|
# Resolution (voxel size in Angstroms)
|
|
173
|
-
|
|
296
|
+
res_val = _vdw_settings.get("resolution", 0.125)
|
|
297
|
+
# Clamp to safe limits just in case
|
|
298
|
+
if res_val < 0.01: res_val = 0.01
|
|
299
|
+
spacing = (res_val, res_val, res_val)
|
|
174
300
|
|
|
175
301
|
dims = np.ceil((max_bounds - min_bounds) / spacing).astype(int)
|
|
176
302
|
|
|
@@ -242,6 +368,9 @@ def run(mw):
|
|
|
242
368
|
_config_window = VDWConfigWindow(mw)
|
|
243
369
|
_config_window.finished.connect(lambda: _cleanup_config())
|
|
244
370
|
|
|
371
|
+
# Ensure UI reflects the loaded settings (important if window was already open or reused)
|
|
372
|
+
_config_window.refresh_ui_values()
|
|
373
|
+
|
|
245
374
|
_config_window.show()
|
|
246
375
|
_config_window.raise_()
|
|
247
376
|
_config_window.activateWindow()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.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
|
|
@@ -12,7 +12,7 @@ moleditpy/modules/bond_item.py,sha256=eVkEeKvM4igYI67DYxpey3FllqDyt_iWDo4VPYMhaP
|
|
|
12
12
|
moleditpy/modules/bond_length_dialog.py,sha256=k5x_DhK9Q8CSwouKhEo_kLRRdaYHDaK84KDNmuDNLvY,14868
|
|
13
13
|
moleditpy/modules/calculation_worker.py,sha256=KiGQY7i-QCQofEoE0r65KoQgpEGFcbhmxWv6egfkUdc,42324
|
|
14
14
|
moleditpy/modules/color_settings_dialog.py,sha256=Ow44BhCOLo0AFb6klO001k6B4drOgKX9DeNBQhZLp5o,15474
|
|
15
|
-
moleditpy/modules/constants.py,sha256=
|
|
15
|
+
moleditpy/modules/constants.py,sha256=7m9mLA8eKnYh2PPXu5pXMtRndPdZVQdSej_WjMGpsrI,4704
|
|
16
16
|
moleditpy/modules/constrained_optimization_dialog.py,sha256=IEdNVhFoNSEMeA5ABpUH9Q88-YzDXFloQM2gwnPwnHY,30150
|
|
17
17
|
moleditpy/modules/custom_interactor_style.py,sha256=NjsXE2a43IDNEanZBlcG9eR4ZIERT1MsQC6lbfesapQ,38453
|
|
18
18
|
moleditpy/modules/custom_qt_interactor.py,sha256=MFaTuDh-FPeFBS4303CqxsxmsOIOW4QXUz6USwI8PHQ,2451
|
|
@@ -29,7 +29,7 @@ moleditpy/modules/main_window_main_init.py,sha256=2MWBLY_u4UoSC4orjhDh1WcfR8FoWE
|
|
|
29
29
|
moleditpy/modules/main_window_molecular_parsers.py,sha256=Ex4-urYsKf6PyHp4XToOhgXzuYWa_n7q--QmHci4OCU,48401
|
|
30
30
|
moleditpy/modules/main_window_project_io.py,sha256=q1vEmWQDqla32HVkmk8-j0OY9ut5TI5NJ4ikahewkEo,17259
|
|
31
31
|
moleditpy/modules/main_window_string_importers.py,sha256=mQVDv2Dj4MwnPgMRe2IqdAAKnB_quE6QfYeAgCjfv28,10892
|
|
32
|
-
moleditpy/modules/main_window_ui_manager.py,sha256=
|
|
32
|
+
moleditpy/modules/main_window_ui_manager.py,sha256=HofI6T9EvcSSzPbsdPqkYEEDoB6Hui1Uj2Ll-wwczGA,24016
|
|
33
33
|
moleditpy/modules/main_window_view_3d.py,sha256=TKRerktpCTYxX9HU-dSOnIhx4OyZaVrRYj4pEOUXmGc,74088
|
|
34
34
|
moleditpy/modules/main_window_view_loaders.py,sha256=Dbdgv4TY_ZkX8Qyaevwr-mBJYJ59CBzRTEks-U1FiGw,14462
|
|
35
35
|
moleditpy/modules/mirror_dialog.py,sha256=c3v4qY6R4FAljzk4EPaDjL9ZdZMjLQSFLqDMXz2fBUk,4696
|
|
@@ -59,17 +59,17 @@ moleditpy/plugins/File/orca_out_freq_analyzer.py,sha256=6opjTpcK3B2XUIPk8fpOKlZ_
|
|
|
59
59
|
moleditpy/plugins/File/paste_xyz.py,sha256=kV-_CMmXLcqMIyFNRAeiwsOECPE64GCizT3hDCNfaXk,15112
|
|
60
60
|
moleditpy/plugins/Input Generator/gaussian_input_generator_neo.py,sha256=3EXzxcxmJmgxVF9F-jFOPYJksubUdxZxvmNoUx7DTW4,37769
|
|
61
61
|
moleditpy/plugins/Input Generator/orca_input_generator_neo.py,sha256=vqMpwJ9NaUw2SLcSqgIhWpdUaaJjnBvWHc4S0vtA7FI,40013
|
|
62
|
-
moleditpy/plugins/Input Generator/orca_xyz2inp_gui.py,sha256=
|
|
62
|
+
moleditpy/plugins/Input Generator/orca_xyz2inp_gui.py,sha256=6d6v_UC9s-2bJihGqCX3usIplw-lOUVq96kEBf32S3g,11045
|
|
63
63
|
moleditpy/plugins/Optimization/all-trans_optimizer.py,sha256=_7zAnYIRShPquIOFUf8_5N1o0g7iIXKFmcD0Eey8Lac,2532
|
|
64
64
|
moleditpy/plugins/Optimization/complex_molecule_untangler.py,sha256=kGJ1nIWdLCcSxmKJOHLhTW4SAQSrESMkKsILeDqKbhA,10837
|
|
65
65
|
moleditpy/plugins/Optimization/conf_search.py,sha256=equ6W02Yf2DAYSj1jSNeVrQSYPPpdlNrPDt3lm_Bek8,9110
|
|
66
|
-
moleditpy/plugins/Utility/atom_colorizer.py,sha256=
|
|
66
|
+
moleditpy/plugins/Utility/atom_colorizer.py,sha256=BUO-EkIeWwkGE6DtOuXgw0QkDABet_YfNXfpPZFWBlQ,9936
|
|
67
67
|
moleditpy/plugins/Utility/console.py,sha256=4_WgDiEHhalDFOLJGmYNRa1odzxdtg46qr9DUz_ht4I,5943
|
|
68
68
|
moleditpy/plugins/Utility/pubchem_ressolver.py,sha256=w1Zfm_2LTDhuU6uYKQSSaGpyU36-14kvDssc0L8hsDc,10048
|
|
69
|
-
moleditpy/plugins/Utility/vdw_radii_overlay.py,sha256=
|
|
70
|
-
moleditpy-2.2.
|
|
71
|
-
moleditpy-2.2.
|
|
72
|
-
moleditpy-2.2.
|
|
73
|
-
moleditpy-2.2.
|
|
74
|
-
moleditpy-2.2.
|
|
75
|
-
moleditpy-2.2.
|
|
69
|
+
moleditpy/plugins/Utility/vdw_radii_overlay.py,sha256=C7cD82AiJIeaQk12gKjIt0oneJny2fDRAbw-t01vpEg,16533
|
|
70
|
+
moleditpy-2.2.0a2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
71
|
+
moleditpy-2.2.0a2.dist-info/METADATA,sha256=0pjsuxHg7SWfSJWfdNf-0zi2R5j4fbG0s8KSPYWeE3s,59277
|
|
72
|
+
moleditpy-2.2.0a2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
73
|
+
moleditpy-2.2.0a2.dist-info/entry_points.txt,sha256=yH1h9JjALhok1foXT3-hYrC4ufoZt8b7oiBcsdnGNNM,54
|
|
74
|
+
moleditpy-2.2.0a2.dist-info/top_level.txt,sha256=ARICrS4ihlPXqywlKl6o-oJa3Qz3gZRWu_VZsQ3_c44,10
|
|
75
|
+
moleditpy-2.2.0a2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|