From 6747bc043d0af20d6fa02a6cf385d81eb44643d0 Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期六, 28 六月 2025 11:29:42 +0800
Subject: [PATCH] 1.自绘按钮,修改为支持文字在按钮下,或在按钮右。 2.日志页,修改为“包含”和“排除”关键字,以及正则表达式的支持,便于在调试过程中快速观察日志

---
 SourceCode/Bond/Servo/Configuration.h            |    2 
 SourceCode/Bond/Servo/BlButton.h                 |    2 
 SourceCode/Bond/Servo/PageLog.h                  |   11 ++
 SourceCode/Bond/x64/Debug/Res/logcat_include.ico |    0 
 SourceCode/Bond/Servo/LogEdit.h                  |    2 
 SourceCode/Bond/Servo/Servo.rc                   |    0 
 SourceCode/Bond/Servo/PageLog.cpp                |   62 ++++++++-------
 SourceCode/Bond/Servo/Configuration.cpp          |   11 ++
 SourceCode/Bond/Servo/LogEdit.cpp                |   64 ++++++++++-----
 SourceCode/Bond/Servo/BlButton.cpp               |   24 +++++-
 SourceCode/Bond/Servo/ServoDlg.cpp               |    7 +
 11 files changed, 125 insertions(+), 60 deletions(-)

diff --git a/SourceCode/Bond/Servo/BlButton.cpp b/SourceCode/Bond/Servo/BlButton.cpp
index 2bddd2b..ff75530 100644
--- a/SourceCode/Bond/Servo/BlButton.cpp
+++ b/SourceCode/Bond/Servo/BlButton.cpp
@@ -36,6 +36,7 @@
 	m_hIcon[1] = nullptr;
 	m_nIconWidth = 0;
 	m_nFlashState = 0;
+	m_bTextRight = FALSE;
 }
 
 
@@ -159,6 +160,11 @@
 	return m_nFlashState != 0;
 }
 
