工具栏优化

This commit is contained in:
ayuan9957 2026-03-18 08:59:03 +08:00
parent c4a507c6ac
commit 6524f8306b
5 changed files with 289 additions and 70 deletions

View File

@ -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

View File

@ -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

View File

@ -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 组件选择

View File

@ -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)

View File

@ -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()