Krita Source Code Documentation
Loading...
Searching...
No Matches
StoryboardDockerDock Class Reference

#include <StoryboardDockerDock.h>

+ Inheritance diagram for StoryboardDockerDock:

Classes

struct  ExportPage
 
struct  ExportPageShot
 

Public Member Functions

QString observerName () override
 
void setCanvas (KoCanvasBase *canvas) override
 
void setViewManager (KisViewManager *kisview) override
 
 StoryboardDockerDock ()
 
void unsetCanvas () override
 
 ~StoryboardDockerDock () override
 
- Public Member Functions inherited from KisMainwindowObserver
 KisMainwindowObserver ()
 
 ~KisMainwindowObserver () override
 
- Public Member Functions inherited from KoCanvasObserverBase
 KoCanvasObserverBase ()
 
KoCanvasBaseobservedCanvas () const
 
void setObservedCanvas (KoCanvasBase *canvas)
 
void unsetObservedCanvas ()
 
virtual ~KoCanvasObserverBase ()
 

Private Slots

void notifyImageDeleted ()
 sets the image in Model to nullptr if there is no canvas set or no KisImage
 
void slotExport (ExportFormat format)
 Creates the DlgExportStoryboard and performs the actual export.
 
void slotExportAsPdf ()
 calls slotExport(ExportFormat) with PDF parameter.
 
void slotExportAsSvg ()
 calls slotExport(ExportFormat) with SVG parameter.
 
void slotLockClicked (bool)
 called when lock toggle button is clicked.
 
void slotModeChanged (QAbstractButton *)
 called when a mode option is selected in Arrange menu.
 
void slotModelChanged ()
 called to reflect changes to the model.
 
void slotUpdateCommentModelList ()
 sets the CommentModel's comment list to be the same as KisDocument's storyboardCommentList
 
void slotUpdateDocumentList ()
 sets the KisDocument's storyboardItemList to be the same as StoryboardModel's storyboardItemList and KisDocument's storyboardCommentList to be the same as CommentModel's commentList
 
void slotUpdateMinimumWidth ()
 called to update minimum width on reaction to model changes. Should change based on available content.
 
void slotUpdateStoryboardModelList ()
 sets the StoryboardModel's storyboardItemList to be the same as KisDocument's storyboardItemList
 
void slotViewChanged (QAbstractButton *)
 called when a view option is selected in Arrange menu.
 

Private Member Functions

QString buildDurationString (int seconds, int frames)
 
ExportPage getPageLayout (int rows, int columns, const QRect &imageSize, const QRect &pageRect, const QFontMetrics &painter)
 
ExportPage getPageLayout (QString layoutSvgFileName, QPrinter *printer)
 

Private Attributes

ArrangeMenum_arrangeMenu
 
KisCanvas2m_canvas
 
CommentMenum_commentMenu
 
QPointer< StoryboardCommentModelm_commentModel
 
KisActionm_exportAsPdfAction
 
KisActionm_exportAsSvgAction
 
QMenu * m_exportMenu
 
KisActionm_lockAction
 
QButtonGroup * m_modeGroup
 
KisNodeManagerm_nodeManager
 
QPointer< StoryboardDelegatem_storyboardDelegate
 
QSharedPointer< StoryboardModelm_storyboardModel
 
QScopedPointer< Ui_WdgStoryboardDock > m_ui
 
QButtonGroup * m_viewGroup
 

Additional Inherited Members

Detailed Description

Definition at line 31 of file StoryboardDockerDock.h.

Constructor & Destructor Documentation

◆ StoryboardDockerDock()

StoryboardDockerDock::StoryboardDockerDock ( )

Definition at line 170 of file StoryboardDockerDock.cpp.

