2023-04-18 18:21:34 +08:00
|
|
|
#include "expertboxlayoutwin.h"
|
2023-08-21 11:21:00 +08:00
|
|
|
#include "expertwin.h"
|
2023-04-18 18:21:34 +08:00
|
|
|
#include "gutil/qgui.h"
|
2023-07-28 14:48:41 +08:00
|
|
|
#include "gutil/qjson.h"
|
|
|
|
#include "globalfunc.h"
|
2023-04-18 18:21:34 +08:00
|
|
|
#include <QPushButton>
|
|
|
|
#include <QCheckBox>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QScrollArea>
|
2023-07-28 14:48:41 +08:00
|
|
|
#include <QFileDialog>
|
2023-08-21 11:21:00 +08:00
|
|
|
#include <QPainter>
|
|
|
|
#include <QMouseEvent>
|
|
|
|
#include <QToolButton>
|
|
|
|
#include <QPainterPath>
|
2023-08-24 16:55:38 +08:00
|
|
|
#include <QGroupBox>
|
2023-04-18 18:21:34 +08:00
|
|
|
|
2023-08-21 11:21:00 +08:00
|
|
|
ExpertBoxLayoutWin::ExpertBoxLayoutWin(ExpertWin *parent) : BaseWin{parent} {
|
2023-04-18 18:21:34 +08:00
|
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
setWindowTitle("箱体高级布局");
|
|
|
|
resize(1024, 720);
|
2023-08-21 11:21:00 +08:00
|
|
|
setStyleSheet("QToolButton {border: none; }");
|
2023-04-18 18:21:34 +08:00
|
|
|
|
|
|
|
auto vBox = new VBox(center);
|
|
|
|
vBox->setContentsMargins(0,0,0,0);
|
|
|
|
vBox->setSpacing(3);
|
2023-08-21 11:21:00 +08:00
|
|
|
vBox->addLayout(addBtns(new QHBoxLayout));
|
2023-04-18 18:21:34 +08:00
|
|
|
|
|
|
|
auto hBox = new HBox(vBox);
|
|
|
|
vBox = new VBox(hBox);
|
|
|
|
|
2023-08-24 16:55:38 +08:00
|
|
|
auto gBox = new QGroupBox("模组编辑");
|
|
|
|
vBox->addWidget(gBox);
|
|
|
|
auto grid = new Grid(gBox);
|
2023-04-18 18:21:34 +08:00
|
|
|
|
|
|
|
auto btnAdd = new QPushButton("添加");
|
2023-08-21 11:21:00 +08:00
|
|
|
connect(btnAdd, &QPushButton::clicked, this, [=] {
|
2023-07-28 14:48:41 +08:00
|
|
|
auto file = QFileDialog::getOpenFileName(this, tr("打开单元板文件"), gFileHome, tr("单元板文件 (*.module)"));
|
|
|
|
if(file.isEmpty()) return;
|
2023-08-21 11:21:00 +08:00
|
|
|
gFileHome = QFileInfo(file).absolutePath();
|
2023-07-28 14:48:41 +08:00
|
|
|
QFile qFile(file);
|
|
|
|
if(! qFile.open(QFile::ReadOnly)) {
|
|
|
|
QMessageBox::critical(this, tr("打开单元板文件失败"), file);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QString err;
|
2023-08-21 11:21:00 +08:00
|
|
|
auto json = JFrom(&qFile, &err);
|
2023-07-28 14:48:41 +08:00
|
|
|
qFile.close();
|
|
|
|
if(! err.isEmpty()) {
|
|
|
|
QMessageBox::critical(this, tr("解析 json 失败"), err+" "+file);
|
|
|
|
return;
|
|
|
|
}
|
2023-08-21 11:21:00 +08:00
|
|
|
QDialog dlg(this);
|
|
|
|
dlg.setWindowTitle(tr("添加模组"));
|
|
|
|
auto vBox = new VBox(&dlg);
|
|
|
|
auto hBox = new HBox(vBox);
|
|
|
|
hBox->addLabel(tr("横向数量"));
|
|
|
|
auto fdHNum = new QSpinBox;
|
|
|
|
fdHNum->setRange(1, 999);
|
|
|
|
fdHNum->setValue(1);
|
|
|
|
hBox->addWidget(fdHNum);
|
|
|
|
hBox->addStretch();
|
|
|
|
|
|
|
|
hBox = new HBox(vBox);
|
|
|
|
hBox->addLabel(tr("纵向数量"));
|
|
|
|
auto fdVNum = new QSpinBox;
|
|
|
|
fdVNum->setRange(1, 999);
|
|
|
|
fdVNum->setValue(1);
|
|
|
|
hBox->addWidget(fdVNum);
|
|
|
|
hBox->addStretch();
|
|
|
|
vBox->addStretch();
|
|
|
|
connect(vBox->addBtnBox(&dlg), &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
|
|
|
|
if(dlg.exec()!=QDialog::Accepted) return;
|
|
|
|
auto hNum = fdHNum->value();
|
|
|
|
auto vNum = fdVNum->value();
|
|
|
|
auto width = json["ModuleWidth"].toInt();
|
|
|
|
auto height = json["ModuleHeight"].toInt();
|
|
|
|
for(int vv=0; vv < vNum; ++vv) for(int hh=0; hh < hNum; ++hh) {
|
|
|
|
auto unit = new ModuleUnit(width*hh, height*vv, width, height, json.toObj(), "", box);
|
|
|
|
unit->show();
|
|
|
|
}
|
|
|
|
fdModNum->setNum(box->children().size());
|
|
|
|
box->fitSize();
|
2023-07-28 14:48:41 +08:00
|
|
|
});
|
2023-04-18 18:21:34 +08:00
|
|
|
grid->addWidget(btnAdd, 0, 0);
|
|
|
|
auto btnDel = new QPushButton("删除");
|
|
|
|
grid->addWidget(btnDel, 0, 1);
|
|
|
|
auto btnMove = new QPushButton("移动");
|
|
|
|
grid->addWidget(btnMove, 1, 0);
|
|
|
|
auto btnRotate = new QPushButton("旋转");
|
|
|
|
grid->addWidget(btnRotate, 1, 1);
|
|
|
|
|
2023-08-21 11:21:00 +08:00
|
|
|
auto btnDraw = new QPushButton("开始走线");
|
|
|
|
btnDraw->setCheckable(true);
|
|
|
|
connect(btnDraw, &QPushButton::clicked, this, [=](bool checked) {
|
|
|
|
box->isDrawing = checked;
|
|
|
|
btnDraw->setText(checked ? "结束走线" : "开始走线");
|
|
|
|
});
|
|
|
|
grid->addWidget(btnDraw, 2, 0);
|
|
|
|
|
|
|
|
auto btnClearLines = new QPushButton("清空所有走线");
|
|
|
|
connect(btnClearLines, &QPushButton::clicked, this, [=] {
|
|
|
|
for(auto btn : grpGrp->buttons()) if(btn->property("mods").isValid()) btn->setProperty("mods", QVariant());
|
|
|
|
for(auto child : box->children()) ((ModuleUnit*)child)->name = QString();
|
|
|
|
box->update();
|
|
|
|
});
|
|
|
|
grid->addWidget(btnClearLines, 3, 0);
|
|
|
|
|
|
|
|
auto btnClearLine = new QPushButton("清空当前走线");
|
|
|
|
connect(btnClearLine, &QPushButton::clicked, this, [=] {
|
|
|
|
for(auto btn : grpGrp->buttons()) {
|
|
|
|
auto mods = btn->property("mods").toList();
|
|
|
|
for(auto mod : mods) if(((ModuleUnit*) mod.value<void*>())->isSel) {
|
|
|
|
btn->setProperty("mods", QVariant());
|
|
|
|
for(auto mod : mods) ((ModuleUnit*) mod.value<void*>())->name = QString();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
box->update();
|
|
|
|
});
|
|
|
|
grid->addWidget(btnClearLine, 3, 1);
|
|
|
|
|
2023-08-24 16:55:38 +08:00
|
|
|
vBox->addSpacing(10);
|
|
|
|
|
|
|
|
gBox = new QGroupBox("数据组数设置");
|
|
|
|
vBox->addWidget(gBox);
|
|
|
|
auto hh = new HBox(gBox);
|
2023-08-21 11:21:00 +08:00
|
|
|
|
|
|
|
hh->addLabel("组数:");
|
|
|
|
auto fdGNum = new QSpinBox;
|
|
|
|
fdGNum->setRange(1, 128);
|
|
|
|
fdGNum->setValue(16);
|
|
|
|
hh->addWidget(fdGNum);
|
|
|
|
|
|
|
|
auto btnSet = new QPushButton("设置");
|
|
|
|
hh->addWidget(btnSet);
|
2023-04-18 18:21:34 +08:00
|
|
|
|
|
|
|
grid = new Grid(vBox);
|
2023-08-21 11:21:00 +08:00
|
|
|
grpGrp = new QButtonGroup(fdGNum);
|
|
|
|
connect(btnSet, &QPushButton::clicked, this, [=] {
|
|
|
|
auto newCnt = fdGNum->value();
|
|
|
|
auto oldCnt = grpGrp->buttons().size();
|
|
|
|
if(newCnt>oldCnt) for(int i=oldCnt; i<newCnt; ++i) {
|
|
|
|
auto btn = new QPushButton("G"+QString::number(i+1));
|
|
|
|
btn->setCheckable(true);
|
|
|
|
btn->setMaximumWidth(40);
|
|
|
|
btn->setFixedHeight(24);
|
|
|
|
grpGrp->addButton(btn, i);
|
|
|
|
grid->addWidget(btn, i / 4, i % 4);
|
|
|
|
} else if(newCnt<oldCnt) for(int i=oldCnt-1; i>=newCnt; --i) {
|
|
|
|
auto btn = grpGrp->button(i);
|
|
|
|
grpGrp->removeButton(btn);
|
|
|
|
grid->removeWidget(btn);
|
|
|
|
delete btn;
|
|
|
|
}
|
|
|
|
if(grpGrp->checkedButton()==0) grpGrp->buttons()[0]->setChecked(true);
|
|
|
|
});
|
|
|
|
emit btnSet->clicked();
|
|
|
|
|
2023-08-24 16:55:38 +08:00
|
|
|
vBox->addSpacing(10);
|
2023-04-18 18:21:34 +08:00
|
|
|
|
2023-08-24 16:55:38 +08:00
|
|
|
gBox = new QGroupBox("显示");
|
|
|
|
vBox->addWidget(gBox);
|
|
|
|
grid = new Grid(gBox);
|
2023-04-18 18:21:34 +08:00
|
|
|
|
2023-08-21 11:21:00 +08:00
|
|
|
fdHasPos = new QCheckBox("位置");
|
|
|
|
fdHasPos->setChecked(true);
|
2023-04-18 18:21:34 +08:00
|
|
|
grid->addWidget(fdHasPos, 0, 0);
|
2023-08-21 11:21:00 +08:00
|
|
|
fdHasSize = new QCheckBox("大小");
|
|
|
|
fdHasSize->setChecked(true);
|
2023-04-18 18:21:34 +08:00
|
|
|
grid->addWidget(fdHasSize, 0, 1);
|
2023-08-21 11:21:00 +08:00
|
|
|
fdHasConn = new QCheckBox("连接");
|
|
|
|
fdHasConn->setChecked(true);
|
2023-04-18 18:21:34 +08:00
|
|
|
grid->addWidget(fdHasConn, 1, 0);
|
2023-08-21 11:21:00 +08:00
|
|
|
fdHasName = new QCheckBox("名称");
|
|
|
|
fdHasName->setChecked(true);
|
2023-04-18 18:21:34 +08:00
|
|
|
grid->addWidget(fdHasName, 1, 1);
|
2023-08-21 11:21:00 +08:00
|
|
|
fdHasOutline = new QCheckBox("轮廓");
|
|
|
|
fdHasOutline->setChecked(true);
|
2023-04-18 18:21:34 +08:00
|
|
|
grid->addWidget(fdHasOutline, 2, 0);
|
2023-08-24 16:55:38 +08:00
|
|
|
fdSnap = new QCheckBox("吸附");
|
|
|
|
fdSnap->setChecked(true);
|
|
|
|
grid->addWidget(fdSnap, 2, 1);
|
|
|
|
|
|
|
|
vBox->addSpacing(10);
|
2023-08-21 11:21:00 +08:00
|
|
|
|
2023-08-24 16:55:38 +08:00
|
|
|
gBox = new QGroupBox("对齐");
|
|
|
|
vBox->addWidget(gBox);
|
|
|
|
hh = new HBox(gBox);
|
2023-08-21 11:21:00 +08:00
|
|
|
|
|
|
|
QSize imgSize(32,32);
|
|
|
|
|
|
|
|
auto bnAlignLeft = new QToolButton;
|
|
|
|
bnAlignLeft->setIconSize(imgSize);
|
|
|
|
bnAlignLeft->setIcon(QIcon(":/imgs/align-left.png"));
|
|
|
|
connect(bnAlignLeft, &QToolButton::clicked, this, [=] {
|
|
|
|
int bound = INT_MAX;
|
|
|
|
ModuleUnit* mod;
|
|
|
|
for(auto child : box->children()) if((mod = (ModuleUnit*)child)->isSel && mod->x() < bound) bound = mod->x();
|
|
|
|
bool needFit = false;
|
|
|
|
if(bound != INT_MAX) for(auto child : box->children()) if((mod = (ModuleUnit*)child)->isSel && mod->x() != bound) {
|
|
|
|
mod->move(bound, mod->y());
|
|
|
|
mod->mX = qRound(mod->x() / box->rate);
|
|
|
|
needFit = true;
|
|
|
|
}
|
|
|
|
if(needFit) box->fitSize();
|
|
|
|
});
|
|
|
|
hh->addWidget(bnAlignLeft);
|
|
|
|
|
|
|
|
auto bnAlignRight = new QToolButton;
|
|
|
|
bnAlignRight->setIconSize(imgSize);
|
|
|
|
bnAlignRight->setIcon(QIcon(":/imgs/align-right.png"));
|
|
|
|
connect(bnAlignRight, &QToolButton::clicked, this, [=] {
|
|
|
|
int bound = INT_MIN, temp;
|
|
|
|
ModuleUnit* mod;
|
|
|
|
for(auto child : box->children()) if((mod = (ModuleUnit*)child)->isSel && (temp = mod->x()+mod->width()) > bound) bound = temp;
|
|
|
|
bool needFit = false;
|
|
|
|
if(bound != INT_MIN) for(auto child : box->children()) if((mod = (ModuleUnit*)child)->isSel && mod->x() != (temp = bound-mod->width())) {
|
|
|
|
mod->move(temp, mod->y());
|
|
|
|
mod->mX = qRound(mod->x() / box->rate);
|
|
|
|
needFit = true;
|
|
|
|
}
|
|
|
|
if(needFit) box->fitSize();
|
|
|
|
});
|
|
|
|
hh->addWidget(bnAlignRight);
|
|
|
|
|
|
|
|
auto bnAlignTop = new QToolButton;
|
|
|
|
bnAlignTop->setIconSize(imgSize);
|
|
|
|
bnAlignTop->setIcon(QIcon(":/imgs/align-top.png"));
|
|
|
|
connect(bnAlignTop, &QToolButton::clicked, this, [=] {
|
|
|
|
int bound = INT_MAX;
|
|
|
|
ModuleUnit* mod;
|
|
|
|
for(auto child : box->children()) if((mod = (ModuleUnit*)child)->isSel && mod->y() < bound) bound = mod->y();
|
|
|
|
bool needFit = false;
|
|
|
|
if(bound != INT_MAX) for(auto child : box->children()) if((mod = (ModuleUnit*)child)->isSel && mod->y() != bound) {
|
|
|
|
mod->move(mod->x(), bound);
|
|
|
|
mod->mY = qRound(mod->y() / box->rate);
|
|
|
|
needFit = true;
|
|
|
|
}
|
|
|
|
if(needFit) box->fitSize();
|
|
|
|
});
|
|
|
|
hh->addWidget(bnAlignTop);
|
|
|
|
|
|
|
|
auto bnAlignBottom = new QToolButton;
|
|
|
|
bnAlignBottom->setIconSize(imgSize);
|
|
|
|
bnAlignBottom->setIcon(QIcon(":/imgs/align-bottom.png"));
|
|
|
|
connect(bnAlignBottom, &QToolButton::clicked, this, [=] {
|
|
|
|
int bound = INT_MIN, temp;
|
|
|
|
ModuleUnit* mod;
|
|
|
|
for(auto child : box->children()) if((mod = (ModuleUnit*)child)->isSel && (temp = mod->y()+mod->height()) > bound) bound = temp;
|
|
|
|
bool needFit = false;
|
|
|
|
if(bound != INT_MIN) for(auto child : box->children()) if((mod = (ModuleUnit*)child)->isSel && mod->y() != (temp = bound-mod->height())) {
|
|
|
|
mod->move(mod->x(), temp);
|
|
|
|
mod->mY = qRound(mod->y() / box->rate);
|
|
|
|
needFit = true;
|
|
|
|
}
|
|
|
|
if(needFit) box->fitSize();
|
|
|
|
});
|
|
|
|
hh->addWidget(bnAlignBottom);
|
|
|
|
|
2023-08-24 16:55:38 +08:00
|
|
|
gBox = new QGroupBox("排列");
|
|
|
|
vBox->addWidget(gBox);
|
|
|
|
hh = new HBox(gBox);
|
2023-08-21 11:21:00 +08:00
|
|
|
|
|
|
|
auto bnArrangeLeft = new QToolButton;
|
|
|
|
bnArrangeLeft->setIconSize(imgSize);
|
|
|
|
bnArrangeLeft->setIcon(QIcon(":/imgs/arrange-left.png"));
|
|
|
|
connect(bnArrangeLeft, &QToolButton::clicked, this, [=] {
|
|
|
|
int bound = INT_MAX;
|
|
|
|
ModuleUnit* tmod;
|
|
|
|
std::vector<ModuleUnit*> mods;
|
|
|
|
for(auto child : box->children()) if((tmod = (ModuleUnit*)child)->isSel) {
|
|
|
|
auto it = mods.begin();
|
|
|
|
while(it!=mods.end() && (*it)->y() <= tmod->y()) it++;
|
|
|
|
mods.insert(it, tmod);
|
|
|
|
if(tmod->x() < bound) bound = tmod->x();
|
|
|
|
}
|
|
|
|
tmod = 0;
|
|
|
|
for(auto mod : mods) {
|
|
|
|
mod->move(bound, tmod ? tmod->y()+tmod->height() : mod->y());
|
|
|
|
tmod = mod;
|
|
|
|
mod->mX = qRound(mod->x() / box->rate);
|
|
|
|
mod->mY = qRound(mod->y() / box->rate);
|
|
|
|
}
|
|
|
|
if(! mods.empty()) box->fitSize();
|
|
|
|
});
|
|
|
|
hh->addWidget(bnArrangeLeft);
|
|
|
|
|
|
|
|
auto bnArrangeRight = new QToolButton;
|
|
|
|
bnArrangeRight->setIconSize(imgSize);
|
|
|
|
bnArrangeRight->setIcon(QIcon(":/imgs/arrange-right.png"));
|
|
|
|
connect(bnArrangeRight, &QToolButton::clicked, this, [=] {
|
|
|
|
int bound = INT_MIN;
|
|
|
|
ModuleUnit* tmod;
|
|
|
|
std::vector<ModuleUnit*> mods;
|
|
|
|
for(auto child : box->children()) if((tmod = (ModuleUnit*)child)->isSel) {
|
|
|
|
auto it = mods.begin();
|
|
|
|
while(it!=mods.end() && (*it)->y() <= tmod->y()) it++;
|
|
|
|
mods.insert(it, tmod);
|
|
|
|
if(tmod->x()+tmod->width() > bound) bound = tmod->x()+tmod->width();
|
|
|
|
}
|
|
|
|
tmod = 0;
|
|
|
|
for(auto mod : mods) {
|
|
|
|
mod->move(bound-mod->width(), tmod ? tmod->y()+tmod->height() : mod->y());
|
|
|
|
tmod = mod;
|
|
|
|
mod->mX = qRound(mod->x() / box->rate);
|
|
|
|
mod->mY = qRound(mod->y() / box->rate);
|
|
|
|
}
|
|
|
|
if(! mods.empty()) box->fitSize();
|
|
|
|
});
|
|
|
|
hh->addWidget(bnArrangeRight);
|
|
|
|
|
|
|
|
auto bnArrangeTop = new QToolButton;
|
|
|
|
bnArrangeTop->setIconSize(imgSize);
|
|
|
|
bnArrangeTop->setIcon(QIcon(":/imgs/arrange-top.png"));
|
|
|
|
connect(bnArrangeTop, &QToolButton::clicked, this, [=] {
|
|
|
|
int bound = INT_MAX;
|
|
|
|
ModuleUnit* tmod;
|
|
|
|
std::vector<ModuleUnit*> mods;
|
|
|
|
for(auto child : box->children()) if((tmod = (ModuleUnit*)child)->isSel) {
|
|
|
|
auto it = mods.begin();
|
|
|
|
while(it!=mods.end() && (*it)->x() <= tmod->x()) it++;
|
|
|
|
mods.insert(it, tmod);
|
|
|
|
if(tmod->y() < bound) bound = tmod->y();
|
|
|
|
}
|
|
|
|
tmod = 0;
|
|
|
|
for(auto mod : mods) {
|
|
|
|
mod->move(tmod ? tmod->x()+tmod->width() : mod->x(), bound);
|
|
|
|
tmod = mod;
|
|
|
|
mod->mX = qRound(mod->x() / box->rate);
|
|
|
|
mod->mY = qRound(mod->y() / box->rate);
|
|
|
|
}
|
|
|
|
if(! mods.empty()) box->fitSize();
|
|
|
|
});
|
|
|
|
hh->addWidget(bnArrangeTop);
|
|
|
|
|
|
|
|
auto bnArrangeBottom = new QToolButton;
|
|
|
|
bnArrangeBottom->setIconSize(imgSize);
|
|
|
|
bnArrangeBottom->setIcon(QIcon(":/imgs/arrange-bottom.png"));
|
|
|
|
connect(bnArrangeBottom, &QToolButton::clicked, this, [=] {
|
|
|
|
int bound = INT_MIN;
|
|
|
|
ModuleUnit* tmod;
|
|
|
|
std::vector<ModuleUnit*> mods;
|
|
|
|
for(auto child : box->children()) if((tmod = (ModuleUnit*)child)->isSel) {
|
|
|
|
auto it = mods.begin();
|
|
|
|
while(it!=mods.end() && (*it)->x() <= tmod->x()) it++;
|
|
|
|
mods.insert(it, tmod);
|
|
|
|
if(tmod->y()+tmod->height() > bound) bound = tmod->y()+tmod->height();
|
|
|
|
}
|
|
|
|
tmod = 0;
|
|
|
|
for(auto mod : mods) {
|
|
|
|
mod->move(tmod ? tmod->x()+tmod->width() : mod->x(), bound-mod->height());
|
|
|
|
tmod = mod;
|
|
|
|
mod->mX = qRound(mod->x() / box->rate);
|
|
|
|
mod->mY = qRound(mod->y() / box->rate);
|
|
|
|
}
|
|
|
|
if(! mods.empty()) box->fitSize();
|
|
|
|
});
|
|
|
|
hh->addWidget(bnArrangeBottom);
|
2023-04-18 18:21:34 +08:00
|
|
|
|
|
|
|
vBox->addStretch();
|
|
|
|
|
|
|
|
vBox = new VBox(hBox);
|
|
|
|
hBox = new HBox(vBox);
|
2023-08-21 11:21:00 +08:00
|
|
|
auto fdRoom = new QComboBox;
|
|
|
|
fdRoom->setEditable(true);
|
|
|
|
fdRoom->addItem("1600%");
|
|
|
|
fdRoom->addItem("800%");
|
|
|
|
fdRoom->addItem("400%");
|
|
|
|
fdRoom->addItem("200%");
|
|
|
|
fdRoom->addItem("100%");
|
|
|
|
fdRoom->addItem("50%");
|
|
|
|
fdRoom->addItem("25%");
|
|
|
|
connect(fdRoom, &QComboBox::currentTextChanged, this, [=](const QString &text) {
|
|
|
|
if(box==0) return;
|
|
|
|
box->rate = text.trimmed().replace('%',"").toInt() / 100.0;
|
|
|
|
auto childs = box->children();
|
|
|
|
foreach(auto child, childs) {
|
|
|
|
auto mod = (ModuleUnit*)child;
|
|
|
|
mod->setGeometry(mod->mX*box->rate, mod->mY*box->rate, mod->mW*box->rate, mod->mH*box->rate);
|
|
|
|
}
|
|
|
|
box->fitSize();
|
|
|
|
});
|
|
|
|
hBox->addWidget(fdRoom);
|
|
|
|
|
|
|
|
hBox->addLabel("模组数量: ");
|
|
|
|
fdModNum = hBox->addLabel();
|
|
|
|
hBox->addSpacing(20);
|
|
|
|
|
|
|
|
hBox->addLabel("箱体大小: ");
|
|
|
|
fdBoxSize = hBox->addLabel();
|
|
|
|
|
2023-04-18 18:21:34 +08:00
|
|
|
hBox->addStretch();
|
|
|
|
|
|
|
|
auto scroll = new QScrollArea;
|
|
|
|
vBox->addWidget(scroll);
|
|
|
|
|
2023-08-21 11:21:00 +08:00
|
|
|
box = new BoxPanel(this);
|
2023-07-28 14:48:41 +08:00
|
|
|
scroll->setWidget(box);
|
|
|
|
box->resize(1024, 1024);
|
|
|
|
box->setAutoFillBackground(true);
|
2023-04-18 18:21:34 +08:00
|
|
|
auto pal = palette();
|
|
|
|
pal.setColor(QPalette::Window, QColor(0x222222));
|
2023-07-28 14:48:41 +08:00
|
|
|
box->setPalette(pal);
|
2023-08-24 16:55:38 +08:00
|
|
|
SetCurText(fdRoom, "400%");
|
2023-08-21 11:21:00 +08:00
|
|
|
|
2023-08-24 16:55:38 +08:00
|
|
|
connect(btnDel, &QPushButton::clicked, box, &BoxPanel::del);
|
2023-08-21 11:21:00 +08:00
|
|
|
connect(fdHasPos, &QCheckBox::stateChanged, box, (void(QWidget::*)())&QWidget::update);
|
|
|
|
connect(fdHasSize, &QCheckBox::stateChanged, box, (void(QWidget::*)())&QWidget::update);
|
|
|
|
connect(fdHasConn, &QCheckBox::stateChanged, box, (void(QWidget::*)())&QWidget::update);
|
|
|
|
connect(fdHasName, &QCheckBox::stateChanged, box, (void(QWidget::*)())&QWidget::update);
|
|
|
|
connect(fdHasOutline, &QCheckBox::stateChanged, box, (void(QWidget::*)())&QWidget::update);
|
|
|
|
|
|
|
|
auto ModuleWidth = parent->mModule["ModuleWidth"].toInt();
|
|
|
|
auto ModuleHeight = parent->mModule["ModuleHeight"].toInt();
|
|
|
|
new ModuleUnit(0, 0, ModuleWidth, ModuleHeight, parent->mModule, "", box);
|
|
|
|
new ModuleUnit(ModuleWidth, 0, ModuleWidth, ModuleHeight, parent->mModule, "", box);
|
|
|
|
new ModuleUnit(0, ModuleHeight, ModuleWidth, ModuleHeight, parent->mModule, "", box);
|
|
|
|
new ModuleUnit(ModuleWidth, ModuleHeight, ModuleWidth, ModuleHeight, parent->mModule, "", box);
|
|
|
|
fdModNum->setNum(4);
|
|
|
|
box->fitSize();
|
|
|
|
}
|
|
|
|
|
2023-08-24 16:55:38 +08:00
|
|
|
void BoxPanel::del() {
|
|
|
|
for(auto child=children().begin(); child<children().end();) {
|
|
|
|
if(((ModuleUnit*) *child)->isSel) {
|
|
|
|
for(auto copied = copieds.begin(); copied < copieds.end(); copied++) if(*copied==*child) {
|
|
|
|
copieds.erase(copied);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(! ((ModuleUnit*) *child)->name.isEmpty()) for(auto btn : boxWin->grpGrp->buttons()) {
|
|
|
|
auto mods = btn->property("mods").toList();
|
|
|
|
for(auto mod=mods.begin(); mod<mods.end(); mod++) if(mod->value<void*>() == *child) {
|
|
|
|
mods.erase(mod);
|
|
|
|
btn->setProperty("mods", mods);
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end:
|
|
|
|
delete *child;
|
|
|
|
} else child++;
|
|
|
|
}
|
|
|
|
boxWin->fdModNum->setNum(children().size());
|
|
|
|
fitSize();
|
|
|
|
}
|
|
|
|
void BoxPanel::keyPressEvent(QKeyEvent *event) {
|
|
|
|
if(event->modifiers() & Qt::ControlModifier) {
|
|
|
|
if(event->key()==Qt::Key_C) {
|
|
|
|
copieds.clear();
|
|
|
|
for(auto child : children()) if(((ModuleUnit*) child)->isSel) copieds.emplace_back((ModuleUnit*) child);
|
|
|
|
} else if(event->key()==Qt::Key_V) {
|
|
|
|
for(auto child : children()) if(((ModuleUnit*) child)->isSel) ((ModuleUnit*) child)->isSel = false;
|
|
|
|
auto off = 16 / rate;
|
|
|
|
for(auto copied = copieds.begin(); copied < copieds.end(); copied++) {
|
|
|
|
auto unit = new ModuleUnit((*copied)->mX+off, (*copied)->mY+off, (*copied)->mW, (*copied)->mH, (*copied)->mModule, "", this);
|
|
|
|
unit->isSel = true;
|
|
|
|
unit->show();
|
|
|
|
*copied = unit;
|
|
|
|
}
|
|
|
|
boxWin->fdModNum->setNum(children().size());
|
|
|
|
fitSize();
|
|
|
|
}
|
|
|
|
} else if(event->key()==Qt::Key_Delete) del();
|
|
|
|
}
|
2023-08-21 11:21:00 +08:00
|
|
|
void BoxPanel::mousePressEvent(QMouseEvent *event) {
|
|
|
|
if(event->button() != Qt::LeftButton) return;
|
|
|
|
if(isDrawing) return;
|
|
|
|
rect = QRectF(event->localPos(), event->localPos());
|
|
|
|
for(auto child : children()) ((ModuleUnit*) child)->isSel = false;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
void BoxPanel::mouseReleaseEvent(QMouseEvent *event) {
|
|
|
|
if(event->button() != Qt::LeftButton) return;
|
|
|
|
if(rect.isNull()) return;
|
|
|
|
rect = QRectF();
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
void BoxPanel::mouseMoveEvent(QMouseEvent *event) {
|
|
|
|
if(! (event->buttons() & Qt::LeftButton)) return;
|
|
|
|
if(isDrawing) {
|
|
|
|
auto mod = (ModuleUnit*) childAt(event->pos());
|
|
|
|
if(mod && mod->name.isEmpty()) mod->drawed();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
rect.setBottomRight(event->localPos());
|
|
|
|
for(auto child : children()) {
|
|
|
|
auto mod = (ModuleUnit*) child;
|
|
|
|
mod->isSel = rect.intersects(mod->geometry());
|
|
|
|
}
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
void BoxPanel::paintEvent(QPaintEvent *) {
|
|
|
|
QPainter painter(this);
|
2023-08-24 16:55:38 +08:00
|
|
|
if(rate>=2) {
|
|
|
|
QBrush bra(0x666666);
|
|
|
|
for(int xx=rate; xx<width(); xx+=rate) painter.fillRect(QRectF(xx, 0, -0.5, height()), bra);
|
|
|
|
for(int yy=rate; yy<height(); yy+=rate) painter.fillRect(QRectF(0, yy, width(), -0.5), bra);
|
|
|
|
}
|
2023-08-21 11:21:00 +08:00
|
|
|
ModuleUnit *mod;
|
|
|
|
for(auto child : children()) {
|
|
|
|
mod = (ModuleUnit*) child;
|
|
|
|
QPointF pos(mod->x(), mod->y());
|
|
|
|
painter.translate(pos);
|
|
|
|
painter.fillRect(QRectF(1, 1, mod->width()-2, mod->height()-2), mod->isSel ? QColor(0, 0xaa, 0, 0xaa) : QColor(0, 0x44, 0xff, 0x77));
|
|
|
|
painter.setPen(QColor(mod->isSel ? 0xffffff : 0xdddddd));
|
|
|
|
if(boxWin->fdHasOutline->isChecked()) painter.drawRect(QRectF(0.5, 0.5, mod->width()-1, mod->height()-1));
|
|
|
|
int off = 0;
|
|
|
|
if(boxWin->fdHasPos->isChecked()) painter.drawText(2, off+=15, QString::number(mod->mX)+", "+QString::number(mod->mY));
|
|
|
|
if(boxWin->fdHasSize->isChecked()) painter.drawText(2, off+=15, QString::number(mod->mW)+" x "+QString::number(mod->mH));
|
|
|
|
if(! mod->name.isEmpty()) painter.drawText(2, off+15, mod->name);
|
|
|
|
painter.translate(-pos);
|
|
|
|
}
|
|
|
|
QPen pen(0xff8800);
|
|
|
|
pen.setCapStyle(Qt::FlatCap);
|
|
|
|
pen.setDashPattern(QVector<qreal>{4, 4});
|
|
|
|
painter.setPen(pen);
|
|
|
|
painter.drawRect(QRectF(boxRect.x()-0.5, boxRect.y()-0.5, boxRect.width()+1, boxRect.height()+1));
|
|
|
|
|
|
|
|
if(boxWin->fdHasConn->isChecked()) {
|
|
|
|
QBrush brush(0x0088ff);
|
|
|
|
painter.setPen(QPen(brush, 3));
|
|
|
|
QPainterPath path;
|
|
|
|
for(auto btn : boxWin->grpGrp->buttons()) {
|
|
|
|
auto mods = btn->property("mods").toList();
|
|
|
|
if(mods.isEmpty()) continue;
|
|
|
|
QPointF last = ((ModuleUnit*) mods[0].value<void*>())->geometry().center();
|
|
|
|
for(int mm=1; mm<mods.size(); mm++) {
|
|
|
|
QPointF pos = ((ModuleUnit*) mods[mm].value<void*>())->geometry().center();
|
|
|
|
painter.drawLine(last, pos);
|
|
|
|
auto deg = 180 / 3.1415926535 * atan((pos.y()-last.y()) / (pos.x()-last.x()));
|
|
|
|
if(pos.x()<last.x()) deg += 180;
|
|
|
|
last = pos;
|
|
|
|
painter.translate(pos);
|
|
|
|
painter.rotate(deg);
|
|
|
|
path.clear();
|
|
|
|
path.lineTo(-30,6);
|
|
|
|
path.lineTo(-30,-6);
|
|
|
|
path.closeSubpath();
|
|
|
|
painter.fillPath(path, brush);
|
|
|
|
painter.rotate(-deg);
|
|
|
|
painter.translate(-pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(rect.isNull()) return;
|
|
|
|
painter.setPen(0x00aa00);
|
|
|
|
painter.drawRect(rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ModuleUnit::ModuleUnit(int x, int y, int w, int h, const JObj &module, const QString &name, QWidget *parent) : QWidget{parent}, mX{x}, mY{y}, mW{w}, mH{h}, mModule{module}, name{name} {
|
|
|
|
box = (BoxPanel*)parent;
|
|
|
|
setGeometry(x*box->rate, y*box->rate, w*box->rate, h*box->rate);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleUnit::drawed() {
|
|
|
|
auto btn = box->boxWin->grpGrp->checkedButton();
|
|
|
|
if(btn==0) return;
|
|
|
|
auto mods = btn->property("mods").toList();
|
2023-09-05 10:02:20 +08:00
|
|
|
if(! mods.isEmpty() && ((ExpertWin*)box->boxWin->parentWidget())->m_iRcvCardType==enum_zrf) {
|
|
|
|
auto last = (ModuleUnit*) mods.last().value<void*>();
|
|
|
|
if(last->mY!=mY || last->mX+last->mW!=mX) {
|
|
|
|
QMessageBox::warning(this, "注意", "模组要紧跟着前一个");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2023-08-21 11:21:00 +08:00
|
|
|
mods.append(QVariant::fromValue((void*)this));
|
|
|
|
btn->setProperty("mods", mods);
|
|
|
|
name = "G"+QString::number(box->boxWin->grpGrp->id(btn)+1)+"-"+QString::number(mods.size());
|
2023-08-24 16:55:38 +08:00
|
|
|
for(auto child : box->children()) ((ModuleUnit*)child)->isSel = false;
|
|
|
|
isSel = true;
|
2023-08-21 11:21:00 +08:00
|
|
|
box->update();
|
|
|
|
}
|
|
|
|
void ModuleUnit::mousePressEvent(QMouseEvent *event) {
|
|
|
|
QWidget::mousePressEvent(event);
|
|
|
|
if(event->button() != Qt::LeftButton) return;
|
|
|
|
event->accept();
|
|
|
|
if(box->isDrawing) return;
|
2023-08-24 16:55:38 +08:00
|
|
|
if(event->modifiers() & Qt::ControlModifier) return;
|
2023-08-21 11:21:00 +08:00
|
|
|
setCursor(Qt::SizeAllCursor);
|
|
|
|
auto glbPos = event->globalPos();
|
|
|
|
box->grpRect = geometry();
|
|
|
|
if(isSel) {
|
2023-08-24 16:55:38 +08:00
|
|
|
box->sels.clear();
|
2023-08-21 11:21:00 +08:00
|
|
|
ModuleUnit* mod;
|
|
|
|
for(auto child : box->children()) if(child!=this && (mod = (ModuleUnit*)child)->isSel) {
|
|
|
|
mod->mPressRel = mod->pos() - pos();
|
|
|
|
box->grpRect |= mod->geometry();
|
2023-08-24 16:55:38 +08:00
|
|
|
box->sels.emplace_back(mod);
|
2023-08-21 11:21:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
mPressRel = pos() - box->grpRect.topLeft();
|
|
|
|
box->grpRect.translate(-glbPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModuleUnit::mouseReleaseEvent(QMouseEvent *event) {
|
|
|
|
QWidget::mouseReleaseEvent(event);
|
|
|
|
if(Qt::LeftButton != event->button()) return;
|
|
|
|
event->accept();
|
|
|
|
if(box->isDrawing) {
|
|
|
|
if(name.isEmpty()) drawed();
|
|
|
|
return;
|
|
|
|
}
|
2023-08-24 16:55:38 +08:00
|
|
|
if(event->modifiers() & Qt::ControlModifier) {
|
|
|
|
isSel = true;
|
|
|
|
update();
|
|
|
|
return;
|
|
|
|
}
|
2023-08-21 11:21:00 +08:00
|
|
|
unsetCursor();
|
|
|
|
mPressRel.setX(INT_MIN);
|
|
|
|
if(! isSel) {
|
|
|
|
isSel = true;
|
|
|
|
update();
|
|
|
|
for(auto item : box->children()) if(item!=this && ((ModuleUnit*)item)->isSel) {
|
|
|
|
((ModuleUnit*)item)->isSel = false;
|
|
|
|
((ModuleUnit*)item)->update();
|
|
|
|
}
|
|
|
|
}
|
2023-08-24 16:55:38 +08:00
|
|
|
for(auto sel : box->sels) sel->mPressRel.setX(INT_MIN);
|
|
|
|
box->sels.clear();
|
2023-08-21 11:21:00 +08:00
|
|
|
}
|
2023-08-24 16:55:38 +08:00
|
|
|
#define SnapSpace 12
|
2023-08-21 11:21:00 +08:00
|
|
|
void ModuleUnit::mouseMoveEvent(QMouseEvent *e) {
|
|
|
|
if(! (e->buttons() & Qt::LeftButton)) return;
|
|
|
|
if(box->isDrawing) {
|
|
|
|
if(name.isEmpty()) drawed();
|
|
|
|
else {
|
|
|
|
auto mod = (ModuleUnit*) box->childAt(x()+e->x(), y()+e->y());
|
|
|
|
if(mod && mod!=this && mod->name.isEmpty()) mod->drawed();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(mPressRel.x()==INT_MIN) return;
|
2023-08-24 16:55:38 +08:00
|
|
|
ModuleUnit* mod;
|
2023-08-21 11:21:00 +08:00
|
|
|
if(! isSel) {
|
|
|
|
isSel = true;
|
2023-08-24 16:55:38 +08:00
|
|
|
for(auto child : box->children()) if(child!=this && (mod = (ModuleUnit*)child)->isSel) mod->isSel = false;
|
|
|
|
}
|
|
|
|
auto grpRect = box->grpRect;
|
|
|
|
grpRect.translate(e->globalPos());
|
|
|
|
auto dstHor = qMax(0, grpRect.x());
|
|
|
|
auto dstVer = qMax(0, grpRect.y());
|
|
|
|
if(box->boxWin->fdSnap->isChecked() && (dstHor || dstVer)) {
|
|
|
|
bool needH = dstHor, needV = dstVer;
|
|
|
|
auto nearRect = grpRect.marginsAdded({24,24,24,24});
|
|
|
|
for(auto child : box->children()) if(! (mod = (ModuleUnit*)child)->isSel && mod->geometry().intersects(nearRect)) {//左右
|
|
|
|
if(needH) {
|
|
|
|
if(abs(dstHor - mod->x()) < SnapSpace) {
|
|
|
|
dstHor = mod->x();
|
|
|
|
needH = false;
|
|
|
|
goto vvv;
|
|
|
|
}
|
|
|
|
auto eleRight = mod->x() + mod->width();
|
|
|
|
if(abs(dstHor - eleRight) < SnapSpace) {
|
|
|
|
dstHor = eleRight;
|
|
|
|
needH = false;
|
|
|
|
goto vvv;
|
|
|
|
}
|
|
|
|
auto right = dstHor + grpRect.width();
|
|
|
|
if(abs(right - mod->x()) < SnapSpace && mod->x() - grpRect.width() >= 0) {
|
|
|
|
dstHor = mod->x() - grpRect.width();
|
|
|
|
needH = false;
|
|
|
|
goto vvv;
|
|
|
|
}
|
|
|
|
if(abs(right - eleRight) < SnapSpace && eleRight - grpRect.width() >= 0) {
|
|
|
|
dstHor = eleRight - grpRect.width();
|
|
|
|
needH = false;
|
|
|
|
goto vvv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vvv:
|
|
|
|
if(needV) {
|
|
|
|
if(abs(dstVer-mod->y()) < SnapSpace) {
|
|
|
|
dstVer = mod->y();
|
|
|
|
needV = false;
|
|
|
|
goto eee;
|
|
|
|
}
|
|
|
|
auto eleBtm = mod->y() + mod->height();
|
|
|
|
if(abs(dstVer - eleBtm) < SnapSpace) {
|
|
|
|
dstVer = eleBtm;
|
|
|
|
needV = false;
|
|
|
|
goto eee;
|
|
|
|
}
|
|
|
|
auto btm = dstVer + grpRect.height();
|
|
|
|
if(abs(btm - mod->y()) < SnapSpace && mod->y() - grpRect.height() >= 0) {
|
|
|
|
dstVer = mod->y() - grpRect.height();
|
|
|
|
needV = false;
|
|
|
|
goto eee;
|
|
|
|
}
|
|
|
|
if(abs(btm - eleBtm) < SnapSpace && eleBtm - grpRect.height() >= 0) {
|
|
|
|
dstVer = eleBtm - grpRect.height();
|
|
|
|
needV = false;
|
|
|
|
goto eee;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eee:
|
|
|
|
if(! needH && ! needV) break;
|
|
|
|
}
|
2023-08-21 11:21:00 +08:00
|
|
|
}
|
|
|
|
move(mPressRel.x() + dstHor, mPressRel.y() + dstVer);
|
|
|
|
mX = qRound(x() / box->rate);
|
|
|
|
mY = qRound(y() / box->rate);
|
2023-08-24 16:55:38 +08:00
|
|
|
for(auto sel : box->sels) {
|
2023-08-21 11:21:00 +08:00
|
|
|
if(sel->mPressRel.x()==INT_MIN) continue;
|
|
|
|
sel->move(sel->mPressRel.x() + x(), sel->mPressRel.y() + y());
|
|
|
|
sel->mX = qRound(sel->x() / box->rate);
|
|
|
|
sel->mY = qRound(sel->y() / box->rate);
|
|
|
|
}
|
|
|
|
box->fitSize();
|
2023-04-18 18:21:34 +08:00
|
|
|
}
|