+void CBlButton::SetTextRight()
+{
+	m_bTextRight = TRUE;
+}
+
 void CBlButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
 {
 	HDC hDC = lpDrawItemStruct->hDC;
@@ -200,15 +206,24 @@
 	HICON hIcon = this->IsWindowEnabled() ? m_hIcon[0] : m_hIcon[01];
 	if (hIcon != nullptr) {
 		int xIcon = (rcClient.right - rcClient.top - m_nIconWidth) / 2;
+		if (m_bTextRight) {
+			xIcon = 15;
+		}
+
 		if (m_hMenu != nullptr) xIcon -= 10;
 		int yIcon = (rcClient.bottom - rcClient.top - m_nIconWidth) / 2;
-		if (nTextLen != 0) {
+		if (nTextLen != 0 && !m_bTextRight) {
 			yIcon -= 8;
 		}
 
 		DrawIconEx(hDC, xIcon, yIcon,
 			hIcon, m_nIconWidth, m_nIconWidth, 0, 0, DI_NORMAL);
-		rcText.top = yIcon + m_nIconWidth + 2;
+		if (m_bTextRight) {
+			rcText.left = xIcon + m_nIconWidth + 2;
+		}
+		else {
+			rcText.top = yIcon + m_nIconWidth + 2;
+		}
 	}
 
 
@@ -223,18 +238,19 @@
 	::SetBkMode(hDC, TRANSPARENT);
 	::SetTextColor(hDC, m_crText[state]);
 
+	UINT format1 = m_bTextRight ? DT_LEFT : DT_CENTER;
 	if ((BS_MULTILINE & GetStyle()) == BS_MULTILINE) {
 		CRect rcBound;
 		int height = DrawTextA(hDC, szText, (int)strlen(szText), &rcBound,  DT_CENTER | DT_CALCRECT | DT_EDITCONTROL);
 		rcText.top = rcBound.top + (rcClient.bottom - rcClient.top - height) / 2;
 		rcText.bottom = rcText.top + height;
-		DrawTextA(hDC, szText, (int)strlen(szText), &rcText,  DT_CENTER | DT_EDITCONTROL);
+		DrawTextA(hDC, szText, (int)strlen(szText), &rcText, format1 | DT_EDITCONTROL);
 	}
 	else {
 		if (m_hMenu != nullptr) {
 			rcText.right -= (10);
 		}
-		DrawTextA(hDC, szText, (int)strlen(szText), &rcText, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
+		DrawTextA(hDC, szText, (int)strlen(szText), &rcText, format1 | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
 	}
 	::SelectObject(hDC, hOldFont);
 
diff --git a/SourceCode/Bond/Servo/BlButton.h b/SourceCode/Bond/Servo/BlButton.h
index 7b9bcea..f97f9af 100644
--- a/SourceCode/Bond/Servo/BlButton.h
+++ b/SourceCode/Bond/Servo/BlButton.h
@@ -53,6 +53,7 @@
 	void Flash(int ms);
 	void StopFlash();
 	BOOL IsFlash();
+	void SetTextRight();
 
 private:
 	BOOL CustomBitBlt(HDC hDC, LPRECT lprc, CString& strBkgndBmp, int nFrame, int nAllFrame,
@@ -78,6 +79,7 @@
 	HICON m_hIcon[2];
 	int m_nIconWidth;
 	int m_nFlashState;		// 闪烁状态,0:不闪;1和2为闪烁切换中
+	BOOL m_bTextRight;
 
 public:
 	virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
diff --git a/SourceCode/Bond/Servo/Configuration.cpp b/SourceCode/Bond/Servo/Configuration.cpp
index d24527a..5df0f4b 100644
--- a/SourceCode/Bond/Servo/Configuration.cpp
+++ b/SourceCode/Bond/Servo/Configuration.cpp
@@ -92,6 +92,17 @@
 	return (int)texts.size();	
 }
 
+void CConfiguration::setFilterMode(int mode)
+{
+	WritePrivateProfileString(_T("Logcat"), _T("FilterMode"),
+		std::to_string(mode).c_str(), m_strFilepath);
+}
+
+int CConfiguration::getFilterMode()
+{
+	return GetPrivateProfileInt(_T("Logcat"), _T("FilterMode"), 0, m_strFilepath);
+}
+
 int CConfiguration::getP2RemoteEqReconnectInterval()
 {
 	return GetPrivateProfileInt(_T("P2"), _T("RemoteEqReconnectInterval"), 20, m_strFilepath);
diff --git a/SourceCode/Bond/Servo/Configuration.h b/SourceCode/Bond/Servo/Configuration.h
index 78fde46..1de8b08 100644
--- a/SourceCode/Bond/Servo/Configuration.h
+++ b/SourceCode/Bond/Servo/Configuration.h
@@ -20,6 +20,8 @@
 	void setLogcatIncludeRegex(BOOL bRegex);
 	BOOL isLogcatIncludeRegex();
 	int getCustomLogcatIncludeTexts(std::vector<std::string>& texts);
+	void setFilterMode(int mode);
+	int getFilterMode();
 	BOOL getPortParms(unsigned int index, BOOL& bEnable, int& type, int& mode,
 		int& cassetteType, int& transferMode, BOOL& bAutoChangeEnable);
 
diff --git a/SourceCode/Bond/Servo/LogEdit.cpp b/SourceCode/Bond/Servo/LogEdit.cpp
index 3b4742f..1b08345 100644
--- a/SourceCode/Bond/Servo/LogEdit.cpp
+++ b/SourceCode/Bond/Servo/LogEdit.cpp
@@ -21,12 +21,13 @@
 BEGIN_MESSAGE_MAP(CLogEdit, CEdit)
 	ON_WM_CONTEXTMENU()
 	ON_WM_VSCROLL()
+    ON_WM_MOUSEWHEEL()
 END_MESSAGE_MAP()
 
 void CLogEdit::SetMaxLineCount(int line)
 {
 	m_nMaxLines = line;
-	m_nTrimLines = min(m_nMaxLines, 100);
+	m_nTrimLines = min(m_nMaxLines, 4000);
 }
 
 void CLogEdit::OnContextMenu(CWnd* pWnd, CPoint point)
@@ -60,6 +61,13 @@
 	CEdit::OnVScroll(nSBCode, nPos, pScrollBar);
 }
 
+BOOL CLogEdit::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+{
+    // 每次滚动时检查是否还在底部
+    m_bAutoScroll = IsScrollBarAtBottom();
+    return CEdit::OnMouseWheel(nFlags, zDelta, pt);
+}
+
 BOOL CLogEdit::IsScrollBarAtBottom()
 {
 	SCROLLINFO si = { sizeof(si), SIF_ALL };
@@ -69,31 +77,41 @@
 
 void CLogEdit::AppendText(const char* pszText)
 {
-	SetRedraw(FALSE);
+    SetRedraw(FALSE);
 
-	// 裁剪逻辑
-	int totalLines = GetLineCount();
-	if (totalLines > m_nMaxLines) {
-		// 获取要删除的字符范围
-		int startChar = LineIndex(0);			// 第0行首字符位置
-		int endChar = LineIndex(m_nTrimLines);	// 第N行首字符位置
+    // 剪切过多行
+    int totalLines = GetLineCount();
+    if (totalLines > m_nMaxLines) {
+        int startChar = LineIndex(0);
+        int endChar = LineIndex(m_nTrimLines);
+        if (startChar >= 0 && endChar > startChar) {
+            SetSel(startChar, endChar);
+            ReplaceSel(_T(""));
+        }
+    }
 
-		if (startChar >= 0 && endChar > startChar) {
-			SetSel(startChar, endChar);
-			ReplaceSel(_T("")); // 删除前面行
-		}
-	}
+    // 保存当前选择
+    int start, end;
+    GetSel(start, end);
+    bool hasSelection = (start != end);
 
+    int endPos = GetWindowTextLength();
+    SetSel(endPos, endPos);
+    ReplaceSel(lpszText);
 
-	int len = GetWindowTextLength();
-	SetSel(len, len);
-	ReplaceSel(pszText);
+    if (m_bAutoScroll && !hasSelection) {
+        LineScroll(GetLineCount());
+    }
 
-	if (m_bAutoScroll) {
-		LineScroll(GetLineCount());
-	}
+    // 恢复选择
+    if (hasSelection) {
+        SetSel(start, end);
+    }
 
-	SetRedraw(TRUE);
-	Invalidate();
-	UpdateWindow();
-}
\ No newline at end of file
+    SetRedraw(TRUE);
+
+    if (m_bAutoScroll && !hasSelection) {
+        Invalidate();
+        UpdateWindow();
+    }
+}
diff --git a/SourceCode/Bond/Servo/LogEdit.h b/SourceCode/Bond/Servo/LogEdit.h
index 3a3e823..617b444 100644
--- a/SourceCode/Bond/Servo/LogEdit.h
+++ b/SourceCode/Bond/Servo/LogEdit.h
@@ -20,5 +20,7 @@
 	DECLARE_MESSAGE_MAP()
 	afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
 	afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+public:
+	afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
 };
 
diff --git a/SourceCode/Bond/Servo/PageLog.cpp b/SourceCode/Bond/Servo/PageLog.cpp
index 4729c34..7fe626a 100644
--- a/SourceCode/Bond/Servo/PageLog.cpp
+++ b/SourceCode/Bond/Servo/PageLog.cpp
@@ -20,8 +20,9 @@
 	m_hbrBkgnd = nullptr;
 	m_pObserver = nullptr;
 	m_nLevel = 0;
-	m_strIncludeText = _T("");
-	m_bIncludeRegex = FALSE;
+	m_strFilterText = _T("");
+	m_bRegex = FALSE;
+	m_filterMode = FilterMode::Include;
 }
 
 CPageLog::~CPageLog()
@@ -70,19 +71,24 @@
 					&& pAny->getIntValue("exCode", level)) {
 					if (level >= m_nLevel) {
 						CString strText = pszLogMsg;
-						BOOL bInclude = TRUE;
-						if (!m_strIncludeText.IsEmpty()) {
-							if (!m_bIncludeRegex) {
-								bInclude = (strText.Find(m_strIncludeText) >= 0);
+						BOOL bMatch = TRUE;
+						if (!m_strFilterText.IsEmpty()) {
+							if (!m_bRegex) {
+								bMatch = (strText.Find(m_strFilterText) >= 0);
 							}
 							else {
-								bInclude = std::regex_search((LPTSTR)(LPCTSTR)strText,
-									std::regex((LPTSTR)(LPCTSTR)m_strIncludeText));
+								CString strTemp = strText;
+								strTemp.TrimRight();
+								bMatch = std::regex_match((LPTSTR)(LPCTSTR)strTemp,
+									std::regex((LPTSTR)(LPCTSTR)m_strFilterText));
+							}
+							if (m_filterMode == FilterMode::Exclude) {
+								bMatch = !bMatch;
 							}
 						}
 
 
-						if (bInclude) {
+						if (bMatch) {
 							strText.Replace("\n", "\r\n");
 							AppendLog(level, (LPTSTR)(LPCTSTR)strText);
 						}
@@ -110,9 +116,12 @@
 
 	// 缓存
 	m_nLevel = theApp.m_model.m_configuration.getLogcatLevel();
-	theApp.m_model.m_configuration.getLogcatIncludeText(m_strIncludeText);
-	m_bIncludeRegex = theApp.m_model.m_configuration.isLogcatIncludeRegex();
+	theApp.m_model.m_configuration.getLogcatIncludeText(m_strFilterText);
+	m_bRegex = theApp.m_model.m_configuration.isLogcatIncludeRegex();
 	theApp.m_model.m_configuration.getCustomLogcatIncludeTexts(m_customIncludeTexts);
+	m_customIncludeTexts.clear();
+	m_customIncludeTexts.push_back("包含");
+	m_customIncludeTexts.push_back("排除");
 
 
 	// Level
@@ -135,6 +144,9 @@
 		strIcon1, IMAGE_ICON, 24, 24,
 		LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
 	m_btnInclude.SetIcon(hIcon, hIcon, 24);
+	m_filterMode = (FilterMode)theApp.m_model.m_configuration.getFilterMode();
+	m_btnInclude.SetTextRight();
+	m_btnInclude.SetWindowText(m_filterMode == FilterMode::Include ? "包含" : "排除");
 
 	{
 		HMENU hMenu = LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCEA(IDR_MENU_INCLUDE));
@@ -143,19 +155,19 @@
 		int i = 0;
 		for (auto& item : m_customIncludeTexts) {
 			i++;
-			InsertMenu(hSubMenu, 0, MF_BYPOSITION, 0x1998 + i, item.c_str());
+			InsertMenu(hSubMenu, i, MF_BYPOSITION, 0x1998 + i, item.c_str());
 			m_btnInclude.SetMenu(hMenu);
 		}
 	}
 
 
-	SetDlgItemText(IDC_EDIT_INCLUDE, m_strIncludeText);
+	SetDlgItemText(IDC_EDIT_INCLUDE, m_strFilterText);
 	CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK_REGEX);
-	pCheckBox->SetCheck(m_bIncludeRegex ? BST_CHECKED : BST_UNCHECKED);
+	pCheckBox->SetCheck(m_bRegex ? BST_CHECKED : BST_UNCHECKED);
 
 
 	// 内容
-	m_logEdit.SetMaxLineCount(500);
+	m_logEdit.SetMaxLineCount(6000);
 	m_logEdit.SetLimitText(-1);
 	Resize();
 
@@ -290,28 +302,22 @@
 void CPageLog::OnButtonIncludeMenuClicked(NMHDR* pNMHDR, LRESULT* pResult)
 {
 	BLBUTTON_NMHDR* pblbNmhdr = reinterpret_cast<BLBUTTON_NMHDR*>(pNMHDR);
-	int position = (int)pblbNmhdr->dwData;
-	std::string& strInclude = m_customIncludeTexts.at(position);
-	SetDlgItemText(IDC_EDIT_INCLUDE, strInclude.c_str());
-	CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK_REGEX);
-	m_bIncludeRegex = FALSE;
-	pCheckBox->SetCheck(BST_UNCHECKED);
-
-	theApp.m_model.m_configuration.setLogcatIncludeRegex(m_bIncludeRegex);
-	theApp.m_model.m_configuration.setLogcatIncludeText(m_strIncludeText);
+	m_filterMode = (FilterMode)pblbNmhdr->dwData;
+	theApp.m_model.m_configuration.setFilterMode((int)m_filterMode);
+	m_btnInclude.SetWindowText(m_filterMode == FilterMode::Include ? "包含" : "排除");
 
 	*pResult = 0;
 }
 
 void CPageLog::OnEnChangeEditInclude()
 {
-	GetDlgItemText(IDC_EDIT_INCLUDE, m_strIncludeText);
-	theApp.m_model.m_configuration.setLogcatIncludeText(m_strIncludeText);
+	GetDlgItemText(IDC_EDIT_INCLUDE, m_strFilterText);
+	theApp.m_model.m_configuration.setLogcatIncludeText(m_strFilterText);
 }
 
 void CPageLog::OnBnClickedCheckRegex()
 {
 	CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK_REGEX);
-	m_bIncludeRegex = pCheckBox->GetCheck();
-	theApp.m_model.m_configuration.setLogcatIncludeRegex(m_bIncludeRegex);
+	m_bRegex = pCheckBox->GetCheck();
+	theApp.m_model.m_configuration.setLogcatIncludeRegex(m_bRegex);
 }
diff --git a/SourceCode/Bond/Servo/PageLog.h b/SourceCode/Bond/Servo/PageLog.h
index 391f64d..4e373d2 100644
--- a/SourceCode/Bond/Servo/PageLog.h
+++ b/SourceCode/Bond/Servo/PageLog.h
@@ -7,6 +7,12 @@
 
 #define ID_MSG_LOGDLG_HIDE		WM_USER + 1023
 
+
+enum class FilterMode {
+	Include,  // 只保留匹配行
+	Exclude   // 排除匹配行
+};
+
 // CPageLog 对话框
 
 class CPageLog : public CDialogEx
@@ -29,14 +35,15 @@
 	HBRUSH m_hbrBkgnd;
 	IObserver* m_pObserver;
 	int m_nLevel;
-	CString m_strIncludeText;
-	BOOL m_bIncludeRegex;
+	CString m_strFilterText;
+	BOOL m_bRegex;
 	std::vector<std::string> m_customIncludeTexts;
 
 private:
 	CBlButton m_btnLevel;
 	CBlButton m_btnInclude;
 	CLogEdit m_logEdit;
+	FilterMode m_filterMode;
 
 
 // 对话框数据
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 3cb2416..63b6347 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index de985ad..26b9e62 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/SourceCode/Bond/Servo/ServoDlg.cpp
@@ -285,6 +285,10 @@
 	SetIcon(m_hIcon, FALSE);		// 设置小图标
 
 
+	// model init
+	theApp.m_model.init();
+
+
 	// 菜单
 	CMenu menu;
 	menu.LoadMenu(IDR_MENU_APP);
@@ -353,9 +357,6 @@
 	int height = GetSystemMetrics(SM_CYSCREEN);
 	MoveWindow((width - rcWnd.Width()) / 2, 0, rcWnd.Width(), rcWnd.Height(), TRUE);
 
-
-	// model init
-	theApp.m_model.init();
 
 
 	SetTimer(TIMER_ID_CREATE_TERMINAL, 3000, nullptr);
diff --git a/SourceCode/Bond/x64/Debug/Res/logcat_include.ico b/SourceCode/Bond/x64/Debug/Res/logcat_include.ico
index 275a472..9608f1b 100644
--- a/SourceCode/Bond/x64/Debug/Res/logcat_include.ico
+++ b/SourceCode/Bond/x64/Debug/Res/logcat_include.ico
Binary files differ

--
Gitblit v1.9.3