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"