- UI refinement, button position ui file as source no dirty drafting anymore
This commit is contained in:
+108
-362
@@ -73,6 +73,7 @@ from fluency.geometry_occ.sketch import OCCSketch, OCCSketchEntity
|
||||
from fluency.geometry.base import Point2D, Point3D
|
||||
from fluency.rendering.occ_renderer import OCCRenderer
|
||||
from fluency.models.data_model import Project, Component, Sketch, Body
|
||||
from gui_ui import Ui_fluencyCAD
|
||||
|
||||
|
||||
def _project_face_to_uv(
|
||||
@@ -689,6 +690,7 @@ class WorkplaneOrientationDialog(QDialog):
|
||||
x = np.array([1.0, 0.0, 0.0])
|
||||
self._normal = tuple(float(v) for v in n)
|
||||
self._x_dir = tuple(float(v) for v in x)
|
||||
|
||||
else:
|
||||
btn = self._preset_group.checkedButton()
|
||||
if btn is not None:
|
||||
@@ -3992,11 +3994,15 @@ class MainWindow(QMainWindow):
|
||||
self._create_menus()
|
||||
self._create_central_widget()
|
||||
self._create_dock_widgets()
|
||||
self._setup_ui_aliases()
|
||||
|
||||
logger.info("Ready")
|
||||
|
||||
def _create_menus(self):
|
||||
# Remove UI-built menu actions to avoid duplication
|
||||
menubar = self.menuBar()
|
||||
for action in menubar.actions():
|
||||
menubar.removeAction(action)
|
||||
|
||||
file_menu = menubar.addMenu("&File")
|
||||
|
||||
@@ -4047,377 +4053,123 @@ class MainWindow(QMainWindow):
|
||||
help_menu.addAction("About", self._show_about)
|
||||
|
||||
def _create_central_widget(self):
|
||||
"""
|
||||
Recreates the classic grid-based layout from the original fluencyCAD.
|
||||
"""Load the compiled UI file and add programmatic custom widgets."""
|
||||
self._ui = Ui_fluencyCAD()
|
||||
self._ui.setupUi(self)
|
||||
|
||||
Grid layout:
|
||||
Col 0 (≤200px) Col 1 (expand) Col 2 (expand) Col 3 (≤200px)
|
||||
r0: Workplanes InputTab Model Viewer Modify
|
||||
r1: Drawing
|
||||
r2: Constrain
|
||||
r3: Snaps (tab) r6: Export
|
||||
r4: (Snaps cont) r7-8: Bodies
|
||||
r5: (Snaps cont)
|
||||
r6-8: Sketch List
|
||||
r9: Comp Tools Comp Buttons (span 2) Assembly Tools
|
||||
"""
|
||||
central = QWidget()
|
||||
self.setCentralWidget(central)
|
||||
# Keep a reference to the grid for panel-focus management.
|
||||
self._grid = self._ui.gridLayout
|
||||
|
||||
grid = QGridLayout(central)
|
||||
grid.setContentsMargins(5, 5, 5, 5)
|
||||
grid.setSpacing(4)
|
||||
grid.setColumnStretch(0, 0) # left column fixed
|
||||
# Sketch (col 1) and 3D viewer (col 2) share the remaining width.
|
||||
# The split is hover-driven: entering the sketch enlarges it, entering
|
||||
# the 3D viewer grows it to 2/3 (sketch shrinks to 1/3). Resting = 1:1.
|
||||
grid.setColumnStretch(1, 1)
|
||||
grid.setColumnStretch(2, 1)
|
||||
grid.setColumnStretch(3, 0) # right column fixed
|
||||
self._grid = grid
|
||||
# -- Add programmatic custom widgets to their placeholder locations --
|
||||
|
||||
# ---- Row 0, Col 0: Workplanes ----
|
||||
wp_group = QGroupBox("Workplanes")
|
||||
wp_group.setMaximumWidth(200)
|
||||
wp_layout = QGridLayout(wp_group)
|
||||
self._btn_wp_origin = QPushButton("WP Origin")
|
||||
self._btn_wp_origin.setToolTip("Working Plane at 0, 0, 0")
|
||||
self._btn_wp_origin.setShortcut("W")
|
||||
wp_layout.addWidget(self._btn_wp_origin, 0, 0)
|
||||
self._btn_wp_face = QPushButton("WP Face")
|
||||
self._btn_wp_face.setToolTip("Working Plane from selected face")
|
||||
self._btn_wp_face.setShortcut("P")
|
||||
self._btn_wp_face.setCheckable(True)
|
||||
wp_layout.addWidget(self._btn_wp_face, 0, 1)
|
||||
self._btn_wp_flip = QPushButton("WP Flip")
|
||||
self._btn_wp_flip.setToolTip("Flip normal direction")
|
||||
self._btn_wp_flip.setShortcut("N")
|
||||
wp_layout.addWidget(self._btn_wp_flip, 1, 0)
|
||||
self._btn_wp_move = QPushButton("WP Mve")
|
||||
self._btn_wp_move.setToolTip("Move workplane")
|
||||
self._btn_wp_move.setShortcut("M")
|
||||
wp_layout.addWidget(self._btn_wp_move, 1, 1)
|
||||
# ── New Workplane button ──
|
||||
self._btn_wp_new = QPushButton("WP New")
|
||||
self._btn_wp_new.setToolTip("Create a new independent workplane (datum plane)")
|
||||
self._btn_wp_new.setShortcut("Shift+W")
|
||||
wp_layout.addWidget(self._btn_wp_new, 2, 0, 1, 2)
|
||||
# Underlay: show / hide the construction lines projected from the
|
||||
# source face. Off by default is meaningless (no face picked yet)
|
||||
# so it auto-unchecks when the user clears the source face.
|
||||
self._btn_underlay = QPushButton("Underlay")
|
||||
self._btn_underlay.setToolTip(
|
||||
"Show / hide the construction lines projected from the source face"
|
||||
)
|
||||
self._btn_underlay.setCheckable(True)
|
||||
self._btn_underlay.setChecked(True)
|
||||
self._btn_underlay.setEnabled(False) # becomes enabled after WP Face
|
||||
wp_layout.addWidget(self._btn_underlay, 3, 0)
|
||||
# ClrFace: forget the picked source face. Removes the underlay
|
||||
# construction-line entities and leaves the workplane + sketch
|
||||
# intact, so the user can keep drawing on a free-standing sketch.
|
||||
self._btn_clr_face = QPushButton("ClrFace")
|
||||
self._btn_clr_face.setToolTip("Forget the picked source face (keep the workplane)")
|
||||
self._btn_clr_face.setEnabled(False) # becomes enabled after WP Face
|
||||
wp_layout.addWidget(self._btn_clr_face, 3, 1)
|
||||
# ToSketch: convert the underlay (projected construction lines)
|
||||
# into regular non-construction sketch geometry so the user can
|
||||
# offset, modify, or extrude the projected shape directly without
|
||||
# having to redraw it manually.
|
||||
self._btn_to_sketch = QPushButton("ToSketch")
|
||||
self._btn_to_sketch.setToolTip(
|
||||
"Convert projected construction lines into real sketch geometry"
|
||||
)
|
||||
self._btn_to_sketch.setEnabled(False)
|
||||
wp_layout.addWidget(self._btn_to_sketch, 4, 0, 1, 2)
|
||||
grid.addWidget(wp_group, 0, 0)
|
||||
|
||||
# ---- Row 1, Col 0: Drawing ----
|
||||
draw_group = QGroupBox("Drawing")
|
||||
draw_group.setMaximumWidth(200)
|
||||
draw_layout = QGridLayout(draw_group)
|
||||
self._btn_line = QPushButton("Line")
|
||||
self._btn_line.setCheckable(True)
|
||||
self._btn_line.setShortcut("S")
|
||||
draw_layout.addWidget(self._btn_line, 0, 0)
|
||||
self._btn_rect = QPushButton("Rctgl")
|
||||
self._btn_rect.setCheckable(True)
|
||||
draw_layout.addWidget(self._btn_rect, 0, 1)
|
||||
self._btn_circle = QPushButton("Circle")
|
||||
self._btn_circle.setCheckable(True)
|
||||
draw_layout.addWidget(self._btn_circle, 1, 0)
|
||||
self._btn_slot = QPushButton("Slot")
|
||||
self._btn_slot.setCheckable(True)
|
||||
draw_layout.addWidget(self._btn_slot, 1, 1)
|
||||
self._btn_move_sketch = QPushButton("Move")
|
||||
self._btn_move_sketch.setCheckable(True)
|
||||
self._btn_move_sketch.setToolTip("Move a drawn element (drag a point/line/rectangle/circle).")
|
||||
self._btn_move_sketch.setShortcut("Q")
|
||||
draw_layout.addWidget(self._btn_move_sketch, 1, 2, 1, 1)
|
||||
self._btn_arc = QPushButton("Arc")
|
||||
self._btn_arc.setCheckable(True)
|
||||
draw_layout.addWidget(self._btn_arc, 2, 0)
|
||||
# separator (shifted right to leave column 0 for Arc)
|
||||
sep = QFrame()
|
||||
sep.setFrameShape(QFrame.HLine)
|
||||
sep.setFrameShadow(QFrame.Sunken)
|
||||
draw_layout.addWidget(sep, 2, 1, 1, 2)
|
||||
self._btn_construct = QPushButton("Cstrct")
|
||||
self._btn_construct.setCheckable(True)
|
||||
draw_layout.addWidget(self._btn_construct, 3, 0)
|
||||
self._btn_snap = QPushButton("Snap")
|
||||
self._btn_snap.setCheckable(True)
|
||||
self._btn_snap.setChecked(True)
|
||||
draw_layout.addWidget(self._btn_snap, 3, 1)
|
||||
self._btn_offset = QPushButton("Offst")
|
||||
self._btn_offset.setToolTip("Offset selected sketch face (duplicate + offset boundary)")
|
||||
draw_layout.addWidget(self._btn_offset, 4, 0, 1, 2)
|
||||
grid.addWidget(draw_group, 1, 0)
|
||||
|
||||
# ---- Row 2, Col 0: Constrain ----
|
||||
con_group = QGroupBox("Constrain")
|
||||
con_group.setMaximumWidth(200)
|
||||
con_layout = QGridLayout(con_group)
|
||||
self._btn_con_ptpt = QPushButton("Pt_Pt")
|
||||
self._btn_con_ptpt.setCheckable(True)
|
||||
self._btn_con_ptpt.setToolTip("Point to Point Coincident")
|
||||
con_layout.addWidget(self._btn_con_ptpt, 0, 0)
|
||||
self._btn_con_ptline = QPushButton("Pt_Lne")
|
||||
self._btn_con_ptline.setCheckable(True)
|
||||
self._btn_con_ptline.setToolTip("Point to Line Distance")
|
||||
con_layout.addWidget(self._btn_con_ptline, 0, 1)
|
||||
self._btn_con_mid = QPushButton("Pt_Mid_L")
|
||||
self._btn_con_mid.setCheckable(True)
|
||||
self._btn_con_mid.setToolTip("Point to Midpoint")
|
||||
con_layout.addWidget(self._btn_con_mid, 1, 0)
|
||||
self._btn_con_perp = QPushButton("Perp_Lne")
|
||||
self._btn_con_perp.setCheckable(True)
|
||||
self._btn_con_perp.setToolTip("Perpendicular Constraint")
|
||||
con_layout.addWidget(self._btn_con_perp, 1, 1)
|
||||
self._btn_con_horiz = QPushButton("Horiz")
|
||||
self._btn_con_horiz.setCheckable(True)
|
||||
self._btn_con_horiz.setToolTip("Horizontal Constraint")
|
||||
con_layout.addWidget(self._btn_con_horiz, 2, 0)
|
||||
self._btn_con_vert = QPushButton("Vert")
|
||||
self._btn_con_vert.setCheckable(True)
|
||||
self._btn_con_vert.setToolTip("Vertical Constraint")
|
||||
con_layout.addWidget(self._btn_con_vert, 2, 1)
|
||||
self._btn_con_dist = QPushButton("Distnce")
|
||||
self._btn_con_dist.setCheckable(True)
|
||||
self._btn_con_dist.setToolTip("Distance Constraint")
|
||||
con_layout.addWidget(self._btn_con_dist, 3, 0)
|
||||
self._btn_con_sym = QPushButton("Symetrc")
|
||||
self._btn_con_sym.setCheckable(True)
|
||||
con_layout.addWidget(self._btn_con_sym, 3, 1)
|
||||
grid.addWidget(con_group, 2, 0)
|
||||
|
||||
# ---- Row 3-5, Col 0: Snaps tab ----
|
||||
self._snaps_tab = QTabWidget()
|
||||
self._snaps_tab.setMaximumWidth(200)
|
||||
self._snaps_tab.setTabPosition(QTabWidget.TabPosition.South)
|
||||
snaps_tab1 = QWidget()
|
||||
snaps_layout = QVBoxLayout(snaps_tab1)
|
||||
snap_group = QGroupBox("Snapping Points")
|
||||
snap_grid = QGridLayout(snap_group)
|
||||
snap_grid.setContentsMargins(2, 2, 2, 2)
|
||||
self._btn_snap_point = QPushButton("Pnt")
|
||||
self._btn_snap_point.setCheckable(True)
|
||||
self._btn_snap_point.setChecked(True)
|
||||
snap_grid.addWidget(self._btn_snap_point, 0, 0)
|
||||
self._btn_snap_mid = QPushButton("MidP")
|
||||
self._btn_snap_mid.setCheckable(True)
|
||||
snap_grid.addWidget(self._btn_snap_mid, 0, 1)
|
||||
self._btn_snap_horiz = QPushButton("Horiz")
|
||||
self._btn_snap_horiz.setCheckable(True)
|
||||
snap_grid.addWidget(self._btn_snap_horiz, 1, 0)
|
||||
self._btn_snap_vert = QPushButton("Vert")
|
||||
self._btn_snap_vert.setCheckable(True)
|
||||
snap_grid.addWidget(self._btn_snap_vert, 1, 1)
|
||||
self._btn_snap_angle = QPushButton("Angles")
|
||||
self._btn_snap_angle.setCheckable(True)
|
||||
snap_grid.addWidget(self._btn_snap_angle, 2, 0)
|
||||
self._btn_snap_grid = QPushButton("Grid")
|
||||
self._btn_snap_grid.setCheckable(True)
|
||||
snap_grid.addWidget(self._btn_snap_grid, 2, 1)
|
||||
# separator
|
||||
sep2 = QFrame()
|
||||
sep2.setFrameShape(QFrame.HLine)
|
||||
sep2.setFrameShadow(QFrame.Sunken)
|
||||
snap_grid.addWidget(sep2, 3, 0, 1, 2)
|
||||
snap_grid.addWidget(QLabel("Snp Dst"), 4, 0)
|
||||
snap_grid.addWidget(QLabel("Angl Stps"), 4, 1)
|
||||
self._spin_snap_dist = QSpinBox()
|
||||
self._spin_snap_dist.setRange(1, 30)
|
||||
self._spin_snap_dist.setValue(10)
|
||||
self._spin_snap_dist.setSuffix("px")
|
||||
snap_grid.addWidget(self._spin_snap_dist, 5, 0)
|
||||
self._spin_angle = QSpinBox()
|
||||
self._spin_angle.setRange(1, 180)
|
||||
self._spin_angle.setValue(15)
|
||||
self._spin_angle.setSuffix("°")
|
||||
snap_grid.addWidget(self._spin_angle, 5, 1)
|
||||
snaps_layout.addWidget(snap_group)
|
||||
self._snaps_tab.addTab(snaps_tab1, "Setg 1")
|
||||
self._snaps_tab.addTab(QWidget(), "Setg 2")
|
||||
grid.addWidget(self._snaps_tab, 3, 0)
|
||||
# snaps tab spans rows 3-5
|
||||
grid.setRowStretch(3, 0)
|
||||
grid.setRowStretch(4, 1)
|
||||
grid.setRowStretch(5, 1)
|
||||
# Build row 6-8 spacer for left column
|
||||
# Reserve space so the sketch list reaches the bottom
|
||||
grid.setRowMinimumHeight(6, 0)
|
||||
grid.setRowMinimumHeight(7, 0)
|
||||
grid.setRowMinimumHeight(8, 0)
|
||||
|
||||
# ---- Row 6-8, Col 0: Sketch List ----
|
||||
sk_list_group = QGroupBox("Sketch")
|
||||
sk_list_group.setMaximumWidth(200)
|
||||
sk_list_layout = QVBoxLayout(sk_list_group)
|
||||
self._sketch_list = QListWidget()
|
||||
self._sketch_list.setSelectionRectVisible(True)
|
||||
sk_list_layout.addWidget(self._sketch_list)
|
||||
sk_tools = QGroupBox("Tools")
|
||||
sk_tools_grid = QGridLayout(sk_tools)
|
||||
sk_tools_grid.setContentsMargins(2, 2, 2, 2)
|
||||
self._btn_add_sketch = QPushButton("Add")
|
||||
sk_tools_grid.addWidget(self._btn_add_sketch, 0, 0)
|
||||
self._btn_edit_sketch = QPushButton("Edt")
|
||||
sk_tools_grid.addWidget(self._btn_edit_sketch, 0, 1)
|
||||
self._btn_del_sketch = QPushButton("Del")
|
||||
sk_tools_grid.addWidget(self._btn_del_sketch, 0, 2)
|
||||
sk_list_layout.addWidget(sk_tools)
|
||||
grid.addWidget(sk_list_group, 6, 0, 3, 1)
|
||||
|
||||
# ---- Row 0-8, Col 1: Input Tabs ----
|
||||
self._input_tabs = QTabWidget()
|
||||
sketch_tab = QWidget()
|
||||
sketch_tab_layout = QVBoxLayout(sketch_tab)
|
||||
sketch_tab_layout.setContentsMargins(0, 0, 0, 0)
|
||||
# Sketch2DWidget goes in the sketch tab’s QVBoxLayout.
|
||||
self._sketch_widget = Sketch2DWidget()
|
||||
sketch_tab_layout.addWidget(self._sketch_widget)
|
||||
self._input_tabs.addTab(sketch_tab, "Sketch")
|
||||
code_tab = QWidget()
|
||||
code_tab_layout = QVBoxLayout(code_tab)
|
||||
self._code_edit = QTextEdit()
|
||||
self._ui.sketch_tab.layout().addWidget(self._sketch_widget)
|
||||
|
||||
# Viewer3DWidget goes in the gl_box QHBoxLayout.
|
||||
self._viewer_3d = Viewer3DWidget()
|
||||
self._ui.gl_box.layout().addWidget(self._viewer_3d)
|
||||
|
||||
# Code editor — use the UI’s textEdit with our custom font.
|
||||
self._code_edit = self._ui.textEdit
|
||||
self._code_edit.setFont(QFont("Monaco", 10))
|
||||
self._code_edit.setPlaceholderText("# Enter Python code here...")
|
||||
code_tab_layout.addWidget(self._code_edit)
|
||||
code_tools = QHBoxLayout()
|
||||
self._btn_apply_code = QPushButton("Apply Code")
|
||||
self._btn_load_code = QPushButton("Load Code")
|
||||
self._btn_save_code = QPushButton("Save Code")
|
||||
self._btn_del_code = QPushButton("Delete Code")
|
||||
code_tools.addWidget(self._btn_apply_code)
|
||||
code_tools.addWidget(self._btn_load_code)
|
||||
code_tools.addWidget(self._btn_save_code)
|
||||
code_tools.addWidget(self._btn_del_code)
|
||||
code_tab_layout.addLayout(code_tools)
|
||||
self._input_tabs.addTab(code_tab, "Code")
|
||||
grid.addWidget(self._input_tabs, 0, 1, 9, 1)
|
||||
|
||||
# ---- Row 0-8, Col 2: Model Viewer ----
|
||||
viewer_group = QGroupBox("Model Viewer")
|
||||
viewer_layout = QVBoxLayout(viewer_group)
|
||||
viewer_layout.setContentsMargins(5, 5, 5, 5)
|
||||
self._viewer_3d = Viewer3DWidget()
|
||||
viewer_layout.addWidget(self._viewer_3d)
|
||||
grid.addWidget(viewer_group, 0, 2, 9, 1)
|
||||
|
||||
# Focus split is toggled by Spacebar / the Layout button
|
||||
# (see _toggle_panel_focus).
|
||||
self._panel_focus: str = "equal" # "equal" | "sketch" | "viewer"
|
||||
|
||||
# ---- Row 0, Col 3: Modify ----
|
||||
modify_group = QGroupBox("Modify")
|
||||
modify_group.setMaximumWidth(200)
|
||||
modify_layout = QGridLayout(modify_group)
|
||||
self._btn_extrude = QPushButton("Extrd")
|
||||
self._btn_extrude.setToolTip("Extrude sketch")
|
||||
modify_layout.addWidget(self._btn_extrude, 0, 0)
|
||||
self._btn_cut = QPushButton("Cut")
|
||||
self._btn_cut.setToolTip("Boolean cut")
|
||||
modify_layout.addWidget(self._btn_cut, 0, 1)
|
||||
self._btn_combine = QPushButton("Comb")
|
||||
self._btn_combine.setToolTip("Boolean union")
|
||||
modify_layout.addWidget(self._btn_combine, 1, 0)
|
||||
self._btn_move = QPushButton("Mve")
|
||||
self._btn_move.setToolTip("Move body")
|
||||
modify_layout.addWidget(self._btn_move, 1, 1)
|
||||
self._btn_revolve = QPushButton("Rev")
|
||||
self._btn_revolve.setToolTip("Revolve sketch")
|
||||
modify_layout.addWidget(self._btn_revolve, 2, 0)
|
||||
self._btn_array = QPushButton("Arry")
|
||||
self._btn_array.setToolTip("Pattern array")
|
||||
modify_layout.addWidget(self._btn_array, 2, 1)
|
||||
grid.addWidget(modify_group, 0, 3, 1, 1, Qt.AlignTop)
|
||||
|
||||
# ---- Row 6, Col 3: Export ----
|
||||
export_group = QGroupBox("Export")
|
||||
export_group.setMaximumWidth(200)
|
||||
export_layout = QVBoxLayout(export_group)
|
||||
self._btn_export_stl = QPushButton("STL")
|
||||
export_layout.addWidget(self._btn_export_stl)
|
||||
self._btn_export_step = QPushButton("STEP")
|
||||
export_layout.addWidget(self._btn_export_step)
|
||||
self._btn_export_iges = QPushButton("IGES")
|
||||
export_layout.addWidget(self._btn_export_iges)
|
||||
grid.addWidget(export_group, 6, 3)
|
||||
|
||||
# ---- Row 7-8, Col 3: Bodies / Operations ----
|
||||
body_group = QGroupBox("Bodys / Operations")
|
||||
body_group.setMaximumWidth(200)
|
||||
body_layout = QVBoxLayout(body_group)
|
||||
self._body_list = QListWidget()
|
||||
self._body_list.setSelectionRectVisible(True)
|
||||
body_layout.addWidget(self._body_list)
|
||||
body_tools_grid = QGridLayout()
|
||||
body_tools_grid.setContentsMargins(2, 2, 2, 2)
|
||||
self._btn_update_body = QPushButton("Upd")
|
||||
body_tools_grid.addWidget(self._btn_update_body, 0, 0)
|
||||
self._btn_edit_sketch_3 = QPushButton("Nothing")
|
||||
body_tools_grid.addWidget(self._btn_edit_sketch_3, 0, 1)
|
||||
self._btn_del_body = QPushButton("Del")
|
||||
body_tools_grid.addWidget(self._btn_del_body, 0, 2)
|
||||
body_layout.addLayout(body_tools_grid)
|
||||
grid.addWidget(body_group, 7, 3, 2, 1)
|
||||
|
||||
# ---- Row 9, Col 0: Component Tools ----
|
||||
comp_tool_group = QGroupBox("Component Tools")
|
||||
comp_tool_group.setMinimumHeight(50)
|
||||
comp_tool_layout = QHBoxLayout(comp_tool_group)
|
||||
self._btn_new_compo = QPushButton("New")
|
||||
self._btn_new_compo.setFixedSize(QSize(50, 50))
|
||||
comp_tool_layout.addWidget(self._btn_new_compo)
|
||||
self._btn_del_compo = QPushButton("Del")
|
||||
self._btn_del_compo.setFixedSize(QSize(50, 50))
|
||||
comp_tool_layout.addWidget(self._btn_del_compo)
|
||||
grid.addWidget(comp_tool_group, 9, 0)
|
||||
|
||||
# ---- Row 9, Col 1-2: Components (button box) ----
|
||||
compo_group = QGroupBox("Components")
|
||||
compo_group.setMinimumHeight(50)
|
||||
compo_layout = QHBoxLayout(compo_group)
|
||||
# Component buttons (dynamically generated per component, not in UI).
|
||||
self._component_box = QWidget()
|
||||
self._component_box_layout = QHBoxLayout(self._component_box)
|
||||
self._component_box_layout.setAlignment(Qt.AlignLeft)
|
||||
self._component_group = QButtonGroup(self)
|
||||
self._component_group.setExclusive(True)
|
||||
# Add to the Components group box from the UI.
|
||||
compo_layout = self._ui.compo_box.layout()
|
||||
if compo_layout is None:
|
||||
compo_layout = QHBoxLayout(self._ui.compo_box)
|
||||
compo_layout.setContentsMargins(0, 0, 0, 0)
|
||||
compo_layout.addWidget(self._component_box)
|
||||
compo_layout.addStretch()
|
||||
grid.addWidget(compo_group, 9, 1, 1, 2)
|
||||
|
||||
# ---- Row 9, Col 3: Assembly Tools ----
|
||||
assy_group = QGroupBox("Assembly Tools")
|
||||
assy_group.setMinimumHeight(50)
|
||||
assy_layout = QHBoxLayout(assy_group)
|
||||
self._btn_add_connector = QPushButton("+ Cnct")
|
||||
self._btn_add_connector.setFixedSize(QSize(50, 50))
|
||||
assy_layout.addWidget(self._btn_add_connector)
|
||||
self._btn_del_connector = QPushButton("- Cnct")
|
||||
self._btn_del_connector.setFixedSize(QSize(50, 50))
|
||||
assy_layout.addWidget(self._btn_del_connector)
|
||||
grid.addWidget(assy_group, 9, 3)
|
||||
# Panel-focus mode (equal | sketch | viewer).
|
||||
self._panel_focus: str = "equal"
|
||||
|
||||
def _setup_ui_aliases(self):
|
||||
"""Create _btn_* aliases pointing to the UI-loaded widgets.
|
||||
|
||||
The rest of the application references widgets via ``self._btn_*``
|
||||
names. This method maps those to the ``pb_*`` / ``pushButton_*``
|
||||
names created by the compiled UI file so existing signal connections
|
||||
and mode-switching code continues to work unchanged.
|
||||
"""
|
||||
ui = self._ui
|
||||
# ── Workplanes ──
|
||||
self._btn_wp_origin = ui.pb_origin_wp
|
||||
self._btn_wp_face = ui.pb_origin_face
|
||||
self._btn_wp_flip = ui.pb_flip_face
|
||||
self._btn_wp_new = ui.pb_wp_new
|
||||
self._btn_underlay = ui.pb_underlay
|
||||
self._btn_clr_face = ui.pb_clr_face
|
||||
self._btn_to_sketch = ui.pb_to_sketch
|
||||
# ── Drawing ──
|
||||
self._btn_line = ui.pb_linetool
|
||||
self._btn_rect = ui.pb_rectool
|
||||
self._btn_circle = ui.pb_circtool
|
||||
self._btn_slot = ui.pb_slotool
|
||||
self._btn_arc = ui.pb_arc_tool
|
||||
self._btn_construct = ui.pb_enable_construct
|
||||
self._btn_snap = ui.pb_enable_snap
|
||||
self._btn_offset = ui.pb_offset_tool
|
||||
# ── Constrain ──
|
||||
self._btn_con_ptpt = ui.pb_con_ptpt
|
||||
self._btn_con_ptline = ui.pb_con_line
|
||||
self._btn_con_mid = ui.pb_con_mid
|
||||
self._btn_con_perp = ui.pb_con_perp
|
||||
self._btn_con_horiz = ui.pb_con_horiz
|
||||
self._btn_con_vert = ui.pb_con_vert
|
||||
self._btn_con_dist = ui.pb_con_dist
|
||||
self._btn_con_sym = ui.pb_con_sym
|
||||
# ── Snaps ──
|
||||
self._btn_snap_point = ui.pushButton_8
|
||||
self._btn_snap_mid = ui.pb_snap_midp
|
||||
self._btn_snap_horiz = ui.pb_snap_horiz
|
||||
self._btn_snap_vert = ui.pb_snap_vert
|
||||
self._btn_snap_angle = ui.pb_snap_angle
|
||||
self._btn_snap_grid = ui.pushButton_7
|
||||
self._spin_snap_dist = ui.spinbox_snap_distance
|
||||
self._spin_angle = ui.spinbox_angle_steps
|
||||
# ── Modify ──
|
||||
self._btn_extrude = ui.pb_extrdop
|
||||
self._btn_cut = ui.pb_cutop
|
||||
self._btn_combine = ui.pb_combop
|
||||
self._btn_move = ui.pb_moveop
|
||||
self._btn_revolve = ui.pb_revop
|
||||
self._btn_array = ui.pb_arrayop
|
||||
# ── Export ──
|
||||
self._btn_export_stl = ui.pushButton_2
|
||||
self._btn_export_step = ui.pb_export_step
|
||||
self._btn_export_iges = ui.pb_export_iges
|
||||
# ── Sketch list tools ──
|
||||
self._btn_add_sketch = ui.pb_nw_sktch
|
||||
self._btn_edit_sketch = ui.pb_edt_sktch
|
||||
self._btn_del_sketch = ui.pb_del_sketch
|
||||
# ── Body tools ──
|
||||
self._btn_update_body = ui.pb_update_body
|
||||
self._btn_edit_sketch_3 = ui.pb_edt_sktch_3
|
||||
self._btn_del_body = ui.pb_del_body
|
||||
# ── Component tools ──
|
||||
self._btn_new_compo = ui.pb_new_compo
|
||||
self._btn_del_compo = ui.pb_del_compo
|
||||
# ── Assembly / Connector ──
|
||||
self._btn_add_connector = ui.pb_add_connector
|
||||
self._btn_del_connector = ui.pb_remove_connector
|
||||
# ── Code tab ──
|
||||
self._btn_apply_code = ui.pb_apply_code
|
||||
self._btn_load_code = ui.pushButton_5
|
||||
self._btn_save_code = ui.pushButton_4
|
||||
self._btn_del_code = ui.pushButton
|
||||
# ── List views & tabs ──
|
||||
self._sketch_list = ui.sketch_list
|
||||
self._body_list = ui.body_list
|
||||
self._input_tabs = ui.InputTab
|
||||
|
||||
def _toggle_panel_focus(self):
|
||||
"""Cycle the sketch/viewer split: equal → sketch → viewer → equal.
|
||||
@@ -4468,7 +4220,6 @@ class MainWindow(QMainWindow):
|
||||
self._btn_circle.clicked.connect(lambda: self._set_sketch_mode("circle"))
|
||||
self._btn_arc.clicked.connect(lambda: self._set_sketch_mode("arc"))
|
||||
self._btn_slot.clicked.connect(lambda: self._set_sketch_mode("slot"))
|
||||
self._btn_move_sketch.clicked.connect(lambda: self._set_sketch_mode("select"))
|
||||
self._btn_construct.clicked.connect(self._on_construct_change)
|
||||
|
||||
self._btn_con_ptpt.clicked.connect(lambda: self._set_sketch_mode("constrain_coincident"))
|
||||
@@ -4535,7 +4286,6 @@ class MainWindow(QMainWindow):
|
||||
self._btn_wp_origin.clicked.connect(self._new_sketch_origin)
|
||||
self._btn_wp_new.clicked.connect(self._new_workplane)
|
||||
self._btn_wp_flip.clicked.connect(self._flip_workplane)
|
||||
self._btn_wp_move.clicked.connect(self._move_workplane)
|
||||
# Underlay show/hide, ClrFace, and ToSketch — all stay in sync
|
||||
# with the source face state managed by set_source_face /
|
||||
# clear_source_face / _project_body_to_active_wp.
|
||||
@@ -4564,7 +4314,6 @@ class MainWindow(QMainWindow):
|
||||
self._btn_circle,
|
||||
self._btn_arc,
|
||||
self._btn_slot,
|
||||
self._btn_move_sketch,
|
||||
self._btn_con_ptpt,
|
||||
self._btn_con_ptline,
|
||||
self._btn_con_horiz,
|
||||
@@ -4587,8 +4336,6 @@ class MainWindow(QMainWindow):
|
||||
self._btn_arc.setChecked(True)
|
||||
elif mode == "slot":
|
||||
self._btn_slot.setChecked(True)
|
||||
elif mode == "select":
|
||||
self._btn_move_sketch.setChecked(True)
|
||||
elif mode.startswith("constrain_"):
|
||||
if mode == "constrain_coincident":
|
||||
self._btn_con_ptpt.setChecked(True)
|
||||
@@ -4607,7 +4354,6 @@ class MainWindow(QMainWindow):
|
||||
self._btn_circle,
|
||||
self._btn_arc,
|
||||
self._btn_slot,
|
||||
self._btn_move_sketch,
|
||||
self._btn_con_ptpt,
|
||||
self._btn_con_ptline,
|
||||
self._btn_con_horiz,
|
||||
|
||||
@@ -1013,7 +1013,7 @@ class OCCRenderer(Renderer):
|
||||
# • Left button drag → orbit (rotate around target)
|
||||
# • Middle button drag → pan
|
||||
# • Right button → (reserved for future use)
|
||||
# • Wheel → zoom toward cursor
|
||||
# • Wheel → zoom centered on viewport
|
||||
# • Double-click left → fit all (handled by the widget)
|
||||
|
||||
def _qt_buttons(self, event) -> Any:
|
||||
@@ -1079,20 +1079,19 @@ class OCCRenderer(Renderer):
|
||||
self._nav_mode = None
|
||||
|
||||
def handle_wheel(self, event) -> None:
|
||||
"""Zoom toward the cursor on scroll."""
|
||||
"""Zoom centered on the viewport (body midpoint) on scroll.
|
||||
|
||||
Uses the view's scale factor so the zoom is always centered
|
||||
on the viewport centre — the body never drifts to an edge.
|
||||
"""
|
||||
if self._view is None:
|
||||
return
|
||||
# Qt6: QWheelEvent has no .x()/.y(); use position().toPoint().
|
||||
pos = event.position().toPoint() if hasattr(event, "position") else event.pos()
|
||||
x, y = pos.x(), pos.y()
|
||||
delta = event.angleDelta().y()
|
||||
if delta == 0:
|
||||
return
|
||||
# ZoomAtPoint(startX, startY, endX, endY): move the cursor anchor
|
||||
# by a few pixels to drive a smooth zoom centered on the pointer.
|
||||
step = 30 if delta > 0 else -30
|
||||
self._view.ZoomAtPoint(x, y, x, y - step)
|
||||
self._view.ZFitAll()
|
||||
|
||||
factor = 1.15 if delta > 0 else 1.0 / 1.15
|
||||
self._view.SetScale(self._view.Scale() * factor)
|
||||
|
||||
def handle_resize(self, w: int, h: int) -> None:
|
||||
"""Resize the OCC view when the widget is resized."""
|
||||
|
||||
Reference in New Issue
Block a user