multicookview.cpp 6.24 KB
#include "multicookview.h"

#include <QMouseEvent>
#include <QPainter>
#include <QDebug>

MultiCookView::MultiCookView(QWidget *parent)
    : QWidget(parent),
      timePosition(0)
{
    barPixmap.load(":/images/multi/bar.png");

    connect(&checkTimer, SIGNAL(timeout()), SLOT(check()));
}

void MultiCookView::setContainer(MultiCookContainer *container)
{
    this->container = container;
    rects = calcRects();
    checkTimer.start(33);
}

void MultiCookView::setTimeBar(MultiCookTimeBar *bar)
{
    this->bar = bar;
}

void MultiCookView::showNow()
{
    timePosition = 0;
    updateView();

    bar->showNow();
}

void MultiCookView::showNext()
{
    if (timePosition < 0 || !nothingOnRight())
    {
        timePosition++;
        updateView();

        bar->showNext();
    }
}

void MultiCookView::showPrev()
{
    if (timePosition > 0)
    {
        timePosition--;
        updateView();

        bar->showPrev();
    }
}

void MultiCookView::updateView()
{
    rects = calcRects();
    update();
}

void MultiCookView::mousePressEvent(QMouseEvent *event)
{
    int x = event->x();
    int y = event->y();

    pressedSlot = calcSlot(x, y);
}

void MultiCookView::mouseReleaseEvent(QMouseEvent *event)
{
    if (pressedSlot == -1)
        return;

    int x = event->x();
    int y = event->y();

    if (calcSlot(x, y) == pressedSlot)
        emit clicked(pressedSlot);
}

void MultiCookView::paintEvent(QPaintEvent */*event*/)
{
    QPainter painter(this);
    paintGrids(painter);
    paintBars(painter);
    paintCurrentTime(painter);
}

void MultiCookView::resizeEvent(QResizeEvent *event)
{
    rects = calcRects();

    QWidget::resizeEvent(event);
}

void MultiCookView::check()
{
    bool needUpdate = false;

    QList<QRect> rects = calcRects();
    for (int i = 0; i < 10; i++)
    {
        if (rects.at(i) != this->rects.at(i))
        {
            needUpdate = true;
            break;
        }
    }

    if (needUpdate)
    {
        this->rects = rects;
        update();
    }
}

QList<QRect> MultiCookView::calcRects()
{
    int w = width();
    int h = height();
    int x = w * (2-timePosition) / 10 + 1;
    int y = (h / 10 - 67) / 2;

    QList<QRect> list;
    for (int i = 0; i < 10; i++)
    {
        MultiCook *cook = container->at(i);
        if (cook == Q_NULLPTR)
        {
            list.append(QRect());
            continue;
        }

        int barY = y + h * i / 10;
        int barW = 0;

        // bar width = remaining time(ms) / 200s * width of a grid
        int remainingTime = cook->remainingTime();
        if (remainingTime > 0)
            barW = qCeil(remainingTime / 2000000.0 * w);

        list.append(QRect(x, barY, barW, 67));
    }

    return list;
}

int MultiCookView::calcSlot(int x, int y)
{
    for (int i = 0; i < 10; i++)
    {
        const QRect &r = rects.at(i);
        if (r.isNull())
            continue;

        if (r.contains(x, y))
            return i;
    }

    return -1;
}

void MultiCookView::paintGrids(QPainter &painter)
{
    static const int padding = 12;

    int w = width();
    int h = height();

    painter.setBrush(Qt::NoBrush);
    painter.setPen(QColor(70,70,70));

    for (int i = 1; i < 10; i++)
        painter.drawLine(0, h * i / 10, w, h * i / 10);

    for (int i = 1; i < 10; i++)
        painter.drawLine(w * i / 10, padding, w * i / 10, h - padding);
}

void MultiCookView::paintBars(QPainter &painter)
{
    for (int i = 0; i < 10; i++)
    {
        MultiCook *cook = container->at(i);
        if (cook == Q_NULLPTR)
            continue;

        QRect r = rects.at(i);
        if (!r.isNull())
            paintBar(painter, r);

        r.translate(12, 0);

        if (r.left() < 12)
            r.moveLeft(12);

        painter.setBrush(Qt::NoBrush);
        painter.setPen(Qt::white);
        painter.drawText(r, Qt::AlignVCenter | Qt::TextDontClip, cook->name());
    }
}

void MultiCookView::paintCurrentTime(QPainter &painter)
{
    static const int padding = 12;

    int w = width();
    int h = height();
    int x = w * (2-timePosition) / 10;

    QPen pen(Qt::yellow);
    pen.setWidth(4);
    painter.setPen(pen);
    painter.setBrush(Qt::NoBrush);
    painter.drawLine(x, padding, x, h - padding);
}

void MultiCookView::paintBar(QPainter &painter, QRect r)
{
    static const int fullWidth = 337;
    static const int headWidth = 8;
    static const int tailWidth = fullWidth - 306;
    static const int bodyWidth = fullWidth - headWidth - tailWidth;
    static const int height = 67;

    static const int bodyOffset = headWidth;
    static const int tailOffset = fullWidth - tailWidth;

    int w = r.width();
    if (w < tailWidth)
    {
        // Clip tail
        QRect sourceRect(tailWidth - w + tailOffset, 0, w, height);
        painter.drawPixmap(r, barPixmap, sourceRect);
    }
    else if (w < headWidth + tailWidth)
    {
        // Full tail
        QRect sourceRect(tailOffset, 0, tailWidth, height);
        QRect targetRect(r.x() + w - tailWidth, r.y(), tailWidth, height);
        painter.drawPixmap(targetRect, barPixmap, sourceRect);

        // Clip head
//        sourceRect = QRect(0, 0, w - tailWidth, height);
//        targetRect = QRect(r.x(), r.y(), w - tailWidth, height);
//        painter.drawPixmap(targetRect, barPixmap, sourceRect);
        sourceRect = QRect(headWidth - (w - tailWidth), 0, w - tailWidth, height);
        targetRect = QRect(r.x(), r.y(), w - tailWidth, height);
        painter.drawPixmap(targetRect, barPixmap, sourceRect);
    }
    else
    {
        // Full tail
        QRect sourceRect(tailOffset, 0, tailWidth, height);
        QRect targetRect(r.x() + w - tailWidth, r.y(), tailWidth, height);
        painter.drawPixmap(targetRect, barPixmap, sourceRect);

        // Full head
        sourceRect = QRect(0, 0, headWidth, height);
        targetRect = QRect(r.x(), r.y(), headWidth, height);
        painter.drawPixmap(targetRect, barPixmap, sourceRect);

        // Stretch body
        sourceRect = QRect(bodyOffset, 0, bodyWidth, 0);
        targetRect = QRect(r.x() + bodyOffset, r.y(), w - headWidth - tailWidth, height);
        painter.drawPixmap(targetRect, barPixmap, sourceRect);
    }
}

bool MultiCookView::nothingOnRight()
{
    int rightMost = width() * 2 / 3;

    foreach (QRect r, rects)
        if (r.right() > rightMost)
            return false;

    return true;
}