171 : QDockWidget(i18nc("Storyboard Docker", "Storyboard"))
172 , m_canvas(0)
173 , m_ui(new Ui_WdgStoryboardDock())
174 , m_exportMenu(new QMenu(this))
177 , m_arrangeMenu(new ArrangeMenu(this))
180{
181 QWidget* mainWidget = new QWidget(this);
182 setWidget(mainWidget);
183 m_ui->setupUi(mainWidget);
184
185 m_ui->btnExport->setMenu(m_exportMenu);
186 m_ui->btnExport->setPopupMode(QToolButton::InstantPopup);
187
188 m_exportAsPdfAction = new KisAction(i18nc("Export storyboard as PDF", "Export as PDF"), m_exportMenu);
190
191 m_exportAsSvgAction = new KisAction(i18nc("Export storyboard as SVG", "Export as SVG"), m_exportMenu);
193 connect(m_exportAsPdfAction, SIGNAL(triggered()), this, SLOT(slotExportAsPdf()));
194 connect(m_exportAsSvgAction, SIGNAL(triggered()), this, SLOT(slotExportAsSvg()));
195
196 //Setup dynamic QListView Width Based on Comment Model Columns...
198 connect(m_storyboardModel.data(), &StoryboardModel::rowsInserted, this, &StoryboardDockerDock::slotUpdateMinimumWidth);
199
200 connect(m_storyboardModel.data(), &StoryboardModel::rowsInserted, this, &StoryboardDockerDock::slotModelChanged);
201 connect(m_storyboardModel.data(), &StoryboardModel::rowsRemoved, this, &StoryboardDockerDock::slotModelChanged);
202
203 m_ui->btnComment->setMenu(m_commentMenu);
204 m_ui->btnComment->setPopupMode(QToolButton::InstantPopup);
205
207 i18nc("Freeze keyframe positions and ignore storyboard adjustments", "Freeze Keyframe Data"), m_ui->btnLock);
208 m_lockAction->setCheckable(true);
209 m_ui->btnLock->setDefaultAction(m_lockAction);
210 m_ui->btnLock->setIconSize(QSize(16, 16));
211 connect(m_lockAction, SIGNAL(toggled(bool)), this, SLOT(slotLockClicked(bool)));
212
213 m_ui->btnArrange->setMenu(m_arrangeMenu);
214 m_ui->btnArrange->setPopupMode(QToolButton::InstantPopup);
215 m_ui->btnArrange->setIcon(KisIconUtils::loadIcon("view-choose"));
216 m_ui->btnArrange->setAutoRaise(true);
217 m_ui->btnArrange->setIconSize(QSize(16, 16));
218
221
222 connect(m_modeGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(slotModeChanged(QAbstractButton*)));
223 connect(m_viewGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(slotViewChanged(QAbstractButton*)));
224
225 m_storyboardDelegate->setView(m_ui->sceneView);
226 m_storyboardModel->setView(m_ui->sceneView);
227 m_ui->sceneView->setModel(m_storyboardModel.data());
228 m_ui->sceneView->setItemDelegate(m_storyboardDelegate);
229
230 m_storyboardModel->setCommentModel(m_commentModel);
231
232 m_modeGroup->button(Mode::Row)->click();
233 m_viewGroup->button(View::All)->click();
234
235 { // Footer section...
236 QAction* action = new QAction(i18nc("Add new scene as the last storyboard", "Add Scene"), this);
237 connect(action, &QAction::triggered, this, [this](bool){
238 if (!m_canvas) return;
239
240 QModelIndex currentSelection = m_ui->sceneView->currentIndex();
241 if (currentSelection.parent().isValid()) {
242 currentSelection = currentSelection.parent();
243 }
244
245 m_storyboardModel->insertItem(currentSelection, true);
246 });
247 action->setIcon(KisIconUtils::loadIcon("list-add"));
248 m_ui->btnCreateScene->setAutoRaise(true);
249 m_ui->btnCreateScene->setIconSize(QSize(22,22));
250 m_ui->btnCreateScene->setDefaultAction(action);
251
252 action = new QAction(i18nc("Remove current scene from storyboards", "Remove Scene"), this);
253 connect(action, &QAction::triggered, this, [this](bool){
254 if (!m_canvas) return;
255
256 QModelIndex currentSelection = m_ui->sceneView->currentIndex();
257 if (currentSelection.parent().isValid()) {
258 currentSelection = currentSelection.parent();
259 }
260
261 if (currentSelection.isValid()) {
262 int row = currentSelection.row();
263 KisRemoveStoryboardCommand *command = new KisRemoveStoryboardCommand(row, m_storyboardModel->getData().at(row), m_storyboardModel.data());
264
265 m_storyboardModel->removeItem(currentSelection, command);
266 m_storyboardModel->pushUndoCommand(command);
267 }
268 });
269 action->setIcon(KisIconUtils::loadIcon("edit-delete"));
270 m_ui->btnDeleteScene->setAutoRaise(true);
271 m_ui->btnDeleteScene->setIconSize(QSize(22,22));
272 m_ui->btnDeleteScene->setDefaultAction(action);
273 }
274
275 setEnabled(false);
276}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
QButtonGroup * getModeGroup()
QButtonGroup * getViewGroup()
void sigCommentListChanged()
Emitted whenever m_items is changed. it is used to keep the StoryboardItemList in KisDocument in sync...
void slotModelChanged()
called to reflect changes to the model.
void slotUpdateMinimumWidth()
called to update minimum width on reaction to model changes. Should change based on available content...
QScopedPointer< Ui_WdgStoryboardDock > m_ui
void slotLockClicked(bool)
called when lock toggle button is clicked.
QPointer< StoryboardCommentModel > m_commentModel
void slotModeChanged(QAbstractButton *)
called when a mode option is selected in Arrange menu.
QPointer< StoryboardDelegate > m_storyboardDelegate
void slotViewChanged(QAbstractButton *)
called when a view option is selected in Arrange menu.
QSharedPointer< StoryboardModel > m_storyboardModel
void slotExportAsPdf()
calls slotExport(ExportFormat) with PDF parameter.
void slotExportAsSvg()
calls slotExport(ExportFormat) with SVG parameter.
The main storyboard model. This class manages a StoryboardItemList which is a list of StoryboardItem ...
QIcon loadIcon(const QString &name)

References connect(), ArrangeMenu::getModeGroup(), ArrangeMenu::getViewGroup(), KisIconUtils::loadIcon(), m_arrangeMenu, m_canvas, m_commentMenu, m_commentModel, m_exportAsPdfAction, m_exportAsSvgAction, m_exportMenu, m_lockAction, m_modeGroup, m_storyboardDelegate, m_storyboardModel, m_ui, m_viewGroup, Row, StoryboardCommentModel::sigCommentListChanged(), slotExportAsPdf(), slotExportAsSvg(), slotLockClicked(), slotModeChanged(), slotModelChanged(), slotUpdateMinimumWidth(), and slotViewChanged().

◆ ~StoryboardDockerDock()

StoryboardDockerDock::~StoryboardDockerDock ( )
override

Definition at line 278 of file StoryboardDockerDock.cpp.

279{
280 delete m_commentModel;
281 m_storyboardModel.reset();
283}

References m_commentModel, m_storyboardDelegate, and m_storyboardModel.

Member Function Documentation

◆ buildDurationString()

QString StoryboardDockerDock::buildDurationString ( int seconds,
int frames )
private

Definition at line 916 of file StoryboardDockerDock.cpp.

917{
918 QString durationString = QString::number(seconds);
919 durationString += i18nc("suffix in spin box in storyboard that means 'seconds'", "s");
920 durationString += "+";
921 durationString += QString::number(frames);
922 durationString += i18nc("suffix in spin box in storyboard that means 'frames'", "f");
923 return durationString;
924}

◆ getPageLayout() [1/2]

StoryboardDockerDock::ExportPage StoryboardDockerDock::getPageLayout ( int rows,
int columns,
const QRect & imageSize,
const QRect & pageRect,
const QFontMetrics & painter )
private

Definition at line 721 of file StoryboardDockerDock.cpp.

