Intial version of new song-editor, more of a viewer right now

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@2013 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Paul Giblock
2009-02-11 00:56:03 +00:00
parent a48b0b6ce0
commit f057a52ab9
12 changed files with 756 additions and 2 deletions

View File

@@ -1,3 +1,22 @@
2009-02-10 Paul Giblock <drfaygo/at/gmail/dot/com>
* include/gui:
* include/gui/tracks:
* include/gui/tracks/track_content_object_item.h:
* include/gui/tracks/track_item.h:
* include/gui/tracks/track_container_scene.h:
* include/track_container.h:
* include/track.h:
* src/gui/tracks:
* src/gui/tracks/track_content_object_item.cpp:
* src/gui/tracks/track_item.cpp:
* src/gui/tracks/track_container_scene.cpp:
* src/gui/main_window.cpp:
* src/core/track_container.cpp:
* src/core/track.cpp:
- Commit initial version of QGraphicsScene-based Song Editor
- Please save bugreports for another week or so, this is immature code
2009-02-09 Paul Giblock <drfaygo/at/gmail/dot/com>
* include/basic_filters.h:

View File

@@ -0,0 +1,122 @@
/*
* track_container_scene.h - view-component for trackContainer
*
* Copyright (c) 2009 Paul Giblock <pgib/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* 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 (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef _TRACK_CONTAINER_SCENE_H
#define _TRACK_CONTAINER_SCENE_H
#include <QtCore/QVector>
#include <QGraphicsScene>
#include "track.h"
class trackContainer;
class TrackContentObjectItem;
class TrackItem;
class TrackContainerScene : public QGraphicsScene
{
Q_OBJECT
public:
const static float DEFAULT_CELL_HEIGHT = 32;
const static float DEFAULT_CELL_WIDTH = 16;
TrackContainerScene( QObject * parent, trackContainer * _tc );
virtual ~TrackContainerScene();
inline const midiTime & currentPosition( void ) const
{
return( m_currentPosition );
}
inline float pixelsPerTact( void ) const
{
return( m_ppt );
}
void setPixelsPerTact( float _ppt );
trackContainer * model( void )
{
return( m_trackContainer );
}
const trackContainer * model( void ) const
{
return( m_trackContainer );
}
virtual QString nodeName( void ) const
{
return( "trackcontainerscene" );
}
private slots:
void addTrack( track * _t );
void removeTrack( track * _t );
/*
virtual void dragEnterEvent( QDragEnterEvent * _dee );
virtual void dropEvent( QDropEvent * _de );
virtual void mousePressEvent( QMouseEvent * _me );
virtual void mouseMoveEvent( QMouseEvent * _me );
virtual void mouseReleaseEvent( QMouseEvent * _me );
virtual void resizeEvent( QResizeEvent * );
virtual void undoStep( journalEntry & _je );
virtual void redoStep( journalEntry & _je );
*/
protected:
midiTime m_currentPosition;
trackContainer * m_trackContainer;
float m_ppt;
//QVector<TrackContentItem*> m_trackItems;
QMap<track*, TrackItem*> m_trackItems;
virtual void keyPressEvent( QKeyEvent * event );
private:
/*
enum Actions
{
AddTrack,
RemoveTrack
} ;*/
//signals:
//void positionChanged( const midiTime & _pos );
} ;
#endif

View File

@@ -0,0 +1,64 @@
#ifndef TRACK_CONTENT_OBJECT_ITEM_H_
#define TRACK_CONTENT_OBJECT_ITEM_H_
#include <QtCore/QVector>
#include <QGraphicsScene>
#include <QGraphicsItem>
#include <QTimeLine>
#include <QGraphicsItemAnimation>
#include <QPainter>
#include <math.h>
class trackContentObject;
class TrackItem;
class TrackContentObjectItem : public QObject, public QGraphicsItem
{
Q_OBJECT
friend class TrackContainerScene;
public:
TrackContentObjectItem( TrackItem * _track, trackContentObject * _object );
virtual ~TrackContentObjectItem()
{
if( m_snapBackAnimation != NULL )
{
delete m_snapBackAnimation;
}
};
QRectF boundingRect() const;
void paint( QPainter * _painter, const QStyleOptionGraphicsItem * _option,
QWidget * _widget );
QVariant itemChange( GraphicsItemChange _change, const QVariant & _value );
virtual qreal zValue() const;
// For TrackItem to call
void updateGeometry();
protected:
void prepareSnapBackAnimation( QTimeLine * timeLine );
void prepareSnapBackAnimation( QTimeLine * timeLine, int newX );
virtual void mousePressEvent( QGraphicsSceneMouseEvent * event );
virtual void mouseReleaseEvent( QGraphicsSceneMouseEvent * event );
virtual void hoverEnterEvent( QGraphicsSceneHoverEvent * event );
virtual void hoverLeaveEvent( QGraphicsSceneHoverEvent * event );
protected:
QPointF m_lastPos;
QPointF m_lastDest;
QGraphicsItemAnimation * m_snapBackAnimation;
static QTimeLine s_snapBackTimeLine;
TrackItem * m_trackItem;
trackContentObject * m_tco;
};
#endif

