86 lines
3.7 KiB
C++
86 lines
3.7 KiB
C++
// PreviewTipWnd.h
|
||
// 双击在线主机时弹出的浮窗:上方 JPEG 缩略图,下方主机信息文本。
|
||
// 无图片时显示"加载预览…"占位,供 OnListClick 即时弹窗、收到响应后再 SetImage 重画。
|
||
#pragma once
|
||
|
||
#include <afxwin.h>
|
||
#include <memory>
|
||
#include <vector>
|
||
|
||
namespace Gdiplus { class Bitmap; }
|
||
|
||
class CPreviewTipWnd : public CWnd
|
||
{
|
||
public:
|
||
CPreviewTipWnd();
|
||
virtual ~CPreviewTipWnd();
|
||
|
||
// 创建浮窗。
|
||
// anchor 屏幕坐标,浮窗左上角
|
||
// text 下方显示的主机详情文本(宽字符,确保跨语言系统正确渲染)
|
||
// imageReserveW 上方图像区域预留宽度(即将到来的预览最大宽度,仅作初始布局)
|
||
// 为 0 表示不预留 — 与老 STATIC 路径行为一致(仅文本)
|
||
// loopMode true: 真正的可拖拽/缩放/最小化/最大化的独立窗口("播放快照"循环),
|
||
// 带标题栏 + 任务栏图标,关闭按钮走系统菜单;
|
||
// false: 单发 tooltip(双击主机的预览),无 chrome、不激活、置顶。
|
||
// windowTitle loopMode=true 时显示在标题栏与任务栏的文本;false 时忽略。
|
||
BOOL Create(CWnd* pParent, CPoint anchor, const CStringW& text, int imageReserveW,
|
||
bool loopMode = false, const CStringW& windowTitle = L"");
|
||
|
||
// 收到 JPEG 后调用:解码并重画。线程安全前提是只在主 UI 线程调用。
|
||
void SetImageFromJpeg(const BYTE* data, size_t bytes);
|
||
// 标记预览不可用(请求超时 / 客户端报错)。
|
||
void MarkPreviewUnavailable();
|
||
|
||
WORD GetReqId() const { return m_reqId; }
|
||
void SetReqId(WORD id) { m_reqId = id; }
|
||
|
||
// 循环快照模式:开启后窗口销毁时会向 ownerHwnd 发送 msgId(LPARAM 是堆上的
|
||
// uint64_t* 携带 clientId,接收方负责 delete),且 PostNcDestroy 会自动 delete this。
|
||
// 调用方需在自行销毁前用 SetLoopOwner(NULL, 0, 0) 解除回调,避免重复通知。
|
||
void SetLoopOwner(HWND ownerHwnd, UINT msgId, uint64_t clientId);
|
||
uint64_t GetClientID() const { return m_clientId; }
|
||
bool IsLoopMode() const { return m_loopMode; }
|
||
|
||
protected:
|
||
afx_msg void OnPaint();
|
||
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
|
||
afx_msg void OnDestroy();
|
||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||
afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
|
||
virtual void PostNcDestroy();
|
||
DECLARE_MESSAGE_MAP()
|
||
|
||
private:
|
||
void RecalcLayoutAndResize();
|
||
void DrawImageArea(CDC& dc, const CRect& rc);
|
||
void DrawTextArea(CDC& dc, const CRect& rc);
|
||
// 循环模式:基于当前 client rect 重新分配图像区/文本区
|
||
void LayoutForLoopMode(const CRect& client, CRect& outImg, CRect& outText);
|
||
|
||
CStringW m_text;
|
||
int m_imageReserveW = 0; // 预留图像宽度(图像未到达时占位)
|
||
int m_imageReserveH = 0; // 预留图像高度(按 16:9)
|
||
int m_imageDrawW = 0; // 实际图像绘制宽度
|
||
int m_imageDrawH = 0; // 实际图像绘制高度
|
||
int m_textW = 0;
|
||
int m_textH = 0;
|
||
|
||
bool m_hasImage = false;
|
||
bool m_unavailable = false;
|
||
std::unique_ptr<Gdiplus::Bitmap> m_image;
|
||
|
||
CFont m_font;
|
||
WORD m_reqId = 0;
|
||
|
||
// 循环快照模式相关
|
||
bool m_loopMode = false;
|
||
HWND m_loopOwner = nullptr;
|
||
UINT m_loopMsg = 0;
|
||
uint64_t m_clientId = 0;
|
||
// 标题栏 / 任务栏图标。WM_SETICON 不转移所有权(MSDN:originator 必须自己释放),
|
||
// 析构时 DestroyIcon;不能在 OnDestroy 里销毁,因为系统在 WM_NCDESTROY 之前还在用它。
|
||
HICON m_hIconSmall = nullptr;
|
||
HICON m_hIconBig = nullptr;
|
||
};
|