EG/ui/panels/editor_panels_center.py
2026-03-12 22:07:48 +08:00

223 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from imgui_bundle import imgui, imgui_ctx
import io
import tempfile
import time
from pathlib import Path
from panda3d.core import Filename
try:
from PIL import Image
except Exception: # pragma: no cover - pillow may be missing in minimal env
Image = None
class EditorPanelsCenterMixin:
"""Auto-split mixin from editor_panels.py."""
def _on_create_web_panel(self):
"""创建或激活 ImGui Web 面板。"""
self._ensure_web_panel_state()
self.app.set_panel_visible("web", 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.baidu.com"
if not hasattr(self.app, "_imgui_webview"):
self.app._imgui_webview = None
if not hasattr(self.app, "_imgui_webview_tex_id"):
self.app._imgui_webview_tex_id = None
if not hasattr(self.app, "_imgui_webview_texture_path"):
self.app._imgui_webview_texture_path = 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
texture_path = getattr(self.app, "_imgui_webview_texture_path", None)
if texture_path:
try:
Path(texture_path).unlink(missing_ok=True)
except Exception:
pass
self.app._imgui_webview_texture_path = 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
try:
if Image is None:
self.app.add_warning_message("缺少 Pillow无法更新Web纹理")
return
img = Image.open(io.BytesIO(jpeg_bytes)).convert("RGBA")
# p3dimgui 纹理坐标系与网页截图存在Y轴方向差异先在像素层修正
img = img.transpose(Image.FLIP_TOP_BOTTOM)
temp_dir = Path(tempfile.gettempdir()) / "eg_imgui_webpanel"
temp_dir.mkdir(parents=True, exist_ok=True)
temp_path = temp_dir / f"webview_{time.time_ns()}.png"
img.save(temp_path, format="PNG")
panda_path = Filename.fromOsSpecific(str(temp_path)).getFullpath()
new_tex_id = self.app.imgui.loadTexture(panda_path)
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
old_texture_path = getattr(self.app, "_imgui_webview_texture_path", None)
if old_texture_path:
try:
Path(old_texture_path).unlink(missing_ok=True)
except Exception:
pass
self.app._imgui_webview_tex_id = new_tex_id
self.app._imgui_webview_texture_path = str(temp_path)
except Exception as e:
self.app.add_warning_message(f"Web纹理更新失败: {e}")
finally:
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_web_panel(self):
"""绘制 Web 面板ImGui + 后台浏览器截图)。"""
self._ensure_web_panel_state()
if not self.app.is_panel_visible("web"):
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.set_panel_visible("web", False)
self._stop_imgui_webview()
return
self.app.set_panel_visible("web", opened)
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视图...")