View File

@@ -0,0 +1,47 @@
/*
* track_item.h
*
* Created on: Jan 27, 2009
* Author: llama
*/
#ifndef TRACK_ITEM_H_
#define TRACK_ITEM_H_
#include <QObject>
#include <QRectF>
#include <QMap>
class TrackContainerScene;
class track;
class trackContentObject;
class TrackContentObjectItem;
class TrackItem : public QObject
{
Q_OBJECT;
public:
TrackItem( TrackContainerScene * _scene, track * _track );
virtual ~TrackItem( );
float height();
void setHeight( float _height );
float y();
void setY( float _x );
private slots:
void addTCO( trackContentObject * _tco );
void removeTCO( trackContentObject * _tco );
private:
QRectF m_rect;
TrackContainerScene * m_scene;
track * m_track;
QMap<trackContentObject*, TrackContentObjectItem *> m_tcoItems;
};
#endif /* TRACK_ITEM_H_ */

View File

@@ -63,7 +63,7 @@ const int TCO_BORDER_WIDTH = 1;
class trackContentObject : public model, public journallingObject
{
Q_OBJECT
mapPropertyFromModel(bool,isMuted,setMuted,m_mutedModel);
mapPropertyFromModel( bool, isMuted, setMuted, m_mutedModel);
public:
trackContentObject( track * _track );
virtual ~trackContentObject();
@@ -463,6 +463,7 @@ signals:
void destroyedTrack( void );
void nameChanged( void );
void trackContentObjectAdded( trackContentObject * );
void trackContentObjectRemoved( trackContentObject * );
} ;

View File

@@ -82,6 +82,7 @@ public:
signals:
void trackAdded( track * _track );
void trackRemoved( track * _track );
protected:
mutable QReadWriteLock m_tracksMutex;

View File

@@ -493,7 +493,7 @@ void trackContentObjectView::dropEvent( QDropEvent * _de )
// the user doesn't expect...
midiTime pos = m_tco->startPosition();
m_tco->restoreState( mmp.content().firstChild().toElement() );
m_tco->movePosition( pos );
m_tco->movePosition( pos );
automationPattern::resolveAllIDs();
_de->accept();
}
@@ -1776,6 +1776,7 @@ void track::removeTCO( trackContentObject * _tco )
if( it != m_trackContentObjects.end() )
{
m_trackContentObjects.erase( it );
emit trackContentObjectRemoved( _tco );
engine::getSong()->setModified();
}
}

View File

@@ -170,6 +170,7 @@ void trackContainer::removeTrack( track * _track )
m_tracksMutex.lockForWrite();
m_tracks.remove( index );
m_tracksMutex.unlock();
emit trackRemoved( _track );
if( engine::getSong() )
{
@@ -193,6 +194,7 @@ void trackContainer::clearAllTracks( void )
//m_tracksMutex.lockForWrite();
while( !m_tracks.isEmpty() )
{
emit trackRemoved( m_tracks.first() );
delete m_tracks.first();
}
//m_tracksMutex.unlock();

View File

@@ -40,6 +40,8 @@
#include <QtGui/QRadioButton>
#include <QShortcut>
#include <QGraphicsView>
#include "lmmsversion.h"
#include "main_window.h"
@@ -74,6 +76,7 @@
#include "cpuload_widget.h"
#include "visualization_widget.h"
#include "gui/tracks/track_container_scene.h"
mainWindow::mainWindow( void ) :
@@ -192,6 +195,29 @@ mainWindow::mainWindow( void ) :
vbox->addWidget( w );
setCentralWidget( main_widget );
/// HACK TO CREATE EXTRA SONG EDITOR FOR NOW ///
//Fun test
TrackContainerScene * scene = new TrackContainerScene( this, engine::getSong() );
// Mem leak
QPixmap * sceneBg = new QPixmap( 16*4*2, 32 );
QPainter * sceneBgPainter = new QPainter( sceneBg );
engine::getLmmsStyle()->drawTrackContentBackground(
sceneBgPainter,
QSize( 16*4, 32 ),
16 );
QGraphicsView *view = new QGraphicsView( scene );
view->setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
view->setDragMode( QGraphicsView::RubberBandDrag );
view->setAlignment( Qt::AlignLeft | Qt::AlignTop );
view->setBackgroundBrush( QBrush(*sceneBg) );
view->show();
//view->scale(2.0, 1.0);
QMdiSubWindow * subWin = workspace()->addSubWindow( view );
/// END HACK TO CREATE EXTRA SONG EDITOR FOR NOW ///
m_updateTimer.start( 1000 / 20, this ); // 20 fps
}

