Audacity 3.2.0
Public Member Functions | Private Attributes | List of all members
RealtimeEffectListWindow Class Reference
Inheritance diagram for RealtimeEffectListWindow:
[legend]
Collaboration diagram for RealtimeEffectListWindow:
[legend]

Public Member Functions

 RealtimeEffectListWindow (wxWindow *parent, wxWindowID winid=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxScrolledWindowStyle, const wxString &name=wxPanelNameStr)
 
void OnSizeChanged (wxSizeEvent &event)
 
void OnEffectListItemChange (const RealtimeEffectListMessage &msg)
 
void ResetTrack ()
 
void SetTrack (AudacityProject &project, const std::shared_ptr< Track > &track)
 
void EnableEffects (bool enable)
 
void ReloadEffectsList ()
 
void OnAddEffectClicked (const wxCommandEvent &event)
 
void InsertEffectRow (size_t index, const std::shared_ptr< RealtimeEffectState > &pState)
 

Private Attributes

wxWeakRef< AudacityProjectmProject
 
std::shared_ptr< TrackmTrack
 
AButtonmAddEffect {nullptr}
 
wxStaticText * mAddEffectHint {nullptr}
 
wxWindow * mAddEffectTutorialLink {nullptr}
 
wxWindow * mEffectListContainer {nullptr}
 
Observer::Subscription mEffectListItemMovedSubscription
 

Detailed Description

Definition at line 956 of file RealtimeEffectPanel.cpp.

Constructor & Destructor Documentation

◆ RealtimeEffectListWindow()

RealtimeEffectListWindow::RealtimeEffectListWindow ( wxWindow *  parent,
wxWindowID  winid = wxID_ANY,
const wxPoint &  pos = wxDefaultPosition,
const wxSize &  size = wxDefaultSize,
long  style = wxScrolledWindowStyle,
const wxString &  name = wxPanelNameStr 
)
inline

i18n-hint: undo history record first parameter - realtime effect name second parameter - track name

i18n-hint: undo history record first parameter - realtime effect name second parameter - track name

Definition at line 968 of file RealtimeEffectPanel.cpp.

