From 6dc80508b1c0f431007f8a8c947c152ec00c3d15 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期一, 08 九月 2025 09:24:05 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang

---
 SourceCode/Bond/Servo/CExpandableListCtrl.cpp |  192 ++++++++++++++++++++++++++++++++++++------------
 1 files changed, 144 insertions(+), 48 deletions(-)

diff --git a/SourceCode/Bond/Servo/CExpandableListCtrl.cpp b/SourceCode/Bond/Servo/CExpandableListCtrl.cpp
index c15cf59..11470ce 100644
--- a/SourceCode/Bond/Servo/CExpandableListCtrl.cpp
+++ b/SourceCode/Bond/Servo/CExpandableListCtrl.cpp
@@ -19,16 +19,18 @@
 
     // 鎶ヨ〃椋庢牸鍒椾妇渚�
     SetExtendedStyle(GetExtendedStyle()
-        | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_GRIDLINES);
-
-    // 绀轰緥鍒楋紙鍙湪澶栭儴璁剧疆锛�
-    if (GetHeaderCtrl() == nullptr || GetHeaderCtrl()->GetItemCount() == 0) {
-        InsertColumn(0, _T("鍚嶇О"), LVCFMT_LEFT, 260);
-        InsertColumn(1, _T("鐘舵��"), LVCFMT_LEFT, 120);
-        InsertColumn(2, _T("鎻忚堪"), LVCFMT_LEFT, 260);
-    }
+        | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
 
     return 0;
