LAPTOP-SNT8I5JK\Boounion
2025-01-04 aeb4b40768164ebf38bc3cd64b17c06681356d68
1.增加日志窗口和模块;
已添加8个文件
已修改10个文件
1277 ■■■■■ 文件已修改
SourceCode/Bond/Servo/Common.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Configuration.cpp 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Configuration.h 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Log.cpp 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Log.h 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/LogDlg.cpp 314 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/LogDlg.h 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/LogEdit.cpp 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/LogEdit.h 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.cpp 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Model.h 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.cpp 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.rc 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Servo.vcxproj.filters 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.cpp 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/ServoDlg.h 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/resource.h 补丁 | 查看 | 原始文档 | blame | 历史
SourceCode/Bond/Servo/Common.h
@@ -12,6 +12,7 @@
/* é¢œè‰² */
#define APPDLG_BACKGROUND_COLOR            RGB(255, 255, 255)
#define LOGDLG_BACKGROUND_COLOR            RGB(255, 255, 255)
/* LOG BTN */
SourceCode/Bond/Servo/Configuration.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
#include "stdafx.h"
#include "Configuration.h"
CConfiguration::CConfiguration()
{
}
CConfiguration::CConfiguration(const char* pszFilepath)
{
    m_strFilepath = pszFilepath;
}
CConfiguration::~CConfiguration()
{
}
void CConfiguration::setFilepath(const char* pszFilepath)
{
    m_strFilepath = pszFilepath;
}
void CConfiguration::getUnitId(CString& strUnitId)
{
    char szTemp[256];
    GetPrivateProfileString("App", _T("UnitId"), _T(""), szTemp, 256, m_strFilepath);
    strUnitId = szTemp;
}
void CConfiguration::getBond1(CString& strIp, UINT& port, UINT& doorCount)
{
    char szTemp[256];
    // è¯»IP和端口
    GetPrivateProfileString("Bond1", _T("IP"), _T(""), szTemp, 256, m_strFilepath);
    strIp = szTemp;
    port = GetPrivateProfileInt("Bond1", _T("Port"), 0, m_strFilepath);
    doorCount = GetPrivateProfileInt("Bond1", _T("DoorCount"), 0, m_strFilepath);
}
int CConfiguration::getLogcatLevel()
{
    return GetPrivateProfileInt(_T("Logcat"), _T("Level"), 0, m_strFilepath);
}
void CConfiguration::setLogcatLevel(int level)
{
    WritePrivateProfileString(_T("Logcat"), _T("Level"),
        std::to_string(level).c_str(), m_strFilepath);
}
int CConfiguration::setLogcatIncludeText(CString& strInclude)
{
    WritePrivateProfileString(_T("Logcat"), _T("IncludeText"),
        strInclude, m_strFilepath);
    return 0;
}
int CConfiguration::getLogcatIncludeText(CString& strInclude)
{
    char szTemp[256];
    GetPrivateProfileString("Logcat", _T("IncludeText"), _T(""), szTemp, 256, m_strFilepath);
    strInclude = szTemp;
    return 0;
}
void CConfiguration::setLogcatIncludeRegex(BOOL bRegex)
{
    WritePrivateProfileString(_T("Logcat"), _T("IncludeRegex"),
        bRegex ? "1" : "0", m_strFilepath);
}
BOOL CConfiguration::isLogcatIncludeRegex()
{
    return GetPrivateProfileInt(_T("Logcat"), _T("IncludeRegex"), 0, m_strFilepath);
}
int CConfiguration::getCustomLogcatIncludeTexts(std::vector<std::string>& texts)
{
    char szSection[256], szTemp[256];
    for (int i = 0; i < 10; i++) {
        sprintf_s(szSection, 256, "CustomInclude%d", i + 1);
        GetPrivateProfileString("Logcat", szSection, _T(""),
            szTemp, 256, m_strFilepath);
        std::string strInclude(szTemp);
        if (!strInclude.empty()) {
            texts.push_back(strInclude);
        }
    }
    return (int)texts.size();
}
int CConfiguration::getP2RemoteEqReconnectInterval()
{
    return GetPrivateProfileInt(_T("P2"), _T("RemoteEqReconnectInterval"), 20, m_strFilepath);
}
void CConfiguration::setP2RemoteEqReconnectInterval(int second)
{
    WritePrivateProfileString(_T("P2"), _T("RemoteEqReconnectInterval"),
        std::to_string(second).c_str(), m_strFilepath);
}
SourceCode/Bond/Servo/Configuration.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
#pragma once
#include <vector>
#include <string>
class CConfiguration
{
public:
    CConfiguration();
    CConfiguration(const char* pszFilepath);
    ~CConfiguration();
public:
    void setFilepath(const char* pszFilepath);
    void getUnitId(CString& strUnitId);
    void getBond1(CString& strIp, UINT& port, UINT& doorCount);
    int getLogcatLevel();
    void setLogcatLevel(int level);
    int setLogcatIncludeText(CString& strInclude);
    int getLogcatIncludeText(CString& strInclude);
    void setLogcatIncludeRegex(BOOL bRegex);
    BOOL isLogcatIncludeRegex();
    int getCustomLogcatIncludeTexts(std::vector<std::string>& texts);
public:
    void setP2RemoteEqReconnectInterval(int second);
    int getP2RemoteEqReconnectInterval();
private:
    CString m_strFilepath;
};
SourceCode/Bond/Servo/Log.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,214 @@
#include "stdafx.h"
#include "Log.h"
static const char* pszLevel[] = {" [Debug] ", " [Info] ", " [Warn] ", " [Error] "};
CLog::CLog()
{
    m_nLevel = 0;
    m_nOutputTarget = OT_TRACE;
    m_bAutoAppendTime = TRUE;
    m_strEquipmentId = _T("Unknown");
    m_nDay = 0;
    m_funOnLog = nullptr;
    InitializeCriticalSection(&m_criticalSection);
}
CLog::~CLog()
{
    DeleteCriticalSection(&m_criticalSection);
}
CLog *CLog::GetLog(void)
{
    static CLog* pLog = NULL;
    if (pLog == NULL) {
        static CLog log;
        pLog = &log;
    }
    return pLog;
}
void CLog::SetOnLogCallback(ONLOG funOnLog)
{
    m_funOnLog = funOnLog;
}
void CLog::SetOutputTarget(int flag)
{
    m_nOutputTarget = flag;
}
void CLog::SetEquipmentId(const char* pszEquipmentId)
{
    m_strEquipmentId = pszEquipmentId;
}
void CLog::SetAutoAppendTimeString(BOOL bAutoAppendTime)
{
    m_bAutoAppendTime = bAutoAppendTime;
}
void CLog::Batch()
{
    if (m_file.m_hFile != CFile::hFileNull) {
        m_file.Close();
    }
}
BOOL CLog::BatchAndNew(int& nDay)
{
    Batch();
    if ( (m_nOutputTarget & OT_FILE) && m_file.m_hFile == CFile::hFileNull) {
        CString strFilepath;
        BOOL bRet = m_file.Open(MakeFilepathD(strFilepath, nDay), CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite | CFile::shareDenyWrite);
        if (bRet) {
            m_file.SeekToEnd();
        }
        return bRet;
    }
    return FALSE;
}
#define BUFFERSIZE        1024*10
void CLog::LogFormat(int nLevel, const char* pszTag, char* szMessage, ...)
{
    // æ£€æŸ¥æ—¥æœŸæ˜¯å¦æœ‰å˜åŒ–,有变化则结批
    Lock();
    _SYSTEMTIME sysTime;
    GetLocalTime(&sysTime);
    if(m_nDay != sysTime.wDay) {
        int nDay = 0;
        if (BatchAndNew(nDay)) {
            m_nDay = nDay;
        }
    }
    Unlock();
    if (nLevel < m_nLevel) {
        return;
    }
    char szFullMessage[BUFFERSIZE];
    char szFormatMessage[BUFFERSIZE];
    // format message
    va_list ap;
    va_start(ap, szMessage);
    _vsnprintf_s(szFormatMessage, BUFFERSIZE, szMessage, ap);
    va_end(ap);
    if (m_bAutoAppendTime) {
        CString strTime;
        strcpy_s(szFullMessage, BUFFERSIZE, (LPTSTR)(LPCTSTR)GetCurTime(strTime));
    }
    strcat_s(szFullMessage, BUFFERSIZE, pszLevel[nLevel]);
    strcat_s(szFullMessage, szFormatMessage);
    strcat_s(szFullMessage, BUFFERSIZE, "\n");
    if (m_nOutputTarget & OT_FILE) {
        Lock();
        if (m_file.m_hFile != CFile::hFileNull) {
            m_file.WriteString(szFullMessage);
        }
        Unlock();
    }
    if (m_nOutputTarget & OT_ODSTRING) {
        OutputDebugStringA(szFullMessage);
    }
    else if(m_nOutputTarget & OT_TRACE) {
        TRACE(szFormatMessage);
    }
    if (m_funOnLog != nullptr) {
        m_funOnLog(nLevel, szFullMessage);
    }
}
void CLog::Log(int nLevel, const char* pszTag, const char* szMessage)
{
    // æ£€æŸ¥æ—¥æœŸæ˜¯å¦æœ‰å˜åŒ–,有变化则结批
    Lock();
    _SYSTEMTIME sysTime;
    GetLocalTime(&sysTime);
    if (m_nDay != sysTime.wDay) {
        int nDay = 0;
        if (BatchAndNew(nDay)) {
            m_nDay = nDay;
        }
    }
    Unlock();
    if (nLevel < m_nLevel) {
        return;
    }
    CString strMsg;
    if (m_bAutoAppendTime) {
        CString strTime;
        GetCurTime(strTime);
        strMsg.Append(strTime);
    }
    strMsg.Append(pszTag);
    strMsg.Append(szMessage);
    strMsg.Append("\n");
    if (m_nOutputTarget & OT_FILE) {
        Lock();
        if (m_file.m_hFile != CFile::hFileNull) {
            m_file.WriteString(strMsg);
        }
        Unlock();
    }
    if (m_nOutputTarget & OT_ODSTRING) {
        OutputDebugStringA(strMsg);
    }
    else if (m_nOutputTarget & OT_TRACE) {
        TRACE(strMsg);
    }
    if (m_funOnLog != nullptr) {
        m_funOnLog(nLevel, strMsg);
    }
}
CString& CLog::GetCurTime(CString& strTime)
{
    _SYSTEMTIME sysTime;
    GetLocalTime(&sysTime);
    strTime.Format(_T("%d/%02d/%02d %02d:%02d:%02d.%03d"), sysTime.wYear, sysTime.wMonth, sysTime.wDay,
        sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds);
    return strTime;
}
CString& CLog::MakeFilepath(CString& strFilepath)
{
    _SYSTEMTIME sysTime;
    GetLocalTime(&sysTime);
    strFilepath.Format(_T("%s\\Log(%s)_%d_%02d_%02d.log"), (LPTSTR)(LPCTSTR)m_strLogsDir,
        (LPTSTR)(LPCTSTR)m_strEquipmentId,
        sysTime.wYear, sysTime.wMonth, sysTime.wDay);
    return strFilepath;
}
CString& CLog::MakeFilepathD(CString& strFilepath, int& day)
{
    _SYSTEMTIME sysTime;
    GetLocalTime(&sysTime);
    strFilepath.Format(_T("%s\\Log(%s)_%d_%02d_%02d.log"), (LPTSTR)(LPCTSTR)m_strLogsDir,
        (LPTSTR)(LPCTSTR)m_strEquipmentId,
        sysTime.wYear, sysTime.wMonth, sysTime.wDay);
    day = sysTime.wDay;
    return strFilepath;
}
void CLog::SetLogsDir(CString strDir)
{
    m_strLogsDir = strDir;
}
SourceCode/Bond/Servo/Log.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
#pragma once
#include <functional>
#define LEVEL_DEBUG        0
#define LEVEL_INFO        1
#define LEVEL_WARN        2
#define LEVEL_ERROR        3
#define LOGD(msg, ...)        CLog::GetLog()->LogFormat(LEVEL_DEBUG, "", msg, __VA_ARGS__)
#define LOGI(msg, ...)        CLog::GetLog()->LogFormat(LEVEL_INFO, "", msg, __VA_ARGS__)
#define LOGW(msg, ...)        CLog::GetLog()->LogFormat(LEVEL_WARN, "", msg, __VA_ARGS__)
#define LOGE(msg, ...)        CLog::GetLog()->LogFormat(LEVEL_ERROR, "", msg, __VA_ARGS__)
#define OT_FILE            0x01
#define OT_ODSTRING        0x02
#define OT_TRACE        0x04
#define LOGBATHCH()                CLog::GetLog()->Batch()
#define LOGNEW()                CLog::GetLog()->BatchAndNew()
typedef std::function<void(int level, const char* pszMessage)> ONLOG;
class CLog
{
public:
    CLog();
    ~CLog();
public:
    void SetOnLogCallback(ONLOG funOnLog);
    static CLog *GetLog(void);
    void SetOutputTarget(int flag);
    void SetEquipmentId(const char* pszEquipmentId);
    static CString& GetCurTime(CString& strTime);
    CString& MakeFilepath(CString& strFilepath);
    CString& MakeFilepathD(CString& strFilepath, int& day);
    void LogFormat(int nLevel, const char* pszTag, char* szMessage, ...);
    void Log(int nLevel, const char* pszTag, const char* szMessage);
    void SetAutoAppendTimeString(BOOL bAutoAppendTime);
    void SetLogsDir(CString strDir);
    void Batch();
    BOOL BatchAndNew(int& nDay);
private:
    inline void Lock() { EnterCriticalSection(&m_criticalSection); }
    inline void Unlock() { LeaveCriticalSection(&m_criticalSection); }
private:
    ONLOG m_funOnLog;
    int m_nOutputTarget;
    int m_nLevel;
    BOOL m_bAutoAppendTime;
    CString m_strLogsDir;
    CString m_strEquipmentId;
    CStdioFile m_file;
    int m_nDay;                        // æŒ‰æ—¥ä¿å­˜ä¸€æ¡è®°å½•,比较此数字,以决定是否结批并创建新文件
    CRITICAL_SECTION m_criticalSection;
};
SourceCode/Bond/Servo/LogDlg.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,314 @@
// LogDlg.cpp : å®žçŽ°æ–‡ä»¶
//
#include "stdafx.h"
#include "Servo.h"
#include "LogDlg.h"
#include "afxdialogex.h"
#include "Common.h"
#include <regex>
// CLogDlg å¯¹è¯æ¡†
IMPLEMENT_DYNAMIC(CLogDlg, CDialogEx)
CLogDlg::CLogDlg(CWnd* pParent /*=NULL*/)
    : CDialogEx(IDD_DIALOG_LOG, pParent)
{
    m_crBkgnd = LOGDLG_BACKGROUND_COLOR;
    m_hbrBkgnd = nullptr;
    m_pObserver = nullptr;
    m_nLevel = 0;
    m_strIncludeText = _T("");
    m_bIncludeRegex = FALSE;
}
CLogDlg::~CLogDlg()
{
}
void CLogDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_BUTTON_LEVEL, m_btnLevel);
    DDX_Control(pDX, IDC_BUTTON_INCLUDE, m_btnInclude);
    DDX_Control(pDX, IDC_EDIT_LOG, m_logEdit);
}
BEGIN_MESSAGE_MAP(CLogDlg, CDialogEx)
    ON_WM_CTLCOLOR()
    ON_WM_SIZE()
    ON_WM_DESTROY()
    ON_WM_CLOSE()
    ON_NOTIFY(BLBUTTON_MENU_ITEM_CLICKED, IDC_BUTTON_LEVEL, &CLogDlg::OnButtonLevelMenuClicked)
    ON_NOTIFY(BLBUTTON_MENU_ITEM_CLICKED, IDC_BUTTON_INCLUDE, &CLogDlg::OnButtonIncludeMenuClicked)
    ON_EN_CHANGE(IDC_EDIT_INCLUDE, &CLogDlg::OnEnChangeEditInclude)
    ON_BN_CLICKED(IDC_CHECK_REGEX, &CLogDlg::OnBnClickedCheckRegex)
