Files
dl/build/backup/dl_ui_msg_box.h
2026-09-16 14:07:40 +08:00

302 lines
6.5 KiB
C++
Vendored

/**
* @file dl_ui_msg_box.h
* @brief 消息框
*
*
* @version 1.0
* @author lveyou
* @date 22-05-11
*
* @note 带有标题、内容、按钮、关闭按钮的弹窗
*/
#pragma once
#ifndef DL_DISABLE_RENDER
#include "ui/dl_ui_button_sprite.h"
#include "system/dl_system.h"
namespace dl::UI
{
//! 消息框最大按钮数量
constexpr size_t NUM_MSG_BOX_BTN = 10;
//! UI消息框
class MsgBox
{
public:
/**
* @brief 构造
* @param[in] bg 九图精灵作为背景
* @param[in] txt_title 标题文本
* @param[in] txt 内容文本
* @param[in] btn 普通按钮
* @param[in] btn_close 关闭按钮
* @param[in] dx_btn 按钮(额外)间隔,艺术性调整
*
* @note 应该立即调用Set设置内容
*/
static MsgBox* Create(
Background* bg,
gcText txt_title,
gcText txt,
UI::ButtonSprite* btn,
UI::ButtonSprite* btn_close,
Float dx_btn = 0.0)
{
MsgBox* ret = new MsgBox;
Coor* coor = Coor::Create();
coor->SetPosition(toPosition(g_system->GetWindowSize() / 2u));
bg->SetUI(true);
ret->_coor = coor;
ret->_bg = bg;
ret->_txtTitle = txt_title;
ret->_txt = txt;
ret->_btn = btn;
ret->_btnClose = btn_close;
ret->_dxBtn = dx_btn;
ret->_refresh_coor();
ret->SetOrder(Z_DEFAULT_UI);
return ret;
}
MsgBox* Clone()
{
MsgBox* ret = new MsgBox(*this);
ret->_coor = _coor->Clone();
ret->_bg = _bg->Clone();
ret->_btn = _btn->Clone();
ret->_btnClose = _btnClose->Clone();
for (size_t i = 0; i < _allBtn.size(); ++i)
{
ret->_allBtn[i] = _allBtn[i]->Clone();
}
ret->_refresh_coor();
return ret;
}
/**
* @brief 设置内容
* @param[in] title 标题
* @param[in] info 内容
* @param[in] btns 按钮内容
*
*/
void Set(std::string_view title, std::string_view info, std::vector<std::string_view> all_btn)
{
_txtTitle->SetString(title);
if(_bAddTab)
_txt->SetString(std::string{ "\t" } + std::string{ info });
else
_txt->SetString(info);
//少了就新建按钮
_numBtn = all_btn.size();
if (_numBtn > _allBtn.size())
{
_allBtn.resize(_numBtn);
for (UI::ButtonSprite*& btn : _allBtn)
{
if (!btn)
{
btn = _btn->Clone();
}
}
}
for (std::size_t i = 0; i < _numBtn; ++i)
{
_allBtn[i]->SetString(all_btn[i]);
}
//--------------------------------更新布局--------------------------------
Float w_btn = _btn->GetSize()[0]; //按钮宽度
Float h_btn = _btn->GetSize()[1];
//整体宽度为 按钮宽度 + 间隔(多一个)
Float w = w_btn * _numBtn + _dxBtn * (1 + _numBtn);
_txt->SetMaxW(w);//设置文本宽度
Float h_txt = _txt->GetSize()[1]; //文本高度
Float h_title = _txtTitle->GetSize()[1];//标题高度
//整体高度 标题 + 文本 + 按钮
Float h = h_title + h_txt * 1 + h_btn * 1;
_txt->SetCenter();
Position size{ w, h };
Position size_half{ size * 0.5f };
_bg->SetSize(size);
//设置位置
_bg->GetCoor()->SetPosition(toPosition(_bg->GetOffset()) - size_half);
_txtTitle->SetPositionAlign(-size_half, Align::LC);
_btnClose->GetCoor()->SetPosition({ size_half[0], -size_half[1] });
if (_numBtn > 0)
{
//偏移为 负的 按钮总宽度的一半(间隔少一个) + 半个按钮
Float sx_btn = (w_btn * _numBtn + _dxBtn * (_numBtn - 1)) * -0.5_f + w_btn * 0.5_f;
for (std::size_t i = 0; i < _numBtn; ++i)
{
_allBtn[i]->GetCoor()->SetPosition({ sx_btn + i * (w_btn + _dxBtn), size_half[1] });
}
}
}
/**
* @brief 设置内容,以语言文件配置的名称
*
*/
void Set(std::string_view str)
{
std::string_view str_title = lang("msg_box", std::string{ str } + "_title");
std::string_view str_info = lang("msg_box", std::string{ str } + "_info");
std::vector<std::string_view> all_btn;
for (std::size_t i = 0; i < NUM_MSG_BOX_BTN; ++i)
{
std::string str_name = fmt::format("{}_{}", str, i);
auto str = g_lang->GetCheck("msg_box", str_name);
if (!str.has_value())
{
break;
}
all_btn.push_back(str.value());
}
Set(str_title, str_info, all_btn);
}
void Update()
{
_btnClose->Update();
for (size_t i = 0; i < _numBtn; ++i)
{
_allBtn[i]->Update();
}
if (_posPick)
{
if (g_input->KeyUp(MouseCode::LEFT))
_posPick.reset();
}
else
{
if (g_input->KeyDown(MouseCode::LEFT) && IsPickupTitle())
{
_posPick = _coor->WorldToThis(toPosition(g_input->GetCursorPosition()));
}
}
//左键拖动
if (_posPick)
{
Point pos = g_input->GetCursorPosition();
_coor->SetPosition(toPosition(pos) - _posPick.value());
}
}
void Render()
{
_bg->Render();
_txtTitle->Render();
_txt->Render();
}
/**
* @brief 返回点击按钮索引,返回-1代表没有点击
*/
size_t GetClick()
{
for (size_t i = 0; i < _numBtn; ++i)
{
if (_allBtn[i]->IsClick())
return i;
}
return -1;
}
/**
* @brief 是否点击了关闭按钮
*/
bool IsClickClose()
{
return _btnClose->IsClick();
}
/**
* @brief 是否选中标题栏
*/
bool IsPickupTitle()
{
if (_bg->IsPickup())
{//按钮会屏蔽bg的IsPickup
Position pos = _txtTitle->GetCoor()->WorldToThis(toPosition(g_input->GetCursorPosition()));
if (pos[1] < _txtTitle->GetSize()[1])
return true;
}
return false;
}
void SetOrder(float order)
{
_txt->SetOrder(Math::OffsetOrder(order, 0, 0, -1));
_txtTitle->SetOrder(Math::OffsetOrder(order, 0, 0, -1));
_btnClose->SetOrder(Math::OffsetOrder(order, 0, 0, -1));
_btn->SetOrder(Math::OffsetOrder(order, 0, 0, -1));
for (auto& iter : _allBtn)
{
iter->SetOrder(Math::OffsetOrder(order, 0, 0, -1));
}
_bg->SetOrder(Math::OffsetOrder(order, 0, 0, 0));
}
~MsgBox()
{
delete _coor;
delete _bg;
delete _btn;
delete _btnClose;
for (auto& iter : _allBtn)
delete iter;
}
private:
MsgBox():
_coor{nullptr},
_bg{nullptr},
_btn{nullptr},
_btnClose{nullptr},
_numBtn{0},
_bAddTab{true}
{}
Coor* _coor;
Background* _bg;
gcText _txtTitle;
gcText _txt;
UI::ButtonSprite* _btn;
UI::ButtonSprite* _btnClose;
//动态改变长度,多余的不会自动删除,所以需要标记使用数量
std::vector<UI::ButtonSprite*> _allBtn;
std::size_t _numBtn;
Float _dxBtn;
std::optional<Position> _posPick;//被拾取位置(差值,相加即可)(直到再抬起)
bool _bAddTab;//添加段首缩进
void _refresh_coor()
{
_bg->GetCoor()->SetParent(_coor);
_txtTitle->GetCoor()->SetParent(_coor);
_txt->GetCoor()->SetParent(_coor);
_btn->GetCoor()->SetParent(_coor);
_btnClose->GetCoor()->SetParent(_coor);
for (size_t i = 0; i < _allBtn.size(); ++i)
{
_allBtn[i]->GetCoor()->SetParent(_coor);
}
}
};
}
#endif