Program Listing for File showcontrolwidget.cpp

Return to documentation for file (src/widget/showcontrolwidget.cpp)

#include <QKeyEvent>
#include <QListIterator>
#include <QListWidget>
#include <QModelIndex>
#include <QRegExp>
#include <QSettings>
#include <QTime>
#include "dialog/preferencesdialog.h"
#include "dialog/editeventdialog.h"
#include "showcontrolwidget.h"
#include "ui_showcontrolwidget.h"
#include "controller/showcontroller.h"

namespace PixelMaestroStudio {

    QString ShowControlWidget::time_format = QStringLiteral("hh:mm:ss.zzz");

    ShowControlWidget::ShowControlWidget(QWidget *parent) :
            QWidget(parent),
            ui(new Ui::ShowControlWidget),
            maestro_control_widget_(*dynamic_cast<MaestroControlWidget*>(parent)) {
        ui->setupUi(this);

        // Capture key presses
        qApp->installEventFilter(this);

        show_timer_.start();

        connect(ui->eventQueueWidget->model(), &QAbstractItemModel::rowsMoved, this, &ShowControlWidget::on_eventQueueWidget_rowsMoved);
    }

    void ShowControlWidget::add_event_to_history(uint8_t *cue) {
        ui->eventHistoryWidget->addItem(CueInterpreter::interpret_cue(cue));

        // Convert the Cue into an actual byte array, which we'll store in the Event History for later use.
        uint32_t cue_size = maestro_control_widget_.cue_controller_->get_cue_size(cue);
        QVector<uint8_t> cue_vector(cue_size);
        for (uint16_t byte = 0; byte < cue_size; byte++) {
            cue_vector[byte] = cue[byte];
        }

        event_history_.push_back(cue_vector);

        // Remove all but the last XX events
        QSettings settings;
        if (event_history_.size() >= settings.value(PreferencesDialog::event_history_max, 200).toInt()) {
            ui->eventHistoryWidget->takeItem(0);
            event_history_.remove(0);
        }
    }

    bool ShowControlWidget::eventFilter(QObject *watched, QEvent *event) {
        if (event->type() == QEvent::KeyPress) {
            QKeyEvent* key_event = dynamic_cast<QKeyEvent*>(event);
            // Delete queued events only when when Event queue has focus
            if (watched == ui->eventQueueWidget) {
                if (key_event->key() == Qt::Key_Delete) {
                    on_removeEventButton_clicked();
                    return true;
                }
            }
        }

        return QObject::eventFilter(watched, event);
    }

    void ShowControlWidget::initialize() {
        // Disable controls by default
        set_show_controls_enabled(false);

        // Setup timer
        show_timer_.setTimerType(Qt::CoarseTimer);
        show_timer_.setInterval(TIMER_INTERVAL_);
        connect(&show_timer_, SIGNAL(timeout()), this, SLOT(timer_refresh()));

        // Initialize ShowController
        if (show_controller_ == nullptr) {
            show_controller_ = new ShowController();
        }
        else {
            show_controller_->clear();
        }

        on_clearHistoryButton_clicked();
        on_clearQueueButton_clicked();
    }

    bool ShowControlWidget::get_maestro_locked() const {
        return maestro_locked_;
    }

    void ShowControlWidget::move_event(int current_index, int target_index) {
        QListWidgetItem* item = ui->eventQueueWidget->takeItem(current_index);

        show_controller_->move(current_index, target_index);
        ui->eventQueueWidget->insertItem(target_index, item);
        ui->eventQueueWidget->setCurrentRow(target_index);
    }

    void ShowControlWidget::on_addEventButton_clicked() {
        for (QModelIndex index : ui->eventHistoryWidget->selectionModel()->selectedIndexes()) {
            QTime time = ui->eventTimeEdit->time();
            show_controller_->add_event(
                (uint32_t)time.msecsSinceStartOfDay(),
                (uint8_t*)event_history_.at(index.row()).data()
            );

            ui->eventQueueWidget->addItem(
                time.toString(time_format) +
                QString(": ") +
                ui->eventHistoryWidget->item(index.row())->text()
            );
        }

        maestro_control_widget_.run_cue(
            maestro_control_widget_.show_handler->set_events(
                show_controller_->get_events()->data(),
                show_controller_->get_events()->size(),
                true
            )
        );
    }

    void ShowControlWidget::on_clearHistoryButton_clicked() {
        ui->eventHistoryWidget->clear();
        event_history_.clear();
    }

    void ShowControlWidget::on_clearQueueButton_clicked() {
        ui->eventQueueWidget->clear();
        show_controller_->get_events()->clear();
        maestro_control_widget_.run_cue(
            maestro_control_widget_.show_handler->set_events(
                nullptr,
                0,
                false
            )
        );
    }

