<commit_before>#include <QtGui>
#include "metadataWindow.h"

QString metadataWindow::base64_encode(QString string){
    QByteArray ba;
    ba.append(string);
    return ba.toBase64();
}

QString metadataWindow::base64_decode(QString string){
    QByteArray ba;
    ba.append(string);
    return QByteArray::fromBase64(ba);
}

static void SetTextToLabel(QLabel *label, QString text)
{
    QFontMetrics metrix(label->font());
    int width = label->width() - 10;
    QString clippedText = metrix.elidedText(text, Qt::ElideRight, width);
    label->setText(clippedText);
}

metadataWindow::metadataWindow(QWidget *parent) : QWidget(parent)
{
    const char *metadata_file = "/tmp/shairport-sync-metadata";

    // Initialize the Track object with empty strings and the like
    initialise_track_object();

    this->setupUI();

    // Connect to the metadata pipe
    FILE *fd = fopen(metadata_file, "r");
    if (fd==NULL)
    {
        cout << "No metadata file found, testing UI." << "\n";
    } else {
        // Use for actual reads
        pipe = new QTextStream(fd);

        // Use for events when the pipe is filled
        streamReader = new QSocketNotifier(fileno(fd), QSocketNotifier::Read, qApp);
        QObject::connect(streamReader, SIGNAL(activated(int)), this, SLOT(onData()));
        streamReader->setEnabled(true);

        // Now disable cursor
        QApplication::setOverrideCursor(Qt::BlankCursor);
    }
}

void metadataWindow::setupUI()
{
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

    // Create Fonts
    standard_font = new QFont("Droid Sans");
    standard_font->setPixelSize(14);

    title_font = new QFont("Droid Sans");
    title_font->setPixelSize(22);

    title_em_font = new QFont("Droid Sans");
    title_em_font->setPixelSize(22);
    title_em_font->setItalic(true);

    em_font = new QFont("Droid Sans");
    em_font->setPixelSize(14);
    em_font->setItalic(true);

    // Add cover image
    size = new QSize(120,120);
    image = new QPixmap(":/images/default_cover");
    image_label  = new QLabel();
        image_label->setPixmap(*image);
        image_label->setFixedHeight(size->height());
        image_label->setFixedWidth(size->width());

    // Add labels
    QPixmap note(":/icons/note");
    QLabel *title_label_icon = new QLabel();
    title_label_icon->setPixmap(note);
    title_label_icon->setFixedWidth(20);

    title_label = new QLabel("N/A");
    title_label->setFont(*title_em_font);
    title_label->setFixedHeight(30);
    title_label->setStyleSheet("/*background-color: #123456;*/ padding-right:6px;");

    QHBoxLayout *title_label_layout = new QHBoxLayout();
    title_label_layout->addWidget(title_label_icon);
    title_label_layout->addWidget(title_label);
    title_label_layout->setContentsMargins(0,0,0,0);

    // Artist widget
    QPixmap artist(":/icons/artist");
    QLabel *artist_label_icon = new QLabel();
    artist_label_icon->setPixmap(artist);
    artist_label_icon->setFixedWidth(20);

    artist_label = new QLabel("N/A");
    artist_label->setFont(*em_font);
    artist_label->setWordWrap(true);
    artist_label->setStyleSheet("/*background-color: #123456;*/ padding-right:6px;");

    QHBoxLayout *artist_label_layout = new QHBoxLayout();
    artist_label_layout->addWidget(artist_label_icon);
    artist_label_layout->addWidget(artist_label);

    // Album widget
    QPixmap cd(":/icons/cd");
    QLabel *release_label_icon = new QLabel();
    release_label_icon->setPixmap(cd);
    release_label_icon->setFixedWidth(20);

    release_label = new QLabel("N/A");
    release_label->setFont(*em_font);
    release_label->setWordWrap(true);
    release_label->setStyleSheet("/*background-color: #123456;*/ padding-right:6px;");

    QHBoxLayout *release_label_layout = new QHBoxLayout();
    release_label_layout->addWidget(release_label_icon);
    release_label_layout->addWidget(release_label);

    // Status bar
    QMovie *load = new QMovie(":/icons/load");
    status_label_icon = new QLabel();
    status_label_icon->setMovie(load);
    load->start();
    status_label_icon->setFixedWidth(20);

    status_label = new QLabel("En attente de données ...");
    status_label->setStyleSheet("padding-right:6px;");
    status_label->setFixedHeight(30);
    status_label->setFont(*standard_font);

    QHBoxLayout *status_label_layout = new QHBoxLayout();
    status_label_layout->addWidget(status_label_icon);
    status_label_layout->addWidget(status_label);

    // Make the whole layout
    QVBoxLayout *main_layout = new QVBoxLayout();
    main_layout->setContentsMargins(4,10,4,12);

    QHBoxLayout *hbl = new QHBoxLayout();

    QVBoxLayout *vbl = new QVBoxLayout();
    vbl->addLayout(artist_label_layout);
    vbl->setSpacing(8);
    vbl->addLayout(release_label_layout);

    hbl->addWidget(image_label);
    hbl->setSpacing(14);
    hbl->addLayout(vbl);

    QLabel *separator = new QLabel();
    separator->setFixedHeight(1);
    separator->setStyleSheet("border-top: 1px solid white;");

    main_layout->addLayout(title_label_layout);
    main_layout->addWidget(separator);
    main_layout->addLayout(hbl);
    main_layout->addLayout(status_label_layout);

    this->setLayout(main_layout);
}

void metadataWindow::initialise_track_object()
{
    track.title.clear();
    track.artist.clear();
    track.release.clear();
    track.playing = false;
    track.pending = true;
    client_ip.clear();
    client_name.clear();
}

void metadataWindow::updateUI()
{
    if (track.title.empty() || track.playing == false) {
        title_label->setFont(*title_em_font);
        title_label->setText("N/A");
    } else {
        title_label->setFont(*title_font);
        SetTextToLabel(title_label,QString::fromStdString(track.title));
    }

    if (track.artist.empty() || track.playing == false) {
        artist_label->setFont(*em_font);
        artist_label->setText("N/A");
    } else {
        artist_label->setText(QString::fromStdString(track.artist));
        artist_label->setFont(*standard_font);
    }

    if (track.release.empty() || track.playing == false) {
        release_label->setFont(*em_font);
        release_label->setText("N/A");
    } else {
        release_label->setText(QString::fromStdString(track.release));
        release_label->setFont(*standard_font);
    }

    // Create the name
    QString name = " en cours ...";
    QPixmap icon(":/icons/collection");
    if (client_name.length()) {
        name = " depuis " + QString::fromStdString(client_name);
        icon = QPixmap(":/icons/yt");
    } else if (client_ip.length() != 0) {
        name = " depuis " + QString::fromStdString(client_ip);
        icon = QPixmap(":/icons/device");
    }

    if (track.playing && !track.pending) {
        status_label->setFont(*standard_font);
        SetTextToLabel(status_label, "Lecture" + name);
        status_label_icon->setPixmap(icon);
    } else if (!track.pending) {
        status_label->setFont(*standard_font);
        SetTextToLabel(status_label, "En pause");
        status_label_icon->setPixmap(icon);
    } else if (track.pending) {
        QMovie *load = new QMovie(":/icons/load");
        status_label_icon->setMovie(load);
        load->start();
        status_label->setFont(*em_font);
        status_label->setText("En attente de données ...");
    } else {
        status_label->setFont(*em_font);
        status_label->setText("Pas de streaming en cours");
        QPixmap load_full(":/icons/load_full");
        status_label_icon->setPixmap(load_full);
    }

    if (track.playing && !track.image.isNull()) {
        image->convertFromImage(track.image);
        *image = image->scaled(*size, Qt::KeepAspectRatioByExpanding);
        image_label->setPixmap(*image);
    } else {
        image = new QPixmap(":/images/default_cover");
        image_label->setPixmap(*image);
    }

    image_label->update();

}

void metadataWindow::onData()
{
    emit dataReceived();
}

void metadataWindow::dataReceived()
{
    //cout << "\nProcessing new metadata ...\n";

    if (pipe->atEnd()) {
        //cout << " > No more data to read ...\n";
        return;
    }

    QString line = pipe->readLine();
    if (line.isEmpty() || line.isNull()) {
        //cout << " > Skipping empty line.\n";
        return;
    }

    if (line == "<data encoding=\"base64\">") {
        cout << "How did we get here ???\n";
    }

    const char * message = line.toStdString().c_str();

    uint32_t type, code, length;
    QImage base64_image;
    bool ret_pic = false;

    //cout << "Message: [" << message << "]\n";
    int ret = sscanf(message,"<item><type>%8x</type><code>%8x</code><length>%u</length>",&type,&code,&length);

    // Get code and type strings
    char typestring[5];
    *(uint32_t*)typestring = htonl(type);
    typestring[4] = 0;
    char codestring[5];
    *(uint32_t*)codestring = htonl(code);
    codestring[4] = 0;

    cout << " > Found tag: " << typestring << " / " << codestring << " of length " << length << "\n";

    if (type > 0 && code > 0 && ret == 3) {
        // now, think about processing the tag.
        // basically, we need to get hold of the base-64 data, if any
        QString payload;

        if (length > 0) {
            //cout << " > Extracting data ..." << "\n";

            // get the next line, which should be a data tag
            QString line = pipe->readLine();

            if (line == "<data encoding=\"base64\">") {
                // now, read in that big (possibly) base64 buffer
                //cout << " > Data is base64 buffer" << "\n";

                QString line = pipe->readLine();
                if (line.size() > 14) {
                    line.chop(14); // remove "</data></item>"
                    if (code != 'PICT') {
                        payload = base64_decode(line);
                    } else {
                        QByteArray base64Data = line.toAscii();
                        ret_pic = base64_image.loadFromData(QByteArray::fromBase64(base64Data));
                    }
                } else {
                    //cout << " > Looks like a bad payload" << "\n";
                }
            }

            //cout << " > Got it decoded. Length of decoded string is " << payload.size() << " bytes.\n";
        }

        // this has more information about tags, which might be relevant:
        // https://code.google.com/p/ytrack/wiki/DMAP
        if (code == 'asal') {
            track.release = payload.toStdString();
            //cout << "Album Name: " << payload.toStdString() << "\n";
        } else if (code == 'asar' || (code == 'asaa' && !payload.isEmpty())) {
            track.artist = payload.toStdString();
            //cout << "Artist: " << payload.toStdString() << "\n";
        } else if (code == 'minm') {
            track.title = payload.toStdString();
            //cout << "Title: " << payload.toStdString() << "\n";
        } else if (code == 'PICT' && ret_pic) {
            track.image = base64_image;
            //cout << "Picture received, length " << length << " bytes." << "\n";
        } else if (code == 'clip') {
            client_ip = payload.toStdString();
            //cout << "Client's IP: " << payload.toStdString() << "\n";
        } else if (code == 'snam') {
            client_name = payload.toStdString();
            //cout << "Device Name: " << payload.toStdString() << "\n";
        } else if (code == 'snua') {
            client_name = payload.toStdString();
            //cout << "User Agent: " << payload.toStdString() << "\n";
        } else if (code == 'pfls' || code =='pbeg') {
            track.pending = true;
            //cout << "Started playing" << "\n";
        } else if (code == 'prsm') {
            track.playing = true;
            track.pending = false;
            //cout << "Started playing" << "\n";
        } else if (code == 'pend') {
            track.playing = false;
            track.pending = false;
            QImage null_image;
            track.image = null_image; // Clear the image
            //cout << "Stopped playing" << "\n";
        } else if (type=='ssnc') {
            //cout << "SSNC Stuff : " << typestring << "/" << codestring << " : " << payload.toStdString() << "\n";
        } else {
            //cout << "Other Stuff : " << typestring << "/" << codestring << " : " << payload.toStdString() << "\n";
        }

    } else {
        //cout << "Could not decipher the message.\n";;
    }

    pipe->flush();
    updateUI();
}
<commit_msg>Reword PFLS / PRSM stuff<commit_after>#include <QtGui>
#include "metadataWindow.h"