+}
+
+void CExpandableListCtrl::PreSubclassWindow()
+{
+    // 鎶ヨ〃椋庢牸鍒椾妇渚�
+    SetExtendedStyle(GetExtendedStyle()
+        | LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
+
+    CListCtrl::PreSubclassWindow();
 }
 
 CExpandableListCtrl::Node* CExpandableListCtrl::InsertRoot(const std::vector<CString>& cols)
@@ -119,20 +121,25 @@
 
 CRect CExpandableListCtrl::expanderRectForRow(int row) const
 {
-    CRect rc;
-    // 鍙栭鍒楃煩褰�
-    if (!GetSubItemRect(row, 0, LVIR_BOUNDS, rc))
+    CRect rcLabel;
+    if (!const_cast<CExpandableListCtrl*>(this)->GetSubItemRect(row, 0, LVIR_LABEL, rcLabel))
         return CRect(0, 0, 0, 0);
 
     Node* n = const_cast<CExpandableListCtrl*>(this)->GetNodeByVisibleIndex(row);
-    int indent = (n ? n->level : 0);
+    if (!n || n->children.empty())
+        return CRect(0, 0, 0, 0); // 鍙跺瓙涓嶅崰浣嶏紝鏂囨湰灏变笉浼氳澶氭帹涓�鏍�
 
-    // 缂╄繘锛氭瘡绾х粰 16px
-    int left = rc.left + m_expanderPadding + indent * 16;
-    CRect box(left, rc.CenterPoint().y - m_expanderSize / 2,
-        left + m_expanderSize, rc.CenterPoint().y + m_expanderSize / 2);
-    return box;
+    const int indent = n->level;
+    const int left = rcLabel.left + m_expanderPadding + indent * 16;
+
+    return CRect(
+        left,
+        rcLabel.CenterPoint().y - m_expanderSize / 2,
+        left + m_expanderSize,
+        rcLabel.CenterPoint().y + m_expanderSize / 2
+    );
 }
+
 
 void CExpandableListCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult)
 {
@@ -168,50 +175,139 @@
 
     case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
     {
-        int row = (int)pCD->nmcd.dwItemSpec;
-        int col = pCD->iSubItem;
+        const int row = (int)pCD->nmcd.dwItemSpec;
+        const int col = pCD->iSubItem;
         CDC* pDC = CDC::FromHandle(pCD->nmcd.hdc);
 
-        // 浠呭湪棣栧垪缁樺埗灞曞紑鎸夐挳涓庣缉杩涘紩瀵�
-        if (col == 0) {
-            CRect rc;
-            GetSubItemRect(row, 0, LVIR_BOUNDS, rc);
-
-            // 榛樿鏂囨湰璁╃郴缁熺敾锛氭垜浠厛鐢绘寜閽拰缂╄繘鑳屾櫙锛屽啀杩斿洖 CDRF_DODEFAULT
+        if (col == 0)
+        {
+            CRect rc; GetSubItemRect(row, 0, LVIR_LABEL, rc);
             Node* n = GetNodeByVisibleIndex(row);
-            if (n) {
-                // 缁樺埗灞曞紑涓夎/鏂瑰潡
-                if (!n->children.empty()) {
-                    CRect box = expanderRectForRow(row);
-                    // 灏忔柟妗�
-                    pDC->Rectangle(box);
+            if (!n) { *pResult = CDRF_DODEFAULT; return; }
 
-                    // 鐢烩��+鈥濇垨鈥�-鈥�
-                    CPen pen(PS_SOLID, 1, RGB(0, 0, 0));
-                    CPen* oldPen = pDC->SelectObject(&pen);
-                    // 妯嚎
-                    pDC->MoveTo(box.left + 2, box.CenterPoint().y);
-                    pDC->LineTo(box.right - 2, box.CenterPoint().y);
-                    if (!n->expanded) {
-                        // 绔栫嚎锛堣〃绀� + 鍙凤級
-                        pDC->MoveTo(box.CenterPoint().x, box.top + 2);
-                        pDC->LineTo(box.CenterPoint().x, box.bottom - 2);
-                    }
-                    pDC->SelectObject(oldPen);
+            // 1) 鑳屾櫙/鍓嶆櫙棰滆壊锛氭寜鏄惁閫変腑
+            const bool selected = (GetItemState(row, LVIS_SELECTED) & LVIS_SELECTED) != 0;
+            const bool focusOnCtrl = (GetSafeHwnd() == ::GetFocus());
+            COLORREF bk = selected ? GetSysColor(focusOnCtrl ? COLOR_HIGHLIGHT : COLOR_3DFACE)
+                : ListView_GetBkColor(m_hWnd);
+            COLORREF txt = selected ? GetSysColor(focusOnCtrl ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT)
+                : ListView_GetTextColor(m_hWnd);
+
+            // 浠呭湪闇�瑕佹椂濉厖鑳屾櫙锛堥伩鍏嶁�滈粦涓�鐗団�濓級
+            CBrush bkBrush(bk);
+            pDC->FillRect(rc, &bkBrush);
+
+            // 2) 灞曞紑/鎶樺彔鎸囩ず锛堝弬鑰冩棫椤圭洰鐨勫彸瀵归綈鍧愭爣娉曪紝鍋氬儚绱犲榻愶紝绾疓DI锛�
+            if (!n->children.empty())
+            {
+                CRect box = expanderRectForRow(row);
+
+                // ---- 鍙皟鍙傛暟锛氫笌鏃т唬鐮佸懡鍚嶄竴鑷� ----
+                // 鍙充晶鐣欑櫧锛堜笌鏂囨湰闂撮殭/缃戞牸绾夸繚鎸佽窛绂伙級
+                const int ROFFSET = 2;
+                // 闂悎/灞曞紑鐨勨�滃搴︹�濊缃細濂囨暟鏇撮『鐪硷紙9/11 閮借锛�
+                const int WIDE = max(9, min(min(box.Width(), box.Height()), 13)); // 鈻� 鐨勮竟闀�
+                const int WIDE2 = WIDE / 2;                                        // 涓�鍗�
+                const int EXPANDED_WIDE = WIDE;                                           // 鈻� 鐨勮竟闀�
+
+                // 杞诲井鍐呯缉锛岄伩鍏嶈创杈癸紙涓庝綘鏃т唬鐮佲�滄寜閽鍒蜂竴涓嬧�濆悓鏁堬級
+                box.DeflateRect(1, 1);
+
+                // 缁熶竴鍋氬伓鏁板榻愶紝鍑忓皯鍗婂儚绱犻敮榻�
+                auto even = [](int v) { return (v & 1) ? (v - 1) : v; };
+
+                // 璁$畻鈥滆嚜涓嬪悜涓娾�濈殑鍩哄噯鍋忕Щ锛屼笌鏃� TreeCtrl 涓�鑷�
+                // 杩欓噷鐢� box 浣滀负 pRect
+                POINT pt[3];
+                if (n->expanded) {
+                    // 鈻�
+                    int nBottomOffset = (box.Height() - EXPANDED_WIDE) / 2;
+                    pt[0].x = box.right - ROFFSET - EXPANDED_WIDE;
+                    pt[0].y = box.bottom - nBottomOffset;
+                    pt[1].x = box.right - ROFFSET;
+                    pt[1].y = box.bottom - nBottomOffset;
+                    pt[2].x = box.right - ROFFSET;
+                    pt[2].y = box.bottom - nBottomOffset - EXPANDED_WIDE;
+                }
+                else {
+                    // 鈻�
+                    int nBottomOffset = (box.Height() - WIDE) / 2;
+
+                    pt[0].x = box.right - ROFFSET - WIDE2;
+                    pt[0].y = box.bottom - nBottomOffset - WIDE;
+                    pt[1].x = box.right - ROFFSET - WIDE2;
+                    pt[1].y = box.bottom - nBottomOffset;
+                    pt[2].x = box.right - ROFFSET;
+                    pt[2].y = box.bottom - nBottomOffset - WIDE2;
                 }
 
-                // 鎶婃枃鏈乏杈圭晫鍙崇Щ锛岀暀鍑虹缉杩涗笌鎸夐挳绌洪棿
-                // 杩欓噷涓嶆敼绯荤粺缁樺埗鐨勬枃鏈捣鐐癸紝鑰屾槸閫氳繃鍦ㄦ枃鏈墠缃┖鏍肩殑鏂瑰紡澶勭悊鏇寸畝鍗曪細
-                // 鎴戜滑鐩存帴鏀规樉绀烘枃鏈紙鎬ц兘瓒冲锛夛細鍦� RebuildVisible 鏃跺凡缁忓~浜嗙函鏂囨湰銆�
-                // 濡傛灉浣犺绮惧噯鎺у埗鏂囨湰浣嶇疆锛屽彲浠ユ敼 OWNERDRAW 鎴栬嚜缁樻枃鏈��
+                // 浠呭~鍏咃紝涓嶆弿杈癸紙鎻忚竟浼氬姞閲嶅彴闃舵劅锛夛紱棰滆壊鐢� txt 涓庝富棰樹竴鑷�
+                HGDIOBJ oldPen = pDC->SelectObject(GetStockObject(NULL_PEN));
+                HBRUSH   hBrush = CreateSolidBrush(txt);
+                HGDIOBJ oldBrush = pDC->SelectObject(hBrush);
+
+                pDC->Polygon(pt, 3);
+
+                pDC->SelectObject(oldPen);
+                pDC->SelectObject(oldBrush);
+                DeleteObject(hBrush);
             }
+
+
+
+            // 3) 鏂囨湰锛氬熀浜庨鍒楀尯鍩熷彸绉伙紙鍖哄垎鏄惁鏈夊瓙鑺傜偣锛�
+            const int indentPx = n->level * 14;
+            const int baseLeft = rc.left + m_expanderPadding + indentPx;
+
+            CRect textRc = rc;
+            if (!n->children.empty()) {
+                // 鏈夊瓙椤癸細棰勭暀鎸夐挳浣� + 鏂囨湰闂撮殭
+                textRc.left = baseLeft + m_expanderSize + m_textGap;
+            }
+            else {
+                // 鍙跺瓙琛岋細涓嶉鐣欐寜閽綅锛屽彧缁欎竴鐐圭偣鍙跺瓙闂撮殭锛堣灞傜骇缂╄繘浠嶇劧鐢熸晥锛�
+                constexpr int kLeafGap = 2; // 浣犲彲璋� 0~4
+                textRc.left = baseLeft + kLeafGap;
+            }
+
+            pDC->SetBkMode(TRANSPARENT);
+            pDC->SetTextColor(txt);
+            CString txt0 = n->cols.empty() ? _T("") : n->cols[0];
+            pDC->DrawText(txt0, textRc, DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS);
+
+
+            // 鈥斺�� 鐢诲畬涓夎涓庢枃鏈箣鍚庯紝琛ヤ竴鏉¤琛岀殑搴曢儴妯悜缃戞牸绾� 鈥斺��
+            // 浠呭綋寮�鍚簡 LVS_EX_GRIDLINES 鎵嶇粯鍒�
+            if (GetExtendedStyle() & LVS_EX_GRIDLINES)
+            {
+                // 鐢ㄦ暣琛� bounds锛屼繚璇佹í绾胯疮绌挎墍鏈夊垪鐨勫彲瑙佸搴�
+                CRect rcRow;
+                GetSubItemRect(row, 0, LVIR_BOUNDS, rcRow);
+
+                // 搴曡竟 y 鍧愭爣锛堜笌绯荤粺缃戞牸绾垮榻愶級
+                const int y = rcRow.bottom - 1;
+
+                // 棰滆壊涓庣郴缁熼鏍兼帴杩戯紱鑻ヨ寰楀亸娴咃紝鍙崲 COLOR_3DSHADOW
+                CPen pen(PS_SOLID, 1, GetSysColor(COLOR_3DLIGHT));
+                CPen* oldPen = pDC->SelectObject(&pen);
+
+                // 妯嚎浠庤宸﹀埌琛屽彸锛堝綋鍓嶅彲瑙佸尯鍩燂級
+                pDC->MoveTo(rcRow.left, y);
+                pDC->LineTo(rcRow.right, y);
+
+                pDC->SelectObject(oldPen);
+            }
+
+            *pResult = CDRF_SKIPDEFAULT;
+            return;
         }
 
+        // 鍏朵粬鍒楅粯璁ょ粯鍒�
         *pResult = CDRF_DODEFAULT;
         return;
     }
+
     }
 
     *pResult = CDRF_DODEFAULT;
 }
-

--
Gitblit v1.9.3