    void ShowControlWidget::on_enableCheckBox_toggled(bool checked) {
        set_show_controls_enabled(checked);

        if (checked) {
            maestro_control_widget_.run_cue(
                maestro_control_widget_.maestro_handler->set_show()
            );
        }
        else {
            maestro_control_widget_.run_cue(
                maestro_control_widget_.maestro_handler->remove_show()
            );
        }
    }

    void ShowControlWidget::on_eventQueueWidget_itemDoubleClicked(QListWidgetItem *item) {
        int row = ui->eventQueueWidget->row(item);

        // Make sure the row is in the bounds of the Event queue
        if (row > -1 && row < show_controller_->get_events()->size()) {
            Event* event = &show_controller_->get_events()->data()[row];
            EditEventDialog dialog(*event, this);
            if (dialog.exec() == QDialog::Accepted) {
                // Update the UI and actual Show Event
                item->setText(locale_.toString(event->get_time()) +
                              QString(": ") +
                              CueInterpreter::interpret_cue(event->get_cue()));

                maestro_control_widget_.run_cue(
                    maestro_control_widget_.show_handler->set_events(
                        show_controller_->get_events()->data(),
                        show_controller_->get_events()->size()
                    )
                );
            }
        }
    }

    void ShowControlWidget::on_eventQueueWidget_rowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) {
        if (parent == destination) {
            for (int i = start; i < end; i++) {
                int dest_row = row;
                if (dest_row >= show_controller_->get_events()->size()) {
                    dest_row = show_controller_->get_events()->size() - 1;
                }
                show_controller_->move(start, dest_row);
            }

            maestro_control_widget_.run_cue(
                maestro_control_widget_.show_handler->set_events(
                    show_controller_->get_events()->data(),
                    show_controller_->get_events()->size()
                )
            );
        }
    }

    void ShowControlWidget::on_loopCheckBox_toggled(bool checked) {
        maestro_control_widget_.run_cue(
            maestro_control_widget_.show_handler->set_looping(checked)
        );
    }

    void ShowControlWidget::on_moveEventDownButton_clicked() {
        QModelIndexList list = ui->eventQueueWidget->selectionModel()->selectedIndexes();
        for (int i = list.size() - 1; i >= 0; i--) {
            int current_index = list.at(i).row();
            if (current_index != ui->eventQueueWidget->count() - 1) {
                move_event(current_index, current_index + 1);
            }
        }

        maestro_control_widget_.run_cue(
            maestro_control_widget_.show_handler->set_events(
                show_controller_->get_events()->data(),
                show_controller_->get_events()->size()
            )
        );
    }

    void ShowControlWidget::on_moveEventUpButton_clicked() {
        QModelIndexList list = ui->eventQueueWidget->selectionModel()->selectedIndexes();
        for (int i = 0; i < list.size(); i++) {
            int current_index = list.at(i).row();
            if (current_index != 0) {
                move_event(current_index, current_index - 1);
            }
        }

        maestro_control_widget_.run_cue(
            maestro_control_widget_.show_handler->set_events(
                show_controller_->get_events()->data(),
                show_controller_->get_events()->size()
            )
        );
    }

    void ShowControlWidget::on_removeEventButton_clicked() {
        // Sort selected rows by index before removing them
        QModelIndexList list = ui->eventQueueWidget->selectionModel()->selectedRows();
        qSort(list.begin(), list.end(), qGreater<QModelIndex>());
        for (QModelIndex index : list) {
            show_controller_->remove_event(index.row());
            ui->eventQueueWidget->takeItem(index.row());
        }

        // Re-initialize the Event list
        maestro_control_widget_.run_cue(
            maestro_control_widget_.show_handler->set_events(
                show_controller_->get_events()->data(),
                show_controller_->get_events()->size(),
                true
            )
        );
    }

    void ShowControlWidget::on_timingModeComboBox_currentIndexChanged(int index) {
        maestro_control_widget_.run_cue(
            maestro_control_widget_.show_handler->set_timing_mode(
                (Show::TimingMode)index
            )
        );

        // Enable loop checkbox if we're in relative mode
        bool relative_mode = (Show::TimingMode)index == Show::TimingMode::Relative;
        ui->loopCheckBox->setEnabled(relative_mode);
        ui->relativeTimeLineEdit->setEnabled(relative_mode);
    }

    void ShowControlWidget::refresh() {
        Show* show = maestro_control_widget_.get_maestro_controller()->get_maestro().get_show();
        ui->enableCheckBox->blockSignals(true);
        ui->enableCheckBox->setChecked(show != nullptr);
        set_show_controls_enabled(show != nullptr);
        ui->enableCheckBox->blockSignals(false);

        if (show != nullptr) {
            for (uint16_t i = 0; i < show->get_num_events(); i++) {
                Event* event = show->get_event_at_index(i);
                if (event != nullptr) {
                    // Check for Events before adding them to prevent duplicates
                    if (show_controller_->get_event_index(event) < 0) {
                        show_controller_->add_event(event->get_time(), event->get_cue());

                        QTime event_time = QTime::fromMSecsSinceStartOfDay(event->get_time());
                        ui->eventQueueWidget->addItem(
                            event_time.toString(time_format) +
                            QString(": ") +
                            CueInterpreter::interpret_cue(event->get_cue())
                        );
                    }
                }
            }

            ui->timingModeComboBox->blockSignals(true);
            ui->timingModeComboBox->setCurrentIndex((uint8_t)show->get_timing());
            ui->timingModeComboBox->blockSignals(false);

            ui->loopCheckBox->blockSignals(true);
            ui->loopCheckBox->setChecked(show->get_looping());
            ui->loopCheckBox->blockSignals(false);

            ui->relativeTimeLineEdit->blockSignals(true);
            ui->relativeTimeLineEdit->setEnabled(show->get_timing() == Show::TimingMode::Relative);
            ui->relativeTimeLineEdit->blockSignals(false);
        }
        else {
            ui->timingModeComboBox->blockSignals(true);
            ui->timingModeComboBox->setCurrentIndex(0);
            ui->timingModeComboBox->blockSignals(false);

            ui->loopCheckBox->blockSignals(true);
            ui->loopCheckBox->setChecked(false);
            ui->loopCheckBox->blockSignals(false);

            ui->relativeTimeLineEdit->blockSignals(true);
            ui->relativeTimeLineEdit->setEnabled(false);
            ui->relativeTimeLineEdit->blockSignals(false);
        }
    }

    void ShowControlWidget::set_maestro_locked(bool locked) {
        this->maestro_locked_ = locked;
    }

    void ShowControlWidget::timer_refresh() {

        // Update 'Absolute Time' text box
        uint absolute_time = (uint)maestro_control_widget_.get_maestro_controller()->get_total_elapsed_time();
        ui->absoluteTimeLineEdit->setText(QTime::fromMSecsSinceStartOfDay(absolute_time).toString(time_format));

        Show* show = maestro_control_widget_.get_maestro_controller()->get_maestro().get_show();
        if (show == nullptr) return;

        // If relative mode is enabled, calculate the time since the last Event
        if (show->get_timing() == Show::TimingMode::Relative) {
            uint relative_time = absolute_time - show->get_last_time();
            ui->relativeTimeLineEdit->setText(QTime::fromMSecsSinceStartOfDay(relative_time).toString(time_format));
        }

        // Get the last event that ran, and if it differs from the Show's current index, update the Event Queue
        if (last_event_time_ != show->get_last_time()) {
            last_event_time_ = show->get_last_time();

            // Darken events that have already ran
            for (int i = 0; i < ui->eventQueueWidget->count(); i++) {
                if (i < show->get_current_index()) {
                    ui->eventQueueWidget->item(i)->setTextColor(Qt::GlobalColor::darkGray);
                }
                else {
                    ui->eventQueueWidget->item(i)->setTextColor(Qt::GlobalColor::white);
                }
            }

            // If live update triggers are enabled, send the last Event's queue to the DeviceControlWidget to be sent to remote devices
            QSettings settings;
            if (settings.value(PreferencesDialog::events_trigger_device_updates, false).toBool()) {
                Event* event = show->get_event_at_index(show->get_current_index());
                if (event != nullptr) {
                    CueController* cue_controller = &maestro_control_widget_.get_maestro_controller()->get_maestro().get_cue_controller();
                    maestro_control_widget_.device_control_widget_->run_cue(
                        event->get_cue(),
                        cue_controller->get_cue_size(event->get_cue())
                    );
                }
            }

            maestro_control_widget_.set_refresh_needed(true);
        }
    }

    void ShowControlWidget::set_show_controls_enabled(bool enabled) {
        ui->timingModeLabel->setEnabled(enabled);
        ui->timingModeComboBox->setEnabled(enabled);
        ui->loopCheckBox->setEnabled(enabled);
        ui->eventsGroupBox->setEnabled(enabled);
    }

    ShowControlWidget::~ShowControlWidget() {
        qApp->removeEventFilter(this);
        delete show_controller_;
        delete ui;
    }
}