View File

@@ -0,0 +1,118 @@
#include <QGraphicsScene>
#include <QKeyEvent>
#include <QTimeLine>
#include <stdio.h>
#include "gui/tracks/track_container_scene.h"
#include "gui/tracks/track_content_object_item.h"
#include "gui/tracks/track_item.h"
#include "track_container.h"
TrackContainerScene::TrackContainerScene( QObject * parent, trackContainer * _tc ) :
QGraphicsScene( parent ),
//modelView( NULL, this ),
//journallingObject(),
//serializingObjectHook(),
m_trackContainer( _tc ),
m_ppt( 16 )
{
connect( m_trackContainer, SIGNAL( trackAdded( track * ) ),
this, SLOT( addTrack( track * ) ),
Qt::QueuedConnection );
connect( m_trackContainer, SIGNAL( trackRemoved( track * ) ),
this, SLOT( removeTrack( track * ) ) );
}
TrackContainerScene::~TrackContainerScene()
{
}
void TrackContainerScene::setPixelsPerTact( float _ppt )
{
m_ppt = _ppt;
}
void TrackContainerScene::addTrack( track * _t )
{
TrackItem * item = new TrackItem( this, _t );
item->setHeight( DEFAULT_CELL_HEIGHT );
item->setY( m_trackItems.size() * DEFAULT_CELL_HEIGHT );
m_trackItems.insert( _t, item );
}
void TrackContainerScene::removeTrack( track * _t )
{
QMap<track*, TrackItem*>::iterator i =
m_trackItems.find( _t );
if( i != m_trackItems.end() && i.key() == _t )
{
TrackItem * item = i.value();
qreal h = item->height();
i = m_trackItems.erase(i);
delete item;
// Now move everything after back up
while( i != m_trackItems.end() )
{
(*i)->setY( (*i)->y() - h );
++i;
}
}
}
void TrackContainerScene::keyPressEvent( QKeyEvent * event )
{
if( event->modifiers() == Qt::ShiftModifier )
{
const qreal cellWidth = TrackContainerScene::DEFAULT_CELL_WIDTH;
if( event->key() == Qt::Key_Left )
{
}
else if( event->key() == Qt::Key_Right )
{
QTimeLine * timeLine = new QTimeLine();
// TODO: Cleanup the friendly references
QList<QGraphicsItem*> selItems = selectedItems();
for( QList<QGraphicsItem *>::iterator it = selItems.begin();
it != selItems.end(); ++it )
{
TrackContentObjectItem * tcoItem =
dynamic_cast<TrackContentObjectItem*>( *it );
if( tcoItem )
{
qreal destPos = tcoItem->m_snapBackAnimation->posAt( 1.0 ).x();
tcoItem->prepareSnapBackAnimation( timeLine, destPos + cellWidth );
}
}
timeLine->setCurrentTime( 0.0f );
timeLine->setDuration( 300 );
timeLine->setCurveShape( QTimeLine::EaseInOutCurve );
connect( timeLine, SIGNAL(finished()), timeLine, SLOT(deleteLater()));
timeLine->start();
}
}
}
#include "gui/tracks/moc_track_container_scene.cxx"

View File

