mirror of https://github.com/PCSX2/pcsx2.git
653 lines
18 KiB
C++
653 lines
18 KiB
C++
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#include "NewSymbolDialogs.h"
|
|
|
|
#include <QtCore/QTimer>
|
|
#include <QtCore/QMetaMethod>
|
|
#include <QtWidgets/QMessageBox>
|
|
#include <QtWidgets/QPushButton>
|
|
|
|
#include "TypeString.h"
|
|
|
|
NewSymbolDialog::NewSymbolDialog(u32 flags, u32 alignment, DebugInterface& cpu, QWidget* parent)
|
|
: QDialog(parent)
|
|
, m_cpu(cpu)
|
|
, m_alignment(alignment)
|
|
{
|
|
m_ui.setupUi(this);
|
|
|
|
connect(m_ui.buttonBox, &QDialogButtonBox::accepted, this, &NewSymbolDialog::createSymbol);
|
|
connect(m_ui.storageTabBar, &QTabBar::currentChanged, this, &NewSymbolDialog::onStorageTabChanged);
|
|
|
|
if (flags & GLOBAL_STORAGE)
|
|
{
|
|
int tab = m_ui.storageTabBar->addTab(tr("Global"));
|
|
m_ui.storageTabBar->setTabData(tab, GLOBAL_STORAGE);
|
|
}
|
|
|
|
if (flags & REGISTER_STORAGE)
|
|
{
|
|
int tab = m_ui.storageTabBar->addTab(tr("Register"));
|
|
m_ui.storageTabBar->setTabData(tab, REGISTER_STORAGE);
|
|
|
|
setupRegisterField();
|
|
}
|
|
|
|
if (flags & STACK_STORAGE)
|
|
{
|
|
int tab = m_ui.storageTabBar->addTab(tr("Stack"));
|
|
m_ui.storageTabBar->setTabData(tab, STACK_STORAGE);
|
|
}
|
|
|
|
if (m_ui.storageTabBar->count() == 1)
|
|
m_ui.storageTabBar->hide();
|
|
|
|
m_ui.form->setRowVisible(Row::SIZE, flags & SIZE_FIELD);
|
|
m_ui.form->setRowVisible(Row::EXISTING_FUNCTIONS, flags & EXISTING_FUNCTIONS_FIELD);
|
|
m_ui.form->setRowVisible(Row::TYPE, flags & TYPE_FIELD);
|
|
m_ui.form->setRowVisible(Row::FUNCTION, flags & FUNCTION_FIELD);
|
|
|
|
if (flags & SIZE_FIELD)
|
|
{
|
|
setupSizeField();
|
|
updateSizeField();
|
|
}
|
|
|
|
if (flags & FUNCTION_FIELD)
|
|
setupFunctionField();
|
|
|
|
connectInputWidgets();
|
|
onStorageTabChanged(0);
|
|
adjustSize();
|
|
}
|
|
|
|
void NewSymbolDialog::setName(QString name)
|
|
{
|
|
m_ui.nameLineEdit->setText(name);
|
|
}
|
|
|
|
void NewSymbolDialog::setAddress(u32 address)
|
|
{
|
|
m_ui.addressLineEdit->setText(QString::number(address, 16));
|
|
}
|
|
|
|
void NewSymbolDialog::setCustomSize(u32 size)
|
|
{
|
|
m_ui.customSizeRadioButton->setChecked(true);
|
|
m_ui.customSizeSpinBox->setValue(size);
|
|
}
|
|
|
|
void NewSymbolDialog::setupRegisterField()
|
|
{
|
|
m_ui.registerComboBox->clear();
|
|
for (int i = 0; i < m_cpu.getRegisterCount(0); i++)
|
|
m_ui.registerComboBox->addItem(m_cpu.getRegisterName(0, i));
|
|
}
|
|
|
|
void NewSymbolDialog::setupSizeField()
|
|
{
|
|
connect(m_ui.customSizeRadioButton, &QRadioButton::toggled, m_ui.customSizeSpinBox, &QSpinBox::setEnabled);
|
|
connect(m_ui.addressLineEdit, &QLineEdit::textChanged, this, &NewSymbolDialog::updateSizeField);
|
|
}
|
|
|
|
void NewSymbolDialog::setupFunctionField()
|
|
{
|
|
m_cpu.GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
|
const ccc::Function* default_function = database.functions.symbol_overlapping_address(m_cpu.getPC());
|
|
|
|
for (const ccc::Function& function : database.functions)
|
|
{
|
|
QString name = QString::fromStdString(function.name());
|
|
name.truncate(64);
|
|
m_ui.functionComboBox->addItem(name);
|
|
m_functions.emplace_back(function.handle());
|
|
|
|
if (default_function && function.handle() == default_function->handle())
|
|
m_ui.functionComboBox->setCurrentIndex(m_ui.functionComboBox->count() - 1);
|
|
}
|
|
});
|
|
}
|
|
|
|
void NewSymbolDialog::connectInputWidgets()
|
|
{
|
|
QMetaMethod parse_user_input = metaObject()->method(metaObject()->indexOfSlot("parseUserInput()"));
|
|
for (QObject* child : children())
|
|
{
|
|
QWidget* widget = qobject_cast<QWidget*>(child);
|
|
if (!widget)
|
|
continue;
|
|
|
|
QMetaProperty property = widget->metaObject()->userProperty();
|
|
if (!property.isValid() || !property.hasNotifySignal())
|
|
continue;
|
|
|
|
connect(widget, property.notifySignal(), this, parse_user_input);
|
|
}
|
|
}
|
|
|
|
void NewSymbolDialog::updateErrorMessage(QString error_message)
|
|
{
|
|
m_ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(error_message.isEmpty());
|
|
m_ui.errorMessage->setText(error_message);
|
|
}
|
|
|
|
NewSymbolDialog::FunctionSizeType NewSymbolDialog::functionSizeType() const
|
|
{
|
|
if (m_ui.fillExistingFunctionRadioButton->isChecked())
|
|
return FILL_EXISTING_FUNCTION;
|
|
|
|
if (m_ui.fillEmptySpaceRadioButton->isChecked())
|
|
return FILL_EMPTY_SPACE;
|
|
|
|
return CUSTOM_SIZE;
|
|
}
|
|
|
|
void NewSymbolDialog::updateSizeField()
|
|
{
|
|
bool ok;
|
|
u32 address = m_ui.addressLineEdit->text().toUInt(&ok, 16);
|
|
if (ok)
|
|
{
|
|
m_cpu.GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
|
std::optional<u32> fill_existing_function_size = fillExistingFunctionSize(address, database);
|
|
if (fill_existing_function_size.has_value())
|
|
m_ui.fillExistingFunctionRadioButton->setText(
|
|
tr("Fill existing function (%1 bytes)").arg(*fill_existing_function_size));
|
|
else
|
|
m_ui.fillExistingFunctionRadioButton->setText(
|
|
tr("Fill existing function (none found)"));
|
|
m_ui.fillExistingFunctionRadioButton->setEnabled(fill_existing_function_size.has_value());
|
|
|
|
std::optional<u32> fill_empty_space_size = fillEmptySpaceSize(address, database);
|
|
if (fill_empty_space_size.has_value())
|
|
m_ui.fillEmptySpaceRadioButton->setText(
|
|
tr("Fill space (%1 bytes)").arg(*fill_empty_space_size));
|
|
else
|
|
m_ui.fillEmptySpaceRadioButton->setText(tr("Fill space (no next symbol)"));
|
|
m_ui.fillEmptySpaceRadioButton->setEnabled(fill_empty_space_size.has_value());
|
|
});
|
|
}
|
|
else
|
|
{
|
|
// Add some padding to the end of the radio button text so that the
|
|
// layout engine knows we need some more space for the size.
|
|
QString padding(16, ' ');
|
|
m_ui.fillExistingFunctionRadioButton->setText(tr("Fill existing function").append(padding));
|
|
m_ui.fillEmptySpaceRadioButton->setText(tr("Fill space").append(padding));
|
|
}
|
|
}
|
|
|
|
std::optional<u32> NewSymbolDialog::fillExistingFunctionSize(u32 address, const ccc::SymbolDatabase& database)
|
|
{
|
|
const ccc::Function* existing_function = database.functions.symbol_overlapping_address(address);
|
|
if (!existing_function)
|
|
return std::nullopt;
|
|
|
|
return existing_function->address_range().high.value - address;
|
|
}
|
|
|
|
std::optional<u32> NewSymbolDialog::fillEmptySpaceSize(u32 address, const ccc::SymbolDatabase& database)
|
|
{
|
|
const ccc::Symbol* next_symbol = database.symbol_after_address(
|
|
address, ccc::FUNCTION | ccc::GLOBAL_VARIABLE | ccc::LOCAL_VARIABLE);
|
|
if (!next_symbol)
|
|
return std::nullopt;
|
|
|
|
return next_symbol->address().value - address;
|
|
}
|
|
|
|
u32 NewSymbolDialog::storageType() const
|
|
{
|
|
return m_ui.storageTabBar->tabData(m_ui.storageTabBar->currentIndex()).toUInt();
|
|
}
|
|
|
|
void NewSymbolDialog::onStorageTabChanged(int index)
|
|
{
|
|
u32 storage = m_ui.storageTabBar->tabData(index).toUInt();
|
|
|
|
m_ui.form->setRowVisible(Row::ADDRESS, storage == GLOBAL_STORAGE);
|
|
m_ui.form->setRowVisible(Row::REGISTER, storage == REGISTER_STORAGE);
|
|
m_ui.form->setRowVisible(Row::STACK_POINTER_OFFSET, storage == STACK_STORAGE);
|
|
|
|
QTimer::singleShot(0, this, [&]() {
|
|
parseUserInput();
|
|
});
|
|
}
|
|
|
|
std::string NewSymbolDialog::parseName(QString& error_message)
|
|
{
|
|
std::string name = m_ui.nameLineEdit->text().toStdString();
|
|
if (name.empty())
|
|
error_message = tr("Name is empty.");
|
|
|
|
return name;
|
|
}
|
|
|
|
u32 NewSymbolDialog::parseAddress(QString& error_message)
|
|
{
|
|
bool ok;
|
|
u32 address = m_ui.addressLineEdit->text().toUInt(&ok, 16);
|
|
if (!ok)
|
|
error_message = tr("Address is not valid.");
|
|
|
|
if (address % m_alignment != 0)
|
|
error_message = tr("Address is not aligned.");
|
|
|
|
return address;
|
|
}
|
|
|
|
// *****************************************************************************
|
|
|
|
NewFunctionDialog::NewFunctionDialog(DebugInterface& cpu, QWidget* parent)
|
|
: NewSymbolDialog(GLOBAL_STORAGE | SIZE_FIELD | EXISTING_FUNCTIONS_FIELD, 4, cpu, parent)
|
|
{
|
|
setWindowTitle("New Function");
|
|
|
|
m_ui.customSizeSpinBox->setValue(8);
|
|
}
|
|
|
|
bool NewFunctionDialog::parseUserInput()
|
|
{
|
|
QString error_message;
|
|
m_cpu.GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
|
m_name = parseName(error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
|
|
m_address = parseAddress(error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
|
|
m_size = 0;
|
|
switch (functionSizeType())
|
|
{
|
|
case FILL_EXISTING_FUNCTION:
|
|
{
|
|
std::optional<u32> fill_existing_function_size = fillExistingFunctionSize(m_address, database);
|
|
if (!fill_existing_function_size.has_value())
|
|
{
|
|
error_message = tr("No existing function found.");
|
|
return;
|
|
}
|
|
|
|
m_size = *fill_existing_function_size;
|
|
|
|
break;
|
|
}
|
|
case FILL_EMPTY_SPACE:
|
|
{
|
|
std::optional<u32> fill_space_size = fillEmptySpaceSize(m_address, database);
|
|
if (!fill_space_size.has_value())
|
|
{
|
|
error_message = tr("No next symbol found.");
|
|
return;
|
|
}
|
|
|
|
m_size = *fill_space_size;
|
|
|
|
break;
|
|
}
|
|
case CUSTOM_SIZE:
|
|
{
|
|
m_size = m_ui.customSizeSpinBox->value();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (m_size == 0 || m_size > 256 * 1024 * 1024)
|
|
{
|
|
error_message = tr("Size is invalid.");
|
|
return;
|
|
}
|
|
|
|
if (m_size % 4 != 0)
|
|
{
|
|
error_message = tr("Size is not a multiple of 4.");
|
|
return;
|
|
}
|
|
|
|
// Handle an existing function if it exists.
|
|
const ccc::Function* existing_function = database.functions.symbol_overlapping_address(m_address);
|
|
m_existing_function = ccc::FunctionHandle();
|
|
if (existing_function)
|
|
{
|
|
if (existing_function->address().value == m_address)
|
|
{
|
|
error_message = tr("A function already exists at that address.");
|
|
return;
|
|
}
|
|
|
|
if (m_ui.shrinkExistingRadioButton->isChecked())
|
|
{
|
|
m_new_existing_function_size = m_address - existing_function->address().value;
|
|
m_existing_function = existing_function->handle();
|
|
}
|
|
}
|
|
});
|
|
|
|
updateErrorMessage(error_message);
|
|
return error_message.isEmpty();
|
|
}
|
|
|
|
void NewFunctionDialog::createSymbol()
|
|
{
|
|
if (!parseUserInput())
|
|
return;
|
|
|
|
QString error_message;
|
|
m_cpu.GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
|
ccc::Result<ccc::SymbolSourceHandle> source = database.get_symbol_source("User-Defined");
|
|
if (!source.success())
|
|
{
|
|
error_message = tr("Cannot create symbol source.");
|
|
return;
|
|
}
|
|
|
|
ccc::Result<ccc::Function*> function = database.functions.create_symbol(std::move(m_name), m_address, *source, nullptr);
|
|
if (!function.success())
|
|
{
|
|
error_message = tr("Cannot create symbol.");
|
|
return;
|
|
}
|
|
|
|
(*function)->set_size(m_size);
|
|
|
|
ccc::Function* existing_function = database.functions.symbol_from_handle(m_existing_function);
|
|
if (existing_function)
|
|
existing_function->set_size(m_new_existing_function_size);
|
|
});
|
|
|
|
if (!error_message.isEmpty())
|
|
QMessageBox::warning(this, tr("Cannot Create Function"), error_message);
|
|
}
|
|
|
|
// *****************************************************************************
|
|
|
|
NewGlobalVariableDialog::NewGlobalVariableDialog(DebugInterface& cpu, QWidget* parent)
|
|
: NewSymbolDialog(GLOBAL_STORAGE | TYPE_FIELD, 1, cpu, parent)
|
|
{
|
|
setWindowTitle("New Global Variable");
|
|
}
|
|
|
|
bool NewGlobalVariableDialog::parseUserInput()
|
|
{
|
|
QString error_message;
|
|
m_cpu.GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
|
m_name = parseName(error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
|
|
m_address = parseAddress(error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
|
|
m_type = stringToType(m_ui.typeLineEdit->text().toStdString(), database, error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
});
|
|
|
|
updateErrorMessage(error_message);
|
|
return error_message.isEmpty();
|
|
}
|
|
|
|
void NewGlobalVariableDialog::createSymbol()
|
|
{
|
|
if (!parseUserInput())
|
|
return;
|
|
|
|
QString error_message;
|
|
m_cpu.GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
|
ccc::Result<ccc::SymbolSourceHandle> source = database.get_symbol_source("User-Defined");
|
|
if (!source.success())
|
|
{
|
|
error_message = tr("Cannot create symbol source.");
|
|
return;
|
|
}
|
|
|
|
ccc::Result<ccc::GlobalVariable*> global_variable = database.global_variables.create_symbol(std::move(m_name), m_address, *source, nullptr);
|
|
if (!global_variable.success())
|
|
{
|
|
error_message = tr("Cannot create symbol.");
|
|
return;
|
|
}
|
|
|
|
(*global_variable)->set_type(std::move(m_type));
|
|
});
|
|
|
|
if (!error_message.isEmpty())
|
|
QMessageBox::warning(this, tr("Cannot Create Global Variable"), error_message);
|
|
}
|
|
|
|
// *****************************************************************************
|
|
|
|
NewLocalVariableDialog::NewLocalVariableDialog(DebugInterface& cpu, QWidget* parent)
|
|
: NewSymbolDialog(GLOBAL_STORAGE | REGISTER_STORAGE | STACK_STORAGE | TYPE_FIELD | FUNCTION_FIELD, 1, cpu, parent)
|
|
{
|
|
setWindowTitle("New Local Variable");
|
|
}
|
|
|
|
bool NewLocalVariableDialog::parseUserInput()
|
|
{
|
|
QString error_message;
|
|
m_cpu.GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
|
m_name = parseName(error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
|
|
int function_index = m_ui.functionComboBox->currentIndex();
|
|
if (function_index > 0 && function_index < (int)m_functions.size())
|
|
m_function = m_functions[m_ui.functionComboBox->currentIndex()];
|
|
else
|
|
m_function = ccc::FunctionHandle();
|
|
|
|
const ccc::Function* function = database.functions.symbol_from_handle(m_function);
|
|
if (!function)
|
|
{
|
|
error_message = tr("Invalid function.");
|
|
return;
|
|
}
|
|
|
|
switch (storageType())
|
|
{
|
|
case GLOBAL_STORAGE:
|
|
{
|
|
m_storage.emplace<ccc::GlobalStorage>();
|
|
|
|
m_address = parseAddress(error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
|
|
break;
|
|
}
|
|
case REGISTER_STORAGE:
|
|
{
|
|
ccc::RegisterStorage& register_storage = m_storage.emplace<ccc::RegisterStorage>();
|
|
register_storage.dbx_register_number = m_ui.registerComboBox->currentIndex();
|
|
break;
|
|
}
|
|
case STACK_STORAGE:
|
|
{
|
|
ccc::StackStorage& stack_storage = m_storage.emplace<ccc::StackStorage>();
|
|
stack_storage.stack_pointer_offset = m_ui.stackPointerOffsetSpinBox->value();
|
|
|
|
// Convert to caller sp relative.
|
|
if (std::optional<u32> stack_frame_size = m_cpu.getStackFrameSize(*function))
|
|
stack_storage.stack_pointer_offset -= *stack_frame_size;
|
|
else
|
|
{
|
|
error_message = tr("Cannot determine stack frame size of selected function.");
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::string type_string = m_ui.typeLineEdit->text().toStdString();
|
|
m_type = stringToType(type_string, database, error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
});
|
|
|
|
updateErrorMessage(error_message);
|
|
return error_message.isEmpty();
|
|
}
|
|
|
|
void NewLocalVariableDialog::createSymbol()
|
|
{
|
|
if (!parseUserInput())
|
|
return;
|
|
|
|
QString error_message;
|
|
m_cpu.GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
|
ccc::Function* function = database.functions.symbol_from_handle(m_function);
|
|
if (!function)
|
|
{
|
|
error_message = tr("Invalid function.");
|
|
return;
|
|
}
|
|
|
|
ccc::Result<ccc::SymbolSourceHandle> source = database.get_symbol_source("User-Defined");
|
|
if (!source.success())
|
|
{
|
|
error_message = tr("Cannot create symbol source.");
|
|
return;
|
|
}
|
|
|
|
ccc::Result<ccc::LocalVariable*> local_variable =
|
|
database.local_variables.create_symbol(std::move(m_name), m_address, *source, nullptr);
|
|
if (!local_variable.success())
|
|
{
|
|
error_message = tr("Cannot create symbol.");
|
|
return;
|
|
}
|
|
|
|
(*local_variable)->set_type(std::move(m_type));
|
|
(*local_variable)->storage = m_storage;
|
|
|
|
std::vector<ccc::LocalVariableHandle> local_variables;
|
|
if (function->local_variables().has_value())
|
|
local_variables = *function->local_variables();
|
|
local_variables.emplace_back((*local_variable)->handle());
|
|
function->set_local_variables(local_variables, database);
|
|
});
|
|
|
|
if (!error_message.isEmpty())
|
|
QMessageBox::warning(this, tr("Cannot Create Local Variable"), error_message);
|
|
}
|
|
|
|
// *****************************************************************************
|
|
|
|
NewParameterVariableDialog::NewParameterVariableDialog(DebugInterface& cpu, QWidget* parent)
|
|
: NewSymbolDialog(REGISTER_STORAGE | STACK_STORAGE | TYPE_FIELD | FUNCTION_FIELD, 1, cpu, parent)
|
|
{
|
|
setWindowTitle("New Parameter Variable");
|
|
}
|
|
|
|
bool NewParameterVariableDialog::parseUserInput()
|
|
{
|
|
QString error_message;
|
|
m_cpu.GetSymbolGuardian().Read([&](const ccc::SymbolDatabase& database) {
|
|
m_name = parseName(error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
|
|
int function_index = m_ui.functionComboBox->currentIndex();
|
|
if (function_index > 0 && function_index < (int)m_functions.size())
|
|
m_function = m_functions[m_ui.functionComboBox->currentIndex()];
|
|
else
|
|
m_function = ccc::FunctionHandle();
|
|
|
|
const ccc::Function* function = database.functions.symbol_from_handle(m_function);
|
|
if (!function)
|
|
{
|
|
error_message = tr("Invalid function.");
|
|
return;
|
|
}
|
|
|
|
std::variant<ccc::RegisterStorage, ccc::StackStorage> storage;
|
|
switch (storageType())
|
|
{
|
|
case GLOBAL_STORAGE:
|
|
{
|
|
error_message = tr("Invalid storage type.");
|
|
return;
|
|
}
|
|
case REGISTER_STORAGE:
|
|
{
|
|
ccc::RegisterStorage& register_storage = storage.emplace<ccc::RegisterStorage>();
|
|
register_storage.dbx_register_number = m_ui.registerComboBox->currentIndex();
|
|
break;
|
|
}
|
|
case STACK_STORAGE:
|
|
{
|
|
ccc::StackStorage& stack_storage = storage.emplace<ccc::StackStorage>();
|
|
stack_storage.stack_pointer_offset = m_ui.stackPointerOffsetSpinBox->value();
|
|
|
|
// Convert to caller sp relative.
|
|
if (std::optional<u32> stack_frame_size = m_cpu.getStackFrameSize(*function))
|
|
stack_storage.stack_pointer_offset -= *stack_frame_size;
|
|
else
|
|
{
|
|
error_message = tr("Cannot determine stack frame size of selected function.");
|
|
return;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::string type_string = m_ui.typeLineEdit->text().toStdString();
|
|
m_type = stringToType(type_string, database, error_message);
|
|
if (!error_message.isEmpty())
|
|
return;
|
|
});
|
|
|
|
updateErrorMessage(error_message);
|
|
return error_message.isEmpty();
|
|
}
|
|
|
|
void NewParameterVariableDialog::createSymbol()
|
|
{
|
|
if (!parseUserInput())
|
|
return;
|
|
|
|
QString error_message;
|
|
m_cpu.GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
|
ccc::Function* function = database.functions.symbol_from_handle(m_function);
|
|
if (!function)
|
|
{
|
|
error_message = tr("Invalid function.");
|
|
return;
|
|
}
|
|
|
|
ccc::Result<ccc::SymbolSourceHandle> source = database.get_symbol_source("User-Defined");
|
|
if (!source.success())
|
|
{
|
|
error_message = tr("Cannot create symbol source.");
|
|
return;
|
|
}
|
|
|
|
ccc::Result<ccc::ParameterVariable*> parameter_variable =
|
|
database.parameter_variables.create_symbol(std::move(m_name), *source, nullptr);
|
|
if (!parameter_variable.success())
|
|
{
|
|
error_message = tr("Cannot create symbol.");
|
|
return;
|
|
}
|
|
|
|
(*parameter_variable)->set_type(std::move(m_type));
|
|
(*parameter_variable)->storage = m_storage;
|
|
|
|
std::vector<ccc::ParameterVariableHandle> parameter_variables;
|
|
if (function->parameter_variables().has_value())
|
|
parameter_variables = *function->parameter_variables();
|
|
parameter_variables.emplace_back((*parameter_variable)->handle());
|
|
function->set_parameter_variables(parameter_variables, database);
|
|
});
|
|
|
|
if (!error_message.isEmpty())
|
|
QMessageBox::warning(this, tr("Cannot Create Parameter Variable"), error_message);
|
|
}
|