END_MESSAGE_MAP()
// CLogDlg æ¶ˆæ¯å¤„理程序
void CLogDlg::InitRxWindow()
{
    /* code */
    // è®¢é˜…数据
    IRxWindows* pRxWindows = RX_GetRxWindows();
    pRxWindows->enableLog(5);
    if (m_pObserver == NULL) {
        m_pObserver = pRxWindows->allocObserver([&](IAny* pAny) -> void {
            // onNext
            pAny->addRef();
            int code = pAny->getCode();
            if (RX_CODE_LOG == code && ::IsWindow(m_hWnd)) {
                const char* pszLogMsg;
                int level;
                if (pAny->getStringValue("text", pszLogMsg)
                    && 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);
                            }
                            else {
                                bInclude = std::regex_search((LPTSTR)(LPCTSTR)strText,
                                    std::regex((LPTSTR)(LPCTSTR)m_strIncludeText));
                            }
                        }
                        if (bInclude) {
                            strText.Replace("\n", "\r\n");
                            AppendLog(level, (LPTSTR)(LPCTSTR)strText);
                        }
                    }
                }
            }
            pAny->release();
        }, [&]() -> void {
            // onComplete
        }, [&](IThrowable* pThrowable) -> void {
            // onErrorm
            pThrowable->printf();
        });
        theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())
            ->subscribe(m_pObserver);
    }
}
BOOL CLogDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    // ç¼“å­˜
    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.getCustomLogcatIncludeTexts(m_customIncludeTexts);
    // Level
    HMENU hMenu = LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCEA(IDR_MENU_LOGCAT_LEVEL));
    m_btnLevel.SetMenu(hMenu);
    m_btnLevel.SetCurrentMenuItem(m_nLevel);
    m_btnLevel.SetBkgndColor(BS_NORMAL, RGB(241, 242, 244));
    m_btnLevel.SetBkgndColor(BS_HOVER, RGB(220, 223, 228));
    m_btnLevel.SetBkgndColor(BS_PRESS, RGB(179, 185, 196));
    m_btnLevel.SetFrameColor(BS_NORMAL, RGB(133, 144, 162));
    m_btnLevel.SetFrameColor(BS_HOVER, RGB(56, 139, 255));
    m_btnLevel.SetFrameColor(BS_PRESS, RGB(56, 139, 255));
    m_btnLevel.SetFrameColor(BS_FOCUS, RGB(56, 139, 255));
    // åŒ…含字符串
    CString strIcon1;
    strIcon1.Format(_T("%s\\Res\\logcat_include.ico"), theApp.m_strAppDir);
    HICON hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(),
        strIcon1, IMAGE_ICON, 24, 24,
        LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
    m_btnInclude.SetIcon(hIcon, hIcon, 24);
    {
        HMENU hMenu = LoadMenu(AfxGetInstanceHandle(), MAKEINTRESOURCEA(IDR_MENU_INCLUDE));
        HMENU hSubMenu = GetSubMenu(hMenu, 0);
        DeleteMenu(hSubMenu, 0, MF_BYPOSITION);
        int i = 0;
        for (auto& item : m_customIncludeTexts) {
            i++;
            InsertMenu(hSubMenu, 0, MF_BYPOSITION, 0x1998 + i, item.c_str());
            m_btnInclude.SetMenu(hMenu);
        }
    }
    SetDlgItemText(IDC_EDIT_INCLUDE, m_strIncludeText);
    CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK_REGEX);
    pCheckBox->SetCheck(m_bIncludeRegex ? BST_CHECKED : BST_UNCHECKED);
    // å†…容
    m_logEdit.SetMaxLineCount(20);
    m_logEdit.SetLimitText(-1);
    InitRxWindow();
    return TRUE;  // return TRUE unless you set the focus to a control
                  // å¼‚常: OCX å±žæ€§é¡µåº”返回 FALSE
}
void CLogDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialogEx::OnSize(nType, cx, cy);
    if (GetDlgItem(IDC_EDIT_LOG) == nullptr) return;
    int x, y, y2, temp;
    CRect rcClient, rcItem;
    CWnd* pItem;
    GetClientRect(&rcClient);
    y = 0;
    x = 12;
    pItem = GetDlgItem(IDC_BUTTON_LEVEL);
    pItem->GetWindowRect(&rcItem);
    ScreenToClient(&rcItem);
    pItem->MoveWindow(x, y, rcItem.Width(), rcItem.Height());
    x += rcItem.Width();
    x += 18;
    y2 = rcItem.bottom;
    pItem = GetDlgItem(IDC_BUTTON_INCLUDE);
    pItem->GetWindowRect(&rcItem);
    pItem->MoveWindow(x, y, rcItem.Width(), rcItem.Height());
    x += rcItem.Width();
    x += 2;
    pItem = GetDlgItem(IDC_EDIT_INCLUDE);
    pItem->GetWindowRect(&rcItem);
    pItem->MoveWindow(x, y, rcItem.Width(), rcItem.Height());
    x += rcItem.Width();
    x += 12;
    temp = rcItem.Height();
    pItem = GetDlgItem(IDC_CHECK_REGEX);
    pItem->GetWindowRect(&rcItem);
    pItem->MoveWindow(x, y + (temp - rcItem.Height()) / 2, rcItem.Width(), rcItem.Height());
    x = 12;
    pItem = GetDlgItem(IDC_EDIT_LOG);
    pItem->MoveWindow(x, y2, rcClient.Width() - 24, rcClient.Height() - 5 - y2);
}
void CLogDlg::OnDestroy()
{
    CDialogEx::OnDestroy();
    {
        HMENU hMenu = m_btnLevel.GetMenu();
        if (hMenu != NULL) {
            ::DestroyMenu(hMenu);
        }
    }
    {
        HMENU hMenu = m_btnInclude.GetMenu();
        if (hMenu != NULL) {
            ::DestroyMenu(hMenu);
        }
    }
    if (m_hbrBkgnd != nullptr) {
        ::DeleteObject(m_hbrBkgnd);
    }
    if (m_pObserver != NULL) {
        m_pObserver->unsubscribe();
        m_pObserver = NULL;
    }
}
HBRUSH CLogDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    if (nCtlColor == CTLCOLOR_STATIC) {
        pDC->SetBkColor(m_crBkgnd);
    }
    if (m_hbrBkgnd == nullptr) {
        m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
    }
    return m_hbrBkgnd;
}
void CLogDlg::OnClose()
{
    ShowWindow(SW_HIDE);
    GetParent()->PostMessage(ID_MSG_LOGDLG_HIDE, 0, 0);
}
BOOL CLogDlg::PreTranslateMessage(MSG* pMsg)
{
    if (pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE) {
        return TRUE;
    }
    return CDialogEx::PreTranslateMessage(pMsg);
}
void CLogDlg::AppendLog(int level, const char* pszText)
{
    if (!::IsWindow(m_logEdit.m_hWnd)) {
        return;
    }
    m_logEdit.AppendText(pszText);
}
void CLogDlg::OnButtonLevelMenuClicked(NMHDR* pNMHDR, LRESULT* pResult)
{
    BLBUTTON_NMHDR* pblbNmhdr = reinterpret_cast<BLBUTTON_NMHDR*>(pNMHDR);
    m_nLevel = (int)pblbNmhdr->dwData;
    theApp.m_model.m_configuration.setLogcatLevel(m_nLevel);
    m_btnLevel.SetCurrentMenuItem(m_nLevel);
    *pResult = 0;
}
void CLogDlg::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);
    *pResult = 0;
}
void CLogDlg::OnEnChangeEditInclude()
{
    GetDlgItemText(IDC_EDIT_INCLUDE, m_strIncludeText);
    theApp.m_model.m_configuration.setLogcatIncludeText(m_strIncludeText);
}
void CLogDlg::OnBnClickedCheckRegex()
{
    CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK_REGEX);
    m_bIncludeRegex = pCheckBox->GetCheck();
    theApp.m_model.m_configuration.setLogcatIncludeRegex(m_bIncludeRegex);
}
SourceCode/Bond/Servo/LogDlg.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
#pragma once
#include "LogEdit.h"
#include "BlButton.h"
#include <vector>
#include <string>
#define ID_MSG_LOGDLG_HIDE        WM_USER + 1023
// CLogDlg å¯¹è¯æ¡†
class CLogDlg : public CDialogEx
{
    DECLARE_DYNAMIC(CLogDlg)
public:
    CLogDlg(CWnd* pParent = NULL);   // æ ‡å‡†æž„造函数
    virtual ~CLogDlg();
private:
    void InitRxWindow();
    void AppendLog(int level, const char* pszText);
private:
    COLORREF m_crBkgnd;
    HBRUSH m_hbrBkgnd;
    IObserver* m_pObserver;
    int m_nLevel;
    CString m_strIncludeText;
    BOOL m_bIncludeRegex;
    std::vector<std::string> m_customIncludeTexts;
private:
    CBlButton m_btnLevel;
    CBlButton m_btnInclude;
    CLogEdit m_logEdit;
// å¯¹è¯æ¡†æ•°æ®
#ifdef AFX_DESIGN_TIME
    enum { IDD = IDD_DIALOG_LOG };
#endif
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV æ”¯æŒ
    DECLARE_MESSAGE_MAP()
public:
    virtual BOOL OnInitDialog();
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnDestroy();
    afx_msg void OnClose();
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    virtual BOOL PreTranslateMessage(MSG* pMsg);
    afx_msg void OnButtonLevelMenuClicked(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnButtonIncludeMenuClicked(NMHDR* pNMHDR, LRESULT* pResult);
    afx_msg void OnEnChangeEditInclude();
    afx_msg void OnBnClickedCheckRegex();
};
SourceCode/Bond/Servo/LogEdit.cpp
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
#include "stdafx.h"
#include "LogEdit.h"
#define MENU_ITEM_SEL_ALL        0x666
#define MENU_ITEM_COPY            0x667
#define MENU_ITEM_CLEAR            0x668
CLogEdit::CLogEdit()
{
    m_nMaxLineCount = 0xffff;
}
CLogEdit::~CLogEdit()
{
}
BEGIN_MESSAGE_MAP(CLogEdit, CEdit)
    ON_WM_CONTEXTMENU()
END_MESSAGE_MAP()
void CLogEdit::SetMaxLineCount(int line)
{
    m_nMaxLineCount = line;
}
void CLogEdit::OnContextMenu(CWnd* pWnd, CPoint point)
{
    HMENU hMenu = CreatePopupMenu();
    InsertMenu(hMenu, 0, MF_BYPOSITION, MENU_ITEM_SEL_ALL, "ȫѡ");
    InsertMenu(hMenu, 1, MF_BYPOSITION, MENU_ITEM_COPY, "复制");
    InsertMenu(hMenu, 2, MF_BYPOSITION | MF_SEPARATOR, NULL, NULL);
    InsertMenu(hMenu, 3, MF_BYPOSITION, MENU_ITEM_CLEAR, "全部清除");
    int cmd = ::TrackPopupMenu(hMenu,
        TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
        point.x, point.y + 2, 0, m_hWnd, NULL);
    DestroyMenu(hMenu);
    if (cmd == MENU_ITEM_SEL_ALL) {
        SetFocus();
        this->SetSel(0, -1);
    }
    else if (cmd == MENU_ITEM_COPY) {
        this->Copy();
    }
    else if (cmd == MENU_ITEM_CLEAR) {
        SetWindowText(_T(""));
    }
}
void CLogEdit::AppendText(const char* pszText)
{
    // èŽ·å–é€‰æ‹©èŒƒå›´ä»¥ä¾¿æ¢å¤
    int nStart, nEnd;
    GetSel(nStart, nEnd);
    // è¶…过指定行数则删除最前面的行
    int nLineCount = GetLineCount();
    while (nLineCount > m_nMaxLineCount) {
        int nLin1End = LineIndex(1);
        nStart -= nLin1End;
        if (nStart < 0) nStart = 0;
        nEnd -= nLin1End;
        if (nEnd < 0) nEnd = 0;
        SetSel(0, nLin1End);
        ReplaceSel(_T(""));
        nLineCount = GetLineCount();
    }
    // è¿½åŠ åˆ°æœ€åŽ
    int length = GetWindowTextLength();
    SetSel(length, length);
    ReplaceSel(pszText);
    PostMessage(WM_VSCROLL, SB_BOTTOM, 0);
    // æ¢å¤
    if (nStart == 0 && nEnd == 0) {
        nStart = GetWindowTextLength();
        nEnd = nStart;
    }
    SetSel(nStart, nEnd);
}
SourceCode/Bond/Servo/LogEdit.h
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
#pragma once
#include "afxwin.h"
class CLogEdit :
    public CEdit
{
public:
    CLogEdit();
    ~CLogEdit();
public:
    void SetMaxLineCount(int line);
    void AppendText(const char* pszText);
private:
    int m_nMaxLineCount;
    DECLARE_MESSAGE_MAP()
    afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
};
SourceCode/Bond/Servo/Model.cpp
@@ -1,21 +1,267 @@
#include "stdafx.h"
#include "Model.h"
#include "Log.h"
#include "Common.h"
CModel::CModel()
{
    m_pObservableEmitter = nullptr;
    m_pObservable = nullptr;
}
CModel::~CModel()
{
}
IObservable* CModel::getObservable()
{
    return m_pObservable;
}
void CModel::setWorkDir(const char* pszWorkDir)
{
    m_strWorkDir = pszWorkDir;
}
int CModel::init()
{
    CString strIniFile;
    CString strUnitId;
    strIniFile.Format(_T("%s\\ServoConfiguration.ini"), (LPTSTR)(LPCTSTR)m_strWorkDir);
    m_configuration.setFilepath((LPTSTR)(LPCTSTR)strIniFile);
    m_configuration.getUnitId(strUnitId);
    // Log
    CString strLogDir;
    strLogDir.Format(_T("%s\\Log"), (LPTSTR)(LPCTSTR)m_strWorkDir);
    ::CreateDirectory(strLogDir, NULL);
    CLog::GetLog()->SetOnLogCallback([&](int level, const char* pszMessage) -> void {
        notifyTextAndInt(RX_CODE_LOG, pszMessage, level);
    });
    CLog::GetLog()->SetAutoAppendTimeString(TRUE);
    CLog::GetLog()->SetOutputTarget(OT_FILE);
    CLog::GetLog()->SetLogsDir(strLogDir);
    CLog::GetLog()->SetEquipmentId((LPTSTR)(LPCTSTR)strUnitId);
    LOGI("\r\n\r\n~~~ Prog Start! ~~~");
    m_pObservable = RX_AllocaObservable([&](IObservableEmitter* e) -> void {
        m_pObservableEmitter = e;            // ä¿å­˜å‘射器
    });
    return 0;
}
int CModel::term()
{
    CLog::GetLog()->SetOnLogCallback(nullptr);
    return 0;
}
int CModel::notify(int code)
{
    /* code */
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 1;
}
int CModel::notifyPtr(int code, void* ptr/* = NULL*/)
{
    /* code */
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setPtrValue("ptr", ptr);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 1;
}
int CModel::notifyObj(int code, IRxObject* pObj)
{
    /* code */
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setObject("obj", pObj);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 1;
}
int CModel::notifyObjAndPtr(int code, IRxObject* pObj, void* ptr)
{
    /* code */
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setObject("obj", pObj);
            pAny->setPtrValue("ptr", ptr);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 1;
}
int CModel::notifyInt(int code, int exCode)
{
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setIntValue("exCode", exCode);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 0;
}
int CModel::notifyInt2(int code, int exCode, int exCode2)
{
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setIntValue("exCode", exCode);
            pAny->setIntValue("exCode2", exCode2);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 0;
}
int CModel::notifyDouble(int code, double dValue)
{
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setDoubleValue("value", dValue);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 0;
}
int CModel::notifyObjAndInt(int code, IRxObject* pObj1, IRxObject* pObj2, int exCode)
{
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            if (pObj1 != nullptr) pAny->setObject("obj", pObj1);
            if (pObj2 != nullptr) pAny->setObject("obj2", pObj2);
            pAny->setIntValue("exCode", exCode);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 0;
}
int CModel::notifyText(int code, const char* pszText)
{
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setStringValue("text", pszText);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 0;
}
int CModel::notifyTextAndInt(int code, const char* pszText, int exCode)
{
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setStringValue("text", pszText);
            pAny->setIntValue("exCode", exCode);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 0;
}
int CModel::notifyPtrAndInt(int code, void* ptr1, void* ptr2, int exCode)
{
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setPtrValue("ptr", ptr1);
            pAny->setPtrValue("ptr1", ptr1);
            pAny->setPtrValue("ptr2", ptr2);
            pAny->setIntValue("exCode", exCode);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 0;
}
int CModel::notifyMesMsg(int code, int stream, int function, const char* pszText)
{
    if (m_pObservableEmitter != NULL) {
        IAny* pAny = RX_AllocaAny();
        if (pAny != NULL) {
            pAny->addRef();
            pAny->setCode(code);
            pAny->setIntValue("stream", stream);
            pAny->setIntValue("function", function);
            pAny->setStringValue("text", pszText);
            m_pObservableEmitter->onNext(pAny);
            pAny->release();
        }
    }
    return 0;
}
SourceCode/Bond/Servo/Model.h
@@ -1,4 +1,6 @@
#pragma once
#include "Configuration.h"
class CModel
{
public:
@@ -6,7 +8,32 @@
    ~CModel();
public:
    IObservable* getObservable();
    void setWorkDir(const char* pszWorkDir);
    int init();
    int term();
public:
    int notify(int code);
    int notifyPtr(int code, void* ptr = NULL);
    int notifyObj(int code, IRxObject* pObj);
    int notifyObjAndPtr(int code, IRxObject* pObj, void* ptr);
    int notifyObjAndInt(int code, IRxObject* pObj1, IRxObject* pObj2, int exCode);
    int notifyInt(int code, int exCode);
    int notifyInt2(int code, int exCode, int exCode2);
    int notifyDouble(int code, double dValue);
    int notifyText(int code, const char* pszText);
    int notifyPtrAndInt(int code, void* ptr1, void* ptr2, int exCode);
    int notifyTextAndInt(int code, const char* pszText, int exCode);
    int notifyMesMsg(int code, int stream, int function, const char* pszText);
public:
    CConfiguration m_configuration;
private:
    IObservable* m_pObservable;
    IObservableEmitter* m_pObservableEmitter;
    CString m_strWorkDir;
    CString m_strDataDir;
};
SourceCode/Bond/Servo/Servo.cpp
@@ -81,6 +81,7 @@
    _tsplitpath_s(sAppFilename, sDrive, sDir, sFilename, sExt);
    m_strAppDir = CString(sDrive) + CString(sDir);
    m_strAppFile = CString(sFilename);
    m_model.setWorkDir((LPTSTR)(LPCTSTR)m_strAppDir);
    // æ³¨å†ŒæŽ§ä»¶
SourceCode/Bond/Servo/Servo.rc
Binary files differ
SourceCode/Bond/Servo/Servo.vcxproj
@@ -119,6 +119,7 @@
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
    </Link>
    <Midl>
      <MkTypLibCompatible>false</MkTypLibCompatible>
@@ -191,6 +192,10 @@
  <ItemGroup>
    <ClInclude Include="BlButton.h" />
    <ClInclude Include="Common.h" />
    <ClInclude Include="Configuration.h" />
    <ClInclude Include="Log.h" />
    <ClInclude Include="LogDlg.h" />
    <ClInclude Include="LogEdit.h" />
    <ClInclude Include="Model.h" />
    <ClInclude Include="Resource.h" />
    <ClInclude Include="Servo.h" />
@@ -201,6 +206,10 @@
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="BlButton.cpp" />
    <ClCompile Include="Configuration.cpp" />
    <ClCompile Include="Log.cpp" />
    <ClCompile Include="LogDlg.cpp" />
    <ClCompile Include="LogEdit.cpp" />
    <ClCompile Include="Model.cpp" />
    <ClCompile Include="Servo.cpp" />
    <ClCompile Include="ServoDlg.cpp" />
SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -45,6 +45,18 @@
    <ClInclude Include="Common.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="LogDlg.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="LogEdit.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Configuration.h">
      <Filter>头文件</Filter>
    </ClInclude>
    <ClInclude Include="Log.h">
      <Filter>头文件</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="Servo.cpp">
@@ -65,6 +77,18 @@
    <ClCompile Include="BlButton.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="LogDlg.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="LogEdit.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="Configuration.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
    <ClCompile Include="Log.cpp">
      <Filter>源文件</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="Servo.rc">
SourceCode/Bond/Servo/ServoDlg.cpp
@@ -7,6 +7,7 @@
#include "ServoDlg.h"
#include "afxdialogex.h"
#include "Common.h"
#include "Log.h"
#ifdef _DEBUG
@@ -73,6 +74,7 @@
    m_crBkgnd = APPDLG_BACKGROUND_COLOR;
    m_hbrBkgnd = nullptr;
    m_bShowLogWnd = FALSE;
    m_pLogDlg = nullptr;
}
void CServoDlg::DoDataExchange(CDataExchange* pDX)
@@ -91,6 +93,10 @@
    ON_WM_DESTROY()
    ON_BN_CLICKED(IDC_BUTTON_LOG, &CServoDlg::OnBnClickedButtonLog)
    ON_WM_SIZE()
    ON_WM_CLOSE()
    ON_MESSAGE(ID_MSG_LOGDLG_HIDE, &CServoDlg::OnLogDlgHide)
    ON_WM_MOVING()
    ON_WM_MOVE()
