File indexing completed on 2024-05-12 16:39:50

0001 /* This file is part of the KDE libraries
0002    Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
0003    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
0004    Copyright (C) 2009 Jarosław Staniek <staniek@kde.org>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License version 2 as published by the Free Software Foundation.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "resizehandle.h"
0022 #include "form.h"
0023 #include "container.h"
0024 #include "widgetfactory.h"
0025 #include "widgetlibrary.h"
0026 
0027 #include <QDebug>
0028 #include <QCursor>
0029 #include <QMouseEvent>
0030 #include <QPaintEvent>
0031 
0032 #define MINIMUM_WIDTH 10
0033 #define MINIMUM_HEIGHT 10
0034 
0035 using namespace KFormDesigner;
0036 
0037 namespace KFormDesigner {
0038 /**
0039 * A single widget which represents a small rectangle for resizing a form widget.
0040 */
0041 class KFORMDESIGNER_EXPORT ResizeHandle : public QWidget
0042 {
0043     Q_OBJECT
0044 public:
0045     enum HandlePos {
0046         TopLeftCorner = 1,
0047         TopCenter = 2,
0048         TopRightCorner = 4,
0049         LeftCenter = 8,
0050         RightCenter = 16,
0051         BottomLeftCorner = 32,
0052         BottomCenter = 64,
0053         BottomRightCorner = 128
0054     };
0055 
0056     ResizeHandle(ResizeHandleSet *set, HandlePos pos);
0057 
0058     virtual ~ResizeHandle();
0059 
0060     void setEditingMode(bool editing);
0061 
0062 protected:
0063     virtual void mousePressEvent(QMouseEvent *ev) override;
0064     virtual void mouseMoveEvent(QMouseEvent *ev) override;
0065     virtual void mouseReleaseEvent(QMouseEvent *ev) override;
0066     virtual void paintEvent(QPaintEvent *ev) override;
0067 
0068 protected Q_SLOTS:
0069     bool eventFilter(QObject *obj, QEvent *ev) override;
0070     void updatePos();
0071 
0072 private:
0073     class Private;
0074     Private* const d;
0075 };
0076 
0077 class Q_DECL_HIDDEN ResizeHandle::Private
0078 {
0079 public:
0080     Private(ResizeHandleSet* set_, HandlePos pos_)
0081         : set(set_), pos(pos_), dragging(false), x(0), y(0)
0082     {}
0083     ~Private() {}
0084 
0085     ResizeHandleSet *set;
0086     HandlePos pos;
0087     bool dragging;
0088     int x;
0089     int y;
0090 };
0091 }
0092 
0093 ResizeHandle::ResizeHandle(ResizeHandleSet *set, HandlePos pos)
0094     : QWidget(set->widget()->parentWidget()), d(new Private(set, pos))
0095 {
0096     setFixedSize(6, 6);
0097     d->set->widget()->installEventFilter(this);
0098     setAutoFillBackground(true);
0099     updatePos();
0100     setEditingMode(false);
0101     show();
0102 }
0103 
0104 ResizeHandle::~ResizeHandle()
0105 {
0106     delete d;
0107 }
0108 
0109 void ResizeHandle::setEditingMode(bool editing)
0110 {
0111     QPalette pal(palette());
0112     pal.setBrush(backgroundRole(), editing ? QBrush(Qt::blue) : pal.text());
0113     setPalette(pal);
0114 }
0115 
0116 void ResizeHandle::updatePos()
0117 {
0118     switch (d->pos) {
0119     case TopLeftCorner:
0120         move(d->set->widget()->x() - 3, d->set->widget()->y() - 3);
0121         setCursor(QCursor(Qt::SizeFDiagCursor));
0122         break;
0123     case TopCenter:
0124         move(d->set->widget()->x() + d->set->widget()->width() / 2 - 3, d->set->widget()->y() - 3);
0125         setCursor(QCursor(Qt::SizeVerCursor));
0126         break;
0127     case TopRightCorner:
0128         move(d->set->widget()->x() + d->set->widget()->width() - 3, d->set->widget()->y() - 3);
0129         setCursor(QCursor(Qt::SizeBDiagCursor));
0130         break;
0131     case LeftCenter:
0132         move(d->set->widget()->x() - 3, d->set->widget()->y() + d->set->widget()->height() / 2 - 3);
0133         setCursor(QCursor(Qt::SizeHorCursor));
0134         break;
0135     case RightCenter:
0136         move(d->set->widget()->x() + d->set->widget()->width() - 3, d->set->widget()->y() + d->set->widget()->height() / 2 - 3);
0137         setCursor(QCursor(Qt::SizeHorCursor));
0138         break;
0139     case BottomLeftCorner:
0140         move(d->set->widget()->x() - 3, d->set->widget()->y() + d->set->widget()->height() - 3);
0141         setCursor(QCursor(Qt::SizeBDiagCursor));
0142         break;
0143     case BottomCenter:
0144         move(d->set->widget()->x() + d->set->widget()->width() / 2 - 3, d->set->widget()->y() + d->set->widget()->height() - 3);
0145         setCursor(QCursor(Qt::SizeVerCursor));
0146         break;
0147     case BottomRightCorner:
0148         move(d->set->widget()->x() + d->set->widget()->width() - 3, d->set->widget()->y() + d->set->widget()->height() - 3);
0149         setCursor(QCursor(Qt::SizeFDiagCursor));
0150         break;
0151     }
0152 }
0153 
0154 bool ResizeHandle::eventFilter(QObject *o, QEvent *ev)
0155 {
0156     if (((ev->type() == QEvent::Move) || (ev->type() == QEvent::Resize)) && o == d->set->widget()) {
0157         updatePos();
0158     }
0159     return false;
0160 }
0161 
0162 void ResizeHandle::mousePressEvent(QMouseEvent *ev)
0163 {
0164     if (ev->button() != Qt::LeftButton)
0165         return;
0166 
0167     const bool startDragging = !d->dragging;
0168     d->dragging = true;
0169     d->x = ev->x();
0170     d->y = ev->y();
0171     if (startDragging) {
0172         d->set->resizeStarted();
0173         d->set->form()->resetInlineEditor();
0174         emit d->set->geometryChangeStarted();
0175     }
0176 }
0177 
0178 void ResizeHandle::mouseMoveEvent(QMouseEvent *ev)
0179 {
0180     int gridX = d->set->form()->gridSize();
0181     int gridY = d->set->form()->gridSize();
0182 
0183     if (!d->dragging)
0184         return;
0185 
0186     int tmpx = d->set->widget()->x();
0187     int tmpy = d->set->widget()->y();
0188     int tmpw = d->set->widget()->width();
0189     int tmph = d->set->widget()->height();
0190 
0191     int dummyx = ev->x() - d->x;
0192     int dummyy = ev->y() - d->y;
0193 
0194     if (   d->set->form()->isSnapToGridEnabled() && ev->buttons() == Qt::LeftButton
0195         && ev->modifiers() != (Qt::ControlModifier | Qt::AltModifier))
0196     {
0197         dummyx = alignValueToGrid(dummyx, gridX);
0198         dummyy = alignValueToGrid(dummyy, gridY);
0199     }
0200 
0201     switch (d->pos) {
0202     case TopRightCorner:
0203         tmpw += dummyx;
0204         tmpy += dummyy;
0205         tmph -= dummyy;
0206         break;
0207     case RightCenter:
0208         tmpw += dummyx;
0209         break;
0210     case BottomRightCorner:
0211         tmpw += dummyx;
0212         tmph += dummyy;
0213         break;
0214     case TopCenter:
0215         tmpy += dummyy;
0216         tmph -= dummyy;
0217         break;
0218     case BottomCenter:
0219         tmph = tmph + dummyy;
0220         break;
0221     case TopLeftCorner:
0222         tmpx += dummyx;
0223         tmpw -= dummyx;
0224         tmpy += dummyy;
0225         tmph -= dummyy;
0226         break;
0227     case LeftCenter:
0228         tmpx += dummyx;
0229         tmpw -= dummyx;
0230         break;
0231     case BottomLeftCorner:
0232         tmpx += dummyx;
0233         tmpw -= dummyx;
0234         tmph += dummyy;
0235         break;
0236     }
0237 
0238     // Do not move the top-left corner further than the bottom-right corner
0239     if (tmpx >= d->set->widget()->x() + d->set->widget()->width()) {
0240         tmpx = d->set->widget()->x() + d->set->widget()->width() - MINIMUM_WIDTH;
0241         tmpw = MINIMUM_WIDTH;
0242     }
0243 
0244     if (tmpy >= d->set->widget()->y() + d->set->widget()->height()) {
0245         tmpy = d->set->widget()->y() + d->set->widget()->height() - MINIMUM_HEIGHT;
0246         tmph = MINIMUM_HEIGHT;
0247     }
0248 
0249     // Do not resize a widget outside of parent boundaries
0250     if (tmpx < 0) {
0251         tmpw += tmpx;
0252         tmpx = 0;
0253     } else if (tmpx + tmpw > d->set->widget()->parentWidget()->width()) {
0254         tmpw = d->set->widget()->parentWidget()->width() - tmpx;
0255     }
0256 
0257     if (tmpy < 0) {
0258         tmph += tmpy;
0259         tmpy = 0;
0260     } else if (tmpy + tmph > d->set->widget()->parentWidget()->height()) {
0261         tmph = d->set->widget()->parentWidget()->height() - tmpy;
0262     }
0263 
0264     const bool shouldBeMoved = (tmpx != d->set->widget()->x()) || (tmpy != d->set->widget()->y());
0265     const bool shouldBeResized = (tmpw != d->set->widget()->width()) || (tmph != d->set->widget()->height());
0266 
0267     if (shouldBeMoved && shouldBeResized) {
0268         d->set->widget()->hide();
0269     }
0270 
0271     // Resize it
0272     if (shouldBeResized) {
0273         // Keep a QSize(10, 10) minimum size
0274         tmpw = (tmpw < MINIMUM_WIDTH) ? MINIMUM_WIDTH : tmpw;
0275         tmph = (tmph < MINIMUM_HEIGHT) ? MINIMUM_HEIGHT : tmph;
0276     }
0277 
0278     //qDebug() << "geometry: OLD" << d->set->widget()->geometry() << "NEW" << QRect(tmpx, tmpy, tmpw, tmph);
0279     emit d->set->geometryChanged(QRect(tmpx, tmpy, tmpw, tmph));
0280 
0281     if (shouldBeMoved && shouldBeResized) {
0282         d->set->widget()->show();
0283     }
0284 }
0285 
0286 void ResizeHandle::mouseReleaseEvent(QMouseEvent *)
0287 {
0288     d->dragging = false;
0289     d->set->resizeFinished();
0290 }
0291 
0292 void ResizeHandle::paintEvent(QPaintEvent *)
0293 {
0294 }
0295 
0296 /////////////// ResizeHandleSet //////////////////
0297 
0298 class Q_DECL_HIDDEN ResizeHandleSet::Private
0299 {
0300 public:
0301     Private();
0302     ~Private() {}
0303 
0304     QRect origWidgetRect;
0305     QPointer<ResizeHandle> handles[8];
0306     QPointer<QWidget> widget;
0307     QPointer<Form>   form;
0308 };
0309 
0310 ResizeHandleSet::Private::Private() : widget(0)
0311 {
0312 }
0313 
0314 ResizeHandleSet::ResizeHandleSet(QWidget *modify, Form *form)
0315     : QObject(modify->parentWidget()), d(new Private)
0316 {
0317     d->form = form;
0318     setWidget(modify);
0319 }
0320 
0321 ResizeHandleSet::~ResizeHandleSet()
0322 {
0323     for (int i = 0; i < 8; i++)
0324         delete d->handles[i];
0325     delete d;
0326 }
0327 
0328 void
0329 ResizeHandleSet::setWidget(QWidget *modify)
0330 {
0331     if (modify == d->widget)
0332         return;
0333 
0334     if (d->widget) {
0335         for (int i = 0; i < 8; i++)
0336             delete d->handles[i];
0337     }
0338 
0339     d->widget = modify;
0340 
0341     d->handles[0] = new ResizeHandle(this, ResizeHandle::TopLeftCorner);
0342     d->handles[1] = new ResizeHandle(this, ResizeHandle::TopCenter);
0343     d->handles[2] = new ResizeHandle(this, ResizeHandle::TopRightCorner);
0344     d->handles[3] = new ResizeHandle(this, ResizeHandle::LeftCenter);
0345     d->handles[4] = new ResizeHandle(this, ResizeHandle::RightCenter);
0346     d->handles[5] = new ResizeHandle(this, ResizeHandle::BottomLeftCorner);
0347     d->handles[6] = new ResizeHandle(this, ResizeHandle::BottomCenter);
0348     d->handles[7] = new ResizeHandle(this, ResizeHandle::BottomRightCorner);
0349 }
0350 
0351 void
0352 ResizeHandleSet::raise()
0353 {
0354     for (int i = 0; i < 8; i++)
0355         d->handles[i]->raise();
0356 }
0357 
0358 void ResizeHandleSet::setEditingMode(bool editing)
0359 {
0360     for (int i = 0; i < 8; i++)
0361         d->handles[i]->setEditingMode(editing);
0362 }
0363 
0364 void ResizeHandleSet::resizeStarted()
0365 {
0366     d->origWidgetRect = d->widget->geometry();
0367 }
0368 
0369 void ResizeHandleSet::resizeFinished()
0370 {
0371     if (d->widget) {
0372         //qDebug() << "old:" << d->origWidgetRect << "new:" << d->widget->geometry();
0373     }
0374 }
0375 
0376 QWidget* ResizeHandleSet::widget() const
0377 {
0378     return d->widget;
0379 }
0380 
0381 Form* ResizeHandleSet::form() const
0382 {
0383     return d->form;
0384 }
0385 
0386 #include "resizehandle.moc"