QString metadataWindow::base64_encode(QString string){
    QByteArray ba;
    ba.append(string);
    return ba.toBase64();
}

QString metadataWindow::base64_decode(QString string){
    QByteArray ba;
    ba.append(string);
    return QByteArray::fromBase64(ba);
}

static void SetTextToLabel(QLabel *label, QString text)
{
    QFontMetrics metrix(label->font());
    int width = label->width() - 10;
    QString clippedText = metrix.elidedText(text, Qt::ElideRight, width);
    label->setText(clippedText);
}

metadataWindow::metadataWindow(QWidget *parent) : QWidget(parent)
{
    const char *metadata_file = "/tmp/shairport-sync-metadata";

    // Initialize the Track object with empty strings and the like
    initialise_track_object();

    this->setupUI();

    // Connect to the metadata pipe
    FILE *fd = fopen(metadata_file, "r");
    if (fd==NULL)
    {
        cout << "No metadata file found, testing UI." << "\n";
    } else {
        // Use for actual reads
        pipe = new QTextStream(fd);

        // Use for events when the pipe is filled
        streamReader = new QSocketNotifier(fileno(fd), QSocketNotifier::Read, qApp);
        QObject::connect(streamReader, SIGNAL(activated(int)), this, SLOT(onData()));
        streamReader->setEnabled(true);

        // Now disable cursor
        QApplication::setOverrideCursor(Qt::BlankCursor);
    }
}

void metadataWindow::setupUI()
{
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));

    // Create Fonts
    standard_font = new QFont("Droid Sans");
    standard_font->setPixelSize(14);

    title_font = new QFont("Droid Sans");
    title_font->setPixelSize(22);

    title_em_font = new QFont("Droid Sans");
    title_em_font->setPixelSize(22);
    title_em_font->setItalic(true);

    em_font = new QFont("Droid Sans");
    em_font->setPixelSize(14);
    em_font->setItalic(true);

    // Add cover image
    size = new QSize(120,120);
    image = new QPixmap(":/images/default_cover");
    image_label  = new QLabel();
        image_label->setPixmap(*image);
        image_label->setFixedHeight(size->height());
        image_label->setFixedWidth(size->width());

    // Add labels
    QPixmap note(":/icons/note");
    QLabel *title_label_icon = new QLabel();
    title_label_icon->setPixmap(note);
    title_label_icon->setFixedWidth(20);

    title_label = new QLabel("N/A");
    title_label->setFont(*title_em_font);
    title_label->setFixedHeight(30);
    title_label->setStyleSheet("/*background-color: #123456;*/ padding-right:6px;");

    QHBoxLayout *title_label_layout = new QHBoxLayout();
    title_label_layout->addWidget(title_label_icon);
    title_label_layout->addWidget(title_label);
    title_label_layout->setContentsMargins(0,0,0,0);

    // Artist widget
    QPixmap artist(":/icons/artist");
    QLabel *artist_label_icon = new QLabel();
    artist_label_icon->setPixmap(artist);
    artist_label_icon->setFixedWidth(20);

    artist_label = new QLabel("N/A");
    artist_label->setFont(*em_font);
    artist_label->setWordWrap(true);
    artist_label->setStyleSheet("/*background-color: #123456;*/ padding-right:6px;");

    QHBoxLayout *artist_label_layout = new QHBoxLayout();
    artist_label_layout->addWidget(artist_label_icon);
    artist_label_layout->addWidget(artist_label);

    // Album widget
    QPixmap cd(":/icons/cd");
    QLabel *release_label_icon = new QLabel();
    release_label_icon->setPixmap(cd);
    release_label_icon->setFixedWidth(20);

    release_label = new QLabel("N/A");
    release_label->setFont(*em_font);
    release_label->setWordWrap(true);
    release_label->setStyleSheet("/*background-color: #123456;*/ padding-right:6px;");

    QHBoxLayout *release_label_layout = new QHBoxLayout();
    release_label_layout->addWidget(release_label_icon);
    release_label_layout->addWidget(release_label);

    // Status bar
    QMovie *load = new QMovie(":/icons/load");
    status_label_icon = new QLabel();
    status_label_icon->setMovie(load);
    load->start();
    status_label_icon->setFixedWidth(20);

    status_label = new QLabel("En attente de données ...");
    status_label->setStyleSheet("padding-right:6px;");
    status_label->setFixedHeight(30);
    status_label->setFont(*standard_font);

    QHBoxLayout *status_label_layout = new QHBoxLayout();
    status_label_layout->addWidget(status_label_icon);
    status_label_layout->addWidget(status_label);

    // Make the whole layout
    QVBoxLayout *main_layout = new QVBoxLayout();
    main_layout->setContentsMargins(4,10,4,12);

    QHBoxLayout *hbl = new QHBoxLayout();

    QVBoxLayout *vbl = new QVBoxLayout();
    vbl->addLayout(artist_label_layout);
    vbl->setSpacing(8);
    vbl->addLayout(release_label_layout);

    hbl->addWidget(image_label);
    hbl->setSpacing(14);
    hbl->addLayout(vbl);

    QLabel *separator = new QLabel();
    separator->setFixedHeight(1);
    separator->setStyleSheet("border-top: 1px solid white;");

    main_layout->addLayout(title_label_layout);
    main_layout->addWidget(separator);
    main_layout->addLayout(hbl);
    main_layout->addLayout(status_label_layout);

    this->setLayout(main_layout);
}

void metadataWindow::initialise_track_object()
{
    track.title.clear();
    track.artist.clear();
    track.release.clear();
    track.playing = false;
    track.pending = true;
    client_ip.clear();
    client_name.clear();
}

void metadataWindow::updateUI()
{
    if (track.title.empty() || track.playing == false) {
        title_label->setFont(*title_em_font);
        title_label->setText("N/A");
    } else {
        title_label->setFont(*title_font);
        SetTextToLabel(title_label,QString::fromStdString(track.title));
    }

    if (track.artist.empty() || track.playing == false) {
        artist_label->setFont(*em_font);
        artist_label->setText("N/A");
    } else {
        artist_label->setText(QString::fromStdString(track.artist));
        artist_label->setFont(*standard_font);
    }

    if (track.release.empty() || track.playing == false) {
        release_label->setFont(*em_font);
        release_label->setText("N/A");
    } else {
        release_label->setText(QString::fromStdString(track.release));
        release_label->setFont(*standard_font);
    }

    // Create the name
    QString name = " en cours ...";
    QPixmap icon(":/icons/collection");
    if (client_name.length()) {
        name = " depuis " + QString::fromStdString(client_name);
        icon = QPixmap(":/icons/yt");
    } else if (client_ip.length() != 0) {
        name = " depuis " + QString::fromStdString(client_ip);
        icon = QPixmap(":/icons/device");
    }

    if (track.playing && !track.pending) {
        status_label->setFont(*standard_font);
        SetTextToLabel(status_label, "Lecture" + name);
        status_label_icon->setPixmap(icon);
    } else if (!track.pending) {
        status_label->setFont(*standard_font);
        SetTextToLabel(status_label, "En pause");
        status_label_icon->setPixmap(icon);
    } else if (track.pending) {
        QMovie *load = new QMovie(":/icons/load");
        status_label_icon->setMovie(load);
        load->start();
        status_label->setFont(*em_font);
        status_label->setText("En attente de données ...");
    } else {
        status_label->setFont(*em_font);
        status_label->setText("Pas de streaming en cours");
        QPixmap load_full(":/icons/load_full");
        status_label_icon->setPixmap(load_full);
    }

    if (track.playing && !track.image.isNull()) {
        image->convertFromImage(track.image);
        *image = image->scaled(*size, Qt::KeepAspectRatioByExpanding);
        image_label->setPixmap(*image);
    } else {
        image = new QPixmap(":/images/default_cover");
        image_label->setPixmap(*image);
    }

    image_label->update();

}

void metadataWindow::onData()
{
    emit dataReceived();
}

void metadataWindow::dataReceived()
{
    //cout << "\nProcessing new metadata ...\n";

    if (pipe->atEnd()) {
        //cout << " > No more data to read ...\n";
        return;
    }

    QString line = pipe->readLine();
    if (line.isEmpty() || line.isNull()) {
        //cout << " > Skipping empty line.\n";
        return;
    }

    if (line == "<data encoding=\"base64\">") {
        cout << "How did we get here ???\n";
    }

    const char * message = line.toStdString().c_str();

    uint32_t type, code, length;
    QImage base64_image;
    bool ret_pic = false;

    //cout << "Message: [" << message << "]\n";
    int ret = sscanf(message,"<item><type>%8x</type><code>%8x</code><length>%u</length>",&type,&code,&length);

    // DEBUG : Get code and type strings
    // char typestring[5];
    // *(uint32_t*)typestring = htonl(type);
    // typestring[4] = 0;
    // char codestring[5];
    // *(uint32_t*)codestring = htonl(code);
    // codestring[4] = 0;

    // cout << " > Found tag: " << typestring << " / " << codestring << " of length " << length << "\n";

    if (type > 0 && code > 0 && ret == 3) {
        // now, think about processing the tag.
        // basically, we need to get hold of the base-64 data, if any
        QString payload;

        if (length > 0) {
            //cout << " > Extracting data ..." << "\n";

            // get the next line, which should be a data tag
            QString line = pipe->readLine();

            if (line == "<data encoding=\"base64\">") {
                // now, read in that big (possibly) base64 buffer
                //cout << " > Data is base64 buffer" << "\n";

                QString line = pipe->readLine();
                if (line.size() > 14) {
                    line.chop(14); // remove "</data></item>"
                    if (code != 'PICT') {
                        payload = base64_decode(line);
                    } else {
                        QByteArray base64Data = line.toAscii();
                        ret_pic = base64_image.loadFromData(QByteArray::fromBase64(base64Data));
                    }
                } else {
                    //cout << " > Looks like a bad payload" << "\n";
                }
            }

            //cout << " > Got it decoded. Length of decoded string is " << payload.size() << " bytes.\n";
        }

        // See DMAP_DAAP_Codes.md
        if (code == 'asal') {
            track.release = payload.toStdString();
            //cout << "Album Name: " << payload.toStdString() << "\n";
        } else if (code == 'asar' || (code == 'asaa' && !payload.isEmpty())) {
            track.artist = payload.toStdString();
            //cout << "Artist: " << payload.toStdString() << "\n";
        } else if (code == 'minm') {
            track.title = payload.toStdString();
            //cout << "Title: " << payload.toStdString() << "\n";
        } else if (code == 'PICT' && ret_pic) {
            track.image = base64_image;
            //cout << "Picture received, length " << length << " bytes." << "\n";
        } else if (code == 'clip') {
            client_ip = payload.toStdString();
            //cout << "Client's IP: " << payload.toStdString() << "\n";
        } else if (code == 'snam') {
            client_name = payload.toStdString();
            //cout << "Device Name: " << payload.toStdString() << "\n";
        } else if (code == 'snua') {
            client_name = payload.toStdString();
            //cout << "User Agent: " << payload.toStdString() << "\n";
        } else if (code == 'pfls' || code =='pbeg') {
            // FLUSH or BEGIN
            // We set pending to true. 'pfls' without 'prsm' can happen between tracks too,
            // that's why we look for 'mden' too so we are not stuck in pending state.
            track.pending = true;
            //cout << "Started playing" << "\n";
        } else if (code == 'mden') {
            // A sequence of metadata has ended, let's un-pending
            track.pending = false;
        } else if (code == 'prsm') {
            // RESUME, which means a track is being actually played after the metadata has been sent
            track.playing = true;
            track.pending = false;
            //cout << "Started playing" << "\n";
        } else if (code == 'pend') {
            // END OF SESSION. pending is reset to false, as is playing state.
            track.playing = false;
            track.pending = false;
            QImage null_image;
            track.image = null_image; // Clear the image
            //cout << "Stopped playing" << "\n";
        } else if (type=='ssnc') {
            //cout << "SSNC Stuff : " << typestring << "/" << codestring << " : " << payload.toStdString() << "\n";
        } else {
            //cout << "Other Stuff : " << typestring << "/" << codestring << " : " << payload.toStdString() << "\n";
        }

        updateUI();

    } else {
        //cout << "Could not decipher the message.\n";;
    }

    pipe->flush();
}
<|endoftext|>