722{
723 QSizeF pageSize = pageRect.size();
724 QRectF border = pageRect;
725 QSizeF cellSize(pageSize.width() / columns, pageSize.height() / rows);
726 QVector<QRectF> rects;
727
728 int numericFontWidth = fontMetrics.horizontalAdvance("0");
729
730 for (int row = 0; row < rows; row++) {
731
732 QRectF cellRect = border;
733 cellRect.moveTop(border.top() + row * cellSize.height());
734 cellRect.setSize(cellSize - QSize(200,200));
735 for (int column = 0; column < columns; column++) {
736 cellRect.moveLeft(border.left() + column * cellSize.width());
737 cellRect.setSize(cellSize * 0.9);
738 rects.push_back(cellRect);
739 }
740 }
741
743
744 for (int i = 0; i < rects.length(); i++) {
745 QRectF& cellRect = rects[i];
746
747 const bool horizontal = cellRect.width() > cellRect.height(); // Determine general image / text flow orientation.
748 ExportPageShot layout;
749
750 QVector<StoryboardComment> comments = m_commentModel->getData();
751 const int numComments = comments.size();
752
753 if (horizontal) {
754 QRectF sourceRect = cellRect;
755 layout.cutDurationRect = kisTrimTop(fontMetrics.height() * 1.5, sourceRect);
756 layout.cutNameRect = kisTrimLeft(layout.cutDurationRect.value().width() - numericFontWidth * 6, layout.cutDurationRect.value());
757
758 const int imageWidth = sourceRect.height() * static_cast<qreal>(imageSize.width()) / static_cast<qreal>(imageSize.height());
759 layout.cutImageRect = kisTrimLeft(imageWidth, sourceRect);
760 const float commentWidth = sourceRect.width() / numComments;
761 if (commentWidth > 100) {
762 for (int i = 0; i < numComments; i++) {
763 QRectF rect = kisTrimLeft(commentWidth, sourceRect);
764 layout.commentRects.insert(comments[i].name, rect);
765 }
766 }
767 } else {
768 QRectF sourceRect = cellRect;
769 layout.cutDurationRect = kisTrimTop(fontMetrics.height() * 1.5, sourceRect);
770 layout.cutNameRect = kisTrimLeft(layout.cutDurationRect.value().width() - numericFontWidth * 6, layout.cutDurationRect.value());
771
772 const int imageHeight = sourceRect.width() * static_cast<qreal>(imageSize.height()) / static_cast<qreal>(imageSize.width());
773 layout.cutImageRect = kisTrimTop(imageHeight, sourceRect);
774 const float commentHeight = sourceRect.height() / numComments;
775 if (commentHeight > 200) {
776 for (int i = 0; i < numComments; i++) {
777 QRectF rect = kisTrimTop(commentHeight, sourceRect);
778 layout.commentRects.insert(comments[i].name, rect);
779 }
780 }
781 }
782
783 elements.push_back(layout);
784 }
785
786 ExportPage layout;
787 layout.elements = elements;
788 return layout;
789}
QRectF kisTrimTop(int height, QRectF &toTakeFrom)
Definition kis_global.h:305
QRectF kisTrimLeft(int width, QRectF &toTakeFrom)
Definition kis_global.h:288

References kisTrimLeft(), kisTrimTop(), and m_commentModel.

◆ getPageLayout() [2/2]

StoryboardDockerDock::ExportPage StoryboardDockerDock::getPageLayout ( QString layoutSvgFileName,
QPrinter * printer )
private

Definition at line 791 of file StoryboardDockerDock.cpp.

792{
793 QDomDocument svgDoc;
794 ExportPage page;
796
797 // Load DOM from file...
798 QFile f(layoutSvgFileName);
799 if (!f.open(QIODevice::ReadOnly ))
800 {
801 qDebug()<<"svg layout file didn't open";
802 return page;
803 }
804
805 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(svgDoc.setContent(&f), page);
806 f.close();
807
808 QDomElement eroot = svgDoc.documentElement();
809
810 QStringList lst = eroot.attribute("viewBox").split(" ");
811 QSizeF sizeMM(lst.at(2).toDouble(), lst.at(3).toDouble());
812 printer->setPageSize(QPageSize(sizeMM, QPageSize::Millimeter));
813 QSizeF size = printer->pageLayout().paintRectPixels(printer->resolution()).size();
814 QSizeF scaling = QSizeF( size.width() / sizeMM.width(), size.height() / sizeMM.height());
815
816 QVector<QString> commentLayers;
817 Q_FOREACH( StoryboardComment channel, m_commentModel->getData()) {
818 commentLayers.push_back(channel.name);
819 }
820
821 QMap<int, ExportPageShot> elementMap;
822
823 { // Go through all root-level svg data and preconfigure...
824 QMap<QString, QDomNode> groupsMap = rootItemsInSvg(svgDoc);
825
826 KIS_ASSERT_RECOVER_RETURN_VALUE(groupsMap.contains("layout"), page);
827
828 groupsMap["layout"].toElement().setAttribute("display", "none");
829 if (groupsMap.contains("overlay")) {
830 groupsMap["overlay"].toElement().setAttribute("display", "nonde");
831 }
832
833 QDomNodeList nodeList = groupsMap["layout"].toElement().elementsByTagName("rect");
834 for(int i = 0; i < nodeList.size(); i++) {
835 QDomNode node = nodeList.at(i);
836 QDomNamedNodeMap attrMap = node.attributes();
837
838 for (int j = 0; j < attrMap.length(); j++) {
839 QDomAttr attribute = attrMap.item(j).toAttr();
840 QString afterNamespace = attribute.name().split(":").last();
841
842 auto isValidLabel = [&](QString label, int& index) -> bool {
843 if (attribute.value().startsWith(label)) {
844 if (attribute.value() == label) {
845 index = 0;
846 return true;
847 }
848
849 QString indexString = attribute.value().remove(0, label.length());
850 bool ok = false;
851 index = indexString.toInt(&ok);
852 if (ok) {
853 if (!elementMap.contains(index))
854 elementMap.insert(index, ExportPageShot());
855 return true;
856 }
857 }
858 return false;
859 };
860
861 auto extractRect = [&](boost::optional<QRectF>& to) {
862 double x = scaling.width() * attrMap.namedItem("x").nodeValue().toDouble();
863 double y = scaling.height() * attrMap.namedItem("y").nodeValue().toDouble();
864 double width = scaling.width() * attrMap.namedItem("width").nodeValue().toDouble();
865 double height = scaling.height() * attrMap.namedItem("height").nodeValue().toDouble();
866 to = QRectF(x,y, width, height);
867 };
868
869 if (afterNamespace == "label") {
870 int index = 0;
871 if (isValidLabel("image", index)) {
872 extractRect(elementMap[index].cutImageRect);
873 } else if (isValidLabel("time",index)) {
874 extractRect(elementMap[index].cutDurationRect);
875 } else if (isValidLabel("name", index)) {
876 extractRect(elementMap[index].cutNameRect);
877 } else if (isValidLabel("shot", index)) {
878 extractRect(elementMap[index].cutNumberRect);
879 } else if (isValidLabel("page-time", index)) {
880 extractRect(page.pageTimeRect);
881 } else if (isValidLabel("page-number", index)) {
882 extractRect(page.pageNumberRect);
883 } else {
884 for(int commentIndex = 0; commentIndex < commentLayers.length(); commentIndex++) {
885 const QString& comment = commentLayers[commentIndex];
886 if (isValidLabel(comment.toLower(), index)) {
887 boost::optional<QRectF> rect;
888 extractRect(rect);
889 if (rect) {
890 elementMap[index].commentRects.insert(comment, rect.value());
891 }
892 }
893 }
894 }
895 }
896 }
897
898 }
899 }
900
901 // Sort fetched elements and push to array to return...
902 QList<int> indices = elementMap.keys();
903 std::sort(indices.begin(), indices.end(), [](const int& a, const int& b){
904 return a < b;
905 });
906
907 Q_FOREACH(const int& index, indices){
908 elements.push_back(elementMap[index]);
909 }
910
911 page.svg = svgDoc;
912 page.elements = elements;
913 return page;
914}
QMap< QString, QDomNode > rootItemsInSvg(const QDomDocument &d)
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:85
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
int size(const Forest< T > &forest)
Definition KisForest.h:1232

