qt/ledset/expertboxlayoutwin.cpp
2023-08-24 16:55:38 +08:00

704 lines
26 KiB
C++

#include "expertboxlayoutwin.h"
#include "expertwin.h"
#include "gutil/qgui.h"
#include "gutil/qjson.h"
#include "globalfunc.h"
#include <QPushButton>
#include <QCheckBox>
#include <QMessageBox>
#include <QScrollArea>
#include <QFileDialog>
#include <QPainter>
#include <QMouseEvent>
#include <QToolButton>
#include <QPainterPath>
#include <QGroupBox>
ExpertBoxLayoutWin::ExpertBoxLayoutWin(ExpertWin *parent) : BaseWin{parent} {
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle("箱体高级布局");
resize(1024, 720);
setStyleSheet("QToolButton {border: none; }");
auto vBox = new VBox(center);
vBox->setContentsMargins(0,0,0,0);
vBox->setSpacing(3);
vBox->addLayout(addBtns(new QHBoxLayout));
auto hBox = new HBox(vBox);
vBox = new VBox(hBox);
auto gBox = new QGroupBox("模组编辑");
vBox->addWidget(gBox);
auto grid = new Grid(gBox);
auto btnAdd = new QPushButton("添加");
connect(btnAdd, &QPushButton::clicked, this, [=] {
auto file = QFileDialog::getOpenFileName(this, tr("打开单元板文件"), gFileHome, tr("单元板文件 (*.module)"));
if(file.isEmpty()) return;
gFileHome = QFileInfo(file).absolutePath();
QFile qFile(file);
if(! qFile.open(QFile::ReadOnly)) {
QMessageBox::critical(this, tr("打开单元板文件失败"), file);
return;
}
QString err;
auto json = JFrom(&qFile, &err);
qFile.close();
if(! err.isEmpty()) {
QMessageBox::critical(this, tr("解析 json 失败"), err+" "+file);
return;
}
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();
});
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);
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);
vBox->addSpacing(10);
gBox = new QGroupBox("数据组数设置");
vBox->addWidget(gBox);
auto hh = new HBox(gBox);
hh->addLabel("组数:");
auto fdGNum = new QSpinBox;
fdGNum->setRange(1, 128);
fdGNum->setValue(16);
hh->addWidget(fdGNum);
auto btnSet = new QPushButton("设置");
hh->addWidget(btnSet);
grid = new Grid(vBox);
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();
vBox->addSpacing(10);
gBox = new QGroupBox("显示");
vBox->addWidget(gBox);
grid = new Grid(gBox);
fdHasPos = new QCheckBox("位置");
fdHasPos->setChecked(true);
grid->addWidget(fdHasPos, 0, 0);
fdHasSize = new QCheckBox("大小");
fdHasSize->setChecked(true);
grid->addWidget(fdHasSize, 0, 1);
fdHasConn = new QCheckBox("连接");
fdHasConn->setChecked(true);
grid->addWidget(fdHasConn, 1, 0);
fdHasName = new QCheckBox("名称");
fdHasName->setChecked(true);
grid->addWidget(fdHasName, 1, 1);
fdHasOutline = new QCheckBox("轮廓");
fdHasOutline->setChecked(true);
grid->addWidget(fdHasOutline, 2, 0);
fdSnap = new QCheckBox("吸附");
fdSnap->setChecked(true);
grid->addWidget(fdSnap, 2, 1);
vBox->addSpacing(10);
gBox = new QGroupBox("对齐");
vBox->addWidget(gBox);
hh = new HBox(gBox);
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);
gBox = new QGroupBox("排列");
vBox->addWidget(gBox);
hh = new HBox(gBox);
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);
vBox->addStretch();
vBox = new VBox(hBox);
hBox = new HBox(vBox);
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();
hBox->addStretch();
auto scroll = new QScrollArea;
vBox->addWidget(scroll);
box = new BoxPanel(this);
scroll->setWidget(box);
box->resize(1024, 1024);
box->setAutoFillBackground(true);
auto pal = palette();
pal.setColor(QPalette::Window, QColor(0x222222));
box->setPalette(pal);
SetCurText(fdRoom, "400%");
connect(btnDel, &QPushButton::clicked, box, &BoxPanel::del);
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();
}
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();
}
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);
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);
}
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();
mods.append(QVariant::fromValue((void*)this));
btn->setProperty("mods", mods);
name = "G"+QString::number(box->boxWin->grpGrp->id(btn)+1)+"-"+QString::number(mods.size());
for(auto child : box->children()) ((ModuleUnit*)child)->isSel = false;
isSel = true;
box->update();
}
void ModuleUnit::mousePressEvent(QMouseEvent *event) {
QWidget::mousePressEvent(event);
if(event->button() != Qt::LeftButton) return;
event->accept();
if(box->isDrawing) return;
if(event->modifiers() & Qt::ControlModifier) return;
setCursor(Qt::SizeAllCursor);
auto glbPos = event->globalPos();
box->grpRect = geometry();
if(isSel) {
box->sels.clear();
ModuleUnit* mod;
for(auto child : box->children()) if(child!=this && (mod = (ModuleUnit*)child)->isSel) {
mod->mPressRel = mod->pos() - pos();
box->grpRect |= mod->geometry();
box->sels.emplace_back(mod);
}
}
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;
}
if(event->modifiers() & Qt::ControlModifier) {
isSel = true;
update();
return;
}
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();
}
}
for(auto sel : box->sels) sel->mPressRel.setX(INT_MIN);
box->sels.clear();
}
#define SnapSpace 12
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;
ModuleUnit* mod;
if(! isSel) {
isSel = true;
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;
}
}
move(mPressRel.x() + dstHor, mPressRel.y() + dstVer);
mX = qRound(x() / box->rate);
mY = qRound(y() / box->rate);
for(auto sel : box->sels) {
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();
}