拖动导入模型帧率异常修复,添加web视图
This commit is contained in:
parent
fe373c0e5d
commit
79b9aa44dc
@ -313,10 +313,15 @@ class ModelDragDropService:
|
|||||||
if not path.exists() or not self._is_supported_model(path):
|
if not path.exists() or not self._is_supported_model(path):
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
model_node = self.app._import_model_for_runtime(str(path), prefer_scene_manager=True)
|
model_node = self.app._import_model_with_menu_logic(
|
||||||
|
str(path),
|
||||||
|
select_model=False,
|
||||||
|
set_origin=True,
|
||||||
|
show_info_message=False,
|
||||||
|
show_success_message=False,
|
||||||
|
)
|
||||||
if not model_node:
|
if not model_node:
|
||||||
continue
|
continue
|
||||||
self._postprocess_imported_model(model_node)
|
|
||||||
imported_models.append(model_node)
|
imported_models.append(model_node)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[外部拖拽] 导入模型失败 {path}: {e}")
|
print(f"[外部拖拽] 导入模型失败 {path}: {e}")
|
||||||
@ -377,7 +382,13 @@ class ModelDragDropService:
|
|||||||
if not self._is_supported_model(path):
|
if not self._is_supported_model(path):
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
model_node = self.app._import_model_for_runtime(str(path), prefer_scene_manager=True)
|
model_node = self.app._import_model_with_menu_logic(
|
||||||
|
str(path),
|
||||||
|
select_model=False,
|
||||||
|
set_origin=True,
|
||||||
|
show_info_message=False,
|
||||||
|
show_success_message=False,
|
||||||
|
)
|
||||||
if not model_node:
|
if not model_node:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -387,7 +398,6 @@ class ModelDragDropService:
|
|||||||
except Exception:
|
except Exception:
|
||||||
model_node.reparentTo(target_parent)
|
model_node.reparentTo(target_parent)
|
||||||
|
|
||||||
self._postprocess_imported_model(model_node)
|
|
||||||
imported_models.append(model_node)
|
imported_models.append(model_node)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[拖拽导入] 导入失败 {path}: {e}")
|
print(f"[拖拽导入] 导入失败 {path}: {e}")
|
||||||
@ -446,16 +456,10 @@ class ModelDragDropService:
|
|||||||
self.app.add_error_message(f"不支持的文件格式: {path.suffix.lower()}")
|
self.app.add_error_message(f"不支持的文件格式: {path.suffix.lower()}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
model_node = self.app._import_model_for_runtime(str(path), prefer_scene_manager=True)
|
model_node = self.app._import_model_with_menu_logic(str(path))
|
||||||
if not model_node:
|
if not model_node:
|
||||||
self.app.add_error_message(f"导入模型失败: {path}")
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self._postprocess_imported_model(model_node, set_origin=True)
|
|
||||||
if getattr(self.app, "selection", None):
|
|
||||||
self.app.selection.updateSelection(model_node)
|
|
||||||
|
|
||||||
self.app.add_success_message(f"成功导入模型: {path.name}")
|
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.app.add_error_message(f"导入模型时发生错误: {e}")
|
self.app.add_error_message(f"导入模型时发生错误: {e}")
|
||||||
|
|||||||
43
imgui.ini
43
imgui.ini
@ -24,26 +24,26 @@ Size=832,45
|
|||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][工具栏]
|
[Window][工具栏]
|
||||||
Pos=327,20
|
Pos=241,20
|
||||||
Size=1862,32
|
Size=908,74
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000000D,0
|
DockId=0x0000000D,0
|
||||||
|
|
||||||
[Window][场景树]
|
[Window][场景树]
|
||||||
Pos=0,20
|
Pos=0,20
|
||||||
Size=325,854
|
Size=239,468
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000007,0
|
DockId=0x00000007,0
|
||||||
|
|
||||||
[Window][属性面板]
|
[Window][属性面板]
|
||||||
Pos=2191,20
|
Pos=1151,20
|
||||||
Size=369,1331
|
Size=229,730
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000003,0
|
DockId=0x00000003,0
|
||||||
|
|
||||||
[Window][控制台]
|
[Window][控制台]
|
||||||
Pos=0,876
|
Pos=0,490
|
||||||
Size=325,475
|
Size=239,260
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000008,0
|
DockId=0x00000008,0
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ Collapsed=0
|
|||||||
|
|
||||||
[Window][WindowOverViewport_11111111]
|
[Window][WindowOverViewport_11111111]
|
||||||
Pos=0,20
|
Pos=0,20
|
||||||
Size=2560,1331
|
Size=1380,730
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][测试窗口1]
|
[Window][测试窗口1]
|
||||||
@ -99,8 +99,8 @@ Size=600,500
|
|||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][资源管理器]
|
[Window][资源管理器]
|
||||||
Pos=327,1013
|
Pos=241,464
|
||||||
Size=1862,338
|
Size=908,286
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000006,0
|
DockId=0x00000006,0
|
||||||
|
|
||||||
@ -200,18 +200,23 @@ Pos=660,304
|
|||||||
Size=600,400
|
Size=600,400
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Web面板]
|
||||||
|
Pos=373,98
|
||||||
|
Size=942,580
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
[Docking][Data]
|
[Docking][Data]
|
||||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=2560,1331 Split=X
|
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,20 Size=1380,730 Split=X
|
||||||
DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=1549,989 Split=X
|
DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=1689,989 Split=X
|
||||||
DockNode ID=0x00000009 Parent=0x00000001 SizeRef=325,989 Split=Y Selected=0xE0015051
|
DockNode ID=0x00000009 Parent=0x00000001 SizeRef=239,989 Split=Y Selected=0xE0015051
|
||||||
DockNode ID=0x00000007 Parent=0x00000009 SizeRef=271,634 Selected=0xE0015051
|
DockNode ID=0x00000007 Parent=0x00000009 SizeRef=271,634 Selected=0xE0015051
|
||||||
DockNode ID=0x00000008 Parent=0x00000009 SizeRef=271,353 Selected=0x5428E753
|
DockNode ID=0x00000008 Parent=0x00000009 SizeRef=271,353 Selected=0x5428E753
|
||||||
DockNode ID=0x0000000A Parent=0x00000001 SizeRef=1862,989 Split=Y
|
DockNode ID=0x0000000A Parent=0x00000001 SizeRef=1448,989 Split=Y
|
||||||
DockNode ID=0x0000000D Parent=0x0000000A SizeRef=1318,32 HiddenTabBar=1 Selected=0x43A39006
|
DockNode ID=0x0000000D Parent=0x0000000A SizeRef=1318,74 HiddenTabBar=1 Selected=0x43A39006
|
||||||
DockNode ID=0x0000000E Parent=0x0000000A SizeRef=1318,955 Split=Y
|
DockNode ID=0x0000000E Parent=0x0000000A SizeRef=1318,913 Split=Y
|
||||||
DockNode ID=0x00000005 Parent=0x0000000E SizeRef=1341,957 CentralNode=1
|
DockNode ID=0x00000005 Parent=0x0000000E SizeRef=1341,625 CentralNode=1
|
||||||
DockNode ID=0x00000006 Parent=0x0000000E SizeRef=1341,338 Selected=0x3A2E05C3
|
DockNode ID=0x00000006 Parent=0x0000000E SizeRef=1341,286 Selected=0x3A2E05C3
|
||||||
DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=369,989 Split=Y Selected=0x3188AB8D
|
DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=229,989 Split=Y Selected=0x3188AB8D
|
||||||
DockNode ID=0x00000003 Parent=0x00000002 SizeRef=351,390 Selected=0x5DB6FF37
|
DockNode ID=0x00000003 Parent=0x00000002 SizeRef=351,390 Selected=0x5DB6FF37
|
||||||
DockNode ID=0x00000004 Parent=0x00000002 SizeRef=351,597 Selected=0x1EB923B7
|
DockNode ID=0x00000004 Parent=0x00000002 SizeRef=351,597 Selected=0x1EB923B7
|
||||||
|
|
||||||
|
|||||||
13
main.py
13
main.py
@ -262,6 +262,8 @@ class MyWorld(CoreWorld):
|
|||||||
self.showScriptPanel = not self.use_ssbo_mouse_picking
|
self.showScriptPanel = not self.use_ssbo_mouse_picking
|
||||||
self.showToolbar = True
|
self.showToolbar = True
|
||||||
self.showResourceManager = True
|
self.showResourceManager = True
|
||||||
|
self.showWebPanel = False
|
||||||
|
self.webPanelUrl = "https://www.baidu.com"
|
||||||
|
|
||||||
# 脚本系统状态变量
|
# 脚本系统状态变量
|
||||||
self.hotReloadEnabled = True
|
self.hotReloadEnabled = True
|
||||||
@ -770,6 +772,10 @@ class MyWorld(CoreWorld):
|
|||||||
if self.showPropertyPanel:
|
if self.showPropertyPanel:
|
||||||
self._draw_property_panel()
|
self._draw_property_panel()
|
||||||
|
|
||||||
|
# Web面板
|
||||||
|
if self.showWebPanel:
|
||||||
|
self._draw_web_panel()
|
||||||
|
|
||||||
# 脚本面板
|
# 脚本面板
|
||||||
if self.showScriptPanel:
|
if self.showScriptPanel:
|
||||||
self._draw_script_panel()
|
self._draw_script_panel()
|
||||||
@ -876,6 +882,9 @@ class MyWorld(CoreWorld):
|
|||||||
def _draw_property_panel(self, *args, **kwargs):
|
def _draw_property_panel(self, *args, **kwargs):
|
||||||
return self.editor_panels._draw_property_panel(*args, **kwargs)
|
return self.editor_panels._draw_property_panel(*args, **kwargs)
|
||||||
|
|
||||||
|
def _draw_web_panel(self, *args, **kwargs):
|
||||||
|
return self.editor_panels._draw_web_panel(*args, **kwargs)
|
||||||
|
|
||||||
def _draw_node_properties(self, *args, **kwargs):
|
def _draw_node_properties(self, *args, **kwargs):
|
||||||
return self.editor_panels._draw_node_properties(*args, **kwargs)
|
return self.editor_panels._draw_node_properties(*args, **kwargs)
|
||||||
|
|
||||||
@ -1306,6 +1315,10 @@ class MyWorld(CoreWorld):
|
|||||||
|
|
||||||
def _import_model(self, *args, **kwargs):
|
def _import_model(self, *args, **kwargs):
|
||||||
return self.app_actions._import_model(*args, **kwargs)
|
return self.app_actions._import_model(*args, **kwargs)
|
||||||
|
|
||||||
|
def _import_model_with_menu_logic(self, *args, **kwargs):
|
||||||
|
return self.app_actions._import_model_with_menu_logic(*args, **kwargs)
|
||||||
|
|
||||||
def _draw_new_project_dialog(self, *args, **kwargs):
|
def _draw_new_project_dialog(self, *args, **kwargs):
|
||||||
return self.dialog_panels._draw_new_project_dialog(*args, **kwargs)
|
return self.dialog_panels._draw_new_project_dialog(*args, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@ -1094,6 +1094,82 @@ class AppActions:
|
|||||||
return self.scene_manager.importModel(file_path)
|
return self.scene_manager.importModel(file_path)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _import_model_with_menu_logic(
|
||||||
|
self,
|
||||||
|
file_path,
|
||||||
|
select_model=True,
|
||||||
|
set_origin=True,
|
||||||
|
show_info_message=True,
|
||||||
|
show_success_message=True,
|
||||||
|
):
|
||||||
|
"""统一的单文件导入入口,保持与菜单导入一致的处理流程。"""
|
||||||
|
try:
|
||||||
|
if not file_path:
|
||||||
|
self.add_error_message("请选择要导入的文件")
|
||||||
|
return None
|
||||||
|
|
||||||
|
normalized_path = os.fspath(file_path)
|
||||||
|
if not os.path.exists(normalized_path):
|
||||||
|
self.add_error_message(f"文件不存在: {normalized_path}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
file_ext = os.path.splitext(normalized_path)[1].lower()
|
||||||
|
if file_ext not in self.supported_formats:
|
||||||
|
self.add_error_message(f"不支持的文件格式: {file_ext}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not hasattr(self, 'scene_manager') or not self.scene_manager:
|
||||||
|
self.add_error_message("场景管理器未初始化")
|
||||||
|
return None
|
||||||
|
|
||||||
|
file_name = os.path.basename(normalized_path)
|
||||||
|
if show_info_message:
|
||||||
|
self.add_info_message(f"正在导入模型: {file_name}")
|
||||||
|
|
||||||
|
model_node = self._import_model_for_runtime(normalized_path)
|
||||||
|
if not model_node:
|
||||||
|
self.add_error_message("模型导入失败")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if hasattr(self.scene_manager, 'processMaterials'):
|
||||||
|
self.scene_manager.processMaterials(model_node)
|
||||||
|
if show_info_message:
|
||||||
|
self.add_info_message("已应用默认材质")
|
||||||
|
|
||||||
|
try:
|
||||||
|
model_node.clearMaterial()
|
||||||
|
model_node.clearTexture()
|
||||||
|
|
||||||
|
if hasattr(self.scene_manager, 'processMaterials'):
|
||||||
|
self.scene_manager.processMaterials(model_node)
|
||||||
|
|
||||||
|
try:
|
||||||
|
color = model_node.getColor()
|
||||||
|
if color and len(color) >= 4 and color == (1, 1, 1, 1):
|
||||||
|
model_node.setColor(0.8, 0.8, 0.8, 1.0)
|
||||||
|
elif not color:
|
||||||
|
model_node.setColor(0.8, 0.8, 0.8, 1.0)
|
||||||
|
except Exception:
|
||||||
|
model_node.setColor(0.8, 0.8, 0.8, 1.0)
|
||||||
|
except Exception as e:
|
||||||
|
self.add_warning_message(f"材质处理警告: {e}")
|
||||||
|
|
||||||
|
if set_origin:
|
||||||
|
model_node.setPos(0, 0, 0)
|
||||||
|
|
||||||
|
if hasattr(self.scene_manager, 'models'):
|
||||||
|
self.scene_manager.models.append(model_node)
|
||||||
|
|
||||||
|
if select_model and hasattr(self, 'selection') and self.selection:
|
||||||
|
self.selection.updateSelection(model_node)
|
||||||
|
|
||||||
|
if show_success_message:
|
||||||
|
self.add_success_message(f"模型导入成功: {file_name}")
|
||||||
|
return model_node
|
||||||
|
except Exception as e:
|
||||||
|
self.add_error_message(f"导入模型失败: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def _on_import_model(self):
|
def _on_import_model(self):
|
||||||
"""处理导入模型菜单项"""
|
"""处理导入模型菜单项"""
|
||||||
self.add_info_message("打开导入模型对话框")
|
self.add_info_message("打开导入模型对话框")
|
||||||
@ -1102,77 +1178,6 @@ class AppActions:
|
|||||||
|
|
||||||
def _import_model(self):
|
def _import_model(self):
|
||||||
"""导入模型的具体实现"""
|
"""导入模型的具体实现"""
|
||||||
try:
|
model_node = self._import_model_with_menu_logic(self.import_file_path)
|
||||||
if not self.import_file_path:
|
|
||||||
self.add_error_message("请选择要导入的文件")
|
|
||||||
return
|
|
||||||
|
|
||||||
if not os.path.exists(self.import_file_path):
|
|
||||||
self.add_error_message(f"文件不存在: {self.import_file_path}")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 检查文件格式
|
|
||||||
file_ext = os.path.splitext(self.import_file_path)[1].lower()
|
|
||||||
if file_ext not in self.supported_formats:
|
|
||||||
self.add_error_message(f"不支持的文件格式: {file_ext}")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 调用场景管理器导入模型
|
|
||||||
if hasattr(self, 'scene_manager') and self.scene_manager:
|
|
||||||
self.add_info_message(f"正在导入模型: {os.path.basename(self.import_file_path)}")
|
|
||||||
|
|
||||||
# 导入模型
|
|
||||||
model_node = self._import_model_for_runtime(self.import_file_path)
|
|
||||||
|
|
||||||
if model_node:
|
|
||||||
# 添加材质处理确保颜色正常
|
|
||||||
if hasattr(self.scene_manager, 'processMaterials'):
|
|
||||||
self.scene_manager.processMaterials(model_node)
|
|
||||||
self.add_info_message("已应用默认材质")
|
|
||||||
|
|
||||||
# 额外的材质处理,确保颜色正确显示
|
|
||||||
try:
|
|
||||||
# 强制刷新模型显示
|
|
||||||
model_node.clearMaterial()
|
|
||||||
model_node.clearTexture()
|
|
||||||
|
|
||||||
# 重新应用材质
|
|
||||||
if hasattr(self.scene_manager, 'processMaterials'):
|
|
||||||
self.scene_manager.processMaterials(model_node)
|
|
||||||
|
|
||||||
# 设置默认的基础颜色(如果模型没有颜色)
|
|
||||||
try:
|
|
||||||
color = model_node.getColor()
|
|
||||||
if color and len(color) >= 4 and color == (1, 1, 1, 1): # 默认白色
|
|
||||||
model_node.setColor(0.8, 0.8, 0.8, 1.0) # 设置为中性灰
|
|
||||||
elif not color: # 如果没有颜色
|
|
||||||
model_node.setColor(0.8, 0.8, 0.8, 1.0) # 设置为中性灰
|
|
||||||
except:
|
|
||||||
# 如果getColor失败,直接设置默认颜色
|
|
||||||
model_node.setColor(0.8, 0.8, 0.8, 1.0) # 设置为中性灰
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.add_warning_message(f"材质处理警告: {e}")
|
|
||||||
|
|
||||||
# 设置模型位置
|
|
||||||
model_node.setPos(0, 0, 0)
|
|
||||||
|
|
||||||
# 添加到场景管理器的模型列表
|
|
||||||
if hasattr(self.scene_manager, 'models'):
|
|
||||||
self.scene_manager.models.append(model_node)
|
|
||||||
|
|
||||||
# 选中新导入的模型
|
|
||||||
if hasattr(self, 'selection') and self.selection:
|
|
||||||
self.selection.updateSelection(model_node)
|
|
||||||
|
|
||||||
self.add_success_message(f"模型导入成功: {os.path.basename(self.import_file_path)}")
|
|
||||||
else:
|
|
||||||
self.add_error_message("模型导入失败")
|
|
||||||
else:
|
|
||||||
self.add_error_message("场景管理器未初始化")
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.add_error_message(f"导入模型失败: {e}")
|
|
||||||
|
|
||||||
# 清空导入路径
|
|
||||||
self.import_file_path = ""
|
self.import_file_path = ""
|
||||||
|
return model_node
|
||||||
|
|||||||
@ -204,12 +204,14 @@ class CreateActions:
|
|||||||
def _on_create_web_panel(self):
|
def _on_create_web_panel(self):
|
||||||
"""创建Web面板"""
|
"""创建Web面板"""
|
||||||
try:
|
try:
|
||||||
result = self.createWebPanel()
|
result = self.editor_panels._on_create_web_panel()
|
||||||
if result:
|
if result:
|
||||||
self.add_success_message("Web面板创建成功")
|
self.add_success_message("Web面板创建成功")
|
||||||
else:
|
else:
|
||||||
self.add_error_message("Web面板创建失败")
|
self.add_error_message("Web面板创建失败")
|
||||||
|
return result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.add_error_message(f"创建Web面板失败: {str(e)}")
|
self.add_error_message(f"创建Web面板失败: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
# ==================== 3D对象和GUI创建方法 ====================
|
# ==================== 3D对象和GUI创建方法 ====================
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from imgui_bundle import imgui, imgui_ctx
|
from imgui_bundle import imgui, imgui_ctx
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from panda3d.core import PNMImage, StringStream, Texture
|
||||||
|
|
||||||
|
|
||||||
class EditorPanels:
|
class EditorPanels:
|
||||||
@ -19,6 +20,117 @@ class EditorPanels:
|
|||||||
else:
|
else:
|
||||||
setattr(self.app, name, value)
|
setattr(self.app, name, value)
|
||||||
|
|
||||||
|
def _on_create_web_panel(self):
|
||||||
|
"""创建或激活 ImGui Web 面板。"""
|
||||||
|
self._ensure_web_panel_state()
|
||||||
|
self.app.showWebPanel = True
|
||||||
|
|
||||||
|
webview = getattr(self.app, "_imgui_webview", None)
|
||||||
|
if webview and getattr(webview, "_running", False):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return self._start_imgui_webview(self.app.web_panel_url_input)
|
||||||
|
|
||||||
|
def _ensure_web_panel_state(self):
|
||||||
|
if not hasattr(self.app, "web_panel_url_input") or not self.app.web_panel_url_input:
|
||||||
|
self.app.web_panel_url_input = "https://www.example.com"
|
||||||
|
if not hasattr(self.app, "_imgui_webview"):
|
||||||
|
self.app._imgui_webview = None
|
||||||
|
if not hasattr(self.app, "_imgui_webview_texture"):
|
||||||
|
self.app._imgui_webview_texture = None
|
||||||
|
if not hasattr(self.app, "_imgui_webview_tex_id"):
|
||||||
|
self.app._imgui_webview_tex_id = None
|
||||||
|
|
||||||
|
def _start_imgui_webview(self, url):
|
||||||
|
self._ensure_web_panel_state()
|
||||||
|
self._stop_imgui_webview()
|
||||||
|
try:
|
||||||
|
target_url = (url or "").strip()
|
||||||
|
if not target_url:
|
||||||
|
target_url = "https://www.example.com"
|
||||||
|
if not target_url.startswith(("http://", "https://", "file://")):
|
||||||
|
target_url = "https://" + target_url
|
||||||
|
|
||||||
|
from core.imgui_webview import ImGuiWebView
|
||||||
|
webview = ImGuiWebView(width=1280, height=720)
|
||||||
|
webview.start(target_url)
|
||||||
|
self.app._imgui_webview = webview
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
self.app.add_error_message(f"启动Web视图失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _stop_imgui_webview(self):
|
||||||
|
webview = getattr(self.app, "_imgui_webview", None)
|
||||||
|
if webview:
|
||||||
|
try:
|
||||||
|
webview.stop()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self.app._imgui_webview = None
|
||||||
|
|
||||||
|
tex_id = getattr(self.app, "_imgui_webview_tex_id", None)
|
||||||
|
if tex_id:
|
||||||
|
try:
|
||||||
|
self.app.imgui.removeTexture(tex_id)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self.app._imgui_webview_tex_id = None
|
||||||
|
self.app._imgui_webview_texture = None
|
||||||
|
|
||||||
|
def _navigate_web_panel(self):
|
||||||
|
self._ensure_web_panel_state()
|
||||||
|
url = (self.app.web_panel_url_input or "").strip()
|
||||||
|
if not url:
|
||||||
|
return
|
||||||
|
|
||||||
|
webview = getattr(self.app, "_imgui_webview", None)
|
||||||
|
if not webview or not getattr(webview, "_running", False):
|
||||||
|
self._start_imgui_webview(url)
|
||||||
|
return
|
||||||
|
|
||||||
|
webview.navigate(url)
|
||||||
|
|
||||||
|
def _update_web_panel_texture(self):
|
||||||
|
webview = getattr(self.app, "_imgui_webview", None)
|
||||||
|
if not webview:
|
||||||
|
return
|
||||||
|
if not webview.tex_dirty:
|
||||||
|
return
|
||||||
|
|
||||||
|
jpeg_bytes = webview.get_screenshot_bytes()
|
||||||
|
if not jpeg_bytes:
|
||||||
|
return
|
||||||
|
|
||||||
|
pnm = PNMImage()
|
||||||
|
if not pnm.read(StringStream(jpeg_bytes), "imgui_webview.png"):
|
||||||
|
webview.tex_dirty = False
|
||||||
|
return
|
||||||
|
# p3dimgui 纹理坐标系与网页截图存在Y轴方向差异,先在像素层修正
|
||||||
|
pnm.flip(False, True, False)
|
||||||
|
|
||||||
|
# 某些后端在“已注册纹理原位更新”时存在稳定性问题。
|
||||||
|
# 改为每次创建新纹理并替换旧纹理ID,避免原位更新导致崩溃。
|
||||||
|
texture = Texture("imgui_web_panel_texture")
|
||||||
|
texture.load(pnm)
|
||||||
|
new_tex_id = self.app.imgui.loadTexture(texture)
|
||||||
|
|
||||||
|
old_tex_id = getattr(self.app, "_imgui_webview_tex_id", None)
|
||||||
|
if old_tex_id:
|
||||||
|
try:
|
||||||
|
self.app.imgui.removeTexture(old_tex_id)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.app._imgui_webview_texture = texture
|
||||||
|
self.app._imgui_webview_tex_id = new_tex_id
|
||||||
|
|
||||||
|
webview.tex_dirty = False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _clamp01(value):
|
||||||
|
return 0.0 if value < 0.0 else 1.0 if value > 1.0 else value
|
||||||
|
|
||||||
def draw_menu_bar(self):
|
def draw_menu_bar(self):
|
||||||
"""绘制菜单栏"""
|
"""绘制菜单栏"""
|
||||||
with imgui_ctx.begin_main_menu_bar() as main_menu:
|
with imgui_ctx.begin_main_menu_bar() as main_menu:
|
||||||
@ -159,6 +271,12 @@ class EditorPanels:
|
|||||||
_, self.app.showConsole = imgui.menu_item("控制台", "", self.app.showConsole, True)
|
_, self.app.showConsole = imgui.menu_item("控制台", "", self.app.showConsole, True)
|
||||||
_, self.app.showScriptPanel = imgui.menu_item("脚本管理", "", self.app.showScriptPanel, True)
|
_, self.app.showScriptPanel = imgui.menu_item("脚本管理", "", self.app.showScriptPanel, True)
|
||||||
_, self.app.showLUIEditor = imgui.menu_item("LUI编辑器", "", self.app.showLUIEditor, True)
|
_, self.app.showLUIEditor = imgui.menu_item("LUI编辑器", "", self.app.showLUIEditor, True)
|
||||||
|
prev_show_web_panel = self.app.showWebPanel
|
||||||
|
_, self.app.showWebPanel = imgui.menu_item("Web面板", "", self.app.showWebPanel, True)
|
||||||
|
if prev_show_web_panel and not self.app.showWebPanel:
|
||||||
|
self._stop_imgui_webview()
|
||||||
|
elif (not prev_show_web_panel) and self.app.showWebPanel:
|
||||||
|
self._on_create_web_panel()
|
||||||
|
|
||||||
# 工具菜单
|
# 工具菜单
|
||||||
with imgui_ctx.begin_menu("工具") as tools_menu:
|
with imgui_ctx.begin_menu("工具") as tools_menu:
|
||||||
@ -926,6 +1044,86 @@ class EditorPanels:
|
|||||||
self.app.is_dragging = True
|
self.app.is_dragging = True
|
||||||
self.app.show_drag_overlay = True
|
self.app.show_drag_overlay = True
|
||||||
|
|
||||||
|
def _draw_web_panel(self):
|
||||||
|
"""绘制 Web 面板(ImGui + 后台浏览器截图)。"""
|
||||||
|
self._ensure_web_panel_state()
|
||||||
|
if not self.app.showWebPanel:
|
||||||
|
self._stop_imgui_webview()
|
||||||
|
return
|
||||||
|
|
||||||
|
flags = self.app.style_manager.get_window_flags("panel")
|
||||||
|
with self.app.style_manager.begin_styled_window("Web面板", self.app.showWebPanel, flags) as (_, opened):
|
||||||
|
if not opened:
|
||||||
|
self.app.showWebPanel = False
|
||||||
|
self._stop_imgui_webview()
|
||||||
|
return
|
||||||
|
|
||||||
|
self.app.showWebPanel = True
|
||||||
|
|
||||||
|
changed, self.app.web_panel_url_input = imgui.input_text(
|
||||||
|
"URL", self.app.web_panel_url_input, 1024
|
||||||
|
)
|
||||||
|
if changed:
|
||||||
|
self.app.web_panel_url_input = self.app.web_panel_url_input.strip()
|
||||||
|
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("访问"):
|
||||||
|
self._navigate_web_panel()
|
||||||
|
|
||||||
|
webview = getattr(self.app, "_imgui_webview", None)
|
||||||
|
if not webview:
|
||||||
|
if not self._start_imgui_webview(self.app.web_panel_url_input):
|
||||||
|
imgui.text_colored((1.0, 0.4, 0.4, 1.0), "Web视图启动失败")
|
||||||
|
return
|
||||||
|
webview = self.app._imgui_webview
|
||||||
|
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("后退"):
|
||||||
|
webview.go_back()
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("前进"):
|
||||||
|
webview.go_forward()
|
||||||
|
imgui.same_line()
|
||||||
|
if imgui.button("刷新"):
|
||||||
|
webview.reload()
|
||||||
|
|
||||||
|
current_url = webview.current_url or self.app.web_panel_url_input
|
||||||
|
if current_url:
|
||||||
|
imgui.text_colored((0.7, 0.7, 0.7, 1.0), current_url)
|
||||||
|
if webview.error:
|
||||||
|
imgui.text_colored((1.0, 0.4, 0.4, 1.0), webview.error)
|
||||||
|
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
self._update_web_panel_texture()
|
||||||
|
tex_id = getattr(self.app, "_imgui_webview_tex_id", None)
|
||||||
|
available = imgui.get_content_region_avail()
|
||||||
|
display_w = max(float(available.x), 64.0)
|
||||||
|
display_h = max(float(available.y), 64.0)
|
||||||
|
|
||||||
|
if tex_id:
|
||||||
|
imgui.image(tex_id, (display_w, display_h))
|
||||||
|
|
||||||
|
if imgui.is_item_hovered():
|
||||||
|
mouse_wheel = imgui.get_io().mouse_wheel
|
||||||
|
if abs(mouse_wheel) > 1e-4:
|
||||||
|
webview.scroll(-mouse_wheel * 120.0)
|
||||||
|
|
||||||
|
if imgui.is_mouse_clicked(0):
|
||||||
|
item_min = imgui.get_item_rect_min()
|
||||||
|
item_max = imgui.get_item_rect_max()
|
||||||
|
item_w = max(float(item_max.x - item_min.x), 1.0)
|
||||||
|
item_h = max(float(item_max.y - item_min.y), 1.0)
|
||||||
|
mouse_pos = imgui.get_mouse_pos()
|
||||||
|
|
||||||
|
x_ratio = self._clamp01((float(mouse_pos.x) - float(item_min.x)) / item_w)
|
||||||
|
y_ratio = self._clamp01((float(mouse_pos.y) - float(item_min.y)) / item_h)
|
||||||
|
webview.click(x_ratio, y_ratio)
|
||||||
|
elif webview.is_loading:
|
||||||
|
imgui.text("网页加载中...")
|
||||||
|
else:
|
||||||
|
imgui.text("正在初始化Web视图...")
|
||||||
|
|
||||||
|
|
||||||
def _draw_property_panel(self):
|
def _draw_property_panel(self):
|
||||||
"""绘制属性面板"""
|
"""绘制属性面板"""
|
||||||
@ -2216,3 +2414,5 @@ class EditorPanels:
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"绘制着色模型面板失败: {e}")
|
print(f"绘制着色模型面板失败: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user