@@ -0,0 +1,244 @@
#include <QObject>
#include <QGraphicsItem>
#include <QTimeLine>
#include <QGraphicsItemAnimation>
#include <QStyleOptionGraphicsItem>
#include "gui/tracks/track_content_object_item.h"
#include "gui/tracks/track_container_scene.h"
#include "gui/tracks/track_item.h"
#include "track.h"
//QTimeLine TrackContentObjectItem::s_timeLine;
//QGraphicsItemAnimation TrackContentObjectItem::s_animation;
QTimeLine TrackContentObjectItem::s_snapBackTimeLine;
TrackContentObjectItem::TrackContentObjectItem( TrackItem * _track, trackContentObject * _object ) :
QObject(),
QGraphicsItem(),
m_trackItem( _track ),
m_tco( _object ),
m_snapBackAnimation( NULL )
{
//m_object = _object;
setFlags( QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable );
setCursor( Qt::OpenHandCursor );
midiTime startPos = _object->startPosition();
float x = TrackContainerScene::DEFAULT_CELL_WIDTH *
startPos.getTicks() / midiTime::ticksPerTact();
setPos( x, _track->y() );
setZValue(x);
m_snapBackAnimation = new QGraphicsItemAnimation();
m_snapBackAnimation->setItem( this );
}
QRectF TrackContentObjectItem::boundingRect() const
{
qreal penWidth = 1;
// TODO: Calculate based on track length and an adjustable height.
/*return QRectF( -64 - penWidth / 2, -16 - penWidth / 2,
128 + penWidth / 2, 32 + penWidth / 2 );*/
QRectF rc = QRectF( 0, 0, TrackContainerScene::DEFAULT_CELL_WIDTH *
m_tco->length().getTicks() / midiTime::ticksPerTact(), m_trackItem->height() );
return rc;
}
qreal TrackContentObjectItem::zValue() const
{
//return x();
//return m_tco->startPotion().getTicks();
return QGraphicsItem::zValue();
}
void TrackContentObjectItem::updateGeometry()
{
prepareGeometryChange();
}
void TrackContentObjectItem::paint( QPainter * _painter,
const QStyleOptionGraphicsItem * _option, QWidget * _widget )
{
QColor col;
if( !isSelected() )
{
col = QColor( 0x00, 0x33, 0x99 );
}
else
{
col = QColor( 0x99, 0x33, 0x00 );
}
QColor col0 = col.light( 130 );
QColor col1 = col.light( 70 );
QColor col2 = col.light( 40 );
QRectF rc = boundingRect();
qreal xscale = _option->matrix.m11();
_painter->save();
_painter->scale( 1.0f/xscale, 1.0f );
rc.setWidth( rc.width() * xscale );
QLinearGradient lingrad( 0, 0, 0, rc.height() );
lingrad.setColorAt( 0, col0 );
lingrad.setColorAt( 1, col1 );
QLinearGradient bordergrad( 0, 0, 0, rc.height() );
bordergrad.setColorAt( 1, col2 );
bordergrad.setColorAt( 0, col1 );
rc.adjust( 0, 0, -1, -1 );
_painter->setRenderHint( QPainter::Antialiasing, true );
_painter->setBrush( lingrad );
_painter->setPen( QPen( bordergrad, 1.5 ) ); // QColor( 6, 6, 6 ) );
_painter->drawRoundedRect( rc, 4, 4 );
_painter->setRenderHint( QPainter::Antialiasing, false );
_painter->restore();
}
QVariant TrackContentObjectItem::itemChange( GraphicsItemChange _change, const QVariant & _value )
{
if( _change == ItemPositionChange && scene( ) )
{
// value is the new position
QPointF newPos = _value.toPointF( );
//printf("TCO %lld: itemChange (%.2f %.2f) -> ", m_tco, newPos.x(), newPos.y());
if( newPos.x() < 0 )
{
newPos.setX( 0 );
}
if( newPos.y() < 0 )
{
newPos.setY( 0 );
}
/* Let's just short-circuit the Y for now
if( fmod( newPos.y(), 32 ) != 16 )
{
newPos.setY( newPos.y() + 16 - ( fmod( newPos.y(), 32 ) ) );
} */
newPos.setY( m_trackItem->y() );
/*
if( fmod( newPos.x(), 16 ) != 0 )
{
newPos.setX( newPos.x() - ( fmod( newPos.x(), 16 ) ) );
}
if( newPos.x() != x() ) {
setZValue(newPos.x());
}*/
//printf("(%.2f %.2f)\n", newPos.x(), newPos.y());
return newPos;
}
else if( _change == QGraphicsItem::ItemSelectedChange && scene() )
{
bool sel = _value.toBool();
if( sel )
{
setCursor( Qt::OpenHandCursor );
}
else
{
setCursor( Qt::OpenHandCursor );
}
}
return QGraphicsItem::itemChange( _change, _value );
}
void TrackContentObjectItem::mousePressEvent( QGraphicsSceneMouseEvent * event )
{
QGraphicsItem::mousePressEvent( event );
if( isSelected() )
{
setCursor( Qt::ClosedHandCursor );
}
}
void TrackContentObjectItem::mouseReleaseEvent( QGraphicsSceneMouseEvent * event )
{
QGraphicsItem::mouseReleaseEvent( event );
setCursor( Qt::OpenHandCursor );
QTimeLine * timeLine = new QTimeLine();
prepareSnapBackAnimation( timeLine );
if( isSelected() ) {
QList<QGraphicsItem*> selItems = scene()->selectedItems();
for( QList<QGraphicsItem *>::iterator it = selItems.begin();
it != selItems.end(); ++it )
{
TrackContentObjectItem * tcoItem =
dynamic_cast<TrackContentObjectItem*>( *it );
if( tcoItem )
{
tcoItem->prepareSnapBackAnimation( timeLine );
}
}
}
timeLine->setCurrentTime( 0.0f );
timeLine->setDuration( 300 );
timeLine->setCurveShape( QTimeLine::EaseInOutCurve );
connect( timeLine, SIGNAL(finished()), timeLine, SLOT(deleteLater()));
timeLine->start();
}
void TrackContentObjectItem::hoverEnterEvent( QGraphicsSceneHoverEvent * event )
{
QGraphicsItem::hoverEnterEvent( event );
}
void TrackContentObjectItem::hoverLeaveEvent( QGraphicsSceneHoverEvent * event )
{
QGraphicsItem::hoverLeaveEvent( event );
}
void TrackContentObjectItem::prepareSnapBackAnimation( QTimeLine * timeLine )
{
prepareSnapBackAnimation( timeLine, x() );
}
void TrackContentObjectItem::prepareSnapBackAnimation( QTimeLine * timeLine, int newX )
{
const qreal cellWidth = TrackContainerScene::DEFAULT_CELL_WIDTH;
const qreal xVal = newX + TrackContainerScene::DEFAULT_CELL_WIDTH * 0.5f;
QPointF newPos( xVal - ( fmod( xVal, cellWidth) ), y() );
m_snapBackAnimation->setTimeLine( timeLine );
m_snapBackAnimation->setPosAt( 0.0, pos() );
m_snapBackAnimation->setPosAt( 1.0, newPos );
}
#include "gui/tracks/moc_track_content_object_item.cxx"

