Program Listing for File sectioncontrolwidget.cpp¶
↰ Return to documentation for file (src/widget/sectioncontrolwidget.cpp
)
#include "sectioncontrolwidget.h"
#include "ui_sectioncontrolwidget.h"
#include "utility/canvasutility.h"
namespace PixelMaestroStudio {
SectionControlWidget::SectionControlWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::SectionControlWidget),
maestro_control_widget_(*dynamic_cast<MaestroControlWidget*>(parent)) {
ui->setupUi(this);
}
void SectionControlWidget::on_addLayerButton_clicked() {
// Get the number of Layers (and the index of the last Layer) in the Section
Section* base_section = maestro_control_widget_.get_maestro_controller()->get_maestro().get_section(get_section_index());
int num_layers = 0;
while (base_section->get_layer() != nullptr) {
base_section = base_section->get_layer()->section;
num_layers++;
}
uint8_t layer_index = ui->layerListWidget->count() - 1;
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_layer(
get_section_index(),
layer_index,
Colors::MixMode::None,
0
)
);
ui->layerListWidget->addItem(QString("Layer ") + QString::number(layer_index + 1));
ui->layerListWidget->setCurrentRow(layer_index + 1);
}
Section& SectionControlWidget::get_active_section() {
return *active_section_;
}
uint8_t SectionControlWidget::get_layer_index() {
return get_layer_index(*active_section_);
}
uint8_t SectionControlWidget::get_layer_index(Section& section) {
/*
* Find the depth of the current Section by traversing parent_section_.
* Once parent_section == nullptr, we know we've hit the base Section.
*/
uint8_t level = 0;
Section* test_section = §ion;
while (test_section->get_parent_section() != nullptr) {
test_section = test_section->get_parent_section();
level++;
}
return level;
}
uint8_t SectionControlWidget::get_num_layers(Section& section) {
uint8_t count = 0;
Section::Layer* layer = section.get_layer();
while (layer != nullptr) {
layer = layer->section->get_layer();
count++;
}
return count;
}
uint8_t SectionControlWidget::get_section_index() {
return get_section_index(*active_section_);
}
uint8_t SectionControlWidget::get_section_index(Section& section) {
Section* target_section = §ion;
// If this is an Layer, iterate until we find the parent ID
while (target_section->get_parent_section() != nullptr) {
target_section = target_section->get_parent_section();
}
// Iterate until we find the Section that active_section_ points to
uint8_t index = 0;
Section* test_section = maestro_control_widget_.get_maestro_controller()->get_maestro().get_section(0);
while (test_section != target_section) {
index++;
test_section = maestro_control_widget_.get_maestro_controller()->get_maestro().get_section(index);
}
return index;
}
void SectionControlWidget::initialize() {
ui->alphaSpinBox->blockSignals(true);
ui->alphaSpinBox->clear();
ui->alphaSpinBox->blockSignals(false);
// Build Section list
ui->sectionListWidget->blockSignals(true);
ui->sectionListWidget->clear();
for (uint16_t section = 0; section < maestro_control_widget_.get_maestro_controller()->get_maestro().get_num_sections(); section++) {
ui->sectionListWidget->addItem(QString("Section ") + QString::number(section + 1));
}
ui->sectionListWidget->blockSignals(false);
set_active_section(maestro_control_widget_.get_maestro_controller()->get_maestro().get_section(0));
populate_layer_combobox();
}
void SectionControlWidget::on_alphaSpinBox_editingFinished() {
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_layer(
get_section_index(),
get_layer_index(*active_section_->get_parent_section()),
active_section_->get_parent_section()->get_layer()->mix_mode,
ui->alphaSpinBox->value()
)
);
}
void SectionControlWidget::on_brightnessSlider_valueChanged(int value) {
ui->brightnessSpinBox->blockSignals(true);
ui->brightnessSpinBox->setValue(value);
ui->brightnessSpinBox->blockSignals(false);
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_brightness(
get_section_index(),
get_layer_index(),
static_cast<uint8_t>(value)
)
);
}
void SectionControlWidget::on_brightnessSpinBox_editingFinished() {
uint8_t brightness = ui->brightnessSpinBox->value();
ui->brightnessSlider->blockSignals(true);
ui->brightnessSlider->setValue(brightness);
ui->brightnessSlider->blockSignals(false);
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_brightness(
get_section_index(),
get_layer_index(),
static_cast<uint8_t>(brightness)
)
);
}
void SectionControlWidget::on_gridSizeXSpinBox_editingFinished() {
set_section_size();
}
void SectionControlWidget::on_gridSizeYSpinBox_editingFinished() {
set_section_size();
}
void SectionControlWidget::on_layerListWidget_currentRowChanged(int currentRow) {
/*
* If we selected an Layer, iterate through the Section's nested Layers until we find it.
* If we selected 'None', use the base Section as the active Section.
*/
Section* layer_section = maestro_control_widget_.get_maestro_controller()->get_maestro().get_section(get_section_index());
for (int i = 0; i < currentRow; i++) {
layer_section = layer_section->get_layer()->section;
}
// Show Layer controls
set_layer_controls_enabled(currentRow > 0);
// Set active Section to Layer Section
set_active_section(layer_section);
}
void SectionControlWidget::on_mirrorXCheckBox_toggled(bool checked) {
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_mirror(
get_section_index(),
get_layer_index(),
checked,
ui->mirrorYCheckBox->isChecked()
)
);
}
void SectionControlWidget::on_mirrorYCheckBox_toggled(bool checked) {
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_mirror(
get_section_index(),
get_layer_index(),
ui->mirrorXCheckBox->isChecked(),
checked
)
);
}
void SectionControlWidget::on_mixModeComboBox_currentIndexChanged(int index) {
// Only continue if the active Section is a Layer.
if (get_layer_index() == 0) return ;
if ((Colors::MixMode)index != active_section_->get_parent_section()->get_layer()->mix_mode) {
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_layer(
get_section_index(),
get_layer_index(*active_section_->get_parent_section()),
(Colors::MixMode)index,
ui->alphaSpinBox->value()
)
);
}
// Enable spin box for alpha only
ui->alphaLabel->setEnabled((Colors::MixMode)index == Colors::MixMode::Alpha);
ui->alphaSpinBox->setEnabled((Colors::MixMode)index == Colors::MixMode::Alpha);
}
void SectionControlWidget::on_offsetXSpinBox_editingFinished() {
set_offset();
}
void SectionControlWidget::on_offsetYSpinBox_editingFinished() {
set_offset();
}
void SectionControlWidget::on_scrollXSpinBox_editingFinished() {
set_scroll();
}
void SectionControlWidget::on_scrollYSpinBox_editingFinished() {
set_scroll();
}
void SectionControlWidget::on_removeLayerButton_clicked() {
// Don't allow user to delete the base Section
if (ui->layerListWidget->count() == 1) return;
uint8_t target_layer = ui->layerListWidget->count() - 1;
ui->layerListWidget->takeItem(target_layer);
// Change the active Layer to the previous available one
if (ui->layerListWidget->currentRow() == target_layer) {
ui->layerListWidget->setCurrentRow(target_layer - 1);
}
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->remove_layer(
get_section_index(),
target_layer - 1
)
);
}
void SectionControlWidget::on_sectionListWidget_currentRowChanged(int currentRow) {
set_layer_controls_enabled(false);
set_active_section(maestro_control_widget_.get_maestro_controller()->get_maestro().get_section(currentRow));
}
void SectionControlWidget::on_wrapCheckBox_stateChanged(int arg1) {
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_wrap(
get_section_index(),
get_layer_index(),
arg1
)
);
}
void SectionControlWidget::refresh() {
// Update the Layer list, but only if the refresh was triggered by a Section, not a Layer
if (!get_layer_index()) {
populate_layer_combobox();
}
// Set dimensions
ui->gridSizeXSpinBox->blockSignals(true);
ui->gridSizeYSpinBox->blockSignals(true);
ui->gridSizeXSpinBox->setValue(active_section_->get_dimensions().x);
ui->gridSizeYSpinBox->setValue(active_section_->get_dimensions().y);
ui->gridSizeXSpinBox->blockSignals(false);
ui->gridSizeYSpinBox->blockSignals(false);
// Set offset
ui->offsetXSpinBox->blockSignals(true);
ui->offsetYSpinBox->blockSignals(true);
ui->offsetXSpinBox->setValue(active_section_->get_offset().x);
ui->offsetYSpinBox->setValue(active_section_->get_offset().y);
ui->offsetXSpinBox->blockSignals(false);
ui->offsetYSpinBox->blockSignals(false);
// Set scroll
ui->scrollXSpinBox->blockSignals(true);
ui->scrollYSpinBox->blockSignals(true);
int32_t interval_x = 0;
int32_t interval_y = 0;
if (active_section_->get_scroll() != nullptr) {
Section::Scroll* scroll = active_section_->get_scroll();
uint16_t refresh = maestro_control_widget_.get_maestro_controller()->get_maestro().get_timer().get_interval();
// x axis
if (scroll->timer_x != nullptr) {
float x = refresh / (float)scroll->timer_x->get_interval();
interval_x = (active_section_->get_dimensions().x * refresh) / x;
}
else {
if (scroll->step_x > 0) {
interval_x = (active_section_->get_dimensions().x * refresh) / (float)scroll->step_x;
}
}
if (scroll->reverse_x) interval_x *= -1;
// y axis
if (scroll->timer_y != nullptr) {
float y = refresh / (float)scroll->timer_y->get_interval();
interval_y = (active_section_->get_dimensions().y * refresh) / y;
}
else {
if (scroll->step_y > 0) {
interval_y = (active_section_->get_dimensions().y * refresh) / (float)scroll->step_y;
}
}
if (scroll->reverse_y) interval_y *= -1;
}
ui->scrollXSpinBox->setValue(interval_x);
ui->scrollYSpinBox->setValue(interval_y);
ui->scrollXSpinBox->blockSignals(false);
ui->scrollYSpinBox->blockSignals(false);
// Set mirror
ui->mirrorXCheckBox->blockSignals(true);
ui->mirrorYCheckBox->blockSignals(true);
if (active_section_->get_mirror()) {
ui->mirrorXCheckBox->setChecked(active_section_->get_mirror()->x);
ui->mirrorYCheckBox->setChecked(active_section_->get_mirror()->y);
}
else {
ui->mirrorXCheckBox->setChecked(false);
ui->mirrorYCheckBox->setChecked(false);
}
ui->mirrorXCheckBox->blockSignals(false);
ui->mirrorYCheckBox->blockSignals(false);
// Set wrap
ui->wrapCheckBox->blockSignals(true);
ui->wrapCheckBox->setChecked(active_section_->get_wrap());
ui->wrapCheckBox->blockSignals(false);
// Update brightness
uint8_t brightness = active_section_->get_brightness();
ui->brightnessSlider->blockSignals(true);
ui->brightnessSpinBox->blockSignals(true);
ui->brightnessSlider->setValue(brightness);
ui->brightnessSpinBox->setValue(brightness);
ui->brightnessSlider->blockSignals(false);
ui->brightnessSpinBox->blockSignals(false);
// If this is a Layer, get the MixMode and alpha
if (active_section_->get_parent_section() != nullptr) {
set_layer_controls_enabled(true);
Section::Layer* layer = active_section_->get_parent_section()->get_layer();
ui->mixModeComboBox->blockSignals(true);
ui->alphaSpinBox->blockSignals(true);
ui->mixModeComboBox->setCurrentIndex((uint8_t)layer->mix_mode);
ui->alphaSpinBox->setValue(layer->alpha);
ui->alphaSpinBox->setEnabled((Colors::MixMode)ui->mixModeComboBox->currentIndex() == Colors::MixMode::Alpha);
ui->alphaLabel->setEnabled((Colors::MixMode)ui->mixModeComboBox->currentIndex() == Colors::MixMode::Alpha);
ui->mixModeComboBox->blockSignals(false);
ui->alphaSpinBox->blockSignals(false);
}
else {
set_layer_controls_enabled(false);
}
}
void SectionControlWidget::populate_layer_combobox() {
ui->layerListWidget->blockSignals(true);
ui->layerListWidget->clear();
ui->layerListWidget->addItem("Base Section");
for (uint8_t layer = 0; layer < get_num_layers(*maestro_control_widget_.get_maestro_controller()->get_maestro().get_section(get_section_index())); layer++) {
ui->layerListWidget->addItem(QString("Layer ") + QString::number(layer + 1));
}
ui->layerListWidget->blockSignals(false);
// Enable/disable layer buttons
ui->addLayerButton->setEnabled(ui->layerListWidget->count() <= 256);
ui->removeLayerButton->setEnabled(ui->layerListWidget->count() > 1);
}
void SectionControlWidget::set_active_section(Section* section) {
active_section_ = section;
ui->sectionListWidget->blockSignals(true);
ui->sectionListWidget->setCurrentRow(get_section_index(*active_section_));
ui->sectionListWidget->blockSignals(false);
maestro_control_widget_.refresh_section_settings();
}
void SectionControlWidget::set_layer_controls_enabled(bool enabled) {
ui->mixModeLabel->setEnabled(enabled);
ui->mixModeComboBox->setEnabled(enabled);
ui->alphaLabel->setEnabled(enabled);
ui->alphaSpinBox->setEnabled(enabled);
}
void SectionControlWidget::set_offset() {
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_offset(
get_section_index(),
get_layer_index(),
ui->offsetXSpinBox->value(),
ui->offsetYSpinBox->value()
)
);
}
void SectionControlWidget::set_scroll() {
int new_x = ui->scrollXSpinBox->value();
int new_y = ui->scrollYSpinBox->value();
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_scroll(
get_section_index(),
get_layer_index(),
Utility::abs_int(new_x),
Utility::abs_int(new_y),
(new_x < 0),
(new_y < 0)
)
);
// Disable offset controls if scrolling is enabled
ui->offsetXSpinBox->setEnabled(new_x == 0);
ui->offsetYSpinBox->setEnabled(new_y == 0);
if (new_x == 0) {
ui->offsetXSpinBox->blockSignals(true);
ui->offsetXSpinBox->setValue(active_section_->get_offset().x);
ui->offsetYSpinBox->blockSignals(false);
}
if (new_y == 0) {
ui->offsetYSpinBox->blockSignals(true);
ui->offsetYSpinBox->setValue(active_section_->get_offset().y);
ui->offsetYSpinBox->blockSignals(false);
}
}
void SectionControlWidget::set_section_size() {
// Only resize if the dimensions are different
Point new_dimensions(ui->gridSizeXSpinBox->value(), ui->gridSizeYSpinBox->value());
if (new_dimensions != active_section_->get_dimensions()) {
/*
* Check for a Canvas.
* The old Canvas gets deleted on resize.
* If one is set, copy its contents to a temporary buffer, then copy it back once the new Canvas is created.
*/
Canvas* canvas = active_section_->get_canvas();
if (canvas != nullptr) {
Point frame_bounds(active_section_->get_dimensions().x, active_section_->get_dimensions().y);
uint8_t** frames = new uint8_t*[canvas->get_num_frames()];
for (uint16_t frame = 0; frame < canvas->get_num_frames(); frame++) {
frames[frame] = new uint8_t[frame_bounds.size()];
}
CanvasUtility::copy_from_canvas(*canvas, frames, frame_bounds.x, frame_bounds.y);
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_dimensions(
get_section_index(),
0,
new_dimensions.x,
new_dimensions.y
)
);
CanvasUtility::copy_to_canvas(*canvas, frames, frame_bounds.x, frame_bounds.y, maestro_control_widget_);
for (uint16_t frame = 0; frame < canvas->get_num_frames(); frame++) {
delete[] frames[frame];
}
delete[] frames;
}
else { // No Canvas set
maestro_control_widget_.run_cue(
maestro_control_widget_.section_handler->set_dimensions(
get_section_index(),
0,
new_dimensions.x,
new_dimensions.y
)
);
}
}
}
SectionControlWidget::~SectionControlWidget() {
delete ui;
}
}