References StoryboardDockerDock::ExportPage::elements, KIS_ASSERT_RECOVER_RETURN_VALUE, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_commentModel, StoryboardComment::name, StoryboardDockerDock::ExportPage::pageNumberRect, StoryboardDockerDock::ExportPage::pageTimeRect, rootItemsInSvg(), and StoryboardDockerDock::ExportPage::svg.

◆ notifyImageDeleted

void StoryboardDockerDock::notifyImageDeleted ( )
privateslot

sets the image in Model to nullptr if there is no canvas set or no KisImage

Definition at line 344 of file StoryboardDockerDock.cpp.

345{
346 //if there is no image
347 if (!m_canvas || !m_canvas->image()){
348 m_storyboardModel->setImage(0);
349 }
350}
KisImageWSP image() const

References KisCanvas2::image(), m_canvas, and m_storyboardModel.

◆ observerName()

QString StoryboardDockerDock::observerName ( )
inlineoverridevirtual

Reimplemented from KoCanvasObserverBase.

Definition at line 36 of file StoryboardDockerDock.h.

36{ return "StoryboardDockerDock"; }

◆ setCanvas()

void StoryboardDockerDock::setCanvas ( KoCanvasBase * canvas)
overridevirtual

re-implement this method in your canvas observer. It will be called whenever a canvas becomes active. Note that you are responsible for not connecting more than one time to the signals of a canvas or any of the QObjects you can access through the canvas.

Implements KoCanvasObserverBase.

Definition at line 285 of file StoryboardDockerDock.cpp.

286{
287 if (m_canvas == canvas) {
288 return;
289 }
290
291 if (m_canvas) {
292 disconnect(m_storyboardModel.data(), SIGNAL(sigStoryboardItemListChanged()), this, SLOT(slotUpdateDocumentList()));
293 disconnect(m_commentModel, SIGNAL(sigCommentListChanged()), this, SLOT(slotUpdateDocumentList()));
294 disconnect(m_canvas->imageView()->document(), SIGNAL(sigStoryboardItemListChanged()), this, SLOT(slotUpdateStoryboardModelList()));
295 disconnect(m_canvas->imageView()->document(), SIGNAL(sigStoryboardItemListChanged()), this, SLOT(slotUpdateCommentModelList()));
296
297 //update the lists in KisDocument and empty storyboardModel's list and commentModel's list
301 m_storyboardModel->slotSetActiveNode(nullptr);
302 }
303
304 m_canvas = dynamic_cast<KisCanvas2*>(canvas);
305 setEnabled(m_canvas != 0);
306
307 if (m_canvas && m_canvas->image()) {
308 //sync data between KisDocument and models
311
312 connect(m_storyboardModel.data(), SIGNAL(sigStoryboardItemListChanged()), SLOT(slotUpdateDocumentList()), Qt::UniqueConnection);
313 connect(m_commentModel, SIGNAL(sigCommentListChanged()), SLOT(slotUpdateDocumentList()), Qt::UniqueConnection);
314 connect(m_canvas->imageView()->document(), SIGNAL(sigStoryboardItemListChanged()), this, SLOT(slotUpdateStoryboardModelList()), Qt::UniqueConnection);
315 connect(m_canvas->imageView()->document(), SIGNAL(sigStoryboardCommentListChanged()), this, SLOT(slotUpdateCommentModelList()), Qt::UniqueConnection);
316
317 m_storyboardModel->setImage(m_canvas->image());
318 m_storyboardDelegate->setImageSize(m_canvas->image()->size());
319 connect(m_canvas->image(), SIGNAL(sigAboutToBeDeleted()), SLOT(notifyImageDeleted()), Qt::UniqueConnection);
320
321 if (m_nodeManager) {
322 m_storyboardModel->slotSetActiveNode(m_nodeManager->activeNode());
323 }
324 }
325
328}
QPointer< KisView > imageView() const
QSize size() const
Definition kis_image.h:547
KisNodeSP activeNode()
Convenience function to get the active layer or mask.
void slotUpdateStoryboardModelList()
sets the StoryboardModel's storyboardItemList to be the same as KisDocument's storyboardItemList
void slotUpdateCommentModelList()
sets the CommentModel's comment list to be the same as KisDocument's storyboardCommentList
void notifyImageDeleted()
sets the image in Model to nullptr if there is no canvas set or no KisImage
void slotUpdateDocumentList()
sets the KisDocument's storyboardItemList to be the same as StoryboardModel's storyboardItemList and ...
KisNodeManager * m_nodeManager
QVector< StoryboardItemSP > StoryboardItemList
Definition kis_types.h:324

References KisNodeManager::activeNode(), connect(), KisCanvas2::image(), KisCanvas2::imageView(), m_canvas, m_commentModel, m_nodeManager, m_storyboardDelegate, m_storyboardModel, notifyImageDeleted(), KisImage::size(), slotModelChanged(), slotUpdateCommentModelList(), slotUpdateDocumentList(), slotUpdateMinimumWidth(), and slotUpdateStoryboardModelList().

