MoleditPy-linux 1.17.1__py3-none-any.whl → 1.18.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.
Files changed (27) hide show
  1. moleditpy_linux/modules/align_plane_dialog.py +1 -1
  2. moleditpy_linux/modules/alignment_dialog.py +1 -1
  3. moleditpy_linux/modules/angle_dialog.py +2 -2
  4. moleditpy_linux/modules/bond_item.py +96 -5
  5. moleditpy_linux/modules/bond_length_dialog.py +2 -2
  6. moleditpy_linux/modules/constants.py +1 -1
  7. moleditpy_linux/modules/constrained_optimization_dialog.py +2 -2
  8. moleditpy_linux/modules/dihedral_dialog.py +1 -1
  9. moleditpy_linux/modules/main_window_app_state.py +1 -1
  10. moleditpy_linux/modules/main_window_compute.py +6 -0
  11. moleditpy_linux/modules/main_window_edit_3d.py +7 -7
  12. moleditpy_linux/modules/main_window_export.py +106 -49
  13. moleditpy_linux/modules/main_window_main_init.py +3 -3
  14. moleditpy_linux/modules/main_window_molecular_parsers.py +4 -3
  15. moleditpy_linux/modules/main_window_project_io.py +2 -2
  16. moleditpy_linux/modules/main_window_view_3d.py +359 -131
  17. moleditpy_linux/modules/main_window_view_loaders.py +1 -1
  18. moleditpy_linux/modules/molecule_scene.py +14 -15
  19. moleditpy_linux/modules/planarize_dialog.py +1 -1
  20. moleditpy_linux/modules/settings_dialog.py +86 -20
  21. moleditpy_linux/modules/user_template_dialog.py +9 -8
  22. {moleditpy_linux-1.17.1.dist-info → moleditpy_linux-1.18.1.dist-info}/METADATA +1 -2
  23. {moleditpy_linux-1.17.1.dist-info → moleditpy_linux-1.18.1.dist-info}/RECORD +27 -27
  24. {moleditpy_linux-1.17.1.dist-info → moleditpy_linux-1.18.1.dist-info}/WHEEL +0 -0
  25. {moleditpy_linux-1.17.1.dist-info → moleditpy_linux-1.18.1.dist-info}/entry_points.txt +0 -0
  26. {moleditpy_linux-1.17.1.dist-info → moleditpy_linux-1.18.1.dist-info}/licenses/LICENSE +0 -0
  27. {moleditpy_linux-1.17.1.dist-info → moleditpy_linux-1.18.1.dist-info}/top_level.txt +0 -0
@@ -317,7 +317,7 @@ class MainWindowViewLoaders(object):
317
317
  # Keep mol as-is (may lack conformer); downstream code checks for conformers
318
318
  else:
319
319
  raise
320
- except:
320
+ except Exception:
321
321
  self.statusBar().showMessage("Failed to generate 3D coordinates")
322
322
  return
323
323
 
@@ -11,6 +11,7 @@ DOI: 10.5281/zenodo.17268532
11
11
  """
12
12
 
13
13
  import traceback
14
+ import logging
14
15
 
15
16
  from PyQt6.QtWidgets import (
16
17
  QApplication, QGraphicsScene, QGraphicsItem,
@@ -203,9 +204,7 @@ class MoleculeScene(QGraphicsScene):
203
204
  self.window.push_undo_state()
204
205
  data_changed = False # ここでundo済みなので以降で積まない
205
206
  except Exception as e:
206
- print(f"Error clearing E/Z label: {e}")
207
-
208
- traceback.print_exc()
207
+ logging.error(f"Error clearing E/Z label: {e}", exc_info=True)
209
208
  if hasattr(self.window, 'statusBar'):
210
209
  self.window.statusBar().showMessage(f"Error clearing E/Z label: {e}", 5000)
211
210
  # AtomItemは何もしない
@@ -387,9 +386,7 @@ class MoleculeScene(QGraphicsScene):
387
386
  self.update_bond_stereo(b, new_stereo)
388
387
  self.window.push_undo_state() # ここでUndo stackに積む
389
388
  except Exception as e:
390
- print(f"Error in E/Z stereo toggle: {e}")
391
-
392
- traceback.print_exc()
389
+ logging.error(f"Error in E/Z stereo toggle: {e}", exc_info=True)
393
390
  if hasattr(self.window, 'statusBar'):
394
391
  self.window.statusBar().showMessage(f"Error changing E/Z stereochemistry: {e}", 5000)
395
392
  return # この後の処理は行わない
@@ -610,7 +607,7 @@ class MoleculeScene(QGraphicsScene):
610
607
  def create_bond(self, start_atom, end_atom, bond_order=None, bond_stereo=None):
611
608
  try:
612
609
  if start_atom is None or end_atom is None:
613
- print("Error: Cannot create bond with None atoms")
610
+ logging.error("Error: Cannot create bond with None atoms")
614
611
  return
615
612
 
616
613
  exist_b = self.find_bond_between(start_atom, end_atom)
@@ -637,9 +634,7 @@ class MoleculeScene(QGraphicsScene):
637
634
  end_atom.update_style()
638
635
 
639
636
  except Exception as e:
640
- print(f"Error creating bond: {e}")
641
-
642
- traceback.print_exc()
637
+ logging.error(f"Error creating bond: {e}", exc_info=True)
643
638
 
644
639
  def add_molecule_fragment(self, points, bonds_info, existing_items=None, symbol='C'):
645
640
  """
@@ -1668,9 +1663,9 @@ class MoleculeScene(QGraphicsScene):
1668
1663
  elif key == Qt.Key.Key_1 and (bond.order != 1 or bond.stereo != 0):
