view editor/edtimeline.cpp @ 1896:f80b2dc77c30

Work begins on IFF ILBM/PBM image writer. It is pretty broken, some things will not work and some things are hardcoded. The ByteRun1 compression implementation is somewhat inefficient. Interleaved files do not work yet.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 26 Jun 2018 03:13:38 +0300
parents b4992d9f72fe
children
line wrap: on
line source

#include <QtGui>
#include "edtimeline.h"


QEDTimelineTrackDisplay::QEDTimelineTrackDisplay(QWidget *parent) : QWidget(parent)
{
    track = NULL;
    time = offs = 0;
    scale = 1.0f;
    
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
}


QSize QEDTimelineTrackDisplay::minimumSizeHint() const
{
    return QSize(100, 60);
}


QSize QEDTimelineTrackDisplay::sizeHint() const
{
    return QSize(600, 60);
}


void QEDTimelineTrackDisplay::setTrack(DMTimelineTrack *mtrack)
{
    track = mtrack;
}


float QEDTimelineTrackDisplay::getTimeScale(float value)
{
    return value * scale;
}


float QEDTimelineTrackDisplay::getTimeFromCoord(float value)
{
    return value * scale * 1000.0f;
}


void QEDTimelineTrackDisplay::setTime(const float mtime)
{
    if (time != mtime && mtime >= 0)
    {
        time = mtime;
        emit timeChanged(time);
    }
}


void QEDTimelineTrackDisplay::setOffset(const float moffs)
{
    if (offs != moffs && moffs >= 0)
    {
        offs = moffs;
        emit offsetChanged(offs);
    }
}


void QEDTimelineTrackDisplay::setScale(const float mscale)
{
    if (mscale > 0.05)
        scale = mscale;
}


void QEDTimelineTrackDisplay::setSelection(const float mstart, const float mend)
{
    if (mstart >= 0 && mend >= 0 && fabs(mend - mstart) > 0)
    {
        selectionValid = true;
        if (mend > mstart)
        {
            selectionStart    = mstart;
            selectionDuration = mend - mstart + 1;
        }
        else
        {
            selectionStart    = mend;
            selectionDuration = mstart - mend + 1;
        }
        emit selectionChanged(selectionStart, selectionDuration);
    }
}


void QEDTimelineTrackDisplay::clearSelection()
{
    selectionValid    = false;
    selectionStart    = 0;
    selectionDuration = 0;
    emit selectionChanged(selectionStart, selectionDuration);
}


bool QEDTimelineTrackDisplay::getSelection(float *mstart, float *mduration)
{
    if (selectionValid)
    {
        *mstart = selectionStart;
        *mduration = selectionDuration;
    }
    return selectionValid;
}


QList<DMTimelineEvent *> QEDTimelineTrackDisplay::getEventsAt(const int time)
{
    QList<DMTimelineEvent *> list;

    for (int event = 0; event < track->nevents; event++)
    {
        DMTimelineEvent *ev = track->events[event];
        if (time >= ev->start && time <= ev->start + ev->duration)
            list.append(ev);
    }

    return list;
}



QList<DMTimelineEvent *> QEDTimelineTrackDisplay::getEventsForRange(const int start, const int duration)
{
    QList<DMTimelineEvent *> list;

    for (int event = 0; event < track->nevents; event++)
    {
        DMTimelineEvent *ev = track->events[event];
    }

    return list;
}