◆ setViewManager()

void StoryboardDockerDock::setViewManager ( KisViewManager * kisview)
overridevirtual

Implements KisMainwindowObserver.

Definition at line 335 of file StoryboardDockerDock.cpp.

336{
337 m_nodeManager = kisview->nodeManager();
338 if (m_nodeManager) {
339 connect(m_nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), m_storyboardModel.data(), SLOT(slotSetActiveNode(KisNodeSP)));
340 }
341}
KisNodeManager * nodeManager() const
The node manager handles everything about nodes.

References connect(), m_nodeManager, m_storyboardModel, and KisViewManager::nodeManager().

◆ slotExport

void StoryboardDockerDock::slotExport ( ExportFormat format)
privateslot

Creates the DlgExportStoryboard and performs the actual export.

See also
DlgExportStoryboard

Definition at line 378 of file StoryboardDockerDock.cpp.

379{
380 QFileInfo fileInfo(m_canvas->imageView()->document()->path());
381 const QString imageFileName = fileInfo.baseName();
382 const int storyboardCount = m_storyboardModel->rowCount();
383 KIS_SAFE_ASSERT_RECOVER_RETURN(storyboardCount > 0);
385
386 if (dlg.exec() == QDialog::Accepted) {
387 dlg.hide();
388 KisCursorOverrideLock cursorLock(Qt::WaitCursor);
389
390 ExportPage layoutPage;
391 QPrinter printer(QPrinter::HighResolution);
392
393 // Setup export parameters...
394 QPainter painter;
395 QSvgGenerator generator;
396
397 QFont font = painter.font();
398 font.setPointSize(dlg.fontSize());
399
400 StoryboardItemList storyboardList = m_storyboardModel->getData();
401
402 // Setup per-element layout details...
403 bool layoutSpecifiedBySvg = dlg.layoutSpecifiedBySvgFile();
404 if (layoutSpecifiedBySvg) {
405 QString svgFileName = dlg.layoutSvgFile();
406 layoutPage = getPageLayout(svgFileName, &printer);
407 }
408 else {
409 int rows = dlg.rows();
410 int columns = dlg.columns();
411 printer.setOutputFileName(dlg.saveFileName());
412 printer.setPageSize(dlg.pageSize());
413 printer.setPageOrientation(dlg.pageOrientation());
414 painter.begin(&printer); // We need to begin the painter temporarily for font metrics.
415 painter.setFont(font);
416 layoutPage = getPageLayout(rows,
417 columns,
418 QRect(0, 0, m_canvas->image()->width(), m_canvas->image()->height()),
419 printer.pageLayout().paintRectPixels(printer.resolution()),
420 painter.fontMetrics());
421 painter.end(); // End temporary painter begin.
422 }
423
424 KIS_SAFE_ASSERT_RECOVER_RETURN(layoutPage.elements.length() > 0);
425
426 // Get a range of items to render. Used to be configurable in an older version but now simplified...
427 QModelIndex firstIndex = m_storyboardModel->index(0,0);
428 QModelIndex lastIndex = m_storyboardModel->index(m_storyboardModel->rowCount() - 1, 0);
429
430 if (!firstIndex.isValid() || !lastIndex.isValid()) {
431 QMessageBox::warning((QWidget*)(&dlg), i18nc("@title:window", "Krita"), i18n("Please enter correct range. There are no panels in the range of frames provided."));
432 return;
433 }
434
435 int firstItemRow = firstIndex.row();
436 int lastItemRow = lastIndex.row();
437
438 int numBoards = lastItemRow - firstItemRow + 1;
439 if (numBoards <= 0) {
440 QMessageBox::warning((QWidget*)(&dlg), i18nc("@title:window", "Krita"), i18n("Please enter correct range. There are no panels in the range of frames provided."));
441 return;
442 }
443
444 if (dlg.format() == ExportFormat::SVG) {
445 generator.setFileName(dlg.saveFileName() + "/" + imageFileName + "0.svg");
446 QSize sz = printer.pageLayout().paintRectPixels(printer.resolution()).size();
447 generator.setSize(sz);
448 generator.setViewBox(QRect(0, 0, sz.width(), sz.height()));
449 generator.setResolution(printer.resolution());
450 painter.begin(&generator);
451 painter.setBrush(QBrush(QColor(255,255,255)));
452 painter.drawRect(QRect(0,0, sz.width(), sz.height()));
453 }
454 else {
455 printer.setOutputFileName(dlg.saveFileName());
456 printer.setOutputFormat(QPrinter::PdfFormat);
457 painter.begin(&printer);
458 painter.setFont(font);
459 painter.setBackgroundMode(Qt::BGMode::OpaqueMode);
460 }
461
462 // Paint boards
463 int pageNumber = 1;
464 int pageDurationInFrames = 0;
465
466 for (int currentBoard = 0; currentBoard < numBoards; currentBoard++) {
467 if (currentBoard % layoutPage.elements.length() == 0) {
468 if (dlg.format() == ExportFormat::SVG) {
469 if (currentBoard != 0) {
470 painter.end();
471 painter.eraseRect(printer.pageLayout().paintRectPixels(printer.resolution()));
472 generator.setFileName(dlg.saveFileName() + "/" + imageFileName + QString::number(currentBoard / layoutPage.elements.length()) + ".svg");
473 QSize sz = printer.pageLayout().paintRectPixels(printer.resolution()).size();
474 generator.setSize(sz);
475 generator.setViewBox(QRect(0, 0, sz.width(), sz.height()));
476 generator.setResolution(printer.resolution());
477 painter.begin(&generator);
478 }
479 }
480 else {
481 if (currentBoard != 0 ) { // New page!
482 printer.newPage();
483
484 pageNumber++;
485 pageDurationInFrames = 0;
486 }
487
488 if(layoutPage.svg) {
489 QMap<QString, QDomNode> groups = rootItemsInSvg(layoutPage.svg.value());
490 if (groups.contains("overlay")) {
491 QMapIterator<QString, QDomNode> iter(groups);
492 while(iter.hasNext()) {
493 iter.next();
494 if (iter.key() == "overlay" || iter.key() == "layout") {
495 iter.value().toElement().setAttribute("display","none");
496 } else {
497 iter.value().toElement().setAttribute("display","inline");
498 }
499 }
500 }
501 QSvgRenderer renderer(layoutPage.svg->toByteArray());
502 renderer.render(&painter);
503 }
504 }
505 }
506
507 ThumbnailData data = qvariant_cast<ThumbnailData>(storyboardList.at(currentBoard + firstItemRow)->child(StoryboardItem::FrameNumber)->data());
508 QPixmap pxmp = qvariant_cast<QPixmap>(data.pixmap);
509 QVector<StoryboardComment> comments = m_commentModel->getData();
510 const int numComments = comments.size();
511
512 const ExportPageShot* const layoutShot = &layoutPage.elements[currentBoard % layoutPage.elements.length()];
513
514 QPen pen(QColor(1, 0, 0));
515 pen.setWidth(5);
516 painter.setPen(pen);
517
518 // Draw image
519 if (layoutShot->cutImageRect.has_value()) {
520 QRectF imgRect = layoutShot->cutImageRect.value();
521 QSizeF resizedImage = QSizeF(pxmp.size()).scaled(layoutShot->cutImageRect->size(), Qt::KeepAspectRatio);
522 const int MARGIN = -2;
523 resizedImage = QSize(resizedImage.width() + MARGIN * 2, resizedImage.height() + MARGIN * 2);
524 imgRect.setSize(resizedImage);
525 imgRect.translate((layoutShot->cutImageRect.value().width() - imgRect.size().width()) / 2 - MARGIN,
526 (layoutShot->cutImageRect->height() - imgRect.size().height()) / 2 - MARGIN);
527 painter.drawPixmap(imgRect, pxmp, pxmp.rect());
528 painter.drawRect(layoutShot->cutImageRect.value());
529 }
530
531 { // Insert shot text elements...
532 painter.save();
533 painter.setBackgroundMode(Qt::TransparentMode);
534
535 // Draw shot name
536 if (layoutShot->cutNameRect.has_value()) {
537 QString str = storyboardList.at(currentBoard + firstItemRow)->child(StoryboardItem::ItemName)->data().toString();
538 painter.drawText(layoutShot->cutNameRect.value().translated(painter.fontMetrics().averageCharWidth() / 2, 0), Qt::AlignLeft | Qt::AlignVCenter, str);
539
540 if (!layoutPage.svg) {
541 painter.drawRect(layoutShot->cutNameRect.value());
542 }
543 }
544
545 // Draw shot number
546 if (layoutShot->cutNumberRect.has_value()) {
547 painter.drawText(layoutShot->cutNumberRect.value(), Qt::AlignCenter, QString::number(currentBoard + firstItemRow));
548
549 if (!layoutPage.svg) {
550 painter.drawRect(layoutShot->cutNumberRect.value());
551 }
552 }
553
554 QModelIndex boardIndex = m_storyboardModel->index(currentBoard + firstItemRow, 0);
555
556 const int boardDurationFrames = m_storyboardModel->data(boardIndex, StoryboardModel::TotalSceneDurationInFrames).toInt();
557 pageDurationInFrames += boardDurationFrames;
558
559 // Draw shot duration
560 if (layoutShot->cutDurationRect.has_value()) {
561 // Split shot duration into tuple of seconds + frames (remainder)..
562 int durationSecondsPart = boardDurationFrames / m_storyboardModel->getFramesPerSecond();
563 int durationFramesPart = boardDurationFrames % m_storyboardModel->getFramesPerSecond();
564
565 painter.drawText(layoutShot->cutDurationRect.value(), Qt::AlignCenter,
566 buildDurationString(durationSecondsPart, durationFramesPart));
567
568 if (!layoutPage.svg) {
569 painter.drawRect(layoutShot->cutDurationRect.value());
570 }
571 }
572
573 painter.restore();
574 }
575
576
577 // Draw shot comments
578 for (int commentIndex = 0; commentIndex < numComments; commentIndex++) {
579 if (!layoutShot->commentRects.contains(comments[commentIndex].name))
580 continue;
581
582 const QString& commentName = comments[commentIndex].name;
583
584 QTextDocument doc;
585 doc.setDocumentMargin(0);
586 doc.setDefaultFont(painter.font());
587 QString comment;
588 comment += "<p><b>" + commentName + "</b></p>"; // if arrange options are used check for visibility
589 QString originalCommentText = qvariant_cast<CommentBox>(storyboardList.at(currentBoard + firstItemRow)->child(StoryboardItem::Comments + commentIndex)->data()).content.toString();
590 originalCommentText = originalCommentText.replace('\n', "</p><p>");
591 comment += "<p>&nbsp;" + originalCommentText + "</p>";
592 const int MARGIN = painter.fontMetrics().averageCharWidth() / 2;
593
594 doc.setHtml(comment);
595 doc.setTextWidth(layoutShot->commentRects[commentName].width() - MARGIN * 2);
596
597 QAbstractTextDocumentLayout::PaintContext ctx;
598 ctx.palette.setColor(QPalette::Text, painter.pen().color());
599
600 //draw the comments
601 painter.save();
602 painter.translate(layoutShot->commentRects[commentName].topLeft() + QPoint(MARGIN, MARGIN));
603 painter.setClipRegion(QRegion(0,0,layoutShot->commentRects[commentName].width(), layoutShot->commentRects[commentName].height() - painter.fontMetrics().height()));
604 painter.setBackgroundMode(Qt::TransparentMode);
605 doc.documentLayout()->draw(&painter, ctx);
606 painter.restore();
607
608 painter.drawRect(layoutShot->commentRects[commentName]);
609 }
610
611 // Draw overlays after drawing last element on page or after drawing last element in general.
612 if ((currentBoard % layoutPage.elements.length()) == (layoutPage.elements.length() - 1) || (currentBoard == numBoards - 1)) {
613
614 painter.save();
615 painter.setBackgroundMode(Qt::TransparentMode);
616
617 if (layoutPage.pageNumberRect) {
618 painter.drawText(layoutPage.pageNumberRect.value(), Qt::AlignCenter, QString::number(pageNumber));
619 }
620
621 if (layoutPage.pageTimeRect) {
622 int pageDurationSecondsPart = pageDurationInFrames / m_storyboardModel->getFramesPerSecond();
623 int pageDurationFramesPart = pageDurationInFrames % m_storyboardModel->getFramesPerSecond();
624
625 painter.drawText(layoutPage.pageTimeRect.value(), Qt::AlignCenter, buildDurationString(pageDurationSecondsPart, pageDurationFramesPart));
626 }
627
628 if (layoutPage.svg) {
629 QMap<QString, QDomNode> groups = rootItemsInSvg(layoutPage.svg.value());
630 if (groups.contains("overlay")) {
631 QMapIterator<QString, QDomNode> iter(groups);
632 while(iter.hasNext()) {
633 iter.next();
634 if (iter.key() == "overlay") {
635 iter.value().toElement().setAttribute("display","inline");
636 } else {
637 iter.value().toElement().setAttribute("display","none");
638 }
639 }
640 }
641 QSvgRenderer renderer(layoutPage.svg->toByteArray());
642 renderer.render(&painter);
643 }
644
645 painter.restore();
646 }
647 }
648 painter.end();
649 }
650}
#define MARGIN
qint32 width() const
qint32 height() const
QString buildDurationString(int seconds, int frames)
ExportPage getPageLayout(int rows, int columns, const QRect &imageSize, const QRect &pageRect, const QFontMetrics &painter)
@ FrameNumber
Store the frame number at index 0. Data type stored here should be ThumbnailData.
@ ItemName
Store the item name at index 1. Data type stored here should be string.
@ Comments
Store the comments at indices greater_than_or_equal_to to index 4. Data type stored here should be Co...
This class is a simple combination of two QVariants. It can be converted to and from QVariant type an...
QVariant pixmap
a scaled down thumbnail version of the frame
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128

