diff --git a/imgui.ini b/imgui.ini index 5760f2f1..4f4f7d46 100644 --- a/imgui.ini +++ b/imgui.ini @@ -24,34 +24,34 @@ Size=832,45 Collapsed=0 [Window][工具栏] -Pos=354,20 -Size=1334,32 +Pos=255,20 +Size=1398,383 Collapsed=0 DockId=0x0000000D,0 [Window][场景树] Pos=0,20 -Size=352,748 +Size=274,1012 Collapsed=0 DockId=0x00000007,0 [Window][属性面板] -Pos=1690,20 -Size=358,748 +Pos=1527,20 +Size=393,1012 Collapsed=0 DockId=0x00000002,0 [Window][控制台] -Pos=1690,20 -Size=358,748 +Pos=276,632 +Size=1249,400 Collapsed=0 -DockId=0x00000002,1 +DockId=0x00000006,1 [Window][脚本管理] Pos=1950,20 Size=610,995 Collapsed=0 -DockId=0x00000002,2 +DockId=0x00000005,2 [Window][中文显示测试] Pos=60,60 @@ -60,7 +60,7 @@ Collapsed=0 [Window][WindowOverViewport_11111111] Pos=0,20 -Size=2048,1084 +Size=1920,1012 Collapsed=0 [Window][测试窗口1] @@ -99,8 +99,8 @@ Size=600,500 Collapsed=0 [Window][资源管理器] -Pos=0,770 -Size=2048,334 +Pos=276,632 +Size=1249,400 Collapsed=0 DockId=0x00000006,0 @@ -153,7 +153,7 @@ Collapsed=0 Pos=1690,20 Size=358,748 Collapsed=0 -DockId=0x00000002,2 +DockId=0x00000005,2 [Window][LUI测试控制面板] Pos=6,10 @@ -204,7 +204,7 @@ Collapsed=0 Pos=1438,20 Size=610,748 Collapsed=0 -DockId=0x00000002,2 +DockId=0x00000005,2 [Window][项目另存为] Pos=794,432 @@ -212,13 +212,13 @@ Size=460,240 Collapsed=0 [Docking][Data] -DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=2048,1084 Split=Y - DockNode ID=0x00000005 Parent=0x08BD597D SizeRef=2560,995 Split=X - DockNode ID=0x00000007 Parent=0x00000005 SizeRef=352,1084 Selected=0xE0015051 - DockNode ID=0x00000008 Parent=0x00000005 SizeRef=2206,1084 Split=X - DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1846,989 Split=Y - DockNode ID=0x0000000D Parent=0x00000001 SizeRef=1318,32 HiddenTabBar=1 Selected=0x43A39006 - DockNode ID=0x0000000E Parent=0x00000001 SizeRef=1318,961 CentralNode=1 - DockNode ID=0x00000002 Parent=0x00000008 SizeRef=358,989 Selected=0x5DB6FF37 - DockNode ID=0x00000006 Parent=0x08BD597D SizeRef=2560,334 Selected=0x3A2E05C3 +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1920,1012 Split=X + DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=1525,1012 Split=X + DockNode ID=0x00000007 Parent=0x00000001 SizeRef=274,1084 Selected=0xE0015051 + DockNode ID=0x00000008 Parent=0x00000001 SizeRef=1249,1084 Split=Y + DockNode ID=0x00000005 Parent=0x00000008 SizeRef=2048,610 Split=Y + DockNode ID=0x0000000D Parent=0x00000005 SizeRef=1318,383 HiddenTabBar=1 Selected=0x43A39006 + DockNode ID=0x0000000E Parent=0x00000005 SizeRef=1318,363 CentralNode=1 Selected=0xE0015051 + DockNode ID=0x00000006 Parent=0x00000008 SizeRef=2048,400 Selected=0x3A2E05C3 + DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=393,1012 Selected=0x5DB6FF37 diff --git a/ui/panels/editor_panels_center.py b/ui/panels/editor_panels_center.py index 270be8c0..40e75b05 100644 --- a/ui/panels/editor_panels_center.py +++ b/ui/panels/editor_panels_center.py @@ -155,6 +155,14 @@ class EditorPanelsCenterMixin: return self.app.set_panel_visible("web", opened) + window_pos = imgui.get_window_pos() + window_size = imgui.get_window_size() + self.app._web_panel_window_rect = ( + float(window_pos.x), + float(window_pos.y), + float(window_size.x), + float(window_size.y), + ) changed, self.app.web_panel_url_input = imgui.input_text( "URL", self.app.web_panel_url_input, 1024 diff --git a/ui/panels/editor_panels_right.py b/ui/panels/editor_panels_right.py index 5db184ba..6a06e0e1 100644 --- a/ui/panels/editor_panels_right.py +++ b/ui/panels/editor_panels_right.py @@ -146,6 +146,14 @@ class EditorPanelsRightMixin( return self.app.showPropertyPanel = opened + window_pos = imgui.get_window_pos() + window_size = imgui.get_window_size() + self.app._property_panel_window_rect = ( + float(window_pos.x), + float(window_pos.y), + float(window_size.x), + float(window_size.y), + ) # --- LUI Component Properties --- # 优先检查 LUI 组件选择 diff --git a/ui/panels/editor_panels_top.py b/ui/panels/editor_panels_top.py index 0e40fb59..0103f702 100644 --- a/ui/panels/editor_panels_top.py +++ b/ui/panels/editor_panels_top.py @@ -3,6 +3,150 @@ from imgui_bundle import imgui, imgui_ctx class EditorPanelsTopMixin: """Auto-split mixin from editor_panels.py.""" + @staticmethod + def _normalize_window_rect(rect): + if not rect or len(rect) != 4: + return None + x, y, w, h = [float(v) for v in rect] + if w <= 0 or h <= 0: + return None + return (x, y, w, h) + + def _get_toolbar_anchor(self): + viewport = imgui.get_main_viewport() + menu_bar_height = imgui.get_frame_height() + viewport_left = float(viewport.pos.x) + viewport_top = float(viewport.pos.y) + float(menu_bar_height) + viewport_right = float(viewport.pos.x + viewport.size.x) + viewport_bottom = float(viewport.pos.y + viewport.size.y) + viewport_width = max(1.0, viewport_right - viewport_left) + viewport_height = max(1.0, viewport_bottom - viewport_top) + edge_margin = 12.0 + panel_gap = 10.0 + top_boundary = viewport_top + + blocker_names = ( + "_scene_tree_window_rect", + "_resource_manager_window_rect", + "_property_panel_window_rect", + "_script_panel_window_rect", + "_console_window_rect", + "_web_panel_window_rect", + ) + blockers = [] + for name in blocker_names: + rect = self._normalize_window_rect(getattr(self.app, name, None)) + if rect: + blockers.append(rect) + + def is_top_docked(rect): + bx, by, bw, bh = rect + touches_left = bx <= viewport_left + 6.0 + touches_right = (bx + bw) >= viewport_right - 6.0 + return ( + by <= viewport_top + 6.0 and + bh <= viewport_height * 0.45 and + ( + bw >= viewport_width * 0.80 or + touches_left or + touches_right + ) + ) + + def is_left_docked(rect, render_top): + bx, by, bw, bh = rect + touches_top_band = by <= render_top + 6.0 + reaches_bottom = (by + bh) >= viewport_bottom - 6.0 + return ( + bx <= viewport_left + 6.0 and + bw <= viewport_width * 0.45 and + bh >= viewport_height * 0.20 and + by <= render_top + 40.0 and + by + bh >= render_top + 40.0 and + ( + touches_top_band or + reaches_bottom or + bh >= viewport_height * 0.60 + ) + ) + + for bx, by, bw, bh in blockers: + if is_top_docked((bx, by, bw, bh)): + top_boundary = max(top_boundary, by + bh) + + left_boundary = viewport_left + probe_y = min(viewport_bottom - edge_margin, top_boundary + 40.0) + + for bx, by, bw, bh in blockers: + if is_left_docked((bx, by, bw, bh), top_boundary): + left_boundary = max(left_boundary, bx + bw) + + anchor_x = max(viewport_left + edge_margin, left_boundary + panel_gap) + anchor_y = max(viewport_top + panel_gap * 0.6, top_boundary + panel_gap * 0.6) + max_x = viewport_right - edge_margin + max_y = viewport_bottom - edge_margin + return min(anchor_x, max_x), min(anchor_y, max_y) + + @staticmethod + def _draw_toolbar_icon_button(texture_id, fallback_label, active=False, tooltip=None, enabled=True, size=(26, 26)): + """Draw a compact icon-first toolbar button for the vertical dock toolbar.""" + if active: + button_color = (0.24, 0.42, 0.72, 1.0) + hovered_color = (0.28, 0.48, 0.82, 1.0) + tint_color = (1.0, 1.0, 1.0, 1.0) + border_color = (0.38, 0.62, 0.95, 1.0) + else: + button_color = (0.30, 0.31, 0.33, 1.0) + hovered_color = (0.38, 0.39, 0.42, 1.0) + tint_color = (0.9, 0.92, 0.96, 1.0) + border_color = (0.20, 0.21, 0.23, 1.0) + + imgui.push_style_color(imgui.Col_.button, button_color) + imgui.push_style_color(imgui.Col_.button_hovered, hovered_color) + imgui.push_style_color(imgui.Col_.button_active, hovered_color) + imgui.push_style_color(imgui.Col_.border, border_color) + imgui.push_style_var(imgui.StyleVar_.frame_rounding, 4.0) + imgui.push_style_var(imgui.StyleVar_.frame_border_size, 1.0) + imgui.push_style_var(imgui.StyleVar_.frame_padding, (3.0, 3.0)) + + if not enabled: + imgui.begin_disabled() + + if texture_id: + clicked = imgui.image_button(texture_id, size, (0, 1), (1, 0), (0, 0, 0, 0), tint_color) + else: + clicked = imgui.button(fallback_label, size) + + if not enabled: + imgui.end_disabled() + + if tooltip and imgui.is_item_hovered(): + imgui.set_tooltip(tooltip) + + imgui.pop_style_var(3) + imgui.pop_style_color(4) + return clicked + + @staticmethod + def _draw_toolbar_separator(): + imgui.dummy((1, 2)) + draw_list = imgui.get_window_draw_list() + cursor_pos = imgui.get_cursor_screen_pos() + window_pos = imgui.get_window_pos() + window_size = imgui.get_window_size() + left_inset = 10.0 + right_inset = 10.0 + line_width = max(18.0, float(window_size.x) - left_inset - right_inset) + start_x = float(window_pos.x) + left_inset + line_y = float(cursor_pos.y) + draw_list.add_line( + (start_x, line_y), + (start_x + line_width, line_y), + imgui.color_convert_float4_to_u32((0.38, 0.39, 0.42, 1.0)), + 1.0, + ) + imgui.dummy((1, 6)) + @staticmethod def _truncate_toolbar_text(text, limit=20): text = text or "" @@ -280,69 +424,112 @@ class EditorPanelsTopMixin: def draw_toolbar(self): """绘制工具栏""" - # 工具栏可以保持无标题栏,但允许移动和调整大小 - flags = self.app.style_manager.get_window_flags("toolbar") - - with self.app.style_manager.begin_styled_window("工具栏", self.app.showToolbar, flags) as (_, opened): + anchor_x, anchor_y = self._get_toolbar_anchor() + imgui.set_next_window_pos((anchor_x, anchor_y), imgui.Cond_.always) + imgui.set_next_window_size_constraints((48.0, 170.0), (64.0, 500.0)) + + flags = ( + imgui.WindowFlags_.no_title_bar | + imgui.WindowFlags_.no_collapse | + imgui.WindowFlags_.no_move | + imgui.WindowFlags_.no_scrollbar | + imgui.WindowFlags_.always_auto_resize | + imgui.WindowFlags_.no_saved_settings | + imgui.WindowFlags_.no_docking + ) + + with imgui_ctx.begin("工具栏", self.app.showToolbar, flags) as (_, opened): if not opened: self.app.showToolbar = False return self.app.showToolbar = opened - style_manager = self.app.style_manager command_manager = getattr(self.app, "command_manager", None) can_undo = command_manager.can_undo() if command_manager else False can_redo = command_manager.can_redo() if command_manager else False selection_name = self._truncate_toolbar_text(self._get_toolbar_selection_name(), 18) - project_name = self._truncate_toolbar_text(self._get_toolbar_project_name(), 18) - tool_name = getattr(self.app.tool_manager, "getCurrentTool", lambda: "选择")() + icons = getattr(self.app, "icons", {}) or {} + button_width = 24.0 - imgui.push_style_var(imgui.StyleVar_.item_spacing, (8.0, 6.0)) - imgui.push_style_var(imgui.StyleVar_.frame_padding, (8.0, 5.0)) + imgui.push_style_var(imgui.StyleVar_.item_spacing, (5.0, 5.0)) + imgui.push_style_var(imgui.StyleVar_.window_padding, (7.0, 8.0)) - tool_buttons = [ - ("Q 选择", "选择", self.app.tool_manager.isSelectionTool(), "选择工具 (Q)"), - ("W 移动", "移动", self.app.tool_manager.isMoveTool(), "移动工具 (W)"), - ("E 旋转", "旋转", self.app.tool_manager.isRotateTool(), "旋转工具 (E)"), - ("R 缩放", "缩放", self.app.tool_manager.isScaleTool(), "缩放工具 (R)"), - ] + def align_item(item_width): + window_width = float(imgui.get_window_size().x) + centered_x = max(0.0, (window_width - float(item_width)) * 0.5) + imgui.set_cursor_pos_x(centered_x) - for index, (label, tool_id, is_active, tooltip) in enumerate(tool_buttons): - if style_manager.draw_toolbar_button(label, active=is_active, size=(74, 28), tooltip=tooltip): - self.app.tool_manager.setCurrentTool(tool_id) - if index != len(tool_buttons) - 1: - imgui.same_line() + align_item(imgui.calc_text_size("工具").x) + imgui.text_disabled("工具") + self._draw_toolbar_separator() - imgui.same_line() - imgui.separator() - imgui.same_line() - - if style_manager.draw_toolbar_button("撤销", size=(56, 28), tooltip="撤销上一步 (Ctrl+Z)", enabled=can_undo): - self.app._on_undo() - imgui.same_line() - if style_manager.draw_toolbar_button("重做", size=(56, 28), tooltip="重做上一步 (Ctrl+Y)", enabled=can_redo): - self.app._on_redo() - imgui.same_line() - if style_manager.draw_toolbar_button( - "聚焦", - size=(56, 28), - tooltip="聚焦当前选择 (F)", - enabled=selection_name != "未选择", + align_item(button_width) + if self._draw_toolbar_icon_button( + icons.get("select"), + "Q", + active=self.app.tool_manager.isSelectionTool(), + tooltip="选择工具 (Q)", ): + self.app.tool_manager.setCurrentTool("选择") + align_item(button_width) + if self._draw_toolbar_icon_button( + icons.get("move"), + "W", + active=self.app.tool_manager.isMoveTool(), + tooltip="移动工具 (W)", + ): + self.app.tool_manager.setCurrentTool("移动") + align_item(button_width) + if self._draw_toolbar_icon_button( + icons.get("rotate"), + "E", + active=self.app.tool_manager.isRotateTool(), + tooltip="旋转工具 (E)", + ): + self.app.tool_manager.setCurrentTool("旋转") + align_item(button_width) + if self._draw_toolbar_icon_button( + icons.get("scale"), + "R", + active=self.app.tool_manager.isScaleTool(), + tooltip="缩放工具 (R)", + ): + self.app.tool_manager.setCurrentTool("缩放") + + self._draw_toolbar_separator() + + align_item(button_width) + if self._draw_toolbar_icon_button(None, "U", tooltip="撤销上一步 (Ctrl+Z)", enabled=can_undo): + self.app._on_undo() + align_item(button_width) + if self._draw_toolbar_icon_button(None, "Y", tooltip="重做上一步 (Ctrl+Y)", enabled=can_redo): + self.app._on_redo() + align_item(button_width) + if self._draw_toolbar_icon_button(None, "F", tooltip="聚焦当前选择 (F)", enabled=selection_name != "未选择"): self.app.onFocusKeyPressed() - imgui.same_line() - imgui.separator() - imgui.same_line() - style_manager.draw_stat_chip(f"项目 {project_name}", tint=(0.12, 0.14, 0.18, 1.0)) - imgui.same_line() - style_manager.draw_stat_chip(f"工具 {tool_name}", tint=(0.16, 0.19, 0.24, 1.0)) - imgui.same_line() - style_manager.draw_stat_chip(f"选择 {selection_name}", tint=(0.18, 0.24, 0.32, 1.0)) - imgui.same_line() - style_manager.draw_stat_chip( - f"历史 {command_manager.get_undo_count() if command_manager else 0}/{command_manager.get_redo_count() if command_manager else 0}", - tint=(0.16, 0.18, 0.2, 1.0), + self._draw_toolbar_separator() + + current_label = "当前" + align_item(imgui.calc_text_size(current_label).x) + imgui.text_disabled("当前") + align_item(imgui.calc_text_size(selection_name).x) + imgui.text(selection_name) + + history_text = ( + f"历史 {command_manager.get_undo_count() if command_manager else 0}/" + f"{command_manager.get_redo_count() if command_manager else 0}" + ) + align_item(imgui.calc_text_size(history_text).x) + imgui.text_disabled(history_text) + + window_pos = imgui.get_window_pos() + window_size = imgui.get_window_size() + self.app._toolbar_window_rect = ( + float(window_pos.x), + float(window_pos.y), + float(window_size.x), + float(window_size.y), ) imgui.pop_style_var(2) diff --git a/ui/panels/script_panels.py b/ui/panels/script_panels.py index 68710ad1..5929e965 100644 --- a/ui/panels/script_panels.py +++ b/ui/panels/script_panels.py @@ -28,6 +28,14 @@ class ScriptPanels: return self.app.showConsole = opened + window_pos = imgui.get_window_pos() + window_size = imgui.get_window_size() + self.app._console_window_rect = ( + float(window_pos.x), + float(window_pos.y), + float(window_size.x), + float(window_size.y), + ) imgui.text("控制台输出") imgui.separator() @@ -114,6 +122,14 @@ class ScriptPanels: return self.app.showScriptPanel = opened + window_pos = imgui.get_window_pos() + window_size = imgui.get_window_size() + self.app._script_panel_window_rect = ( + float(window_pos.x), + float(window_pos.y), + float(window_size.x), + float(window_size.y), + ) # 1. 脚本系统状态组 self._draw_script_status_group()