Seamly2D
Code documentation
pieces_widget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  ** @file pieces_widget.cpp
3  ** @author Douglas S Caskey
4  ** @date Jan 3, 2023
5  **
6  ** @copyright
7  ** Copyright (C) 2017 - 2023 Seamly, LLC
8  ** https://github.com/fashionfreedom/seamly2d
9  **
10  ** @brief
11  ** Seamly2D is free software: you can redistribute it and/or modify
12  ** it under the terms of the GNU General Public License as published by
13  ** the Free Software Foundation, either version 3 of the License, or
14  ** (at your option) any later version.
15  **
16  ** Seamly2D is distributed in the hope that it will be useful,
17  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  ** GNU General Public License for more details.
20  **
21  ** You should have received a copy of the GNU General Public License
22  ** along with Seamly2D. if not, see <http://www.gnu.org/licenses/>.
23  **************************************************************************/
24 
25 /************************************************************************
26  **
27  ** @file vwidgetdetails.cpp
28  ** @author Roman Telezhynskyi <dismine(at)gmail.com>
29  ** @date 25 6, 2016
30  **
31  ** @brief
32  ** @copyright
33  ** This source code is part of the Valentina project, a pattern making
34  ** program, whose allow create and modeling patterns of clothing.
35  ** Copyright (C) 2016 Valentina project
36  ** <https://bitbucket.org/dismine/valentina> All Rights Reserved.
37  **
38  ** Valentina is free software: you can redistribute it and/or modify
39  ** it under the terms of the GNU General Public License as published by
40  ** the Free Software Foundation, either version 3 of the License, or
41  ** (at your option) any later version.
42  **
43  ** Valentina is distributed in the hope that it will be useful,
44  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
45  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46  ** GNU General Public License for more details.
47  **
48  ** You should have received a copy of the GNU General Public License
49  ** along with Valentina. If not, see <http://www.gnu.org/licenses/>.
50  **
51  *************************************************************************/
52 
53 #include "pieces_widget.h"
54 #include "ui_pieces_widget.h"
55 #include "../ifc/xml/vabstractpattern.h"
56 #include "../vpatterndb/vcontainer.h"
57 #include "../vmisc/vabstractapplication.h"
58 #include "../vtools/tools/pattern_piece_tool.h"
59 #include "../vtools/undocommands/togglepieceinlayout.h"
60 #include "../vtools/undocommands/toggle_piecelock.h"
61 #include "../vtools/undocommands/set_piece_color.h"
62 #include "../vwidgets/piece_tablewidgetitem.h"
63 #include "../vwidgets/vmaingraphicsscene.h"
64 
65 #include <QColorDialog>
66 #include <QMenu>
67 #include <QPixmap>
68 #include <QTableWidget>
69 #include <QUndoStack>
70 
71 //---------------------------------------------------------------------------------------------------------------------
73  : QWidget(parent)
74  , ui(new Ui::PiecesWidget)
75  , m_doc(doc)
76  , m_data(data)
77 {
78  ui->setupUi(this);
79 
80  ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
81 
83 
84  connect(ui->tableWidget, &QTableWidget::cellClicked, this, &PiecesWidget::cellClicked);
85  connect(ui->tableWidget, &QTableWidget::cellDoubleClicked, this, &PiecesWidget::cellDoubleClicked);
86  connect(ui->tableWidget, &QTableWidget::customContextMenuRequested, this, &PiecesWidget::showContextMenu);
87 }
88 
89 //---------------------------------------------------------------------------------------------------------------------
91 {
92  delete ui;
93 }
94 
95 //---------------------------------------------------------------------------------------------------------------------
96 void PiecesWidget::togglePiece(quint32 id)
97 {
98  ui->tableWidget->setSortingEnabled(false);
99 
100  int selectedRow = 0;
101  const QHash<quint32, VPiece> *pieces = m_data->DataPieces();
102 
103  if (pieces->contains(id))
104  {
105  for (int row = 0; row < ui->tableWidget->rowCount(); ++row)
106  {
107  QTableWidgetItem *item = ui->tableWidget->item(row, 0);
108  SCASSERT(item != nullptr)
109 
110  if (item && item->data(Qt::UserRole).toUInt() == id)
111  {
112  selectedRow = row;
113  VPiece piece = pieces->value(id);
114  const bool inLayout = piece.isInLayout();
115  inLayout ? item->setIcon(QIcon("://icon/32x32/checkmark.png")) : item->setIcon(QIcon());
116 
117  QTableWidgetItem *lockItem = ui->tableWidget->item(row, 1);
118  const bool locked = piece.isLocked();
119  locked ? lockItem->setIcon(QIcon("://icon/32x32/lock_on.png"))
120  : lockItem->setIcon(QIcon("://icon/32x32/lock_off.png"));
121 
122  QTableWidgetItem *colorItem = ui->tableWidget->item(row, 2);
123  QPixmap pixmap(20, 20);
124  pixmap.fill(QColor(piece.getColor()));
125  colorItem->setIcon(QIcon(pixmap));
126 
127  QTableWidgetItem *nameItem = ui->tableWidget->item(row, 3);
128  nameItem->setText(piece.GetName());
129  }
130  }
131  }
132 
133  ui->tableWidget->selectRow(selectedRow);
134  ui->tableWidget->setSortingEnabled(true);
135 }
136 
137 //---------------------------------------------------------------------------------------------------------------------
139 {
141 }
142 
143 
144 //---------------------------------------------------------------------------------------------------------------------
146 {
147  const int rowCount = ui->tableWidget->rowCount();
148  for (int row = 0; row < rowCount; ++row)
149  {
150  QTableWidgetItem *item = ui->tableWidget->item(row, 0);
151 
152  if (item->data(Qt::UserRole).toUInt() == id)
153  {
154  ui->tableWidget->setCurrentItem(item);
155  return;
156  }
157  }
158 }
159 
160 //---------------------------------------------------------------------------------------------------------------------
161 void PiecesWidget::cellClicked(int row, int column)
162 {
163  QTableWidgetItem *item = ui->tableWidget->item(row, 0);
164  if (!item) return;
165 
166  const quint32 id = item->data(Qt::UserRole).toUInt();
167  const QHash<quint32, VPiece> *allPieces = m_data->DataPieces();
168 
169  if (column == 0)
170  {
171  const bool inLayout = !allPieces->value(id).isInLayout();
172 
173  TogglePieceInLayout *command = new TogglePieceInLayout(id, inLayout, m_data, m_doc);
175  qApp->getUndoStack()->push(command);
176  }
177  else if (column == 1)
178  {
179  const bool lock = !allPieces->value(id).isLocked();
180 
181  TogglePieceLock *command = new TogglePieceLock(id, lock, m_data, m_doc);
182  connect(command, &TogglePieceLock::updateList, this, &PiecesWidget::togglePiece);
183  qApp->getUndoStack()->push(command);
184 
185  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(qApp->getCurrentScene());
186  SCASSERT(scene != nullptr)
187  emit scene->pieceLockedChanged(id, !lock);
188  }
189  else if (column == 3)
190  {
191  emit Highlight(id);
192  }
193  ui->tableWidget->clearSelection();
194 }
195 
196 //---------------------------------------------------------------------------------------------------------------------
197 void PiecesWidget::cellDoubleClicked(int row, int column)
198 {
199  QTableWidgetItem *item = ui->tableWidget->item(row, 0);
200  if (!item) return;
201 
202  const quint32 id = item->data(Qt::UserRole).toUInt();
203  const QHash<quint32, VPiece> *allPieces = m_data->DataPieces();
204  if (allPieces->value(id).isLocked())
205  {
206  QApplication::beep();
207  ui->tableWidget->clearSelection();
208  return;
209  }
210 
211  if (column == 2)
212  {
213  const QColor color = QColorDialog::getColor(Qt::white, this, "Select Color", QColorDialog::DontUseNativeDialog);
214 
215  if (color.isValid())
216  {
217  SetPieceColor *command = new SetPieceColor(id, color.name(), m_data, m_doc);
218  connect(command, &SetPieceColor::updateList, this, &PiecesWidget::togglePiece);
219  qApp->getUndoStack()->push(command);
220  emit Highlight(id);
221  }
222  }
223  else if (column == 3)
224  {
225  PatternPieceTool *tool = qobject_cast<PatternPieceTool*>(VAbstractPattern::getTool(id));
226  SCASSERT(tool != nullptr);
227  tool->editPieceProperties();
228  }
229  ui->tableWidget->clearSelection();
230 }
231 
232 //---------------------------------------------------------------------------------------------------------------------
234 {
235  ui->tableWidget->blockSignals(true);
236 
237  const int selectedRow = ui->tableWidget->currentRow();
238  ui->tableWidget->clearContents();
239  ui->tableWidget->setColumnCount(4);
240  ui->tableWidget->setRowCount(pieces->size());
241  ui->tableWidget->setSortingEnabled(false);
242 
243  qint32 currentRow = -1;
244  auto i = pieces->constBegin();
245  while (i != pieces->constEnd())
246  {
247  ++currentRow;
248  const VPiece piece = i.value();
249 
250  // Add in layout item
252  item->setTextAlignment(Qt::AlignHCenter);
253  item->setSizeHint(QSize(20, 20));
254  item->setIcon(piece.isInLayout() ? QIcon("://icon/32x32/checkmark.png") : QIcon());
255  item->setData(Qt::UserRole, i.key());
256  item->setFlags(item->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
257  item->setToolTip(tr("Toggle inclusion of pattern piece in layout"));
258 
259  ui->tableWidget->setItem(currentRow, 0, item);
260 
261  // Add locked item
262  item = new PieceTableWidgetItem(m_data);
263  item->setTextAlignment(Qt::AlignHCenter);
264  item->setSizeHint(QSize(20, 20));
265  item->setIcon(piece.isLocked() ? QIcon("://icon/32x32/lock_on.png") : QIcon("://icon/32x32/lock_off.png"));
266  item->setData(Qt::UserRole, i.key());
267  item->setFlags(item->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
268  item->setToolTip("Toggle lock on pattern piece");
269  ui->tableWidget->setItem(currentRow, 1, item);
270 
271  // Add color item
272  item = new PieceTableWidgetItem(m_data);
273  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
274  item->setSizeHint(QSize(20, 20));
275  QPixmap pixmap(20, 20);
276  pixmap.fill(QColor(piece.getColor()));
277  item->setIcon(QIcon(pixmap));
278  item->setFlags(item->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
279  item->setToolTip("Double click opens color selector");
280  ui->tableWidget->setItem(currentRow, 2, item);
281 
282  // Add name item
283  QString name = piece.GetName();
284  if (name.isEmpty())
285  {
286  name = tr("Unnamed");
287  }
288  QTableWidgetItem *nameItem = new QTableWidgetItem(name);
289  nameItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
290  nameItem->setFlags(nameItem->flags() &= ~(Qt::ItemIsEditable)); // set the item non-editable (view only), and non-selectable
291  nameItem->setToolTip("Double click opens pattern piece properties dialog");
292  ui->tableWidget->setItem(currentRow, 3, nameItem);
293 
294  ++i;
295  }
296 
297  ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("I"));
298  ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("L"));
299  ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("C"));
300  ui->tableWidget->setHorizontalHeaderItem(3, new QTableWidgetItem(tr("Name")));
301  ui->tableWidget->horizontalHeaderItem(3)->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
302  ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
303  ui->tableWidget->resizeColumnsToContents();
304  ui->tableWidget->resizeRowsToContents();
305  ui->tableWidget->setCurrentCell(selectedRow, 0);
306  ui->tableWidget->setSortingEnabled(true);
307  ui->tableWidget->blockSignals(false);
308 }
309 
310 //---------------------------------------------------------------------------------------------------------------------
312 {
313  const QHash<quint32, VPiece> *allPieces = m_data->DataPieces();
314  if (allPieces->count() == 0)
315  {
316  return;
317  }
318 
319  for (int row = 0; row<ui->tableWidget->rowCount(); ++row)
320  {
321  QTableWidgetItem *item = ui->tableWidget->item(row, 0);
322  const quint32 id = item->data(Qt::UserRole).toUInt();
323  if (allPieces->contains(id))
324  {
325  if (!(inLayout == allPieces->value(id).isInLayout()))
326  {
327  TogglePieceInLayout *command = new TogglePieceInLayout(id, inLayout, m_data, m_doc);
329  qApp->getUndoStack()->push(command);
330  }
331  }
332  }
333 }
334 
335 //---------------------------------------------------------------------------------------------------------------------
337 {
338  ui->tableWidget->blockSignals(true);
339  ui->tableWidget->horizontalHeader()->setSortIndicator(-1, Qt::AscendingOrder);
340  const QHash<quint32, VPiece> *allPieces = m_data->DataPieces();
341  if (allPieces->count() == 0)
342  {
343  return;
344  }
345 
346  for (int row = 0; row<ui->tableWidget->rowCount(); ++row)
347  {
348  QTableWidgetItem *item = ui->tableWidget->item(row, 1);
349  const quint32 id = item->data(Qt::UserRole).toUInt();
350  if (allPieces->contains(id))
351  {
352  if (!(lock == allPieces->value(id).isLocked()))
353  {
354  TogglePieceLock *command = new TogglePieceLock(id, lock, m_data, m_doc);
355  connect(command, &TogglePieceLock::updateList, this, &PiecesWidget::togglePiece);
356  qApp->getUndoStack()->push(command);
357 
358  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(qApp->getCurrentScene());
359  SCASSERT(scene != nullptr)
360  emit scene->pieceLockedChanged(id, !lock);
361  }
362  }
363  }
364  ui->tableWidget->blockSignals(false);
365 }
366 
367 //---------------------------------------------------------------------------------------------------------------------
368 void PiecesWidget::showContextMenu(const QPoint &pos)
369 {
370  ui->tableWidget->horizontalHeader()->setSortIndicator(-1, Qt::AscendingOrder);
371  ui->tableWidget->setSortingEnabled(false);
372  ui->tableWidget->blockSignals(true);
373 
374  // workaround for https://bugreports.qt.io/browse/QTBUG-97559: assign parent to QMenu
375  QScopedPointer<QMenu> menu(new QMenu(ui->tableWidget));
376  QAction *selectAll = menu->addAction(tr("Include all pieces"));
377  QAction *selectNone = menu->addAction(tr("Exclude all pieces"));
378  QAction *invertSelection = menu->addAction(tr("Invert included pieces"));
379 
380  QAction *separator = new QAction(this);
381  separator->setSeparator(true);
382  menu->addAction(separator);
383 
384  QAction *lockAll = menu->addAction(tr("Lock all pieces"));
385  QAction *unlockAll = menu->addAction(tr("Unlock all pieces"));
386  QAction *invertLocked = menu->addAction(tr("Invert locked pieces"));
387 
388  const QHash<quint32, VPiece> *allPieces = m_data->DataPieces();
389  if (allPieces->count() == 0)
390  {
391  return;
392  }
393 
394  int selectedPieces = 0;
395  int lockedPieces = 0;
396 
397  auto piece = allPieces->constBegin();
398  while (piece != allPieces->constEnd())
399  {
400  if(piece.value().isInLayout())
401  {
402  selectedPieces++;
403  }
404  if(piece.value().isLocked())
405  {
406  lockedPieces++;
407  }
408  ++piece;
409  }
410 
411  if (selectedPieces == 0)
412  {
413  selectNone->setDisabled(true);
414  }
415  else if (selectedPieces == allPieces->size())
416  {
417  selectAll->setDisabled(true);
418  }
419 
420  if (lockedPieces == 0)
421  {
422  unlockAll->setDisabled(true);
423  }
424  else if (lockedPieces == allPieces->size())
425  {
426  lockAll->setDisabled(true);
427  }
428 
429  QAction *selectedAction = menu->exec(ui->tableWidget->viewport()->mapToGlobal(pos));
430 
431  if (selectedAction == selectAll)
432  {
433  qApp->getUndoStack()->beginMacro(tr("Include all pieces"));
434  toggleInLayoutPieces(true);
435  qApp->getUndoStack()->endMacro();
436  }
437  else if (selectedAction == selectNone)
438  {
439  qApp->getUndoStack()->beginMacro(tr("Exclude all pieces"));
440  toggleInLayoutPieces(false);
441  qApp->getUndoStack()->endMacro();
442  }
443  else if (selectedAction == invertSelection)
444  {
445  qApp->getUndoStack()->beginMacro(tr("Invert included pieces"));
446 
447  for (int row = 0; row < ui->tableWidget->rowCount(); ++row)
448  {
449  QTableWidgetItem *item = ui->tableWidget->item(row, 0);
450  const quint32 id = item->data(Qt::UserRole).toUInt();
451  if (allPieces->contains(id))
452  {
453  const bool inLayout = !allPieces->value(id).isInLayout();
454 
455  TogglePieceInLayout *command = new TogglePieceInLayout(id, inLayout, m_data, m_doc);
457  qApp->getUndoStack()->push(command);
458  }
459  }
460 
461  qApp->getUndoStack()->endMacro();
462  }
463 
464  else if (selectedAction == lockAll)
465  {
466  qApp->getUndoStack()->beginMacro(tr("Lock all pieces"));
467  toggleLockedPieces(true);
468  qApp->getUndoStack()->endMacro();
469  }
470  else if (selectedAction == unlockAll)
471  {
472  qApp->getUndoStack()->beginMacro(tr("Unlock all pieces"));
473  toggleLockedPieces(false);
474  qApp->getUndoStack()->endMacro();
475  }
476  else if (selectedAction == invertLocked)
477  {
478  qApp->getUndoStack()->beginMacro(tr("Invert locked pieces"));
479 
480  for (int row = 0; row < ui->tableWidget->rowCount(); ++row)
481  {
482  QTableWidgetItem *item = ui->tableWidget->item(row, 1);
483  const quint32 id = item->data(Qt::UserRole).toUInt();
484  if (allPieces->contains(id))
485  {
486  const bool lock = !allPieces->value(id).isLocked();
487 
488  TogglePieceLock *command = new TogglePieceLock(id, lock, m_data, m_doc);
489  connect(command, &TogglePieceLock::updateList, this, &PiecesWidget::togglePiece);
490  qApp->getUndoStack()->push(command);
491 
492  VMainGraphicsScene *scene = qobject_cast<VMainGraphicsScene *>(qApp->getCurrentScene());
493  SCASSERT(scene != nullptr)
494  emit scene->pieceLockedChanged(id, !lock);
495  }
496  }
497 
498  qApp->getUndoStack()->endMacro();
499  }
500  ui->tableWidget->setSortingEnabled(true);
501  ui->tableWidget->blockSignals(false);
502 }
void editPieceProperties()
editPieceProperties - routine to edit pattern piece properties .
void fillTable(const QHash< quint32, VPiece > *details)
void cellClicked(int row, int column)
void showContextMenu(const QPoint &pos)
void toggleLockedPieces(bool lock)
void togglePiece(quint32 id)
void Highlight(quint32 id)
void selectPiece(quint32 id)
void toggleInLayoutPieces(bool inLayout)
VAbstractPattern * m_doc
Definition: pieces_widget.h:92
virtual ~PiecesWidget()
PiecesWidget(VContainer *data, VAbstractPattern *doc, QWidget *parent=nullptr)
void cellDoubleClicked(int row, int column)
VContainer * m_data
Definition: pieces_widget.h:93
Ui::PiecesWidget * ui
Definition: pieces_widget.h:91
void updateList(quint32 m_id)
void updateList(quint32 m_id)
void updateList(quint32 m_id)
static VDataTool * getTool(quint32 id)
getTool return tool from tool list.
QString getColor() const
QString GetName() const
The VContainer class container of all variables.
Definition: vcontainer.h:141
const QHash< quint32, VPiece > * DataPieces() const
Definition: vcontainer.cpp:712
The VMainGraphicsScene class main scene.
void pieceLockedChanged(quint32 id, bool lock)
Definition: vpiece.h:88
bool isInLayout() const
Definition: vpiece.cpp:376
bool isLocked() const
Definition: vpiece.cpp:388
#define SCASSERT(cond)
Definition: def.h:317
#define qApp
Definition: vapplication.h:67