1669
1664
  bond.order = 1; bond.stereo = 0
1670
1665
  elif key == Qt.Key.Key_2 and (bond.order != 2 or bond.stereo != 0):
1671
- bond.order = 2; bond.stereo = 0; needs_update = True
1666
+ bond.order = 2; bond.stereo = 0
1672
1667
  elif key == Qt.Key.Key_3 and bond.order != 3:
1673
- bond.order = 3; bond.stereo = 0; needs_update = True
1668
+ bond.order = 3; bond.stereo = 0
1674
1669
 
1675
1670
  # 4. 実際に変更があった場合のみデータモデルを更新
1676
1671
  if old_order != bond.order or old_stereo != bond.stereo:
@@ -1712,7 +1707,11 @@ class MoleculeScene(QGraphicsScene):
1712
1707
  return
1713
1708
 
1714
1709
  # --- 3. Atomに対する操作 (原子の追加 - マージされた機能) ---
1715
- if key == Qt.Key.Key_1:
1710
+ if key in [Qt.Key.Key_1, Qt.Key.Key_2, Qt.Key.Key_3]:
1711
+ target_order = 1
1712
+ if key == Qt.Key.Key_2: target_order = 2
1713
+ elif key == Qt.Key.Key_3: target_order = 3
1714
+
1716
1715
  start_atom = None
1717
1716
  if isinstance(item_at_cursor, AtomItem):
1718
1717
  start_atom = item_at_cursor
@@ -1802,12 +1801,12 @@ class MoleculeScene(QGraphicsScene):
1802
1801
 
1803
1802
  if near_atom and near_atom is not start_atom:
1804
1803
  # 近くに既存原子があれば結合
1805
- self.create_bond(start_atom, near_atom)
1804
+ self.create_bond(start_atom, near_atom, bond_order=target_order, bond_stereo=0)
1806
1805
  else:
1807
1806
  # 新規原子を作成し結合
1808
1807
  new_atom_id = self.create_atom('C', target_pos)
1809
1808
  new_atom_item = self.data.atoms[new_atom_id]['item']
1810
- self.create_bond(start_atom, new_atom_item)
1809
+ self.create_bond(start_atom, new_atom_item, bond_order=target_order, bond_stereo=0)
1811
1810
 
1812
1811
  self.clearSelection()
1813
1812
  self.window.push_undo_state()
@@ -157,7 +157,7 @@ class PlanarizeDialog(Dialog3DPickingMixin, QDialog):
157
157
  for label_actor in self.selection_labels:
158
158
  try:
159
159
  self.main_window.plotter.remove_actor(label_actor)
160
- except:
160
+ except Exception:
161
161
  pass
162
162
  self.selection_labels = []
163
163
 
@@ -53,7 +53,6 @@ class SettingsDialog(QDialog):
53
53
  'wireframe_bond_radius': 0.01,
54
54
  'wireframe_resolution': 6,
55
55
  # Stick model parameters
56
- 'stick_atom_radius': 0.15,
57
56
  'stick_bond_radius': 0.15,
58
57
  'stick_resolution': 16,
59
58
  # Multiple bond offset parameters (per-model)
@@ -69,6 +68,9 @@ class SettingsDialog(QDialog):
69
68
  'stick_triple_bond_offset_factor': 1.0,
70
69
  'stick_double_bond_radius_factor': 0.6,
71
70
  'stick_triple_bond_radius_factor': 0.4,
71
+ 'aromatic_torus_thickness_factor': 0.6,
72
+ # Whether to draw an aromatic circle inside rings in 3D
73
+ 'display_aromatic_circles_3d': False,
72
74
  # If True, attempts to be permissive when RDKit raises chemical/sanitization errors
73
75
  # during file import (useful for viewing malformed XYZ/MOL files). When enabled,
74
76
  # element symbol recognition will be coerced where possible and Chem.SanitizeMol
@@ -86,6 +88,7 @@ class SettingsDialog(QDialog):
86
88
  # If True, RDKit will attempt to kekulize aromatic systems for 3D display
87
89
  # (shows alternating single/double bonds rather than aromatic circles)
88
90
  'display_kekule_3d': False,
91
+ 'ball_stick_use_cpk_bond_color': False,
89
92
  }
90
93
 
91
94
  # --- 選択された色を管理する専用のインスタンス変数 ---
@@ -118,6 +121,13 @@ class SettingsDialog(QDialog):
118
121
 
119
122
  # 渡された設定でUIと内部変数を初期化
120
123
  self.update_ui_from_settings(current_settings)
124
+
125
+ # Initialize aromatic circle checkbox and torus thickness from settings
126
+ self.aromatic_circle_checkbox.setChecked(current_settings.get('display_aromatic_circles_3d', self.default_settings.get('display_aromatic_circles_3d', False)))
127
+ # Thickness factor is stored as a multiplier (e.g., 1.0), slider uses integer 0-300 representing 0.1x-3.0x
128
+ thickness_factor = current_settings.get('aromatic_torus_thickness_factor', self.default_settings.get('aromatic_torus_thickness_factor', 1.0))
129
+ self.aromatic_torus_thickness_slider.setValue(int(thickness_factor * 100))
130
+ self.aromatic_torus_thickness_label.setText(f"{thickness_factor:.1f}")
121
131
 
122
132
  # --- ボタンの配置 ---
123
133
  buttons = QHBoxLayout()
@@ -243,11 +253,42 @@ class SettingsDialog(QDialog):
243
253
  except Exception:
244
254
  pass
245
255
 
