| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- #include "pch.h"
- #include "CDiandanNatureItemUI.h"
- #include "../wnd/CDiandanNatureWnd.h"
- namespace
- {
- // 测量指定字体下文本的像素宽度(GDI,用于 mini-html {x offset} 右对齐加价)
- int MeasureTextWidth(DuiLib::CPaintManagerUI* pManager, int fontId, const std::wstring& text)
- {
- if (!pManager || text.empty()) return 0;
- DuiLib::TFontInfo* pFontInfo = pManager->GetFontInfo(fontId);
- if (!pFontInfo || !pFontInfo->hFont) return 0;
- HDC hdc = GetDC(NULL);
- if (!hdc) return 0;
- HDC memDC = CreateCompatibleDC(hdc);
- int width = 0;
- if (memDC)
- {
- HGDIOBJ hOldFont = SelectObject(memDC, pFontInfo->hFont);
- SIZE size = { 0, 0 };
- if (GetTextExtentPoint32W(memDC, text.c_str(), (int)text.length(), &size))
- {
- width = size.cx;
- }
- SelectObject(memDC, hOldFont);
- DeleteDC(memDC);
- }
- ReleaseDC(NULL, hdc);
- return width;
- }
- // 去掉属性值名称末尾的加价后缀(如 +3 / +27 / +0.5),避免与右侧红橙价重复
- // 规则:尾部空格 + +号 + 可选小数数字;若去掉后为空则保留原名,防止无名称
- std::wstring StripTrailingPrice(const std::wstring& name)
- {
- if (name.empty()) return name;
- int n = (int)name.size();
- int i = n - 1;
- while (i >= 0 && name[i] == L' ') i--;
- if (i < 0) return name;
- // 必须以数字结尾
- if (i >= 0 && name[i] >= L'0' && name[i] <= L'9')
- {
- // 整数部分
- while (i >= 0 && name[i] >= L'0' && name[i] <= L'9') i--;
- // 可选小数部分:.digits
- if (i >= 0 && name[i] == L'.')
- {
- int dotPos = i;
- int j = i - 1;
- while (j >= 0 && name[j] >= L'0' && name[j] <= L'9') j--;
- if (j < dotPos - 1) i = j; // 小数点后有数字,一起去掉
- }
- // 前面必须是 '+'
- if (i >= 0 && name[i] == L'+')
- {
- int cut = i;
- while (cut > 0 && name[cut - 1] == L' ') cut--;
- if (cut > 0) return name.substr(0, cut);
- // 整个字符串只剩下 +N 时保留原名,避免按钮名字为空
- return name;
- }
- }
- return name;
- }
- }
- CDiandanNatureItemUI::CDiandanNatureItemUI()
- {
- }
- CDiandanNatureItemUI::~CDiandanNatureItemUI()
- {
- }
- void CDiandanNatureItemUI::SetNatureName(std::string name)
- {
- m_nature_name = name;
- CLabelUI* pName = static_cast<CLabelUI*>(this->FindSubControl(_T("diandan_nature_layout_name")));
- pName->SetText(CLewaimaiString::UTF8ToUnicode(name).c_str());
- }
- void CDiandanNatureItemUI::SetNatureLimitChoose(std::string limit_choose)
- {
- m_nLimitChoose = atoi(limit_choose.c_str());
- }
- void CDiandanNatureItemUI::SetNatureNameNum(int nNum)
- {
- m_nNatureNameNum = nNum;
- }
- void CDiandanNatureItemUI::addNatureValue(FoodNatureValue value)
- {
- m_nature_value.push_back(value);
- }
- std::wstring CDiandanNatureItemUI::MakeBtnText(DuiLib::CPaintManagerUI* pManager, const std::wstring& name, int value, bool selected)
- {
- // 去掉商品属性值名称末尾自带的加价后缀(如 "+3"),避免与右侧红橙价重复显示
- std::wstring baseName = StripTrailingPrice(name);
- if (baseName.empty()) baseName = name;
- std::wstring s = baseName;
- if (value > 0)
- {
- // 文本区宽度 = 按钮 185 - 左 padding 12 - 右 padding 12 - 右侧安全边距 2
- const int TEXT_AREA_W = 185 - 12 - 12 - 2;
- int nameFontId = selected ? 112 : 12; // 选中 13 粗体 / 未选 13 常规
- int priceFontId = 112; // 加价始终 13px 粗体(与属性名同字号;选中/未选中都加粗)
- // 加价:暖红橙 #F5623D + 13 粗体,与属性名同字号但恒定加粗
- // 数字前加人民币符号 ¥(紧贴数字,+ 为加价标识)
- std::wstring price = L"+¥" + std::to_wstring(value);
- int priceW = MeasureTextWidth(pManager, priceFontId, price);
- const int MIN_GAP = 4; // 名称与加价之间的最小间距
- // 名称超长时截断并加省略号,保证加价始终完整可见(不会被右侧 padding 裁掉)
- std::wstring showName = baseName;
- int nameW = MeasureTextWidth(pManager, nameFontId, showName);
- int availForName = TEXT_AREA_W - priceW - MIN_GAP;
- if (nameW > availForName)
- {
- std::wstring trunc = baseName;
- while (trunc.length() > 1)
- {
- trunc = trunc.substr(0, trunc.length() - 1);
- if (MeasureTextWidth(pManager, nameFontId, trunc + L"…") <= availForName) break;
- }
- showName = trunc + L"…";
- nameW = MeasureTextWidth(pManager, nameFontId, showName);
- }
- int offset = TEXT_AREA_W - nameW - priceW;
- if (offset < MIN_GAP) offset = MIN_GAP; // 兜底间距,防止极端情况下重叠
- // 仅改红色 + 强制 13 粗体(选中/未选中都加粗,font 112),与属性名同字号
- s = showName + L"{x " + std::to_wstring(offset) + L"}<c #F5623D><f 112>" + price + L"</f></c>";
- }
- return s;
- }
- void CDiandanNatureItemUI::ApplySelectStyle(CButtonUI* pBtn, int index, bool selected)
- {
- DuiLib::CPaintManagerUI* pManager = pBtn->GetManager();
- if (selected)
- {
- // C3 选中态:白底 + 主绿描边 + 绿字
- pBtn->SetNormalImage(L"file='nature_pill_sel_n.png'");
- pBtn->SetHotImage(L"file='nature_pill_sel_h.png'");
- pBtn->SetPushedImage(L"file='nature_pill_sel_p.png'");
- pBtn->SetTextColor(0xFF60B177);
- pBtn->SetHotTextColor(0xFF60B177);
- pBtn->SetPushedTextColor(0xFF60B177);
- pBtn->SetFont(112);
- }
- else
- {
- // C3 未选中态:白底 + 浅灰描边 + 深色字
- pBtn->SetNormalImage(L"file='nature_pill_n.png'");
- pBtn->SetHotImage(L"file='nature_pill_h.png'");
- pBtn->SetPushedImage(L"file='nature_pill_p.png'");
- pBtn->SetTextColor(0xFF1F2329);
- pBtn->SetHotTextColor(0xFF1F2329);
- pBtn->SetPushedTextColor(0xFF1F2329);
- pBtn->SetFont(12);
- }
- FoodNatureValue& v = m_nature_value[index];
- pBtn->SetText(MakeBtnText(pManager, CLewaimaiString::UTF8ToUnicode(v.name), v.value, selected).c_str());
- pBtn->Invalidate();
- }
- void CDiandanNatureItemUI::ShowNatureValue()
- {
- CHorizontalLayoutUI* pValueLayout = static_cast<CHorizontalLayoutUI*>(this->FindSubControl(_T("diandan_nature_layout_value")));
- int totoal_value_size = m_nature_value.size();
- int nRows = (totoal_value_size - 1) / 4 + 1;
- int nCols = 4;
- //设置属性区域的高度
- pValueLayout->SetFixedHeight(nRows * 54);
- // 组高 = 网格高 + 分组头 28 + 头与网格间距 12(childpadding) + 顶 padding 10
- // 注意:XML 中 padding top=10 会减少内容区高度,必须同步补回来,否则最后一行底部被截断
- this->SetFixedHeight(nRows * 54 + 28 + 12 + 10);
- //开始设置每个控件的位置
- int value_num = 0;
- for (std::vector<FoodNatureValue>::iterator it = m_nature_value.begin(); it != m_nature_value.end(); it++)
- {
- //这里面的是属性值信息
- CButtonUI* newButton = new CButtonUI();
- newButton->SetFixedWidth(185);
- newButton->SetFixedHeight(44);
- newButton->SetShowHtml(true);
- newButton->SetTextPadding(RECT{ 12, 0, 12, 0 });
- newButton->SetBorderSize(0);
- newButton->SetBkColor(0);
- newButton->SetHotBkColor(0);
- newButton->SetPushedBkColor(0);
- //设置定义属性,在点击按钮的时候好区分
- newButton->SetAttribute(L"name", L"diandan_nature_value_btn");
- newButton->AddCustomAttribute(L"nature_name_num", std::to_wstring(m_nNatureNameNum).c_str());
- newButton->AddCustomAttribute(L"nature_value_num", std::to_wstring(value_num).c_str());
- //必须先Add,才能调用下面的SetPos,否则无效
- pValueLayout->Add(newButton);
- //设置位置,根据行数和列数来计算,行数和列数第一个都是1,按钮宽度185,高度44,右和下间距10
- int curRow = value_num / 4 + 1;
- int curCol = value_num % 4 + 1;
- RECT rect;
- rect.left = (curCol - 1) * 195;
- rect.right = rect.left + 185;
- rect.top = (curRow - 1) * 54;
- rect.bottom = rect.top + 44;
- newButton->SetFloat(true);
- // 强制设置固定大小和位置
- SIZE size;
- size.cx = rect.left;
- size.cy = rect.top;
- newButton->SetFixedXY(size);
- newButton->SetFixedWidth(rect.right - rect.left);
- newButton->SetFixedHeight(rect.bottom - rect.top);
- //默认未选中样式(C3 白底描边 + 右对齐加价)
- ApplySelectStyle(newButton, value_num, false);
- value_num++;
- }
- //初始化选中
- //如果是点击商品的,默认选中第一个
- if (m_InitFoodNatureSelectValue.m_nature_selects.size() == 0)
- {
- m_nature_value[0].is_select = true;
- CButtonUI* newButton = static_cast<CButtonUI*>(pValueLayout->GetItemAt(0));
- ApplySelectStyle(newButton, 0, true);
- m_nSelectNum = 1;
- }
- else
- {
- m_nSelectNum = 0;
- //可能有1到多个商品属性值被选中
- for (std::vector< FoodNatureSelectValueInfo>::iterator it = m_InitFoodNatureSelectValue.m_nature_selects.begin(); it != m_InitFoodNatureSelectValue.m_nature_selects.end(); it++)
- {
- int index = (*it).nature_select_index;
- m_nature_value[index].is_select = true;
- CButtonUI* newButton = static_cast<CButtonUI*>(pValueLayout->GetItemAt(index));
- ApplySelectStyle(newButton, index, true);
- m_nSelectNum++;
- }
- }
- }
- void CDiandanNatureItemUI::SetNatureSelected(int index)
- {
- CHorizontalLayoutUI* pValueLayout = static_cast<CHorizontalLayoutUI*>(this->FindSubControl(_T("diandan_nature_layout_value")));
- if (m_nature_value[index].is_select == true)
- {
- //点击的这个当前是选中状态
- if (m_nLimitChoose == 1)
- {
- //如果最多就只能选一个属性值的,点了选中状态的就没变化
- }
- else
- {
- //如果是可以选多个值的,点了选中状态就改为非选中状态
- if (m_nSelectNum == 1)
- {
- m_pNatureWnd->ShowToast(L"最少选择1个属性");
- return;
- }
- m_nature_value[index].is_select = false;
- CButtonUI* old_btn = static_cast<CButtonUI*>(pValueLayout->GetItemAt(index));
- ApplySelectStyle(old_btn, index, false);
- m_nSelectNum--;
- }
- }
- else
- {
- //点击的这个是非选中状态
- if (m_nLimitChoose == 1)
- {
- //如果最大限制就是1个,点击非选中状态的,就自动选中这个
- int num = 0;
- for (std::vector<FoodNatureValue>::iterator it = m_nature_value.begin(); it != m_nature_value.end(); it++)
- {
- if (it->is_select == true)
- {
- //把旧的选中的设为非选中
- m_nature_value[num].is_select = false;
- CButtonUI* old_btn = static_cast<CButtonUI*>(pValueLayout->GetItemAt(num));
- ApplySelectStyle(old_btn, num, false);
- }
- num++;
- }
- //再把刚点击的设为选中
- m_nature_value[index].is_select = true;
- CButtonUI* new_btn = static_cast<CButtonUI*>(pValueLayout->GetItemAt(index));
- ApplySelectStyle(new_btn, index, true);
- }
- else
- {
- if (m_nSelectNum >= m_nLimitChoose)
- {
- m_pNatureWnd->ShowToast(L"最多选择" + std::to_wstring(m_nLimitChoose) + L"个属性");
- return;
- }
- //否则进行选中
- m_nature_value[index].is_select = true;
- CButtonUI* new_btn = static_cast<CButtonUI*>(pValueLayout->GetItemAt(index));
- ApplySelectStyle(new_btn, index, true);
- m_nSelectNum++;
- }
- }
- }
- std::string CDiandanNatureItemUI::GetNatureName()
- {
- return m_nature_name;
- }
- int CDiandanNatureItemUI::GetNatureNameNum()
- {
- return m_nNatureNameNum;
- }
- std::vector<FoodNatureSelectValueInfo> CDiandanNatureItemUI::GetSelectedNatureInfo()
- {
- std::vector<FoodNatureSelectValueInfo> infoArray;
- int num = 0;
- for (std::vector<FoodNatureValue>::iterator it = m_nature_value.begin(); it != m_nature_value.end(); it++)
- {
- if (it->is_select == true)
- {
- FoodNatureSelectValueInfo newInfo;
- newInfo.nature_select_name = (*it).name;
- newInfo.nature_select_value = (*it).value;
- newInfo.nature_select_index = num;
- infoArray.push_back(newInfo);
- }
- num++;
- }
- return infoArray;
- }
|