* feat(ui): 动画时钟、渲染剔除与文本框扩展,并优化 msimeui 性能 - 新增 Animation.h:cubic-bezier 缓动、Tween、颜色插值,Window 提供 RequestAnimationFrame / GetFrameTime,动画帧随显示刷新率推进 - Window 可选 DirectComposition 渲染(含不透明模式以支持 ClearType)、 双击按下、捕获丢失时结束按压、悬停刷新、可关闭销毁时退出消息循环 - Scene 把滚轮交给光标下最内层可滚动元素并逐级冒泡 - DeviceResources:裁剪栈驱动的离屏剔除、按帧回收的笔刷缓存、SVG 栅格缓存 - ScrollViewer 可配置外观与平滑滚动;Popup 支持阴影通道与出现动画; 卡片阴影缓存抽成可复用的 ShadowCache - TextBox 支持 SetText、密码掩码、多行滚动、字重/字间距/行高与外观设置 - 调试日志默认关闭(MSIMEUI_DEBUG_LOG=1 才写文件),不再在每次点击和 TSF GetTextExt 时打开文件 - 字体回退在 CJK/emoji 映射之后保留系统回退,缺字不再显示方框 - 新增动画与剔除单元测试 * feat(server): 新增实验性的 Direct2D 设置窗口 设置窗口可通过 appearance.settings_ui_backend 选择渲染方式:默认 webview2, d2d 为实验性的 msimeui 原生实现(server/src/settings/native/),1:1 复刻 网页设置页,包括侧栏切换时竖向高亮条的滑动动画。 - 两个前端共用同一套 webview 契约消息与 HandleClientMessage,配置读写 映射仍只在 settings_app.cpp - 切换渲染方式后设置进程自动以新方式重新打开;--d2d / --webview2 可临时指定 - 新配置项写入出厂模板与开发配置,UiBackendPolicy 与测试同步更新 - METASEQUOIA_IME_SETTINGS_INSTANCE 允许开发版与已安装的设置窗口并存 - 更新 ui-backends 文档与 server/AGENTS.md * feat(ui-html): 外观页新增设置窗口渲染方式选项
124 lines
4.7 KiB
C++
124 lines
4.7 KiB
C++
#pragma once
|
|
|
|
#include "DeviceResources.h"
|
|
#include "Scene.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
namespace msimeui
|
|
{
|
|
enum class WindowInitialPlacement
|
|
{
|
|
Center,
|
|
BottomCenter,
|
|
};
|
|
|
|
class Window
|
|
{
|
|
public:
|
|
Window(std::wstring className, std::wstring title, int width, int height);
|
|
~Window();
|
|
|
|
bool Create();
|
|
bool AdoptExistingHwnd(HWND hwnd);
|
|
LRESULT DispatchImportedMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
|
void SetStealFocusOnClick(bool enabled);
|
|
int Run(int nCmdShow);
|
|
|
|
HWND GetHandle() const;
|
|
HINSTANCE GetInstance() const;
|
|
Scene *GetScene() const;
|
|
DeviceResources &GetDeviceResources();
|
|
/// DPI override, mirrored into the window's own DeviceResources. Only for
|
|
/// cases where the system window DPI diverges from the content's real
|
|
/// scale (RDP client-scaling sync); see DeviceResources::SetDpiOverride.
|
|
/// GetDpi() and every pixels<->DIPs conversion (hit testing, drag region,
|
|
/// layout) honor it while set.
|
|
void SetDpiOverride(FLOAT dpi);
|
|
float GetDpi() const;
|
|
PointF ClientPixelsToDips(const POINT &point) const;
|
|
SizeF ClientPixelsToDips(const SIZE &size) const;
|
|
RECT DipsToClientPixels(const RectF &rect) const;
|
|
void Invalidate();
|
|
void Invalidate(const RectF &rect);
|
|
void InvalidateMeasure();
|
|
void InvalidateMeasure(Visual *source);
|
|
void InvalidateArrange();
|
|
void InvalidateArrange(Visual *source);
|
|
void Relayout();
|
|
void FocusVisual(Visual *visual);
|
|
void SetWindowStyle(DWORD style, DWORD extendedStyle = 0);
|
|
void SetDragRegionHeight(float height);
|
|
void SetRoundedCorners(bool enabled);
|
|
void SetInitialPlacement(WindowInitialPlacement placement, int bottomMargin = 12);
|
|
// Hosts that own the message loop (an adopted HWND in a larger application) keep
|
|
// running after this window goes away.
|
|
void SetQuitOnDestroy(bool quit);
|
|
// Replaces ThemeManager's windowBackground as the color each frame is cleared to.
|
|
void SetBackgroundColor(const D2D1_COLOR_F &color);
|
|
void SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE mode);
|
|
// Presents through a DirectComposition swap chain instead of an HWND render target.
|
|
// Needed by windows whose frame is drawn by the app over DWM's extended frame, where
|
|
// an HWND target's output is not composited; it also avoids the redirection copy.
|
|
// `opaque` ignores alpha, which an opaque window needs for ClearType text.
|
|
void SetCompositionRendering(bool enabled, bool opaque = false);
|
|
// Caret blinking for TextBox. Create() starts it; an adopted HWND has to ask.
|
|
void StartCaretTimer();
|
|
|
|
// Schedules another frame after the current one. Animated visuals call this from
|
|
// Render while they are still moving, so frames keep coming at the display rate
|
|
// and stop on their own when everything has settled.
|
|
void RequestAnimationFrame();
|
|
// Timestamp of the frame being rendered (NowMs() outside of painting). Every
|
|
// animation sampled in one frame sees the same time.
|
|
double GetFrameTime() const;
|
|
// Re-evaluates which visual is under the cursor, e.g. after content scrolled or
|
|
// was replaced without the mouse moving.
|
|
void RefreshHover();
|
|
|
|
void SetScene(std::unique_ptr<Scene> scene);
|
|
|
|
private:
|
|
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
LRESULT HandleMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
|
void OnPaint();
|
|
void OnSize();
|
|
bool OnMouseWheel(WPARAM wParam, LPARAM lParam);
|
|
LRESULT OnLeftButtonDown(WPARAM wParam, LPARAM lParam);
|
|
void UpdateHover(const POINT &point);
|
|
void SetFocusedVisual(Visual *visual);
|
|
bool UpdateCursorForClientPoint(const POINT &point);
|
|
|
|
std::wstring className_;
|
|
std::wstring title_;
|
|
int width_ = 0;
|
|
int height_ = 0;
|
|
HINSTANCE instance_ = nullptr;
|
|
HWND hwnd_ = nullptr;
|
|
FLOAT dpiOverride_ = 0.0f;
|
|
DeviceResources deviceResources_;
|
|
std::unique_ptr<Scene> scene_;
|
|
Visual *focusedVisual_ = nullptr;
|
|
Visual *hoveredVisual_ = nullptr;
|
|
Visual *capturedVisual_ = nullptr;
|
|
bool mouseLeaveTracking_ = false;
|
|
DWORD windowStyle_ = WS_OVERLAPPEDWINDOW;
|
|
DWORD extendedWindowStyle_ = 0;
|
|
float dragRegionHeight_ = 0.0f;
|
|
bool roundedCorners_ = false;
|
|
WindowInitialPlacement initialPlacement_ = WindowInitialPlacement::Center;
|
|
int initialBottomMargin_ = 12;
|
|
bool stealFocusOnClick_ = true;
|
|
bool adoptedHwnd_ = false;
|
|
bool quitOnDestroy_ = true;
|
|
bool hasBackgroundColor_ = false;
|
|
D2D1_COLOR_F backgroundColor_ = {};
|
|
D2D1_TEXT_ANTIALIAS_MODE textAntialiasMode_ = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT;
|
|
bool painting_ = false;
|
|
bool composition_ = false;
|
|
bool animationRequested_ = false;
|
|
double frameTimeMs_ = 0.0;
|
|
};
|
|
} // namespace msimeui
|