References buildDurationString(), DlgExportStoryboard::columns(), StoryboardDockerDock::ExportPageShot::commentRects, StoryboardItem::Comments, StoryboardDockerDock::ExportPageShot::cutDurationRect, StoryboardDockerDock::ExportPageShot::cutImageRect, StoryboardDockerDock::ExportPageShot::cutNameRect, StoryboardDockerDock::ExportPageShot::cutNumberRect, StoryboardDockerDock::ExportPage::elements, DlgExportStoryboard::fontSize(), DlgExportStoryboard::format(), StoryboardItem::FrameNumber, getPageLayout(), KisImage::height(), KisCanvas2::image(), KisCanvas2::imageView(), StoryboardItem::ItemName, KIS_SAFE_ASSERT_RECOVER_RETURN, DlgExportStoryboard::layoutSpecifiedBySvgFile(), DlgExportStoryboard::layoutSvgFile(), m_canvas, m_commentModel, m_storyboardModel, MARGIN, StoryboardDockerDock::ExportPage::pageNumberRect, DlgExportStoryboard::pageOrientation(), DlgExportStoryboard::pageSize(), StoryboardDockerDock::ExportPage::pageTimeRect, ThumbnailData::pixmap, rootItemsInSvg(), DlgExportStoryboard::rows(), DlgExportStoryboard::saveFileName(), SVG, StoryboardDockerDock::ExportPage::svg, StoryboardModel::TotalSceneDurationInFrames, and KisImage::width().