END_MESSAGE_MAP()
@@ -206,6 +212,18 @@
    m_pGraph->SetBoxText(INDICATE_MEASUREMENT, "13", "Measurement");
    // è°ƒæ•´åˆå§‹çª—口位置
    CRect rcWnd;
    GetWindowRect(&rcWnd);
    int width = GetSystemMetrics(SM_CXSCREEN);
    int height = GetSystemMetrics(SM_CYSCREEN);
    MoveWindow((width - rcWnd.Width()) / 2, 0, rcWnd.Width(), rcWnd.Height(), TRUE);
    // model init
    theApp.m_model.init();
    UpdateLogBtn();
    Resize();
    return TRUE;  // é™¤éžå°†ç„¦ç‚¹è®¾ç½®åˆ°æŽ§ä»¶ï¼Œå¦åˆ™è¿”回 TRUE
@@ -295,6 +313,12 @@
{
    CDialogEx::OnDestroy();
    if (m_pLogDlg != nullptr) {
        m_pLogDlg->DestroyWindow();
        delete m_pLogDlg;
        m_pLogDlg = nullptr;
    }
    if (m_hbrBkgnd != nullptr) {
        ::DeleteObject(m_hbrBkgnd);
    }
@@ -303,6 +327,18 @@
void CServoDlg::OnBnClickedButtonLog()
{
    m_bShowLogWnd = !m_bShowLogWnd;
    if (m_pLogDlg == nullptr) {
        m_pLogDlg = new CLogDlg();
        m_pLogDlg->Create(IDD_DIALOG_LOG, this);
        CRect rcWnd;
        GetWindowRect(&rcWnd);
        m_pLogDlg->MoveWindow(rcWnd.left, rcWnd.bottom - 8, rcWnd.Width(), 200);
    }
    ASSERT(m_pLogDlg);
    m_pLogDlg->ShowWindow(m_bShowLogWnd ? SW_SHOW : SW_HIDE);
    LOGE("OnBnClickedButtonLog");
    UpdateLogBtn();
}
@@ -314,6 +350,7 @@
    m_btnLog.SetBkgndColor(BS_NORMAL, m_bShowLogWnd ? BTN_LOG_BKGND_PRESS : BTN_LOG_BKGND_NORMAL);
    m_btnLog.SetBkgndColor(BS_HOVER, BTN_LOG_BKGND_HOVER);
    m_btnLog.SetBkgndColor(BS_PRESS, BTN_LOG_BKGND_PRESS);
    m_btnLog.Invalidate();
}
void CServoDlg::OnSize(UINT nType, int cx, int cy)
@@ -342,3 +379,35 @@
    pItem->GetClientRect(&rcItem);
    pItem->MoveWindow(x, y, rcItem.Width(), rcItem.Height());
}
void CServoDlg::OnClose()
{
    // TODO: åœ¨æ­¤æ·»åŠ æ¶ˆæ¯å¤„ç†ç¨‹åºä»£ç å’Œ/或调用默认值
    CDialogEx::OnClose();
}
LRESULT CServoDlg::OnLogDlgHide(WPARAM wParam, LPARAM lParam)
{
    m_bShowLogWnd = FALSE;
    UpdateLogBtn();
    LOGE("OnLogDlgHide");
    return 0;
}
void CServoDlg::OnMoving(UINT fwSide, LPRECT pRect)
{
    CDialogEx::OnMoving(fwSide, pRect);
}
void CServoDlg::OnMove(int x, int y)
{
    if (m_pLogDlg != nullptr && !m_pLogDlg->IsZoomed()) {
        CRect rcWnd;
        GetWindowRect(&rcWnd);
        m_pLogDlg->MoveWindow(rcWnd.left, rcWnd.bottom - 8, rcWnd.Width(), 200);
    }
    CDialogEx::OnMove(x, y);
}
SourceCode/Bond/Servo/ServoDlg.h
@@ -5,6 +5,7 @@
#pragma once
#include "ServoGraph.h"
#include "BlButton.h"
#include "LogDlg.h"
// CServoDlg å¯¹è¯æ¡†
@@ -31,6 +32,7 @@
private:
    BOOL m_bShowLogWnd;
    CLogDlg* m_pLogDlg;
// å®žçް
protected:
@@ -54,4 +56,8 @@
    afx_msg void OnDestroy();
    afx_msg void OnBnClickedButtonLog();
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnClose();
    afx_msg LRESULT OnLogDlgHide(WPARAM wParam, LPARAM lParam);
    afx_msg void OnMoving(UINT fwSide, LPRECT pRect);
    afx_msg void OnMove(int x, int y);
};
SourceCode/Bond/Servo/resource.h
Binary files differ