void QEDTimelineTrackDisplay::paintEvent(QPaintEvent *)
{
    if (track == NULL)
        return;

    QColor eventColor(150, 150, 150, 128);
    QColor invalidEventColor(250, 150, 150, 128);
    QColor eventBorder(200, 250, 200, 200);
    QColor eventParam(200, 150, 100);
    QColor eventText(255, 255, 255);
    QColor markerColor(255,255,255);
    QColor selectionColor(0,255,0, 150);
    QColor selectionEnd(0,255,0, 200);

    QFont fantti;
    fantti.setFamily("Arial");
    fantti.setPointSizeF(8.0f);
    fantti.setStyleHint(QFont::SansSerif);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);


    painter.save();
    painter.scale(scale, 1);

    float wd = getTimeScale(width());
    for (int event = 0; event < track->nevents; event++)
    {
        DMTimelineEvent *ev = track->events[event];

        float x0 = getTimeScale(ev->start - offs),
              x1 = getTimeScale(ev->start + ev->duration - offs);

        if ((x0 >= 0 && x0 < wd) || (x0 < 0 && x1 >= 0))
        {
            painter.setFont(fantti);
            painter.setBrush(ev->effect != NULL ? eventColor : invalidEventColor);
            painter.setPen(eventBorder);
            x0 = ev->start - offs;
            x1 = ev->duration;
            painter.fillRect(x0, 0, x1, height(), eventColor);

            QPainterPath path;
            path.addText(QPointF(x0 + 2, 10), fantti, ev->effect != NULL ? QString(ev->effect->name) : "INVALID");

            painter.save();
            painter.translate(1,1);
            painter.setPen(Qt::black);
            painter.setBrush(Qt::black);
            painter.drawPath(path);
            painter.restore();

            painter.setPen(eventText);
            painter.setBrush(eventText);
            painter.drawPath(path);
        }

    }

    painter.restore();

    if (selectionValid)
    {
        float x0 = getTimeScale(selectionStart - offs),
              x1 = getTimeScale(selectionStart + selectionDuration - offs);

        if ((x0 >= 0 && x0 < wd) || (x0 < 0 && x1 >= 0))
        {
            painter.setBrush(selectionColor);
            painter.setPen(selectionEnd);
            x0 = selectionStart - offs;
            x1 = selectionDuration;
            painter.fillRect(x0, 0, x1, height(), eventColor);
            
            painter.drawLine(x0, 0, x0, height());
            painter.drawLine(x1, 0, x1, height());
        }
    }


    if (time >= offs * scale && time - offs <= width() * scale)
    {
        int xc = time - offs;
        painter.save();
        painter.scale(scale, 1);
        painter.setPen(markerColor);
        painter.drawLine(xc, 0, xc, height());
        painter.restore();
    }
}


void QEDTimelineTrackDisplay::mousePressEvent(QMouseEvent *ev)
{
    switch (ev->button())
    {
        case Qt::LeftButton:
            if (parent.getActiveTrack() != this)
                emit trackActivated(this);

            selectionPoint = ev->pos();
            selectionOffs = offs / scale;
            selecting = false;
            break;

        case Qt::RightButton:
            dragPoint = ev->pos();
            dragOffs = offs / scale;
            dragging = false;
            break;

        default:
            break;
    }
}


void QEDTimelineTrackDisplay::mouseMoveEvent(QMouseEvent *ev)
{
    if ((ev->buttons() & Qt::LeftButton) && ev->pos().x() != selectionPoint.x())
    {
        selecting = true;
        setSelection(selectionOffs, offs + (ev->pos().x() - selectionPoint.x()) / scale);
    }

    if ((ev->buttons() & Qt::RightButton) && ev->pos().x() != dragPoint.x())
    {
        dragging = true;
        setOffset(dragOffs - (ev->pos().x() - dragPoint.x()) / scale);
    }
}


void QEDTimelineTrackDisplay::mouseReleaseEvent(QMouseEvent *ev)
{
    if (ev->button() == Qt::LeftButton)
    {
        if (selecting)
        {
            selecting = false;
            setSelection(selectionOffs + (ev->pos().x() - selectionPoint.x()) / scale);
        }
    }
    else
    if (ev->button() == Qt::RightButton && !dragging)
    {
        setTime(offs + getTimeFromCoord(ev->pos().x()));
    }
}


QEDTimelineTrackView::QEDTimelineTrackView(QWidget *parent) : QWidget(parent)
{
    QHBoxLayout *mainLayout = new QHBoxLayout(this);
    mainLayout->setMargin(0);
    track = new QEDTimelineTrackDisplay(this);

    QFrame *infoLayoutContainer = new QFrame(this);
    infoLayoutContainer->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
    infoLayoutContainer->setLineWidth(2);
    infoLayoutContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
    infoLayoutContainer->setFixedWidth(200);

    QVBoxLayout *infoLayout = new QVBoxLayout(infoLayoutContainer);
    infoLayout->setMargin(0);
    infoName = new QLineEdit();
    infoName->setFrame(false);
    infoName->setMaxLength(DT_MAX_NAME_LENGTH);
    infoName->setStyleSheet("QLineEdit { background-color: black; color: white; padding: 2px; }");
    connect(infoName, SIGNAL(textEdited(const QString&)), this, SLOT(slotTrackNameChanged(const QString&)));
    infoLayout->addWidget(infoName);


    enabledCheck = new QCheckBox("Enabled");
    infoLayout->addWidget(enabledCheck);
    connect(enabledCheck, SIGNAL(toggled(bool)), this, SLOT(slotTrackEnabledChanged(bool)));
    
    infoData = new QLabel();
    infoData->setStyleSheet("QLabel { padding: 2px; }");
    infoLayout->addWidget(infoData);

    mainLayout->addWidget(infoLayoutContainer);
    mainLayout->addWidget(track);
}


