#include "StdAfx.h" #include "resource.h" #include "EarThwormDef.h" #include "askaiPaletteSet.h" #include "AIChatSettingDlg.h" #include "AICloudSettingDlg.h" #include namespace { // 请求 SHAI::Request g_Request; // 回答 SHAI::Response g_Response; // 线程句柄 HANDLE g_hThread = NULL; unsigned int __stdcall requestSendProc(void *pParam) { g_Request.send(g_Response); CString finishReason(AIJSON::utf2w(g_Response.finish_reason()).c_str()); if (finishReason.CompareNoCase(_T("stop")) == 0) { if (g_Response.needRecordContext() && !g_Response.allContent().empty()) g_Request.addAssistantMessage(g_Response.allContent().c_str()); } else { if (finishReason.CompareNoCase(_T("length")) == 0) { g_aiPaletteSet::instance().sendTextToAnswer(_T("\r\n达到生成的最大长度限制。")); } else if (finishReason.CompareNoCase(_T("content_filter")) == 0) { g_aiPaletteSet::instance().sendTextToAnswer(_T("\r\n内容因安全策略被过滤系统拦截,可能是触发了敏感词、违规内容检测等。")); } else if (finishReason.CompareNoCase(_T("timeout")) == 0) { g_aiPaletteSet::instance().sendTextToAnswer(_T("\r\n超时。")); } else if (finishReason.CompareNoCase(_T("insufficient_system_resource")) == 0) { g_aiPaletteSet::instance().sendTextToAnswer(_T("\r\n由于后端推理资源受限,请求被打断。")); } else { #ifdef NDEBUG g_aiPaletteSet::instance().sendTextToAnswer(_T("\r\n服务器繁忙,请稍候再试。")); #else g_aiPaletteSet::instance().sendTextToAnswer( CString(_T("\r\n")) + finishReason); #endif } // 弹出最后一条 user message g_Request.popbackMessage(); return 0; } return 0; } } #pragma region CAskAIPaletteSet IMPLEMENT_DYNAMIC(CAskAIPaletteSet, CAdUiPaletteSet) BEGIN_MESSAGE_MAP(CAskAIPaletteSet, CAdUiPaletteSet) ON_WM_CREATE() ON_WM_DESTROY() END_MESSAGE_MAP() CAskAIPaletteSet::CAskAIPaletteSet() : m_pAiPalette(NULL) { } CAskAIPaletteSet::~CAskAIPaletteSet() { } bool CAskAIPaletteSet::CreatePaletteSet(LPCTSTR pszTitle) { CMDIFrameWnd* pFrame = acedGetAcadFrame(); ASSERT(NULL != pFrame); if (!Create(pszTitle, WS_CHILD | WS_VISIBLE | CBRS_SIZE_DYNAMIC | CBRS_RIGHT, CRect(0, 0, 160, 100), pFrame)) { acutPrintf(_T("\n创建失败!")); return FALSE; } EnableDocking(CBRS_ALIGN_ANY); RestoreControlBar(AFX_IDW_DOCKBAR_FLOAT); m_pAiPalette = new CAskAIPalette; if (m_pAiPalette->Create(WS_CHILD | WS_VISIBLE, _T("问问AI"), this, NULL)) AddPalette(m_pAiPalette); if (this->GetPaletteCount() > 0) { SetActivePalette(0); } return true; } int CAskAIPaletteSet::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CAdUiPaletteSet::OnCreate(lpCreateStruct) == -1) return -1; CWnd* pWnd = GetDlgItem(idCloseBtn); ASSERT(NULL != pWnd); pWnd->EnableWindow(FALSE); static GUID cMenuBar = { 0x40929771, 0xf51d, 0x42ad, { 0x97, 0xa, 0x9a, 0xf9, 0xd3, 0x78, 0x2c, 0xea } }; SetToolID(&cMenuBar); return 0; } void CAskAIPaletteSet::OnDestroy() { CAdUiPalette* pPage = NULL; while (GetPaletteCount() > 0) { pPage = GetPalette(0); RemovePalette(pPage); delete pPage; } CAdUiPaletteSet::OnDestroy(); } BOOL CAskAIPaletteSet::PreTranslateMessage(MSG *pMsg) { if (pMsg->message == WM_KEYDOWN) { CWnd *pWnd = CWnd::FromHandle(pMsg->hwnd); if (pWnd->GetDlgCtrlID() == IDC_EDIT_ASK || pWnd->GetDlgCtrlID() == IDC_EDIT_ANSWER ) { if (pMsg->wParam == VK_ESCAPE) return TRUE; } } return CAdUiPaletteSet::PreTranslateMessage(pMsg); } bool CAskAIPaletteSet::OnClosing() { return (IDYES != MessageBox(_T("窗口即将关闭。\n\n是否要关闭?"), _T("问问AI"), MB_YESNO | MB_ICONQUESTION)); } void CAskAIPaletteSet::GetFloatingMinSize(long * plMinWidth, long * plMinHeight) { *plMinWidth = 1024; *plMinHeight = 800; } void CAskAIPaletteSet::SizeChanged(CRect * lpRect, BOOL bFloating, int flags) { CAdUiPaletteSet::SizeChanged(lpRect, bFloating, flags); CRect rc(lpRect); rc.DeflateRect(6, 6); CString sKey; CAdUiPalette* pPage = NULL; for (int i = 0; i < GetPaletteCount(); i++) { pPage = GetPalette(i); if (pPage != NULL) { ((CAskAIPalette*)pPage)->MoveWindow(rc); } } } void CAskAIPaletteSet::GetMinimumSize(CSize & size) { size.cx = 1024; size.cy = 800; CAdUiPaletteSet::GetMinimumSize(size); } void CAskAIPaletteSet::GetMaximumSize(CSize & size) { CAdUiPaletteSet::GetMaximumSize (size) ; } void CAskAIPaletteSet::sendTextToAnswer(LPCTSTR lpszText) { CString s(lpszText); s.Replace(_T("\r\n"), _T("\n")); s.Replace(_T("\n"), _T("\r\n")); if (m_pAiPalette) m_pAiPalette->sendTextToAnswer(s); } void CAskAIPaletteSet::setFocusToAsk() { if (m_pAiPalette) m_pAiPalette->setFocusToAsk(); } void CAskAIPaletteSet::refreshAiCloud() { if (m_pAiPalette && ::IsWindow(g_aiPaletteSet::instance().m_hWnd)) m_pAiPalette->refreshAiCloud(); } void CAskAIPaletteSet::start() { #if ARX > 18 if (!::IsWindow(g_aiPaletteSet::instance().m_hWnd)) { g_aiPaletteSet::instance().CreatePaletteSet(_T("问问AI")); } if (::IsWindow(g_aiPaletteSet::instance().m_hWnd)) { g_aiPaletteSet::instance().m_pDockSite->ShowControlBar(&g_aiPaletteSet::instance(), TRUE, FALSE); g_aiPaletteSet::instance().setFocusToAsk(); g_aiPaletteSet::instance().refreshAiCloud(); } #else AfxMessageBox(_T("CAD2013以下版本不支持此功能。")); #endif } void CAskAIPaletteSet::setAiCloud() { #if ARX > 18 CAcModuleResourceOverride myResources; CAICloudSettingDlg dlg; dlg.DoModal(); #else AfxMessageBox(_T("CAD2013以下版本不支持此功能。")); #endif } #pragma endregion /////////////////////////////////////////////////////////////////////////////////////////////////// #pragma region CAskAIPalette IMPLEMENT_DYNAMIC(CAskAIPalette, CAdUiPalette) BEGIN_MESSAGE_MAP(CAskAIPalette, CAdUiPalette) ON_WM_CREATE() ON_WM_PAINT() ON_WM_WINDOWPOSCHANGED() ON_BN_CLICKED(IDC_BTN_NEWCHAT, &CAskAIPalette::OnBtnClickNewChat) ON_BN_CLICKED(IDC_BTN_UPLOAD, &CAskAIPalette::OnBtnClickUpload) ON_BN_CLICKED(IDC_BTN_EN2CH, &CAskAIPalette::OnBtnClickTranslate) ON_BN_CLICKED(IDC_BTN_EXPORT, &CAskAIPalette::OnBtnClickExport) ON_BN_CLICKED(IDC_BTN_SETTING, &CAskAIPalette::OnBtnClickSetting) ON_BN_CLICKED(IDC_BTN_SEND, &CAskAIPalette::OnBtnClickSend) ON_CBN_SELCHANGE(IDC_COMBO_MODEL, &CAskAIPalette::OnComboBoxModelListSelChange) ON_CBN_DROPDOWN(IDC_COMBO_MODEL, &CAskAIPalette::OnComboBoxModelListDropDown) END_MESSAGE_MAP() CAskAIPalette::CAskAIPalette() : m_pEdAnswer(NULL) , m_pEdAsk(NULL) , m_pBtnNewChat(NULL) , m_pBtnUploadFile(NULL) , m_pBtnTranslate(NULL) , m_pBtnSend(NULL) , m_pBtnExport(NULL) , m_pBtnSetting(NULL) , m_pStaticCloudName(NULL) , m_pComboModelList(NULL) , m_pAiCloud(NULL) { LOGFONT lf; ::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf); CClientDC dc(this); _tcscpy(lf.lfFaceName, _T("微软雅黑")); lf.lfHeight = -MulDiv(13, GetDeviceCaps(dc.m_hDC, LOGPIXELSY), 72); m_fontEdit.CreateFontIndirect(&lf); ::memset(&lf, 0, sizeof(LOGFONT)); ::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf); _tcscpy(lf.lfFaceName, _T("宋体")); lf.lfHeight = -MulDiv(12, GetDeviceCaps(dc.m_hDC, LOGPIXELSY), 72); m_fontBTN.CreateFontIndirect(&lf); } CAskAIPalette::~CAskAIPalette() { DELETE_PTR(m_pEdAnswer); DELETE_PTR(m_pEdAsk); DELETE_PTR(m_pBtnNewChat); DELETE_PTR(m_pBtnUploadFile); DELETE_PTR(m_pBtnTranslate); DELETE_PTR(m_pBtnSend); DELETE_PTR(m_pBtnExport); DELETE_PTR(m_pBtnSetting); DELETE_PTR(m_pStaticCloudName); DELETE_PTR(m_pComboModelList); DELETE_PTR(m_pAiCloud); ::DeleteObject(m_fontEdit); ::DeleteObject(m_fontBTN); } void CAskAIPalette::sendTextToAnswer(LPCTSTR lpszText) { if (!::IsWindow(g_aiPaletteSet::instance().m_hWnd)) return; int nLength = m_pEdAnswer->GetWindowTextLength(); m_pEdAnswer->SetSel(nLength, nLength); m_pEdAnswer->ReplaceSel(lpszText); m_pEdAnswer->LineScroll(m_pEdAnswer->GetLineCount()); } void CAskAIPalette::setFocusToAsk() { m_pEdAsk->SetFocus(); } void CAskAIPalette::refreshAiCloud() { DELETE_PTR(m_pAiCloud); if (!CAICloudSettingDlg::getActiveAIClouds(m_pAiCloud)) { AfxMessageBox(_T("未找到当前的AI配置,请先运行co_llm命令进行配置。")); acedPostCommand(_T("co_llm ")); return; } CAIChatSettingDlg::getChatConfig(m_chatConfig); m_pAiCloud->getModels(); if (m_pAiCloud->models().size() == 0) { AfxMessageBox(_T("获取模型列表失败,请重试,或者更换供应商。")); return; } g_Request.setapikey(m_pAiCloud->apiKey().c_str()); g_Request.seturl(m_pAiCloud->endpoint().c_str()); g_Request.setmodel(m_pAiCloud->currentModel().c_str()); g_Request.set_temperature(m_chatConfig.temperature()); g_Request.set_top_p(m_chatConfig.top_p()); g_Request.set_top_k(m_chatConfig.top_k()); g_Request.set_max_tokens(m_chatConfig.max_tokens()); g_Request.set_frequency_penalty(m_chatConfig.frequency_penalty()); m_pComboModelList->ResetContent(); const std::vector &models = m_pAiCloud->models(); int idx(-1); for (size_t i(0); i < models.size(); ++i) { idx = m_pComboModelList->AddString(AIJSON::utf2w(models[i]).c_str()); if (m_pAiCloud->currentModel() == models[i]) m_pComboModelList->SetCurSel(idx); } m_pStaticCloudName->SetWindowText(AIJSON::utf2w(m_pAiCloud->cloudName()).c_str()); CalcCtrlPosition(); } void CAskAIPalette::OnBtnClickNewChat() { g_Request.clearMessages(); g_Response.clear(); m_pEdAnswer->SetWindowText(_T("")); } void CAskAIPalette::OnBtnClickUpload() { } void CAskAIPalette::OnBtnClickTranslate() { if (hasActiveRequest()) { AfxMessageBox(_T("还有一个问题没有解答完成,请稍等!")); return; } CString sAsk; m_pEdAsk->GetWindowText(sAsk); if (sAsk.IsEmpty()) { AfxMessageBox(_T("消息为空!")); return; } m_pEdAsk->SetWindowText(_T("")); CString ss(m_pEdAnswer->GetLineCount() == 1 ? _T("") : _T("\r\n\r\n")); sendTextToAnswer(ss + _T("原文:\r\n") + sAsk); g_Request.clearMessages(); g_Request.setstream(true); g_Response.clear(); // 不需要记录上下文 g_Response.setRecordContext(false); g_Request.addSystemMessage( "你是一个中英文翻译专家,将用户输入的中文翻译成英文,或将用户输入的英文翻译成中文。" "对于非中文内容,它将提供中文翻译结果。" "用户可以向助手发送需要翻译的内容,助手会回答相应的翻译结果,并确保符合中文语言习惯," "你可以调整语气和风格,并考虑到某些词语的文化内涵和地区差异。" "同时作为翻译家,需将原文翻译成具有信达雅标准的译文。" "\"信\" 即忠实于原文的内容与意图;" "\"达\" 意味着译文应通顺易懂,表达清晰;" "\"雅\" 则追求译文的文化审美和语言的优美。" "目标是创作出既忠于原作精神,又符合目标语言文化和读者审美的翻译。"); g_Request.addUserMessage(CW2A((LPCTSTR)sAsk, CP_UTF8)); g_hThread = (HANDLE)::_beginthreadex(NULL , 0 , requestSendProc , NULL , NULL , NULL); return; } void CAskAIPalette::OnBtnClickExport() { // 取出 Answer 的内容 CString sAnswer; m_pEdAnswer->GetWindowText(sAnswer); if (sAnswer.IsEmpty()) { AfxMessageBox(_T("回答窗口内容为空!")); return; } CTime currentTime = CTime::GetCurrentTime(); // 将时间格式化为 yyyy-mm-dd 字符串 CString dateString = currentTime.Format(_T("%Y-%m-%d")); CString fileName; fileName.Format(_T("上华AskAI%s.txt"), dateString); CFileDialog dlg(FALSE , _T("txt") , fileName , OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT); if (dlg.DoModal() != IDOK) return; CString sPath(dlg.GetPathName()); CFile file(sPath, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary); if (file.m_hFile) { std::string str(CW2A((LPCTSTR)sAnswer, CP_UTF8)); file.Write(str.c_str(), (UINT)(sizeof(char) * str.length())); file.Close(); } return; } void CAskAIPalette::OnBtnClickSend() { if (hasActiveRequest()) { AfxMessageBox(_T("还有一个问题没有解答完成,请稍等!")); return; } CString sAsk; m_pEdAsk->GetWindowText(sAsk); if (sAsk.IsEmpty()) { AfxMessageBox(_T("消息为空!")); return; } m_pEdAsk->SetWindowText(_T("")); g_Request.setstream(true); g_Response.clear(); CString ss(m_pEdAnswer->GetLineCount() == 1 ? _T("") : _T("\r\n\r\n")); sendTextToAnswer(ss + _T("我:\r\n") + sAsk); g_Request.addUserMessage(CW2A((LPCTSTR)sAsk, CP_UTF8)); g_hThread = (HANDLE)::_beginthreadex(NULL , 0 , requestSendProc , NULL , NULL , NULL); return; } void CAskAIPalette::OnBtnClickSetting() { CAcModuleResourceOverride myResources; CAIChatSettingDlg dlg; if (dlg.DoModal() == IDOK) CAIChatSettingDlg::getChatConfig(m_chatConfig); } int CAskAIPalette::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CAdUiPalette::OnCreate(lpCreateStruct) == -1) return -1; DWORD dwStyle(WS_CHILD | WS_VISIBLE); CRect rctmp; do { m_pEdAnswer = new CEdit(); if (!m_pEdAnswer->Create(dwStyle | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL | WS_BORDER , rctmp , this , IDC_EDIT_ANSWER)) break; m_pEdAnswer->SetFont(&m_fontEdit); m_pEdAsk = new CEdit(); if (!m_pEdAsk->Create(dwStyle | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_BORDER , rctmp , this , IDC_EDIT_ASK)) break; m_pEdAsk->SetFont(&m_fontEdit); m_pBtnNewChat = new CAcUiBitmapButton(); if (!m_pBtnNewChat->Create(_T("新话题") , dwStyle | BS_PUSHBUTTON , rctmp , this , IDC_BTN_NEWCHAT)) break; m_pBtnNewChat->SetFont(&m_fontBTN); m_pBtnUploadFile = new CAcUiBitmapButton(); if (!m_pBtnUploadFile->Create(_T("上传文件") , dwStyle | BS_PUSHBUTTON , rctmp , this , IDC_BTN_UPLOAD)) break; m_pBtnUploadFile->EnableWindow(FALSE); m_pBtnUploadFile->SetFont(&m_fontBTN); m_pBtnTranslate = new CAcUiBitmapButton(); if (!m_pBtnTranslate->Create(_T("中英互译") , dwStyle | BS_PUSHBUTTON , rctmp , this , IDC_BTN_EN2CH)) break; m_pBtnTranslate->SetFont(&m_fontBTN); m_pBtnSend = new CAcUiBitmapButton(); if (!m_pBtnSend->Create(_T("发送(ctrl+Enter)") , dwStyle | BS_PUSHBUTTON , rctmp , this , IDC_BTN_SEND)) break; m_pBtnSend->SetFont(&m_fontBTN); m_pBtnExport = new CAcUiBitmapButton(); if (!m_pBtnExport->Create(_T("导出") , dwStyle | BS_PUSHBUTTON , rctmp , this , IDC_BTN_EXPORT)) break; m_pBtnExport->SetFont(&m_fontBTN); m_pBtnSetting = new CAcUiBitmapButton(); if (!m_pBtnSetting->Create(_T("设置") , dwStyle | BS_PUSHBUTTON , rctmp , this , IDC_BTN_SETTING)) break; m_pBtnSetting->SetFont(&m_fontBTN); m_pStaticCloudName = new CStatic(); if (!m_pStaticCloudName->Create(_T("") , dwStyle | SS_RIGHT , rctmp , this , IDC_STATIC)) break; m_pStaticCloudName->SetFont(&m_fontBTN); m_pComboModelList = new CAcUiComboBox(); if (!m_pComboModelList->Create(dwStyle | CBS_DROPDOWNLIST | WS_VSCROLL , CRect(0, 0, 300, 300) , this , IDC_COMBO_MODEL)) break; m_pComboModelList->SetFont(&m_fontBTN); return 0; } while (false); DELETE_PTR(m_pEdAnswer); DELETE_PTR(m_pEdAsk); DELETE_PTR(m_pBtnNewChat); DELETE_PTR(m_pBtnUploadFile); DELETE_PTR(m_pBtnTranslate); DELETE_PTR(m_pBtnSend); DELETE_PTR(m_pBtnExport); DELETE_PTR(m_pStaticCloudName); DELETE_PTR(m_pComboModelList); return -1; } void CAskAIPalette::OnComboBoxModelListSelChange() { int idx = m_pComboModelList->GetCurSel(); if (idx == -1) return; CString sModel; m_pComboModelList->GetLBString(idx, sModel); m_pAiCloud->setCurrentModel(AIJSON::w2utf(sModel).c_str()); g_Request.setmodel(m_pAiCloud->currentModel().c_str()); CalcCtrlPosition(); } void CAskAIPalette::OnComboBoxModelListDropDown() { int iCount = m_pComboModelList->GetCount(); CString str; int len(0); CSize sz; for (int i(0); i < iCount; ++i) { m_pComboModelList->GetLBString(i, str); sz = getControlWndTextSize(m_pComboModelList, m_fontBTN, str); if (len < sz.cx) len = sz.cx; } int nMin = m_pComboModelList->GetMinVisible(); m_pComboModelList->SetDroppedWidth(len + (nMin < iCount ? 25 : 5)); } #define MOVE_WINDOW(wnd,rc) if (wnd && ::IsWindow(wnd->GetSafeHwnd())) wnd->MoveWindow(rc) void CAskAIPalette::CalcCtrlPosition() { CRect rc; GetClientRect(rc); rc.InflateRect(-3, -3, -3, -3); int nSpace(3), nAnswerH, nAskH, nBtnH(26), nComboModelsW(300), nStaticCloudH(26); int nAllEditH(rc.Height() - nBtnH - 2 * nSpace - nStaticCloudH - 2 * nSpace); nAskH = (int)(nAllEditH * .25); nAnswerH = nAllEditH - nAskH; CSize csStatic = getControlWndTextSize(m_pStaticCloudName, m_fontBTN); CRect rcStaticCloud(CPoint(rc.left + 1, rc.bottom - nStaticCloudH + 1) , CSize(csStatic.cx, nStaticCloudH - 2)); MOVE_WINDOW(m_pStaticCloudName, rcStaticCloud); CSize csCombo = getControlWndTextSize(m_pComboModelList, m_fontBTN); CRect rcComboModels(CPoint(rcStaticCloud.right + 2 * nSpace, rc.bottom - nSpace - nStaticCloudH) , CSize(csCombo.cx + 30, nStaticCloudH)); MOVE_WINDOW(m_pComboModelList, rcComboModels); CRect rcAsk(CPoint(rc.left, rcComboModels.top - nSpace - nAskH), CSize(rc.Width(), nAskH)); MOVE_WINDOW(m_pEdAsk, rcAsk); const CSize szBtn(100, nBtnH); int btTop(rcAsk.top - nSpace - szBtn.cy); int btBottom(btTop + szBtn.cy); CRect rcNewChat(rc.left, btTop, rc.left + szBtn.cx, btBottom); MOVE_WINDOW(m_pBtnNewChat, rcNewChat); CRect rcUpload(rcNewChat.right + 10, btTop, rcNewChat.right + 10 + szBtn.cx, btBottom); MOVE_WINDOW(m_pBtnUploadFile, rcUpload); CRect rcEn2Ch(rcUpload.right + 10, btTop, rcUpload.right + 10 + szBtn.cx, btBottom); MOVE_WINDOW(m_pBtnTranslate, rcEn2Ch); CRect rcExport(rcEn2Ch.right + 10, btTop, rcEn2Ch.right + 10 + szBtn.cx, btBottom); MOVE_WINDOW(m_pBtnExport, rcExport); CRect rcSetting(rcExport.right + 10, btTop, rcExport.right + 10 + szBtn.cx, btBottom); MOVE_WINDOW(m_pBtnSetting, rcSetting); CRect rcSend(CPoint(rc.right - 20 - (int)(szBtn.cx * 2), rcComboModels.top) , CSize(szBtn.cx * 2, szBtn.cy +4)); MOVE_WINDOW(m_pBtnSend, rcSend); CRect rcAnswer(rc.TopLeft(), CSize(rc.Width(), nAnswerH)); MOVE_WINDOW(m_pEdAnswer, rcAnswer); Invalidate(); } bool CAskAIPalette::hasActiveRequest() { DWORD dwExitCode; BOOL bResult = GetExitCodeThread(g_hThread, &dwExitCode); if (bResult && dwExitCode == STILL_ACTIVE) { return true; } return false; } CSize CAskAIPalette::getControlWndTextSize(CWnd *pS, CFont &font, LPCTSTR psz) { CRect rect; CSize size(0, 0); CDC *pDc = pS->GetDC(); pDc->SelectObject(font); CString str; if (psz) str = psz; else pS->GetWindowText(str); ::GetTextExtentPoint32(pDc->m_hDC, str, str.GetLength(), &size); pS->ReleaseDC(pDc); return size; } void CAskAIPalette::OnWindowPosChanged(WINDOWPOS * lpwndpos) { CAdUiPalette::OnWindowPosChanged(lpwndpos); CalcCtrlPosition(); } void CAskAIPalette::OnPaint() { CPaintDC dc(this); CRect rc; GetClientRect(rc); rc.InflateRect(-2, 0, -2, 0); dc.FillSolidRect(rc, RGB(158, 158, 158)); rc.InflateRect(-1, -1, -1, -1); dc.FillSolidRect(rc, RGB(240, 240, 240)); } void CAskAIPalette::GetFloatingMinSize(long * pnMinWidth, long * pnMinHeight) { *pnMinWidth = 1023; *pnMinHeight = 767; } BOOL CAskAIPalette::PreTranslateMessage(MSG *pMsg) { if (pMsg->message == WM_KEYDOWN) { CWnd *pWnd = CWnd::FromHandle(pMsg->hwnd); if (pWnd->GetDlgCtrlID() == IDC_EDIT_ASK) { if (pMsg->wParam == VK_RETURN && (GetKeyState(VK_CONTROL) & 0x8000)) { OnBtnClickSend(); return TRUE; } } } return CAdUiPalette::PreTranslateMessage(pMsg); } bool CAskAIPalette::CanFrameworkTakeFocus() { return false; } #pragma endregion