From 4cc1027cc8ea1f3c8d0bb46fbcc8c9b9053b8434 Mon Sep 17 00:00:00 2001 From: ykcheungab Date: Mon, 29 Jun 2026 10:47:46 +0800 Subject: [PATCH] fix open 3d cannot work in linux --- examples/gui/dashboard.py | 110 ++++++++++++++++++++++++++++++++++---- examples/gui/layout.py | 12 ++--- 2 files changed, 106 insertions(+), 16 deletions(-) diff --git a/examples/gui/dashboard.py b/examples/gui/dashboard.py index e8e94f4..5b79021 100644 --- a/examples/gui/dashboard.py +++ b/examples/gui/dashboard.py @@ -147,7 +147,7 @@ class FingerDashboardWindow(QMainWindow): root_layout.addWidget(h_splitter) - self.resize(layout.window_width, layout.window_height) + self.resize(*self._target_window_size()) QTimer.singleShot(0, self._apply_panel_layout) def _set_log_panel_visible(self, visible: bool) -> None: @@ -157,7 +157,8 @@ class FingerDashboardWindow(QMainWindow): def _apply_panel_layout(self) -> None: setup = self.layout.panel_setup - column_height = self.layout.charts_column_height_px() + scale = self._layout_scale_factor() + column_height = self._scaled_top_row_height(scale) charts_slot = self.layout.top_slot("charts") log_slot = setup.log_panel @@ -165,10 +166,18 @@ class FingerDashboardWindow(QMainWindow): if not slot.enabled: continue if slot.id in ("mesh", "arrows"): - self._panel_widgets[slot.id].set_fixed_size(slot.width_px, column_height) + self._panel_widgets[slot.id].set_fixed_size( + self._scaled_px(slot.width_px, scale), + column_height, + ) elif slot.id == "settings": - settings_height = slot.height_px if slot.height_px > 0 else column_height - self.settings_panel.set_panel_size(slot.width_px, settings_height) + settings_height = ( + self._scaled_px(slot.height_px, scale) if slot.height_px > 0 else column_height + ) + self.settings_panel.set_panel_size( + self._scaled_px(slot.width_px, scale), + settings_height, + ) if ( self._log_panel_visible @@ -176,15 +185,96 @@ class FingerDashboardWindow(QMainWindow): and log_slot.height_px > 0 ): self.log_widget.show() - self.log_widget.setFixedHeight(log_slot.height_px) - self.force_charts.set_panel_size(charts_slot.width_px, charts_slot.height_px) - self.charts_column.setSizes([charts_slot.height_px, log_slot.height_px]) + log_height = self._scaled_px(log_slot.height_px, scale) + charts_height = self._scaled_px(charts_slot.height_px, scale) + self.log_widget.setFixedHeight(log_height) + self.force_charts.set_panel_size( + self._scaled_px(charts_slot.width_px, scale), + charts_height, + ) + self.charts_column.setSizes([charts_height, log_height]) else: self.log_widget.hide() - self.force_charts.set_panel_size(charts_slot.width_px, column_height) + self.force_charts.set_panel_size( + self._scaled_px(charts_slot.width_px, scale), + column_height, + ) self.charts_column.setSizes([column_height, 0]) - self.h_splitter.setSizes(list(top_row_splitter_sizes(self.layout))) + self.h_splitter.setSizes( + [self._scaled_px(slot.width_px, scale) for slot in setup.top_row.slots if slot.enabled] + ) + + def _target_window_size(self) -> tuple[int, int]: + """Match the top-level window to the fixed panel layout. + + The packaged Windows build can use different style metrics than a dev run, + so sizing only from hard-coded window dimensions may stretch or compress the + fixed-width panels. Derive the initial size from the actual panel layout and + current splitter handle widths instead. + """ + layout = self.layout + enabled_slots = [slot for slot in layout.panel_setup.top_row.slots if slot.enabled] + margins = self.centralWidget().layout().contentsMargins() + + width = sum(slot.width_px for slot in enabled_slots) + width += max(len(enabled_slots) - 1, 0) * self.h_splitter.handleWidth() + width += margins.left() + margins.right() + + height = layout.charts_column_height_px() + if ( + self._log_panel_visible + and layout.panel_setup.log_panel.enabled + and layout.panel_setup.log_panel.height_px > 0 + ): + height += self.charts_column.handleWidth() + height += margins.top() + margins.bottom() + + return max(layout.window_width, width), max(layout.window_height, height) + + def _layout_scale_factor(self) -> float: + """Uniformly scale the dashboard to fit the available content area. + + Only scale up when the user has explicitly maximized/fullscreened the + window. Keeping normal windowed mode at scale 1 avoids a feedback loop + where larger fixed-size child widgets increase the top-level size hint, + which can make packaged Windows builds keep growing after launch. + """ + if not (self.isMaximized() or self.isFullScreen()): + return 1.0 + + central = self.centralWidget() + if central is None: + return 1.0 + root_layout = central.layout() + if root_layout is None: + return 1.0 + + margins = root_layout.contentsMargins() + available_width = max(1, central.width() - margins.left() - margins.right()) + available_height = max(1, central.height() - margins.top() - margins.bottom()) + + enabled_slots = [slot for slot in self.layout.panel_setup.top_row.slots if slot.enabled] + base_width = sum(slot.width_px for slot in enabled_slots) + base_width += max(len(enabled_slots) - 1, 0) * self.h_splitter.handleWidth() + + base_height = self.layout.charts_column_height_px() + if ( + self._log_panel_visible + and self.layout.panel_setup.log_panel.enabled + and self.layout.panel_setup.log_panel.height_px > 0 + ): + base_height += self.charts_column.handleWidth() + if base_width <= 0 or base_height <= 0: + return 1.0 + return min(available_width / base_width, available_height / base_height) + + @staticmethod + def _scaled_px(value: int, scale: float) -> int: + return max(int(round(value * scale)), 64) + + def _scaled_top_row_height(self, scale: float) -> int: + return self._scaled_px(self.layout.charts_column_height_px(), scale) def resizeEvent(self, event): super().resizeEvent(event) diff --git a/examples/gui/layout.py b/examples/gui/layout.py index 7218a57..e41eb35 100644 --- a/examples/gui/layout.py +++ b/examples/gui/layout.py @@ -84,9 +84,9 @@ class PanelSetup: # --- Top strip: mesh | arrows? | charts | settings (edit order and sizes here) --- TOP_ROW = PanelRow( slots=( - PanelSlot("mesh", "3D mesh", width_px=600, height_px=600), - PanelSlot("arrows", "UV Unrolled", width_px=500, height_px=500, enabled=True), - PanelSlot("charts", "Force charts", width_px=400, height_px=500), + PanelSlot("mesh", "3D mesh", width_px=400, height_px=400), + PanelSlot("arrows", "UV Unrolled", width_px=400, height_px=400, enabled=True), + PanelSlot("charts", "Force charts", width_px=300, height_px=400), PanelSlot("settings", "Settings", width_px=200, height_px=0), ), ) @@ -223,8 +223,8 @@ class DashboardLayout: panel_setup: PanelSetup = PANEL_SETUP window_title: str = "Orisys Finger Dashboard" - window_width: int = 1600 - window_height: int = 620 + window_width: int = 1300 + window_height: int = 520 root_margin_px: int = 6 root_spacing_px: int = 6 @@ -242,7 +242,7 @@ class DashboardLayout: # UV arrow panel: min flow magnitude to draw an arrow (display only; not dd02-ov.json contact.flow_threshold) arrow_flow_threshold: float = 1.0 # "unrolled" = sensor texture; "pure_color" = solid canvas (tune colors via arrow_canvas_colors) - arrow_background: ArrowBackground = "unrolled" + arrow_background: ArrowBackground = "pure_color" arrow_canvas_colors: ArrowCanvasColors = ARROW_CANVAS_COLORS mesh_lighting: MeshLighting = MESH_LIGHTING