void QEDTimelineTrackView::update()
{
    if (track != NULL && track->track)
    {
        infoName->setText(QString(track->track->name));
        enabledCheck->setChecked(track->track->enabled);
        infoData->setText(QString("<b>%1</b> events").arg(track->track->nevents));
    }
    else
    {
        infoName->setText("");
        infoData->setText("-");
        enabledCheck->setChecked(false);
    }

    QWidget::update();
}


void QEDTimelineTrackView::setTrack(DMTimelineTrack *mtrack)
{
    track->setTrack(mtrack);
    update();
}


void QEDTimelineTrackView::slotTrackEnabledChanged(bool value)
{
    track->track->enabled = value;
    emit trackChanged();
}


void QEDTimelineTrackView::slotTrackNameChanged(const QString & text)
{
    QByteArray ba = text.toUtf8();
    track->track->name = dm_strdup(ba.constData());
    emit trackChanged();
}



QEDTimelineView::QEDTimelineView(QWidget *parent) : QWidget(parent)
{
    layout = new QVBoxLayout(this);
    tl = NULL;
}


void QEDTimelineView::setTimeline(EDTimelineObject *mtl)
{
    tl = mtl;

    delete layout;
    layout = new QVBoxLayout(this);
    layout->setMargin(0);
    
    tracks.clear();

    if (tl != NULL && tl->tl != NULL)
    {
        for (int track = 0; track < tl->tl->ntracks; track++)
        {
            QEDTimelineTrackView *vtr = new QEDTimelineTrackView(this);
            vtr->setTrack(tl->tl->tracks[track]);
            tracks.append(vtr);
            layout->addWidget(vtr);
            connect(vtr, SIGNAL(trackChanged()), this, SLOT(slotTimelineChanged()));
            connect(vtr, SIGNAL(timeChanged(float)), this, SLOT(slotTimeChanged(float)));
            connect(vtr, SIGNAL(offsetChanged(float)), this, SLOT(slotOffsetChanged(float)));
            connect(vtr, SIGNAL(selectionChanged(float,float)), this, SLOT(slotSelectionChanged(float,float)));
        }
    }
    update();
}


void QEDTimelineView::slotTimelineChanged()
{
    if (tl != NULL)
    {
        tl->touch();
        emit timelineChanged();
    }
}


void QEDTimelineView::setTime(const float mtime)
{
    if (tl != NULL && tl->tl != NULL)
    {
        QList<QEDTimelineTrackView *>::iterator track;
        for (track = tracks.begin(); track != tracks.end(); track++)
        {
            (*track)->track->setTime(mtime);
        }
        update();
    }
}


void QEDTimelineView::setOffset(const float moffs)
{
    if (tl != NULL && tl->tl != NULL)
    {
        QList<QEDTimelineTrackView *>::iterator track;
        for (track = tracks.begin(); track != tracks.end(); track++)
        {
            (*track)->track->setOffset(moffs);
        }
        update();
    }
}


void QEDTimelineView::setScale(const float mscale)
{
    if (tl != NULL && tl->tl != NULL)
    {
        QList<QEDTimelineTrackView *>::iterator track;
        for (track = tracks.begin(); track != tracks.end(); track++)
        {
            (*track)->track->setScale(mscale);
        }
        update();
    }
}


QList<DMTimelineEvent *> QEDTimelineView::getEventsAt(const int time)
{
    if (tl != NULL && tl->tl != NULL &&
        activeTrack >= 0 && activeTrack < tl->tl->ntracks)
    {
        return tracks[activeTrack]->tl->getEventsAt(time);
    }
    else
        return QList<DMTimelineEvent *>();
}


QList<DMTimelineEvent *> QEDTimelineView::getEventsForRange(const int start, const int duration)
{
}