<commit_before>// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#if defined(V8_TARGET_ARCH_MIPS)

#include "codegen.h"
#include "debug.h"

namespace v8 {
namespace internal {

#ifdef ENABLE_DEBUGGER_SUPPORT

bool BreakLocationIterator::IsDebugBreakAtReturn() {
  UNIMPLEMENTED_MIPS();
  return false;
}

void BreakLocationIterator::SetDebugBreakAtReturn() {
  UNIMPLEMENTED_MIPS();
}

// Restore the JS frame exit code.
void BreakLocationIterator::ClearDebugBreakAtReturn() {
  UNIMPLEMENTED_MIPS();
}

// A debug break in the exit code is identified by the JS frame exit code
// having been patched with li/call psuedo-instrunction (liu/ori/jalr)
bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
  UNIMPLEMENTED_MIPS();
  return false;
}

bool BreakLocationIterator::IsDebugBreakAtSlot() {
  UNIMPLEMENTED_MIPS();
  return false;
}

void BreakLocationIterator::SetDebugBreakAtSlot() {
  UNIMPLEMENTED_MIPS();
}

void BreakLocationIterator::ClearDebugBreakAtSlot() {
  UNIMPLEMENTED_MIPS();
}

#define __ ACCESS_MASM(masm)

void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateSlot(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
  UNIMPLEMENTED_MIPS();
}

const bool Debug::kFrameDropperSupported = false;

#undef __

#endif  // ENABLE_DEBUGGER_SUPPORT

} }  // namespace v8::internal

#endif  // V8_TARGET_ARCH_MIPS
<commit_msg>Submit debug-mips.cc.<commit_after>// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "v8.h"

#if defined(V8_TARGET_ARCH_MIPS)

#include "codegen.h"
#include "debug.h"

namespace v8 {
namespace internal {

#ifdef ENABLE_DEBUGGER_SUPPORT

bool BreakLocationIterator::IsDebugBreakAtReturn() {
  return Debug::IsDebugBreakAtReturn(rinfo());
}

void BreakLocationIterator::SetDebugBreakAtReturn() {
  // Mips return sequence:
  // mov sp, fp
  // lw fp, sp(0)
  // lw ra, sp(4)
  // addiu sp, sp, 8
  // addiu sp, sp, N
  // jr ra
  // nop (in branch delay slot)

  // Make sure this constant matches the number if instrucntions we emit.
  ASSERT(Assembler::kJSReturnSequenceInstructions == 7);
  CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
  // li and Call pseudo-instructions emit two instructions each.
  patcher.masm()->li(v8::internal::t9,
      Operand(reinterpret_cast<int32_t>(
          Isolate::Current()->debug()->debug_break_return()->entry())));
  patcher.masm()->Call(v8::internal::t9);
  patcher.masm()->nop();
  patcher.masm()->nop();
  patcher.masm()->nop();

  // TODO(mips): Open issue about using breakpoint instruction instead of nops.
  // patcher.masm()->bkpt(0);
}

// Restore the JS frame exit code.
void BreakLocationIterator::ClearDebugBreakAtReturn() {
  rinfo()->PatchCode(original_rinfo()->pc(),
                     Assembler::kJSReturnSequenceInstructions);
}

// A debug break in the exit code is identified by the JS frame exit code
// having been patched with li/call psuedo-instrunction (liu/ori/jalr).
bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
  ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
  return rinfo->IsPatchedReturnSequence();
}

bool BreakLocationIterator::IsDebugBreakAtSlot() {
  ASSERT(IsDebugBreakSlot());
  // Check whether the debug break slot instructions have been patched.
  return rinfo()->IsPatchedDebugBreakSlotSequence();
}

void BreakLocationIterator::SetDebugBreakAtSlot() {
  ASSERT(IsDebugBreakSlot());
  // Patch the code changing the debug break slot code from:
  //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
  //   nop(DEBUG_BREAK_NOP)
  //   nop(DEBUG_BREAK_NOP)
  //   nop(DEBUG_BREAK_NOP)
  // to a call to the debug break slot code.
  //   li t9, address   (lui t9 / ori t9 instruction pair)
  //   call t9          (jalr t9 / nop instruction pair)
  CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
  patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
      Isolate::Current()->debug()->debug_break_return()->entry())));
  patcher.masm()->Call(v8::internal::t9);
}

void BreakLocationIterator::ClearDebugBreakAtSlot() {
  ASSERT(IsDebugBreakSlot());
  rinfo()->PatchCode(original_rinfo()->pc(),
                     Assembler::kDebugBreakSlotInstructions);
}

#define __ ACCESS_MASM(masm)

static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
                                          RegList object_regs,
                                          RegList non_object_regs) {
  __ EnterInternalFrame();

  // Store the registers containing live values on the expression stack to
  // make sure that these are correctly updated during GC. Non object values
  // are stored as a smi causing it to be untouched by GC.
  ASSERT((object_regs & ~kJSCallerSaved) == 0);
  ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
  ASSERT((object_regs & non_object_regs) == 0);
  if ((object_regs | non_object_regs) != 0) {
    for (int i = 0; i < kNumJSCallerSaved; i++) {
      int r = JSCallerSavedCode(i);
      Register reg = { r };
      if ((non_object_regs & (1 << r)) != 0) {
        if (FLAG_debug_code) {
          __ And(at, reg, 0xc0000000);
          __ Assert(eq, "Unable to encode value as smi", at, Operand(zero_reg));
        }
        __ sll(reg, reg, kSmiTagSize);
      }
    }
    __ MultiPush(object_regs | non_object_regs);
  }

#ifdef DEBUG
  __ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
  __ mov(a0, zero_reg);  // No arguments.
  __ li(a1, Operand(ExternalReference::debug_break(masm->isolate())));

  CEntryStub ceb(1);
  __ CallStub(&ceb);

  // Restore the register values from the expression stack.
  if ((object_regs | non_object_regs) != 0) {
    __ MultiPop(object_regs | non_object_regs);
    for (int i = 0; i < kNumJSCallerSaved; i++) {
      int r = JSCallerSavedCode(i);
      Register reg = { r };
      if ((non_object_regs & (1 << r)) != 0) {
        __ srl(reg, reg, kSmiTagSize);
      }
      if (FLAG_debug_code &&
          (((object_regs |non_object_regs) & (1 << r)) == 0)) {
        __ li(reg, kDebugZapValue);
      }
    }
  }

  __ LeaveInternalFrame();

  // Now that the break point has been handled, resume normal execution by
  // jumping to the target address intended by the caller and that was
  // overwritten by the address of DebugBreakXXX.
  __ li(t9, Operand(
      ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate())));
  __ lw(t9, MemOperand(t9));
  __ Jump(t9);
}

void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
  // Calling convention for IC load (from ic-mips.cc).
  // ----------- S t a t e -------------
  //  -- a2    : name
  //  -- ra    : return address
  //  -- a0    : receiver
  //  -- [sp]  : receiver
  // -----------------------------------
  // Registers a0 and a2 contain objects that need to be pushed on the
  // expression stack of the fake JS frame.
  Generate_DebugBreakCallHelper(masm, a0.bit() | a2.bit(), 0);
}

void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
  // Calling convention for IC store (from ic-mips.cc).
  // ----------- S t a t e -------------
  //  -- a0    : value
  //  -- a1    : receiver
  //  -- a2    : name
  //  -- ra    : return address
  // -----------------------------------
  // Registers a0, a1, and a2 contain objects that need to be pushed on the
  // expression stack of the fake JS frame.
  Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
}

void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
  // ---------- S t a t e --------------
  //  -- ra  : return address
  //  -- a0  : key
  //  -- a1  : receiver
  Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit(), 0);
}

void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
  // ---------- S t a t e --------------
  //  -- a0     : value
  //  -- a1     : key
  //  -- a2     : receiver
  //  -- ra     : return address
  Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
}

void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
  // Calling convention for IC call (from ic-mips.cc).
  // ----------- S t a t e -------------
  //  -- a2: name
  // -----------------------------------
  Generate_DebugBreakCallHelper(masm, a2.bit(), 0);
}

void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
  // Calling convention for construct call (from builtins-mips.cc).
  //  -- a0     : number of arguments (not smi)
  //  -- a1     : constructor function
  Generate_DebugBreakCallHelper(masm, a1.bit(), a0.bit());
}

void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
  // In places other than IC call sites it is expected that v0 is TOS which
  // is an object - this is not generally the case so this should be used with
  // care.
  Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
}

void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
  // ----------- S t a t e -------------
  //  No registers used on entry.
  // -----------------------------------
  Generate_DebugBreakCallHelper(masm, 0, 0);
}

void Debug::GenerateSlot(MacroAssembler* masm) {
  // Generate enough nop's to make space for a call instruction. Avoid emitting
  // the trampoline pool in the debug break slot code.
  Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
  Label check_codesize;
  __ bind(&check_codesize);
  __ RecordDebugBreakSlot();
  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
    __ nop(MacroAssembler::DEBUG_BREAK_NOP);
  }
  ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
            masm->InstructionsGeneratedSince(&check_codesize));
}

void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
  // In the places where a debug break slot is inserted no registers can contain
  // object pointers.
  Generate_DebugBreakCallHelper(masm, 0, 0);
}

void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
  masm->Abort("LiveEdit frame dropping is not supported on mips");
}

void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
  masm->Abort("LiveEdit frame dropping is not supported on mips");
}

const bool Debug::kFrameDropperSupported = false;

#undef __

#endif  // ENABLE_DEBUGGER_SUPPORT

} }  // namespace v8::internal

#endif  // V8_TARGET_ARCH_MIPS
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE "test_file_reading"

#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif

#include "toml.hpp"
#include <fstream>

