#include "expertboxlayoutwin.h" #include "expertwin.h" #include "gutil/qgui.h" #include "gutil/qjson.h" #include "globalfunc.h" #include #include #include #include #include #include #include #include #include #include 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())->isSel) { btn->setProperty("mods", QVariant()); for(auto mod : mods) ((ModuleUnit*) mod.value())->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; isetCheckable(true); btn->setMaximumWidth(40); btn->setFixedHeight(24); grpGrp->addButton(btn, i); grid->addWidget(btn, i / 4, i % 4); } else if(newCnt=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 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 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 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 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(); childisSel) { 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(); modvalue() == *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; xxx(), 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{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())->geometry().center(); for(int mm=1; mm())->geometry().center(); painter.drawLine(last, pos); auto deg = 180 / 3.1415926535 * atan((pos.y()-last.y()) / (pos.x()-last.x())); if(pos.x()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(); if(! mods.isEmpty() && ((ExpertWin*)box->boxWin->parentWidget())->m_iRcvCardType==enum_zrf) { auto last = (ModuleUnit*) mods.last().value(); if(last->mY!=mY || last->mX+last->mW!=mX) { QMessageBox::warning(this, "注意", "模组要紧跟着前一个"); return; } } 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(); }