Exteor/src/dialog/Term2Function.cpp

244 lines
7.0 KiB
C++
Raw Normal View History

2024-06-07 20:30:06 +03:00
#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