#include "ui/views/widget/sublevel_manager.h"
#include "base/containers/cxx20_erase_vector.h"
#include "base/ranges/algorithm.h"
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
namespace views {
SublevelManager::SublevelManager(Widget* owner, int sublevel)
: owner_(owner), sublevel_(sublevel) {
owner_observation_.Observe(owner);
}
SublevelManager::~SublevelManager() = default;
void SublevelManager::TrackChildWidget(Widget* child) {
DCHECK_EQ(0, base::ranges::count(children_, child));
DCHECK(child->parent() == owner_);
children_.push_back(child);
}
void SublevelManager::UntrackChildWidget(Widget* child) {
children_.erase(base::ranges::remove(children_, child), std::end(children_));
}
void SublevelManager::SetSublevel(int sublevel) {
sublevel_ = sublevel;
EnsureOwnerSublevel();
}
int SublevelManager::GetSublevel() const {
return sublevel_;
}
void SublevelManager::EnsureOwnerSublevel() {
Widget* parent = owner_->parent();
Widget* child = owner_;
while (parent && parent->GetSublevelManager()->IsTrackingChildWidget(child)) {
parent->GetSublevelManager()->OrderChildWidget(child);
child = parent;
parent = parent->parent();
}
}
void SublevelManager::OrderChildWidget(Widget* child) {
DCHECK_EQ(1, base::ranges::count(children_, child));
children_.erase(base::ranges::remove(children_, child), std::end(children_));
ui::ZOrderLevel child_level = child->GetZOrderLevel();
auto insert_it = FindInsertPosition(child);
auto find_visible_widget_of_same_level = [child_level](Widget* widget) {
return widget->IsVisible() && widget->GetZOrderLevel() == child_level;
};
auto prev_it = base::ranges::find_if(std::make_reverse_iterator(insert_it),
std::crend(children_),
find_visible_widget_of_same_level);
if (prev_it == children_.rend()) {
auto next_it = base::ranges::find_if(insert_it, std::cend(children_),
find_visible_widget_of_same_level);
if (next_it != std::end(children_)) {
child->StackAboveWidget(*next_it);
(*next_it)->StackAboveWidget(child);
}
} else {
child->StackAboveWidget(*prev_it);
}
children_.insert(insert_it, child);
}
void SublevelManager::OnWidgetDestroying(Widget* owner) {
DCHECK(owner == owner_);
if (owner->parent())
owner->parent()->GetSublevelManager()->UntrackChildWidget(owner);
}
bool SublevelManager::IsTrackingChildWidget(Widget* child) {
return base::ranges::find(children_, child) != children_.end();
}
SublevelManager::ChildIterator SublevelManager::FindInsertPosition(
Widget* child) const {
ui::ZOrderLevel child_level = child->GetZOrderLevel();
int child_sublevel = child->GetZOrderSublevel();
return base::ranges::find_if(children_, [&](Widget* widget) {
return widget->GetZOrderLevel() == child_level &&
widget->GetZOrderSublevel() > child_sublevel;
});
}
}