Files
envi-code/SourceCode/Code2026/CoreCommand/AskAIPaletteSet.cpp
T
2026-09-28 15:28:50 +08:00

803 lines
38 KiB
C++

#include "StdAfx.h"
#include "resource.h"
#include "EarThwormDef.h"
#include "askaiPaletteSet.h"
#include "AIChatSettingDlg.h"
#include "AICloudSettingDlg.h"
#include <atlconv.h>
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<std::string> &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