◆ slotExportAsPdf

void StoryboardDockerDock::slotExportAsPdf ( )
privateslot

calls slotExport(ExportFormat) with PDF parameter.

Definition at line 368 of file StoryboardDockerDock.cpp.

369{
371}
void slotExport(ExportFormat format)
Creates the DlgExportStoryboard and performs the actual export.

References PDF, and slotExport().

◆ slotExportAsSvg

void StoryboardDockerDock::slotExportAsSvg ( )
privateslot

calls slotExport(ExportFormat) with SVG parameter.

Definition at line 373 of file StoryboardDockerDock.cpp.

374{
376}

References slotExport(), and SVG.

◆ slotLockClicked

void StoryboardDockerDock::slotLockClicked ( bool isLocked)
privateslot

called when lock toggle button is clicked.

Parameters
valueThe new lock toggle value.

Definition at line 652 of file StoryboardDockerDock.cpp.

652 {
653 if (isLocked) {
654 m_lockAction->setIcon(KisIconUtils::loadIcon("locked"));
655 m_storyboardModel->setLocked(true);
656 }
657 else {
658 m_lockAction->setIcon(KisIconUtils::loadIcon("unlocked"));
659 m_storyboardModel->setLocked(false);
660 }
661}

References KisIconUtils::loadIcon(), m_lockAction, and m_storyboardModel.

◆ slotModeChanged

void StoryboardDockerDock::slotModeChanged ( QAbstractButton * button)
privateslot

called when a mode option is selected in Arrange menu.

Parameters
buttonThe button selected.

Definition at line 663 of file StoryboardDockerDock.cpp.

664{
665 int mode = m_modeGroup->id(button);
666 if (mode == Mode::Column) {
667 m_ui->sceneView->setFlow(QListView::LeftToRight);
668 m_ui->sceneView->setWrapping(false);
669 m_ui->sceneView->setItemOrientation(Qt::Vertical);
670 m_viewGroup->button(View::CommentsOnly)->setEnabled(true);
671 }
672 else if (mode == Mode::Row) {
673 m_ui->sceneView->setFlow(QListView::TopToBottom);
674 m_ui->sceneView->setWrapping(false);
675 m_ui->sceneView->setItemOrientation(Qt::Horizontal);
676 m_viewGroup->button(View::CommentsOnly)->setEnabled(false); //disable the comments only view
677 }
678 else if (mode == Mode::Grid) {
679 m_ui->sceneView->setFlow(QListView::LeftToRight);
680 m_ui->sceneView->setWrapping(true);
681 m_ui->sceneView->setItemOrientation(Qt::Vertical);
682 m_viewGroup->button(View::CommentsOnly)->setEnabled(true);
683 }
684 m_storyboardModel->layoutChanged();
685}
QString button(const QWheelEvent &ev)

References button(), Column, Grid, m_modeGroup, m_storyboardModel, m_ui, m_viewGroup, and Row.

◆ slotModelChanged

void StoryboardDockerDock::slotModelChanged ( )
privateslot

called to reflect changes to the model.

Definition at line 714 of file StoryboardDockerDock.cpp.

715{
716 if (m_storyboardModel) {
717 m_ui->btnExport->setDisabled(m_storyboardModel->rowCount() == 0);
718 }
719}

References m_storyboardModel, and m_ui.