256
+ # Add separator after Kekule bonds option
257
+ separator = QFrame()
258
+ separator.setFrameShape(QFrame.Shape.HLine)
259
+ separator.setFrameShadow(QFrame.Shadow.Sunken)
260
+ self.other_form_layout.addRow(separator)
261
+
246
262
  # Place the Kekulé option after the always-ask-charge option
247
263
  try:
248
264
  self.other_form_layout.addRow("Display Kekulé bonds in 3D:", self.kekule_3d_checkbox)
249
265
  except Exception:
250
266
  pass
267
+
268
+
269
+ # Aromatic ring circle display option
270
+ self.aromatic_circle_checkbox = QCheckBox()
271
+ self.aromatic_circle_checkbox.setToolTip("When enabled, aromatic rings will be displayed with a circle inside the ring in 3D view.")
272
+ try:
273
+ self.other_form_layout.addRow("Display aromatic rings as circles in 3D:", self.aromatic_circle_checkbox)
274
+ except Exception:
275
+ pass
276
+
277
+ # Aromatic torus thickness factor
278
+ self.aromatic_torus_thickness_slider = QSlider(Qt.Orientation.Horizontal)
279
+ self.aromatic_torus_thickness_slider.setRange(10, 300) # 0.1x to 3.0x
280
+ self.aromatic_torus_thickness_slider.setValue(60) # Default 0.6x
281
+ self.aromatic_torus_thickness_label = QLabel("0.6")
282
+ self.aromatic_torus_thickness_slider.valueChanged.connect(
283
+ lambda v: self.aromatic_torus_thickness_label.setText(f"{v/100:.1f}")
284
+ )
285
+ thickness_layout = QHBoxLayout()
286
+ thickness_layout.addWidget(self.aromatic_torus_thickness_slider)
287
+ thickness_layout.addWidget(self.aromatic_torus_thickness_label)
288
+ try:
289
+ self.other_form_layout.addRow("Aromatic torus thickness (× bond radius):", thickness_layout)
290
+ except Exception:
291
+ pass
251
292
 
252
293
  # Add Other tab to the tab widget
253
294
  self.tab_widget.addTab(self.other_widget, "Other")
@@ -378,6 +419,12 @@ class SettingsDialog(QDialog):
378
419
  resolution_layout.addWidget(self.bs_resolution_label)
379
420
  form_layout.addRow("Resolution (Quality):", resolution_layout)
380
421
 
422
+ # --- 区切り線(水平ライン) ---
423
+ line = QFrame()
424
+ line.setFrameShape(QFrame.Shape.HLine)
425
+ line.setFrameShadow(QFrame.Shadow.Sunken)
426
+ form_layout.addRow(line)
427
+
381
428
  # --- Ball & Stick bond color ---
382
429
  self.bs_bond_color_button = QPushButton()
383
430
  self.bs_bond_color_button.setFixedSize(36, 24)
@@ -385,6 +432,11 @@ class SettingsDialog(QDialog):
385
432
  self.bs_bond_color_button.setToolTip("Choose the uniform bond color for Ball & Stick model (3D)")
386
433
  form_layout.addRow("Ball & Stick bond color:", self.bs_bond_color_button)
387
434
 
435
+ # Use CPK colors for bonds option
436
+ self.bs_use_cpk_bond_checkbox = QCheckBox()
437
+ self.bs_use_cpk_bond_checkbox.setToolTip("If checked, bonds will be colored using the atom colors (split bonds). If unchecked, a uniform color is used.")
438
+ form_layout.addRow("Use CPK colors for bonds:", self.bs_use_cpk_bond_checkbox)
439
+
388
440
  self.tab_widget.addTab(ball_stick_widget, "Ball & Stick")
389
441
 
390
442
  def create_cpk_tab(self):
@@ -511,17 +563,7 @@ class SettingsDialog(QDialog):
511
563
  info_label.setStyleSheet("color: #666; font-style: italic; margin-top: 10px;")
512
564
  form_layout.addRow(info_label)
513
565
 
514
- # 原子半径
515
- self.stick_atom_radius_slider = QSlider(Qt.Orientation.Horizontal)
516
- self.stick_atom_radius_slider.setRange(5, 50) # 0.05 ~ 0.5
517
- self.stick_atom_radius_label = QLabel("0.15")
518
- self.stick_atom_radius_slider.valueChanged.connect(lambda v: self.stick_atom_radius_label.setText(f"{v/100:.2f}"))
519
- atom_radius_layout = QHBoxLayout()
520
- atom_radius_layout.addWidget(self.stick_atom_radius_slider)
521
- atom_radius_layout.addWidget(self.stick_atom_radius_label)
522
- form_layout.addRow("Atom Radius:", atom_radius_layout)
523
-
524
- # ボンド半径
566
+ # ボンド半径(原子半径も同じ値を使用)
525
567
  self.stick_bond_radius_slider = QSlider(Qt.Orientation.Horizontal)
526
568
  self.stick_bond_radius_slider.setRange(5, 50) # 0.05 ~ 0.5
527
569
  self.stick_bond_radius_label = QLabel("0.15")
@@ -619,6 +661,8 @@ class SettingsDialog(QDialog):
619
661
  'skip_chemistry_checks': self.default_settings.get('skip_chemistry_checks', False),
620
662
  'display_kekule_3d': self.default_settings.get('display_kekule_3d', False),
621
663
  'always_ask_charge': self.default_settings.get('always_ask_charge', False),
664
+ 'display_aromatic_circles_3d': self.default_settings.get('display_aromatic_circles_3d', False),
665
+ 'aromatic_torus_thickness_factor': self.default_settings.get('aromatic_torus_thickness_factor', 0.6),
622
666
  },
