MoleditPy-linux 2.4.6__py3-none-any.whl → 2.4.8__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/modules/bond_item.py +34 -27
- moleditpy_linux/modules/constants.py +1 -1
- moleditpy_linux/modules/main_window_app_state.py +43 -3
- {moleditpy_linux-2.4.6.dist-info → moleditpy_linux-2.4.8.dist-info}/METADATA +1 -1
- {moleditpy_linux-2.4.6.dist-info → moleditpy_linux-2.4.8.dist-info}/RECORD +9 -9
- {moleditpy_linux-2.4.6.dist-info → moleditpy_linux-2.4.8.dist-info}/WHEEL +1 -1
- {moleditpy_linux-2.4.6.dist-info → moleditpy_linux-2.4.8.dist-info}/entry_points.txt +0 -0
- {moleditpy_linux-2.4.6.dist-info → moleditpy_linux-2.4.8.dist-info}/licenses/LICENSE +0 -0
- {moleditpy_linux-2.4.6.dist-info → moleditpy_linux-2.4.8.dist-info}/top_level.txt +0 -0
|
@@ -164,43 +164,50 @@ class BondItem(QGraphicsItem):
|
|
|
164
164
|
return rect
|
|
165
165
|
|
|
166
166
|
def shape(self):
|
|
167
|
+
"""Define the precise collision/selection area, separate from the drawing area (boundingRect)."""
|
|
167
168
|
path = QPainterPath()
|
|
168
169
|
try:
|
|
169
170
|
line = self.get_line_in_local_coords()
|
|
171
|
+
# Create a simple path along the bond line
|
|
172
|
+
path.moveTo(line.p1())
|
|
173
|
+
path.lineTo(line.p2())
|
|
174
|
+
|
|
175
|
+
# Stroke it to give it some width (e.g., 10px or dynamic based on settings) generally easier to click
|
|
176
|
+
# even if the visual width is smaller.
|
|
177
|
+
stroker = QPainterPathStroker()
|
|
178
|
+
stroker.setWidth(DESIRED_BOND_PIXEL_WIDTH) # Use constant (20.0)
|
|
179
|
+
path = stroker.createStroke(path)
|
|
180
|
+
|
|
181
|
+
# If there's an E/Z label, add its rect to the selection shape
|
|
182
|
+
label_rect = self.get_ez_label_local_rect()
|
|
183
|
+
if label_rect:
|
|
184
|
+
path.addRect(label_rect)
|
|
185
|
+
|
|
170
186
|
except Exception:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
scene = self.scene()
|
|
176
|
-
if not scene or not scene.views():
|
|
177
|
-
return super().shape()
|
|
178
|
-
|
|
179
|
-
view = scene.views()[0]
|
|
180
|
-
scale = view.transform().m11()
|
|
187
|
+
# Fallback to a small rect around the origin if calculation fails
|
|
188
|
+
path.addRect(QRectF(-5, -5, 10, 10))
|
|
189
|
+
|
|
190
|
+
return path
|
|
181
191
|
|
|
182
|
-
|
|
183
|
-
|
|
192
|
+
def get_ez_label_local_rect(self):
|
|
193
|
+
"""Helper to get E/Z label rect in local coordinates."""
|
|
194
|
+
if self.order != 2 or self.stereo not in [3, 4]:
|
|
195
|
+
return None
|
|
184
196
|
try:
|
|
185
|
-
|
|
186
|
-
|
|
197
|
+
line = self.get_line_in_local_coords()
|
|
198
|
+
center = line.center()
|
|
199
|
+
|
|
200
|
+
# Logic similar to boundingRect but returning just the label box
|
|
201
|
+
font_size = 20
|
|
202
|
+
# ... (Simpler logic: just return a box around center)
|
|
203
|
+
# Standard size estimate
|
|
204
|
+
box_size = 30
|
|
205
|
+
return QRectF(center.x() - box_size/2, center.y() - box_size/2, box_size, box_size)
|
|
187
206
|
except Exception:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
# Hit area should be roughly closely matched or slightly larger than visual
|
|
191
|
-
# Ensure minimum hit width for usability
|
|
192
|
-
scene_width = max(DESIRED_BOND_PIXEL_WIDTH, width_2d * 10) / scale
|
|
207
|
+
return None
|
|
193
208
|
|
|
194
209
|
|
|
195
|
-
stroker = QPainterPathStroker()
|
|
196
|
-
stroker.setWidth(scene_width)
|
|
197
|
-
stroker.setCapStyle(Qt.PenCapStyle.RoundCap)
|
|
198
|
-
stroker.setJoinStyle(Qt.PenJoinStyle.RoundJoin)
|
|
199
210
|
|
|
200
|
-
center_line_path = QPainterPath(line.p1())
|
|
201
|
-
center_line_path.lineTo(line.p2())
|
|
202
|
-
|
|
203
|
-
return stroker.createStroke(center_line_path)
|
|
204
211
|
|
|
205
212
|
def paint(self, painter, option, widget):
|
|
206
213
|
if self.atom1 is None or self.atom2 is None:
|
|
@@ -109,7 +109,21 @@ class MainWindowAppState(object):
|
|
|
109
109
|
|
|
110
110
|
state['version'] = VERSION
|
|
111
111
|
|
|
112
|
-
if self.current_mol:
|
|
112
|
+
if self.current_mol:
|
|
113
|
+
state['mol_3d'] = self.current_mol.ToBinary()
|
|
114
|
+
# RDKit binary serialization does not preserve custom properties like _original_atom_id.
|
|
115
|
+
# We store them separately to ensure we can restore the 2D-3D link after undo/redo.
|
|
116
|
+
mol_3d_atom_ids = []
|
|
117
|
+
for i in range(self.current_mol.GetNumAtoms()):
|
|
118
|
+
atom = self.current_mol.GetAtomWithIdx(i)
|
|
119
|
+
try:
|
|
120
|
+
if atom.HasProp("_original_atom_id"):
|
|
121
|
+
mol_3d_atom_ids.append(atom.GetIntProp("_original_atom_id"))
|
|
122
|
+
else:
|
|
123
|
+
mol_3d_atom_ids.append(None)
|
|
124
|
+
except Exception:
|
|
125
|
+
mol_3d_atom_ids.append(None)
|
|
126
|
+
state['mol_3d_atom_ids'] = mol_3d_atom_ids
|
|
113
127
|
|
|
114
128
|
state['is_3d_viewer_mode'] = not self.is_2d_editable
|
|
115
129
|
|
|
@@ -204,6 +218,27 @@ class MainWindowAppState(object):
|
|
|
204
218
|
self.current_mol = Chem.Mol(loaded_data['mol_3d'])
|
|
205
219
|
# デバッグ:3D構造が有効かチェック
|
|
206
220
|
if self.current_mol and self.current_mol.GetNumAtoms() > 0:
|
|
221
|
+
# Restore _original_atom_id if present in saved state
|
|
222
|
+
if 'mol_3d_atom_ids' in loaded_data:
|
|
223
|
+
atom_ids = loaded_data['mol_3d_atom_ids']
|
|
224
|
+
if len(atom_ids) == self.current_mol.GetNumAtoms():
|
|
225
|
+
for i, aid in enumerate(atom_ids):
|
|
226
|
+
if aid is not None:
|
|
227
|
+
try:
|
|
228
|
+
self.current_mol.GetAtomWithIdx(i).SetIntProp("_original_atom_id", int(aid))
|
|
229
|
+
except Exception:
|
|
230
|
+
pass
|
|
231
|
+
|
|
232
|
+
# Re-create atom ID mapping to synchronize 2D atoms with 3D actors
|
|
233
|
+
# This MUST be done before draw_molecule_3d for labels to be correct.
|
|
234
|
+
try:
|
|
235
|
+
self.create_atom_id_mapping()
|
|
236
|
+
self.update_atom_id_menu_text()
|
|
237
|
+
self.update_atom_id_menu_state()
|
|
238
|
+
except Exception:
|
|
239
|
+
pass
|
|
240
|
+
|
|
241
|
+
# draw_molecule_3d will use the restored IDs for labels/picking if show_all_atom_info is called.
|
|
207
242
|
self.draw_molecule_3d(self.current_mol)
|
|
208
243
|
self.plotter.reset_camera()
|
|
209
244
|
# 3D関連機能を統一的に有効化
|
|
@@ -254,7 +289,11 @@ class MainWindowAppState(object):
|
|
|
254
289
|
'atoms': {k: (v['symbol'], v['item'].pos().x(), v['item'].pos().y(), v.get('charge', 0), v.get('radical', 0)) for k, v in self.data.atoms.items()},
|
|
255
290
|
'bonds': {k: (v['order'], v.get('stereo', 0)) for k, v in self.data.bonds.items()},
|
|
256
291
|
'_next_atom_id': self.data._next_atom_id,
|
|
257
|
-
'mol_3d': self.current_mol.ToBinary() if self.current_mol else None
|
|
292
|
+
'mol_3d': self.current_mol.ToBinary() if self.current_mol else None,
|
|
293
|
+
'mol_3d_atom_ids': [
|
|
294
|
+
(a.GetIntProp("_original_atom_id") if a.HasProp("_original_atom_id") else None)
|
|
295
|
+
for a in self.current_mol.GetAtoms()
|
|
296
|
+
] if self.current_mol else None
|
|
258
297
|
}
|
|
259
298
|
|
|
260
299
|
last_state_for_comparison = None
|
|
@@ -266,7 +305,8 @@ class MainWindowAppState(object):
|
|
|
266
305
|
'atoms': {k: (v['symbol'], v['pos'][0], v['pos'][1], v.get('charge', 0), v.get('radical', 0)) for k, v in last_atoms.items()},
|
|
267
306
|
'bonds': {k: (v['order'], v.get('stereo', 0)) for k, v in last_bonds.items()},
|
|
268
307
|
'_next_atom_id': last_state.get('_next_atom_id'),
|
|
269
|
-
'mol_3d': last_state.get('mol_3d', None)
|
|
308
|
+
'mol_3d': last_state.get('mol_3d', None),
|
|
309
|
+
'mol_3d_atom_ids': last_state.get('mol_3d_atom_ids', None)
|
|
270
310
|
}
|
|
271
311
|
|
|
272
312
|
if not last_state_for_comparison or current_state_for_comparison != last_state_for_comparison:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy-linux
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.8
|
|
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
|
|
@@ -8,18 +8,18 @@ moleditpy_linux/modules/alignment_dialog.py,sha256=CPubSJI52mNSXmWt7oKQ2un5lXnN8
|
|
|
8
8
|
moleditpy_linux/modules/analysis_window.py,sha256=zjP5ipSTpKw8oLr1eKdoxW8Bk1SslGlPqsVucD-x_5w,9403
|
|
9
9
|
moleditpy_linux/modules/angle_dialog.py,sha256=uc2WbvSfRe892xoEirqpZ78pf2Smwzkinkso6zLWr0Y,17751
|
|
10
10
|
moleditpy_linux/modules/atom_item.py,sha256=9x0xojz6eih-N6UFgGJHNdRshgOurx3F5ysMzcHup6Y,18034
|
|
11
|
-
moleditpy_linux/modules/bond_item.py,sha256=
|
|
11
|
+
moleditpy_linux/modules/bond_item.py,sha256=21oX1sR5kpY-MlfUsmekkV6XATVwIAhmsH1UMwV34rg,24225
|
|
12
12
|
moleditpy_linux/modules/bond_length_dialog.py,sha256=6bFPGssnqlgINuqpxLv-OhjMH3_hspnaH8QtorAyu2M,14782
|
|
13
13
|
moleditpy_linux/modules/calculation_worker.py,sha256=KiGQY7i-QCQofEoE0r65KoQgpEGFcbhmxWv6egfkUdc,42324
|
|
14
14
|
moleditpy_linux/modules/color_settings_dialog.py,sha256=Ow44BhCOLo0AFb6klO001k6B4drOgKX9DeNBQhZLp5o,15474
|
|
15
|
-
moleditpy_linux/modules/constants.py,sha256=
|
|
15
|
+
moleditpy_linux/modules/constants.py,sha256=M1dGZR8B9RNXfzFq1GhX7lUxMmZn1b_Whtu9ShCQ6wk,4702
|
|
16
16
|
moleditpy_linux/modules/constrained_optimization_dialog.py,sha256=REsk4ePsqNmAGPMTS_jckeM7jexrU3krwun8sKqKUCs,30062
|
|
17
17
|
moleditpy_linux/modules/custom_interactor_style.py,sha256=LDNODMJoNHGe1AUSrvqv6PdeJm-hpPmSpWINppnJLt0,38942
|
|
18
18
|
moleditpy_linux/modules/custom_qt_interactor.py,sha256=vCZsDfRO-FtphD5cTP7Ps-5rpHZMIGloaoe6EaKzrsw,4139
|
|
19
19
|
moleditpy_linux/modules/dialog3_d_picking_mixin.py,sha256=z4udbkiX9PYmIGazPXsbftkk_oRRwZhcvlCqbyJzr24,6493
|
|
20
20
|
moleditpy_linux/modules/dihedral_dialog.py,sha256=bOTDO6-b74vEDn_z6OyuBr5cRz3RnRj83PiaEBUyWJA,18002
|
|
21
21
|
moleditpy_linux/modules/main_window.py,sha256=w52L0F7V3b0BiNhQImbulZ9N8cRKolYy06szfoMOIcg,36830
|
|
22
|
-
moleditpy_linux/modules/main_window_app_state.py,sha256=
|
|
22
|
+
moleditpy_linux/modules/main_window_app_state.py,sha256=Civ28scAuIPXdD1qix5IkUAgEgl4Wy3wCqblomF3EY4,37493
|
|
23
23
|
moleditpy_linux/modules/main_window_compute.py,sha256=ipIkhH_DONXDnPzh7xeym9X-Yfx8EhsvXYOdyxsAj4c,53347
|
|
24
24
|
moleditpy_linux/modules/main_window_dialog_manager.py,sha256=QR96LqHAPSOShXbc9cK-Ffq8a16JrXAoMKB0pHjESrQ,20072
|
|
25
25
|
moleditpy_linux/modules/main_window_edit_3d.py,sha256=CUArB5wcsgq1C7LygAEC6URlbnn4RhRYDa5n-Y-etWI,19731
|
|
@@ -51,9 +51,9 @@ moleditpy_linux/modules/assets/file_icon.ico,sha256=yyVj084A7HuMNbV073cE_Ag3Ne40
|
|
|
51
51
|
moleditpy_linux/modules/assets/icon.icns,sha256=wD5R6-Vw7K662tVKhu2E1ImN0oUuyAP4youesEQsn9c,139863
|
|
52
52
|
moleditpy_linux/modules/assets/icon.ico,sha256=RfgFcx7-dHY_2STdsOQCQziY5SNhDr3gPnjO6jzEDPI,147975
|
|
53
53
|
moleditpy_linux/modules/assets/icon.png,sha256=kCFN1WacYIdy0GN6SFEbNA00ef39pCczBnFdkkBI8Bs,147110
|
|
54
|
-
moleditpy_linux-2.4.
|
|
55
|
-
moleditpy_linux-2.4.
|
|
56
|
-
moleditpy_linux-2.4.
|
|
57
|
-
moleditpy_linux-2.4.
|
|
58
|
-
moleditpy_linux-2.4.
|
|
59
|
-
moleditpy_linux-2.4.
|
|
54
|
+
moleditpy_linux-2.4.8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
55
|
+
moleditpy_linux-2.4.8.dist-info/METADATA,sha256=bPGIJkXQU-1D9JHLW-CNn270Ei-Z2eIx81XXwJQLwnU,60708
|
|
56
|
+
moleditpy_linux-2.4.8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
57
|
+
moleditpy_linux-2.4.8.dist-info/entry_points.txt,sha256=-OzipSi__yVwlimNtu3eiRP5t5UMg55Cs0udyhXYiyw,60
|
|
58
|
+
moleditpy_linux-2.4.8.dist-info/top_level.txt,sha256=qyqe-hDYL6CXyin9E5Me5rVl3PG84VqiOjf9bQvfJLs,16
|
|
59
|
+
moleditpy_linux-2.4.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|