From 8bbd7c0ccac667b74ce56cfd2de51a3bbc2b3972 Mon Sep 17 00:00:00 2001 From: Krish Joshi Date: Sat, 11 Jul 2026 13:59:24 +0530 Subject: [PATCH] redefined component selector UI --- src/main/python/mainApp.py | 267 ++++++++++++++++++++++++++++++++++--- src/main/ui/utils/main.ui | 6 +- 2 files changed, 251 insertions(+), 22 deletions(-) diff --git a/src/main/python/mainApp.py b/src/main/python/mainApp.py index e3cf093..61df6e5 100644 --- a/src/main/python/mainApp.py +++ b/src/main/python/mainApp.py @@ -197,18 +197,14 @@ def __init__(self): self.addDockWidget(Qt.LeftDockWidgetArea, self.selectedElementsDock) self.selectedElementsDock.hide() - self.dockWidget.setFeatures(QDockWidget.DockWidgetFloatable | - QDockWidget.DockWidgetMovable | - QDockWidget.DockWidgetClosable) + # ── Rebuild Component Selector dock with compact modern design ── + self._build_component_selector() + self.dockWidget_2.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetClosable) - - self.dockWidget.setMinimumSize(200, 200) self.dockWidget_2.setMinimumSize(200, 100) - - self.dockWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - self.dockWidget_2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + self.dockWidget_2.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) # Setting up interactive canvas self.scene = self.container.graphics.get_scene() @@ -224,6 +220,9 @@ def __init__(self): self.setCorner(Qt.BottomRightCorner, Qt.RightDockWidgetArea) self.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) self.addDockWidget(Qt.RightDockWidgetArea, self.dockWidget) + # Pin dock width AFTER addDockWidget — this is the only point where it sticks. + # setFixedWidth before addDockWidget gets overridden by Qt's layout engine. + self.dockWidget.setFixedWidth(240) self.addDockWidget(Qt.BottomDockWidgetArea, self.dockWidget_2) # Set initial dock sizes after the window has been shown @@ -246,19 +245,249 @@ def __init__(self): push('Undo', initial_snapshot) self._update_undo_redo_actions() - def _apply_initial_layout(self): - # Component Selector: ~300px wide, Selected Compounds: ~130px wide - self.resizeDocks( - [self.selectedElementsDock, self.dockWidget], - [130, 300], - Qt.Horizontal + def _build_component_selector(self): + """Rebuild the Component Selector dock with collapse/expand toggle.""" + ACCENT = '#0a84ff' + ACCENT_LIGHT = '#3d9fff' + BG = '#ffffff' + HEADER_BG = '#f2f2f2' + BTN_BG = '#ffffff' + BTN_BORDER = '#e0e0e0' + TEXT = '#333333' + ICON_SIZE = 30 + BTN_HEIGHT = 50 + HEADER_HEIGHT = 30 + + icons_base = os.path.join(parentPath, 'resources', 'base', 'icons') + + sections = [ + ('Streams', [ + ('pushButton', 'MaterialStream', 'MaterialStream.png'), + ]), + ('Mixer/Splitter', [ + ('pushButton_7', 'Mixer', 'Mixer.png'), + ('pushButton_10', 'Splitter', 'Splitter.png'), + ]), + ('Exchangers', [ + ('pushButton_11', 'Heater', 'Heater.png'), + ('pushButton_12', 'Cooler', 'Cooler.png'), + ]), + ('Separator', [ + ('pushButton_9', 'Flash', 'Flash.png'), + ('pushButton_13', 'Compound Sep.', 'CompoundSeparator.png'), + ]), + ('Pressure Changers', [ + ('pushButton_25', 'Valve', 'Valve.png'), + ('pushButton_14', 'Centrifugal Pump', 'CentrifugalPump.png'), + ('pushButton_15', 'Adiab. Compressor','AdiabaticCompressor.png'), + ('pushButton_16', 'Adiab. Expander', 'AdiabaticExpander.png'), + ]), + ('Columns', [ + ('pushButton_26', 'Distillation Col.','DistillationColumn.png'), + ('pushButton_18', 'Shortcut Col.', 'ShortcutColumn.png'), + ]), + ] + + # ── State storage for toggle ── + self._panel_collapsed = False + self._comp_btn_data = [] # list of (QPushButton, display_text) + self._comp_headers = [] # section header QLabels + + # Pre-build the two button stylesheets so toggle is instant + self._btn_style_expanded = f""" + QPushButton {{ + background: {BTN_BG}; + color: {TEXT}; + font: bold 10pt 'Microsoft JhengHei'; + border: 1px solid {BTN_BORDER}; + border-radius: 4px; + text-align: left; + padding: 0 6px; + }} + QPushButton:hover {{ + background: #e8f0fe; + border-color: {ACCENT}; + color: {ACCENT}; + }} + QPushButton:pressed {{ + background: #d0e3ff; + border-color: {ACCENT}; + }} + """ + self._btn_style_collapsed = f""" + QPushButton {{ + background: {BTN_BG}; + border: 1px solid {BTN_BORDER}; + border-radius: 4px; + text-align: center; + padding: 0; + }} + QPushButton:hover {{ + background: #e8f0fe; + border-color: {ACCENT}; + }} + QPushButton:pressed {{ + background: #d0e3ff; + border-color: {ACCENT}; + }} + """ + + # ── Configure dockWidget ── + self.dockWidget.setFeatures( + QDockWidget.DockWidgetFloatable | + QDockWidget.DockWidgetMovable | + QDockWidget.DockWidgetClosable ) + self.dockWidget.setWindowTitle('Components') + # Width pinned after addDockWidget in __init__ + + # ── content widget ── + content = QWidget() + content.setStyleSheet(f'background: {BG};') + main_layout = QVBoxLayout(content) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setSpacing(0) + + # ── Collapse / Expand toggle button ── + toggle_btn = QPushButton('▶') + toggle_btn.setFixedHeight(24) + toggle_btn.setCursor(Qt.PointingHandCursor) + toggle_btn.setToolTip('Collapse panel') + toggle_btn.setStyleSheet(f""" + QPushButton {{ + background: #f8f8f8; + color: #999999; + font: bold 11pt; + border: none; + border-bottom: 1px solid #e0e0e0; + border-radius: 0; + }} + QPushButton:hover {{ + background: #e8f0fe; + color: {ACCENT}; + }} + QPushButton:pressed {{ + background: #d0e3ff; + }} + """) + toggle_btn.clicked.connect(self._toggle_component_panel) + self._panel_toggle_btn = toggle_btn + main_layout.addWidget(toggle_btn) + + # ── scroll area ── + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) + scroll.setFrameShape(QFrame.NoFrame) + scroll.setStyleSheet(f""" + QScrollArea {{ + background: {BG}; + border: none; + }} + QScrollBar:vertical {{ + background: {BG}; + width: 6px; + margin: 0; + border: none; + }} + QScrollBar::handle:vertical {{ + background: #c8c8c8; + min-height: 30px; + border-radius: 3px; + }} + QScrollBar::handle:vertical:hover {{ + background: {ACCENT_LIGHT}; + }} + QScrollBar::add-line:vertical, + QScrollBar::sub-line:vertical {{ + height: 0; + }} + """) + + # ── scroll contents widget ── + scroll_widget = QWidget() + scroll_widget.setStyleSheet(f'background: {BG};') + scroll_layout = QVBoxLayout(scroll_widget) + scroll_layout.setContentsMargins(4, 4, 4, 4) + scroll_layout.setSpacing(2) + + for section_name, buttons in sections: + header = QLabel(section_name.upper()) + header.setFixedHeight(HEADER_HEIGHT) + header.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) + header.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + header.setStyleSheet(f""" + QLabel {{ + color: #666666; + font: bold 8pt 'Segoe UI'; + background: {HEADER_BG}; + border-radius: 3px; + padding: 0 6px; + }} + """) + self._comp_headers.append(header) + scroll_layout.addWidget(header) + + for attr_name, display_text, icon_file in buttons: + btn = QPushButton(f' {display_text}') + btn.setFixedHeight(BTN_HEIGHT) + btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + btn.setCursor(Qt.PointingHandCursor) + + icon_path = os.path.join(icons_base, icon_file) + if os.path.exists(icon_path): + btn.setIcon(QIcon(icon_path)) + btn.setIconSize(QSize(ICON_SIZE, ICON_SIZE)) + + btn.setStyleSheet(self._btn_style_expanded) + + setattr(self, attr_name, btn) + self._comp_btn_data.append((btn, display_text)) + scroll_layout.addWidget(btn) + + scroll_layout.addStretch(1) + scroll.setWidget(scroll_widget) + main_layout.addWidget(scroll) + self.dockWidget.setWidget(content) + + def _toggle_component_panel(self): + """Collapse to icon-only (48px) or expand to full text (240px).""" + COLLAPSED_W = 48 + EXPANDED_W = 240 + + if not self._panel_collapsed: + # ── Collapse ── + for btn, _ in self._comp_btn_data: + btn.setText('') + btn.setStyleSheet(self._btn_style_collapsed) + for h in self._comp_headers: + h.hide() + self._panel_toggle_btn.setText('◀') + self._panel_toggle_btn.setToolTip('Expand panel') + self.dockWidget.setFixedWidth(COLLAPSED_W) + self._panel_collapsed = True + else: + # ── Expand ── + for btn, text in self._comp_btn_data: + btn.setText(f' {text}') + btn.setStyleSheet(self._btn_style_expanded) + for h in self._comp_headers: + h.show() + self._panel_toggle_btn.setText('▶') + self._panel_toggle_btn.setToolTip('Collapse panel') + # Set to target width then unlock so the user can still resize + self.dockWidget.setFixedWidth(EXPANDED_W) + self.dockWidget.setMinimumWidth(240) + self.dockWidget.setMaximumWidth(524287) + self._panel_collapsed = False + + def _apply_initial_layout(self): + # Unlock the dock from its startup fixed width so the user can resize it. + self.dockWidget.setMinimumWidth(240) + self.dockWidget.setMaximumWidth(524287) # Message Browser: ~120px tall - self.resizeDocks( - [self.dockWidget_2], - [120], - Qt.Vertical - ) + self.resizeDocks([self.dockWidget_2], [120], Qt.Vertical) def _style_dock_separators(self): self.setStyleSheet(self.styleSheet() + """ diff --git a/src/main/ui/utils/main.ui b/src/main/ui/utils/main.ui index 879793e..9cd5810 100644 --- a/src/main/ui/utils/main.ui +++ b/src/main/ui/utils/main.ui @@ -25,7 +25,7 @@ - + 0 0 @@ -230,7 +230,7 @@ - 200 + 150 300 @@ -298,7 +298,7 @@ 0 0 - 221 + 165 956