valentina/src/app/puzzle/carousel/vpcarrouselpiecelist.cpp
2024-02-20 08:58:06 +02:00

341 lines
11 KiB
C++

/************************************************************************
**
** @file vpcarrouselpiecelist.cpp
** @author Ronan Le Tiec
** @date 25 4, 2020
**
** @brief
** @copyright
** This source code is part of the Valentina project, a pattern making
** program, whose allow create and modeling patterns of clothing.
** Copyright (C) 2020 Valentina project
** <https://gitlab.com/smart-pattern/valentina> All Rights Reserved.
**
** Valentina 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.
**
** Valentina 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 Valentina. If not, see <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "vpcarrouselpiecelist.h"
#include <QApplication>
#include <QDrag>
#include <QDragMoveEvent>
#include <QLoggingCategory>
#include <QMenu>
#include <QPainter>
#include "../layout/vplayout.h"
#include "../layout/vppiece.h"
#include "../layout/vpsheet.h"
#include "../undocommands/vpundomovepieceonsheet.h"
#include "../vmisc/theme/vtheme.h"
#include "vpcarrousel.h"
#include "vpcarrouselpiece.h"
#include "vpmimedatapiece.h"
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG("-Wmissing-prototypes")
QT_WARNING_DISABLE_INTEL(1418)
Q_LOGGING_CATEGORY(pCarrouselPieceList, "p.carrouselPieceList") // NOLINT
QT_WARNING_POP
//---------------------------------------------------------------------------------------------------------------------
VPCarrouselPieceList::VPCarrouselPieceList(QWidget *parent)
: QListWidget(parent)
{
InitStyleSheet();
setContextMenuPolicy(Qt::DefaultContextMenu);
setSelectionMode(QAbstractItemView::MultiSelection);
setViewMode(QListView::IconMode);
// Because we cannot control icon color with stylesheet we must wait until scene style update. It happens after
// the palette change signal.
connect(VTheme::Instance(), &VTheme::ThemeSettingsChanged, this,
[this]()
{
for (int i = 0; i < count(); ++i)
{
if (auto *pieceItem = dynamic_cast<VPCarrouselPiece *>(item(i)))
{
pieceItem->RefreshPieceIcon();
}
}
InitStyleSheet();
});
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::SetCarrousel(VPCarrousel *carrousel)
{
m_carrousel = carrousel;
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::Refresh()
{
clear();
if (m_pieceList.isEmpty())
{
return;
}
// create the corresponding carrousel pieces
for (const auto &piece : qAsConst(m_pieceList)) // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)
{
if (not piece.isNull())
{
// update the label of the piece
auto *carrouselpiece = new VPCarrouselPiece(piece, this);
carrouselpiece->setSelected(piece->IsSelected());
}
}
sortItems();
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::SetCurrentPieceList(const QList<VPPiecePtr> &pieceList)
{
m_pieceList = pieceList;
Refresh();
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_dragStart = event->pos();
}
if (!(event->modifiers() & Qt::ControlModifier))
{
// clearSelection doesn't work properly here so we go through the elements.
const QList<QListWidgetItem *> items = selectedItems();
for (auto *item : items)
{
item->setSelected(false);
}
}
QListWidget::mousePressEvent(event);
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::mouseMoveEvent(QMouseEvent *event)
{
if (((event->buttons() & Qt::LeftButton) != 0U) &&
((event->pos() - m_dragStart).manhattanLength() >= QApplication::startDragDistance()) &&
(selectedItems().count() > 0) &&
(not m_pieceList.isEmpty() &&
m_pieceList.constFirst()->Sheet() == nullptr)) // only if it's from unplaced pieces
{
startDrag(Qt::MoveAction);
}
else
{
QListWidget::mouseMoveEvent(event);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::startDrag(Qt::DropActions supportedActions)
{
Q_UNUSED(supportedActions)
QListWidgetItem *_item = currentItem();
if (_item->type() == VPCarrouselPiece::Type)
{
auto *pieceItem = dynamic_cast<VPCarrouselPiece *>(_item);
SCASSERT(pieceItem != nullptr)
if (m_carrousel == nullptr)
{
return;
}
VPLayoutPtr const layout = m_carrousel->Layout().toStrongRef();
if (layout.isNull())
{
return;
}
// starts the dragging
auto *drag = new QDrag(this);
auto *mimeData = new VPMimeDataPiece(layout->Uuid());
VPPiecePtr const piece = pieceItem->GetPiece();
mimeData->SetPiecePtr(piece);
QIcon const pieceIcon = pieceItem->CreatePieceIcon(QSize(120, 120), true);
QPixmap const pixmap;
if (!pieceIcon.isNull())
{
pieceIcon.pixmap(QSize(120, 120));
}
drag->setDragCursor(VPMimeDataPiece::DragCursor(pixmap), Qt::MoveAction);
drag->setMimeData(mimeData);
if (drag->exec() == Qt::MoveAction)
{
m_carrousel->Refresh();
piece->SetSelected(false);
VPLayoutPtr const pieceLayout = piece->Layout();
if (not pieceLayout.isNull())
{
emit pieceLayout->PieceSelectionChanged(piece);
}
}
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::dragMoveEvent(QDragMoveEvent *e)
{
qCDebug(pCarrouselPieceList, "drag move");
e->acceptProposedAction();
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::contextMenuEvent(QContextMenuEvent *event)
{
QListWidgetItem *_item = currentItem();
if (_item == nullptr || _item->type() != VPCarrouselPiece::Type)
{
return;
}
auto *pieceItem = dynamic_cast<VPCarrouselPiece *>(_item);
SCASSERT(pieceItem != nullptr)
VPPiecePtr const piece = pieceItem->GetPiece();
VPLayoutPtr const layout = piece->Layout();
if (piece.isNull() || layout.isNull())
{
return;
}
QMenu menu;
QVector<QAction *> moveToActions;
if (not piece->Sheet().isNull())
{
QList<VPSheetPtr> sheets = layout->GetSheets();
sheets.removeAll(piece->Sheet());
if (not sheets.isEmpty())
{
QMenu *moveMenu = menu.addMenu(tr("Move to"));
for (const auto &sheet : sheets)
{
if (not sheet.isNull())
{
QAction *moveToSheet = moveMenu->addAction(sheet->GetName());
moveToSheet->setData(QVariant::fromValue(sheet));
moveToActions.append(moveToSheet);
}
}
}
}
QAction *moveAction = menu.addAction(tr("Move to Sheet"));
moveAction->setVisible(false);
QAction *deleteAction = menu.addAction(tr("Delete"));
deleteAction->setVisible(false);
QAction *removeAction = menu.addAction(tr("Remove from Sheet"));
removeAction->setVisible(false);
if (not m_pieceList.isEmpty() && m_pieceList.constFirst()->Sheet() == nullptr)
{
moveAction->setVisible(true);
deleteAction->setVisible(true);
}
if (not m_pieceList.isEmpty() && m_pieceList.constFirst()->Sheet() != nullptr)
{
removeAction->setVisible(true);
}
QAction *selectedAction = menu.exec(event->globalPos());
if (selectedAction == moveAction)
{
VPSheetPtr const sheet = layout->GetFocusedSheet();
if (not sheet.isNull())
{
piece->ClearTransformations();
QRectF const rect = sheet->GetMarginsRect();
piece->SetPosition(QPointF(rect.topLeft().x() + 1, rect.topLeft().y() + 1));
piece->SetZValue(1.0);
auto *command = new VPUndoMovePieceOnSheet(layout->GetFocusedSheet(), piece);
layout->UndoStack()->push(command);
}
}
else if (selectedAction == deleteAction)
{
auto *command = new VPUndoMovePieceOnSheet(layout->GetTrashSheet(), piece);
layout->UndoStack()->push(command);
}
else if (selectedAction == removeAction)
{
auto *command = new VPUndoMovePieceOnSheet(VPSheetPtr(), piece);
layout->UndoStack()->push(command);
}
else if (moveToActions.contains(selectedAction))
{
auto *command = new VPUndoMovePieceOnSheet(qvariant_cast<VPSheetPtr>(selectedAction->data()), piece);
layout->UndoStack()->push(command);
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::InitStyleSheet()
{
if (VTheme::ColorSheme() == VColorSheme::Dark)
{
setStyleSheet("QListWidget::item{border: 2px solid transparent;}"
"QListWidget::item:selected {border: 2px solid rgb(255,160,160);}");
}
else
{
setStyleSheet("QListWidget::item{border: 2px solid transparent; color: black;} "
"QListWidget::item:selected {border: 2px solid rgb(255,160,160);}");
}
}
//---------------------------------------------------------------------------------------------------------------------
void VPCarrouselPieceList::on_SelectionChangedExternal()
{
blockSignals(true);
for (int i = 0; i < count(); ++i)
{
QListWidgetItem *_item = item(i);
if (_item->type() == VPCarrouselPiece::Type)
{
auto *itemPiece = dynamic_cast<VPCarrouselPiece *>(_item);
SCASSERT(itemPiece != nullptr)
itemPiece->RefreshSelection();
}
}
blockSignals(false);
}