974 : wxScrolledWindow(parent, winid, pos, size, style, name)
975 {
976 Bind(wxEVT_SIZE, &RealtimeEffectListWindow::OnSizeChanged, this);
977#ifdef __WXMSW__
978 //Fixes flickering on redraw
979 wxScrolledWindow::SetDoubleBuffered(true);
980#endif
981 auto rootSizer = std::make_unique<wxBoxSizer>(wxVERTICAL);
982
983 auto effectListContainer = safenew ThemedWindowWrapper<wxPanel>(this, wxID_ANY);
984 effectListContainer->SetBackgroundColorIndex(clrMedium);
985 effectListContainer->SetSizer(safenew wxBoxSizer(wxVERTICAL));
986 effectListContainer->SetDoubleBuffered(true);
987 effectListContainer->Hide();
988 mEffectListContainer = effectListContainer;
989
990 auto addEffect = safenew ThemedAButtonWrapper<AButton>(this, wxID_ANY);
991 addEffect->SetImageIndices(0,
992 bmpHButtonNormal,
993 bmpHButtonHover,
994 bmpHButtonDown,
995 bmpHButtonHover,
996 bmpHButtonDisabled);
997 addEffect->SetTranslatableLabel(XO("Add effect"));
998 addEffect->SetButtonType(AButton::TextButton);
999 addEffect->SetBackgroundColorIndex(clrMedium);
1000 addEffect->SetForegroundColorIndex(clrTrackPanelText);
1001 addEffect->Bind(wxEVT_BUTTON, &RealtimeEffectListWindow::OnAddEffectClicked, this);
1002 mAddEffect = addEffect;
1003
1004 auto addEffectHint = safenew ThemedWindowWrapper<wxStaticText>(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE);
1005 //Workaround: text is set in the OnSizeChange
1006 addEffectHint->SetForegroundColorIndex(clrTrackPanelText);
1007 mAddEffectHint = addEffectHint;
1008
1009 auto addEffectTutorialLink = safenew ThemedWindowWrapper<wxHyperlinkCtrl>(
1010 this, wxID_ANY, _("Watch video"),
1011 "https://www.audacityteam.org/realtime-video", wxDefaultPosition,
1012 wxDefaultSize, wxHL_ALIGN_LEFT | wxHL_CONTEXTMENU);
1013
1014 //i18n-hint: Hyperlink to the effects stack panel tutorial video
1015 addEffectTutorialLink->SetTranslatableLabel(XO("Watch video"));
1016#if wxUSE_ACCESSIBILITY
1017 safenew WindowAccessible(addEffectTutorialLink);
1018#endif
1019
1020 addEffectTutorialLink->Bind(
1021 wxEVT_HYPERLINK, [](wxHyperlinkEvent& event)
1022 { BasicUI::OpenInDefaultBrowser(event.GetURL()); });
1023
1024 mAddEffectTutorialLink = addEffectTutorialLink;
1025
1026 //indicates the insertion position of the item
1027 auto dropHintLine = safenew ThemedWindowWrapper<DropHintLine>(effectListContainer, wxID_ANY);
1028 dropHintLine->SetBackgroundColorIndex(clrDropHintHighlight);
1029 dropHintLine->Hide();
1030
1031 rootSizer->Add(mEffectListContainer, 0, wxEXPAND | wxBOTTOM, 10);
1032 rootSizer->Add(addEffect, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 20);
1033 rootSizer->Add(addEffectHint, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 20);
1034 rootSizer->Add(addEffectTutorialLink, 0, wxLEFT | wxRIGHT | wxEXPAND, 20);
1035
1036 SetSizer(rootSizer.release());
1037 SetMinSize({});
1038
1039 Bind(EVT_MOVABLE_CONTROL_DRAG_STARTED, [dropHintLine](const MovableControlEvent& event)
1040 {
1041 if(auto window = dynamic_cast<wxWindow*>(event.GetEventObject()))
1042 window->Raise();
1043 });
1044 Bind(EVT_MOVABLE_CONTROL_DRAG_POSITION, [this, dropHintLine](const MovableControlEvent& event)
1045 {
1046 constexpr auto DropHintLineHeight { 3 };//px
1047
1048 auto sizer = mEffectListContainer->GetSizer();
1049 assert(sizer != nullptr);
1050
1051 if(event.GetSourceIndex() == event.GetTargetIndex())
1052 {
1053 //do not display hint line if position didn't change
1054 dropHintLine->Hide();
1055 return;
1056 }
1057
1058 if(!dropHintLine->IsShown())
1059 {
1060 dropHintLine->Show();
1061 dropHintLine->Raise();
1062 if(auto window = dynamic_cast<wxWindow*>(event.GetEventObject()))
1063 window->Raise();
1064 }
1065
1066 auto item = sizer->GetItem(event.GetTargetIndex());
1067 dropHintLine->SetSize(item->GetSize().x, DropHintLineHeight);
1068
1069 if(event.GetTargetIndex() > event.GetSourceIndex())
1070 dropHintLine->SetPosition(item->GetRect().GetBottomLeft() - wxPoint(0, DropHintLineHeight));
1071 else
1072 dropHintLine->SetPosition(item->GetRect().GetTopLeft());
1073 });
1074 Bind(EVT_MOVABLE_CONTROL_DRAG_FINISHED, [this, dropHintLine](const MovableControlEvent& event)
1075 {
1076 dropHintLine->Hide();
1077
1078 if(mProject == nullptr)
1079 return;
1080
1081 auto& effectList = RealtimeEffectList::Get(*mTrack);
1082 const auto from = event.GetSourceIndex();
1083 const auto to = event.GetTargetIndex();
1084 if(from != to)
1085 {
1086 auto effectName =
1087 effectList.GetStateAt(from)->GetEffect()->GetName();
1088 bool up = (to < from);
1089 effectList.MoveEffect(from, to);
1090 ProjectHistory::Get(*mProject).PushState(
1091 (up
1096 ? XO("Moved %s up in %s")
1101 : XO("Moved %s down in %s"))
1102 .Format(effectName, mTrack->GetName()),
1103 XO("Change effect order"), UndoPush::CONSOLIDATE);
1104 }
1105 else
1106 {
1107 wxWindowUpdateLocker freeze(this);
1108 Layout();
1109 }
1110 });
1111 SetScrollRate(0, 20);
1112 }
const TranslatableString name
Definition: Distortion.cpp:74
XO("Cut/Copy/Paste")
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
@ TextButton
Definition: AButton.h:112
Abstract base class used in importing a file.
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
static RealtimeEffectList & Get(AudacityProject &project)
std::shared_ptr< Track > mTrack
void OnAddEffectClicked(const wxCommandEvent &event)
void OnSizeChanged(wxSizeEvent &event)
wxWeakRef< AudacityProject > mProject
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
bool OpenInDefaultBrowser(const wxString &url)
Open an URL in default browser.
Definition: BasicUI.cpp:238

