/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "UBGraphicsItemDelegate.h" #include "UBGraphicsDelegateFrame.h" #include "UBGraphicsScene.h" #include "UBGraphicsItemUndoCommand.h" #include "UBGraphicsItemTransformUndoCommand.h" #include "board/UBBoardController.h" // TODO UB 4.x clean that dependency #include "board/UBBoardView.h" // TODO UB 4.x clean that dependency #include "core/UBApplication.h" #include "core/UBApplicationController.h" #include "core/UBDisplayManager.h" #include "core/UBSettings.h" #include "core/UBPersistenceManager.h" #include "document/UBDocumentProxy.h" #include "UBGraphicsWidgetItem.h" #include "domain/UBAbstractWidget.h" #include "web/UBWebController.h" #include "frameworks/UBFileSystemUtils.h" #include "board/UBDrawingController.h" #include "core/memcheck.h" class UBGraphicsParaschoolEditorWidgetItem; void DelegateButton::mousePressEvent(QGraphicsSceneMouseEvent *event) { // make sure delegate is selected, to avoid control being hidden mPressedTime = QTime::currentTime(); // mDelegated->setSelected(true); event->setAccepted(!mIsTransparentToMouseEvent); } void DelegateButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { int timeto = qAbs(QTime::currentTime().msecsTo(mPressedTime)); if (timeto < UBSettings::longClickInterval) { emit clicked(); } else { emit longClicked(); } event->setAccepted(!mIsTransparentToMouseEvent); } UBGraphicsItemDelegate::UBGraphicsItemDelegate(QGraphicsItem* pDelegated, QObject * parent, bool respectRatio, bool canRotate) : QObject(parent) , mDelegated(pDelegated) , mDeleteButton(NULL) , mDuplicateButton(NULL) , mMenuButton(NULL) , mMenu(0) , mLockAction(0) , mShowOnDisplayAction(0) , mGotoContentSourceAction(0) , mFrame(0) , mFrameWidth(UBSettings::settings()->objectFrameWidth) , mAntiScaleRatio(1.0) , mCanRotate(canRotate) , mCanDuplicate(true) , mRespectRatio(respectRatio) , mMimeData(NULL) , mFlippable(false) { // NOOP } void UBGraphicsItemDelegate::init() { mFrame = new UBGraphicsDelegateFrame(this, QRectF(0, 0, 0, 0), mFrameWidth, mRespectRatio); mFrame->hide(); mFrame->setFlag(QGraphicsItem::ItemIsSelectable, true); mDeleteButton = new DelegateButton(":/images/close.svg", mDelegated, mFrame, Qt::TopLeftSection); mButtons << mDeleteButton; connect(mDeleteButton, SIGNAL(clicked()), this, SLOT(remove())); if (canDuplicate()){ mDuplicateButton = new DelegateButton(":/images/duplicate.svg", mDelegated, mFrame, Qt::TopLeftSection); connect(mDuplicateButton, SIGNAL(clicked(bool)), this, SLOT(duplicate())); mButtons << mDuplicateButton; } mMenuButton = new DelegateButton(":/images/menu.svg", mDelegated, mFrame, Qt::TopLeftSection); connect(mMenuButton, SIGNAL(clicked()), this, SLOT(showMenu())); mButtons << mMenuButton; mZOrderUpButton = new DelegateButton(":/images/plus.svg", mDelegated, mFrame, Qt::BottomLeftSection); connect(mZOrderUpButton, SIGNAL(clicked()), this, SLOT(increaseZLevelUp())); connect(mZOrderUpButton, SIGNAL(longClicked()), this, SLOT(increaseZlevelTop())); mButtons << mZOrderUpButton; mZOrderDownButton = new DelegateButton(":/images/minus.svg", mDelegated, mFrame, Qt::BottomLeftSection); connect(mZOrderDownButton, SIGNAL(clicked()), this, SLOT(increaseZLevelDown())); connect(mZOrderDownButton, SIGNAL(longClicked()), this, SLOT(increaseZlevelBottom())); mButtons << mZOrderDownButton; buildButtons(); foreach(DelegateButton* button, mButtons) { button->hide(); button->setFlag(QGraphicsItem::ItemIsSelectable, true); } } UBGraphicsItemDelegate::~UBGraphicsItemDelegate() { qDeleteAll(mButtons); // do not release mMimeData. // the mMimeData is owned by QDrag since the setMimeData call as specified in the documentation } QVariant UBGraphicsItemDelegate::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { if ((change == QGraphicsItem::ItemSelectedHasChanged || change == QGraphicsItem::ItemPositionHasChanged || change == QGraphicsItem::ItemTransformHasChanged) && mDelegated->scene()) { mAntiScaleRatio = 1 / (UBApplication::boardController->systemScaleFactor() * UBApplication::boardController->currentZoom()); if (mDelegated->isSelected()) { QList items = mDelegated->scene()->selectedItems(); foreach(QGraphicsItem* item, items) { if (item != mDelegated) { item->setSelected(false); } } } positionHandles(); } if (change == QGraphicsItem::ItemPositionHasChanged || change == QGraphicsItem::ItemTransformHasChanged || change == QGraphicsItem::ItemZValueHasChanged) { UBGraphicsScene* ubScene = qobject_cast(mDelegated->scene()); if(ubScene) ubScene->setModified(true); } return value; } UBGraphicsScene *UBGraphicsItemDelegate::castUBGraphicsScene() { UBGraphicsScene *castScene = dynamic_cast(delegated()->scene()); return castScene; } bool UBGraphicsItemDelegate::mousePressEvent(QGraphicsSceneMouseEvent *event) { mDragStartPosition = event->pos(); startUndoStep(); if (!mDelegated->isSelected()) { mDelegated->setSelected(true); positionHandles(); return true; } else { return false; } } void UBGraphicsItemDelegate::setMimeData(QMimeData *mimeData) { mMimeData = mimeData; } bool UBGraphicsItemDelegate::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if((NULL != mMimeData) && ((event->pos() - mDragStartPosition).manhattanLength() < QApplication::startDragDistance())) { QDrag* mDrag = new QDrag(event->widget()); mDrag->setMimeData(mMimeData); if (!mDragPixmap.isNull()) { mDrag->setPixmap(mDragPixmap); mDrag->setHotSpot(mDragPixmap.rect().center()); } mDrag->exec(); mDragPixmap = QPixmap(); return true; } if(isLocked()) { event->accept(); return true; } else return true; } bool UBGraphicsItemDelegate::weelEvent(QGraphicsSceneWheelEvent *event) { Q_UNUSED(event); if( mDelegated->isSelected() ) { // event->accept(); return true; } else { // event->ignore(); return false; } } bool UBGraphicsItemDelegate::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { Q_UNUSED(event); commitUndoStep(); return true; } void UBGraphicsItemDelegate::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event) // if (!mDelegated->isSelected()) { // setZOrderButtonsVisible(true); // } } void UBGraphicsItemDelegate::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event) // if (!mDelegated->isSelected()) { // setZOrderButtonsVisible(false); // } } void UBGraphicsItemDelegate::positionHandles() { if (mDelegated->isSelected()) { bool shownOnDisplay = mDelegated->data(UBGraphicsItemData::ItemLayerType).toInt() != UBItemLayerType::Control; showHide(shownOnDisplay); lock(isLocked()); updateFrame(); mFrame->show(); updateButtons(true); } else { foreach(DelegateButton* button, mButtons) button->hide(); mFrame->hide(); } } void UBGraphicsItemDelegate::setZOrderButtonsVisible(bool visible) { if (visible) { updateFrame(); updateButtons(); QPointF newUpPoint = mFrame->mapToItem(mDelegated, mZOrderUpButton->pos()); QPointF newDownPoint = mFrame->mapToItem(mDelegated, mZOrderDownButton->pos()); mZOrderUpButton->setParentItem(mDelegated); mZOrderDownButton->setParentItem(mDelegated); mZOrderUpButton->setPos(newUpPoint + QPointF(0,0)); mZOrderDownButton->setPos(newDownPoint + QPointF(0,0)); mZOrderUpButton->show(); mZOrderDownButton->show(); } else { mZOrderUpButton->hide(); mZOrderDownButton->hide(); } } void UBGraphicsItemDelegate::remove(bool canUndo) { // QGraphicsScene* scene = mDelegated->scene(); UBGraphicsScene* scene = (UBGraphicsScene*)(mDelegated->scene()); if (scene) { foreach(DelegateButton* button, mButtons) scene->removeItem(button); scene->removeItem(mFrame); scene->removeItem(mDelegated); if (canUndo) { UBGraphicsItemUndoCommand *uc = new UBGraphicsItemUndoCommand((UBGraphicsScene*) scene, mDelegated, 0); UBApplication::undoStack->push(uc); } } } bool UBGraphicsItemDelegate::isLocked() { return mDelegated->data(UBGraphicsItemData::ItemLocked).toBool(); } void UBGraphicsItemDelegate::duplicate() { // TODO UB 4.x .. rewrite .. .this is absurde ... we know what we are duplicating UBApplication::boardController->copy(); UBApplication::boardController->paste(); } void UBGraphicsItemDelegate::increaseZLevelUp() { UBGraphicsScene *curScene = castUBGraphicsScene(); if (curScene) { curScene->changeZLevelTo(delegated(), UBZLayerController::up); } } void UBGraphicsItemDelegate::increaseZlevelTop() { UBGraphicsScene *curScene = castUBGraphicsScene(); if (curScene) { curScene->changeZLevelTo(delegated(), UBZLayerController::top); } } void UBGraphicsItemDelegate::increaseZLevelDown() { UBGraphicsScene *curScene = castUBGraphicsScene(); if (curScene) { curScene->changeZLevelTo(delegated(), UBZLayerController::down); } } void UBGraphicsItemDelegate::increaseZlevelBottom() { UBGraphicsScene *curScene = castUBGraphicsScene(); if (curScene) { curScene->changeZLevelTo(delegated(), UBZLayerController::bottom); } } void UBGraphicsItemDelegate::lock(bool locked) { if (locked) { mDelegated->setData(UBGraphicsItemData::ItemLocked, QVariant(true)); } else { mDelegated->setData(UBGraphicsItemData::ItemLocked, QVariant(false)); } mDelegated->update(); mFrame->positionHandles(); } void UBGraphicsItemDelegate::showHide(bool show) { if (show) { mDelegated->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Object)); } else { mDelegated->setData(UBGraphicsItemData::ItemLayerType, QVariant(UBItemLayerType::Control)); } mDelegated->update(); emit showOnDisplayChanged(show); } void UBGraphicsItemDelegate::gotoContentSource(bool checked) { Q_UNUSED(checked) UBItem* item = dynamic_cast(mDelegated); if(item && !item->sourceUrl().isEmpty()) { UBApplication::applicationController->showInternet(); UBApplication::webController->loadUrl(item->sourceUrl()); } } void UBGraphicsItemDelegate::startUndoStep() { mPreviousPosition = mDelegated->pos(); mPreviousTransform = mDelegated->transform(); mPreviousZValue = mDelegated->zValue(); UBResizableGraphicsItem* resizableItem = dynamic_cast(mDelegated); if (resizableItem) mPreviousSize = resizableItem->size(); else mPreviousSize = QSizeF(); } void UBGraphicsItemDelegate::commitUndoStep() { UBResizableGraphicsItem* resizableItem = dynamic_cast(mDelegated); if (mDelegated->pos() != mPreviousPosition || mDelegated->transform() != mPreviousTransform || mDelegated->zValue() != mPreviousZValue || (resizableItem && resizableItem->size() != mPreviousSize)) { UBGraphicsItemTransformUndoCommand *uc = new UBGraphicsItemTransformUndoCommand(mDelegated, mPreviousPosition, mPreviousTransform, mPreviousZValue, mPreviousSize); UBApplication::undoStack->push(uc); } } void UBGraphicsItemDelegate::decorateMenu(QMenu* menu) { mLockAction = menu->addAction(tr("Locked"), this, SLOT(lock(bool))); QIcon lockIcon; lockIcon.addPixmap(QPixmap(":/images/locked.svg"), QIcon::Normal, QIcon::On); lockIcon.addPixmap(QPixmap(":/images/unlocked.svg"), QIcon::Normal, QIcon::Off); mLockAction->setIcon(lockIcon); mLockAction->setCheckable(true); mShowOnDisplayAction = mMenu->addAction(tr("Visible on Extended Screen"), this, SLOT(showHide(bool))); mShowOnDisplayAction->setCheckable(true); QIcon showIcon; showIcon.addPixmap(QPixmap(":/images/eyeOpened.svg"), QIcon::Normal, QIcon::On); showIcon.addPixmap(QPixmap(":/images/eyeClosed.svg"), QIcon::Normal, QIcon::Off); mShowOnDisplayAction->setIcon(showIcon); mGotoContentSourceAction = menu->addAction(tr("Go to Content Source"), this, SLOT(gotoContentSource(bool))); QIcon sourceIcon; sourceIcon.addPixmap(QPixmap(":/images/toolbar/internet.png"), QIcon::Normal, QIcon::On); mGotoContentSourceAction->setIcon(sourceIcon); } void UBGraphicsItemDelegate::updateMenuActionState() { if (mLockAction) mLockAction->setChecked(isLocked()); if (mShowOnDisplayAction) { bool isControl = mDelegated->data(UBGraphicsItemData::ItemLayerType) == UBItemLayerType::Control; mShowOnDisplayAction->setChecked(!isControl); } if (mGotoContentSourceAction) { UBItem* item = dynamic_cast(mDelegated); mGotoContentSourceAction->setEnabled(item && !item->sourceUrl().isEmpty()); } } void UBGraphicsItemDelegate::showMenu() { if (!mMenu) { mMenu = new QMenu(UBApplication::boardController->controlView()); decorateMenu(mMenu); } updateMenuActionState(); UBBoardView* cv = UBApplication::boardController->controlView(); QRect pinPos = cv->mapFromScene(mMenuButton->sceneBoundingRect()).boundingRect(); mMenu->exec(cv->mapToGlobal(pinPos.bottomRight())); } void UBGraphicsItemDelegate::setFlippable(bool flippable) { mFlippable = flippable; } bool UBGraphicsItemDelegate::isFlippable() { return mFlippable; } void UBGraphicsItemDelegate::updateFrame() { if (mFrame && !mFrame->scene() && mDelegated->scene()) { mDelegated->scene()->addItem(mFrame); } mFrame->setAntiScale(mAntiScaleRatio); mFrame->positionHandles(); } void UBGraphicsItemDelegate::updateButtons(bool showUpdated) { QTransform tr; tr.scale(mAntiScaleRatio, mAntiScaleRatio); mDeleteButton->setParentItem(mFrame); mDeleteButton->setTransform(tr); qreal topX = mFrame->rect().left() - mDeleteButton->renderer()->viewBox().width() * mAntiScaleRatio / 2; qreal topY = mFrame->rect().top() - mDeleteButton->renderer()->viewBox().height() * mAntiScaleRatio / 2; qreal bottomX = mFrame->rect().left() - mDeleteButton->renderer()->viewBox().width() * mAntiScaleRatio / 2; qreal bottomY = mFrame->rect().bottom() - mDeleteButton->renderer()->viewBox().height() * mAntiScaleRatio / 2; mDeleteButton->setPos(topX, topY); if (!mDeleteButton->scene()) { if (mDelegated->scene()) mDelegated->scene()->addItem(mDeleteButton); } if (showUpdated /*&& mFrame->isResizing()*/) mDeleteButton->show(); int i = 1, j = 0, k = 0; while ((i + j + k) < mButtons.size()) { DelegateButton* button = mButtons[i + j]; button->setParentItem(mFrame); button->setTransform(tr); if (button->getSection() == Qt::TopLeftSection) { button->setPos(topX + (i++ * 1.6 * mFrameWidth * mAntiScaleRatio), topY); } else if (button->getSection() == Qt::BottomLeftSection) { button->setPos(bottomX + (++j * 1.6 * mFrameWidth * mAntiScaleRatio), bottomY); } else if (button->getSection() == Qt::NoSection) { ++k; } if (!button->scene()) { if (mDelegated->scene()) mDelegated->scene()->addItem(button); } if (showUpdated) { button->show(); button->setZValue(delegated()->zValue()); } } } void UBGraphicsItemDelegate::setButtonsVisible(bool visible) { foreach(DelegateButton* pButton, mButtons){ pButton->setVisible(visible); } }