From d0e33355e8e6c563d45bfefd035de8b357c03ba2 Mon Sep 17 00:00:00 2001 From: Daniel Kulp Date: Sat, 13 Apr 2024 13:31:21 -0400 Subject: [PATCH] Allow Canvas mode effects to select the model blending layer as a possible layer. --- xLights/LayerSelectDialog.cpp | 225 ++++++++++++++--------------- xLights/LayerSelectDialog.h | 5 +- xLights/Render.cpp | 15 +- xLights/TimingPanel.cpp | 2 +- xLights/TimingPanel.h | 3 +- xLights/sequencer/tabSequencer.cpp | 7 +- 6 files changed, 127 insertions(+), 130 deletions(-) diff --git a/xLights/LayerSelectDialog.cpp b/xLights/LayerSelectDialog.cpp index 5398566182..af14d7610c 100644 --- a/xLights/LayerSelectDialog.cpp +++ b/xLights/LayerSelectDialog.cpp @@ -27,178 +27,163 @@ const long LayerSelectDialog::ID_MCU_SELECTALL = wxNewId(); const long LayerSelectDialog::ID_MCU_SELECTNONE = wxNewId(); const long LayerSelectDialog::ID_MCU_SELECTPOPULATED = wxNewId(); -BEGIN_EVENT_TABLE(LayerSelectDialog,wxDialog) - //(*EventTable(LayerSelectDialog) - //*) +BEGIN_EVENT_TABLE(LayerSelectDialog, wxDialog) +//(*EventTable(LayerSelectDialog) +//*) END_EVENT_TABLE() -LayerSelectDialog::LayerSelectDialog(wxWindow* parent, int startLayer, int endLayer, std::string layersSelected, std::vector layerWithEffect, wxWindowID id,const wxPoint& pos,const wxSize& size): - _layerWithEffect(layerWithEffect) -{ - //(*Initialize(LayerSelectDialog) - wxFlexGridSizer* FlexGridSizer1; - wxFlexGridSizer* FlexGridSizer2; - - Create(parent, id, _("Choose canvas layers ..."), wxDefaultPosition, wxDefaultSize, wxCAPTION|wxRESIZE_BORDER|wxMAXIMIZE_BOX, _T("id")); - SetClientSize(wxDefaultSize); - Move(wxDefaultPosition); - FlexGridSizer1 = new wxFlexGridSizer(0, 1, 0, 0); - FlexGridSizer1->AddGrowableCol(0); - FlexGridSizer1->AddGrowableRow(0); - CheckListBox_Layers = new wxCheckListBox(this, ID_CHECKLISTBOX1, wxDefaultPosition, wxSize(-1,300), 0, 0, 0, wxDefaultValidator, _T("ID_CHECKLISTBOX1")); - FlexGridSizer1->Add(CheckListBox_Layers, 1, wxALL|wxEXPAND, 5); - FlexGridSizer2 = new wxFlexGridSizer(0, 3, 0, 0); - Button_Ok = new wxButton(this, ID_BUTTON1, _("Ok"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1")); - Button_Ok->SetDefault(); - FlexGridSizer2->Add(Button_Ok, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); - Button_Cancel = new wxButton(this, ID_BUTTON2, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON2")); - FlexGridSizer2->Add(Button_Cancel, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); - FlexGridSizer1->Add(FlexGridSizer2, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5); - SetSizer(FlexGridSizer1); - FlexGridSizer1->Fit(this); - FlexGridSizer1->SetSizeHints(this); - - Connect(ID_CHECKLISTBOX1,wxEVT_COMMAND_CHECKLISTBOX_TOGGLED,(wxObjectEventFunction)&LayerSelectDialog::OnCheckListBox_LayersToggled); - Connect(ID_BUTTON1,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&LayerSelectDialog::OnButton_OkClick); - Connect(ID_BUTTON2,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&LayerSelectDialog::OnButton_CancelClick); - //*) - - Connect(ID_CHECKLISTBOX1, wxEVT_CONTEXT_MENU, (wxObjectEventFunction)&LayerSelectDialog::OnListRClick); +LayerSelectDialog::LayerSelectDialog(wxWindow* parent, int startLayer, int endLayer, bool blendLayer, const std::string &layersSelected, + const std::vector &layerWithEffect, wxWindowID id, const wxPoint& pos, const wxSize& size) : + _layerWithEffect(layerWithEffect), _blending(blendLayer) { + //(*Initialize(LayerSelectDialog) + wxFlexGridSizer* FlexGridSizer1; + wxFlexGridSizer* FlexGridSizer2; + + Create(parent, id, _("Choose canvas layers ..."), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxRESIZE_BORDER | wxMAXIMIZE_BOX, _T("id")); + SetClientSize(wxDefaultSize); + Move(wxDefaultPosition); + FlexGridSizer1 = new wxFlexGridSizer(0, 1, 0, 0); + FlexGridSizer1->AddGrowableCol(0); + FlexGridSizer1->AddGrowableRow(0); + CheckListBox_Layers = new wxCheckListBox(this, ID_CHECKLISTBOX1, wxDefaultPosition, wxSize(-1, 300), 0, 0, 0, wxDefaultValidator, _T("ID_CHECKLISTBOX1")); + FlexGridSizer1->Add(CheckListBox_Layers, 1, wxALL | wxEXPAND, 5); + FlexGridSizer2 = new wxFlexGridSizer(0, 3, 0, 0); + Button_Ok = new wxButton(this, ID_BUTTON1, _("Ok"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON1")); + Button_Ok->SetDefault(); + FlexGridSizer2->Add(Button_Ok, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + Button_Cancel = new wxButton(this, ID_BUTTON2, _("Cancel"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON2")); + FlexGridSizer2->Add(Button_Cancel, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + FlexGridSizer1->Add(FlexGridSizer2, 1, wxALL | wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL, 5); + SetSizer(FlexGridSizer1); + FlexGridSizer1->Fit(this); + FlexGridSizer1->SetSizeHints(this); + + Connect(ID_CHECKLISTBOX1, wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, (wxObjectEventFunction)&LayerSelectDialog::OnCheckListBox_LayersToggled); + Connect(ID_BUTTON1, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&LayerSelectDialog::OnButton_OkClick); + Connect(ID_BUTTON2, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&LayerSelectDialog::OnButton_CancelClick); + //*) + + Connect(ID_CHECKLISTBOX1, wxEVT_CONTEXT_MENU, (wxObjectEventFunction)&LayerSelectDialog::OnListRClick); _start = startLayer; - for (int i = startLayer; i <= endLayer; i++) - { + for (int i = startLayer; i <= endLayer; i++) { CheckListBox_Layers->Append(wxString::Format("Layer %d", i)); } - - if (layersSelected == "") - { - SelectAllLayers(); + if (_blending) { + CheckListBox_Layers->Append("Model Blending"); } - else - { + if (layersSelected == "") { + SelectAllLayers(false); + } else { wxArrayString layers = wxSplit(layersSelected, '|'); - for (const auto& it : layers) - { - int l = wxAtoi(it); - if (l < (int)CheckListBox_Layers->GetCount()) - { + for (const auto& it : layers) { + int l = 99999; + if (it == "Blend" && _blending) { + l = CheckListBox_Layers->GetCount() - 1; + } else { + l = wxAtoi(it); + } + if (l < (int)CheckListBox_Layers->GetCount()) { CheckListBox_Layers->Check(l); } } } SetEscapeId(Button_Cancel->GetId()); - + ValidateWindow(); } -LayerSelectDialog::~LayerSelectDialog() -{ - //(*Destroy(LayerSelectDialog) - //*) +LayerSelectDialog::~LayerSelectDialog() { + //(*Destroy(LayerSelectDialog) + //*) } -std::string LayerSelectDialog::GetSelectedLayers() const -{ +std::string LayerSelectDialog::GetSelectedLayers() const { std::string res; wxArrayInt items; CheckListBox_Layers->GetCheckedItems(items); - for (auto it = items.begin(); it != items.end(); ++it) - { - if (res != "") res += "|"; - res = res + wxString::Format("%d", *it).ToStdString(); + for (auto it = items.begin(); it != items.end(); ++it) { + if (res != "") + res += "|"; + std::string s = std::to_string(*it); + if (_blending && (*it == CheckListBox_Layers->GetCount() - 1)) { + s = "Blend"; + } + res += s; } return res; } -void LayerSelectDialog::SelectAllLayers() -{ - for (size_t i = 0; i < CheckListBox_Layers->GetCount(); i++) - { - CheckListBox_Layers->Check(i); +void LayerSelectDialog::SelectAllLayers(bool incBlendingLayer) { + for (size_t i = 0; i < CheckListBox_Layers->GetCount(); i++) { + if (_blending && (i == CheckListBox_Layers->GetCount() - 1)) { + if (incBlendingLayer) { + CheckListBox_Layers->Check(i); + } + } else { + CheckListBox_Layers->Check(i); + } } } - -void LayerSelectDialog::OnButton_CancelClick(wxCommandEvent& event) -{ +void LayerSelectDialog::OnButton_CancelClick(wxCommandEvent& event) { EndDialog(wxID_CANCEL); } -void LayerSelectDialog::OnButton_OkClick(wxCommandEvent& event) -{ +void LayerSelectDialog::OnButton_OkClick(wxCommandEvent& event) { EndDialog(wxID_OK); } -void LayerSelectDialog::OnCheckListBox_LayersToggled(wxCommandEvent& event) -{ +void LayerSelectDialog::OnCheckListBox_LayersToggled(wxCommandEvent& event) { ValidateWindow(); } -void LayerSelectDialog::ValidateWindow() -{ +void LayerSelectDialog::ValidateWindow() { wxArrayInt items; CheckListBox_Layers->GetCheckedItems(items); - if (items.Count() == 0) - { + if (items.Count() == 0) { Button_Ok->Enable(false); - } - else - { + } else { Button_Ok->Enable(true); } } -void LayerSelectDialog::OnListRClick(wxContextMenuEvent& event) -{ - wxMenu mnu; - mnu.Append(ID_MCU_SELECTALL, "Select All"); - mnu.Append(ID_MCU_SELECTNONE, "Deselect All"); - mnu.Append(ID_MCU_SELECTPOPULATED, "Select Layers With Effects"); +void LayerSelectDialog::OnListRClick(wxContextMenuEvent& event) { + wxMenu mnu; + mnu.Append(ID_MCU_SELECTALL, "Select All"); + mnu.Append(ID_MCU_SELECTNONE, "Deselect All"); + mnu.Append(ID_MCU_SELECTPOPULATED, "Select Layers With Effects"); - mnu.Connect(wxEVT_MENU, (wxObjectEventFunction)&LayerSelectDialog::OnPopup, nullptr, this); - PopupMenu(&mnu); + mnu.Connect(wxEVT_MENU, (wxObjectEventFunction)&LayerSelectDialog::OnPopup, nullptr, this); + PopupMenu(&mnu); } -void LayerSelectDialog::OnPopup(wxCommandEvent& event) -{ - if (event.GetId() == ID_MCU_SELECTALL) - { - SelectAllLayers(); - } - else if (event.GetId() == ID_MCU_SELECTNONE) - { - DeselectAllLayers(); - } - else if (event.GetId() == ID_MCU_SELECTPOPULATED) - { - SelectLayersWithEffects(); - } +void LayerSelectDialog::OnPopup(wxCommandEvent& event) { + if (event.GetId() == ID_MCU_SELECTALL) { + SelectAllLayers(); + } else if (event.GetId() == ID_MCU_SELECTNONE) { + DeselectAllLayers(); + } else if (event.GetId() == ID_MCU_SELECTPOPULATED) { + SelectLayersWithEffects(); + } } -void LayerSelectDialog::DeselectAllLayers() -{ - for (size_t i = 0; i < CheckListBox_Layers->GetCount(); i++) - { - CheckListBox_Layers->Check(i, false); - } +void LayerSelectDialog::DeselectAllLayers() { + for (size_t i = 0; i < CheckListBox_Layers->GetCount(); i++) { + CheckListBox_Layers->Check(i, false); + } } -void LayerSelectDialog::SelectLayersWithEffects() -{ - for (size_t i = 0; i < CheckListBox_Layers->GetCount(); i++) - { - int layer = _start + i - 1;//zero based index - if (std::find(_layerWithEffect.begin(), _layerWithEffect.end(), layer) != _layerWithEffect.end()) - { - CheckListBox_Layers->Check(i); - } - else - { - CheckListBox_Layers->Check(i, false); - } - } +void LayerSelectDialog::SelectLayersWithEffects() { + for (size_t i = 0; i < CheckListBox_Layers->GetCount(); i++) { + int layer = _start + i - 1; // zero based index + if (std::find(_layerWithEffect.begin(), _layerWithEffect.end(), layer) != _layerWithEffect.end()) { + CheckListBox_Layers->Check(i); + } else { + CheckListBox_Layers->Check(i, false); + } + } } diff --git a/xLights/LayerSelectDialog.h b/xLights/LayerSelectDialog.h index 5e71d3255b..df534e13b3 100644 --- a/xLights/LayerSelectDialog.h +++ b/xLights/LayerSelectDialog.h @@ -20,16 +20,17 @@ class LayerSelectDialog: public wxDialog { int _start; + bool _blending; std::vector _layerWithEffect; void ValidateWindow(); public: - LayerSelectDialog(wxWindow* parent, int startLayer, int endLayer, std::string layersSelected, std::vector layerWithEffect, wxWindowID id=wxID_ANY,const wxPoint& pos=wxDefaultPosition,const wxSize& size=wxDefaultSize); + LayerSelectDialog(wxWindow* parent, int startLayer, int endLayer, bool blendLayer, const std::string &layersSelected, const std::vector &layerWithEffect, wxWindowID id=wxID_ANY,const wxPoint& pos=wxDefaultPosition,const wxSize& size=wxDefaultSize); virtual ~LayerSelectDialog(); void SelectLayer(wxString layer); std::string GetSelectedLayers() const; - void SelectAllLayers(); + void SelectAllLayers(bool incBlendingLayer = false); //(*Declarations(LayerSelectDialog) wxButton* Button_Cancel; diff --git a/xLights/Render.cpp b/xLights/Render.cpp index bdeb00258b..e69edf3b4b 100644 --- a/xLights/Render.cpp +++ b/xLights/Render.cpp @@ -655,14 +655,20 @@ class RenderJob: public Job, public NextRenderer { maybeWaitForFrame(frame); auto vl = info.validLayers; + bool doBlendLayer = false; if (info.settingsMaps[layer].Get("LayersSelected", "") != "") { // remove from valid layers any layers we dont need to include - wxArrayString ls = wxSplit(info.settingsMaps[layer].Get("LayersSelected", ""), '|'); + std::vector ls; + Split(info.settingsMaps[layer].Get("LayersSelected", ""), '|', ls); + if (!ls.empty() && ls.back() == "Blend") { + doBlendLayer = true; + ls.pop_back(); + } for (int i = layer + 1; i < vl.size(); i++) { if (vl[i]) { bool found = false; for (auto it = ls.begin(); !found && it != ls.end(); ++it) { - if (wxAtoi(*it) + layer + 1 == i) { + if (std::atoi((*it).c_str()) + layer + 1 == i) { found = true; } } @@ -671,6 +677,11 @@ class RenderJob: public Job, public NextRenderer { } } } + if (doBlendLayer) { + buffer->SetColors(numLayers, &((*seqData)[frame][0])); + vl[numLayers] = true; + blend = false; + } } // preload the buffer with the output from the lower layers diff --git a/xLights/TimingPanel.cpp b/xLights/TimingPanel.cpp index 2b475eb5f2..a0ceae5e0a 100644 --- a/xLights/TimingPanel.cpp +++ b/xLights/TimingPanel.cpp @@ -565,7 +565,7 @@ void TimingPanel::OnCheckBox_ResetTimingPanelClick(wxCommandEvent& event) void TimingPanel::OnButton_LayersClick(wxCommandEvent& event) { wxASSERT(_startLayer <= _endLayer); - LayerSelectDialog dlg(this, _startLayer, _endLayer, _layersSelected, _layerWithEffect); + LayerSelectDialog dlg(this, _startLayer, _endLayer, _modelBlending, _layersSelected, _layerWithEffect); OptimiseDialogPosition(&dlg); if (dlg.ShowModal() == wxID_OK) { diff --git a/xLights/TimingPanel.h b/xLights/TimingPanel.h index 04f5fc02d5..4e5e557db0 100644 --- a/xLights/TimingPanel.h +++ b/xLights/TimingPanel.h @@ -42,6 +42,7 @@ class TimingPanel: public xlEffectPanel std::string _layersSelected; int _startLayer; int _endLayer; + bool _modelBlending; std::vector _layerWithEffect; public: @@ -49,7 +50,7 @@ class TimingPanel: public xlEffectPanel TimingPanel(wxWindow* parent,wxWindowID id=wxID_ANY,const wxPoint& pos=wxDefaultPosition,const wxSize& size=wxDefaultSize); virtual ~TimingPanel(); - void SetLayersBelow(int start, int end, std::vector effects) { _startLayer = start; _endLayer = end; _layerWithEffect = effects; } + void SetLayersBelow(int start, int end, std::vector effects, bool blending) { _startLayer = start; _endLayer = end; _layerWithEffect = effects; _modelBlending = blending;} wxString GetTimingString(); void SetDefaultControls(const Model *model, bool optionbased = false); void ValidateWindow(); diff --git a/xLights/sequencer/tabSequencer.cpp b/xLights/sequencer/tabSequencer.cpp index 5fdae5ba76..3d0d2b6599 100644 --- a/xLights/sequencer/tabSequencer.cpp +++ b/xLights/sequencer/tabSequencer.cpp @@ -1115,14 +1115,13 @@ void xLightsFrame::EffectChanged(wxCommandEvent& event) // flags something has changed in an effect but does not send the effect void xLightsFrame::EffectUpdated(wxCommandEvent& event) { - if (selectedEffect != nullptr) - { + if (selectedEffect != nullptr) { // For canvas mode the timing panel needs to know how many layers are under this effect int layers = selectedEffect->GetParentEffectLayer()->GetParentElement()->GetEffectLayerCount(); int start = selectedEffect->GetParentEffectLayer()->GetLayerNumber() + 1; std::vector effectLayers = selectedEffect->GetParentEffectLayer()->GetParentElement()->GetLayersWithEffectsByTime(selectedEffect->GetStartTimeMS(), selectedEffect->GetEndTimeMS()); if (start > layers) start = -1; - timingPanel->SetLayersBelow(start, layers, effectLayers); + timingPanel->SetLayersBelow(start, layers, effectLayers, _sequenceElements.SupportsModelBlending()); } } @@ -1209,7 +1208,7 @@ void xLightsFrame::SelectedEffectChanged(SelectedEffectChangedEvent& event) int start = effect->GetParentEffectLayer()->GetLayerNumber() + 1; std::vector effectLayers = effect->GetParentEffectLayer()->GetParentElement()->GetLayersWithEffectsByTime(effect->GetStartTimeMS(), effect->GetEndTimeMS()); if (start > layers) start = -1; - timingPanel->SetLayersBelow(start, layers, effectLayers); + timingPanel->SetLayersBelow(start, layers, effectLayers, _sequenceElements.SupportsModelBlending()); bool resetStrings = false; if ("Random" == effect->GetEffectName()) {