BOOST_AUTO_TEST_CASE(test_example)
{
    std::ifstream ifs("example.toml");
    if(ifs.good())
    {
        toml::Data data = toml::parse(ifs);
        std::string title = toml::get<toml::String>(data["title"]);
        BOOST_CHECK_EQUAL(title, std::string("TOML Example"));

        toml::Table owner = toml::get<toml::Table>(data["owner"]);
        std::string owner_name = toml::get<toml::String>(owner["name"]);
        BOOST_CHECK_EQUAL(owner_name, std::string("Tom Preston-Werner"));
        std::string owner_organization = toml::get<toml::String>(owner["organization"]);
        BOOST_CHECK_EQUAL(owner_organization, std::string("GitHub"));
        std::string owner_bio = toml::get<toml::String>(owner["bio"]);
        BOOST_CHECK_EQUAL(owner_bio, std::string("GitHub Cofounder & CEO\nLikes tater tots and beer."));
        toml::chrono::system_clock::time_point owner_dob = toml::get<toml::Datetime>(owner["dob"]);
        std::tm t;
        t.tm_year = 79;
        t.tm_mon = 4;
        t.tm_mday = 27;
        t.tm_hour = 7;
        t.tm_min = 32;
        t.tm_sec = 0;
        const std::time_t gtime = std::mktime(&t);
        const std::time_t dob = toml::chrono::system_clock::to_time_t(owner_dob);
        BOOST_CHECK_EQUAL(gtime, dob);

        toml::Table database = toml::get<toml::Table>(data["database"]);
        std::string server = toml::get<toml::String>(database["server"]);
        BOOST_CHECK_EQUAL(server, std::string("192.168.1.1"));
#ifdef TOML_ENABLE_CXX11
        std::vector<toml::Integer> ports = toml::get<toml::Array<toml::Integer>>(database["ports"]);
#else
        std::vector<toml::Integer> ports = toml::get<toml::Array<toml::Integer>::type>(database["ports"]);
#endif
        BOOST_CHECK_EQUAL(ports.at(0), 8001);
        BOOST_CHECK_EQUAL(ports.at(1), 8001);
        BOOST_CHECK_EQUAL(ports.at(2), 8002);

        toml::Integer connection_max = toml::get<toml::Integer>(database["connection_max"]);
        BOOST_CHECK_EQUAL(connection_max, 5000);
        bool enabled = toml::get<toml::Boolean>(database["enabled"]);
        BOOST_CHECK_EQUAL(enabled, true);

        toml::Table servers = toml::get<toml::Table>(data["servers"]);
        toml::Table servers_alpha = toml::get<toml::Table>(servers["alpha"]);
        {
            std::string ip = toml::get<toml::String>(servers_alpha["ip"]);
            BOOST_CHECK_EQUAL(ip, "10.0.0.1");
            std::string dc = toml::get<toml::String>(servers_alpha["dc"]);
            BOOST_CHECK_EQUAL(dc, "eqdc10");
        }
        toml::Table servers_beta = toml::get<toml::Table>(servers["beta"]);
        {
            std::string ip = toml::get<toml::String>(servers_beta["ip"]);
            BOOST_CHECK_EQUAL(ip, "10.0.0.2");
            std::string dc = toml::get<toml::String>(servers_beta["dc"]);
            BOOST_CHECK_EQUAL(dc, "eqdc10");
            std::string country = toml::get<toml::String>(servers_beta["country"]);
            BOOST_CHECK_EQUAL(country, "中国");
        }

        toml::Table clients = toml::get<toml::Table>(data["clients"]);
#ifdef TOML_ENABLE_CXX11
        std::vector<toml::ValueBase> clients_data =
            toml::get<toml::Array<toml::ValueBase> >(clients["data"]);
        std::vector<std::string> first_array =
            toml::get<toml::Array<toml::String> >(clients_data.at(0));
#else
        std::vector<toml::ValueBase> clients_data =
            toml::get<toml::Array<toml::ValueBase>::type>(clients["data"]);
        std::vector<std::string> first_array =
            toml::get<toml::Array<toml::String>::type>(clients_data.at(0));
#endif
        BOOST_CHECK_EQUAL(first_array.at(0), "gamma");
        BOOST_CHECK_EQUAL(first_array.at(1), "delta");
#ifdef TOML_ENABLE_CXX11
        std::vector<toml::Integer> second_array =
            toml::get<toml::Array<toml::Integer>>(clients_data.at(1));
#else
        std::vector<toml::Integer> second_array =
            toml::get<toml::Array<toml::Integer>::type>(clients_data.at(1));
#endif
        BOOST_CHECK_EQUAL(second_array.at(0), 1);
        BOOST_CHECK_EQUAL(second_array.at(1), 2);

#ifdef TOML_ENABLE_CXX11
        std::vector<std::string> hosts =
            toml::get<toml::Array<toml::String>>(clients["hosts"]);
#else
        std::vector<std::string> hosts =
            toml::get<toml::Array<toml::String>::type>(clients["hosts"]);
#endif
        BOOST_CHECK_EQUAL(hosts.at(0), "alpha");
        BOOST_CHECK_EQUAL(hosts.at(1), "omega");

#ifdef TOML_ENABLE_CXX11
        std::vector<toml::Table> products =
            toml::get<toml::Array<toml::Table>>(data["products"]);
#else
        std::vector<toml::Table> products =
            toml::get<toml::Array<toml::Table>::type>(data["products"]);
#endif
        {
            std::string name = toml::get<toml::String>(products.at(0)["name"]);
            BOOST_CHECK_EQUAL(name, "Hammer");
            toml::Integer sku = toml::get<toml::Integer>(products.at(0)["sku"]);
            BOOST_CHECK_EQUAL(sku, 738594937);
        }
        {
            std::string name = toml::get<toml::String>(products.at(1)["name"]);
            BOOST_CHECK_EQUAL(name, "Nail");
            toml::Integer sku = toml::get<toml::Integer>(products.at(1)["sku"]);
            BOOST_CHECK_EQUAL(sku, 284758393);
            std::string color = toml::get<toml::String>(products.at(1)["color"]);
            BOOST_CHECK_EQUAL(color, "gray");
        }
    }
    else
    {
        std::cerr << "file open error." << std::endl;
    }
}

BOOST_AUTO_TEST_CASE(test_hard_example)
{
    std::ifstream ifs("hard_example.toml");
    if(ifs.good())
    {
        toml::Data data = toml::parse(ifs);
        toml::Table the = toml::get<toml::Table>(data["the"]);
        std::string test_string = toml::get<toml::String>(the["test_string"]);
        BOOST_CHECK_EQUAL(test_string, "You'll hate me after this - #");

        toml::Table the_hard = toml::get<toml::Table>(the["hard"]);
#ifdef TOML_ENABLE_CXX11
        std::vector<std::string> test_array =
            toml::get<toml::Array<toml::String>>(the_hard["test_array"]);
#else
        std::vector<std::string> test_array =
            toml::get<toml::Array<toml::String>::type>(the_hard["test_array"]);
#endif
        BOOST_CHECK_EQUAL(test_array.at(0), "] ");
        BOOST_CHECK_EQUAL(test_array.at(1), " # ");

        std::vector<std::string> test_array2 =
            toml::get<toml::Array<toml::String> >(the_hard["test_array2"]);
        BOOST_CHECK_EQUAL(test_array2.at(0), "Test #11 ]proved that");
        BOOST_CHECK_EQUAL(test_array2.at(1), "Experiment #9 was a success");

        std::string another_test_string =
            toml::get<toml::String>(the_hard["another_test_string"]);
        BOOST_CHECK_EQUAL(another_test_string, " Same thing, but with a string #");
        std::string harder_test_string =
            toml::get<toml::String>(the_hard["harder_test_string"]);
        BOOST_CHECK_EQUAL(harder_test_string, " And when \"\'s are in the string, along with # \"");

        toml::Table the_hard_bit = toml::get<toml::Table>(the_hard["bit#"]);
        std::string what = toml::get<toml::String>(the_hard_bit["what?"]);
        BOOST_CHECK_EQUAL(what, "You don't think some user won't do that?");
        std::vector<std::string> multi_line_array =
#ifdef TOML_ENABLE_CXX11
            toml::get<toml::Array<toml::String>>(the_hard_bit["multi_line_array"]);
#else
            toml::get<toml::Array<toml::String>::type>(the_hard_bit["multi_line_array"]);
#endif
        BOOST_CHECK_EQUAL(multi_line_array.at(0), "]");
    }
    else
    {
        std::cerr << "file open error." << std::endl;
    }
}

BOOST_AUTO_TEST_CASE(test_hard_example_error)
{
    {
    std::ifstream err("hard_example_error1.toml");
    if(err.good())
    {
        bool exception_thrown = false;
        try{toml::Data data = toml::parse(err);}
        catch(toml::syntax_error& except)
        {
            exception_thrown = true;
        }
        BOOST_CHECK(exception_thrown);
    }
    else
    {
        std::cerr << "file open error. hard_example_error.toml" << std::endl;
    }
    }

    {
    std::ifstream err("hard_example_error2.toml");
    if(err.good())
    {
        bool exception_thrown = false;
        try{toml::Data data = toml::parse(err);}
        catch(toml::syntax_error& except)
        {
            exception_thrown = true;
        }
        BOOST_CHECK(exception_thrown);
    }
    else
    {
        std::cerr << "file open error. hard_example_error.toml" << std::endl;
    }
    }

    {
    std::ifstream err("hard_example_error3.toml");
    if(err.good())
    {
        bool exception_thrown = false;
        try{toml::Data data = toml::parse(err);}
        catch(toml::syntax_error& except)
        {
            exception_thrown = true;
        }
        BOOST_CHECK(exception_thrown);
    }
    else
    {
        std::cerr << "file open error. hard_example_error.toml" << std::endl;
    }
    }
}

BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
{
    std::ifstream ifs("hard_example_unicode.toml");
    if(ifs.good())
    {
        toml::Data data = toml::parse(ifs);
        toml::Table the = toml::get<toml::Table>(data["the"]);
        std::string test_string = toml::get<toml::String>(the["test_string"]);
        BOOST_CHECK_EQUAL(test_string, "Ýôú'ℓℓ λáƭè ₥è áƒƭèř ƭλïƨ - #");

        toml::Table the_hard = toml::get<toml::Table>(the["hard"]);
        std::vector<std::string> test_array =
#ifdef TOML_ENABLE_CXX11
            toml::get<toml::Array<toml::String>>(the_hard["test_array"]);
#else
            toml::get<toml::Array<toml::String>::type>(the_hard["test_array"]);
#endif
        BOOST_CHECK_EQUAL(test_array.at(0), "] ");
        BOOST_CHECK_EQUAL(test_array.at(1), " # ");

        std::vector<std::string> test_array2 =
#ifdef TOML_ENABLE_CXX11
            toml::get<toml::Array<toml::String>>(the_hard["test_array2"]);
#else
            toml::get<toml::Array<toml::String>::type>(the_hard["test_array2"]);
#endif
        BOOST_CHECK_EQUAL(test_array2.at(0), "Tèƨƭ #11 ]ƥřôƲèδ ƭλáƭ");
        BOOST_CHECK_EQUAL(test_array2.at(1), "Éжƥèřï₥èñƭ #9 ωáƨ á ƨúççèƨƨ");

        std::string another_test_string =
            toml::get<toml::String>(the_hard["another_test_string"]);
        BOOST_CHECK_EQUAL(another_test_string, "§á₥è ƭλïñϱ, βúƭ ωïƭλ á ƨƭřïñϱ #");
        std::string harder_test_string =
            toml::get<toml::String>(the_hard["harder_test_string"]);
        BOOST_CHECK_EQUAL(harder_test_string, " Âñδ ωλèñ \"'ƨ ářè ïñ ƭλè ƨƭřïñϱ, áℓôñϱ ωïƭλ # \"");

        toml::Table the_hard_bit = toml::get<toml::Table>(the_hard["βïƭ#"]);
        std::string what = toml::get<toml::String>(the_hard_bit["ωλáƭ?"]);
        BOOST_CHECK_EQUAL(what, "Ýôú δôñ'ƭ ƭλïñƙ ƨô₥è úƨèř ωôñ'ƭ δô ƭλáƭ?");
        std::vector<std::string> multi_line_array =
#ifdef TOML_ENABLE_CXX11
            toml::get<toml::Array<toml::String>>(the_hard_bit["multi_line_array"]);
#else
            toml::get<toml::Array<toml::String>::type>(the_hard_bit["multi_line_array"]);
#endif
        BOOST_CHECK_EQUAL(multi_line_array.at(0), "]");
    }
    else
    {
        std::cerr << "file open error." << std::endl;
    }
}
<commit_msg>forgot to add macro<commit_after>#define BOOST_TEST_MODULE "test_file_reading"

#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
#include <boost/test/unit_test.hpp>
#else
#define BOOST_TEST_NO_LIB
#include <boost/test/included/unit_test.hpp>
#endif

#include "toml.hpp"
#include <fstream>

