Files
msime-windows/ui/src/Scene.cpp
T
Evan 42238a2af6 style: 用 .clang-format 重排 server / windows / ui / log
一次性重排,无任何行为改动。四个目录各自的 .clang-format 放在仓库里已久,但全组织只有
MSIME-Linux 在 CI 里执行 clang-format 检查,这边 149 个文件里有 149 个不符合自己声明的风格。

已逐文件核对语义等价:去掉空白、注释与相邻字符串字面量拆分之后,全部 149 个文件与重排前逐字节
相同。差异只有三类——缩进与换行、clang-format 补的 } // namespace 结尾注释、以及长字符串被拆成
相邻字面量(C++ 保证自动拼接)。

这个提交会写进 .git-blame-ignore-revs。
2026-09-06 12:13:47 +09:00

412 lines
8.4 KiB
C++

#include "msimeui/Scene.h"
#include "msimeui/DeviceResources.h"
#include "msimeui/Window.h"
#include <algorithm>
namespace msimeui
{
namespace
{
Visual *FindCommonAncestor(Visual *lhs, Visual *rhs)
{
if (!lhs)
{
return rhs;
}
if (!rhs)
{
return lhs;
}
if (lhs == rhs)
{
return lhs;
}
for (Visual *left = lhs; left; left = left->GetParentVisual())
{
for (Visual *right = rhs; right; right = right->GetParentVisual())
{
if (left == right)
{
return left;
}
}
}
return lhs;
}
bool RemeasureDirtyPath(Visual *source, Visual *root)
{
if (!source || !root)
{
return false;
}
std::vector<Visual *> path;
for (Visual *current = source; current; current = current->GetParentVisual())
{
path.push_back(current);
if (current == root)
{
break;
}
}
if (path.empty() || path.back() != root)
{
return false;
}
for (Visual *current : path)
{
if (!current->HasMeasureSlot())
{
return false;
}
}
for (Visual *current : path)
{
current->MeasureInLayout(current->GetLastMeasureAvailableSize());
}
return true;
}
} // namespace
void Scene::SetRoot(std::shared_ptr<Visual> root)
{
root_ = std::move(root);
if (root_ && window_)
{
root_->Attach(window_);
}
measureDirty_ = true;
arrangeDirty_ = true;
measureDirtySource_ = root_.get();
arrangeDirtyRoot_ = root_.get();
}
void Scene::Attach(Window *window)
{
window_ = window;
if (root_)
{
root_->Attach(window);
}
for (auto &popup : popups_)
{
if (popup.visual)
{
popup.visual->Attach(window);
}
}
}
void Scene::EnsureLayout(const SizeF &size)
{
const bool sizeChanged =
!hasLastLayoutSize_ || lastLayoutSize_.width != size.width || lastLayoutSize_.height != size.height;
if (sizeChanged || measureDirty_ || arrangeDirty_)
{
Layout(size);
}
}
void Scene::Layout(const SizeF &size)
{
const bool sizeChanged =
!hasLastLayoutSize_ || lastLayoutSize_.width != size.width || lastLayoutSize_.height != size.height;
const bool needsMeasure = sizeChanged || measureDirty_ || !hasLastLayoutSize_;
const bool needsArrange = needsMeasure || sizeChanged || arrangeDirty_ || !hasLastLayoutSize_;
if (!root_)
{
lastLayoutSize_ = size;
hasLastLayoutSize_ = true;
measureDirty_ = false;
arrangeDirty_ = false;
measureDirtySource_ = nullptr;
arrangeDirtyRoot_ = nullptr;
return;
}
const SizeF innerSize = size;
if (needsMeasure)
{
const bool canUseDirtyPath = !sizeChanged && measureDirtySource_ && measureDirtySource_ != root_.get();
if (!canUseDirtyPath || !RemeasureDirtyPath(measureDirtySource_, root_.get()))
{
root_->MeasureInLayout(innerSize);
}
}
if (needsArrange)
{
const RectF rootSlot = {0.0f, 0.0f, innerSize.width, innerSize.height};
if (!needsMeasure && !sizeChanged && arrangeDirtyRoot_ && arrangeDirtyRoot_ != root_.get() &&
arrangeDirtyRoot_->HasArrangeSlot())
{
arrangeDirtyRoot_->ArrangeInLayout(arrangeDirtyRoot_->lastArrangeRect_);
}
else
{
root_->ArrangeInLayout(rootSlot);
}
}
lastLayoutSize_ = size;
hasLastLayoutSize_ = true;
measureDirty_ = false;
arrangeDirty_ = false;
measureDirtySource_ = nullptr;
arrangeDirtyRoot_ = nullptr;
for (auto &popup : popups_)
{
if (popup.visual)
{
popup.visual->LayoutOverlay(size);
}
}
}
void Scene::AddPopup(std::shared_ptr<Visual> popup, std::function<void()> onClose)
{
if (!popup)
{
return;
}
for (const auto &entry : popups_)
{
if (entry.visual == popup)
{
return;
}
}
if (window_)
{
popup->Attach(window_);
}
popups_.push_back({std::move(popup), std::move(onClose)});
arrangeDirty_ = true;
InvalidateVisual();
}
void Scene::RemovePopup(Visual *popup, bool notify)
{
if (!popup)
{
return;
}
auto it = std::find_if(popups_.begin(), popups_.end(),
[popup](const PopupEntry &entry) { return entry.visual.get() == popup; });
if (it == popups_.end())
{
return;
}
std::function<void()> onClose = std::move(it->onClose);
popups_.erase(it);
if (notify && onClose)
{
onClose();
}
InvalidateVisual();
}
void Scene::ClearPopups(bool notify)
{
if (popups_.empty())
{
return;
}
auto popups = std::move(popups_);
popups_.clear();
if (notify)
{
for (auto &entry : popups)
{
if (entry.onClose)
{
entry.onClose();
}
}
}
InvalidateVisual();
}
bool Scene::DismissPopupsForClick(const PointF &point, Visual *target)
{
if (popups_.empty())
{
return false;
}
if (target && target->KeepsPopupsOpenOnClick())
{
return false;
}
for (auto it = popups_.rbegin(); it != popups_.rend(); ++it)
{
if (it->visual && it->visual->HitTest(point))
{
return false;
}
}
ClearPopups(true);
return true;
}
void Scene::RelayoutPopups()
{
if (!hasLastLayoutSize_)
{
return;
}
for (auto &popup : popups_)
{
if (popup.visual)
{
popup.visual->LayoutOverlay(lastLayoutSize_);
}
}
InvalidateVisual();
}
void Scene::InvalidateMeasure()
{
measureDirty_ = true;
arrangeDirty_ = true;
measureDirtySource_ = root_.get();
arrangeDirtyRoot_ = root_.get();
InvalidateVisual();
}
void Scene::InvalidateMeasure(Visual *source)
{
measureDirty_ = true;
arrangeDirty_ = true;
if (!source || !root_)
{
measureDirtySource_ = root_.get();
arrangeDirtyRoot_ = root_.get();
}
else if (!measureDirtySource_)
{
measureDirtySource_ = source;
arrangeDirtyRoot_ = source;
}
else
{
measureDirtySource_ = FindCommonAncestor(measureDirtySource_, source);
arrangeDirtyRoot_ = FindCommonAncestor(arrangeDirtyRoot_, source);
}
InvalidateVisual();
}
void Scene::InvalidateArrange()
{
arrangeDirty_ = true;
arrangeDirtyRoot_ = root_.get();
InvalidateVisual();
}
void Scene::InvalidateArrange(Visual *source)
{
arrangeDirty_ = true;
if (!source || !root_)
{
arrangeDirtyRoot_ = root_.get();
}
else if (!arrangeDirtyRoot_)
{
arrangeDirtyRoot_ = source;
}
else
{
arrangeDirtyRoot_ = FindCommonAncestor(arrangeDirtyRoot_, source);
}
InvalidateVisual();
}
void Scene::InvalidateVisual()
{
if (window_)
{
window_->Invalidate();
}
}
void Scene::Render(DeviceResources &deviceResources)
{
if (root_)
{
root_->Render(deviceResources);
}
for (const auto &popup : popups_)
{
if (popup.visual)
{
popup.visual->Render(deviceResources);
}
}
}
Visual *Scene::FindVisualAt(const PointF &point)
{
for (auto it = popups_.rbegin(); it != popups_.rend(); ++it)
{
if (it->visual)
{
if (Visual *hit = it->visual->FindVisualAt(point))
{
return hit;
}
}
}
return root_ ? root_->FindVisualAt(point) : nullptr;
}
Visual *Scene::FindFocusableAt(const PointF &point)
{
for (auto it = popups_.rbegin(); it != popups_.rend(); ++it)
{
if (it->visual)
{
if (Visual *focusable = it->visual->FindFocusableAt(point))
{
return focusable;
}
}
}
return root_ ? root_->FindFocusableAt(point) : nullptr;
}
bool Scene::OnMouseWheel(const POINT &point, short delta, WPARAM keyState)
{
for (auto it = popups_.rbegin(); it != popups_.rend(); ++it)
{
if (it->visual && it->visual->OnMouseWheel(point, delta, keyState))
{
return true;
}
}
return root_ ? root_->OnMouseWheel(point, delta, keyState) : false;
}
bool Scene::OnTimer(UINT_PTR timerId)
{
return root_ ? root_->OnTimer(timerId) : false;
}
} // namespace msimeui