mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-02 17:09:26 +02:00
Move code for common track menu items
This commit is contained in:
parent
bd0603b66a
commit
0e5e7b1c05
@ -151,7 +151,6 @@ is time to refresh some aspect of the screen.
|
|||||||
|
|
||||||
*//*****************************************************************/
|
*//*****************************************************************/
|
||||||
|
|
||||||
|
|
||||||
#include "Audacity.h"
|
#include "Audacity.h"
|
||||||
#include "Experimental.h"
|
#include "Experimental.h"
|
||||||
#include "TrackPanel.h"
|
#include "TrackPanel.h"
|
||||||
@ -291,14 +290,8 @@ template < class CLIPPEE, class CLIPVAL >
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
TrackPanelFirstID = 2000,
|
TrackPanelFirstID = 2000,
|
||||||
OnSetNameID,
|
|
||||||
OnSetFontID,
|
OnSetFontID,
|
||||||
|
|
||||||
OnMoveUpID,
|
|
||||||
OnMoveDownID,
|
|
||||||
OnMoveTopID,
|
|
||||||
OnMoveBottomID,
|
|
||||||
|
|
||||||
OnUpOctaveID,
|
OnUpOctaveID,
|
||||||
OnDownOctaveID,
|
OnDownOctaveID,
|
||||||
|
|
||||||
@ -364,12 +357,9 @@ BEGIN_EVENT_TABLE(TrackPanel, OverlayPanel)
|
|||||||
EVT_SET_FOCUS(TrackPanel::OnSetFocus)
|
EVT_SET_FOCUS(TrackPanel::OnSetFocus)
|
||||||
EVT_KILL_FOCUS(TrackPanel::OnKillFocus)
|
EVT_KILL_FOCUS(TrackPanel::OnKillFocus)
|
||||||
EVT_CONTEXT_MENU(TrackPanel::OnContextMenu)
|
EVT_CONTEXT_MENU(TrackPanel::OnContextMenu)
|
||||||
EVT_MENU(OnSetNameID, TrackPanel::OnSetName)
|
|
||||||
EVT_MENU(OnSetFontID, TrackPanel::OnSetFont)
|
EVT_MENU(OnSetFontID, TrackPanel::OnSetFont)
|
||||||
EVT_MENU(OnSetTimeTrackRangeID, TrackPanel::OnSetTimeTrackRange)
|
EVT_MENU(OnSetTimeTrackRangeID, TrackPanel::OnSetTimeTrackRange)
|
||||||
|
|
||||||
EVT_MENU_RANGE(OnMoveUpID, OnMoveDownID, TrackPanel::OnMoveTrack)
|
|
||||||
EVT_MENU_RANGE(OnMoveTopID, OnMoveBottomID, TrackPanel::OnMoveTrack)
|
|
||||||
EVT_MENU_RANGE(OnUpOctaveID, OnDownOctaveID, TrackPanel::OnChangeOctave)
|
EVT_MENU_RANGE(OnUpOctaveID, OnDownOctaveID, TrackPanel::OnChangeOctave)
|
||||||
EVT_MENU_RANGE(OnChannelLeftID, OnChannelMonoID,
|
EVT_MENU_RANGE(OnChannelLeftID, OnChannelMonoID,
|
||||||
TrackPanel::OnChannelChange)
|
TrackPanel::OnChannelChange)
|
||||||
@ -630,7 +620,6 @@ void TrackPanel::BuildMenus(void)
|
|||||||
|
|
||||||
/* build the pop-down menu used on wave (sampled audio) tracks */
|
/* build the pop-down menu used on wave (sampled audio) tracks */
|
||||||
mWaveTrackMenu = std::make_unique<wxMenu>();
|
mWaveTrackMenu = std::make_unique<wxMenu>();
|
||||||
BuildCommonDropMenuItems(mWaveTrackMenu.get()); // does name, up/down etc
|
|
||||||
mWaveTrackMenu->AppendRadioItem(OnWaveformID, _("Wa&veform"));
|
mWaveTrackMenu->AppendRadioItem(OnWaveformID, _("Wa&veform"));
|
||||||
mWaveTrackMenu->AppendRadioItem(OnWaveformDBID, _("&Waveform (dB)"));
|
mWaveTrackMenu->AppendRadioItem(OnWaveformDBID, _("&Waveform (dB)"));
|
||||||
mWaveTrackMenu->AppendRadioItem(OnSpectrumID, _("&Spectrogram"));
|
mWaveTrackMenu->AppendRadioItem(OnSpectrumID, _("&Spectrogram"));
|
||||||
@ -659,18 +648,15 @@ void TrackPanel::BuildMenus(void)
|
|||||||
|
|
||||||
/* build the pop-down menu used on note (MIDI) tracks */
|
/* build the pop-down menu used on note (MIDI) tracks */
|
||||||
mNoteTrackMenu = std::make_unique<wxMenu>();
|
mNoteTrackMenu = std::make_unique<wxMenu>();
|
||||||
BuildCommonDropMenuItems(mNoteTrackMenu.get()); // does name, up/down etc
|
|
||||||
mNoteTrackMenu->Append(OnUpOctaveID, _("Up &Octave"));
|
mNoteTrackMenu->Append(OnUpOctaveID, _("Up &Octave"));
|
||||||
mNoteTrackMenu->Append(OnDownOctaveID, _("Down Octa&ve"));
|
mNoteTrackMenu->Append(OnDownOctaveID, _("Down Octa&ve"));
|
||||||
|
|
||||||
/* build the pop-down menu used on label tracks */
|
/* build the pop-down menu used on label tracks */
|
||||||
mLabelTrackMenu = std::make_unique<wxMenu>();
|
mLabelTrackMenu = std::make_unique<wxMenu>();
|
||||||
BuildCommonDropMenuItems(mLabelTrackMenu.get()); // does name, up/down etc
|
|
||||||
mLabelTrackMenu->Append(OnSetFontID, _("&Font..."));
|
mLabelTrackMenu->Append(OnSetFontID, _("&Font..."));
|
||||||
|
|
||||||
/* build the pop-down menu used on time warping tracks */
|
/* build the pop-down menu used on time warping tracks */
|
||||||
mTimeTrackMenu = std::make_unique<wxMenu>();
|
mTimeTrackMenu = std::make_unique<wxMenu>();
|
||||||
BuildCommonDropMenuItems(mTimeTrackMenu.get()); // does name, up/down etc
|
|
||||||
mTimeTrackMenu->AppendRadioItem(OnTimeTrackLinID, wxT("&Linear scale"));
|
mTimeTrackMenu->AppendRadioItem(OnTimeTrackLinID, wxT("&Linear scale"));
|
||||||
mTimeTrackMenu->AppendRadioItem(OnTimeTrackLogID, _("L&ogarithmic scale"));
|
mTimeTrackMenu->AppendRadioItem(OnTimeTrackLogID, _("L&ogarithmic scale"));
|
||||||
|
|
||||||
@ -691,24 +677,6 @@ void TrackPanel::BuildMenus(void)
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::BuildCommonDropMenuItems(wxMenu * menu)
|
|
||||||
{
|
|
||||||
menu->Append(OnSetNameID, _("&Name..."));
|
|
||||||
menu->AppendSeparator();
|
|
||||||
// It is not correct to use KeyStringDisplay here -- wxWidgets will apply
|
|
||||||
// its equivalent to the key names passed to menu functions.
|
|
||||||
menu->Append(OnMoveUpID, _("Move Track &Up") + wxT("\t") +
|
|
||||||
(GetProject()->GetCommandManager()->GetKeyFromName(wxT("TrackMoveUp"))));
|
|
||||||
menu->Append(OnMoveDownID, _("Move Track &Down") + wxT("\t") +
|
|
||||||
(GetProject()->GetCommandManager()->GetKeyFromName(wxT("TrackMoveDown"))));
|
|
||||||
menu->Append(OnMoveTopID, _("Move Track to &Top") + wxT("\t") +
|
|
||||||
(GetProject()->GetCommandManager()->GetKeyFromName(wxT("TrackMoveTop"))));
|
|
||||||
menu->Append(OnMoveBottomID, _("Move Track to &Bottom") + wxT("\t") +
|
|
||||||
(GetProject()->GetCommandManager()->GetKeyFromName(wxT("TrackMoveBottom"))));
|
|
||||||
menu->AppendSeparator();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// left over from PRL's vertical ruler context menu experiment in 2.1.2
|
// left over from PRL's vertical ruler context menu experiment in 2.1.2
|
||||||
// static
|
// static
|
||||||
@ -6068,11 +6036,6 @@ void TrackPanel::OnTrackMenu(Track *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (theMenu) {
|
if (theMenu) {
|
||||||
theMenu->Enable(OnMoveUpID, mTracks->CanMoveUp(t));
|
|
||||||
theMenu->Enable(OnMoveDownID, mTracks->CanMoveDown(t));
|
|
||||||
theMenu->Enable(OnMoveTopID, mTracks->CanMoveUp(t));
|
|
||||||
theMenu->Enable(OnMoveBottomID, mTracks->CanMoveDown(t));
|
|
||||||
|
|
||||||
//We need to find the location of the menu rectangle.
|
//We need to find the location of the menu rectangle.
|
||||||
const wxRect rect = FindTrackRect(t,true);
|
const wxRect rect = FindTrackRect(t,true);
|
||||||
wxRect titleRect;
|
wxRect titleRect;
|
||||||
@ -6926,27 +6889,6 @@ void TrackPanel::OnZoomFitVertical(wxCommandEvent &)
|
|||||||
HandleWaveTrackVZoom(static_cast<WaveTrack*>(mPopupMenuTarget), true, true);
|
HandleWaveTrackVZoom(static_cast<WaveTrack*>(mPopupMenuTarget), true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move a track up, down, to top or to bottom.
|
|
||||||
|
|
||||||
void TrackPanel::OnMoveTrack(wxCommandEvent &event)
|
|
||||||
{
|
|
||||||
AudacityProject::MoveChoice choice;
|
|
||||||
switch (event.GetId()) {
|
|
||||||
default:
|
|
||||||
wxASSERT(false);
|
|
||||||
case OnMoveUpID:
|
|
||||||
choice = AudacityProject::OnMoveUpID; break;
|
|
||||||
case OnMoveDownID:
|
|
||||||
choice = AudacityProject::OnMoveDownID; break;
|
|
||||||
case OnMoveTopID:
|
|
||||||
choice = AudacityProject::OnMoveTopID; break;
|
|
||||||
case OnMoveBottomID:
|
|
||||||
choice = AudacityProject::OnMoveBottomID; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
GetProject()->MoveTrack(mPopupMenuTarget, choice);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This only applies to MIDI tracks. Presumably, it shifts the
|
/// This only applies to MIDI tracks. Presumably, it shifts the
|
||||||
/// whole sequence by an octave.
|
/// whole sequence by an octave.
|
||||||
void TrackPanel::OnChangeOctave(wxCommandEvent & event)
|
void TrackPanel::OnChangeOctave(wxCommandEvent & event)
|
||||||
@ -6965,38 +6907,6 @@ void TrackPanel::OnChangeOctave(wxCommandEvent & event)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrackPanel::OnSetName(wxCommandEvent & WXUNUSED(event))
|
|
||||||
{
|
|
||||||
Track *t = mPopupMenuTarget;
|
|
||||||
if (t)
|
|
||||||
{
|
|
||||||
wxString oldName = t->GetName();
|
|
||||||
wxString newName =
|
|
||||||
wxGetTextFromUser(_("Change track name to:"),
|
|
||||||
_("Track Name"), oldName);
|
|
||||||
if (newName != wxT("")) // wxGetTextFromUser returns empty string on Cancel.
|
|
||||||
{
|
|
||||||
t->SetName(newName);
|
|
||||||
// if we have a linked channel this name should change as well
|
|
||||||
// (otherwise sort by name and time will crash).
|
|
||||||
if (t->GetLinked())
|
|
||||||
t->GetLink()->SetName(newName);
|
|
||||||
|
|
||||||
MixerBoard* pMixerBoard = this->GetMixerBoard();
|
|
||||||
auto pt = dynamic_cast<PlayableTrack*>(t);
|
|
||||||
if (pMixerBoard && pt)
|
|
||||||
pMixerBoard->UpdateName(pt);
|
|
||||||
|
|
||||||
MakeParentPushState(wxString::Format(_("Renamed '%s' to '%s'"),
|
|
||||||
oldName.c_str(),
|
|
||||||
newName.c_str()),
|
|
||||||
_("Name Change"));
|
|
||||||
|
|
||||||
Refresh(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Small helper class to enumerate all fonts in the system
|
// Small helper class to enumerate all fonts in the system
|
||||||
// We use this because the default implementation of
|
// We use this because the default implementation of
|
||||||
// wxFontEnumerator::GetFacenames() has changed between wx2.6 and 2.8
|
// wxFontEnumerator::GetFacenames() has changed between wx2.6 and 2.8
|
||||||
|
@ -340,14 +340,6 @@ class AUDACITY_DLL_API TrackPanel final : public OverlayPanel {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual MixerBoard* GetMixerBoard();
|
virtual MixerBoard* GetMixerBoard();
|
||||||
/** @brief Populates the track pop-down menu with the common set of
|
|
||||||
* initial items.
|
|
||||||
*
|
|
||||||
* Ensures that all pop-down menus start with Name, and the commands for moving
|
|
||||||
* the track around, via a single set of c ode.
|
|
||||||
* @param menu the menu to add the commands to.
|
|
||||||
*/
|
|
||||||
virtual void BuildCommonDropMenuItems(wxMenu * menu);
|
|
||||||
|
|
||||||
// left over from PRL's vertical ruler context menu experiment in 2.1.2
|
// left over from PRL's vertical ruler context menu experiment in 2.1.2
|
||||||
// static void BuildVRulerMenuItems(wxMenu * menu, int firstId, const wxArrayString &names);
|
// static void BuildVRulerMenuItems(wxMenu * menu, int firstId, const wxArrayString &names);
|
||||||
@ -496,11 +488,9 @@ protected:
|
|||||||
UndoPush flags);
|
UndoPush flags);
|
||||||
virtual void MakeParentModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after
|
virtual void MakeParentModifyState(bool bWantsAutoSave); // if true, writes auto-save file. Should set only if you really want the state change restored after
|
||||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
||||||
virtual void OnSetName(wxCommandEvent &event);
|
|
||||||
|
|
||||||
virtual void OnSetFont(wxCommandEvent &event);
|
virtual void OnSetFont(wxCommandEvent &event);
|
||||||
|
|
||||||
virtual void OnMoveTrack (wxCommandEvent &event);
|
|
||||||
virtual void OnChangeOctave (wxCommandEvent &event);
|
virtual void OnChangeOctave (wxCommandEvent &event);
|
||||||
virtual void OnChannelChange(wxCommandEvent &event);
|
virtual void OnChannelChange(wxCommandEvent &event);
|
||||||
virtual void OnSpectrogramSettings(wxCommandEvent &event);
|
virtual void OnSpectrogramSettings(wxCommandEvent &event);
|
||||||
|
@ -13,8 +13,12 @@ Paul Licameli split from TrackPanel.cpp
|
|||||||
#include "TrackButtonHandles.h"
|
#include "TrackButtonHandles.h"
|
||||||
#include "../../HitTestResult.h"
|
#include "../../HitTestResult.h"
|
||||||
#include "../../RefreshCode.h"
|
#include "../../RefreshCode.h"
|
||||||
|
#include "../../MixerBoard.h"
|
||||||
|
#include "../../Project.h"
|
||||||
#include "../../TrackPanel.h"
|
#include "../../TrackPanel.h"
|
||||||
#include "../../TrackPanelMouseEvent.h"
|
#include "../../TrackPanelMouseEvent.h"
|
||||||
|
#include "../../WaveTrack.h"
|
||||||
|
#include <wx/textdlg.h>
|
||||||
|
|
||||||
int TrackControls::gCaptureState;
|
int TrackControls::gCaptureState;
|
||||||
|
|
||||||
@ -47,6 +51,15 @@ Track *TrackControls::FindTrack()
|
|||||||
return GetTrack();
|
return GetTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
OnSetNameID = 2000,
|
||||||
|
OnMoveUpID,
|
||||||
|
OnMoveDownID,
|
||||||
|
OnMoveTopID,
|
||||||
|
OnMoveBottomID,
|
||||||
|
};
|
||||||
|
|
||||||
class TrackMenuTable : public PopupMenuTable
|
class TrackMenuTable : public PopupMenuTable
|
||||||
{
|
{
|
||||||
TrackMenuTable() : mpData(NULL) {}
|
TrackMenuTable() : mpData(NULL) {}
|
||||||
@ -56,11 +69,10 @@ public:
|
|||||||
static TrackMenuTable &Instance();
|
static TrackMenuTable &Instance();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void OnSetName(wxCommandEvent &);
|
||||||
|
void OnMoveTrack(wxCommandEvent &event);
|
||||||
|
|
||||||
void InitMenu(Menu*, void *pUserData) override
|
void InitMenu(Menu *pMenu, void *pUserData) override;
|
||||||
{
|
|
||||||
mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DestroyMenu() override
|
void DestroyMenu() override
|
||||||
{
|
{
|
||||||
@ -76,9 +88,107 @@ TrackMenuTable &TrackMenuTable::Instance()
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TrackMenuTable::InitMenu(Menu *pMenu, void *pUserData)
|
||||||
|
{
|
||||||
|
mpData = static_cast<TrackControls::InitMenuData*>(pUserData);
|
||||||
|
Track *const pTrack = mpData->pTrack;
|
||||||
|
|
||||||
|
TrackList *const tracks = GetActiveProject()->GetTracks();
|
||||||
|
|
||||||
|
pMenu->Enable(OnMoveUpID, tracks->CanMoveUp(pTrack));
|
||||||
|
pMenu->Enable(OnMoveDownID, tracks->CanMoveDown(pTrack));
|
||||||
|
pMenu->Enable(OnMoveTopID, tracks->CanMoveUp(pTrack));
|
||||||
|
pMenu->Enable(OnMoveBottomID, tracks->CanMoveDown(pTrack));
|
||||||
|
}
|
||||||
|
|
||||||
BEGIN_POPUP_MENU(TrackMenuTable)
|
BEGIN_POPUP_MENU(TrackMenuTable)
|
||||||
|
POPUP_MENU_ITEM(OnSetNameID, _("&Name..."), OnSetName)
|
||||||
|
POPUP_MENU_SEPARATOR()
|
||||||
|
POPUP_MENU_ITEM(
|
||||||
|
// It is not correct to use KeyStringDisplay here -- wxWidgets will apply
|
||||||
|
// its equivalent to the key names passed to menu functions.
|
||||||
|
OnMoveUpID,
|
||||||
|
_("Move Track &Up") + wxT("\t") +
|
||||||
|
(GetActiveProject()->GetCommandManager()->
|
||||||
|
GetKeyFromName(wxT("TrackMoveUp"))),
|
||||||
|
OnMoveTrack)
|
||||||
|
POPUP_MENU_ITEM(
|
||||||
|
OnMoveDownID,
|
||||||
|
_("Move Track &Down") + wxT("\t") +
|
||||||
|
(GetActiveProject()->GetCommandManager()->
|
||||||
|
GetKeyFromName(wxT("TrackMoveDown"))),
|
||||||
|
OnMoveTrack)
|
||||||
|
POPUP_MENU_ITEM(
|
||||||
|
OnMoveTopID,
|
||||||
|
_("Move Track to &Top") + wxT("\t") +
|
||||||
|
(GetActiveProject()->GetCommandManager()->
|
||||||
|
GetKeyFromName(wxT("TrackMoveTop"))),
|
||||||
|
OnMoveTrack)
|
||||||
|
POPUP_MENU_ITEM(
|
||||||
|
OnMoveBottomID,
|
||||||
|
_("Move Track to &Bottom") + wxT("\t") +
|
||||||
|
(GetActiveProject()->GetCommandManager()->
|
||||||
|
GetKeyFromName(wxT("TrackMoveBottom"))),
|
||||||
|
OnMoveTrack)
|
||||||
END_POPUP_MENU()
|
END_POPUP_MENU()
|
||||||
|
|
||||||
|
void TrackMenuTable::OnSetName(wxCommandEvent &)
|
||||||
|
{
|
||||||
|
Track *const pTrack = mpData->pTrack;
|
||||||
|
if (pTrack)
|
||||||
|
{
|
||||||
|
AudacityProject *const proj = ::GetActiveProject();
|
||||||
|
const wxString oldName = pTrack->GetName();
|
||||||
|
const wxString newName =
|
||||||
|
wxGetTextFromUser(_("Change track name to:"),
|
||||||
|
_("Track Name"), oldName);
|
||||||
|
if (newName != wxT("")) // wxGetTextFromUser returns empty string on Cancel.
|
||||||
|
{
|
||||||
|
pTrack->SetName(newName);
|
||||||
|
// if we have a linked channel this name should change as well
|
||||||
|
// (otherwise sort by name and time will crash).
|
||||||
|
if (pTrack->GetLinked())
|
||||||
|
pTrack->GetLink()->SetName(newName);
|
||||||
|
|
||||||
|
MixerBoard *const pMixerBoard = proj->GetMixerBoard();
|
||||||
|
auto pt = dynamic_cast<PlayableTrack*>(pTrack);
|
||||||
|
if (pt && pMixerBoard)
|
||||||
|
pMixerBoard->UpdateName(pt);
|
||||||
|
|
||||||
|
proj->PushState(wxString::Format(_("Renamed '%s' to '%s'"),
|
||||||
|
oldName.c_str(),
|
||||||
|
newName.c_str()),
|
||||||
|
_("Name Change"));
|
||||||
|
|
||||||
|
mpData->result = RefreshCode::RefreshAll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackMenuTable::OnMoveTrack(wxCommandEvent &event)
|
||||||
|
{
|
||||||
|
AudacityProject *const project = GetActiveProject();
|
||||||
|
AudacityProject::MoveChoice choice;
|
||||||
|
switch (event.GetId()) {
|
||||||
|
default:
|
||||||
|
wxASSERT(false);
|
||||||
|
case OnMoveUpID:
|
||||||
|
choice = AudacityProject::OnMoveUpID; break;
|
||||||
|
case OnMoveDownID:
|
||||||
|
choice = AudacityProject::OnMoveDownID; break;
|
||||||
|
case OnMoveTopID:
|
||||||
|
choice = AudacityProject::OnMoveTopID; break;
|
||||||
|
case OnMoveBottomID:
|
||||||
|
choice = AudacityProject::OnMoveBottomID; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
project->MoveTrack(mpData->pTrack, choice);
|
||||||
|
|
||||||
|
// MoveTrack already refreshed TrackPanel, which means repaint will happen.
|
||||||
|
// This is a harmless redundancy:
|
||||||
|
mpData->result = RefreshCode::RefreshAll;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned TrackControls::DoContextMenu
|
unsigned TrackControls::DoContextMenu
|
||||||
(const wxRect &rect, wxWindow *pParent, wxPoint *)
|
(const wxRect &rect, wxWindow *pParent, wxPoint *)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user