BOOST_AUTO_TEST_CASE(test_example)
{
    std::ifstream ifs("example.toml");
    if(ifs.good())
    {
        toml::Data data = toml::parse(ifs);
        std::string title = toml::get<toml::String>(data["title"]);
        BOOST_CHECK_EQUAL(title, std::string("TOML Example"));

        toml::Table owner = toml::get<toml::Table>(data["owner"]);
        std::string owner_name = toml::get<toml::String>(owner["name"]);
        BOOST_CHECK_EQUAL(owner_name, std::string("Tom Preston-Werner"));
        std::string owner_organization = toml::get<toml::String>(owner["organization"]);
        BOOST_CHECK_EQUAL(owner_organization, std::string("GitHub"));
        std::string owner_bio = toml::get<toml::String>(owner["bio"]);
        BOOST_CHECK_EQUAL(owner_bio, std::string("GitHub Cofounder & CEO\nLikes tater tots and beer."));
        toml::chrono::system_clock::time_point owner_dob = toml::get<toml::Datetime>(owner["dob"]);
        std::tm t;
        t.tm_year = 79;
        t.tm_mon = 4;
        t.tm_mday = 27;
        t.tm_hour = 7;
        t.tm_min = 32;
        t.tm_sec = 0;
        const std::time_t gtime = std::mktime(&t);
        const std::time_t dob = toml::chrono::system_clock::to_time_t(owner_dob);
        BOOST_CHECK_EQUAL(gtime, dob);

        toml::Table database = toml::get<toml::Table>(data["database"]);
        std::string server = toml::get<toml::String>(database["server"]);
        BOOST_CHECK_EQUAL(server, std::string("192.168.1.1"));
#ifdef TOML_ENABLE_CXX11
        std::vector<toml::Integer> ports = toml::get<toml::Array<toml::Integer>>(database["ports"]);
#else
        std::vector<toml::Integer> ports = toml::get<toml::Array<toml::Integer>::type>(database["ports"]);
#endif
        BOOST_CHECK_EQUAL(ports.at(0), 8001);
        BOOST_CHECK_EQUAL(ports.at(1), 8001);
        BOOST_CHECK_EQUAL(ports.at(2), 8002);

        toml::Integer connection_max = toml::get<toml::Integer>(database["connection_max"]);
        BOOST_CHECK_EQUAL(connection_max, 5000);
        bool enabled = toml::get<toml::Boolean>(database["enabled"]);
        BOOST_CHECK_EQUAL(enabled, true);

        toml::Table servers = toml::get<toml::Table>(data["servers"]);
        toml::Table servers_alpha = toml::get<toml::Table>(servers["alpha"]);
        {
            std::string ip = toml::get<toml::String>(servers_alpha["ip"]);
            BOOST_CHECK_EQUAL(ip, "10.0.0.1");
            std::string dc = toml::get<toml::String>(servers_alpha["dc"]);
            BOOST_CHECK_EQUAL(dc, "eqdc10");
        }
        toml::Table servers_beta = toml::get<toml::Table>(servers["beta"]);
        {
            std::string ip = toml::get<toml::String>(servers_beta["ip"]);
            BOOST_CHECK_EQUAL(ip, "10.0.0.2");
            std::string dc = toml::get<toml::String>(servers_beta["dc"]);
            BOOST_CHECK_EQUAL(dc, "eqdc10");
            std::string country = toml::get<toml::String>(servers_beta["country"]);
            BOOST_CHECK_EQUAL(country, "中国");
        }

        toml::Table clients = toml::get<toml::Table>(data["clients"]);
#ifdef TOML_ENABLE_CXX11
        std::vector<toml::ValueBase> clients_data =
            toml::get<toml::Array<toml::ValueBase> >(clients["data"]);
        std::vector<std::string> first_array =
            toml::get<toml::Array<toml::String> >(clients_data.at(0));
#else
        std::vector<toml::ValueBase> clients_data =
            toml::get<toml::Array<toml::ValueBase>::type>(clients["data"]);
        std::vector<std::string> first_array =
            toml::get<toml::Array<toml::String>::type>(clients_data.at(0));
#endif

        BOOST_CHECK_EQUAL(first_array.at(0), "gamma");
        BOOST_CHECK_EQUAL(first_array.at(1), "delta");
#ifdef TOML_ENABLE_CXX11
        std::vector<toml::Integer> second_array =
            toml::get<toml::Array<toml::Integer>>(clients_data.at(1));
#else
        std::vector<toml::Integer> second_array =
            toml::get<toml::Array<toml::Integer>::type>(clients_data.at(1));
#endif
        BOOST_CHECK_EQUAL(second_array.at(0), 1);
        BOOST_CHECK_EQUAL(second_array.at(1), 2);

#ifdef TOML_ENABLE_CXX11
        std::vector<std::string> hosts =
            toml::get<toml::Array<toml::String>>(clients["hosts"]);
#else
        std::vector<std::string> hosts =
            toml::get<toml::Array<toml::String>::type>(clients["hosts"]);
#endif
        BOOST_CHECK_EQUAL(hosts.at(0), "alpha");
        BOOST_CHECK_EQUAL(hosts.at(1), "omega");

#ifdef TOML_ENABLE_CXX11
        std::vector<toml::Table> products =
            toml::get<toml::Array<toml::Table>>(data["products"]);
#else
        std::vector<toml::Table> products =
            toml::get<toml::Array<toml::Table>::type>(data["products"]);
#endif
        {
            std::string name = toml::get<toml::String>(products.at(0)["name"]);
            BOOST_CHECK_EQUAL(name, "Hammer");
            toml::Integer sku = toml::get<toml::Integer>(products.at(0)["sku"]);
            BOOST_CHECK_EQUAL(sku, 738594937);
        }
        {
            std::string name = toml::get<toml::String>(products.at(1)["name"]);
            BOOST_CHECK_EQUAL(name, "Nail");
            toml::Integer sku = toml::get<toml::Integer>(products.at(1)["sku"]);
            BOOST_CHECK_EQUAL(sku, 284758393);
            std::string color = toml::get<toml::String>(products.at(1)["color"]);
            BOOST_CHECK_EQUAL(color, "gray");
        }
    }
    else
    {
        std::cerr << "file open error." << std::endl;
    }
}

BOOST_AUTO_TEST_CASE(test_hard_example)
{
    std::ifstream ifs("hard_example.toml");
    if(ifs.good())
    {
        toml::Data data = toml::parse(ifs);
        toml::Table the = toml::get<toml::Table>(data["the"]);
        std::string test_string = toml::get<toml::String>(the["test_string"]);
        BOOST_CHECK_EQUAL(test_string, "You'll hate me after this - #");

        toml::Table the_hard = toml::get<toml::Table>(the["hard"]);
#ifdef TOML_ENABLE_CXX11
        std::vector<std::string> test_array =
            toml::get<toml::Array<toml::String>>(the_hard["test_array"]);
#else
        std::vector<std::string> test_array =
            toml::get<toml::Array<toml::String>::type>(the_hard["test_array"]);
#endif
        BOOST_CHECK_EQUAL(test_array.at(0), "] ");
        BOOST_CHECK_EQUAL(test_array.at(1), " # ");

        std::vector<std::string> test_array2 =
#ifdef TOML_ENABLE_CXX11
            toml::get<toml::Array<toml::String>>(the_hard["test_array2"]);
#else
            toml::get<toml::Array<toml::String>::type>(the_hard["test_array2"]);
#endif
        BOOST_CHECK_EQUAL(test_array2.at(0), "Test #11 ]proved that");
        BOOST_CHECK_EQUAL(test_array2.at(1), "Experiment #9 was a success");

        std::string another_test_string =
            toml::get<toml::String>(the_hard["another_test_string"]);
        BOOST_CHECK_EQUAL(another_test_string, " Same thing, but with a string #");
        std::string harder_test_string =
            toml::get<toml::String>(the_hard["harder_test_string"]);
        BOOST_CHECK_EQUAL(harder_test_string, " And when \"\'s are in the string, along with # \"");

        toml::Table the_hard_bit = toml::get<toml::Table>(the_hard["bit#"]);
        std::string what = toml::get<toml::String>(the_hard_bit["what?"]);
        BOOST_CHECK_EQUAL(what, "You don't think some user won't do that?");
        std::vector<std::string> multi_line_array =
#ifdef TOML_ENABLE_CXX11
            toml::get<toml::Array<toml::String>>(the_hard_bit["multi_line_array"]);
#else
            toml::get<toml::Array<toml::String>::type>(the_hard_bit["multi_line_array"]);
#endif
        BOOST_CHECK_EQUAL(multi_line_array.at(0), "]");
    }
    else
    {
        std::cerr << "file open error." << std::endl;
    }
}

BOOST_AUTO_TEST_CASE(test_hard_example_error)
{
    {
    std::ifstream err("hard_example_error1.toml");
    if(err.good())
    {
        bool exception_thrown = false;
        try{toml::Data data = toml::parse(err);}
        catch(toml::syntax_error& except)
        {
            exception_thrown = true;
        }
        BOOST_CHECK(exception_thrown);
    }
    else
    {
        std::cerr << "file open error. hard_example_error.toml" << std::endl;
    }
    }

    {
    std::ifstream err("hard_example_error2.toml");
    if(err.good())
    {
        bool exception_thrown = false;
        try{toml::Data data = toml::parse(err);}
        catch(toml::syntax_error& except)
        {
            exception_thrown = true;
        }
        BOOST_CHECK(exception_thrown);
    }
    else
    {
        std::cerr << "file open error. hard_example_error.toml" << std::endl;
    }
    }

    {
    std::ifstream err("hard_example_error3.toml");
    if(err.good())
    {
        bool exception_thrown = false;
        try{toml::Data data = toml::parse(err);}
        catch(toml::syntax_error& except)
        {
            exception_thrown = true;
        }
        BOOST_CHECK(exception_thrown);
    }
    else
    {
        std::cerr << "file open error. hard_example_error.toml" << std::endl;
    }
    }
}

BOOST_AUTO_TEST_CASE(test_hard_example_unicode)
{
    std::ifstream ifs("hard_example_unicode.toml");
    if(ifs.good())
    {
        toml::Data data = toml::parse(ifs);
        toml::Table the = toml::get<toml::Table>(data["the"]);
        std::string test_string = toml::get<toml::String>(the["test_string"]);
        BOOST_CHECK_EQUAL(test_string, "Ýôú'ℓℓ λáƭè ₥è áƒƭèř ƭλïƨ - #");

        toml::Table the_hard = toml::get<toml::Table>(the["hard"]);
        std::vector<std::string> test_array =
#ifdef TOML_ENABLE_CXX11
            toml::get<toml::Array<toml::String>>(the_hard["test_array"]);
#else
            toml::get<toml::Array<toml::String>::type>(the_hard["test_array"]);
#endif
        BOOST_CHECK_EQUAL(test_array.at(0), "] ");
        BOOST_CHECK_EQUAL(test_array.at(1), " # ");

        std::vector<std::string> test_array2 =
#ifdef TOML_ENABLE_CXX11
            toml::get<toml::Array<toml::String>>(the_hard["test_array2"]);
#else
            toml::get<toml::Array<toml::String>::type>(the_hard["test_array2"]);
#endif
        BOOST_CHECK_EQUAL(test_array2.at(0), "Tèƨƭ #11 ]ƥřôƲèδ ƭλáƭ");
        BOOST_CHECK_EQUAL(test_array2.at(1), "Éжƥèřï₥èñƭ #9 ωáƨ á ƨúççèƨƨ");

        std::string another_test_string =
            toml::get<toml::String>(the_hard["another_test_string"]);
        BOOST_CHECK_EQUAL(another_test_string, "§á₥è ƭλïñϱ, βúƭ ωïƭλ á ƨƭřïñϱ #");
        std::string harder_test_string =
            toml::get<toml::String>(the_hard["harder_test_string"]);
        BOOST_CHECK_EQUAL(harder_test_string, " Âñδ ωλèñ \"'ƨ ářè ïñ ƭλè ƨƭřïñϱ, áℓôñϱ ωïƭλ # \"");

        toml::Table the_hard_bit = toml::get<toml::Table>(the_hard["βïƭ#"]);
        std::string what = toml::get<toml::String>(the_hard_bit["ωλáƭ?"]);
        BOOST_CHECK_EQUAL(what, "Ýôú δôñ'ƭ ƭλïñƙ ƨô₥è úƨèř ωôñ'ƭ δô ƭλáƭ?");
        std::vector<std::string> multi_line_array =
#ifdef TOML_ENABLE_CXX11
            toml::get<toml::Array<toml::String>>(the_hard_bit["multi_line_array"]);
#else
            toml::get<toml::Array<toml::String>::type>(the_hard_bit["multi_line_array"]);
#endif
        BOOST_CHECK_EQUAL(multi_line_array.at(0), "]");
    }
    else
    {
        std::cerr << "file open error." << std::endl;
    }
}
<|endoftext|>


<commit_before>//----------------------------  quadrature_test.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  quadrature_test.cc  ---------------------------

