MoleditPy 3.5.2__tar.gz → 3.6.0__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.5.2 → moleditpy-3.6.0}/PKG-INFO +3 -3
- {moleditpy-3.5.2 → moleditpy-3.6.0}/README.md +2 -2
- {moleditpy-3.5.2 → moleditpy-3.6.0}/pyproject.toml +1 -1
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/MoleditPy.egg-info/PKG-INFO +3 -3
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/MoleditPy.egg-info/SOURCES.txt +1 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/main.py +10 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/custom_interactor_style.py +55 -14
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/dialog_logic.py +61 -13
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/main_window_init.py +8 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/molecular_scene_handler.py +108 -24
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/molecule_scene.py +4 -4
- moleditpy-3.6.0/src/moleditpy/ui/move_selected_atoms_dialog.py +640 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/settings_tabs/settings_3d_tabs.py +3 -1
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/settings_tabs/settings_other_tab.py +18 -4
- moleditpy-3.6.0/src/moleditpy/ui/settings_tabs/settings_tab_base.py +108 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/ui_manager.py +1 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/utils/default_settings.py +1 -1
- moleditpy-3.5.2/src/moleditpy/ui/settings_tabs/settings_tab_base.py +0 -70
- {moleditpy-3.5.2 → moleditpy-3.6.0}/LICENSE +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/setup.cfg +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/MoleditPy.egg-info/dependency_links.txt +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/MoleditPy.egg-info/entry_points.txt +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/MoleditPy.egg-info/requires.txt +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/MoleditPy.egg-info/top_level.txt +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/__init__.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/__main__.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/assets/file_icon.ico +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/assets/icon.icns +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/assets/icon.ico +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/assets/icon.png +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/core/__init__.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/core/mol_geometry.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/core/molecular_data.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/plugins/__init__.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/plugins/plugin_interface.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/plugins/plugin_manager.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/plugins/plugin_manager_window.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/__init__.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/about_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/align_plane_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/alignment_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/analysis_window.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/angle_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/app_state.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/atom_item.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/atom_picking.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/base_picking_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/bond_item.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/bond_length_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/calculation_worker.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/color_settings_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/compute_logic.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/constrained_optimization_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/custom_qt_interactor.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/dialog_3d_picking_mixin.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/dihedral_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/edit_3d_logic.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/edit_actions_logic.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/export_logic.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/geometry_base_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/io_logic.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/main_window.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/mirror_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/move_group_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/periodic_table_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/planarize_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/settings_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/settings_tabs/__init__.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/settings_tabs/settings_2d_tab.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/string_importers.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/template_preview_item.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/template_preview_view.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/translation_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/user_template_dialog.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/view_3d_logic.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/ui/zoomable_view.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/utils/__init__.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/utils/constants.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/utils/sip_isdeleted_safe.py +0 -0
- {moleditpy-3.5.2 → moleditpy-3.6.0}/src/moleditpy/utils/system_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6.0
|
|
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
|
|
@@ -805,7 +805,7 @@ For detailed instructions, please refer to the project [Wiki](https://github.com
|
|
|
805
805
|
After installation, run this command to create the shortcut in your application menu (e.g., Start Menu or Applications folder).
|
|
806
806
|
|
|
807
807
|
```bash
|
|
808
|
-
|
|
808
|
+
python -m moleditpy_installer
|
|
809
809
|
```
|
|
810
810
|
|
|
811
811
|
#### Running the Application
|
|
@@ -938,7 +938,7 @@ Yokoyama, H. (2026). MoleditPy — A Python-based molecular editing software. Ze
|
|
|
938
938
|
インストール後、このコマンドを実行すると、アプリケーションメニュー(スタートメニューやアプリケーションフォルダなど)にショートカットが作成されます。
|
|
939
939
|
|
|
940
940
|
```bash
|
|
941
|
-
|
|
941
|
+
python -m moleditpy_installer
|
|
942
942
|
```
|
|
943
943
|
|
|
944
944
|
#### アプリケーションの起動
|
|
@@ -101,7 +101,7 @@ For detailed instructions, please refer to the project [Wiki](https://github.com
|
|
|
101
101
|
After installation, run this command to create the shortcut in your application menu (e.g., Start Menu or Applications folder).
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
|
-
|
|
104
|
+
python -m moleditpy_installer
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
#### Running the Application
|
|
@@ -234,7 +234,7 @@ Yokoyama, H. (2026). MoleditPy — A Python-based molecular editing software. Ze
|
|
|
234
234
|
インストール後、このコマンドを実行すると、アプリケーションメニュー(スタートメニューやアプリケーションフォルダなど)にショートカットが作成されます。
|
|
235
235
|
|
|
236
236
|
```bash
|
|
237
|
-
|
|
237
|
+
python -m moleditpy_installer
|
|
238
238
|
```
|
|
239
239
|
|
|
240
240
|
#### アプリケーションの起動
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: MoleditPy
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6.0
|
|
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
|
|
@@ -805,7 +805,7 @@ For detailed instructions, please refer to the project [Wiki](https://github.com
|
|
|
805
805
|
After installation, run this command to create the shortcut in your application menu (e.g., Start Menu or Applications folder).
|
|
806
806
|
|
|
807
807
|
```bash
|
|
808
|
-
|
|
808
|
+
python -m moleditpy_installer
|
|
809
809
|
```
|
|
810
810
|
|
|
811
811
|
#### Running the Application
|
|
@@ -938,7 +938,7 @@ Yokoyama, H. (2026). MoleditPy — A Python-based molecular editing software. Ze
|
|
|
938
938
|
インストール後、このコマンドを実行すると、アプリケーションメニュー(スタートメニューやアプリケーションフォルダなど)にショートカットが作成されます。
|
|
939
939
|
|
|
940
940
|
```bash
|
|
941
|
-
|
|
941
|
+
python -m moleditpy_installer
|
|
942
942
|
```
|
|
943
943
|
|
|
944
944
|
#### アプリケーションの起動
|
|
@@ -53,6 +53,7 @@ src/moleditpy/ui/mirror_dialog.py
|
|
|
53
53
|
src/moleditpy/ui/molecular_scene_handler.py
|
|
54
54
|
src/moleditpy/ui/molecule_scene.py
|
|
55
55
|
src/moleditpy/ui/move_group_dialog.py
|
|
56
|
+
src/moleditpy/ui/move_selected_atoms_dialog.py
|
|
56
57
|
src/moleditpy/ui/periodic_table_dialog.py
|
|
57
58
|
src/moleditpy/ui/planarize_dialog.py
|
|
58
59
|
src/moleditpy/ui/settings_dialog.py
|
|
@@ -148,4 +148,14 @@ def main() -> None:
|
|
|
148
148
|
app = QApplication([sys.argv[0]] + remaining)
|
|
149
149
|
window = MainWindow(initial_file=args.file, safe_mode=args.safe)
|
|
150
150
|
window.show()
|
|
151
|
+
|
|
152
|
+
# Force Windows to refresh taskbar/titlebar icon after event loop starts
|
|
153
|
+
if sys.platform == "win32":
|
|
154
|
+
try:
|
|
155
|
+
from PyQt6.QtCore import QTimer
|
|
156
|
+
|
|
157
|
+
QTimer.singleShot(100, lambda: window.setWindowIcon(window.windowIcon()))
|
|
158
|
+
except Exception:
|
|
159
|
+
pass
|
|
160
|
+
|
|
151
161
|
sys.exit(app.exec())
|
|
@@ -22,10 +22,8 @@ from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera #
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
try:
|
|
25
|
-
from .move_group_dialog import MoveGroupDialog
|
|
26
25
|
from .atom_picking import pick_atom_index_from_screen
|
|
27
26
|
except ImportError:
|
|
28
|
-
from moleditpy.ui.move_group_dialog import MoveGroupDialog
|
|
29
27
|
from moleditpy.ui.atom_picking import pick_atom_index_from_screen
|
|
30
28
|
|
|
31
29
|
from rdkit import Geometry
|
|
@@ -107,10 +105,15 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
107
105
|
self._mouse_press_pos = None
|
|
108
106
|
|
|
109
107
|
# Check Move Group dialog
|
|
108
|
+
# Check Move Group or Move Selected Atoms dialog
|
|
110
109
|
move_group_dialog = None
|
|
111
110
|
for widget in QApplication.topLevelWidgets():
|
|
112
111
|
try:
|
|
113
|
-
if
|
|
112
|
+
if (
|
|
113
|
+
type(widget).__name__
|
|
114
|
+
in ("MoveGroupDialog", "MoveSelectedAtomsDialog")
|
|
115
|
+
and widget.isVisible()
|
|
116
|
+
):
|
|
114
117
|
move_group_dialog = widget
|
|
115
118
|
break
|
|
116
119
|
except (AttributeError, RuntimeError, TypeError):
|
|
@@ -147,6 +150,20 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
147
150
|
self._suppress_next_left_button_up = True
|
|
148
151
|
return # Disable camera rotation
|
|
149
152
|
else:
|
|
153
|
+
if type(move_group_dialog).__name__ == "MoveSelectedAtomsDialog":
|
|
154
|
+
# For MoveSelectedAtomsDialog, we toggle ONLY the clicked atom, no BFS!
|
|
155
|
+
def _deferred_toggle(
|
|
156
|
+
idx=clicked_atom_idx, dlg=move_group_dialog
|
|
157
|
+
):
|
|
158
|
+
try:
|
|
159
|
+
dlg.on_atom_picked(idx)
|
|
160
|
+
except (AttributeError, RuntimeError):
|
|
161
|
+
pass
|
|
162
|
+
|
|
163
|
+
QTimer.singleShot(0, _deferred_toggle)
|
|
164
|
+
self._suppress_next_left_button_up = True
|
|
165
|
+
return
|
|
166
|
+
|
|
150
167
|
# Clicked outside group - Search connected component
|
|
151
168
|
visited = set()
|
|
152
169
|
queue = [clicked_atom_idx]
|
|
@@ -172,8 +189,14 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
172
189
|
|
|
173
190
|
# Multi-selection with Ctrl
|
|
174
191
|
is_ctrl_pressed = bool(
|
|
175
|
-
|
|
176
|
-
|
|
192
|
+
(
|
|
193
|
+
QApplication.keyboardModifiers()
|
|
194
|
+
& Qt.KeyboardModifier.ControlModifier
|
|
195
|
+
)
|
|
196
|
+
or (
|
|
197
|
+
self.GetInteractor()
|
|
198
|
+
and self.GetInteractor().GetControlKey()
|
|
199
|
+
)
|
|
177
200
|
)
|
|
178
201
|
|
|
179
202
|
if is_ctrl_pressed:
|
|
@@ -208,8 +231,10 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
208
231
|
super(CustomInteractorStyle, self).OnLeftButtonDown()
|
|
209
232
|
return
|
|
210
233
|
|
|
234
|
+
interactor = self.GetInteractor()
|
|
211
235
|
is_temp_mode = bool(
|
|
212
|
-
QApplication.keyboardModifiers() & Qt.KeyboardModifier.AltModifier
|
|
236
|
+
(QApplication.keyboardModifiers() & Qt.KeyboardModifier.AltModifier)
|
|
237
|
+
or (interactor and interactor.GetAltKey())
|
|
213
238
|
)
|
|
214
239
|
is_edit_active = mw.edit_3d_manager.is_3d_edit_mode or is_temp_mode
|
|
215
240
|
|
|
@@ -293,11 +318,15 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
293
318
|
"""
|
|
294
319
|
mw = self.main_window
|
|
295
320
|
|
|
296
|
-
# Check if Move Group dialog is open
|
|
321
|
+
# Check if Move Group dialog or Move Selected Atoms dialog is open
|
|
297
322
|
move_group_dialog = None
|
|
298
323
|
try:
|
|
299
324
|
for widget in QApplication.topLevelWidgets():
|
|
300
|
-
if
|
|
325
|
+
if (
|
|
326
|
+
type(widget).__name__
|
|
327
|
+
in ("MoveGroupDialog", "MoveSelectedAtomsDialog")
|
|
328
|
+
and widget.isVisible()
|
|
329
|
+
):
|
|
301
330
|
move_group_dialog = widget
|
|
302
331
|
break
|
|
303
332
|
except (AttributeError, RuntimeError, TypeError) as e:
|
|
@@ -350,11 +379,15 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
350
379
|
"""
|
|
351
380
|
mw = self.main_window
|
|
352
381
|
|
|
353
|
-
# Move Group drag handling
|
|
382
|
+
# Move Group / Selected Atoms drag handling
|
|
354
383
|
move_group_dialog = None
|
|
355
384
|
try:
|
|
356
385
|
for widget in QApplication.topLevelWidgets():
|
|
357
|
-
if
|
|
386
|
+
if (
|
|
387
|
+
type(widget).__name__
|
|
388
|
+
in ("MoveGroupDialog", "MoveSelectedAtomsDialog")
|
|
389
|
+
and widget.isVisible()
|
|
390
|
+
):
|
|
358
391
|
move_group_dialog = widget
|
|
359
392
|
break
|
|
360
393
|
except (AttributeError, RuntimeError, TypeError):
|
|
@@ -442,11 +475,15 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
442
475
|
"""
|
|
443
476
|
mw = self.main_window
|
|
444
477
|
|
|
445
|
-
# Finalize Move Group drag
|
|
478
|
+
# Finalize Move Group / Selected Atoms drag
|
|
446
479
|
move_group_dialog = None
|
|
447
480
|
try:
|
|
448
481
|
for widget in QApplication.topLevelWidgets():
|
|
449
|
-
if
|
|
482
|
+
if (
|
|
483
|
+
type(widget).__name__
|
|
484
|
+
in ("MoveGroupDialog", "MoveSelectedAtomsDialog")
|
|
485
|
+
and widget.isVisible()
|
|
486
|
+
):
|
|
450
487
|
move_group_dialog = widget
|
|
451
488
|
break
|
|
452
489
|
except (AttributeError, RuntimeError, TypeError):
|
|
@@ -749,11 +786,15 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
749
786
|
"""
|
|
750
787
|
mw = self.main_window
|
|
751
788
|
|
|
752
|
-
# Finalize Move Group rotation
|
|
789
|
+
# Finalize Move Group / Selected Atoms rotation
|
|
753
790
|
move_group_dialog = None
|
|
754
791
|
try:
|
|
755
792
|
for widget in QApplication.topLevelWidgets():
|
|
756
|
-
if
|
|
793
|
+
if (
|
|
794
|
+
type(widget).__name__
|
|
795
|
+
in ("MoveGroupDialog", "MoveSelectedAtomsDialog")
|
|
796
|
+
and widget.isVisible()
|
|
797
|
+
):
|
|
757
798
|
move_group_dialog = widget
|
|
758
799
|
break
|
|
759
800
|
except (AttributeError, RuntimeError, TypeError):
|
|
@@ -18,7 +18,8 @@ import json
|
|
|
18
18
|
import os
|
|
19
19
|
from typing import Any, List, Literal, Optional, cast
|
|
20
20
|
|
|
21
|
-
from PyQt6.QtWidgets import QInputDialog, QMessageBox
|
|
21
|
+
from PyQt6.QtWidgets import QInputDialog, QMessageBox, QDialog
|
|
22
|
+
from PyQt6.QtCore import Qt
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
try:
|
|
@@ -33,6 +34,7 @@ try:
|
|
|
33
34
|
from .dihedral_dialog import DihedralDialog
|
|
34
35
|
from .mirror_dialog import MirrorDialog
|
|
35
36
|
from .move_group_dialog import MoveGroupDialog
|
|
37
|
+
from .move_selected_atoms_dialog import MoveSelectedAtomsDialog
|
|
36
38
|
from .periodic_table_dialog import PeriodicTableDialog
|
|
37
39
|
from .planarize_dialog import PlanarizeDialog
|
|
38
40
|
from .settings_dialog import SettingsDialog
|
|
@@ -53,6 +55,7 @@ except ImportError:
|
|
|
53
55
|
from moleditpy.ui.dihedral_dialog import DihedralDialog
|
|
54
56
|
from moleditpy.ui.mirror_dialog import MirrorDialog
|
|
55
57
|
from moleditpy.ui.move_group_dialog import MoveGroupDialog
|
|
58
|
+
from moleditpy.ui.move_selected_atoms_dialog import MoveSelectedAtomsDialog
|
|
56
59
|
from moleditpy.ui.periodic_table_dialog import PeriodicTableDialog
|
|
57
60
|
from moleditpy.ui.planarize_dialog import PlanarizeDialog
|
|
58
61
|
from moleditpy.ui.settings_dialog import SettingsDialog
|
|
@@ -213,6 +216,13 @@ class DialogManager:
|
|
|
213
216
|
self.host, "Error", f"Failed to save template: {str(e)}"
|
|
214
217
|
)
|
|
215
218
|
|
|
219
|
+
def _show_modeless_dialog(self, dialog: QDialog) -> None:
|
|
220
|
+
"""Show a modeless dialog on top, especially important for macOS."""
|
|
221
|
+
dialog.setWindowFlag(Qt.WindowType.WindowStaysOnTopHint, True)
|
|
222
|
+
dialog.show()
|
|
223
|
+
dialog.raise_()
|
|
224
|
+
dialog.activateWindow()
|
|
225
|
+
|
|
216
226
|
def open_translation_dialog(self) -> None:
|
|
217
227
|
"""Open the translation dialog"""
|
|
218
228
|
# Get preselected atoms
|
|
@@ -229,8 +239,8 @@ class DialogManager:
|
|
|
229
239
|
preselected_atoms,
|
|
230
240
|
parent=self.host,
|
|
231
241
|
)
|
|
232
|
-
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
233
|
-
|
|
242
|
+
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
243
|
+
self._show_modeless_dialog(dialog)
|
|
234
244
|
dialog.accepted.connect(
|
|
235
245
|
lambda: self.host.statusBar().showMessage("Translation applied.")
|
|
236
246
|
)
|
|
@@ -256,7 +266,7 @@ class DialogManager:
|
|
|
256
266
|
parent=self.host,
|
|
257
267
|
)
|
|
258
268
|
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
259
|
-
|
|
269
|
+
self._show_modeless_dialog(dialog)
|
|
260
270
|
dialog.accepted.connect(
|
|
261
271
|
lambda: self.host.statusBar().showMessage("Group transformation applied.")
|
|
262
272
|
)
|
|
@@ -265,6 +275,34 @@ class DialogManager:
|
|
|
265
275
|
lambda: self.host.edit_3d_manager.remove_dialog_from_list(dialog)
|
|
266
276
|
)
|
|
267
277
|
|
|
278
|
+
def open_move_selected_atoms_dialog(self) -> None:
|
|
279
|
+
"""Open Move Selected Atoms dialog"""
|
|
280
|
+
# Get preselected atoms
|
|
281
|
+
preselected_atoms = self._get_preselected_atoms_3d()
|
|
282
|
+
|
|
283
|
+
# Disable measurement mode
|
|
284
|
+
if self.host.edit_3d_manager.measurement_mode:
|
|
285
|
+
self.host.init_manager.measurement_action.setChecked(False)
|
|
286
|
+
self.host.edit_3d_manager.toggle_measurement_mode(False)
|
|
287
|
+
|
|
288
|
+
dialog = MoveSelectedAtomsDialog(
|
|
289
|
+
self.host.view_3d_manager.current_mol,
|
|
290
|
+
self.host,
|
|
291
|
+
preselected_atoms,
|
|
292
|
+
parent=self.host,
|
|
293
|
+
)
|
|
294
|
+
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
295
|
+
self._show_modeless_dialog(dialog)
|
|
296
|
+
dialog.accepted.connect(
|
|
297
|
+
lambda: self.host.statusBar().showMessage(
|
|
298
|
+
"Selected atoms transformation applied."
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
dialog.accepted.connect(self.host.edit_actions_manager.push_undo_state)
|
|
302
|
+
dialog.finished.connect(
|
|
303
|
+
lambda: self.host.edit_3d_manager.remove_dialog_from_list(dialog)
|
|
304
|
+
)
|
|
305
|
+
|
|
268
306
|
def open_align_plane_dialog(self, plane: str) -> None:
|
|
269
307
|
"""Open align dialog"""
|
|
270
308
|
# Get pre-selected atoms
|
|
@@ -283,7 +321,7 @@ class DialogManager:
|
|
|
283
321
|
parent=self.host,
|
|
284
322
|
)
|
|
285
323
|
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
286
|
-
|
|
324
|
+
self._show_modeless_dialog(dialog)
|
|
287
325
|
dialog.accepted.connect(
|
|
288
326
|
lambda: self.host.statusBar().showMessage(
|
|
289
327
|
f"Atoms aligned to {plane.upper()} plane."
|
|
@@ -311,7 +349,7 @@ class DialogManager:
|
|
|
311
349
|
parent=self.host,
|
|
312
350
|
)
|
|
313
351
|
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
314
|
-
|
|
352
|
+
self._show_modeless_dialog(dialog)
|
|
315
353
|
dialog.accepted.connect(
|
|
316
354
|
lambda: self.host.statusBar().showMessage(
|
|
317
355
|
"Selection planarized to best-fit plane."
|
|
@@ -340,7 +378,7 @@ class DialogManager:
|
|
|
340
378
|
parent=self.host,
|
|
341
379
|
)
|
|
342
380
|
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
343
|
-
|
|
381
|
+
self._show_modeless_dialog(dialog)
|
|
344
382
|
dialog.accepted.connect(
|
|
345
383
|
lambda: self.host.statusBar().showMessage(
|
|
346
384
|
f"Atoms aligned to {axis.upper()}-axis."
|
|
@@ -368,7 +406,7 @@ class DialogManager:
|
|
|
368
406
|
parent=self.host,
|
|
369
407
|
)
|
|
370
408
|
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
371
|
-
|
|
409
|
+
self._show_modeless_dialog(dialog)
|
|
372
410
|
dialog.accepted.connect(
|
|
373
411
|
lambda: self.host.statusBar().showMessage("Bond length adjusted.")
|
|
374
412
|
)
|
|
@@ -394,7 +432,7 @@ class DialogManager:
|
|
|
394
432
|
parent=self.host,
|
|
395
433
|
)
|
|
396
434
|
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
397
|
-
|
|
435
|
+
self._show_modeless_dialog(dialog)
|
|
398
436
|
dialog.accepted.connect(
|
|
399
437
|
lambda: self.host.statusBar().showMessage("Angle adjusted.")
|
|
400
438
|
)
|
|
@@ -420,7 +458,7 @@ class DialogManager:
|
|
|
420
458
|
parent=self.host,
|
|
421
459
|
)
|
|
422
460
|
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
423
|
-
|
|
461
|
+
self._show_modeless_dialog(dialog)
|
|
424
462
|
dialog.accepted.connect(
|
|
425
463
|
lambda: self.host.statusBar().showMessage("Dihedral angle adjusted.")
|
|
426
464
|
)
|
|
@@ -440,8 +478,18 @@ class DialogManager:
|
|
|
440
478
|
self.host.init_manager.measurement_action.setChecked(False)
|
|
441
479
|
self.host.edit_3d_manager.toggle_measurement_mode(False)
|
|
442
480
|
|
|
443
|
-
dialog = MirrorDialog(
|
|
444
|
-
|
|
481
|
+
dialog = MirrorDialog(
|
|
482
|
+
self.host.view_3d_manager.current_mol, self.host, parent=self.host
|
|
483
|
+
)
|
|
484
|
+
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
485
|
+
self._show_modeless_dialog(dialog)
|
|
486
|
+
dialog.accepted.connect(
|
|
487
|
+
lambda: self.host.statusBar().showMessage("Mirror applied.")
|
|
488
|
+
)
|
|
489
|
+
dialog.accepted.connect(self.host.edit_actions_manager.push_undo_state)
|
|
490
|
+
dialog.finished.connect(
|
|
491
|
+
lambda: self.host.edit_3d_manager.remove_dialog_from_list(dialog)
|
|
492
|
+
)
|
|
445
493
|
|
|
446
494
|
def open_settings_dialog(self) -> None:
|
|
447
495
|
"""Open the application settings dialog."""
|
|
@@ -468,7 +516,7 @@ class DialogManager:
|
|
|
468
516
|
self.host.view_3d_manager.current_mol, self.host, parent=self.host
|
|
469
517
|
)
|
|
470
518
|
self.host.edit_3d_manager.active_3d_dialogs.append(dialog)
|
|
471
|
-
|
|
519
|
+
self._show_modeless_dialog(dialog)
|
|
472
520
|
dialog.finished.connect(
|
|
473
521
|
lambda: self.host.edit_3d_manager.remove_dialog_from_list(dialog)
|
|
474
522
|
)
|
|
@@ -1866,6 +1866,14 @@ class MainInitManager:
|
|
|
1866
1866
|
edit_3d_menu.addAction(translation_action)
|
|
1867
1867
|
self.host.translation_action = translation_action
|
|
1868
1868
|
|
|
1869
|
+
move_selected_atoms_action = QAction("Move Selected Atoms...", self.host)
|
|
1870
|
+
move_selected_atoms_action.triggered.connect(
|
|
1871
|
+
self.host.dialog_manager.open_move_selected_atoms_dialog
|
|
1872
|
+
)
|
|
1873
|
+
move_selected_atoms_action.setEnabled(False)
|
|
1874
|
+
edit_3d_menu.addAction(move_selected_atoms_action)
|
|
1875
|
+
self.host.move_selected_atoms_action = move_selected_atoms_action
|
|
1876
|
+
|
|
1869
1877
|
move_group_action = QAction("Move Group...", self.host)
|
|
1870
1878
|
move_group_action.triggered.connect(
|
|
1871
1879
|
self.host.dialog_manager.open_move_group_dialog
|