diff --git a/plugins/dockers/storyboarddocker/commentDelegate.cpp b/plugins/dockers/storyboarddocker/commentDelegate.cpp index 95a1415b86..9532f65a6e 100644 --- a/plugins/dockers/storyboarddocker/commentDelegate.cpp +++ b/plugins/dockers/storyboarddocker/commentDelegate.cpp @@ -1,133 +1,132 @@ /* * Copyright (c) 2020 Saurabh Kumar * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "commentDelegate.h" #include #include #include #include #include #include #include #include CommentDelegate::CommentDelegate(QObject *parent) : QStyledItemDelegate(parent) { } CommentDelegate::~CommentDelegate() { } void CommentDelegate::paint(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { p->save(); { QStyle *style = option.widget ? option.widget->style() : QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, p, option.widget); p->setFont(option.font); { QIcon icon =index.model()->data(index, Qt::DecorationRole).value(); QRect r = option.rect; r.setSize(QSize(22, 22)); icon.paint(p, r); } { QRect r = option.rect; r.translate(25, 0); QString value = index.model()->data(index, Qt::DisplayRole).toString(); p->drawText(r, Qt::AlignLeft | Qt::AlignVCenter, value); } } p->restore(); } QSize CommentDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { Q_UNUSED(index); return QSize(option.rect.width(), 22); } QWidget *CommentDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option , const QModelIndex &index) const { QLineEdit *editor = new QLineEdit(parent); return editor; } bool CommentDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { QStyleOptionViewItem newOption = option; if ((event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) && (index.flags() & Qt::ItemIsEnabled)) { QMouseEvent *mouseEvent = static_cast(event); QRect visibilityRect = option.rect; visibilityRect.setSize(QSize(22, 22)); const bool visibilityClicked = visibilityRect.isValid() && visibilityRect.contains(mouseEvent->pos()); const bool leftButton = mouseEvent->buttons() & Qt::LeftButton; if (leftButton && visibilityClicked) { model->setData(index, true, Qt::DecorationRole); return true; } } return false; } //set the existing data in the editor void CommentDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QString value = index.model()->data(index, Qt::EditRole).toString(); QLineEdit *lineEdit = static_cast(editor); lineEdit->setText(value); } void CommentDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QLineEdit *lineEdit = static_cast(editor); QString value = lineEdit->text(); //don't add empty string model->setData(index, value, Qt::EditRole); //do we need to emit closeEditor() ??? } void CommentDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { editor->setGeometry(option.rect); - qDebug()<<"setting geometry"; } \ No newline at end of file diff --git a/plugins/dockers/storyboarddocker/commentModel.cpp b/plugins/dockers/storyboarddocker/commentModel.cpp index cf3582a50c..362b163338 100644 --- a/plugins/dockers/storyboarddocker/commentModel.cpp +++ b/plugins/dockers/storyboarddocker/commentModel.cpp @@ -1,129 +1,124 @@ /* * Copyright (c) 2020 Saurabh Kumar * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "commentModel.h" #include #include CommentModel::CommentModel(QObject *parent) : QAbstractListModel(parent) { //initialize variables } int CommentModel::rowCount(const QModelIndex &parent) const { return m_commentList.count(); } QVariant CommentModel::data(const QModelIndex &index, int role) const { if(!index.isValid()) return QVariant(); if(index.row() >= m_commentList.size()) return QVariant(); if (role == Qt::DisplayRole || role == Qt::EditRole) { return m_commentList.at(index.row()).name; } if (role == Qt::DecorationRole) { if (m_commentList.at(index.row()).visibility){ return KisIconUtils::loadIcon("visible"); } else { return KisIconUtils::loadIcon("novisible"); } } return QVariant(); } bool CommentModel::setData(const QModelIndex & index, const QVariant & value, int role) { - qDebug()<<"attempting data set"<=m_commentList.size()) return false; m_commentList.insert(position, newcomment); } endInsertRows(); return true; } bool CommentModel::removeRows(int position, int rows, const QModelIndex &parent) { - qDebug()<<"row removed"; beginRemoveRows(QModelIndex(), position, position+rows-1); for (int row = 0; row < rows; ++row) { - if (position < 0 && position>=m_commentList.size()) return false; + if (position < 0 || position >= m_commentList.size()) return false; m_commentList.removeAt(position); } endRemoveRows(); return true; } Qt::DropActions CommentModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions CommentModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } diff --git a/plugins/dockers/storyboarddocker/commentModel.h b/plugins/dockers/storyboarddocker/commentModel.h index 8a0fff16d8..45603448f3 100644 --- a/plugins/dockers/storyboarddocker/commentModel.h +++ b/plugins/dockers/storyboarddocker/commentModel.h @@ -1,58 +1,59 @@ /* * Copyright (c) 2020 Saurabh Kumar * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef COMMENT_MODEL #define COMMENT_MODEL #include +class StoryboardModel; struct Comment { QString name; bool visibility; }; /* This model manages the comment data of StoryboardModel */ class CommentModel : public QAbstractListModel { Q_OBJECT public: CommentModel(QObject *parent = 0); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()); bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()); Qt::DropActions supportedDropActions() const override; Qt::DropActions supportedDragActions() const override; private: QVector m_commentList; - + friend class StoryboardModel; }; #endif \ No newline at end of file diff --git a/plugins/dockers/storyboarddocker/storyboardDelegate.cpp b/plugins/dockers/storyboarddocker/storyboardDelegate.cpp index bf0ca3b18b..1b34aca505 100644 --- a/plugins/dockers/storyboarddocker/storyboardDelegate.cpp +++ b/plugins/dockers/storyboarddocker/storyboardDelegate.cpp @@ -1,320 +1,341 @@ /* * Copyright (c) 2020 Saurabh Kumar * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "storyboardDelegate.h" #include #include #include #include #include #include #include #include #include #include #include "storyboardModel.h" StoryboardDelegate::StoryboardDelegate(QObject *parent) : QStyledItemDelegate(parent) { } StoryboardDelegate::~StoryboardDelegate() { } void StoryboardDelegate::paint(QPainter *p, const QStyleOptionViewItem &option, const QModelIndex &index) const { p->save(); { QStyle *style = option.widget ? option.widget->style() : QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, p, option.widget); p->setFont(option.font); if (!index.isValid()){ p->restore(); return; } if (!index.parent().isValid()){ QRect parentRect = option.rect; p->drawRect(parentRect); parentRect.setTopLeft(parentRect.topLeft() + QPoint(4, 4)); parentRect.setBottomRight(parentRect.bottomRight() - QPoint(4, 4)); //TODO: change highlight color and the area that is highlighted if (option.state & QStyle::State_Selected){ p->fillRect(option.rect, option.palette.foreground()); } else { p->fillRect(option.rect, option.palette.background()); } p->eraseRect(parentRect); } else{ //paint Child index (the indices that hold data) QModelIndex parent = index.parent(); //draw the child items int rowNum = index.model()->rowCount(parent); int childNum = index.row(); QString data = index.model()->data(index, Qt::DisplayRole).toString(); switch (childNum) { case 0: { QRect frameNumRect = option.rect; frameNumRect.setHeight(m_view->fontMetrics().height()+3); frameNumRect.setWidth(3 * m_view->fontMetrics().width("0")+2); frameNumRect.moveBottom(option.rect.top()-1); p->setPen(QPen(option.palette.dark(), 2)); p->drawRect(frameNumRect); p->setPen(QPen(option.palette.text(), 1)); p->drawText(frameNumRect, Qt::AlignHCenter | Qt::AlignVCenter, data); QIcon icon = KisIconUtils::loadIcon("krita-base"); icon.paint(p, option.rect); p->setPen(QPen(option.palette.dark(), 2)); p->drawRect(option.rect); + + if (option.state & QStyle::State_MouseOver){ + QRect buttonsRect = option.rect; + buttonsRect.setTop(option.rect.bottom() - 22); + p->fillRect(buttonsRect, option.palette.background()); + + buttonsRect.setWidth(22); + buttonsRect.moveBottomLeft(option.rect.bottomLeft()); + QIcon addIcon = KisIconUtils::loadIcon("list-add"); + addIcon.paint(p, buttonsRect); + + buttonsRect.moveBottomRight(option.rect.bottomRight()); + QIcon deleteIcon = KisIconUtils::loadIcon("trash-empty"); + deleteIcon.paint(p, buttonsRect); + } break; } case 1: { QRect itemNameRect = option.rect; itemNameRect.setLeft(option.rect.left() + 5); p->setPen(QPen(option.palette.text(), 1)); p->drawText(itemNameRect, Qt::AlignLeft | Qt::AlignVCenter, data); p->setPen(QPen(option.palette.dark(), 2)); p->drawRect(option.rect); break; } case 2: //time duration case 3: //frame duration { drawSpinBox(p, option, data); break; } default: { p->setPen(QPen(option.palette.dark(), 2)); p->drawRect(option.rect); break; } } } } p->restore(); } void StoryboardDelegate::drawSpinBox(QPainter *p, const QStyleOptionViewItem &option, QString data) const { QStyle *style = option.widget ? option.widget->style() : QApplication::style(); QStyleOptionSpinBox spinBoxOption; spinBoxOption.stepEnabled = QAbstractSpinBox::StepDownEnabled | QAbstractSpinBox::StepUpEnabled; spinBoxOption.subControls = QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown; spinBoxOption.rect = option.rect; p->setPen(QPen(option.palette.dark(), 2)); p->drawRect(option.rect); style->drawComplexControl(QStyle::CC_SpinBox, &spinBoxOption, p, option.widget); QRect rect = style->subControlRect(QStyle::CC_SpinBox, &spinBoxOption, QStyle::QStyle::SC_SpinBoxEditField); rect.moveTopLeft(option.rect.topLeft()); p->setPen(QPen(option.palette.text(), 1)); p->drawText(rect, Qt::AlignHCenter | Qt::AlignVCenter, data); } +/*void StoryboardDelegate::drawScrollbar(QPainter *p, const QStyleOptionViewItem &option, QString data) +{ + //draw comments box +}*/ + QSize StoryboardDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { if (!index.parent().isValid()){ int width = option.widget->width() - 17; const StoryboardModel* model = dynamic_cast(index.model()); int numComments = model->commentCount(); int numItem = width/250; if(numItem <=0){ return QSize(0, 0); } return QSize(width / numItem, 140 + numComments*100); } else { return option.rect.size(); } return QSize(0,0); } QWidget *StoryboardDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option , const QModelIndex &index) const { //only create editor for children if (index.parent().isValid()){ int row = index.row(); switch (row) { case 0: //frame thumbnail is uneditable return nullptr; case 2: //second and frame spin box case 3: { QSpinBox *spinbox = new QSpinBox(parent); + spinbox->setRange(0,999); return spinbox; } default: // for itemName and comments { QLineEdit *editor = new QLineEdit(parent); return editor; } } } return nullptr; } bool StoryboardDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { if ((event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick) && (index.flags() & Qt::ItemIsEnabled)) { QMouseEvent *mouseEvent = static_cast(event); //handle the duration edit event if (index.parent().isValid() && (index.row() == 2 || index.row() == 3)){ QRect upButton = spinBoxUpButton(option); QRect downButton = spinBoxDownButton(option); bool upButtonClicked = upButton.isValid() && upButton.contains(mouseEvent->pos()); bool downButtonClicked = downButton.isValid() && downButton.contains(mouseEvent->pos()); const bool leftButton = mouseEvent->buttons() & Qt::LeftButton; if (leftButton && upButtonClicked){ model->setData(index, index.data().toInt() + 1); return true; } else if (leftButton && downButtonClicked){ model->setData(index, std::max(0,index.data().toInt() - 1)); return true; } } } return false; } //set the existing data in the editor void StoryboardDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QVariant value = index.data(); if (index.parent().isValid()){ int row = index.row(); switch (row) { case 0: //frame thumbnail is uneditable return; case 2: //second and frame spin box case 3: { QSpinBox *spinbox = static_cast(editor); spinbox->setValue(value.toInt()); return; } default: // for itemName and comments { QLineEdit *lineEdit = static_cast(editor); lineEdit->setText(value.toString()); return; } } } } void StoryboardDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QVariant value = index.data(); if (index.parent().isValid()){ int row = index.row(); switch (row) { case 0: //frame thumbnail is uneditable return; case 2: //second and frame spin box case 3: { QSpinBox *spinbox = static_cast(editor); int value = spinbox->value(); model->setData(index, value, Qt::EditRole); return; } default: // for itemName and comments { QLineEdit *lineEdit = static_cast(editor); QString value = lineEdit->text(); model->setData(index, value, Qt::EditRole); return; } } } } void StoryboardDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { editor->setGeometry(option.rect); qDebug()<<"setting geometry"; } void StoryboardDelegate::setView(QListView *view) { m_view = view; } QRect StoryboardDelegate::spinBoxUpButton(const QStyleOptionViewItem &option) { QStyle *style = option.widget ? option.widget->style() : QApplication::style(); QStyleOptionSpinBox spinOption; spinOption.rect = option.rect; QRect rect = style->subControlRect(QStyle::CC_SpinBox, &spinOption, QStyle::QStyle::SC_SpinBoxUp); rect.moveTopRight(option.rect.topRight()); return rect; } QRect StoryboardDelegate::spinBoxDownButton(const QStyleOptionViewItem &option) { QStyle *style = option.widget ? option.widget->style() : QApplication::style(); QStyleOptionSpinBox spinOption; spinOption.rect = option.rect; QRect rect = style->subControlRect(QStyle::CC_SpinBox, &spinOption, QStyle::QStyle::SC_SpinBoxDown); rect.moveBottomRight(option.rect.bottomRight()); return rect; } QRect StoryboardDelegate::spinBoxEditField(const QStyleOptionViewItem &option) { QStyle *style = option.widget ? option.widget->style() : QApplication::style(); QStyleOptionSpinBox spinOption; spinOption.rect = option.rect; QRect rect = style->subControlRect(QStyle::CC_SpinBox, &spinOption, QStyle::QStyle::SC_SpinBoxEditField); rect.moveTopLeft(option.rect.topLeft()); return rect; } \ No newline at end of file diff --git a/plugins/dockers/storyboarddocker/storyboardModel.cpp b/plugins/dockers/storyboarddocker/storyboardModel.cpp index db3c49eefe..429e3dc042 100644 --- a/plugins/dockers/storyboarddocker/storyboardModel.cpp +++ b/plugins/dockers/storyboarddocker/storyboardModel.cpp @@ -1,225 +1,271 @@ /* * Copyright (c) 2020 Saurabh Kumar * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "storyboardModel.h" #include #include StoryboardModel::StoryboardModel(QObject *parent) : QAbstractItemModel(parent) - , m_commentCount(1) //dummy value + , m_commentCount(0) {} QModelIndex StoryboardModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); if (row < 0 || row >= rowCount()) return QModelIndex(); if (column !=0) return QModelIndex(); //1st level node has invalid parent if (!parent.isValid()){ return createIndex(row, column, m_items.at(row)); } else if (!parent.parent().isValid()){ StoryboardItem *parentItem = static_cast(parent.internalPointer()); StoryboardChild *childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); } return QModelIndex(); } QModelIndex StoryboardModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); { //no parent for 1st level node StoryboardItem *childItem = static_cast(index.internalPointer()); if (m_items.contains(childItem)){ return QModelIndex(); } } //return parent only for 2nd level nodes StoryboardChild *childItem = static_cast(index.internalPointer()); StoryboardItem *parentItem = childItem->parent(); int indexOfParent = m_items.indexOf(const_cast(parentItem)); return createIndex(indexOfParent, 0, parentItem); } int StoryboardModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) return m_items.count(); else if (!parent.parent().isValid()){ StoryboardItem *parentItem = static_cast(parent.internalPointer()); return parentItem->childCount(); } return 0; //2nd level nodes have no child } int StoryboardModel::columnCount(const QModelIndex &parent) const { if (!parent.isValid()){ return 1; } //1st level nodes have 1 column if (!parent.parent().isValid()){ return 1; } //end level nodes have no child return 0; } QVariant StoryboardModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= m_items.size()) return QVariant(); if(role == Qt::SizeHintRole){ return QSize(200,200); } //return data only for the storyboardChild i.e. 2nd level nodes if (!index.parent().isValid()){ return QVariant(); } if (role == Qt::DisplayRole || role == Qt::EditRole) { StoryboardChild *child = static_cast(index.internalPointer()); return child->data(); } return QVariant(); } bool StoryboardModel::setData(const QModelIndex & index, const QVariant & value, int role) { - //qDebug()<<"attempting data set"<(index.internalPointer()); if (child){ int fps = 24; if(index.row() == 3 && value.toInt() >= fps){ //TODO : set fps QModelIndex secondIndex = index.siblingAtRow(2); setData(secondIndex, secondIndex.data().toInt() + value.toInt() / fps, role); child->setData(value.toInt() % fps); } else { child->setData(value); } emit dataChanged(index, index); return true; } } return false; } Qt::ItemFlags StoryboardModel::flags(const QModelIndex & index) const { - //qDebug()<<"flags requested"; if(!index.isValid()) return Qt::ItemIsDropEnabled; //1st level nodes if (!index.parent().isValid()) return Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled; //2nd level nodes return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; } bool StoryboardModel::insertRows(int position, int rows, const QModelIndex &parent) { - qDebug()<<"row inserted"; if (!parent.isValid()){ beginInsertRows(QModelIndex(), position, position+rows-1); for (int row = 0; row < rows; ++row) { StoryboardItem *newItem = new StoryboardItem(); m_items.insert(position, newItem); } endInsertRows(); return true; } //insert 2nd level nodes if (!parent.parent().isValid()){ StoryboardItem *item = static_cast(parent.internalPointer()); beginInsertRows(QModelIndex(), position, position+rows-1); for (int row = 0; row < rows; ++row) { item->insertChild(position, QVariant()); } endInsertRows(); return true; } //we can't insert to 2nd level nodes as they are leaf nodes return false; } bool StoryboardModel::removeRows(int position, int rows, const QModelIndex &parent) { - qDebug()<<"row removed"; //remove 1st level nodes if (!parent.isValid()){ beginRemoveRows(QModelIndex(), position, position+rows-1); for (int row = 0; row < rows; ++row) { delete m_items.at(row); m_items.removeAt(position); } endRemoveRows(); return true; } //remove 2nd level nodes if (!parent.parent().isValid()){ StoryboardItem *item = static_cast(parent.internalPointer()); if (m_items.contains(item)){ beginRemoveRows(QModelIndex(), position, position+rows-1); for (int row = 0; row < rows; ++row) { item->removeChild(position); } endRemoveRows(); return true; } } //2nd level node has no child return false; } Qt::DropActions StoryboardModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions StoryboardModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } + +int StoryboardModel::commentCount() const +{ + return m_commentList.count(); +} + +void StoryboardModel::setCommentModel(CommentModel *commentModel) +{ + m_commentModel = commentModel; + connect(m_commentModel, SIGNAL(dataChanged(const QModelIndex ,const QModelIndex)), + this, SLOT(slotCommentDataChanged())); + connect(m_commentModel, SIGNAL(rowsRemoved(const QModelIndex ,int, int)), + this, SLOT(slotCommentRowRemoved(const QModelIndex ,int, int))); + connect(m_commentModel, SIGNAL(rowsInserted(const QModelIndex, int, int)), + this, SLOT(slotCommentRowInserted(const QModelIndex, int, int))); + //TODO: handle move events +} + +void StoryboardModel::slotCommentDataChanged() +{ + m_commentList = m_commentModel->m_commentList; + emit(dataChanged(QModelIndex(), QModelIndex())); +} + +void StoryboardModel::slotCommentRowInserted(const QModelIndex parent, int first, int last) +{ + int numItems = rowCount(); + for(int row = 0; row < numItems; row++){ + QModelIndex parentIndex = index(row, 0); + insertRows(4 + first, last - first + 1, parentIndex); //four indices are already there + } + slotCommentDataChanged(); +} + +void StoryboardModel::slotCommentRowRemoved(const QModelIndex parent, int first, int last) +{ + int numItems = rowCount(); + for(int row = 0; row < numItems; row++){ + QModelIndex parentIndex = index(row, 0); + removeRows(4 + first, last - first + 1, parentIndex); + } + slotCommentDataChanged(); +} + +/* +void StoryboardModel::slotCommentRowsMoved() +{ + qDebug()<<"comment row moved"; +} +*/ diff --git a/plugins/dockers/storyboarddocker/storyboardModel.h b/plugins/dockers/storyboarddocker/storyboardModel.h index 248325c557..49fec11918 100644 --- a/plugins/dockers/storyboarddocker/storyboardModel.h +++ b/plugins/dockers/storyboarddocker/storyboardModel.h @@ -1,67 +1,75 @@ /* * Copyright (c) 2020 Saurabh Kumar * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef STORYBOARD_MODEL #define STORYBOARD_MODEL #include #include #include "storyboardItem.h" +#include "commentModel.h" /* The main storyboard model. */ class StoryboardModel : public QAbstractItemModel { Q_OBJECT public: //if we don't need this constructor change it StoryboardModel(QObject *parent = nullptr); QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; //QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; //for removing and inserting rows bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()); bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()); //for drag and drop Qt::DropActions supportedDropActions() const override; Qt::DropActions supportedDragActions() const override; //this function accesses the value from the comment model - int commentCount() const { - return m_commentCount; - } + int commentCount() const; + void setCommentModel(CommentModel *commentModel); + +private Q_SLOTS: + void slotCommentDataChanged(); + void slotCommentRowInserted(const QModelIndex, int, int); + void slotCommentRowRemoved(const QModelIndex, int, int); + private: QVector m_items; int m_commentCount = 0; + QVector m_commentList; + CommentModel *m_commentModel; }; #endif \ No newline at end of file diff --git a/plugins/dockers/storyboarddocker/storyboardView.cpp b/plugins/dockers/storyboarddocker/storyboardView.cpp index 4be954410a..0506b19bd5 100644 --- a/plugins/dockers/storyboarddocker/storyboardView.cpp +++ b/plugins/dockers/storyboarddocker/storyboardView.cpp @@ -1,149 +1,160 @@ /* Copyright (c) 2020 Saurabh Kumar This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "storyboardView.h" #include "storyboardModel.h" /** * This view draws the children of every index in the first column of * the model inside the parent * * */ StoryboardView::StoryboardView(QWidget *parent) :QListView(parent) { setWrapping(true); setFlow(QListView::LeftToRight); setResizeMode(QListView::Adjust); setUniformItemSizes(true); setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - - qDebug()<<"storyview created"; + QWidget::setMouseTracking(true); + viewport()->setAttribute( Qt::WA_Hover ); } StoryboardView::~StoryboardView() {} void StoryboardView::paintEvent(QPaintEvent *event) { event->accept(); QListView::paintEvent(event); //ask delegate to draw the child nodes too QPainter painter(viewport()); int itemNum = model()->rowCount(); for (int row = 0; row < itemNum; row++){ QModelIndex index = model()->index(row, 0); int childNum = model()->rowCount(index); for (int childRow = 0; childRow < childNum; childRow++){ QModelIndex childIndex = model()->index(childRow, 0, index); QStyleOptionViewItem option; //TO DO: check if the childIndex is in focus //TO DO: set proper options for spinbox type indices if (selectionModel()->isSelected(childIndex)) { option.state |= QStyle::State_Selected; } if (childIndex == selectionModel()->currentIndex()) { option.state |= QStyle::State_HasFocus; } + if (childIndex == m_hoverIndex){ + option.state |= QStyle::State_MouseOver; + } option.rect = visualRect(childIndex); itemDelegate()->paint(&painter, option, childIndex); } } } QRect StoryboardView::visualRect(const QModelIndex &index) const { if (!index.isValid() || !index.parent().isValid()) { return QListView::visualRect(index); } else { QRect parentRect = visualRect(index.parent()); parentRect.setTopLeft(parentRect.topLeft() + QPoint(5, 5)); parentRect.setBottomRight(parentRect.bottomRight() - QPoint(5, 5)); int fontHeight = fontMetrics().height() + 3; int numericFontWidth = fontMetrics().width("0"); int height = parentRect.height(); int width = parentRect.width(); int childRow = index.row(); switch (childRow) { case 0: { //the frame thumbnail rect parentRect.setSize(QSize(width, 120)); parentRect.translate(0, fontHeight); return parentRect; } case 1: { QRect itemNameRect = parentRect; itemNameRect.setSize(QSize(width - (10 * numericFontWidth + 22), fontHeight)); itemNameRect.moveLeft(parentRect.left() + 3*numericFontWidth + 2); return itemNameRect; } case 2: { QRect secondRect = parentRect; secondRect.setSize(QSize(4 * numericFontWidth + 10, fontHeight)); secondRect.moveRight(parentRect.right() - 3*numericFontWidth -10); return secondRect; } case 3: { QRect frameRect = parentRect; frameRect.setSize(QSize(3 * numericFontWidth + 10, fontHeight)); frameRect.moveRight(parentRect.right()); return frameRect; } default: { //comment rect parentRect.setTop(parentRect.top() + 120+fontHeight); return parentRect; } } } return QRect(); } QModelIndex StoryboardView::indexAt(const QPoint &point) const { QModelIndex index = QListView::indexAt(point); if (index.isValid()) { //look for the index in children of the current index int numChild = model()->rowCount(index); for (int row = 0; row < numChild; row++) { QRect childRect = visualRect(model()->index(row, 0, index)); if (childRect.contains(point)) { return model()->index(row, 0, index); } } } return index; } + +void StoryboardView::mouseMoveEvent(QMouseEvent *event) +{ + event->accept(); + QListView::mouseMoveEvent(event); + + m_hoverIndex = indexAt(event->pos()); +} diff --git a/plugins/dockers/storyboarddocker/storyboardView.h b/plugins/dockers/storyboarddocker/storyboardView.h index 9d143acc11..0c293db6f5 100644 --- a/plugins/dockers/storyboarddocker/storyboardView.h +++ b/plugins/dockers/storyboarddocker/storyboardView.h @@ -1,48 +1,51 @@ /* Copyright (c) 2020 Saurabh Kumar This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef STORYBOARD_VIEW_H #define STORYBOARD_VIEW_H #include #include class QStyleOptionViewItem; class StoryboardModel; /** * This view draws the children of every index in the first column of * the model inside the parent index * * */ class StoryboardView: public QListView { Q_OBJECT public: explicit StoryboardView(QWidget *parent = 0); ~StoryboardView() override; void paintEvent(QPaintEvent *event) override; QRect visualRect(const QModelIndex &index) const override; QModelIndex indexAt(const QPoint &point) const override; + void mouseMoveEvent(QMouseEvent *event) override; +private: + QModelIndex m_hoverIndex; }; #endif diff --git a/plugins/dockers/storyboarddocker/storyboarddocker_dock.cpp b/plugins/dockers/storyboarddocker/storyboarddocker_dock.cpp index 5b35b7cb04..f520cebe9a 100644 --- a/plugins/dockers/storyboarddocker/storyboarddocker_dock.cpp +++ b/plugins/dockers/storyboarddocker/storyboarddocker_dock.cpp @@ -1,238 +1,240 @@ /* * Copyright (c) 2020 Saurabh Kumar * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "storyboarddocker_dock.h" #include "commentDelegate.h" #include "commentModel.h" #include "storyboardModel.h" #include "storyboardDelegate.h" #include #include #include #include #include #include #include #include #include #include #include "ui_wdgstoryboarddock.h" #include "ui_wdgcommentmenu.h" #include "ui_wdgarrangemenu.h" class CommentMenu: public QMenu { Q_OBJECT public: - CommentMenu(QWidget *parent) + CommentMenu(QWidget *parent, CommentModel *m_model) : QMenu(parent) , m_menuUI(new Ui_WdgCommentMenu()) - , model(new CommentModel(this)) + , model(m_model) , delegate(new CommentDelegate(this)) { QWidget* commentWidget = new QWidget(this); m_menuUI->setupUi(commentWidget); m_menuUI->fieldListView->setDragEnabled(true); m_menuUI->fieldListView->setAcceptDrops(true); m_menuUI->fieldListView->setDropIndicatorShown(true); m_menuUI->fieldListView->setDragDropMode(QAbstractItemView::InternalMove); m_menuUI->fieldListView->setModel(model); m_menuUI->fieldListView->setItemDelegate(delegate); m_menuUI->fieldListView->setEditTriggers(QAbstractItemView::AnyKeyPressed | QAbstractItemView::DoubleClicked ); m_menuUI->btnAddField->setIcon(KisIconUtils::loadIcon("list-add")); m_menuUI->btnDeleteField->setIcon(KisIconUtils::loadIcon("trash-empty")); m_menuUI->btnAddField->setIconSize(QSize(22, 22)); m_menuUI->btnDeleteField->setIconSize(QSize(22, 22)); connect(m_menuUI->btnAddField, SIGNAL(clicked()), this, SLOT(slotaddItem())); connect(m_menuUI->btnDeleteField, SIGNAL(clicked()), this, SLOT(slotdeleteItem())); KisAction *commentAction = new KisAction(commentWidget); commentAction->setDefaultWidget(commentWidget); this->addAction(commentAction); } private Q_SLOTS: void slotaddItem() { int row = m_menuUI->fieldListView->currentIndex().row()+1; model->insertRows(row, 1); QModelIndex index = model->index(row); m_menuUI->fieldListView->setCurrentIndex(index); m_menuUI->fieldListView->edit(index); } void slotdeleteItem() { model->removeRows(m_menuUI->fieldListView->currentIndex().row(), 1); } private: QScopedPointer m_menuUI; CommentModel *model; CommentDelegate *delegate; }; class ArrangeMenu: public QMenu { public: ArrangeMenu(QWidget *parent) : QMenu(parent) , m_menuUI(new Ui_WdgArrangeMenu()) , modeGroup(new QButtonGroup(this)) , viewGroup(new QButtonGroup(this)) { QWidget* arrangeWidget = new QWidget(this); m_menuUI->setupUi(arrangeWidget); modeGroup->addButton(m_menuUI->btnColumnMode, Qt::FlatCap); modeGroup->addButton(m_menuUI->btnRowMode, Qt::FlatCap); modeGroup->addButton(m_menuUI->btnGridMode, Qt::FlatCap); viewGroup->addButton(m_menuUI->btnAllView, Qt::FlatCap); viewGroup->addButton(m_menuUI->btnThumbnailsView, Qt::FlatCap); viewGroup->addButton(m_menuUI->btnCommentsView, Qt::FlatCap); KisAction *arrangeAction = new KisAction(arrangeWidget); arrangeAction->setDefaultWidget(arrangeWidget); this->addAction(arrangeAction); } QButtonGroup* getModeGroup(){ return modeGroup;} QButtonGroup* getViewGroup(){ return viewGroup;} private: QScopedPointer m_menuUI; QButtonGroup *modeGroup; QButtonGroup *viewGroup; }; StoryboardDockerDock::StoryboardDockerDock( ) : QDockWidget(i18n("Storyboard")) , m_ui(new Ui_WdgStoryboardDock()) { QWidget* mainWidget = new QWidget(this); setWidget(mainWidget); m_ui->setupUi(mainWidget); m_exportMenu = new QMenu(this); m_ui->btnExport->setMenu(m_exportMenu); m_ui->btnExport->setPopupMode(QToolButton::MenuButtonPopup); m_exportAsPdfAction = new KisAction("Export as PDF", m_exportMenu); m_exportMenu->addAction(m_exportAsPdfAction); m_exportAsSvgAction = new KisAction("Export as SVG"); m_exportMenu->addAction(m_exportAsSvgAction); connect(m_exportAsPdfAction, SIGNAL(triggered()), this, SLOT(slotExportAsPdf())); connect(m_exportAsSvgAction, SIGNAL(triggered()), this, SLOT(slotExportAsSvg())); - m_commentMenu = new CommentMenu(this); + m_commentModel = new CommentModel(this); + m_commentMenu = new CommentMenu(this, m_commentModel); m_ui->btnComment->setMenu(m_commentMenu); m_ui->btnComment->setPopupMode(QToolButton::MenuButtonPopup); m_lockAction = new KisAction(KisIconUtils::loadIcon("unlocked"), "Lock", m_ui->btnLock); m_lockAction->setCheckable(true); m_ui->btnLock->setDefaultAction(m_lockAction); m_ui->btnLock->setIconSize(QSize(22, 22)); connect(m_lockAction, SIGNAL(toggled(bool)), this, SLOT(slotLockClicked(bool))); m_arrangeMenu = new ArrangeMenu(this); m_ui->btnArrange->setMenu(m_arrangeMenu); m_ui->btnArrange->setPopupMode(QToolButton::InstantPopup); m_ui->btnArrange->setIcon(KisIconUtils::loadIcon("view-choose")); m_ui->btnArrange->setIconSize(QSize(22, 22)); m_modeGroup = m_arrangeMenu->getModeGroup(); m_viewGroup = m_arrangeMenu->getViewGroup(); connect(m_modeGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(slotModeChanged(QAbstractButton*))); connect(m_viewGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(slotViewChanged(QAbstractButton*))); - StoryboardModel *model = new StoryboardModel(this); + m_storyboardModel = new StoryboardModel(this); StoryboardDelegate *delegate = new StoryboardDelegate(this); delegate->setView(m_ui->listView); - m_ui->listView->setModel(model); + m_ui->listView->setModel(m_storyboardModel); m_ui->listView->setItemDelegate(delegate); delegate->setView(m_ui->listView); - model->insertRows(0, 10); + m_storyboardModel->insertRows(0, 10); + m_storyboardModel->setCommentModel(m_commentModel); } StoryboardDockerDock::~StoryboardDockerDock() { } void StoryboardDockerDock::setCanvas(KoCanvasBase *canvas) { } void StoryboardDockerDock::setViewManager(KisViewManager* kisview) { } void StoryboardDockerDock::slotExportAsPdf() { qDebug()<<"export as pdf"; slotExport("pdf"); } void StoryboardDockerDock::slotExportAsSvg() { qDebug()<<"export as svg"; slotExport("svg"); } void StoryboardDockerDock::slotExport(QString mode) { qDebug()<<"mode is "<setIcon(KisIconUtils::loadIcon("locked")); } else{ m_lockAction->setIcon(KisIconUtils::loadIcon("unlocked")); } } void StoryboardDockerDock::slotModeChanged(QAbstractButton* button) { qDebug()<<"Mode changed to "<text(); } void StoryboardDockerDock::slotViewChanged(QAbstractButton* button) { qDebug()<<"View changed to "<text(); } #include "storyboarddocker_dock.moc" \ No newline at end of file diff --git a/plugins/dockers/storyboarddocker/storyboarddocker_dock.h b/plugins/dockers/storyboarddocker/storyboarddocker_dock.h index eae3e232ad..8337ea8229 100644 --- a/plugins/dockers/storyboarddocker/storyboarddocker_dock.h +++ b/plugins/dockers/storyboarddocker/storyboarddocker_dock.h @@ -1,71 +1,76 @@ /* * Copyright (c) 2020 Saurabh Kumar * * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _STORYBOARDDOCKER_DOCK_H_ #define _STORYBOARDDOCKER_DOCK_H_ #include #include #include #include #include class Ui_WdgStoryboardDock; class CommentMenu; class ArrangeMenu; +class CommentModel; +class StoryboardModel; class StoryboardDockerDock : public QDockWidget, public KisMainwindowObserver{ Q_OBJECT public: StoryboardDockerDock(); ~StoryboardDockerDock() override; QString observerName() override { return "StoryboardDockerDock"; } void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override {} void setViewManager(KisViewManager* kisview) override; private: QScopedPointer m_ui; - + QMenu *m_exportMenu; KisAction *m_exportAsPdfAction; KisAction *m_exportAsSvgAction; + QPointer m_commentModel; CommentMenu *m_commentMenu; - + KisAction *m_lockAction; - + ArrangeMenu *m_arrangeMenu; QButtonGroup *m_modeGroup; QButtonGroup *m_viewGroup; + QPointer m_storyboardModel; + private Q_SLOTS: void slotExportAsPdf(); void slotExportAsSvg(); void slotExport(QString); //the comment button slots void slotLockClicked(bool); void slotModeChanged(QAbstractButton*); void slotViewChanged(QAbstractButton*); }; #endif