10#include <QtDesigner/abstractformeditor.h>
11#include <QtDesigner/qextensionmanager.h>
14#include <qdesigner_command_p.h>
15#include <qdesigner_propertycommand_p.h>
17#include <layoutinfo_p.h>
18#include <formwindowbase_p.h>
21#include <QtWidgets/qmenu.h>
22#include <QtWidgets/qwidget.h>
23#include <QtGui/qevent.h>
24#include <QtWidgets/qstylepainter.h>
25#include <QtWidgets/qgridlayout.h>
26#include <QtWidgets/qformlayout.h>
27#include <QtWidgets/qstyleoption.h>
28#include <QtWidgets/qapplication.h>
30#include <QtCore/qvariant.h>
31#include <QtCore/qdebug.h>
37using namespace Qt::StringLiterals;
43template <
class Layout>
46 const Layout * =
nullptr)
48 if (
QWidget *p = w->parentWidget())
49 if (QLayout *l = LayoutInfo::managedLayout(core, p))
50 return qobject_cast<Layout*>(l);
59 m_formWindow( parent),
63 setMouseTracking(
false);
64 setAutoFillBackground(
true);
66 setBackgroundRole(m_active ? QPalette::Text : QPalette::Dark);
76 setCursor(Qt::ArrowCursor);
82 setCursor(Qt::SizeFDiagCursor);
85 setCursor(Qt::SizeVerCursor);
88 setCursor(Qt::SizeBDiagCursor);
91 setCursor(Qt::SizeHorCursor);
94 setCursor(Qt::SizeFDiagCursor);
97 setCursor(Qt::SizeVerCursor);
100 setCursor(Qt::SizeBDiagCursor);
103 setCursor(Qt::SizeHorCursor);
122 setBackgroundRole(m_active ? QPalette::Text : QPalette::Dark);
133 QDesignerFormWindowManagerInterface *m = m_formWindow
->core()->formWindowManager();
135 QStylePainter p(
this);
136 if (m_formWindow->currentWidget() == m_widget) {
137 p.setPen(m->activeFormWindow() == m_formWindow ? Qt::blue : Qt::red);
138 p.drawRect(0, 0, width() - 1, height() - 1);
146 if (!m_formWindow->hasFeature(FormWindow::EditFeature))
149 if (!(m_widget && e->button() == Qt::LeftButton))
155 QWidget *container = m_widget->parentWidget();
157 m_origPressPos = container->mapFromGlobal(e->globalPosition().toPoint());
158 m_geom = m_origGeom = m_widget->geometry();
160 switch (WidgetSelection::widgetState(m_formWindow
->core(), m_widget)) {
163 m_formWindow->setHandleOperation(FormWindow::ResizeHandleOperation);
167 m_formWindow->setHandleOperation(FormWindow::ChangeLayoutSpanHandleOperation);
174 if (!(m_widget && m_active && e->buttons() & Qt::LeftButton))
179 QWidget *container = m_widget->parentWidget();
181 const QPoint rp = container->mapFromGlobal(e->globalPosition().toPoint());
182 const QPoint d = rp - m_origPressPos;
184 const QRect pr = container->rect();
188 grid = fwb->designerGrid();
193 if (rp.x() > pr.width() - 2 * width() || rp.y() > pr.height() - 2 * height())
196 int w = m_origGeom.width() - d.x();
198 w = grid.widgetHandleAdjustX(w);
200 int h = m_origGeom.height() - d.y();
202 h = grid.widgetHandleAdjustY(h);
204 const int dx = m_widget->width() - w;
205 const int dy = m_widget->height() - h;
207 trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y() + dy, w, h);
211 if (rp.y() > pr.height() - 2 * height())
214 int h = m_origGeom.height() - d.y();
216 h = grid.widgetHandleAdjustY(h);
218 const int dy = m_widget->height() - h;
219 trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, m_widget->width(), h);
223 if (rp.x() < 2 * width() || rp.y() > pr.height() - 2 * height())
226 int h = m_origGeom.height() - d.y();
228 h = grid.widgetHandleAdjustY(h);
230 const int dy = m_widget->height() - h;
232 int w = m_origGeom.width() + d.x();
234 w = grid.widgetHandleAdjustX(w);
236 trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, w, h);
240 if (rp.x() < 2 * width())
243 int w = m_origGeom.width() + d.x();
245 w = grid.widgetHandleAdjustX(w);
247 tryResize(m_widget, w, m_widget->height());
251 if (rp.x() < 2 * width() || rp.y() < 2 * height())
254 int w = m_origGeom.width() + d.x();
256 w = grid.widgetHandleAdjustX(w);
258 int h = m_origGeom.height() + d.y();
260 h = grid.widgetHandleAdjustY(h);
262 tryResize(m_widget, w, h);
266 if (rp.y() < 2 * height())
269 int h = m_origGeom.height() + d.y();
271 h = grid.widgetHandleAdjustY(h);
273 tryResize(m_widget, m_widget->width(), h);
277 if (rp.x() > pr.width() - 2 * width() || rp.y() < 2 * height())
280 int w = m_origGeom.width() - d.x();
282 w = grid.widgetHandleAdjustX(w);
284 int h = m_origGeom.height() + d.y();
286 h = grid.widgetHandleAdjustY(h);
288 int dx = m_widget->width() - w;
290 trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, h);
294 if (rp.x() > pr.width() - 2 * width())
297 int w = m_origGeom.width() - d.x();
299 w = grid.widgetHandleAdjustX(w);
301 const int dx = m_widget->width() - w;
303 trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, m_widget->height());
312 if (LayoutInfo::layoutType(m_formWindow->core(), m_widget) != LayoutInfo::NoLayout)
318 m_formWindow->setHandleOperation(FormWindow::NoHandleOperation);
320 if (e->button() != Qt::LeftButton || !m_active)
325 if (!m_formWindow->hasFeature(FormWindow::EditFeature))
328 switch (WidgetSelection::widgetState(m_formWindow
->core(), m_widget)) {
330 if (m_geom != m_widget->geometry()) {
331 SetPropertyCommand *cmd =
new SetPropertyCommand(m_formWindow);
332 cmd->init(m_widget, u"geometry"_s, m_widget->geometry());
333 cmd->setOldValue(m_origGeom);
334 m_formWindow->commandHistory()->push(cmd);
341 changeGridLayoutItemSpan();
344 changeFormLayoutItemSpan();
353 if (possibleOperations & ChangeFormLayoutItemRoleCommand::FieldToSpanning)
354 return ChangeFormLayoutItemRoleCommand::FieldToSpanning;
357 if (possibleOperations & ChangeFormLayoutItemRoleCommand::SpanningToField)
358 return ChangeFormLayoutItemRoleCommand::SpanningToField;
365 if (possibleOperations & ChangeFormLayoutItemRoleCommand::SpanningToLabel)
366 return ChangeFormLayoutItemRoleCommand::SpanningToLabel;
369 if (possibleOperations & ChangeFormLayoutItemRoleCommand::LabelToSpanning)
370 return ChangeFormLayoutItemRoleCommand::LabelToSpanning;
377 QUndoCommand *cmd =
nullptr;
379 const int dx = m_widget->geometry().center().x() - m_origGeom.center().x();
380 if (qAbs(dx) >= QApplication::startDragDistance()) {
382 if (
const unsigned possibleOperations = ChangeFormLayoutItemRoleCommand::possibleOperations(m_formWindow->core(), m_widget)) {
384 case WidgetHandle::Left:
387 case WidgetHandle::Right:
394 ChangeFormLayoutItemRoleCommand *fcmd =
new ChangeFormLayoutItemRoleCommand(m_formWindow);
395 fcmd->init(m_widget,
static_cast<ChangeFormLayoutItemRoleCommand::Operation>(operation));
401 m_formWindow->commandHistory()->push(cmd);
404 if (QFormLayout *form = managedLayoutOf<QFormLayout>(m_formWindow
->core(), m_widget)) {
415 QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core()->extensionManager(), m_widget->parentWidget());
418 QGridLayout *grid = managedLayoutOf<QGridLayout>(m_formWindow->core(), m_widget);
422 const int index = deco->indexOf(m_widget);
423 const QRect info = deco->itemInfo(index);
424 const int top = deco->findItemAt(info.top() - 1, info.left());
425 const int left = deco->findItemAt(info.top(), info.left() - 1);
426 const int bottom = deco->findItemAt(info.bottom() + 1, info.left());
427 const int right = deco->findItemAt(info.top(), info.right() + 1);
429 const QPoint pt = m_origGeom.center() - m_widget->geometry().center();
431 ChangeLayoutItemGeometry *cmd =
nullptr;
437 case WidgetHandle::Top: {
438 if (pt.y() < 0 && info.height() > 1) {
439 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
440 cmd->init(m_widget, info.y() + 1, info.x(), info.height() - 1, info.width());
441 }
else if (pt.y() > 0 && top != -1 && grid->itemAt(top)->spacerItem()) {
442 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
443 cmd->init(m_widget, info.y() - 1, info.x(), info.height() + 1, info.width());
448 case WidgetHandle::Left: {
449 if (pt.x() < 0 && info.width() > 1) {
450 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
451 cmd->init(m_widget, info.y(), info.x() + 1, info.height(), info.width() - 1);
452 }
else if (pt.x() > 0 && left != -1 && grid->itemAt(left)->spacerItem()) {
453 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
454 cmd->init(m_widget, info.y(), info.x() - 1, info.height(), info.width() + 1);
459 case WidgetHandle::Right: {
460 if (pt.x() > 0 && info.width() > 1) {
461 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
462 cmd->init(m_widget, info.y(), info.x(), info.height(), info.width() - 1);
463 }
else if (pt.x() < 0 && right != -1 && grid->itemAt(right)->spacerItem()) {
464 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
465 cmd->init(m_widget, info.y(), info.x(), info.height(), info.width() + 1);
470 case WidgetHandle::Bottom: {
471 if (pt.y() > 0 && info.height() > 1) {
472 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
473 cmd->init(m_widget, info.y(), info.x(), info.height() - 1, info.width());
474 }
else if (pt.y() < 0 && bottom != -1 && grid->itemAt(bottom)->spacerItem()) {
475 cmd =
new ChangeLayoutItemGeometry(m_formWindow);
476 cmd->init(m_widget, info.y(), info.x(), info.height() + 1, info.width());
482 if (cmd !=
nullptr) {
483 m_formWindow->commandHistory()->push(cmd);
494 if (!m_formWindow->hasFeature(FormWindow::EditFeature))
497 int minw = w->minimumSize().width();
498 minw = qMax(minw, 2 * m_formWindow->grid().x());
500 int minh = w->minimumSize().height();
501 minh = qMax(minh, 2 * m_formWindow->grid().y());
503 if (qMax(minw, width) > w->maximumWidth() ||
504 qMax(minh, height) > w->maximumHeight())
507 if (width < minw && x != w->x())
510 if (height < minh && y != w->y())
513 w->setGeometry(x, y, qMax(minw, width), qMax(minh, height));
518 int minw = w->minimumSize().width();
519 minw = qMax(minw, 16);
521 int minh = w->minimumSize().height();
522 minh = qMax(minh, 16);
524 w->resize(qMax(minw, width), qMax(minh, height));
532 const LayoutInfo::Type lt = LayoutInfo::laidoutWidgetType(core, w, &isManaged);
533 if (lt == LayoutInfo::NoLayout)
538 case LayoutInfo::Grid:
540 case LayoutInfo::Form:
552 for (
int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
553 m_handles[i] =
new WidgetHandle(m_formWindow,
static_cast<WidgetHandle::Type>(i),
this);
559 if (m_widget !=
nullptr)
560 m_widget->removeEventFilter(
this);
570 m_widget->installEventFilter(
this);
580 const WidgetState ws = widgetState(m_formWindow->core(), m_widget);
581 bool active[WidgetHandle::TypeCount];
582 std::fill(active, active + WidgetHandle::TypeCount,
false);
586 std::fill(active, active + WidgetHandle::TypeCount,
true);
588 case ManagedGridLayout:
589 active[WidgetHandle::Left] = active[WidgetHandle::Top] = active[WidgetHandle::Right] = active[WidgetHandle::Bottom] =
true;
592 if (
const unsigned operation = ChangeFormLayoutItemRoleCommand::possibleOperations(m_formWindow->core(), m_widget)) {
593 active[WidgetHandle::Left] = operation & (ChangeFormLayoutItemRoleCommand::SpanningToField|ChangeFormLayoutItemRoleCommand::FieldToSpanning);
594 active[WidgetHandle::Right] = operation & (ChangeFormLayoutItemRoleCommand::SpanningToLabel|ChangeFormLayoutItemRoleCommand::LabelToSpanning);
601 for (
int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i)
603 h->setWidget(m_widget);
610 return m_widget !=
nullptr;
615 if (!m_widget || !m_widget->parentWidget())
618 QPoint p = m_widget->parentWidget()->mapToGlobal(m_widget->pos());
620 const QRect r(p, m_widget->size());
625 for (
int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) {
630 case WidgetHandle::LeftTop:
631 hndl->move(r.x() - w / 2, r.y() - h / 2);
633 case WidgetHandle::Top:
634 hndl->move(r.x() + r.width() / 2 - w / 2, r.y() - h / 2);
636 case WidgetHandle::RightTop:
637 hndl->move(r.x() + r.width() - w / 2, r.y() - h / 2);
639 case WidgetHandle::Right:
640 hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() / 2 - h / 2);
642 case WidgetHandle::RightBottom:
643 hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() - h / 2);
645 case WidgetHandle::Bottom:
646 hndl->move(r.x() + r.width() / 2 - w / 2, r.y() + r.height() - h / 2);
648 case WidgetHandle::LeftBottom:
649 hndl->move(r.x() - w / 2, r.y() + r.height() - h / 2);
651 case WidgetHandle::Left:
652 hndl->move(r.x() - w / 2, r.y() + r.height() / 2 - h / 2);
662 for (WidgetHandle *h : m_handles) {
670 for (WidgetHandle *h : m_handles) {
680 for (WidgetHandle *h : m_handles) {
701 if (object != widget())
704 switch (event->type()) {
711 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)