nim_duilib/tool_kits/duilib/Core/WindowBuilder.cpp

545 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "StdAfx.h"
namespace ui
{
WindowBuilder::WindowBuilder()
{
}
Box* WindowBuilder::Create(STRINGorID xml, CreateControlCallback pCallback,
Window* pManager, Box* pParent, Box* pUserDefinedBox)
{
//资源ID为0-65535两个字节字符串指针为4个字节
//字符串以<开头认为是XML字符串否则认为是XML文件
//如果使用了 zip 压缩包,则从内存中读取
if (HIWORD(xml.m_lpstr) != NULL) {
if (*(xml.m_lpstr) == _T('<')) {
if (!m_xml.Load(xml.m_lpstr)) return NULL;
}
else if (GlobalManager::IsUseZip()) {
std::wstring sFile = GlobalManager::GetResourcePath();
sFile += xml.m_lpstr;
HGLOBAL hGlobal = GlobalManager::GetData(sFile);
if (hGlobal)
{
std::string src((LPSTR)GlobalLock(hGlobal), GlobalSize(hGlobal));
std::wstring string_resourse;
StringHelper::MBCSToUnicode(src.c_str(), string_resourse, CP_UTF8);
GlobalFree(hGlobal);
if (!m_xml.Load(string_resourse.c_str())) return NULL;
}
else
{
if (!m_xml.LoadFromFile(xml.m_lpstr)) return NULL;
}
}
else {
if (!m_xml.LoadFromFile(xml.m_lpstr)) return NULL;
}
}
else {
ASSERT(FALSE);
}
return Create(pCallback, pManager, pParent, pUserDefinedBox);
}
Box* WindowBuilder::Create(CreateControlCallback pCallback, Window* pManager, Box* pParent, Box* pUserDefinedBox)
{
m_createControlCallback = pCallback;
CMarkupNode root = m_xml.GetRoot();
if( !root.IsValid() ) return NULL;
if( pManager ) {
std::wstring strClass;
int nAttributes = 0;
std::wstring strName;
std::wstring strValue;
LPTSTR pstr = NULL;
strClass = root.GetName();
if( strClass == _T("Global") )
{
int nAttributes = root.GetAttributeCount();
for( int i = 0; i < nAttributes; i++ ) {
strName = root.GetAttributeName(i);
strValue = root.GetAttributeValue(i);
if( strName == _T("disabledfontcolor") ) {
GlobalManager::SetDefaultDisabledTextColor(strValue);
}
else if( strName == _T("defaultfontcolor") ) {
GlobalManager::SetDefaultTextColor(strValue);
}
else if( strName == _T("linkfontcolor") ) {
DWORD clrColor = GlobalManager::GetTextColor(strValue);
GlobalManager::SetDefaultLinkFontColor(clrColor);
}
else if( strName == _T("linkhoverfontcolor") ) {
DWORD clrColor = GlobalManager::GetTextColor(strValue);
GlobalManager::SetDefaultLinkHoverFontColor(clrColor);
}
else if( strName == _T("selectedcolor") ) {
DWORD clrColor = GlobalManager::GetTextColor(strValue);
GlobalManager::SetDefaultSelectedBkColor(clrColor);
}
}
}
else if( strClass == _T("Window") ) {
if( pManager->GetHWND() ) {
int nAttributes = root.GetAttributeCount();
for( int i = 0; i < nAttributes; i++ ) {
strName = root.GetAttributeName(i);
strValue = root.GetAttributeValue(i);
if( strName == _T("size") ) {
LPTSTR pstr = NULL;
int cx = _tcstol(strValue.c_str(), &pstr, 10); ASSERT(pstr);
int cy = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->SetInitSize(cx, cy);
}
else if( strName == _T("heightpercent") ) {
double lfHeightPercent = _ttof(strValue.c_str());
pManager->SetHeightPercent(lfHeightPercent);
MONITORINFO oMonitor = {};
oMonitor.cbSize = sizeof(oMonitor);
::GetMonitorInfo(::MonitorFromWindow(pManager->GetHWND(), MONITOR_DEFAULTTOPRIMARY), &oMonitor);
int nWindowHeight = int((oMonitor.rcWork.bottom - oMonitor.rcWork.top) * lfHeightPercent);
int nMinHeight = pManager->GetMinInfo().cy;
int nMaxHeight = pManager->GetMaxInfo().cy;
if (nMinHeight != 0 && nWindowHeight < nMinHeight) {
nWindowHeight = nMinHeight;
}
if (nMaxHeight != 0 && nWindowHeight > nMaxHeight) {
nWindowHeight = nMaxHeight;
}
CSize xy = pManager->GetInitSize();
pManager->SetInitSize(xy.cx, nWindowHeight, false, false);
}
else if( strName == _T("sizebox") ) {
UiRect rcSizeBox;
LPTSTR pstr = NULL;
rcSizeBox.left = _tcstol(strValue.c_str(), &pstr, 10); ASSERT(pstr);
rcSizeBox.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rcSizeBox.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rcSizeBox.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->SetSizeBox(rcSizeBox);
}
else if( strName == _T("caption") ) {
UiRect rcCaption;
LPTSTR pstr = NULL;
rcCaption.left = _tcstol(strValue.c_str(), &pstr, 10); ASSERT(pstr);
rcCaption.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rcCaption.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rcCaption.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->SetCaptionRect(rcCaption);
}
else if( strName == _T("textid") ) {
pManager->SetTextId(strValue);
}
else if( strName == _T("roundcorner") ) {
LPTSTR pstr = NULL;
int cx = _tcstol(strValue.c_str(), &pstr, 10); ASSERT(pstr);
int cy = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->SetRoundCorner(cx, cy);
}
else if( strName == _T("mininfo") ) {
LPTSTR pstr = NULL;
int cx = _tcstol(strValue.c_str(), &pstr, 10); ASSERT(pstr);
int cy = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->SetMinInfo(cx, cy);
}
else if( strName == _T("maxinfo") ) {
LPTSTR pstr = NULL;
int cx = _tcstol(strValue.c_str(), &pstr, 10); ASSERT(pstr);
int cy = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->SetMaxInfo(cx, cy);
}
else if( strName == _T("shadowattached") ) {
pManager->SetShadowAttached(strValue == _T("true"));
}
else if (strName == _T("shadowimage")) {
pManager->SetShadowImage(strValue);
}
else if (strName == _T("shadowcorner")) {
UiRect rc;
LPTSTR pstr = NULL;
rc.left = _tcstol(strValue.c_str(), &pstr, 10); ASSERT(pstr);
rc.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rc.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rc.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->SetShadowCorner(rc);
}
else if (strName == _T("alphafixcorner") || strName == _T("custom_shadow")) {
UiRect rc;
LPTSTR pstr = NULL;
rc.left = _tcstol(strValue.c_str(), &pstr, 10); ASSERT(pstr);
rc.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rc.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rc.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
pManager->SetAlphaFixCorner(rc);
}
}
}
}
if( strClass == _T("Global") ) {
for( CMarkupNode node = root.GetChild() ; node.IsValid(); node = node.GetSibling() ) {
strClass = node.GetName();
if( strClass == _T("Image") ) {
ASSERT(FALSE); //废弃
}
else if( strClass == _T("Font") ) {
nAttributes = node.GetAttributeCount();
std::wstring strFontName;
int size = 12;
bool bold = false;
bool underline = false;
bool italic = false;
for( int i = 0; i < nAttributes; i++ ) {
strName = node.GetAttributeName(i);
strValue = node.GetAttributeValue(i);
if( strName == _T("name") ) {
strFontName = strValue;
}
else if( strName == _T("size") ) {
size = _tcstol(strValue.c_str(), &pstr, 10);
}
else if( strName == _T("bold") ) {
bold = (strValue == _T("true"));
}
else if( strName == _T("underline") ) {
underline = (strValue == _T("true"));
}
else if( strName == _T("italic") ) {
italic = (strValue == _T("true"));
}
else if( strName == _T("default") ) {
ASSERT(FALSE);//废弃
}
}
if( !strFontName.empty() ) {
GlobalManager::AddFont(strFontName, size, bold, underline, italic);
}
}
else if( strClass == _T("Class") ) {
nAttributes = node.GetAttributeCount();
std::wstring strClassName;
std::wstring strAttribute;
for( int i = 0; i < nAttributes; i++ ) {
strName = node.GetAttributeName(i);
strValue = node.GetAttributeValue(i);
if( strName == _T("name") ) {
strClassName = strValue;
}
else if( strName == _T("value") ) {
strAttribute.append(strValue);
}
else {
strAttribute.append(StringHelper::Printf(L" %s=\"%s\"",
strName.c_str(), strValue.c_str()));
}
}
if( !strClassName.empty() ) {
StringHelper::TrimLeft(strAttribute);
GlobalManager::AddClass(strClassName, strAttribute);
}
}
else if( strClass == _T("TextColor") ) {
nAttributes = node.GetAttributeCount();
std::wstring strColorName;
std::wstring strColor;
for( int i = 0; i < nAttributes; i++ ) {
strName = node.GetAttributeName(i);
strValue = node.GetAttributeValue(i);
if( strName == _T("name") ) {
strColorName = strValue;
}
else if( strName == _T("value") ) {
strColor = strValue;
}
}
if( !strColorName.empty()) {
GlobalManager::AddTextColor(strColorName, strColor);
}
}
}
}
else if ( strClass == _T("Window") )
{
for( CMarkupNode node = root.GetChild() ; node.IsValid(); node = node.GetSibling() ) {
strClass = node.GetName();
if( strClass == _T("Class") ) {
nAttributes = node.GetAttributeCount();
std::wstring strClassName;
std::wstring strAttribute;
for( int i = 0; i < nAttributes; i++ ) {
strName = node.GetAttributeName(i);
strValue = node.GetAttributeValue(i);
if( strName == _T("name") ) {
strClassName = strValue;
}
else if( strName == _T("value") ) {
strAttribute.append(strValue);
}
else {
strAttribute.append(StringHelper::Printf(L" %s=\"%s\"",
strName.c_str(), strValue.c_str()));
}
}
if( !strClassName.empty() ) {
ASSERT( GlobalManager::GetClassAttributes(strClassName).empty() ); //窗口中的Class不能与全局的重名
StringHelper::TrimLeft(strAttribute);
pManager->AddClass(strClassName, strAttribute);
}
}
}
}
}
for( CMarkupNode node = root.GetChild() ; node.IsValid(); node = node.GetSibling() ) {
std::wstring strClass = node.GetName();
if( strClass == _T("Image") || strClass == _T("Font")
|| strClass == _T("Class") || strClass == _T("TextColor") ) {
}
else {
if (!pUserDefinedBox) {
return (Box*)_Parse(&root, pParent, pManager);
}
else {
int nAttributes = node.GetAttributeCount();
for( int i = 0; i < nAttributes; i++ ) {
ASSERT(i == 0 || _tcscmp(node.GetAttributeName(i), _T("class")) != 0); //class必须是第一个属性
pUserDefinedBox->SetAttribute(node.GetAttributeName(i), node.GetAttributeValue(i));
}
_Parse(&node, pUserDefinedBox, pManager);
return pUserDefinedBox;
}
}
}
return nullptr;
}
CMarkup* WindowBuilder::GetMarkup()
{
return &m_xml;
}
void WindowBuilder::GetLastErrorMessage(LPTSTR pstrMessage, SIZE_T cchMax) const
{
return m_xml.GetLastErrorMessage(pstrMessage, cchMax);
}
void WindowBuilder::GetLastErrorLocation(LPTSTR pstrSource, SIZE_T cchMax) const
{
return m_xml.GetLastErrorLocation(pstrSource, cchMax);
}
Control* WindowBuilder::_Parse(CMarkupNode* pRoot, Control* pParent, Window* pManager)
{
Control* pReturn = NULL;
for( CMarkupNode node = pRoot->GetChild() ; node.IsValid(); node = node.GetSibling() ) {
std::wstring strClass = node.GetName();
if( strClass == _T("Image") || strClass == _T("Font")
|| strClass == _T("Class") || strClass == _T("TextColor") ) {
continue;
}
Control* pControl = NULL;
if( strClass == _T("Include") ) {
if( !node.HasAttributes() ) continue;
int nCount = 1;
LPTSTR pstr = NULL;
TCHAR szValue[500] = { 0 };
SIZE_T cchLen = lengthof(szValue) - 1;
if ( node.GetAttributeValue(_T("count"), szValue, cchLen) )
nCount = _tcstol(szValue, &pstr, 10);
cchLen = lengthof(szValue) - 1;
if ( !node.GetAttributeValue(_T("source"), szValue, cchLen) ) continue;
for ( int i = 0; i < nCount; i++ ) {
WindowBuilder builder;
pControl = builder.Create((LPCTSTR)szValue, m_createControlCallback, pManager, (Box*)pParent);
}
continue;
}
else {
pControl = CreateControlByClass(strClass);
if (pControl == nullptr) {
if (strClass == L"Event" || strClass == L"BubbledEvent") {
bool bBubbled = (strClass == L"BubbledEvent");
AttachXmlEvent(bBubbled, node, pParent);
continue;
}
}
// User-supplied control factory
if( pControl == NULL ) {
pControl = GlobalManager::CreateControl(strClass);
}
if( pControl == NULL && m_createControlCallback ) {
pControl = m_createControlCallback(strClass);
}
}
if( pControl == NULL ) {
ASSERT(FALSE);
continue;
}
pControl->SetWindow(pManager);
// Process attributes
if( node.HasAttributes() ) {
// Set ordinary attributes
int nAttributes = node.GetAttributeCount();
for( int i = 0; i < nAttributes; i++ ) {
ASSERT(i == 0 || _tcscmp(node.GetAttributeName(i), _T("class")) != 0); //class必须是第一个属性
pControl->SetAttribute(node.GetAttributeName(i), node.GetAttributeValue(i));
}
}
// Add children
if( node.HasChildren() ) {
_Parse(&node, (Box*)pControl, pManager);
}
// Attach to parent
// 因为某些属性和父窗口相关比如selected必须先Add到父窗口
if( pParent != NULL ) {
Box* pContainer = dynamic_cast<Box*>(pParent);
ASSERT(pContainer);
if( pContainer == NULL ) return NULL;
if( !pContainer->Add(pControl) ) {
ASSERT(FALSE);
delete pControl;
continue;
}
}
// Return first item
if( pReturn == NULL ) pReturn = pControl;
}
return pReturn;
}
Control* WindowBuilder::CreateControlByClass(const std::wstring& strControlClass)
{
Control* pControl = nullptr;
SIZE_T cchLen = strControlClass.length();
switch( cchLen ) {
case 3:
if( strControlClass == DUI_CTR_BOX ) pControl = new Box;
break;
case 4:
if( strControlClass == DUI_CTR_HBOX ) pControl = new HBox;
else if( strControlClass == DUI_CTR_VBOX ) pControl = new VBox;
break;
case 5:
if( strControlClass == DUI_CTR_COMBO ) pControl = new Combo;
else if( strControlClass == DUI_CTR_LABEL ) pControl = new Label;
break;
case 6:
if( strControlClass == DUI_CTR_BUTTON ) pControl = new Button;
else if( strControlClass == DUI_CTR_OPTION ) pControl = new Option;
else if( strControlClass == DUI_CTR_SLIDER ) pControl = new Slider;
else if( strControlClass == DUI_CTR_TABBOX ) pControl = new TabBox;
break;
case 7:
if( strControlClass == DUI_CTR_CONTROL ) pControl = new Control;
else if( strControlClass == DUI_CTR_TILEBOX ) pControl = new TileBox;
else if (strControlClass == DUI_CTR_LISTBOX) pControl = new ListBox(new Layout);
//else if( pstrClass == DUI_CTR_ACTIVEX ) pControl = new ActiveX;
break;
case 8:
if( strControlClass == DUI_CTR_PROGRESS ) pControl = new Progress;
else if( strControlClass == DUI_CTR_RICHEDIT ) pControl = new RichEdit;
else if( strControlClass == DUI_CTR_CHECKBOX ) pControl = new CheckBox;
//else if( pstrClass == DUI_CTR_DATETIME ) pControl = new DateTime;
else if( strControlClass == DUI_CTR_TREEVIEW ) pControl = new TreeView;
else if( strControlClass == DUI_CTR_TREENODE ) pControl = new TreeNode;
else if( strControlClass == DUI_CTR_HLISTBOX ) pControl = new ListBox(new HLayout);
else if( strControlClass == DUI_CTR_VLISTBOX ) pControl = new ListBox(new VLayout);
else if ( strControlClass == DUI_CTR_CHILDBOX ) pControl = new ChildBox;
else if( strControlClass == DUI_CTR_LABELBOX ) pControl = new LabelBox;
break;
case 9:
if( strControlClass == DUI_CTR_SCROLLBAR ) pControl = new ScrollBar;
else if( strControlClass == DUI_CTR_BUTTONBOX ) pControl = new ButtonBox;
else if( strControlClass == DUI_CTR_OPTIONBOX ) pControl = new OptionBox;
break;
case 10:
//if( pstrClass == DUI_CTR_WEBBROWSER ) pControl = new WebBrowser;
break;
case 11:
if( strControlClass == DUI_CTR_TILELISTBOX ) pControl = new ListBox(new TileLayout);
else if( strControlClass == DUI_CTR_CHECKBOXBOX ) pControl = new CheckBoxBox;
break;
case 14:
if (strControlClass == DUI_CTR_VIRTUALLISTBOX) pControl = new VirtualListBox;
break;
case 15:
break;
case 16:
break;
case 20:
if( strControlClass == DUI_CTR_LISTCONTAINERELEMENT ) pControl = new ListContainerElement;
break;
}
return pControl;
}
void WindowBuilder::AttachXmlEvent(bool bBubbled, CMarkupNode& node, Control* pParent)
{
auto nAttributes = node.GetAttributeCount();
std::wstring strType;
std::wstring strReceiver;
std::wstring strApplyAttribute;
std::wstring strName;
std::wstring strValue;
for( int i = 0; i < nAttributes; i++ ) {
strName = node.GetAttributeName(i);
strValue = node.GetAttributeValue(i);
ASSERT(i != 0 || strName == _T("type"));
ASSERT(i != 1 || strName == _T("receiver"));
ASSERT(i != 2 || strName == _T("applyattribute"));
if( strName == _T("type") ) {
strType = strValue;
}
else if( strName == _T("receiver") ) {
strReceiver = strValue;
}
else if( strName == _T("applyattribute") ) {
strApplyAttribute = strValue;
}
}
auto typeList = StringHelper::Split(strType, L" ");
auto receiverList = StringHelper::Split(strReceiver, L" ");
for (auto itType = typeList.begin(); itType != typeList.end(); itType++) {
for (auto itReceiver = receiverList.begin(); itReceiver != receiverList.end(); itReceiver++) {
EventType eventType = StringToEnum(*itType);
auto callback = nbase::Bind(&Control::OnApplyAttributeList, pParent, *itReceiver, strApplyAttribute, std::placeholders::_1);
if (bBubbled == false) {
pParent->AttachXmlEvent(eventType, callback);
}
else {
if (Box* tmpParent = dynamic_cast<Box*>(pParent)) {
tmpParent->AttachXmlBubbledEvent(eventType, callback);
}
else {
ASSERT(FALSE);
}
}
}
}
}
} // namespace ui