623
667
  "Ball & Stick": {
624
668
  'ball_stick_atom_scale': self.default_settings['ball_stick_atom_scale'],
@@ -627,11 +671,14 @@ class SettingsDialog(QDialog):
627
671
  'ball_stick_double_bond_offset_factor': self.default_settings.get('ball_stick_double_bond_offset_factor', 2.0),
628
672
  'ball_stick_triple_bond_offset_factor': self.default_settings.get('ball_stick_triple_bond_offset_factor', 2.0),
629
673
  'ball_stick_double_bond_radius_factor': self.default_settings.get('ball_stick_double_bond_radius_factor', 0.8),
630
- 'ball_stick_triple_bond_radius_factor': self.default_settings.get('ball_stick_triple_bond_radius_factor', 0.75)
674
+ 'ball_stick_triple_bond_radius_factor': self.default_settings.get('ball_stick_triple_bond_radius_factor', 0.75),
675
+ 'ball_stick_use_cpk_bond_color': self.default_settings['ball_stick_use_cpk_bond_color'],
676
+ 'ball_stick_bond_color': self.default_settings.get('ball_stick_bond_color', '#7F7F7F')
631
677
  },
632
678
  "CPK (Space-filling)": {
633
679
  'cpk_atom_scale': self.default_settings['cpk_atom_scale'],
634
680
  'cpk_resolution': self.default_settings['cpk_resolution'],
681
+ 'cpk_colors': {}
635
682
  },
636
683
  "Wireframe": {
637
684
  'wireframe_bond_radius': self.default_settings['wireframe_bond_radius'],
@@ -642,7 +689,6 @@ class SettingsDialog(QDialog):
642
689
  'wireframe_triple_bond_radius_factor': self.default_settings.get('wireframe_triple_bond_radius_factor', 0.75)
643
690
  },
644
691
  "Stick": {
645
- 'stick_atom_radius': self.default_settings['stick_atom_radius'],
646
692
  'stick_bond_radius': self.default_settings['stick_bond_radius'],
647
693
  'stick_resolution': self.default_settings['stick_resolution'],
648
694
  'stick_double_bond_offset_factor': self.default_settings.get('stick_double_bond_offset_factor', 1.5),
@@ -665,6 +711,7 @@ class SettingsDialog(QDialog):
665
711
 
666
712
  # UIを更新
667
713
  self.update_ui_from_settings(updated_settings)
714
+ # CPK tab: do not change parent/settings immediately; let Apply/OK persist any changes
668
715
 
669
716
  # ユーザーへのフィードバック
670
717
  QMessageBox.information(self, "Reset Complete", f"Settings for '{tab_name}' tab have been reset to defaults.")
@@ -785,7 +832,6 @@ class SettingsDialog(QDialog):
785
832
  'wireframe_bond_radius': self.wf_bond_radius_slider.value() / 100.0,
786
833
  'wireframe_resolution': self.wf_resolution_slider.value(),
787
834
  # Stick settings
788
- 'stick_atom_radius': self.stick_atom_radius_slider.value() / 100.0,
789
835
  'stick_bond_radius': self.stick_bond_radius_slider.value() / 100.0,
790
836
  'stick_resolution': self.stick_resolution_slider.value(),
791
837
  # Multi-bond settings (per-model)
@@ -801,6 +847,17 @@ class SettingsDialog(QDialog):
801
847
  'stick_triple_bond_offset_factor': self.stick_triple_offset_slider.value() / 100.0,
802
848
  'stick_double_bond_radius_factor': self.stick_double_radius_slider.value() / 100.0,
803
849
  'stick_triple_bond_radius_factor': self.stick_triple_radius_slider.value() / 100.0,
850
+ # Projection mode
851
+ 'projection_mode': self.projection_combo.currentText(),
852
+ # Kekule / aromatic / torus settings
853
+ 'display_kekule_3d': self.kekule_3d_checkbox.isChecked(),
854
+ 'display_aromatic_circles_3d': self.aromatic_circle_checkbox.isChecked(),
855
+ 'aromatic_torus_thickness_factor': self.aromatic_torus_thickness_slider.value() / 100.0,
856
+ 'skip_chemistry_checks': self.skip_chem_checks_checkbox.isChecked(),
857
+ 'always_ask_charge': self.always_ask_charge_checkbox.isChecked(),
858
+ # Ball & Stick bond color and use-cpk option
859
+ 'ball_stick_bond_color': getattr(self, 'bs_bond_color', self.default_settings.get('ball_stick_bond_color')),
860
+ 'ball_stick_use_cpk_bond_color': self.bs_use_cpk_bond_checkbox.isChecked(),
804
861
  }
805
862
 
806
863
  def reset_to_defaults(self):
@@ -854,6 +911,9 @@ class SettingsDialog(QDialog):
854
911
  except Exception:
855
912
  pass
856
913
 
914
+ # Ball & Stick CPK bond color option
915
+ self.bs_use_cpk_bond_checkbox.setChecked(settings_dict.get('ball_stick_use_cpk_bond_color', self.default_settings['ball_stick_use_cpk_bond_color']))
916
+
857
917
  # CPK設定
858
918
  cpk_atom_scale = int(settings_dict.get('cpk_atom_scale', self.default_settings['cpk_atom_scale']) * 100)
859
919
  self.cpk_atom_scale_slider.setValue(cpk_atom_scale)
@@ -871,10 +931,6 @@ class SettingsDialog(QDialog):
871
931
  self.wf_resolution_label.setText(str(settings_dict.get('wireframe_resolution', self.default_settings['wireframe_resolution'])))
872
932
 
873
933
  # Stick設定