View File

@@ -0,0 +1,109 @@
#include "track.h"
#include "gui/tracks/track_item.h"
#include "gui/tracks/track_content_object_item.h"
#include "gui/tracks/track_container_scene.h"
TrackItem::TrackItem( TrackContainerScene * _scene, track * _track )
{
m_scene = _scene;
m_track = _track;
// create views for already existing TCOs
const track::tcoVector & tcos = m_track->getTCOs();
for( track::tcoVector::const_iterator it = tcos.begin(); it != tcos.end(); ++it )
{
addTCO( *it );
}
QObject * obj = _track;
connect( obj, SIGNAL( trackContentObjectAdded( trackContentObject * ) ),
this, SLOT( addTCO( trackContentObject * ) ),
Qt::QueuedConnection );
connect( obj, SIGNAL( trackContentObjectRemoved( trackContentObject * ) ),
this, SLOT( removeTCO( trackContentObject * ) ) );
}
/* WTF?!?! */
TrackItem::~TrackItem()
{
for( QMap<trackContentObject*, TrackContentObjectItem*>::iterator i = m_tcoItems.begin();
i != m_tcoItems.end(); ++i )
{
TrackContentObjectItem * item = i.value();
m_scene->removeItem(item);
m_tcoItems.erase(i);
delete item;
}
}
void TrackItem::addTCO( trackContentObject * _tco )
{
TrackContentObjectItem * tcoItem = new TrackContentObjectItem( this, _tco );
// TODO refactor to private updateTCOGeometry
tcoItem->setPos( tcoItem->x(), y() );
m_tcoItems.insert( _tco, tcoItem );
m_scene->addItem( tcoItem );
}
void TrackItem::removeTCO( trackContentObject * _tco )
{
QMap<trackContentObject*, TrackContentObjectItem*>::iterator i =
m_tcoItems.find( _tco );
if( i != m_tcoItems.end() && i.key() == _tco )
{
TrackContentObjectItem * item = i.value();
m_scene->removeItem(*i);
m_tcoItems.erase(i);
delete item;
}
}
void TrackItem::setHeight( float _height )
{
m_rect.setHeight( _height );
for( QMap<trackContentObject*, TrackContentObjectItem*>::const_iterator it = m_tcoItems.constBegin();
it != m_tcoItems.constEnd(); ++it )
{
(*it)->updateGeometry();
}
}
void TrackItem::setY( float _y )
{
//printf("TRK %lld: setY(%.2f)\n", m_track, _y);
m_rect.moveTop( _y );
for( QMap<trackContentObject*, TrackContentObjectItem*>::const_iterator it = m_tcoItems.constBegin();
it != m_tcoItems.constEnd(); ++it )
{
(*it)->setPos( (*it)->x(), y() );
}
}
float TrackItem::height()
{
return m_rect.height();
}
float TrackItem::y()
{
return m_rect.y();
}
#include "gui/tracks/moc_track_item.cxx"