244 lines
7.0 KiB
C++
244 lines
7.0 KiB
C++
![]() |
#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<std::string> 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<EntityUID> 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
|