874
- stick_atom_radius = int(settings_dict.get('stick_atom_radius', self.default_settings['stick_atom_radius']) * 100)
875
- self.stick_atom_radius_slider.setValue(stick_atom_radius)
876
- self.stick_atom_radius_label.setText(f"{stick_atom_radius/100:.2f}")
877
-
878
934
  stick_bond_radius = int(settings_dict.get('stick_bond_radius', self.default_settings['stick_bond_radius']) * 100)
879
935
  self.stick_bond_radius_slider.setValue(stick_bond_radius)
880
936
  self.stick_bond_radius_label.setText(f"{stick_bond_radius/100:.2f}")
@@ -944,6 +1000,14 @@ class SettingsDialog(QDialog):
944
1000
  self.kekule_3d_checkbox.setChecked(settings_dict.get('display_kekule_3d', self.default_settings.get('display_kekule_3d', False)))
945
1001
  # always ask for charge on XYZ imports
946
1002
  self.always_ask_charge_checkbox.setChecked(settings_dict.get('always_ask_charge', self.default_settings.get('always_ask_charge', False)))
1003
+ # Aromatic ring circle display and torus thickness factor
1004
+ self.aromatic_circle_checkbox.setChecked(settings_dict.get('display_aromatic_circles_3d', self.default_settings.get('display_aromatic_circles_3d', False)))
1005
+ thickness_factor = float(settings_dict.get('aromatic_torus_thickness_factor', self.default_settings.get('aromatic_torus_thickness_factor', 0.6)))
1006
+ try:
1007
+ self.aromatic_torus_thickness_slider.setValue(int(thickness_factor * 100))
1008
+ self.aromatic_torus_thickness_label.setText(f"{thickness_factor:.1f}")
1009
+ except Exception:
1010
+ pass
947
1011
 
948
1012
  def select_color(self):
949
1013
  """カラーピッカーを開き、選択された色を内部変数とUIに反映させる"""
@@ -979,7 +1043,6 @@ class SettingsDialog(QDialog):
979
1043
  'wireframe_bond_radius': self.wf_bond_radius_slider.value() / 100.0,
980
1044
  'wireframe_resolution': self.wf_resolution_slider.value(),
981
1045
  # Stick settings
982
- 'stick_atom_radius': self.stick_atom_radius_slider.value() / 100.0,
983
1046
  'stick_bond_radius': self.stick_bond_radius_slider.value() / 100.0,
984
1047
  'stick_resolution': self.stick_resolution_slider.value(),
985
1048
  # Multiple bond offset settings (per-model)
@@ -996,10 +1059,13 @@ class SettingsDialog(QDialog):
996
1059
  'stick_double_bond_radius_factor': self.stick_double_radius_slider.value() / 100.0,
997
1060
  'stick_triple_bond_radius_factor': self.stick_triple_radius_slider.value() / 100.0,
998
1061
  'display_kekule_3d': self.kekule_3d_checkbox.isChecked(),
1062
+ 'display_aromatic_circles_3d': self.aromatic_circle_checkbox.isChecked(),
1063
+ 'aromatic_torus_thickness_factor': self.aromatic_torus_thickness_slider.value() / 100.0,
999
1064
  'skip_chemistry_checks': self.skip_chem_checks_checkbox.isChecked(),
1000
1065
  'always_ask_charge': self.always_ask_charge_checkbox.isChecked(),
1001
1066
  # Ball & Stick bond color (3D grey/uniform color)
1002
1067
  'ball_stick_bond_color': getattr(self, 'bs_bond_color', self.default_settings.get('ball_stick_bond_color', '#7F7F7F')),
1068
+ 'ball_stick_use_cpk_bond_color': self.bs_use_cpk_bond_checkbox.isChecked(),
1003
1069
  }
1004
1070
 
1005
1071
  def pick_bs_bond_color(self):
@@ -23,6 +23,7 @@ except Exception:
23
23
  from modules.constants import VERSION, CPK_COLORS
24
24
  import os
25
25
  import json
26
+ import logging
26
27
 
27
28
  class UserTemplateDialog(QDialog):
28
29
  """ユーザーテンプレート管理ダイアログ"""
@@ -106,7 +107,7 @@ class UserTemplateDialog(QDialog):
106
107
  elif hasattr(child, 'refit_view'):
107
108
  child.refit_view()
108
109
  except Exception as e:
109
- print(f"Warning: Failed to refit template previews: {e}")
110
+ logging.warning(f"Warning: Failed to refit template previews: {e}")
110
111
 
111
112
  def showEvent(self, event):
112
113
  """ダイアログ表示時にプレビューを適切にフィット"""
@@ -136,7 +137,7 @@ class UserTemplateDialog(QDialog):
136
137
  template_data['filepath'] = filepath
137
138
  self.user_templates.append(template_data)
138
139
  except Exception as e:
139
- print(f"Error loading user templates: {e}")
140
+ logging.error(f"Error loading user templates: {e}")
140
141
 
141
142
  self.update_template_grid()
142
143
 
@@ -146,7 +147,7 @@ class UserTemplateDialog(QDialog):
146
147
  with open(filepath, 'r', encoding='utf-8') as f:
147
148
  return json.load(f)
148
149
  except Exception as e:
149
- print(f"Error loading template file {filepath}: {e}")
150
+ logging.error(f"Error loading template file {filepath}: {e}")
150
151
  return None
151
152
 
152
153
  def save_template_file(self, filepath, template_data):
@@ -156,7 +157,7 @@ class UserTemplateDialog(QDialog):
156
157
  json.dump(template_data, f, indent=2, ensure_ascii=False)
157
158
  return True
158
159
  except Exception as e:
159
- print(f"Error saving template file {filepath}: {e}")
160
+ logging.error(f"Error saving template file {filepath}: {e}")
160
161
  return False
161
162
 
162
163
  def update_template_grid(self):
@@ -253,7 +254,7 @@ class UserTemplateDialog(QDialog):
253
254
  if view and not rect.isEmpty():
254
255
  view.fitInView(rect, Qt.AspectRatioMode.KeepAspectRatio)
255
256
  except Exception as e:
256
- print(f"Warning: Failed to fit preview view: {e}")
257
+ logging.warning(f"Warning: Failed to fit preview view: {e}")
257
258
 
258
259
  def draw_template_preview(self, scene, template_data, view_size=None):
259
260
  """テンプレートプレビューを描画 - fitInView縮小率に基づく動的スケーリング"""
@@ -303,7 +304,7 @@ class UserTemplateDialog(QDialog):
303
304
  scale_factor = 4.0
304
305
 
305
306
  # Debug info (can be removed in production)
306
- # print(f"Mol size: {mol_size:.1f}, Fit scale: {fit_scale:.3f}, Scale factor: {scale_factor:.2f}")
307
+ # logging.debug(f"Mol size: {mol_size:.1f}, Fit scale: {fit_scale:.3f}, Scale factor: {scale_factor:.2f}")
307
308
  else:
308
309
  scale_factor = 1.0
309
310
 
@@ -481,7 +482,7 @@ class UserTemplateDialog(QDialog):
481
482
  except Exception:
482
483
  pass
483
484
  except Exception as e:
484
- print(f"Warning: Failed to switch main window to template mode: {e}")
485
+ logging.warning(f"Warning: Failed to switch main window to template mode: {e}")
485
486
 
486
487
  def use_template(self, template_data):
487
488
  """テンプレートを使用(エディタに適用)"""
@@ -518,7 +519,7 @@ class UserTemplateDialog(QDialog):
518
519
  # Mark selected and keep dialog open
519
520
  self.selected_template = template_data
520
521
  except Exception as e:
521
- print(f"Warning: Failed to switch main window to template mode: {e}")
522
+ logging.warning(f"Warning: Failed to switch main window to template mode: {e}")
522
523
 
523
524
  # Don't close dialog - keep it open for easy template switching
524
525
  # self.accept()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoleditPy-linux
3
- Version: 1.17.1
3
+ Version: 1.18.1
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
@@ -684,7 +684,6 @@ Classifier: Programming Language :: Python :: 3
684
684
  Classifier: Operating System :: OS Independent
685
685
  Classifier: Intended Audience :: Science/Research
686
686
  Classifier: Topic :: Scientific/Engineering :: Chemistry
687
- Classifier: Programming Language :: Python :: 3.8
688
687
  Classifier: Programming Language :: Python :: 3.9
689
688
  Classifier: Programming Language :: Python :: 3.10
690
689
  Classifier: Programming Language :: Python :: 3.11
@@ -3,53 +3,53 @@ moleditpy_linux/__main__.py,sha256=bYu_h7lhc6PIl1-I_VI4_Q5MdBHmVrMiO4DYsy9jbiY,8
3
3
  moleditpy_linux/main.py,sha256=0D8_CXe4xdgqlu2TWoT2pi35K9y2b4ilFj6LWD9Qk7w,1178
4
4
  moleditpy_linux/modules/__init__.py,sha256=PFwvuEKXsgQlHTYL8oT5sTeo22gR0XmQcySp7kOTtqk,1396
5
5
  moleditpy_linux/modules/about_dialog.py,sha256=zkR-w0vtqLH1Y0baQaoTb0tYmVamT4ztEMBdIANKKvc,3693
6
- moleditpy_linux/modules/align_plane_dialog.py,sha256=ULqc0Ik1ju0HSnkkr0f-VLQw7TJbV9PdjDirYYpBXL0,11934
7
- moleditpy_linux/modules/alignment_dialog.py,sha256=Oikb5lzTxrRX2MJXoeziYqBc9hckVR0PbuBb4KJUCCc,11409
6
+ moleditpy_linux/modules/align_plane_dialog.py,sha256=A4sGfnpWSLM5v4g2ADUVmZnWtKEaQxeGQk7ZRLTRj58,11944
7
+ moleditpy_linux/modules/alignment_dialog.py,sha256=lZOWo1Y7uKt31nxZAguNDHNZxKww_aLcg-JPilM2CPQ,11419
8
8
  moleditpy_linux/modules/analysis_window.py,sha256=zjP5ipSTpKw8oLr1eKdoxW8Bk1SslGlPqsVucD-x_5w,9403
9
- moleditpy_linux/modules/angle_dialog.py,sha256=e06-Bw2E9khyjC3209HuGc5FDS3Pj0StV8u5bO1gKFw,17817
9
+ moleditpy_linux/modules/angle_dialog.py,sha256=ytuE5VqT0dskgob1x08B6VW06qnslgCdAs_dwS2ANgY,17837
10
10
  moleditpy_linux/modules/atom_item.py,sha256=u8ge6B1M9sOGobfzg3tp1-EGXtEUmvdee7Fx6msg8Wk,15566
