674 lines
13 KiB
C++
674 lines
13 KiB
C++
#include "ui/dl_ui_panel.h"
|
||
|
||
#ifndef DL_DISABLE_RENDER
|
||
#include "io/dl_file.h"
|
||
#include "ui/dl_ui_manager.h"
|
||
#include "ui/dl_ui_edit_box.h"
|
||
#include "base/dl_range_find.h"
|
||
#include "system/dl_system.h"
|
||
|
||
namespace dl::UI
|
||
{
|
||
|
||
void Panel::AddCpt(Components* cpt)
|
||
{
|
||
//ElementData组件处理
|
||
Cpt::ElementData* ele_data = cpt->Get<Cpt::ElementData>();
|
||
|
||
Position offset{};
|
||
Position size{};
|
||
int order_offset{};
|
||
if (ele_data)
|
||
{
|
||
size = ele_data->GetSize();
|
||
// 大小处理
|
||
if (ele_data->_bParentW)
|
||
size.w = _size.w;
|
||
if (ele_data->_bParentH)
|
||
size.h = _size.h;
|
||
if (ele_data->_bParentW || ele_data->_bParentH)
|
||
{
|
||
Cpt::SetSize* comp_size = cpt->Get<Cpt::SetSize>();
|
||
if (comp_size)
|
||
comp_size->Call(size);
|
||
else
|
||
log_warn0("元素没有SetSize成员!");
|
||
}
|
||
// 计算offset
|
||
offset = ele_data->GetOffset();
|
||
order_offset = ele_data->GetOrderOffset();
|
||
}
|
||
|
||
// 位置计算
|
||
Position pos = offset;
|
||
_locator.ExGet(_allEle.size(), toSizeNeg2Zero(size), pos);
|
||
|
||
// 组件处理
|
||
for (AnyType& iter : cpt->GetVectorAny())
|
||
{
|
||
if (auto comp = iter.Cast<Cpt::GetCoor>())
|
||
{
|
||
Coor* coor = comp->Call();
|
||
coor->SetParent(_coor);
|
||
// 最终坐标为 自身ElementData对齐 + 定位器
|
||
coor->SetPosition(pos);
|
||
}
|
||
else if (auto comp = iter.Cast<Cpt::SetOrder>())
|
||
{
|
||
comp->Call(Math::OffsetOrder(_order, 0, order_offset));
|
||
}
|
||
else if (auto comp = iter.Cast<Panel*>())
|
||
{// 添加自己为父节点
|
||
*comp = this;
|
||
}
|
||
}
|
||
|
||
_allEle.push_back(cpt);
|
||
}
|
||
|
||
void Panel::DelCpt(Components* cpt)
|
||
{
|
||
auto iter = std::find(_allEle.begin(), _allEle.end(), cpt);
|
||
if(iter != _allEle.end())
|
||
_allEle.erase(iter);
|
||
}
|
||
|
||
void Panel::Add(std::string_view json_path)
|
||
{
|
||
std::ifstream ifs = File::Get(json_path);
|
||
if (!ifs.is_open())
|
||
{
|
||
log_err("json文件并不存在:{}", json_path);
|
||
return;
|
||
}
|
||
json j = json::parse(ifs);
|
||
for (auto& iter : j)
|
||
{
|
||
std::string type;
|
||
std::string str;
|
||
Json::Get(iter, "type", type);
|
||
Json::Get(iter, "string", str);
|
||
//解析type
|
||
std::vector<std::string> vec_type = String::Split(type, '.');
|
||
if (vec_type.size() != 2)
|
||
{
|
||
log_err0("元素的type应该有两个字段!");
|
||
continue;
|
||
}
|
||
ElementType ele_type = String2ElementType(vec_type[0]);
|
||
if (ele_type == ElementType::UNKNOWN)
|
||
continue;
|
||
if (ele_type == ElementType::BUTTON)
|
||
{
|
||
ButtonSprite* btn = g_ui->CreateButtonSprite(vec_type[1]);
|
||
btn->SetString(lang_auto(str));
|
||
Add(btn);
|
||
}
|
||
|
||
//debug(type + str);
|
||
}
|
||
}
|
||
|
||
|
||
void Panel::AddPanel(Panel* child)
|
||
{
|
||
g_ui->SetPanelParent(child, this);
|
||
}
|
||
|
||
|
||
Panel* Panel::Clone()
|
||
{
|
||
Panel* ret = g_ui->CreatePanel(_node->GetParent()->GetValue());
|
||
|
||
NTree<Panel*>::Node* node = ret->_node;
|
||
Coor* coor = ret->_coor;
|
||
|
||
*ret = *this;
|
||
|
||
ret->_coor = coor;
|
||
ret->_coor->SetParent(_coor->GetParent());
|
||
ret->_node = node;
|
||
|
||
// 复制子节点
|
||
for(auto node_child : _node->GetChild())
|
||
{
|
||
g_ui->SetPanelParent(node_child->GetValue()->Clone(), ret);
|
||
}
|
||
|
||
ret->_allEle.clear();
|
||
for (Components* cpt : _allEle)
|
||
{
|
||
Cpt::Clone* comp = cpt->Get<Cpt::Clone>();
|
||
if (!comp)
|
||
{
|
||
log_err0("可复制panel的元素必须包含Clone组件!");
|
||
continue;
|
||
}
|
||
ret->AddCpt(comp->Call());
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
void Panel::SetLocator(std::string_view name)
|
||
{
|
||
SetLocator(g_ui->CreateLocator(name));
|
||
}
|
||
|
||
void Panel::Update()
|
||
{
|
||
if (_bUpdate)
|
||
{
|
||
log_err("已经调用过Update!");
|
||
return;
|
||
}
|
||
_bUpdate = true;
|
||
|
||
// 先优先级组件(drag)
|
||
for (Components* cpt : _allEle)
|
||
{
|
||
_update_cpt_drag(cpt);
|
||
}
|
||
|
||
// 位置刷新
|
||
if (_bNeedRefreshPos)
|
||
{
|
||
_bNeedRefreshPos = false;
|
||
_refresh_pos(GetParentSize());
|
||
}
|
||
|
||
// 后优先级组件
|
||
for (Components* cpt : _allEle)
|
||
{
|
||
if (Cpt::ElementData* comp = cpt->Get<Cpt::ElementData>())
|
||
{
|
||
if(!comp->_bRunAble || !comp->_bUpdateAble)
|
||
continue;
|
||
}
|
||
|
||
|
||
if (Cpt::Update* comp = cpt->Get<Cpt::Update>())
|
||
comp->Call();
|
||
|
||
_update_cpt_radio(cpt);
|
||
}
|
||
_update_child();
|
||
}
|
||
|
||
void Panel::UpdateRadio()
|
||
{
|
||
// todo
|
||
for (auto& iter : _node->GetChild())
|
||
{
|
||
Panel* child = iter->GetValue();
|
||
if (child->GetSelect())
|
||
{
|
||
for (auto& iter1 : _node->GetChild())
|
||
{
|
||
Panel* child1 = iter1->GetValue();
|
||
if (child != child1)
|
||
{
|
||
child1->SetSelectAll(false);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void Panel::Render()
|
||
{
|
||
if (g_ui->IsHide())
|
||
return;
|
||
if (_bRender)
|
||
{
|
||
log_warn("已经调用过Render:{}", _name);
|
||
return;
|
||
}
|
||
|
||
// 这里包含自动调用、手动调用的情况,但自动调用后执行
|
||
_bRender = true;
|
||
|
||
// TODO panel默认穿透
|
||
/*if (_pickupMode & E_SIZE)
|
||
{
|
||
if (IsPickup())
|
||
{
|
||
g_factory->SetOrderPickup(_order);
|
||
}
|
||
}*/
|
||
|
||
for (Components* cpt : _allEle)
|
||
{
|
||
if (Cpt::ElementData* comp = cpt->Get<Cpt::ElementData>())
|
||
{
|
||
if (!comp->_bRunAble || !comp->_bRenderAble)
|
||
continue;
|
||
}
|
||
Cpt::Render* comp = cpt->Get<Cpt::Render>();
|
||
if (!comp)
|
||
continue;
|
||
comp->Call();
|
||
}
|
||
_render_child();
|
||
}
|
||
|
||
void Panel::_refresh_pos(const Position& size)
|
||
{
|
||
assert(_bAutoCoor);
|
||
_coor->SetPosition(_posPixel + _posScale * size - Align::Size2Anchor(GetSize(), _align) + Align::Dir2Offset(GetSize(), _dir));
|
||
|
||
for (auto& iter : _node->GetChild())
|
||
{
|
||
Panel* child = iter->GetValue();
|
||
if (child->_bAutoCoor)
|
||
child->_refresh_pos(GetSize());
|
||
}
|
||
}
|
||
|
||
void Panel::_update_child()
|
||
{
|
||
for (auto& iter : _node->GetChild())
|
||
{
|
||
Panel* child = iter->GetValue();
|
||
if (child->_bAutoRun)
|
||
{
|
||
child->Update();
|
||
}
|
||
}
|
||
}
|
||
|
||
void Panel::_render_child()
|
||
{
|
||
for (auto& iter : _node->GetChild())
|
||
{
|
||
Panel* child = iter->GetValue();
|
||
if (child->_bAutoRun)
|
||
{
|
||
child->Render();
|
||
}
|
||
else if(child->_bAutoRender && child->_bUpdate && !child->_bRender)
|
||
{
|
||
child->Render();
|
||
}
|
||
}
|
||
}
|
||
|
||
void Panel::_refresh_size()
|
||
{
|
||
if (_align != Align::LT)
|
||
{
|
||
assert(_bAutoCoor);
|
||
_bNeedRefreshPos = true; // 修改大小会影响自己的对齐,即Align
|
||
}
|
||
|
||
if (_bSizeFull)
|
||
{
|
||
// 父节点大小
|
||
if (_node->GetParent())
|
||
{
|
||
_size = _node->GetParent()->GetValue()->_size;
|
||
}
|
||
else
|
||
{// 顶层以窗口大小
|
||
_size = toPosition(g_system->GetWindowSize()) / g_ui->GetScale();
|
||
}
|
||
}
|
||
|
||
// 子元素相关处理
|
||
for (auto& iter : _allEle)
|
||
{
|
||
if (UI::Sprite* spr = iter->Cast<UI::Sprite>())
|
||
{
|
||
if (spr->GetAutoSize() != Sprite::AutoSize::NONE)
|
||
{
|
||
spr->SetMode(spr->GetAutoSize(), spr->GetFillMode());
|
||
}
|
||
}
|
||
else if (UI::Background* bg = iter->Cast<UI::Background>())
|
||
{
|
||
bg->RefreshSize();
|
||
}
|
||
// 跟随大小处理
|
||
if (Cpt::ElementData* comp = iter->Get<Cpt::ElementData>())
|
||
{
|
||
Position size;
|
||
bool change_size = false;
|
||
if (comp->_bParentW && comp->_bParentH)
|
||
{
|
||
size = GetSize();
|
||
change_size = true;
|
||
}
|
||
else if (comp->_bParentW || comp->_bParentH)
|
||
{
|
||
Cpt::GetSize* comp_get_size = iter->Get<Cpt::GetSize>();
|
||
if (comp_get_size)
|
||
{
|
||
size = comp_get_size->Call();
|
||
if (comp->_bParentW)
|
||
size.w = GetSize().w;
|
||
if (comp->_bParentH)
|
||
size.h = GetSize().h;
|
||
change_size = true;
|
||
}
|
||
}
|
||
|
||
if (change_size)
|
||
{
|
||
Cpt::SetSize* comp_size = iter->Get<Cpt::SetSize>();
|
||
if (comp_size)
|
||
comp_size->Call(size);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void Panel::OnChangeElementData(Components* cpt)
|
||
{
|
||
std::size_t i = Find::FirstIndex(_allEle, cpt);
|
||
if (i == -1)
|
||
{
|
||
log_err0("不属于Panel的成员!");
|
||
return;
|
||
}
|
||
//ElementData组件处理
|
||
Cpt::ElementData* ele_data = cpt->Get<Cpt::ElementData>();
|
||
if (!ele_data)
|
||
{
|
||
log_err0("ElementData不存在!");
|
||
return;
|
||
}
|
||
Position offset = ele_data->GetOffset();
|
||
Position size = ele_data->GetSize();
|
||
|
||
// 位置计算
|
||
Position pos = offset;
|
||
_locator.ExGet(i, toSizeNeg2Zero(size), pos);
|
||
|
||
// 组件处理
|
||
for (AnyType& iter : cpt->GetVectorAny())
|
||
{
|
||
if (auto comp = iter.Cast<Cpt::GetCoor>())
|
||
{
|
||
Coor* coor = comp->Call();
|
||
coor->SetParent(_coor);
|
||
coor->SetPosition(pos);
|
||
}
|
||
}
|
||
}
|
||
|
||
void Panel::_refresh_order()
|
||
{
|
||
switch (_orderMode)
|
||
{
|
||
case Panel::AUTO:
|
||
{
|
||
auto node_parent = _node->GetParent();
|
||
if (node_parent)
|
||
{
|
||
Panel* parent = node_parent->GetValue();
|
||
size_t i = parent->GetChildIndex(this);
|
||
_order = Math::OffsetOrder(parent->_order, 0, -(int)i - 1);
|
||
}
|
||
}
|
||
break;
|
||
case Panel::CUSTOM:
|
||
{
|
||
auto node_parent = _node->GetParent();
|
||
if (node_parent)
|
||
{
|
||
Panel* parent = node_parent->GetValue();
|
||
size_t i = parent->GetChildIndex(this);
|
||
_order = Math::OffsetOrder(parent->_order, 0, _orderInParent);
|
||
}
|
||
}
|
||
break;
|
||
case Panel::FORCE:
|
||
default:
|
||
break;
|
||
}
|
||
// 更新元素
|
||
for (Components*& cpt : _allEle)
|
||
{
|
||
if (auto comp = cpt->Get<Cpt::SetOrder>())
|
||
{
|
||
comp->Call(Math::OffsetOrder(_order, 0, 0, -1));
|
||
}
|
||
}
|
||
// 更新子节点
|
||
for (auto& iter : _node->GetChild())
|
||
{
|
||
Panel* child = iter->GetValue();
|
||
child->_refresh_order();
|
||
}
|
||
}
|
||
|
||
dl::UI::Button* Panel::ExGetButton(size_t n /*= 0*/, bool show_log /*= true*/)
|
||
{
|
||
auto* btn = GetElement<UI::Button>(n);
|
||
if (btn)
|
||
return btn;
|
||
if (show_log)
|
||
log_warn("获取第{}个 Button失败!", n);
|
||
return nullptr;
|
||
}
|
||
|
||
dl::UI::ButtonSprite* Panel::ExGetButtonSprite(size_t n, bool show_log)
|
||
{
|
||
auto* btn = GetElement<UI::Button>(n);
|
||
auto* ret = dynamic_cast<UI::ButtonSprite*>(btn);
|
||
if (ret)
|
||
return ret;
|
||
if (show_log)
|
||
log_warn("获取第{}个 ButtonSprite失败!", n);
|
||
return nullptr;
|
||
}
|
||
|
||
dl::UI::ButtonSprite9* Panel::ExGetButtonSprite9(size_t n /*= 0*/, bool show_log /*= true*/)
|
||
{
|
||
auto* btn = GetElement<UI::Button>(n);
|
||
auto* ret = dynamic_cast<UI::ButtonSprite9*>(btn);
|
||
if (ret)
|
||
return ret;
|
||
if (show_log)
|
||
log_warn("获取第{}个 ButtonSprite9失败!", n);
|
||
return nullptr;
|
||
}
|
||
|
||
dl::UI::EditBox* Panel::ExGetEditBox(size_t n /*= 0*/, bool show_log)
|
||
{
|
||
auto ret = GetElement<UI::EditBox>(n);
|
||
if (ret)
|
||
return ret;
|
||
if (show_log)
|
||
log_warn("获取第{}个 EditBox失败!", n);
|
||
return nullptr;
|
||
}
|
||
|
||
dl::UI::Text* Panel::ExGetText(size_t n /*= 0*/, bool show_log)
|
||
{
|
||
auto ret = GetElement<UI::Text>(n);
|
||
if (ret)
|
||
return ret;
|
||
if (show_log)
|
||
log_warn("获取第{}个 Text失败!", n);
|
||
return nullptr;
|
||
}
|
||
|
||
dl::UI::Background* Panel::ExGetBackground(size_t n /*= 0*/, bool show_log /*= true*/)
|
||
{
|
||
auto ret = GetElement<UI::Background>(n);
|
||
if (ret)
|
||
return ret;
|
||
if (show_log)
|
||
log_warn("获取第{}个 Background失败!", n);
|
||
return nullptr;
|
||
}
|
||
|
||
void Panel::ExSetString(std::string_view str, size_t n /*= 0*/)
|
||
{
|
||
auto txt = ExGetText(n, false);
|
||
if (txt)
|
||
{
|
||
txt->SetString(str);
|
||
return;
|
||
}
|
||
auto btn = ExGetButton(n, false);
|
||
if (btn)
|
||
{
|
||
btn->SetString(str);
|
||
return;
|
||
}
|
||
auto btn9 = ExGetButtonSprite9(n, false);
|
||
if (btn9)
|
||
{
|
||
btn9->SetString(str);
|
||
return;
|
||
}
|
||
log_warn("设置 Panel第{}个 String失败!", n);
|
||
}
|
||
|
||
void Panel::_update_cpt_drag(Components* cpt)
|
||
{
|
||
// 拖拽组件处理
|
||
Cpt::Drag* drag = cpt->Get<Cpt::Drag>();
|
||
if (!drag)
|
||
return;
|
||
if (!drag->_bEnable)
|
||
return;
|
||
//
|
||
Cpt::IsPickup* cpt_pickup = cpt->Get<Cpt::IsPickup>();
|
||
if (!cpt_pickup)
|
||
return;
|
||
//
|
||
Coor* coor;
|
||
if (drag->_bControlPanel)
|
||
coor = _coor;
|
||
else
|
||
{
|
||
Cpt::GetCoor* get_coor = cpt->Get<Cpt::GetCoor>();
|
||
if (get_coor)
|
||
coor = get_coor->Call();
|
||
}
|
||
Position pos_pre = coor->GetPosition();
|
||
drag->Update(coor, cpt_pickup->Call());
|
||
Position pos_dt = coor->GetPosition() - pos_pre;
|
||
|
||
if (drag->_bControlPanel)
|
||
{
|
||
// drag->Update 已更新
|
||
_posPixel += pos_dt;
|
||
//log_info("拖拽:{} dt {}", to_string(_posPixel), to_string(pos_dt));
|
||
}
|
||
}
|
||
|
||
void Panel::_update_cpt_radio(Components* cpt)
|
||
{
|
||
// 如果自己是radio且打开,则将其它radio变为非open
|
||
if (UI::Button* c = cpt->Cast<UI::Button>())
|
||
{
|
||
if (c->GetMode() == UI::Button::Mode::RADIO
|
||
&& c->IsSelect())
|
||
{
|
||
for (Components* cpt1 : _allEle)
|
||
{
|
||
if (cpt1 != cpt)
|
||
{
|
||
UI::Button* c1 = cpt1->Cast<UI::Button>();
|
||
if (c1 && c1->GetMode() == UI::Button::Mode::RADIO)
|
||
{
|
||
c1->SetSelect(false);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
dl::UI::Panel* Panel::GetChildSelect()
|
||
{
|
||
for (auto& iter : _node->GetChild())
|
||
{
|
||
Panel* child = iter->GetValue();
|
||
if (child->GetSelect())
|
||
return child;
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
void Panel::SetChildSelect(Panel* panel)
|
||
{
|
||
for (auto& iter : _node->GetChild())
|
||
{
|
||
Panel* child = iter->GetValue();
|
||
child->SetSelectAll(panel == child);
|
||
}
|
||
}
|
||
|
||
dl::UI::Panel* Panel::GetChildPickup()
|
||
{
|
||
for (auto& iter : _node->GetChild())
|
||
{
|
||
Panel* child = iter->GetValue();
|
||
if (child->IsPickup())
|
||
return child;
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
RectF Panel::GetRect()
|
||
{
|
||
RectF ret{};
|
||
for (Components* cpt : _allEle)
|
||
{
|
||
Cpt::ElementData* comp = cpt->Get<Cpt::ElementData>();
|
||
if (!comp)
|
||
continue;
|
||
RectF rect = comp->GetRect();
|
||
ret[0] = std::min(ret[0], rect[0]);
|
||
ret[1] = std::min(ret[1], rect[1]);
|
||
ret[2] = std::max(ret[2], rect[2]);
|
||
ret[3] = std::max(ret[3], rect[3]);
|
||
}
|
||
for (auto& iter : _node->GetChild())
|
||
{
|
||
Panel* child = iter->GetValue();
|
||
RectF rect = child->GetRect();
|
||
ret[0] = std::min(ret[0], rect[0]);
|
||
ret[1] = std::min(ret[1], rect[1]);
|
||
ret[2] = std::max(ret[2], rect[2]);
|
||
ret[3] = std::max(ret[3], rect[3]);
|
||
}
|
||
return ret;
|
||
}
|
||
|
||
dl::Position Panel::GetParentSize()
|
||
{
|
||
auto parent = GetParent();
|
||
if (parent && parent->GetSize()!= Position{})
|
||
{
|
||
return parent->GetSize();
|
||
}
|
||
|
||
return toPosition(g_system->GetWindowSize()) / g_ui->GetScale();
|
||
}
|
||
|
||
dl::Position Panel::GetSize()
|
||
{
|
||
if (_bSizeAuto)
|
||
return _locator.GetSize();
|
||
if (_size == Position{})
|
||
{
|
||
return GetParentSize();
|
||
}
|
||
return _size;
|
||
}
|
||
|
||
void Panel::SetDir(Align::Dir4 dir)
|
||
{
|
||
_coor->SetRotate(Align::Dir2Rotate(dir));
|
||
_dir = dir;
|
||
_refresh_pos(GetParentSize());
|
||
}
|
||
|
||
}
|
||
|
||
#endif |