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 const auto maxHeight = std::max(1, wxDisplay().GetGeometry().GetHeight() - 100);
247 const auto minHeight =
std::min({ sz.y, 600, maxHeight });
248 SetSizeHints(sz.x, minHeight, wxDefaultCoord, maxHeight);
251 for(
unsigned i = 0; i < mEditTags.size(); ++i)
253 mEditTags[i]->Clear();
254 *mEditTags[i] = *mTags[i];
257 wxRect r = GetRect();
260 gPrefs->
Read(
wxT(
"/TagsEditorDialog/width"), &r.width, r.width);
261 gPrefs->
Read(
wxT(
"/TagsEditorDialog/height"), &r.height, r.height);
264 if (IsWindowRectValid(&r))
265 Move(r.GetPosition());
267 SetSize(r.GetSize());
271 wxScrollBar sb(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL);
272 r = mGrid->GetClientRect();
273 r.width -= mGrid->GetColSize(0);
274 r.width -= sb.GetSize().GetWidth();
277 mGrid->SetColSize(1, r.width);
300 S.StartVerticalLay();
302 S.StartHorizontalLay(wxALIGN_LEFT, 0);
304 S.AddUnits(
XO(
"Use arrow keys (or ENTER key after editing) to navigate fields."));
306 S.EndHorizontalLay();
310 S.StartHorizontalLay(wxEXPAND, 0);
313 mName =
S.Style(wxALIGN_CENTER).AddVariableText({},
true, wxEXPAND);
316 S.EndHorizontalLay();
326 mGrid->RegisterDataType(
wxT(
"Combo"),
330 mGrid->SetColLabelSize(
mGrid->GetDefaultRowSize());
332 auto cs = transform_container<wxArrayStringEx>(
336 mGrid->CreateGrid(0, 2, wxGrid::wxGridSelectRows);
337 mGrid->SetRowLabelSize(0);
338 mGrid->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
339 mGrid->SetColLabelValue(0,
_(
"Tag"));
340 mGrid->SetColLabelValue(1,
_(
"Value"));
343 wxComboBox tc(
this, wxID_ANY,
wxT(
""), wxDefaultPosition, wxDefaultSize, cs);
344 mGrid->SetColSize(0, tc.GetSize().x);
345 mGrid->SetColMinimalWidth(0, tc.GetSize().x);
348 .Position(wxEXPAND | wxALL)
351 S.StartMultiColumn(4, wxALIGN_CENTER);
360 S.StartHorizontalLay(wxALIGN_CENTRE, 0);
362 S.StartStatic(
XO(
"Genres"));
364 S.StartMultiColumn(4, wxALIGN_CENTER);
372 S.StartStatic(
XO(
"Template"));
374 S.StartMultiColumn(4, wxALIGN_CENTER);
385 S.EndHorizontalLay();
399 int i, cnt =
mGrid->GetNumberRows();
401 if (
mGrid->IsCellEditControlShown()) {
402 mGrid->SaveEditControlValue();
403 mGrid->HideCellEditControl();
409 for (i = 0; i < cnt; i++) {
412 auto n =
mGrid->GetCellValue(i, 0);
413 wxString v =
mGrid->GetCellValue(i, 1);
419 bool bSpecialTag =
true;
425 else if (n.CmpNoCase(
LABEL_TITLE.Translation()) == 0) {
428 else if (n.CmpNoCase(
LABEL_ALBUM.Translation()) == 0) {
431 else if (n.CmpNoCase(
LABEL_TRACK.Translation()) == 0) {
434 else if (n.CmpNoCase(
LABEL_YEAR.Translation()) == 0) {
437 else if (n.CmpNoCase(
LABEL_GENRE.Translation()) == 0) {
447 local.SetTag(n, v, bSpecialTag);
471 if (
mGrid->GetNumberRows()) {
479 mGrid->SetReadOnly(i, 0);
487 mGrid->SetReadOnly(i, 1);
492 mGrid->SetReadOnly(i, 1);
499 for (
const auto &pair : local.GetRange()) {
500 const auto &n = pair.first;
501 const auto &v = pair.second;
502 if (popTagMap.find(n) == popTagMap.end()) {
504 mGrid->SetCellValue(i, 0, n);
505 mGrid->SetCellValue(i, 1, v);
511 mGrid->AppendRows(1);
526 static bool ischanging =
false;
535 if (event.GetCol() != 0) {
541 auto row =
event.GetRow();
542 const wxString
key0 =
mGrid->GetCellValue(row, 0).Upper();
543 auto nn =
mGrid->GetNumberRows();
544 for (
decltype(nn) ii = 0; ii < nn; ++ii) {
547 auto key =
mGrid->GetCellValue(ii, 0).Upper();
548 if (
key0.CmpNoCase(
key) == 0) {
551 mGrid->SetGridCursor(ii, 0);
563 if (
mGrid->IsCellEditControlShown()) {
564 mGrid->SaveEditControlValue();
565 mGrid->HideCellEditControl();
569 wxDefaultPosition, wxDefaultSize,
570 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
576 S.StartVerticalLay(
true);
578 tc =
S.AddTextWindow(
wxT(
""));
582 S.AddStandardButtons();
587 int cnt = local.GetNumUserGenres();
588 for (
int i = 0; i < cnt; i++) {
589 g.push_back(local.GetUserGenre(i));
591 std::sort( g.begin(), g.end() );
593 for (
int i = 0; i < cnt; i++) {
594 tc->AppendText(g[i] +
wxT(
"\n"));
598 if (dlg.ShowModal() == wxID_CANCEL) {
603 wxFile f(
fn.GetFullPath(), wxFile::write);
604 if (!f.IsOpened() || !f.Write(tc->GetValue())) {
606 XO(
"Unable to save genre file."),
607 XO(
"Reset Genres") );
619 XO(
"Are you sure you want to reset the genre list to defaults?"),
628 local.LoadDefaultGenres();
631 wxTextFile tf(
fn.GetFullPath());
633 bool open = (tf.Exists() && tf.Open()) ||
634 (!tf.Exists() && tf.Create());
638 XO(
"Unable to open genre file."),
639 XO(
"Reset Genres") );
645 int cnt = local.GetNumUserGenres();
646 for (
int i = 0; i < cnt; i++) {
647 tf.AddLine(local.GetUserGenre(i));
652 XO(
"Unable to save genre file."),
653 XO(
"Reset Genres") );
678 XO(
"Load Metadata As:"),
683 wxFD_OPEN | wxRESIZE_BORDER,
694 if (!reader.
Parse(&temp,
fn)) {
698 XO(
"Error Loading Metadata"),
706 wxString track = local.GetTag(
TAG_TRACK);
738 XO(
"Save Metadata As:"),
743 wxFD_SAVE | wxFD_OVERWRITE_PROMPT | wxRESIZE_BORDER,
757 wxString track = local.GetTag(
TAG_TRACK);
769 auto cleanup =
finally( [&] {
782 local.WriteXML(writer);
796 wxString track = local.GetTag(
TAG_TRACK);
812 for (
const auto &pair : local.GetRange()) {
813 const auto &n = pair.first;
814 const auto &v = pair.second;
837 size_t row =
mGrid->GetGridCursorRow();
844 mGrid->GetCellValue(row, 0)
849 mGrid->SetCellValue(row, 1, wxEmptyString);
852 mGrid->DeleteRows(row, 1);
858 if (
mGrid->IsCellEditControlShown()) {
859 mGrid->SaveEditControlValue();
860 mGrid->HideCellEditControl();
861#if defined(__WXMAC__)
873 for(
unsigned i = 0; i <
mEditTags.size(); ++i)
876 wxRect r = GetRect();
893 if (
mGrid->IsCellEditControlShown()) {
894 auto editor =
mGrid->GetCellEditor(
mGrid->GetGridCursorRow(),
895 mGrid->GetGridCursorCol());
899 mGrid->HideCellEditControl();
900#if defined(__WXMSW__)
906 if (escKey && focus ==
mGrid)
909 EndModal(wxID_CANCEL);
914 if (event.GetKeyCode() == WXK_ESCAPE)
922 int cnt =
mGrid->GetNumberRows();
924 for (
int i = 0; i < cnt; i++) {
928 mGrid->SetCellEditor(i, 1,
mGrid->GetDefaultEditorForType(
wxT(
"Combo")));
931 mGrid->SetCellEditor(i, 1, NULL);
960 int cnt = local.GetNumUserGenres();
965 for (i = 0; i < cnt; i++) {
966 g.push_back(local.GetUserGenre(i));
968 std::sort( g.begin(), g.end() );
970 for (i = 0; i < cnt; i++) {
971 parm = parm + (i == 0 ?
wxT(
"") :
wxT(
",")) + g[i];
976 auto editor =
mGrid->GetDefaultEditorForType(
wxT(
"Combo"));
977 editor->SetParameters(parm);
984 wxPoint topLeft(windowRect->GetTopLeft().x, windowRect->GetTopLeft().y);
985 wxPoint topRight(windowRect->GetTopRight().x, windowRect->GetTopRight().y);
986 wxPoint bottomLeft(windowRect->GetBottomLeft().x, windowRect->GetBottomLeft().y);
987 wxPoint bottomRight(windowRect->GetBottomRight().x, windowRect->GetBottomRight().y);
988 display.GetFromPoint(topLeft);
989 if (display.GetFromPoint(topLeft) == -1 &&
990 display.GetFromPoint(topRight) == -1 &&
991 display.GetFromPoint(bottomLeft) == -1 &&
992 display.GetFromPoint(bottomRight) == -1) {
1001#include <wx/frame.h>
1014 auto newTags = tags.Duplicate();
1017 if (tags != *newTags) {
1038 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.