References _, CONSOLIDATE, ProjectHistory::Get(), RealtimeEffectList::Get(), mAddEffect, mAddEffectHint, mAddEffectTutorialLink, mEffectListContainer, mProject, mTrack, OnAddEffectClicked(), OnSizeChanged(), BasicUI::OpenInDefaultBrowser(), ProjectHistory::PushState(), safenew, AButton::TextButton, and XO().

Here is the call graph for this function:

Member Function Documentation

◆ EnableEffects()

void RealtimeEffectListWindow::EnableEffects ( bool  enable)
inline

Definition at line 1231 of file RealtimeEffectPanel.cpp.

1232 {
1233 if (mTrack)
1234 RealtimeEffectList::Get(*mTrack).SetActive(enable);
1235 }
void SetActive(bool value)
Done by main thread only, under a lock guard.

References RealtimeEffectList::Get(), mTrack, and RealtimeEffectList::SetActive().

Referenced by RealtimeEffectPanel::RealtimeEffectPanel().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ InsertEffectRow()

void RealtimeEffectListWindow::InsertEffectRow ( size_t  index,
const std::shared_ptr< RealtimeEffectState > &  pState 
)
inline

Definition at line 1306 of file RealtimeEffectPanel.cpp.

1308 {
1309 if(mProject == nullptr)
1310 return;
1311
1312 // See comment in ReloadEffectsList
1313 if(!mEffectListContainer->IsShown())
1314 mEffectListContainer->Show();
1315
1317 row->SetBackgroundColorIndex(clrEffectListItemBackground);
1318 row->SetEffect(*mProject, mTrack, pState);
1319 mEffectListContainer->GetSizer()->Insert(index, row, 0, wxEXPAND);
1320 }

References mEffectListContainer, mProject, mTrack, and safenew.

Referenced by OnEffectListItemChange(), and ReloadEffectsList().

Here is the caller graph for this function:

◆ OnAddEffectClicked()

void RealtimeEffectListWindow::OnAddEffectClicked ( const wxCommandEvent &  event)
inline

i18n-hint: undo history record first parameter - realtime effect name second parameter - track name

Definition at line 1268 of file RealtimeEffectPanel.cpp.

1269 {
1270 if(!mTrack || mProject == nullptr)
1271 return;
1272
1273 const auto effectID = ShowSelectEffectMenu(dynamic_cast<wxWindow*>(event.GetEventObject()));
1274 if(effectID.empty())
1275 return;
1276
1277 auto plug = PluginManager::Get().GetPlugin(effectID);
1278 if(!plug)
1279 return;
1280
1283 XO("This plugin could not be loaded.\nIt may have been deleted."),
1285 .Caption(XO("Plugin Error")));
1286
1287 return;
1288 }
1289
1290 if(auto state = AudioIO::Get()->AddState(*mProject, &*mTrack, effectID))
1291 {
1292 auto effect = state->GetEffect();
1293 assert(effect); // postcondition of AddState
1294 const auto effectName = effect->GetName();
1295 ProjectHistory::Get(*mProject).PushState(
1300 XO("Added %s to %s").Format(effectName, mTrack->GetName()),
1301 //i18n-hint: undo history record
1302 XO("Add %s").Format(effectName));
1303 }
1304 }
static AudioIO * Get()
Definition: AudioIO.cpp:147
static bool IsPluginAvailable(const PluginDescriptor &plug)
const PluginDescriptor * GetPlugin(const PluginID &ID) const
static PluginManager & Get()
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:269
PluginID ShowSelectEffectMenu(wxWindow *parent, RealtimeEffectControl *currentEffectControl=nullptr)

References AudioIO::Get(), PluginManager::Get(), ProjectHistory::Get(), PluginManager::GetPlugin(), PluginManager::IsPluginAvailable(), mProject, mTrack, ProjectHistory::PushState(), BasicUI::ShowMessageBox(), anonymous_namespace{RealtimeEffectPanel.cpp}::ShowSelectEffectMenu(), and XO().

Referenced by RealtimeEffectListWindow().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OnEffectListItemChange()

void RealtimeEffectListWindow::OnEffectListItemChange ( const RealtimeEffectListMessage msg)
inline

Definition at line 1130 of file RealtimeEffectPanel.cpp.

