20#include <wx/combobox.h>
21#include <wx/display.h>
22#include <wx/scrolbar.h>
24#include <wx/bmpbuttn.h>
25#include <wx/stattext.h>
33 return dlg.ShowModal() == wxID_OK;
43 ComboEditor(
const wxArrayString& choices,
bool allowOthers =
false)
44 : wxGridCellChoiceEditor(choices, allowOthers)
50 void PaintBackground(wxDC&,
const wxRect& WXUNUSED(rectCell),
const wxGridCellAttr & WXUNUSED(attr))
override
57 wxGridCellChoiceEditor::SetParameters(
params);
66 void SetSize(
const wxRect& rectOrig)
override
68 wxRect rect(rectOrig);
69 wxRect r = Combo()->GetRect();
72 rect.y -= (r.GetHeight() - rect.GetHeight()) / 2;
73 rect.height = r.GetHeight();
75 wxGridCellChoiceEditor::SetSize(rect);
92 wxComboBox * tc = Combo();
98 ch =
event.GetUnicodeKey();
104 ch =
event.GetKeyCode();
105 isPrintable = ch >= WXK_SPACE && ch < WXK_START;
118 const long pos = tc->GetLastPosition();
119 tc->Remove(pos - 1, pos);
125 tc->WriteText(
static_cast<wxChar
>(ch));
131 wxGridCellEditor *
Clone()
const override
145#define LABEL_ARTIST XO("Artist Name")
146#define LABEL_TITLE XO("Track Title")
147#define LABEL_ALBUM XO("Album Title")
148#define LABEL_TRACK XO("Track Number")
149#define LABEL_YEAR XO("Year")
150#define LABEL_GENRE XO("Genre")
151#define LABEL_COMMENTS XO("Comments")
179#define STATICCNT WXSIZEOF(labelmap)
219 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
220 mTags(
std::move(tags)),
222 mEditTitle(editTitle),
223 mEditTrack(editTrack)
225 assert(mTags.size() == 1 || (mTags.size() > 1 && mTags.size() == mNames.size()));
232 mEditTags.reserve(mTags.size());
233 for(
auto ptr : mTags)
234 mEditTags.push_back(std::make_unique<Tags>(*ptr));
238 PopulateOrExchange(
S);
240 TransferDataToWindow();
245 wxSize sz = GetSize();
246 SetSizeHints(sz.x,
std::min(sz.y, 600));
249 for(
unsigned i = 0; i < mEditTags.size(); ++i)
251 mEditTags[i]->Clear();
252 *mEditTags[i] = *mTags[i];
255 wxRect r = GetRect();
258 gPrefs->
Read(
wxT(
"/TagsEditorDialog/width"), &r.width, r.width);
259 gPrefs->
Read(
wxT(
"/TagsEditorDialog/height"), &r.height, r.height);
262 if (IsWindowRectValid(&r))
263 Move(r.GetPosition());
265 SetSize(r.GetSize());
269 wxScrollBar sb(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL);
270 r = mGrid->GetClientRect();
271 r.width -= mGrid->GetColSize(0);
272 r.width -= sb.GetSize().GetWidth();
275 mGrid->SetColSize(1, r.width);
298 S.StartVerticalLay();
300 S.StartHorizontalLay(wxALIGN_LEFT, 0);
302 S.AddUnits(
XO(
"Use arrow keys (or ENTER key after editing) to navigate fields."));
304 S.EndHorizontalLay();
308 S.StartHorizontalLay(wxEXPAND, 0);
311 mName =
S.Style(wxALIGN_CENTER).AddVariableText({},
true, wxEXPAND);
314 S.EndHorizontalLay();
324 mGrid->RegisterDataType(
wxT(
"Combo"),
328 mGrid->SetColLabelSize(
mGrid->GetDefaultRowSize());
330 auto cs = transform_container<wxArrayStringEx>(
334 mGrid->CreateGrid(0, 2, wxGrid::wxGridSelectRows);
335 mGrid->SetRowLabelSize(0);
336 mGrid->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
337 mGrid->SetColLabelValue(0,
_(
"Tag"));
338 mGrid->SetColLabelValue(1,
_(
"Value"));
341 wxComboBox tc(
this, wxID_ANY,
wxT(
""), wxDefaultPosition, wxDefaultSize, cs);
342 mGrid->SetColSize(0, tc.GetSize().x);
343 mGrid->SetColMinimalWidth(0, tc.GetSize().x);
346 .Position(wxEXPAND | wxALL)
349 S.StartMultiColumn(4, wxALIGN_CENTER);
358 S.StartHorizontalLay(wxALIGN_CENTRE, 0);
360 S.StartStatic(
XO(
"Genres"));
362 S.StartMultiColumn(4, wxALIGN_CENTER);
370 S.StartStatic(
XO(
"Template"));
372 S.StartMultiColumn(4, wxALIGN_CENTER);
383 S.EndHorizontalLay();
397 int i, cnt =
mGrid->GetNumberRows();
399 if (
mGrid->IsCellEditControlShown()) {
400 mGrid->SaveEditControlValue();
401 mGrid->HideCellEditControl();
407 for (i = 0; i < cnt; i++) {
410 auto n =
mGrid->GetCellValue(i, 0);
411 wxString v =
mGrid->GetCellValue(i, 1);
417 bool bSpecialTag =
true;
423 else if (n.CmpNoCase(
LABEL_TITLE.Translation()) == 0) {
426 else if (n.CmpNoCase(
LABEL_ALBUM.Translation()) == 0) {
429 else if (n.CmpNoCase(
LABEL_TRACK.Translation()) == 0) {
432 else if (n.CmpNoCase(
LABEL_YEAR.Translation()) == 0) {
435 else if (n.CmpNoCase(
LABEL_GENRE.Translation()) == 0) {
445 local.SetTag(n, v, bSpecialTag);
469 if (
mGrid->GetNumberRows()) {
477 mGrid->SetReadOnly(i, 0);
485 mGrid->SetReadOnly(i, 1);
490 mGrid->SetReadOnly(i, 1);
497 for (
const auto &pair : local.GetRange()) {
498 const auto &n = pair.first;
499 const auto &v = pair.second;
500 if (popTagMap.find(n) == popTagMap.end()) {
502 mGrid->SetCellValue(i, 0, n);
503 mGrid->SetCellValue(i, 1, v);
509 mGrid->AppendRows(1);
524 static bool ischanging =
false;
533 if (event.GetCol() != 0) {
539 auto row =
event.GetRow();
540 const wxString
key0 =
mGrid->GetCellValue(row, 0).Upper();
541 auto nn =
mGrid->GetNumberRows();
542 for (
decltype(nn) ii = 0; ii < nn; ++ii) {
545 auto key =
mGrid->GetCellValue(ii, 0).Upper();
546 if (
key0.CmpNoCase(
key) == 0) {
549 mGrid->SetGridCursor(ii, 0);
561 if (
mGrid->IsCellEditControlShown()) {
562 mGrid->SaveEditControlValue();
563 mGrid->HideCellEditControl();
567 wxDefaultPosition, wxDefaultSize,
568 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
574 S.StartVerticalLay(
true);
576 tc =
S.AddTextWindow(
wxT(
""));
580 S.AddStandardButtons();
585 int cnt = local.GetNumUserGenres();
586 for (
int i = 0; i < cnt; i++) {
587 g.push_back(local.GetUserGenre(i));
589 std::sort( g.begin(), g.end() );
591 for (
int i = 0; i < cnt; i++) {
592 tc->AppendText(g[i] +
wxT(
"\n"));
596 if (dlg.ShowModal() == wxID_CANCEL) {
601 wxFile f(
fn.GetFullPath(), wxFile::write);
602 if (!f.IsOpened() || !f.Write(tc->GetValue())) {
604 XO(
"Unable to save genre file."),
605 XO(
"Reset Genres") );
617 XO(
"Are you sure you want to reset the genre list to defaults?"),
626 local.LoadDefaultGenres();
629 wxTextFile tf(
fn.GetFullPath());
631 bool open = (tf.Exists() && tf.Open()) ||
632 (!tf.Exists() && tf.Create());
636 XO(
"Unable to open genre file."),
637 XO(
"Reset Genres") );
643 int cnt = local.GetNumUserGenres();
644 for (
int i = 0; i < cnt; i++) {
645 tf.AddLine(local.GetUserGenre(i));
650 XO(
"Unable to save genre file."),
651 XO(
"Reset Genres") );
676 XO(
"Load Metadata As:"),
681 wxFD_OPEN | wxRESIZE_BORDER,
692 if (!reader.
Parse(&temp,
fn)) {
696 XO(
"Error Loading Metadata"),
704 wxString track = local.GetTag(
TAG_TRACK);
736 XO(
"Save Metadata As:"),
741 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
755 wxString track = local.GetTag(
TAG_TRACK);
767 auto cleanup =
finally( [&] {
780 local.WriteXML(writer);
794 wxString track = local.GetTag(
TAG_TRACK);
810 for (
const auto &pair : local.GetRange()) {
811 const auto &n = pair.first;
812 const auto &v = pair.second;
835 size_t row =
mGrid->GetGridCursorRow();
842 mGrid->GetCellValue(row, 0)
847 mGrid->SetCellValue(row, 1, wxEmptyString);
850 mGrid->DeleteRows(row, 1);
856 if (
mGrid->IsCellEditControlShown()) {
857 mGrid->SaveEditControlValue();
858 mGrid->HideCellEditControl();
859#if defined(__WXMAC__)
871 for(
unsigned i = 0; i <
mEditTags.size(); ++i)
874 wxRect r = GetRect();
891 if (
mGrid->IsCellEditControlShown()) {
892 auto editor =
mGrid->GetCellEditor(
mGrid->GetGridCursorRow(),
893 mGrid->GetGridCursorCol());
897 mGrid->HideCellEditControl();
898#if defined(__WXMSW__)
904 if (escKey && focus ==
mGrid)
907 EndModal(wxID_CANCEL);
912 if (event.GetKeyCode() == WXK_ESCAPE)
920 int cnt =
mGrid->GetNumberRows();
922 for (
int i = 0; i < cnt; i++) {
926 mGrid->SetCellEditor(i, 1,
mGrid->GetDefaultEditorForType(
wxT(
"Combo")));
929 mGrid->SetCellEditor(i, 1, NULL);
958 int cnt = local.GetNumUserGenres();
963 for (i = 0; i < cnt; i++) {
964 g.push_back(local.GetUserGenre(i));
966 std::sort( g.begin(), g.end() );
968 for (i = 0; i < cnt; i++) {
969 parm = parm + (i == 0 ?
wxT(
"") :
wxT(
",")) + g[i];
974 auto editor =
mGrid->GetDefaultEditorForType(
wxT(
"Combo"));
975 editor->SetParameters(parm);
982 wxPoint topLeft(windowRect->GetTopLeft().x, windowRect->GetTopLeft().y);
983 wxPoint topRight(windowRect->GetTopRight().x, windowRect->GetTopRight().y);
984 wxPoint bottomLeft(windowRect->GetBottomLeft().x, windowRect->GetBottomLeft().y);
985 wxPoint bottomRight(windowRect->GetBottomRight().x, windowRect->GetBottomRight().y);
986 display.GetFromPoint(topLeft);
987 if (display.GetFromPoint(topLeft) == -1 &&
988 display.GetFromPoint(topRight) == -1 &&
989 display.GetFromPoint(bottomLeft) == -1 &&
990 display.GetFromPoint(bottomRight) == -1) {
1012 auto newTags = tags.Duplicate();
1015 if (tags != *newTags) {
1036 XO(
"Edit Metadata Tags"),
XO(
"Metadata Tags"));
R GuardedCall(const F1 &body, const F2 &handler=F2::Default(), F3 delayedHandler=DefaultDelayedHandlerAction) noexcept(noexcept(handler(std::declval< AudacityException * >())) &&noexcept(handler(nullptr)) &&noexcept(std::function< void(AudacityException *)>{std::move(delayedHandler)}))
Execute some code on any thread; catch any AudacityException; enqueue error report on the main thread...
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
const ReservedCommandFlag & AudioIONotBusyFlag()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
EffectDistortionSettings params
XXO("&Cut/Copy/Paste Toolbar")
audacity::BasicSettings * gPrefs
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
accessors for certain important windows associated with each project
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
std::vector< TranslatableString > TranslatableStrings
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
void PaintBackground(wxDC &, const wxRect &WXUNUSED(rectCell), const wxGridCellAttr &WXUNUSED(attr)) override
ComboEditor(const wxArrayString &choices, bool allowOthers=false)
virtual void StartingKey(wxKeyEvent &event) override
void SetParameters(const wxString ¶ms) override
void SetSize(const wxRect &rectOrig) override
wxGridCellEditor * Clone() const override
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
FILES_API const FileType XMLFiles
static FormatterContext EmptyContext()
Supplies an accessible grid based on wxGrid.
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
Generates classes whose instances register items at construction.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
Reads a file and passes the results through an XMLTagHandler.
const TranslatableString & GetErrorStr() const
bool Parse(XMLTagHandler *baseHandler, const FilePath &fname)
Wrapper to output XML data to files.
virtual bool Flush() noexcept=0
bool DeleteGroup(const wxString &key)
Deletes specified group if exists.
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
void SetName(const TranslatableString &title)
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
FILES_API FilePath DataDir()
Audacity user data directory.