mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-03 01:19:24 +02:00
Bug1119: Windows menu on Mac should list all project names...
... Reimplemented without making dependency cycles. Project and ProjectFileManager publish events for change of active project or change of a project title. WindowMenus.cpp can listen for those events, so that it can update the menu appropriately. So it's all done nonintrusively in the rest of the code.
This commit is contained in:
parent
3348e2fecd
commit
c3d0d0370b
@ -19,6 +19,7 @@
|
||||
#include <wx/frame.h>
|
||||
|
||||
wxDEFINE_EVENT(EVT_TRACK_PANEL_TIMER, wxCommandEvent);
|
||||
wxDEFINE_EVENT(EVT_PROJECT_ACTIVATION, wxCommandEvent);
|
||||
|
||||
size_t AllProjects::size() const
|
||||
{
|
||||
@ -111,6 +112,7 @@ void SetActiveProject(AudacityProject * project)
|
||||
if ( gActiveProject != project ) {
|
||||
gActiveProject = project;
|
||||
KeyboardCapture::Capture( nullptr );
|
||||
wxTheApp->QueueEvent( safenew wxCommandEvent{ EVT_PROJECT_ACTIVATION } );
|
||||
}
|
||||
wxTheApp->SetTopWindow( FindProjectFrame( project ) );
|
||||
}
|
||||
|
@ -93,6 +93,11 @@ using AttachedWindows = ClientData::Site<
|
||||
wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
|
||||
EVT_TRACK_PANEL_TIMER, wxCommandEvent);
|
||||
|
||||
// This event is emitted by the application object when there is a change
|
||||
// in the activated project
|
||||
wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
|
||||
EVT_PROJECT_ACTIVATION, wxCommandEvent);
|
||||
|
||||
///\brief The top-level handle to an Audacity project. It serves as a source
|
||||
/// of events that other objects can bind to, and a container of associated
|
||||
/// sub-objects that it treats opaquely. It stores a filename and a status
|
||||
|
@ -24,6 +24,8 @@ Paul Licameli split from AudacityProject.cpp
|
||||
#include "widgets/AudacityMessageBox.h"
|
||||
#include "widgets/NumericTextCtrl.h"
|
||||
|
||||
wxDEFINE_EVENT(EVT_PROJECT_TITLE_CHANGE, wxCommandEvent);
|
||||
|
||||
static void RefreshAllTitles(bool bShowProjectNumbers )
|
||||
{
|
||||
for ( auto pProject : AllProjects{} ) {
|
||||
@ -130,8 +132,13 @@ void ProjectFileIO::SetProjectTitle( int number)
|
||||
name += _("(Recovered)");
|
||||
}
|
||||
|
||||
window.SetTitle( name );
|
||||
window.SetName(name); // to make the nvda screen reader read the correct title
|
||||
if ( name != window.GetTitle() ) {
|
||||
window.SetTitle( name );
|
||||
window.SetName(name); // to make the nvda screen reader read the correct title
|
||||
|
||||
project.QueueEvent(
|
||||
safenew wxCommandEvent{ EVT_PROJECT_TITLE_CHANGE } );
|
||||
}
|
||||
}
|
||||
|
||||
// Most of this string was duplicated 3 places. Made the warning consistent in this global.
|
||||
|
@ -96,4 +96,9 @@ public:
|
||||
size_t UnnamedCount;
|
||||
};
|
||||
|
||||
// This event is emitted by the project when there is a change
|
||||
// in its title
|
||||
wxDECLARE_EXPORTED_EVENT(AUDACITY_DLL_API,
|
||||
EVT_PROJECT_TITLE_CHANGE, wxCommandEvent);
|
||||
|
||||
#endif
|
||||
|
@ -10,9 +10,11 @@
|
||||
#include "../CommonCommandFlags.h"
|
||||
#include "../Menus.h"
|
||||
#include "../Project.h"
|
||||
#include "../ProjectFileIO.h"
|
||||
#include "../commands/CommandContext.h"
|
||||
|
||||
#include <wx/frame.h>
|
||||
#include <wx/menu.h>
|
||||
|
||||
#undef USE_COCOA
|
||||
|
||||
@ -51,8 +53,64 @@ void DoMacMinimize(AudacityProject *project)
|
||||
}
|
||||
}
|
||||
|
||||
std::vector< wxWindowID > sReservedIds;
|
||||
std::vector< std::weak_ptr< AudacityProject > > sProjects;
|
||||
|
||||
void RebuildMenu(wxCommandEvent &evt)
|
||||
{
|
||||
// Let other listeners hear it too
|
||||
evt.Skip();
|
||||
|
||||
// This is a big hammer.
|
||||
// Really we just need to recreate just the Window menu.
|
||||
// This causes the checkmark to be put in the right place for the
|
||||
// currently active project
|
||||
MenuCreator::RebuildAllMenuBars();
|
||||
}
|
||||
|
||||
wxWindowID ReservedID(
|
||||
size_t index, const std::shared_ptr< AudacityProject > &pProject )
|
||||
{
|
||||
if ( sReservedIds.empty() ) {
|
||||
// Do this once only per session, and don't worry about unbinding
|
||||
wxTheApp->Bind( EVT_PROJECT_ACTIVATION, RebuildMenu );
|
||||
wxTheApp->Bind( EVT_PROJECT_TITLE_CHANGE, RebuildMenu );
|
||||
}
|
||||
|
||||
while ( sReservedIds.size() <= index )
|
||||
sReservedIds.emplace_back( wxIdManager::ReserveId() );
|
||||
|
||||
if ( sProjects.size() < sReservedIds.size() )
|
||||
sProjects.resize( sReservedIds.size() );
|
||||
sProjects[ index ] = pProject;
|
||||
|
||||
return sReservedIds[ index ];
|
||||
}
|
||||
|
||||
void OnWindow( wxCommandEvent &evt )
|
||||
{
|
||||
const auto begin = sReservedIds.begin(), end = sReservedIds.end(),
|
||||
iter = std::find( begin, end, evt.GetId() );
|
||||
size_t index = iter - begin;
|
||||
if ( index < sProjects.size() ) {
|
||||
auto pProject = sProjects[ index ].lock();
|
||||
if ( pProject ) {
|
||||
// Make it the active project
|
||||
SetActiveProject(pProject.get());
|
||||
|
||||
// And ensure it's visible
|
||||
wxFrame *frame = pProject->GetFrame();
|
||||
if (frame->IsIconized())
|
||||
{
|
||||
frame->Restore();
|
||||
}
|
||||
frame->Raise();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/// Namespace for functions for window management (mac only?)
|
||||
namespace WindowActions {
|
||||
|
||||
@ -144,6 +202,39 @@ BaseItemSharedPtr WindowMenu()
|
||||
* windows un-hidden */
|
||||
Command( wxT("MacBringAllToFront"), XXO("&Bring All to Front"),
|
||||
FN(OnMacBringAllToFront), AlwaysEnabledFlag )
|
||||
),
|
||||
|
||||
Section( "",
|
||||
Special( wxT("PopulateWindowsStep"),
|
||||
[](AudacityProject &, wxMenu &theMenu)
|
||||
{
|
||||
// Undo previous bindings
|
||||
for ( auto id : sReservedIds )
|
||||
wxTheApp->Unbind( wxEVT_MENU, OnWindow, id );
|
||||
|
||||
// Add all projects to this project's Window menu
|
||||
size_t ii = 0;
|
||||
for (auto project : AllProjects{})
|
||||
{
|
||||
int itemId = ReservedID( ii++, project );
|
||||
wxString itemName = project->GetFrame()->GetTitle();
|
||||
bool isActive = (GetActiveProject() == project.get());
|
||||
|
||||
// This should never really happen, but a menu item must have a name
|
||||
if (itemName.empty())
|
||||
{
|
||||
itemName = _("<untitled>");
|
||||
}
|
||||
|
||||
// Add it to the menu and check it if it's the active project
|
||||
wxMenuItem *item = theMenu.Append(itemId, itemName);
|
||||
item->SetCheckable(true);
|
||||
item->Check(isActive);
|
||||
|
||||
// Bind the callback
|
||||
wxTheApp->Bind( wxEVT_MENU, OnWindow, itemId );
|
||||
}
|
||||
} )
|
||||
)
|
||||
) ) };
|
||||
return menu;
|
||||
|
Loading…
x
Reference in New Issue
Block a user