1131 {
1132 auto sizer = mEffectListContainer->GetSizer();
1133 const auto insertItem = [this, &msg](){
1134 auto& effects = RealtimeEffectList::Get(*mTrack);
1135 InsertEffectRow(msg.srcIndex, effects.GetStateAt(msg.srcIndex));
1136 mAddEffectHint->Hide();
1137 mAddEffectTutorialLink->Hide();
1138 };
1139 const auto removeItem = [&](){
1141 // Don't need to auto-save changed settings of effect that is deleted
1142 // Undo history push will do it anyway
1143 ui.Hide();
1144
1145 auto window = sizer->GetItem(msg.srcIndex)->GetWindow();
1146 sizer->Remove(msg.srcIndex);
1147 wxTheApp->CallAfter([ref = wxWeakRef { window }] {
1148 if(ref) ref->Destroy();
1149 });
1150
1151 if(sizer->IsEmpty())
1152 {
1153 if(mEffectListContainer->IsDescendant(FindFocus()))
1154 mAddEffect->SetFocus();
1155
1156 mEffectListContainer->Hide();
1157 mAddEffectHint->Show();
1158 mAddEffectTutorialLink->Show();
1159 }
1160 };
1161
1162 wxWindowUpdateLocker freeze(this);
1164 {
1165 const auto sizer = mEffectListContainer->GetSizer();
1166
1167 const auto movedItem = sizer->GetItem(msg.srcIndex);
1168
1169 const auto proportion = movedItem->GetProportion();
1170 const auto flag = movedItem->GetFlag();
1171 const auto border = movedItem->GetBorder();
1172 const auto window = movedItem->GetWindow();
1173
1174 if(msg.srcIndex < msg.dstIndex)
1175 window->MoveAfterInTabOrder(sizer->GetItem(msg.dstIndex)->GetWindow());
1176 else
1177 window->MoveBeforeInTabOrder(sizer->GetItem(msg.dstIndex)->GetWindow());
1178
1179 sizer->Remove(msg.srcIndex);
1180 sizer->Insert(msg.dstIndex, window, proportion, flag, border);
1181 }
1183 {
1184 insertItem();
1185 }
1187 {
1188 removeItem();
1189 }
1191 {
1192 insertItem();
1193 }
1195 {
1196 removeItem();
1197 }
1198 SendSizeEventToParent();
1199 }
static std::once_flag flag
void InsertEffectRow(size_t index, const std::shared_ptr< RealtimeEffectState > &pState)
static RealtimeEffectStateUI & Get(RealtimeEffectState &state)
@ Remove
Effect item was removed from the list at srcIndex position. affectedState is removed state.
@ DidReplace
Effect item was replaced with a new item at srcIndex position. affectedState is an old state.
@ Move
Item position has changed, from srcIndex to dstIndex. affectedState is the moved state.
@ Insert
New effect item was added to the list at srcIndex position. affectedState is a new state.
@ WillReplace
Effect item will be replaced with a new item at srcIndex position. affectedState is the state to be r...
std::shared_ptr< RealtimeEffectState > affectedState

References RealtimeEffectListMessage::affectedState, RealtimeEffectListMessage::DidReplace, RealtimeEffectListMessage::dstIndex, flag, RealtimeEffectList::Get(), RealtimeEffectStateUI::Get(), RealtimeEffectListMessage::Insert, InsertEffectRow(), mAddEffect, mAddEffectHint, mAddEffectTutorialLink, mEffectListContainer, RealtimeEffectListMessage::Move, mTrack, RealtimeEffectListMessage::Remove, RealtimeEffectListMessage::srcIndex, RealtimeEffectListMessage::type, and RealtimeEffectListMessage::WillReplace.

Referenced by SetTrack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OnSizeChanged()

void RealtimeEffectListWindow::OnSizeChanged ( wxSizeEvent &  event)
inline

Definition at line 1114 of file RealtimeEffectPanel.cpp.

1115 {
1116 if(auto sizerItem = GetSizer()->GetItem(mAddEffectHint))
1117 {
1118 //We need to wrap the text whenever panel width changes and adjust widget height
1119 //so that text is fully visible, but there is no height-for-width layout algorithm
1120 //in wxWidgets yet, so for now we just do it manually
1121
1122 //Restore original text, because 'Wrap' will replace it with wrapped one
1123 mAddEffectHint->SetLabel(_("Realtime effects are non-destructive and can be changed at any time."));
1124 mAddEffectHint->Wrap(GetClientSize().x - sizerItem->GetBorder() * 2);
1125 mAddEffectHint->InvalidateBestSize();
1126 }
1127 event.Skip();
1128 }