11
- moleditpy_linux/modules/bond_item.py,sha256=3pbas_VeVzFG8fMlPd3zsUOclAlC9zt_Rf6ZcDAbY1M,13047
12
- moleditpy_linux/modules/bond_length_dialog.py,sha256=Gaiu4XN3CmMXl-hHl_C5_-ADEA_0VhL5GlAmIKYGRLw,14848
11
+ moleditpy_linux/modules/bond_item.py,sha256=eVkEeKvM4igYI67DYxpey3FllqDyt_iWDo4VPYMhaPk,19137
12
+ moleditpy_linux/modules/bond_length_dialog.py,sha256=k5x_DhK9Q8CSwouKhEo_kLRRdaYHDaK84KDNmuDNLvY,14868
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=luUaOUS11yugyJjUuwhFZ3lH_K-0BedYn5DCIPDzUac,4703
16
- moleditpy_linux/modules/constrained_optimization_dialog.py,sha256=OFWJ715N92XLKlJwEnvCa-y01GHst_VoiyzURS9WGvM,30130
15
+ moleditpy_linux/modules/constants.py,sha256=BmnH8wNO4QnsenarqQeN9pnaHyIeIo6PJJyT2HFWLfc,4703
16
+ moleditpy_linux/modules/constrained_optimization_dialog.py,sha256=IEdNVhFoNSEMeA5ABpUH9Q88-YzDXFloQM2gwnPwnHY,30150
17
17
  moleditpy_linux/modules/custom_interactor_style.py,sha256=NjsXE2a43IDNEanZBlcG9eR4ZIERT1MsQC6lbfesapQ,38453
18
18
  moleditpy_linux/modules/custom_qt_interactor.py,sha256=MFaTuDh-FPeFBS4303CqxsxmsOIOW4QXUz6USwI8PHQ,2451
19
19
  moleditpy_linux/modules/dialog3_d_picking_mixin.py,sha256=2Sut0J5ltXMtrUJ9R3o1oZ4ysed27mdSIqLpWxmGdyM,5037
20
- moleditpy_linux/modules/dihedral_dialog.py,sha256=J_Ri71gkqYzBWK3MFaQv9Uq_iN6caTsEtFCTz4hr4Mk,18078
20
+ moleditpy_linux/modules/dihedral_dialog.py,sha256=rgry7LqyX9JMAR7d82QSroTPoKT3xz18EgKN1GzYZx4,18088
21
21
  moleditpy_linux/modules/main_window.py,sha256=bWgYP3EMOAcy1fnjg5DTXHb2d7Xm6zKQtFcleYjg7Ac,35789
22
- moleditpy_linux/modules/main_window_app_state.py,sha256=4iwmnaiKu7uJ98r1KpdWgZ1_GBCGsM38hf7DNTFXEZE,33592
23
- moleditpy_linux/modules/main_window_compute.py,sha256=dE5iwQBBADdH7F32OfsI9nwPkTKLNMVG5HYsENKwJBs,51564
22
+ moleditpy_linux/modules/main_window_app_state.py,sha256=ONdjo-ZAPdat1_ToFodzuUep3c8qbKRPX6glnY24c9o,33602
23
+ moleditpy_linux/modules/main_window_compute.py,sha256=DsyMvGD2gnB-9XC6SU-ICuScyyQxubfaDYAk8hkY-vk,51911
24
24
  moleditpy_linux/modules/main_window_dialog_manager.py,sha256=S1ROCWqzB2uVSKHY4o5CbTtJAEjSyEXGPC1AgmdVgK4,20065
25
- moleditpy_linux/modules/main_window_edit_3d.py,sha256=xBZxqzkTSUFqY2-WrTGEpTNIgzHdT_oMK5NcHaU2XVQ,19771
25
+ moleditpy_linux/modules/main_window_edit_3d.py,sha256=uY203adPg3CLyAdbG2NCThG2Am0WduzPDan9rXAlc14,19841
26
26
  moleditpy_linux/modules/main_window_edit_actions.py,sha256=lUFxNFTUQzeXN8CNlb4_4S9j4M1EEq8kpJmh9dCzM3M,64818
27
- moleditpy_linux/modules/main_window_export.py,sha256=piWCXSdC2Qfd1BgNvSlAOgCrce7n8YH99GexuTifhlg,34683
28
- moleditpy_linux/modules/main_window_main_init.py,sha256=rgPCUGB6yto0wTaMvWw721wNurGQ5hHpg0rpa3a1fPI,75595
29
- moleditpy_linux/modules/main_window_molecular_parsers.py,sha256=yac8DMa4zL35o7fCZFz_qwqLUvkzpzZBITheNO8PM8A,48394
30
- moleditpy_linux/modules/main_window_project_io.py,sha256=mj6rqLMziNb8YDEBtlt2FLJ3eylmz1pTokjaQ3F1r8k,17239
27
+ moleditpy_linux/modules/main_window_export.py,sha256=e0HA_jeaokIOBunQqGxUn5QKdniCmE8GrsE1Igy6zm8,38351
28
+ moleditpy_linux/modules/main_window_main_init.py,sha256=Ox6P8MQtEnOw47NWdgOmxNNSAFgR6Vv8My71gNvj8RY,75608
29
+ moleditpy_linux/modules/main_window_molecular_parsers.py,sha256=Ex4-urYsKf6PyHp4XToOhgXzuYWa_n7q--QmHci4OCU,48401
30
+ moleditpy_linux/modules/main_window_project_io.py,sha256=q1vEmWQDqla32HVkmk8-j0OY9ut5TI5NJ4ikahewkEo,17259
31
31
  moleditpy_linux/modules/main_window_string_importers.py,sha256=mQVDv2Dj4MwnPgMRe2IqdAAKnB_quE6QfYeAgCjfv28,10892
32
32
  moleditpy_linux/modules/main_window_ui_manager.py,sha256=p2KPzAj0GK9ZWP7SbAg0jGrmKeLaLC0X7l9ISC4GVu4,22256
33
- moleditpy_linux/modules/main_window_view_3d.py,sha256=md3-e-l8b0VJ2t-ich487KA6eLPUsUdp8vcxM-t9q90,58208
34
- moleditpy_linux/modules/main_window_view_loaders.py,sha256=DbsjW-C6XymIaqd0wsGQckOX8Qqx8UKwIOvtKeoUkfc,14452
33
+ moleditpy_linux/modules/main_window_view_3d.py,sha256=MQCW2GnqGUpdJO4-GeR_18z7dS5K8C2GzKY9Nf8Nm8U,69627
34
+ moleditpy_linux/modules/main_window_view_loaders.py,sha256=Dbdgv4TY_ZkX8Qyaevwr-mBJYJ59CBzRTEks-U1FiGw,14462
35
35
  moleditpy_linux/modules/mirror_dialog.py,sha256=c3v4qY6R4FAljzk4EPaDjL9ZdZMjLQSFLqDMXz2fBUk,4696
36
36
  moleditpy_linux/modules/molecular_data.py,sha256=8gE9ByYg3kSBfb1zANsyad_BVBTm6WOLF7NsZIYuG2E,13250
37
- moleditpy_linux/modules/molecule_scene.py,sha256=AOgsWCXBEOa7EjP_rC9DrBSleqORCFQOEsHiQRsm4Mg,94881
37
+ moleditpy_linux/modules/molecule_scene.py,sha256=Ced3-U_03epwb1yL2QToq9MtILN4qCYDe0qpayHMWAE,94997
38
38
  moleditpy_linux/modules/move_group_dialog.py,sha256=65HVXTJSaQ9lp03XFhI1l7OzUsXmH_aqd8OgwjpjfGg,27174
39
39
  moleditpy_linux/modules/periodic_table_dialog.py,sha256=ItEZUts1XCietz9paY-spvbzxh6SXak3GnikwqkHZCw,4006
40
- moleditpy_linux/modules/planarize_dialog.py,sha256=uwd4zU1YWfG8lgEYr6_pMjX1nPKjeQEHAtvHC7IuC-s,8671
41
- moleditpy_linux/modules/settings_dialog.py,sha256=vAxu4cvEJtzwoDZLx2BHFzrvEBbiKgT8wIlT4WIzZeA,60927
40
+ moleditpy_linux/modules/planarize_dialog.py,sha256=yY8o-SxT8vGEHVWnjDTXecRv5NUaEejEsXH-836Xk8g,8681
41
+ moleditpy_linux/modules/settings_dialog.py,sha256=Nr7yE8UmYRi3VObWvRlrnv0DnjSjmYXbvqryZ02O12k,65348
42
42
  moleditpy_linux/modules/template_preview_item.py,sha256=Ks3C35pYFuLT5G4fsloI7ljE6ESXoYyGvLkM22qcmt0,6673
43
43
  moleditpy_linux/modules/template_preview_view.py,sha256=4OCHZDO51BvJpKdfrBWJ4_4WfLfFSKxsVIyf7I-Kj2E,3350
44
44
  moleditpy_linux/modules/translation_dialog.py,sha256=aWlgTR9mtEMbzGIY1SoQhDltsX-01LtCxjqy5NWtGuA,14663
45
- moleditpy_linux/modules/user_template_dialog.py,sha256=0AOnJpxqOL4iGeZAmbuicXUB5wguEbSq-MlFFByJpGQ,28224
45
+ moleditpy_linux/modules/user_template_dialog.py,sha256=L2D2AUokh7flqHiCBXWNcVG9Z8RgjXnlUhi2ZO6fgVg,28312
46
46
  moleditpy_linux/modules/zoomable_view.py,sha256=hjwljui13QpvjvxJHY4Evot4jMQvxRBQUNH5HUlyFOk,5966
47
47
  moleditpy_linux/modules/assets/icon.icns,sha256=wD5R6-Vw7K662tVKhu2E1ImN0oUuyAP4youesEQsn9c,139863
48
48
  moleditpy_linux/modules/assets/icon.ico,sha256=RfgFcx7-dHY_2STdsOQCQziY5SNhDr3gPnjO6jzEDPI,147975
49
49
  moleditpy_linux/modules/assets/icon.png,sha256=kCFN1WacYIdy0GN6SFEbNA00ef39pCczBnFdkkBI8Bs,147110
50
- moleditpy_linux-1.17.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
51
- moleditpy_linux-1.17.1.dist-info/METADATA,sha256=kLUfj73j5fvn7f782tjK1C18M5X3evrSx4rxNqG9olI,58734
52
- moleditpy_linux-1.17.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
- moleditpy_linux-1.17.1.dist-info/entry_points.txt,sha256=-OzipSi__yVwlimNtu3eiRP5t5UMg55Cs0udyhXYiyw,60
54
- moleditpy_linux-1.17.1.dist-info/top_level.txt,sha256=qyqe-hDYL6CXyin9E5Me5rVl3PG84VqiOjf9bQvfJLs,16
55
- moleditpy_linux-1.17.1.dist-info/RECORD,,
50
+ moleditpy_linux-1.18.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
51
+ moleditpy_linux-1.18.1.dist-info/METADATA,sha256=Af61_lPyAZ-3Os7uWmdbsb7raba3VK_ynPdfrUTLwZk,58683
52
+ moleditpy_linux-1.18.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
+ moleditpy_linux-1.18.1.dist-info/entry_points.txt,sha256=-OzipSi__yVwlimNtu3eiRP5t5UMg55Cs0udyhXYiyw,60
54
+ moleditpy_linux-1.18.1.dist-info/top_level.txt,sha256=qyqe-hDYL6CXyin9E5Me5rVl3PG84VqiOjf9bQvfJLs,16
55
+ moleditpy_linux-1.18.1.dist-info/RECORD,,