9#include <QtDesigner/abstractformeditor.h>
10#include <QtDesigner/qextensionmanager.h>
13#include <qdesigner_command_p.h>
14#include <qdesigner_propertycommand_p.h>
16#include <layoutinfo_p.h>
17#include <formwindowbase_p.h>
20#include <QtWidgets/qmenu.h>
21#include <QtWidgets/qwidget.h>
22#include <QtGui/qevent.h>
23#include <QtWidgets/qstylepainter.h>
24#include <QtWidgets/qgridlayout.h>
25#include <QtWidgets/qformlayout.h>
26#include <QtWidgets/qstyleoption.h>
27#include <QtWidgets/qapplication.h>
29#include <QtCore/qvariant.h>
30#include <QtCore/qdebug.h>
36using namespace Qt::StringLiterals;
42template <
class Layout>
45 const Layout * =
nullptr)
47 if (
QWidget *p = w->parentWidget())
48 if (QLayout *l = LayoutInfo::managedLayout(core, p))
49 return qobject_cast<Layout*>(l);
58 m_formWindow( parent),
62 setMouseTracking(
false);
63 setAutoFillBackground(
true);
65 setBackgroundRole(m_active ? QPalette::Text : QPalette::Dark);
75 setCursor(Qt::ArrowCursor);
81 setCursor(Qt::SizeFDiagCursor);
84 setCursor(Qt::SizeVerCursor);
87 setCursor(Qt::SizeBDiagCursor);
90 setCursor(Qt::SizeHorCursor);
93 setCursor(Qt::SizeFDiagCursor);
96 setCursor(Qt::SizeVerCursor);
99 setCursor(Qt::SizeBDiagCursor);
102 setCursor(Qt::SizeHorCursor);
121 setBackgroundRole(m_active ? QPalette::Text : QPalette::Dark);
132 QDesignerFormWindowManagerInterface *m = m_formWindow->core()->formWindowManager();
134 QStylePainter p(
this);
135 if (m_formWindow->currentWidget() == m_widget) {
136 p.setPen(m->activeFormWindow() == m_formWindow ? Qt::blue : Qt::red);
137 p.drawRect(0, 0, width() - 1, height() - 1);
145 if (!m_formWindow->hasFeature(FormWindow::EditFeature))
148 if (!(m_widget && e->button() == Qt::LeftButton))
154 QWidget *container = m_widget->parentWidget();
156 m_origPressPos = container->mapFromGlobal(e->globalPosition().toPoint());
157 m_geom = m_origGeom = m_widget->geometry();
159 switch (WidgetSelection::widgetState(m_formWindow->core(), m_widget)) {
160 case WidgetSelection::UnlaidOut:
161 case WidgetSelection::LaidOut:
162 m_formWindow->setHandleOperation(FormWindow::ResizeHandleOperation);
164 case WidgetSelection::ManagedGridLayout:
165 case WidgetSelection::ManagedFormLayout:
166 m_formWindow->setHandleOperation(FormWindow::ChangeLayoutSpanHandleOperation);
173 if (!(m_widget && m_active && e->buttons() & Qt::LeftButton))
178 QWidget *container = m_widget->parentWidget();
180 const QPoint rp = container->mapFromGlobal(e->globalPosition().toPoint());
181 const QPoint d = rp - m_origPressPos;
183 const QRect pr = container->rect();
187 grid = fwb->designerGrid();
192 if (rp.x() > pr.width() - 2 * width() || rp.y() > pr.height() - 2 * height())
195 int w = m_origGeom.width() - d.x();
197 w = grid.widgetHandleAdjustX(w);
199 int h = m_origGeom.height() - d.y();
201 h = grid.widgetHandleAdjustY(h);
203 const int dx = m_widget->width() - w;
204 const int dy = m_widget->height() - h;
206 trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y() + dy, w, h);
210 if (rp.y() > pr.height() - 2 * height())
213 int h = m_origGeom.height() - d.y();
215 h = grid.widgetHandleAdjustY(h);
217 const int dy = m_widget->height() - h;
218 trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, m_widget->width(), h);
222 if (rp.x() < 2 * width() || rp.y() > pr.height() - 2 * height())
225 int h = m_origGeom.height() - d.y();
227 h = grid.widgetHandleAdjustY(h);
229 const int dy = m_widget->height() - h;
231 int w = m_origGeom.width() + d.x();
233 w = grid.widgetHandleAdjustX(w);
235 trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, w, h);
239 if (rp.x() < 2 * width())
242 int w = m_origGeom.width() + d.x();
244 w = grid.widgetHandleAdjustX(w);
246 tryResize(m_widget, w, m_widget->height());
250 if (rp.x() < 2 * width() || rp.y() < 2 * height())
253 int w = m_origGeom.width() + d.x();
255 w = grid.widgetHandleAdjustX(w);
257 int h = m_origGeom.height() + d.y();
259 h = grid.widgetHandleAdjustY(h);
261 tryResize(m_widget, w, h);
265 if (rp.y() < 2 * height())
268 int h = m_origGeom.height() + d.y();
270 h = grid.widgetHandleAdjustY(h);
272 tryResize(m_widget, m_widget->width(), h);
276 if (rp.x() > pr.width() - 2 * width() || rp.y() < 2 * height())
279 int w = m_origGeom.width() - d.x();
281 w = grid.widgetHandleAdjustX(w);
283 int h = m_origGeom.height() + d.y();
285 h = grid.widgetHandleAdjustY(h);
287 int dx = m_widget->width() - w;
289 trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, h);
293 if (rp.x() > pr.width() - 2 * width())
296 int w = m_origGeom.width() - d.x();
298 w = grid.widgetHandleAdjustX(w);
300 const int dx = m_widget->width() - w;
302 trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, m_widget->height());
311 if (LayoutInfo::layoutType(m_formWindow->core(), m_widget) != LayoutInfo::NoLayout)
312 m_formWindow->updateChildSelections(m_widget);
317 m_formWindow->setHandleOperation(FormWindow::NoHandleOperation);
319 if (e->button() != Qt::LeftButton || !m_active)
324 if (!m_formWindow->hasFeature(FormWindow::EditFeature))
327 switch (WidgetSelection::widgetState(m_formWindow->core(), m_widget)) {
329 if (m_geom != m_widget->geometry()) {
330 SetPropertyCommand *cmd =
new SetPropertyCommand(m_formWindow);
331 cmd->init(m_widget, u"geometry"_s, m_widget->geometry());
332 cmd->setOldValue(m_origGeom);
333 m_formWindow->commandHistory()->push(cmd);
340 changeGridLayoutItemSpan();
343 changeFormLayoutItemSpan();
352 if (possibleOperations & ChangeFormLayoutItemRoleCommand::FieldToSpanning)
353 return ChangeFormLayoutItemRoleCommand::FieldToSpanning;
356 if (possibleOperations & ChangeFormLayoutItemRoleCommand::SpanningToField)
357 return ChangeFormLayoutItemRoleCommand::SpanningToField;
364 if (possibleOperations & ChangeFormLayoutItemRoleCommand::SpanningToLabel)
365 return ChangeFormLayoutItemRoleCommand::SpanningToLabel;
368 if (possibleOperations & ChangeFormLayoutItemRoleCommand::LabelToSpanning)
369 return ChangeFormLayoutItemRoleCommand::LabelToSpanning;
376 QUndoCommand *cmd =
nullptr;
378 const int dx = m_widget->geometry().center().x() - m_origGeom.center().x();
379 if (qAbs(dx) >= QApplication::startDragDistance()) {
381 if (
const unsigned possibleOperations = ChangeFormLayoutItemRoleCommand::possibleOperations(m_formWindow->core(), m_widget)) {
383 case WidgetHandle::Left:
386 case WidgetHandle::Right:
393 ChangeFormLayoutItemRoleCommand *fcmd =
new ChangeFormLayoutItemRoleCommand(m_formWindow);
394 fcmd->init(m_widget,
static_cast<ChangeFormLayoutItemRoleCommand::Operation>(operation));
400 m_formWindow->commandHistory()->push(cmd);
403 if (QFormLayout *form = managedLayoutOf<QFormLayout>(m_formWindow->core(), m_widget)) {
407 m_formWindow->selectWidget(m_widget);
414 QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core()->extensionManager(), m_widget->parentWidget());
417 QGridLayout *grid = managedLayoutOf<QGridLayout>(m_formWindow->core(), m_widget);
421 const int index = deco->indexOf(m_widget);
422 const QRect info = deco->itemInfo(index);
423 const int top = deco->findItemAt(info.top() - 1, info.left());
424 const int left = deco->findItemAt(info.top(), info.left() - 1);
425 const int bottom = deco->findItemAt(info.bottom() + 1, info.left());
426 const int right = deco->findItemAt(info.top(), info.right() + 1);
428 const QPoint pt = m_origGeom.center() - m_widget->geometry().center();
430 ChangeLayoutItemGeometry *cmd =
nullptr;
436 case WidgetHandle::Top: {
437 if (pt.y() < 0 && info.height() > 1) {
438 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
439 cmd->init(m_widget, info.y() + 1, info.x(), info.height() - 1, info.width());
440 }
else if (pt.y() > 0 && top != -1 && grid->itemAt(top)->spacerItem()) {
441 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
442 cmd->init(m_widget, info.y() - 1, info.x(), info.height() + 1, info.width());
447 case WidgetHandle::Left: {
448 if (pt.x() < 0 && info.width() > 1) {
449 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
450 cmd->init(m_widget, info.y(), info.x() + 1, info.height(), info.width() - 1);
451 }
else if (pt.x() > 0 && left != -1 && grid->itemAt(left)->spacerItem()) {
452 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
453 cmd->init(m_widget, info.y(), info.x() - 1, info.height(), info.width() + 1);
458 case WidgetHandle::Right: {
459 if (pt.x() > 0 && info.width() > 1) {
460 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
461 cmd->init(m_widget, info.y(), info.x(), info.height(), info.width() - 1);
462 }
else if (pt.x() < 0 && right != -1 && grid->itemAt(right)->spacerItem()) {
463 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
464 cmd->init(m_widget, info.y(), info.x(), info.height(), info.width() + 1);
469 case WidgetHandle::Bottom: {
470 if (pt.y() > 0 && info.height() > 1) {
471 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
472 cmd->init(m_widget, info.y(), info.x(), info.height() - 1, info.width());
473 }
else if (pt.y() < 0 && bottom != -1 && grid->itemAt(bottom)->spacerItem()) {
474 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
475 cmd->init(m_widget, info.y(), info.x(), info.height() + 1, info.width());
481 if (cmd !=
nullptr) {
482 m_formWindow->commandHistory()->push(cmd);
487 m_formWindow->selectWidget(m_widget);
493 if (!m_formWindow->hasFeature(FormWindow::EditFeature))
496 int minw = w->minimumSize().width();
497 minw = qMax(minw, 2 * m_formWindow->grid().x());
499 int minh = w->minimumSize().height();
500 minh = qMax(minh, 2 * m_formWindow->grid().y());
502 if (qMax(minw, width) > w->maximumWidth() ||
503 qMax(minh, height) > w->maximumHeight())
506 if (width < minw && x != w->x())
509 if (height < minh && y != w->y())
512 w->setGeometry(x, y, qMax(minw, width), qMax(minh, height));
517 int minw = w->minimumSize().width();
518 minw = qMax(minw, 16);
520 int minh = w->minimumSize().height();
521 minh = qMax(minh, 16);
523 w->resize(qMax(minw, width), qMax(minh, height));
531 const LayoutInfo::Type lt = LayoutInfo::laidoutWidgetType(core, w, &isManaged);
532 if (lt == LayoutInfo::NoLayout)
537 case LayoutInfo::Grid:
539 case LayoutInfo::Form:
551 for (
int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
552 m_handles[i] =
new WidgetHandle(m_formWindow,
static_cast<WidgetHandle::Type>(i),
this);
558 if (m_widget !=
nullptr)
559 m_widget->removeEventFilter(
this);
569 m_widget->installEventFilter(
this);
579 const WidgetState ws = widgetState(m_formWindow->core(), m_widget);
580 bool active[WidgetHandle::TypeCount];
581 std::fill(active, active + WidgetHandle::TypeCount,
false);
585 std::fill(active, active + WidgetHandle::TypeCount,
true);
587 case ManagedGridLayout:
588 active[WidgetHandle::Left] = active[WidgetHandle::Top] = active[WidgetHandle::Right] = active[WidgetHandle::Bottom] =
true;
591 if (
const unsigned operation = ChangeFormLayoutItemRoleCommand::possibleOperations(m_formWindow->core(), m_widget)) {
592 active[WidgetHandle::Left] = operation & (ChangeFormLayoutItemRoleCommand::SpanningToField|ChangeFormLayoutItemRoleCommand::FieldToSpanning);
593 active[WidgetHandle::Right] = operation & (ChangeFormLayoutItemRoleCommand::SpanningToLabel|ChangeFormLayoutItemRoleCommand::LabelToSpanning);
600 for (
int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
602 h->setWidget(m_widget);
609 return m_widget !=
nullptr;
614 if (!m_widget || !m_widget->parentWidget())
617 QPoint p = m_widget->parentWidget()->mapToGlobal(m_widget->pos());
619 const QRect r(p, m_widget->size());
624 for (
int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) {
629 case WidgetHandle::LeftTop:
630 hndl->move(r.x() - w / 2, r.y() - h / 2);
632 case WidgetHandle::Top:
633 hndl->move(r.x() + r.width() / 2 - w / 2, r.y() - h / 2);
635 case WidgetHandle::RightTop:
636 hndl->move(r.x() + r.width() - w / 2, r.y() - h / 2);
638 case WidgetHandle::Right:
639 hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() / 2 - h / 2);
641 case WidgetHandle::RightBottom:
642 hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() - h / 2);
644 case WidgetHandle::Bottom:
645 hndl->move(r.x() + r.width() / 2 - w / 2, r.y() + r.height() - h / 2);
647 case WidgetHandle::LeftBottom:
648 hndl->move(r.x() - w / 2, r.y() + r.height() - h / 2);
650 case WidgetHandle::Left:
651 hndl->move(r.x() - w / 2, r.y() + r.height() / 2 - h / 2);
661 for (WidgetHandle *h : m_handles) {
669 for (WidgetHandle *h : m_handles) {
679 for (WidgetHandle *h : m_handles) {
700 if (object != widget())
703 switch (event->type()) {
710 case QEvent::ZOrderChange:
Auxiliary methods to store/retrieve settings.
static int formLayoutRightHandleOperation(int dx, unsigned possibleOperations)
static int formLayoutLeftHandleOperation(int dx, unsigned possibleOperations)
static Layout * managedLayoutOf(const QDesignerFormEditorInterface *core, QWidget *w, const Layout *=nullptr)