RoundRectItem.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package
19 * @author
20 * @date
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24#include "RoundRectItem.h"
25
26#include <QApplication>
27#include <QGraphicsSceneMouseEvent>
28#include <QGraphicsView>
29#include <QtGui>
30
33
34#include "MorphingItem.h"
35#define RESIZE_RECT 30
36#define ROUNDEDGESIZE 50
37
38RoundRectItem::RoundRectItem(const QRectF& bounds, const QColor& color, QGraphicsItem* parent) :
39 QGraphicsObject(parent), rimPen(Qt::black, 1), bounds(bounds)
40{
41 setCursor = false;
42 scalingActive = false;
43 editable = true;
44 resizingMode = eNone;
45 setCacheMode(DeviceCoordinateCache);
46 setColor(color);
47 setFlag(QGraphicsItem::ItemIsSelectable, true);
48 setFlag(QGraphicsItem::ItemIsMovable, true);
49 // setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
50 setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
51 setAcceptHoverEvents(true);
52
53
54 float curScale = scale();
55 // adjustScale(curScale);
56 setScale(curScale);
57 QPointF curPos = pos();
58 adjustPosition(curPos);
59 setPos(curPos);
60}
61
62void
64{
65 color = newColor;
66 fillGradient.setStart(bounds.topLeft());
67 fillGradient.setFinalStop(bounds.bottomRight());
68 fillGradient.setColorAt(0, newColor);
69 fillGradient.setColorAt(1, newColor.darker(100));
70 update();
71}
72
73void
75{
76 rimPen = newPen;
77}
78
79QRectF
81{
82 return bounds.adjusted(0, 0, 2, 2);
83}
84
85void
86RoundRectItem::setBounds(QRectF newBounds)
87{
88 if (bounds == newBounds)
89 {
90 return;
91 }
92
93 prepareGeometryChange();
94 QRectF oldBounds = bounds;
95 bounds = newBounds;
96 itemResized(oldBounds, bounds);
97}
98
99void
100RoundRectItem::setSize(const QSizeF& newSize)
101{
102 if (newSize == bounds.size())
103 {
104 return;
105 }
106
107 QRectF oldBounds = bounds;
108 prepareGeometryChange();
109 bounds.setSize(newSize);
110 setColor(color);
111 itemResized(oldBounds, bounds);
112}
113
114void
115RoundRectItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
116{
117
118
119 painter->setPen(Qt::NoPen);
120 painter->setBrush(QColor(0, 0, 0, 64));
121 painter->drawRoundedRect(bounds.translated(2, 2), ROUNDEDGESIZE, ROUNDEDGESIZE);
122
123 QLinearGradient tempGradient = fillGradient;
124 QPen tmpRimPen = rimPen;
125 if (isSelected())
126 {
127 tempGradient.setColorAt(1, color.lighter(130));
128 tmpRimPen.setStyle(Qt::DashLine);
129 // tmpRimPen.setWidthF(tmpRimPen.widthF() * 2);
130 }
131
132 painter->setBrush(tempGradient);
133 painter->setPen(tmpRimPen);
134 painter->drawRoundedRect(bounds, ROUNDEDGESIZE, ROUNDEDGESIZE);
135
136 painter->setPen(QPen(Qt::black, 1));
137
138 // QGraphicsObject::paint(painter, option, widget);
139}
140
141void
142RoundRectItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
143{
144 RoundRectItem* parent = dynamic_cast<RoundRectItem*>(parentItem());
145 if (event->modifiers().testFlag(Qt::ShiftModifier) && (!parent || parent->isEditable()))
146 {
147 setFlag(QGraphicsItem::ItemIsMovable, true);
148 }
149 else
150 {
151 setFlag(QGraphicsItem::ItemIsMovable, false);
152 }
153
154 if (isLevelOfDetailLow(event))
155 {
156 event->ignore();
157 return;
158 }
159
160 // std::cout << "item pos : " << pos().x() << ", " << pos().y() << std::endl;
161 // std::cout << "item scene pos : " << this->mapToScene(pos()).x() << ", " << this->mapToScene(pos()).y()<< std::endl;
162 QPointF pos = event->pos();
163 // ARMARX_INFO_S << "pos: " << pos;
164 QRectF oldRect = boundingRect();
165 QRectF rect = boundingRect();
166 // rect = rect.size().scale(scale());
167 // ARMARX_INFO_S << "rect: " << rect.width() << ", " << rect.height();
168 rect.setTopLeft(
169 QPointF(rect.bottomRight().rx() - RESIZE_RECT, rect.bottomRight().ry() - RESIZE_RECT));
170
171 // ARMARX_INFO_S << "rect: " << rect.topLeft() << ", " << rect.bottomRight();
172 if (rect.contains(pos))
173 {
174 scalingActive = true;
175 prepareGeometryChange();
176 // bounds.setBottomRight(QPointF(pos.x()+2, pos.y()+2));
177 itemResized(oldRect, bounds);
178 // update(/*bounds.adjusted(-20,-20,20,20)*/);
179 // if(parentItem())
180 // parentItem()->update(mapRectToParent(bounds.adjusted(-20,-20,20,20)));
181 }
182 else if (getBottomResizeBB().contains(pos))
183 {
184 resizingMode = eBottomResizing;
185 }
186 else if (getTopResizeBB().contains(pos))
187 {
188 resizingMode = eTopResizing;
189 }
190 else if (getLeftResizeBB().contains(pos))
191 {
192 resizingMode = eLeftResizing;
193 }
194 else if (getRightResizeBB().contains(pos))
195 {
196 resizingMode = eRightResizing;
197 }
198 else
199 {
200 QGraphicsObject::mousePressEvent(event);
201 }
202}
203
204void
205RoundRectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
206{
207 // ARMARX_INFO_S << "pos: " << event->pos();
208 if (setCursor)
209 {
210 QApplication::restoreOverrideCursor();
211 }
212
213 setCursor = false;
214 scalingActive = false;
215 resizingMode = eNone;
216 QGraphicsItem::mouseReleaseEvent(event);
217}
218
219void
220RoundRectItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
221{
222 QPointF pos = event->pos();
223
224 if (scalingActive)
225 {
226 QRectF oldRect = boundingRect();
227 prepareGeometryChange();
228 QRectF newRect = oldRect;
229 newRect.setBottomRight(QPointF(pos.x() + 2, pos.y() + 2));
230
231 // if(parentItem())
232 // {
233 // QRectF boundsP = mapRectFromParent(parentItem()->boundingRect());
234 // float xRatio = newRect.width()/boundsP.width();
235 // float yRatio = newRect.height()/boundsP.height();
236 // float maxRatio = std::max(xRatio,yRatio);
237 //// ARMARX_INFO << VAROUT(ratio) << " " << newRect.width() << ", " << newRect.height() << " --- " << boundsP.width() << ", " << boundsP.height();
238 // if(maxRatio > 0.4)
239 // {
240 // newRect.setWidth(newRect.width() * 0.4/maxRatio);
241 // newRect.setHeight(newRect.height() * 0.4/maxRatio);
242 // }
243 // }
244
245 float xScale = newRect.width() / oldRect.width();
246 float yScale = newRect.height() / oldRect.height();
247
248
249 float resultScalefactor = std::max(xScale, yScale);
250 resultScalefactor *= scale();
251 resultScalefactor = std::max(resultScalefactor, 0.01f);
252 // ARMARX_INFO << resultScalefactor;
253
254 setScale(resultScalefactor);
255 }
256 else if (resizingMode != eNone)
257 {
258 QRectF oldRect = boundingRect();
259 prepareGeometryChange();
260 QRectF newBounds = bounds;
261
262 switch (resizingMode)
263 {
264 // TODO: Fix top and left state rezising
265 // case eTopResizing:
266 // bounds.setTop(pos.y()-2);
267 // break;
268 case eBottomResizing:
269 newBounds.setBottom(pos.y() + 2);
270 break;
271
272 // case eLeftResizing:
273 // bounds.setLeft(pos.x()-2);
274 // break;
275 case eRightResizing:
276 newBounds.setRight(pos.x() + 2);
277 break;
278
279 default:
280 break;
281 }
282
283 newBounds.setWidth(std::max(50.0, newBounds.width()));
284 newBounds.setHeight(std::max(50.0, newBounds.height()));
285
286 QRectF bbInP = mapRectToParent(newBounds);
287 QRectF obbInP = mapRectToParent(oldRect);
288
289 if (itemResizing(oldRect, newBounds))
290 {
291 bounds = newBounds;
292 itemBoundingBoxChanged(std::max(obbInP.width(), obbInP.height()),
293 std::max(bbInP.width(), bbInP.height()));
294 itemResized(oldRect, newBounds);
295 }
296 }
297 else
298 {
299 QGraphicsItem::mouseMoveEvent(event);
300 }
301}
302
303void
304RoundRectItem::adjustCursor(Qt::CursorShape shape)
305{
306 if (!setCursor ||
307 (QApplication::overrideCursor() && QApplication::overrideCursor()->shape() != shape))
308 {
309
310 if (QApplication::overrideCursor() && QApplication::overrideCursor()->shape() != shape)
311 {
312 QApplication::changeOverrideCursor(QCursor(shape));
313 }
314 else
315 {
316 QApplication::setOverrideCursor(QCursor(shape));
317 }
318
319 setCursor = true;
320 }
321}
322
323void
324RoundRectItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
325{
326 QPointF pos = event->pos();
327 QRectF rect = boundingRect();
328 rect.setTopLeft(
329 QPointF(rect.bottomRight().rx() - RESIZE_RECT, rect.bottomRight().ry() - RESIZE_RECT));
330
331 if (isLevelOfDetailLow(event))
332 {
333 event->ignore();
334 return;
335 }
336
337 if (rect.contains(pos))
338 {
339 adjustCursor(Qt::SizeFDiagCursor);
340 }
341 else if (getBottomResizeBB().contains(pos))
342 {
343 adjustCursor(Qt::SizeVerCursor);
344 }
345 // else if(getTopResizeBB().contains(pos))
346 // {
347 // adjustCursor(Qt::SizeVerCursor);
348 // }
349 // else if(getLeftResizeBB().contains(pos))
350 // {
351 // adjustCursor(Qt::SizeHorCursor);
352 // }
353 else if (getRightResizeBB().contains(pos))
354 {
355 adjustCursor(Qt::SizeHorCursor);
356 }
357 else if (QApplication::overrideCursor())
358 {
359 QApplication::restoreOverrideCursor();
360 setCursor = false;
361 }
362}
363
364void
365RoundRectItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
366{
367}
368
369void
370RoundRectItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
371{
372
373 if (setCursor)
374 {
375 QApplication::restoreOverrideCursor();
376 }
377
378 setCursor = false;
379}
380
381QRectF
383{
384 QRectF result = boundingRect();
385 result.setTop(result.bottom());
386 return result.adjusted(0, -RESIZE_RECT, 0, 0);
387}
388
389QRectF
391{
392 QRectF result = boundingRect();
393 result.setBottom(result.top());
394 return result.adjusted(0, 0, 0, RESIZE_RECT);
395}
396
397QRectF
399{
400 QRectF result = boundingRect();
401 result.setRight(result.left());
402 return result.adjusted(0, 0, RESIZE_RECT, 0);
403}
404
405QRectF
407{
408 QRectF result = boundingRect();
409 result.setLeft(result.right());
410 return result.adjusted(-RESIZE_RECT, 0, 0, 0);
411}
412
413void
414RoundRectItem::adjustScale(float& resultScalefactor)
415{
416 if (!parentItem())
417 {
418 return;
419 }
420
421 QRectF rectP = (parentItem()->boundingRect());
422 QRectF rect = boundingRect();
423 float areaP = rectP.width() * rectP.height();
424 float area = rect.width() * rect.height() * resultScalefactor;
425 ARMARX_INFO << VAROUT(rect) << "," << VAROUT(rectP);
426 ARMARX_INFO << VAROUT(area) << ", " << VAROUT(areaP);
427
428 if (area / areaP > 0.4)
429 {
430 resultScalefactor =
431 std::max(rect.width(), rect.height()) / std::max(rectP.width(), rectP.height());
432 ARMARX_IMPORTANT << "bigger scale prohibited";
433 }
434}
435
436QPointF
438{
439 if (!parentItem())
440 {
441 return newPos;
442 }
443
444 QRectF rect = parentItem()->boundingRect();
445 QPointF oldPos = boundingRect().topLeft(); //TODO: Bounding rect is wrong here
446
447 newPos.setX(
448 qMin(rect.right() - boundingRect().width() * scale() -
449 rect.width() /** itemParent->scale()*/ * 0.03,
450 qMax(newPos.x(), rect.left() + rect.width() /** itemParent->scale()*/ * 0.03)));
451 newPos.setY(
452 qMin(rect.bottom() - boundingRect().height() * scale() -
453 rect.height() /* * itemParent->scale()*/ * 0.03,
454 qMax(newPos.y(), rect.top() + rect.height() /* * itemParent->scale()*/ * 0.20)));
455
456 return oldPos;
457}
458
459bool
460RoundRectItem::isLevelOfDetailLow(QGraphicsSceneEvent* event) const
461{
462 if (event->widget())
463 {
464 QGraphicsView* view = qobject_cast<QGraphicsView*>(event->widget()->parent());
465
466 if (parentItem())
467 {
468 auto bbparent =
469 view->mapFromScene(parentItem()->mapToScene(parentItem()->boundingRect()))
470 .boundingRect();
471 // auto bb = view->mapFromScene(mapToScene(parentItem()->boundingRect())).boundingRect();
472 // auto qlod = QStyleOptionGraphicsItem::levelOfDetailFromTransform((view->transform() * this->sceneTransform()));
473 // float lod = bb.width() / this->boundingRect().width();
474
475 // if(view)
476 // ARMARX_INFO << "View " << view->metaObject()->className() << VAROUT(lod) << VAROUT(qlod)<< VAROUT(bbparent.width()) << VAROUT(bb.width());
477 // else
478 // ARMARX_INFO << "NoView";
480 {
481 // ARMARX_INFO << "lod low -> no interaction";
482
483 return true;
484 }
485 }
486 else
487 {
488 // ARMARX_INFO << "no Parent";
489 }
490 }
491
492 return false;
493}
494
495bool
497{
498 return editable;
499}
500
501void
503{
504 this->editable = editable;
505}
506
507QVariant
508RoundRectItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value)
509{
510 if (change == ItemPositionChange)
511 {
512 // value is the new position.
513 QPointF newPos = value.toPointF();
514 RoundRectItem* itemParent = qgraphicsitem_cast<RoundRectItem*>(parentItem());
515
516 if (itemParent)
517 {
518 /* QPointF oldPos = */ adjustPosition(newPos);
519
520 // ARMARX_INFO << "bounds " << boundingRect() << " newPos " << newPos;
521 itemMoved(boundingRect().topLeft(),
522 newPos /*+QPointF(boundingRect().width()/2, boundingRect().height()/2)*/);
523 return newPos;
524 }
525 }
526 else if (change == ItemScaleChange)
527 {
528 if (parentItem())
529 {
530
531 float resultScalefactor = value.toFloat();
532 // adjustScale(resultScalefactor);
533 // ARMARX_INFO << "new scale: " << resultScalefactor << " proposed scale: " << value.toFloat();
534 return resultScalefactor;
535 }
536 }
537
538 return QGraphicsItem::itemChange(change, value);
539}
540
541void
542RoundRectItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
543{
544}
#define option(type, fn)
#define RESIZE_RECT
#define ROUNDEDGESIZE
#define VAROUT(x)
bool isEditable() const
QRectF getBottomResizeBB() const
void setBounds(QRectF newBounds)
bool isLevelOfDetailLow(QGraphicsSceneEvent *event) const
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override
QRectF getRightResizeBB() const
QRectF getLeftResizeBB() const
RoundRectItem(const QRectF &bounds, const QColor &color, QGraphicsItem *parent=0)
void setEditable(bool editable)
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override
QRectF getTopResizeBB() const
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=0) override
virtual void itemBoundingBoxChanged(float oldSize, float size)
virtual void itemResized(const QRectF &oldSize, const QRectF &newSize)
virtual void itemMoved(const QPointF &oldPos, const QPointF &newPos)
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override
void setColor(QColor newColor)
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override
void mousePressEvent(QGraphicsSceneMouseEvent *event) override
QRectF boundingRect() const override
virtual QPointF adjustPosition(QPointF &newPos)
void adjustScale(float &resultScalefactor)
void setRimPen(QPen newPen)
void setSize(const QSizeF &newSize)
virtual bool itemResizing(const QRectF &oldSize, QRectF &proposedSize)
void adjustCursor(Qt::CursorShape shape)
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override
static constexpr float minSizeToShowSubstates
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190