References _, and mAddEffectHint.

Referenced by RealtimeEffectListWindow().

Here is the caller graph for this function:

◆ ReloadEffectsList()

void RealtimeEffectListWindow::ReloadEffectsList ( )
inline

Definition at line 1237 of file RealtimeEffectPanel.cpp.

1238 {
1239 wxWindowUpdateLocker freeze(this);
1240
1241 const auto hadFocus = mEffectListContainer->IsDescendant(FindFocus());
1242 //delete items that were added to the sizer
1243 mEffectListContainer->Hide();
1244 mEffectListContainer->GetSizer()->Clear(true);
1245
1246
1247 if(!mTrack || RealtimeEffectList::Get(*mTrack).GetStatesCount() == 0)
1248 mEffectListContainer->Hide();
1249
1250 auto isEmpty{true};
1251 if(mTrack)
1252 {
1253 auto& effects = RealtimeEffectList::Get(*mTrack);
1254 isEmpty = effects.GetStatesCount() == 0;
1255 for(size_t i = 0, count = effects.GetStatesCount(); i < count; ++i)
1256 InsertEffectRow(i, effects.GetStateAt(i));
1257 }
1259 //Workaround for GTK: Underlying GTK widget does not update
1260 //its size when wxWindow size is set to zero
1261 mEffectListContainer->Show(!isEmpty);
1262 mAddEffectHint->Show(isEmpty);
1263 mAddEffectTutorialLink->Show(isEmpty);
1264
1265 SendSizeEventToParent();
1266 }
void SetEnabled(bool state)
Definition: AButton.h:182
size_t GetStatesCount() const noexcept

References RealtimeEffectList::Get(), RealtimeEffectList::GetStatesCount(), InsertEffectRow(), mAddEffect, mAddEffectHint, mAddEffectTutorialLink, mEffectListContainer, mTrack, and AButton::SetEnabled().

Referenced by ResetTrack(), and SetTrack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ResetTrack()

void RealtimeEffectListWindow::ResetTrack ( )
inline

Definition at line 1201 of file RealtimeEffectPanel.cpp.

1202 {
1204
1205 mTrack.reset();
1206 mProject = nullptr;
1208 }
void Reset() noexcept
Breaks the connection (constant time)
Definition: Observer.cpp:101
Observer::Subscription mEffectListItemMovedSubscription

References mEffectListItemMovedSubscription, mProject, mTrack, ReloadEffectsList(), and Observer::Subscription::Reset().

Referenced by RealtimeEffectPanel::ResetTrack().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetTrack()

void RealtimeEffectListWindow::SetTrack ( AudacityProject project,
const std::shared_ptr< Track > &  track 
)
inline

Definition at line 1210 of file RealtimeEffectPanel.cpp.

1211 {
1212 if (mTrack == track)
1213 return;
1214
1216
1217 mTrack = track;
1218 mProject = &project;
1220
1221 if (track)
1222 {
1223 auto& effects = RealtimeEffectList::Get(*mTrack);
1224 mEffectListItemMovedSubscription = effects.Subscribe(
1226
1228 }
1229 }
void OnEffectListItemChange(const RealtimeEffectListMessage &msg)

References RealtimeEffectList::Get(), mEffectListItemMovedSubscription, mProject, mTrack, OnEffectListItemChange(), ReloadEffectsList(), Observer::Subscription::Reset(), and anonymous_namespace{RealtimeEffectPanel.cpp}::UpdateRealtimeEffectUIData().

Referenced by RealtimeEffectPanel::SetTrack().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mAddEffect

AButton* RealtimeEffectListWindow::mAddEffect {nullptr}
private

◆ mAddEffectHint

wxStaticText* RealtimeEffectListWindow::mAddEffectHint {nullptr}
private

◆ mAddEffectTutorialLink

wxWindow* RealtimeEffectListWindow::mAddEffectTutorialLink {nullptr}
private

◆ mEffectListContainer

wxWindow* RealtimeEffectListWindow::mEffectListContainer {nullptr}
private

◆ mEffectListItemMovedSubscription

Observer::Subscription RealtimeEffectListWindow::mEffectListItemMovedSubscription
private

Definition at line 965 of file RealtimeEffectPanel.cpp.

Referenced by ResetTrack(), and SetTrack().

◆ mProject

wxWeakRef<AudacityProject> RealtimeEffectListWindow::mProject
private

◆ mTrack

std::shared_ptr<Track> RealtimeEffectListWindow::mTrack
private

The documentation for this class was generated from the following file: