#include "stdafx.h" #include "xtr/dialog/Term2Function.h" #include "resource.h" #include "xtr/ExteorOptions.h" #include "xtr/cclDescriptor.h" #include "xtr/ui/HelpHandler.h" #include "xtr/ui/KeyboardHandler.h" #include "xtr/ui/UIHelper.h" #include "ccl/semantic/CstFilters.hpp" #include "ccl/rslang/RSGenerator.h" #include "ccl/rslang/RSExpr.h" namespace xtr::dialog { using ccl::semantic::CstType; struct Term2Function::Header : xtr::ui::Header { enum Columns : uint8_t { POS_NAME = 0, POS_TYPE, COLOUMN_COUNT }; static constexpr auto widthName = 60; static constexpr auto widthTypification = 250; Header() { AddColumn({ IXTRS_HEADER_NAME, Alignment::left, widthName }); AddColumn({ IXTRS_HEADER_TYPE, Alignment::left, widthTypification }); } }; #pragma warning( push ) #pragma warning( disable : 26440 26436 26454 ) BEGIN_MESSAGE_MAP(Term2Function, CDialog) ON_CBN_SELCHANGE(IXTRC_TERM_CB, &ThisClass::OnSelchangeTermCb) ON_BN_CLICKED(IXTRC_UPDATE_EXP, &ThisClass::OnBnClickedUpdateExp) ON_BN_CLICKED(IXTRC_RIGHT, &ThisClass::OnBnClickedRight) ON_BN_CLICKED(IXTRC_LEFT, &ThisClass::OnBnClickedLeft) ON_BN_CLICKED(IXTRC_ADDFUNC, &ThisClass::OnBnClickedApply) ON_NOTIFY(NM_DBLCLK, IXTRC_GLOBAL_LIST, &ThisClass::OnDblClickGlobal) ON_NOTIFY(NM_DBLCLK, IXTRC_ARG_LIST, &ThisClass::OnDblClickArg) END_MESSAGE_MAP() #pragma warning( pop ) Term2Function::Term2Function(doc::RSFacade& editor, const EntityUID startID, CWnd* pParent) : CDialog(IXTRD_GENERATE_FUNC, pParent), editor{ editor } { if (const auto& cst = editor.GetRS(startID); cst.type == CstType::term) { cstName = mfc::ToMFC(cst.alias); inputExpr = mfc::ToMFC(cst.definition); } } BOOL Term2Function::OnInitDialog() { CDialog::OnInitDialog(); InitControls(); InitHeaders(); InitCstNameList(); UpdateData(FALSE); return TRUE; } void Term2Function::InitControls() { inputCtrl.InitRE(ui::Keyboard::Layout::MATH, TRUE, TRUE); expressionCtrl.InitRE(ui::Keyboard::Layout::MATH, TRUE, TRUE); definitionCtrl.InitRE(ui::Keyboard::Layout::RUS); definitionCtrl.SetFont(&XTROptions::App().fontText); } void Term2Function::InitCstNameList() { const auto selection = cstPicker.GetCurSel(); cstPicker.ResetContent(); for (const auto uid : ccl::semantic::FilterCst(editor.Core(), CstType::term)) { cstPicker.AddString(mfc::ToMFC(editor.GetRS(uid).alias)); } cstPicker.SetCurSel(selection); } void Term2Function::InitHeaders() { static const Header listHeader{}; ui::InitHeaderFor(globalsCtrl, listHeader); ui::InitHeaderFor(argsCtrl, listHeader); } void Term2Function::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); ::DDX_Control(pDX, IXTRC_TERM_CB, cstPicker); ::DDX_Control(pDX, IXTRC_EXPR_INPUT, inputCtrl); ::DDX_Control(pDX, IXTRC_EXPR_OUTPUT, expressionCtrl); ::DDX_Control(pDX, IXTRC_INTER, definitionCtrl); ::DDX_Control(pDX, IXTRC_GLOBAL_LIST, globalsCtrl); ::DDX_Control(pDX, IXTRC_ARG_LIST, argsCtrl); ::DDX_Text(pDX, IXTRC_EXPR_INPUT, inputExpr); ::DDX_Text(pDX, IXTRC_EXPR_OUTPUT, expression); ::DDX_Text(pDX, IXTRC_INTER, textRef); ::DDX_CBString(pDX, IXTRC_TERM_CB, cstName); if (!pDX->m_bSaveAndValidate) { UpdateUI(); } } BOOL Term2Function::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_F1) { ui::HelpHandler::RunHelp(ui::HelpID::generateCst); return TRUE; } return CDialog::PreTranslateMessage(pMsg); } void Term2Function::OnSelchangeTermCb() { UpdateData(TRUE); const auto uid = editor.Core().FindAlias(mfc::ToSTL(cstName)).value(); inputExpr = mfc::ToMFC(editor.GetRS(uid).definition); UpdateData(FALSE); } void Term2Function::OnBnClickedUpdateExp() { using ccl::rslang::Generator; UpdateData(TRUE); if (argsCtrl.GetItemCount() == 0) { ::AfxMessageBox(IXTRE_NO_ARGS, MB_ICONEXCLAMATION); return; } std::vector args{}; args.reserve(argsCtrl.GetItemCount()); for (auto i = 0; i < argsCtrl.GetItemCount(); ++i) { args.emplace_back(mfc::ToSTL(argsCtrl.GetItemText(i, Header::POS_NAME))); } expression = mfc::ToMFC(Generator(editor.Core().RSLang()).FunctionFromExpr(args, mfc::ToSTL(inputExpr))); expressionCtrl.SetWindowTextW(expression); } void Term2Function::OnOK() { if (AddFunction().has_value()) { CDialog::OnOK(); } } void Term2Function::OnBnClickedApply() { if (const auto uid = AddFunction(); uid.has_value()) { ::AfxMessageBox(mfc::FormatSID(IXTRS_TERMFUNC_SUCCESS, editor.GetRS(uid.value()).alias.c_str()), MB_OK | MB_ICONINFORMATION); } } void Term2Function::OnBnClickedRight() { globalsCtrl.MoveSelectedItemsTo(argsCtrl, Header::COLOUMN_COUNT); } void Term2Function::OnBnClickedLeft() { argsCtrl.MoveSelectedItemsTo(globalsCtrl, Header::COLOUMN_COUNT); } void Term2Function::OnDblClickGlobal(NMHDR* /*pNMHDR*/, LRESULT* pResult) { OnBnClickedRight(); *pResult = TRUE; } void Term2Function::OnDblClickArg(NMHDR* /*pNMHDR*/, LRESULT* pResult) { OnBnClickedLeft(); *pResult = TRUE; } std::optional Term2Function::AddFunction() { UpdateData(TRUE); if (expression.IsEmpty()) { ::AfxMessageBox(IXTRE_FUNC2TERM, MB_OK | MB_ICONEXCLAMATION); expressionCtrl.SetActiveWindow(); return std::nullopt; } const auto convention = mfc::ToSTL(mfc::FormatSID(IXTRS_TERMFUNC_FROM_TERM, cstName.GetString())); const auto uid = editor.Emplace(CstType::function, mfc::ToSTL(expressionCtrl.Text())); editor.SetDefinitionFor(uid, mfc::ToSTL(definitionCtrl.Text())); editor.SetConventionFor(uid, convention); addedCst.emplace_back(uid); textRef.Empty(); expression.Empty(); argsCtrl.DeleteAllItems(); UpdateData(FALSE); return uid; } void Term2Function::UpdateUI() { InputGlobals(); UpdateArgs(); inputCtrl.UpdateFormat(); } void Term2Function::InputGlobals() { globalsCtrl.DeleteAllItems(); const auto cstFromExpr = ccl::rslang::ExtractUGlobals(mfc::ToSTL(inputExpr)); SetOfEntities entities{}; entities.reserve(size(cstFromExpr)); for (const auto& name : cstFromExpr) { if (auto uid = editor.Core().FindAlias(name); uid.has_value()) { entities.emplace(uid.value()); } } const auto sortedCst = editor.List().SortSubset(entities); auto line = 0; for (const auto uid : sortedCst) { const auto& cst = editor.GetRS(uid); if (const auto type = cst.type; type == CstType::structured || type == CstType::term) { auto typification = mfc::ToSTL(info::Label(editor.GetParse(uid).TypePtr())); globalsCtrl.InsertItem(line, mfc::ToMFC(cst.alias)); globalsCtrl.SetItemText(line, Header::POS_TYPE, mfc::ToMFC(typification)); ++line; } } } void Term2Function::UpdateArgs() { LVFINDINFOW info{}; info.flags = LVFI_STRING; for (auto i = 0; i < argsCtrl.GetItemCount(); ++i) { auto name = argsCtrl.GetItemText(i, 0); info.psz = name; if (const auto findItem = globalsCtrl.FindItem(&info); findItem == mfc::noItems) { argsCtrl.DeleteItem(i); i = i == 0 ? i : i - 1; } else { globalsCtrl.DeleteItem(findItem); } } } } // namespace xtr::dialog