◆ slotUpdateCommentModelList

void StoryboardDockerDock::slotUpdateCommentModelList ( )
privateslot

sets the CommentModel's comment list to be the same as KisDocument's storyboardCommentList

Definition at line 363 of file StoryboardDockerDock.cpp.

364{
365 m_commentModel->resetData(m_canvas->imageView()->document()->getStoryboardCommentsList());
366}

References KisCanvas2::imageView(), m_canvas, and m_commentModel.

◆ slotUpdateDocumentList

void StoryboardDockerDock::slotUpdateDocumentList ( )
privateslot

sets the KisDocument's storyboardItemList to be the same as StoryboardModel's storyboardItemList and KisDocument's storyboardCommentList to be the same as CommentModel's commentList

Definition at line 352 of file StoryboardDockerDock.cpp.

353{
354 m_canvas->imageView()->document()->setStoryboardItemList(m_storyboardModel->getData());
355 m_canvas->imageView()->document()->setStoryboardCommentList(m_commentModel->getData());
356}

References KisCanvas2::imageView(), m_canvas, m_commentModel, and m_storyboardModel.

◆ slotUpdateMinimumWidth

void StoryboardDockerDock::slotUpdateMinimumWidth ( )
privateslot

called to update minimum width on reaction to model changes. Should change based on available content.

Definition at line 709 of file StoryboardDockerDock.cpp.

710{
711 m_ui->sceneView->setMinimumSize(m_ui->sceneView->sizeHint());
712}

References m_ui.

◆ slotUpdateStoryboardModelList

void StoryboardDockerDock::slotUpdateStoryboardModelList ( )
privateslot

sets the StoryboardModel's storyboardItemList to be the same as KisDocument's storyboardItemList

Definition at line 358 of file StoryboardDockerDock.cpp.

359{
360 m_storyboardModel->resetData(m_canvas->imageView()->document()->getStoryboardItemList());
361}

References KisCanvas2::imageView(), m_canvas, and m_storyboardModel.

◆ slotViewChanged

void StoryboardDockerDock::slotViewChanged ( QAbstractButton * button)
privateslot

called when a view option is selected in Arrange menu.

Parameters
buttonThe button selected.

Definition at line 687 of file StoryboardDockerDock.cpp.

688{
689 int view = m_viewGroup->id(button);
690 if (view == View::All) {
691 m_ui->sceneView->setCommentVisibility(true);
692 m_ui->sceneView->setThumbnailVisibility(true);
693 m_modeGroup->button(Mode::Row)->setEnabled(true);
694 }
695 else if (view == View::ThumbnailsOnly) {
696 m_ui->sceneView->setCommentVisibility(false);
697 m_ui->sceneView->setThumbnailVisibility(true);
698 m_modeGroup->button(Mode::Row)->setEnabled(true);
699 }
700
701 else if (view == View::CommentsOnly) {
702 m_ui->sceneView->setCommentVisibility(true);
703 m_ui->sceneView->setThumbnailVisibility(false);
704 m_modeGroup->button(Mode::Row)->setEnabled(false); //disable the row mode
705 }
706 m_storyboardModel->layoutChanged();
707}

References button(), m_modeGroup, m_storyboardModel, m_ui, m_viewGroup, and Row.

◆ unsetCanvas()

void StoryboardDockerDock::unsetCanvas ( )
overridevirtual

Re-implement to notify the observer that its canvas is no longer among the living. The daisies, it is pushing up. This means you don't have to disconnect, it's dead.

The old canvas should be deleted already, so if you stored a pointer to it, don't touch!

Note that currently there is a bug where in certain specific circumstances unsetCanvas can be called when it shouldn't, see for example KWStatisticsDocker for a workaround for this problem.

Implements KoCanvasObserverBase.

Definition at line 330 of file StoryboardDockerDock.cpp.

331{
332 setCanvas(0);
333}
void setCanvas(KoCanvasBase *canvas) override

References setCanvas().

Member Data Documentation

◆ m_arrangeMenu

ArrangeMenu* StoryboardDockerDock::m_arrangeMenu
private

Definition at line 149 of file StoryboardDockerDock.h.

◆ m_canvas

KisCanvas2* StoryboardDockerDock::m_canvas
private

Definition at line 136 of file StoryboardDockerDock.h.

◆ m_commentMenu

CommentMenu* StoryboardDockerDock::m_commentMenu
private

Definition at line 145 of file StoryboardDockerDock.h.

◆ m_commentModel

QPointer<StoryboardCommentModel> StoryboardDockerDock::m_commentModel
private

Definition at line 144 of file StoryboardDockerDock.h.

◆ m_exportAsPdfAction

KisAction* StoryboardDockerDock::m_exportAsPdfAction
private

Definition at line 141 of file StoryboardDockerDock.h.

◆ m_exportAsSvgAction

KisAction* StoryboardDockerDock::m_exportAsSvgAction
private

Definition at line 142 of file StoryboardDockerDock.h.

◆ m_exportMenu

QMenu* StoryboardDockerDock::m_exportMenu
private

Definition at line 140 of file StoryboardDockerDock.h.

◆ m_lockAction

KisAction* StoryboardDockerDock::m_lockAction
private

Definition at line 147 of file StoryboardDockerDock.h.

◆ m_modeGroup

QButtonGroup* StoryboardDockerDock::m_modeGroup
private

Definition at line 151 of file StoryboardDockerDock.h.

◆ m_nodeManager

KisNodeManager* StoryboardDockerDock::m_nodeManager
private

Definition at line 137 of file StoryboardDockerDock.h.

◆ m_storyboardDelegate

QPointer<StoryboardDelegate> StoryboardDockerDock::m_storyboardDelegate
private

Definition at line 155 of file StoryboardDockerDock.h.

◆ m_storyboardModel

QSharedPointer<StoryboardModel> StoryboardDockerDock::m_storyboardModel
private

Definition at line 154 of file StoryboardDockerDock.h.

◆ m_ui

QScopedPointer<Ui_WdgStoryboardDock> StoryboardDockerDock::m_ui
private

Definition at line 138 of file StoryboardDockerDock.h.

◆ m_viewGroup

QButtonGroup* StoryboardDockerDock::m_viewGroup
private

Definition at line 152 of file StoryboardDockerDock.h.


The documentation for this class was generated from the following files: