Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions gui/dialogs/createchasedialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ CreateChaseDialog::CreateChaseDialog()
_list(),
_newChaseFrame("Chase objects"),
_addObjectToChaseButton(),
_clearChaseButton("Clear"),
_newChase(nullptr) {
_clearChaseButton("Clear") {
set_size_request(600, 400);

initListPart();
Expand All @@ -34,7 +33,8 @@ CreateChaseDialog::CreateChaseDialog()
add_button("Cancel", Gtk::ResponseType::CANCEL);
_makeChaseButton = add_button("Make chase", Gtk::ResponseType::OK);
_makeChaseButton->signal_clicked().connect(
sigc::mem_fun(*this, &CreateChaseDialog::onCreateChaseButtonClicked));
sigc::mem_fun(*this, &CreateChaseDialog::onCreateChaseButtonClicked),
false);
_makeChaseButton->set_sensitive(false);
}

Expand Down Expand Up @@ -104,12 +104,12 @@ void CreateChaseDialog::onCreateChaseButtonClicked() {
theatre::Management &management = Instance::Management();
std::unique_lock<std::mutex> lock(management.Mutex());

_newChase = management.AddChasePtr();
management.AddSourceValue(*_newChase, 0);
_newChase->SetName(folder.GetAvailableName("Chase"));
folder.Add(_newChase);
system::ObservingPtr<theatre::Chase> new_chase = management.AddChasePtr();
management.AddSourceValue(*new_chase, 0);
new_chase->SetName(folder.GetAvailableName("Chase"));
folder.Add(new_chase);

theatre::Sequence &sequence = _newChase->GetSequence();
theatre::Sequence &sequence = new_chase->GetSequence();
Gtk::TreeModel::Children children = _newChaseListModel->children();
for (const Gtk::TreeRow &row : children) {
theatre::Controllable *object = row[_newChaseListColumns._controllable];
Expand All @@ -121,6 +121,8 @@ void CreateChaseDialog::onCreateChaseButtonClicked() {
Instance::Events().EmitUpdate();
_newChaseListModel->clear();
_makeChaseButton->set_sensitive(false);

signal_new_chase_(*new_chase);
}
}

Expand Down
6 changes: 4 additions & 2 deletions gui/dialogs/createchasedialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ class CreateChaseDialog : public Gtk::Dialog {
public:
CreateChaseDialog();

theatre::Chase &CreatedChase() { return *_newChase; }
sigc::signal<void(theatre::Chase &)> SignalNewChase() {
return signal_new_chase_;
}

private:
void initListPart();
Expand Down Expand Up @@ -65,7 +67,7 @@ class CreateChaseDialog : public Gtk::Dialog {
Gtk::Button *_makeChaseButton;

RecursionLock _delayUpdates;
system::ObservingPtr<theatre::Chase> _newChase;
sigc::signal<void(theatre::Chase &)> signal_new_chase_;
};

} // namespace glight::gui
Expand Down
20 changes: 10 additions & 10 deletions gui/mainwindow/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,16 @@ void NewChase(std::unique_ptr<Gtk::Dialog> &dialog, ObjectBrowser &browser,
ObjectWindowList<PropertiesWindow> &property_windows,
Gtk::Window &parent) {
dialog = std::make_unique<CreateChaseDialog>();
dialog->signal_response().connect(
[d = dialog.get(), &browser, &property_windows, &parent](int response) {
if (response == Gtk::ResponseType::OK) {
theatre::Chase &new_chase =
static_cast<CreateChaseDialog *>(d)->CreatedChase();
browser.SelectObject(new_chase);
AssignFader(new_chase);
OpenPropertiesWindow(property_windows, new_chase, parent);
}
});
CreateChaseDialog &chase_dialog = static_cast<CreateChaseDialog &>(*dialog);
chase_dialog.set_transient_for(parent);
chase_dialog.SignalNewChase().connect([&dialog, &browser, &property_windows,
&parent](theatre::Chase &new_chase) {
browser.SelectObject(new_chase);
AssignFader(new_chase);
dialog.reset();
OpenPropertiesWindow(property_windows, new_chase, parent);
});
dialog->show();
}

void NewTimeSequence(ObjectBrowser &browser,
Expand Down
6 changes: 3 additions & 3 deletions gui/mainwindow/mainmenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ MainMenu::MainMenu(Gio::ActionMap& actions) {
Add(preset_menu, "From current", "add_current_preset", AddCurrentPreset);
add_section->append_submenu("Add preset", preset_menu);

Add(add_section, "Add chase", "design_lock", AddChase);
Add(add_section, "Add sequence", "design_lock", AddTimeSequence);
Add(add_section, "Add chase", "add_chase", AddChase);
Add(add_section, "Add sequence", "add_sequence", AddTimeSequence);

auto effect_menu = Gio::Menu::create();
std::vector<theatre::EffectType> effect_types = theatre::GetEffectTypes();
Expand All @@ -77,7 +77,7 @@ MainMenu::MainMenu(Gio::ActionMap& actions) {
}
add_section->append_submenu("Add effect", effect_menu);
Add(add_section, "Add folder", "add_folder", AddFolder);
delete_object_ = Add(add_section, "Delete", "design_lock", DeleteObject);
delete_object_ = Add(add_section, "Delete", "delete_object", DeleteObject);
Add(add_section, "Design wizard...", "design_wizard", DesignWizard);
design_menu->append_section(add_section);

Expand Down
10 changes: 7 additions & 3 deletions gui/mainwindow/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,12 @@ MainWindow::~MainWindow() {
_visualizationWidget.reset();
child_windows_.Clear();

_faderWindows.clear();
while (!_faderWindows.empty()) {
// First move the window out of the list so that the hide signal won't
// cause a double delete of the window.
std::unique_ptr<FaderWindow> window = std::move(_faderWindows.back());
_faderWindows.erase(_faderWindows.end() - 1);
}

_management.reset();

Expand Down Expand Up @@ -189,8 +194,7 @@ void MainWindow::addFaderWindow(FaderSetState *stateOrNull) {
else
newWindow->LoadState(stateOrNull);
newWindow->add_controller(GetKeyController());
newWindow->signal_hide().connect(sigc::bind(
sigc::mem_fun(*this, &MainWindow::onFaderWindowHidden), newWindow));
newWindow->signal_hide().connect([&]() { onFaderWindowHidden(newWindow); });
newWindow->show();
_state.EmitFaderSetChangeSignal();
}
Expand Down
79 changes: 73 additions & 6 deletions gui/windows/scenewindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ SceneWindow::SceneWindow(MainWindow &parentWindow)

_audioWidget.SignalClicked().connect(
sigc::mem_fun(*this, &SceneWindow::onAudioWidgetClicked));
_audioWidget.set_expand(true);
_vBox.append(_audioWidget);

_audioBox.append(_audioLabel);
Expand Down Expand Up @@ -154,20 +155,30 @@ SceneWindow::SceneWindow(MainWindow &parentWindow)
_setFadeSpeedButton.set_sensitive(false);
_sceneItemUButtonBox.append(_setFadeSpeedButton);

copy_button_.signal_clicked().connect([&]() { CopySelection(); });
copy_button_.set_sensitive(false);
_sceneItemUButtonBox.append(copy_button_);

paste_button_.signal_clicked().connect([&]() { PasteSelection(); });
paste_button_.set_sensitive(false);
_sceneItemUButtonBox.append(paste_button_);

_sceneItemBox.append(_sceneItemUButtonBox);

_startScale.set_inverted(true);
_startScale.set_draw_value(false);
_startScale.set_sensitive(false);
_startScale.signal_value_changed().connect(
sigc::mem_fun(*this, &SceneWindow::onScalesChanged));
_startScale.set_expand(true);
_scalesBox.append(_startScale);

_endScale.set_inverted(true);
_endScale.set_draw_value(false);
_endScale.set_sensitive(false);
_endScale.signal_value_changed().connect(
sigc::mem_fun(*this, &SceneWindow::onScalesChanged));
_endScale.set_expand(true);
_scalesBox.append(_endScale);

_sceneItemBox.append(_scalesBox);
Expand Down Expand Up @@ -203,6 +214,8 @@ void SceneWindow::Update() {
fillSceneItemList();
updateAudio();
UpdateAudioWidgetKeys();
copy_buffer_.clear();
paste_button_.set_sensitive(false);
}

void SceneWindow::createSceneItemsList() {
Expand All @@ -223,12 +236,11 @@ void SceneWindow::createSceneItemsList() {
sigc::mem_fun(*this, &SceneWindow::onSelectedSceneItemChanged));
_sceneItemsListView.set_rubber_banding(true);
_listScrolledWindow.set_child(_sceneItemsListView);
_sceneItemsListView.show();

_listScrolledWindow.set_policy(Gtk::PolicyType::NEVER,
Gtk::PolicyType::AUTOMATIC);
_listScrolledWindow.set_expand(true);
_hBox.append(_listScrolledWindow);
_listScrolledWindow.show();
}

void SceneWindow::createControllablesList() {
Expand Down Expand Up @@ -455,6 +467,7 @@ void SceneWindow::onSelectedSceneItemChanged() {
_setFadeSpeedButton.set_sensitive(false);
_startScale.set_sensitive(false);
_endScale.set_sensitive(false);
copy_button_.set_sensitive(false);
break;
case 1: {
std::unique_lock<std::mutex> lock(_management.Mutex());
Expand Down Expand Up @@ -482,6 +495,7 @@ void SceneWindow::onSelectedSceneItemChanged() {
_setFadeSpeedButton.set_sensitive(is_blackout);
_startScale.set_sensitive(true);
_endScale.set_sensitive(true);
copy_button_.set_sensitive(true);
} break;
default:
_createControlItemButton.set_sensitive(true);
Expand All @@ -492,6 +506,7 @@ void SceneWindow::onSelectedSceneItemChanged() {
_setFadeSpeedButton.set_sensitive(false);
_startScale.set_sensitive(true);
_endScale.set_sensitive(true);
copy_button_.set_sensitive(true);
break;
}
}
Expand Down Expand Up @@ -650,10 +665,16 @@ void SceneWindow::onAudioWidgetClicked(double timeInMS) {
std::vector<Gtk::TreeModel::Path> pathHandle =
selection->get_selected_rows();
std::unique_lock<std::mutex> lock(_management.Mutex());
for (const Gtk::TreeModel::Path &path : pathHandle) {
theatre::SceneItem *item =
(*_sceneItemsListModel->get_iter(path))[_sceneItemsListColumns._item];
_selectedScene->ChangeSceneItemStartTime(item, timeInMS);
if (!pathHandle.empty()) {
theatre::SceneItem *first_item = (*_sceneItemsListModel->get_iter(
pathHandle[0]))[_sceneItemsListColumns._item];
const double shift = timeInMS - first_item->OffsetInMS();
for (const Gtk::TreeModel::Path &path : pathHandle) {
theatre::SceneItem *item = (*_sceneItemsListModel->get_iter(
path))[_sceneItemsListColumns._item];
const double new_time = item->OffsetInMS() + shift;
_selectedScene->ChangeSceneItemStartTime(item, new_time);
}
}
lock.unlock();
_isUpdating = false;
Expand Down Expand Up @@ -843,4 +864,50 @@ void SceneWindow::SetFadeSpeed() {
}
}

void SceneWindow::CopySelection() {
copy_buffer_.clear();
Glib::RefPtr<Gtk::TreeSelection> selection =
_sceneItemsListView.get_selection();
std::vector<Gtk::TreeModel::Path> pathHandle = selection->get_selected_rows();
for (const Gtk::TreeModel::Path &path : pathHandle) {
theatre::SceneItem *item =
(*_sceneItemsListModel->get_iter(path))[_sceneItemsListColumns._item];
copy_buffer_.push_back(item);
}
if (!copy_buffer_.empty()) paste_button_.set_sensitive(true);
}

void SceneWindow::PasteSelection() {
if (!copy_buffer_.empty()) {
_isUpdating = true;

std::unique_lock<std::mutex> lock(_management.Mutex());
const double shift =
_audioWidget.Position() - copy_buffer_.front()->OffsetInMS();
for (theatre::SceneItem *item : copy_buffer_) {
if (theatre::ControlSceneItem *ct_item =
dynamic_cast<theatre::ControlSceneItem *>(item);
ct_item) {
theatre::ControlSceneItem *new_item =
_selectedScene->AddControlSceneItem(item->OffsetInMS() + shift,
ct_item->GetControllable(),
ct_item->GetInput());
if (_management.HasCycle())
_selectedScene->Remove(new_item);
else {
new_item->SetDurationInMS(ct_item->DurationInMS());
new_item->StartValue() = ct_item->StartValue();
new_item->EndValue() = ct_item->EndValue();
}
}
}
lock.unlock();

fillSceneItemList();
UpdateAudioWidgetKeys();
_isUpdating = false;
onSelectedSceneItemChanged();
}
}

} // namespace glight::gui
7 changes: 7 additions & 0 deletions gui/windows/scenewindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ class SceneWindow : public windows::ChildWindow {
Gtk::Button _blackoutButton;
Gtk::Button _restoreButton;
Gtk::Button _setFadeSpeedButton;
Gtk::Button copy_button_{"Copy"};
Gtk::Button paste_button_{"Paste"};
Gtk::Scale _startScale, _endScale;
std::unique_ptr<Gtk::Dialog> dialog_;
Gtk::Entry dialog_entry_;
Expand All @@ -128,6 +130,8 @@ class SceneWindow : public windows::ChildWindow {

theatre::Scene *_selectedScene;
theatre::SourceValue *_sourceValue;
std::vector<theatre::SceneItem *> copy_buffer_;

bool _isUpdating;

void NewScene();
Expand Down Expand Up @@ -164,6 +168,9 @@ class SceneWindow : public windows::ChildWindow {
void UpdateAudioWidgetKeys();
void SetFadeSpeed();

void CopySelection();
void PasteSelection();

size_t selectedSceneItemCount() const {
return _sceneItemsListView.get_selection()->count_selected_rows();
}
Expand Down
39 changes: 39 additions & 0 deletions tests/theatre/ttransition.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "theatre/effects/variableeffect.h"
#include "theatre/transition.h"

#include "tests/tolerance_check.h"
Expand All @@ -10,6 +11,7 @@ using theatre::ControlValue;
using theatre::Timing;
using theatre::Transition;
using theatre::TransitionType;
using theatre::VariableEffect;

BOOST_AUTO_TEST_SUITE(transition)

Expand Down Expand Up @@ -51,6 +53,43 @@ BOOST_AUTO_TEST_CASE(fade_out) {
BOOST_CHECK_EQUAL(after.UInt(), 0);
}

BOOST_AUTO_TEST_CASE(fade_mix) {
const Timing timing;
const Transition t(500.0, TransitionType::Fade);

VariableEffect result_a;
t.Mix(result_a, 0, result_a, 1, 0.0, ControlValue::Max(), timing);
BOOST_CHECK_EQUAL(result_a.InputValue(0).ToUChar(), 255);
BOOST_CHECK_EQUAL(result_a.InputValue(1).ToUChar(), 0);

VariableEffect result_b;
t.Mix(result_b, 0, result_b, 1, 500.0, ControlValue::Max() / 2, timing);
BOOST_CHECK_EQUAL(result_b.InputValue(0).ToUChar(), 0);
BOOST_CHECK_EQUAL(result_b.InputValue(1).ToUChar(), 127);

VariableEffect result_c;
t.Mix(result_c, 0, result_c, 1, 125.0, ControlValue::Max(), timing);
BOOST_CHECK_EQUAL(result_c.InputValue(0).ToUChar(), 192);
BOOST_CHECK_EQUAL(result_c.InputValue(1).ToUChar(), 63);

// Test for time values outside the transition range
VariableEffect result_d;
t.Mix(result_d, 0, result_d, 1, -100.0, ControlValue::Max(), timing);
BOOST_CHECK_EQUAL(result_d.InputValue(0).ToUChar(), 255);
BOOST_CHECK_EQUAL(result_d.InputValue(1).ToUChar(), 0);

VariableEffect result_e;
t.Mix(result_e, 0, result_e, 1, 600.0, ControlValue::Max(), timing);
BOOST_CHECK_EQUAL(result_e.InputValue(0).ToUChar(), 0);
BOOST_CHECK_EQUAL(result_e.InputValue(1).ToUChar(), 255);

// Test for too high control values
VariableEffect result_f;
t.Mix(result_f, 0, result_f, 1, 500.0, ControlValue::Max() * 5u / 4, timing);
BOOST_CHECK_EQUAL(result_f.InputValue(0).ToUChar(), 0);
BOOST_CHECK_EQUAL(result_f.InputValue(1).ToUChar(), 255);
}

BOOST_AUTO_TEST_CASE(fade_through_black_in) {
const Transition t(100, TransitionType::FadeThroughBlack);

Expand Down
5 changes: 5 additions & 0 deletions theatre/controlvalue.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ inline constexpr ControlValue operator+(const ControlValue& lhs,
return ControlValue(lhs.UInt() + rhs.UInt());
}

inline constexpr ControlValue operator-(const ControlValue& lhs,
const ControlValue& rhs) noexcept {
return ControlValue(lhs.UInt() - rhs.UInt());
}

inline constexpr ControlValue operator*(const ControlValue& lhs,
const ControlValue& rhs) noexcept {
return ControlValue(ControlValue::MultiplyValues(lhs.UInt(), rhs.UInt()));
Expand Down
Loading