// Test projection onto lines

#include "../tests.h"
#include <iostream>
#include <fstream>

#include <base/logstream.h>
#include <base/quadrature_lib.h>
#include <base/qprojector.h>
#include <cmath>

template<int dim>
void check_line(Quadrature<1>& quadrature)
{
  Point<dim> p1;
  Point<dim> p2;
  p1(0) = 1.;
  p2(0) = 7.;
  if (dim>1)
    {
      p1(1) = 3;
      p2(1) = -5.;
    }
  if (dim>2)
    {
      p1(2) = 0;
      p2(2) = 10.;
    }
  Quadrature<dim> q = QProjector<dim>::project_to_line(quadrature, p1, p2);
  double s = 0.;

  for (unsigned int k=0;k<q.n_quadrature_points;++k)
    {
      deallog << k << '\t' << q.point(k) << std::endl;
      s += q.weight(k);
    }
  deallog << "length: " << s << std::endl;
}

int main()
{
  std::ofstream logfile("qprojector.output");
  deallog.attach(logfile);
  deallog.depth_console(10);
  deallog.threshold_double(1.e-10);

  QTrapez<1> trapez;
  check_line<1> (trapez);
  check_line<2> (trapez);
  check_line<3> (trapez);

  QSimpson<1> simpson;
  check_line<1> (simpson);
  check_line<2> (simpson);
  check_line<3> (simpson);

  QMilne<1> milne;
  check_line<1> (milne);
  check_line<2> (milne);
  check_line<3> (milne);

  QWeddle<1> weddle;
  check_line<1> (weddle);
  check_line<2> (weddle);
  check_line<3> (weddle);
}
<commit_msg>No output to console.<commit_after>//----------------------------  quadrature_test.cc  ---------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//----------------------------  quadrature_test.cc  ---------------------------

// Test projection onto lines

#include "../tests.h"
#include <iostream>
#include <fstream>

#include <base/logstream.h>
#include <base/quadrature_lib.h>
#include <base/qprojector.h>
#include <cmath>

template<int dim>
void check_line(Quadrature<1>& quadrature)
{
  Point<dim> p1;
  Point<dim> p2;
  p1(0) = 1.;
  p2(0) = 7.;
  if (dim>1)
    {
      p1(1) = 3;
      p2(1) = -5.;
    }
  if (dim>2)
    {
      p1(2) = 0;
      p2(2) = 10.;
    }
  Quadrature<dim> q = QProjector<dim>::project_to_line(quadrature, p1, p2);
  double s = 0.;

  for (unsigned int k=0;k<q.n_quadrature_points;++k)
    {
      deallog << k << '\t' << q.point(k) << std::endl;
      s += q.weight(k);
    }
  deallog << "length: " << s << std::endl;
}

int main()
{
  std::ofstream logfile("qprojector.output");
  deallog.attach(logfile);
  deallog.depth_console(0);
  deallog.threshold_double(1.e-10);

  QTrapez<1> trapez;
  check_line<1> (trapez);
  check_line<2> (trapez);
  check_line<3> (trapez);

  QSimpson<1> simpson;
  check_line<1> (simpson);
  check_line<2> (simpson);
  check_line<3> (simpson);

  QMilne<1> milne;
  check_line<1> (milne);
  check_line<2> (milne);
  check_line<3> (milne);

  QWeddle<1> weddle;
  check_line<1> (weddle);
  check_line<2> (weddle);
  check_line<3> (weddle);
}
<|endoftext|>


<commit_before>#include "QRenderingWidget.h"
#include <qpainter.h>
#include <QKeyEvent>
#include <memory>
#include "Global.h"
#include "PrimitiveTypes.h"
#include "ImageFormats.h"
#include "Vector3.h"
#include "ObjLoader.h"
#include "ImageExporter.h"
#include "Material.h"
#include "TestScene.h"

QRenderingWidget::QRenderingWidget(QWidget* parent)
	: QOpenGLWidget(parent)
	, m_renderingTimeMs(0.0)
{
	setFocusPolicy(Qt::StrongFocus);
	bRenderer = std::make_unique<Renderer>();
	setMouseTracking(false);
	SetScene("");
}

QRenderingWidget::~QRenderingWidget()
{
	m_loop = false;
	m_renderThread.join();
}

void QRenderingWidget::SetScene(const char* filename)
{
	filename;
	scene.reset(TestScene());
}

void QRenderingWidget::SaveFrame(const char* path)
{
	std::string fileName;
	std::unique_ptr<FrameBuffer> frame = std::make_unique<FrameBuffer>(imgDisplay->width(), imgDisplay->height());
	{
		std::scoped_lock<std::mutex> img_lock(m_renderMtx);
		CopyQImageToFrameBuffer(*frame.get(), *imgDisplay);
		fileName = Renderer::GenerateFilename("ui", frame->GetHeight(), m_renderingMode, m_shadingMode, m_pixelSamples, m_maxBounces);
	}

	ImageExporter::ExportToBMP(std::string(path), fileName, *frame);
}

void QRenderingWidget::SetRenderingMode(int index)
{
	switch (index)
	{
	case 1:
		m_renderingMode = Renderer::RenderingMode::RAYTRACER;
		break;
	default:
		m_renderingMode = Renderer::RenderingMode::RASTERIZER;
		break;
	}
}

void QRenderingWidget::SetShadingMode(int index)
{
	switch (index)
	{
	case 1:
		m_shadingMode = Renderer::ShadingMode::NORMAL;
		break;
	default:
		m_shadingMode = Renderer::ShadingMode::LIT;
		break;
	}
}

void QRenderingWidget::initializeGL()
{
	imgDisplay = std::make_unique<QImage>(width(), height(), QImage::Format_ARGB32);
	imgDisplay->fill(QColor(211, 211, 211));

	connect(this, SIGNAL(RenderingCompleted(double)), this, SLOT(RenderFrame()));

	Raytracer& raytracer = bRenderer->GetRaytracer();
	raytracer.m_pixelSamples = m_pixelSamples;
	raytracer.m_maxBounces = m_maxBounces;

	m_renderThread = std::thread(&QRenderingWidget::RenderLoopThread, this);
}

void QRenderingWidget::resizeGL(int w, int h)
{
	{
		std::scoped_lock<std::mutex> inputLock(m_inputMtx);
		m_inputEvents.clear();
	}

	{
		std::scoped_lock<std::mutex> renderLock(m_renderMtx);
		imgDisplay = std::make_unique<QImage>(w, h, QImage::Format_ARGB32);
	}

	emit RendererResized();
}

void QRenderingWidget::paintGL()
{

}

void QRenderingWidget::RenderFrame()
{
	//Calls paintEvent()
	update();
}

void QRenderingWidget::paintEvent(QPaintEvent* e)
{
	e;
	QPainter painter(this);

	{
		std::scoped_lock<std::mutex> frame_lock(m_renderMtx);

		painter.drawImage(0, 0, *imgDisplay);
	}

	emit RenderingCompleted(m_renderingTimeMs); // atomic
}

void QRenderingWidget::RenderLoopThread()
{
	while (m_loop) // atomic
	{
		const auto beginTime = std::chrono::high_resolution_clock::now();

		InputManager& inputMgr = bRenderer->GetInputManager();
		{
			std::scoped_lock<std::mutex> inputLock(m_inputMtx);
			for (auto& event : m_inputEvents)
			{
				inputMgr.AddEvent(event);
			}

			m_inputEvents.clear();
		}

		const FrameBuffer* frame = bRenderer->Render(width(), height(), *scene, m_renderingMode, m_shadingMode, m_renderingTimeMs * 0.001f);

		{
			std::scoped_lock<std::mutex> renderLock(m_renderMtx);

			uint imgSize = static_cast<uint>(imgDisplay->width() * imgDisplay->height());

			if (frame->NumPixels() == imgSize)
			{
				CopyFrameBufferToQImage(*imgDisplay.get(), *frame);
			}
		}

		const auto endTime = std::chrono::high_resolution_clock::now();

		ConvertChronoDuration<std::chrono::milliseconds>(endTime - beginTime, m_renderingTimeMs); // atomic
	}
}

void QRenderingWidget::CopyFrameBufferToQImage(QImage& img, const FrameBuffer& frame)
{
	assert(img.width() == frame.GetWidth() && img.height() == frame.GetHeight());

	QRgb* rgb = reinterpret_cast<QRgb*>(img.bits());
	uint size = img.width() * img.height();

	const Color* c = frame.GetColorBuffer();

	if (c != nullptr)
	{
		for (uint i = 0; i < size; ++i)
		{
			uint ua = 255u << 24;
			ua |= static_cast<uint>(c[i].x * 255.999f) << 16;
			ua |= static_cast<uint>(c[i].y * 255.999f) << 8;
			ua |= static_cast<uint>(c[i].z * 255.999f);

			rgb[i] = ua;
		}
	}
}

void QRenderingWidget::CopyQImageToFrameBuffer(FrameBuffer& frame, const QImage& img)
{
	assert(img.width() == frame.GetWidth() && img.height() == frame.GetHeight());

	const QRgb* rgb = reinterpret_cast<const QRgb*>(img.bits());
	uint size = frame.GetWidth() * frame.GetHeight();

		for (uint i = 0; i < size; ++i)
		{
			uint ua = rgb[i];
			uint r = 0u, g = 0u, b = 0u;

			r |= (ua >> 16) & 255u;
			g |= (ua >> 8) & 255u;
			b |= ua & 255u;

			Color c(r / 255.999f, g / 255.999f, b / 255.999f);

			frame.WriteToColor(i, c);
		}
}

void QRenderingWidget::keyPressEvent(QKeyEvent* event)
{
	ButtonState state;
	ButtonType type;
	bool matched = false;

	if (event->type() == QKeyEvent::KeyPress)
	{
		state = ButtonState::PRESSED;

		switch (event->key())
		{
		case Qt::Key::Key_W:
		{
			type = ButtonType::KEY_W;
			matched = true;
			break;
		}

		case Qt::Key::Key_A:
		{
			type = ButtonType::KEY_A;
			matched = true;
			break;
		}

		case Qt::Key::Key_S:
		{
			type = ButtonType::KEY_S;
			matched = true;
			break;
		}

		case Qt::Key::Key_D:
		{
			type = ButtonType::KEY_D;
			matched = true;
			break;
		}

		case Qt::Key::Key_Q:
		{
			type = ButtonType::KEY_Q;
			matched = true;
			break;
		}

		case Qt::Key::Key_E:
		{
			type = ButtonType::KEY_E;
			matched = true;
			break;
		}

		}
	}
	else if (event->type() == QKeyEvent::KeyRelease)
	{
		state = ButtonState::RELEASED;

		switch (event->key())
		{
		case Qt::Key::Key_Escape:
		{
			type = ButtonType::KEY_ESCAPE;
			matched = true;
			break;
		}
		}
	}

	if (matched)
	{
		std::unique_ptr<ButtonInputEvent> inputEvent = std::make_unique<ButtonInputEvent>(type, state);

		std::scoped_lock<std::mutex> inputLock(m_inputMtx);
		m_inputEvents.push_back(std::move(inputEvent));
	}
}

void QRenderingWidget::mousePressEvent(QMouseEvent* event)
{
	const Vector2 currentMousePos(event->x(), event->y());
	ButtonType type;
	bool matched = false;

	switch (event->button())
	{
	case Qt::MouseButton::LeftButton:
	{
		type = ButtonType::CURSOR_PRIMARY;
		matched = true;
		break;
	}

	case Qt::MouseButton::RightButton:
	{
		type = ButtonType::CURSOR_SECONDARY;
		matched = true;
		break;
	}

	}

	if (matched)
	{
		std::unique_ptr<ButtonInputEvent> inputEvent = std::make_unique<ButtonInputEvent>(type, ButtonState::PRESSED, currentMousePos);

		std::scoped_lock<std::mutex> inputLock(m_inputMtx);
		m_inputEvents.push_back(std::move(inputEvent));
	}
}

