The complete source code of IdealIRC http://www.idealirc.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
idealirc/ScriptDialog/ScriptDialog.cpp

1151 lines
35 KiB

/*
* IdealIRC - Internet Relay Chat client
* Copyright (C) 2021 Tom-Andre Barstad.
* This software is licensed under the Software Attribution License.
* See LICENSE for more information.
*/
#include "ScriptDialog.h"
#include "Script/Dialog.h"
#include "Script/ScriptException.h"
#include "Script/ValueExtract.h"
#include "Script/Builtin/ListUtils.h" // Needed for LIST_END_MAGIC
#include "IdealIRC.h"
#include <QDialog>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QPlainTextEdit>
#include <QSpinBox>
#include <QListWidget>
#include <QComboBox>
#include <QTableWidget>
#include <QHeaderView>
#include <QTreeWidget>
#include <QGroupBox>
#include <QRadioButton>
#include <QCheckBox>
#include <QScrollBar>
#include <unordered_map>
#include <string>
#include <stdexcept>
extern IdealIRC* IIRC_MainWindow_Ptr;
struct ScriptWidget
{
explicit ScriptWidget(Script& script_) : script(script_) {}
std::unordered_map<std::string, ValueHolder> customAttrs;
QWidget* widget{ nullptr }; // Pointer owned by the QDialog
const DialogWidget* tmpl{ nullptr };
Script& script;
};
struct ScriptDialogPriv
{
explicit ScriptDialogPriv(Script& script_)
: dialog(new QDialog(nullptr))
, script(script_)
{
dialog->setAttribute(Qt::WA_DeleteOnClose, false);
}
std::unordered_map<std::string, ValueHolder> customAttrs;
std::unordered_map<std::string, ScriptWidget> widgets;
std::unique_ptr<QDialog> dialog;
const Dialog* tmpl{ nullptr };
Script& script;
};
namespace {
template<DialogWidget::Type type, typename T>
void buildWidget(T* widget, const DialogWidget& tmpl)
{
ValueHolder valX = tmpl.defaultAttr("x");
ValueHolder valY = tmpl.defaultAttr("y");
ValueHolder valWidth = tmpl.defaultAttr("width");
ValueHolder valHeight = tmpl.defaultAttr("height");
ValueHolder valFont = tmpl.defaultAttr("font");
ValueHolder valFontsize = tmpl.defaultAttr("fontsize");
ValueHolder valEnabled = tmpl.defaultAttr("enabled");
ValueHolder valVisible = tmpl.defaultAttr("visible");
ValueHolder valText = tmpl.defaultAttr("text");
ValueHolder valTooltip = tmpl.defaultAttr("tooltip");
auto rect = widget->geometry();
if (valX.getType() != ValueHolder::Type::Void)
rect.setX(ValueExtract(valX).toInt());
if (valY.getType() != ValueHolder::Type::Void)
rect.setY(ValueExtract(valY).toInt());
if (valWidth.getType() != ValueHolder::Type::Void)
rect.setWidth(ValueExtract(valWidth).toInt());
if (valHeight.getType() != ValueHolder::Type::Void)
rect.setHeight(ValueExtract(valHeight).toInt());
widget->setGeometry(rect);
auto font = widget->font();
if (valFont.getType() != ValueHolder::Type::Void)
font.setFamily(ValueExtract(valFont).toString().c_str());
if (valFontsize.getType() != ValueHolder::Type::Void)
font.setPixelSize(ValueExtract(valFontsize).toInt());
widget->setFont(font);
if (valEnabled.getType() != ValueHolder::Type::Void)
widget->setEnabled(ValueExtract(valEnabled).toBool());
if (valVisible.getType() != ValueHolder::Type::Void)
widget->setVisible(ValueExtract(valVisible).toBool());
if (valTooltip.getType() != ValueHolder::Type::Void)
widget->setToolTip(ValueExtract(valHeight).toString().c_str());
using WType = DialogWidget::Type;
if constexpr (type == WType::Spinbox) {
ValueHolder value = tmpl.defaultAttr("value");
ValueHolder min = tmpl.defaultAttr("min");
ValueHolder max = tmpl.defaultAttr("max");
ValueHolder step = tmpl.defaultAttr("step");
if (min.getType() == ValueHolder::Type::Void)
throw ScriptException("Attribute 'min' is required for Spinbox");
if (max.getType() == ValueHolder::Type::Void)
throw ScriptException("Attribute 'max' is required for Spinbox");
if (min.getType() != ValueHolder::Type::Integer)
throw ScriptException("Attribute 'min' for Spinbox must be a whole number");
if (max.getType() != ValueHolder::Type::Integer)
throw ScriptException("Attribute 'max' for Spinbox must be a whole number");
if (value.getType() == ValueHolder::Type::Void)
value = min;
if (step.getType() == ValueHolder::Type::Void)
step = 1;
if (value.getType() != ValueHolder::Type::Integer)
throw ScriptException("Attribute 'value' for Spinbox must be a whole number");
if (step.getType() != ValueHolder::Type::Integer)
throw ScriptException("Attribute 'step' for Spinbox must be a whole number");
widget->setMinimum(ValueExtract(min).toInt());
widget->setMaximum(ValueExtract(max).toInt());
widget->setValue(ValueExtract(value).toInt());
widget->setSingleStep(ValueExtract(step).toInt());
}
else if constexpr (type == WType::Textbox) {
ValueHolder readOnly = tmpl.defaultAttr("readonly");
if (readOnly.getType() != ValueHolder::Type::Void)
widget->setEnabled(ValueExtract(readOnly).toBool());
widget->setPlainText(ValueExtract(valText).toString().c_str());
}
else if constexpr (type == WType::Groupbox) {
ValueHolder readOnly = tmpl.defaultAttr("readonly");
if (readOnly.getType() != ValueHolder::Type::Void)
widget->setEnabled(ValueExtract(readOnly).toBool());
widget->setTitle(ValueExtract(valText).toString().c_str());
}
else if constexpr (type == WType::Button) {
ValueHolder checkable = tmpl.defaultAttr("checkable");
ValueHolder checked = tmpl.defaultAttr("checked");
if (checkable.getType() != ValueHolder::Type::Void)
widget->setCheckable(ValueExtract(checkable).toBool());
if (checked.getType() != ValueHolder::Type::Void)
widget->setChecked(ValueExtract(checked).toBool());
widget->setText(ValueExtract(valText).toString().c_str());
}
else if constexpr (type == WType::Checkbox) {
ValueHolder checked = tmpl.defaultAttr("checked");
if (checked.getType() != ValueHolder::Type::Void)
widget->setChecked(ValueExtract(checked).toBool());
widget->setText(ValueExtract(valText).toString().c_str());
}
else if constexpr (type == WType::Radio) {
ValueHolder checked = tmpl.defaultAttr("checked");
if (checked.getType() != ValueHolder::Type::Void)
widget->setChecked(ValueExtract(checked).toBool());
widget->setText(ValueExtract(valText).toString().c_str());
}
else if constexpr (type == WType::Table) {
}
else if constexpr (type != WType::Vscroll && type != WType::Hscroll
&& type != WType::Listbox && type != WType::Combobox
&& type != WType::Tree) {
widget->setText(ValueExtract(valText).toString().c_str());
}
}
void widgetSetText(ScriptWidget& widget, ValueHolder& valh)
{
std::string text = ValueExtract(valh).toString();
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Label) {
auto* cw = dynamic_cast<QLabel*>(widget.widget);
cw->setText(text.c_str());
}
else if (widget.tmpl->type() == WType::Groupbox) {
auto* cw = dynamic_cast<QGroupBox*>(widget.widget);
cw->setTitle(text.c_str());
}
else if (widget.tmpl->type() == WType::Textline) {
auto* cw = dynamic_cast<QLineEdit*>(widget.widget);
cw->setText(text.c_str());
}
else if (widget.tmpl->type() == WType::Textbox) {
auto* cw = dynamic_cast<QPlainTextEdit*>(widget.widget);
cw->setPlainText(text.c_str());
}
else if (widget.tmpl->type() == WType::Button) {
auto* cw = dynamic_cast<QPushButton*>(widget.widget);
cw->setText(text.c_str());
}
else if (widget.tmpl->type() == WType::Radio) {
auto* cw = dynamic_cast<QRadioButton*>(widget.widget);
cw->setText(text.c_str());
}
else if (widget.tmpl->type() == WType::Checkbox) {
auto* cw = dynamic_cast<QCheckBox*>(widget.widget);
cw->setText(text.c_str());
}
else {
widget.customAttrs.insert_or_assign("text", valh);
}
}
void widgetSetCheckable(ScriptWidget& widget, ValueHolder& valh)
{
bool value = ValueExtract(valh).toBool();
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Button) {
auto* cw = dynamic_cast<QPushButton*>(widget.widget);
cw->setCheckable(value);
}
else {
widget.customAttrs.insert_or_assign("checkable", valh);
}
}
void widgetSetChecked(ScriptWidget& widget, ValueHolder& valh)
{
bool value = ValueExtract(valh).toBool();
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Button) {
auto* cw = dynamic_cast<QPushButton*>(widget.widget);
cw->setChecked(value);
}
else if (widget.tmpl->type() == WType::Radio) {
auto* cw = dynamic_cast<QRadioButton*>(widget.widget);
cw->setChecked(value);
}
else if (widget.tmpl->type() == WType::Checkbox) {
auto* cw = dynamic_cast<QCheckBox*>(widget.widget);
cw->setChecked(value);
}
else {
widget.customAttrs.insert_or_assign("checked", valh);
}
}
void widgetSetReadOnly(ScriptWidget& widget, ValueHolder& valh)
{
bool value = ValueExtract(valh).toBool();
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Textline) {
auto* cw = dynamic_cast<QLineEdit*>(widget.widget);
cw->setReadOnly(value);
}
else if (widget.tmpl->type() == WType::Textbox) {
auto* cw = dynamic_cast<QPlainTextEdit*>(widget.widget);
cw->setReadOnly(value);
}
else {
widget.customAttrs.insert_or_assign("readonly", valh);
}
}
void widgetSetValue(ScriptWidget& widget, ValueHolder& valh)
{
int value = ValueExtract(valh).toInt();
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Spinbox) {
auto* cw = dynamic_cast<QSpinBox*>(widget.widget);
cw->setValue(value);
}
else {
widget.customAttrs.insert_or_assign("value", valh);
}
}
void widgetSetMin(ScriptWidget& widget, ValueHolder& valh)
{
int value = ValueExtract(valh).toInt();
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Spinbox) {
auto* cw = dynamic_cast<QSpinBox*>(widget.widget);
cw->setMinimum(value);
}
else {
widget.customAttrs.insert_or_assign("min", valh);
}
}
void widgetSetMax(ScriptWidget& widget, ValueHolder& valh)
{
int value = ValueExtract(valh).toInt();
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Spinbox) {
auto* cw = dynamic_cast<QSpinBox*>(widget.widget);
cw->setMaximum(value);
}
else {
widget.customAttrs.insert_or_assign("max", valh);
}
}
void widgetSetStep(ScriptWidget& widget, ValueHolder& valh)
{
int value = ValueExtract(valh).toInt();
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Spinbox) {
auto* cw = dynamic_cast<QSpinBox*>(widget.widget);
cw->setSingleStep(value);
}
else {
widget.customAttrs.insert_or_assign("step", valh);
}
}
void widgetSetHeader(ScriptWidget& widget, ValueHolder& valh)
{
ValueArray& list = ValueExtract(valh).toMap();
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Table) {
auto* cw = dynamic_cast<QTableWidget*>(widget.widget);
QStringList header;
for (int i = 0; ; ++i) {
std::string si = std::to_string(i);
try {
ValueHolder& val = *list.at(si).get();
switch (val.getType()) {
case ValueHolder::Type::Integer:
header.push_back(QString::number(ValueExtract(val).toInt()));
break;
case ValueHolder::Type::Real:
header.push_back(QString::number(ValueExtract(val).toReal()));
break;
case ValueHolder::Type::Bool:
header.push_back(ValueExtract(val).toBool() ? QStringLiteral("True") : QStringLiteral("False"));
break;
case ValueHolder::Type::String:
header.push_back(ValueExtract(val).toString().c_str());
break;
default:
header.push_back(QStringLiteral(""));
}
} catch (const std::out_of_range&) {
break;
}
}
cw->setColumnCount(header.size());
cw->setHorizontalHeaderLabels(header);
cw->resizeColumnsToContents();
}
else {
widget.customAttrs.insert_or_assign("step", valh);
}
}
ValueHolder widgetGetText(ScriptWidget& widget)
{
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Label) {
auto* cw = dynamic_cast<QLabel*>(widget.widget);
return cw->text().toStdString();
}
else if (widget.tmpl->type() == WType::Groupbox) {
auto* cw = dynamic_cast<QGroupBox*>(widget.widget);
return cw->title().toStdString();
}
else if (widget.tmpl->type() == WType::Textline) {
auto* cw = dynamic_cast<QLineEdit*>(widget.widget);
return cw->text().toStdString();
}
else if (widget.tmpl->type() == WType::Textbox) {
auto* cw = dynamic_cast<QPlainTextEdit*>(widget.widget);
return cw->toPlainText().toStdString();
}
else if (widget.tmpl->type() == WType::Button) {
auto* cw = dynamic_cast<QPushButton*>(widget.widget);
return cw->text().toStdString();
}
else if (widget.tmpl->type() == WType::Radio) {
auto* cw = dynamic_cast<QRadioButton*>(widget.widget);
return cw->text().toStdString();
}
else if (widget.tmpl->type() == WType::Checkbox) {
auto* cw = dynamic_cast<QCheckBox*>(widget.widget);
return cw->text().toStdString();
}
else {
ValueHolder val;
try {
val = widget.customAttrs.at("text");
}
catch (...) {}
return val;
}
}
ValueHolder widgetGetCheckable(ScriptWidget& widget)
{
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Button) {
auto* cw = dynamic_cast<QPushButton*>(widget.widget);
return cw->isCheckable();
}
else {
ValueHolder val;
try {
val = widget.customAttrs.at("checkable");
}
catch (...) {}
return val;
}
}
ValueHolder widgetGetChecked(ScriptWidget& widget)
{
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Button) {
auto* cw = dynamic_cast<QPushButton*>(widget.widget);
return cw->isChecked();
}
else if (widget.tmpl->type() == WType::Radio) {
auto* cw = dynamic_cast<QRadioButton*>(widget.widget);
return cw->isChecked();
}
else if (widget.tmpl->type() == WType::Checkbox) {
auto* cw = dynamic_cast<QCheckBox*>(widget.widget);
return cw->isChecked();
}
else {
ValueHolder val;
try {
val = widget.customAttrs.at("checked");
}
catch (...) {}
return val;
}
}
ValueHolder widgetGetReadOnly(ScriptWidget& widget)
{
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Textline) {
auto* cw = dynamic_cast<QLineEdit*>(widget.widget);
return cw->isReadOnly();
}
else if (widget.tmpl->type() == WType::Textbox) {
auto* cw = dynamic_cast<QPlainTextEdit*>(widget.widget);
return cw->isReadOnly();
}
else {
ValueHolder val;
try {
val = widget.customAttrs.at("readonly");
}
catch (...) {}
return val;
}
}
ValueHolder widgetGetValue(ScriptWidget& widget)
{
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Spinbox) {
auto* cw = dynamic_cast<QSpinBox*>(widget.widget);
return cw->value();
}
else {
ValueHolder val;
try {
val = widget.customAttrs.at("value");
}
catch (...) {}
return val;
}
}
ValueHolder widgetGetMin(ScriptWidget& widget)
{
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Spinbox) {
auto* cw = dynamic_cast<QSpinBox*>(widget.widget);
return cw->minimum();
}
else {
ValueHolder val;
try {
val = widget.customAttrs.at("min");
}
catch (...) {}
return val;
}
}
ValueHolder widgetGetMax(ScriptWidget& widget)
{
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Spinbox) {
auto* cw = dynamic_cast<QSpinBox*>(widget.widget);
return cw->maximum();
}
else {
ValueHolder val;
try {
val = widget.customAttrs.at("max");
}
catch (...) {}
return val;
}
}
ValueHolder widgetGetStep(ScriptWidget& widget)
{
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Spinbox) {
auto* cw = dynamic_cast<QSpinBox*>(widget.widget);
return cw->singleStep();
}
else {
ValueHolder val;
try {
val = widget.customAttrs.at("step");
}
catch (...) {}
return val;
}
}
ValueHolder widgetGetHeader(ScriptWidget& widget)
{
using WType = DialogWidget::Type;
if (widget.tmpl->type() == WType::Table) {
auto* cw = dynamic_cast<QTableWidget*>(widget.widget);
ValueArray header;
for (int i = 0; ; ++i) {
auto* item = cw->horizontalHeaderItem(i);
if (!item)
break;
header.emplace(std::to_string(i), new ValueHolder(item->text().toStdString()));
}
return ValueHolder(std::move(header));
}
else {
ValueHolder val;
try {
val = widget.customAttrs.at("header");
}
catch (...) {}
return val;
}
}
} // anonymous namespace
ScriptDialog::ScriptDialog(const Dialog& dialog, Script& script, int handle)
: mp(new ScriptDialogPriv(script))
{
ValueHolder valX = dialog.defaultAttr("x");
ValueHolder valY = dialog.defaultAttr("y");
ValueHolder valWidth = dialog.defaultAttr("width");
ValueHolder valHeight = dialog.defaultAttr("height");
ValueHolder valTitle = dialog.defaultAttr("title");
ValueHolder valFont = dialog.defaultAttr("font");
ValueHolder valFontsize = dialog.defaultAttr("fontsize");
ValueHolder valIcon = dialog.defaultAttr("icon");
mp->tmpl = &dialog;
ValueHolder voidValue;
auto IIRC_rect = IIRC_MainWindow_Ptr->geometry();
if (valWidth != voidValue)
setAttr("width", valWidth);
if (valHeight != voidValue)
setAttr("height", valHeight);
if (valX != voidValue)
setAttr("x", valX);
else {
int width = ValueExtract(valWidth).toInt();
ValueHolder x = (2 * IIRC_rect.x() + IIRC_rect.width() - width) / 2;
setAttr("x", x);
}
if (valY != voidValue)
setAttr("y", valY);
else {
int height = ValueExtract(valHeight).toInt();
ValueHolder y = (2 * IIRC_rect.y() + IIRC_rect.height() - height) / 2;
setAttr("y", y);
}
if (valTitle != voidValue)
setAttr("title", valTitle);
else {
ValueHolder defaultTitle = std::string("Unnamed dialog");
setAttr("title", defaultTitle);
}
if (valFont != voidValue)
setAttr("font", valFont);
if (valFontsize != voidValue)
setAttr("fontsize", valFontsize);
if (valIcon != voidValue)
setAttr("icon", valIcon);
for (auto wref : dialog.allWidgets()) {
auto& widget = wref.get();
mp->widgets.emplace(widget.name(), ScriptWidget(script));
auto& qw = mp->widgets.at(widget.name());
qw.tmpl = &widget;
using WType = DialogWidget::Type;
switch (widget.type()) {
case WType::Label:
{
auto* w = new QLabel(mp->dialog.get());
buildWidget<WType::Label, QLabel>(w, widget);
qw.widget = w;
break;
}
case WType::Button:
{
auto* w = new QPushButton(mp->dialog.get());
buildWidget<WType::Button, QPushButton>(w, widget);
qw.widget = w;
const DialogWidget* widgetTemplate = qw.tmpl;
Script* scr = &mp->script;
connect(w, &QPushButton::clicked, [scr, widgetTemplate, handle]{
auto hook = widgetTemplate->hook("clicked");
if (!hook) return;
SymbolScope sym;
sym.set("handle", handle);
if (!scr->runScopeWithSymbols(*hook, sym))
ScriptManager::printError(scr->lastError());
});
break;
}
case WType::Textline:
{
auto* w = new QLineEdit(mp->dialog.get());
buildWidget<WType::Textline, QLineEdit>(w, widget);
qw.widget = w;
break;
}
case WType::Textbox:
{
auto* w = new QPlainTextEdit(mp->dialog.get());
buildWidget<WType::Textbox, QPlainTextEdit>(w, widget);
qw.widget = w;
break;
}
case WType::Spinbox:
{
auto* w = new QSpinBox(mp->dialog.get());
buildWidget<WType::Spinbox, QSpinBox>(w, widget);
qw.widget = w;
break;
}
case WType::Listbox:
{
auto* w = new QListWidget(mp->dialog.get());
buildWidget<WType::Listbox, QListWidget>(w, widget);
qw.widget = w;
break;
}
case WType::Combobox:
{
auto* w = new QComboBox(mp->dialog.get());
buildWidget<WType::Combobox, QComboBox>(w, widget);
qw.widget = w;
break;
}
case WType::Table:
{
auto* w = new QTableWidget(mp->dialog.get());
buildWidget<WType::Table, QTableWidget>(w, widget);
qw.widget = w;
w->setSelectionMode(QAbstractItemView::SingleSelection);
w->setSelectionBehavior(QAbstractItemView::SelectRows);
break;
}
case WType::Tree:
{
auto* w = new QTreeWidget(mp->dialog.get());
buildWidget<WType::Tree, QTreeWidget>(w, widget);
qw.widget = w;
break;
}
case WType::Groupbox:
{
auto* w = new QGroupBox(mp->dialog.get());
buildWidget<WType::Groupbox, QGroupBox>(w, widget);
qw.widget = w;
break;
}
// TODO case DialogWidget::Type::Tab:
// break;
case WType::Radio:
{
auto* w = new QRadioButton(mp->dialog.get());
buildWidget<WType::Radio, QRadioButton>(w, widget);
qw.widget = w;
break;
}
case WType::Checkbox:
{
auto* w = new QCheckBox(mp->dialog.get());
buildWidget<WType::Checkbox, QCheckBox>(w, widget);
qw.widget = w;
break;
}
case WType::Vscroll:
{
auto* w = new QScrollBar(mp->dialog.get());
buildWidget<WType::Vscroll, QScrollBar>(w, widget);
qw.widget = w;
break;
}
case WType::Hscroll:
{
auto* w = new QScrollBar(mp->dialog.get());
buildWidget<WType::Hscroll, QScrollBar>(w, widget);
qw.widget = w;
break;
}
// TODO case DialogWidget::Type::Canvas:
// break;
}
}
show();
}
ScriptDialog::ScriptDialog(ScriptDialog&& other)
: mp(std::move(other.mp))
{}
ScriptDialog::~ScriptDialog() = default;
void ScriptDialog::setAttr(const std::string& key, ValueHolder& value)
{
if (key == "x") {
auto rect = mp->dialog->geometry();
rect.setX(ValueExtract(value).toInt());
mp->dialog->setGeometry(rect);
}
else if (key == "y") {
auto rect = mp->dialog->geometry();
rect.setY(ValueExtract(value).toInt());
mp->dialog->setGeometry(rect);
}
else if (key == "width") {
auto rect = mp->dialog->geometry();
int width = ValueExtract(value).toInt();
rect.setWidth(width);
mp->dialog->setGeometry(rect);
mp->dialog->setMinimumWidth(width);
mp->dialog->setMaximumWidth(width);
}
else if (key == "height") {
auto rect = mp->dialog->geometry();
int height = ValueExtract(value).toInt();
rect.setHeight(height);
mp->dialog->setGeometry(rect);
mp->dialog->setMinimumHeight(height);
mp->dialog->setMaximumHeight(height);
}
else if (key == "title") {
mp->dialog->setWindowTitle(ValueExtract(value).toString().c_str());
}
else if (key == "font") {
QFont font = mp->dialog->font();
font.setFamily(ValueExtract(value).toString().c_str());
mp->dialog->setFont(font);
}
else if (key == "fontsize") {
QFont font = mp->dialog->font();
font.setPixelSize(ValueExtract(value).toInt());
mp->dialog->setFont(font);
}
else if (key == "icon") {
mp->dialog->setWindowIcon(QIcon(ValueExtract(value).toString().c_str()));
}
else {
mp->customAttrs.insert_or_assign(key, value);
}
}
ValueHolder ScriptDialog::attr(const std::string& key) const
{
if (key == "x") {
auto rect = mp->dialog->geometry();
return rect.x();
}
else if (key == "y") {
auto rect = mp->dialog->geometry();
return rect.y();
}
else if (key == "width") {
auto rect = mp->dialog->geometry();
return rect.width();
}
else if (key == "height") {
auto rect = mp->dialog->geometry();
return rect.height();
}
else if (key == "title") {
return mp->dialog->windowTitle().toStdString();
}
else if (key == "font") {
QFont font = mp->dialog->font();
return font.family().toStdString();
}
else if (key == "fontsize") {
QFont font = mp->dialog->font();
return font.pixelSize();
}
else if (key == "icon") {
return mp->dialog->windowIcon().name().toStdString();
}
else {
auto iter = mp->customAttrs.find(key);
if (iter == mp->customAttrs.end())
return ValueHolder();
return iter->second;
}
}
void ScriptDialog::setWidgetAttr(const std::string& widgetName, const std::string& key, ValueHolder& value)
{
try {
ScriptWidget& widget = mp->widgets.at(widgetName);
if (key == "x") {
auto rect = widget.widget->geometry();
rect.setX(ValueExtract(value).toInt());
widget.widget->setGeometry(rect);
}
else if (key == "y") {
auto rect = widget.widget->geometry();
rect.setY(ValueExtract(value).toInt());
widget.widget->setGeometry(rect);
}
else if (key == "width") {
auto rect = widget.widget->geometry();
rect.setWidth(ValueExtract(value).toInt());
widget.widget->setGeometry(rect);
}
else if (key == "height") {
auto rect = widget.widget->geometry();
rect.setHeight(ValueExtract(value).toInt());
widget.widget->setGeometry(rect);
}
else if (key == "font") {
QFont font = widget.widget->font();
font.setFamily(ValueExtract(value).toString().c_str());
widget.widget->setFont(font);
}
else if (key == "fontsize") {
QFont font = widget.widget->font();
font.setPixelSize(ValueExtract(value).toInt());
widget.widget->setFont(font);
}
else if (key == "enabled") {
widget.widget->setEnabled(ValueExtract(value).toBool());
}
else if (key == "visible") {
widget.widget->setVisible(ValueExtract(value).toBool());
}
else if (key == "text") {
widgetSetText(widget, value);
}
else if (key == "checkable") {
widgetSetCheckable(widget, value);
}
else if (key == "checked") {
widgetSetChecked(widget, value);
}
else if (key == "readonly") {
widgetSetReadOnly(widget, value);
}
else if (key == "tooltip") {
widget.widget->setToolTip(ValueExtract(value).toString().c_str());
}
else if (key == "value") {
widgetSetValue(widget, value);
}
else if (key == "min") {
widgetSetMin(widget, value);
}
else if (key == "max") {
widgetSetMax(widget, value);
}
else if (key == "step") {
widgetSetStep(widget, value);
}
else if (key == "header") {
widgetSetHeader(widget, value);
}
else {
widget.customAttrs.insert_or_assign(key, value);
}
} catch (std::out_of_range&) {
throw ScriptException("Widget not found: " + widgetName);
}
}
ValueHolder ScriptDialog::widgetAttr(const std::string& widgetName, const std::string& key) const
{
try {
auto& widget = mp->widgets.at(widgetName);
if (key == "x") {
auto rect = widget.widget->geometry();
return rect.x();
}
else if (key == "y") {
auto rect = widget.widget->geometry();
return rect.y();
}
else if (key == "width") {
auto rect = widget.widget->geometry();
return rect.width();
}
else if (key == "height") {
auto rect = widget.widget->geometry();
return rect.height();
}
else if (key == "font") {
QFont font = widget.widget->font();
return font.family().toStdString();
}
else if (key == "fontsize") {
QFont font = widget.widget->font();
return font.pixelSize();
}
else if (key == "enabled") {
return widget.widget->isEnabled();
}
else if (key == "visible") {
return widget.widget->isVisible();
}
else if (key == "text") {
return widgetGetText(widget);
}
else if (key == "checkable") {
return widgetGetCheckable(widget);
}
else if (key == "checked") {
return widgetGetChecked(widget);
}
else if (key == "readonly") {
return widgetGetReadOnly(widget);
}
else if (key == "tooltip") {
return widget.widget->toolTip().toStdString();
}
else if (key == "value") {
return widgetGetValue(widget);
}
else if (key == "min") {
return widgetGetMin(widget);
}
else if (key == "max") {
return widgetGetMax(widget);
}
else if (key == "step") {
return widgetGetStep(widget);
}
else if (key == "header") {
return widgetGetHeader(widget);
}
else {
auto iter = widget.customAttrs.find(key);
if (iter == widget.customAttrs.end())
return ValueHolder();
return iter->second;
}
} catch (std::out_of_range&) {
throw ScriptException("Widget not found: " + widgetName);
}
}
int ScriptDialog::tableWidgetCount(const std::string& widgetName)
{
auto& baseWidget = mp->widgets.at(widgetName);
auto* widget = dynamic_cast<QTableWidget*>(baseWidget.widget);
if (!widget)
throw ScriptException("Not a table widget");
return widget->rowCount();
}
void ScriptDialog::tableWidgetInsert(const std::string& widgetName, const ValueArray& cols)
{
auto& baseWidget = mp->widgets.at(widgetName);
auto* widget = dynamic_cast<QTableWidget*>(baseWidget.widget);
if (!widget)
throw ScriptException("Not a table widget");
const int rowCount = widget->rowCount() + 1;
widget->setRowCount(rowCount);
try {
const auto& colCountHolder = cols.at(LIST_END_MAGIC);
int colCount = ValueExtract(*(colCountHolder.get())).toInt();
if (colCount > widget->columnCount())
colCount = widget->columnCount();
for (int i = 0; i < colCount; ++i) {
auto& valHolder = *(cols.at(std::to_string(i)).get());
QString value;
switch (valHolder.getType()) {
case ValueHolder::Type::Void:
value = "[Void]";
break;
case ValueHolder::Type::Integer: {
int n = ValueExtract(valHolder).toInt();
value = QString::number(n);
break;
}
case ValueHolder::Type::Real: {
double n = ValueExtract(valHolder).toReal();
value = QString::number(n);
break;
}
case ValueHolder::Type::Bool: {
bool n = ValueExtract(valHolder).toBool();
value = QString::number(n);
break;
}
case ValueHolder::Type::String:
value = QString::fromStdString( ValueExtract(valHolder).toString() );
break;
case ValueHolder::Type::Map:
value = "[Map]";
break;
}
auto* item = new QTableWidgetItem(value);
widget->setItem(rowCount - 1, i, item);
}
widget->resizeColumnsToContents();
} catch (const std::out_of_range&) {
throw ScriptException("Not a list");
}
}
void ScriptDialog::tableWidgetRemove(const std::string& widgetName, int index)
{
auto& baseWidget = mp->widgets.at(widgetName);
auto* widget = dynamic_cast<QTableWidget*>(baseWidget.widget);
if (!widget)
throw ScriptException("Not a table widget");
if (index < 0 || index >= widget->rowCount())
return;
widget->removeRow(index);
}
int ScriptDialog::tableWidgetSelected(const std::string& widgetName)
{
auto& baseWidget = mp->widgets.at(widgetName);
auto* widget = dynamic_cast<QTableWidget*>(baseWidget.widget);
if (!widget)
throw ScriptException("Not a table widget");
auto* selection = widget->selectionModel();
auto idx = selection->currentIndex();
return idx.isValid() ? idx.row() : -1;
}
ValueArray ScriptDialog::tableWidgetRow(const std::string& widgetName, int index)
{
auto& baseWidget = mp->widgets.at(widgetName);
auto* widget = dynamic_cast<QTableWidget*>(baseWidget.widget);
if (!widget)
throw ScriptException("Not a table widget");
ValueArray ret;
if (index < 0 || index >= widget->rowCount()) {
ret.emplace(LIST_END_MAGIC, std::make_unique<ValueHolder>(0));
return ret;
}
const int colCount = widget->columnCount();
int i = 0;
for (; i < colCount; ++i) {
auto* item = widget->item(index, i);
const auto text = item->text().toStdString();
ret.emplace(std::to_string(i), std::make_unique<ValueHolder>(text));
}
ret.emplace(LIST_END_MAGIC, std::make_unique<ValueHolder>(i));
return ret;
}
const std::string& ScriptDialog::name() const
{
return mp->tmpl->name();
}
void ScriptDialog::close()
{
mp->dialog->close();
mp->dialog->deleteLater();
mp->dialog.release();
}
void ScriptDialog::hide()
{
mp->dialog->hide();
}
void ScriptDialog::show()
{
mp->dialog->show();
}