allow to expand a frame 2000 times
[dashstudio.git] / src / components / timeline / framestable.cpp
blobf03e2541f5aa04148bf2e2b1098346f49c1afac5
1 /***************************************************************************
2 * Copyright (C) 2005 by David Cuadrado *
3 * krawek@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include "framestable.h"
23 #include <QPainter>
24 #include <QPaintEvent>
25 #include <QItemSelectionModel>
26 #include <QPainterPath>
27 #include <QScrollBar>
28 #include <QHeaderView>
29 #include <QMenu>
30 #include <QInputDialog>
32 #include <dcore/debug.h>
33 #include <dcore/algorithm.h>
35 #include "tlruler.h"
37 namespace Dash {
38 namespace Component {
40 ////////// FramesTableItemDelegate ///////////
42 class FramesTableItemDelegate : public QAbstractItemDelegate
44 public:
45 FramesTableItemDelegate(QObject * parent = 0 );
46 ~FramesTableItemDelegate();
47 virtual void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
48 virtual QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;
51 FramesTableItemDelegate::FramesTableItemDelegate(QObject * parent) : QAbstractItemDelegate(parent)
55 FramesTableItemDelegate::~FramesTableItemDelegate()
61 void FramesTableItemDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
63 Q_ASSERT(index.isValid());
65 FramesTable *table = qobject_cast<FramesTable *>(index.model()->parent());
66 FramesTableItem *item = dynamic_cast<FramesTableItem *>(table->itemFromIndex(index));
68 QVariant value;
69 QStyleOptionViewItem opt = option;
71 // draw the background color
72 value = index.data( Qt::BackgroundColorRole );
74 if (value.isValid())
76 painter->save();
78 bool sound = table->isSoundLayer(index.row());
80 if( !sound )
82 painter->fillRect(option.rect, value.value<QColor>() );
84 painter->restore();
86 else
88 painter->save();
90 bool sound = table->isSoundLayer(index.row());
91 painter->setPen(QPen(Qt::lightGray, 1));
92 if( !sound )
94 if ( index.column() % 5 == 0 )
96 painter->setBrush(Qt::lightGray);
97 painter->drawRect(option.rect ); //FIXME: user paleta de colores
99 else
101 painter->setBrush(Qt::white);
102 painter->drawRect(option.rect);//FIXME: user paleta de color
105 else
107 painter->fillRect(option.rect, Qt::white);
110 painter->restore();
113 // Draw attributes
115 int offset = option.rect.width() - 4;
117 if ( item && index.isValid() )
119 if(item->isUsed() )
121 painter->save();
122 painter->setBrush(Qt::black);
124 if( !item->isSound() )
126 QColor color = Qt::white; //FIXME: user paleta de color
127 if ( item->inGroupPosition() == FramesTableItem::Begin )
129 painter->fillRect(option.rect, color);
130 painter->drawLine(option.rect.topLeft(), option.rect.bottomLeft());
131 painter->drawEllipse(option.rect.left()+2, option.rect.bottom() - (offset+2), offset, offset);
133 else if ( item->inGroupPosition() == FramesTableItem::End )
135 painter->fillRect(option.rect, color );
136 painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
138 else if( item->inGroupPosition() == FramesTableItem::Intermediate )
140 painter->fillRect(option.rect, color );
142 else
144 painter->drawEllipse(option.rect.left()+2, option.rect.bottom() - (offset+2), offset, offset);
147 else
149 painter->setPen(QPen(Qt::blue, 1));
151 int y = option.rect.center().y();
152 int xi = option.rect.x();
153 int xf = option.rect.width();
155 painter->drawLine(QPoint(xi, y) , QPoint(xf, y));
158 painter->restore();
161 if ( item->isLocked() )
163 painter->save();
164 painter->setBrush(Qt::red);
166 painter->drawEllipse(option.rect.left()+2, option.rect.bottom() - (offset+2), offset, offset);
168 painter->restore();
172 // Selection!
173 if (option.showDecorationSelected && (option.state & QStyle::State_Selected))
175 QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
177 painter->save();
178 painter->setPen(QPen(option.palette.brush(cg, QPalette::Highlight), 2));
180 QRectF rectSelection = option.rect.adjusted(1,1,-1,-1);
181 painter->drawRect(rectSelection);
182 painter->restore();
185 painter->save();
186 QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
187 painter->setPen(QPen(option.palette.brush(cg, QPalette::Foreground), 1)),
189 painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
190 painter->drawLine(option.rect.topLeft(), option.rect.topRight());
191 painter->restore();
194 QSize FramesTableItemDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
196 Q_ASSERT(index.isValid());
197 const QAbstractItemModel *model = index.model();
198 Q_ASSERT(model);
200 QVariant value = model->data(index, Qt::FontRole);
201 QFont fnt = value.isValid() ? qvariant_cast<QFont>(value) : option.font;
202 QString text = model->data(index, Qt::DisplayRole).toString();
203 QRect pixmapRect;
204 if (model->data(index, Qt::DecorationRole).isValid())
205 pixmapRect = QRect(0, 0, option.decorationSize.width(),
206 option.decorationSize.height());
208 QFontMetrics fontMetrics(fnt);
210 return (pixmapRect).size();
214 ////////// FramesTableItem ////////
216 FramesTableItem::FramesTableItem()
220 FramesTableItem::~FramesTableItem()
225 bool FramesTableItem::isUsed()
227 return data(IsUsed).toBool();
230 bool FramesTableItem::isLocked()
232 return data(IsLocked).toBool();
235 bool FramesTableItem::isVisible()
237 return data(IsVisible).toBool();
240 bool FramesTableItem::isSound()
242 QVariant data = this->data(IsSound);
244 if( data.canConvert<bool>() )
246 return data.toBool();
248 return false;
251 bool FramesTableItem::isClone()
253 QVariant data = this->data(IsClone);
255 if( data.canConvert<bool>() )
257 return data.toBool();
259 return false;
262 FramesTableItem::InGroupPositionType FramesTableItem::inGroupPosition()
264 QVariant data = this->data(InGroupPosition);
266 if( data.canConvert<int>() )
268 return InGroupPositionType(data.toInt());
270 return None;
274 //// FramesTable
276 struct FramesTable::Private
278 struct LayerItem
280 LayerItem() : lastItem(-1), sound(false) {};
281 int lastItem;
282 bool sound;
286 void swapItem( QTableWidgetItem *it, QTableWidgetItem *nextIt )
288 QVariant data = it->data(FramesTableItem::IsUsed);
290 it->setData(FramesTableItem::IsUsed, nextIt->data(FramesTableItem::IsUsed).toBool() );
291 nextIt->setData(FramesTableItem::IsUsed, data);
293 data = it->data(FramesTableItem::IsLocked);
294 it->setData(FramesTableItem::IsLocked, nextIt->data(FramesTableItem::IsLocked).toBool());
295 nextIt->setData(FramesTableItem::IsLocked, data);
298 data = it->data(FramesTableItem::IsVisible);
299 it->setData(FramesTableItem::IsVisible, nextIt->data(FramesTableItem::IsVisible).toBool());
300 nextIt->setData(FramesTableItem::IsVisible, data);
302 data = it->data(FramesTableItem::IsSound);
303 it->setData(FramesTableItem::IsSound, nextIt->data(FramesTableItem::IsSound).toBool());
304 nextIt->setData(FramesTableItem::IsSound, data);
306 data = it->data(FramesTableItem::InGroupPosition);
307 it->setData(FramesTableItem::InGroupPosition, nextIt->data(FramesTableItem::InGroupPosition));
308 nextIt->setData(FramesTableItem::InGroupPosition, data);
312 int groupSize(FramesTable *table, int layer, int beginFrame)
314 QTableWidgetItem *item = table->item(layer, beginFrame);
316 int count = 0;
318 dfDebug << "begin Frame " << beginFrame << " type " << item->data(FramesTableItem::InGroupPosition).toInt();
320 if(item->data(FramesTableItem::InGroupPosition).toInt() == FramesTableItem::Begin)
322 while(item && item->data(FramesTableItem::InGroupPosition).toInt() != FramesTableItem::End)
324 count++;
325 item = table->item(layer, beginFrame+count);
329 return count+1;
332 int rectWidth, rectHeight;
333 QList<LayerItem> layers;
334 TLRuler *ruler;
336 enum Action {
337 InsertFrame = 0,
338 RemoveFrame,
339 ToggleLockFrame,
340 ToggleFrameVisibility,
341 ExpandFrame
346 FramesTable::FramesTable(QWidget *parent) : QTableWidget(0, 100, parent), d(new Private)
348 d->ruler = new TLRuler;
349 setup();
352 FramesTable::~FramesTable()
354 delete d;
357 void FramesTable::setup()
359 setItemDelegate( new FramesTableItemDelegate(this) );
361 setSelectionBehavior(QAbstractItemView::SelectItems);
362 setSelectionMode (QAbstractItemView::SingleSelection);
364 setHorizontalHeader(d->ruler);
366 connect(d->ruler, SIGNAL(logicalSectionSelected( int )), this, SLOT(emitFrameSelected( int )));
367 // connect(this, SIGNAL(currentItemChanged( QTableWidgetItem *, QTableWidgetItem *)), this, SLOT(emitFrameSelected(QTableWidgetItem *, QTableWidgetItem *)));
368 verticalHeader()->hide();
371 connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(onItemSelectionChanged()));
373 connect( this, SIGNAL(cellDoubleClicked ( int , int )), this, SLOT(onCellDoubleClicked(int, int)));
375 setItemSize( 10, 25 );
377 horizontalHeader()->setResizeMode(QHeaderView::Custom);
378 verticalHeader()->setResizeMode(QHeaderView::Custom);
381 setSelectionMode(QAbstractItemView::ContiguousSelection);
382 setShowGrid(false);
385 void FramesTable::emitFrameSelected(int col)
387 selectColumn(col);
389 FramesTableItem *item = dynamic_cast<FramesTableItem *>(this->item(currentRow(), col));
391 if( item )
393 if( item->isUsed())
395 emit frameSelected(visualRow(this->row(item)), visualColumn(this->column(item)));
400 void FramesTable::onItemSelectionChanged()
402 FramesTableItem *item = dynamic_cast<FramesTableItem *>(currentItem());
403 if( item )
405 if( item->isUsed())
407 emit frameSelected(visualRow(this->row(item)), visualColumn(this->column(item)));
410 else
412 emit layerSelected(visualRow(currentRow()));
416 void FramesTable::mousePressEvent ( QMouseEvent * event )
418 QTableWidget::mousePressEvent(event);
421 if(event->buttons() == Qt::RightButton )
423 QMenu *menu = new QMenu(tr("Frames"), this);
425 FramesTableItem *item = dynamic_cast<FramesTableItem *>(currentItem());
426 if(item)
428 menu->addAction( tr("Insert frame"))->setData(Private::InsertFrame);
430 if(item->isUsed())
432 menu->addAction( tr("Remove frame"))->setData(Private::RemoveFrame);
433 menu->addAction( tr("Expand this frame"))->setData(Private::ExpandFrame);
436 menu->addSeparator();
438 if(item->isLocked())
440 menu->addAction( tr("Unlock this frame"))->setData(Private::ToggleLockFrame);
442 else
444 menu->addAction( tr("Lock this frame"))->setData(Private::ToggleLockFrame);
447 if(item->isVisible())
449 menu->addAction( tr("Hide this frame"))->setData(Private::ToggleFrameVisibility);
451 else
453 menu->addAction( tr("Show this frame"))->setData(Private::ToggleFrameVisibility);
457 connect(menu, SIGNAL(triggered(QAction *)), this, SLOT(onMenuActionTriggered(QAction * )));
458 menu->exec( event->globalPos() );
463 void FramesTable::onCellDoubleClicked(int row, int column)
465 row = visualRow(row);
466 if( lastFrameByLayer(row)+1 == column )
468 emit requestInsertFrame(row, column);
472 void FramesTable::onMenuActionTriggered(QAction * action)
474 int layerPos = visualRow(currentRow());
475 int framePos = visualColumn(currentColumn());
477 switch(action->data().toInt())
479 case Private::InsertFrame:
481 FramesTableItem *item = dynamic_cast<FramesTableItem *>(currentItem());
482 if(item)
484 if(item->isUsed())
486 emit requestInsertFrame(layerPos, framePos+1);
490 break;
491 case Private::RemoveFrame:
493 emit requestRemoveFrame(layerPos, framePos);
495 break;
496 case Private::ToggleLockFrame:
498 FramesTableItem *item = dynamic_cast<FramesTableItem *>(currentItem());
499 if(item)
501 emit requestLockFrame(layerPos, framePos, !item->isLocked());
504 break;
505 case Private::ToggleFrameVisibility:
507 FramesTableItem *item = dynamic_cast<FramesTableItem *>(currentItem());
508 if(item)
510 emit requestChangeFrameVisibility(layerPos, framePos, !item->isVisible());
513 break;
514 case Private::ExpandFrame:
516 FramesTableItem *item = dynamic_cast<FramesTableItem *>(currentItem());
517 if(item)
519 bool ok = false;
520 int size = QInputDialog::getInteger ( 0, tr("Expand frame"), tr("number of frames to enlarge this frame?"), 1, 1, 2000, 1, &ok);
522 if(ok)
524 dfDebug << framePos;
525 emit requestExpandFrame(layerPos, framePos, size);
529 break;
533 void FramesTable::setItemSize(int w, int h)
535 d->rectHeight = h;
536 d->rectWidth = w;
538 fixSize();
541 void FramesTable::expandFrame( int layerPosition, int position, int size )
543 groupFrames( layerPosition, position, position+size);
545 for(int i = position; i < position+size; i++)
547 QTableWidgetItem *item = this->item(layerPosition, i);
548 item->setData(FramesTableItem::IsClone, true);
553 void FramesTable::groupFrames( int layerPosition, int from, int to )
555 for(int i = from+1; i <= to; i++)
557 QTableWidgetItem *item = this->item(layerPosition, i);
559 if(item)
561 item->setData(FramesTableItem::InGroupPosition, QVariant( FramesTableItem::Intermediate));
565 QTableWidgetItem *begin = this->item(layerPosition, from);
567 if(begin)
569 begin->setData(FramesTableItem::InGroupPosition ,QVariant(FramesTableItem::Begin));
572 QTableWidgetItem *end = this->item(layerPosition, to);
574 if(end)
576 QTableWidgetItem *nextEnd = this->item(layerPosition, to+1);
578 if(nextEnd)
580 if(nextEnd->data(FramesTableItem::InGroupPosition).toInt() != FramesTableItem::None || nextEnd->data(FramesTableItem::InGroupPosition).toInt() != FramesTableItem::Begin)
582 end->setData(FramesTableItem::InGroupPosition, QVariant(FramesTableItem::Intermediate));
583 viewport()->update();
584 return;
587 end->setData(FramesTableItem::InGroupPosition, QVariant(FramesTableItem::End));
590 viewport()->update();
593 void FramesTable::destroyGroupFrames(int layerPosition, int position, int size)
595 for(int i = position; i <= position+size; i++)
597 QTableWidgetItem *item = this->item(layerPosition, i);
599 if(item)
601 item->setData(FramesTableItem::InGroupPosition, QVariant( FramesTableItem::None));
602 item->setData(FramesTableItem::IsClone, false);
607 bool FramesTable::isSoundLayer(int row)
609 if( row < 0 && row >= d->layers.count() )
610 return false;
612 return d->layers[row].sound;
615 void FramesTable::insertLayer(int pos, const QString &name)
617 insertRow( pos );
619 Private::LayerItem layer;
620 layer.sound = false;
621 d->layers.insert(pos, layer);
623 fixSize();
626 void FramesTable::insertSoundLayer(int layerPos, const QString &name)
628 insertRow(layerPos);
630 Private::LayerItem layer;
631 layer.sound = true;
632 d->layers.insert(layerPos, layer);
634 fixSize();
637 void FramesTable::removeCurrentLayer()
639 int pos = verticalHeader()->logicalIndex(currentRow());
640 removeLayer(pos);
643 void FramesTable::removeLayer(int pos)
645 pos = verticalHeader()->logicalIndex(pos);
646 removeRow( pos );
647 d->layers.removeAt(pos);
650 void FramesTable::moveLayer(int position, int newPosition)
652 if ( position < 0 || position >= rowCount() || newPosition < 0 || newPosition >= rowCount() ) return;
654 blockSignals(true);
656 verticalHeader()->moveSection(position, newPosition);
658 blockSignals(false);
661 int FramesTable::lastFrameByLayer(int layerPos)
663 int pos = verticalHeader()->logicalIndex(layerPos);
664 if ( pos < 0 || pos > d->layers.count() )
666 return -1;
668 return d->layers[pos].lastItem;
671 // FRAMES
673 void FramesTable::addFrame(int layerPos, const QString &name)
675 if ( layerPos < 0 || layerPos >= d->layers.count() ) return;
677 insertFrame(layerPos, lastFrameByLayer(verticalHeader()->logicalIndex(layerPos))+1, name) ;
680 void FramesTable::insertFrame(int layerPos, int framePos, const QString &name)
683 if ( layerPos < 0 || layerPos >= d->layers.count() ) return;
685 layerPos = verticalHeader()->logicalIndex(layerPos);
687 d->layers[layerPos].lastItem++;
689 int position = framePos;
691 if(!d->layers[layerPos].sound)
693 position = d->layers[layerPos].lastItem;
696 setAttribute( layerPos, position, FramesTableItem::IsUsed, true);
697 setAttribute( layerPos, position, FramesTableItem::IsVisible, true);
698 setAttribute( layerPos, position, FramesTableItem::IsSound, d->layers[layerPos].sound);
699 item( layerPos, position)->setData(FramesTableItem::InGroupPosition, FramesTableItem::None);
701 if(!d->layers[layerPos].sound)
703 moveFrame(layerPos, position, framePos);
705 if ( d->layers[layerPos].lastItem >= columnCount()-1 )
707 setColumnCount( d->layers[layerPos].lastItem+50 );
708 fixSize();
711 viewport()->update();
714 void FramesTable::setCurrentFrame(FramesTableItem *item)
716 setCurrentItem(item);
719 void FramesTable::setCurrentLayer(int layerPos)
721 setCurrentItem(item(verticalHeader()->logicalIndex(layerPos), 0));
724 void FramesTable::selectFrame(int index)
726 setCurrentItem( item( currentRow(), index ) );
729 void FramesTable::removeFrame(int layerPos, int position)
731 if ( layerPos < 0 || layerPos >= d->layers.count() )
733 return;
737 QTableWidgetItem *it = this->item(layerPos, position);
739 moveFrame(layerPos, position, d->layers[layerPos].lastItem);
741 QTableWidgetItem *toRemove = takeItem(layerPos, d->layers[layerPos].lastItem);
743 int type = toRemove->data(FramesTableItem::InGroupPosition).toInt();
745 if(type == FramesTableItem::Begin)
747 it = item(layerPos, position);
749 if(it)
751 if(it->data(FramesTableItem::InGroupPosition).toInt() == FramesTableItem::Intermediate)
753 it->setData(FramesTableItem::InGroupPosition, toRemove->data(FramesTableItem::InGroupPosition));
755 else if(it->data(FramesTableItem::InGroupPosition).toInt() == FramesTableItem::End)
757 it->setData(FramesTableItem::InGroupPosition, FramesTableItem::None);
758 it->setData(FramesTableItem::IsClone, false);
762 else if(toRemove->data(FramesTableItem::InGroupPosition).toInt() == FramesTableItem::End)
764 it = item(layerPos, position);
765 if(it)
767 if(it->data(FramesTableItem::InGroupPosition).toInt() == FramesTableItem::Begin)
769 it->setData(FramesTableItem::InGroupPosition, FramesTableItem::None);
775 delete toRemove;
776 toRemove = 0;
778 d->layers[layerPos].lastItem--;
780 viewport()->update( visualRect(indexFromItem(item(layerPos, position) )) );
781 viewport()->update();
784 void FramesTable::moveFrame(int layerPos, int from, int to)
786 if(from == to)
788 return;
791 layerPos = verticalHeader()->logicalIndex(layerPos);
793 if(to > from)
795 int fromSize = d->groupSize(this, layerPos, from);
796 int toSize = d->groupSize(this, layerPos, to);
798 for(int i = 0; i < fromSize; i++)
800 for(int index = from; index < to+toSize-1; index++ )
802 QTableWidgetItem *it = item(layerPos, index);
803 QTableWidgetItem *nextIt = item(layerPos, index+1);
804 if(nextIt)
806 d->swapItem(it, nextIt);
811 else
813 int fromSize = d->groupSize(this, layerPos, from);
814 int toSize = d->groupSize(this, layerPos, to);
816 for(int i = 0; i < fromSize; i++)
818 for(int index = from+i; index > to+i; index-- )
820 QTableWidgetItem *it = item(layerPos, index);
821 QTableWidgetItem *nextIt = item(layerPos, index-1);
822 if(nextIt)
824 d->swapItem(it, nextIt);
830 viewport()->update();
833 void FramesTable::lockFrame(int layerPos, int position, bool locked)
835 if ( layerPos < 0 || layerPos >= d->layers.count() )
837 return;
840 layerPos = verticalHeader()->logicalIndex(layerPos);
842 setAttribute( layerPos, position, FramesTableItem::IsLocked, locked );
844 viewport()->update();
847 void FramesTable::setFrameVisibility(int layerPosition, int position, bool isVisible)
849 if ( layerPosition < 0 || layerPosition >= d->layers.count() )
851 return;
854 layerPosition = verticalHeader()->logicalIndex(layerPosition);
856 setAttribute( layerPosition, position, FramesTableItem::IsVisible, isVisible );
858 viewport()->update();
862 void FramesTable::setAttribute(int row, int col, FramesTableItem::Attributes att, bool value)
864 QTableWidgetItem *item = this->item(row, col);
866 if( !item )
868 item = new FramesTableItem;
869 setItem(row, col, item);
872 item->setData(att, value);
875 void FramesTable::fixSize()
877 for(int column = 0; column < columnCount(); column++)
879 horizontalHeader()->resizeSection(column, d->rectWidth);
881 for( int row = 0; row < rowCount(); row++)
883 verticalHeader()->resizeSection(row, d->rectHeight);