void QRenderingWidget::mouseReleaseEvent(QMouseEvent* event)
{
	const Vector2 currentMousePos(event->x(), event->y());
	ButtonType type;
	bool matched = false;

	switch (event->button())
	{
	case Qt::MouseButton::LeftButton:
	{
		type = ButtonType::CURSOR_PRIMARY;
		matched = true;
		break;
	}

	case Qt::MouseButton::RightButton:
	{
		type = ButtonType::CURSOR_SECONDARY;
		matched = true;
		break;
	}

	}

	if (matched)
	{
		std::unique_ptr<ButtonInputEvent> inputEvent = std::make_unique<ButtonInputEvent>(type, ButtonState::RELEASED, currentMousePos);

		std::scoped_lock<std::mutex> inputLock(m_inputMtx);
		m_inputEvents.push_back(std::move(inputEvent));
	}
}

void QRenderingWidget::mouseMoveEvent(QMouseEvent* event)
{
	const Vector2 currentPos(event->x(), event->y());
	std::unique_ptr<CursorInputEvent> inputEvent = std::make_unique<CursorInputEvent>(currentPos);

	std::scoped_lock<std::mutex> inputLock(m_inputMtx);
	m_inputEvents.push_back(std::move(inputEvent));
}

<commit_msg>added todo<commit_after>#include "QRenderingWidget.h"
#include <qpainter.h>
#include <QKeyEvent>
#include <memory>
#include "Global.h"
#include "PrimitiveTypes.h"
#include "ImageFormats.h"
#include "Vector3.h"
#include "ObjLoader.h"
#include "ImageExporter.h"
#include "Material.h"
#include "TestScene.h"

QRenderingWidget::QRenderingWidget(QWidget* parent)
	: QOpenGLWidget(parent)
	, m_renderingTimeMs(0.0)
{
	setFocusPolicy(Qt::StrongFocus);
	bRenderer = std::make_unique<Renderer>();
	setMouseTracking(false);
	SetScene("");
}

QRenderingWidget::~QRenderingWidget()
{
	m_loop = false;
	m_renderThread.join();
}

void QRenderingWidget::SetScene(const char* filename)
{
	filename;
	scene.reset(TestScene());
}

void QRenderingWidget::SaveFrame(const char* path)
{
	std::string fileName;
	std::unique_ptr<FrameBuffer> frame = std::make_unique<FrameBuffer>(imgDisplay->width(), imgDisplay->height());
	{
		std::scoped_lock<std::mutex> img_lock(m_renderMtx);
		CopyQImageToFrameBuffer(*frame.get(), *imgDisplay);
		fileName = Renderer::GenerateFilename("ui", frame->GetHeight(), m_renderingMode, m_shadingMode, m_pixelSamples, m_maxBounces);
	}

	ImageExporter::ExportToBMP(std::string(path), fileName, *frame);
}

void QRenderingWidget::SetRenderingMode(int index)
{
	switch (index)
	{
	case 1:
		m_renderingMode = Renderer::RenderingMode::RAYTRACER;
		break;
	default:
		m_renderingMode = Renderer::RenderingMode::RASTERIZER;
		break;
	}
}

void QRenderingWidget::SetShadingMode(int index)
{
	switch (index)
	{
	case 1:
		m_shadingMode = Renderer::ShadingMode::NORMAL;
		break;
	default:
		m_shadingMode = Renderer::ShadingMode::LIT;
		break;
	}
}

void QRenderingWidget::initializeGL()
{
	imgDisplay = std::make_unique<QImage>(width(), height(), QImage::Format_ARGB32);
	imgDisplay->fill(QColor(211, 211, 211));

	connect(this, SIGNAL(RenderingCompleted(double)), this, SLOT(RenderFrame()));

	Raytracer& raytracer = bRenderer->GetRaytracer();
	raytracer.m_pixelSamples = m_pixelSamples;
	raytracer.m_maxBounces = m_maxBounces;

	m_renderThread = std::thread(&QRenderingWidget::RenderLoopThread, this);
}

void QRenderingWidget::resizeGL(int w, int h)
{
	{
		std::scoped_lock<std::mutex> inputLock(m_inputMtx);
		m_inputEvents.clear();
	}

	{
		std::scoped_lock<std::mutex> renderLock(m_renderMtx);
		imgDisplay = std::make_unique<QImage>(w, h, QImage::Format_ARGB32);
	}

	emit RendererResized();
}

void QRenderingWidget::paintGL()
{

}

void QRenderingWidget::RenderFrame()
{
	//Calls paintEvent()
	update();
}

void QRenderingWidget::paintEvent(QPaintEvent* e)
{
	e;
	QPainter painter(this);

	{
		std::scoped_lock<std::mutex> frame_lock(m_renderMtx);

		painter.drawImage(0, 0, *imgDisplay);
	}

	emit RenderingCompleted(m_renderingTimeMs); // atomic
}

void QRenderingWidget::RenderLoopThread()
{
	while (m_loop) // atomic
	{
		const auto beginTime = std::chrono::high_resolution_clock::now();

		InputManager& inputMgr = bRenderer->GetInputManager();
		{
			std::scoped_lock<std::mutex> inputLock(m_inputMtx);
			for (auto& event : m_inputEvents)
			{
				inputMgr.AddEvent(event);
			}

			m_inputEvents.clear();
		}

		const FrameBuffer* frame = bRenderer->Render(width(), height(), *scene, m_renderingMode, m_shadingMode, m_renderingTimeMs * 0.001f);

		{
			// TODO double buffering
			std::scoped_lock<std::mutex> renderLock(m_renderMtx);

			uint imgSize = static_cast<uint>(imgDisplay->width() * imgDisplay->height());

			if (frame->NumPixels() == imgSize)
			{
				CopyFrameBufferToQImage(*imgDisplay.get(), *frame);
			}
		}

		const auto endTime = std::chrono::high_resolution_clock::now();

		ConvertChronoDuration<std::chrono::milliseconds>(endTime - beginTime, m_renderingTimeMs); // atomic
	}
}

void QRenderingWidget::CopyFrameBufferToQImage(QImage& img, const FrameBuffer& frame)
{
	assert(img.width() == frame.GetWidth() && img.height() == frame.GetHeight());

	QRgb* rgb = reinterpret_cast<QRgb*>(img.bits());
	uint size = img.width() * img.height();

	const Color* c = frame.GetColorBuffer();

	if (c != nullptr)
	{
		for (uint i = 0; i < size; ++i)
		{
			uint ua = 255u << 24;
			ua |= static_cast<uint>(c[i].x * 255.999f) << 16;
			ua |= static_cast<uint>(c[i].y * 255.999f) << 8;
			ua |= static_cast<uint>(c[i].z * 255.999f);

			rgb[i] = ua;
		}
	}
}

void QRenderingWidget::CopyQImageToFrameBuffer(FrameBuffer& frame, const QImage& img)
{
	assert(img.width() == frame.GetWidth() && img.height() == frame.GetHeight());

	const QRgb* rgb = reinterpret_cast<const QRgb*>(img.bits());
	uint size = frame.GetWidth() * frame.GetHeight();

		for (uint i = 0; i < size; ++i)
		{
			uint ua = rgb[i];
			uint r = 0u, g = 0u, b = 0u;

			r |= (ua >> 16) & 255u;
			g |= (ua >> 8) & 255u;
			b |= ua & 255u;

			Color c(r / 255.999f, g / 255.999f, b / 255.999f);

			frame.WriteToColor(i, c);
		}
}

void QRenderingWidget::keyPressEvent(QKeyEvent* event)
{
	ButtonState state;
	ButtonType type;
	bool matched = false;

	if (event->type() == QKeyEvent::KeyPress)
	{
		state = ButtonState::PRESSED;

		switch (event->key())
		{
		case Qt::Key::Key_W:
		{
			type = ButtonType::KEY_W;
			matched = true;
			break;
		}

		case Qt::Key::Key_A:
		{
			type = ButtonType::KEY_A;
			matched = true;
			break;
		}

		case Qt::Key::Key_S:
		{
			type = ButtonType::KEY_S;
			matched = true;
			break;
		}

		case Qt::Key::Key_D:
		{
			type = ButtonType::KEY_D;
			matched = true;
			break;
		}

		case Qt::Key::Key_Q:
		{
			type = ButtonType::KEY_Q;
			matched = true;
			break;
		}

		case Qt::Key::Key_E:
		{
			type = ButtonType::KEY_E;
			matched = true;
			break;
		}

		}
	}
	else if (event->type() == QKeyEvent::KeyRelease)
	{
		state = ButtonState::RELEASED;

		switch (event->key())
		{
		case Qt::Key::Key_Escape:
		{
			type = ButtonType::KEY_ESCAPE;
			matched = true;
			break;
		}
		}
	}

	if (matched)
	{
		std::unique_ptr<ButtonInputEvent> inputEvent = std::make_unique<ButtonInputEvent>(type, state);

		std::scoped_lock<std::mutex> inputLock(m_inputMtx);
		m_inputEvents.push_back(std::move(inputEvent));
	}
}

void QRenderingWidget::mousePressEvent(QMouseEvent* event)
{
	const Vector2 currentMousePos(event->x(), event->y());
	ButtonType type;
	bool matched = false;

	switch (event->button())
	{
	case Qt::MouseButton::LeftButton:
	{
		type = ButtonType::CURSOR_PRIMARY;
		matched = true;
		break;
	}

	case Qt::MouseButton::RightButton:
	{
		type = ButtonType::CURSOR_SECONDARY;
		matched = true;
		break;
	}

	}

	if (matched)
	{
		std::unique_ptr<ButtonInputEvent> inputEvent = std::make_unique<ButtonInputEvent>(type, ButtonState::PRESSED, currentMousePos);

		std::scoped_lock<std::mutex> inputLock(m_inputMtx);
		m_inputEvents.push_back(std::move(inputEvent));
	}
}

void QRenderingWidget::mouseReleaseEvent(QMouseEvent* event)
{
	const Vector2 currentMousePos(event->x(), event->y());
	ButtonType type;
	bool matched = false;

	switch (event->button())
	{
	case Qt::MouseButton::LeftButton:
	{
		type = ButtonType::CURSOR_PRIMARY;
		matched = true;
		break;
	}

	case Qt::MouseButton::RightButton:
	{
		type = ButtonType::CURSOR_SECONDARY;
		matched = true;
		break;
	}

	}

	if (matched)
	{
		std::unique_ptr<ButtonInputEvent> inputEvent = std::make_unique<ButtonInputEvent>(type, ButtonState::RELEASED, currentMousePos);

		std::scoped_lock<std::mutex> inputLock(m_inputMtx);
		m_inputEvents.push_back(std::move(inputEvent));
	}
}

void QRenderingWidget::mouseMoveEvent(QMouseEvent* event)
{
	const Vector2 currentPos(event->x(), event->y());
	std::unique_ptr<CursorInputEvent> inputEvent = std::make_unique<CursorInputEvent>(currentPos);

	std::scoped_lock<std::mutex> inputLock(m_inputMtx);
	m_inputEvents.push_back(std::move(inputEvent));
}

<|endoftext|>


<commit_before>#include "alarmpersistence.h"
#include "common_errors.h"

#include <QFileInfo>
#include <QDebug>
#include <QApplication>
#include <QMessageBox>

#include <string>
#include <sstream>
#include <fstream>

AlarmPersistence::AlarmPersistence(Config cfg, QObject *parent)
    : QObject(parent)
    , timer(new QTimer(this))
    , currentTime()
    , alarmPoint()
    , snoozeOffset()
    , config(std::move(cfg))
    , active(false)
    , inSnoozeMode(false)
    , fsys()
    , alarmSound()
    , testSound()
{
    connect(timer, SIGNAL(timeout()), this, SLOT(on_timer()));

    load();

    if (!QFile::exists("./sinewave.mp3"))
        QFile::copy(":/sounds/sinewave.mp3", "./sinewave.mp3");

    try {
        testSound = std::static_pointer_cast <FMODSound::Sound> (fsys.createSound(QFileInfo("./sinewave.mp3").absoluteFilePath().toStdString()));
        alarmSound = std::static_pointer_cast <FMODSound::Sound> (fsys.createStream(QFileInfo(QString::fromStdString(config.cget().alarmFile)).absoluteFilePath().toStdString()));
    }
    catch (FMODSound::Error const& exc) {
        showCritical(exc);

        // force exit
        exit(1);
    }

    timer->start(1000);
}

AlarmPersistence::~AlarmPersistence()
{
    timer->stop();
}

void AlarmPersistence::on_timer()
{
    currentTime = std::chrono::system_clock::now();

    auto time = std::chrono::system_clock::to_time_t(currentTime);
    auto local = localtime(&time);

    auto hour = local->tm_hour;
    auto minute = local->tm_min;
    auto second = local->tm_sec;

    // exact match: this is when you should start waking this lazy ass ;)
    if (active)
    {
        if (hour == alarmPoint.first && minute == alarmPoint.second && !inSnoozeMode && second == 0)
        {
            start_alarm();
            snooze();
        }
        // ok already in the snooze section?
        else if (inSnoozeMode)
        {
            auto curTime = std::chrono::hours(hour) + std::chrono::minutes(minute) + std::chrono::seconds(second);
            auto originalPoint = std::chrono::hours(alarmPoint.first) + std::chrono::minutes(alarmPoint.second);
            auto diff = (originalPoint + snoozeOffset) - curTime;

            if (std::chrono::duration_cast <std::chrono::seconds> (diff).count() <= 0)
            {
                start_alarm();
                increment_snooze();
            }
        }
    }

    emit timeout();
}

void AlarmPersistence::start_alarm()
{
    // play Sound
    try {
        auto play = [&]()
        {
            alarmSound->play(true);
            alarmSound->setVolume(static_cast <float> (config.cget().volume) / 100.f);
            alarmSound->unpause();
        };

        fsys.update();
        if (alarmSound->isPersistent())
        {
            if (alarmSound->isPlaying())
            {
                alarmSound->stop();
                play();

            }
            else if (alarmSound->isPaused())
            {
                alarmSound->unpause();
            }
            else
            {
                play();
            }
        }
        else
        {
            play();
        }
    } catch (FMODSound::Error const& exc)
    {
        showCritical(exc);

        // force exit
        exit(1);
    }
}

void AlarmPersistence::save()
{
    auto&& content = config.get();
    content()->alarmPoint = alarmPoint;
    content()->alarmActive = active;
}

void AlarmPersistence::load()
{
    auto&& content = config.get();

    active = content()->alarmActive;
    alarmPoint = content()->alarmPoint;
}

void AlarmPersistence::increment_snooze()
{
    snoozeOffset += std::chrono::minutes(config.cget().snoozeTime);
}

void AlarmPersistence::snooze()
{
    if (!inSnoozeMode)
        increment_snooze();
    inSnoozeMode = true;
}

void AlarmPersistence::reset_snooze()
{
    snoozeOffset = std::chrono::seconds(0);
    inSnoozeMode = false;
}

void AlarmPersistence::increment_hour()
{
    alarmPoint.first++;
    if (alarmPoint.first >= 24)
        alarmPoint.first = 0;
    save();
}

void AlarmPersistence::increment_minute()
{
    alarmPoint.second += 5;
    if (alarmPoint.second == 60)
        alarmPoint.second = 0;
    save();
}

void AlarmPersistence::decrement_hour()
{
    if (alarmPoint.first == 0)
        alarmPoint.first = 24;
    alarmPoint.first--;
    save();
}

void AlarmPersistence::decrement_minute()
{
    if (alarmPoint.second == 0)
        alarmPoint.second = 60;
    alarmPoint.second -= 5;
    save();
}

void AlarmPersistence::toggle_active()
{
    active = !active;
    save();
}

std::chrono::time_point<std::chrono::system_clock> AlarmPersistence::getCurrentTime() const
{
    return currentTime;
}

void AlarmPersistence::setAlarmPoint(short hour, short minute)
{
    alarmPoint = std::make_pair (hour, minute);
}

void AlarmPersistence::setAlarmPoint(std::pair <short, short> const& point)
{
    alarmPoint = point;
}

std::pair<short, short> AlarmPersistence::getNextAlarmPoint() const
{
    auto next = std::chrono::hours(alarmPoint.first) + std::chrono::minutes(alarmPoint.second) + snoozeOffset;
    if (std::chrono::duration_cast <std::chrono::hours> (next).count() >= 24)
    {
        next -= std::chrono::hours(24);
    }
    return {
        std::chrono::duration_cast <std::chrono::hours> (next).count(),
        std::chrono::duration_cast <std::chrono::minutes> (next - std::chrono::duration_cast<std::chrono::hours>(next)).count()
    };
}

std::pair<short, short> AlarmPersistence::getAlarmPoint() const
{
    return alarmPoint;
}

bool AlarmPersistence::isActive() const
{
    return active;
}

void AlarmPersistence::playTestSound() const
{
    try {
        testSound->play(true);
        testSound->setVolume(static_cast <float> (config.cget().volume) / 100.f);
        testSound->unpause();
    } catch (FMODSound::Error const& exc)
    {
        showCritical(exc);

        exit(1);
    }
}

void AlarmPersistence::stop_alarm()
{
    fsys.update();

    try {
        if (alarmSound->isOpened())
            if (alarmSound->isPlaying())
                alarmSound->stop();
    } catch (FMODSound::Error const& exc)
    {
        showCritical(exc);
        exit(1);
    }
}

<commit_msg>deltaMinute constant reintroduced for testing purposes<commit_after>#include "alarmpersistence.h"
#include "common_errors.h"

#include <QFileInfo>
#include <QDebug>
#include <QApplication>
#include <QMessageBox>

#include <string>
#include <sstream>
#include <fstream>

// DEBUG!
const int deltaMinute = 5;

AlarmPersistence::AlarmPersistence(Config cfg, QObject *parent)
    : QObject(parent)
    , timer(new QTimer(this))
    , currentTime()
    , alarmPoint()
    , snoozeOffset()
    , config(std::move(cfg))
    , active(false)
    , inSnoozeMode(false)
    , fsys()
    , alarmSound()
    , testSound()
{
    connect(timer, SIGNAL(timeout()), this, SLOT(on_timer()));

    load();

    if (!QFile::exists("./sinewave.mp3"))
        QFile::copy(":/sounds/sinewave.mp3", "./sinewave.mp3");

    try {
        testSound = std::static_pointer_cast <FMODSound::Sound> (fsys.createSound(QFileInfo("./sinewave.mp3").absoluteFilePath().toStdString()));
        alarmSound = std::static_pointer_cast <FMODSound::Sound> (fsys.createStream(QFileInfo(QString::fromStdString(config.cget().alarmFile)).absoluteFilePath().toStdString()));
    }
    catch (FMODSound::Error const& exc) {
        showCritical(exc);

        // force exit
        exit(1);
    }

    timer->start(1000);
}

AlarmPersistence::~AlarmPersistence()
{
    timer->stop();
}

void AlarmPersistence::on_timer()
{
    currentTime = std::chrono::system_clock::now();

    auto time = std::chrono::system_clock::to_time_t(currentTime);
    auto local = localtime(&time);

    auto hour = local->tm_hour;
    auto minute = local->tm_min;
    auto second = local->tm_sec;

    // exact match: this is when you should start waking this lazy ass ;)
    if (active)
    {
        if (hour == alarmPoint.first && minute == alarmPoint.second && !inSnoozeMode && second == 0)
        {
            start_alarm();
            snooze();
        }
        // ok already in the snooze section?
        else if (inSnoozeMode)
        {
            auto curTime = std::chrono::hours(hour) + std::chrono::minutes(minute) + std::chrono::seconds(second);
            auto originalPoint = std::chrono::hours(alarmPoint.first) + std::chrono::minutes(alarmPoint.second);
            auto diff = (originalPoint + snoozeOffset) - curTime;

            if (std::chrono::duration_cast <std::chrono::seconds> (diff).count() <= 0)
            {
                start_alarm();
                increment_snooze();
            }
        }
    }

    emit timeout();
}

void AlarmPersistence::start_alarm()
{
    // play Sound
    try {
        auto play = [&]()
        {
            alarmSound->play(true);
            alarmSound->setVolume(static_cast <float> (config.cget().volume) / 100.f);
            alarmSound->unpause();
        };

        fsys.update();
        if (alarmSound->isPersistent())
        {
            if (alarmSound->isPlaying())
            {
                alarmSound->stop();
                play();

            }
            else if (alarmSound->isPaused())
            {
                alarmSound->unpause();
            }
            else
            {
                play();
            }
        }
        else
        {
            play();
        }
    } catch (FMODSound::Error const& exc)
    {
        showCritical(exc);

        // force exit
        exit(1);
    }
    emit alarm_fired();
}

void AlarmPersistence::save()
{
    auto&& content = config.get();
    content()->alarmPoint = alarmPoint;
    content()->alarmActive = active;
}

void AlarmPersistence::load()
{
    auto&& content = config.get();

    active = content()->alarmActive;
    alarmPoint = content()->alarmPoint;
}

void AlarmPersistence::increment_snooze()
{
    snoozeOffset += std::chrono::minutes(config.cget().snoozeTime);
}

void AlarmPersistence::snooze()
{
    if (!inSnoozeMode)
        increment_snooze();
    inSnoozeMode = true;
}

void AlarmPersistence::reset_snooze()
{
    snoozeOffset = std::chrono::seconds(0);
    inSnoozeMode = false;
}

void AlarmPersistence::increment_hour()
{
    alarmPoint.first++;
    if (alarmPoint.first >= 24)
        alarmPoint.first = 0;
    save();
}

void AlarmPersistence::increment_minute()
{
    alarmPoint.second += deltaMinute;
    if (alarmPoint.second == 60)
        alarmPoint.second = 0;
    save();
}

void AlarmPersistence::decrement_hour()
{
    if (alarmPoint.first == 0)
        alarmPoint.first = 24;
    alarmPoint.first--;
    save();
}

void AlarmPersistence::decrement_minute()
{
    if (alarmPoint.second == 0)
        alarmPoint.second = 60;
    alarmPoint.second -= deltaMinute;
    save();
}

void AlarmPersistence::toggle_active()
{
    active = !active;
    save();
}

std::chrono::time_point<std::chrono::system_clock> AlarmPersistence::getCurrentTime() const
{
    return currentTime;
}

void AlarmPersistence::setAlarmPoint(short hour, short minute)
{
    alarmPoint = std::make_pair (hour, minute);
}

void AlarmPersistence::setAlarmPoint(std::pair <short, short> const& point)
{
    alarmPoint = point;
}

std::pair<short, short> AlarmPersistence::getNextAlarmPoint() const
{
    auto next = std::chrono::hours(alarmPoint.first) + std::chrono::minutes(alarmPoint.second) + snoozeOffset;
    if (std::chrono::duration_cast <std::chrono::hours> (next).count() >= 24)
    {
        next -= std::chrono::hours(24);
    }
    return {
        std::chrono::duration_cast <std::chrono::hours> (next).count(),
        std::chrono::duration_cast <std::chrono::minutes> (next - std::chrono::duration_cast<std::chrono::hours>(next)).count()
    };
}

std::pair<short, short> AlarmPersistence::getAlarmPoint() const
{
    return alarmPoint;
}

bool AlarmPersistence::isActive() const
{
    return active;
}

void AlarmPersistence::playTestSound() const
{
    try {
        testSound->play(true);
        testSound->setVolume(static_cast <float> (config.cget().volume) / 100.f);
        testSound->unpause();
    } catch (FMODSound::Error const& exc)
    {
        showCritical(exc);

        exit(1);
    }
}

void AlarmPersistence::stop_alarm()
{
    fsys.update();

    try {
        if (alarmSound->isOpened())
            if (alarmSound->isPlaying())
                alarmSound->stop();
    } catch (FMODSound::Error const& exc)
    {
        showCritical(exc);
        exit(1);
    }
    emit alarm_stopped();
}

<|endoftext|>